Merge tag 'media/v5.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab...
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Aug 2022 02:29:28 +0000 (19:29 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 4 Aug 2022 02:29:28 +0000 (19:29 -0700)
Pull media updates from Mauro Carvalho Chehab:

 - New driver for Semi AR0521 sensor

 - rkisp1 CSI code was split into a separate file

 - sun6i has gained support for the A31 MIPI CSI-2 controller

 - sun8i has gained support for the A83T MIPI CSI-2 controller

 - vimc driver got support for virtual lens

 - HEVC uAPI has gained its final form and got added to public headers

 - hantro and cedrus got updates on H-265 support

 - stkwebcam was promoted from staging

 - atomisp staging driver got cleanups on its hmm and kmap related logic

 - ov5640 gained support for more modes and got some rework

 - imx7-media-csi staging driver got several improvements related to mc
   API support

 - uvcvideo now handles better power line control

 - mediatec vcodec gained support for new hardware and got some codec
   updates

 - Lots of other bug fixes, improvements and cleanups.

* tag 'media/v5.20-1' of git://git.kernel.org/pub/scm/linux/kernel/git/mchehab/linux-media: (446 commits)
  media: hantro: Remove dedicated control documentation
  hantro: Remove incorrect HEVC SPS validation
  media: cedrus: hevc: Add check for invalid timestamp
  media: sunxi: sun6i_mipi_csi2.c/sun8i_a83t_mipi_csi2.c: clarify error handling
  media: uvcvideo: Fix invalid pointer in uvc_ctrl_init_ctrl()
  media: Documentation: mc-core: Fix typo
  media: videodev2.h.rst.exceptions: add missing exceptions
  media: vimc: wrong pointer is used with PTR_ERR
  media: rkisp1: debug: Add dump file in debugfs for MI main path registers
  media: rkisp1: Make the internal CSI-2 receiver optional
  media: rkisp1: Add infrastructure to support ISP features
  media: rkisp1: Support the ISP parallel input
  media: dt-bindings: media: rkisp1: Add port for parallel interface
  media: rkisp1: Use fwnode_graph_for_each_endpoint
  media: rkisp1: csi: Plumb the CSI RX subdev
  media: rkisp1: csi: Implement a V4L2 subdev for the CSI receiver
  media: rkisp1: isp: Disallow multiple active sources
  media: rkisp1: isp: Rename rkisp1_get_remote_source()
  media: rkisp1: isp: Constify various local variables
  media: rkisp1: isp: Fix whitespace issues
  ...

360 files changed:
Documentation/admin-guide/media/vimc.dot
Documentation/admin-guide/media/vimc.rst
Documentation/admin-guide/media/vivid.rst
Documentation/devicetree/bindings/media/allwinner,sun6i-a31-csi.yaml
Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt [deleted file]
Documentation/devicetree/bindings/media/i2c/aptina,mt9p031.yaml
Documentation/devicetree/bindings/media/i2c/onnn,ar0521.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/i2c/ovti,ov5693.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/mediatek,vcodec-subdev-decoder.yaml
Documentation/devicetree/bindings/media/mediatek-jpeg-encoder.yaml
Documentation/devicetree/bindings/media/nxp,imx-mipi-csi2.yaml
Documentation/devicetree/bindings/media/qcom,sdm660-camss.yaml
Documentation/devicetree/bindings/media/rockchip,rk3568-vepu.yaml [new file with mode: 0644]
Documentation/devicetree/bindings/media/rockchip-isp1.yaml
Documentation/devicetree/bindings/media/samsung,s5pv210-jpeg.yaml [new file with mode: 0644]
Documentation/driver-api/media/mc-core.rst
Documentation/driver-api/media/v4l2-subdev.rst
Documentation/userspace-api/media/drivers/hantro.rst [deleted file]
Documentation/userspace-api/media/drivers/index.rst
Documentation/userspace-api/media/v4l/control.rst
Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
Documentation/userspace-api/media/v4l/mmap.rst
Documentation/userspace-api/media/v4l/pixfmt-compressed.rst
Documentation/userspace-api/media/v4l/pixfmt-packed-yuv.rst
Documentation/userspace-api/media/v4l/pixfmt-yuv-planar.rst
Documentation/userspace-api/media/v4l/vidioc-g-ext-ctrls.rst
Documentation/userspace-api/media/v4l/vidioc-queryctrl.rst
Documentation/userspace-api/media/videodev2.h.rst.exceptions
MAINTAINERS
drivers/media/cec/core/cec-adap.c
drivers/media/cec/platform/cros-ec/cros-ec-cec.c
drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
drivers/media/common/videobuf2/videobuf2-v4l2.c
drivers/media/i2c/Kconfig
drivers/media/i2c/Makefile
drivers/media/i2c/adv7180.c
drivers/media/i2c/adv748x/adv748x.h
drivers/media/i2c/adv7604.c
drivers/media/i2c/ar0521.c [new file with mode: 0644]
drivers/media/i2c/mt9p031.c
drivers/media/i2c/ov5640.c
drivers/media/i2c/ov5693.c
drivers/media/i2c/ov7251.c
drivers/media/i2c/st-mipid02.c
drivers/media/i2c/tda1997x.c
drivers/media/i2c/tvp5150.c
drivers/media/mc/mc-entity.c
drivers/media/pci/cx18/cx18-av-core.c
drivers/media/pci/cx88/cx88-core.c
drivers/media/pci/ddbridge/ddbridge-ci.c
drivers/media/pci/ddbridge/ddbridge-ci.h
drivers/media/pci/ddbridge/ddbridge-core.c
drivers/media/pci/ddbridge/ddbridge-hw.c
drivers/media/pci/ddbridge/ddbridge-hw.h
drivers/media/pci/ddbridge/ddbridge-i2c.c
drivers/media/pci/ddbridge/ddbridge-i2c.h
drivers/media/pci/ddbridge/ddbridge-io.h
drivers/media/pci/ddbridge/ddbridge-main.c
drivers/media/pci/ddbridge/ddbridge-max.c
drivers/media/pci/ddbridge/ddbridge-max.h
drivers/media/pci/ddbridge/ddbridge-mci.c
drivers/media/pci/ddbridge/ddbridge-mci.h
drivers/media/pci/ddbridge/ddbridge-regs.h
drivers/media/pci/ddbridge/ddbridge-sx8.c
drivers/media/pci/ddbridge/ddbridge.h
drivers/media/pci/intel/ipu3/ipu3-cio2-main.c
drivers/media/pci/saa7164/saa7164-api.c
drivers/media/pci/sta2x11/Kconfig
drivers/media/pci/tw5864/tw5864-core.c
drivers/media/pci/tw686x/tw686x-core.c
drivers/media/pci/tw686x/tw686x-video.c
drivers/media/platform/amphion/vdec.c
drivers/media/platform/amphion/venc.c
drivers/media/platform/amphion/vpu.h
drivers/media/platform/amphion/vpu_cmds.c
drivers/media/platform/amphion/vpu_core.c
drivers/media/platform/amphion/vpu_dbg.c
drivers/media/platform/amphion/vpu_malone.c
drivers/media/platform/amphion/vpu_malone.h
drivers/media/platform/amphion/vpu_msgs.c
drivers/media/platform/amphion/vpu_rpc.c
drivers/media/platform/amphion/vpu_rpc.h
drivers/media/platform/amphion/vpu_v4l2.c
drivers/media/platform/atmel/Kconfig
drivers/media/platform/atmel/atmel-isc-base.c
drivers/media/platform/atmel/atmel-sama7g5-isc.c
drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
drivers/media/platform/mediatek/mdp/mtk_mdp_ipi.h
drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec.c
drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_drv.c
drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.c
drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_hw.h
drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_pm.c
drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateful.c
drivers/media/platform/mediatek/vcodec/mtk_vcodec_dec_stateless.c
drivers/media/platform/mediatek/vcodec/mtk_vcodec_drv.h
drivers/media/platform/mediatek/vcodec/mtk_vcodec_enc.c
drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_common.c
drivers/media/platform/mediatek/vcodec/vdec/vdec_h264_req_multi_if.c
drivers/media/platform/mediatek/vcodec/vdec/vdec_vp8_req_if.c
drivers/media/platform/mediatek/vcodec/vdec/vdec_vp9_req_lat_if.c
drivers/media/platform/mediatek/vcodec/vdec_drv_if.c
drivers/media/platform/mediatek/vcodec/vdec_vpu_if.c
drivers/media/platform/nvidia/tegra-vde/h264.c
drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.c
drivers/media/platform/nxp/imx-jpeg/mxc-jpeg-hw.h
drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h
drivers/media/platform/nxp/imx-mipi-csis.c
drivers/media/platform/qcom/camss/camss-csid.c
drivers/media/platform/qcom/camss/camss-csiphy.c
drivers/media/platform/qcom/camss/camss-ispif.c
drivers/media/platform/qcom/camss/camss-vfe.c
drivers/media/platform/qcom/camss/camss-vfe.h
drivers/media/platform/qcom/camss/camss-video.c
drivers/media/platform/qcom/camss/camss.c
drivers/media/platform/qcom/camss/camss.h
drivers/media/platform/qcom/venus/core.c
drivers/media/platform/qcom/venus/core.h
drivers/media/platform/qcom/venus/dbgfs.c
drivers/media/platform/qcom/venus/dbgfs.h
drivers/media/platform/qcom/venus/helpers.c
drivers/media/platform/qcom/venus/hfi_cmds.c
drivers/media/platform/qcom/venus/hfi_cmds.h
drivers/media/platform/qcom/venus/hfi_helper.h
drivers/media/platform/qcom/venus/hfi_parser.c
drivers/media/platform/qcom/venus/hfi_platform.c
drivers/media/platform/qcom/venus/hfi_platform.h
drivers/media/platform/qcom/venus/hfi_venus.c
drivers/media/platform/renesas/rcar-vin/rcar-core.c
drivers/media/platform/renesas/rcar-vin/rcar-csi2.c
drivers/media/platform/renesas/rcar-vin/rcar-dma.c
drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
drivers/media/platform/renesas/rcar_drif.c
drivers/media/platform/renesas/vsp1/vsp1_entity.c
drivers/media/platform/renesas/vsp1/vsp1_video.c
drivers/media/platform/rockchip/rkisp1/Kconfig
drivers/media/platform/rockchip/rkisp1/Makefile
drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
drivers/media/platform/rockchip/rkisp1/rkisp1-common.c
drivers/media/platform/rockchip/rkisp1/rkisp1-common.h
drivers/media/platform/rockchip/rkisp1/rkisp1-csi.c [new file with mode: 0644]
drivers/media/platform/rockchip/rkisp1/rkisp1-csi.h [new file with mode: 0644]
drivers/media/platform/rockchip/rkisp1/rkisp1-debug.c [new file with mode: 0644]
drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h
drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
drivers/media/platform/samsung/exynos-gsc/gsc-core.c
drivers/media/platform/samsung/exynos-gsc/gsc-core.h
drivers/media/platform/samsung/exynos4-is/common.c
drivers/media/platform/samsung/exynos4-is/fimc-capture.c
drivers/media/platform/samsung/exynos4-is/fimc-is-errno.h
drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c
drivers/media/platform/samsung/exynos4-is/fimc-lite.c
drivers/media/platform/samsung/exynos4-is/media-dev.c
drivers/media/platform/samsung/exynos4-is/mipi-csis.c
drivers/media/platform/samsung/s3c-camif/camif-capture.c
drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c
drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
drivers/media/platform/st/sti/delta/delta-v4l2.c
drivers/media/platform/st/stm32/stm32-dcmi.c
drivers/media/platform/sunxi/Kconfig
drivers/media/platform/sunxi/Makefile
drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
drivers/media/platform/sunxi/sun6i-mipi-csi2/Kconfig [new file with mode: 0644]
drivers/media/platform/sunxi/sun6i-mipi-csi2/Makefile [new file with mode: 0644]
drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c [new file with mode: 0644]
drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.h [new file with mode: 0644]
drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2_reg.h [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Kconfig [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/Makefile [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.c [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_dphy.h [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.h [new file with mode: 0644]
drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2_reg.h [new file with mode: 0644]
drivers/media/platform/ti/cal/cal-camerarx.c
drivers/media/platform/ti/cal/cal-video.c
drivers/media/platform/ti/davinci/vpif.c
drivers/media/platform/ti/omap/omap_voutlib.c
drivers/media/platform/ti/omap3isp/isp.c
drivers/media/platform/ti/omap3isp/ispccdc.c
drivers/media/platform/ti/omap3isp/ispccp2.c
drivers/media/platform/ti/omap3isp/ispcsi2.c
drivers/media/platform/ti/omap3isp/ispvideo.c
drivers/media/platform/video-mux.c
drivers/media/platform/xilinx/xilinx-csi2rxss.c
drivers/media/platform/xilinx/xilinx-dma.c
drivers/media/platform/xilinx/xilinx-vip.h
drivers/media/rc/ati_remote.c
drivers/media/rc/igorplugusb.c
drivers/media/rc/iguanair.c
drivers/media/rc/imon_raw.c
drivers/media/rc/lirc_dev.c
drivers/media/rc/rc-main.c
drivers/media/rc/redrat3.c
drivers/media/rc/streamzap.c
drivers/media/rc/ttusbir.c
drivers/media/rc/xbox_remote.c
drivers/media/test-drivers/vicodec/vicodec-core.c
drivers/media/test-drivers/vimc/Makefile
drivers/media/test-drivers/vimc/vimc-capture.c
drivers/media/test-drivers/vimc/vimc-common.h
drivers/media/test-drivers/vimc/vimc-core.c
drivers/media/test-drivers/vimc/vimc-debayer.c
drivers/media/test-drivers/vimc/vimc-lens.c [new file with mode: 0644]
drivers/media/test-drivers/vimc/vimc-scaler.c
drivers/media/test-drivers/vimc/vimc-sensor.c
drivers/media/test-drivers/vimc/vimc-streamer.c
drivers/media/test-drivers/vivid/vivid-ctrls.c
drivers/media/test-drivers/vivid/vivid-vid-common.c
drivers/media/usb/Kconfig
drivers/media/usb/Makefile
drivers/media/usb/airspy/airspy.c
drivers/media/usb/em28xx/em28xx-audio.c
drivers/media/usb/em28xx/em28xx-camera.c
drivers/media/usb/em28xx/em28xx-cards.c
drivers/media/usb/em28xx/em28xx-core.c
drivers/media/usb/em28xx/em28xx-dvb.c
drivers/media/usb/em28xx/em28xx-i2c.c
drivers/media/usb/em28xx/em28xx-input.c
drivers/media/usb/em28xx/em28xx-v4l.h
drivers/media/usb/em28xx/em28xx-vbi.c
drivers/media/usb/em28xx/em28xx-video.c
drivers/media/usb/em28xx/em28xx.h
drivers/media/usb/gspca/spca501.c
drivers/media/usb/gspca/xirlink_cit.c
drivers/media/usb/hdpvr/hdpvr-video.c
drivers/media/usb/pvrusb2/pvrusb2-hdw.c
drivers/media/usb/stkwebcam/Kconfig [deleted file]
drivers/media/usb/stkwebcam/Makefile [deleted file]
drivers/media/usb/stkwebcam/stk-sensor.c [deleted file]
drivers/media/usb/stkwebcam/stk-webcam.c [deleted file]
drivers/media/usb/stkwebcam/stk-webcam.h [deleted file]
drivers/media/usb/usbtv/usbtv-video.c
drivers/media/usb/usbtv/usbtv.h
drivers/media/usb/uvc/uvc_ctrl.c
drivers/media/usb/uvc/uvc_driver.c
drivers/media/usb/uvc/uvc_isight.c
drivers/media/usb/uvc/uvc_queue.c
drivers/media/usb/uvc/uvc_status.c
drivers/media/usb/uvc/uvc_v4l2.c
drivers/media/usb/uvc/uvc_video.c
drivers/media/usb/uvc/uvcvideo.h
drivers/media/v4l2-core/Kconfig
drivers/media/v4l2-core/v4l2-async.c
drivers/media/v4l2-core/v4l2-common.c
drivers/media/v4l2-core/v4l2-ctrls-api.c
drivers/media/v4l2-core/v4l2-ctrls-core.c
drivers/media/v4l2-core/v4l2-ctrls-defs.c
drivers/media/v4l2-core/v4l2-ctrls-priv.h
drivers/media/v4l2-core/v4l2-ctrls-request.c
drivers/media/v4l2-core/v4l2-ioctl.c
drivers/media/v4l2-core/v4l2-mem2mem.c
drivers/staging/media/Kconfig
drivers/staging/media/Makefile
drivers/staging/media/atomisp/Makefile
drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
drivers/staging/media/atomisp/i2c/atomisp-ov2722.c
drivers/staging/media/atomisp/i2c/ov5693/ov5693.h
drivers/staging/media/atomisp/include/hmm/hmm.h
drivers/staging/media/atomisp/include/hmm/hmm_bo.h
drivers/staging/media/atomisp/include/hmm/hmm_common.h
drivers/staging/media/atomisp/include/hmm/hmm_pool.h [deleted file]
drivers/staging/media/atomisp/include/linux/atomisp.h
drivers/staging/media/atomisp/notes.txt [new file with mode: 0644]
drivers/staging/media/atomisp/pci/atomisp_acc.c [deleted file]
drivers/staging/media/atomisp/pci/atomisp_acc.h [deleted file]
drivers/staging/media/atomisp/pci/atomisp_cmd.c
drivers/staging/media/atomisp/pci/atomisp_compat.h
drivers/staging/media/atomisp/pci/atomisp_compat_css20.c
drivers/staging/media/atomisp/pci/atomisp_compat_ioctl32.h
drivers/staging/media/atomisp/pci/atomisp_drvfs.c
drivers/staging/media/atomisp/pci/atomisp_fops.c
drivers/staging/media/atomisp/pci/atomisp_ioctl.c
drivers/staging/media/atomisp/pci/atomisp_ioctl.h
drivers/staging/media/atomisp/pci/atomisp_subdev.c
drivers/staging/media/atomisp/pci/atomisp_subdev.h
drivers/staging/media/atomisp/pci/atomisp_v4l2.c
drivers/staging/media/atomisp/pci/hive_isp_css_include/host/debug_public.h
drivers/staging/media/atomisp/pci/hmm/hmm.c
drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
drivers/staging/media/atomisp/pci/hmm/hmm_dynamic_pool.c [deleted file]
drivers/staging/media/atomisp/pci/hmm/hmm_reserved_pool.c [deleted file]
drivers/staging/media/atomisp/pci/ia_css_frame_public.h
drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_1.0/ia_css_sdis.host.c
drivers/staging/media/atomisp/pci/isp/kernels/sdis/sdis_2/ia_css_sdis2.host.c
drivers/staging/media/atomisp/pci/isp/modes/interface/isp_const.h
drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c
drivers/staging/media/atomisp/pci/runtime/frame/interface/ia_css_frame.h
drivers/staging/media/atomisp/pci/runtime/frame/src/frame.c
drivers/staging/media/atomisp/pci/runtime/isp_param/src/isp_param.c
drivers/staging/media/atomisp/pci/runtime/rmgr/src/rmgr_vbuf.c
drivers/staging/media/atomisp/pci/runtime/spctrl/src/spctrl.c
drivers/staging/media/atomisp/pci/sh_css.c
drivers/staging/media/atomisp/pci/sh_css_firmware.c
drivers/staging/media/atomisp/pci/sh_css_mipi.c
drivers/staging/media/atomisp/pci/sh_css_params.c
drivers/staging/media/av7110/av7110.c
drivers/staging/media/hantro/hantro.h
drivers/staging/media/hantro/hantro_drv.c
drivers/staging/media/hantro/hantro_g2_hevc_dec.c
drivers/staging/media/hantro/hantro_g2_regs.h
drivers/staging/media/hantro/hantro_g2_vp9_dec.c
drivers/staging/media/hantro/hantro_hevc.c
drivers/staging/media/hantro/hantro_hw.h
drivers/staging/media/hantro/hantro_postproc.c
drivers/staging/media/hantro/hantro_v4l2.c
drivers/staging/media/hantro/hantro_v4l2.h
drivers/staging/media/hantro/imx8m_vpu_hw.c
drivers/staging/media/hantro/rockchip_vpu_hw.c
drivers/staging/media/hantro/sama5d4_vdec_hw.c
drivers/staging/media/hantro/sunxi_vpu_hw.c
drivers/staging/media/imx/imx-media-dev-common.c
drivers/staging/media/imx/imx-media-utils.c
drivers/staging/media/imx/imx7-media-csi.c
drivers/staging/media/omap4iss/iss.c
drivers/staging/media/omap4iss/iss_csi2.c
drivers/staging/media/omap4iss/iss_video.c
drivers/staging/media/rkvdec/rkvdec-h264.c
drivers/staging/media/rkvdec/rkvdec-vp9.c
drivers/staging/media/stkwebcam/Kconfig [new file with mode: 0644]
drivers/staging/media/stkwebcam/Makefile [new file with mode: 0644]
drivers/staging/media/stkwebcam/TODO [new file with mode: 0644]
drivers/staging/media/stkwebcam/stk-sensor.c [new file with mode: 0644]
drivers/staging/media/stkwebcam/stk-webcam.c [new file with mode: 0644]
drivers/staging/media/stkwebcam/stk-webcam.h [new file with mode: 0644]
drivers/staging/media/sunxi/cedrus/cedrus.c
drivers/staging/media/sunxi/cedrus/cedrus.h
drivers/staging/media/sunxi/cedrus/cedrus_dec.c
drivers/staging/media/sunxi/cedrus/cedrus_h264.c
drivers/staging/media/sunxi/cedrus/cedrus_h265.c
drivers/staging/media/sunxi/cedrus/cedrus_mpeg2.c
drivers/staging/media/sunxi/cedrus/cedrus_regs.h
drivers/staging/media/sunxi/cedrus/cedrus_video.c
drivers/staging/media/sunxi/cedrus/cedrus_vp8.c
drivers/staging/media/tegra-video/vi.c
drivers/staging/media/zoran/videocodec.c
drivers/staging/media/zoran/videocodec.h
drivers/staging/media/zoran/zoran.h
drivers/staging/media/zoran/zr36016.c
drivers/staging/media/zoran/zr36050.c
drivers/staging/media/zoran/zr36060.c
include/media/hevc-ctrls.h [deleted file]
include/media/media-entity.h
include/media/tpg/v4l2-tpg.h
include/media/v4l2-async.h
include/media/v4l2-common.h
include/media/v4l2-ctrls.h
include/media/v4l2-subdev.h
include/media/videobuf2-v4l2.h
include/uapi/linux/v4l2-controls.h
include/uapi/linux/videodev2.h

index 8e829c1..92a5bb6 100644 (file)
@@ -5,9 +5,13 @@ digraph board {
        n00000001 [label="{{} | Sensor A\n/dev/v4l-subdev0 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
        n00000001:port0 -> n00000005:port0 [style=bold]
        n00000001:port0 -> n0000000b [style=bold]
+       n00000001 -> n00000002
+       n00000002 [label="{{} | Lens A\n/dev/v4l-subdev5 | {<port0>}}", shape=Mrecord, style=filled, fillcolor=green]
        n00000003 [label="{{} | Sensor B\n/dev/v4l-subdev1 | {<port0> 0}}", shape=Mrecord, style=filled, fillcolor=green]
        n00000003:port0 -> n00000008:port0 [style=bold]
        n00000003:port0 -> n0000000f [style=bold]
+       n00000003 -> n00000004
+       n00000004 [label="{{} | Lens B\n/dev/v4l-subdev6 | {<port0>}}", shape=Mrecord, style=filled, fillcolor=green]
        n00000005 [label="{{<port0> 0} | Debayer A\n/dev/v4l-subdev2 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
        n00000005:port1 -> n00000015:port0
        n00000008 [label="{{<port0> 0} | Debayer B\n/dev/v4l-subdev3 | {<port1> 1}}", shape=Mrecord, style=filled, fillcolor=green]
index 0b07f05..3b4d2b3 100644 (file)
@@ -53,6 +53,25 @@ vimc-sensor:
 
        * 1 Pad source
 
+vimc-lens:
+       Ancillary lens for a sensor. Supports auto focus control. Linked to
+       a vimc-sensor using an ancillary link. The lens supports FOCUS_ABSOLUTE
+       control.
+
+.. code-block:: bash
+
+       media-ctl -p
+       ...
+       - entity 28: Lens A (0 pad, 0 link)
+                       type V4L2 subdev subtype Lens flags 0
+                       device node name /dev/v4l-subdev6
+       - entity 29: Lens B (0 pad, 0 link)
+                       type V4L2 subdev subtype Lens flags 0
+                       device node name /dev/v4l-subdev7
+       v4l2-ctl -d /dev/v4l-subdev7 -C focus_absolute
+       focus_absolute: 0
+
+
 vimc-debayer:
        Transforms images in bayer format into a non-bayer format.
        Exposes:
index 6d7175f..4f680dc 100644 (file)
@@ -714,6 +714,20 @@ The Test Pattern Controls are all specific to video capture.
 
        does the same for the EAV (End of Active Video) code.
 
+- Insert Video Guard Band
+
+       adds 4 columns of pixels with the HDMI Video Guard Band code at the
+       left hand side of the image. This only works with 3 or 4 byte RGB pixel
+       formats. The RGB pixel value 0xab/0x55/0xab turns out to be equivalent
+       to the HDMI Video Guard Band code that precedes each active video line
+       (see section 5.2.2.1 in the HDMI 1.3 Specification). To test if a video
+       receiver has correct HDMI Video Guard Band processing, enable this
+       control and then move the image to the left hand side of the screen.
+       That will result in video lines that start with multiple pixels that
+       have the same value as the Video Guard Band that precedes them.
+       Receivers that will just keep skipping Video Guard Band values will
+       now fail and either loose sync or these video lines will shift.
+
 
 Capture Feature Selection Controls
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index 8b56807..8551c4a 100644 (file)
@@ -42,6 +42,7 @@ properties:
 
   port:
     $ref: /schemas/graph.yaml#/$defs/port-base
+    description: Parallel input port, connect to a parallel sensor
 
     properties:
       endpoint:
@@ -59,7 +60,24 @@ properties:
         required:
           - bus-width
 
-    additionalProperties: false
+    unevaluatedProperties: false
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port@0:
+        $ref: "#/properties/port"
+
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: MIPI CSI-2 bridge input port
+
+    anyOf:
+      - required:
+          - port@0
+      - required:
+          - port@1
 
 required:
   - compatible
@@ -69,6 +87,12 @@ required:
   - clock-names
   - resets
 
+oneOf:
+  - required:
+      - ports
+  - required:
+      - port
+
 additionalProperties: false
 
 examples:
@@ -89,19 +113,25 @@ examples:
                       "ram";
         resets = <&ccu RST_BUS_CSI>;
 
-        port {
-            /* Parallel bus endpoint */
-            csi1_ep: endpoint {
-                remote-endpoint = <&adv7611_ep>;
-                bus-width = <16>;
-
-                /*
-                 * If hsync-active/vsync-active are missing,
-                 * embedded BT.656 sync is used.
-                 */
-                 hsync-active = <0>; /* Active low */
-                 vsync-active = <0>; /* Active low */
-                 pclk-sample = <1>;  /* Rising */
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            port@0 {
+                reg = <0>;
+                /* Parallel bus endpoint */
+                csi1_ep: endpoint {
+                    remote-endpoint = <&adv7611_ep>;
+                    bus-width = <16>;
+
+                    /*
+                     * If hsync-active/vsync-active are missing,
+                     * embedded BT.656 sync is used.
+                     */
+                    hsync-active = <0>; /* Active low */
+                    vsync-active = <0>; /* Active low */
+                    pclk-sample = <1>;  /* Rising */
+                };
             };
         };
     };
diff --git a/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml
new file mode 100644 (file)
index 0000000..09725ca
--- /dev/null
@@ -0,0 +1,137 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/allwinner,sun6i-a31-mipi-csi2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A31 MIPI CSI-2 Device Tree Bindings
+
+maintainers:
+  - Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+
+properties:
+  compatible:
+    oneOf:
+      - const: allwinner,sun6i-a31-mipi-csi2
+      - items:
+          - const: allwinner,sun8i-v3s-mipi-csi2
+          - const: allwinner,sun6i-a31-mipi-csi2
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Bus Clock
+      - description: Module Clock
+
+  clock-names:
+    items:
+      - const: bus
+      - const: mod
+
+  phys:
+    maxItems: 1
+    description: MIPI D-PHY
+
+  phy-names:
+    items:
+      - const: dphy
+
+  resets:
+    maxItems: 1
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port@0:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        description: Input port, connect to a MIPI CSI-2 sensor
+
+        properties:
+          reg:
+            const: 0
+
+          endpoint:
+            $ref: video-interfaces.yaml#
+            unevaluatedProperties: false
+
+            properties:
+              data-lanes:
+                minItems: 1
+                maxItems: 4
+
+            required:
+              - data-lanes
+
+        unevaluatedProperties: false
+
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Output port, connect to a CSI controller
+
+    required:
+      - port@0
+      - port@1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - phys
+  - phy-names
+  - resets
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/sun8i-v3s-ccu.h>
+    #include <dt-bindings/reset/sun8i-v3s-ccu.h>
+
+    mipi_csi2: csi@1cb1000 {
+        compatible = "allwinner,sun8i-v3s-mipi-csi2",
+                     "allwinner,sun6i-a31-mipi-csi2";
+        reg = <0x01cb1000 0x1000>;
+        interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&ccu CLK_BUS_CSI>,
+                 <&ccu CLK_CSI1_SCLK>;
+        clock-names = "bus", "mod";
+        resets = <&ccu RST_BUS_CSI>;
+
+        phys = <&dphy>;
+        phy-names = "dphy";
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            mipi_csi2_in: port@0 {
+                reg = <0>;
+
+                mipi_csi2_in_ov5648: endpoint {
+                    data-lanes = <1 2 3 4>;
+
+                    remote-endpoint = <&ov5648_out_mipi_csi2>;
+                };
+            };
+
+            mipi_csi2_out: port@1 {
+                reg = <1>;
+
+                mipi_csi2_out_csi0: endpoint {
+                    remote-endpoint = <&csi0_in_mipi_csi2>;
+                };
+            };
+        };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml b/Documentation/devicetree/bindings/media/allwinner,sun8i-a83t-mipi-csi2.yaml
new file mode 100644 (file)
index 0000000..5b27482
--- /dev/null
@@ -0,0 +1,125 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/allwinner,sun8i-a83t-mipi-csi2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Allwinner A83T MIPI CSI-2 Device Tree Bindings
+
+maintainers:
+  - Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+
+properties:
+  compatible:
+    const: allwinner,sun8i-a83t-mipi-csi2
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    items:
+      - description: Bus Clock
+      - description: Module Clock
+      - description: MIPI-specific Clock
+      - description: Misc CSI Clock
+
+  clock-names:
+    items:
+      - const: bus
+      - const: mod
+      - const: mipi
+      - const: misc
+
+  resets:
+    maxItems: 1
+
+  ports:
+    $ref: /schemas/graph.yaml#/properties/ports
+
+    properties:
+      port@0:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        description: Input port, connect to a MIPI CSI-2 sensor
+
+        properties:
+          reg:
+            const: 0
+
+          endpoint:
+            $ref: video-interfaces.yaml#
+            unevaluatedProperties: false
+
+            properties:
+              data-lanes:
+                minItems: 1
+                maxItems: 4
+
+            required:
+              - data-lanes
+
+        unevaluatedProperties: false
+
+      port@1:
+        $ref: /schemas/graph.yaml#/properties/port
+        description: Output port, connect to a CSI controller
+
+    required:
+      - port@0
+      - port@1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+  - resets
+  - ports
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/clock/sun8i-a83t-ccu.h>
+    #include <dt-bindings/reset/sun8i-a83t-ccu.h>
+
+    mipi_csi2: csi@1cb1000 {
+        compatible = "allwinner,sun8i-a83t-mipi-csi2";
+        reg = <0x01cb1000 0x1000>;
+        interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+        clocks = <&ccu CLK_BUS_CSI>,
+                 <&ccu CLK_CSI_SCLK>,
+                 <&ccu CLK_MIPI_CSI>,
+                 <&ccu CLK_CSI_MISC>;
+        clock-names = "bus", "mod", "mipi", "misc";
+        resets = <&ccu RST_BUS_CSI>;
+
+        ports {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            mipi_csi2_in: port@0 {
+                reg = <0>;
+
+                mipi_csi2_in_ov8865: endpoint {
+                    data-lanes = <1 2 3 4>;
+
+                    remote-endpoint = <&ov8865_out_mipi_csi2>;
+                };
+            };
+
+            mipi_csi2_out: port@1 {
+                reg = <1>;
+
+                mipi_csi2_out_csi: endpoint {
+                    remote-endpoint = <&csi_in_mipi_csi2>;
+                };
+            };
+        };
+    };
+
+...
diff --git a/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt b/Documentation/devicetree/bindings/media/exynos-jpeg-codec.txt
deleted file mode 100644 (file)
index ce9a226..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-Samsung S5P/Exynos SoC series JPEG codec
-
-Required properties:
-
-- compatible   : should be one of:
-                 "samsung,s5pv210-jpeg", "samsung,exynos4210-jpeg",
-                 "samsung,exynos3250-jpeg", "samsung,exynos5420-jpeg",
-                 "samsung,exynos5433-jpeg";
-- reg          : address and length of the JPEG codec IP register set;
-- interrupts   : specifies the JPEG codec IP interrupt;
-- clock-names   : should contain:
-                  - "jpeg" for the core gate clock,
-                  - "sclk" for the special clock (optional).
-- clocks       : should contain the clock specifier and clock ID list
-                 matching entries in the clock-names property; from
-                 the common clock bindings.
index c2ba781..1d6af1b 100644 (file)
@@ -17,6 +17,7 @@ description: |
 properties:
   compatible:
     enum:
+      - aptina,mt9p006
       - aptina,mt9p031
       - aptina,mt9p031m
 
diff --git a/Documentation/devicetree/bindings/media/i2c/onnn,ar0521.yaml b/Documentation/devicetree/bindings/media/i2c/onnn,ar0521.yaml
new file mode 100644 (file)
index 0000000..b617cc5
--- /dev/null
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/onnn,ar0521.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: ON Semiconductor AR0521 MIPI CSI-2 sensor
+
+maintainers:
+  - Krzysztof Hałasa <khalasa@piap.pl>
+
+description: |-
+  The AR0521 is a raw CMOS image sensor with MIPI CSI-2 and
+  I2C-compatible control interface.
+
+properties:
+  compatible:
+    const: onnn,ar0521
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    maxItems: 1
+
+  clock-names:
+    const: extclk
+
+  vaa-supply:
+    description:
+      Definition of the regulator used as analog (2.7 V) voltage supply.
+
+  vdd-supply:
+    description:
+      Definition of the regulator used as digital core (1.2 V) voltage supply.
+
+  vdd_io-supply:
+    description:
+      Definition of the regulator used as digital I/O (1.8 V) voltage supply.
+
+  reset-gpios:
+    description: reset GPIO, usually active low
+    maxItems: 1
+
+  port:
+    $ref: /schemas/graph.yaml#/$defs/port-base
+    unevaluatedProperties: false
+    description: |
+      Video output port.
+
+    properties:
+      endpoint:
+        $ref: /schemas/media/video-interfaces.yaml#
+        unevaluatedProperties: false
+
+        properties:
+          bus-type:
+            const: 4
+          data-lanes:
+            anyOf:
+              - items:
+                  - const: 1
+              - items:
+                  - const: 1
+                  - const: 2
+              - items:
+                  - const: 1
+                  - const: 2
+                  - const: 3
+                  - const: 4
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - clock-names
+  - vaa-supply
+  - vdd-supply
+  - vdd_io-supply
+  - port
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/clock/imx6qdl-clock.h>
+
+    i2c {
+            #address-cells = <1>;
+            #size-cells = <0>;
+
+            ar0521: camera-sensor@36 {
+                    compatible = "onnn,ar0521";
+                    reg = <0x36>;
+                    pinctrl-names = "default";
+                    pinctrl-0 = <&pinctrl_mipi_camera>;
+                    clocks = <&clks IMX6QDL_CLK_CKO>;
+                    clock-names = "extclk";
+                    reset-gpios = <&gpio1 7 GPIO_ACTIVE_LOW>;
+                    vaa-supply = <&reg_2p7v>;
+                    vdd-supply = <&reg_1p2v>;
+                    vdd_io-supply = <&reg_1p8v>;
+
+                    port {
+                           mipi_camera_to_mipi_csi2: endpoint {
+                                    remote-endpoint = <&mipi_csi2_in>;
+                                    data-lanes = <1 2 3 4>;
+                            };
+                    };
+            };
+    };
diff --git a/Documentation/devicetree/bindings/media/i2c/ovti,ov5693.yaml b/Documentation/devicetree/bindings/media/i2c/ovti,ov5693.yaml
new file mode 100644 (file)
index 0000000..359dc08
--- /dev/null
@@ -0,0 +1,124 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (c) 2022 Amarulasolutions
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/ovti,ov5693.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Omnivision OV5693 CMOS Sensor
+
+maintainers:
+  - Tommaso Merciai <tommaso.merciai@amarulasolutions.com>
+
+description: |
+  The Omnivision OV5693 is a high performance, 1/4-inch, 5 megapixel, CMOS
+  image sensor that delivers 2592x1944 at 30fps. It provides full-frame,
+  sub-sampled, and windowed 10-bit MIPI images in various formats via the
+  Serial Camera Control Bus (SCCB) interface.
+
+  OV5693 is controlled via I2C and two-wire Serial Camera Control Bus (SCCB).
+  The sensor output is available via CSI-2 serial data output (up to 2-lane).
+
+allOf:
+  - $ref: /schemas/media/video-interface-devices.yaml#
+
+properties:
+  compatible:
+    const: ovti,ov5693
+
+  reg:
+    maxItems: 1
+
+  clocks:
+    description:
+      System input clock (aka XVCLK). From 6 to 27 MHz.
+    maxItems: 1
+
+  dovdd-supply:
+    description:
+      Digital I/O voltage supply, 1.8V.
+
+  avdd-supply:
+    description:
+      Analog voltage supply, 2.8V.
+
+  dvdd-supply:
+    description:
+      Digital core voltage supply, 1.2V.
+
+  reset-gpios:
+    description:
+      The phandle and specifier for the GPIO that controls sensor reset.
+      This corresponds to the hardware pin XSHUTDN which is physically
+      active low.
+    maxItems: 1
+
+  port:
+    description: MIPI CSI-2 transmitter port
+    $ref: /schemas/graph.yaml#/$defs/port-base
+    additionalProperties: false
+
+    properties:
+      endpoint:
+        $ref: /schemas/media/video-interfaces.yaml#
+        unevaluatedProperties: false
+
+        properties:
+          link-frequencies: true
+
+          data-lanes:
+            minItems: 1
+            maxItems: 2
+
+        required:
+          - data-lanes
+          - link-frequencies
+
+required:
+  - compatible
+  - reg
+  - clocks
+  - port
+
+unevaluatedProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/px30-cru.h>
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/pinctrl/rockchip.h>
+
+    i2c {
+        #address-cells = <1>;
+        #size-cells = <0>;
+
+        ov5693: camera@36 {
+            compatible = "ovti,ov5693";
+            reg = <0x36>;
+
+            reset-gpios = <&gpio2 RK_PB1 GPIO_ACTIVE_LOW>;
+            pinctrl-names = "default";
+            pinctrl-0 = <&cif_clkout_m0>;
+
+            clocks = <&cru SCLK_CIF_OUT>;
+            assigned-clocks = <&cru SCLK_CIF_OUT>;
+            assigned-clock-rates = <19200000>;
+
+            avdd-supply = <&vcc_1v8>;
+            dvdd-supply = <&vcc_1v2>;
+            dovdd-supply = <&vcc_2v8>;
+
+            rotation = <90>;
+            orientation = <0>;
+
+            port {
+                ucam_out: endpoint {
+                    remote-endpoint = <&mipi_in_ucam>;
+                    data-lanes = <1 2>;
+                    link-frequencies = /bits/ 64 <450000000>;
+                };
+            };
+        };
+    };
+
+...
index 440646e..d4e2051 100644 (file)
@@ -17,20 +17,20 @@ description: |
 
   About the Decoder Hardware Block Diagram, please check below:
 
-    +---------------------------------+------------------------------------+
-    |                                 |                                    |
-    | input -> lat HW -> lat buffer --|--> lat buffer -> core HW -> output |
-    |            ||                   |                     ||             |
-    +------------||-------------------+---------------------||-------------+
-              lat workqueue           |              core workqueue     <parent>
-    -------------||-----------------------------------------||------------------
-                 ||                                         ||          <child>
-                 \/ <----------------HW index-------------->\/
-           +------------------------------------------------------+
-           |                    enable/disable                    |
-           |           clk     power    irq    iommu              |
-           |                 (lat/lat soc/core0/core1)            |
-           +------------------------------------------------------+
+    +------------------------------------------------+-------------------------------------+
+    |                                                |                                     |
+    |  input -> lat soc HW -> lat HW -> lat buffer --|--> lat buffer -> core HW -> output  |
+    |            ||             ||                   |                     ||              |
+    +------------||-------------||-------------------+---------------------||--------------+
+                 ||     lat     ||                   |               core workqueue  <parent>
+    -------------||-------------||-------------------|---------------------||---------------
+                 ||<------------||----------------HW index---------------->||        <child>
+                 \/             \/                                         \/
+               +-------------------------------------------------------------+
+               |                          enable/disable                     |
+               |                 clk     power    irq    iommu               |
+               |                   (lat/lat soc/core0/core1)                 |
+               +-------------------------------------------------------------+
 
   As above, there are parent and child devices, child mean each hardware. The child device
   controls the information of each hardware independent which include clk/power/irq.
@@ -45,11 +45,19 @@ description: |
   For the smi common may not the same for each hardware, can't combine all hardware in one node,
   or leading to iommu fault when access dram data.
 
+  Lat soc is a hardware which is related with some larb(local arbiter) ports. For mt8195
+  platform, there are some ports like RDMA, UFO in lat soc larb, need to enable its power and
+  clock when lat start to work, don't have interrupt.
+
+  mt8195: lat soc HW + lat HW + core HW
+  mt8192: lat HW + core HW
+
 properties:
   compatible:
     enum:
       - mediatek,mt8192-vcodec-dec
       - mediatek,mt8186-vcodec-dec
+      - mediatek,mt8195-vcodec-dec
 
   reg:
     maxItems: 1
@@ -87,7 +95,9 @@ patternProperties:
 
     properties:
       compatible:
-        const: mediatek,mtk-vcodec-lat
+        enum:
+          - mediatek,mtk-vcodec-lat
+          - mediatek,mtk-vcodec-lat-soc
 
       reg:
         maxItems: 1
@@ -125,7 +135,6 @@ patternProperties:
     required:
       - compatible
       - reg
-      - interrupts
       - iommus
       - clocks
       - clock-names
@@ -196,6 +205,17 @@ required:
   - dma-ranges
   - ranges
 
+if:
+  properties:
+    compatible:
+      contains:
+        enum:
+          - mediatek,mtk-vcodec-lat
+
+then:
+  required:
+    - interrupts
+
 additionalProperties: false
 
 examples:
index 8bfdfdf..4fd390c 100644 (file)
@@ -18,6 +18,7 @@ properties:
       - enum:
           - mediatek,mt2701-jpgenc
           - mediatek,mt8183-jpgenc
+          - mediatek,mt8186-jpgenc
       - const: mediatek,mtk-jpgenc
   reg:
     maxItems: 1
@@ -42,6 +43,11 @@ properties:
       Documentation/devicetree/bindings/iommu/mediatek,iommu.yaml for details.
       Ports are according to the HW.
 
+  dma-ranges:
+    maxItems: 1
+    description: |
+      Describes the physical address space of IOMMU maps to memory.
+
 required:
   - compatible
   - reg
index 36b135b..03a23a2 100644 (file)
@@ -22,9 +22,14 @@ description: |-
 
 properties:
   compatible:
-    enum:
-      - fsl,imx7-mipi-csi2
-      - fsl,imx8mm-mipi-csi2
+    oneOf:
+      - enum:
+          - fsl,imx7-mipi-csi2
+          - fsl,imx8mm-mipi-csi2
+      - items:
+          - enum:
+              - fsl,imx8mp-mipi-csi2
+          - const: fsl,imx8mm-mipi-csi2
 
   reg:
     maxItems: 1
index 338ab28..b28c8e1 100644 (file)
@@ -84,6 +84,13 @@ properties:
       - const: vfe0
       - const: vfe1
 
+  interconnects:
+    maxItems: 1
+
+  interconnect-names:
+    items:
+      - const: vfe-mem
+
   iommus:
     maxItems: 4
 
diff --git a/Documentation/devicetree/bindings/media/rockchip,rk3568-vepu.yaml b/Documentation/devicetree/bindings/media/rockchip,rk3568-vepu.yaml
new file mode 100644 (file)
index 0000000..81b26eb
--- /dev/null
@@ -0,0 +1,69 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+
+%YAML 1.2
+---
+$id: "http://devicetree.org/schemas/media/rockchip,rk3568-vepu.yaml#"
+$schema: "http://devicetree.org/meta-schemas/core.yaml#"
+
+title: Hantro G1 VPU encoders implemented on Rockchip SoCs
+
+maintainers:
+  - Nicolas Frattaroli <frattaroli.nicolas@gmail.com>
+
+description:
+  Hantro G1 video encode-only accelerators present on Rockchip SoCs.
+
+properties:
+  compatible:
+    enum:
+      - rockchip,rk3568-vepu
+
+  reg:
+    maxItems: 1
+
+  interrupts:
+    maxItems: 1
+
+  clocks:
+    maxItems: 2
+
+  clock-names:
+    items:
+      - const: aclk
+      - const: hclk
+
+  power-domains:
+    maxItems: 1
+
+  iommus:
+    maxItems: 1
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - clocks
+  - clock-names
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/rk3568-cru.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+    #include <dt-bindings/power/rk3568-power.h>
+
+    bus {
+        #address-cells = <2>;
+        #size-cells = <2>;
+
+        vepu: video-codec@fdee0000 {
+            compatible = "rockchip,rk3568-vepu";
+            reg = <0x0 0xfdee0000 0x0 0x800>;
+            interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+            clocks = <&cru ACLK_JENC>, <&cru HCLK_JENC>;
+            clock-names = "aclk", "hclk";
+            iommus = <&vepu_mmu>;
+            power-domains = <&power RK3568_PD_RGA>;
+        };
+    };
index d1489b1..b3661d7 100644 (file)
@@ -84,8 +84,27 @@ properties:
                 minItems: 1
                 maxItems: 4
 
-    required:
-      - port@0
+      port@1:
+        $ref: /schemas/graph.yaml#/$defs/port-base
+        unevaluatedProperties: false
+        description: connection point for input on the parallel interface
+
+        properties:
+          bus-type:
+            enum: [5, 6]
+
+          endpoint:
+            $ref: video-interfaces.yaml#
+            unevaluatedProperties: false
+
+        required:
+          - bus-type
+
+    anyOf:
+      - required:
+          - port@0
+      - required:
+          - port@1
 
 required:
   - compatible
diff --git a/Documentation/devicetree/bindings/media/samsung,s5pv210-jpeg.yaml b/Documentation/devicetree/bindings/media/samsung,s5pv210-jpeg.yaml
new file mode 100644 (file)
index 0000000..e28d6ec
--- /dev/null
@@ -0,0 +1,123 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/samsung,s5pv210-jpeg.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Samsung S5PV210 and Exynos SoC JPEG codec
+
+maintainers:
+  - Jacek Anaszewski <jacek.anaszewski@gmail.com>
+  - Krzysztof Kozlowski <krzk@kernel.org>
+  - Sylwester Nawrocki <s.nawrocki@samsung.com>
+  - Andrzej Pietrasiewicz <andrzejtp2010@gmail.com>
+
+properties:
+  compatible:
+    enum:
+      - samsung,s5pv210-jpeg
+      - samsung,exynos3250-jpeg
+      - samsung,exynos4210-jpeg
+      - samsung,exynos4212-jpeg
+      - samsung,exynos5420-jpeg
+      - samsung,exynos5433-jpeg
+
+  clocks:
+    minItems: 1
+    maxItems: 4
+
+  clock-names:
+    minItems: 1
+    maxItems: 4
+
+  interrupts:
+    maxItems: 1
+
+  iommus:
+    maxItems: 1
+
+  power-domains:
+    maxItems: 1
+
+  reg:
+    maxItems: 1
+
+
+required:
+  - compatible
+  - clocks
+  - clock-names
+  - interrupts
+  - reg
+
+allOf:
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,s5pv210-jpeg
+              - samsung,exynos4210-jpeg
+              - samsung,exynos4212-jpeg
+              - samsung,exynos5420-jpeg
+    then:
+      properties:
+        clocks:
+          maxItems: 1
+        clock-names:
+          items:
+            - const: jpeg
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,exynos3250-jpeg
+    then:
+      properties:
+        clocks:
+          minItems: 2
+          maxItems: 2
+        clock-names:
+          items:
+            - const: jpeg
+            - const: sclk
+
+  - if:
+      properties:
+        compatible:
+          contains:
+            enum:
+              - samsung,exynos5433-jpeg
+    then:
+      properties:
+        clocks:
+          minItems: 4
+          maxItems: 4
+        clock-names:
+          items:
+            - const: pclk
+            - const: aclk
+            - const: aclk_xiu
+            - const: sclk
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/clock/exynos5433.h>
+    #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+    codec@15020000 {
+        compatible = "samsung,exynos5433-jpeg";
+        reg = <0x15020000 0x10000>;
+        interrupts = <GIC_SPI 411 IRQ_TYPE_LEVEL_HIGH>;
+        clock-names = "pclk", "aclk", "aclk_xiu", "sclk";
+        clocks = <&cmu_mscl CLK_PCLK_JPEG>,
+                 <&cmu_mscl CLK_ACLK_JPEG>,
+                 <&cmu_mscl CLK_ACLK_XIU_MSCLX>,
+                 <&cmu_mscl CLK_SCLK_JPEG>;
+        iommus = <&sysmmu_jpeg>;
+        power-domains = <&pd_mscl>;
+    };
index 02481a2..84aa7cd 100644 (file)
@@ -186,8 +186,9 @@ is required and the graph structure can be freed normally.
 
 Helper functions can be used to find a link between two given pads, or a pad
 connected to another pad through an enabled link
-:c:func:`media_entity_find_link()` and
-:c:func:`media_entity_remote_pad()`.
+(:c:func:`media_entity_find_link()`, :c:func:`media_pad_remote_pad_first()`,
+:c:func:`media_entity_remote_source_pad_unique()` and
+:c:func:`media_pad_remote_pad_unique()`).
 
 Use count and power handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
index cf3b52b..6f8d799 100644 (file)
@@ -243,6 +243,12 @@ notifier callback is called. After all subdevices have been located the
 .complete() callback is called. When a subdevice is removed from the
 system the .unbind() method is called. All three callbacks are optional.
 
+Drivers can store any type of custom data in their driver-specific
+:c:type:`v4l2_async_subdev` wrapper. If any of that data requires special
+handling when the structure is freed, drivers must implement the ``.destroy()``
+notifier callback. The framework will call it right before freeing the
+:c:type:`v4l2_async_subdev`.
+
 Calling subdev operations
 ~~~~~~~~~~~~~~~~~~~~~~~~~
 
diff --git a/Documentation/userspace-api/media/drivers/hantro.rst b/Documentation/userspace-api/media/drivers/hantro.rst
deleted file mode 100644 (file)
index cd9754b..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-.. SPDX-License-Identifier: GPL-2.0
-
-Hantro video decoder driver
-===========================
-
-The Hantro video decoder driver implements the following driver-specific controls:
-
-``V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP (integer)``
-    Specifies to Hantro HEVC video decoder driver the number of data (in bits) to
-    skip in the slice segment header.
-    If non-IDR, the bits to be skipped go from syntax element "pic_output_flag"
-    to before syntax element "slice_temporal_mvp_enabled_flag".
-    If IDR, the skipped bits are just "pic_output_flag"
-    (separate_colour_plane_flag is not supported).
-
-.. note::
-
-        This control is not yet part of the public kernel API and
-        it is expected to change.
index 12e3c51..1a9038f 100644 (file)
@@ -33,7 +33,6 @@ For more details see the file COPYING in the source distribution of Linux.
 
        ccs
        cx2341x-uapi
-        hantro
        imx-uapi
        max2175
        meye-uapi
index 3eec651..4463fce 100644 (file)
@@ -461,10 +461,10 @@ Example: Changing controls
            perror("VIDIOC_QUERYCTRL");
            exit(EXIT_FAILURE);
        } else {
-           printf("V4L2_CID_BRIGHTNESS is not supportedn");
+           printf("V4L2_CID_BRIGHTNESS is not supported\n");
        }
     } else if (queryctrl.flags & V4L2_CTRL_FLAG_DISABLED) {
-       printf("V4L2_CID_BRIGHTNESS is not supportedn");
+       printf("V4L2_CID_BRIGHTNESS is not supported\n");
     } else {
        memset(&control, 0, sizeof (control));
        control.id = V4L2_CID_BRIGHTNESS;
index bee7306..cd33857 100644 (file)
@@ -2048,3 +2048,905 @@ This structure contains all loop filter related parameters. See sections
       - 0x2
       - When set, the bitstream contains additional syntax elements that
         specify which mode and reference frame deltas are to be updated.
+
+.. _v4l2-codec-stateless-hevc:
+
+``V4L2_CID_STATELESS_HEVC_SPS (struct)``
+    Specifies the Sequence Parameter Set fields (as extracted from the
+    bitstream) for the associated HEVC slice data.
+    These bitstream parameters are defined according to :ref:`hevc`.
+    They are described in section 7.4.3.2 "Sequence parameter set RBSP
+    semantics" of the specification.
+
+.. c:type:: v4l2_ctrl_hevc_sps
+
+.. raw:: latex
+
+    \small
+
+.. tabularcolumns:: |p{1.2cm}|p{9.2cm}|p{6.9cm}|
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_sps
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u8
+      - ``video_parameter_set_id``
+      - Specifies the value of the vps_video_parameter_set_id of the active VPS
+        as described in section "7.4.3.2.1 General sequence parameter set RBSP semantics"
+        of H.265 specifications.
+    * - __u8
+      - ``seq_parameter_set_id``
+      - Provides an identifier for the SPS for reference by other syntax elements
+        as described in section "7.4.3.2.1 General sequence parameter set RBSP semantics"
+        of H.265 specifications.
+    * - __u16
+      - ``pic_width_in_luma_samples``
+      - Specifies the width of each decoded picture in units of luma samples.
+    * - __u16
+      - ``pic_height_in_luma_samples``
+      - Specifies the height of each decoded picture in units of luma samples.
+    * - __u8
+      - ``bit_depth_luma_minus8``
+      - This value plus 8 specifies the bit depth of the samples of the luma array.
+    * - __u8
+      - ``bit_depth_chroma_minus8``
+      - This value plus 8 specifies the bit depth of the samples of the chroma arrays.
+    * - __u8
+      - ``log2_max_pic_order_cnt_lsb_minus4``
+      - Specifies the value of the variable MaxPicOrderCntLsb.
+    * - __u8
+      - ``sps_max_dec_pic_buffering_minus1``
+      - This value plus 1 specifies the maximum required size of the decoded picture buffer for
+        the coded video sequence (CVS).
+    * - __u8
+      - ``sps_max_num_reorder_pics``
+      - Indicates the maximum allowed number of pictures.
+    * - __u8
+      - ``sps_max_latency_increase_plus1``
+      - Used to signal MaxLatencyPictures, which indicates the maximum number of
+        pictures that can precede any picture in output order and follow that
+        picture in decoding order.
+    * - __u8
+      - ``log2_min_luma_coding_block_size_minus3``
+      - This value plus 3 specifies the minimum luma coding block size.
+    * - __u8
+      - ``log2_diff_max_min_luma_coding_block_size``
+      - Specifies the difference between the maximum and minimum luma coding block size.
+    * - __u8
+      - ``log2_min_luma_transform_block_size_minus2``
+      - This value plus 2 specifies the minimum luma transform block size.
+    * - __u8
+      - ``log2_diff_max_min_luma_transform_block_size``
+      - Specifies the difference between the maximum and minimum luma transform block size.
+    * - __u8
+      - ``max_transform_hierarchy_depth_inter``
+      - Specifies the maximum hierarchy depth for transform units of coding units coded
+        in inter prediction mode.
+    * - __u8
+      - ``max_transform_hierarchy_depth_intra``
+      - Specifies the maximum hierarchy depth for transform units of coding units coded in
+        intra prediction mode.
+    * - __u8
+      - ``pcm_sample_bit_depth_luma_minus1``
+      - This value plus 1 specifies the number of bits used to represent each of PCM sample values of the
+        luma component.
+    * - __u8
+      - ``pcm_sample_bit_depth_chroma_minus1``
+      - Specifies the number of bits used to represent each of PCM sample values of
+        the chroma components.
+    * - __u8
+      - ``log2_min_pcm_luma_coding_block_size_minus3``
+      - Plus 3 specifies the minimum size of coding blocks.
+    * - __u8
+      - ``log2_diff_max_min_pcm_luma_coding_block_size``
+      - Specifies the difference between the maximum and minimum size of coding blocks.
+    * - __u8
+      - ``num_short_term_ref_pic_sets``
+      - Specifies the number of st_ref_pic_set() syntax structures included in the SPS.
+    * - __u8
+      - ``num_long_term_ref_pics_sps``
+      - Specifies the number of candidate long-term reference pictures that are
+        specified in the SPS.
+    * - __u8
+      - ``chroma_format_idc``
+      - Specifies the chroma sampling.
+    * - __u8
+      - ``sps_max_sub_layers_minus1``
+      - This value plus 1 specifies the maximum number of temporal sub-layers.
+    * - __u64
+      - ``flags``
+      - See :ref:`Sequence Parameter Set Flags <hevc_sps_flags>`
+
+.. raw:: latex
+
+    \normalsize
+
+.. _hevc_sps_flags:
+
+``Sequence Parameter Set Flags``
+
+.. raw:: latex
+
+    \small
+
+.. cssclass:: longtable
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE``
+      - 0x00000001
+      -
+    * - ``V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED``
+      - 0x00000002
+      -
+    * - ``V4L2_HEVC_SPS_FLAG_AMP_ENABLED``
+      - 0x00000004
+      -
+    * - ``V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET``
+      - 0x00000008
+      -
+    * - ``V4L2_HEVC_SPS_FLAG_PCM_ENABLED``
+      - 0x00000010
+      -
+    * - ``V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED``
+      - 0x00000020
+      -
+    * - ``V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT``
+      - 0x00000040
+      -
+    * - ``V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED``
+      - 0x00000080
+      -
+    * - ``V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED``
+      - 0x00000100
+      -
+
+.. raw:: latex
+
+    \normalsize
+
+``V4L2_CID_STATELESS_HEVC_PPS (struct)``
+    Specifies the Picture Parameter Set fields (as extracted from the
+    bitstream) for the associated HEVC slice data.
+    These bitstream parameters are defined according to :ref:`hevc`.
+    They are described in section 7.4.3.3 "Picture parameter set RBSP
+    semantics" of the specification.
+
+.. c:type:: v4l2_ctrl_hevc_pps
+
+.. tabularcolumns:: |p{1.2cm}|p{8.6cm}|p{7.5cm}|
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_pps
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u8
+      - ``pic_parameter_set_id``
+      - Identifies the PPS for reference by other syntax elements.
+    * - __u8
+      - ``num_extra_slice_header_bits``
+      - Specifies the number of extra slice header bits that are present
+        in the slice header RBSP for coded pictures referring to the PPS.
+    * - __u8
+      - ``num_ref_idx_l0_default_active_minus1``
+      - This value plus 1 specifies the inferred value of num_ref_idx_l0_active_minus1.
+    * - __u8
+      - ``num_ref_idx_l1_default_active_minus1``
+      - This value plus 1 specifies the inferred value of num_ref_idx_l1_active_minus1.
+    * - __s8
+      - ``init_qp_minus26``
+      - This value plus 26 specifies the initial value of SliceQp Y for each slice
+        referring to the PPS.
+    * - __u8
+      - ``diff_cu_qp_delta_depth``
+      - Specifies the difference between the luma coding tree block size
+        and the minimum luma coding block size of coding units that
+        convey cu_qp_delta_abs and cu_qp_delta_sign_flag.
+    * - __s8
+      - ``pps_cb_qp_offset``
+      - Specifies the offsets to the luma quantization parameter Cb.
+    * - __s8
+      - ``pps_cr_qp_offset``
+      - Specifies the offsets to the luma quantization parameter Cr.
+    * - __u8
+      - ``num_tile_columns_minus1``
+      - This value plus 1 specifies the number of tile columns partitioning the picture.
+    * - __u8
+      - ``num_tile_rows_minus1``
+      - This value plus 1 specifies the number of tile rows partitioning the picture.
+    * - __u8
+      - ``column_width_minus1[20]``
+      - This value plus 1 specifies the width of the i-th tile column in units of
+        coding tree blocks.
+    * - __u8
+      - ``row_height_minus1[22]``
+      - This value plus 1 specifies the height of the i-th tile row in units of coding
+        tree blocks.
+    * - __s8
+      - ``pps_beta_offset_div2``
+      - Specifies the default deblocking parameter offsets for beta divided by 2.
+    * - __s8
+      - ``pps_tc_offset_div2``
+      - Specifies the default deblocking parameter offsets for tC divided by 2.
+    * - __u8
+      - ``log2_parallel_merge_level_minus2``
+      - This value plus 2 specifies the value of the variable Log2ParMrgLevel.
+    * - __u8
+      - ``padding[4]``
+      - Applications and drivers must set this to zero.
+    * - __u64
+      - ``flags``
+      - See :ref:`Picture Parameter Set Flags <hevc_pps_flags>`
+
+.. _hevc_pps_flags:
+
+``Picture Parameter Set Flags``
+
+.. raw:: latex
+
+    \small
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED``
+      - 0x00000001
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT``
+      - 0x00000002
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED``
+      - 0x00000004
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT``
+      - 0x00000008
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED``
+      - 0x00000010
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED``
+      - 0x00000020
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED``
+      - 0x00000040
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT``
+      - 0x00000080
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED``
+      - 0x00000100
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED``
+      - 0x00000200
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED``
+      - 0x00000400
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_TILES_ENABLED``
+      - 0x00000800
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED``
+      - 0x00001000
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED``
+      - 0x00002000
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED``
+      - 0x00004000
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED``
+      - 0x00008000
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER``
+      - 0x00010000
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT``
+      - 0x00020000
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT``
+      - 0x00040000
+      -
+    * - ``V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT``
+      - 0x00080000
+      - Specifies the presence of deblocking filter control syntax elements in
+        the PPS
+    * - ``V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING``
+      - 0x00100000
+      - Specifies that tile column boundaries and likewise tile row boundaries
+        are distributed uniformly across the picture
+
+.. raw:: latex
+
+    \normalsize
+
+``V4L2_CID_STATELESS_HEVC_SLICE_PARAMS (struct)``
+    Specifies various slice-specific parameters, especially from the NAL unit
+    header, general slice segment header and weighted prediction parameter
+    parts of the bitstream.
+    These bitstream parameters are defined according to :ref:`hevc`.
+    They are described in section 7.4.7 "General slice segment header
+    semantics" of the specification.
+    This control is a dynamically sized 1-dimensional array,
+    V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.
+
+.. c:type:: v4l2_ctrl_hevc_slice_params
+
+.. raw:: latex
+
+    \scriptsize
+
+.. tabularcolumns:: |p{5.4cm}|p{6.8cm}|p{5.1cm}|
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_slice_params
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u32
+      - ``bit_size``
+      - Size (in bits) of the current slice data.
+    * - __u32
+      - ``data_byte_offset``
+      - Offset (in byte) to the video data in the current slice data.
+    * - __u32
+      - ``num_entry_point_offsets``
+      - Specifies the number of entry point offset syntax elements in the slice header.
+        When the driver supports it, the ``V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS``
+        must be set.
+    * - __u8
+      - ``nal_unit_type``
+      - Specifies the coding type of the slice (B, P or I).
+    * - __u8
+      - ``nuh_temporal_id_plus1``
+      - Minus 1 specifies a temporal identifier for the NAL unit.
+    * - __u8
+      - ``slice_type``
+      -
+       (V4L2_HEVC_SLICE_TYPE_I, V4L2_HEVC_SLICE_TYPE_P or
+       V4L2_HEVC_SLICE_TYPE_B).
+    * - __u8
+      - ``colour_plane_id``
+      - Specifies the colour plane associated with the current slice.
+    * - __s32
+      - ``slice_pic_order_cnt``
+      - Specifies the picture order count.
+    * - __u8
+      - ``num_ref_idx_l0_active_minus1``
+      - This value plus 1 specifies the maximum reference index for reference picture list 0
+        that may be used to decode the slice.
+    * - __u8
+      - ``num_ref_idx_l1_active_minus1``
+      - This value plus 1 specifies the maximum reference index for reference picture list 1
+        that may be used to decode the slice.
+    * - __u8
+      - ``collocated_ref_idx``
+      - Specifies the reference index of the collocated picture used for
+        temporal motion vector prediction.
+    * - __u8
+      - ``five_minus_max_num_merge_cand``
+      - Specifies the maximum number of merging motion vector prediction
+        candidates supported in the slice subtracted from 5.
+    * - __s8
+      - ``slice_qp_delta``
+      - Specifies the initial value of QpY to be used for the coding blocks in the slice.
+    * - __s8
+      - ``slice_cb_qp_offset``
+      - Specifies a difference to be added to the value of pps_cb_qp_offset.
+    * - __s8
+      - ``slice_cr_qp_offset``
+      - Specifies a difference to be added to the value of pps_cr_qp_offset.
+    * - __s8
+      - ``slice_act_y_qp_offset``
+      - Specifies the offset to the luma of quantization parameter qP derived in section 8.6.2
+    * - __s8
+      - ``slice_act_cb_qp_offset``
+      - Specifies the offset to the cb of quantization parameter qP derived in section 8.6.2
+    * - __s8
+      - ``slice_act_cr_qp_offset``
+      - Specifies the offset to the cr of quantization parameter qP derived in section 8.6.2
+    * - __s8
+      - ``slice_beta_offset_div2``
+      - Specifies the deblocking parameter offsets for beta divided by 2.
+    * - __s8
+      - ``slice_tc_offset_div2``
+      - Specifies the deblocking parameter offsets for tC divided by 2.
+    * - __u8
+      - ``pic_struct``
+      - Indicates whether a picture should be displayed as a frame or as one or more fields.
+    * - __u32
+      - ``slice_segment_addr``
+      - Specifies the address of the first coding tree block in the slice segment.
+    * - __u8
+      - ``ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - The list of L0 reference elements as indices in the DPB.
+    * - __u8
+      - ``ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - The list of L1 reference elements as indices in the DPB.
+    * - __u16
+      - ``short_term_ref_pic_set_size``
+      - Specifies the size, in bits, of the short-term reference picture set, described as st_ref_pic_set()
+        in the specification, included in the slice header or SPS (section 7.3.6.1).
+    * - __u16
+      - ``long_term_ref_pic_set_size``
+      - Specifies the size, in bits, of the long-term reference picture set include in the slice header
+        or SPS. It is the number of bits in the conditional block if(long_term_ref_pics_present_flag)
+        in section 7.3.6.1 of the specification.
+    * - __u8
+      - ``padding``
+      - Applications and drivers must set this to zero.
+    * - struct :c:type:`v4l2_hevc_pred_weight_table`
+      - ``pred_weight_table``
+      - The prediction weight coefficients for inter-picture prediction.
+    * - __u64
+      - ``flags``
+      - See :ref:`Slice Parameters Flags <hevc_slice_params_flags>`
+
+.. raw:: latex
+
+    \normalsize
+
+.. _hevc_slice_params_flags:
+
+``Slice Parameters Flags``
+
+.. raw:: latex
+
+    \scriptsize
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA``
+      - 0x00000001
+      -
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA``
+      - 0x00000002
+      -
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED``
+      - 0x00000004
+      -
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO``
+      - 0x00000008
+      -
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT``
+      - 0x00000010
+      -
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0``
+      - 0x00000020
+      -
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV``
+      - 0x00000040
+      -
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED``
+      - 0x00000080
+      -
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED``
+      - 0x00000100
+      -
+    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT``
+      - 0x00000200
+      -
+
+.. raw:: latex
+
+    \normalsize
+
+``V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS (integer)``
+    Specifies entry point offsets in bytes.
+    This control is a dynamically sized array. The number of entry point
+    offsets is reported by the ``elems`` field.
+    This bitstream parameter is defined according to :ref:`hevc`.
+    They are described in section 7.4.7.1 "General slice segment header
+    semantics" of the specification.
+    When multiple slices are submitted in a request, the length of
+    this array must be the sum of num_entry_point_offsets of all the
+    slices in the request.
+
+``V4L2_CID_STATELESS_HEVC_SCALING_MATRIX (struct)``
+    Specifies the HEVC scaling matrix parameters used for the scaling process
+    for transform coefficients.
+    These matrix and parameters are defined according to :ref:`hevc`.
+    They are described in section 7.4.5 "Scaling list data semantics" of
+    the specification.
+
+.. c:type:: v4l2_ctrl_hevc_scaling_matrix
+
+.. raw:: latex
+
+    \scriptsize
+
+.. tabularcolumns:: |p{5.4cm}|p{6.8cm}|p{5.1cm}|
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_scaling_matrix
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u8
+      - ``scaling_list_4x4[6][16]``
+      - Scaling list is used for the scaling process for transform
+        coefficients. The values on each scaling list are expected
+        in raster scan order.
+    * - __u8
+      - ``scaling_list_8x8[6][64]``
+      - Scaling list is used for the scaling process for transform
+        coefficients. The values on each scaling list are expected
+        in raster scan order.
+    * - __u8
+      - ``scaling_list_16x16[6][64]``
+      - Scaling list is used for the scaling process for transform
+        coefficients. The values on each scaling list are expected
+        in raster scan order.
+    * - __u8
+      - ``scaling_list_32x32[2][64]``
+      - Scaling list is used for the scaling process for transform
+        coefficients. The values on each scaling list are expected
+        in raster scan order.
+    * - __u8
+      - ``scaling_list_dc_coef_16x16[6]``
+      - Scaling list is used for the scaling process for transform
+        coefficients. The values on each scaling list are expected
+        in raster scan order.
+    * - __u8
+      - ``scaling_list_dc_coef_32x32[2]``
+      - Scaling list is used for the scaling process for transform
+        coefficients. The values on each scaling list are expected
+        in raster scan order.
+
+.. raw:: latex
+
+    \normalsize
+
+.. c:type:: v4l2_hevc_dpb_entry
+
+.. raw:: latex
+
+    \small
+
+.. tabularcolumns:: |p{1.0cm}|p{4.2cm}|p{12.1cm}|
+
+.. flat-table:: struct v4l2_hevc_dpb_entry
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __u64
+      - ``timestamp``
+      - Timestamp of the V4L2 capture buffer to use as reference, used
+        with B-coded and P-coded frames. The timestamp refers to the
+       ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the
+       :c:func:`v4l2_timeval_to_ns()` function to convert the struct
+       :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64.
+    * - __u8
+      - ``flags``
+      - Long term flag for the reference frame
+        (V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE). The flag is set as
+        described in the ITU HEVC specification chapter "8.3.2 Decoding
+        process for reference picture set".
+    * - __u8
+      - ``field_pic``
+      - Whether the reference is a field picture or a frame.
+        See :ref:`HEVC dpb field pic Flags <hevc_dpb_field_pic_flags>`
+    * - __s32
+      - ``pic_order_cnt_val``
+      - The picture order count of the current picture.
+    * - __u8
+      - ``padding[2]``
+      - Applications and drivers must set this to zero.
+
+.. raw:: latex
+
+    \normalsize
+
+.. _hevc_dpb_field_pic_flags:
+
+``HEVC dpb field pic Flags``
+
+.. raw:: latex
+
+    \scriptsize
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_FRAME``
+      - 0
+      - (progressive) Frame
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_TOP_FIELD``
+      - 1
+      - Top field
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_FIELD``
+      - 2
+      - Bottom field
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_TOP_BOTTOM``
+      - 3
+      - Top field, bottom field, in that order
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_TOP``
+      - 4
+      - Bottom field, top field, in that order
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_TOP_BOTTOM_TOP``
+      - 5
+      - Top field, bottom field, top field repeated, in that order
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM``
+      - 6
+      - Bottom field, top field, bottom field repeated, in that order
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING``
+      - 7
+      - Frame doubling
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING``
+      - 8
+      - Frame tripling
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_TOP_PAIRED_PREVIOUS_BOTTOM``
+      - 9
+      - Top field paired with previous bottom field in output order
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_PAIRED_PREVIOUS_TOP``
+      - 10
+      - Bottom field paired with previous top field in output order
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_TOP_PAIRED_NEXT_BOTTOM``
+      - 11
+      - Top field paired with next bottom field in output order
+    * - ``V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_PAIRED_NEXT_TOP``
+      - 12
+      - Bottom field paired with next top field in output order
+
+.. c:type:: v4l2_hevc_pred_weight_table
+
+.. raw:: latex
+
+    \footnotesize
+
+.. tabularcolumns:: |p{0.8cm}|p{10.6cm}|p{5.9cm}|
+
+.. flat-table:: struct v4l2_hevc_pred_weight_table
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __s8
+      - ``delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - The difference of the weighting factor applied to the luma
+        prediction value for list 0.
+    * - __s8
+      - ``luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - The additive offset applied to the luma prediction value for list 0.
+    * - __s8
+      - ``delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]``
+      - The difference of the weighting factor applied to the chroma
+        prediction value for list 0.
+    * - __s8
+      - ``chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]``
+      - The difference of the additive offset applied to the chroma
+        prediction values for list 0.
+    * - __s8
+      - ``delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - The difference of the weighting factor applied to the luma
+        prediction value for list 1.
+    * - __s8
+      - ``luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - The additive offset applied to the luma prediction value for list 1.
+    * - __s8
+      - ``delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]``
+      - The difference of the weighting factor applied to the chroma
+        prediction value for list 1.
+    * - __s8
+      - ``chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]``
+      - The difference of the additive offset applied to the chroma
+        prediction values for list 1.
+    * - __u8
+      - ``luma_log2_weight_denom``
+      - The base 2 logarithm of the denominator for all luma weighting
+        factors.
+    * - __s8
+      - ``delta_chroma_log2_weight_denom``
+      - The difference of the base 2 logarithm of the denominator for
+        all chroma weighting factors.
+    * - __u8
+      - ``padding[6]``
+      - Applications and drivers must set this to zero.
+
+.. raw:: latex
+
+    \normalsize
+
+``V4L2_CID_STATELESS_HEVC_DECODE_MODE (enum)``
+    Specifies the decoding mode to use. Currently exposes slice-based and
+    frame-based decoding but new modes might be added later on.
+    This control is used as a modifier for V4L2_PIX_FMT_HEVC_SLICE
+    pixel format. Applications that support V4L2_PIX_FMT_HEVC_SLICE
+    are required to set this control in order to specify the decoding mode
+    that is expected for the buffer.
+    Drivers may expose a single or multiple decoding modes, depending
+    on what they can support.
+
+.. c:type:: v4l2_stateless_hevc_decode_mode
+
+.. raw:: latex
+
+    \small
+
+.. tabularcolumns:: |p{9.4cm}|p{0.6cm}|p{7.3cm}|
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED``
+      - 0
+      - Decoding is done at the slice granularity.
+        The OUTPUT buffer must contain a single slice.
+    * - ``V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED``
+      - 1
+      - Decoding is done at the frame granularity.
+        The OUTPUT buffer must contain all slices needed to decode the
+        frame.
+
+.. raw:: latex
+
+    \normalsize
+
+``V4L2_CID_STATELESS_HEVC_START_CODE (enum)``
+    Specifies the HEVC slice start code expected for each slice.
+    This control is used as a modifier for V4L2_PIX_FMT_HEVC_SLICE
+    pixel format. Applications that support V4L2_PIX_FMT_HEVC_SLICE
+    are required to set this control in order to specify the start code
+    that is expected for the buffer.
+    Drivers may expose a single or multiple start codes, depending
+    on what they can support.
+
+.. c:type:: v4l2_stateless_hevc_start_code
+
+.. tabularcolumns:: |p{9.2cm}|p{0.6cm}|p{7.5cm}|
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_STATELESS_HEVC_START_CODE_NONE``
+      - 0
+      - Selecting this value specifies that HEVC slices are passed
+        to the driver without any start code. The bitstream data should be
+        according to :ref:`hevc` 7.3.1.1 General NAL unit syntax, hence
+        contains emulation prevention bytes when required.
+    * - ``V4L2_STATELESS_HEVC_START_CODE_ANNEX_B``
+      - 1
+      - Selecting this value specifies that HEVC slices are expected
+        to be prefixed by Annex B start codes. According to :ref:`hevc`
+        valid start codes can be 3-bytes 0x000001 or 4-bytes 0x00000001.
+
+.. raw:: latex
+
+    \normalsize
+
+``V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID (integer)``
+    Specifies a priority identifier for the NAL unit, which will be applied to
+    the base layer. By default this value is set to 0 for the base layer,
+    and the next layer will have the priority ID assigned as 1, 2, 3 and so on.
+    The video encoder can't decide the priority id to be applied to a layer,
+    so this has to come from client.
+    This is applicable to H264 and valid Range is from 0 to 63.
+    Source Rec. ITU-T H.264 (06/2019); G.7.4.1.1, G.8.8.1.
+
+``V4L2_CID_MPEG_VIDEO_LTR_COUNT (integer)``
+    Specifies the maximum number of Long Term Reference (LTR) frames at any
+    given time that the encoder can keep.
+    This is applicable to the H264 and HEVC encoders.
+
+``V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX (integer)``
+    After setting this control the frame that will be queued next
+    will be marked as a Long Term Reference (LTR) frame
+    and given this LTR index which ranges from 0 to LTR_COUNT-1.
+    This is applicable to the H264 and HEVC encoders.
+    Source Rec. ITU-T H.264 (06/2019); Table 7.9
+
+``V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES (bitmask)``
+    Specifies the Long Term Reference (LTR) frame(s) to be used for
+    encoding the next frame queued after setting this control.
+    This provides a bitmask which consists of bits [0, LTR_COUNT-1].
+    This is applicable to the H264 and HEVC encoders.
+
+``V4L2_CID_STATELESS_HEVC_DECODE_PARAMS (struct)``
+    Specifies various decode parameters, especially the references picture order
+    count (POC) for all the lists (short, long, before, current, after) and the
+    number of entries for each of them.
+    These parameters are defined according to :ref:`hevc`.
+    They are described in section 8.3 "Slice decoding process" of the
+    specification.
+
+.. c:type:: v4l2_ctrl_hevc_decode_params
+
+.. cssclass:: longtable
+
+.. flat-table:: struct v4l2_ctrl_hevc_decode_params
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - __s32
+      - ``pic_order_cnt_val``
+      - PicOrderCntVal as described in section 8.3.1 "Decoding process
+        for picture order count" of the specification.
+    * - __u16
+      - ``short_term_ref_pic_set_size``
+      - Specifies the size, in bits, of the short-term reference picture set, of the first slice
+        described as st_ref_pic_set() in the specification, included in the slice header
+        or SPS (section 7.3.6.1).
+    * - __u16
+      - ``long_term_ref_pic_set_size``
+      - Specifies the size, in bits, of the long-term reference picture set, of the first slice
+        included in the slice header or SPS. It is the number of bits in the conditional block
+        if(long_term_ref_pics_present_flag) in section 7.3.6.1 of the specification.
+    * - __u8
+      - ``num_active_dpb_entries``
+      - The number of entries in ``dpb``.
+    * - __u8
+      - ``num_poc_st_curr_before``
+      - The number of reference pictures in the short-term set that come before
+        the current frame.
+    * - __u8
+      - ``num_poc_st_curr_after``
+      - The number of reference pictures in the short-term set that come after
+        the current frame.
+    * - __u8
+      - ``num_poc_lt_curr``
+      - The number of reference pictures in the long-term set.
+    * - __u8
+      - ``poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - PocStCurrBefore as described in section 8.3.2 "Decoding process for reference
+        picture set": provides the index of the short term before references in DPB array.
+    * - __u8
+      - ``poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - PocStCurrAfter as described in section 8.3.2 "Decoding process for reference
+        picture set": provides the index of the short term after references in DPB array.
+    * - __u8
+      - ``poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - PocLtCurr as described in section 8.3.2 "Decoding process for reference
+        picture set": provides the index of the long term references in DPB array.
+    * - struct :c:type:`v4l2_hevc_dpb_entry`
+      - ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
+      - The decoded picture buffer, for meta-data about reference frames.
+    * - __u64
+      - ``flags``
+      - See :ref:`Decode Parameters Flags <hevc_decode_params_flags>`
+
+.. _hevc_decode_params_flags:
+
+``Decode Parameters Flags``
+
+.. cssclass:: longtable
+
+.. flat-table::
+    :header-rows:  0
+    :stub-columns: 0
+    :widths:       1 1 2
+
+    * - ``V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC``
+      - 0x00000001
+      -
+    * - ``V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC``
+      - 0x00000002
+      -
+    * - ``V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR``
+      - 0x00000004
+      -
index 6183f43..2a165ae 100644 (file)
@@ -2658,783 +2658,3 @@ enum v4l2_mpeg_video_hevc_size_of_length_field -
     Indicates whether to generate SPS and PPS at every IDR. Setting it to 0
     disables generating SPS and PPS at every IDR. Setting it to one enables
     generating SPS and PPS at every IDR.
-
-.. _v4l2-mpeg-hevc:
-
-``V4L2_CID_MPEG_VIDEO_HEVC_SPS (struct)``
-    Specifies the Sequence Parameter Set fields (as extracted from the
-    bitstream) for the associated HEVC slice data.
-    These bitstream parameters are defined according to :ref:`hevc`.
-    They are described in section 7.4.3.2 "Sequence parameter set RBSP
-    semantics" of the specification.
-
-.. c:type:: v4l2_ctrl_hevc_sps
-
-.. raw:: latex
-
-    \small
-
-.. tabularcolumns:: |p{1.2cm}|p{9.2cm}|p{6.9cm}|
-
-.. cssclass:: longtable
-
-.. flat-table:: struct v4l2_ctrl_hevc_sps
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __u16
-      - ``pic_width_in_luma_samples``
-      -
-    * - __u16
-      - ``pic_height_in_luma_samples``
-      -
-    * - __u8
-      - ``bit_depth_luma_minus8``
-      -
-    * - __u8
-      - ``bit_depth_chroma_minus8``
-      -
-    * - __u8
-      - ``log2_max_pic_order_cnt_lsb_minus4``
-      -
-    * - __u8
-      - ``sps_max_dec_pic_buffering_minus1``
-      -
-    * - __u8
-      - ``sps_max_num_reorder_pics``
-      -
-    * - __u8
-      - ``sps_max_latency_increase_plus1``
-      -
-    * - __u8
-      - ``log2_min_luma_coding_block_size_minus3``
-      -
-    * - __u8
-      - ``log2_diff_max_min_luma_coding_block_size``
-      -
-    * - __u8
-      - ``log2_min_luma_transform_block_size_minus2``
-      -
-    * - __u8
-      - ``log2_diff_max_min_luma_transform_block_size``
-      -
-    * - __u8
-      - ``max_transform_hierarchy_depth_inter``
-      -
-    * - __u8
-      - ``max_transform_hierarchy_depth_intra``
-      -
-    * - __u8
-      - ``pcm_sample_bit_depth_luma_minus1``
-      -
-    * - __u8
-      - ``pcm_sample_bit_depth_chroma_minus1``
-      -
-    * - __u8
-      - ``log2_min_pcm_luma_coding_block_size_minus3``
-      -
-    * - __u8
-      - ``log2_diff_max_min_pcm_luma_coding_block_size``
-      -
-    * - __u8
-      - ``num_short_term_ref_pic_sets``
-      -
-    * - __u8
-      - ``num_long_term_ref_pics_sps``
-      -
-    * - __u8
-      - ``chroma_format_idc``
-      -
-    * - __u8
-      - ``sps_max_sub_layers_minus1``
-      -
-    * - __u64
-      - ``flags``
-      - See :ref:`Sequence Parameter Set Flags <hevc_sps_flags>`
-
-.. raw:: latex
-
-    \normalsize
-
-.. _hevc_sps_flags:
-
-``Sequence Parameter Set Flags``
-
-.. raw:: latex
-
-    \small
-
-.. cssclass:: longtable
-
-.. flat-table::
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - ``V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE``
-      - 0x00000001
-      -
-    * - ``V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED``
-      - 0x00000002
-      -
-    * - ``V4L2_HEVC_SPS_FLAG_AMP_ENABLED``
-      - 0x00000004
-      -
-    * - ``V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET``
-      - 0x00000008
-      -
-    * - ``V4L2_HEVC_SPS_FLAG_PCM_ENABLED``
-      - 0x00000010
-      -
-    * - ``V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED``
-      - 0x00000020
-      -
-    * - ``V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT``
-      - 0x00000040
-      -
-    * - ``V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED``
-      - 0x00000080
-      -
-    * - ``V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED``
-      - 0x00000100
-      -
-
-.. raw:: latex
-
-    \normalsize
-
-``V4L2_CID_MPEG_VIDEO_HEVC_PPS (struct)``
-    Specifies the Picture Parameter Set fields (as extracted from the
-    bitstream) for the associated HEVC slice data.
-    These bitstream parameters are defined according to :ref:`hevc`.
-    They are described in section 7.4.3.3 "Picture parameter set RBSP
-    semantics" of the specification.
-
-.. c:type:: v4l2_ctrl_hevc_pps
-
-.. tabularcolumns:: |p{1.2cm}|p{8.6cm}|p{7.5cm}|
-
-.. cssclass:: longtable
-
-.. flat-table:: struct v4l2_ctrl_hevc_pps
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __u8
-      - ``num_extra_slice_header_bits``
-      -
-    * - __u8
-      - ``num_ref_idx_l0_default_active_minus1``
-      - Specifies the inferred value of num_ref_idx_l0_active_minus1
-    * - __u8
-      - ``num_ref_idx_l1_default_active_minus1``
-      - Specifies the inferred value of num_ref_idx_l1_active_minus1
-    * - __s8
-      - ``init_qp_minus26``
-      -
-    * - __u8
-      - ``diff_cu_qp_delta_depth``
-      -
-    * - __s8
-      - ``pps_cb_qp_offset``
-      -
-    * - __s8
-      - ``pps_cr_qp_offset``
-      -
-    * - __u8
-      - ``num_tile_columns_minus1``
-      -
-    * - __u8
-      - ``num_tile_rows_minus1``
-      -
-    * - __u8
-      - ``column_width_minus1[20]``
-      -
-    * - __u8
-      - ``row_height_minus1[22]``
-      -
-    * - __s8
-      - ``pps_beta_offset_div2``
-      -
-    * - __s8
-      - ``pps_tc_offset_div2``
-      -
-    * - __u8
-      - ``log2_parallel_merge_level_minus2``
-      -
-    * - __u8
-      - ``padding[4]``
-      - Applications and drivers must set this to zero.
-    * - __u64
-      - ``flags``
-      - See :ref:`Picture Parameter Set Flags <hevc_pps_flags>`
-
-.. _hevc_pps_flags:
-
-``Picture Parameter Set Flags``
-
-.. raw:: latex
-
-    \small
-
-.. flat-table::
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - ``V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED``
-      - 0x00000001
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT``
-      - 0x00000002
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED``
-      - 0x00000004
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT``
-      - 0x00000008
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED``
-      - 0x00000010
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED``
-      - 0x00000020
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED``
-      - 0x00000040
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT``
-      - 0x00000080
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED``
-      - 0x00000100
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED``
-      - 0x00000200
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED``
-      - 0x00000400
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_TILES_ENABLED``
-      - 0x00000800
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED``
-      - 0x00001000
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED``
-      - 0x00002000
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED``
-      - 0x00004000
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED``
-      - 0x00008000
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER``
-      - 0x00010000
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT``
-      - 0x00020000
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT``
-      - 0x00040000
-      -
-    * - ``V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT``
-      - 0x00080000
-      - Specifies the presence of deblocking filter control syntax elements in
-        the PPS
-    * - ``V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING``
-      - 0x00100000
-      - Specifies that tile column boundaries and likewise tile row boundaries
-        are distributed uniformly across the picture
-
-.. raw:: latex
-
-    \normalsize
-
-``V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS (struct)``
-    Specifies various slice-specific parameters, especially from the NAL unit
-    header, general slice segment header and weighted prediction parameter
-    parts of the bitstream.
-    These bitstream parameters are defined according to :ref:`hevc`.
-    They are described in section 7.4.7 "General slice segment header
-    semantics" of the specification.
-
-.. c:type:: v4l2_ctrl_hevc_slice_params
-
-.. raw:: latex
-
-    \scriptsize
-
-.. tabularcolumns:: |p{5.4cm}|p{6.8cm}|p{5.1cm}|
-
-.. cssclass:: longtable
-
-.. flat-table:: struct v4l2_ctrl_hevc_slice_params
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __u32
-      - ``bit_size``
-      - Size (in bits) of the current slice data.
-    * - __u32
-      - ``data_bit_offset``
-      - Offset (in bits) to the video data in the current slice data.
-    * - __u8
-      - ``nal_unit_type``
-      -
-    * - __u8
-      - ``nuh_temporal_id_plus1``
-      -
-    * - __u8
-      - ``slice_type``
-      -
-       (V4L2_HEVC_SLICE_TYPE_I, V4L2_HEVC_SLICE_TYPE_P or
-       V4L2_HEVC_SLICE_TYPE_B).
-    * - __u8
-      - ``colour_plane_id``
-      -
-    * - __u16
-      - ``slice_pic_order_cnt``
-      -
-    * - __u8
-      - ``num_ref_idx_l0_active_minus1``
-      -
-    * - __u8
-      - ``num_ref_idx_l1_active_minus1``
-      -
-    * - __u8
-      - ``collocated_ref_idx``
-      -
-    * - __u8
-      - ``five_minus_max_num_merge_cand``
-      -
-    * - __s8
-      - ``slice_qp_delta``
-      -
-    * - __s8
-      - ``slice_cb_qp_offset``
-      -
-    * - __s8
-      - ``slice_cr_qp_offset``
-      -
-    * - __s8
-      - ``slice_act_y_qp_offset``
-      -
-    * - __s8
-      - ``slice_act_cb_qp_offset``
-      -
-    * - __s8
-      - ``slice_act_cr_qp_offset``
-      -
-    * - __s8
-      - ``slice_beta_offset_div2``
-      -
-    * - __s8
-      - ``slice_tc_offset_div2``
-      -
-    * - __u8
-      - ``pic_struct``
-      -
-    * - __u32
-      - ``slice_segment_addr``
-      -
-    * - __u8
-      - ``ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      - The list of L0 reference elements as indices in the DPB.
-    * - __u8
-      - ``ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      - The list of L1 reference elements as indices in the DPB.
-    * - __u8
-      - ``padding``
-      - Applications and drivers must set this to zero.
-    * - struct :c:type:`v4l2_hevc_pred_weight_table`
-      - ``pred_weight_table``
-      - The prediction weight coefficients for inter-picture prediction.
-    * - __u64
-      - ``flags``
-      - See :ref:`Slice Parameters Flags <hevc_slice_params_flags>`
-
-.. raw:: latex
-
-    \normalsize
-
-.. _hevc_slice_params_flags:
-
-``Slice Parameters Flags``
-
-.. raw:: latex
-
-    \scriptsize
-
-.. flat-table::
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA``
-      - 0x00000001
-      -
-    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA``
-      - 0x00000002
-      -
-    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED``
-      - 0x00000004
-      -
-    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO``
-      - 0x00000008
-      -
-    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT``
-      - 0x00000010
-      -
-    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0``
-      - 0x00000020
-      -
-    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV``
-      - 0x00000040
-      -
-    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED``
-      - 0x00000080
-      -
-    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED``
-      - 0x00000100
-      -
-    * - ``V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT``
-      - 0x00000200
-      -
-
-.. raw:: latex
-
-    \normalsize
-
-``V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX (struct)``
-    Specifies the HEVC scaling matrix parameters used for the scaling process
-    for transform coefficients.
-    These matrix and parameters are defined according to :ref:`hevc`.
-    They are described in section 7.4.5 "Scaling list data semantics" of
-    the specification.
-
-.. c:type:: v4l2_ctrl_hevc_scaling_matrix
-
-.. raw:: latex
-
-    \scriptsize
-
-.. tabularcolumns:: |p{5.4cm}|p{6.8cm}|p{5.1cm}|
-
-.. cssclass:: longtable
-
-.. flat-table:: struct v4l2_ctrl_hevc_scaling_matrix
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __u8
-      - ``scaling_list_4x4[6][16]``
-      - Scaling list is used for the scaling process for transform
-        coefficients. The values on each scaling list are expected
-        in raster scan order.
-    * - __u8
-      - ``scaling_list_8x8[6][64]``
-      - Scaling list is used for the scaling process for transform
-        coefficients. The values on each scaling list are expected
-        in raster scan order.
-    * - __u8
-      - ``scaling_list_16x16[6][64]``
-      - Scaling list is used for the scaling process for transform
-        coefficients. The values on each scaling list are expected
-        in raster scan order.
-    * - __u8
-      - ``scaling_list_32x32[2][64]``
-      - Scaling list is used for the scaling process for transform
-        coefficients. The values on each scaling list are expected
-        in raster scan order.
-    * - __u8
-      - ``scaling_list_dc_coef_16x16[6]``
-      - Scaling list is used for the scaling process for transform
-        coefficients. The values on each scaling list are expected
-        in raster scan order.
-    * - __u8
-      - ``scaling_list_dc_coef_32x32[2]``
-      - Scaling list is used for the scaling process for transform
-        coefficients. The values on each scaling list are expected
-        in raster scan order.
-
-.. raw:: latex
-
-    \normalsize
-
-.. c:type:: v4l2_hevc_dpb_entry
-
-.. raw:: latex
-
-    \small
-
-.. tabularcolumns:: |p{1.0cm}|p{4.2cm}|p{12.1cm}|
-
-.. flat-table:: struct v4l2_hevc_dpb_entry
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __u64
-      - ``timestamp``
-      - Timestamp of the V4L2 capture buffer to use as reference, used
-        with B-coded and P-coded frames. The timestamp refers to the
-       ``timestamp`` field in struct :c:type:`v4l2_buffer`. Use the
-       :c:func:`v4l2_timeval_to_ns()` function to convert the struct
-       :c:type:`timeval` in struct :c:type:`v4l2_buffer` to a __u64.
-    * - __u8
-      - ``flags``
-      - Long term flag for the reference frame
-        (V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE). The flag is set as
-        described in the ITU HEVC specification chapter "8.3.2 Decoding
-        process for reference picture set".
-    * - __u8
-      - ``field_pic``
-      - Whether the reference is a field picture or a frame.
-    * - __u16
-      - ``pic_order_cnt[2]``
-      - The picture order count of the reference. Only the first element of the
-        array is used for frame pictures, while the first element identifies the
-        top field and the second the bottom field in field-coded pictures.
-    * - __u8
-      - ``padding[2]``
-      - Applications and drivers must set this to zero.
-
-.. raw:: latex
-
-    \normalsize
-
-.. c:type:: v4l2_hevc_pred_weight_table
-
-.. raw:: latex
-
-    \footnotesize
-
-.. tabularcolumns:: |p{0.8cm}|p{10.6cm}|p{5.9cm}|
-
-.. flat-table:: struct v4l2_hevc_pred_weight_table
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __u8
-      - ``luma_log2_weight_denom``
-      -
-    * - __s8
-      - ``delta_chroma_log2_weight_denom``
-      -
-    * - __s8
-      - ``delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      -
-    * - __s8
-      - ``luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      -
-    * - __s8
-      - ``delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]``
-      -
-    * - __s8
-      - ``chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]``
-      -
-    * - __s8
-      - ``delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      -
-    * - __s8
-      - ``luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      -
-    * - __s8
-      - ``delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]``
-      -
-    * - __s8
-      - ``chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2]``
-      -
-    * - __u8
-      - ``padding[6]``
-      - Applications and drivers must set this to zero.
-
-.. raw:: latex
-
-    \normalsize
-
-``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE (enum)``
-    Specifies the decoding mode to use. Currently exposes slice-based and
-    frame-based decoding but new modes might be added later on.
-    This control is used as a modifier for V4L2_PIX_FMT_HEVC_SLICE
-    pixel format. Applications that support V4L2_PIX_FMT_HEVC_SLICE
-    are required to set this control in order to specify the decoding mode
-    that is expected for the buffer.
-    Drivers may expose a single or multiple decoding modes, depending
-    on what they can support.
-
-    .. note::
-
-       This menu control is not yet part of the public kernel API and
-       it is expected to change.
-
-.. c:type:: v4l2_mpeg_video_hevc_decode_mode
-
-.. raw:: latex
-
-    \small
-
-.. tabularcolumns:: |p{9.4cm}|p{0.6cm}|p{7.3cm}|
-
-.. flat-table::
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - ``V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED``
-      - 0
-      - Decoding is done at the slice granularity.
-        The OUTPUT buffer must contain a single slice.
-    * - ``V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED``
-      - 1
-      - Decoding is done at the frame granularity.
-        The OUTPUT buffer must contain all slices needed to decode the
-        frame. The OUTPUT buffer must also contain both fields.
-
-.. raw:: latex
-
-    \normalsize
-
-``V4L2_CID_MPEG_VIDEO_HEVC_START_CODE (enum)``
-    Specifies the HEVC slice start code expected for each slice.
-    This control is used as a modifier for V4L2_PIX_FMT_HEVC_SLICE
-    pixel format. Applications that support V4L2_PIX_FMT_HEVC_SLICE
-    are required to set this control in order to specify the start code
-    that is expected for the buffer.
-    Drivers may expose a single or multiple start codes, depending
-    on what they can support.
-
-    .. note::
-
-       This menu control is not yet part of the public kernel API and
-       it is expected to change.
-
-.. c:type:: v4l2_mpeg_video_hevc_start_code
-
-.. tabularcolumns:: |p{9.2cm}|p{0.6cm}|p{7.5cm}|
-
-.. flat-table::
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - ``V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE``
-      - 0
-      - Selecting this value specifies that HEVC slices are passed
-        to the driver without any start code. The bitstream data should be
-        according to :ref:`hevc` 7.3.1.1 General NAL unit syntax, hence
-        contains emulation prevention bytes when required.
-    * - ``V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B``
-      - 1
-      - Selecting this value specifies that HEVC slices are expected
-        to be prefixed by Annex B start codes. According to :ref:`hevc`
-        valid start codes can be 3-bytes 0x000001 or 4-bytes 0x00000001.
-
-``V4L2_CID_MPEG_VIDEO_BASELAYER_PRIORITY_ID (integer)``
-    Specifies a priority identifier for the NAL unit, which will be applied to
-    the base layer. By default this value is set to 0 for the base layer,
-    and the next layer will have the priority ID assigned as 1, 2, 3 and so on.
-    The video encoder can't decide the priority id to be applied to a layer,
-    so this has to come from client.
-    This is applicable to H264 and valid Range is from 0 to 63.
-    Source Rec. ITU-T H.264 (06/2019); G.7.4.1.1, G.8.8.1.
-
-``V4L2_CID_MPEG_VIDEO_LTR_COUNT (integer)``
-    Specifies the maximum number of Long Term Reference (LTR) frames at any
-    given time that the encoder can keep.
-    This is applicable to the H264 and HEVC encoders.
-
-``V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX (integer)``
-    After setting this control the frame that will be queued next
-    will be marked as a Long Term Reference (LTR) frame
-    and given this LTR index which ranges from 0 to LTR_COUNT-1.
-    This is applicable to the H264 and HEVC encoders.
-    Source Rec. ITU-T H.264 (06/2019); Table 7.9
-
-``V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES (bitmask)``
-    Specifies the Long Term Reference (LTR) frame(s) to be used for
-    encoding the next frame queued after setting this control.
-    This provides a bitmask which consists of bits [0, LTR_COUNT-1].
-    This is applicable to the H264 and HEVC encoders.
-
-``V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS (struct)``
-    Specifies various decode parameters, especially the references picture order
-    count (POC) for all the lists (short, long, before, current, after) and the
-    number of entries for each of them.
-    These parameters are defined according to :ref:`hevc`.
-    They are described in section 8.3 "Slice decoding process" of the
-    specification.
-
-.. c:type:: v4l2_ctrl_hevc_decode_params
-
-.. cssclass:: longtable
-
-.. flat-table:: struct v4l2_ctrl_hevc_decode_params
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - __s32
-      - ``pic_order_cnt_val``
-      - PicOrderCntVal as described in section 8.3.1 "Decoding process
-        for picture order count" of the specification.
-    * - __u8
-      - ``num_active_dpb_entries``
-      - The number of entries in ``dpb``.
-    * - struct :c:type:`v4l2_hevc_dpb_entry`
-      - ``dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      - The decoded picture buffer, for meta-data about reference frames.
-    * - __u8
-      - ``num_poc_st_curr_before``
-      - The number of reference pictures in the short-term set that come before
-        the current frame.
-    * - __u8
-      - ``num_poc_st_curr_after``
-      - The number of reference pictures in the short-term set that come after
-        the current frame.
-    * - __u8
-      - ``num_poc_lt_curr``
-      - The number of reference pictures in the long-term set.
-    * - __u8
-      - ``poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      - PocStCurrBefore as described in section 8.3.2 "Decoding process for reference
-        picture set": provides the index of the short term before references in DPB array.
-    * - __u8
-      - ``poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      - PocStCurrAfter as described in section 8.3.2 "Decoding process for reference
-        picture set": provides the index of the short term after references in DPB array.
-    * - __u8
-      - ``poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX]``
-      - PocLtCurr as described in section 8.3.2 "Decoding process for reference
-        picture set": provides the index of the long term references in DPB array.
-    * - __u64
-      - ``flags``
-      - See :ref:`Decode Parameters Flags <hevc_decode_params_flags>`
-
-.. _hevc_decode_params_flags:
-
-``Decode Parameters Flags``
-
-.. cssclass:: longtable
-
-.. flat-table::
-    :header-rows:  0
-    :stub-columns: 0
-    :widths:       1 1 2
-
-    * - ``V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC``
-      - 0x00000001
-      -
-    * - ``V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC``
-      - 0x00000002
-      -
-    * - ``V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR``
-      - 0x00000004
-      -
index 16b1e13..a567257 100644 (file)
@@ -232,7 +232,7 @@ In the write loop, when the application runs out of free buffers, it
 must wait until an empty buffer can be dequeued and reused.
 
 To enqueue and dequeue a buffer applications use the
-:ref:`VIVIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
+:ref:`VIDIOC_QBUF <VIDIOC_QBUF>` and :ref:`VIDIOC_DQBUF <VIDIOC_QBUF>`
 ioctl. The status of a buffer being mapped, enqueued, full or empty can
 be determined at any time using the :ref:`VIDIOC_QUERYBUF` ioctl. Two
 methods exist to suspend execution of the application until one or more
index 967fc80..506dd3c 100644 (file)
@@ -212,14 +212,9 @@ Compressed Formats
         ``V4L2_CID_MPEG_VIDEO_HEVC_SPS``,
         ``V4L2_CID_MPEG_VIDEO_HEVC_PPS``, and
         ``V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS``.
-       See the :ref:`associated Codec Control IDs <v4l2-mpeg-hevc>`.
+       See the :ref:`associated Codec Control IDs <v4l2-codec-stateless-hevc>`.
        Buffers associated with this pixel format must contain the appropriate
        number of macroblocks to decode a full corresponding frame.
-
-       .. note::
-
-          This format is not yet part of the public kernel API and it
-          is expected to change.
     * .. _V4L2-PIX-FMT-FWHT:
 
       - ``V4L2_PIX_FMT_FWHT``
index 65520c3..bf283a1 100644 (file)
@@ -220,6 +220,26 @@ the second byte and Y'\ :sub:`7-0` in the third byte.
       - Y'\ :sub:`7-0`
       - X\ :sub:`7-0`
 
+    * .. _V4L2-PIX-FMT-YUVA32:
+
+      - ``V4L2_PIX_FMT_YUVA32``
+      - 'YUVA'
+
+      - Y'\ :sub:`7-0`
+      - Cb\ :sub:`7-0`
+      - Cr\ :sub:`7-0`
+      - A\ :sub:`7-0`
+
+    * .. _V4L2-PIX-FMT-YUVX32:
+
+      - ``V4L2_PIX_FMT_YUVX32``
+      - 'YUVX'
+
+      - Y'\ :sub:`7-0`
+      - Cb\ :sub:`7-0`
+      - Cr\ :sub:`7-0`
+      - X\ :sub:`7-0`
+
     * .. _V4L2-PIX-FMT-YUV24:
 
       - ``V4L2_PIX_FMT_YUV24``
index 8dff590..10b1fee 100644 (file)
@@ -109,6 +109,20 @@ All components are stored with the same number of bits per component.
       - Cb, Cr
       - No
       - 16x16 tiles
+    * - V4L2_PIX_FMT_P010
+      - 'P010'
+      - 10
+      - 4:2:0
+      - Cb, Cr
+      - Yes
+      - Linear
+    * - V4L2_PIX_FMT_P010_4L4
+      - 'T010'
+      - 10
+      - 4:2:0
+      - Cb, Cr
+      - Yes
+      - 4x4 tiles
     * - V4L2_PIX_FMT_NV16
       - 'NV16'
       - 8
@@ -171,6 +185,7 @@ horizontally.
 .. _V4L2-PIX-FMT-NV21:
 .. _V4L2-PIX-FMT-NV12M:
 .. _V4L2-PIX-FMT-NV21M:
+.. _V4L2-PIX-FMT-P010:
 
 NV12, NV21, NV12M and NV21M
 ---------------------------
@@ -519,6 +534,50 @@ number of lines as the luma plane.
       - Cb\ :sub:`33`
       - Cr\ :sub:`33`
 
+.. _V4L2_PIX_FMT_P010:
+.. _V4L2-PIX-FMT-P010-4L4:
+
+P010 and tiled P010
+-------------------
+
+P010 is like NV12 with 10 bits per component, expanded to 16 bits.
+Data in the 10 high bits, zeros in the 6 low bits, arranged in little endian order.
+
+.. flat-table:: Sample 4x4 P010 Image
+    :header-rows:  0
+    :stub-columns: 0
+
+    * - start + 0:
+      - Y'\ :sub:`00`
+      - Y'\ :sub:`01`
+      - Y'\ :sub:`02`
+      - Y'\ :sub:`03`
+    * - start + 8:
+      - Y'\ :sub:`10`
+      - Y'\ :sub:`11`
+      - Y'\ :sub:`12`
+      - Y'\ :sub:`13`
+    * - start + 16:
+      - Y'\ :sub:`20`
+      - Y'\ :sub:`21`
+      - Y'\ :sub:`22`
+      - Y'\ :sub:`23`
+    * - start + 24:
+      - Y'\ :sub:`30`
+      - Y'\ :sub:`31`
+      - Y'\ :sub:`32`
+      - Y'\ :sub:`33`
+    * - start + 32:
+      - Cb\ :sub:`00`
+      - Cr\ :sub:`00`
+      - Cb\ :sub:`01`
+      - Cr\ :sub:`01`
+    * - start + 40:
+      - Cb\ :sub:`10`
+      - Cr\ :sub:`10`
+      - Cb\ :sub:`11`
+      - Cr\ :sub:`11`
+
 
 Fully Planar YUV Formats
 ========================
@@ -538,6 +597,10 @@ relationship between the luma and chroma line padding and stride.
 
 All components are stored with the same number of bits per component.
 
+``V4L2_PIX_FMT_P010_4L4`` stores pixels in 4x4 tiles, and stores tiles linearly
+in memory. The line stride must be aligned to multiple of 8 and image height to
+a multiple of 4. The layouts of the luma and chroma planes are identical.
+
 .. raw:: latex
 
     \small
index 29971a4..892cfeb 100644 (file)
@@ -249,6 +249,26 @@ still cause this situation.
       - ``p_hdr10_mastering``
       - A pointer to a struct :c:type:`v4l2_ctrl_hdr10_mastering_display`. Valid if this control is
         of type ``V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY``.
+    * - struct :c:type:`v4l2_ctrl_hevc_sps` *
+      - ``p_hevc_sps``
+      - A pointer to a struct :c:type:`v4l2_ctrl_hevc_sps`. Valid if this
+        control is of type ``V4L2_CTRL_TYPE_HEVC_SPS``.
+    * - struct :c:type:`v4l2_ctrl_hevc_pps` *
+      - ``p_hevc_pps``
+      - A pointer to a struct :c:type:`v4l2_ctrl_hevc_pps`. Valid if this
+        control is of type ``V4L2_CTRL_TYPE_HEVC_PPS``.
+    * - struct :c:type:`v4l2_ctrl_hevc_slice_params` *
+      - ``p_hevc_slice_params``
+      - A pointer to a struct :c:type:`v4l2_ctrl_hevc_slice_params`. Valid if this
+        control is of type ``V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS``.
+    * - struct :c:type:`v4l2_ctrl_hevc_scaling_matrix` *
+      - ``p_hevc_scaling_matrix``
+      - A pointer to a struct :c:type:`v4l2_ctrl_hevc_scaling_matrix`. Valid if this
+        control is of type ``V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX``.
+    * - struct :c:type:`v4l2_ctrl_hevc_decode_params` *
+      - ``p_hevc_decode_params``
+      - A pointer to a struct :c:type:`v4l2_ctrl_hevc_decode_params`. Valid if this
+        control is of type ``V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS``.
     * - void *
       - ``ptr``
       - A pointer to a compound type which can be an N-dimensional array
index 88f6302..a20dfa2 100644 (file)
@@ -625,6 +625,14 @@ See also the examples in :ref:`control`.
        ``V4L2_CTRL_FLAG_GRABBED`` flag when buffers are allocated or
        streaming is in progress since most drivers do not support changing
        the format in that case.
+    * - ``V4L2_CTRL_FLAG_DYNAMIC_ARRAY``
+      - 0x0800
+      - This control is a dynamically sized 1-dimensional array. It
+        behaves the same as a regular array, except that the number
+       of elements as reported by the ``elems`` field is between 1 and
+       ``dims[0]``. So setting the control with a differently sized
+       array will change the ``elems`` field when the control is
+       queried afterwards.
 
 Return Value
 ============
index 9cbb7a0..64b2c0b 100644 (file)
@@ -70,6 +70,7 @@ replace symbol V4L2_COLORSPACE_REC709 :c:type:`v4l2_colorspace`
 replace symbol V4L2_COLORSPACE_SMPTE170M :c:type:`v4l2_colorspace`
 replace symbol V4L2_COLORSPACE_SMPTE240M :c:type:`v4l2_colorspace`
 replace symbol V4L2_COLORSPACE_SRGB :c:type:`v4l2_colorspace`
+replace symbol V4L2_COLORSPACE_LAST :c:type:`v4l2_colorspace`
 
 # Documented enum v4l2_xfer_func
 replace symbol V4L2_XFER_FUNC_709 :c:type:`v4l2_xfer_func`
@@ -81,6 +82,7 @@ replace symbol V4L2_XFER_FUNC_NONE :c:type:`v4l2_xfer_func`
 replace symbol V4L2_XFER_FUNC_SMPTE2084 :c:type:`v4l2_xfer_func`
 replace symbol V4L2_XFER_FUNC_SMPTE240M :c:type:`v4l2_xfer_func`
 replace symbol V4L2_XFER_FUNC_SRGB :c:type:`v4l2_xfer_func`
+replace symbol V4L2_XFER_FUNC_LAST :c:type:`v4l2_xfer_func`
 
 # Documented enum v4l2_ycbcr_encoding
 replace symbol V4L2_YCBCR_ENC_601 :c:type:`v4l2_ycbcr_encoding`
@@ -92,6 +94,7 @@ replace symbol V4L2_YCBCR_ENC_SYCC :c:type:`v4l2_ycbcr_encoding`
 replace symbol V4L2_YCBCR_ENC_XV601 :c:type:`v4l2_ycbcr_encoding`
 replace symbol V4L2_YCBCR_ENC_XV709 :c:type:`v4l2_ycbcr_encoding`
 replace symbol V4L2_YCBCR_ENC_SMPTE240M :c:type:`v4l2_ycbcr_encoding`
+replace symbol V4L2_YCBCR_ENC_LAST :c:type:`v4l2_ycbcr_encoding`
 
 # Documented enum v4l2_hsv_encoding
 replace symbol V4L2_HSV_ENC_180 :c:type:`v4l2_hsv_encoding`
@@ -153,6 +156,11 @@ replace symbol V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR :c:type:`v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_VP9_FRAME :c:type:`v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_HDR10_CLL_INFO :c:type:`v4l2_ctrl_type`
 replace symbol V4L2_CTRL_TYPE_HDR10_MASTERING_DISPLAY :c:type:`v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_HEVC_SPS :c:type:`v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_HEVC_PPS :c:type:`v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS :c:type:`v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX :c:type:`v4l2_ctrl_type`
+replace symbol V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS :c:type:`v4l2_ctrl_type`
 
 # V4L2 capability defines
 replace define V4L2_CAP_VIDEO_CAPTURE device-capabilities
@@ -379,6 +387,7 @@ replace define V4L2_CTRL_FLAG_VOLATILE control-flags
 replace define V4L2_CTRL_FLAG_HAS_PAYLOAD control-flags
 replace define V4L2_CTRL_FLAG_EXECUTE_ON_WRITE control-flags
 replace define V4L2_CTRL_FLAG_MODIFY_LAYOUT control-flags
+replace define V4L2_CTRL_FLAG_DYNAMIC_ARRAY control-flags
 
 replace define V4L2_CTRL_FLAG_NEXT_CTRL control
 replace define V4L2_CTRL_FLAG_NEXT_COMPOUND control
index 17273f0..9101b31 100644 (file)
@@ -766,6 +766,14 @@ T: git git://linuxtv.org/media_tree.git
 F:     Documentation/devicetree/bindings/media/allwinner,sun4i-a10-csi.yaml
 F:     drivers/media/platform/sunxi/sun4i-csi/
 
+ALLWINNER A31 MIPI CSI-2 BRIDGE DRIVER
+M:     Paul Kocialkowski <paul.kocialkowski@bootlin.com>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+T:     git git://linuxtv.org/media_tree.git
+F:     Documentation/devicetree/bindings/media/allwinner,sun6i-a31-mipi-csi2.yaml
+F:     drivers/media/platform/sunxi/sun6i-mipi-csi2/
+
 ALLWINNER CPUFREQ DRIVER
 M:     Yangtao Li <tiny.windzz@gmail.com>
 L:     linux-pm@vger.kernel.org
@@ -1473,6 +1481,13 @@ S:       Supported
 W:     http://www.aquantia.com
 F:     drivers/net/ethernet/aquantia/atlantic/aq_ptp*
 
+AR0521 ON SEMICONDUCTOR CAMERA SENSOR DRIVER
+M:     Krzysztof Hałasa <khalasa@piap.pl>
+L:     linux-media@vger.kernel.org
+S:     Maintained
+F:     Documentation/devicetree/bindings/media/i2c/onnn,ar0521.yaml
+F:     drivers/media/i2c/ar0521.c
+
 ARASAN NAND CONTROLLER DRIVER
 M:     Miquel Raynal <miquel.raynal@bootlin.com>
 M:     Naga Sureshkumar Relli <nagasure@xilinx.com>
@@ -2726,6 +2741,7 @@ M:        Sylwester Nawrocki <s.nawrocki@samsung.com>
 L:     linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
 L:     linux-media@vger.kernel.org
 S:     Maintained
+F:     Documentation/devicetree/bindings/media/samsung,s5pv210-jpeg.yaml
 F:     drivers/media/platform/samsung/s5p-jpeg/
 
 ARM/SAMSUNG S5P SERIES Multi Format Codec (MFC) SUPPORT
@@ -8811,6 +8827,7 @@ L:        linux-media@vger.kernel.org
 L:     linux-rockchip@lists.infradead.org
 S:     Maintained
 F:     Documentation/devicetree/bindings/media/nxp,imx8mq-vpu.yaml
+F:     Documentation/devicetree/bindings/media/rockchip,rk3568-vepu.yaml
 F:     Documentation/devicetree/bindings/media/rockchip-vpu.yaml
 F:     drivers/staging/media/hantro/
 
@@ -12630,6 +12647,7 @@ F:      Documentation/driver-api/media/
 F:     Documentation/userspace-api/media/
 F:     drivers/media/
 F:     drivers/staging/media/
+F:     include/dt-bindings/media/
 F:     include/linux/platform_data/media/
 F:     include/media/
 F:     include/uapi/linux/dvb/
@@ -12712,6 +12730,7 @@ F:      drivers/media/platform/mediatek/vpu/
 MEDIATEK MEDIA DRIVER
 M:     Tiffany Lin <tiffany.lin@mediatek.com>
 M:     Andrew-CT Chen <andrew-ct.chen@mediatek.com>
+M:     Yunfei Dong <yunfei.dong@mediatek.com>
 S:     Supported
 F:     Documentation/devicetree/bindings/media/mediatek,vcodec*.yaml
 F:     Documentation/devicetree/bindings/media/mediatek-vpu.txt
@@ -14915,6 +14934,7 @@ M:      Daniel Scally <djrscally@gmail.com>
 L:     linux-media@vger.kernel.org
 S:     Maintained
 T:     git git://linuxtv.org/media_tree.git
+F:     Documentation/devicetree/bindings/media/i2c/ovti,ov5693.yaml
 F:     drivers/media/i2c/ov5693.c
 
 OMNIVISION OV5695 SENSOR DRIVER
index 8bf91b5..41a7929 100644 (file)
@@ -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
index 8c8d8fc..3b583ed 100644 (file)
@@ -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,
index 7607b51..9b7bcdc 100644 (file)
@@ -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,
index 075d24e..f26cb85 100644 (file)
@@ -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
index 2b20aa6..7806d4b 100644 (file)
@@ -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.
index 3e16969..0a29331 100644 (file)
@@ -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
index e3a57c1..5fde524 100644 (file)
@@ -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 {
index 31bac06..d75eb3d 100644 (file)
@@ -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;
 
index bb0c8fc..497419a 100644 (file)
@@ -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 (file)
index 0000000..c7bdfc6
--- /dev/null
@@ -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");
index cbce8b8..1fd4dc6 100644 (file)
@@ -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 */ },
index db5a19b..502f0b6 100644 (file)
 #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
 #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
 #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.
  */
 
 /*
@@ -829,13 +1331,6 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
 #define OV5640_SYSDIV_MIN      1
 #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) {
index 117ff54..82a9b2d 100644 (file)
 #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,
index 0e7be15..1bd797c 100644 (file)
@@ -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;
 }
index ef976d0..16cc547 100644 (file)
@@ -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;
 }
index 8fafce2..0de7acd 100644 (file)
@@ -2798,6 +2798,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);
index 6547243..93a980c 100644 (file)
@@ -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;
 
index 11f5207..afd1bd7 100644 (file)
@@ -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);
index 76e5a50..d335864 100644 (file)
@@ -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 */
index 89d4d5a..52be42f 100644 (file)
@@ -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) {
index 3779910..ee20813 100644 (file)
@@ -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"
index cc98656..41cd97e 100644 (file)
@@ -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__
index 92fe051..fe833f3 100644 (file)
@@ -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>
index f9c91bd..d7d9cd0 100644 (file)
@@ -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"
index e34bd94..934f296 100644 (file)
@@ -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_ */
index aafa603..c894be1 100644 (file)
@@ -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>
index 90830f7..48555d4 100644 (file)
@@ -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__
index 1a5b31b..991246c 100644 (file)
@@ -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__
index 25d0d67..91733ab 100644 (file)
@@ -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
index 576dd23..0582b86 100644 (file)
@@ -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>
index 6543dfc..da1553f 100644 (file)
@@ -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_ */
index 97384ae..a006cb0 100644 (file)
@@ -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"
index 2424111..d9799fb 100644 (file)
@@ -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_
index 2942a7f..42256fc 100644 (file)
@@ -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__
index 374fcee..c8de8d2 100644 (file)
@@ -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"
index b834449..f3699db 100644 (file)
@@ -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_ */
index dbdbdb6..a3fe547 100644 (file)
@@ -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;
        }
index 5526bcc..965d285 100644 (file)
@@ -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);
index a96e170..118b922 100644 (file)
@@ -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
index 5cae73e..560ff1d 100644 (file)
@@ -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);
 }
 
index 6676e06..c53099c 100644 (file)
@@ -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:
index 6344a47..3ebf7a2 100644 (file)
@@ -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;
        }
 
index 3c02aa2..9e64041 100644 (file)
@@ -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);
        }
 
index 43d61d8..461524d 100644 (file)
@@ -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);
 }
index e56b96a..f914de6 100644 (file)
@@ -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;
index 9b39d77..f4d7ca7 100644 (file)
@@ -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);
 }
 
index 68ad183..73faa50 100644 (file)
@@ -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;
                }
index da62bd7..f72c8a5 100644 (file)
@@ -27,7 +27,7 @@ struct print_buf_desc {
        u32 bytes;
        u32 read;
        u32 write;
-       char buffer[0];
+       char buffer[];
 };
 
 static char *vb2_stat_name[] = {
index f29c223..f4a488b 100644 (file)
@@ -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));
index e5a5cbe..02a9d95 100644 (file)
@@ -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
index d5850df..d8247f3 100644 (file)
@@ -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);
 }
index 18a1647..676f7da 100644 (file)
@@ -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,
index 25119e5..7eb6f01 100644 (file)
@@ -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,
index 446f07d..8a3eed9 100644 (file)
@@ -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)
index 83aebee..f399dba 100644 (file)
@@ -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.
index 2f07a50..9e5317a 100644 (file)
@@ -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;
index 83b1750..8b11aa8 100644 (file)
@@ -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,
index bc5b0a0..87685a6 100644 (file)
@@ -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");
index 2cb8cec..b810c96 100644 (file)
@@ -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;
 };
 
 /**
index 52e5d36..7d194a4 100644 (file)
@@ -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)
index 995e6e2..e0b6ae9 100644 (file)
@@ -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,
+       },
        {},
 };
 
index 14bed2b..376db0e 100644 (file)
@@ -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);
index a63e4b1..36faa8d 100644 (file)
@@ -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
index 0fb7e5b..4305e4e 100644 (file)
@@ -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);
index 9c7e614..035c86e 100644 (file)
@@ -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,
index 16d5578..c45bd25 100644 (file)
@@ -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,
index a29041a..ef4584a 100644 (file)
 #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)
index c213670..25e8168 100644 (file)
@@ -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) {
index ca62832..580ce97 100644 (file)
@@ -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;
 
index 784d01f..4cc9270 100644 (file)
@@ -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);
index eef102f..e1fe260 100644 (file)
@@ -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)
index 023aba4..fb1c36a 100644 (file)
@@ -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,
 };
index 27b4b35..f3807f0 100644 (file)
@@ -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;
index 35f4d55..df309e8 100644 (file)
@@ -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;
index 88f81a1..204e474 100644 (file)
@@ -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,
index 29c604b..9418fcf 100644 (file)
@@ -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");
index d838e87..ecf3b65 100644 (file)
 #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);
index f36b512..32fd04a 100644 (file)
@@ -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;
        }
 
index 760eaf5..c508d41 100644 (file)
@@ -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 {
index 80b1c02..9050728 100644 (file)
 
 /* 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);
 
index f993f34..88f188e 100644 (file)
@@ -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) &&
index 75fcfc6..3f726a7 100644 (file)
@@ -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);
index 4ee11bb..b713f5b 100644 (file)
@@ -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 */
@@ -1252,6 +1252,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
@@ -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);
                }
        }
index 5b148e9..a26e4a5 100644 (file)
@@ -1422,40 +1422,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
        return 0;
 }
 
-/*
- * 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
@@ -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;
index 0eba04e..cbc314c 100644 (file)
@@ -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
index 307bb1d..290df04 100644 (file)
@@ -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;
 
index 79ad82e..1118c40 100644 (file)
@@ -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);
 }
 
 /*
index c9b3e0d..0db80ca 100644 (file)
@@ -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];
 };
index 877eca1..990a151 100644 (file)
@@ -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"},
index d338255..32551c2 100644 (file)
@@ -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];
index 52de47f..726f4b7 100644 (file)
@@ -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)
index b7b621a..c87c135 100644 (file)
@@ -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);
 
index 5c11043..60de420 100644 (file)
@@ -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;
        }
index 4ecd444..930b743 100644 (file)
@@ -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)
 {
index 327ed90..99bc0b6 100644 (file)
@@ -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,
index 2daa88e..d2d6719 100644 (file)
 #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;
 };
index 5b8389b..6cf74b2 100644 (file)
@@ -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);
index f16f896..f07f554 100644 (file)
@@ -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;
+}
+
index 1dcf408..ec89a90 100644 (file)
@@ -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
index 9a34662..2ad40b3 100644 (file)
@@ -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;
 }
 
index 49bdcfb..968a742 100644 (file)
@@ -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 */ }
 };
 
index fea8f00..174aa61 100644 (file)
@@ -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;
index 6644b49..8d37fbd 100644 (file)
@@ -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;
 
index 2e2aa9d..576059f 100644 (file)
@@ -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;
 
index 9a0982f..3fec41f 100644 (file)
@@ -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,
index a116a33..4c3bd2b 100644 (file)
@@ -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.
index 51219b1..e8e0ee5 100644 (file)
@@ -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;
 
index dabd7e4..731c9ac 100644 (file)
@@ -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
index ab32a77..b3844c4 100644 (file)
@@ -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
index fee2aaa..d5904c9 100644 (file)
@@ -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;
 }
index cf88966..f956b90 100644 (file)
  * 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,
index d8fa3f1..8056997 100644 (file)
 
 #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
 #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,
@@ -89,26 +98,90 @@ enum rkisp1_isp_pad {
        RKISP1_ISP_PAD_MAX
 };
 
+/*
+ * 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);
 }
@@ -446,6 +524,13 @@ static inline u32 rkisp1_read(struct rkisp1_device *rkisp1, unsigned int addr)
 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.
  *
@@ -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 (file)
index 0000000..d7acc94
--- /dev/null
@@ -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 (file)
index 0000000..1f5f2af
--- /dev/null
@@ -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 (file)
index 0000000..71df3dc
--- /dev/null
@@ -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);
+}
index 3f5cfa7..f2475c6 100644 (file)
@@ -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
  *
  * 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;
 }
 
index 4415c72..383a3ec 100644 (file)
@@ -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"
  * +---------------------------------------------------------+
  */
 
-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++;
index 8f62f09..9da7dc1 100644 (file)
@@ -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);
 }
index 82f8d33..dd3e6c3 100644 (file)
@@ -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)
 #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)
 #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)
 
 /* 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)
 #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)
 #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)
 #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)
 /* 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)
 
 /* 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)
 
 /* 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)
 #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)
 #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 */
 /*                            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
 #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)
index 2070f4b..f4caa8f 100644 (file)
@@ -59,30 +59,6 @@ struct rkisp1_rsz_config {
        const int min_rsz_width;
        const int min_rsz_height;
        /* 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;
@@ -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)
index be5777c..2795eef 100644 (file)
@@ -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);
index e3559b0..b147c64 100644 (file)
@@ -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];
index e894e85..1ea5fa1 100644 (file)
@@ -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
index 26ee238..e413335 100644 (file)
@@ -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;
 
index 7ff4024..03638c8 100644 (file)
@@ -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;
                        }
index da36b48..9dcbb98 100644 (file)
@@ -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,
index 83688a7..8f12240 100644 (file)
@@ -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;
 
index 1a396b7..41b0a4a 100644 (file)
@@ -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;
 
index 544b54e..52b43ea 100644 (file)
@@ -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;
                }
index 27a2149..6a0d35f 100644 (file)
@@ -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)
index 140854a..c2d8f1e 100644 (file)
@@ -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;
 
index 4562871..5581404 100644 (file)
@@ -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 */
index 72a901e..1878498 100644 (file)
@@ -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;
index 7bb1384..cefe6b7 100644 (file)
@@ -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;
 }
index 420ad4d..03eaee6 100644 (file)
@@ -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;
 }
index 09a743c..2ca95ab 100644 (file)
@@ -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,25 +1581,31 @@ 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,
@@ -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,
        },
 };
 
index 46b7b9b..2dd1508 100644 (file)
@@ -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"
index fc537c9..9aa01cb 100644 (file)
@@ -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/
index 682c265..1d46e11 100644 (file)
@@ -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 (file)
index 0000000..eb98246
--- /dev/null
@@ -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 (file)
index 0000000..14e4e03
--- /dev/null
@@ -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 (file)
index 0000000..a4e3f9a
--- /dev/null
@@ -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 (file)
index 0000000..24b15e3
--- /dev/null
@@ -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 (file)
index 0000000..d9c92cf
--- /dev/null
@@ -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 (file)
index 0000000..789d58e
--- /dev/null
@@ -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 (file)
index 0000000..1427d15
--- /dev/null
@@ -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 (file)
index 0000000..24bbcc8
--- /dev/null
@@ -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 (file)
index 0000000..9ab7090
--- /dev/null
@@ -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 (file)
index 0000000..d052ee7
--- /dev/null
@@ -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 (file)
index 0000000..f1e64c5
--- /dev/null
@@ -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 (file)
index 0000000..2cfc9eb
--- /dev/null
@@ -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
index e69fed1..e136d70 100644 (file)
@@ -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 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;
 
index 07ae1a3..776da0c 100644 (file)
@@ -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;
 
index 97ef770..da27da4 100644 (file)
@@ -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
index 480a7e9..fdea230 100644 (file)
@@ -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;
        }
index 4c937f3..d251736 100644 (file)
@@ -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;
 }
 
index 108b5e9..11afb8a 100644 (file)
@@ -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 =
index acb58b6..fc90ff8 100644 (file)
@@ -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);
 
index 6302e0c..6870980 100644 (file)
@@ -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);
 
index 8811d6d..d705918 100644 (file)
@@ -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;
 
index b31e591..71d9704 100644 (file)
@@ -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;
index 051c60c..cf8e892 100644 (file)
@@ -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;
 
index 338c366..2d1ef7a 100644 (file)
@@ -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;
 
index d0b0e06..48fe229 100644 (file)
@@ -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
index 3155e87..fff4dd4 100644 (file)
@@ -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;
        }
 
index b40dbf5..1464ef9 100644 (file)
@@ -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[] = {
index c9cb827..276bf3c 100644 (file)
@@ -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:
index d41580f..b02ded5 100644 (file)
@@ -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[] = {
index 765375b..25ab61d 100644 (file)
@@ -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)
index b90438a..eba0cd3 100644 (file)
@@ -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);
index cb22316..9f2947a 100644 (file)
@@ -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;
index deb8533..9b209e6 100644 (file)
@@ -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;
        }
index 629787d..560a26f 100644 (file)
@@ -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;
index 7424b20..a157238 100644 (file)
@@ -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);
index be43f7d..1d1bee1 100644 (file)
@@ -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 =
index a53b2b5..9b96315 100644 (file)
@@ -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
 
index d1e2d07..6c43780 100644 (file)
@@ -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
 };
index ba19307..7641a10 100644 (file)
@@ -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
index 06edf9d..2ae7a0f 100644 (file)
@@ -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:
index 2d06cdb..f671251 100644 (file)
 
 #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 (file)
index 0000000..3ce7f4b
--- /dev/null
@@ -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
+};
index 820b8f5..b671774 100644 (file)
 
 /* 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
 };
index 74ab79c..41a3dce 100644 (file)
 
 #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
 };
index 65feb3c..807551a 100644 (file)
@@ -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;
index e7516dc..a78d676 100644 (file)
@@ -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,
index 19701fe..38d788b 100644 (file)
@@ -198,6 +198,21 @@ struct vivid_fmt vivid_formats[] = {
                .planes   = 1,
                .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 },
index 8de0870..af88e07 100644 (file)
@@ -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"
index 044bd46..25fa201 100644 (file)
@@ -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/
index d568452..240a7cc 100644 (file)
@@ -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;
 }
index 4d5ab14..ce1b0d9 100644 (file)
 //
 // 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"
 
index d1e66b5..b5f58dc 100644 (file)
@@ -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"
 
index ae25d2c..4d037c9 100644 (file)
@@ -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"
 
index c837cc5..61d7bf7 100644 (file)
@@ -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"
 
index 471bd74..185e89c 100644 (file)
 // 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"
 
index b9a8d3f..a7eb11f 100644 (file)
@@ -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"
 
index 0b6d77c..5f3b008 100644 (file)
@@ -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"
 
index 6216cdd..8455dcf 100644 (file)
@@ -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);
index 63c4836..b253c44 100644 (file)
@@ -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"
 
index 6b84c34..8181c0e 100644 (file)
 //
 //     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"
 
index 7fc0b68..db18dd8 100644 (file)
@@ -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
index ecc97f8..f7c75d7 100644 (file)
@@ -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 */
index cc87c24..acfb9a1 100644 (file)
@@ -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);
index 60e57e0..fd7d2a9 100644 (file)
@@ -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)
index a966637..62ff1fa 100644 (file)
@@ -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 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 (file)
index d94d023..0000000
+++ /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 (file)
index daa9ae6..0000000
+++ /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 (file)
index 94aa6a2..0000000
+++ /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 (file)
index 787edb3..0000000
+++ /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 (file)
index 136decf..0000000
+++ /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
index a714ad7..1e30e05 100644 (file)
@@ -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));
index 77a368e..b9fa7c0 100644 (file)
@@ -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 {
index 0e78233..8c208db 100644 (file)
@@ -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[] = {
@@ -504,17 +505,6 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
                .v4l2_type      = V4L2_CTRL_TYPE_INTEGER,
                .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,
@@ -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)
index 6c86fae..9c05776 100644 (file)
@@ -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,
index 2578d6e..43cda5e 100644 (file)
@@ -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
index 21a907d..16fa17b 100644 (file)
@@ -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
index 753c822..7518ffc 100644 (file)
@@ -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;
index 648dcd5..4cc3fa6 100644 (file)
@@ -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;
 }
 
index 6d3dfa4..170a008 100644 (file)
@@ -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.
index c5b4feb..24c911a 100644 (file)
@@ -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 {
index 1be9a2c..348559b 100644 (file)
@@ -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.
index c699571..2f1b718 100644 (file)
@@ -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);
        }
 }
index df34b2a..e0fbe6b 100644 (file)
@@ -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 },
index db9baa0..50d012b 100644 (file)
@@ -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);
 }
index 949c188..1f85828 100644 (file)
@@ -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);
index 16f42d2..e22921e 100644 (file)
@@ -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;
index d4bf2c7..aba6176 100644 (file)
@@ -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,
index 7d098f2..c637049 100644 (file)
@@ -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;
 }
index 21470de..c314025 100644 (file)
@@ -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;
index 6469f9a..837e185 100644 (file)
@@ -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);
index 1fd6a0c..421ce9d 100644 (file)
@@ -22,10 +22,14 @@ if STAGING_MEDIA && MEDIA_SUPPORT
 # Please keep them in alphabetic order
 source "drivers/staging/media/atomisp/Kconfig"
 
+source "drivers/staging/media/av7110/Kconfig"
+
 source "drivers/staging/media/hantro/Kconfig"
 
 source "drivers/staging/media/imx/Kconfig"
 
+source "drivers/staging/media/ipu3/Kconfig"
+
 source "drivers/staging/media/max96712/Kconfig"
 
 source "drivers/staging/media/meson/vdec/Kconfig"
@@ -34,14 +38,12 @@ source "drivers/staging/media/omap4iss/Kconfig"
 
 source "drivers/staging/media/rkvdec/Kconfig"
 
-source "drivers/staging/media/sunxi/Kconfig"
+source "drivers/staging/media/stkwebcam/Kconfig"
 
-source "drivers/staging/media/zoran/Kconfig"
+source "drivers/staging/media/sunxi/Kconfig"
 
 source "drivers/staging/media/tegra-video/Kconfig"
 
-source "drivers/staging/media/ipu3/Kconfig"
-
-source "drivers/staging/media/av7110/Kconfig"
+source "drivers/staging/media/zoran/Kconfig"
 
 endif
index 66d6f6d..950e96f 100644 (file)
@@ -5,6 +5,7 @@ obj-$(CONFIG_VIDEO_MAX96712)    += max96712/
 obj-$(CONFIG_VIDEO_MESON_VDEC) += meson/vdec/
 obj-$(CONFIG_VIDEO_OMAP4)      += omap4iss/
 obj-$(CONFIG_VIDEO_ROCKCHIP_VDEC)      += rkvdec/
+obj-$(CONFIG_VIDEO_STKWEBCAM)  += stkwebcam/
 obj-$(CONFIG_VIDEO_SUNXI)      += sunxi/
 obj-$(CONFIG_VIDEO_TEGRA)      += tegra-video/
 obj-$(CONFIG_VIDEO_HANTRO)     += hantro/
index 2485d7b..fb7b406 100644 (file)
@@ -13,7 +13,6 @@ atomisp = $(srctree)/drivers/staging/media/atomisp/
 
 # SPDX-License-Identifier: GPL-2.0
 atomisp-objs += \
-       pci/atomisp_acc.o \
        pci/atomisp_cmd.o \
        pci/atomisp_compat_css20.o \
        pci/atomisp_csi2.o \
@@ -45,9 +44,7 @@ atomisp-objs += \
        pci/camera/pipe/src/pipe_util.o \
        pci/camera/util/src/util.o \
        pci/hmm/hmm_bo.o \
-       pci/hmm/hmm_dynamic_pool.o \
        pci/hmm/hmm.o \
-       pci/hmm/hmm_reserved_pool.o \
        pci/ia_css_device_access.o \
        pci/ia_css_isp_configs.o \
        pci/ia_css_isp_states.o \
index 00d6842..3c81ab7 100644 (file)
@@ -616,13 +616,15 @@ static int mt9m114_get_intg_factor(struct i2c_client *client,
                                   struct camera_mipi_info *info,
                                   const struct mt9m114_res_struct *res)
 {
-       struct atomisp_sensor_mode_data *buf = &info->data;
+       struct atomisp_sensor_mode_data *buf;
        u32 reg_val;
        int ret;
 
        if (!info)
                return -EINVAL;
 
+       buf = &info->data;
+
        ret =  mt9m114_read_reg(client, MISENSOR_32BIT,
                                REG_PIXEL_CLK, &reg_val);
        if (ret)
index da98094..d5d099a 100644 (file)
@@ -906,22 +906,17 @@ static int ov2722_get_fmt(struct v4l2_subdev *sd,
 static int ov2722_detect(struct i2c_client *client)
 {
        struct i2c_adapter *adapter = client->adapter;
-       u16 high, low;
-       int ret;
+       u16 high = 0, low = 0;
        u16 id;
        u8 revision;
 
        if (!i2c_check_functionality(adapter, I2C_FUNC_I2C))
                return -ENODEV;
 
-       ret = ov2722_read_reg(client, OV2722_8BIT,
-                             OV2722_SC_CMMN_CHIP_ID_H, &high);
-       if (ret) {
-               dev_err(&client->dev, "sensor_id_high = 0x%x\n", high);
-               return -ENODEV;
-       }
-       ret = ov2722_read_reg(client, OV2722_8BIT,
-                             OV2722_SC_CMMN_CHIP_ID_L, &low);
+       ov2722_read_reg(client, OV2722_8BIT,
+                       OV2722_SC_CMMN_CHIP_ID_H, &high);
+       ov2722_read_reg(client, OV2722_8BIT,
+                       OV2722_SC_CMMN_CHIP_ID_L, &low);
        id = (high << 8) | low;
 
        if ((id != OV2722_ID) && (id != OV2720_ID)) {
@@ -929,8 +924,9 @@ static int ov2722_detect(struct i2c_client *client)
                return -ENODEV;
        }
 
-       ret = ov2722_read_reg(client, OV2722_8BIT,
-                             OV2722_SC_CMMN_SUB_ID, &high);
+       high = 0;
+       ov2722_read_reg(client, OV2722_8BIT,
+                       OV2722_SC_CMMN_SUB_ID, &high);
        revision = (u8)high & 0x0f;
 
        dev_dbg(&client->dev, "sensor_revision = 0x%x\n", revision);
index 79df07b..a136666 100644 (file)
@@ -855,7 +855,7 @@ static struct ov5693_reg const ov5693_1616x1216_30fps[] = {
        {OV5693_8BIT, 0x3813, 0x06},    /*{3812,3813} windowing Y offset*/
        {OV5693_8BIT, 0x3814, 0x11},    /*X subsample control*/
        {OV5693_8BIT, 0x3815, 0x11},    /*Y subsample control*/
-       {OV5693_8BIT, 0x3820, 0x00},    /*FLIP/Binnning control*/
+       {OV5693_8BIT, 0x3820, 0x00},    /*FLIP/Binning control*/
        {OV5693_8BIT, 0x3821, 0x1e},    /*MIRROR control*/
        {OV5693_8BIT, 0x5002, 0x00},
        {OV5693_8BIT, 0x5041, 0x84},
index b48bdf5..c0384bb 100644 (file)
 #include <linux/slab.h>
 #include <linux/mm.h>
 
-#include "hmm/hmm_pool.h"
+#include "hmm_common.h"
+#include "hmm/hmm_bo.h"
 #include "ia_css_types.h"
 
 #define mmgr_NULL              ((ia_css_ptr)0)
 #define mmgr_EXCEPTION         ((ia_css_ptr) - 1)
 
-int hmm_pool_register(unsigned int pool_size, enum hmm_pool_type pool_type);
-void hmm_pool_unregister(enum hmm_pool_type pool_type);
-
 int hmm_init(void);
 void hmm_cleanup(void);
 
-ia_css_ptr hmm_alloc(size_t bytes, enum hmm_bo_type type,
-                    int from_highmem, const void __user *userptr,
-                    const uint16_t attrs);
+ia_css_ptr hmm_alloc(size_t bytes);
+ia_css_ptr hmm_create_from_userdata(size_t bytes, const void __user *userptr);
 void hmm_free(ia_css_ptr ptr);
 int hmm_load(ia_css_ptr virt, void *data, unsigned int bytes);
 int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes);
@@ -68,17 +65,6 @@ void hmm_vunmap(ia_css_ptr virt);
  */
 void hmm_flush_vmap(ia_css_ptr virt);
 
-/*
- * Address translation from ISP shared memory address to kernel virtual address
- * if the memory is not vmmaped,  then do it.
- */
-void *hmm_isp_vaddr_to_host_vaddr(ia_css_ptr ptr, bool cached);
-
-/*
- * Address translation from kernel virtual address to ISP shared memory address
- */
-ia_css_ptr hmm_host_vaddr_to_hrt_vaddr(const void *ptr);
-
 /*
  * map ISP memory starts with virt to specific vma.
  *
@@ -89,16 +75,6 @@ ia_css_ptr hmm_host_vaddr_to_hrt_vaddr(const void *ptr);
  */
 int hmm_mmap(struct vm_area_struct *vma, ia_css_ptr virt);
 
-/* show memory statistic
- */
-void hmm_show_mem_stat(const char *func, const int line);
-
-/* init memory statistic
- */
-void hmm_init_mem_stat(int res_pgnr, int dyc_en, int dyc_pgnr);
-
-extern bool dypool_enable;
-extern unsigned int dypool_pgnr;
 extern struct hmm_bo_device bo_device;
 
 #endif
index 8c78a5d..385e22f 100644 (file)
 
 enum hmm_bo_type {
        HMM_BO_PRIVATE,
-       HMM_BO_SHARE,
        HMM_BO_USER,
        HMM_BO_LAST,
 };
 
-enum hmm_page_type {
-       HMM_PAGE_TYPE_RESERVED,
-       HMM_PAGE_TYPE_DYNAMIC,
-       HMM_PAGE_TYPE_GENERAL,
-};
-
 #define        HMM_BO_MASK             0x1
 #define        HMM_BO_FREE             0x0
 #define        HMM_BO_ALLOCED  0x1
@@ -121,11 +114,6 @@ struct hmm_bo_device {
        struct kmem_cache *bo_cache;
 };
 
-struct hmm_page_object {
-       struct page             *page;
-       enum hmm_page_type      type;
-};
-
 struct hmm_buffer_object {
        struct hmm_bo_device    *bdev;
        struct list_head        list;
@@ -136,8 +124,6 @@ struct hmm_buffer_object {
        /* mutex protecting this BO */
        struct mutex            mutex;
        enum hmm_bo_type        type;
-       struct hmm_page_object  *page_obj;      /* physical pages */
-       int             from_highmem;
        int             mmap_count;
        int             status;
        int             mem_type;
@@ -218,33 +204,19 @@ void hmm_bo_ref(struct hmm_buffer_object *bo);
  */
 void hmm_bo_unref(struct hmm_buffer_object *bo);
 
-/*
- * allocate/free physical pages for the bo. will try to alloc mem
- * from highmem if from_highmem is set, and type indicate that the
- * pages will be allocated by using video driver (for share buffer)
- * or by ISP driver itself.
- */
-
 int hmm_bo_allocated(struct hmm_buffer_object *bo);
 
 /*
- * allocate/free physical pages for the bo. will try to alloc mem
- * from highmem if from_highmem is set, and type indicate that the
+ * Allocate/Free physical pages for the bo. Type indicates if the
  * pages will be allocated by using video driver (for share buffer)
  * or by ISP driver itself.
  */
 int hmm_bo_alloc_pages(struct hmm_buffer_object *bo,
-                      enum hmm_bo_type type, int from_highmem,
-                      const void __user *userptr, bool cached);
+                      enum hmm_bo_type type,
+                      const void __user *userptr);
 void hmm_bo_free_pages(struct hmm_buffer_object *bo);
 int hmm_bo_page_allocated(struct hmm_buffer_object *bo);
 
-/*
- * get physical page info of the bo.
- */
-int hmm_bo_get_page_info(struct hmm_buffer_object *bo,
-                        struct hmm_page_object **page_obj, int *pgnr);
-
 /*
  * bind/unbind the physical pages to a virtual address space.
  */
@@ -280,9 +252,6 @@ void hmm_bo_vunmap(struct hmm_buffer_object *bo);
 int hmm_bo_mmap(struct vm_area_struct *vma,
                struct hmm_buffer_object *bo);
 
-extern struct hmm_pool dynamic_pool;
-extern struct hmm_pool reserved_pool;
-
 /*
  * find the buffer object by its virtual address vaddr.
  * return NULL if no such buffer object found.
index 7152e9b..d8610b1 100644 (file)
 #define        check_null_return_void(ptr, fmt, arg ...)       \
                var_equal_return_void(ptr, NULL, fmt, ## arg)
 
-/* hmm_mem_stat is used to trace the hmm mem used by ISP pipe. The unit is page
- * number.
- *
- * res_size:  reserved mem pool size, being allocated from system at system boot time.
- *             res_size >= res_cnt.
- * sys_size:  system mem pool size, being allocated from system at camera running time.
- *             dyc_size:  dynamic mem pool size.
- *             dyc_thr:   dynamic mem pool high watermark.
- *             dyc_size <= dyc_thr.
- * usr_size:  user ptr mem size.
- *
- * res_cnt:   track the mem allocated from reserved pool at camera running time.
- * tol_cnt:   track the total mem used by ISP pipe at camera running time.
- */
-struct _hmm_mem_stat {
-       int res_size;
-       int sys_size;
-       int dyc_size;
-       int dyc_thr;
-       int usr_size;
-       int res_cnt;
-       int tol_cnt;
-};
-
-extern struct _hmm_mem_stat hmm_mem_stat;
-
 #endif
diff --git a/drivers/staging/media/atomisp/include/hmm/hmm_pool.h b/drivers/staging/media/atomisp/include/hmm/hmm_pool.h
deleted file mode 100644 (file)
index 3fef57d..0000000
+++ /dev/null
@@ -1,116 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Support for Medifield PNW Camera Imaging ISP subsystem.
- *
- * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
- *
- * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed 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 __HMM_POOL_H__
-#define __HMM_POOL_H__
-
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/mutex.h>
-#include <linux/kref.h>
-#include "hmm_common.h"
-#include "hmm/hmm_bo.h"
-
-#define ALLOC_PAGE_FAIL_NUM            5
-
-enum hmm_pool_type {
-       HMM_POOL_TYPE_RESERVED,
-       HMM_POOL_TYPE_DYNAMIC,
-};
-
-/**
- * struct hmm_pool_ops  -  memory pool callbacks.
- *
- * @pool_init:            initialize the memory pool.
- * @pool_exit:            uninitialize the memory pool.
- * @pool_alloc_pages:     allocate pages from memory pool.
- * @pool_free_pages:      free pages to memory pool.
- * @pool_inited:          check whether memory pool is initialized.
- */
-struct hmm_pool_ops {
-       int (*pool_init)(void **pool, unsigned int pool_size);
-       void (*pool_exit)(void **pool);
-       unsigned int (*pool_alloc_pages)(void *pool,
-                                        struct hmm_page_object *page_obj,
-                                        unsigned int size, bool cached);
-       void (*pool_free_pages)(void *pool,
-                               struct hmm_page_object *page_obj);
-       int (*pool_inited)(void *pool);
-};
-
-struct hmm_pool {
-       struct hmm_pool_ops     *pops;
-
-       void                    *pool_info;
-};
-
-/**
- * struct hmm_reserved_pool_info  - represents reserved pool private data.
- * @pages:                         a array that store physical pages.
- *                                 The array is as reserved memory pool.
- * @index:                         to indicate the first blank page number
- *                                 in reserved memory pool(pages array).
- * @pgnr:                          the valid page amount in reserved memory
- *                                 pool.
- * @list_lock:                     list lock is used to protect the operation
- *                                 to reserved memory pool.
- * @flag:                          reserved memory pool state flag.
- */
-struct hmm_reserved_pool_info {
-       struct page             **pages;
-
-       unsigned int            index;
-       unsigned int            pgnr;
-       spinlock_t              list_lock;
-       bool                    initialized;
-};
-
-/**
- * struct hmm_dynamic_pool_info  -  represents dynamic pool private data.
- * @pages_list:                            a list that store physical pages.
- *                                 The pages list is as dynamic memory pool.
- * @list_lock:                     list lock is used to protect the operation
- *                                 to dynamic memory pool.
- * @flag:                          dynamic memory pool state flag.
- * @pgptr_cache:                   struct kmem_cache, manages a cache.
- */
-struct hmm_dynamic_pool_info {
-       struct list_head        pages_list;
-
-       /* list lock is used to protect the free pages block lists */
-       spinlock_t              list_lock;
-
-       struct kmem_cache       *pgptr_cache;
-       bool                    initialized;
-
-       unsigned int            pool_size;
-       unsigned int            pgnr;
-};
-
-struct hmm_page {
-       struct page             *page;
-       struct list_head        list;
-};
-
-extern struct hmm_pool_ops     reserved_pops;
-extern struct hmm_pool_ops     dynamic_pops;
-
-#endif
index 22c4103..f96f5ad 100644 (file)
@@ -740,24 +740,6 @@ enum atomisp_frame_status {
        ATOMISP_FRAME_STATUS_FLASH_FAILED,
 };
 
-enum atomisp_acc_type {
-       ATOMISP_ACC_STANDALONE, /* Stand-alone acceleration */
-       ATOMISP_ACC_OUTPUT,     /* Accelerator stage on output frame */
-       ATOMISP_ACC_VIEWFINDER  /* Accelerator stage on viewfinder frame */
-};
-
-enum atomisp_acc_arg_type {
-       ATOMISP_ACC_ARG_SCALAR_IN,    /* Scalar input argument */
-       ATOMISP_ACC_ARG_SCALAR_OUT,   /* Scalar output argument */
-       ATOMISP_ACC_ARG_SCALAR_IO,    /* Scalar in/output argument */
-       ATOMISP_ACC_ARG_PTR_IN,      /* Pointer input argument */
-       ATOMISP_ACC_ARG_PTR_OUT,             /* Pointer output argument */
-       ATOMISP_ACC_ARG_PTR_IO,      /* Pointer in/output argument */
-       ATOMISP_ARG_PTR_NOFLUSH,  /* Pointer argument will not be flushed */
-       ATOMISP_ARG_PTR_STABLE,   /* Pointer input argument that is stable */
-       ATOMISP_ACC_ARG_FRAME        /* Frame argument */
-};
-
 /* ISP memories, isp2400 */
 enum atomisp_acc_memory {
        ATOMISP_ACC_MEMORY_PMEM0 = 0,
@@ -836,56 +818,6 @@ enum atomisp_burst_capture_options {
 #define EXT_ISP_SHOT_MODE_ANIMATED_PHOTO       10
 #define EXT_ISP_SHOT_MODE_SPORTS       11
 
-struct atomisp_sp_arg {
-       enum atomisp_acc_arg_type type; /* Type  of SP argument */
-       void                    *value; /* Value of SP argument */
-       unsigned int             size;  /* Size  of SP argument */
-};
-
-/* Acceleration API */
-
-/* For CSS 1.0 only */
-struct atomisp_acc_fw_arg {
-       unsigned int fw_handle;
-       unsigned int index;
-       void __user *value;
-       size_t size;
-};
-
-/*
- * Set arguments after first mapping with ATOMISP_IOC_ACC_S_MAPPED_ARG.
- */
-struct atomisp_acc_s_mapped_arg {
-       unsigned int fw_handle;
-       __u32 memory;                   /* one of enum atomisp_acc_memory */
-       size_t length;
-       unsigned long css_ptr;
-};
-
-struct atomisp_acc_fw_abort {
-       unsigned int fw_handle;
-       /* Timeout in us */
-       unsigned int timeout;
-};
-
-struct atomisp_acc_fw_load {
-       unsigned int size;
-       unsigned int fw_handle;
-       void __user *data;
-};
-
-/*
- * Load firmware to specified pipeline.
- */
-struct atomisp_acc_fw_load_to_pipe {
-       __u32 flags;                    /* Flags, see below for valid values */
-       unsigned int fw_handle;         /* Handle, filled by kernel. */
-       __u32 size;                     /* Firmware binary size */
-       void __user *data;              /* Pointer to firmware */
-       __u32 type;                     /* Binary type */
-       __u32 reserved[3];              /* Set to zero */
-};
-
 /*
  * Set Senor run mode
  */
@@ -893,37 +825,6 @@ struct atomisp_s_runmode {
        __u32 mode;
 };
 
-#define ATOMISP_ACC_FW_LOAD_FL_PREVIEW         BIT(0)
-#define ATOMISP_ACC_FW_LOAD_FL_COPY            BIT(1)
-#define ATOMISP_ACC_FW_LOAD_FL_VIDEO           BIT(2)
-#define ATOMISP_ACC_FW_LOAD_FL_CAPTURE         BIT(3)
-#define ATOMISP_ACC_FW_LOAD_FL_ACC             BIT(4)
-#define ATOMISP_ACC_FW_LOAD_FL_ENABLE          BIT(16)
-
-#define ATOMISP_ACC_FW_LOAD_TYPE_NONE          0 /* Normal binary: don't use */
-#define ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT                1 /* Stage on output */
-#define ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER    2 /* Stage on viewfinder */
-#define ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE    3 /* Stand-alone acceleration */
-
-struct atomisp_acc_map {
-       __u32 flags;                    /* Flags, see list below */
-       __u32 length;                   /* Length of data in bytes */
-       void __user *user_ptr;          /* Pointer into user space */
-       unsigned long css_ptr;          /* Pointer into CSS address space */
-       __u32 reserved[4];              /* Set to zero */
-};
-
-#define ATOMISP_MAP_FLAG_NOFLUSH       0x0001  /* Do not flush cache */
-#define ATOMISP_MAP_FLAG_CACHED                0x0002  /* Enable cache */
-#define ATOMISP_MAP_FLAG_CONTIGUOUS    0x0004
-#define ATOMISP_MAP_FLAG_CLEARED       0x0008
-
-struct atomisp_acc_state {
-       __u32 flags;                    /* Flags, see list below */
-#define ATOMISP_STATE_FLAG_ENABLE      ATOMISP_ACC_FW_LOAD_FL_ENABLE
-       unsigned int fw_handle;
-};
-
 struct atomisp_update_exposure {
        unsigned int gain;
        unsigned int digi_gain;
@@ -1091,29 +992,6 @@ struct atomisp_sensor_ae_bracketing_lut {
 #define ATOMISP_IOC_S_3A_CONFIG \
        _IOW('v', BASE_VIDIOC_PRIVATE + 23, struct atomisp_3a_config)
 
-/* Accelerate ioctls */
-#define ATOMISP_IOC_ACC_LOAD \
-       _IOWR('v', BASE_VIDIOC_PRIVATE + 24, struct atomisp_acc_fw_load)
-
-#define ATOMISP_IOC_ACC_UNLOAD \
-       _IOWR('v', BASE_VIDIOC_PRIVATE + 24, unsigned int)
-
-/* For CSS 1.0 only */
-#define ATOMISP_IOC_ACC_S_ARG \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 24, struct atomisp_acc_fw_arg)
-
-#define ATOMISP_IOC_ACC_START \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 24, unsigned int)
-
-#define ATOMISP_IOC_ACC_WAIT \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 25, unsigned int)
-
-#define ATOMISP_IOC_ACC_ABORT \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 25, struct atomisp_acc_fw_abort)
-
-#define ATOMISP_IOC_ACC_DESTAB \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 25, struct atomisp_acc_fw_arg)
-
 /* sensor OTP memory read */
 #define ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA \
        _IOWR('v', BASE_VIDIOC_PRIVATE + 26, struct v4l2_private_int_data)
@@ -1133,24 +1011,6 @@ struct atomisp_sensor_ae_bracketing_lut {
 #define ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA \
        _IOWR('v', BASE_VIDIOC_PRIVATE + 29, struct v4l2_private_int_data)
 
-/*
- * Ioctls to map and unmap user buffers to CSS address space for acceleration.
- * User fills fields length and user_ptr and sets other fields to zero,
- * kernel may modify the flags and sets css_ptr.
- */
-#define ATOMISP_IOC_ACC_MAP \
-       _IOWR('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_map)
-
-/* User fills fields length, user_ptr, and css_ptr and zeroes other fields. */
-#define ATOMISP_IOC_ACC_UNMAP \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_map)
-
-#define ATOMISP_IOC_ACC_S_MAPPED_ARG \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_s_mapped_arg)
-
-#define ATOMISP_IOC_ACC_LOAD_TO_PIPE \
-       _IOWR('v', BASE_VIDIOC_PRIVATE + 31, struct atomisp_acc_fw_load_to_pipe)
-
 #define ATOMISP_IOC_S_PARAMETERS \
        _IOW('v', BASE_VIDIOC_PRIVATE + 32, struct atomisp_parameters)
 
@@ -1184,12 +1044,6 @@ struct atomisp_sensor_ae_bracketing_lut {
 #define ATOMISP_IOC_S_EXPOSURE_WINDOW \
        _IOW('v', BASE_VIDIOC_PRIVATE + 40, struct atomisp_ae_window)
 
-#define ATOMISP_IOC_S_ACC_STATE \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 41, struct atomisp_acc_state)
-
-#define ATOMISP_IOC_G_ACC_STATE \
-       _IOR('v', BASE_VIDIOC_PRIVATE + 41, struct atomisp_acc_state)
-
 #define ATOMISP_IOC_INJECT_A_FAKE_EVENT \
        _IOW('v', BASE_VIDIOC_PRIVATE + 42, int)
 
diff --git a/drivers/staging/media/atomisp/notes.txt b/drivers/staging/media/atomisp/notes.txt
new file mode 100644 (file)
index 0000000..d128b79
--- /dev/null
@@ -0,0 +1,30 @@
+Some notes about the working of the atomisp drivers (learned while working
+on cleaning it up).
+
+The atomisp seems to be a generic DSP(ISP) like processor without a fixed
+pipeline. It does not have its own memory, but instead uses main memory.
+The ISP has its own address-space and main memory needs to be mapped into
+its address space through the ISP's MMU.
+
+Memory is allocated by the hmm code. hmm_alloc() returns an ISP virtual
+address. The hmm code keeps a list of all allocations and when necessary
+the hmm code finds the backing hmm-buffer-object (hmm_bo) by looking
+up the hmm_bo based on the ISP virtual address.
+
+The actual processing pipeline is made by loading one or more programs,
+called binaries. The shisp_240??0_v21.bin firmware file contains many
+different binaries. Binaries are picked by filling a ia_css_binary_descr
+struct with various input and output parameters and then calling
+ia_css_binary_find(). Some binaries support creating multiple outputs
+(preview + video frame?) at the same time.
+
+For example for the /dev/video0 preview node load_preview_binaries()
+from atomisp/pci/sh_css.c is called and then loads a preview and
+optionally a scalar binary. Note when digital zoom is disabled
+(it is enabled by default) only the preview binary is loaded.
+So in this case a single binary handles the entire pipeline.
+
+Since getting a picture requires multiple processing steps,
+this means that unlike in fixed pipelines the soft pipelines
+on the ISP can do multiple processing steps in a single pipeline
+element (in a single binary).
diff --git a/drivers/staging/media/atomisp/pci/atomisp_acc.c b/drivers/staging/media/atomisp/pci/atomisp_acc.c
deleted file mode 100644 (file)
index 28cb271..0000000
+++ /dev/null
@@ -1,625 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Support for Clovertrail PNW Camera Imaging ISP subsystem.
- *
- * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- */
-
-/*
- * This file implements loadable acceleration firmware API,
- * including ioctls to map and unmap acceleration parameters and buffers.
- */
-
-#include <linux/init.h>
-#include <media/v4l2-event.h>
-
-#include "hmm.h"
-
-#include "atomisp_acc.h"
-#include "atomisp_internal.h"
-#include "atomisp_compat.h"
-#include "atomisp_cmd.h"
-
-#include "ia_css.h"
-
-static const struct {
-       unsigned int flag;
-       enum ia_css_pipe_id pipe_id;
-} acc_flag_to_pipe[] = {
-       { ATOMISP_ACC_FW_LOAD_FL_PREVIEW, IA_CSS_PIPE_ID_PREVIEW },
-       { ATOMISP_ACC_FW_LOAD_FL_COPY, IA_CSS_PIPE_ID_COPY },
-       { ATOMISP_ACC_FW_LOAD_FL_VIDEO, IA_CSS_PIPE_ID_VIDEO },
-       { ATOMISP_ACC_FW_LOAD_FL_CAPTURE, IA_CSS_PIPE_ID_CAPTURE },
-       { ATOMISP_ACC_FW_LOAD_FL_ACC, IA_CSS_PIPE_ID_ACC }
-};
-
-/*
- * Allocate struct atomisp_acc_fw along with space for firmware.
- * The returned struct atomisp_acc_fw is cleared (firmware region is not).
- */
-static struct atomisp_acc_fw *acc_alloc_fw(unsigned int fw_size)
-{
-       struct atomisp_acc_fw *acc_fw;
-
-       acc_fw = kzalloc(sizeof(*acc_fw), GFP_KERNEL);
-       if (!acc_fw)
-               return NULL;
-
-       acc_fw->fw = vmalloc(fw_size);
-       if (!acc_fw->fw) {
-               kfree(acc_fw);
-               return NULL;
-       }
-
-       return acc_fw;
-}
-
-static void acc_free_fw(struct atomisp_acc_fw *acc_fw)
-{
-       vfree(acc_fw->fw);
-       kfree(acc_fw);
-}
-
-static struct atomisp_acc_fw *
-acc_get_fw(struct atomisp_sub_device *asd, unsigned int handle)
-{
-       struct atomisp_acc_fw *acc_fw;
-
-       list_for_each_entry(acc_fw, &asd->acc.fw, list)
-               if (acc_fw->handle == handle)
-                       return acc_fw;
-
-       return NULL;
-}
-
-static struct atomisp_map *acc_get_map(struct atomisp_sub_device *asd,
-                                      unsigned long css_ptr, size_t length)
-{
-       struct atomisp_map *atomisp_map;
-
-       list_for_each_entry(atomisp_map, &asd->acc.memory_maps, list) {
-               if (atomisp_map->ptr == css_ptr &&
-                   atomisp_map->length == length)
-                       return atomisp_map;
-       }
-       return NULL;
-}
-
-static int acc_stop_acceleration(struct atomisp_sub_device *asd)
-{
-       int ret;
-
-       ret = atomisp_css_stop_acc_pipe(asd);
-       atomisp_css_destroy_acc_pipe(asd);
-
-       return ret;
-}
-
-void atomisp_acc_cleanup(struct atomisp_device *isp)
-{
-       int i;
-
-       for (i = 0; i < isp->num_of_streams; i++)
-               ida_destroy(&isp->asd[i].acc.ida);
-}
-
-void atomisp_acc_release(struct atomisp_sub_device *asd)
-{
-       struct atomisp_acc_fw *acc_fw, *ta;
-       struct atomisp_map *atomisp_map, *tm;
-
-       /* Stop acceleration if already running */
-       if (asd->acc.pipeline)
-               acc_stop_acceleration(asd);
-
-       /* Unload all loaded acceleration binaries */
-       list_for_each_entry_safe(acc_fw, ta, &asd->acc.fw, list) {
-               list_del(&acc_fw->list);
-               ida_free(&asd->acc.ida, acc_fw->handle);
-               acc_free_fw(acc_fw);
-       }
-
-       /* Free all mapped memory blocks */
-       list_for_each_entry_safe(atomisp_map, tm, &asd->acc.memory_maps, list) {
-               list_del(&atomisp_map->list);
-               hmm_free(atomisp_map->ptr);
-               kfree(atomisp_map);
-       }
-}
-
-int atomisp_acc_load_to_pipe(struct atomisp_sub_device *asd,
-                            struct atomisp_acc_fw_load_to_pipe *user_fw)
-{
-       static const unsigned int pipeline_flags =
-           ATOMISP_ACC_FW_LOAD_FL_PREVIEW | ATOMISP_ACC_FW_LOAD_FL_COPY |
-           ATOMISP_ACC_FW_LOAD_FL_VIDEO |
-           ATOMISP_ACC_FW_LOAD_FL_CAPTURE | ATOMISP_ACC_FW_LOAD_FL_ACC;
-
-       struct atomisp_acc_fw *acc_fw;
-       int handle;
-
-       if (!user_fw->data || user_fw->size < sizeof(*acc_fw->fw))
-               return -EINVAL;
-
-       /* Binary has to be enabled at least for one pipeline */
-       if (!(user_fw->flags & pipeline_flags))
-               return -EINVAL;
-
-       /* We do not support other flags yet */
-       if (user_fw->flags & ~pipeline_flags)
-               return -EINVAL;
-
-       if (user_fw->type < ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT ||
-           user_fw->type > ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE)
-               return -EINVAL;
-
-       if (asd->acc.pipeline || asd->acc.extension_mode)
-               return -EBUSY;
-
-       acc_fw = acc_alloc_fw(user_fw->size);
-       if (!acc_fw)
-               return -ENOMEM;
-
-       if (copy_from_user(acc_fw->fw, user_fw->data, user_fw->size)) {
-               acc_free_fw(acc_fw);
-               return -EFAULT;
-       }
-
-       handle = ida_alloc(&asd->acc.ida, GFP_KERNEL);
-       if (handle < 0) {
-               acc_free_fw(acc_fw);
-               return -ENOSPC;
-       }
-
-       user_fw->fw_handle = handle;
-       acc_fw->handle = handle;
-       acc_fw->flags = user_fw->flags;
-       acc_fw->type = user_fw->type;
-       acc_fw->fw->handle = handle;
-
-       /*
-        * correct isp firmware type in order ISP firmware can be appended
-        * to correct pipe properly
-        */
-       if (acc_fw->fw->type == ia_css_isp_firmware) {
-               static const int type_to_css[] = {
-                       [ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT] =
-                       IA_CSS_ACC_OUTPUT,
-                       [ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER] =
-                       IA_CSS_ACC_VIEWFINDER,
-                       [ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE] =
-                       IA_CSS_ACC_STANDALONE,
-               };
-               acc_fw->fw->info.isp.type = type_to_css[acc_fw->type];
-       }
-
-       list_add_tail(&acc_fw->list, &asd->acc.fw);
-       return 0;
-}
-
-int atomisp_acc_load(struct atomisp_sub_device *asd,
-                    struct atomisp_acc_fw_load *user_fw)
-{
-       struct atomisp_acc_fw_load_to_pipe ltp = {0};
-       int r;
-
-       ltp.flags = ATOMISP_ACC_FW_LOAD_FL_ACC;
-       ltp.type = ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE;
-       ltp.size = user_fw->size;
-       ltp.data = user_fw->data;
-       r = atomisp_acc_load_to_pipe(asd, &ltp);
-       user_fw->fw_handle = ltp.fw_handle;
-       return r;
-}
-
-int atomisp_acc_unload(struct atomisp_sub_device *asd, unsigned int *handle)
-{
-       struct atomisp_acc_fw *acc_fw;
-
-       if (asd->acc.pipeline || asd->acc.extension_mode)
-               return -EBUSY;
-
-       acc_fw = acc_get_fw(asd, *handle);
-       if (!acc_fw)
-               return -EINVAL;
-
-       list_del(&acc_fw->list);
-       ida_free(&asd->acc.ida, acc_fw->handle);
-       acc_free_fw(acc_fw);
-
-       return 0;
-}
-
-int atomisp_acc_start(struct atomisp_sub_device *asd, unsigned int *handle)
-{
-       struct atomisp_device *isp = asd->isp;
-       struct atomisp_acc_fw *acc_fw;
-       int ret;
-       unsigned int nbin;
-
-       if (asd->acc.pipeline || asd->acc.extension_mode)
-               return -EBUSY;
-
-       /* Invalidate caches. FIXME: should flush only necessary buffers */
-       wbinvd();
-
-       ret = atomisp_css_create_acc_pipe(asd);
-       if (ret)
-               return ret;
-
-       nbin = 0;
-       list_for_each_entry(acc_fw, &asd->acc.fw, list) {
-               if (*handle != 0 && *handle != acc_fw->handle)
-                       continue;
-
-               if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_STANDALONE)
-                       continue;
-
-               /* Add the binary into the pipeline */
-               ret = atomisp_css_load_acc_binary(asd, acc_fw->fw, nbin);
-               if (ret < 0) {
-                       dev_err(isp->dev, "acc_load_binary failed\n");
-                       goto err_stage;
-               }
-
-               ret = atomisp_css_set_acc_parameters(acc_fw);
-               if (ret < 0) {
-                       dev_err(isp->dev, "acc_set_parameters failed\n");
-                       goto err_stage;
-               }
-               nbin++;
-       }
-       if (nbin < 1) {
-               /* Refuse creating pipelines with no binaries */
-               dev_err(isp->dev, "%s: no acc binary available\n", __func__);
-               ret = -EINVAL;
-               goto err_stage;
-       }
-
-       ret = atomisp_css_start_acc_pipe(asd);
-       if (ret) {
-               dev_err(isp->dev, "%s: atomisp_acc_start_acc_pipe failed\n",
-                       __func__);
-               goto err_stage;
-       }
-
-       return 0;
-
-err_stage:
-       atomisp_css_destroy_acc_pipe(asd);
-       return ret;
-}
-
-int atomisp_acc_wait(struct atomisp_sub_device *asd, unsigned int *handle)
-{
-       struct atomisp_device *isp = asd->isp;
-       int ret;
-
-       if (!asd->acc.pipeline)
-               return -ENOENT;
-
-       if (*handle && !acc_get_fw(asd, *handle))
-               return -EINVAL;
-
-       ret = atomisp_css_wait_acc_finish(asd);
-       if (acc_stop_acceleration(asd) == -EIO) {
-               atomisp_reset(isp);
-               return -EINVAL;
-       }
-
-       return ret;
-}
-
-void atomisp_acc_done(struct atomisp_sub_device *asd, unsigned int handle)
-{
-       struct v4l2_event event = { 0 };
-
-       event.type = V4L2_EVENT_ATOMISP_ACC_COMPLETE;
-       event.u.frame_sync.frame_sequence = atomic_read(&asd->sequence);
-       event.id = handle;
-
-       v4l2_event_queue(asd->subdev.devnode, &event);
-}
-
-int atomisp_acc_map(struct atomisp_sub_device *asd, struct atomisp_acc_map *map)
-{
-       struct atomisp_map *atomisp_map;
-       ia_css_ptr cssptr;
-       int pgnr;
-
-       if (map->css_ptr)
-               return -EINVAL;
-
-       if (asd->acc.pipeline)
-               return -EBUSY;
-
-       if (map->user_ptr) {
-               /* Buffer to map must be page-aligned */
-               if ((unsigned long)map->user_ptr & ~PAGE_MASK) {
-                       dev_err(asd->isp->dev,
-                               "%s: mapped buffer address %p is not page aligned\n",
-                               __func__, map->user_ptr);
-                       return -EINVAL;
-               }
-
-               pgnr = DIV_ROUND_UP(map->length, PAGE_SIZE);
-               if (pgnr < ((PAGE_ALIGN(map->length)) >> PAGE_SHIFT)) {
-                       dev_err(asd->isp->dev,
-                               "user space memory size is less than the expected size..\n");
-                       return -ENOMEM;
-               } else if (pgnr > ((PAGE_ALIGN(map->length)) >> PAGE_SHIFT)) {
-                       dev_err(asd->isp->dev,
-                               "user space memory size is large than the expected size..\n");
-                       return -ENOMEM;
-               }
-
-               cssptr = hmm_alloc(map->length, HMM_BO_USER, 0, map->user_ptr,
-                                  map->flags & ATOMISP_MAP_FLAG_CACHED);
-
-       } else {
-               /* Allocate private buffer. */
-               cssptr = hmm_alloc(map->length, HMM_BO_PRIVATE, 0, NULL,
-                                  map->flags & ATOMISP_MAP_FLAG_CACHED);
-       }
-
-       if (!cssptr)
-               return -ENOMEM;
-
-       atomisp_map = kmalloc(sizeof(*atomisp_map), GFP_KERNEL);
-       if (!atomisp_map) {
-               hmm_free(cssptr);
-               return -ENOMEM;
-       }
-       atomisp_map->ptr = cssptr;
-       atomisp_map->length = map->length;
-       list_add(&atomisp_map->list, &asd->acc.memory_maps);
-
-       dev_dbg(asd->isp->dev, "%s: userptr %p, css_address 0x%x, size %d\n",
-               __func__, map->user_ptr, cssptr, map->length);
-       map->css_ptr = cssptr;
-       return 0;
-}
-
-int atomisp_acc_unmap(struct atomisp_sub_device *asd,
-                     struct atomisp_acc_map *map)
-{
-       struct atomisp_map *atomisp_map;
-
-       if (asd->acc.pipeline)
-               return -EBUSY;
-
-       atomisp_map = acc_get_map(asd, map->css_ptr, map->length);
-       if (!atomisp_map)
-               return -EINVAL;
-
-       list_del(&atomisp_map->list);
-       hmm_free(atomisp_map->ptr);
-       kfree(atomisp_map);
-       return 0;
-}
-
-int atomisp_acc_s_mapped_arg(struct atomisp_sub_device *asd,
-                            struct atomisp_acc_s_mapped_arg *arg)
-{
-       struct atomisp_acc_fw *acc_fw;
-
-       if (arg->memory >= ATOMISP_ACC_NR_MEMORY)
-               return -EINVAL;
-
-       if (asd->acc.pipeline)
-               return -EBUSY;
-
-       acc_fw = acc_get_fw(asd, arg->fw_handle);
-       if (!acc_fw)
-               return -EINVAL;
-
-       if (arg->css_ptr != 0 || arg->length != 0) {
-               /* Unless the parameter is cleared, check that it exists */
-               if (!acc_get_map(asd, arg->css_ptr, arg->length))
-                       return -EINVAL;
-       }
-
-       acc_fw->args[arg->memory].length = arg->length;
-       acc_fw->args[arg->memory].css_ptr = arg->css_ptr;
-
-       dev_dbg(asd->isp->dev, "%s: mem %d, address %p, size %ld\n",
-               __func__, arg->memory, (void *)arg->css_ptr,
-               (unsigned long)arg->length);
-       return 0;
-}
-
-static void atomisp_acc_unload_some_extensions(struct atomisp_sub_device *asd,
-                                             int i,
-                                             struct atomisp_acc_fw *acc_fw)
-{
-       while (--i >= 0) {
-               if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
-                       atomisp_css_unload_acc_extension(asd, acc_fw->fw,
-                                                        acc_flag_to_pipe[i].pipe_id);
-               }
-       }
-}
-
-/*
- * Appends the loaded acceleration binary extensions to the
- * current ISP mode. Must be called just before sh_css_start().
- */
-int atomisp_acc_load_extensions(struct atomisp_sub_device *asd)
-{
-       struct atomisp_acc_fw *acc_fw;
-       bool ext_loaded = false;
-       bool continuous = asd->continuous_mode->val &&
-                         asd->run_mode->val == ATOMISP_RUN_MODE_PREVIEW;
-       int ret = 0, i = -1;
-       struct atomisp_device *isp = asd->isp;
-
-       if (asd->acc.pipeline || asd->acc.extension_mode)
-               return -EBUSY;
-
-       /* Invalidate caches. FIXME: should flush only necessary buffers */
-       wbinvd();
-
-       list_for_each_entry(acc_fw, &asd->acc.fw, list) {
-               if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT &&
-                   acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER)
-                       continue;
-
-               for (i = 0; i < ARRAY_SIZE(acc_flag_to_pipe); i++) {
-                       /*
-                        * QoS (ACC pipe) acceleration stages are
-                        * currently allowed only in continuous mode.
-                        * Skip them for all other modes.
-                        */
-                       if (!continuous &&
-                           acc_flag_to_pipe[i].flag ==
-                           ATOMISP_ACC_FW_LOAD_FL_ACC)
-                               continue;
-
-                       if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
-                               ret = atomisp_css_load_acc_extension(asd,
-                                                                    acc_fw->fw,
-                                                                    acc_flag_to_pipe[i].pipe_id,
-                                                                    acc_fw->type);
-                               if (ret) {
-                                       atomisp_acc_unload_some_extensions(asd, i, acc_fw);
-                                       goto error;
-                               }
-
-                               ext_loaded = true;
-                       }
-               }
-
-               ret = atomisp_css_set_acc_parameters(acc_fw);
-               if (ret < 0) {
-                       atomisp_acc_unload_some_extensions(asd, i, acc_fw);
-                       goto error;
-               }
-       }
-
-       if (!ext_loaded)
-               return ret;
-
-       ret = atomisp_css_update_stream(asd);
-       if (ret) {
-               dev_err(isp->dev, "%s: update stream failed.\n", __func__);
-               atomisp_acc_unload_extensions(asd);
-               goto error;
-       }
-
-       asd->acc.extension_mode = true;
-       return 0;
-
-error:
-       list_for_each_entry_continue_reverse(acc_fw, &asd->acc.fw, list) {
-               if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT &&
-                   acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER)
-                       continue;
-
-               for (i = ARRAY_SIZE(acc_flag_to_pipe) - 1; i >= 0; i--) {
-                       if (!continuous &&
-                           acc_flag_to_pipe[i].flag ==
-                           ATOMISP_ACC_FW_LOAD_FL_ACC)
-                               continue;
-                       if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
-                               atomisp_css_unload_acc_extension(asd,
-                                                                acc_fw->fw,
-                                                                acc_flag_to_pipe[i].pipe_id);
-                       }
-               }
-       }
-       return ret;
-}
-
-void atomisp_acc_unload_extensions(struct atomisp_sub_device *asd)
-{
-       struct atomisp_acc_fw *acc_fw;
-       int i;
-
-       if (!asd->acc.extension_mode)
-               return;
-
-       list_for_each_entry_reverse(acc_fw, &asd->acc.fw, list) {
-               if (acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_OUTPUT &&
-                   acc_fw->type != ATOMISP_ACC_FW_LOAD_TYPE_VIEWFINDER)
-                       continue;
-
-               for (i = ARRAY_SIZE(acc_flag_to_pipe) - 1; i >= 0; i--) {
-                       if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
-                               atomisp_css_unload_acc_extension(asd,
-                                                                acc_fw->fw,
-                                                                acc_flag_to_pipe[i].pipe_id);
-                       }
-               }
-       }
-
-       asd->acc.extension_mode = false;
-}
-
-int atomisp_acc_set_state(struct atomisp_sub_device *asd,
-                         struct atomisp_acc_state *arg)
-{
-       struct atomisp_acc_fw *acc_fw;
-       bool enable = (arg->flags & ATOMISP_STATE_FLAG_ENABLE) != 0;
-       struct ia_css_pipe *pipe;
-       int r;
-       int i;
-
-       if (!asd->acc.extension_mode)
-               return -EBUSY;
-
-       if (arg->flags & ~ATOMISP_STATE_FLAG_ENABLE)
-               return -EINVAL;
-
-       acc_fw = acc_get_fw(asd, arg->fw_handle);
-       if (!acc_fw)
-               return -EINVAL;
-
-       if (enable)
-               wbinvd();
-
-       for (i = 0; i < ARRAY_SIZE(acc_flag_to_pipe); i++) {
-               if (acc_fw->flags & acc_flag_to_pipe[i].flag) {
-                       pipe = asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL].
-                              pipes[acc_flag_to_pipe[i].pipe_id];
-                       r = ia_css_pipe_set_qos_ext_state(pipe, acc_fw->handle,
-                                                         enable);
-                       if (r)
-                               return -EBADRQC;
-               }
-       }
-
-       if (enable)
-               acc_fw->flags |= ATOMISP_ACC_FW_LOAD_FL_ENABLE;
-       else
-               acc_fw->flags &= ~ATOMISP_ACC_FW_LOAD_FL_ENABLE;
-
-       return 0;
-}
-
-int atomisp_acc_get_state(struct atomisp_sub_device *asd,
-                         struct atomisp_acc_state *arg)
-{
-       struct atomisp_acc_fw *acc_fw;
-
-       if (!asd->acc.extension_mode)
-               return -EBUSY;
-
-       acc_fw = acc_get_fw(asd, arg->fw_handle);
-       if (!acc_fw)
-               return -EINVAL;
-
-       arg->flags = acc_fw->flags;
-
-       return 0;
-}
diff --git a/drivers/staging/media/atomisp/pci/atomisp_acc.h b/drivers/staging/media/atomisp/pci/atomisp_acc.h
deleted file mode 100644 (file)
index 48d9423..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Support for Clovertrail PNW Camera Imaging ISP subsystem.
- *
- * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- *
- */
-
-#ifndef __ATOMISP_ACC_H__
-#define __ATOMISP_ACC_H__
-
-#include "../../include/linux/atomisp.h"
-#include "atomisp_internal.h"
-
-#include "ia_css_types.h"
-
-/*
- * Interface functions for AtomISP driver acceleration API implementation.
- */
-
-struct atomisp_sub_device;
-
-void atomisp_acc_cleanup(struct atomisp_device *isp);
-
-/*
- * Free up any allocated resources.
- * Must be called each time when the device is closed.
- * Note that there isn't corresponding open() call;
- * this function may be called sequentially multiple times.
- * Must be called to free up resources before driver is unloaded.
- */
-void atomisp_acc_release(struct atomisp_sub_device *asd);
-
-/* Load acceleration binary. DEPRECATED. */
-int atomisp_acc_load(struct atomisp_sub_device *asd,
-                    struct atomisp_acc_fw_load *fw);
-
-/* Load acceleration binary with specified properties */
-int atomisp_acc_load_to_pipe(struct atomisp_sub_device *asd,
-                            struct atomisp_acc_fw_load_to_pipe *fw);
-
-/* Unload specified acceleration binary */
-int atomisp_acc_unload(struct atomisp_sub_device *asd,
-                      unsigned int *handle);
-
-/*
- * Map a memory region into ISP memory space.
- */
-int atomisp_acc_map(struct atomisp_sub_device *asd,
-                   struct atomisp_acc_map *map);
-
-/*
- * Unmap a mapped memory region.
- */
-int atomisp_acc_unmap(struct atomisp_sub_device *asd,
-                     struct atomisp_acc_map *map);
-
-/*
- * Set acceleration binary argument to a previously mapped memory region.
- */
-int atomisp_acc_s_mapped_arg(struct atomisp_sub_device *asd,
-                            struct atomisp_acc_s_mapped_arg *arg);
-
-/*
- * Start acceleration.
- * Return immediately, acceleration is left running in background.
- * Specify either acceleration binary or pipeline which to start.
- */
-int atomisp_acc_start(struct atomisp_sub_device *asd,
-                     unsigned int *handle);
-
-/*
- * Wait until acceleration finishes.
- * This MUST be called after each acceleration has been started.
- * Specify either acceleration binary or pipeline handle.
- */
-int atomisp_acc_wait(struct atomisp_sub_device *asd,
-                    unsigned int *handle);
-
-/*
- * Used by ISR to notify ACC stage finished.
- * This is internally used and does not export as IOCTL.
- */
-void atomisp_acc_done(struct atomisp_sub_device *asd, unsigned int handle);
-
-/*
- * Appends the loaded acceleration binary extensions to the
- * current ISP mode. Must be called just before atomisp_css_start().
- */
-int atomisp_acc_load_extensions(struct atomisp_sub_device *asd);
-
-/*
- * Must be called after streaming is stopped:
- * unloads any loaded acceleration extensions.
- */
-void atomisp_acc_unload_extensions(struct atomisp_sub_device *asd);
-
-/*
- * Set acceleration firmware flags.
- */
-int atomisp_acc_set_state(struct atomisp_sub_device *asd,
-                         struct atomisp_acc_state *arg);
-
-/*
- * Get acceleration firmware flags.
- */
-int atomisp_acc_get_state(struct atomisp_sub_device *asd,
-                         struct atomisp_acc_state *arg);
-
-#endif /* __ATOMISP_ACC_H__ */
index 97d5a52..c932f34 100644 (file)
@@ -42,7 +42,6 @@
 #include "atomisp_ioctl.h"
 #include "atomisp-regs.h"
 #include "atomisp_tables.h"
-#include "atomisp_acc.h"
 #include "atomisp_compat.h"
 #include "atomisp_subdev.h"
 #include "atomisp_dfs_tables.h"
@@ -539,7 +538,7 @@ irqreturn_t atomisp_isr(int irq, void *dev)
 
        clear_irq_reg(isp);
 
-       if (!atomisp_streaming_count(isp) && !atomisp_is_acc_enabled(isp))
+       if (!atomisp_streaming_count(isp))
                goto out_nowake;
 
        for (i = 0; i < isp->num_of_streams; i++) {
@@ -901,9 +900,9 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
        int err;
        unsigned long irqflags;
        struct ia_css_frame *frame = NULL;
-       struct atomisp_s3a_buf *s3a_buf = NULL, *_s3a_buf_tmp;
-       struct atomisp_dis_buf *dis_buf = NULL, *_dis_buf_tmp;
-       struct atomisp_metadata_buf *md_buf = NULL, *_md_buf_tmp;
+       struct atomisp_s3a_buf *s3a_buf = NULL, *_s3a_buf_tmp, *s3a_iter;
+       struct atomisp_dis_buf *dis_buf = NULL, *_dis_buf_tmp, *dis_iter;
+       struct atomisp_metadata_buf *md_buf = NULL, *_md_buf_tmp, *md_iter;
        enum atomisp_metadata_type md_type;
        struct atomisp_device *isp = asd->isp;
        struct v4l2_control ctrl;
@@ -942,60 +941,75 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
 
        switch (buf_type) {
        case IA_CSS_BUFFER_TYPE_3A_STATISTICS:
-               list_for_each_entry_safe(s3a_buf, _s3a_buf_tmp,
+               list_for_each_entry_safe(s3a_iter, _s3a_buf_tmp,
                                         &asd->s3a_stats_in_css, list) {
-                       if (s3a_buf->s3a_data ==
+                       if (s3a_iter->s3a_data ==
                            buffer.css_buffer.data.stats_3a) {
-                               list_del_init(&s3a_buf->list);
-                               list_add_tail(&s3a_buf->list,
+                               list_del_init(&s3a_iter->list);
+                               list_add_tail(&s3a_iter->list,
                                              &asd->s3a_stats_ready);
+                               s3a_buf = s3a_iter;
                                break;
                        }
                }
 
                asd->s3a_bufs_in_css[css_pipe_id]--;
                atomisp_3a_stats_ready_event(asd, buffer.css_buffer.exp_id);
-               dev_dbg(isp->dev, "%s: s3a stat with exp_id %d is ready\n",
-                       __func__, s3a_buf->s3a_data->exp_id);
+               if (s3a_buf)
+                       dev_dbg(isp->dev, "%s: s3a stat with exp_id %d is ready\n",
+                               __func__, s3a_buf->s3a_data->exp_id);
+               else
+                       dev_dbg(isp->dev, "%s: s3a stat is ready with no exp_id found\n",
+                               __func__);
                break;
        case IA_CSS_BUFFER_TYPE_METADATA:
                if (error)
                        break;
 
                md_type = atomisp_get_metadata_type(asd, css_pipe_id);
-               list_for_each_entry_safe(md_buf, _md_buf_tmp,
+               list_for_each_entry_safe(md_iter, _md_buf_tmp,
                                         &asd->metadata_in_css[md_type], list) {
-                       if (md_buf->metadata ==
+                       if (md_iter->metadata ==
                            buffer.css_buffer.data.metadata) {
-                               list_del_init(&md_buf->list);
-                               list_add_tail(&md_buf->list,
+                               list_del_init(&md_iter->list);
+                               list_add_tail(&md_iter->list,
                                              &asd->metadata_ready[md_type]);
+                               md_buf = md_iter;
                                break;
                        }
                }
                asd->metadata_bufs_in_css[stream_id][css_pipe_id]--;
                atomisp_metadata_ready_event(asd, md_type);
-               dev_dbg(isp->dev, "%s: metadata with exp_id %d is ready\n",
-                       __func__, md_buf->metadata->exp_id);
+               if (md_buf)
+                       dev_dbg(isp->dev, "%s: metadata with exp_id %d is ready\n",
+                               __func__, md_buf->metadata->exp_id);
+               else
+                       dev_dbg(isp->dev, "%s: metadata is ready with no exp_id found\n",
+                               __func__);
                break;
        case IA_CSS_BUFFER_TYPE_DIS_STATISTICS:
-               list_for_each_entry_safe(dis_buf, _dis_buf_tmp,
+               list_for_each_entry_safe(dis_iter, _dis_buf_tmp,
                                         &asd->dis_stats_in_css, list) {
-                       if (dis_buf->dis_data ==
+                       if (dis_iter->dis_data ==
                            buffer.css_buffer.data.stats_dvs) {
                                spin_lock_irqsave(&asd->dis_stats_lock,
                                                  irqflags);
-                               list_del_init(&dis_buf->list);
-                               list_add(&dis_buf->list, &asd->dis_stats);
+                               list_del_init(&dis_iter->list);
+                               list_add(&dis_iter->list, &asd->dis_stats);
                                asd->params.dis_proj_data_valid = true;
                                spin_unlock_irqrestore(&asd->dis_stats_lock,
                                                       irqflags);
+                               dis_buf = dis_iter;
                                break;
                        }
                }
                asd->dis_bufs_in_css--;
-               dev_dbg(isp->dev, "%s: dis stat with exp_id %d is ready\n",
-                       __func__, dis_buf->dis_data->exp_id);
+               if (dis_buf)
+                       dev_dbg(isp->dev, "%s: dis stat with exp_id %d is ready\n",
+                               __func__, dis_buf->dis_data->exp_id);
+               else
+                       dev_dbg(isp->dev, "%s: dis stat is ready with no exp_id found\n",
+                               __func__);
                break;
        case IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME:
        case IA_CSS_BUFFER_TYPE_SEC_VF_OUTPUT_FRAME:
@@ -1302,34 +1316,11 @@ static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout)
 
        for (i = 0; i < isp->num_of_streams; i++) {
                struct atomisp_sub_device *asd = &isp->asd[i];
-               struct ia_css_pipeline *acc_pipeline;
-               struct ia_css_pipe *acc_pipe = NULL;
 
                if (asd->streaming != ATOMISP_DEVICE_STREAMING_ENABLED &&
                    !asd->stream_prepared)
                        continue;
 
-               /*
-               * AtomISP::waitStageUpdate is blocked when WDT happens.
-               * By calling acc_done() for all loaded fw_handles,
-               * HAL will be unblocked.
-               */
-               acc_pipe = asd->stream_env[i].pipes[IA_CSS_PIPE_ID_ACC];
-               if (acc_pipe) {
-                       acc_pipeline = ia_css_pipe_get_pipeline(acc_pipe);
-                       if (acc_pipeline) {
-                               struct ia_css_pipeline_stage *stage;
-
-                               for (stage = acc_pipeline->stages; stage;
-                                    stage = stage->next) {
-                                       const struct ia_css_fw_info *fw;
-
-                                       fw = stage->firmware;
-                                       atomisp_acc_done(asd, fw->handle);
-                               }
-                       }
-               }
-
                depth_cnt++;
 
                if (asd->delayed_init == ATOMISP_DELAYED_INIT_QUEUED)
@@ -1350,8 +1341,6 @@ static void __atomisp_css_recover(struct atomisp_device *isp, bool isp_timeout)
                        dev_warn(isp->dev,
                                 "can't stop streaming on sensor!\n");
 
-               atomisp_acc_unload_extensions(asd);
-
                atomisp_clear_css_buffer_counters(asd);
 
                css_pipe_id = atomisp_get_css_pipe_id(asd);
@@ -1863,7 +1852,7 @@ irqreturn_t atomisp_isr_thread(int irq, void *isp_ptr)
 
        spin_lock_irqsave(&isp->lock, flags);
 
-       if (!atomisp_streaming_count(isp) && !atomisp_is_acc_enabled(isp)) {
+       if (!atomisp_streaming_count(isp)) {
                spin_unlock_irqrestore(&isp->lock, flags);
                return IRQ_HANDLED;
        }
@@ -1914,9 +1903,6 @@ out:
                    && isp->sw_contex.file_input)
                        v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
                                         video, s_stream, 1);
-               /* FIXME! FIX ACC implementation */
-               if (asd->acc.pipeline && css_pipe_done[asd->index])
-                       atomisp_css_acc_done(asd);
        }
        dev_dbg(isp->dev, "<%s\n", __func__);
 
@@ -6504,7 +6490,7 @@ int atomisp_set_raw_buffer_bitmap(struct atomisp_sub_device *asd, int exp_id)
                ret = atomisp_css_exp_id_unlock(asd, exp_id);
                if (ret) {
                        dev_err(asd->isp->dev,
-                               "%s exp_id is wrapping back to %d but force unlock failed,, err %d.\n",
+                               "%s exp_id is wrapping back to %d but force unlock failed, err %d.\n",
                                __func__, exp_id, ret);
                        return ret;
                }
index 64c1bf0..3393ae6 100644 (file)
@@ -240,7 +240,7 @@ int atomisp_css_input_configure_port(struct atomisp_sub_device *asd,
                                     unsigned int metadata_width,
                                     unsigned int metadata_height);
 
-void atomisp_create_pipes_stream(struct atomisp_sub_device *asd);
+int atomisp_create_pipes_stream(struct atomisp_sub_device *asd);
 void atomisp_destroy_pipes_stream_force(struct atomisp_sub_device *asd);
 
 void atomisp_css_stop(struct atomisp_sub_device *asd,
@@ -442,33 +442,6 @@ int atomisp_css_get_dis_stat(struct atomisp_sub_device *asd,
 
 int atomisp_css_update_stream(struct atomisp_sub_device *asd);
 
-int atomisp_css_create_acc_pipe(struct atomisp_sub_device *asd);
-
-int atomisp_css_start_acc_pipe(struct atomisp_sub_device *asd);
-
-int atomisp_css_stop_acc_pipe(struct atomisp_sub_device *asd);
-
-void atomisp_css_destroy_acc_pipe(struct atomisp_sub_device *asd);
-
-int atomisp_css_load_acc_extension(struct atomisp_sub_device *asd,
-                                  struct ia_css_fw_info *fw,
-                                  enum ia_css_pipe_id pipe_id,
-                                  unsigned int type);
-
-void atomisp_css_unload_acc_extension(struct atomisp_sub_device *asd,
-                                     struct ia_css_fw_info *fw,
-                                     enum ia_css_pipe_id pipe_id);
-
-int atomisp_css_wait_acc_finish(struct atomisp_sub_device *asd);
-
-void atomisp_css_acc_done(struct atomisp_sub_device *asd);
-
-int atomisp_css_load_acc_binary(struct atomisp_sub_device *asd,
-                               struct ia_css_fw_info *fw,
-                               unsigned int index);
-
-void atomisp_css_unload_acc_binary(struct atomisp_sub_device *asd);
-
 struct atomisp_acc_fw;
 int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw);
 
index 781a11c..5aa108a 100644 (file)
@@ -31,7 +31,6 @@
 #include "atomisp-regs.h"
 #include "atomisp_fops.h"
 #include "atomisp_ioctl.h"
-#include "atomisp_acc.h"
 
 #include "ia_css_debug.h"
 #include "ia_css_isp_param.h"
@@ -419,24 +418,14 @@ static void __dump_stream_config(struct atomisp_sub_device *asd,
 }
 
 static int __destroy_stream(struct atomisp_sub_device *asd,
-                           struct atomisp_stream_env *stream_env, bool force)
+                           struct atomisp_stream_env *stream_env)
 {
        struct atomisp_device *isp = asd->isp;
-       int i;
        unsigned long timeout;
 
        if (!stream_env->stream)
                return 0;
 
-       if (!force) {
-               for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++)
-                       if (stream_env->update_pipe[i])
-                               break;
-
-               if (i == IA_CSS_PIPE_ID_NUM)
-                       return 0;
-       }
-
        if (stream_env->stream_state == CSS_STREAM_STARTED
            && ia_css_stream_stop(stream_env->stream) != 0) {
                dev_err(isp->dev, "stop stream failed.\n");
@@ -470,12 +459,12 @@ static int __destroy_stream(struct atomisp_sub_device *asd,
        return 0;
 }
 
-static int __destroy_streams(struct atomisp_sub_device *asd, bool force)
+static int __destroy_streams(struct atomisp_sub_device *asd)
 {
        int ret, i;
 
        for (i = 0; i < ATOMISP_INPUT_STREAM_NUM; i++) {
-               ret = __destroy_stream(asd, &asd->stream_env[i], force);
+               ret = __destroy_stream(asd, &asd->stream_env[i]);
                if (ret)
                        return ret;
        }
@@ -530,21 +519,19 @@ static int __create_streams(struct atomisp_sub_device *asd)
        return 0;
 rollback:
        for (i--; i >= 0; i--)
-               __destroy_stream(asd, &asd->stream_env[i], true);
+               __destroy_stream(asd, &asd->stream_env[i]);
        return ret;
 }
 
 static int __destroy_stream_pipes(struct atomisp_sub_device *asd,
-                                 struct atomisp_stream_env *stream_env,
-                                 bool force)
+                                 struct atomisp_stream_env *stream_env)
 {
        struct atomisp_device *isp = asd->isp;
        int ret = 0;
        int i;
 
        for (i = 0; i < IA_CSS_PIPE_ID_NUM; i++) {
-               if (!stream_env->pipes[i] ||
-                   !(force || stream_env->update_pipe[i]))
+               if (!stream_env->pipes[i])
                        continue;
                if (ia_css_pipe_destroy(stream_env->pipes[i])
                    != 0) {
@@ -558,7 +545,7 @@ static int __destroy_stream_pipes(struct atomisp_sub_device *asd,
        return ret;
 }
 
-static int __destroy_pipes(struct atomisp_sub_device *asd, bool force)
+static int __destroy_pipes(struct atomisp_sub_device *asd)
 {
        struct atomisp_device *isp = asd->isp;
        int i;
@@ -572,7 +559,7 @@ static int __destroy_pipes(struct atomisp_sub_device *asd, bool force)
                        continue;
                }
 
-               ret = __destroy_stream_pipes(asd, &asd->stream_env[i], force);
+               ret = __destroy_stream_pipes(asd, &asd->stream_env[i]);
                if (ret)
                        return ret;
        }
@@ -582,8 +569,11 @@ static int __destroy_pipes(struct atomisp_sub_device *asd, bool force)
 
 void atomisp_destroy_pipes_stream_force(struct atomisp_sub_device *asd)
 {
-       __destroy_streams(asd, true);
-       __destroy_pipes(asd, true);
+       if (__destroy_streams(asd))
+               dev_warn(asd->isp->dev, "destroy stream failed.\n");
+
+       if (__destroy_pipes(asd))
+               dev_warn(asd->isp->dev, "destroy pipe failed.\n");
 }
 
 static void __apply_additional_pipe_config(
@@ -786,39 +776,32 @@ pipe_err:
        return -EINVAL;
 }
 
-void atomisp_create_pipes_stream(struct atomisp_sub_device *asd)
-{
-       __create_pipes(asd);
-       __create_streams(asd);
-}
-
-int atomisp_css_update_stream(struct atomisp_sub_device *asd)
+int atomisp_create_pipes_stream(struct atomisp_sub_device *asd)
 {
        int ret;
-       struct atomisp_device *isp = asd->isp;
-
-       if (__destroy_streams(asd, true))
-               dev_warn(isp->dev, "destroy stream failed.\n");
-
-       if (__destroy_pipes(asd, true))
-               dev_warn(isp->dev, "destroy pipe failed.\n");
 
        ret = __create_pipes(asd);
        if (ret) {
-               dev_err(isp->dev, "create pipe failed %d.\n", ret);
-               return -EIO;
+               dev_err(asd->isp->dev, "create pipe failed %d.\n", ret);
+               return ret;
        }
 
        ret = __create_streams(asd);
        if (ret) {
-               dev_warn(isp->dev, "create stream failed %d.\n", ret);
-               __destroy_pipes(asd, true);
-               return -EIO;
+               dev_warn(asd->isp->dev, "create stream failed %d.\n", ret);
+               __destroy_pipes(asd);
+               return ret;
        }
 
        return 0;
 }
 
+int atomisp_css_update_stream(struct atomisp_sub_device *asd)
+{
+       atomisp_destroy_pipes_stream_force(asd);
+       return atomisp_create_pipes_stream(asd);
+}
+
 int atomisp_css_init(struct atomisp_device *isp)
 {
        unsigned int mmu_base_addr;
@@ -1103,23 +1086,12 @@ int atomisp_css_start(struct atomisp_sub_device *asd,
        int ret = 0, i = 0;
 
        if (in_reset) {
-               if (__destroy_streams(asd, true))
-                       dev_warn(isp->dev, "destroy stream failed.\n");
-
-               if (__destroy_pipes(asd, true))
-                       dev_warn(isp->dev, "destroy pipe failed.\n");
+               ret = atomisp_css_update_stream(asd);
+               if (ret)
+                       return ret;
 
-               if (__create_pipes(asd)) {
-                       dev_err(isp->dev, "create pipe error.\n");
-                       return -EINVAL;
-               }
-               if (__create_streams(asd)) {
-                       dev_err(isp->dev, "create stream error.\n");
-                       ret = -EINVAL;
-                       goto stream_err;
-               }
-               /* in_reset == true, extension firmwares are reloaded after the recovery */
-               atomisp_acc_load_extensions(asd);
+               /* Invalidate caches. FIXME: should flush only necessary buffers */
+               wbinvd();
        }
 
        /*
@@ -1134,15 +1106,9 @@ int atomisp_css_start(struct atomisp_sub_device *asd,
         * recreated in the next stream on.
         */
        if (!asd->stream_prepared) {
-               if (__create_pipes(asd)) {
-                       dev_err(isp->dev, "create pipe error.\n");
-                       return -EINVAL;
-               }
-               if (__create_streams(asd)) {
-                       dev_err(isp->dev, "create stream error.\n");
-                       ret = -EINVAL;
-                       goto stream_err;
-               }
+               ret = atomisp_create_pipes_stream(asd);
+               if (ret)
+                       return ret;
        }
        /*
         * SP can only be started one time
@@ -1181,9 +1147,7 @@ int atomisp_css_start(struct atomisp_sub_device *asd,
        return 0;
 
 start_err:
-       __destroy_streams(asd, true);
-stream_err:
-       __destroy_pipes(asd, true);
+       atomisp_destroy_pipes_stream_force(asd);
 
        /* css 2.0 API limitation: ia_css_stop_sp() could be only called after
         * destroy all pipes
@@ -2088,13 +2052,8 @@ void atomisp_css_stop(struct atomisp_sub_device *asd,
        unsigned long irqflags;
        unsigned int i;
 
-       /* if is called in atomisp_reset(), force destroy stream */
-       if (__destroy_streams(asd, true))
-               dev_err(isp->dev, "destroy stream failed.\n");
-
-       /* if is called in atomisp_reset(), force destroy all pipes */
-       if (__destroy_pipes(asd, true))
-               dev_err(isp->dev, "destroy pipes failed.\n");
+       /* if is called in atomisp_reset(), force destroy streams and pipes */
+       atomisp_destroy_pipes_stream_force(asd);
 
        atomisp_init_raw_buffer_bitmap(asd);
 
@@ -2634,27 +2593,15 @@ static int __get_frame_info(struct atomisp_sub_device *asd,
        struct ia_css_pipe_info p_info;
 
        /* FIXME! No need to destroy/recreate all streams */
-       if (__destroy_streams(asd, true))
-               dev_warn(isp->dev, "destroy stream failed.\n");
-
-       if (__destroy_pipes(asd, true))
-               dev_warn(isp->dev, "destroy pipe failed.\n");
-
-       if (__create_pipes(asd)) {
-               dev_err(isp->dev, "can't create pipes\n");
-               return -EINVAL;
-       }
-
-       if (__create_streams(asd)) {
-               dev_err(isp->dev, "can't create streams\n");
-               goto stream_err;
-       }
+       ret = atomisp_css_update_stream(asd);
+       if (ret)
+               return ret;
 
        ret = ia_css_pipe_get_info(asd->stream_env[stream_index].pipes[pipe_id],
                                   &p_info);
        if (ret) {
                dev_err(isp->dev, "can't get info from pipe\n");
-               goto stream_err;
+               goto get_info_err;
        }
 
        switch (type) {
@@ -2685,8 +2632,8 @@ static int __get_frame_info(struct atomisp_sub_device *asd,
 
        return 0;
 
-stream_err:
-       __destroy_pipes(asd, true);
+get_info_err:
+       atomisp_destroy_pipes_stream_force(asd);
        return -EINVAL;
 }
 
@@ -3824,30 +3771,6 @@ void atomisp_css_set_cont_prev_start_time(struct atomisp_device *isp,
        return;
 }
 
-void atomisp_css_acc_done(struct atomisp_sub_device *asd)
-{
-       complete(&asd->acc.acc_done);
-}
-
-int atomisp_css_wait_acc_finish(struct atomisp_sub_device *asd)
-{
-       int ret = 0;
-       struct atomisp_device *isp = asd->isp;
-
-       /* Unlock the isp mutex taken in IOCTL handler before sleeping! */
-       rt_mutex_unlock(&isp->mutex);
-       if (wait_for_completion_interruptible_timeout(&asd->acc.acc_done,
-               ATOMISP_ISP_TIMEOUT_DURATION) == 0) {
-               dev_err(isp->dev, "<%s: completion timeout\n", __func__);
-               ia_css_debug_dump_sp_sw_debug_info();
-               ia_css_debug_dump_debug_info(__func__);
-               ret = -EIO;
-       }
-       rt_mutex_lock(&isp->mutex);
-
-       return ret;
-}
-
 /* Set the ACC binary arguments */
 int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw)
 {
@@ -3866,204 +3789,6 @@ int atomisp_css_set_acc_parameters(struct atomisp_acc_fw *acc_fw)
        return 0;
 }
 
-/* Load acc binary extension */
-int atomisp_css_load_acc_extension(struct atomisp_sub_device *asd,
-                                  struct ia_css_fw_info *fw,
-                                  enum ia_css_pipe_id pipe_id,
-                                  unsigned int type)
-{
-       struct ia_css_fw_info **hd;
-
-       fw->next = NULL;
-       hd = &(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
-              .pipe_configs[pipe_id].acc_extension);
-       while (*hd)
-               hd = &(*hd)->next;
-       *hd = fw;
-
-       asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
-       .update_pipe[pipe_id] = true;
-       return 0;
-}
-
-/* Unload acc binary extension */
-void atomisp_css_unload_acc_extension(struct atomisp_sub_device *asd,
-                                     struct ia_css_fw_info *fw,
-                                     enum ia_css_pipe_id pipe_id)
-{
-       struct ia_css_fw_info **hd;
-
-       hd = &(asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
-              .pipe_configs[pipe_id].acc_extension);
-       while (*hd && *hd != fw)
-               hd = &(*hd)->next;
-       if (!*hd) {
-               dev_err(asd->isp->dev, "did not find acc fw for removal\n");
-               return;
-       }
-       *hd = fw->next;
-       fw->next = NULL;
-
-       asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
-       .update_pipe[pipe_id] = true;
-}
-
-int atomisp_css_create_acc_pipe(struct atomisp_sub_device *asd)
-{
-       struct atomisp_device *isp = asd->isp;
-       struct ia_css_pipe_config *pipe_config;
-       struct atomisp_stream_env *stream_env =
-                   &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
-
-       if (stream_env->acc_stream) {
-               if (stream_env->acc_stream_state == CSS_STREAM_STARTED) {
-                       if (ia_css_stream_stop(stream_env->acc_stream)
-                           != 0) {
-                               dev_err(isp->dev, "stop acc_stream failed.\n");
-                               return -EBUSY;
-                       }
-               }
-
-               if (ia_css_stream_destroy(stream_env->acc_stream)
-                   != 0) {
-                       dev_err(isp->dev, "destroy acc_stream failed.\n");
-                       return -EBUSY;
-               }
-               stream_env->acc_stream = NULL;
-       }
-
-       pipe_config = &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC];
-       ia_css_pipe_config_defaults(pipe_config);
-       asd->acc.acc_stages = kzalloc(MAX_ACC_STAGES *
-                                     sizeof(void *), GFP_KERNEL);
-       if (!asd->acc.acc_stages)
-               return -ENOMEM;
-       pipe_config->acc_stages = asd->acc.acc_stages;
-       pipe_config->mode = IA_CSS_PIPE_MODE_ACC;
-       pipe_config->num_acc_stages = 0;
-
-       /*
-        * We delay the ACC pipeline creation to atomisp_css_start_acc_pipe,
-        * because pipe configuration will soon be changed by
-        * atomisp_css_load_acc_binary()
-        */
-       return 0;
-}
-
-int atomisp_css_start_acc_pipe(struct atomisp_sub_device *asd)
-{
-       struct atomisp_device *isp = asd->isp;
-       struct atomisp_stream_env *stream_env =
-                   &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
-       struct ia_css_pipe_config *pipe_config =
-                   &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC];
-
-       if (ia_css_pipe_create(pipe_config,
-                              &stream_env->pipes[IA_CSS_PIPE_ID_ACC]) != 0) {
-               dev_err(isp->dev, "%s: ia_css_pipe_create failed\n",
-                       __func__);
-               return -EBADE;
-       }
-
-       memset(&stream_env->acc_stream_config, 0,
-              sizeof(struct ia_css_stream_config));
-       if (ia_css_stream_create(&stream_env->acc_stream_config, 1,
-                                &stream_env->pipes[IA_CSS_PIPE_ID_ACC],
-                                &stream_env->acc_stream) != 0) {
-               dev_err(isp->dev, "%s: create acc_stream error.\n", __func__);
-               return -EINVAL;
-       }
-       stream_env->acc_stream_state = CSS_STREAM_CREATED;
-
-       init_completion(&asd->acc.acc_done);
-       asd->acc.pipeline = stream_env->pipes[IA_CSS_PIPE_ID_ACC];
-
-       atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_MAX, false);
-
-       if (ia_css_start_sp()) {
-               dev_err(isp->dev, "start sp error.\n");
-               return -EIO;
-       }
-
-       if (ia_css_stream_start(stream_env->acc_stream)
-           != 0) {
-               dev_err(isp->dev, "acc_stream start error.\n");
-               return -EIO;
-       }
-
-       stream_env->acc_stream_state = CSS_STREAM_STARTED;
-       return 0;
-}
-
-int atomisp_css_stop_acc_pipe(struct atomisp_sub_device *asd)
-{
-       struct atomisp_stream_env *stream_env =
-                   &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
-       if (stream_env->acc_stream_state == CSS_STREAM_STARTED) {
-               ia_css_stream_stop(stream_env->acc_stream);
-               stream_env->acc_stream_state = CSS_STREAM_STOPPED;
-       }
-       return 0;
-}
-
-void atomisp_css_destroy_acc_pipe(struct atomisp_sub_device *asd)
-{
-       struct atomisp_stream_env *stream_env =
-                   &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL];
-       if (stream_env->acc_stream) {
-               if (ia_css_stream_destroy(stream_env->acc_stream)
-                   != 0)
-                       dev_warn(asd->isp->dev,
-                                "destroy acc_stream failed.\n");
-               stream_env->acc_stream = NULL;
-       }
-
-       if (stream_env->pipes[IA_CSS_PIPE_ID_ACC]) {
-               if (ia_css_pipe_destroy(stream_env->pipes[IA_CSS_PIPE_ID_ACC])
-                   != 0)
-                       dev_warn(asd->isp->dev,
-                                "destroy ACC pipe failed.\n");
-               stream_env->pipes[IA_CSS_PIPE_ID_ACC] = NULL;
-               stream_env->update_pipe[IA_CSS_PIPE_ID_ACC] = false;
-               ia_css_pipe_config_defaults(
-                   &stream_env->pipe_configs[IA_CSS_PIPE_ID_ACC]);
-               ia_css_pipe_extra_config_defaults(
-                   &stream_env->pipe_extra_configs[IA_CSS_PIPE_ID_ACC]);
-       }
-       asd->acc.pipeline = NULL;
-
-       /* css 2.0 API limitation: ia_css_stop_sp() could be only called after
-        * destroy all pipes
-        */
-       ia_css_stop_sp();
-
-       kfree(asd->acc.acc_stages);
-       asd->acc.acc_stages = NULL;
-
-       atomisp_freq_scaling(asd->isp, ATOMISP_DFS_MODE_LOW, false);
-}
-
-int atomisp_css_load_acc_binary(struct atomisp_sub_device *asd,
-                               struct ia_css_fw_info *fw,
-                               unsigned int index)
-{
-       struct ia_css_pipe_config *pipe_config =
-                   &asd->stream_env[ATOMISP_INPUT_STREAM_GENERAL]
-                   .pipe_configs[IA_CSS_PIPE_ID_ACC];
-
-       if (index >= MAX_ACC_STAGES) {
-               dev_dbg(asd->isp->dev, "%s: index(%d) out of range\n",
-                       __func__, index);
-               return -ENOMEM;
-       }
-
-       pipe_config->acc_stages[index] = fw;
-       pipe_config->num_acc_stages = index + 1;
-       pipe_config->acc_num_execs = 1;
-
-       return 0;
-}
-
 static struct atomisp_sub_device *__get_atomisp_subdev(
     struct ia_css_pipe *css_pipe,
     struct atomisp_device *isp,
@@ -4075,8 +3800,7 @@ static struct atomisp_sub_device *__get_atomisp_subdev(
 
        for (i = 0; i < isp->num_of_streams; i++) {
                asd = &isp->asd[i];
-               if (asd->streaming == ATOMISP_DEVICE_STREAMING_DISABLED &&
-                   !asd->acc.pipeline)
+               if (asd->streaming == ATOMISP_DEVICE_STREAMING_DISABLED)
                        continue;
                for (j = 0; j < ATOMISP_INPUT_STREAM_NUM; j++) {
                        stream_env = &asd->stream_env[j];
@@ -4211,8 +3935,7 @@ int atomisp_css_isr_thread(struct atomisp_device *isp,
                        css_pipe_done[asd->index] = true;
                        break;
                case IA_CSS_EVENT_TYPE_ACC_STAGE_COMPLETE:
-                       dev_dbg(isp->dev, "event: acc stage done");
-                       atomisp_acc_done(asd, current_event.event.fw_handle);
+                       dev_warn(isp->dev, "unexpected event: acc stage done");
                        break;
                default:
                        dev_dbg(isp->dev, "unhandled css stored event: 0x%x\n",
index 86d3fbe..33821b5 100644 (file)
@@ -140,19 +140,6 @@ struct atomisp_calibration_group32 {
        compat_uptr_t calb_grp_values;
 };
 
-struct atomisp_acc_fw_load32 {
-       unsigned int size;
-       unsigned int fw_handle;
-       compat_uptr_t data;
-};
-
-struct atomisp_acc_fw_arg32 {
-       unsigned int fw_handle;
-       unsigned int index;
-       compat_uptr_t value;
-       compat_size_t size;
-};
-
 struct v4l2_private_int_data32 {
        __u32 size;
        compat_uptr_t data;
@@ -170,21 +157,6 @@ struct atomisp_shading_table32 {
        compat_uptr_t data[ATOMISP_NUM_SC_COLORS];
 };
 
-struct atomisp_acc_map32 {
-       __u32 flags;                    /* Flags, see list below */
-       __u32 length;                   /* Length of data in bytes */
-       compat_uptr_t user_ptr;         /* Pointer into user space */
-       compat_ulong_t css_ptr;         /* Pointer into CSS address space */
-       __u32 reserved[4];              /* Set to zero */
-};
-
-struct atomisp_acc_s_mapped_arg32 {
-       unsigned int fw_handle;
-       __u32 memory;                   /* one of enum atomisp_acc_memory */
-       compat_size_t length;
-       compat_ulong_t css_ptr;
-};
-
 struct atomisp_parameters32 {
        compat_uptr_t wb_config;  /* White Balance config */
        compat_uptr_t cc_config;  /* Color Correction config */
@@ -265,15 +237,6 @@ struct atomisp_parameters32 {
        u32     per_frame_setting;
 };
 
-struct atomisp_acc_fw_load_to_pipe32 {
-       __u32 flags;                    /* Flags, see below for valid values */
-       unsigned int fw_handle;         /* Handle, filled by kernel. */
-       __u32 size;                     /* Firmware binary size */
-       compat_uptr_t data;             /* Pointer to firmware */
-       __u32 type;                     /* Binary type */
-       __u32 reserved[3];              /* Set to zero */
-};
-
 struct atomisp_dvs_6axis_config32 {
        u32 exp_id;
        u32 width_y;
@@ -323,15 +286,6 @@ struct atomisp_sensor_ae_bracketing_lut32 {
 #define ATOMISP_IOC_G_SENSOR_CALIBRATION_GROUP32 \
        _IOWR('v', BASE_VIDIOC_PRIVATE + 22, struct atomisp_calibration_group32)
 
-#define ATOMISP_IOC_ACC_LOAD32 \
-       _IOWR('v', BASE_VIDIOC_PRIVATE + 24, struct atomisp_acc_fw_load32)
-
-#define ATOMISP_IOC_ACC_S_ARG32 \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 24, struct atomisp_acc_fw_arg32)
-
-#define ATOMISP_IOC_ACC_DESTAB32 \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 25, struct atomisp_acc_fw_arg32)
-
 #define ATOMISP_IOC_G_SENSOR_PRIV_INT_DATA32 \
        _IOWR('v', BASE_VIDIOC_PRIVATE + 26, struct v4l2_private_int_data32)
 
@@ -341,18 +295,6 @@ struct atomisp_sensor_ae_bracketing_lut32 {
 #define ATOMISP_IOC_G_MOTOR_PRIV_INT_DATA32 \
        _IOWR('v', BASE_VIDIOC_PRIVATE + 29, struct v4l2_private_int_data32)
 
-#define ATOMISP_IOC_ACC_MAP32 \
-       _IOWR('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_map32)
-
-#define ATOMISP_IOC_ACC_UNMAP32 \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_map32)
-
-#define ATOMISP_IOC_ACC_S_MAPPED_ARG32 \
-       _IOW('v', BASE_VIDIOC_PRIVATE + 30, struct atomisp_acc_s_mapped_arg32)
-
-#define ATOMISP_IOC_ACC_LOAD_TO_PIPE32 \
-       _IOWR('v', BASE_VIDIOC_PRIVATE + 31, struct atomisp_acc_fw_load_to_pipe32)
-
 #define ATOMISP_IOC_S_PARAMETERS32 \
        _IOW('v', BASE_VIDIOC_PRIVATE + 32, struct atomisp_parameters32)
 
index dcb571f..3ddc935 100644 (file)
@@ -45,10 +45,8 @@ struct _iunit_debug {
 
 #define OPTION_BIN_LIST                        BIT(0)
 #define OPTION_BIN_RUN                 BIT(1)
-#define OPTION_MEM_STAT                        BIT(2)
 #define OPTION_VALID                   (OPTION_BIN_LIST \
-                                       | OPTION_BIN_RUN \
-                                       | OPTION_MEM_STAT)
+                                       | OPTION_BIN_RUN)
 
 static struct _iunit_debug iunit_debug = {
        .dbglvl = 0,
@@ -81,9 +79,6 @@ static inline int iunit_dump_dbgopt(struct atomisp_device *isp,
                                goto opt_err;
                        }
                }
-
-               if (opt & OPTION_MEM_STAT)
-                       hmm_show_mem_stat(__func__, __LINE__);
        } else {
                ret = -EINVAL;
                dev_err(isp->dev, "%s dump nothing[ret=%d]\n", __func__, ret);
index be6a74d..77150e4 100644 (file)
@@ -38,8 +38,6 @@
 #include "type_support.h"
 #include "device_access/device_access.h"
 
-#include "atomisp_acc.h"
-
 #define ISP_LEFT_PAD                   128     /* equal to 2*NWAY */
 
 /*
@@ -865,12 +863,6 @@ dev_init:
                goto error;
        }
 
-       if (dypool_enable) {
-               ret = hmm_pool_register(dypool_pgnr, HMM_POOL_TYPE_DYNAMIC);
-               if (ret)
-                       dev_err(isp->dev, "Failed to register dynamic memory pool.\n");
-       }
-
        /* Init ISP */
        if (atomisp_css_init(isp)) {
                ret = -EINVAL;
@@ -910,7 +902,6 @@ css_error:
        atomisp_css_uninit(isp);
        pm_runtime_put(vdev->v4l2_dev->dev);
 error:
-       hmm_pool_unregister(HMM_POOL_TYPE_DYNAMIC);
        rt_mutex_unlock(&isp->mutex);
        return ret;
 }
@@ -1021,8 +1012,6 @@ subdev_uninit:
        if (atomisp_dev_users(isp))
                goto done;
 
-       atomisp_acc_release(asd);
-
        atomisp_destroy_pipes_stream_force(asd);
        atomisp_css_uninit(isp);
 
@@ -1032,8 +1021,6 @@ subdev_uninit:
                isp->css_env.isp_css_fw.bytes = 0;
        }
 
-       hmm_pool_unregister(HMM_POOL_TYPE_DYNAMIC);
-
        ret = v4l2_subdev_call(isp->flash, core, s_power, 0);
        if (ret < 0 && ret != -ENODEV && ret != -ENOIOCTLCMD)
                dev_warn(isp->dev, "Failed to power-off flash\n");
index 8fd470e..459645c 100644 (file)
@@ -25,7 +25,6 @@
 #include <media/v4l2-event.h>
 #include <media/videobuf-vmalloc.h>
 
-#include "atomisp_acc.h"
 #include "atomisp_cmd.h"
 #include "atomisp_common.h"
 #include "atomisp_fops.h"
@@ -625,17 +624,6 @@ unsigned int atomisp_streaming_count(struct atomisp_device *isp)
        return sum;
 }
 
-unsigned int atomisp_is_acc_enabled(struct atomisp_device *isp)
-{
-       unsigned int i;
-
-       for (i = 0; i < isp->num_of_streams; i++)
-               if (isp->asd[i].acc.pipeline)
-                       return 1;
-
-       return 0;
-}
-
 /*
  * get input are used to get current primary/secondary camera
  */
@@ -1371,7 +1359,7 @@ static int atomisp_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
 
                ret = ia_css_frame_map(&handle, &frame_info,
                                            (void __user *)buf->m.userptr,
-                                           0, pgnr);
+                                           pgnr);
                if (ret) {
                        dev_err(isp->dev, "Failed to map user buffer\n");
                        goto error;
@@ -1913,11 +1901,8 @@ static int atomisp_streamon(struct file *file, void *fh,
 
        css_pipe_id = atomisp_get_css_pipe_id(asd);
 
-       ret = atomisp_acc_load_extensions(asd);
-       if (ret < 0) {
-               dev_err(isp->dev, "acc extension failed to load\n");
-               goto out;
-       }
+       /* Invalidate caches. FIXME: should flush only necessary buffers */
+       wbinvd();
 
        if (asd->params.css_update_params_needed) {
                atomisp_apply_css_parameters(asd, &asd->params.css_param);
@@ -2154,7 +2139,6 @@ int __atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
                                         video, s_stream, 0);
 
                rt_mutex_lock(&isp->mutex);
-               atomisp_acc_unload_extensions(asd);
        }
 
        spin_lock_irqsave(&isp->lock, flags);
@@ -2283,8 +2267,17 @@ stopsensor:
                dev_err(isp->dev, "atomisp_reset");
                atomisp_reset(isp);
                for (i = 0; i < isp->num_of_streams; i++) {
-                       if (recreate_streams[i])
-                               atomisp_create_pipes_stream(&isp->asd[i]);
+                       if (recreate_streams[i]) {
+                               int ret2;
+
+                               ret2 = atomisp_create_pipes_stream(&isp->asd[i]);
+                               if (ret2) {
+                                       dev_err(isp->dev, "%s error re-creating streams: %d\n",
+                                               __func__, ret2);
+                                       if (!ret)
+                                               ret = ret2;
+                               }
+                       }
                }
                isp->isp_timeout = false;
        }
@@ -3118,38 +3111,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh,
                        err = -EINVAL;
                break;
 
-       case ATOMISP_IOC_ACC_LOAD:
-               err = atomisp_acc_load(asd, arg);
-               break;
-
-       case ATOMISP_IOC_ACC_LOAD_TO_PIPE:
-               err = atomisp_acc_load_to_pipe(asd, arg);
-               break;
-
-       case ATOMISP_IOC_ACC_UNLOAD:
-               err = atomisp_acc_unload(asd, arg);
-               break;
-
-       case ATOMISP_IOC_ACC_START:
-               err = atomisp_acc_start(asd, arg);
-               break;
-
-       case ATOMISP_IOC_ACC_WAIT:
-               err = atomisp_acc_wait(asd, arg);
-               break;
-
-       case ATOMISP_IOC_ACC_MAP:
-               err = atomisp_acc_map(asd, arg);
-               break;
-
-       case ATOMISP_IOC_ACC_UNMAP:
-               err = atomisp_acc_unmap(asd, arg);
-               break;
-
-       case ATOMISP_IOC_ACC_S_MAPPED_ARG:
-               err = atomisp_acc_s_mapped_arg(asd, arg);
-               break;
-
        case ATOMISP_IOC_S_ISP_SHD_TAB:
                err = atomisp_set_shading_table(asd, arg);
                break;
@@ -3198,12 +3159,6 @@ static long atomisp_vidioc_default(struct file *file, void *fh,
        case ATOMISP_IOC_S_EXPOSURE_WINDOW:
                err = atomisp_s_ae_window(asd, arg);
                break;
-       case ATOMISP_IOC_S_ACC_STATE:
-               err = atomisp_acc_set_state(asd, arg);
-               break;
-       case ATOMISP_IOC_G_ACC_STATE:
-               err = atomisp_acc_get_state(asd, arg);
-               break;
        case ATOMISP_IOC_INJECT_A_FAKE_EVENT:
                err = atomisp_inject_a_fake_event(asd, arg);
                break;
index 412bfcf..d85e0d6 100644 (file)
@@ -57,7 +57,6 @@ extern const struct v4l2_ioctl_ops atomisp_file_ioctl_ops;
 
 unsigned int atomisp_streaming_count(struct atomisp_device *isp);
 
-unsigned int atomisp_is_acc_enabled(struct atomisp_device *isp);
 /* compat_ioctl for 32bit userland app and 64bit kernel */
 long atomisp_compat_ioctl32(struct file *file,
                            unsigned int cmd, unsigned long arg);
index 1807cfa..394fe69 100644 (file)
@@ -1081,9 +1081,6 @@ static void atomisp_init_acc_pipe(struct atomisp_sub_device *asd,
 {
        pipe->asd = asd;
        pipe->isp = asd->isp;
-       INIT_LIST_HEAD(&asd->acc.fw);
-       INIT_LIST_HEAD(&asd->acc.memory_maps);
-       ida_init(&asd->acc.ida);
 }
 
 /*
index 7d731f1..798a937 100644 (file)
@@ -322,16 +322,6 @@ struct atomisp_sub_device {
 
        struct v4l2_ctrl *disable_dz;
 
-       struct {
-               struct list_head fw;
-               struct list_head memory_maps;
-               struct ia_css_pipe *pipeline;
-               bool extension_mode;
-               struct ida ida;
-               struct completion acc_done;
-               void *acc_stages;
-       } acc;
-
        struct atomisp_subdev_params params;
 
        struct atomisp_stream_env stream_env[ATOMISP_INPUT_STREAM_NUM];
index 49ccfb1..643ba98 100644 (file)
@@ -37,7 +37,6 @@
 #include "atomisp_file.h"
 #include "atomisp_ioctl.h"
 #include "atomisp_internal.h"
-#include "atomisp_acc.h"
 #include "atomisp-regs.h"
 #include "atomisp_dfs_tables.h"
 #include "atomisp_drvfs.h"
@@ -59,23 +58,6 @@ static uint skip_fwload;
 module_param(skip_fwload, uint, 0644);
 MODULE_PARM_DESC(skip_fwload, "Skip atomisp firmware load");
 
-/* set reserved memory pool size in page */
-static unsigned int repool_pgnr = 32768;
-module_param(repool_pgnr, uint, 0644);
-MODULE_PARM_DESC(repool_pgnr,
-                "Set the reserved memory pool size in page (default:32768)");
-
-/* set dynamic memory pool size in page */
-unsigned int dypool_pgnr = UINT_MAX;
-module_param(dypool_pgnr, uint, 0644);
-MODULE_PARM_DESC(dypool_pgnr,
-                "Set the dynamic memory pool size in page (default: unlimited)");
-
-bool dypool_enable = true;
-module_param(dypool_enable, bool, 0644);
-MODULE_PARM_DESC(dypool_enable,
-                "dynamic memory pool enable/disable (default:enabled)");
-
 /* memory optimization: deferred firmware loading */
 bool defer_fw_load;
 module_param(defer_fw_load, bool, 0644);
@@ -1770,13 +1752,6 @@ static int atomisp_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
        pm_runtime_put_noidle(&pdev->dev);
        pm_runtime_allow(&pdev->dev);
 
-       hmm_init_mem_stat(repool_pgnr, dypool_enable, dypool_pgnr);
-       err = hmm_pool_register(repool_pgnr, HMM_POOL_TYPE_RESERVED);
-       if (err) {
-               dev_err(&pdev->dev, "Failed to register reserved memory pool.\n");
-               goto hmm_pool_fail;
-       }
-
        /* Init ISP memory management */
        hmm_init();
 
@@ -1813,12 +1788,9 @@ css_init_fail:
        devm_free_irq(&pdev->dev, pdev->irq, isp);
 request_irq_fail:
        hmm_cleanup();
-       hmm_pool_unregister(HMM_POOL_TYPE_RESERVED);
-hmm_pool_fail:
        pm_runtime_get_noresume(&pdev->dev);
        destroy_workqueue(isp->wdt_work_queue);
 wdt_work_queue_fail:
-       atomisp_acc_cleanup(isp);
        atomisp_unregister_entities(isp);
 register_entities_fail:
        atomisp_uninitialize_modules(isp);
@@ -1869,8 +1841,6 @@ static void atomisp_pci_remove(struct pci_dev *pdev)
 
        atomisp_drvfs_exit();
 
-       atomisp_acc_cleanup(isp);
-
        ia_css_unload_firmware();
        hmm_cleanup();
 
@@ -1885,8 +1855,6 @@ static void atomisp_pci_remove(struct pci_dev *pdev)
        atomisp_file_input_cleanup(isp);
 
        release_firmware(isp->firmware);
-
-       hmm_pool_unregister(HMM_POOL_TYPE_RESERVED);
 }
 
 static const struct pci_device_id atomisp_pci_tbl[] = {
index ee861dd..5660bd4 100644 (file)
@@ -25,7 +25,7 @@
  * Simple queuing trace buffer for debug data
  * instantiatable in SP DMEM
  *
- * The buffer has a remote and and a local store
+ * The buffer has a remote and a local store
  * which contain duplicate data (when in sync).
  * The buffers are automatically synched when the
  * user dequeues, or manualy using the synch function
index c1cda16..fc6cfe9 100644 (file)
@@ -28,7 +28,6 @@
 #include <linux/sysfs.h>
 
 #include "hmm/hmm.h"
-#include "hmm/hmm_pool.h"
 #include "hmm/hmm_bo.h"
 
 #include "atomisp_internal.h"
 #include "mmu/sh_mmu_mrfld.h"
 
 struct hmm_bo_device bo_device;
-struct hmm_pool        dynamic_pool;
-struct hmm_pool        reserved_pool;
 static ia_css_ptr dummy_ptr = mmgr_EXCEPTION;
 static bool hmm_initialized;
-struct _hmm_mem_stat hmm_mem_stat;
 
 /*
  * p: private
@@ -113,62 +109,13 @@ static ssize_t free_bo_show(struct device *dev, struct device_attribute *attr,
        return bo_show(dev, attr, buf, &bo_device.entire_bo_list, false);
 }
 
-static ssize_t reserved_pool_show(struct device *dev,
-                                 struct device_attribute *attr,
-                                 char *buf)
-{
-       ssize_t ret = 0;
-
-       struct hmm_reserved_pool_info *pinfo = reserved_pool.pool_info;
-       unsigned long flags;
-
-       if (!pinfo || !pinfo->initialized)
-               return 0;
-
-       spin_lock_irqsave(&pinfo->list_lock, flags);
-       ret = scnprintf(buf, PAGE_SIZE, "%d out of %d pages available\n",
-                       pinfo->index, pinfo->pgnr);
-       spin_unlock_irqrestore(&pinfo->list_lock, flags);
-
-       if (ret > 0)
-               ret++; /* Add trailing zero, not included by scnprintf */
-
-       return ret;
-};
-
-static ssize_t dynamic_pool_show(struct device *dev,
-                                struct device_attribute *attr,
-                                char *buf)
-{
-       ssize_t ret = 0;
-
-       struct hmm_dynamic_pool_info *pinfo = dynamic_pool.pool_info;
-       unsigned long flags;
-
-       if (!pinfo || !pinfo->initialized)
-               return 0;
-
-       spin_lock_irqsave(&pinfo->list_lock, flags);
-       ret = scnprintf(buf, PAGE_SIZE, "%d (max %d) pages available\n",
-                       pinfo->pgnr, pinfo->pool_size);
-       spin_unlock_irqrestore(&pinfo->list_lock, flags);
-
-       if (ret > 0)
-               ret++; /* Add trailing zero, not included by scnprintf */
-
-       return ret;
-};
 
 static DEVICE_ATTR_RO(active_bo);
 static DEVICE_ATTR_RO(free_bo);
-static DEVICE_ATTR_RO(reserved_pool);
-static DEVICE_ATTR_RO(dynamic_pool);
 
 static struct attribute *sysfs_attrs_ctrl[] = {
        &dev_attr_active_bo.attr,
        &dev_attr_free_bo.attr,
-       &dev_attr_reserved_pool.attr,
-       &dev_attr_dynamic_pool.attr,
        NULL
 };
 
@@ -194,7 +141,7 @@ int hmm_init(void)
         * at the beginning, to avoid hmm_alloc return 0 in the
         * further allocation.
         */
-       dummy_ptr = hmm_alloc(1, HMM_BO_PRIVATE, 0, NULL, 0);
+       dummy_ptr = hmm_alloc(1);
 
        if (!ret) {
                ret = sysfs_create_group(&atomisp_dev->kobj,
@@ -221,17 +168,12 @@ void hmm_cleanup(void)
        hmm_initialized = false;
 }
 
-ia_css_ptr hmm_alloc(size_t bytes, enum hmm_bo_type type,
-                    int from_highmem, const void __user *userptr,
-                    const uint16_t attrs)
+static ia_css_ptr __hmm_alloc(size_t bytes, enum hmm_bo_type type, const void __user *userptr)
 {
        unsigned int pgnr;
        struct hmm_buffer_object *bo;
-       bool cached = attrs & ATOMISP_MAP_FLAG_CACHED;
        int ret;
 
-       WARN_ON(attrs & ATOMISP_MAP_FLAG_CONTIGUOUS);
-
        /*
         * Check if we are initialized. In the ideal world we wouldn't need
         * this but we can tackle it once the driver is a lot cleaner
@@ -250,7 +192,7 @@ ia_css_ptr hmm_alloc(size_t bytes, enum hmm_bo_type type,
        }
 
        /* Allocate pages for memory */
-       ret = hmm_bo_alloc_pages(bo, type, from_highmem, userptr, cached);
+       ret = hmm_bo_alloc_pages(bo, type, userptr);
        if (ret) {
                dev_err(atomisp_dev, "hmm_bo_alloc_pages failed.\n");
                goto alloc_page_err;
@@ -263,14 +205,9 @@ ia_css_ptr hmm_alloc(size_t bytes, enum hmm_bo_type type,
                goto bind_err;
        }
 
-       hmm_mem_stat.tol_cnt += pgnr;
-
-       if (attrs & ATOMISP_MAP_FLAG_CLEARED)
-               hmm_set(bo->start, 0, bytes);
-
        dev_dbg(atomisp_dev,
-               "%s: pages: 0x%08x (%zu bytes), type: %d from highmem %d, user ptr %p, cached %d\n",
-               __func__, bo->start, bytes, type, from_highmem, userptr, cached);
+               "%s: pages: 0x%08x (%zu bytes), type: %d, user ptr %p\n",
+               __func__, bo->start, bytes, type, userptr);
 
        return bo->start;
 
@@ -282,6 +219,16 @@ create_bo_err:
        return 0;
 }
 
+ia_css_ptr hmm_alloc(size_t bytes)
+{
+       return __hmm_alloc(bytes, HMM_BO_PRIVATE, NULL);
+}
+
+ia_css_ptr hmm_create_from_userdata(size_t bytes, const void __user *userptr)
+{
+       return __hmm_alloc(bytes, HMM_BO_USER, userptr);
+}
+
 void hmm_free(ia_css_ptr virt)
 {
        struct hmm_buffer_object *bo;
@@ -300,8 +247,6 @@ void hmm_free(ia_css_ptr virt)
                return;
        }
 
-       hmm_mem_stat.tol_cnt -= bo->pgnr;
-
        hmm_bo_unbind(bo);
        hmm_bo_free_pages(bo);
        hmm_bo_unref(bo);
@@ -350,7 +295,7 @@ static int load_and_flush_by_kmap(ia_css_ptr virt, void *data,
                idx = (virt - bo->start) >> PAGE_SHIFT;
                offset = (virt - bo->start) - (idx << PAGE_SHIFT);
 
-               src = (char *)kmap(bo->page_obj[idx].page) + offset;
+               src = (char *)kmap_local_page(bo->pages[idx]) + offset;
 
                if ((bytes + offset) >= PAGE_SIZE) {
                        len = PAGE_SIZE - offset;
@@ -369,7 +314,7 @@ static int load_and_flush_by_kmap(ia_css_ptr virt, void *data,
 
                clflush_cache_range(src, len);
 
-               kunmap(bo->page_obj[idx].page);
+               kunmap_local(src);
        }
 
        return 0;
@@ -482,10 +427,7 @@ int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes)
                idx = (virt - bo->start) >> PAGE_SHIFT;
                offset = (virt - bo->start) - (idx << PAGE_SHIFT);
 
-               if (in_atomic())
-                       des = (char *)kmap_atomic(bo->page_obj[idx].page);
-               else
-                       des = (char *)kmap(bo->page_obj[idx].page);
+               des = (char *)kmap_local_page(bo->pages[idx]);
 
                if (!des) {
                        dev_err(atomisp_dev,
@@ -512,14 +454,7 @@ int hmm_store(ia_css_ptr virt, const void *data, unsigned int bytes)
 
                clflush_cache_range(des, len);
 
-               if (in_atomic())
-                       /*
-                        * Note: kunmap_atomic requires return addr from
-                        * kmap_atomic, not the page. See linux/highmem.h
-                        */
-                       kunmap_atomic(des - offset);
-               else
-                       kunmap(bo->page_obj[idx].page);
+               kunmap_local(des);
        }
 
        return 0;
@@ -563,7 +498,7 @@ int hmm_set(ia_css_ptr virt, int c, unsigned int bytes)
                idx = (virt - bo->start) >> PAGE_SHIFT;
                offset = (virt - bo->start) - (idx << PAGE_SHIFT);
 
-               des = (char *)kmap(bo->page_obj[idx].page) + offset;
+               des = (char *)kmap_local_page(bo->pages[idx]) + offset;
 
                if ((bytes + offset) >= PAGE_SIZE) {
                        len = PAGE_SIZE - offset;
@@ -579,7 +514,7 @@ int hmm_set(ia_css_ptr virt, int c, unsigned int bytes)
 
                clflush_cache_range(des, len);
 
-               kunmap(bo->page_obj[idx].page);
+               kunmap_local(des);
        }
 
        return 0;
@@ -602,7 +537,7 @@ phys_addr_t hmm_virt_to_phys(ia_css_ptr virt)
        idx = (virt - bo->start) >> PAGE_SHIFT;
        offset = (virt - bo->start) - (idx << PAGE_SHIFT);
 
-       return page_to_phys(bo->page_obj[idx].page) + offset;
+       return page_to_phys(bo->pages[idx]) + offset;
 }
 
 int hmm_mmap(struct vm_area_struct *vma, ia_css_ptr virt)
@@ -671,96 +606,3 @@ void hmm_vunmap(ia_css_ptr virt)
 
        hmm_bo_vunmap(bo);
 }
-
-int hmm_pool_register(unsigned int pool_size, enum hmm_pool_type pool_type)
-{
-#if 0  // Just use the "normal" pool
-       switch (pool_type) {
-       case HMM_POOL_TYPE_RESERVED:
-               reserved_pool.pops = &reserved_pops;
-               return reserved_pool.pops->pool_init(&reserved_pool.pool_info,
-                                                    pool_size);
-       case HMM_POOL_TYPE_DYNAMIC:
-               dynamic_pool.pops = &dynamic_pops;
-               return dynamic_pool.pops->pool_init(&dynamic_pool.pool_info,
-                                                   pool_size);
-       default:
-               dev_err(atomisp_dev, "invalid pool type.\n");
-               return -EINVAL;
-       }
-#else
-       return 0;
-#endif
-}
-
-void hmm_pool_unregister(enum hmm_pool_type pool_type)
-{
-#if 0  // Just use the "normal" pool
-       switch (pool_type) {
-       case HMM_POOL_TYPE_RESERVED:
-               if (reserved_pool.pops && reserved_pool.pops->pool_exit)
-                       reserved_pool.pops->pool_exit(&reserved_pool.pool_info);
-               break;
-       case HMM_POOL_TYPE_DYNAMIC:
-               if (dynamic_pool.pops && dynamic_pool.pops->pool_exit)
-                       dynamic_pool.pops->pool_exit(&dynamic_pool.pool_info);
-               break;
-       default:
-               dev_err(atomisp_dev, "invalid pool type.\n");
-               break;
-       }
-#endif
-
-       return;
-}
-
-void *hmm_isp_vaddr_to_host_vaddr(ia_css_ptr ptr, bool cached)
-{
-       return hmm_vmap(ptr, cached);
-       /* vmunmap will be done in hmm_bo_release() */
-}
-
-ia_css_ptr hmm_host_vaddr_to_hrt_vaddr(const void *ptr)
-{
-       struct hmm_buffer_object *bo;
-
-       bo = hmm_bo_device_search_vmap_start(&bo_device, ptr);
-       if (bo)
-               return bo->start;
-
-       dev_err(atomisp_dev,
-               "can not find buffer object whose kernel virtual address is %p\n",
-               ptr);
-       return 0;
-}
-
-void hmm_show_mem_stat(const char *func, const int line)
-{
-       pr_info("tol_cnt=%d usr_size=%d res_size=%d res_cnt=%d sys_size=%d  dyc_thr=%d dyc_size=%d.\n",
-               hmm_mem_stat.tol_cnt,
-               hmm_mem_stat.usr_size, hmm_mem_stat.res_size,
-               hmm_mem_stat.res_cnt, hmm_mem_stat.sys_size,
-               hmm_mem_stat.dyc_thr, hmm_mem_stat.dyc_size);
-}
-
-void hmm_init_mem_stat(int res_pgnr, int dyc_en, int dyc_pgnr)
-{
-       hmm_mem_stat.res_size = res_pgnr;
-       /* If reserved mem pool is not enabled, set its "mem stat" values as -1. */
-       if (hmm_mem_stat.res_size == 0) {
-               hmm_mem_stat.res_size = -1;
-               hmm_mem_stat.res_cnt = -1;
-       }
-
-       /* If dynamic memory pool is not enabled, set its "mem stat" values as -1. */
-       if (!dyc_en) {
-               hmm_mem_stat.dyc_size = -1;
-               hmm_mem_stat.dyc_thr = -1;
-       } else {
-               hmm_mem_stat.dyc_size = 0;
-               hmm_mem_stat.dyc_thr = dyc_pgnr;
-       }
-       hmm_mem_stat.usr_size = 0;
-       hmm_mem_stat.sys_size = 0;
-       hmm_mem_stat.tol_cnt = 0;
-}
index 0168f98..f504941 100644 (file)
@@ -42,7 +42,6 @@
 
 #include "atomisp_internal.h"
 #include "hmm/hmm_common.h"
-#include "hmm/hmm_pool.h"
 #include "hmm/hmm_bo.h"
 
 static unsigned int order_to_nr(unsigned int order)
@@ -627,75 +626,31 @@ found:
 }
 
 static void free_private_bo_pages(struct hmm_buffer_object *bo,
-                                 struct hmm_pool *dypool,
-                                 struct hmm_pool *repool,
                                  int free_pgnr)
 {
        int i, ret;
 
        for (i = 0; i < free_pgnr; i++) {
-               switch (bo->page_obj[i].type) {
-               case HMM_PAGE_TYPE_RESERVED:
-                       if (repool->pops
-                           && repool->pops->pool_free_pages) {
-                               repool->pops->pool_free_pages(repool->pool_info,
-                                                             &bo->page_obj[i]);
-                               hmm_mem_stat.res_cnt--;
-                       }
-                       break;
-               /*
-                * HMM_PAGE_TYPE_GENERAL indicates that pages are from system
-                * memory, so when free them, they should be put into dynamic
-                * pool.
-                */
-               case HMM_PAGE_TYPE_DYNAMIC:
-               case HMM_PAGE_TYPE_GENERAL:
-                       if (dypool->pops
-                           && dypool->pops->pool_inited
-                           && dypool->pops->pool_inited(dypool->pool_info)) {
-                               if (dypool->pops->pool_free_pages)
-                                       dypool->pops->pool_free_pages(
-                                           dypool->pool_info,
-                                           &bo->page_obj[i]);
-                               break;
-                       }
-
-                       fallthrough;
-
+               ret = set_pages_wb(bo->pages[i], 1);
+               if (ret)
+                       dev_err(atomisp_dev,
+                               "set page to WB err ...ret = %d\n",
+                               ret);
                /*
-                * if dynamic memory pool doesn't exist, need to free
-                * pages to system directly.
-                */
-               default:
-                       ret = set_pages_wb(bo->page_obj[i].page, 1);
-                       if (ret)
-                               dev_err(atomisp_dev,
-                                       "set page to WB err ...ret = %d\n",
-                                       ret);
-                       /*
-                       W/A: set_pages_wb seldom return value = -EFAULT
-                       indicate that address of page is not in valid
-                       range(0xffff880000000000~0xffffc7ffffffffff)
-                       then, _free_pages would panic; Do not know why page
-                       address be valid,it maybe memory corruption by lowmemory
-                       */
-                       if (!ret) {
-                               __free_pages(bo->page_obj[i].page, 0);
-                               hmm_mem_stat.sys_size--;
-                       }
-                       break;
+               W/A: set_pages_wb seldom return value = -EFAULT
+               indicate that address of page is not in valid
+               range(0xffff880000000000~0xffffc7ffffffffff)
+               then, _free_pages would panic; Do not know why page
+               address be valid,it maybe memory corruption by lowmemory
+               */
+               if (!ret) {
+                       __free_pages(bo->pages[i], 0);
                }
        }
-
-       return;
 }
 
 /*Allocate pages which will be used only by ISP*/
-static int alloc_private_pages(struct hmm_buffer_object *bo,
-                              int from_highmem,
-                              bool cached,
-                              struct hmm_pool *dypool,
-                              struct hmm_pool *repool)
+static int alloc_private_pages(struct hmm_buffer_object *bo)
 {
        int ret;
        unsigned int pgnr, order, blk_pgnr, alloc_pgnr;
@@ -706,50 +661,11 @@ static int alloc_private_pages(struct hmm_buffer_object *bo,
        bool reduce_order = false;
        bool lack_mem = true;
 
-       if (from_highmem)
-               gfp |= __GFP_HIGHMEM;
-
        pgnr = bo->pgnr;
 
-       bo->page_obj = kmalloc_array(pgnr, sizeof(struct hmm_page_object),
-                                    GFP_KERNEL);
-       if (unlikely(!bo->page_obj))
-               return -ENOMEM;
-
        i = 0;
        alloc_pgnr = 0;
 
-       /*
-        * get physical pages from dynamic pages pool.
-        */
-       if (dypool->pops && dypool->pops->pool_alloc_pages) {
-               alloc_pgnr = dypool->pops->pool_alloc_pages(dypool->pool_info,
-                            bo->page_obj, pgnr,
-                            cached);
-               hmm_mem_stat.dyc_size -= alloc_pgnr;
-
-               if (alloc_pgnr == pgnr)
-                       return 0;
-       }
-
-       pgnr -= alloc_pgnr;
-       i += alloc_pgnr;
-
-       /*
-        * get physical pages from reserved pages pool for atomisp.
-        */
-       if (repool->pops && repool->pops->pool_alloc_pages) {
-               alloc_pgnr = repool->pops->pool_alloc_pages(repool->pool_info,
-                            &bo->page_obj[i], pgnr,
-                            cached);
-               hmm_mem_stat.res_cnt += alloc_pgnr;
-               if (alloc_pgnr == pgnr)
-                       return 0;
-       }
-
-       pgnr -= alloc_pgnr;
-       i += alloc_pgnr;
-
        while (pgnr) {
                order = nr_to_order_bottom(pgnr);
                /*
@@ -804,28 +720,24 @@ retry:
                } else {
                        blk_pgnr = order_to_nr(order);
 
-                       if (!cached) {
-                               /*
-                                * set memory to uncacheable -- UC_MINUS
-                                */
-                               ret = set_pages_uc(pages, blk_pgnr);
-                               if (ret) {
-                                       dev_err(atomisp_dev,
-                                               "set page uncacheablefailed.\n");
+                       /*
+                        * set memory to uncacheable -- UC_MINUS
+                        */
+                       ret = set_pages_uc(pages, blk_pgnr);
+                       if (ret) {
+                               dev_err(atomisp_dev,
+                                       "set page uncacheablefailed.\n");
 
-                                       __free_pages(pages, order);
+                               __free_pages(pages, order);
 
-                                       goto cleanup;
-                               }
+                               goto cleanup;
                        }
 
-                       for (j = 0; j < blk_pgnr; j++) {
-                               bo->page_obj[i].page = pages + j;
-                               bo->page_obj[i++].type = HMM_PAGE_TYPE_GENERAL;
+                       for (j = 0; j < blk_pgnr; j++, i++) {
+                               bo->pages[i] = pages + j;
                        }
 
                        pgnr -= blk_pgnr;
-                       hmm_mem_stat.sys_size += blk_pgnr;
 
                        /*
                         * if order is not reduced this time, clear
@@ -841,60 +753,31 @@ retry:
        return 0;
 cleanup:
        alloc_pgnr = i;
-       free_private_bo_pages(bo, dypool, repool, alloc_pgnr);
-
-       kfree(bo->page_obj);
-
+       free_private_bo_pages(bo, alloc_pgnr);
        return -ENOMEM;
 }
 
-static void free_private_pages(struct hmm_buffer_object *bo,
-                              struct hmm_pool *dypool,
-                              struct hmm_pool *repool)
-{
-       free_private_bo_pages(bo, dypool, repool, bo->pgnr);
-
-       kfree(bo->page_obj);
-}
-
 static void free_user_pages(struct hmm_buffer_object *bo,
                            unsigned int page_nr)
 {
        int i;
 
-       hmm_mem_stat.usr_size -= bo->pgnr;
-
        if (bo->mem_type == HMM_BO_MEM_TYPE_PFN) {
                unpin_user_pages(bo->pages, page_nr);
        } else {
                for (i = 0; i < page_nr; i++)
                        put_page(bo->pages[i]);
        }
-       kfree(bo->pages);
-       kfree(bo->page_obj);
 }
 
 /*
  * Convert user space virtual address into pages list
  */
 static int alloc_user_pages(struct hmm_buffer_object *bo,
-                           const void __user *userptr, bool cached)
+                           const void __user *userptr)
 {
        int page_nr;
-       int i;
        struct vm_area_struct *vma;
-       struct page **pages;
-
-       pages = kmalloc_array(bo->pgnr, sizeof(struct page *), GFP_KERNEL);
-       if (unlikely(!pages))
-               return -ENOMEM;
-
-       bo->page_obj = kmalloc_array(bo->pgnr, sizeof(struct hmm_page_object),
-                                    GFP_KERNEL);
-       if (unlikely(!bo->page_obj)) {
-               kfree(pages);
-               return -ENOMEM;
-       }
 
        mutex_unlock(&bo->mutex);
        mmap_read_lock(current->mm);
@@ -902,8 +785,6 @@ static int alloc_user_pages(struct hmm_buffer_object *bo,
        mmap_read_unlock(current->mm);
        if (!vma) {
                dev_err(atomisp_dev, "find_vma failed\n");
-               kfree(bo->page_obj);
-               kfree(pages);
                mutex_lock(&bo->mutex);
                return -EFAULT;
        }
@@ -915,18 +796,16 @@ static int alloc_user_pages(struct hmm_buffer_object *bo,
 
        userptr = untagged_addr(userptr);
 
-       bo->pages = pages;
-
        if (vma->vm_flags & (VM_IO | VM_PFNMAP)) {
                page_nr = pin_user_pages((unsigned long)userptr, bo->pgnr,
                                         FOLL_LONGTERM | FOLL_WRITE,
-                                        pages, NULL);
+                                        bo->pages, NULL);
                bo->mem_type = HMM_BO_MEM_TYPE_PFN;
        } else {
                /*Handle frame buffer allocated in user space*/
                mutex_unlock(&bo->mutex);
                page_nr = get_user_pages_fast((unsigned long)userptr,
-                                             (int)(bo->pgnr), 1, pages);
+                                             (int)(bo->pgnr), 1, bo->pages);
                mutex_lock(&bo->mutex);
                bo->mem_type = HMM_BO_MEM_TYPE_USER;
        }
@@ -936,8 +815,6 @@ static int alloc_user_pages(struct hmm_buffer_object *bo,
                bo->pgnr,
                bo->mem_type == HMM_BO_MEM_TYPE_USER ? "user" : "pfn", page_nr);
 
-       hmm_mem_stat.usr_size += bo->pgnr;
-
        /* can be written by caller, not forced */
        if (page_nr != bo->pgnr) {
                dev_err(atomisp_dev,
@@ -948,11 +825,6 @@ static int alloc_user_pages(struct hmm_buffer_object *bo,
                goto out_of_mem;
        }
 
-       for (i = 0; i < bo->pgnr; i++) {
-               bo->page_obj[i].page = pages[i];
-               bo->page_obj[i].type = HMM_PAGE_TYPE_GENERAL;
-       }
-
        return 0;
 
 out_of_mem:
@@ -966,20 +838,14 @@ out_of_mem:
  * allocate/free physical pages for the bo.
  *
  * type indicate where are the pages from. currently we have 3 types
- * of memory: HMM_BO_PRIVATE, HMM_BO_USER, HMM_BO_SHARE.
- *
- * from_highmem is only valid when type is HMM_BO_PRIVATE, it will
- * try to alloc memory from highmem if from_highmem is set.
+ * of memory: HMM_BO_PRIVATE, HMM_BO_USER.
  *
  * userptr is only valid when type is HMM_BO_USER, it indicates
  * the start address from user space task.
- *
- * from_highmem and userptr will both be ignored when type is
- * HMM_BO_SHARE.
  */
 int hmm_bo_alloc_pages(struct hmm_buffer_object *bo,
-                      enum hmm_bo_type type, int from_highmem,
-                      const void __user *userptr, bool cached)
+                      enum hmm_bo_type type,
+                      const void __user *userptr)
 {
        int ret = -EINVAL;
 
@@ -988,15 +854,20 @@ int hmm_bo_alloc_pages(struct hmm_buffer_object *bo,
        mutex_lock(&bo->mutex);
        check_bo_status_no_goto(bo, HMM_BO_PAGE_ALLOCED, status_err);
 
+       bo->pages = kmalloc_array(bo->pgnr, sizeof(struct page *), GFP_KERNEL);
+       if (unlikely(!bo->pages)) {
+               ret = -ENOMEM;
+               goto alloc_err;
+       }
+
        /*
         * TO DO:
         * add HMM_BO_USER type
         */
        if (type == HMM_BO_PRIVATE) {
-               ret = alloc_private_pages(bo, from_highmem,
-                                         cached, &dynamic_pool, &reserved_pool);
+               ret = alloc_private_pages(bo);
        } else if (type == HMM_BO_USER) {
-               ret = alloc_user_pages(bo, userptr, cached);
+               ret = alloc_user_pages(bo, userptr);
        } else {
                dev_err(atomisp_dev, "invalid buffer type.\n");
                ret = -EINVAL;
@@ -1013,6 +884,7 @@ int hmm_bo_alloc_pages(struct hmm_buffer_object *bo,
        return 0;
 
 alloc_err:
+       kfree(bo->pages);
        mutex_unlock(&bo->mutex);
        dev_err(atomisp_dev, "alloc pages err...\n");
        return ret;
@@ -1038,11 +910,13 @@ void hmm_bo_free_pages(struct hmm_buffer_object *bo)
        bo->status &= (~HMM_BO_PAGE_ALLOCED);
 
        if (bo->type == HMM_BO_PRIVATE)
-               free_private_pages(bo, &dynamic_pool, &reserved_pool);
+               free_private_bo_pages(bo, bo->pgnr);
        else if (bo->type == HMM_BO_USER)
                free_user_pages(bo, bo->pgnr);
        else
                dev_err(atomisp_dev, "invalid buffer type.\n");
+
+       kfree(bo->pages);
        mutex_unlock(&bo->mutex);
 
        return;
@@ -1060,32 +934,6 @@ int hmm_bo_page_allocated(struct hmm_buffer_object *bo)
        return bo->status & HMM_BO_PAGE_ALLOCED;
 }
 
-/*
- * get physical page info of the bo.
- */
-int hmm_bo_get_page_info(struct hmm_buffer_object *bo,
-                        struct hmm_page_object **page_obj, int *pgnr)
-{
-       check_bo_null_return(bo, -EINVAL);
-
-       mutex_lock(&bo->mutex);
-
-       check_bo_status_yes_goto(bo, HMM_BO_PAGE_ALLOCED, status_err);
-
-       *page_obj = bo->page_obj;
-       *pgnr = bo->pgnr;
-
-       mutex_unlock(&bo->mutex);
-
-       return 0;
-
-status_err:
-       dev_err(atomisp_dev,
-               "buffer object not page allocated yet.\n");
-       mutex_unlock(&bo->mutex);
-       return -EINVAL;
-}
-
 /*
  * bind the physical pages to a virtual address space.
  */
@@ -1113,7 +961,7 @@ int hmm_bo_bind(struct hmm_buffer_object *bo)
        for (i = 0; i < bo->pgnr; i++) {
                ret =
                    isp_mmu_map(&bdev->mmu, virt,
-                               page_to_phys(bo->page_obj[i].page), 1);
+                               page_to_phys(bo->pages[i]), 1);
                if (ret)
                        goto map_err;
                virt += (1 << PAGE_SHIFT);
@@ -1227,9 +1075,6 @@ int hmm_bo_binded(struct hmm_buffer_object *bo)
 
 void *hmm_bo_vmap(struct hmm_buffer_object *bo, bool cached)
 {
-       struct page **pages;
-       int i;
-
        check_bo_null_return(bo, NULL);
 
        mutex_lock(&bo->mutex);
@@ -1246,27 +1091,15 @@ void *hmm_bo_vmap(struct hmm_buffer_object *bo, bool cached)
                bo->status &= ~(HMM_BO_VMAPED | HMM_BO_VMAPED_CACHED);
        }
 
-       pages = kmalloc_array(bo->pgnr, sizeof(*pages), GFP_KERNEL);
-       if (unlikely(!pages)) {
-               mutex_unlock(&bo->mutex);
-               return NULL;
-       }
-
-       for (i = 0; i < bo->pgnr; i++)
-               pages[i] = bo->page_obj[i].page;
-
-       bo->vmap_addr = vmap(pages, bo->pgnr, VM_MAP,
+       bo->vmap_addr = vmap(bo->pages, bo->pgnr, VM_MAP,
                             cached ? PAGE_KERNEL : PAGE_KERNEL_NOCACHE);
        if (unlikely(!bo->vmap_addr)) {
-               kfree(pages);
                mutex_unlock(&bo->mutex);
                dev_err(atomisp_dev, "vmap failed...\n");
                return NULL;
        }
        bo->status |= (cached ? HMM_BO_VMAPED_CACHED : HMM_BO_VMAPED);
 
-       kfree(pages);
-
        mutex_unlock(&bo->mutex);
        return bo->vmap_addr;
 }
@@ -1396,7 +1229,7 @@ int hmm_bo_mmap(struct vm_area_struct *vma, struct hmm_buffer_object *bo)
 
        virt = vma->vm_start;
        for (i = 0; i < pgnr; i++) {
-               pfn = page_to_pfn(bo->page_obj[i].page);
+               pfn = page_to_pfn(bo->pages[i]);
                if (remap_pfn_range(vma, virt, pfn, PAGE_SIZE, PAGE_SHARED)) {
                        dev_warn(atomisp_dev,
                                 "remap_pfn_range failed: virt = 0x%x, pfn = 0x%x, mapped_pgnr = %d\n",
diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_dynamic_pool.c b/drivers/staging/media/atomisp/pci/hmm/hmm_dynamic_pool.c
deleted file mode 100644 (file)
index eaf97e5..0000000
+++ /dev/null
@@ -1,234 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Support for Medifield PNW Camera Imaging ISP subsystem.
- *
- * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
- *
- * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed 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.
- *
- *
- */
-/*
- * This file contains functions for dynamic memory pool management
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-
-#include <asm/set_memory.h>
-
-#include "atomisp_internal.h"
-
-#include "hmm/hmm_pool.h"
-
-/*
- * dynamic memory pool ops.
- */
-static unsigned int get_pages_from_dynamic_pool(void *pool,
-       struct hmm_page_object *page_obj,
-       unsigned int size, bool cached)
-{
-       struct hmm_page *hmm_page;
-       unsigned long flags;
-       unsigned int i = 0;
-       struct hmm_dynamic_pool_info *dypool_info = pool;
-
-       if (!dypool_info)
-               return 0;
-
-       spin_lock_irqsave(&dypool_info->list_lock, flags);
-       if (dypool_info->initialized) {
-               while (!list_empty(&dypool_info->pages_list)) {
-                       hmm_page = list_entry(dypool_info->pages_list.next,
-                                             struct hmm_page, list);
-
-                       list_del(&hmm_page->list);
-                       dypool_info->pgnr--;
-                       spin_unlock_irqrestore(&dypool_info->list_lock, flags);
-
-                       page_obj[i].page = hmm_page->page;
-                       page_obj[i++].type = HMM_PAGE_TYPE_DYNAMIC;
-                       kmem_cache_free(dypool_info->pgptr_cache, hmm_page);
-
-                       if (i == size)
-                               return i;
-
-                       spin_lock_irqsave(&dypool_info->list_lock, flags);
-               }
-       }
-       spin_unlock_irqrestore(&dypool_info->list_lock, flags);
-
-       return i;
-}
-
-static void free_pages_to_dynamic_pool(void *pool,
-                                      struct hmm_page_object *page_obj)
-{
-       struct hmm_page *hmm_page;
-       unsigned long flags;
-       int ret;
-       struct hmm_dynamic_pool_info *dypool_info = pool;
-
-       if (!dypool_info)
-               return;
-
-       spin_lock_irqsave(&dypool_info->list_lock, flags);
-       if (!dypool_info->initialized) {
-               spin_unlock_irqrestore(&dypool_info->list_lock, flags);
-               return;
-       }
-       spin_unlock_irqrestore(&dypool_info->list_lock, flags);
-
-       if (page_obj->type == HMM_PAGE_TYPE_RESERVED)
-               return;
-
-       if (dypool_info->pgnr >= dypool_info->pool_size) {
-               /* free page directly back to system */
-               ret = set_pages_wb(page_obj->page, 1);
-               if (ret)
-                       dev_err(atomisp_dev,
-                               "set page to WB err ...ret=%d\n", ret);
-               /*
-               W/A: set_pages_wb seldom return value = -EFAULT
-               indicate that address of page is not in valid
-               range(0xffff880000000000~0xffffc7ffffffffff)
-               then, _free_pages would panic; Do not know why page
-               address be valid, it maybe memory corruption by lowmemory
-               */
-               if (!ret) {
-                       __free_pages(page_obj->page, 0);
-                       hmm_mem_stat.sys_size--;
-               }
-               return;
-       }
-       hmm_page = kmem_cache_zalloc(dypool_info->pgptr_cache,
-                                    GFP_KERNEL);
-       if (!hmm_page) {
-               /* free page directly */
-               ret = set_pages_wb(page_obj->page, 1);
-               if (ret)
-                       dev_err(atomisp_dev,
-                               "set page to WB err ...ret=%d\n", ret);
-               if (!ret) {
-                       __free_pages(page_obj->page, 0);
-                       hmm_mem_stat.sys_size--;
-               }
-               return;
-       }
-
-       hmm_page->page = page_obj->page;
-
-       /*
-        * add to pages_list of pages_pool
-        */
-       spin_lock_irqsave(&dypool_info->list_lock, flags);
-       list_add_tail(&hmm_page->list, &dypool_info->pages_list);
-       dypool_info->pgnr++;
-       spin_unlock_irqrestore(&dypool_info->list_lock, flags);
-       hmm_mem_stat.dyc_size++;
-}
-
-static int hmm_dynamic_pool_init(void **pool, unsigned int pool_size)
-{
-       struct hmm_dynamic_pool_info *dypool_info;
-
-       if (pool_size == 0)
-               return 0;
-
-       dypool_info = kmalloc(sizeof(struct hmm_dynamic_pool_info),
-                             GFP_KERNEL);
-       if (unlikely(!dypool_info))
-               return -ENOMEM;
-
-       dypool_info->pgptr_cache = kmem_cache_create("pgptr_cache",
-                                  sizeof(struct hmm_page), 0,
-                                  SLAB_HWCACHE_ALIGN, NULL);
-       if (!dypool_info->pgptr_cache) {
-               kfree(dypool_info);
-               return -ENOMEM;
-       }
-
-       INIT_LIST_HEAD(&dypool_info->pages_list);
-       spin_lock_init(&dypool_info->list_lock);
-       dypool_info->initialized = true;
-       dypool_info->pool_size = pool_size;
-       dypool_info->pgnr = 0;
-
-       *pool = dypool_info;
-
-       return 0;
-}
-
-static void hmm_dynamic_pool_exit(void **pool)
-{
-       struct hmm_dynamic_pool_info *dypool_info = *pool;
-       struct hmm_page *hmm_page;
-       unsigned long flags;
-       int ret;
-
-       if (!dypool_info)
-               return;
-
-       spin_lock_irqsave(&dypool_info->list_lock, flags);
-       if (!dypool_info->initialized) {
-               spin_unlock_irqrestore(&dypool_info->list_lock, flags);
-               return;
-       }
-       dypool_info->initialized = false;
-
-       while (!list_empty(&dypool_info->pages_list)) {
-               hmm_page = list_entry(dypool_info->pages_list.next,
-                                     struct hmm_page, list);
-
-               list_del(&hmm_page->list);
-               spin_unlock_irqrestore(&dypool_info->list_lock, flags);
-
-               /* can cause thread sleep, so cannot be put into spin_lock */
-               ret = set_pages_wb(hmm_page->page, 1);
-               if (ret)
-                       dev_err(atomisp_dev,
-                               "set page to WB err...ret=%d\n", ret);
-               if (!ret) {
-                       __free_pages(hmm_page->page, 0);
-                       hmm_mem_stat.dyc_size--;
-                       hmm_mem_stat.sys_size--;
-               }
-               kmem_cache_free(dypool_info->pgptr_cache, hmm_page);
-               spin_lock_irqsave(&dypool_info->list_lock, flags);
-       }
-
-       spin_unlock_irqrestore(&dypool_info->list_lock, flags);
-
-       kmem_cache_destroy(dypool_info->pgptr_cache);
-
-       kfree(dypool_info);
-
-       *pool = NULL;
-}
-
-static int hmm_dynamic_pool_inited(void *pool)
-{
-       struct hmm_dynamic_pool_info *dypool_info = pool;
-
-       if (!dypool_info)
-               return 0;
-
-       return dypool_info->initialized;
-}
-
-struct hmm_pool_ops dynamic_pops = {
-       .pool_init              = hmm_dynamic_pool_init,
-       .pool_exit              = hmm_dynamic_pool_exit,
-       .pool_alloc_pages       = get_pages_from_dynamic_pool,
-       .pool_free_pages        = free_pages_to_dynamic_pool,
-       .pool_inited            = hmm_dynamic_pool_inited,
-};
diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_reserved_pool.c b/drivers/staging/media/atomisp/pci/hmm/hmm_reserved_pool.c
deleted file mode 100644 (file)
index 57525fe..0000000
+++ /dev/null
@@ -1,253 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0
-/*
- * Support for Medifield PNW Camera Imaging ISP subsystem.
- *
- * Copyright (c) 2010 Intel Corporation. All Rights Reserved.
- *
- * Copyright (c) 2010 Silicon Hive www.siliconhive.com.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License version
- * 2 as published by the Free Software Foundation.
- *
- * This program is distributed 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.
- *
- *
- */
-/*
- * This file contains functions for reserved memory pool management
- */
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/mm.h>
-
-#include <asm/set_memory.h>
-
-#include "atomisp_internal.h"
-#include "hmm/hmm_pool.h"
-
-/*
- * reserved memory pool ops.
- */
-static unsigned int get_pages_from_reserved_pool(void *pool,
-       struct hmm_page_object *page_obj,
-       unsigned int size, bool cached)
-{
-       unsigned long flags;
-       unsigned int i = 0;
-       unsigned int repool_pgnr;
-       int j;
-       struct hmm_reserved_pool_info *repool_info = pool;
-
-       if (!repool_info)
-               return 0;
-
-       spin_lock_irqsave(&repool_info->list_lock, flags);
-       if (repool_info->initialized) {
-               repool_pgnr = repool_info->index;
-
-               for (j = repool_pgnr - 1; j >= 0; j--) {
-                       page_obj[i].page = repool_info->pages[j];
-                       page_obj[i].type = HMM_PAGE_TYPE_RESERVED;
-                       i++;
-                       repool_info->index--;
-                       if (i == size)
-                               break;
-               }
-       }
-       spin_unlock_irqrestore(&repool_info->list_lock, flags);
-       return i;
-}
-
-static void free_pages_to_reserved_pool(void *pool,
-                                       struct hmm_page_object *page_obj)
-{
-       unsigned long flags;
-       struct hmm_reserved_pool_info *repool_info = pool;
-
-       if (!repool_info)
-               return;
-
-       spin_lock_irqsave(&repool_info->list_lock, flags);
-
-       if (repool_info->initialized &&
-           repool_info->index < repool_info->pgnr &&
-           page_obj->type == HMM_PAGE_TYPE_RESERVED) {
-               repool_info->pages[repool_info->index++] = page_obj->page;
-       }
-
-       spin_unlock_irqrestore(&repool_info->list_lock, flags);
-}
-
-static int hmm_reserved_pool_setup(struct hmm_reserved_pool_info **repool_info,
-                                  unsigned int pool_size)
-{
-       struct hmm_reserved_pool_info *pool_info;
-
-       pool_info = kmalloc(sizeof(struct hmm_reserved_pool_info),
-                           GFP_KERNEL);
-       if (unlikely(!pool_info))
-               return -ENOMEM;
-
-       pool_info->pages = kmalloc(sizeof(struct page *) * pool_size,
-                                  GFP_KERNEL);
-       if (unlikely(!pool_info->pages)) {
-               kfree(pool_info);
-               return -ENOMEM;
-       }
-
-       pool_info->index = 0;
-       pool_info->pgnr = 0;
-       spin_lock_init(&pool_info->list_lock);
-       pool_info->initialized = true;
-
-       *repool_info = pool_info;
-
-       return 0;
-}
-
-static int hmm_reserved_pool_init(void **pool, unsigned int pool_size)
-{
-       int ret;
-       unsigned int blk_pgnr;
-       unsigned int pgnr = pool_size;
-       unsigned int order = 0;
-       unsigned int i = 0;
-       int fail_number = 0;
-       struct page *pages;
-       int j;
-       struct hmm_reserved_pool_info *repool_info;
-
-       if (pool_size == 0)
-               return 0;
-
-       ret = hmm_reserved_pool_setup(&repool_info, pool_size);
-       if (ret) {
-               dev_err(atomisp_dev, "hmm_reserved_pool_setup failed.\n");
-               return ret;
-       }
-
-       pgnr = pool_size;
-
-       i = 0;
-       order = MAX_ORDER;
-
-       while (pgnr) {
-               blk_pgnr = 1U << order;
-               while (blk_pgnr > pgnr) {
-                       order--;
-                       blk_pgnr >>= 1U;
-               }
-               BUG_ON(order > MAX_ORDER);
-
-               pages = alloc_pages(GFP_KERNEL | __GFP_NOWARN, order);
-               if (unlikely(!pages)) {
-                       if (order == 0) {
-                               fail_number++;
-                               dev_err(atomisp_dev, "%s: alloc_pages failed: %d\n",
-                                       __func__, fail_number);
-                               /* if fail five times, will goto end */
-
-                               /* FIXME: whether is the mechanism is ok? */
-                               if (fail_number == ALLOC_PAGE_FAIL_NUM)
-                                       goto end;
-                       } else {
-                               order--;
-                       }
-               } else {
-                       blk_pgnr = 1U << order;
-
-                       ret = set_pages_uc(pages, blk_pgnr);
-                       if (ret) {
-                               dev_err(atomisp_dev,
-                                       "set pages uncached failed\n");
-                               __free_pages(pages, order);
-                               goto end;
-                       }
-
-                       for (j = 0; j < blk_pgnr; j++)
-                               repool_info->pages[i++] = pages + j;
-
-                       repool_info->index += blk_pgnr;
-                       repool_info->pgnr += blk_pgnr;
-
-                       pgnr -= blk_pgnr;
-
-                       fail_number = 0;
-               }
-       }
-
-end:
-       repool_info->initialized = true;
-
-       *pool = repool_info;
-
-       dev_info(atomisp_dev,
-                "hmm_reserved_pool init successfully,hmm_reserved_pool is with %d pages.\n",
-                repool_info->pgnr);
-       return 0;
-}
-
-static void hmm_reserved_pool_exit(void **pool)
-{
-       unsigned long flags;
-       int i, ret;
-       unsigned int pgnr;
-       struct hmm_reserved_pool_info *repool_info = *pool;
-
-       if (!repool_info)
-               return;
-
-       spin_lock_irqsave(&repool_info->list_lock, flags);
-       if (!repool_info->initialized) {
-               spin_unlock_irqrestore(&repool_info->list_lock, flags);
-               return;
-       }
-       pgnr = repool_info->pgnr;
-       repool_info->index = 0;
-       repool_info->pgnr = 0;
-       repool_info->initialized = false;
-       spin_unlock_irqrestore(&repool_info->list_lock, flags);
-
-       for (i = 0; i < pgnr; i++) {
-               ret = set_pages_wb(repool_info->pages[i], 1);
-               if (ret)
-                       dev_err(atomisp_dev,
-                               "set page to WB err...ret=%d\n", ret);
-               /*
-               W/A: set_pages_wb seldom return value = -EFAULT
-               indicate that address of page is not in valid
-               range(0xffff880000000000~0xffffc7ffffffffff)
-               then, _free_pages would panic; Do not know why
-               page address be valid, it maybe memory corruption by lowmemory
-               */
-               if (!ret)
-                       __free_pages(repool_info->pages[i], 0);
-       }
-
-       kfree(repool_info->pages);
-       kfree(repool_info);
-
-       *pool = NULL;
-}
-
-static int hmm_reserved_pool_inited(void *pool)
-{
-       struct hmm_reserved_pool_info *repool_info = pool;
-
-       if (!repool_info)
-               return 0;
-
-       return repool_info->initialized;
-}
-
-struct hmm_pool_ops reserved_pops = {
-       .pool_init              = hmm_reserved_pool_init,
-       .pool_exit              = hmm_reserved_pool_exit,
-       .pool_alloc_pages       = get_pages_from_reserved_pool,
-       .pool_free_pages        = free_pages_to_reserved_pool,
-       .pool_inited            = hmm_reserved_pool_inited,
-};
index 96c86f0..514d933 100644 (file)
@@ -169,7 +169,6 @@ struct ia_css_frame {
        /** exposure id, see ia_css_event_public.h for more detail */
        u32 isp_config_id; /** Unique ID to track which config was actually applied to a particular frame */
        bool valid; /** First video output frame is not valid */
-       bool contiguous; /** memory is allocated physically contiguously */
        union {
                unsigned int    _initialisation_dummy;
                struct ia_css_frame_plane raw;
@@ -245,44 +244,6 @@ ia_css_frame_allocate_from_info(struct ia_css_frame **frame,
 void
 ia_css_frame_free(struct ia_css_frame *frame);
 
-/* @brief Allocate a contiguous CSS frame structure
- *
- * @param      frame           The allocated frame.
- * @param      width           The width (in pixels) of the frame.
- * @param      height          The height (in lines) of the frame.
- * @param      format          The frame format.
- * @param      stride          The padded stride, in pixels.
- * @param      raw_bit_depth   The raw bit depth, in bits.
- * @return                     The error code.
- *
- * Contiguous frame allocation, only for FPGA display driver which needs
- * physically contiguous memory.
- * Deprecated.
- */
-int
-ia_css_frame_allocate_contiguous(struct ia_css_frame **frame,
-                                unsigned int width,
-                                unsigned int height,
-                                enum ia_css_frame_format format,
-                                unsigned int stride,
-                                unsigned int raw_bit_depth);
-
-/* @brief Allocate a contiguous CSS frame from a frame info structure.
- *
- * @param      frame   The allocated frame.
- * @param[in]  info    The frame info structure.
- * @return             The error code.
- *
- * Allocate a frame using the resolution and format from a frame info struct.
- * This is a convenience function, implemented on top of
- * ia_css_frame_allocate_contiguous().
- * Only for FPGA display driver which needs physically contiguous memory.
- * Deprecated.
- */
-int
-ia_css_frame_allocate_contiguous_from_info(struct ia_css_frame **frame,
-       const struct ia_css_frame_info *info);
-
 /* @brief Allocate a CSS frame structure using a frame info structure.
  *
  * @param      frame   The allocated frame.
@@ -334,7 +295,6 @@ int
 ia_css_frame_map(struct ia_css_frame **frame,
                 const struct ia_css_frame_info *info,
                 const void __user *data,
-                u16 attribute,
                 unsigned int pgnr);
 
 /* @brief Unmap a CSS frame structure.
index 13caa55..bf0a768 100644 (file)
@@ -331,7 +331,7 @@ ia_css_isp_dvs_statistics_allocate(
                            HIVE_ISP_DDR_WORD_BYTES);
 
        me->size = hor_size + ver_size;
-       me->data_ptr = hmm_alloc(me->size, HMM_BO_PRIVATE, 0, NULL, 0);
+       me->data_ptr = hmm_alloc(me->size);
        if (me->data_ptr == mmgr_NULL)
                goto err;
        me->hor_size = hor_size;
index f608740..c13de28 100644 (file)
@@ -294,7 +294,7 @@ ia_css_isp_dvs2_statistics_allocate(
               * grid->aligned_height * IA_CSS_DVS2_NUM_COEF_TYPES;
 
        me->size = 2 * size;
-       me->data_ptr = hmm_alloc(me->size, HMM_BO_PRIVATE, 0, NULL, 0);
+       me->data_ptr = hmm_alloc(me->size);
        if (me->data_ptr == mmgr_NULL)
                goto err;
        me->hor_proj = me->data_ptr;
index bfe4f59..73432dc 100644 (file)
@@ -145,12 +145,6 @@ more details.
 
 #define RAW_BUF_LINES ((ENABLE_RAW_BINNING || ENABLE_FIXED_BAYER_DS) ? 4 : 2)
 
-#define RAW_BUF_STRIDE \
-       (BINARY_ID == SH_CSS_BINARY_ID_POST_ISP ? MAX_VECTORS_PER_INPUT_CHUNK : \
-        ISP_NUM_STRIPES > 1 ? MAX_VECTORS_PER_INPUT_STRIPE + _ISP_EXTRA_PADDING_VECS : \
-        !ENABLE_CONTINUOUS ? MAX_VECTORS_PER_INPUT_LINE : \
-        MAX_VECTORS_PER_INPUT_CHUNK)
-
 /* [isp vmem] table size[vectors] per line per color (GR,R,B,GB),
    multiples of NWAY */
 #define ISP2400_SCTBL_VECTORS_PER_LINE_PER_COLOR \
index f462387..3d269bd 100644 (file)
@@ -1305,8 +1305,6 @@ void ia_css_debug_frame_print(const struct ia_css_frame *frame,
        ia_css_debug_dtrace(2, "  padded width  = %d\n",
                            frame->info.padded_width);
        ia_css_debug_dtrace(2, "  format        = %d\n", frame->info.format);
-       ia_css_debug_dtrace(2, "  is contiguous = %s\n",
-                           frame->contiguous ? "yes" : "no");
        switch (frame->info.format) {
        case IA_CSS_FRAME_FORMAT_NV12:
        case IA_CSS_FRAME_FORMAT_NV16:
index c756a13..700070c 100644 (file)
@@ -109,16 +109,13 @@ void ia_css_frame_free_multiple(unsigned int num_frames,
  *
  * @param      frame   The allocated frame.
  * @param[in]  size_bytes      The frame size in bytes.
- * @param[in]  contiguous      Allocate memory physically contiguously or not.
  * @return     The error code.
  *
  * Allocate a frame using the given size in bytes.
  * The frame structure is partially null initialized.
  */
-int ia_css_frame_allocate_with_buffer_size(
-    struct ia_css_frame **frame,
-    const unsigned int size_bytes,
-    const bool contiguous);
+int ia_css_frame_allocate_with_buffer_size(struct ia_css_frame **frame,
+                                          const unsigned int size_bytes);
 
 /* @brief Check whether 2 frames are same type
  *
index a3aae63..5a70583 100644 (file)
@@ -48,12 +48,6 @@ static void frame_init_raw_single_plane(
     unsigned int subpixels_per_line,
     unsigned int bits_per_pixel);
 
-static void frame_init_mipi_plane(struct ia_css_frame *frame,
-                                 struct ia_css_frame_plane *plane,
-                                 unsigned int height,
-                                 unsigned int subpixels_per_line,
-                                 unsigned int bytes_per_pixel);
-
 static void frame_init_nv_planes(struct ia_css_frame *frame,
                                 unsigned int horizontal_decimation,
                                 unsigned int vertical_decimation,
@@ -77,15 +71,13 @@ static int frame_allocate_with_data(struct ia_css_frame **frame,
        unsigned int height,
        enum ia_css_frame_format format,
        unsigned int padded_width,
-       unsigned int raw_bit_depth,
-       bool contiguous);
+       unsigned int raw_bit_depth);
 
 static struct ia_css_frame *frame_create(unsigned int width,
        unsigned int height,
        enum ia_css_frame_format format,
        unsigned int padded_width,
        unsigned int raw_bit_depth,
-       bool contiguous,
        bool valid);
 
 static unsigned
@@ -137,7 +129,7 @@ int ia_css_frame_allocate(struct ia_css_frame **frame,
                            width, height, format, padded_width, raw_bit_depth);
 
        err = frame_allocate_with_data(frame, width, height, format,
-                                      padded_width, raw_bit_depth, false);
+                                      padded_width, raw_bit_depth);
 
        if ((*frame) && err == 0)
                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
@@ -154,7 +146,6 @@ int ia_css_frame_allocate(struct ia_css_frame **frame,
 int ia_css_frame_map(struct ia_css_frame **frame,
                                 const struct ia_css_frame_info *info,
                                 const void __user *data,
-                                u16 attribute,
                                 unsigned int pgnr)
 {
        int err = 0;
@@ -180,9 +171,7 @@ int ia_css_frame_map(struct ia_css_frame **frame,
                goto error;
        }
 
-       me->data = hmm_alloc(me->data_bytes, HMM_BO_USER, 0, data,
-                            attribute & ATOMISP_MAP_FLAG_CACHED);
-
+       me->data = hmm_create_from_userdata(me->data_bytes, data);
        if (me->data == mmgr_NULL)
                err = -EINVAL;
 
@@ -216,7 +205,6 @@ int ia_css_frame_create_from_info(struct ia_css_frame **frame,
                          info->format,
                          info->padded_width,
                          info->raw_bit_depth,
-                         false,
                          false);
        if (!me) {
                ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
@@ -270,49 +258,6 @@ int ia_css_frame_set_data(struct ia_css_frame *frame,
        return err;
 }
 
-int ia_css_frame_allocate_contiguous(struct ia_css_frame **frame,
-       unsigned int width,
-       unsigned int height,
-       enum ia_css_frame_format format,
-       unsigned int padded_width,
-       unsigned int raw_bit_depth)
-{
-       int err = 0;
-
-       ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
-                           "ia_css_frame_allocate_contiguous() enter: width=%d, height=%d, format=%d, padded_width=%d, raw_bit_depth=%d\n",
-                           width, height, format, padded_width, raw_bit_depth);
-
-       err = frame_allocate_with_data(frame, width, height, format,
-                                      padded_width, raw_bit_depth, true);
-
-       ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
-                           "ia_css_frame_allocate_contiguous() leave: frame=%p\n",
-                           frame ? *frame : (void *)-1);
-
-       return err;
-}
-
-int ia_css_frame_allocate_contiguous_from_info(
-    struct ia_css_frame **frame,
-    const struct ia_css_frame_info *info)
-{
-       int err = 0;
-
-       assert(frame);
-       ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
-                           "ia_css_frame_allocate_contiguous_from_info() enter:\n");
-       err = ia_css_frame_allocate_contiguous(frame,
-                                              info->res.width,
-                                              info->res.height,
-                                              info->format,
-                                              info->padded_width,
-                                              info->raw_bit_depth);
-       ia_css_debug_dtrace(IA_CSS_DEBUG_TRACE,
-                           "ia_css_frame_allocate_contiguous_from_info() leave:\n");
-       return err;
-}
-
 void ia_css_frame_free(struct ia_css_frame *frame)
 {
        IA_CSS_ENTER_PRIVATE("frame = %p", frame);
@@ -343,11 +288,9 @@ int ia_css_frame_init_planes(struct ia_css_frame *frame)
 
        switch (frame->info.format) {
        case IA_CSS_FRAME_FORMAT_MIPI:
-               frame_init_mipi_plane(frame, &frame->planes.raw,
-                                     frame->info.res.height,
-                                     frame->info.padded_width,
-                                     frame->info.raw_bit_depth <= 8 ? 1 : 2);
-               break;
+               dev_err(atomisp_dev,
+                       "%s: unexpected use of IA_CSS_FRAME_FORMAT_MIPI\n", __func__);
+               return -EINVAL;
        case IA_CSS_FRAME_FORMAT_RAW_PACKED:
                frame_init_raw_single_plane(frame, &frame->planes.raw,
                                            frame->info.res.height,
@@ -460,10 +403,7 @@ void ia_css_frame_info_set_width(struct ia_css_frame_info *info,
                IA_CSS_LEAVE_PRIVATE("");
                return;
        }
-       if (min_padded_width > width)
-               align = min_padded_width;
-       else
-               align = width;
+       align = max(min_padded_width, width);
 
        info->res.width = width;
        /* frames with a U and V plane of 8 bits per pixel need to have
@@ -529,16 +469,14 @@ void ia_css_frame_free_multiple(unsigned int num_frames,
        }
 }
 
-int ia_css_frame_allocate_with_buffer_size(
-    struct ia_css_frame **frame,
-    const unsigned int buffer_size_bytes,
-    const bool contiguous)
+int ia_css_frame_allocate_with_buffer_size(struct ia_css_frame **frame,
+                                          const unsigned int buffer_size_bytes)
 {
        /* AM: Body coppied from frame_allocate_with_data(). */
        int err;
        struct ia_css_frame *me = frame_create(0, 0,
                                               IA_CSS_FRAME_FORMAT_NUM,/* Not valid format yet */
-                                              0, 0, contiguous, false);
+                                              0, 0, false);
 
        if (!me)
                return -ENOMEM;
@@ -670,22 +608,6 @@ static void frame_init_raw_single_plane(
        return;
 }
 
-static void frame_init_mipi_plane(struct ia_css_frame *frame,
-                                 struct ia_css_frame_plane *plane,
-                                 unsigned int height,
-                                 unsigned int subpixels_per_line,
-                                 unsigned int bytes_per_pixel)
-{
-       unsigned int stride;
-
-       stride = subpixels_per_line * bytes_per_pixel;
-       frame->data_bytes = 8388608; /* 8*1024*1024 */
-       frame->valid = false;
-       frame->contiguous = true;
-       frame_init_plane(plane, subpixels_per_line, stride, height, 0);
-       return;
-}
-
 static void frame_init_nv_planes(struct ia_css_frame *frame,
                                 unsigned int horizontal_decimation,
                                 unsigned int vertical_decimation,
@@ -803,11 +725,7 @@ static int frame_allocate_buffer_data(struct ia_css_frame *frame)
 #ifdef ISP2401
        IA_CSS_ENTER_LEAVE_PRIVATE("frame->data_bytes=%d\n", frame->data_bytes);
 #endif
-       frame->data = hmm_alloc(frame->data_bytes,
-                               HMM_BO_PRIVATE, 0, NULL,
-                               frame->contiguous ?
-                               ATOMISP_MAP_FLAG_CONTIGUOUS : 0);
-
+       frame->data = hmm_alloc(frame->data_bytes);
        if (frame->data == mmgr_NULL)
                return -ENOMEM;
        return 0;
@@ -818,8 +736,7 @@ static int frame_allocate_with_data(struct ia_css_frame **frame,
        unsigned int height,
        enum ia_css_frame_format format,
        unsigned int padded_width,
-       unsigned int raw_bit_depth,
-       bool contiguous)
+       unsigned int raw_bit_depth)
 {
        int err;
        struct ia_css_frame *me = frame_create(width,
@@ -827,7 +744,6 @@ static int frame_allocate_with_data(struct ia_css_frame **frame,
                                               format,
                                               padded_width,
                                               raw_bit_depth,
-                                              contiguous,
                                               true);
 
        if (!me)
@@ -857,7 +773,6 @@ static struct ia_css_frame *frame_create(unsigned int width,
        enum ia_css_frame_format format,
        unsigned int padded_width,
        unsigned int raw_bit_depth,
-       bool contiguous,
        bool valid)
 {
        struct ia_css_frame *me = kvmalloc(sizeof(*me), GFP_KERNEL);
@@ -871,7 +786,6 @@ static struct ia_css_frame *frame_create(unsigned int width,
        me->info.format = format;
        me->info.padded_width = padded_width;
        me->info.raw_bit_depth = raw_bit_depth;
-       me->contiguous = contiguous;
        me->valid = valid;
        me->data_bytes = 0;
        me->data = mmgr_NULL;
index 823ec54..99c2f3a 100644 (file)
@@ -131,7 +131,7 @@ ia_css_isp_param_allocate_isp_parameters(
                                        goto cleanup;
                                }
                                if (pclass != IA_CSS_PARAM_CLASS_PARAM) {
-                                       css_params->params[pclass][mem].address = hmm_alloc(size, HMM_BO_PRIVATE, 0, NULL, 0);
+                                       css_params->params[pclass][mem].address = hmm_alloc(size);
                                        if (!css_params->params[pclass][mem].address) {
                                                err = -ENOMEM;
                                                goto cleanup;
index 3960475..2e07dab 100644 (file)
@@ -254,14 +254,15 @@ void rmgr_pop_handle(struct ia_css_rmgr_vbuf_pool *pool,
 void ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool *pool,
                          struct ia_css_rmgr_vbuf_handle **handle)
 {
-       struct ia_css_rmgr_vbuf_handle h = { 0 };
-
        if ((!pool) || (!handle) || (!*handle)) {
                IA_CSS_LOG("Invalid inputs");
                return;
        }
 
        if (pool->copy_on_write) {
+               struct ia_css_rmgr_vbuf_handle *new_handle;
+               struct ia_css_rmgr_vbuf_handle h = { 0 };
+
                /* only one reference, reuse (no new retain) */
                if ((*handle)->count == 1)
                        return;
@@ -272,23 +273,29 @@ void ia_css_rmgr_acq_vbuf(struct ia_css_rmgr_vbuf_pool *pool,
                        h.size = (*handle)->size;
                        /* release ref to current buffer */
                        ia_css_rmgr_refcount_release_vbuf(handle);
-                       **handle = h;
+                       new_handle = &h;
+               } else {
+                       new_handle = *handle;
                }
                /* get new buffer for needed size */
-               if ((*handle)->vptr == 0x0) {
+               if (new_handle->vptr == 0x0) {
                        if (pool->recycle) {
                                /* try and pop from pool */
-                               rmgr_pop_handle(pool, handle);
+                               rmgr_pop_handle(pool, &new_handle);
                        }
-                       if ((*handle)->vptr == 0x0) {
+                       if (new_handle->vptr == 0x0) {
                                /* we need to allocate */
-                               (*handle)->vptr = hmm_alloc((*handle)->size,
-                                                            HMM_BO_PRIVATE, 0, NULL, 0);
+                               new_handle->vptr = hmm_alloc(new_handle->size);
                        } else {
                                /* we popped a buffer */
+                               *handle = new_handle;
                                return;
                        }
                }
+               /* Note that new_handle will change to an internally maintained one */
+               ia_css_rmgr_refcount_retain_vbuf(&new_handle);
+               *handle = new_handle;
+               return;
        }
        /* Note that handle will change to an internally maintained one */
        ia_css_rmgr_refcount_retain_vbuf(handle);
index 7f45925..c34bfc5 100644 (file)
@@ -64,7 +64,7 @@ int ia_css_spctrl_load_fw(sp_ID_t sp_id, ia_css_spctrl_cfg *spctrl_cfg)
         * Data used to be stored separately, because of access alignment constraints,
         * fix the FW generation instead
         */
-       code_addr = hmm_alloc(spctrl_cfg->code_size, HMM_BO_PRIVATE, 0, NULL, 0);
+       code_addr = hmm_alloc(spctrl_cfg->code_size);
        if (code_addr == mmgr_NULL)
                return -ENOMEM;
        hmm_store(code_addr, spctrl_cfg->code, spctrl_cfg->code_size);
index 1d605e5..da96aaf 100644 (file)
@@ -3061,7 +3061,6 @@ init_vf_frameinfo_defaults(struct ia_css_pipe *pipe,
        assert(vf_frame);
 
        sh_css_pipe_get_viewfinder_frame_info(pipe, &vf_frame->info, idx);
-       vf_frame->contiguous = false;
        vf_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_VF_OUTPUT_FRAME + idx, thread_id, &queue_id);
@@ -3243,7 +3242,6 @@ init_in_frameinfo_memory_defaults(struct ia_css_pipe *pipe,
        in_frame->info.raw_bit_depth =
        ia_css_pipe_util_pipe_input_format_bpp(pipe);
        ia_css_frame_info_set_width(&in_frame->info, pipe->stream->config.input_config.input_res.width, 0);
-       in_frame->contiguous = false;
        in_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_INPUT_FRAME, thread_id, &queue_id);
@@ -3271,7 +3269,6 @@ init_out_frameinfo_defaults(struct ia_css_pipe *pipe,
        assert(out_frame);
 
        sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, idx);
-       out_frame->contiguous = false;
        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME + idx, thread_id, &queue_id);
@@ -3510,8 +3507,7 @@ create_host_acc_pipeline(struct ia_css_pipe *pipe)
        if (pipe->config.acc_extension)
                pipe->pipeline.pipe_qos_config = 0;
 
-       fw = pipe->vf_stage;
-       for (i = 0; fw; fw = fw->next) {
+       for (fw = pipe->vf_stage; fw; fw = fw->next) {
                err = sh_css_pipeline_add_acc_stage(&pipe->pipeline, fw);
                if (err)
                        goto ERR;
@@ -7158,7 +7154,6 @@ create_host_copy_pipeline(struct ia_css_pipe *pipe,
        ia_css_pipeline_clean(me);
 
        /* Construct out_frame info */
-       out_frame->contiguous = false;
        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
 
        if (copy_on_sp(pipe) &&
@@ -7208,7 +7203,6 @@ create_host_isyscopy_capture_pipeline(struct ia_css_pipe *pipe)
        err = sh_css_pipe_get_output_frame_info(pipe, &out_frame->info, 0);
        if (err)
                return err;
-       out_frame->contiguous = false;
        out_frame->flash_state = IA_CSS_FRAME_FLASH_STATE_NONE;
        ia_css_pipeline_get_sp_thread_id(ia_css_pipe_get_pipe_num(pipe), &thread_id);
        ia_css_query_internal_queue_id(IA_CSS_BUFFER_TYPE_OUTPUT_FRAME, thread_id, &queue_id);
index dd688f8..e7ef578 100644 (file)
@@ -369,7 +369,7 @@ void sh_css_unload_firmware(void)
 ia_css_ptr
 sh_css_load_blob(const unsigned char *blob, unsigned int size)
 {
-       ia_css_ptr target_addr = hmm_alloc(size, HMM_BO_PRIVATE, 0, NULL, 0);
+       ia_css_ptr target_addr = hmm_alloc(size);
        /*
         * this will allocate memory aligned to a DDR word boundary which
         * is required for the CSS DMA to read the instructions.
index 0acf754..bc6e859 100644 (file)
@@ -431,8 +431,7 @@ allocate_mipi_frames(struct ia_css_pipe *pipe,
                                /* allocate new frame */
                                err = ia_css_frame_allocate_with_buffer_size(
                                          &my_css.mipi_frames[port][i],
-                                         my_css.mipi_frame_size[port] * HIVE_ISP_DDR_WORD_BYTES,
-                                         false);
+                                         my_css.mipi_frame_size[port] * HIVE_ISP_DDR_WORD_BYTES);
                                if (err) {
                                        for (j = 0; j < i; j++) {
                                                if (my_css.mipi_frames[port][j]) {
index 09f87c2..0e7c38b 100644 (file)
@@ -2072,8 +2072,7 @@ static bool realloc_isp_css_mm_buf(
     size_t *curr_size,
     size_t needed_size,
     bool force,
-    int *err,
-    uint16_t mmgr_attribute)
+    int *err)
 {
        s32 id;
 
@@ -2095,11 +2094,7 @@ static bool realloc_isp_css_mm_buf(
 
        id = IA_CSS_REFCOUNT_PARAM_BUFFER;
        ia_css_refcount_decrement(id, *curr_buf);
-       *curr_buf = ia_css_refcount_increment(id, hmm_alloc(needed_size,
-                                                           HMM_BO_PRIVATE, 0,
-                                                           NULL,
-                                                           mmgr_attribute));
-
+       *curr_buf = ia_css_refcount_increment(id, hmm_alloc(needed_size));
        if (!*curr_buf) {
                *err = -ENOMEM;
                *curr_size = 0;
@@ -2122,7 +2117,7 @@ static bool reallocate_buffer(
        IA_CSS_ENTER_PRIVATE("void");
 
        ret = realloc_isp_css_mm_buf(curr_buf,
-                                    curr_size, needed_size, force, err, 0);
+                                    curr_size, needed_size, force, err);
 
        IA_CSS_LEAVE_PRIVATE("ret=%d", ret);
        return ret;
@@ -2161,7 +2156,7 @@ ia_css_isp_3a_statistics_allocate(const struct ia_css_3a_grid_info *grid)
        me->hmem_size = CEIL_MUL(me->hmem_size, HIVE_ISP_DDR_WORD_BYTES);
 
        me->size = me->dmem_size + me->vmem_size * 2 + me->hmem_size;
-       me->data_ptr = hmm_alloc(me->size, HMM_BO_PRIVATE, 0, NULL, 0);
+       me->data_ptr = hmm_alloc(me->size);
        if (me->data_ptr == mmgr_NULL) {
                kvfree(me);
                me = NULL;
@@ -2211,7 +2206,7 @@ ia_css_metadata_allocate(const struct ia_css_metadata_info *metadata_info)
 
        md->info = *metadata_info;
        md->exp_id = 0;
-       md->address = hmm_alloc(metadata_info->size, HMM_BO_PRIVATE, 0, NULL, 0);
+       md->address = hmm_alloc(metadata_info->size);
        if (md->address == mmgr_NULL)
                goto error;
 
@@ -2364,13 +2359,13 @@ sh_css_create_isp_params(struct ia_css_stream *stream,
        ddr_ptrs_size->isp_param = params_size;
        ddr_ptrs->isp_param =
        ia_css_refcount_increment(IA_CSS_REFCOUNT_PARAM_BUFFER,
-                                 hmm_alloc(params_size, HMM_BO_PRIVATE, 0, NULL, 0));
+                                 hmm_alloc(params_size));
        succ &= (ddr_ptrs->isp_param != mmgr_NULL);
 
        ddr_ptrs_size->macc_tbl = sizeof(struct ia_css_macc_table);
        ddr_ptrs->macc_tbl =
        ia_css_refcount_increment(IA_CSS_REFCOUNT_PARAM_BUFFER,
-                                 hmm_alloc(sizeof(struct ia_css_macc_table), HMM_BO_PRIVATE, 0, NULL, 0));
+                                 hmm_alloc(sizeof(struct ia_css_macc_table)));
        succ &= (ddr_ptrs->macc_tbl != mmgr_NULL);
 
        *isp_params_out = params;
@@ -2584,14 +2579,10 @@ sh_css_params_init(void)
                for (i = 0; i < SH_CSS_MAX_STAGES; i++) {
                        xmem_sp_stage_ptrs[p][i] =
                        ia_css_refcount_increment(-1,
-                                                 hmm_alloc(sizeof(struct sh_css_sp_stage),
-                                                           HMM_BO_PRIVATE, 0, NULL,
-                                                           ATOMISP_MAP_FLAG_CLEARED));
+                                                 hmm_alloc(sizeof(struct sh_css_sp_stage)));
                        xmem_isp_stage_ptrs[p][i] =
                        ia_css_refcount_increment(-1,
-                                                 hmm_alloc(sizeof(struct sh_css_sp_stage),
-                                                           HMM_BO_PRIVATE, 0, NULL,
-                                                           ATOMISP_MAP_FLAG_CLEARED));
+                                                 hmm_alloc(sizeof(struct sh_css_sp_stage)));
 
                        if ((xmem_sp_stage_ptrs[p][i] == mmgr_NULL) ||
                            (xmem_isp_stage_ptrs[p][i] == mmgr_NULL)) {
@@ -2599,6 +2590,9 @@ sh_css_params_init(void)
                                IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM);
                                return -ENOMEM;
                        }
+
+                       hmm_set(xmem_sp_stage_ptrs[p][i], 0, sizeof(struct sh_css_sp_stage));
+                       hmm_set(xmem_isp_stage_ptrs[p][i], 0, sizeof(struct sh_css_sp_stage));
                }
        }
 
@@ -2609,13 +2603,9 @@ sh_css_params_init(void)
 
        sp_ddr_ptrs = ia_css_refcount_increment(-1,
                                                hmm_alloc(CEIL_MUL(sizeof(struct sh_css_ddr_address_map),
-                                                                  HIVE_ISP_DDR_WORD_BYTES),
-                                                         HMM_BO_PRIVATE, 0, NULL,
-                                                         ATOMISP_MAP_FLAG_CLEARED));
+                                                                  HIVE_ISP_DDR_WORD_BYTES)));
        xmem_sp_group_ptrs = ia_css_refcount_increment(-1,
-                                                      hmm_alloc(sizeof(struct sh_css_sp_group),
-                                                                HMM_BO_PRIVATE, 0, NULL,
-                                                                ATOMISP_MAP_FLAG_CLEARED));
+                                                      hmm_alloc(sizeof(struct sh_css_sp_group)));
 
        if ((sp_ddr_ptrs == mmgr_NULL) ||
            (xmem_sp_group_ptrs == mmgr_NULL)) {
@@ -2623,6 +2613,9 @@ sh_css_params_init(void)
                IA_CSS_LEAVE_ERR_PRIVATE(-ENOMEM);
                return -ENOMEM;
        }
+       hmm_set(sp_ddr_ptrs, 0, CEIL_MUL(sizeof(struct sh_css_ddr_address_map),
+                                        HIVE_ISP_DDR_WORD_BYTES));
+       hmm_set(xmem_sp_group_ptrs, 0, sizeof(struct sh_css_sp_group));
        IA_CSS_LEAVE_ERR_PRIVATE(0);
        return 0;
 }
@@ -2667,7 +2660,7 @@ int ia_css_pipe_set_bci_scaler_lut(struct ia_css_pipe *pipe,
        }
 
        if (!stream_started) {
-               pipe->scaler_pp_lut = hmm_alloc(sizeof(zoom_table), HMM_BO_PRIVATE, 0, NULL, 0);
+               pipe->scaler_pp_lut = hmm_alloc(sizeof(zoom_table));
 
                if (pipe->scaler_pp_lut == mmgr_NULL) {
                        ia_css_debug_dtrace(IA_CSS_DEBUG_ERROR,
@@ -2709,7 +2702,7 @@ int sh_css_params_map_and_store_default_gdc_lut(void)
 
        host_lut_store((void *)zoom_table);
 
-       default_gdc_lut = hmm_alloc(sizeof(zoom_table), HMM_BO_PRIVATE, 0, NULL, 0);
+       default_gdc_lut = hmm_alloc(sizeof(zoom_table));
 
        if (default_gdc_lut == mmgr_NULL)
                return -ENOMEM;
@@ -3802,7 +3795,7 @@ static int write_ia_css_isp_parameter_set_info_to_ddr(
        assert(out);
 
        *out = ia_css_refcount_increment(IA_CSS_REFCOUNT_PARAM_SET_POOL,
-                                        hmm_alloc(sizeof(struct ia_css_isp_parameter_set_info), HMM_BO_PRIVATE, 0, NULL, 0));
+                                        hmm_alloc(sizeof(struct ia_css_isp_parameter_set_info)));
        succ = (*out != mmgr_NULL);
        if (succ)
                hmm_store(*out,
index d74ee0e..df81a9b 100644 (file)
@@ -2364,7 +2364,7 @@ static int av7110_attach(struct saa7146_dev* dev,
                budgetpatch = 0;
                /* autodetect the presence of budget patch
                 * this only works if saa7146 has been recently
-                * reset with with MASK_31 to MC1
+                * reset with MASK_31 to MC1
                 *
                 * will wait for VBI_B event (vertical blank at port B)
                 * and will reset GPIO3 after VBI_B is detected.
index 26308bb..2989ebc 100644 (file)
@@ -227,6 +227,7 @@ struct hantro_dev {
  *
  * @ctrl_handler:      Control handler used to register controls.
  * @jpeg_quality:      User-specified JPEG compression quality.
+ * @bit_depth:         Bit depth of current frame
  *
  * @codec_ops:         Set of operations related to codec mode.
  * @postproc:          Post-processing context.
@@ -252,6 +253,7 @@ struct hantro_ctx {
 
        struct v4l2_ctrl_handler ctrl_handler;
        int jpeg_quality;
+       int bit_depth;
 
        const struct hantro_codec_ops *codec_ops;
        struct hantro_postproc_ctx postproc;
@@ -277,6 +279,7 @@ struct hantro_ctx {
  * @enc_fmt:   Format identifier for encoder registers.
  * @frmsize:   Supported range of frame sizes (only for bitstream formats).
  * @postprocessed: Indicates if this format needs the post-processor.
+ * @match_depth: Indicates if format bit depth must match video bit depth
  */
 struct hantro_fmt {
        char *name;
@@ -287,6 +290,7 @@ struct hantro_fmt {
        enum hantro_enc_fmt enc_fmt;
        struct v4l2_frmsize_stepwise frmsize;
        bool postprocessed;
+       bool match_depth;
 };
 
 struct hantro_reg {
index ac232b5..2036f72 100644 (file)
@@ -47,12 +47,10 @@ dma_addr_t hantro_get_ref(struct hantro_ctx *ctx, u64 ts)
 {
        struct vb2_queue *q = v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx);
        struct vb2_buffer *buf;
-       int index;
 
-       index = vb2_find_timestamp(q, ts, 0);
-       if (index < 0)
+       buf = vb2_find_buffer(q, ts);
+       if (!buf)
                return 0;
-       buf = vb2_get_buffer(q, index);
        return hantro_get_dec_buf_addr(ctx, buf);
 }
 
@@ -265,7 +263,7 @@ static int hantro_try_ctrl(struct v4l2_ctrl *ctrl)
                if (sps->bit_depth_luma_minus8 != 0)
                        /* Only 8-bit is supported */
                        return -EINVAL;
-       } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_SPS) {
+       } else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) {
                const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
 
                if (sps->bit_depth_luma_minus8 != sps->bit_depth_chroma_minus8)
@@ -304,18 +302,16 @@ static int hantro_jpeg_s_ctrl(struct v4l2_ctrl *ctrl)
        return 0;
 }
 
-static int hantro_hevc_s_ctrl(struct v4l2_ctrl *ctrl)
+static int hantro_vp9_s_ctrl(struct v4l2_ctrl *ctrl)
 {
        struct hantro_ctx *ctx;
 
        ctx = container_of(ctrl->handler,
                           struct hantro_ctx, ctrl_handler);
 
-       vpu_debug(1, "s_ctrl: id = %d, val = %d\n", ctrl->id, ctrl->val);
-
        switch (ctrl->id) {
-       case V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP:
-               ctx->hevc_dec.ctrls.hevc_hdr_skip_length = ctrl->val;
+       case V4L2_CID_STATELESS_VP9_FRAME:
+               ctx->bit_depth = ctrl->p_new.p_vp9_frame->bit_depth;
                break;
        default:
                return -EINVAL;
@@ -332,8 +328,8 @@ static const struct v4l2_ctrl_ops hantro_jpeg_ctrl_ops = {
        .s_ctrl = hantro_jpeg_s_ctrl,
 };
 
-static const struct v4l2_ctrl_ops hantro_hevc_ctrl_ops = {
-       .s_ctrl = hantro_hevc_s_ctrl,
+static const struct v4l2_ctrl_ops hantro_vp9_ctrl_ops = {
+       .s_ctrl = hantro_vp9_s_ctrl,
 };
 
 #define HANTRO_JPEG_ACTIVE_MARKERS     (V4L2_JPEG_ACTIVE_MARKER_APP0 | \
@@ -438,18 +434,18 @@ static const struct hantro_ctrl controls[] = {
        }, {
                .codec = HANTRO_HEVC_DECODER,
                .cfg = {
-                       .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE,
-                       .min = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
-                       .max = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
-                       .def = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
+                       .id = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
+                       .min = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+                       .max = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+                       .def = V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
                },
        }, {
                .codec = HANTRO_HEVC_DECODER,
                .cfg = {
-                       .id = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE,
-                       .min = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
-                       .max = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
-                       .def = V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
+                       .id = V4L2_CID_STATELESS_HEVC_START_CODE,
+                       .min = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+                       .max = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+                       .def = V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
                },
        }, {
                .codec = HANTRO_HEVC_DECODER,
@@ -469,40 +465,29 @@ static const struct hantro_ctrl controls[] = {
        }, {
                .codec = HANTRO_HEVC_DECODER,
                .cfg = {
-                       .id = V4L2_CID_MPEG_VIDEO_HEVC_SPS,
+                       .id = V4L2_CID_STATELESS_HEVC_SPS,
                        .ops = &hantro_ctrl_ops,
                },
        }, {
                .codec = HANTRO_HEVC_DECODER,
                .cfg = {
-                       .id = V4L2_CID_MPEG_VIDEO_HEVC_PPS,
+                       .id = V4L2_CID_STATELESS_HEVC_PPS,
                },
        }, {
                .codec = HANTRO_HEVC_DECODER,
                .cfg = {
-                       .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS,
+                       .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
                },
        }, {
                .codec = HANTRO_HEVC_DECODER,
                .cfg = {
-                       .id = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX,
-               },
-       }, {
-               .codec = HANTRO_HEVC_DECODER,
-               .cfg = {
-                       .id = V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP,
-                       .name = "Hantro HEVC slice header skip bytes",
-                       .type = V4L2_CTRL_TYPE_INTEGER,
-                       .min = 0,
-                       .def = 0,
-                       .max = 0x100,
-                       .step = 1,
-                       .ops = &hantro_hevc_ctrl_ops,
+                       .id = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
                },
        }, {
                .codec = HANTRO_VP9_DECODER,
                .cfg = {
                        .id = V4L2_CID_STATELESS_VP9_FRAME,
+                       .ops = &hantro_vp9_ctrl_ops,
                },
        }, {
                .codec = HANTRO_VP9_DECODER,
@@ -638,6 +623,7 @@ static const struct of_device_id of_hantro_match[] = {
        { .compatible = "rockchip,rk3288-vpu", .data = &rk3288_vpu_variant, },
        { .compatible = "rockchip,rk3328-vpu", .data = &rk3328_vpu_variant, },
        { .compatible = "rockchip,rk3399-vpu", .data = &rk3399_vpu_variant, },
+       { .compatible = "rockchip,rk3568-vepu", .data = &rk3568_vepu_variant, },
        { .compatible = "rockchip,rk3568-vpu", .data = &rk3568_vpu_variant, },
 #endif
 #ifdef CONFIG_VIDEO_HANTRO_IMX8M
index 5df6f08..233ecd8 100644 (file)
@@ -117,6 +117,41 @@ static void prepare_tile_info_buffer(struct hantro_ctx *ctx)
                vpu_debug(1, "%s: no chroma!\n", __func__);
 }
 
+static int compute_header_skip_length(struct hantro_ctx *ctx)
+{
+       const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
+       const struct v4l2_ctrl_hevc_decode_params *decode_params = ctrls->decode_params;
+       const struct v4l2_ctrl_hevc_sps *sps = ctrls->sps;
+       const struct v4l2_ctrl_hevc_pps *pps = ctrls->pps;
+       int skip = 0;
+
+       if (pps->flags & V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT)
+               /* size of pic_output_flag */
+               skip++;
+
+       if (sps->flags & V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE)
+               /* size of pic_order_cnt_lsb */
+               skip += 2;
+
+       if (!(decode_params->flags & V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC)) {
+               /* size of pic_order_cnt_lsb */
+               skip += sps->log2_max_pic_order_cnt_lsb_minus4 + 4;
+
+               /* size of short_term_ref_pic_set_sps_flag */
+               skip++;
+
+               if (decode_params->short_term_ref_pic_set_size)
+                       /* size of st_ref_pic_set( num_short_term_ref_pic_sets ) */
+                       skip += decode_params->short_term_ref_pic_set_size;
+               else if (sps->num_short_term_ref_pic_sets > 1)
+                       skip += fls(sps->num_short_term_ref_pic_sets - 1);
+
+               skip += decode_params->long_term_ref_pic_set_size;
+       }
+
+       return skip;
+}
+
 static void set_params(struct hantro_ctx *ctx)
 {
        const struct hantro_hevc_dec_ctrls *ctrls = &ctx->hevc_dec.ctrls;
@@ -134,7 +169,7 @@ static void set_params(struct hantro_ctx *ctx)
 
        hantro_reg_write(vpu, &g2_output_8_bits, 0);
 
-       hantro_reg_write(vpu, &g2_hdr_skip_length, ctrls->hevc_hdr_skip_length);
+       hantro_reg_write(vpu, &g2_hdr_skip_length, compute_header_skip_length(ctx));
 
        min_log2_cb_size = sps->log2_min_luma_coding_block_size_minus3 + 3;
        max_log2_ctb_size = min_log2_cb_size + sps->log2_diff_max_min_luma_coding_block_size;
@@ -390,11 +425,10 @@ static int set_ref(struct hantro_ctx *ctx)
                         !!(pps->flags & V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED));
 
        /*
-        * Write POC count diff from current pic. For frame decoding only compute
-        * pic_order_cnt[0] and ignore pic_order_cnt[1] used in field-coding.
+        * Write POC count diff from current pic.
         */
        for (i = 0; i < decode_params->num_active_dpb_entries && i < ARRAY_SIZE(cur_poc); i++) {
-               char poc_diff = decode_params->pic_order_cnt_val - dpb[i].pic_order_cnt[0];
+               char poc_diff = decode_params->pic_order_cnt_val - dpb[i].pic_order_cnt_val;
 
                hantro_reg_write(vpu, &cur_poc[i], poc_diff);
        }
@@ -421,7 +455,7 @@ static int set_ref(struct hantro_ctx *ctx)
        dpb_longterm_e = 0;
        for (i = 0; i < decode_params->num_active_dpb_entries &&
             i < (V4L2_HEVC_DPB_ENTRIES_NUM_MAX - 1); i++) {
-               luma_addr = hantro_hevc_get_ref_buf(ctx, dpb[i].pic_order_cnt[0]);
+               luma_addr = hantro_hevc_get_ref_buf(ctx, dpb[i].pic_order_cnt_val);
                if (!luma_addr)
                        return -ENOMEM;
 
index 877d663..8260678 100644 (file)
 
 #define g2_start_code_e                G2_DEC_REG(10, 31, 0x1)
 #define g2_init_qp_old         G2_DEC_REG(10, 25, 0x3f)
-#define g2_init_qp             G2_DEC_REG(10, 24, 0x3f)
+#define g2_init_qp             G2_DEC_REG(10, 24, 0x7f)
 #define g2_num_tile_cols_old   G2_DEC_REG(10, 20, 0x1f)
 #define g2_num_tile_cols       G2_DEC_REG(10, 19, 0x1f)
 #define g2_num_tile_rows_old   G2_DEC_REG(10, 15, 0x1f)
index 91c21b6..6fc4b55 100644 (file)
@@ -111,17 +111,17 @@ get_ref_buf(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
 {
        struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
        struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
-       int buf_idx;
+       struct vb2_buffer *buf;
 
        /*
         * If a ref is unused or invalid, address of current destination
         * buffer is returned.
         */
-       buf_idx = vb2_find_timestamp(cap_q, timestamp, 0);
-       if (buf_idx < 0)
-               return vb2_to_hantro_decoded_buf(&dst->vb2_buf);
+       buf = vb2_find_buffer(cap_q, timestamp);
+       if (!buf)
+               buf = &dst->vb2_buf;
 
-       return vb2_to_hantro_decoded_buf(vb2_get_buffer(cap_q, buf_idx));
+       return vb2_to_hantro_decoded_buf(buf);
 }
 
 static void update_dec_buf_info(struct hantro_decoded_buffer *buf,
@@ -515,16 +515,8 @@ static void
 config_bit_depth(struct hantro_ctx *ctx, const struct v4l2_ctrl_vp9_frame *dec_params)
 {
        if (ctx->dev->variant->legacy_regs) {
-               u8 pp_shift = 0;
-
                hantro_reg_write(ctx->dev, &g2_bit_depth_y, dec_params->bit_depth);
                hantro_reg_write(ctx->dev, &g2_bit_depth_c, dec_params->bit_depth);
-               hantro_reg_write(ctx->dev, &g2_rs_out_bit_depth, dec_params->bit_depth);
-
-               if (dec_params->bit_depth > 8)
-                       pp_shift = 16 - dec_params->bit_depth;
-
-               hantro_reg_write(ctx->dev, &g2_pp_pix_shift, pp_shift);
                hantro_reg_write(ctx->dev, &g2_pix_shift, 0);
        } else {
                hantro_reg_write(ctx->dev, &g2_bit_depth_y_minus8, dec_params->bit_depth - 8);
index f86c98e..b990bc9 100644 (file)
@@ -33,7 +33,7 @@ void hantro_hevc_ref_init(struct hantro_ctx *ctx)
 }
 
 dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx,
-                                  int poc)
+                                  s32 poc)
 {
        struct hantro_hevc_dec_hw_ctx *hevc_dec = &ctx->hevc_dec;
        int i;
@@ -154,6 +154,25 @@ err_free_tile_buffers:
        return -ENOMEM;
 }
 
+static int hantro_hevc_validate_sps(struct hantro_ctx *ctx, const struct v4l2_ctrl_hevc_sps *sps)
+{
+       /*
+        * for tile pixel format check if the width and height match
+        * hardware constraints
+        */
+       if (ctx->vpu_dst_fmt->fourcc == V4L2_PIX_FMT_NV12_4L4) {
+               if (ctx->dst_fmt.width !=
+                   ALIGN(sps->pic_width_in_luma_samples, ctx->vpu_dst_fmt->frmsize.step_width))
+                       return -EINVAL;
+
+               if (ctx->dst_fmt.height !=
+                   ALIGN(sps->pic_height_in_luma_samples, ctx->vpu_dst_fmt->frmsize.step_height))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
 int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx)
 {
        struct hantro_hevc_dec_hw_ctx *hevc_ctx = &ctx->hevc_dec;
@@ -163,22 +182,26 @@ int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx)
        hantro_start_prepare_run(ctx);
 
        ctrls->decode_params =
-               hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS);
+               hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
        if (WARN_ON(!ctrls->decode_params))
                return -EINVAL;
 
        ctrls->scaling =
-               hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX);
+               hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
        if (WARN_ON(!ctrls->scaling))
                return -EINVAL;
 
        ctrls->sps =
-               hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_SPS);
+               hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_SPS);
        if (WARN_ON(!ctrls->sps))
                return -EINVAL;
 
+       ret = hantro_hevc_validate_sps(ctx, ctrls->sps);
+       if (ret)
+               return ret;
+
        ctrls->pps =
-               hantro_get_ctrl(ctx, V4L2_CID_MPEG_VIDEO_HEVC_PPS);
+               hantro_get_ctrl(ctx, V4L2_CID_STATELESS_HEVC_PPS);
        if (WARN_ON(!ctrls->pps))
                return -EINVAL;
 
index 52a960f..e83f0c5 100644 (file)
 #define DEC_8190_ALIGN_MASK    0x07U
 
 #define MB_DIM                 16
+#define TILE_MB_DIM            4
 #define MB_WIDTH(w)            DIV_ROUND_UP(w, MB_DIM)
 #define MB_HEIGHT(h)           DIV_ROUND_UP(h, MB_DIM)
 
+#define FMT_MIN_WIDTH          48
+#define FMT_MIN_HEIGHT         48
+#define FMT_HD_WIDTH           1280
+#define FMT_HD_HEIGHT          720
+#define FMT_FHD_WIDTH          1920
+#define FMT_FHD_HEIGHT         1088
+#define FMT_UHD_WIDTH          3840
+#define FMT_UHD_HEIGHT         2160
+#define FMT_4K_WIDTH           4096
+#define FMT_4K_HEIGHT          2304
+
 #define NUM_REF_PICTURES       (V4L2_HEVC_DPB_ENTRIES_NUM_MAX + 1)
 
 struct hantro_dev;
@@ -133,7 +145,7 @@ struct hantro_hevc_dec_hw_ctx {
        struct hantro_aux_buf tile_bsd;
        struct hantro_aux_buf ref_bufs[NUM_REF_PICTURES];
        struct hantro_aux_buf scaling_lists;
-       int ref_bufs_poc[NUM_REF_PICTURES];
+       s32 ref_bufs_poc[NUM_REF_PICTURES];
        u32 ref_bufs_used;
        struct hantro_hevc_dec_ctrls ctrls;
        unsigned int num_tile_cols_allocated;
@@ -306,6 +318,7 @@ extern const struct hantro_variant rk3066_vpu_variant;
 extern const struct hantro_variant rk3288_vpu_variant;
 extern const struct hantro_variant rk3328_vpu_variant;
 extern const struct hantro_variant rk3399_vpu_variant;
+extern const struct hantro_variant rk3568_vepu_variant;
 extern const struct hantro_variant rk3568_vpu_variant;
 extern const struct hantro_variant sama5d4_vdec_variant;
 extern const struct hantro_variant sunxi_vpu_variant;
@@ -345,9 +358,10 @@ void hantro_hevc_dec_exit(struct hantro_ctx *ctx);
 int hantro_g2_hevc_dec_run(struct hantro_ctx *ctx);
 int hantro_hevc_dec_prepare_run(struct hantro_ctx *ctx);
 void hantro_hevc_ref_init(struct hantro_ctx *ctx);
-dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, int poc);
+dma_addr_t hantro_hevc_get_ref_buf(struct hantro_ctx *ctx, s32 poc);
 int hantro_hevc_add_ref_buf(struct hantro_ctx *ctx, int poc, dma_addr_t addr);
 
+
 static inline unsigned short hantro_vp9_num_sbs(unsigned short dimension)
 {
        return (dimension + 63) / 64;
index ab168c1..a0928c5 100644 (file)
@@ -12,6 +12,7 @@
 #include "hantro_hw.h"
 #include "hantro_g1_regs.h"
 #include "hantro_g2_regs.h"
+#include "hantro_v4l2.h"
 
 #define HANTRO_PP_REG_WRITE(vpu, reg_name, val) \
 { \
@@ -112,12 +113,14 @@ static void hantro_postproc_g2_enable(struct hantro_ctx *ctx)
 {
        struct hantro_dev *vpu = ctx->dev;
        struct vb2_v4l2_buffer *dst_buf;
-       size_t chroma_offset = ctx->dst_fmt.width * ctx->dst_fmt.height;
        int down_scale = down_scale_factor(ctx);
+       size_t chroma_offset;
        dma_addr_t dst_dma;
 
        dst_buf = hantro_get_dst_buf(ctx);
        dst_dma = vb2_dma_contig_plane_dma_addr(&dst_buf->vb2_buf, 0);
+       chroma_offset = ctx->dst_fmt.plane_fmt[0].bytesperline *
+                       ctx->dst_fmt.height;
 
        if (down_scale) {
                hantro_reg_write(vpu, &g2_down_scale_e, 1);
@@ -129,6 +132,16 @@ static void hantro_postproc_g2_enable(struct hantro_ctx *ctx)
                hantro_write_addr(vpu, G2_RS_OUT_LUMA_ADDR, dst_dma);
                hantro_write_addr(vpu, G2_RS_OUT_CHROMA_ADDR, dst_dma + chroma_offset);
        }
+       if (ctx->dev->variant->legacy_regs) {
+               int out_depth = hantro_get_format_depth(ctx->dst_fmt.pixelformat);
+               u8 pp_shift = 0;
+
+               if (out_depth > 8)
+                       pp_shift = 16 - out_depth;
+
+               hantro_reg_write(ctx->dev, &g2_rs_out_bit_depth, out_depth);
+               hantro_reg_write(ctx->dev, &g2_pp_pix_shift, pp_shift);
+       }
        hantro_reg_write(vpu, &g2_out_rs_e, 1);
 }
 
@@ -174,18 +187,27 @@ int hantro_postproc_alloc(struct hantro_ctx *ctx)
        struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
        struct vb2_queue *cap_queue = &m2m_ctx->cap_q_ctx.q;
        unsigned int num_buffers = cap_queue->num_buffers;
+       struct v4l2_pix_format_mplane pix_mp;
+       const struct hantro_fmt *fmt;
        unsigned int i, buf_size;
 
-       buf_size = ctx->dst_fmt.plane_fmt[0].sizeimage;
+       /* this should always pick native format */
+       fmt = hantro_get_default_fmt(ctx, false);
+       if (!fmt)
+               return -EINVAL;
+       v4l2_fill_pixfmt_mp(&pix_mp, fmt->fourcc, ctx->src_fmt.width,
+                           ctx->src_fmt.height);
+
+       buf_size = pix_mp.plane_fmt[0].sizeimage;
        if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_H264_SLICE)
-               buf_size += hantro_h264_mv_size(ctx->dst_fmt.width,
-                                               ctx->dst_fmt.height);
+               buf_size += hantro_h264_mv_size(pix_mp.width,
+                                               pix_mp.height);
        else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_VP9_FRAME)
-               buf_size += hantro_vp9_mv_size(ctx->dst_fmt.width,
-                                              ctx->dst_fmt.height);
+               buf_size += hantro_vp9_mv_size(pix_mp.width,
+                                              pix_mp.height);
        else if (ctx->vpu_src_fmt->fourcc == V4L2_PIX_FMT_HEVC_SLICE)
-               buf_size += hantro_hevc_mv_size(ctx->dst_fmt.width,
-                                               ctx->dst_fmt.height);
+               buf_size += hantro_hevc_mv_size(pix_mp.width,
+                                               pix_mp.height);
 
        for (i = 0; i < num_buffers; ++i) {
                struct hantro_aux_buf *priv = &ctx->postproc.dec_q[i];
index 22ad182..2c7a805 100644 (file)
@@ -64,6 +64,42 @@ hantro_get_postproc_formats(const struct hantro_ctx *ctx,
        return ctx->dev->variant->postproc_fmts;
 }
 
+int hantro_get_format_depth(u32 fourcc)
+{
+       switch (fourcc) {
+       case V4L2_PIX_FMT_P010:
+       case V4L2_PIX_FMT_P010_4L4:
+               return 10;
+       default:
+               return 8;
+       }
+}
+
+static bool
+hantro_check_depth_match(const struct hantro_ctx *ctx,
+                        const struct hantro_fmt *fmt)
+{
+       int fmt_depth, ctx_depth = 8;
+
+       if (!fmt->match_depth && !fmt->postprocessed)
+               return true;
+
+       /* 0 means default depth, which is 8 */
+       if (ctx->bit_depth)
+               ctx_depth = ctx->bit_depth;
+
+       fmt_depth = hantro_get_format_depth(fmt->fourcc);
+
+       /*
+        * Allow only downconversion for postproc formats for now.
+        * It may be possible to relax that on some HW.
+        */
+       if (!fmt->match_depth)
+               return fmt_depth <= ctx_depth;
+
+       return fmt_depth == ctx_depth;
+}
+
 static const struct hantro_fmt *
 hantro_find_format(const struct hantro_ctx *ctx, u32 fourcc)
 {
@@ -82,7 +118,7 @@ hantro_find_format(const struct hantro_ctx *ctx, u32 fourcc)
        return NULL;
 }
 
-static const struct hantro_fmt *
+const struct hantro_fmt *
 hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream)
 {
        const struct hantro_fmt *formats;
@@ -91,7 +127,8 @@ hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream)
        formats = hantro_get_formats(ctx, &num_fmts);
        for (i = 0; i < num_fmts; i++) {
                if (bitstream == (formats[i].codec_mode !=
-                                 HANTRO_MODE_NONE))
+                                 HANTRO_MODE_NONE) &&
+                   hantro_check_depth_match(ctx, &formats[i]))
                        return &formats[i];
        }
        return NULL;
@@ -162,11 +199,13 @@ static int vidioc_enum_fmt(struct file *file, void *priv,
        formats = hantro_get_formats(ctx, &num_fmts);
        for (i = 0; i < num_fmts; i++) {
                bool mode_none = formats[i].codec_mode == HANTRO_MODE_NONE;
+               fmt = &formats[i];
 
                if (skip_mode_none == mode_none)
                        continue;
+               if (!hantro_check_depth_match(ctx, fmt))
+                       continue;
                if (j == f->index) {
-                       fmt = &formats[i];
                        f->pixelformat = fmt->fourcc;
                        return 0;
                }
@@ -182,8 +221,11 @@ static int vidioc_enum_fmt(struct file *file, void *priv,
                return -EINVAL;
        formats = hantro_get_postproc_formats(ctx, &num_fmts);
        for (i = 0; i < num_fmts; i++) {
+               fmt = &formats[i];
+
+               if (!hantro_check_depth_match(ctx, fmt))
+                       continue;
                if (j == f->index) {
-                       fmt = &formats[i];
                        f->pixelformat = fmt->fourcc;
                        return 0;
                }
@@ -259,7 +301,7 @@ static int hantro_try_fmt(const struct hantro_ctx *ctx,
        } else if (ctx->is_encoder) {
                vpu_fmt = ctx->vpu_dst_fmt;
        } else {
-               vpu_fmt = ctx->vpu_src_fmt;
+               vpu_fmt = fmt;
                /*
                 * Width/height on the CAPTURE end of a decoder are ignored and
                 * replaced by the OUTPUT ones.
index 18bc682..64f6f57 100644 (file)
@@ -22,5 +22,8 @@ extern const struct v4l2_ioctl_ops hantro_ioctl_ops;
 extern const struct vb2_ops hantro_queue_ops;
 
 void hantro_reset_fmts(struct hantro_ctx *ctx);
+int hantro_get_format_depth(u32 fourcc);
+const struct hantro_fmt *
+hantro_get_default_fmt(const struct hantro_ctx *ctx, bool bitstream);
 
 #endif /* HANTRO_V4L2_H_ */
index 9802508..77f574f 100644 (file)
@@ -83,6 +83,14 @@ static const struct hantro_fmt imx8m_vpu_postproc_fmts[] = {
                .fourcc = V4L2_PIX_FMT_YUYV,
                .codec_mode = HANTRO_MODE_NONE,
                .postprocessed = true,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
        },
 };
 
@@ -90,17 +98,25 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = {
        {
                .fourcc = V4L2_PIX_FMT_NV12,
                .codec_mode = HANTRO_MODE_NONE,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
        },
        {
                .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
                .codec_mode = HANTRO_MODE_MPEG2_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1920,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 1088,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -109,11 +125,11 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = {
                .codec_mode = HANTRO_MODE_VP8_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 3840,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 2160,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -122,11 +138,11 @@ static const struct hantro_fmt imx8m_vpu_dec_fmts[] = {
                .codec_mode = HANTRO_MODE_H264_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 3840,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 2160,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -137,6 +153,14 @@ static const struct hantro_fmt imx8m_vpu_g2_postproc_fmts[] = {
                .fourcc = V4L2_PIX_FMT_NV12,
                .codec_mode = HANTRO_MODE_NONE,
                .postprocessed = true,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
        },
 };
 
@@ -144,18 +168,26 @@ static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = {
        {
                .fourcc = V4L2_PIX_FMT_NV12_4L4,
                .codec_mode = HANTRO_MODE_NONE,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = TILE_MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = TILE_MB_DIM,
+               },
        },
        {
                .fourcc = V4L2_PIX_FMT_HEVC_SLICE,
                .codec_mode = HANTRO_MODE_HEVC_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 3840,
-                       .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 2160,
-                       .step_height = MB_DIM,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = TILE_MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = TILE_MB_DIM,
                },
        },
        {
@@ -163,12 +195,12 @@ static const struct hantro_fmt imx8m_vpu_g2_dec_fmts[] = {
                .codec_mode = HANTRO_MODE_VP9_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 3840,
-                       .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 2160,
-                       .step_height = MB_DIM,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = TILE_MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = TILE_MB_DIM,
                },
        },
 };
index fc96501..8de6fd2 100644 (file)
@@ -63,6 +63,14 @@ static const struct hantro_fmt rockchip_vpu1_postproc_fmts[] = {
                .fourcc = V4L2_PIX_FMT_YUYV,
                .codec_mode = HANTRO_MODE_NONE,
                .postprocessed = true,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
        },
 };
 
@@ -70,17 +78,25 @@ static const struct hantro_fmt rk3066_vpu_dec_fmts[] = {
        {
                .fourcc = V4L2_PIX_FMT_NV12,
                .codec_mode = HANTRO_MODE_NONE,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
        },
        {
                .fourcc = V4L2_PIX_FMT_H264_SLICE,
                .codec_mode = HANTRO_MODE_H264_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1920,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 1088,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -89,11 +105,11 @@ static const struct hantro_fmt rk3066_vpu_dec_fmts[] = {
                .codec_mode = HANTRO_MODE_MPEG2_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1920,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 1088,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -102,11 +118,11 @@ static const struct hantro_fmt rk3066_vpu_dec_fmts[] = {
                .codec_mode = HANTRO_MODE_VP8_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1920,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 1088,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -116,17 +132,25 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = {
        {
                .fourcc = V4L2_PIX_FMT_NV12,
                .codec_mode = HANTRO_MODE_NONE,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_4K_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_4K_HEIGHT,
+                       .step_height = MB_DIM,
+               },
        },
        {
                .fourcc = V4L2_PIX_FMT_H264_SLICE,
                .codec_mode = HANTRO_MODE_H264_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 4096,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_4K_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 2304,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_4K_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -135,11 +159,11 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = {
                .codec_mode = HANTRO_MODE_MPEG2_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1920,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 1088,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -148,31 +172,80 @@ static const struct hantro_fmt rk3288_vpu_dec_fmts[] = {
                .codec_mode = HANTRO_MODE_VP8_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 3840,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 2160,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
 };
 
-static const struct hantro_fmt rk3399_vpu_dec_fmts[] = {
+static const struct hantro_fmt rockchip_vdpu2_dec_fmts[] = {
        {
                .fourcc = V4L2_PIX_FMT_NV12,
                .codec_mode = HANTRO_MODE_NONE,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
        },
        {
                .fourcc = V4L2_PIX_FMT_H264_SLICE,
                .codec_mode = HANTRO_MODE_H264_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1920,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
+               .codec_mode = HANTRO_MODE_MPEG2_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_VP8_FRAME,
+               .codec_mode = HANTRO_MODE_VP8_DEC,
+               .max_depth = 2,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
+       },
+};
+
+static const struct hantro_fmt rk3399_vpu_dec_fmts[] = {
+       {
+               .fourcc = V4L2_PIX_FMT_NV12,
+               .codec_mode = HANTRO_MODE_NONE,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 1088,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -181,11 +254,11 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = {
                .codec_mode = HANTRO_MODE_MPEG2_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1920,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_FHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 1088,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_FHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -194,11 +267,11 @@ static const struct hantro_fmt rk3399_vpu_dec_fmts[] = {
                .codec_mode = HANTRO_MODE_VP8_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 3840,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 2160,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -417,6 +490,14 @@ static const struct hantro_codec_ops rk3399_vpu_codec_ops[] = {
        },
 };
 
+static const struct hantro_codec_ops rk3568_vepu_codec_ops[] = {
+       [HANTRO_MODE_JPEG_ENC] = {
+               .run = rockchip_vpu2_jpeg_enc_run,
+               .reset = rockchip_vpu2_enc_reset,
+               .done = rockchip_vpu2_jpeg_enc_done,
+       },
+};
+
 /*
  * VPU variant.
  */
@@ -439,6 +520,10 @@ static const struct hantro_irq rockchip_vpu2_irqs[] = {
        { "vdpu", rockchip_vpu2_vdpu_irq },
 };
 
+static const struct hantro_irq rk3568_vepu_irqs[] = {
+       { "vepu", rockchip_vpu2_vepu_irq },
+};
+
 static const char * const rk3066_vpu_clk_names[] = {
        "aclk_vdpu", "hclk_vdpu",
        "aclk_vepu", "hclk_vepu"
@@ -516,8 +601,8 @@ const struct hantro_variant rk3288_vpu_variant = {
 
 const struct hantro_variant rk3328_vpu_variant = {
        .dec_offset = 0x400,
-       .dec_fmts = rk3399_vpu_dec_fmts,
-       .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
+       .dec_fmts = rockchip_vdpu2_dec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(rockchip_vdpu2_dec_fmts),
        .codec = HANTRO_MPEG2_DECODER | HANTRO_VP8_DECODER |
                 HANTRO_H264_DECODER,
        .codec_ops = rk3399_vpu_codec_ops,
@@ -528,6 +613,11 @@ const struct hantro_variant rk3328_vpu_variant = {
        .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names),
 };
 
+/*
+ * H.264 decoding explicitly disabled in RK3399.
+ * This ensures userspace applications use the Rockchip VDEC core,
+ * which has better performance.
+ */
 const struct hantro_variant rk3399_vpu_variant = {
        .enc_offset = 0x0,
        .enc_fmts = rockchip_vpu_enc_fmts,
@@ -545,10 +635,23 @@ const struct hantro_variant rk3399_vpu_variant = {
        .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names)
 };
 
+const struct hantro_variant rk3568_vepu_variant = {
+       .enc_offset = 0x0,
+       .enc_fmts = rockchip_vpu_enc_fmts,
+       .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts),
+       .codec = HANTRO_JPEG_ENCODER,
+       .codec_ops = rk3568_vepu_codec_ops,
+       .irqs = rk3568_vepu_irqs,
+       .num_irqs = ARRAY_SIZE(rk3568_vepu_irqs),
+       .init = rockchip_vpu_hw_init,
+       .clk_names = rockchip_vpu_clk_names,
+       .num_clocks = ARRAY_SIZE(rockchip_vpu_clk_names)
+};
+
 const struct hantro_variant rk3568_vpu_variant = {
        .dec_offset = 0x400,
-       .dec_fmts = rk3399_vpu_dec_fmts,
-       .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
+       .dec_fmts = rockchip_vdpu2_dec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(rockchip_vdpu2_dec_fmts),
        .codec = HANTRO_MPEG2_DECODER |
                 HANTRO_VP8_DECODER | HANTRO_H264_DECODER,
        .codec_ops = rk3399_vpu_codec_ops,
@@ -564,8 +667,8 @@ const struct hantro_variant px30_vpu_variant = {
        .enc_fmts = rockchip_vpu_enc_fmts,
        .num_enc_fmts = ARRAY_SIZE(rockchip_vpu_enc_fmts),
        .dec_offset = 0x400,
-       .dec_fmts = rk3399_vpu_dec_fmts,
-       .num_dec_fmts = ARRAY_SIZE(rk3399_vpu_dec_fmts),
+       .dec_fmts = rockchip_vdpu2_dec_fmts,
+       .num_dec_fmts = ARRAY_SIZE(rockchip_vdpu2_dec_fmts),
        .codec = HANTRO_JPEG_ENCODER | HANTRO_MPEG2_DECODER |
                 HANTRO_VP8_DECODER | HANTRO_H264_DECODER,
        .codec_ops = rk3399_vpu_codec_ops,
index b2fc1c5..b205e2d 100644 (file)
@@ -16,6 +16,14 @@ static const struct hantro_fmt sama5d4_vdec_postproc_fmts[] = {
                .fourcc = V4L2_PIX_FMT_YUYV,
                .codec_mode = HANTRO_MODE_NONE,
                .postprocessed = true,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_HD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_HD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
        },
 };
 
@@ -23,17 +31,25 @@ static const struct hantro_fmt sama5d4_vdec_fmts[] = {
        {
                .fourcc = V4L2_PIX_FMT_NV12,
                .codec_mode = HANTRO_MODE_NONE,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_HD_WIDTH,
+                       .step_width = MB_DIM,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_HD_HEIGHT,
+                       .step_height = MB_DIM,
+               },
        },
        {
                .fourcc = V4L2_PIX_FMT_MPEG2_SLICE,
                .codec_mode = HANTRO_MODE_MPEG2_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1280,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_HD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 720,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_HD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -42,11 +58,11 @@ static const struct hantro_fmt sama5d4_vdec_fmts[] = {
                .codec_mode = HANTRO_MODE_VP8_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1280,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_HD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 720,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_HD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
@@ -55,11 +71,11 @@ static const struct hantro_fmt sama5d4_vdec_fmts[] = {
                .codec_mode = HANTRO_MODE_H264_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 1280,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_HD_WIDTH,
                        .step_width = MB_DIM,
-                       .min_height = 48,
-                       .max_height = 720,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_HD_HEIGHT,
                        .step_height = MB_DIM,
                },
        },
index c0edd58..02ce8b0 100644 (file)
@@ -14,6 +14,27 @@ static const struct hantro_fmt sunxi_vpu_postproc_fmts[] = {
                .fourcc = V4L2_PIX_FMT_NV12,
                .codec_mode = HANTRO_MODE_NONE,
                .postprocessed = true,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = 32,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = 32,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_P010,
+               .codec_mode = HANTRO_MODE_NONE,
+               .postprocessed = true,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = 32,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = 32,
+               },
        },
 };
 
@@ -21,17 +42,39 @@ static const struct hantro_fmt sunxi_vpu_dec_fmts[] = {
        {
                .fourcc = V4L2_PIX_FMT_NV12_4L4,
                .codec_mode = HANTRO_MODE_NONE,
+               .match_depth = true,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = 32,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = 32,
+               },
+       },
+       {
+               .fourcc = V4L2_PIX_FMT_P010_4L4,
+               .codec_mode = HANTRO_MODE_NONE,
+               .match_depth = true,
+               .frmsize = {
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
+                       .step_width = 32,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
+                       .step_height = 32,
+               },
        },
        {
                .fourcc = V4L2_PIX_FMT_VP9_FRAME,
                .codec_mode = HANTRO_MODE_VP9_DEC,
                .max_depth = 2,
                .frmsize = {
-                       .min_width = 48,
-                       .max_width = 3840,
+                       .min_width = FMT_MIN_WIDTH,
+                       .max_width = FMT_UHD_WIDTH,
                        .step_width = 32,
-                       .min_height = 48,
-                       .max_height = 2160,
+                       .min_height = FMT_MIN_HEIGHT,
+                       .max_height = FMT_UHD_HEIGHT,
                        .step_height = 32,
                },
        },
index 80b69a9..e6d6ed3 100644 (file)
@@ -235,7 +235,7 @@ static int imx_media_inherit_controls(struct imx_media_dev *imxmd,
                if (!(spad->flags & MEDIA_PAD_FL_SINK))
                        continue;
 
-               pad = media_entity_remote_pad(spad);
+               pad = media_pad_remote_pad_first(spad);
                if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
                        continue;
 
index 94bc866..294c808 100644 (file)
@@ -698,7 +698,7 @@ imx_media_pipeline_pad(struct media_entity *start_entity, u32 grp_id,
                    (!upstream && !(spad->flags & MEDIA_PAD_FL_SOURCE)))
                        continue;
 
-               pad = media_entity_remote_pad(spad);
+               pad = media_pad_remote_pad_first(spad);
                if (!pad)
                        continue;
 
index 8467a14..a0553c2 100644 (file)
 #include <linux/pinctrl/consumer.h>
 #include <linux/platform_device.h>
 #include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
 #include <linux/types.h>
 
 #include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
 #include <media/v4l2-fwnode.h>
+#include <media/v4l2-ioctl.h>
 #include <media/v4l2-mc.h>
 #include <media/v4l2-subdev.h>
 #include <media/videobuf2-dma-contig.h>
 
-#include <media/imx.h>
-#include "imx-media.h"
-
 #define IMX7_CSI_PAD_SINK              0
 #define IMX7_CSI_PAD_SRC               1
 #define IMX7_CSI_PADS_NUM              2
 #define CSI_CSICR18                    0x48
 #define CSI_CSICR19                    0x4c
 
+#define IMX7_CSI_VIDEO_NAME            "imx-capture"
+/* In bytes, per queue */
+#define IMX7_CSI_VIDEO_MEM_LIMIT       SZ_64M
+#define IMX7_CSI_VIDEO_EOF_TIMEOUT     2000
+
+#define IMX7_CSI_DEF_MBUS_CODE         MEDIA_BUS_FMT_UYVY8_2X8
+#define IMX7_CSI_DEF_PIX_FORMAT                V4L2_PIX_FMT_UYVY
+#define IMX7_CSI_DEF_PIX_WIDTH         640
+#define IMX7_CSI_DEF_PIX_HEIGHT                480
+
 enum imx_csi_model {
        IMX7_CSI_IMX7 = 0,
        IMX7_CSI_IMX8MQ,
 };
 
+struct imx7_csi_pixfmt {
+       /* the in-memory FourCC pixel format */
+       u32     fourcc;
+       /*
+        * the set of equivalent media bus codes for the fourcc.
+        * NOTE! codes pointer is NULL for in-memory-only formats.
+        */
+       const u32 *codes;
+       int     bpp;     /* total bpp */
+       bool    yuv;
+};
+
+struct imx7_csi_vb2_buffer {
+       struct vb2_v4l2_buffer vbuf;
+       struct list_head list;
+};
+
+static inline struct imx7_csi_vb2_buffer *
+to_imx7_csi_vb2_buffer(struct vb2_buffer *vb)
+{
+       struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+       return container_of(vbuf, struct imx7_csi_vb2_buffer, vbuf);
+}
+
+struct imx7_csi_dma_buf {
+       void *virt;
+       dma_addr_t phys;
+       unsigned long len;
+};
+
 struct imx7_csi {
        struct device *dev;
-       struct v4l2_subdev sd;
-       struct v4l2_async_notifier notifier;
-       struct imx_media_video_dev *vdev;
-       struct imx_media_dev *imxmd;
-       struct media_pad pad[IMX7_CSI_PADS_NUM];
 
-       /* lock to protect members below */
-       struct mutex lock;
-       /* lock to protect irq handler when stop streaming */
-       spinlock_t irqlock;
+       /* Resources and locks */
+       void __iomem *regbase;
+       int irq;
+       struct clk *mclk;
+
+       struct mutex lock; /* Protects is_streaming, format_mbus, cc */
+       spinlock_t irqlock; /* Protects last_eof */
+
+       /* Media and V4L2 device */
+       struct media_device mdev;
+       struct v4l2_device v4l2_dev;
+       struct v4l2_async_notifier notifier;
+       struct media_pipeline pipe;
 
        struct v4l2_subdev *src_sd;
+       bool is_csi2;
+
+       /* V4L2 subdev */
+       struct v4l2_subdev sd;
+       struct media_pad pad[IMX7_CSI_PADS_NUM];
 
        struct v4l2_mbus_framefmt format_mbus[IMX7_CSI_PADS_NUM];
-       const struct imx_media_pixfmt *cc[IMX7_CSI_PADS_NUM];
-       struct v4l2_fract frame_interval[IMX7_CSI_PADS_NUM];
+       const struct imx7_csi_pixfmt *cc[IMX7_CSI_PADS_NUM];
 
-       void __iomem *regbase;
-       int irq;
-       struct clk *mclk;
+       /* Video device */
+       struct video_device *vdev;              /* Video device */
+       struct media_pad vdev_pad;              /* Video device pad */
 
-       /* active vb2 buffers to send to video dev sink */
-       struct imx_media_buffer *active_vb2_buf[2];
-       struct imx_media_dma_buf underrun_buf;
+       struct v4l2_pix_format vdev_fmt;        /* The user format */
+       const struct imx7_csi_pixfmt *vdev_cc;
+       struct v4l2_rect vdev_compose;          /* The compose rectangle */
 
+       struct mutex vdev_mutex;                /* Protect vdev operations */
+
+       struct vb2_queue q;                     /* The videobuf2 queue */
+       struct list_head ready_q;               /* List of queued buffers */
+       spinlock_t q_lock;                      /* Protect ready_q */
+
+       /* Buffers and streaming state */
+       struct imx7_csi_vb2_buffer *active_vb2_buf[2];
+       struct imx7_csi_dma_buf underrun_buf;
+
+       bool is_streaming;
        int buf_num;
        u32 frame_sequence;
 
        bool last_eof;
-       bool is_streaming;
-       bool is_csi2;
-
        struct completion last_eof_completion;
 
        enum imx_csi_model model;
@@ -242,7 +298,8 @@ static void imx7_csi_init_default(struct imx7_csi *csi)
        imx7_csi_reg_write(csi, 0, CSI_CSICR2);
        imx7_csi_reg_write(csi, BIT_FRMCNT_RST, CSI_CSICR3);
 
-       imx7_csi_reg_write(csi, BIT_IMAGE_WIDTH(800) | BIT_IMAGE_HEIGHT(600),
+       imx7_csi_reg_write(csi, BIT_IMAGE_WIDTH(IMX7_CSI_DEF_PIX_WIDTH) |
+                          BIT_IMAGE_HEIGHT(IMX7_CSI_DEF_PIX_HEIGHT),
                           CSI_CSIIMAG_PARA);
 
        imx7_csi_reg_write(csi, BIT_DMA_REFLASH_RFF, CSI_CSICR3);
@@ -336,16 +393,17 @@ static void imx7_csi_update_buf(struct imx7_csi *csi, dma_addr_t phys,
                imx7_csi_reg_write(csi, phys, CSI_CSIDMASA_FB1);
 }
 
+static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi);
+
 static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi)
 {
-       struct imx_media_video_dev *vdev = csi->vdev;
-       struct imx_media_buffer *buf;
+       struct imx7_csi_vb2_buffer *buf;
        struct vb2_buffer *vb2_buf;
        dma_addr_t phys[2];
        int i;
 
        for (i = 0; i < 2; i++) {
-               buf = imx_media_capture_device_next_buf(vdev);
+               buf = imx7_csi_video_next_buf(csi);
                if (buf) {
                        csi->active_vb2_buf[i] = buf;
                        vb2_buf = &buf->vbuf.vb2_buf;
@@ -362,7 +420,7 @@ static void imx7_csi_setup_vb2_buf(struct imx7_csi *csi)
 static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi,
                                         enum vb2_buffer_state return_status)
 {
-       struct imx_media_buffer *buf;
+       struct imx7_csi_vb2_buffer *buf;
        int i;
 
        /* return any remaining active frames with return_status */
@@ -378,13 +436,36 @@ static void imx7_csi_dma_unsetup_vb2_buf(struct imx7_csi *csi,
        }
 }
 
+static void imx7_csi_free_dma_buf(struct imx7_csi *csi,
+                                 struct imx7_csi_dma_buf *buf)
+{
+       if (buf->virt)
+               dma_free_coherent(csi->dev, buf->len, buf->virt, buf->phys);
+
+       buf->virt = NULL;
+       buf->phys = 0;
+}
+
+static int imx7_csi_alloc_dma_buf(struct imx7_csi *csi,
+                                 struct imx7_csi_dma_buf *buf, int size)
+{
+       imx7_csi_free_dma_buf(csi, buf);
+
+       buf->len = PAGE_ALIGN(size);
+       buf->virt = dma_alloc_coherent(csi->dev, buf->len, &buf->phys,
+                                      GFP_DMA | GFP_KERNEL);
+       if (!buf->virt)
+               return -ENOMEM;
+
+       return 0;
+}
+
 static int imx7_csi_dma_setup(struct imx7_csi *csi)
 {
-       struct imx_media_video_dev *vdev = csi->vdev;
        int ret;
 
-       ret = imx_media_alloc_dma_buf(csi->dev, &csi->underrun_buf,
-                                     vdev->fmt.sizeimage);
+       ret = imx7_csi_alloc_dma_buf(csi, &csi->underrun_buf,
+                                    csi->vdev_fmt.sizeimage);
        if (ret < 0) {
                v4l2_warn(&csi->sd, "consider increasing the CMA area\n");
                return ret;
@@ -403,7 +484,7 @@ static void imx7_csi_dma_cleanup(struct imx7_csi *csi,
                                 enum vb2_buffer_state return_status)
 {
        imx7_csi_dma_unsetup_vb2_buf(csi, return_status);
-       imx_media_free_dma_buf(csi->dev, &csi->underrun_buf);
+       imx7_csi_free_dma_buf(csi, &csi->underrun_buf);
 }
 
 static void imx7_csi_dma_stop(struct imx7_csi *csi)
@@ -420,7 +501,7 @@ static void imx7_csi_dma_stop(struct imx7_csi *csi)
        /*
         * and then wait for interrupt handler to mark completion.
         */
-       timeout_jiffies = msecs_to_jiffies(IMX_MEDIA_EOF_TIMEOUT);
+       timeout_jiffies = msecs_to_jiffies(IMX7_CSI_VIDEO_EOF_TIMEOUT);
        ret = wait_for_completion_timeout(&csi->last_eof_completion,
                                          timeout_jiffies);
        if (ret == 0)
@@ -431,8 +512,7 @@ static void imx7_csi_dma_stop(struct imx7_csi *csi)
 
 static void imx7_csi_configure(struct imx7_csi *csi)
 {
-       struct imx_media_video_dev *vdev = csi->vdev;
-       struct v4l2_pix_format *out_pix = &vdev->fmt;
+       struct v4l2_pix_format *out_pix = &csi->vdev_fmt;
        int width = out_pix->width;
        u32 stride = 0;
        u32 cr3 = BIT_FRMCNT_RST;
@@ -631,14 +711,13 @@ static void imx7_csi_error_recovery(struct imx7_csi *csi)
 
 static void imx7_csi_vb2_buf_done(struct imx7_csi *csi)
 {
-       struct imx_media_video_dev *vdev = csi->vdev;
-       struct imx_media_buffer *done, *next;
+       struct imx7_csi_vb2_buffer *done, *next;
        struct vb2_buffer *vb;
        dma_addr_t phys;
 
        done = csi->active_vb2_buf[csi->buf_num];
        if (done) {
-               done->vbuf.field = vdev->fmt.field;
+               done->vbuf.field = csi->vdev_fmt.field;
                done->vbuf.sequence = csi->frame_sequence;
                vb = &done->vbuf.vb2_buf;
                vb->timestamp = ktime_get_ns();
@@ -647,7 +726,7 @@ static void imx7_csi_vb2_buf_done(struct imx7_csi *csi)
        csi->frame_sequence++;
 
        /* get next queued buffer */
-       next = imx_media_capture_device_next_buf(vdev);
+       next = imx7_csi_video_next_buf(csi);
        if (next) {
                phys = vb2_dma_contig_plane_dma_addr(&next->vbuf.vb2_buf, 0);
                csi->active_vb2_buf[csi->buf_num] = next;
@@ -718,225 +797,1103 @@ static irqreturn_t imx7_csi_irq_handler(int irq, void *data)
 }
 
 /* -----------------------------------------------------------------------------
- * V4L2 Subdev Operations
+ * Format Helpers
  */
 
-static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable)
+#define IMX_BUS_FMTS(fmt...) (const u32[]) {fmt, 0}
+
+/*
+ * List of supported pixel formats for the subdevs. Keep V4L2_PIX_FMT_UYVY and
+ * MEDIA_BUS_FMT_UYVY8_2X8 first to match IMX7_CSI_DEF_PIX_FORMAT and
+ * IMX7_CSI_DEF_MBUS_CODE.
+ */
+static const struct imx7_csi_pixfmt pixel_formats[] = {
+       /*** YUV formats start here ***/
+       {
+               .fourcc = V4L2_PIX_FMT_UYVY,
+               .codes  = IMX_BUS_FMTS(
+                       MEDIA_BUS_FMT_UYVY8_2X8,
+                       MEDIA_BUS_FMT_UYVY8_1X16
+               ),
+               .yuv    = true,
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_YUYV,
+               .codes  = IMX_BUS_FMTS(
+                       MEDIA_BUS_FMT_YUYV8_2X8,
+                       MEDIA_BUS_FMT_YUYV8_1X16
+               ),
+               .yuv    = true,
+               .bpp    = 16,
+       },
+       /*** raw bayer and grayscale formats start here ***/
+       {
+               .fourcc = V4L2_PIX_FMT_SBGGR8,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR8_1X8),
+               .bpp    = 8,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SGBRG8,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG8_1X8),
+               .bpp    = 8,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SGRBG8,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG8_1X8),
+               .bpp    = 8,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SRGGB8,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB8_1X8),
+               .bpp    = 8,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SBGGR10,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR10_1X10),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SGBRG10,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG10_1X10),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SGRBG10,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG10_1X10),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SRGGB10,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB10_1X10),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SBGGR12,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR12_1X12),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SGBRG12,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG12_1X12),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SGRBG12,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG12_1X12),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SRGGB12,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB12_1X12),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SBGGR14,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SBGGR14_1X14),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SGBRG14,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGBRG14_1X14),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SGRBG14,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SGRBG14_1X14),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_SRGGB14,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_SRGGB14_1X14),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_GREY,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y8_1X8),
+               .bpp    = 8,
+       }, {
+               .fourcc = V4L2_PIX_FMT_Y10,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y10_1X10),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_Y12,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y12_1X12),
+               .bpp    = 16,
+       }, {
+               .fourcc = V4L2_PIX_FMT_Y14,
+               .codes  = IMX_BUS_FMTS(MEDIA_BUS_FMT_Y14_1X14),
+               .bpp    = 16,
+       },
+};
+
+/*
+ * Search in the pixel_formats[] array for an entry with the given fourcc
+ * return it.
+ */
+static const struct imx7_csi_pixfmt *imx7_csi_find_pixel_format(u32 fourcc)
 {
-       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
-       int ret = 0;
+       unsigned int i;
 
-       mutex_lock(&csi->lock);
+       for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
+               const struct imx7_csi_pixfmt *fmt = &pixel_formats[i];
 
-       if (!csi->src_sd) {
-               ret = -EPIPE;
-               goto out_unlock;
+               if (fmt->fourcc == fourcc)
+                       return fmt;
        }
 
-       if (csi->is_streaming == !!enable)
-               goto out_unlock;
+       return NULL;
+}
 
-       if (enable) {
-               ret = imx7_csi_init(csi);
-               if (ret < 0)
-                       goto out_unlock;
+/*
+ * Search in the pixel_formats[] array for an entry with the given media
+ * bus code and return it.
+ */
+static const struct imx7_csi_pixfmt *imx7_csi_find_mbus_format(u32 code)
+{
+       unsigned int i;
 
-               ret = v4l2_subdev_call(csi->src_sd, video, s_stream, 1);
-               if (ret < 0) {
-                       imx7_csi_deinit(csi, VB2_BUF_STATE_QUEUED);
-                       goto out_unlock;
+       for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
+               const struct imx7_csi_pixfmt *fmt = &pixel_formats[i];
+               unsigned int j;
+
+               if (!fmt->codes)
+                       continue;
+
+               for (j = 0; fmt->codes[j]; j++) {
+                       if (code == fmt->codes[j])
+                               return fmt;
                }
+       }
 
-               imx7_csi_enable(csi);
-       } else {
-               imx7_csi_disable(csi);
+       return NULL;
+}
 
-               v4l2_subdev_call(csi->src_sd, video, s_stream, 0);
+/*
+ * Enumerate entries in the pixel_formats[] array that match the
+ * requested search criteria. Return the media-bus code that matches
+ * the search criteria at the requested match index.
+ *
+ * @code: The returned media-bus code that matches the search criteria at
+ *        the requested match index.
+ * @index: The requested match index.
+ */
+static int imx7_csi_enum_mbus_formats(u32 *code, u32 index)
+{
+       unsigned int i;
 
-               imx7_csi_deinit(csi, VB2_BUF_STATE_ERROR);
-       }
+       for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
+               const struct imx7_csi_pixfmt *fmt = &pixel_formats[i];
+               unsigned int j;
 
-       csi->is_streaming = !!enable;
+               if (!fmt->codes)
+                       continue;
 
-out_unlock:
-       mutex_unlock(&csi->lock);
+               for (j = 0; fmt->codes[j]; j++) {
+                       if (index == 0) {
+                               *code = fmt->codes[j];
+                               return 0;
+                       }
 
-       return ret;
+                       index--;
+               }
+       }
+
+       return -EINVAL;
 }
 
-static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
-                            struct v4l2_subdev_state *sd_state)
+static int imx7_csi_mbus_fmt_to_pix_fmt(struct v4l2_pix_format *pix,
+                                       const struct v4l2_mbus_framefmt *mbus,
+                                       const struct imx7_csi_pixfmt *cc)
 {
-       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
-       struct v4l2_mbus_framefmt *mf;
-       int ret;
-       int i;
+       u32 width;
+       u32 stride;
 
-       for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
-               mf = v4l2_subdev_get_try_format(sd, sd_state, i);
-
-               ret = imx_media_init_mbus_fmt(mf, 800, 600, 0, V4L2_FIELD_NONE,
-                                             &csi->cc[i]);
-               if (ret < 0)
-                       return ret;
+       if (!cc) {
+               cc = imx7_csi_find_mbus_format(mbus->code);
+               if (!cc)
+                       return -EINVAL;
        }
 
+       /* Round up width for minimum burst size */
+       width = round_up(mbus->width, 8);
+
+       /* Round up stride for IDMAC line start address alignment */
+       stride = round_up((width * cc->bpp) >> 3, 8);
+
+       pix->width = width;
+       pix->height = mbus->height;
+       pix->pixelformat = cc->fourcc;
+       pix->colorspace = mbus->colorspace;
+       pix->xfer_func = mbus->xfer_func;
+       pix->ycbcr_enc = mbus->ycbcr_enc;
+       pix->quantization = mbus->quantization;
+       pix->field = mbus->field;
+       pix->bytesperline = stride;
+       pix->sizeimage = stride * pix->height;
+
        return 0;
 }
 
-static struct v4l2_mbus_framefmt *
-imx7_csi_get_format(struct imx7_csi *csi,
-                   struct v4l2_subdev_state *sd_state,
-                   unsigned int pad,
-                   enum v4l2_subdev_format_whence which)
+/* -----------------------------------------------------------------------------
+ * Video Capture Device - IOCTLs
+ */
+
+static int imx7_csi_video_querycap(struct file *file, void *fh,
+                                  struct v4l2_capability *cap)
 {
-       if (which == V4L2_SUBDEV_FORMAT_TRY)
-               return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad);
+       struct imx7_csi *csi = video_drvdata(file);
 
-       return &csi->format_mbus[pad];
+       strscpy(cap->driver, IMX7_CSI_VIDEO_NAME, sizeof(cap->driver));
+       strscpy(cap->card, IMX7_CSI_VIDEO_NAME, sizeof(cap->card));
+       snprintf(cap->bus_info, sizeof(cap->bus_info),
+                "platform:%s", dev_name(csi->dev));
+
+       return 0;
 }
 
-static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
-                                  struct v4l2_subdev_state *sd_state,
-                                  struct v4l2_subdev_mbus_code_enum *code)
+static int imx7_csi_video_enum_fmt_vid_cap(struct file *file, void *fh,
+                                          struct v4l2_fmtdesc *f)
 {
-       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
-       struct v4l2_mbus_framefmt *in_fmt;
-       int ret = 0;
+       unsigned int index = f->index;
+       unsigned int i;
 
-       mutex_lock(&csi->lock);
+       for (i = 0; i < ARRAY_SIZE(pixel_formats); i++) {
+               const struct imx7_csi_pixfmt *fmt = &pixel_formats[i];
 
-       in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
-                                    code->which);
+               /*
+                * If a media bus code is specified, only consider formats that
+                * match it.
+                */
+               if (f->mbus_code) {
+                       unsigned int j;
 
-       switch (code->pad) {
-       case IMX7_CSI_PAD_SINK:
-               ret = imx_media_enum_mbus_formats(&code->code, code->index,
-                                                 PIXFMT_SEL_ANY);
-               break;
-       case IMX7_CSI_PAD_SRC:
-               if (code->index != 0) {
-                       ret = -EINVAL;
-                       goto out_unlock;
+                       if (!fmt->codes)
+                               continue;
+
+                       for (j = 0; fmt->codes[j]; j++) {
+                               if (f->mbus_code == fmt->codes[j])
+                                       break;
+                       }
+
+                       if (!fmt->codes[j])
+                               continue;
                }
 
-               code->code = in_fmt->code;
-               break;
-       default:
-               ret = -EINVAL;
+               if (index == 0) {
+                       f->pixelformat = fmt->fourcc;
+                       return 0;
+               }
+
+               index--;
        }
 
-out_unlock:
-       mutex_unlock(&csi->lock);
+       return -EINVAL;
+}
 
-       return ret;
+static int imx7_csi_video_enum_framesizes(struct file *file, void *fh,
+                                         struct v4l2_frmsizeenum *fsize)
+{
+       const struct imx7_csi_pixfmt *cc;
+
+       if (fsize->index > 0)
+               return -EINVAL;
+
+       cc = imx7_csi_find_pixel_format(fsize->pixel_format);
+       if (!cc)
+               return -EINVAL;
+
+       /*
+        * TODO: The constraints are hardware-specific and may depend on the
+        * pixel format. This should come from the driver using
+        * imx_media_capture.
+        */
+       fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+       fsize->stepwise.min_width = 1;
+       fsize->stepwise.max_width = 65535;
+       fsize->stepwise.min_height = 1;
+       fsize->stepwise.max_height = 65535;
+       fsize->stepwise.step_width = 1;
+       fsize->stepwise.step_height = 1;
+
+       return 0;
 }
 
-static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_state *sd_state,
-                           struct v4l2_subdev_format *sdformat)
+static int imx7_csi_video_g_fmt_vid_cap(struct file *file, void *fh,
+                                       struct v4l2_format *f)
 {
-       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
-       struct v4l2_mbus_framefmt *fmt;
-       int ret = 0;
+       struct imx7_csi *csi = video_drvdata(file);
 
-       mutex_lock(&csi->lock);
+       f->fmt.pix = csi->vdev_fmt;
 
-       fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
-                                 sdformat->which);
-       if (!fmt) {
-               ret = -EINVAL;
-               goto out_unlock;
+       return 0;
+}
+
+static const struct imx7_csi_pixfmt *
+__imx7_csi_video_try_fmt(struct v4l2_pix_format *pixfmt,
+                        struct v4l2_rect *compose)
+{
+       struct v4l2_mbus_framefmt fmt_src;
+       const struct imx7_csi_pixfmt *cc;
+
+       /*
+        * Find the pixel format, default to the first supported format if not
+        * found.
+        */
+       cc = imx7_csi_find_pixel_format(pixfmt->pixelformat);
+       if (!cc) {
+               pixfmt->pixelformat = IMX7_CSI_DEF_PIX_FORMAT;
+               cc = imx7_csi_find_pixel_format(pixfmt->pixelformat);
        }
 
-       sdformat->format = *fmt;
+       /* Allow IDMAC interweave but enforce field order from source. */
+       if (V4L2_FIELD_IS_INTERLACED(pixfmt->field)) {
+               switch (pixfmt->field) {
+               case V4L2_FIELD_SEQ_TB:
+                       pixfmt->field = V4L2_FIELD_INTERLACED_TB;
+                       break;
+               case V4L2_FIELD_SEQ_BT:
+                       pixfmt->field = V4L2_FIELD_INTERLACED_BT;
+                       break;
+               default:
+                       break;
+               }
+       }
 
-out_unlock:
-       mutex_unlock(&csi->lock);
+       v4l2_fill_mbus_format(&fmt_src, pixfmt, 0);
+       imx7_csi_mbus_fmt_to_pix_fmt(pixfmt, &fmt_src, cc);
 
-       return ret;
+       if (compose) {
+               compose->width = fmt_src.width;
+               compose->height = fmt_src.height;
+       }
+
+       return cc;
 }
 
-static int imx7_csi_try_fmt(struct imx7_csi *csi,
-                           struct v4l2_subdev_state *sd_state,
-                           struct v4l2_subdev_format *sdformat,
-                           const struct imx_media_pixfmt **cc)
+static int imx7_csi_video_try_fmt_vid_cap(struct file *file, void *fh,
+                                         struct v4l2_format *f)
 {
-       const struct imx_media_pixfmt *in_cc;
-       struct v4l2_mbus_framefmt *in_fmt;
-       u32 code;
+       __imx7_csi_video_try_fmt(&f->fmt.pix, NULL);
+       return 0;
+}
 
-       in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
-                                    sdformat->which);
-       if (!in_fmt)
-               return -EINVAL;
+static int imx7_csi_video_s_fmt_vid_cap(struct file *file, void *fh,
+                                       struct v4l2_format *f)
+{
+       struct imx7_csi *csi = video_drvdata(file);
+       const struct imx7_csi_pixfmt *cc;
 
-       switch (sdformat->pad) {
-       case IMX7_CSI_PAD_SRC:
-               in_cc = imx_media_find_mbus_format(in_fmt->code,
-                                                  PIXFMT_SEL_ANY);
+       if (vb2_is_busy(&csi->q)) {
+               dev_err(csi->dev, "%s queue busy\n", __func__);
+               return -EBUSY;
+       }
 
-               sdformat->format.width = in_fmt->width;
-               sdformat->format.height = in_fmt->height;
-               sdformat->format.code = in_fmt->code;
-               sdformat->format.field = in_fmt->field;
-               *cc = in_cc;
+       cc = __imx7_csi_video_try_fmt(&f->fmt.pix, &csi->vdev_compose);
 
-               sdformat->format.colorspace = in_fmt->colorspace;
-               sdformat->format.xfer_func = in_fmt->xfer_func;
-               sdformat->format.quantization = in_fmt->quantization;
-               sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc;
-               break;
-       case IMX7_CSI_PAD_SINK:
-               *cc = imx_media_find_mbus_format(sdformat->format.code,
-                                                PIXFMT_SEL_ANY);
-               if (!*cc) {
-                       imx_media_enum_mbus_formats(&code, 0,
-                                                   PIXFMT_SEL_YUV_RGB);
-                       *cc = imx_media_find_mbus_format(code,
-                                                        PIXFMT_SEL_YUV_RGB);
-                       sdformat->format.code = (*cc)->codes[0];
-               }
+       csi->vdev_cc = cc;
+       csi->vdev_fmt = f->fmt.pix;
 
-               if (sdformat->format.field != V4L2_FIELD_INTERLACED)
-                       sdformat->format.field = V4L2_FIELD_NONE;
+       return 0;
+}
+
+static int imx7_csi_video_g_selection(struct file *file, void *fh,
+                                     struct v4l2_selection *s)
+{
+       struct imx7_csi *csi = video_drvdata(file);
+
+       switch (s->target) {
+       case V4L2_SEL_TGT_COMPOSE:
+       case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+       case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+               /* The compose rectangle is fixed to the source format. */
+               s->r = csi->vdev_compose;
+               break;
+       case V4L2_SEL_TGT_COMPOSE_PADDED:
+               /*
+                * The hardware writes with a configurable but fixed DMA burst
+                * size. If the source format width is not burst size aligned,
+                * the written frame contains padding to the right.
+                */
+               s->r.left = 0;
+               s->r.top = 0;
+               s->r.width = csi->vdev_fmt.width;
+               s->r.height = csi->vdev_fmt.height;
                break;
        default:
                return -EINVAL;
        }
 
-       imx_media_try_colorimetry(&sdformat->format, false);
-
        return 0;
 }
 
-static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
-                           struct v4l2_subdev_state *sd_state,
-                           struct v4l2_subdev_format *sdformat)
-{
-       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
-       const struct imx_media_pixfmt *outcc;
-       struct v4l2_mbus_framefmt *outfmt;
-       const struct imx_media_pixfmt *cc;
-       struct v4l2_mbus_framefmt *fmt;
-       struct v4l2_subdev_format format;
-       int ret = 0;
+static const struct v4l2_ioctl_ops imx7_csi_video_ioctl_ops = {
+       .vidioc_querycap                = imx7_csi_video_querycap,
 
-       if (sdformat->pad >= IMX7_CSI_PADS_NUM)
-               return -EINVAL;
+       .vidioc_enum_fmt_vid_cap        = imx7_csi_video_enum_fmt_vid_cap,
+       .vidioc_enum_framesizes         = imx7_csi_video_enum_framesizes,
 
-       mutex_lock(&csi->lock);
+       .vidioc_g_fmt_vid_cap           = imx7_csi_video_g_fmt_vid_cap,
+       .vidioc_try_fmt_vid_cap         = imx7_csi_video_try_fmt_vid_cap,
+       .vidioc_s_fmt_vid_cap           = imx7_csi_video_s_fmt_vid_cap,
 
-       if (csi->is_streaming) {
-               ret = -EBUSY;
-               goto out_unlock;
-       }
+       .vidioc_g_selection             = imx7_csi_video_g_selection,
 
-       ret = imx7_csi_try_fmt(csi, sd_state, sdformat, &cc);
-       if (ret < 0)
-               goto out_unlock;
+       .vidioc_reqbufs                 = vb2_ioctl_reqbufs,
+       .vidioc_create_bufs             = vb2_ioctl_create_bufs,
+       .vidioc_prepare_buf             = vb2_ioctl_prepare_buf,
+       .vidioc_querybuf                = vb2_ioctl_querybuf,
+       .vidioc_qbuf                    = vb2_ioctl_qbuf,
+       .vidioc_dqbuf                   = vb2_ioctl_dqbuf,
+       .vidioc_expbuf                  = vb2_ioctl_expbuf,
+       .vidioc_streamon                = vb2_ioctl_streamon,
+       .vidioc_streamoff               = vb2_ioctl_streamoff,
+};
 
-       fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
+/* -----------------------------------------------------------------------------
+ * Video Capture Device - Queue Operations
+ */
+
+static int imx7_csi_video_queue_setup(struct vb2_queue *vq,
+                                     unsigned int *nbuffers,
+                                     unsigned int *nplanes,
+                                     unsigned int sizes[],
+                                     struct device *alloc_devs[])
+{
+       struct imx7_csi *csi = vb2_get_drv_priv(vq);
+       struct v4l2_pix_format *pix = &csi->vdev_fmt;
+       unsigned int count = *nbuffers;
+
+       if (vq->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+               return -EINVAL;
+
+       if (*nplanes) {
+               if (*nplanes != 1 || sizes[0] < pix->sizeimage)
+                       return -EINVAL;
+               count += vq->num_buffers;
+       }
+
+       count = min_t(__u32, IMX7_CSI_VIDEO_MEM_LIMIT / pix->sizeimage, count);
+
+       if (*nplanes)
+               *nbuffers = (count < vq->num_buffers) ? 0 :
+                       count - vq->num_buffers;
+       else
+               *nbuffers = count;
+
+       *nplanes = 1;
+       sizes[0] = pix->sizeimage;
+
+       return 0;
+}
+
+static int imx7_csi_video_buf_init(struct vb2_buffer *vb)
+{
+       struct imx7_csi_vb2_buffer *buf = to_imx7_csi_vb2_buffer(vb);
+
+       INIT_LIST_HEAD(&buf->list);
+
+       return 0;
+}
+
+static int imx7_csi_video_buf_prepare(struct vb2_buffer *vb)
+{
+       struct imx7_csi *csi = vb2_get_drv_priv(vb->vb2_queue);
+       struct v4l2_pix_format *pix = &csi->vdev_fmt;
+
+       if (vb2_plane_size(vb, 0) < pix->sizeimage) {
+               dev_err(csi->dev,
+                       "data will not fit into plane (%lu < %lu)\n",
+                       vb2_plane_size(vb, 0), (long)pix->sizeimage);
+               return -EINVAL;
+       }
+
+       vb2_set_plane_payload(vb, 0, pix->sizeimage);
+
+       return 0;
+}
+
+static void imx7_csi_video_buf_queue(struct vb2_buffer *vb)
+{
+       struct imx7_csi *csi = vb2_get_drv_priv(vb->vb2_queue);
+       struct imx7_csi_vb2_buffer *buf = to_imx7_csi_vb2_buffer(vb);
+       unsigned long flags;
+
+       spin_lock_irqsave(&csi->q_lock, flags);
+
+       list_add_tail(&buf->list, &csi->ready_q);
+
+       spin_unlock_irqrestore(&csi->q_lock, flags);
+}
+
+static int imx7_csi_video_validate_fmt(struct imx7_csi *csi)
+{
+       struct v4l2_subdev_format fmt_src;
+       const struct imx7_csi_pixfmt *cc;
+       int ret;
+
+       /* Retrieve the media bus format on the source subdev. */
+       fmt_src.pad = IMX7_CSI_PAD_SRC;
+       fmt_src.which = V4L2_SUBDEV_FORMAT_ACTIVE;
+       ret = v4l2_subdev_call(&csi->sd, pad, get_fmt, NULL, &fmt_src);
+       if (ret)
+               return ret;
+
+       /*
+        * Verify that the media bus size matches the size set on the video
+        * node. It is sufficient to check the compose rectangle size without
+        * checking the rounded size from pix_fmt, as the rounded size is
+        * derived directly from the compose rectangle size, and will thus
+        * always match if the compose rectangle matches.
+        */
+       if (csi->vdev_compose.width != fmt_src.format.width ||
+           csi->vdev_compose.height != fmt_src.format.height)
+               return -EPIPE;
+
+       /*
+        * Verify that the media bus code is compatible with the pixel format
+        * set on the video node.
+        */
+       cc = imx7_csi_find_mbus_format(fmt_src.format.code);
+       if (!cc || csi->vdev_cc->yuv != cc->yuv)
+               return -EPIPE;
+
+       return 0;
+}
+
+static int imx7_csi_video_start_streaming(struct vb2_queue *vq,
+                                         unsigned int count)
+{
+       struct imx7_csi *csi = vb2_get_drv_priv(vq);
+       struct imx7_csi_vb2_buffer *buf, *tmp;
+       unsigned long flags;
+       int ret;
+
+       ret = imx7_csi_video_validate_fmt(csi);
+       if (ret) {
+               dev_err(csi->dev, "capture format not valid\n");
+               goto err_buffers;
+       }
+
+       mutex_lock(&csi->mdev.graph_mutex);
+
+       ret = __media_pipeline_start(&csi->sd.entity, &csi->pipe);
+       if (ret)
+               goto err_unlock;
+
+       ret = v4l2_subdev_call(&csi->sd, video, s_stream, 1);
+       if (ret)
+               goto err_stop;
+
+       mutex_unlock(&csi->mdev.graph_mutex);
+
+       return 0;
+
+err_stop:
+       __media_pipeline_stop(&csi->sd.entity);
+err_unlock:
+       mutex_unlock(&csi->mdev.graph_mutex);
+       dev_err(csi->dev, "pipeline start failed with %d\n", ret);
+err_buffers:
+       spin_lock_irqsave(&csi->q_lock, flags);
+       list_for_each_entry_safe(buf, tmp, &csi->ready_q, list) {
+               list_del(&buf->list);
+               vb2_buffer_done(&buf->vbuf.vb2_buf, VB2_BUF_STATE_QUEUED);
+       }
+       spin_unlock_irqrestore(&csi->q_lock, flags);
+       return ret;
+}
+
+static void imx7_csi_video_stop_streaming(struct vb2_queue *vq)
+{
+       struct imx7_csi *csi = vb2_get_drv_priv(vq);
+       struct imx7_csi_vb2_buffer *frame;
+       struct imx7_csi_vb2_buffer *tmp;
+       unsigned long flags;
+
+       mutex_lock(&csi->mdev.graph_mutex);
+       v4l2_subdev_call(&csi->sd, video, s_stream, 0);
+       __media_pipeline_stop(&csi->sd.entity);
+       mutex_unlock(&csi->mdev.graph_mutex);
+
+       /* release all active buffers */
+       spin_lock_irqsave(&csi->q_lock, flags);
+       list_for_each_entry_safe(frame, tmp, &csi->ready_q, list) {
+               list_del(&frame->list);
+               vb2_buffer_done(&frame->vbuf.vb2_buf, VB2_BUF_STATE_ERROR);
+       }
+       spin_unlock_irqrestore(&csi->q_lock, flags);
+}
+
+static const struct vb2_ops imx7_csi_video_qops = {
+       .queue_setup     = imx7_csi_video_queue_setup,
+       .buf_init        = imx7_csi_video_buf_init,
+       .buf_prepare     = imx7_csi_video_buf_prepare,
+       .buf_queue       = imx7_csi_video_buf_queue,
+       .wait_prepare    = vb2_ops_wait_prepare,
+       .wait_finish     = vb2_ops_wait_finish,
+       .start_streaming = imx7_csi_video_start_streaming,
+       .stop_streaming  = imx7_csi_video_stop_streaming,
+};
+
+/* -----------------------------------------------------------------------------
+ * Video Capture Device - File Operations
+ */
+
+static int imx7_csi_video_open(struct file *file)
+{
+       struct imx7_csi *csi = video_drvdata(file);
+       int ret;
+
+       if (mutex_lock_interruptible(&csi->vdev_mutex))
+               return -ERESTARTSYS;
+
+       ret = v4l2_fh_open(file);
+       if (ret) {
+               dev_err(csi->dev, "v4l2_fh_open failed\n");
+               goto out;
+       }
+
+       ret = v4l2_pipeline_pm_get(&csi->vdev->entity);
+       if (ret)
+               v4l2_fh_release(file);
+
+out:
+       mutex_unlock(&csi->vdev_mutex);
+       return ret;
+}
+
+static int imx7_csi_video_release(struct file *file)
+{
+       struct imx7_csi *csi = video_drvdata(file);
+       struct vb2_queue *vq = &csi->q;
+
+       mutex_lock(&csi->vdev_mutex);
+
+       if (file->private_data == vq->owner) {
+               vb2_queue_release(vq);
+               vq->owner = NULL;
+       }
+
+       v4l2_pipeline_pm_put(&csi->vdev->entity);
+
+       v4l2_fh_release(file);
+       mutex_unlock(&csi->vdev_mutex);
+       return 0;
+}
+
+static const struct v4l2_file_operations imx7_csi_video_fops = {
+       .owner          = THIS_MODULE,
+       .open           = imx7_csi_video_open,
+       .release        = imx7_csi_video_release,
+       .poll           = vb2_fop_poll,
+       .unlocked_ioctl = video_ioctl2,
+       .mmap           = vb2_fop_mmap,
+};
+
+/* -----------------------------------------------------------------------------
+ * Video Capture Device - Init & Cleanup
+ */
+
+static struct imx7_csi_vb2_buffer *imx7_csi_video_next_buf(struct imx7_csi *csi)
+{
+       struct imx7_csi_vb2_buffer *buf = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&csi->q_lock, flags);
+
+       /* get next queued buffer */
+       if (!list_empty(&csi->ready_q)) {
+               buf = list_entry(csi->ready_q.next, struct imx7_csi_vb2_buffer,
+                                list);
+               list_del(&buf->list);
+       }
+
+       spin_unlock_irqrestore(&csi->q_lock, flags);
+
+       return buf;
+}
+
+static int imx7_csi_video_init_format(struct imx7_csi *csi)
+{
+       struct v4l2_subdev_format fmt_src = {
+               .pad = IMX7_CSI_PAD_SRC,
+               .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+       };
+       fmt_src.format.code = IMX7_CSI_DEF_MBUS_CODE;
+       fmt_src.format.width = IMX7_CSI_DEF_PIX_WIDTH;
+       fmt_src.format.height = IMX7_CSI_DEF_PIX_HEIGHT;
+
+       imx7_csi_mbus_fmt_to_pix_fmt(&csi->vdev_fmt, &fmt_src.format, NULL);
+       csi->vdev_compose.width = fmt_src.format.width;
+       csi->vdev_compose.height = fmt_src.format.height;
+
+       csi->vdev_cc = imx7_csi_find_pixel_format(csi->vdev_fmt.pixelformat);
+
+       return 0;
+}
+
+static int imx7_csi_video_register(struct imx7_csi *csi)
+{
+       struct v4l2_subdev *sd = &csi->sd;
+       struct v4l2_device *v4l2_dev = sd->v4l2_dev;
+       struct video_device *vdev = csi->vdev;
+       int ret;
+
+       vdev->v4l2_dev = v4l2_dev;
+
+       /* Initialize the default format and compose rectangle. */
+       ret = imx7_csi_video_init_format(csi);
+       if (ret < 0)
+               return ret;
+
+       /* Register the video device. */
+       ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+       if (ret) {
+               dev_err(csi->dev, "Failed to register video device\n");
+               return ret;
+       }
+
+       dev_info(csi->dev, "Registered %s as /dev/%s\n", vdev->name,
+                video_device_node_name(vdev));
+
+       /* Create the link from the CSI subdev to the video device. */
+       ret = media_create_pad_link(&sd->entity, IMX7_CSI_PAD_SRC,
+                                   &vdev->entity, 0, MEDIA_LNK_FL_IMMUTABLE |
+                                   MEDIA_LNK_FL_ENABLED);
+       if (ret) {
+               dev_err(csi->dev, "failed to create link to device node\n");
+               video_unregister_device(vdev);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void imx7_csi_video_unregister(struct imx7_csi *csi)
+{
+       media_entity_cleanup(&csi->vdev->entity);
+       video_unregister_device(csi->vdev);
+}
+
+static int imx7_csi_video_init(struct imx7_csi *csi)
+{
+       struct video_device *vdev;
+       struct vb2_queue *vq;
+       int ret;
+
+       mutex_init(&csi->vdev_mutex);
+       INIT_LIST_HEAD(&csi->ready_q);
+       spin_lock_init(&csi->q_lock);
+
+       /* Allocate and initialize the video device. */
+       vdev = video_device_alloc();
+       if (!vdev)
+               return -ENOMEM;
+
+       vdev->fops = &imx7_csi_video_fops;
+       vdev->ioctl_ops = &imx7_csi_video_ioctl_ops;
+       vdev->minor = -1;
+       vdev->release = video_device_release;
+       vdev->vfl_dir = VFL_DIR_RX;
+       vdev->tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM;
+       vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING
+                        | V4L2_CAP_IO_MC;
+       vdev->lock = &csi->vdev_mutex;
+       vdev->queue = &csi->q;
+
+       snprintf(vdev->name, sizeof(vdev->name), "%s capture", csi->sd.name);
+
+       video_set_drvdata(vdev, csi);
+       csi->vdev = vdev;
+
+       /* Initialize the video device pad. */
+       csi->vdev_pad.flags = MEDIA_PAD_FL_SINK;
+       ret = media_entity_pads_init(&vdev->entity, 1, &csi->vdev_pad);
+       if (ret) {
+               video_device_release(vdev);
+               return ret;
+       }
+
+       /* Initialize the vb2 queue. */
+       vq = &csi->q;
+       vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+       vq->io_modes = VB2_MMAP | VB2_DMABUF;
+       vq->drv_priv = csi;
+       vq->buf_struct_size = sizeof(struct imx7_csi_vb2_buffer);
+       vq->ops = &imx7_csi_video_qops;
+       vq->mem_ops = &vb2_dma_contig_memops;
+       vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+       vq->lock = &csi->vdev_mutex;
+       vq->min_buffers_needed = 2;
+       vq->dev = csi->dev;
+
+       ret = vb2_queue_init(vq);
+       if (ret) {
+               dev_err(csi->dev, "vb2_queue_init failed\n");
+               video_device_release(vdev);
+               return ret;
+       }
+
+       return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * V4L2 Subdev Operations
+ */
+
+static int imx7_csi_s_stream(struct v4l2_subdev *sd, int enable)
+{
+       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+       int ret = 0;
+
+       mutex_lock(&csi->lock);
+
+       if (!csi->src_sd) {
+               ret = -EPIPE;
+               goto out_unlock;
+       }
+
+       if (csi->is_streaming == !!enable)
+               goto out_unlock;
+
+       if (enable) {
+               ret = imx7_csi_init(csi);
+               if (ret < 0)
+                       goto out_unlock;
+
+               ret = v4l2_subdev_call(csi->src_sd, video, s_stream, 1);
+               if (ret < 0) {
+                       imx7_csi_deinit(csi, VB2_BUF_STATE_QUEUED);
+                       goto out_unlock;
+               }
+
+               imx7_csi_enable(csi);
+       } else {
+               imx7_csi_disable(csi);
+
+               v4l2_subdev_call(csi->src_sd, video, s_stream, 0);
+
+               imx7_csi_deinit(csi, VB2_BUF_STATE_ERROR);
+       }
+
+       csi->is_streaming = !!enable;
+
+out_unlock:
+       mutex_unlock(&csi->lock);
+
+       return ret;
+}
+
+static struct v4l2_mbus_framefmt *
+imx7_csi_get_format(struct imx7_csi *csi,
+                   struct v4l2_subdev_state *sd_state,
+                   unsigned int pad,
+                   enum v4l2_subdev_format_whence which)
+{
+       if (which == V4L2_SUBDEV_FORMAT_TRY)
+               return v4l2_subdev_get_try_format(&csi->sd, sd_state, pad);
+
+       return &csi->format_mbus[pad];
+}
+
+static int imx7_csi_init_cfg(struct v4l2_subdev *sd,
+                            struct v4l2_subdev_state *sd_state)
+{
+       const enum v4l2_subdev_format_whence which =
+               sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
+       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+       const struct imx7_csi_pixfmt *cc;
+       int i;
+
+       cc = imx7_csi_find_mbus_format(IMX7_CSI_DEF_MBUS_CODE);
+
+       for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
+               struct v4l2_mbus_framefmt *mf =
+                       imx7_csi_get_format(csi, sd_state, i, which);
+
+               mf->code = IMX7_CSI_DEF_MBUS_CODE;
+               mf->width = IMX7_CSI_DEF_PIX_WIDTH;
+               mf->height = IMX7_CSI_DEF_PIX_HEIGHT;
+               mf->field = V4L2_FIELD_NONE;
+
+               mf->colorspace = V4L2_COLORSPACE_SRGB;
+               mf->xfer_func = V4L2_MAP_XFER_FUNC_DEFAULT(mf->colorspace);
+               mf->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(mf->colorspace);
+               mf->quantization = V4L2_MAP_QUANTIZATION_DEFAULT(!cc->yuv,
+                                       mf->colorspace, mf->ycbcr_enc);
+
+               csi->cc[i] = cc;
+       }
+
+       return 0;
+}
+
+static int imx7_csi_enum_mbus_code(struct v4l2_subdev *sd,
+                                  struct v4l2_subdev_state *sd_state,
+                                  struct v4l2_subdev_mbus_code_enum *code)
+{
+       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *in_fmt;
+       int ret = 0;
+
+       mutex_lock(&csi->lock);
+
+       in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
+                                    code->which);
+
+       switch (code->pad) {
+       case IMX7_CSI_PAD_SINK:
+               ret = imx7_csi_enum_mbus_formats(&code->code, code->index);
+               break;
+       case IMX7_CSI_PAD_SRC:
+               if (code->index != 0) {
+                       ret = -EINVAL;
+                       goto out_unlock;
+               }
+
+               code->code = in_fmt->code;
+               break;
+       default:
+               ret = -EINVAL;
+       }
+
+out_unlock:
+       mutex_unlock(&csi->lock);
+
+       return ret;
+}
+
+static int imx7_csi_get_fmt(struct v4l2_subdev *sd,
+                           struct v4l2_subdev_state *sd_state,
+                           struct v4l2_subdev_format *sdformat)
+{
+       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+       struct v4l2_mbus_framefmt *fmt;
+       int ret = 0;
+
+       mutex_lock(&csi->lock);
+
+       fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
+                                 sdformat->which);
+       if (!fmt) {
+               ret = -EINVAL;
+               goto out_unlock;
+       }
+
+       sdformat->format = *fmt;
+
+out_unlock:
+       mutex_unlock(&csi->lock);
+
+       return ret;
+}
+
+/*
+ * Default the colorspace in tryfmt to SRGB if set to an unsupported
+ * colorspace or not initialized. Then set the remaining colorimetry
+ * parameters based on the colorspace if they are uninitialized.
+ *
+ * tryfmt->code must be set on entry.
+ */
+static void imx7_csi_try_colorimetry(struct v4l2_mbus_framefmt *tryfmt)
+{
+       const struct imx7_csi_pixfmt *cc;
+       bool is_rgb = false;
+
+       cc = imx7_csi_find_mbus_format(tryfmt->code);
+       if (cc && !cc->yuv)
+               is_rgb = true;
+
+       switch (tryfmt->colorspace) {
+       case V4L2_COLORSPACE_SMPTE170M:
+       case V4L2_COLORSPACE_REC709:
+       case V4L2_COLORSPACE_JPEG:
+       case V4L2_COLORSPACE_SRGB:
+       case V4L2_COLORSPACE_BT2020:
+       case V4L2_COLORSPACE_OPRGB:
+       case V4L2_COLORSPACE_DCI_P3:
+       case V4L2_COLORSPACE_RAW:
+               break;
+       default:
+               tryfmt->colorspace = V4L2_COLORSPACE_SRGB;
+               break;
+       }
+
+       if (tryfmt->xfer_func == V4L2_XFER_FUNC_DEFAULT)
+               tryfmt->xfer_func =
+                       V4L2_MAP_XFER_FUNC_DEFAULT(tryfmt->colorspace);
+
+       if (tryfmt->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT)
+               tryfmt->ycbcr_enc =
+                       V4L2_MAP_YCBCR_ENC_DEFAULT(tryfmt->colorspace);
+
+       if (tryfmt->quantization == V4L2_QUANTIZATION_DEFAULT)
+               tryfmt->quantization =
+                       V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb,
+                                                     tryfmt->colorspace,
+                                                     tryfmt->ycbcr_enc);
+}
+
+static int imx7_csi_try_fmt(struct imx7_csi *csi,
+                           struct v4l2_subdev_state *sd_state,
+                           struct v4l2_subdev_format *sdformat,
+                           const struct imx7_csi_pixfmt **cc)
+{
+       const struct imx7_csi_pixfmt *in_cc;
+       struct v4l2_mbus_framefmt *in_fmt;
+       u32 code;
+
+       in_fmt = imx7_csi_get_format(csi, sd_state, IMX7_CSI_PAD_SINK,
+                                    sdformat->which);
+       if (!in_fmt)
+               return -EINVAL;
+
+       switch (sdformat->pad) {
+       case IMX7_CSI_PAD_SRC:
+               in_cc = imx7_csi_find_mbus_format(in_fmt->code);
+
+               sdformat->format.width = in_fmt->width;
+               sdformat->format.height = in_fmt->height;
+               sdformat->format.code = in_fmt->code;
+               sdformat->format.field = in_fmt->field;
+               *cc = in_cc;
+
+               sdformat->format.colorspace = in_fmt->colorspace;
+               sdformat->format.xfer_func = in_fmt->xfer_func;
+               sdformat->format.quantization = in_fmt->quantization;
+               sdformat->format.ycbcr_enc = in_fmt->ycbcr_enc;
+               break;
+       case IMX7_CSI_PAD_SINK:
+               *cc = imx7_csi_find_mbus_format(sdformat->format.code);
+               if (!*cc) {
+                       code = IMX7_CSI_DEF_MBUS_CODE;
+                       *cc = imx7_csi_find_mbus_format(code);
+                       sdformat->format.code = code;
+               }
+
+               if (sdformat->format.field != V4L2_FIELD_INTERLACED)
+                       sdformat->format.field = V4L2_FIELD_NONE;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       imx7_csi_try_colorimetry(&sdformat->format);
+
+       return 0;
+}
+
+static int imx7_csi_set_fmt(struct v4l2_subdev *sd,
+                           struct v4l2_subdev_state *sd_state,
+                           struct v4l2_subdev_format *sdformat)
+{
+       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
+       const struct imx7_csi_pixfmt *outcc;
+       struct v4l2_mbus_framefmt *outfmt;
+       const struct imx7_csi_pixfmt *cc;
+       struct v4l2_mbus_framefmt *fmt;
+       struct v4l2_subdev_format format;
+       int ret = 0;
+
+       if (sdformat->pad >= IMX7_CSI_PADS_NUM)
+               return -EINVAL;
+
+       mutex_lock(&csi->lock);
+
+       if (csi->is_streaming) {
+               ret = -EBUSY;
+               goto out_unlock;
+       }
+
+       ret = imx7_csi_try_fmt(csi, sd_state, sdformat, &cc);
+       if (ret < 0)
+               goto out_unlock;
+
+       fmt = imx7_csi_get_format(csi, sd_state, sdformat->pad,
                                  sdformat->which);
        if (!fmt) {
                ret = -EINVAL;
@@ -977,9 +1934,8 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
                                      struct v4l2_subdev_format *sink_fmt)
 {
        struct imx7_csi *csi = v4l2_get_subdevdata(sd);
-       struct imx_media_video_dev *vdev = csi->vdev;
-       const struct v4l2_pix_format *out_pix = &vdev->fmt;
-       struct media_pad *pad;
+       struct media_pad *pad = NULL;
+       unsigned int i;
        int ret;
 
        if (!csi->src_sd)
@@ -1001,7 +1957,17 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
 
        case MEDIA_ENT_F_VID_MUX:
                /* The input is the mux, check its input. */
-               pad = imx_media_pipeline_pad(&csi->src_sd->entity, 0, 0, true);
+               for (i = 0; i < csi->src_sd->entity.num_pads; i++) {
+                       struct media_pad *spad = &csi->src_sd->entity.pads[i];
+
+                       if (!(spad->flags & MEDIA_PAD_FL_SINK))
+                               continue;
+
+                       pad = media_pad_remote_pad_first(spad);
+                       if (pad)
+                               break;
+               }
+
                if (!pad)
                        return -ENODEV;
 
@@ -1017,29 +1983,6 @@ static int imx7_csi_pad_link_validate(struct v4l2_subdev *sd,
                break;
        }
 
-       /* Validate the sink link, ensure the pixel format is supported. */
-       switch (out_pix->pixelformat) {
-       case V4L2_PIX_FMT_UYVY:
-       case V4L2_PIX_FMT_YUYV:
-       case V4L2_PIX_FMT_GREY:
-       case V4L2_PIX_FMT_Y10:
-       case V4L2_PIX_FMT_Y12:
-       case V4L2_PIX_FMT_SBGGR8:
-       case V4L2_PIX_FMT_SGBRG8:
-       case V4L2_PIX_FMT_SGRBG8:
-       case V4L2_PIX_FMT_SRGGB8:
-       case V4L2_PIX_FMT_SBGGR16:
-       case V4L2_PIX_FMT_SGBRG16:
-       case V4L2_PIX_FMT_SGRBG16:
-       case V4L2_PIX_FMT_SRGGB16:
-               break;
-
-       default:
-               dev_dbg(csi->dev, "Invalid capture pixel format 0x%08x\n",
-                       out_pix->pixelformat);
-               return -EINVAL;
-       }
-
        return 0;
 }
 
@@ -1047,31 +1990,27 @@ static int imx7_csi_registered(struct v4l2_subdev *sd)
 {
        struct imx7_csi *csi = v4l2_get_subdevdata(sd);
        int ret;
-       int i;
 
-       for (i = 0; i < IMX7_CSI_PADS_NUM; i++) {
-               /* set a default mbus format  */
-               ret = imx_media_init_mbus_fmt(&csi->format_mbus[i],
-                                             800, 600, 0, V4L2_FIELD_NONE,
-                                             &csi->cc[i]);
-               if (ret < 0)
-                       return ret;
+       ret = imx7_csi_video_init(csi);
+       if (ret)
+               return ret;
 
-               /* init default frame interval */
-               csi->frame_interval[i].numerator = 1;
-               csi->frame_interval[i].denominator = 30;
-       }
+       ret = imx7_csi_video_register(csi);
+       if (ret)
+               return ret;
 
-       csi->vdev = imx_media_capture_device_init(csi->sd.dev, &csi->sd,
-                                                 IMX7_CSI_PAD_SRC, false);
-       if (IS_ERR(csi->vdev))
-               return PTR_ERR(csi->vdev);
+       ret = v4l2_device_register_subdev_nodes(&csi->v4l2_dev);
+       if (ret)
+               goto err_unreg;
 
-       ret = imx_media_capture_device_register(csi->vdev,
-                                               MEDIA_LNK_FL_IMMUTABLE);
+       ret = media_device_register(&csi->mdev);
        if (ret)
-               imx_media_capture_device_remove(csi->vdev);
+               goto err_unreg;
+
+       return 0;
 
+err_unreg:
+       imx7_csi_video_unregister(csi);
        return ret;
 }
 
@@ -1079,8 +2018,7 @@ static void imx7_csi_unregistered(struct v4l2_subdev *sd)
 {
        struct imx7_csi *csi = v4l2_get_subdevdata(sd);
 
-       imx_media_capture_device_unregister(csi->vdev);
-       imx_media_capture_device_remove(csi->vdev);
+       imx7_csi_video_unregister(csi);
 }
 
 static const struct v4l2_subdev_video_ops imx7_csi_video_ops = {
@@ -1125,21 +2063,22 @@ static int imx7_csi_notify_bound(struct v4l2_async_notifier *notifier,
        struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier);
        struct media_pad *sink = &csi->sd.entity.pads[IMX7_CSI_PAD_SINK];
 
-       /*
-        * If the subdev is a video mux, it must be one of the CSI
-        * muxes. Mark it as such via its group id.
-        */
-       if (sd->entity.function == MEDIA_ENT_F_VID_MUX)
-               sd->grp_id = IMX_MEDIA_GRP_ID_CSI_MUX;
-
        csi->src_sd = sd;
 
        return v4l2_create_fwnode_links_to_pad(sd, sink, MEDIA_LNK_FL_ENABLED |
                                               MEDIA_LNK_FL_IMMUTABLE);
 }
 
+static int imx7_csi_notify_complete(struct v4l2_async_notifier *notifier)
+{
+       struct imx7_csi *csi = imx7_csi_notifier_to_dev(notifier);
+
+       return v4l2_device_register_subdev_nodes(&csi->v4l2_dev);
+}
+
 static const struct v4l2_async_notifier_operations imx7_csi_notify_ops = {
        .bound = imx7_csi_notify_bound,
+       .complete = imx7_csi_notify_complete,
 };
 
 static int imx7_csi_async_register(struct imx7_csi *csi)
@@ -1168,48 +2107,133 @@ static int imx7_csi_async_register(struct imx7_csi *csi)
 
        csi->notifier.ops = &imx7_csi_notify_ops;
 
-       ret = v4l2_async_subdev_nf_register(&csi->sd, &csi->notifier);
+       ret = v4l2_async_nf_register(&csi->v4l2_dev, &csi->notifier);
        if (ret)
                return ret;
 
-       return v4l2_async_register_subdev(&csi->sd);
+       return 0;
+}
+
+static void imx7_csi_media_cleanup(struct imx7_csi *csi)
+{
+       v4l2_device_unregister(&csi->v4l2_dev);
+       media_device_unregister(&csi->mdev);
+       media_device_cleanup(&csi->mdev);
+}
+
+static const struct media_device_ops imx7_csi_media_ops = {
+       .link_notify = v4l2_pipeline_link_notify,
+};
+
+static int imx7_csi_media_dev_init(struct imx7_csi *csi)
+{
+       int ret;
+
+       strscpy(csi->mdev.model, "imx-media", sizeof(csi->mdev.model));
+       csi->mdev.ops = &imx7_csi_media_ops;
+       csi->mdev.dev = csi->dev;
+
+       csi->v4l2_dev.mdev = &csi->mdev;
+       strscpy(csi->v4l2_dev.name, "imx-media",
+               sizeof(csi->v4l2_dev.name));
+       snprintf(csi->mdev.bus_info, sizeof(csi->mdev.bus_info),
+                "platform:%s", dev_name(csi->mdev.dev));
+
+       media_device_init(&csi->mdev);
+
+       ret = v4l2_device_register(csi->dev, &csi->v4l2_dev);
+       if (ret < 0) {
+               v4l2_err(&csi->v4l2_dev,
+                        "Failed to register v4l2_device: %d\n", ret);
+               goto cleanup;
+       }
+
+       return 0;
+
+cleanup:
+       media_device_cleanup(&csi->mdev);
+
+       return ret;
+}
+
+static int imx7_csi_media_init(struct imx7_csi *csi)
+{
+       unsigned int i;
+       int ret;
+
+       /* add media device */
+       ret = imx7_csi_media_dev_init(csi);
+       if (ret)
+               return ret;
+
+       v4l2_subdev_init(&csi->sd, &imx7_csi_subdev_ops);
+       v4l2_set_subdevdata(&csi->sd, csi);
+       csi->sd.internal_ops = &imx7_csi_internal_ops;
+       csi->sd.entity.ops = &imx7_csi_entity_ops;
+       csi->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+       csi->sd.dev = csi->dev;
+       csi->sd.owner = THIS_MODULE;
+       csi->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+       snprintf(csi->sd.name, sizeof(csi->sd.name), "csi");
+
+       for (i = 0; i < IMX7_CSI_PADS_NUM; i++)
+               csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ?
+                       MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+
+       ret = media_entity_pads_init(&csi->sd.entity, IMX7_CSI_PADS_NUM,
+                                    csi->pad);
+       if (ret)
+               goto error;
+
+       ret = v4l2_device_register_subdev(&csi->v4l2_dev, &csi->sd);
+       if (ret)
+               goto error;
+
+       return 0;
+
+error:
+       imx7_csi_media_cleanup(csi);
+       return ret;
 }
 
 static int imx7_csi_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct device_node *node = dev->of_node;
-       struct imx_media_dev *imxmd;
        struct imx7_csi *csi;
-       int i, ret;
+       int ret;
 
        csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL);
        if (!csi)
                return -ENOMEM;
 
        csi->dev = dev;
+       platform_set_drvdata(pdev, csi);
 
+       spin_lock_init(&csi->irqlock);
+       mutex_init(&csi->lock);
+
+       /* Acquire resources and install interrupt handler. */
        csi->mclk = devm_clk_get(&pdev->dev, "mclk");
        if (IS_ERR(csi->mclk)) {
                ret = PTR_ERR(csi->mclk);
                dev_err(dev, "Failed to get mclk: %d", ret);
-               return ret;
+               goto destroy_mutex;
        }
 
        csi->irq = platform_get_irq(pdev, 0);
-       if (csi->irq < 0)
-               return csi->irq;
+       if (csi->irq < 0) {
+               ret = csi->irq;
+               goto destroy_mutex;
+       }
 
        csi->regbase = devm_platform_ioremap_resource(pdev, 0);
-       if (IS_ERR(csi->regbase))
-               return PTR_ERR(csi->regbase);
+       if (IS_ERR(csi->regbase)) {
+               ret = PTR_ERR(csi->regbase);
+               goto destroy_mutex;
+       }
 
        csi->model = (enum imx_csi_model)(uintptr_t)of_device_get_match_data(&pdev->dev);
 
-       spin_lock_init(&csi->irqlock);
-       mutex_init(&csi->lock);
-
-       /* install interrupt handler */
        ret = devm_request_irq(dev, csi->irq, imx7_csi_irq_handler, 0, "csi",
                               (void *)csi);
        if (ret < 0) {
@@ -1217,42 +2241,15 @@ static int imx7_csi_probe(struct platform_device *pdev)
                goto destroy_mutex;
        }
 
-       /* add media device */
-       imxmd = imx_media_dev_init(dev, NULL);
-       if (IS_ERR(imxmd)) {
-               ret = PTR_ERR(imxmd);
+       /* Initialize all the media device infrastructure. */
+       ret = imx7_csi_media_init(csi);
+       if (ret)
                goto destroy_mutex;
-       }
-       platform_set_drvdata(pdev, &csi->sd);
-
-       ret = imx_media_of_add_csi(imxmd, node);
-       if (ret < 0 && ret != -ENODEV && ret != -EEXIST)
-               goto cleanup;
-
-       ret = imx_media_dev_notifier_register(imxmd, NULL);
-       if (ret < 0)
-               goto cleanup;
 
-       csi->imxmd = imxmd;
-       v4l2_subdev_init(&csi->sd, &imx7_csi_subdev_ops);
-       v4l2_set_subdevdata(&csi->sd, csi);
-       csi->sd.internal_ops = &imx7_csi_internal_ops;
-       csi->sd.entity.ops = &imx7_csi_entity_ops;
-       csi->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
-       csi->sd.dev = &pdev->dev;
-       csi->sd.owner = THIS_MODULE;
-       csi->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
-       csi->sd.grp_id = IMX_MEDIA_GRP_ID_CSI;
-       snprintf(csi->sd.name, sizeof(csi->sd.name), "csi");
-
-       for (i = 0; i < IMX7_CSI_PADS_NUM; i++)
-               csi->pad[i].flags = (i == IMX7_CSI_PAD_SINK) ?
-                       MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
-
-       ret = media_entity_pads_init(&csi->sd.entity, IMX7_CSI_PADS_NUM,
-                                    csi->pad);
-       if (ret < 0)
-               goto cleanup;
+       /* Set the default mbus formats. */
+       ret = imx7_csi_init_cfg(&csi->sd, NULL);
+       if (ret)
+               goto media_cleanup;
 
        ret = imx7_csi_async_register(csi);
        if (ret)
@@ -1263,13 +2260,8 @@ static int imx7_csi_probe(struct platform_device *pdev)
 subdev_notifier_cleanup:
        v4l2_async_nf_unregister(&csi->notifier);
        v4l2_async_nf_cleanup(&csi->notifier);
-
-cleanup:
-       v4l2_async_nf_unregister(&imxmd->notifier);
-       v4l2_async_nf_cleanup(&imxmd->notifier);
-       v4l2_device_unregister(&imxmd->v4l2_dev);
-       media_device_unregister(&imxmd->md);
-       media_device_cleanup(&imxmd->md);
+media_cleanup:
+       imx7_csi_media_cleanup(csi);
 
 destroy_mutex:
        mutex_destroy(&csi->lock);
@@ -1279,20 +2271,13 @@ destroy_mutex:
 
 static int imx7_csi_remove(struct platform_device *pdev)
 {
-       struct v4l2_subdev *sd = platform_get_drvdata(pdev);
-       struct imx7_csi *csi = v4l2_get_subdevdata(sd);
-       struct imx_media_dev *imxmd = csi->imxmd;
-
-       v4l2_async_nf_unregister(&imxmd->notifier);
-       v4l2_async_nf_cleanup(&imxmd->notifier);
+       struct imx7_csi *csi = platform_get_drvdata(pdev);
 
-       media_device_unregister(&imxmd->md);
-       v4l2_device_unregister(&imxmd->v4l2_dev);
-       media_device_cleanup(&imxmd->md);
+       imx7_csi_media_cleanup(csi);
 
        v4l2_async_nf_unregister(&csi->notifier);
        v4l2_async_nf_cleanup(&csi->notifier);
-       v4l2_async_unregister_subdev(sd);
+       v4l2_async_unregister_subdev(&csi->sd);
 
        mutex_destroy(&csi->lock);
 
index 68588e9..28aacda 100644 (file)
@@ -395,7 +395,7 @@ static int iss_pipeline_disable(struct iss_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;
 
@@ -464,7 +464,7 @@ static int iss_pipeline_enable(struct iss_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;
 
@@ -553,7 +553,7 @@ static int iss_pipeline_is_last(struct media_entity *me)
        pipe = to_iss_pipeline(me);
        if (pipe->stream_state == ISS_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;
 }
 
index 124ab2f..04ce0e7 100644 (file)
@@ -538,7 +538,7 @@ static int csi2_configure(struct iss_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);
        pdata = sensor->host_priv;
 
index d0da083..9512cd3 100644 (file)
@@ -190,7 +190,7 @@ iss_video_remote_subdev(struct iss_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;
index 2992fb8..4af5a83 100644 (file)
@@ -109,7 +109,7 @@ struct rkvdec_h264_run {
        const struct v4l2_ctrl_h264_sps *sps;
        const struct v4l2_ctrl_h264_pps *pps;
        const struct v4l2_ctrl_h264_scaling_matrix *scaling_matrix;
-       int ref_buf_idx[V4L2_H264_NUM_DPB_ENTRIES];
+       struct vb2_buffer *ref_buf[V4L2_H264_NUM_DPB_ENTRIES];
 };
 
 struct rkvdec_h264_ctx {
@@ -742,17 +742,16 @@ static void lookup_ref_buf_idx(struct rkvdec_ctx *ctx,
                struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
                const struct v4l2_h264_dpb_entry *dpb = run->decode_params->dpb;
                struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
-               int buf_idx = -1;
+               struct vb2_buffer *buf = NULL;
 
                if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE) {
-                       buf_idx = vb2_find_timestamp(cap_q,
-                                                    dpb[i].reference_ts, 0);
-                       if (buf_idx < 0)
+                       buf = vb2_find_buffer(cap_q, dpb[i].reference_ts);
+                       if (!buf)
                                pr_debug("No buffer for reference_ts %llu",
                                         dpb[i].reference_ts);
                }
 
-               run->ref_buf_idx[i] = buf_idx;
+               run->ref_buf[i] = buf;
        }
 }
 
@@ -805,7 +804,7 @@ static void assemble_hw_rps(struct rkvdec_ctx *ctx,
                        if (WARN_ON(ref->index >= ARRAY_SIZE(dec_params->dpb)))
                                continue;
 
-                       dpb_valid = run->ref_buf_idx[ref->index] >= 0;
+                       dpb_valid = run->ref_buf[ref->index] != NULL;
                        bottom = ref->fields == V4L2_H264_BOTTOM_FIELD_REF;
 
                        set_ps_field(hw_rps, DPB_INFO(i, j),
@@ -881,24 +880,6 @@ static const u32 poc_reg_tbl_bottom_field[16] = {
        RKVDEC_REG_H264_POC_REFER2(1)
 };
 
-static struct vb2_buffer *
-get_ref_buf(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run,
-           unsigned int dpb_idx)
-{
-       struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
-       struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
-       int buf_idx = run->ref_buf_idx[dpb_idx];
-
-       /*
-        * If a DPB entry is unused or invalid, address of current destination
-        * buffer is returned.
-        */
-       if (buf_idx < 0)
-               return &run->base.bufs.dst->vb2_buf;
-
-       return vb2_get_buffer(cap_q, buf_idx);
-}
-
 static void config_registers(struct rkvdec_ctx *ctx,
                             struct rkvdec_h264_run *run)
 {
@@ -971,8 +952,14 @@ static void config_registers(struct rkvdec_ctx *ctx,
 
        /* config ref pic address & poc */
        for (i = 0; i < ARRAY_SIZE(dec_params->dpb); i++) {
-               struct vb2_buffer *vb_buf = get_ref_buf(ctx, run, i);
-
+               struct vb2_buffer *vb_buf = run->ref_buf[i];
+
+               /*
+                * If a DPB entry is unused or invalid, address of current destination
+                * buffer is returned.
+                */
+               if (!vb_buf)
+                       vb_buf = &dst_buf->vb2_buf;
                refer_addr = vb2_dma_contig_plane_dma_addr(vb_buf, 0);
 
                if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_ACTIVE)
index 311a126..d8c1c0d 100644 (file)
@@ -383,17 +383,17 @@ get_ref_buf(struct rkvdec_ctx *ctx, struct vb2_v4l2_buffer *dst, u64 timestamp)
 {
        struct v4l2_m2m_ctx *m2m_ctx = ctx->fh.m2m_ctx;
        struct vb2_queue *cap_q = &m2m_ctx->cap_q_ctx.q;
-       int buf_idx;
+       struct vb2_buffer *buf;
 
        /*
         * If a ref is unused or invalid, address of current destination
         * buffer is returned.
         */
-       buf_idx = vb2_find_timestamp(cap_q, timestamp, 0);
-       if (buf_idx < 0)
-               return vb2_to_rkvdec_decoded_buf(&dst->vb2_buf);
+       buf = vb2_find_buffer(cap_q, timestamp);
+       if (!buf)
+               buf = &dst->vb2_buf;
 
-       return vb2_to_rkvdec_decoded_buf(vb2_get_buffer(cap_q, buf_idx));
+       return vb2_to_rkvdec_decoded_buf(buf);
 }
 
 static dma_addr_t get_mv_base_addr(struct rkvdec_decoded_buffer *buf)
@@ -1015,7 +1015,6 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx)
 
        vp9_ctx->priv_tbl.size = sizeof(*priv_tbl);
        vp9_ctx->priv_tbl.cpu = priv_tbl;
-       memset(priv_tbl, 0, sizeof(*priv_tbl));
 
        count_tbl = dma_alloc_coherent(rkvdec->dev, RKVDEC_VP9_COUNT_SIZE,
                                       &vp9_ctx->count_tbl.dma, GFP_KERNEL);
@@ -1026,7 +1025,6 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx)
 
        vp9_ctx->count_tbl.size = RKVDEC_VP9_COUNT_SIZE;
        vp9_ctx->count_tbl.cpu = count_tbl;
-       memset(count_tbl, 0, sizeof(*count_tbl));
        rkvdec_init_v4l2_vp9_count_tbl(ctx);
 
        return 0;
diff --git a/drivers/staging/media/stkwebcam/Kconfig b/drivers/staging/media/stkwebcam/Kconfig
new file mode 100644 (file)
index 0000000..4450403
--- /dev/null
@@ -0,0 +1,18 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config VIDEO_STKWEBCAM
+       tristate "USB Syntek DC1125 Camera support (DEPRECATED)"
+       depends on VIDEO_DEV
+       depends on USB
+       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/>
+
+         This driver is deprecated and is scheduled for removal by
+         the end of 2022. See the TODO file for more information.
+
+         To compile this driver as a module, choose M here: the
+         module will be called stkwebcam.
+
diff --git a/drivers/staging/media/stkwebcam/Makefile b/drivers/staging/media/stkwebcam/Makefile
new file mode 100644 (file)
index 0000000..17ad7b6
--- /dev/null
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+stkwebcam-objs :=      stk-webcam.o stk-sensor.o
+
+obj-$(CONFIG_VIDEO_STKWEBCAM)     += stkwebcam.o
+
diff --git a/drivers/staging/media/stkwebcam/TODO b/drivers/staging/media/stkwebcam/TODO
new file mode 100644 (file)
index 0000000..735304a
--- /dev/null
@@ -0,0 +1,12 @@
+This is a very old driver for very old hardware (specifically
+laptops that use this sensor). In addition according to reports
+the picture quality is quite bad.
+
+This is also one of the few drivers still not using the vb2
+framework (or even the old videobuf framework!), so this driver
+is now deprecated with the intent of removing it altogether by
+the end of 2022.
+
+In order to keep this driver it has to be converted to vb2.
+If someone is interested in doing this work, then contact the
+linux-media mailinglist (https://linuxtv.org/lists.php).
diff --git a/drivers/staging/media/stkwebcam/stk-sensor.c b/drivers/staging/media/stkwebcam/stk-sensor.c
new file mode 100644 (file)
index 0000000..94aa6a2
--- /dev/null
@@ -0,0 +1,587 @@
+// 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/staging/media/stkwebcam/stk-webcam.c b/drivers/staging/media/stkwebcam/stk-webcam.c
new file mode 100644 (file)
index 0000000..787edb3
--- /dev/null
@@ -0,0 +1,1434 @@
+// 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/staging/media/stkwebcam/stk-webcam.h b/drivers/staging/media/stkwebcam/stk-webcam.h
new file mode 100644 (file)
index 0000000..136decf
--- /dev/null
@@ -0,0 +1,123 @@
+/* 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
index 68b3dcd..960a013 100644 (file)
@@ -42,7 +42,7 @@ static int cedrus_try_ctrl(struct v4l2_ctrl *ctrl)
                if (sps->bit_depth_luma_minus8 != 0)
                        /* Only 8-bit is supported */
                        return -EINVAL;
-       } else if (ctrl->id == V4L2_CID_MPEG_VIDEO_HEVC_SPS) {
+       } else if (ctrl->id == V4L2_CID_STATELESS_HEVC_SPS) {
                const struct v4l2_ctrl_hevc_sps *sps = ctrl->p_new.p_hevc_sps;
                struct cedrus_ctx *ctx = container_of(ctrl->handler, struct cedrus_ctx, hdl);
 
@@ -164,42 +164,54 @@ static const struct cedrus_control cedrus_controls[] = {
        },
        {
                .cfg = {
-                       .id     = V4L2_CID_MPEG_VIDEO_HEVC_SPS,
+                       .id     = V4L2_CID_STATELESS_HEVC_SPS,
                        .ops    = &cedrus_ctrl_ops,
                },
                .codec          = CEDRUS_CODEC_H265,
        },
        {
                .cfg = {
-                       .id     = V4L2_CID_MPEG_VIDEO_HEVC_PPS,
+                       .id     = V4L2_CID_STATELESS_HEVC_PPS,
                },
                .codec          = CEDRUS_CODEC_H265,
        },
        {
                .cfg = {
-                       .id     = V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS,
+                       .id     = V4L2_CID_STATELESS_HEVC_SLICE_PARAMS,
+                       /* The driver can only handle 1 entry per slice for now */
+                       .dims   = { 1 },
                },
                .codec          = CEDRUS_CODEC_H265,
        },
        {
                .cfg = {
-                       .id     = V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX,
+                       .id     = V4L2_CID_STATELESS_HEVC_SCALING_MATRIX,
                },
                .codec          = CEDRUS_CODEC_H265,
        },
        {
                .cfg = {
-                       .id     = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE,
-                       .max    = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
-                       .def    = V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
+                       .id     = V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS,
+                       /* maximum 256 entry point offsets per slice */
+                       .dims   = { 256 },
+                       .max = 0xffffffff,
+                       .step = 1,
                },
                .codec          = CEDRUS_CODEC_H265,
        },
        {
                .cfg = {
-                       .id     = V4L2_CID_MPEG_VIDEO_HEVC_START_CODE,
-                       .max    = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
-                       .def    = V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
+                       .id     = V4L2_CID_STATELESS_HEVC_DECODE_MODE,
+                       .max    = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
+                       .def    = V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
+               },
+               .codec          = CEDRUS_CODEC_H265,
+       },
+       {
+               .cfg = {
+                       .id     = V4L2_CID_STATELESS_HEVC_START_CODE,
+                       .max    = V4L2_STATELESS_HEVC_START_CODE_NONE,
+                       .def    = V4L2_STATELESS_HEVC_START_CODE_NONE,
                },
                .codec          = CEDRUS_CODEC_H265,
        },
@@ -211,7 +223,7 @@ static const struct cedrus_control cedrus_controls[] = {
        },
        {
                .cfg = {
-                       .id = V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS,
+                       .id = V4L2_CID_STATELESS_HEVC_DECODE_PARAMS,
                },
                .codec          = CEDRUS_CODEC_H265,
        },
@@ -230,6 +242,17 @@ void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id)
        return NULL;
 }
 
+u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id)
+{
+       unsigned int i;
+
+       for (i = 0; ctx->ctrls[i]; i++)
+               if (ctx->ctrls[i]->id == id)
+                       return ctx->ctrls[i]->elems;
+
+       return 0;
+}
+
 static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
 {
        struct v4l2_ctrl_handler *hdl = &ctx->hdl;
@@ -240,7 +263,8 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
        v4l2_ctrl_handler_init(hdl, CEDRUS_CONTROLS_COUNT);
        if (hdl->error) {
                v4l2_err(&dev->v4l2_dev,
-                        "Failed to initialize control handler\n");
+                        "Failed to initialize control handler: %d\n",
+                        hdl->error);
                return hdl->error;
        }
 
@@ -255,7 +279,9 @@ static int cedrus_init_ctrls(struct cedrus_dev *dev, struct cedrus_ctx *ctx)
                                            NULL);
                if (hdl->error) {
                        v4l2_err(&dev->v4l2_dev,
-                                "Failed to create new custom control\n");
+                                "Failed to create %s control: %d\n",
+                                v4l2_ctrl_get_name(cedrus_controls[i].cfg.id),
+                                hdl->error);
 
                        v4l2_ctrl_handler_free(hdl);
                        kfree(ctx->ctrls);
index 3bc094e..0841930 100644 (file)
@@ -81,6 +81,8 @@ struct cedrus_h265_run {
        const struct v4l2_ctrl_hevc_slice_params        *slice_params;
        const struct v4l2_ctrl_hevc_decode_params       *decode_params;
        const struct v4l2_ctrl_hevc_scaling_matrix      *scaling_matrix;
+       const u32                                       *entry_points;
+       u32                                             entry_points_count;
 };
 
 struct cedrus_vp8_run {
@@ -146,6 +148,8 @@ struct cedrus_ctx {
                        ssize_t         mv_col_buf_unit_size;
                        void            *neighbor_info_buf;
                        dma_addr_t      neighbor_info_buf_addr;
+                       void            *entry_points_buf;
+                       dma_addr_t      entry_points_buf_addr;
                } h265;
                struct {
                        unsigned int    last_frame_p_type;
@@ -162,7 +166,7 @@ struct cedrus_dec_ops {
        void (*irq_clear)(struct cedrus_ctx *ctx);
        void (*irq_disable)(struct cedrus_ctx *ctx);
        enum cedrus_irq_status (*irq_status)(struct cedrus_ctx *ctx);
-       void (*setup)(struct cedrus_ctx *ctx, struct cedrus_run *run);
+       int (*setup)(struct cedrus_ctx *ctx, struct cedrus_run *run);
        int (*start)(struct cedrus_ctx *ctx);
        void (*stop)(struct cedrus_ctx *ctx);
        void (*trigger)(struct cedrus_ctx *ctx);
@@ -261,5 +265,6 @@ vb2_to_cedrus_buffer(const struct vb2_buffer *p)
 }
 
 void *cedrus_find_control_data(struct cedrus_ctx *ctx, u32 id);
+u32 cedrus_get_num_of_controls(struct cedrus_ctx *ctx, u32 id);
 
 #endif
index 9c72002..3b6aa78 100644 (file)
@@ -28,6 +28,7 @@ void cedrus_device_run(void *priv)
        struct cedrus_dev *dev = ctx->dev;
        struct cedrus_run run = {};
        struct media_request *src_req;
+       int error;
 
        run.src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
        run.dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@@ -65,15 +66,19 @@ void cedrus_device_run(void *priv)
 
        case V4L2_PIX_FMT_HEVC_SLICE:
                run.h265.sps = cedrus_find_control_data(ctx,
-                       V4L2_CID_MPEG_VIDEO_HEVC_SPS);
+                       V4L2_CID_STATELESS_HEVC_SPS);
                run.h265.pps = cedrus_find_control_data(ctx,
-                       V4L2_CID_MPEG_VIDEO_HEVC_PPS);
+                       V4L2_CID_STATELESS_HEVC_PPS);
                run.h265.slice_params = cedrus_find_control_data(ctx,
-                       V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS);
+                       V4L2_CID_STATELESS_HEVC_SLICE_PARAMS);
                run.h265.decode_params = cedrus_find_control_data(ctx,
-                       V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS);
+                       V4L2_CID_STATELESS_HEVC_DECODE_PARAMS);
                run.h265.scaling_matrix = cedrus_find_control_data(ctx,
-                       V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX);
+                       V4L2_CID_STATELESS_HEVC_SCALING_MATRIX);
+               run.h265.entry_points = cedrus_find_control_data(ctx,
+                       V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS);
+               run.h265.entry_points_count = cedrus_get_num_of_controls(ctx,
+                       V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS);
                break;
 
        case V4L2_PIX_FMT_VP8_FRAME:
@@ -89,16 +94,26 @@ void cedrus_device_run(void *priv)
 
        cedrus_dst_format_set(dev, &ctx->dst_fmt);
 
-       dev->dec_ops[ctx->current_codec]->setup(ctx, &run);
+       error = dev->dec_ops[ctx->current_codec]->setup(ctx, &run);
+       if (error)
+               v4l2_err(&ctx->dev->v4l2_dev,
+                        "Failed to setup decoding job: %d\n", error);
 
        /* Complete request(s) controls if needed. */
 
        if (src_req)
                v4l2_ctrl_request_complete(src_req, &ctx->hdl);
 
-       dev->dec_ops[ctx->current_codec]->trigger(ctx);
-
-       /* Start the watchdog timer. */
-       schedule_delayed_work(&dev->watchdog_work,
-                             msecs_to_jiffies(2000));
+       /* Trigger decoding if setup went well, bail out otherwise. */
+       if (!error) {
+               dev->dec_ops[ctx->current_codec]->trigger(ctx);
+
+               /* Start the watchdog timer. */
+               schedule_delayed_work(&dev->watchdog_work,
+                                     msecs_to_jiffies(2000));
+       } else {
+               v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev,
+                                                ctx->fh.m2m_ctx,
+                                                VB2_BUF_STATE_ERROR);
+       }
 }
index d8fb930..c345e67 100644 (file)
@@ -493,8 +493,7 @@ static void cedrus_h264_irq_disable(struct cedrus_ctx *ctx)
                     reg & ~VE_H264_CTRL_INT_MASK);
 }
 
-static void cedrus_h264_setup(struct cedrus_ctx *ctx,
-                             struct cedrus_run *run)
+static int cedrus_h264_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 {
        struct cedrus_dev *dev = ctx->dev;
 
@@ -510,6 +509,8 @@ static void cedrus_h264_setup(struct cedrus_ctx *ctx,
        cedrus_write_frame_list(ctx, run);
 
        cedrus_set_params(ctx, run);
+
+       return 0;
 }
 
 static int cedrus_h264_start(struct cedrus_ctx *ctx)
index 44f385b..687f875 100644 (file)
@@ -143,10 +143,13 @@ static void cedrus_h265_frame_info_write_dpb(struct cedrus_ctx *ctx,
        for (i = 0; i < num_active_dpb_entries; i++) {
                int buffer_index = vb2_find_timestamp(vq, dpb[i].timestamp, 0);
                u32 pic_order_cnt[2] = {
-                       dpb[i].pic_order_cnt[0],
-                       dpb[i].pic_order_cnt[1]
+                       dpb[i].pic_order_cnt_val,
+                       dpb[i].pic_order_cnt_val
                };
 
+               if (buffer_index < 0)
+                       continue;
+
                cedrus_h265_frame_info_write_single(ctx, i, dpb[i].field_pic,
                                                    pic_order_cnt,
                                                    buffer_index);
@@ -301,8 +304,91 @@ static void cedrus_h265_write_scaling_list(struct cedrus_ctx *ctx,
                }
 }
 
-static void cedrus_h265_setup(struct cedrus_ctx *ctx,
-                             struct cedrus_run *run)
+static int cedrus_h265_is_low_delay(struct cedrus_run *run)
+{
+       const struct v4l2_ctrl_hevc_slice_params *slice_params;
+       const struct v4l2_hevc_dpb_entry *dpb;
+       s32 poc;
+       int i;
+
+       slice_params = run->h265.slice_params;
+       poc = run->h265.decode_params->pic_order_cnt_val;
+       dpb = run->h265.decode_params->dpb;
+
+       for (i = 0; i < slice_params->num_ref_idx_l0_active_minus1 + 1; i++)
+               if (dpb[slice_params->ref_idx_l0[i]].pic_order_cnt_val > poc)
+                       return 1;
+
+       if (slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_B)
+               return 0;
+
+       for (i = 0; i < slice_params->num_ref_idx_l1_active_minus1 + 1; i++)
+               if (dpb[slice_params->ref_idx_l1[i]].pic_order_cnt_val > poc)
+                       return 1;
+
+       return 0;
+}
+
+static void cedrus_h265_write_tiles(struct cedrus_ctx *ctx,
+                                   struct cedrus_run *run,
+                                   unsigned int ctb_addr_x,
+                                   unsigned int ctb_addr_y)
+{
+       const struct v4l2_ctrl_hevc_slice_params *slice_params;
+       const struct v4l2_ctrl_hevc_pps *pps;
+       struct cedrus_dev *dev = ctx->dev;
+       const u32 *entry_points;
+       u32 *entry_points_buf;
+       int i, x, tx, y, ty;
+
+       pps = run->h265.pps;
+       slice_params = run->h265.slice_params;
+       entry_points = run->h265.entry_points;
+       entry_points_buf = ctx->codec.h265.entry_points_buf;
+
+       for (x = 0, tx = 0; tx < pps->num_tile_columns_minus1 + 1; tx++) {
+               if (x + pps->column_width_minus1[tx] + 1 > ctb_addr_x)
+                       break;
+
+               x += pps->column_width_minus1[tx] + 1;
+       }
+
+       for (y = 0, ty = 0; ty < pps->num_tile_rows_minus1 + 1; ty++) {
+               if (y + pps->row_height_minus1[ty] + 1 > ctb_addr_y)
+                       break;
+
+               y += pps->row_height_minus1[ty] + 1;
+       }
+
+       cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, (y << 16) | (x << 0));
+       cedrus_write(dev, VE_DEC_H265_TILE_END_CTB,
+                    ((y + pps->row_height_minus1[ty]) << 16) |
+                    ((x + pps->column_width_minus1[tx]) << 0));
+
+       if (pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED) {
+               for (i = 0; i < slice_params->num_entry_point_offsets; i++)
+                       entry_points_buf[i] = entry_points[i];
+       } else {
+               for (i = 0; i < slice_params->num_entry_point_offsets; i++) {
+                       if (tx + 1 >= pps->num_tile_columns_minus1 + 1) {
+                               x = 0;
+                               tx = 0;
+                               y += pps->row_height_minus1[ty++] + 1;
+                       } else {
+                               x += pps->column_width_minus1[tx++] + 1;
+                       }
+
+                       entry_points_buf[i * 4 + 0] = entry_points[i];
+                       entry_points_buf[i * 4 + 1] = 0x0;
+                       entry_points_buf[i * 4 + 2] = (y << 16) | (x << 0);
+                       entry_points_buf[i * 4 + 3] =
+                               ((y + pps->row_height_minus1[ty]) << 16) |
+                               ((x + pps->column_width_minus1[tx]) << 0);
+               }
+       }
+}
+
+static int cedrus_h265_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 {
        struct cedrus_dev *dev = ctx->dev;
        const struct v4l2_ctrl_hevc_sps *sps;
@@ -312,11 +398,15 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
        const struct v4l2_hevc_pred_weight_table *pred_weight_table;
        unsigned int width_in_ctb_luma, ctb_size_luma;
        unsigned int log2_max_luma_coding_block_size;
+       unsigned int ctb_addr_x, ctb_addr_y;
        dma_addr_t src_buf_addr;
        dma_addr_t src_buf_end_addr;
        u32 chroma_log2_weight_denom;
+       u32 num_entry_point_offsets;
        u32 output_pic_list_index;
        u32 pic_order_cnt[2];
+       u8 *padding;
+       int count;
        u32 reg;
 
        sps = run->h265.sps;
@@ -324,6 +414,15 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
        slice_params = run->h265.slice_params;
        decode_params = run->h265.decode_params;
        pred_weight_table = &slice_params->pred_weight_table;
+       num_entry_point_offsets = slice_params->num_entry_point_offsets;
+
+       /*
+        * If entry points offsets are present, we should get them
+        * exactly the right amount.
+        */
+       if (num_entry_point_offsets &&
+           num_entry_point_offsets != run->h265.entry_points_count)
+               return -ERANGE;
 
        log2_max_luma_coding_block_size =
                sps->log2_min_luma_coding_block_size_minus3 + 3 +
@@ -358,8 +457,7 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
                                        GFP_KERNEL, DMA_ATTR_NO_KERNEL_MAPPING);
                if (!ctx->codec.h265.mv_col_buf) {
                        ctx->codec.h265.mv_col_buf_size = 0;
-                       // TODO: Abort the process here.
-                       return;
+                       return -ENOMEM;
                }
        }
 
@@ -391,12 +489,19 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
        cedrus_write(dev, VE_DEC_H265_BITS_END_ADDR, reg);
 
        /* Coding tree block address */
-       reg = VE_DEC_H265_DEC_CTB_ADDR_X(slice_params->slice_segment_addr % width_in_ctb_luma);
-       reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(slice_params->slice_segment_addr / width_in_ctb_luma);
+       ctb_addr_x = slice_params->slice_segment_addr % width_in_ctb_luma;
+       ctb_addr_y = slice_params->slice_segment_addr / width_in_ctb_luma;
+       reg = VE_DEC_H265_DEC_CTB_ADDR_X(ctb_addr_x);
+       reg |= VE_DEC_H265_DEC_CTB_ADDR_Y(ctb_addr_y);
        cedrus_write(dev, VE_DEC_H265_DEC_CTB_ADDR, reg);
 
-       cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0);
-       cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0);
+       if ((pps->flags & V4L2_HEVC_PPS_FLAG_TILES_ENABLED) ||
+           (pps->flags & V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED)) {
+               cedrus_h265_write_tiles(ctx, run, ctb_addr_x, ctb_addr_y);
+       } else {
+               cedrus_write(dev, VE_DEC_H265_TILE_START_CTB, 0);
+               cedrus_write(dev, VE_DEC_H265_TILE_END_CTB, 0);
+       }
 
        /* Clear the number of correctly-decoded coding tree blocks. */
        if (ctx->fh.m2m_ctx->new_frame)
@@ -405,7 +510,30 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
        /* Initialize bitstream access. */
        cedrus_write(dev, VE_DEC_H265_TRIGGER, VE_DEC_H265_TRIGGER_INIT_SWDEC);
 
-       cedrus_h265_skip_bits(dev, slice_params->data_bit_offset);
+       /*
+        * Cedrus expects that bitstream pointer is actually at the end of the slice header
+        * instead of start of slice data. Padding is 8 bits at most (one bit set to 1 and
+        * at most seven bits set to 0), so we have to inspect only one byte before slice data.
+        */
+
+       if (slice_params->data_byte_offset == 0)
+               return -EOPNOTSUPP;
+
+       padding = (u8 *)vb2_plane_vaddr(&run->src->vb2_buf, 0) +
+               slice_params->data_byte_offset - 1;
+
+       /* at least one bit must be set in that byte */
+       if (*padding == 0)
+               return -EINVAL;
+
+       for (count = 0; count < 8; count++)
+               if (*padding & (1 << count))
+                       break;
+
+       /* Include the one bit. */
+       count++;
+
+       cedrus_h265_skip_bits(dev, slice_params->data_byte_offset * 8 - count);
 
        /* Bitstream parameters. */
 
@@ -500,7 +628,9 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
                                V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED,
                                pps->flags);
 
-       /* TODO: VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TILES_ENABLED */
+       reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TILES_ENABLED,
+                               V4L2_HEVC_PPS_FLAG_TILES_ENABLED,
+                               pps->flags);
 
        reg |= VE_DEC_H265_FLAG(VE_DEC_H265_DEC_PPS_CTRL1_FLAG_TRANSQUANT_BYPASS_ENABLED,
                                V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED,
@@ -559,7 +689,6 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
 
        reg = VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_TC_OFFSET_DIV2(slice_params->slice_tc_offset_div2) |
              VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_BETA_OFFSET_DIV2(slice_params->slice_beta_offset_div2) |
-             VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(decode_params->num_poc_st_curr_after == 0) |
              VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CR_QP_OFFSET(slice_params->slice_cr_qp_offset) |
              VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CB_QP_OFFSET(slice_params->slice_cb_qp_offset) |
              VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_QP_DELTA(slice_params->slice_qp_delta);
@@ -572,16 +701,22 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
                                V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED,
                                slice_params->flags);
 
+       if (slice_params->slice_type != V4L2_HEVC_SLICE_TYPE_I && !cedrus_h265_is_low_delay(run))
+               reg |= VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_NOT_LOW_DELAY;
+
        cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO1, reg);
 
        chroma_log2_weight_denom = pred_weight_table->luma_log2_weight_denom +
                                   pred_weight_table->delta_chroma_log2_weight_denom;
-       reg = VE_DEC_H265_DEC_SLICE_HDR_INFO2_NUM_ENTRY_POINT_OFFSETS(0) |
+       reg = VE_DEC_H265_DEC_SLICE_HDR_INFO2_NUM_ENTRY_POINT_OFFSETS(num_entry_point_offsets) |
              VE_DEC_H265_DEC_SLICE_HDR_INFO2_CHROMA_LOG2_WEIGHT_DENOM(chroma_log2_weight_denom) |
              VE_DEC_H265_DEC_SLICE_HDR_INFO2_LUMA_LOG2_WEIGHT_DENOM(pred_weight_table->luma_log2_weight_denom);
 
        cedrus_write(dev, VE_DEC_H265_DEC_SLICE_HDR_INFO2, reg);
 
+       cedrus_write(dev, VE_DEC_H265_ENTRY_POINT_OFFSET_ADDR,
+                    ctx->codec.h265.entry_points_buf_addr >> 8);
+
        /* Decoded picture size. */
 
        reg = VE_DEC_H265_DEC_PIC_SIZE_WIDTH(ctx->src_fmt.width) |
@@ -659,6 +794,8 @@ static void cedrus_h265_setup(struct cedrus_ctx *ctx,
 
        /* Enable appropriate interruptions. */
        cedrus_write(dev, VE_DEC_H265_CTRL, VE_DEC_H265_CTRL_IRQ_MASK);
+
+       return 0;
 }
 
 static int cedrus_h265_start(struct cedrus_ctx *ctx)
@@ -676,6 +813,18 @@ static int cedrus_h265_start(struct cedrus_ctx *ctx)
        if (!ctx->codec.h265.neighbor_info_buf)
                return -ENOMEM;
 
+       ctx->codec.h265.entry_points_buf =
+               dma_alloc_coherent(dev->dev, CEDRUS_H265_ENTRY_POINTS_BUF_SIZE,
+                                  &ctx->codec.h265.entry_points_buf_addr,
+                                  GFP_KERNEL);
+       if (!ctx->codec.h265.entry_points_buf) {
+               dma_free_attrs(dev->dev, CEDRUS_H265_NEIGHBOR_INFO_BUF_SIZE,
+                              ctx->codec.h265.neighbor_info_buf,
+                              ctx->codec.h265.neighbor_info_buf_addr,
+                              DMA_ATTR_NO_KERNEL_MAPPING);
+               return -ENOMEM;
+       }
+
        return 0;
 }
 
@@ -696,6 +845,9 @@ static void cedrus_h265_stop(struct cedrus_ctx *ctx)
                       ctx->codec.h265.neighbor_info_buf,
                       ctx->codec.h265.neighbor_info_buf_addr,
                       DMA_ATTR_NO_KERNEL_MAPPING);
+       dma_free_coherent(dev->dev, CEDRUS_H265_ENTRY_POINTS_BUF_SIZE,
+                         ctx->codec.h265.entry_points_buf,
+                         ctx->codec.h265.entry_points_buf_addr);
 }
 
 static void cedrus_h265_trigger(struct cedrus_ctx *ctx)
index 5dad2f2..4cfc4a3 100644 (file)
@@ -48,7 +48,7 @@ static void cedrus_mpeg2_irq_disable(struct cedrus_ctx *ctx)
        cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
 }
 
-static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
+static int cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 {
        const struct v4l2_ctrl_mpeg2_sequence *seq;
        const struct v4l2_ctrl_mpeg2_picture *pic;
@@ -185,6 +185,8 @@ static void cedrus_mpeg2_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
              VE_DEC_MPEG_CTRL_MC_CACHE_EN;
 
        cedrus_write(dev, VE_DEC_MPEG_CTRL, reg);
+
+       return 0;
 }
 
 static void cedrus_mpeg2_trigger(struct cedrus_ctx *ctx)
index bdb062a..d81f751 100644 (file)
 
 #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED BIT(23)
 #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED BIT(22)
+#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_FLAG_SLICE_NOT_LOW_DELAY BIT(21)
 
 #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_TC_OFFSET_DIV2(v) \
        SHIFT_AND_MASK_BITS(v, 31, 28)
 #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_BETA_OFFSET_DIV2(v) \
        SHIFT_AND_MASK_BITS(v, 27, 24)
-#define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_POC_BIGEST_IN_RPS_ST(v) \
-       ((v) ? BIT(21) : 0)
 #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CR_QP_OFFSET(v) \
        SHIFT_AND_MASK_BITS(v, 20, 16)
 #define VE_DEC_H265_DEC_SLICE_HDR_INFO1_SLICE_CB_QP_OFFSET(v) \
index 3372617..6671460 100644 (file)
@@ -568,7 +568,6 @@ int cedrus_queue_init(void *priv, struct vb2_queue *src_vq,
 
        src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
        src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
-       src_vq->dma_attrs = DMA_ATTR_NO_KERNEL_MAPPING;
        src_vq->drv_priv = ctx;
        src_vq->buf_struct_size = sizeof(struct cedrus_buffer);
        src_vq->ops = &cedrus_qops;
index f401668..3f750d1 100644 (file)
@@ -651,8 +651,7 @@ static void cedrus_vp8_irq_disable(struct cedrus_ctx *ctx)
                     reg & ~VE_H264_CTRL_INT_MASK);
 }
 
-static void cedrus_vp8_setup(struct cedrus_ctx *ctx,
-                            struct cedrus_run *run)
+static int cedrus_vp8_setup(struct cedrus_ctx *ctx, struct cedrus_run *run)
 {
        const struct v4l2_ctrl_vp8_frame *slice = run->vp8.frame_params;
        struct vb2_queue *cap_q = &ctx->fh.m2m_ctx->cap_q_ctx.q;
@@ -855,6 +854,8 @@ static void cedrus_vp8_setup(struct cedrus_ctx *ctx,
                ctx->codec.vp8.last_sharpness_level =
                        slice->lf.sharpness_level;
        }
+
+       return 0;
 }
 
 static int cedrus_vp8_start(struct cedrus_ctx *ctx)
index 8e184aa..9d46a36 100644 (file)
@@ -157,7 +157,7 @@ tegra_channel_get_remote_csi_subdev(struct tegra_vi_channel *chan)
 {
        struct media_pad *pad;
 
-       pad = media_entity_remote_pad(&chan->pad);
+       pad = media_pad_remote_pad_first(&chan->pad);
        if (!pad)
                return NULL;
 
@@ -177,7 +177,7 @@ tegra_channel_get_remote_source_subdev(struct tegra_vi_channel *chan)
 
        pad = &subdev->entity.pads[0];
        while (!(pad->flags & MEDIA_PAD_FL_SOURCE)) {
-               pad = media_entity_remote_pad(pad);
+               pad = media_pad_remote_pad_first(pad);
                if (!pad || !is_media_entity_v4l2_subdev(pad->entity))
                        break;
                entity = pad->entity;
index 3af7d02..a0c8bde 100644 (file)
 
 #include "videocodec.h"
 
-static int videocodec_debug;
-module_param(videocodec_debug, int, 0);
-MODULE_PARM_DESC(videocodec_debug, "Debug level (0-4)");
-
-#define dprintk(num, format, args...) \
-       do { \
-               if (videocodec_debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 struct attached_list {
        struct videocodec *codec;
        struct attached_list *next;
@@ -47,6 +37,7 @@ static struct codec_list *codeclist_top;
 struct videocodec *videocodec_attach(struct videocodec_master *master)
 {
        struct codec_list *h = codeclist_top;
+       struct zoran *zr;
        struct attached_list *a, *ptr;
        struct videocodec *codec;
        int res;
@@ -56,11 +47,13 @@ struct videocodec *videocodec_attach(struct videocodec_master *master)
                return NULL;
        }
 
-       dprintk(2, "%s: '%s', flags %lx, magic %lx\n", __func__,
-               master->name, master->flags, master->magic);
+       zr = videocodec_master_to_zoran(master);
+
+       zrdev_dbg(zr, "%s: '%s', flags %lx, magic %lx\n", __func__,
+                 master->name, master->flags, master->magic);
 
        if (!h) {
-               pr_err("%s: no device available\n", __func__);
+               zrdev_err(zr, "%s: no device available\n", __func__);
                return NULL;
        }
 
@@ -68,7 +61,7 @@ struct videocodec *videocodec_attach(struct videocodec_master *master)
                // attach only if the slave has at least the flags
                // expected by the master
                if ((master->flags & h->codec->flags) == master->flags) {
-                       dprintk(4, "%s: try '%s'\n", __func__, h->codec->name);
+                       zrdev_dbg(zr, "%s: try '%s'\n", __func__, h->codec->name);
 
                        codec = kmemdup(h->codec, sizeof(struct videocodec), GFP_KERNEL);
                        if (!codec)
@@ -79,7 +72,7 @@ struct videocodec *videocodec_attach(struct videocodec_master *master)
                        codec->master_data = master;
                        res = codec->setup(codec);
                        if (res == 0) {
-                               dprintk(3, "%s: '%s'\n", __func__, codec->name);
+                               zrdev_dbg(zr, "%s: '%s'\n", __func__, codec->name);
                                ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
                                if (!ptr)
                                        goto out_kfree;
@@ -88,12 +81,13 @@ struct videocodec *videocodec_attach(struct videocodec_master *master)
                                a = h->list;
                                if (!a) {
                                        h->list = ptr;
-                                       dprintk(4, "videocodec: first element\n");
+                                       zrdev_dbg(zr, "videocodec: first element\n");
                                } else {
                                        while (a->next)
                                                a = a->next;    // find end
                                        a->next = ptr;
-                                       dprintk(4, "videocodec: in after '%s'\n", h->codec->name);
+                                       zrdev_dbg(zr, "videocodec: in after '%s'\n",
+                                                 h->codec->name);
                                }
 
                                h->attached += 1;
@@ -105,7 +99,7 @@ struct videocodec *videocodec_attach(struct videocodec_master *master)
                h = h->next;
        }
 
-       pr_err("%s: no codec found!\n", __func__);
+       zrdev_err(zr, "%s: no codec found!\n", __func__);
        return NULL;
 
  out_kfree:
@@ -116,6 +110,7 @@ struct videocodec *videocodec_attach(struct videocodec_master *master)
 int videocodec_detach(struct videocodec *codec)
 {
        struct codec_list *h = codeclist_top;
+       struct zoran *zr;
        struct attached_list *a, *prev;
        int res;
 
@@ -124,11 +119,13 @@ int videocodec_detach(struct videocodec *codec)
                return -EINVAL;
        }
 
-       dprintk(2, "%s: '%s', type: %x, flags %lx, magic %lx\n", __func__,
-               codec->name, codec->type, codec->flags, codec->magic);
+       zr = videocodec_to_zoran(codec);
+
+       zrdev_dbg(zr, "%s: '%s', type: %x, flags %lx, magic %lx\n", __func__,
+                 codec->name, codec->type, codec->flags, codec->magic);
 
        if (!h) {
-               pr_err("%s: no device left...\n", __func__);
+               zrdev_err(zr, "%s: no device left...\n", __func__);
                return -ENXIO;
        }
 
@@ -139,18 +136,19 @@ int videocodec_detach(struct videocodec *codec)
                        if (codec == a->codec) {
                                res = a->codec->unset(a->codec);
                                if (res >= 0) {
-                                       dprintk(3, "%s: '%s'\n", __func__, a->codec->name);
+                                       zrdev_dbg(zr, "%s: '%s'\n", __func__,
+                                                 a->codec->name);
                                        a->codec->master_data = NULL;
                                } else {
-                                       pr_err("%s: '%s'\n", __func__, a->codec->name);
+                                       zrdev_err(zr, "%s: '%s'\n", __func__, a->codec->name);
                                        a->codec->master_data = NULL;
                                }
                                if (!prev) {
                                        h->list = a->next;
-                                       dprintk(4, "videocodec: delete first\n");
+                                       zrdev_dbg(zr, "videocodec: delete first\n");
                                } else {
                                        prev->next = a->next;
-                                       dprintk(4, "videocodec: delete middle\n");
+                                       zrdev_dbg(zr, "videocodec: delete middle\n");
                                }
                                kfree(a->codec);
                                kfree(a);
@@ -163,22 +161,25 @@ int videocodec_detach(struct videocodec *codec)
                h = h->next;
        }
 
-       pr_err("%s: given codec not found!\n", __func__);
+       zrdev_err(zr, "%s: given codec not found!\n", __func__);
        return -EINVAL;
 }
 
 int videocodec_register(const struct videocodec *codec)
 {
        struct codec_list *ptr, *h = codeclist_top;
+       struct zoran *zr;
 
        if (!codec) {
                pr_err("%s: no data!\n", __func__);
                return -EINVAL;
        }
 
-       dprintk(2,
-               "videocodec: register '%s', type: %x, flags %lx, magic %lx\n",
-               codec->name, codec->type, codec->flags, codec->magic);
+       zr = videocodec_to_zoran((struct videocodec *)codec);
+
+       zrdev_dbg(zr,
+                 "videocodec: register '%s', type: %x, flags %lx, magic %lx\n",
+                 codec->name, codec->type, codec->flags, codec->magic);
 
        ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
        if (!ptr)
@@ -187,13 +188,13 @@ int videocodec_register(const struct videocodec *codec)
 
        if (!h) {
                codeclist_top = ptr;
-               dprintk(4, "videocodec: hooked in as first element\n");
+               zrdev_dbg(zr, "videocodec: hooked in as first element\n");
        } else {
                while (h->next)
                        h = h->next;    // find the end
                h->next = ptr;
-               dprintk(4, "videocodec: hooked in after '%s'\n",
-                       h->codec->name);
+               zrdev_dbg(zr, "videocodec: hooked in after '%s'\n",
+                         h->codec->name);
        }
 
        return 0;
@@ -202,37 +203,41 @@ int videocodec_register(const struct videocodec *codec)
 int videocodec_unregister(const struct videocodec *codec)
 {
        struct codec_list *prev = NULL, *h = codeclist_top;
+       struct zoran *zr;
 
        if (!codec) {
                pr_err("%s: no data!\n", __func__);
                return -EINVAL;
        }
 
-       dprintk(2,
-               "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n",
-               codec->name, codec->type, codec->flags, codec->magic);
+       zr = videocodec_to_zoran((struct videocodec *)codec);
+
+       zrdev_dbg(zr,
+                 "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n",
+                 codec->name, codec->type, codec->flags, codec->magic);
 
        if (!h) {
-               pr_err("%s: no device left...\n", __func__);
+               zrdev_err(zr, "%s: no device left...\n", __func__);
                return -ENXIO;
        }
 
        while (h) {
                if (codec == h->codec) {
                        if (h->attached) {
-                               pr_err("videocodec: '%s' is used\n", h->codec->name);
+                               zrdev_err(zr, "videocodec: '%s' is used\n",
+                                         h->codec->name);
                                return -EBUSY;
                        }
-                       dprintk(3, "videocodec: unregister '%s' is ok.\n",
-                               h->codec->name);
+                       zrdev_dbg(zr, "videocodec: unregister '%s' is ok.\n",
+                                 h->codec->name);
                        if (!prev) {
                                codeclist_top = h->next;
-                               dprintk(4,
-                                       "videocodec: delete first element\n");
+                               zrdev_dbg(zr,
+                                         "videocodec: delete first element\n");
                        } else {
                                prev->next = h->next;
-                               dprintk(4,
-                                       "videocodec: delete middle element\n");
+                               zrdev_dbg(zr,
+                                         "videocodec: delete middle element\n");
                        }
                        kfree(h);
                        return 0;
@@ -241,7 +246,7 @@ int videocodec_unregister(const struct videocodec *codec)
                h = h->next;
        }
 
-       pr_err("%s: given codec not found!\n", __func__);
+       zrdev_err(zr, "%s: given codec not found!\n", __func__);
        return -EINVAL;
 }
 
index 9dea348..5e6057e 100644 (file)
@@ -307,4 +307,19 @@ extern int videocodec_unregister(const struct videocodec *);
 
 int videocodec_debugfs_show(struct seq_file *m);
 
+#include "zoran.h"
+static inline struct zoran *videocodec_master_to_zoran(struct videocodec_master *master)
+{
+       struct zoran *zr = master->data;
+
+       return zr;
+}
+
+static inline struct zoran *videocodec_to_zoran(struct videocodec *codec)
+{
+       struct videocodec_master *master = codec->master_data;
+
+       return videocodec_master_to_zoran(master);
+}
+
 #endif                         /*ifndef __LINUX_VIDEOCODEC_H */
index 654c95f..05227e5 100644 (file)
@@ -19,6 +19,8 @@
 #define _BUZ_H_
 
 #include <linux/debugfs.h>
+#include <linux/pci.h>
+#include <linux/i2c-algo-bit.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ctrls.h>
 #include <media/videobuf2-core.h>
@@ -301,6 +303,18 @@ static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev)
 
 #endif
 
+/*
+ * Debugging macros
+ */
+#define zrdev_dbg(zr, format, args...) \
+       pci_dbg((zr)->pci_dev, format, ##args) \
+
+#define zrdev_err(zr, format, args...) \
+       pci_err((zr)->pci_dev, format, ##args) \
+
+#define zrdev_info(zr, format, args...) \
+       pci_info((zr)->pci_dev, format, ##args) \
+
 int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir);
 void zoran_queue_exit(struct zoran *zr);
 int zr_set_buf(struct zoran *zr);
index 26c7c32..0e05325 100644 (file)
 /* amount of chips attached via this driver */
 static int zr36016_codecs;
 
-static int zr36016_debug;
-module_param(zr36016_debug, int, 0);
-MODULE_PARM_DESC(zr36016_debug, "Debug level (0-4)");
-
-
-#define dprintk(num, format, args...) \
-       do { \
-               if (zr36016_debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 /* =========================================================================
    Local hardware I/O functions:
 
@@ -43,27 +32,30 @@ MODULE_PARM_DESC(zr36016_debug, "Debug level (0-4)");
 static u8 zr36016_read(struct zr36016 *ptr, u16 reg)
 {
        u8 value = 0;
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
 
        /* just in case something is wrong... */
        if (ptr->codec->master_data->readreg)
                value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xFF;
        else
-               pr_err("%s: invalid I/O setup, nothing read!\n", ptr->name);
+               zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name);
 
-       dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value);
+       zrdev_dbg(zr, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value);
 
        return value;
 }
 
 static void zr36016_write(struct zr36016 *ptr, u16 reg, u8 value)
 {
-       dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg);
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
+
+       zrdev_dbg(zr, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg);
 
        // just in case something is wrong...
        if (ptr->codec->master_data->writereg)
                ptr->codec->master_data->writereg(ptr->codec, reg, value);
        else
-               pr_err("%s: invalid I/O setup, nothing written!\n", ptr->name);
+               zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", ptr->name);
 }
 
 /* indirect read and write functions */
@@ -72,30 +64,34 @@ static void zr36016_write(struct zr36016 *ptr, u16 reg, u8 value)
 static u8 zr36016_readi(struct zr36016 *ptr, u16 reg)
 {
        u8 value = 0;
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
 
        /* just in case something is wrong... */
        if ((ptr->codec->master_data->writereg) && (ptr->codec->master_data->readreg)) {
                ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR
                value = (ptr->codec->master_data->readreg(ptr->codec, ZR016_IDATA)) & 0xFF;     // DATA
        } else {
-               pr_err("%s: invalid I/O setup, nothing read (i)!\n", ptr->name);
+               zrdev_err(zr, "%s: invalid I/O setup, nothing read (i)!\n", ptr->name);
        }
 
-       dprintk(4, "%s: reading indirect from 0x%04x: %02x\n", ptr->name, reg, value);
+       zrdev_dbg(zr, "%s: reading indirect from 0x%04x: %02x\n",
+                 ptr->name, reg, value);
        return value;
 }
 
 static void zr36016_writei(struct zr36016 *ptr, u16 reg, u8 value)
 {
-       dprintk(4, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name,
-               value, reg);
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
+
+       zrdev_dbg(zr, "%s: writing indirect 0x%02x to 0x%04x\n", ptr->name,
+                 value, reg);
 
        /* just in case something is wrong... */
        if (ptr->codec->master_data->writereg) {
                ptr->codec->master_data->writereg(ptr->codec, ZR016_IADDR, reg & 0x0F); // ADDR
                ptr->codec->master_data->writereg(ptr->codec, ZR016_IDATA, value & 0x0FF);      // DATA
        } else {
-               pr_err("%s: invalid I/O setup, nothing written (i)!\n", ptr->name);
+               zrdev_err(zr, "%s: invalid I/O setup, nothing written (i)!\n", ptr->name);
        }
 }
 
@@ -120,32 +116,34 @@ static u8 zr36016_read_version(struct zr36016 *ptr)
 
 static int zr36016_basic_test(struct zr36016 *ptr)
 {
-       if (zr36016_debug) {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
+
+       if (*KERN_INFO <= CONSOLE_LOGLEVEL_DEFAULT) {
                int i;
 
                zr36016_writei(ptr, ZR016I_PAX_LO, 0x55);
-               dprintk(1, KERN_INFO "%s: registers: ", ptr->name);
+               zrdev_dbg(zr, "%s: registers: ", ptr->name);
                for (i = 0; i <= 0x0b; i++)
-                       dprintk(1, "%02x ", zr36016_readi(ptr, i));
-               dprintk(1, "\n");
+                       zrdev_dbg(zr, "%02x ", zr36016_readi(ptr, i));
+               zrdev_dbg(zr, "\n");
        }
        // for testing just write 0, then the default value to a register and read
        // it back in both cases
        zr36016_writei(ptr, ZR016I_PAX_LO, 0x00);
        if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0) {
-               pr_err("%s: attach failed, can't connect to vfe processor!\n", ptr->name);
+               zrdev_err(zr, "%s: attach failed, can't connect to vfe processor!\n", ptr->name);
                return -ENXIO;
        }
        zr36016_writei(ptr, ZR016I_PAX_LO, 0x0d0);
        if (zr36016_readi(ptr, ZR016I_PAX_LO) != 0x0d0) {
-               pr_err("%s: attach failed, can't connect to vfe processor!\n", ptr->name);
+               zrdev_err(zr, "%s: attach failed, can't connect to vfe processor!\n", ptr->name);
                return -ENXIO;
        }
        // we allow version numbers from 0-3, should be enough, though
        zr36016_read_version(ptr);
        if (ptr->version & 0x0c) {
-               pr_err("%s: attach failed, suspicious version %d found...\n", ptr->name,
-                      ptr->version);
+               zrdev_err(zr, "%s: attach failed, suspicious version %d found...\n", ptr->name,
+                         ptr->version);
                return -ENXIO;
        }
 
@@ -164,10 +162,11 @@ static int zr36016_pushit(struct zr36016 *ptr,
                           u16             len,
                           const char     *data)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        int i = 0;
 
-       dprintk(4, "%s: write data block to 0x%04x (len=%d)\n",
-               ptr->name, startreg, len);
+       zrdev_dbg(zr, "%s: write data block to 0x%04x (len=%d)\n",
+                 ptr->name, startreg, len);
        while (i < len) {
                zr36016_writei(ptr, startreg++,  data[i++]);
        }
@@ -225,8 +224,9 @@ static void zr36016_init(struct zr36016 *ptr)
 static int zr36016_set_mode(struct videocodec *codec, int mode)
 {
        struct zr36016 *ptr = (struct zr36016 *)codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
 
-       dprintk(2, "%s: set_mode %d call\n", ptr->name, mode);
+       zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode);
 
        if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION))
                return -EINVAL;
@@ -242,11 +242,12 @@ static int zr36016_set_video(struct videocodec *codec, const struct tvnorm *norm
                             struct vfe_settings *cap, struct vfe_polarity *pol)
 {
        struct zr36016 *ptr = (struct zr36016 *)codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
 
-       dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n",
-               ptr->name, norm->h_start, norm->v_start,
-               cap->x, cap->y, cap->width, cap->height,
-               cap->decimation);
+       zrdev_dbg(zr, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) call\n",
+                 ptr->name, norm->h_start, norm->v_start,
+                 cap->x, cap->y, cap->width, cap->height,
+                 cap->decimation);
 
        /* if () return -EINVAL;
         * trust the master driver that it knows what it does - so
@@ -276,9 +277,11 @@ static int zr36016_set_video(struct videocodec *codec, const struct tvnorm *norm
 static int zr36016_control(struct videocodec *codec, int type, int size, void *data)
 {
        struct zr36016 *ptr = (struct zr36016 *)codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
        int *ival = (int *)data;
 
-       dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type, size);
+       zrdev_dbg(zr, "%s: control %d call with %d byte\n",
+                 ptr->name, type, size);
 
        switch (type) {
        case CODEC_G_STATUS:    /* get last status - we don't know it ... */
@@ -325,11 +328,12 @@ static int zr36016_control(struct videocodec *codec, int type, int size, void *d
 static int zr36016_unset(struct videocodec *codec)
 {
        struct zr36016 *ptr = codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
 
        if (ptr) {
                /* do wee need some codec deinit here, too ???? */
 
-               dprintk(1, "%s: finished codec #%d\n", ptr->name, ptr->num);
+               zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name, ptr->num);
                kfree(ptr);
                codec->data = NULL;
 
@@ -352,12 +356,13 @@ static int zr36016_unset(struct videocodec *codec)
 static int zr36016_setup(struct videocodec *codec)
 {
        struct zr36016 *ptr;
+       struct zoran *zr = videocodec_to_zoran(codec);
        int res;
 
-       dprintk(2, "zr36016: initializing VFE subsystem #%d.\n", zr36016_codecs);
+       zrdev_dbg(zr, "zr36016: initializing VFE subsystem #%d.\n", zr36016_codecs);
 
        if (zr36016_codecs == MAX_CODECS) {
-               pr_err("zr36016: Can't attach more codecs!\n");
+               zrdev_err(zr, "zr36016: Can't attach more codecs!\n");
                return -ENOSPC;
        }
        //mem structure init
@@ -384,7 +389,8 @@ static int zr36016_setup(struct videocodec *codec)
        ptr->ydec = 0;
        zr36016_init(ptr);
 
-       dprintk(1, KERN_INFO "%s: codec v%d attached and running\n", ptr->name, ptr->version);
+       zrdev_dbg(zr, "%s: codec v%d attached and running\n",
+                 ptr->name, ptr->version);
 
        return 0;
 }
@@ -417,9 +423,8 @@ int zr36016_init_module(void)
 void zr36016_cleanup_module(void)
 {
        if (zr36016_codecs) {
-               dprintk(1,
-                       "zr36016: something's wrong - %d codecs left somehow.\n",
-                       zr36016_codecs);
+               pr_debug("zr36016: something's wrong - %d codecs left somehow.\n",
+                        zr36016_codecs);
        }
        videocodec_unregister(&zr36016_codec);
 }
index 38f7021..6a7ef28 100644 (file)
 /* amount of chips attached via this driver */
 static int zr36050_codecs;
 
-/* debugging is available via module parameter */
-static int zr36050_debug;
-module_param(zr36050_debug, int, 0);
-MODULE_PARM_DESC(zr36050_debug, "Debug level (0-4)");
-
-#define dprintk(num, format, args...) \
-       do { \
-               if (zr36050_debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 /* =========================================================================
    Local hardware I/O functions:
 
@@ -49,32 +38,32 @@ MODULE_PARM_DESC(zr36050_debug, "Debug level (0-4)");
 /* read and write functions */
 static u8 zr36050_read(struct zr36050 *ptr, u16 reg)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        u8 value = 0;
 
        /* just in case something is wrong... */
        if (ptr->codec->master_data->readreg)
                value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xFF;
        else
-               dprintk(1,
-                       KERN_ERR "%s: invalid I/O setup, nothing read!\n", ptr->name);
+               zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name);
 
-       dprintk(4, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value);
+       zrdev_dbg(zr, "%s: reading from 0x%04x: %02x\n", ptr->name, reg, value);
 
        return value;
 }
 
 static void zr36050_write(struct zr36050 *ptr, u16 reg, u8 value)
 {
-       dprintk(4, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg);
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
+
+       zrdev_dbg(zr, "%s: writing 0x%02x to 0x%04x\n", ptr->name, value, reg);
 
        /* just in case something is wrong... */
        if (ptr->codec->master_data->writereg)
                ptr->codec->master_data->writereg(ptr->codec, reg, value);
        else
-               dprintk(1,
-                       KERN_ERR
-                       "%s: invalid I/O setup, nothing written!\n",
-                       ptr->name);
+               zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n",
+                         ptr->name);
 }
 
 /* =========================================================================
@@ -117,14 +106,15 @@ static u16 zr36050_read_scalefactor(struct zr36050 *ptr)
 
 static void zr36050_wait_end(struct zr36050 *ptr)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        int i = 0;
 
        while (!(zr36050_read_status1(ptr) & 0x4)) {
                udelay(1);
                if (i++ > 200000) {     // 200ms, there is for sure something wrong!!!
-                       dprintk(1,
-                               "%s: timeout at wait_end (last status: 0x%02x)\n",
-                               ptr->name, ptr->status1);
+                       zrdev_err(zr,
+                                 "%s: timeout at wait_end (last status: 0x%02x)\n",
+                                 ptr->name, ptr->status1);
                        break;
                }
        }
@@ -138,33 +128,32 @@ static void zr36050_wait_end(struct zr36050 *ptr)
 
 static int zr36050_basic_test(struct zr36050 *ptr)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
+
        zr36050_write(ptr, ZR050_SOF_IDX, 0x00);
        zr36050_write(ptr, ZR050_SOF_IDX + 1, 0x00);
        if ((zr36050_read(ptr, ZR050_SOF_IDX) |
             zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0x0000) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: attach failed, can't connect to jpeg processor!\n",
-                       ptr->name);
+               zrdev_err(zr,
+                         "%s: attach failed, can't connect to jpeg processor!\n",
+                         ptr->name);
                return -ENXIO;
        }
        zr36050_write(ptr, ZR050_SOF_IDX, 0xff);
        zr36050_write(ptr, ZR050_SOF_IDX + 1, 0xc0);
        if (((zr36050_read(ptr, ZR050_SOF_IDX) << 8) |
             zr36050_read(ptr, ZR050_SOF_IDX + 1)) != 0xffc0) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: attach failed, can't connect to jpeg processor!\n",
-                       ptr->name);
+               zrdev_err(zr,
+                         "%s: attach failed, can't connect to jpeg processor!\n",
+                         ptr->name);
                return -ENXIO;
        }
 
        zr36050_wait_end(ptr);
        if ((ptr->status1 & 0x4) == 0) {
-               dprintk(1,
-                       KERN_ERR
-                       "%s: attach failed, jpeg processor failed (end flag)!\n",
-                       ptr->name);
+               zrdev_err(zr,
+                         "%s: attach failed, jpeg processor failed (end flag)!\n",
+                         ptr->name);
                return -EBUSY;
        }
 
@@ -179,10 +168,11 @@ static int zr36050_basic_test(struct zr36050 *ptr)
 
 static int zr36050_pushit(struct zr36050 *ptr, u16 startreg, u16 len, const char *data)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        int i = 0;
 
-       dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name,
-               startreg, len);
+       zrdev_dbg(zr, "%s: write data block to 0x%04x (len=%d)\n", ptr->name,
+                 startreg, len);
        while (i < len)
                zr36050_write(ptr, startreg++, data[i++]);
 
@@ -305,11 +295,12 @@ static const char zr36050_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
 
 static int zr36050_set_sof(struct zr36050 *ptr)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        char sof_data[34];      // max. size of register set
        int i;
 
-       dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name,
-               ptr->width, ptr->height, NO_OF_COMPONENTS);
+       zrdev_dbg(zr, "%s: write SOF (%dx%d, %d components)\n", ptr->name,
+                 ptr->width, ptr->height, NO_OF_COMPONENTS);
        sof_data[0] = 0xff;
        sof_data[1] = 0xc0;
        sof_data[2] = 0x00;
@@ -336,10 +327,11 @@ static int zr36050_set_sof(struct zr36050 *ptr)
 
 static int zr36050_set_sos(struct zr36050 *ptr)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        char sos_data[16];      // max. size of register set
        int i;
 
-       dprintk(3, "%s: write SOS\n", ptr->name);
+       zrdev_dbg(zr, "%s: write SOS\n", ptr->name);
        sos_data[0] = 0xff;
        sos_data[1] = 0xda;
        sos_data[2] = 0x00;
@@ -363,9 +355,10 @@ static int zr36050_set_sos(struct zr36050 *ptr)
 
 static int zr36050_set_dri(struct zr36050 *ptr)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        char dri_data[6];       // max. size of register set
 
-       dprintk(3, "%s: write DRI\n", ptr->name);
+       zrdev_dbg(zr, "%s: write DRI\n", ptr->name);
        dri_data[0] = 0xff;
        dri_data[1] = 0xdd;
        dri_data[2] = 0x00;
@@ -387,9 +380,10 @@ static void zr36050_init(struct zr36050 *ptr)
 {
        int sum = 0;
        long bitcnt, tmp;
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
 
        if (ptr->mode == CODEC_DO_COMPRESSION) {
-               dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name);
+               zrdev_dbg(zr, "%s: COMPRESSION SETUP\n", ptr->name);
 
                /* 050 communicates with 057 in master mode */
                zr36050_write(ptr, ZR050_HARDWARE, ZR050_HW_MSTR);
@@ -419,7 +413,7 @@ static void zr36050_init(struct zr36050 *ptr)
 
                /* setup the fixed jpeg tables - maybe variable, though -
                 * (see table init section above) */
-               dprintk(3, "%s: write DQT, DHT, APP\n", ptr->name);
+               zrdev_dbg(zr, "%s: write DQT, DHT, APP\n", ptr->name);
                sum += zr36050_pushit(ptr, ZR050_DQT_IDX,
                                      sizeof(zr36050_dqt), zr36050_dqt);
                sum += zr36050_pushit(ptr, ZR050_DHT_IDX,
@@ -442,11 +436,11 @@ static void zr36050_init(struct zr36050 *ptr)
 
                zr36050_write(ptr, ZR050_GO, 1);        // launch codec
                zr36050_wait_end(ptr);
-               dprintk(2, "%s: Status after table preload: 0x%02x\n",
-                       ptr->name, ptr->status1);
+               zrdev_dbg(zr, "%s: Status after table preload: 0x%02x\n",
+                         ptr->name, ptr->status1);
 
                if ((ptr->status1 & 0x4) == 0) {
-                       pr_err("%s: init aborted!\n", ptr->name);
+                       zrdev_err(zr, "%s: init aborted!\n", ptr->name);
                        return; // something is wrong, its timed out!!!!
                }
 
@@ -457,9 +451,9 @@ static void zr36050_init(struct zr36050 *ptr)
                bitcnt = sum << 3;      /* need the size in bits */
 
                tmp = bitcnt >> 16;
-               dprintk(3,
-                       "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n",
-                       ptr->name, sum, ptr->real_code_vol, bitcnt, tmp);
+               zrdev_dbg(zr,
+                         "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n",
+                         ptr->name, sum, ptr->real_code_vol, bitcnt, tmp);
                zr36050_write(ptr, ZR050_TCV_NET_HI, tmp >> 8);
                zr36050_write(ptr, ZR050_TCV_NET_MH, tmp & 0xff);
                tmp = bitcnt & 0xffff;
@@ -470,8 +464,8 @@ static void zr36050_init(struct zr36050 *ptr)
                bitcnt -= ((bitcnt * 5) >> 6);  // bits without eob
 
                tmp = bitcnt >> 16;
-               dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n",
-                       ptr->name, bitcnt, tmp);
+               zrdev_dbg(zr, "%s: code: nettobit=%ld, highnettobits=%ld\n",
+                         ptr->name, bitcnt, tmp);
                zr36050_write(ptr, ZR050_TCV_DATA_HI, tmp >> 8);
                zr36050_write(ptr, ZR050_TCV_DATA_MH, tmp & 0xff);
                tmp = bitcnt & 0xffff;
@@ -489,7 +483,7 @@ static void zr36050_init(struct zr36050 *ptr)
                              ((ptr->app.len > 0) ? ZR050_ME_APP : 0) |
                              ((ptr->com.len > 0) ? ZR050_ME_COM : 0));
        } else {
-               dprintk(2, "%s: EXPANSION SETUP\n", ptr->name);
+               zrdev_dbg(zr, "%s: EXPANSION SETUP\n", ptr->name);
 
                /* 050 communicates with 055 in master mode */
                zr36050_write(ptr, ZR050_HARDWARE,
@@ -502,7 +496,7 @@ static void zr36050_init(struct zr36050 *ptr)
                zr36050_write(ptr, ZR050_INT_REQ_0, 0);
                zr36050_write(ptr, ZR050_INT_REQ_1, 3); // low 2 bits always 1
 
-               dprintk(3, "%s: write DHT\n", ptr->name);
+               zrdev_dbg(zr, "%s: write DHT\n", ptr->name);
                zr36050_pushit(ptr, ZR050_DHT_IDX, sizeof(zr36050_dht),
                               zr36050_dht);
 
@@ -511,11 +505,11 @@ static void zr36050_init(struct zr36050 *ptr)
 
                zr36050_write(ptr, ZR050_GO, 1);        // launch codec
                zr36050_wait_end(ptr);
-               dprintk(2, "%s: Status after table preload: 0x%02x\n",
-                       ptr->name, ptr->status1);
+               zrdev_dbg(zr, "%s: Status after table preload: 0x%02x\n",
+                         ptr->name, ptr->status1);
 
                if ((ptr->status1 & 0x4) == 0) {
-                       pr_err("%s: init aborted!\n", ptr->name);
+                       zrdev_err(zr, "%s: init aborted!\n", ptr->name);
                        return; // something is wrong, its timed out!!!!
                }
 
@@ -539,8 +533,9 @@ static void zr36050_init(struct zr36050 *ptr)
 static int zr36050_set_mode(struct videocodec *codec, int mode)
 {
        struct zr36050 *ptr = (struct zr36050 *)codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
 
-       dprintk(2, "%s: set_mode %d call\n", ptr->name, mode);
+       zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode);
 
        if ((mode != CODEC_DO_EXPANSION) && (mode != CODEC_DO_COMPRESSION))
                return -EINVAL;
@@ -556,12 +551,13 @@ static int zr36050_set_video(struct videocodec *codec, const struct tvnorm *norm
                             struct vfe_settings *cap, struct vfe_polarity *pol)
 {
        struct zr36050 *ptr = (struct zr36050 *)codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
        int size;
 
-       dprintk(2, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) q%d call\n",
-               ptr->name, norm->h_start, norm->v_start,
-               cap->x, cap->y, cap->width, cap->height,
-               cap->decimation, cap->quality);
+       zrdev_dbg(zr, "%s: set_video %d.%d, %d/%d-%dx%d (0x%x) q%d call\n",
+                 ptr->name, norm->h_start, norm->v_start,
+                 cap->x, cap->y, cap->width, cap->height,
+                 cap->decimation, cap->quality);
        /* if () return -EINVAL;
         * trust the master driver that it knows what it does - so
         * we allow invalid startx/y and norm for now ... */
@@ -594,10 +590,11 @@ static int zr36050_set_video(struct videocodec *codec, const struct tvnorm *norm
 static int zr36050_control(struct videocodec *codec, int type, int size, void *data)
 {
        struct zr36050 *ptr = (struct zr36050 *)codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
        int *ival = (int *)data;
 
-       dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type,
-               size);
+       zrdev_dbg(zr, "%s: control %d call with %d byte\n", ptr->name, type,
+                 size);
 
        switch (type) {
        case CODEC_G_STATUS:    /* get last status */
@@ -713,12 +710,13 @@ static int zr36050_control(struct videocodec *codec, int type, int size, void *d
 static int zr36050_unset(struct videocodec *codec)
 {
        struct zr36050 *ptr = codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
 
        if (ptr) {
                /* do wee need some codec deinit here, too ???? */
 
-               dprintk(1, "%s: finished codec #%d\n", ptr->name,
-                       ptr->num);
+               zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name,
+                         ptr->num);
                kfree(ptr);
                codec->data = NULL;
 
@@ -741,14 +739,15 @@ static int zr36050_unset(struct videocodec *codec)
 static int zr36050_setup(struct videocodec *codec)
 {
        struct zr36050 *ptr;
+       struct zoran *zr = videocodec_to_zoran(codec);
        int res;
 
-       dprintk(2, "zr36050: initializing MJPEG subsystem #%d.\n",
-               zr36050_codecs);
+       zrdev_dbg(zr, "zr36050: initializing MJPEG subsystem #%d.\n",
+                 zr36050_codecs);
 
        if (zr36050_codecs == MAX_CODECS) {
-               dprintk(1,
-                       KERN_ERR "zr36050: Can't attach more codecs!\n");
+               zrdev_err(zr,
+                         "zr36050: Can't attach more codecs!\n");
                return -ENOSPC;
        }
        //mem structure init
@@ -789,8 +788,8 @@ static int zr36050_setup(struct videocodec *codec)
 
        zr36050_init(ptr);
 
-       dprintk(1, KERN_INFO "%s: codec attached and running\n",
-               ptr->name);
+       zrdev_info(zr, "%s: codec attached and running\n",
+                  ptr->name);
 
        return 0;
 }
@@ -823,9 +822,8 @@ int zr36050_init_module(void)
 void zr36050_cleanup_module(void)
 {
        if (zr36050_codecs) {
-               dprintk(1,
-                       "zr36050: something's wrong - %d codecs left somehow.\n",
-                       zr36050_codecs);
+               pr_debug("zr36050: something's wrong - %d codecs left somehow.\n",
+                        zr36050_codecs);
        }
        videocodec_unregister(&zr36050_codec);
 }
index d0c369e..7798016 100644 (file)
@@ -32,16 +32,6 @@ static bool low_bitrate;
 module_param(low_bitrate, bool, 0);
 MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate");
 
-static int zr36060_debug;
-module_param(zr36060_debug, int, 0);
-MODULE_PARM_DESC(zr36060_debug, "Debug level (0-4)");
-
-#define dprintk(num, format, args...) \
-       do { \
-               if (zr36060_debug >= num) \
-                       printk(format, ##args); \
-       } while (0)
-
 /* =========================================================================
  * Local hardware I/O functions:
  * read/write via codec layer (registers are located in the master device)
@@ -51,25 +41,28 @@ MODULE_PARM_DESC(zr36060_debug, "Debug level (0-4)");
 static u8 zr36060_read(struct zr36060 *ptr, u16 reg)
 {
        u8 value = 0;
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
 
        // just in case something is wrong...
        if (ptr->codec->master_data->readreg)
                value = (ptr->codec->master_data->readreg(ptr->codec, reg)) & 0xff;
        else
-               pr_err("%s: invalid I/O setup, nothing read!\n", ptr->name);
+               zrdev_err(zr, "%s: invalid I/O setup, nothing read!\n", ptr->name);
 
        return value;
 }
 
 static void zr36060_write(struct zr36060 *ptr, u16 reg, u8 value)
 {
-       dprintk(4, "0x%02x @0x%04x\n", value, reg);
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
+
+       zrdev_dbg(zr, "0x%02x @0x%04x\n", value, reg);
 
        // just in case something is wrong...
        if (ptr->codec->master_data->writereg)
                ptr->codec->master_data->writereg(ptr->codec, reg, value);
        else
-               pr_err("%s: invalid I/O setup, nothing written!\n", ptr->name);
+               zrdev_err(zr, "%s: invalid I/O setup, nothing written!\n", ptr->name);
 }
 
 /* =========================================================================
@@ -101,14 +94,15 @@ static u16 zr36060_read_scalefactor(struct zr36060 *ptr)
 /* wait if codec is ready to proceed (end of processing) or time is over */
 static void zr36060_wait_end(struct zr36060 *ptr)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        int i = 0;
 
        while (zr36060_read_status(ptr) & ZR060_CFSR_BUSY) {
                udelay(1);
                if (i++ > 200000) {     // 200ms, there is for sure something wrong!!!
-                       dprintk(1,
-                               "%s: timeout at wait_end (last status: 0x%02x)\n",
-                               ptr->name, ptr->status);
+                       zrdev_dbg(zr,
+                                 "%s: timeout at wait_end (last status: 0x%02x)\n",
+                                 ptr->name, ptr->status);
                        break;
                }
        }
@@ -117,15 +111,17 @@ static void zr36060_wait_end(struct zr36060 *ptr)
 /* Basic test of "connectivity", writes/reads to/from memory the SOF marker */
 static int zr36060_basic_test(struct zr36060 *ptr)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
+
        if ((zr36060_read(ptr, ZR060_IDR_DEV) != 0x33) &&
            (zr36060_read(ptr, ZR060_IDR_REV) != 0x01)) {
-               pr_err("%s: attach failed, can't connect to jpeg processor!\n", ptr->name);
+               zrdev_err(zr, "%s: attach failed, can't connect to jpeg processor!\n", ptr->name);
                return -ENXIO;
        }
 
        zr36060_wait_end(ptr);
        if (ptr->status & ZR060_CFSR_BUSY) {
-               pr_err("%s: attach failed, jpeg processor failed (end flag)!\n", ptr->name);
+               zrdev_err(zr, "%s: attach failed, jpeg processor failed (end flag)!\n", ptr->name);
                return -EBUSY;
        }
 
@@ -135,10 +131,11 @@ static int zr36060_basic_test(struct zr36060 *ptr)
 /* simple loop for pushing the init datasets */
 static int zr36060_pushit(struct zr36060 *ptr, u16 startreg, u16 len, const char *data)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        int i = 0;
 
-       dprintk(4, "%s: write data block to 0x%04x (len=%d)\n", ptr->name,
-               startreg, len);
+       zrdev_dbg(zr, "%s: write data block to 0x%04x (len=%d)\n", ptr->name,
+                 startreg, len);
        while (i < len)
                zr36060_write(ptr, startreg++, data[i++]);
 
@@ -249,11 +246,12 @@ static const char zr36060_decimation_v[8] = { 1, 1, 1, 0, 0, 0, 0, 0 };
 /* SOF (start of frame) segment depends on width, height and sampling ratio of each color component */
 static int zr36060_set_sof(struct zr36060 *ptr)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        char sof_data[34];      // max. size of register set
        int i;
 
-       dprintk(3, "%s: write SOF (%dx%d, %d components)\n", ptr->name,
-               ptr->width, ptr->height, NO_OF_COMPONENTS);
+       zrdev_dbg(zr, "%s: write SOF (%dx%d, %d components)\n", ptr->name,
+                 ptr->width, ptr->height, NO_OF_COMPONENTS);
        sof_data[0] = 0xff;
        sof_data[1] = 0xc0;
        sof_data[2] = 0x00;
@@ -277,10 +275,11 @@ static int zr36060_set_sof(struct zr36060 *ptr)
 /* SOS (start of scan) segment depends on the used scan components of each color component */
 static int zr36060_set_sos(struct zr36060 *ptr)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        char sos_data[16];      // max. size of register set
        int i;
 
-       dprintk(3, "%s: write SOS\n", ptr->name);
+       zrdev_dbg(zr, "%s: write SOS\n", ptr->name);
        sos_data[0] = 0xff;
        sos_data[1] = 0xda;
        sos_data[2] = 0x00;
@@ -302,9 +301,10 @@ static int zr36060_set_sos(struct zr36060 *ptr)
 /* DRI (define restart interval) */
 static int zr36060_set_dri(struct zr36060 *ptr)
 {
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
        char dri_data[6];       // max. size of register set
 
-       dprintk(3, "%s: write DRI\n", ptr->name);
+       zrdev_dbg(zr, "%s: write DRI\n", ptr->name);
        dri_data[0] = 0xff;
        dri_data[1] = 0xdd;
        dri_data[2] = 0x00;
@@ -321,9 +321,10 @@ static void zr36060_init(struct zr36060 *ptr)
 {
        int sum = 0;
        long bitcnt, tmp;
+       struct zoran *zr = videocodec_to_zoran(ptr->codec);
 
        if (ptr->mode == CODEC_DO_COMPRESSION) {
-               dprintk(2, "%s: COMPRESSION SETUP\n", ptr->name);
+               zrdev_dbg(zr, "%s: COMPRESSION SETUP\n", ptr->name);
 
                zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SYNC_RST);
 
@@ -376,9 +377,9 @@ static void zr36060_init(struct zr36060 *ptr)
                bitcnt = sum << 3;      /* need the size in bits */
 
                tmp = bitcnt >> 16;
-               dprintk(3,
-                       "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n",
-                       ptr->name, sum, ptr->real_code_vol, bitcnt, tmp);
+               zrdev_dbg(zr,
+                         "%s: code: csize=%d, tot=%d, bit=%ld, highbits=%ld\n",
+                         ptr->name, sum, ptr->real_code_vol, bitcnt, tmp);
                zr36060_write(ptr, ZR060_TCV_NET_HI, tmp >> 8);
                zr36060_write(ptr, ZR060_TCV_NET_MH, tmp & 0xff);
                tmp = bitcnt & 0xffff;
@@ -389,8 +390,8 @@ static void zr36060_init(struct zr36060 *ptr)
                bitcnt -= ((bitcnt * 5) >> 6);  // bits without eob
 
                tmp = bitcnt >> 16;
-               dprintk(3, "%s: code: nettobit=%ld, highnettobits=%ld\n",
-                       ptr->name, bitcnt, tmp);
+               zrdev_dbg(zr, "%s: code: nettobit=%ld, highnettobits=%ld\n",
+                         ptr->name, bitcnt, tmp);
                zr36060_write(ptr, ZR060_TCV_DATA_HI, tmp >> 8);
                zr36060_write(ptr, ZR060_TCV_DATA_MH, tmp & 0xff);
                tmp = bitcnt & 0xffff;
@@ -408,7 +409,7 @@ static void zr36060_init(struct zr36060 *ptr)
                zr36060_write(ptr, ZR060_VCR, ZR060_VCR_RANGE);
 
        } else {
-               dprintk(2, "%s: EXPANSION SETUP\n", ptr->name);
+               zrdev_dbg(zr, "%s: EXPANSION SETUP\n", ptr->name);
 
                zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SYNC_RST);
 
@@ -441,10 +442,11 @@ static void zr36060_init(struct zr36060 *ptr)
        /* Load the tables */
        zr36060_write(ptr, ZR060_LOAD, ZR060_LOAD_SYNC_RST | ZR060_LOAD_LOAD);
        zr36060_wait_end(ptr);
-       dprintk(2, "%s: Status after table preload: 0x%02x\n", ptr->name, ptr->status);
+       zrdev_dbg(zr, "%s: Status after table preload: 0x%02x\n",
+                 ptr->name, ptr->status);
 
        if (ptr->status & ZR060_CFSR_BUSY) {
-               pr_err("%s: init aborted!\n", ptr->name);
+               zrdev_err(zr, "%s: init aborted!\n", ptr->name);
                return;         // something is wrong, its timed out!!!!
        }
 }
@@ -461,8 +463,9 @@ static void zr36060_init(struct zr36060 *ptr)
 static int zr36060_set_mode(struct videocodec *codec, int mode)
 {
        struct zr36060 *ptr = (struct zr36060 *)codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
 
-       dprintk(2, "%s: set_mode %d call\n", ptr->name, mode);
+       zrdev_dbg(zr, "%s: set_mode %d call\n", ptr->name, mode);
 
        if (mode != CODEC_DO_EXPANSION && mode != CODEC_DO_COMPRESSION)
                return -EINVAL;
@@ -478,11 +481,12 @@ static int zr36060_set_video(struct videocodec *codec, const struct tvnorm *norm
                             struct vfe_settings *cap, struct vfe_polarity *pol)
 {
        struct zr36060 *ptr = (struct zr36060 *)codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
        u32 reg;
        int size;
 
-       dprintk(2, "%s: set_video %d/%d-%dx%d (%%%d) call\n", ptr->name,
-               cap->x, cap->y, cap->width, cap->height, cap->decimation);
+       zrdev_dbg(zr, "%s: set_video %d/%d-%dx%d (%%%d) call\n", ptr->name,
+                 cap->x, cap->y, cap->width, cap->height, cap->decimation);
 
        /* if () return -EINVAL;
         * trust the master driver that it knows what it does - so
@@ -637,10 +641,11 @@ static int zr36060_set_video(struct videocodec *codec, const struct tvnorm *norm
 static int zr36060_control(struct videocodec *codec, int type, int size, void *data)
 {
        struct zr36060 *ptr = (struct zr36060 *)codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
        int *ival = (int *)data;
 
-       dprintk(2, "%s: control %d call with %d byte\n", ptr->name, type,
-               size);
+       zrdev_dbg(zr, "%s: control %d call with %d byte\n", ptr->name, type,
+                 size);
 
        switch (type) {
        case CODEC_G_STATUS:    /* get last status */
@@ -753,11 +758,12 @@ static int zr36060_control(struct videocodec *codec, int type, int size, void *d
 static int zr36060_unset(struct videocodec *codec)
 {
        struct zr36060 *ptr = codec->data;
+       struct zoran *zr = videocodec_to_zoran(codec);
 
        if (ptr) {
                /* do wee need some codec deinit here, too ???? */
 
-               dprintk(1, "%s: finished codec #%d\n", ptr->name, ptr->num);
+               zrdev_dbg(zr, "%s: finished codec #%d\n", ptr->name, ptr->num);
                kfree(ptr);
                codec->data = NULL;
 
@@ -778,12 +784,14 @@ static int zr36060_unset(struct videocodec *codec)
 static int zr36060_setup(struct videocodec *codec)
 {
        struct zr36060 *ptr;
+       struct zoran *zr = videocodec_to_zoran(codec);
        int res;
 
-       dprintk(2, "zr36060: initializing MJPEG subsystem #%d.\n", zr36060_codecs);
+       zrdev_dbg(zr, "zr36060: initializing MJPEG subsystem #%d.\n",
+                 zr36060_codecs);
 
        if (zr36060_codecs == MAX_CODECS) {
-               pr_err("zr36060: Can't attach more codecs!\n");
+               zrdev_err(zr, "zr36060: Can't attach more codecs!\n");
                return -ENOSPC;
        }
        //mem structure init
@@ -823,7 +831,7 @@ static int zr36060_setup(struct videocodec *codec)
 
        zr36060_init(ptr);
 
-       dprintk(1, KERN_INFO "%s: codec attached and running\n", ptr->name);
+       zrdev_info(zr, "%s: codec attached and running\n", ptr->name);
 
        return 0;
 }
@@ -852,9 +860,8 @@ int zr36060_init_module(void)
 void zr36060_cleanup_module(void)
 {
        if (zr36060_codecs) {
-               dprintk(1,
-                       "zr36060: something's wrong - %d codecs left somehow.\n",
-                       zr36060_codecs);
+               pr_debug("zr36060: something's wrong - %d codecs left somehow.\n",
+                        zr36060_codecs);
        }
 
        /* however, we can't just stay alive */
diff --git a/include/media/hevc-ctrls.h b/include/media/hevc-ctrls.h
deleted file mode 100644 (file)
index 01ccda4..0000000
+++ /dev/null
@@ -1,250 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * These are the HEVC state controls for use with stateless HEVC
- * codec drivers.
- *
- * It turns out that these structs are not stable yet and will undergo
- * more changes. So keep them private until they are stable and ready to
- * become part of the official public API.
- */
-
-#ifndef _HEVC_CTRLS_H_
-#define _HEVC_CTRLS_H_
-
-#include <linux/videodev2.h>
-
-/* The pixel format isn't stable at the moment and will likely be renamed. */
-#define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5') /* HEVC parsed slices */
-
-#define V4L2_CID_MPEG_VIDEO_HEVC_SPS           (V4L2_CID_CODEC_BASE + 1008)
-#define V4L2_CID_MPEG_VIDEO_HEVC_PPS           (V4L2_CID_CODEC_BASE + 1009)
-#define V4L2_CID_MPEG_VIDEO_HEVC_SLICE_PARAMS  (V4L2_CID_CODEC_BASE + 1010)
-#define V4L2_CID_MPEG_VIDEO_HEVC_SCALING_MATRIX        (V4L2_CID_CODEC_BASE + 1011)
-#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_PARAMS (V4L2_CID_CODEC_BASE + 1012)
-#define V4L2_CID_MPEG_VIDEO_HEVC_DECODE_MODE   (V4L2_CID_CODEC_BASE + 1015)
-#define V4L2_CID_MPEG_VIDEO_HEVC_START_CODE    (V4L2_CID_CODEC_BASE + 1016)
-
-/* enum v4l2_ctrl_type type values */
-#define V4L2_CTRL_TYPE_HEVC_SPS 0x0120
-#define V4L2_CTRL_TYPE_HEVC_PPS 0x0121
-#define V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS 0x0122
-#define V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX 0x0123
-#define V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS 0x0124
-
-enum v4l2_mpeg_video_hevc_decode_mode {
-       V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_SLICE_BASED,
-       V4L2_MPEG_VIDEO_HEVC_DECODE_MODE_FRAME_BASED,
-};
-
-enum v4l2_mpeg_video_hevc_start_code {
-       V4L2_MPEG_VIDEO_HEVC_START_CODE_NONE,
-       V4L2_MPEG_VIDEO_HEVC_START_CODE_ANNEX_B,
-};
-
-#define V4L2_HEVC_SLICE_TYPE_B 0
-#define V4L2_HEVC_SLICE_TYPE_P 1
-#define V4L2_HEVC_SLICE_TYPE_I 2
-
-#define V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE               (1ULL << 0)
-#define V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED                        (1ULL << 1)
-#define V4L2_HEVC_SPS_FLAG_AMP_ENABLED                         (1ULL << 2)
-#define V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET              (1ULL << 3)
-#define V4L2_HEVC_SPS_FLAG_PCM_ENABLED                         (1ULL << 4)
-#define V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED            (1ULL << 5)
-#define V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT          (1ULL << 6)
-#define V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED            (1ULL << 7)
-#define V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED      (1ULL << 8)
-
-/* The controls are not stable at the moment and will likely be reworked. */
-struct v4l2_ctrl_hevc_sps {
-       /* ISO/IEC 23008-2, ITU-T Rec. H.265: Sequence parameter set */
-       __u16   pic_width_in_luma_samples;
-       __u16   pic_height_in_luma_samples;
-       __u8    bit_depth_luma_minus8;
-       __u8    bit_depth_chroma_minus8;
-       __u8    log2_max_pic_order_cnt_lsb_minus4;
-       __u8    sps_max_dec_pic_buffering_minus1;
-       __u8    sps_max_num_reorder_pics;
-       __u8    sps_max_latency_increase_plus1;
-       __u8    log2_min_luma_coding_block_size_minus3;
-       __u8    log2_diff_max_min_luma_coding_block_size;
-       __u8    log2_min_luma_transform_block_size_minus2;
-       __u8    log2_diff_max_min_luma_transform_block_size;
-       __u8    max_transform_hierarchy_depth_inter;
-       __u8    max_transform_hierarchy_depth_intra;
-       __u8    pcm_sample_bit_depth_luma_minus1;
-       __u8    pcm_sample_bit_depth_chroma_minus1;
-       __u8    log2_min_pcm_luma_coding_block_size_minus3;
-       __u8    log2_diff_max_min_pcm_luma_coding_block_size;
-       __u8    num_short_term_ref_pic_sets;
-       __u8    num_long_term_ref_pics_sps;
-       __u8    chroma_format_idc;
-       __u8    sps_max_sub_layers_minus1;
-
-       __u64   flags;
-};
-
-#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED     (1ULL << 0)
-#define V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT                 (1ULL << 1)
-#define V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED            (1ULL << 2)
-#define V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT                  (1ULL << 3)
-#define V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED              (1ULL << 4)
-#define V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED              (1ULL << 5)
-#define V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED                 (1ULL << 6)
-#define V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT (1ULL << 7)
-#define V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED                       (1ULL << 8)
-#define V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED                     (1ULL << 9)
-#define V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED           (1ULL << 10)
-#define V4L2_HEVC_PPS_FLAG_TILES_ENABLED                       (1ULL << 11)
-#define V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED         (1ULL << 12)
-#define V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED    (1ULL << 13)
-#define V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 14)
-#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED  (1ULL << 15)
-#define V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER       (1ULL << 16)
-#define V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT          (1ULL << 17)
-#define V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT (1ULL << 18)
-#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT   (1ULL << 19)
-#define V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING                     (1ULL << 20)
-
-struct v4l2_ctrl_hevc_pps {
-       /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture parameter set */
-       __u8    num_extra_slice_header_bits;
-       __u8    num_ref_idx_l0_default_active_minus1;
-       __u8    num_ref_idx_l1_default_active_minus1;
-       __s8    init_qp_minus26;
-       __u8    diff_cu_qp_delta_depth;
-       __s8    pps_cb_qp_offset;
-       __s8    pps_cr_qp_offset;
-       __u8    num_tile_columns_minus1;
-       __u8    num_tile_rows_minus1;
-       __u8    column_width_minus1[20];
-       __u8    row_height_minus1[22];
-       __s8    pps_beta_offset_div2;
-       __s8    pps_tc_offset_div2;
-       __u8    log2_parallel_merge_level_minus2;
-
-       __u8    padding[4];
-       __u64   flags;
-};
-
-#define V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE        0x01
-
-#define V4L2_HEVC_DPB_ENTRIES_NUM_MAX          16
-
-struct v4l2_hevc_dpb_entry {
-       __u64   timestamp;
-       __u8    flags;
-       __u8    field_pic;
-       __u16   pic_order_cnt[2];
-       __u8    padding[2];
-};
-
-struct v4l2_hevc_pred_weight_table {
-       __s8    delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-       __s8    luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-       __s8    delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-       __s8    chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-
-       __s8    delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-       __s8    luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-       __s8    delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-       __s8    chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
-
-       __u8    padding[6];
-
-       __u8    luma_log2_weight_denom;
-       __s8    delta_chroma_log2_weight_denom;
-};
-
-#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA             (1ULL << 0)
-#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA           (1ULL << 1)
-#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED (1ULL << 2)
-#define V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO                        (1ULL << 3)
-#define V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT                 (1ULL << 4)
-#define V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0         (1ULL << 5)
-#define V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV             (1ULL << 6)
-#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED (1ULL << 7)
-#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 8)
-#define V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT    (1ULL << 9)
-
-struct v4l2_ctrl_hevc_slice_params {
-       __u32   bit_size;
-       __u32   data_bit_offset;
-
-       /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */
-       __u8    nal_unit_type;
-       __u8    nuh_temporal_id_plus1;
-
-       /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-       __u8    slice_type;
-       __u8    colour_plane_id;
-       __u16   slice_pic_order_cnt;
-       __u8    num_ref_idx_l0_active_minus1;
-       __u8    num_ref_idx_l1_active_minus1;
-       __u8    collocated_ref_idx;
-       __u8    five_minus_max_num_merge_cand;
-       __s8    slice_qp_delta;
-       __s8    slice_cb_qp_offset;
-       __s8    slice_cr_qp_offset;
-       __s8    slice_act_y_qp_offset;
-       __s8    slice_act_cb_qp_offset;
-       __s8    slice_act_cr_qp_offset;
-       __s8    slice_beta_offset_div2;
-       __s8    slice_tc_offset_div2;
-
-       /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture timing SEI message */
-       __u8    pic_struct;
-
-       /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
-       __u32   slice_segment_addr;
-       __u8    ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-       __u8    ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-
-       __u8    padding;
-
-       /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */
-       struct v4l2_hevc_pred_weight_table pred_weight_table;
-
-       __u64   flags;
-};
-
-#define V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC           0x1
-#define V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC            0x2
-#define V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR  0x4
-
-struct v4l2_ctrl_hevc_decode_params {
-       __s32   pic_order_cnt_val;
-       __u8    num_active_dpb_entries;
-       struct  v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-       __u8    num_poc_st_curr_before;
-       __u8    num_poc_st_curr_after;
-       __u8    num_poc_lt_curr;
-       __u8    poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-       __u8    poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-       __u8    poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
-       __u64   flags;
-};
-
-struct v4l2_ctrl_hevc_scaling_matrix {
-       __u8    scaling_list_4x4[6][16];
-       __u8    scaling_list_8x8[6][64];
-       __u8    scaling_list_16x16[6][64];
-       __u8    scaling_list_32x32[2][64];
-       __u8    scaling_list_dc_coef_16x16[6];
-       __u8    scaling_list_dc_coef_32x32[2];
-};
-
-/*  MPEG-class control IDs specific to the Hantro driver as defined by V4L2 */
-#define V4L2_CID_CODEC_HANTRO_BASE                             (V4L2_CTRL_CLASS_CODEC | 0x1200)
-/*
- * V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP -
- * the number of data (in bits) to skip in the
- * slice segment header.
- * If non-IDR, the bits to be skipped go from syntax element "pic_output_flag"
- * to before syntax element "slice_temporal_mvp_enabled_flag".
- * If IDR, the skipped bits are just "pic_output_flag"
- * (separate_colour_plane_flag is not supported).
- */
-#define V4L2_CID_HANTRO_HEVC_SLICE_HEADER_SKIP (V4L2_CID_CODEC_HANTRO_BASE + 0)
-
-#endif
index a9a1c0e..f16ffe7 100644 (file)
@@ -848,7 +848,7 @@ struct media_link *media_entity_find_link(struct media_pad *source,
                struct media_pad *sink);
 
 /**
- * media_entity_remote_pad - Find the pad at the remote end of a link
+ * media_pad_remote_pad_first - Find the first pad at the remote end of a link
  * @pad: Pad at the local end of the link
  *
  * Search for a remote pad connected to the given pad by iterating over all
@@ -857,7 +857,71 @@ struct media_link *media_entity_find_link(struct media_pad *source,
  * Return: returns a pointer to the pad at the remote end of the first found
  * enabled link, or %NULL if no enabled link has been found.
  */
-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);
+
+/**
+ * media_pad_remote_pad_unique - Find a remote pad connected to a pad
+ * @pad: The pad
+ *
+ * Search for and return a remote pad connected to @pad through an enabled
+ * link. If multiple (or no) remote pads are found, an error is returned.
+ *
+ * The uniqueness constraint makes this helper function suitable for entities
+ * that support a single active source at a time on a given pad.
+ *
+ * Return: A pointer to the remote pad, or one of the following error pointers
+ * if an error occurs:
+ *
+ * * -ENOTUNIQ - Multiple links are enabled
+ * * -ENOLINK - No connected pad found
+ */
+struct media_pad *media_pad_remote_pad_unique(const struct media_pad *pad);
+
+/**
+ * media_entity_remote_pad_unique - Find a remote pad connected to an entity
+ * @entity: The entity
+ * @type: The type of pad to find (MEDIA_PAD_FL_SINK or MEDIA_PAD_FL_SOURCE)
+ *
+ * Search for and return a remote pad of @type connected to @entity through an
+ * enabled link. If multiple (or no) remote pads match these criteria, an error
+ * is returned.
+ *
+ * The uniqueness constraint makes this helper function suitable for entities
+ * that support a single active source or sink at a time.
+ *
+ * Return: A pointer to the remote pad, or one of the following error pointers
+ * if an error occurs:
+ *
+ * * -ENOTUNIQ - Multiple links are enabled
+ * * -ENOLINK - No connected pad found
+ */
+struct media_pad *
+media_entity_remote_pad_unique(const struct media_entity *entity,
+                              unsigned int type);
+
+/**
+ * media_entity_remote_source_pad_unique - Find a remote source pad connected to
+ *     an entity
+ * @entity: The entity
+ *
+ * Search for and return a remote source pad connected to @entity through an
+ * enabled link. If multiple (or no) remote pads match these criteria, an error
+ * is returned.
+ *
+ * The uniqueness constraint makes this helper function suitable for entities
+ * that support a single active source at a time.
+ *
+ * Return: A pointer to the remote pad, or one of the following error pointers
+ * if an error occurs:
+ *
+ * * -ENOTUNIQ - Multiple links are enabled
+ * * -ENOLINK - No connected pad found
+ */
+static inline struct media_pad *
+media_entity_remote_source_pad_unique(const struct media_entity *entity)
+{
+       return media_entity_remote_pad_unique(entity, MEDIA_PAD_FL_SOURCE);
+}
 
 /**
  * media_entity_is_streaming - Test if an entity is part of a streaming pipeline
@@ -1140,4 +1204,34 @@ struct media_link *
 media_create_ancillary_link(struct media_entity *primary,
                            struct media_entity *ancillary);
 
+/**
+ * __media_entity_next_link() - Iterate through a &media_entity's links
+ *
+ * @entity:    pointer to the &media_entity
+ * @link:      pointer to a &media_link to hold the iterated values
+ * @link_type: one of the MEDIA_LNK_FL_LINK_TYPE flags
+ *
+ * Return the next link against an entity matching a specific link type. This
+ * allows iteration through an entity's links whilst guaranteeing all of the
+ * returned links are of the given type.
+ */
+struct media_link *__media_entity_next_link(struct media_entity *entity,
+                                           struct media_link *link,
+                                           unsigned long link_type);
+
+/**
+ * for_each_media_entity_data_link() - Iterate through an entity's data links
+ *
+ * @entity:    pointer to the &media_entity
+ * @link:      pointer to a &media_link to hold the iterated values
+ *
+ * Iterate over a &media_entity's data links
+ */
+#define for_each_media_entity_data_link(entity, link)                  \
+       for (link = __media_entity_next_link(entity, NULL,              \
+                                            MEDIA_LNK_FL_DATA_LINK);   \
+            link;                                                      \
+            link = __media_entity_next_link(entity, link,              \
+                                            MEDIA_LNK_FL_DATA_LINK))
+
 #endif
index 181dcbe..a550889 100644 (file)
@@ -210,6 +210,7 @@ struct tpg_data {
        bool                            show_square;
        bool                            insert_sav;
        bool                            insert_eav;
+       bool                            insert_hdmi_video_guard_band;
 
        /* Test pattern movement */
        enum tpg_move_mode              mv_hor_mode;
@@ -591,6 +592,21 @@ static inline void tpg_s_insert_eav(struct tpg_data *tpg, bool insert_eav)
        tpg->insert_eav = insert_eav;
 }
 
+/*
+ * This inserts 4 pixels of the RGB color 0xab55ab at the left hand side of the
+ * image. This is only done for 3 or 4 byte RGB pixel formats. This pixel value
+ * equals the Video Guard Band value as defined by HDMI (see section 5.2.2.1
+ * in the HDMI 1.3 Specification) that preceeds the first actual pixel. If the
+ * HDMI receiver doesn't handle this correctly, then it might keep skipping
+ * these Video Guard Band patterns and end up with a shorter video line. So this
+ * is a nice pattern to test with.
+ */
+static inline void tpg_s_insert_hdmi_video_guard_band(struct tpg_data *tpg,
+                                                     bool insert_hdmi_video_guard_band)
+{
+       tpg->insert_hdmi_video_guard_band = insert_hdmi_video_guard_band;
+}
+
 void tpg_update_mv_step(struct tpg_data *tpg);
 
 static inline void tpg_s_mv_hor_mode(struct tpg_data *tpg,
index 13ff3ad..25eb1d1 100644 (file)
@@ -81,6 +81,7 @@ struct v4l2_async_subdev {
  * @complete:  All subdevices have been probed successfully. The complete
  *             callback is only executed for the root notifier.
  * @unbind:    a subdevice is leaving
+ * @destroy:   the asd is about to be freed
  */
 struct v4l2_async_notifier_operations {
        int (*bound)(struct v4l2_async_notifier *notifier,
@@ -90,6 +91,7 @@ struct v4l2_async_notifier_operations {
        void (*unbind)(struct v4l2_async_notifier *notifier,
                       struct v4l2_subdev *subdev,
                       struct v4l2_async_subdev *asd);
+       void (*destroy)(struct v4l2_async_subdev *asd);
 };
 
 /**
index 3eb2022..b708d63 100644 (file)
@@ -563,19 +563,19 @@ static inline void v4l2_buffer_set_timestamp(struct v4l2_buffer *buf,
 static inline bool v4l2_is_colorspace_valid(__u32 colorspace)
 {
        return colorspace > V4L2_COLORSPACE_DEFAULT &&
-              colorspace <= V4L2_COLORSPACE_DCI_P3;
+              colorspace < V4L2_COLORSPACE_LAST;
 }
 
 static inline bool v4l2_is_xfer_func_valid(__u32 xfer_func)
 {
        return xfer_func > V4L2_XFER_FUNC_DEFAULT &&
-              xfer_func <= V4L2_XFER_FUNC_SMPTE2084;
+              xfer_func < V4L2_XFER_FUNC_LAST;
 }
 
 static inline bool v4l2_is_ycbcr_enc_valid(__u8 ycbcr_enc)
 {
        return ycbcr_enc > V4L2_YCBCR_ENC_DEFAULT &&
-              ycbcr_enc <= V4L2_YCBCR_ENC_SMPTE240M;
+              ycbcr_enc < V4L2_YCBCR_ENC_LAST;
 }
 
 static inline bool v4l2_is_hsv_enc_valid(__u8 hsv_enc)
index b3ce438..00828a4 100644 (file)
 #include <linux/videodev2.h>
 #include <media/media-request.h>
 
-/*
- * Include the stateless codec compound control definitions.
- * This will move to the public headers once this API is fully stable.
- */
-#include <media/hevc-ctrls.h>
-
 /* forward references */
 struct file;
 struct poll_table_struct;
@@ -185,6 +179,8 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
  *             and/or has type %V4L2_CTRL_TYPE_STRING. In other words, &struct
  *             v4l2_ext_control uses field p to point to the data.
  * @is_array: If set, then this control contains an N-dimensional array.
+ * @is_dyn_array: If set, then this control contains a dynamically sized 1-dimensional array.
+ *             If this is set, then @is_array is also set.
  * @has_volatiles: If set, then one or more members of the cluster are volatile.
  *             Drivers should never touch this flag.
  * @call_notify: If set, then call the handler's notify function whenever the
@@ -205,6 +201,9 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
  * @step:      The control's step value for non-menu controls.
  * @elems:     The number of elements in the N-dimensional array.
  * @elem_size: The size in bytes of the control.
+ * @new_elems: The number of elements in p_new. This is the same as @elems,
+ *             except for dynamic arrays. In that case it is in the range of
+ *             1 to @p_dyn_alloc_elems.
  * @dims:      The size of each dimension.
  * @nr_of_dims:The number of dimensions in @dims.
  * @menu_skip_mask: The control's skip mask for menu controls. This makes it
@@ -223,15 +222,21 @@ typedef void (*v4l2_ctrl_notify_fnc)(struct v4l2_ctrl *ctrl, void *priv);
  *             :math:`ceil(\frac{maximum - minimum}{step}) + 1`.
  *             Used only if the @type is %V4L2_CTRL_TYPE_INTEGER_MENU.
  * @flags:     The control's flags.
- * @cur:       Structure to store the current value.
- * @cur.val:   The control's current value, if the @type is represented via
- *             a u32 integer (see &enum v4l2_ctrl_type).
- * @val:       The control's new s32 value.
  * @priv:      The control's private pointer. For use by the driver. It is
  *             untouched by the control framework. Note that this pointer is
  *             not freed when the control is deleted. Should this be needed
  *             then a new internal bitfield can be added to tell the framework
  *             to free this pointer.
+ * @p_dyn:     Pointer to the dynamically allocated array. Only valid if
+ *             @is_dyn_array is true.
+ * @p_dyn_alloc_elems: The number of elements in the dynamically allocated
+ *             array for both the cur and new values. So @p_dyn is actually
+ *             sized for 2 * @p_dyn_alloc_elems * @elem_size. Only valid if
+ *             @is_dyn_array is true.
+ * @cur:       Structure to store the current value.
+ * @cur.val:   The control's current value, if the @type is represented via
+ *             a u32 integer (see &enum v4l2_ctrl_type).
+ * @val:       The control's new s32 value.
  * @p_def:     The control's default value represented via a union which
  *             provides a standard way of accessing control types
  *             through a pointer (for compound controls only).
@@ -260,6 +265,7 @@ struct v4l2_ctrl {
        unsigned int is_string:1;
        unsigned int is_ptr:1;
        unsigned int is_array:1;
+       unsigned int is_dyn_array:1;
        unsigned int has_volatiles:1;
        unsigned int call_notify:1;
        unsigned int manual_mode_value:8;
@@ -272,6 +278,7 @@ struct v4l2_ctrl {
        s64 minimum, maximum, default_value;
        u32 elems;
        u32 elem_size;
+       u32 new_elems;
        u32 dims[V4L2_CTRL_MAX_DIMS];
        u32 nr_of_dims;
        union {
@@ -284,6 +291,8 @@ struct v4l2_ctrl {
        };
        unsigned long flags;
        void *priv;
+       void *p_dyn;
+       u32 p_dyn_alloc_elems;
        s32 val;
        struct {
                s32 val;
@@ -309,12 +318,22 @@ struct v4l2_ctrl {
  *             the control has been applied. This prevents applying controls
  *             from a cluster with multiple controls twice (when the first
  *             control of a cluster is applied, they all are).
- * @valid_p_req: If set, then p_req contains the control value for the request.
+ * @p_req_valid: If set, then p_req contains the control value for the request.
+ * @p_req_dyn_enomem: If set, then p_req is invalid since allocating space for
+ *             a dynamic array failed. Attempting to read this value shall
+ *             result in ENOMEM. Only valid if ctrl->is_dyn_array is true.
+ * @p_req_dyn_alloc_elems: The number of elements allocated for the dynamic
+ *             array. Only valid if @p_req_valid and ctrl->is_dyn_array are
+ *             true.
+ * @p_req_elems: The number of elements in @p_req. This is the same as
+ *             ctrl->elems, except for dynamic arrays. In that case it is in
+ *             the range of 1 to @p_req_dyn_alloc_elems. Only valid if
+ *             @p_req_valid is true.
  * @p_req:     If the control handler containing this control reference
  *             is bound to a media request, then this points to the
  *             value of the control that must be applied when the request
  *             is executed, or to the value of the control at the time
- *             that the request was completed. If @valid_p_req is false,
+ *             that the request was completed. If @p_req_valid is false,
  *             then this control was never set for this request and the
  *             control will not be updated when this request is applied.
  *
@@ -329,7 +348,10 @@ struct v4l2_ctrl_ref {
        struct v4l2_ctrl_helper *helper;
        bool from_other_dev;
        bool req_done;
-       bool valid_p_req;
+       bool p_req_valid;
+       bool p_req_dyn_enomem;
+       u32 p_req_dyn_alloc_elems;
+       u32 p_req_elems;
        union v4l2_ctrl_ptr p_req;
 };
 
index b661e18..9689f38 100644 (file)
@@ -1433,6 +1433,40 @@ extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers;
                __result;                                               \
        })
 
+/**
+ * v4l2_subdev_call_state_try - call an operation of a v4l2_subdev which
+ *                             takes state as a parameter, passing the
+ *                             subdev a newly allocated try state.
+ *
+ * @sd: pointer to the &struct v4l2_subdev
+ * @o: name of the element at &struct v4l2_subdev_ops that contains @f.
+ *     Each element there groups a set of callbacks functions.
+ * @f: callback function to be called.
+ *     The callback functions are defined in groups, according to
+ *     each element at &struct v4l2_subdev_ops.
+ * @args: arguments for @f.
+ *
+ * This is similar to v4l2_subdev_call_state_active(), except that as this
+ * version allocates a new state, this is only usable for
+ * V4L2_SUBDEV_FORMAT_TRY use cases.
+ *
+ * Note: only legacy non-MC drivers may need this macro.
+ */
+#define v4l2_subdev_call_state_try(sd, o, f, args...)                 \
+       ({                                                            \
+               int __result;                                         \
+               static struct lock_class_key __key;                   \
+               const char *name = KBUILD_BASENAME                    \
+                       ":" __stringify(__LINE__) ":state->lock";     \
+               struct v4l2_subdev_state *state =                     \
+                       __v4l2_subdev_state_alloc(sd, name, &__key);  \
+               v4l2_subdev_lock_state(state);                        \
+               __result = v4l2_subdev_call(sd, o, f, state, ##args); \
+               v4l2_subdev_unlock_state(state);                      \
+               __v4l2_subdev_state_free(state);                      \
+               __result;                                             \
+       })
+
 /**
  * v4l2_subdev_has_op - Checks if a subdev defines a certain operation.
  *
index d818d97..76e405c 100644 (file)
@@ -78,6 +78,16 @@ struct vb2_v4l2_buffer {
 int vb2_find_timestamp(const struct vb2_queue *q, u64 timestamp,
                       unsigned int start_idx);
 
+/**
+ * vb2_find_buffer() - Find a buffer with given timestamp
+ *
+ * @q:         pointer to &struct vb2_queue with videobuf2 queue.
+ * @timestamp: the timestamp to find.
+ *
+ * Returns the buffer with the given @timestamp, or NULL if not found.
+ */
+struct vb2_buffer *vb2_find_buffer(struct vb2_queue *q, u64 timestamp);
+
 int vb2_querybuf(struct vb2_queue *q, struct v4l2_buffer *b);
 
 /**
index dfff69e..5f46bf4 100644 (file)
@@ -1997,6 +1997,465 @@ struct v4l2_ctrl_mpeg2_quantisation {
        __u8    chroma_non_intra_quantiser_matrix[64];
 };
 
+#define V4L2_CID_STATELESS_HEVC_SPS            (V4L2_CID_CODEC_STATELESS_BASE + 400)
+#define V4L2_CID_STATELESS_HEVC_PPS            (V4L2_CID_CODEC_STATELESS_BASE + 401)
+#define V4L2_CID_STATELESS_HEVC_SLICE_PARAMS   (V4L2_CID_CODEC_STATELESS_BASE + 402)
+#define V4L2_CID_STATELESS_HEVC_SCALING_MATRIX (V4L2_CID_CODEC_STATELESS_BASE + 403)
+#define V4L2_CID_STATELESS_HEVC_DECODE_PARAMS  (V4L2_CID_CODEC_STATELESS_BASE + 404)
+#define V4L2_CID_STATELESS_HEVC_DECODE_MODE    (V4L2_CID_CODEC_STATELESS_BASE + 405)
+#define V4L2_CID_STATELESS_HEVC_START_CODE     (V4L2_CID_CODEC_STATELESS_BASE + 406)
+#define V4L2_CID_STATELESS_HEVC_ENTRY_POINT_OFFSETS (V4L2_CID_CODEC_STATELESS_BASE + 407)
+
+enum v4l2_stateless_hevc_decode_mode {
+       V4L2_STATELESS_HEVC_DECODE_MODE_SLICE_BASED,
+       V4L2_STATELESS_HEVC_DECODE_MODE_FRAME_BASED,
+};
+
+enum v4l2_stateless_hevc_start_code {
+       V4L2_STATELESS_HEVC_START_CODE_NONE,
+       V4L2_STATELESS_HEVC_START_CODE_ANNEX_B,
+};
+
+#define V4L2_HEVC_SLICE_TYPE_B 0
+#define V4L2_HEVC_SLICE_TYPE_P 1
+#define V4L2_HEVC_SLICE_TYPE_I 2
+
+#define V4L2_HEVC_SPS_FLAG_SEPARATE_COLOUR_PLANE               (1ULL << 0)
+#define V4L2_HEVC_SPS_FLAG_SCALING_LIST_ENABLED                        (1ULL << 1)
+#define V4L2_HEVC_SPS_FLAG_AMP_ENABLED                         (1ULL << 2)
+#define V4L2_HEVC_SPS_FLAG_SAMPLE_ADAPTIVE_OFFSET              (1ULL << 3)
+#define V4L2_HEVC_SPS_FLAG_PCM_ENABLED                         (1ULL << 4)
+#define V4L2_HEVC_SPS_FLAG_PCM_LOOP_FILTER_DISABLED            (1ULL << 5)
+#define V4L2_HEVC_SPS_FLAG_LONG_TERM_REF_PICS_PRESENT          (1ULL << 6)
+#define V4L2_HEVC_SPS_FLAG_SPS_TEMPORAL_MVP_ENABLED            (1ULL << 7)
+#define V4L2_HEVC_SPS_FLAG_STRONG_INTRA_SMOOTHING_ENABLED      (1ULL << 8)
+
+/**
+ * struct v4l2_ctrl_hevc_sps - ITU-T Rec. H.265: Sequence parameter set
+ *
+ * @video_parameter_set_id: specifies the value of the
+ *                     vps_video_parameter_set_id of the active VPS
+ * @seq_parameter_set_id: provides an identifier for the SPS for
+ *                       reference by other syntax elements
+ * @pic_width_in_luma_samples: specifies the width of each decoded picture
+ *                             in units of luma samples
+ * @pic_height_in_luma_samples: specifies the height of each decoded picture
+ *                             in units of luma samples
+ * @bit_depth_luma_minus8: this value plus 8specifies the bit depth of the
+ *                         samples of the luma array
+ * @bit_depth_chroma_minus8: this value plus 8 specifies the bit depth of the
+ *                           samples of the chroma arrays
+ * @log2_max_pic_order_cnt_lsb_minus4: this value plus 4 specifies the value of
+ *                                     the variable MaxPicOrderCntLsb
+ * @sps_max_dec_pic_buffering_minus1: this value plus 1 specifies the maximum
+ *                                    required size of the decoded picture
+ *                                    buffer for the codec video sequence
+ * @sps_max_num_reorder_pics: indicates the maximum allowed number of pictures
+ * @sps_max_latency_increase_plus1: not equal to 0 is used to compute the
+ *                                 value of SpsMaxLatencyPictures array
+ * @log2_min_luma_coding_block_size_minus3: plus 3 specifies the minimum
+ *                                         luma coding block size
+ * @log2_diff_max_min_luma_coding_block_size: specifies the difference between
+ *                                           the maximum and minimum luma
+ *                                           coding block size
+ * @log2_min_luma_transform_block_size_minus2: plus 2 specifies the minimum luma
+ *                                            transform block size
+ * @log2_diff_max_min_luma_transform_block_size: specifies the difference between
+ *                                              the maximum and minimum luma
+ *                                              transform block size
+ * @max_transform_hierarchy_depth_inter: specifies the maximum hierarchy
+ *                                      depth for transform units of
+ *                                      coding units coded in inter
+ *                                      prediction mode
+ * @max_transform_hierarchy_depth_intra: specifies the maximum hierarchy
+ *                                      depth for transform units of
+ *                                      coding units coded in intra
+ *                                      prediction mode
+ * @pcm_sample_bit_depth_luma_minus1: this value plus 1 specifies the number of
+ *                                    bits used to represent each of PCM sample
+ *                                    values of the luma component
+ * @pcm_sample_bit_depth_chroma_minus1: this value plus 1 specifies the number
+ *                                      of bits used to represent each of PCM
+ *                                      sample values of the chroma components
+ * @log2_min_pcm_luma_coding_block_size_minus3: this value plus 3 specifies the
+ *                                              minimum size of coding blocks
+ * @log2_diff_max_min_pcm_luma_coding_block_size: specifies the difference between
+ *                                               the maximum and minimum size of
+ *                                               coding blocks
+ * @num_short_term_ref_pic_sets: specifies the number of st_ref_pic_set()
+ *                              syntax structures included in the SPS
+ * @num_long_term_ref_pics_sps: specifies the number of candidate long-term
+ *                             reference pictures that are specified in the SPS
+ * @chroma_format_idc: specifies the chroma sampling
+ * @sps_max_sub_layers_minus1: this value plus 1 specifies the maximum number
+ *                             of temporal sub-layers
+ * @reserved: padding field. Should be zeroed by applications.
+ * @flags: see V4L2_HEVC_SPS_FLAG_{}
+ */
+struct v4l2_ctrl_hevc_sps {
+       __u8    video_parameter_set_id;
+       __u8    seq_parameter_set_id;
+       __u16   pic_width_in_luma_samples;
+       __u16   pic_height_in_luma_samples;
+       __u8    bit_depth_luma_minus8;
+       __u8    bit_depth_chroma_minus8;
+       __u8    log2_max_pic_order_cnt_lsb_minus4;
+       __u8    sps_max_dec_pic_buffering_minus1;
+       __u8    sps_max_num_reorder_pics;
+       __u8    sps_max_latency_increase_plus1;
+       __u8    log2_min_luma_coding_block_size_minus3;
+       __u8    log2_diff_max_min_luma_coding_block_size;
+       __u8    log2_min_luma_transform_block_size_minus2;
+       __u8    log2_diff_max_min_luma_transform_block_size;
+       __u8    max_transform_hierarchy_depth_inter;
+       __u8    max_transform_hierarchy_depth_intra;
+       __u8    pcm_sample_bit_depth_luma_minus1;
+       __u8    pcm_sample_bit_depth_chroma_minus1;
+       __u8    log2_min_pcm_luma_coding_block_size_minus3;
+       __u8    log2_diff_max_min_pcm_luma_coding_block_size;
+       __u8    num_short_term_ref_pic_sets;
+       __u8    num_long_term_ref_pics_sps;
+       __u8    chroma_format_idc;
+       __u8    sps_max_sub_layers_minus1;
+
+       __u8    reserved[6];
+       __u64   flags;
+};
+
+#define V4L2_HEVC_PPS_FLAG_DEPENDENT_SLICE_SEGMENT_ENABLED     (1ULL << 0)
+#define V4L2_HEVC_PPS_FLAG_OUTPUT_FLAG_PRESENT                 (1ULL << 1)
+#define V4L2_HEVC_PPS_FLAG_SIGN_DATA_HIDING_ENABLED            (1ULL << 2)
+#define V4L2_HEVC_PPS_FLAG_CABAC_INIT_PRESENT                  (1ULL << 3)
+#define V4L2_HEVC_PPS_FLAG_CONSTRAINED_INTRA_PRED              (1ULL << 4)
+#define V4L2_HEVC_PPS_FLAG_TRANSFORM_SKIP_ENABLED              (1ULL << 5)
+#define V4L2_HEVC_PPS_FLAG_CU_QP_DELTA_ENABLED                 (1ULL << 6)
+#define V4L2_HEVC_PPS_FLAG_PPS_SLICE_CHROMA_QP_OFFSETS_PRESENT (1ULL << 7)
+#define V4L2_HEVC_PPS_FLAG_WEIGHTED_PRED                       (1ULL << 8)
+#define V4L2_HEVC_PPS_FLAG_WEIGHTED_BIPRED                     (1ULL << 9)
+#define V4L2_HEVC_PPS_FLAG_TRANSQUANT_BYPASS_ENABLED           (1ULL << 10)
+#define V4L2_HEVC_PPS_FLAG_TILES_ENABLED                       (1ULL << 11)
+#define V4L2_HEVC_PPS_FLAG_ENTROPY_CODING_SYNC_ENABLED         (1ULL << 12)
+#define V4L2_HEVC_PPS_FLAG_LOOP_FILTER_ACROSS_TILES_ENABLED    (1ULL << 13)
+#define V4L2_HEVC_PPS_FLAG_PPS_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 14)
+#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_OVERRIDE_ENABLED  (1ULL << 15)
+#define V4L2_HEVC_PPS_FLAG_PPS_DISABLE_DEBLOCKING_FILTER       (1ULL << 16)
+#define V4L2_HEVC_PPS_FLAG_LISTS_MODIFICATION_PRESENT          (1ULL << 17)
+#define V4L2_HEVC_PPS_FLAG_SLICE_SEGMENT_HEADER_EXTENSION_PRESENT (1ULL << 18)
+#define V4L2_HEVC_PPS_FLAG_DEBLOCKING_FILTER_CONTROL_PRESENT   (1ULL << 19)
+#define V4L2_HEVC_PPS_FLAG_UNIFORM_SPACING                     (1ULL << 20)
+
+/**
+ * struct v4l2_ctrl_hevc_pps - ITU-T Rec. H.265: Picture parameter set
+ *
+ * @pic_parameter_set_id: identifies the PPS for reference by other
+ *                       syntax elements
+ * @num_extra_slice_header_bits: specifies the number of extra slice header
+ *                              bits that are present in the slice header RBSP
+ *                              for coded pictures referring to the PPS.
+ * @num_ref_idx_l0_default_active_minus1: this value plus 1 specifies the
+ *                                        inferred value of num_ref_idx_l0_active_minus1
+ * @num_ref_idx_l1_default_active_minus1: this value plus 1 specifies the
+ *                                        inferred value of num_ref_idx_l1_active_minus1
+ * @init_qp_minus26: this value plus 26 specifies the initial value of SliceQp Y for
+ *                  each slice referring to the PPS
+ * @diff_cu_qp_delta_depth: specifies the difference between the luma coding
+ *                         tree block size and the minimum luma coding block
+ *                         size of coding units that convey cu_qp_delta_abs
+ *                         and cu_qp_delta_sign_flag
+ * @pps_cb_qp_offset: specify the offsets to the luma quantization parameter Cb
+ * @pps_cr_qp_offset: specify the offsets to the luma quantization parameter Cr
+ * @num_tile_columns_minus1: this value plus 1 specifies the number of tile columns
+ *                          partitioning the picture
+ * @num_tile_rows_minus1: this value plus 1 specifies the number of tile rows partitioning
+ *                       the picture
+ * @column_width_minus1: this value plus 1 specifies the width of the each tile column in
+ *                      units of coding tree blocks
+ * @row_height_minus1: this value plus 1 specifies the height of the each tile row in
+ *                    units of coding tree blocks
+ * @pps_beta_offset_div2: specify the default deblocking parameter offsets for
+ *                       beta divided by 2
+ * @pps_tc_offset_div2: specify the default deblocking parameter offsets for tC
+ *                     divided by 2
+ * @log2_parallel_merge_level_minus2: this value plus 2 specifies the value of
+ *                                    the variable Log2ParMrgLevel
+ * @reserved: padding field. Should be zeroed by applications.
+ * @flags: see V4L2_HEVC_PPS_FLAG_{}
+ */
+struct v4l2_ctrl_hevc_pps {
+       __u8    pic_parameter_set_id;
+       __u8    num_extra_slice_header_bits;
+       __u8    num_ref_idx_l0_default_active_minus1;
+       __u8    num_ref_idx_l1_default_active_minus1;
+       __s8    init_qp_minus26;
+       __u8    diff_cu_qp_delta_depth;
+       __s8    pps_cb_qp_offset;
+       __s8    pps_cr_qp_offset;
+       __u8    num_tile_columns_minus1;
+       __u8    num_tile_rows_minus1;
+       __u8    column_width_minus1[20];
+       __u8    row_height_minus1[22];
+       __s8    pps_beta_offset_div2;
+       __s8    pps_tc_offset_div2;
+       __u8    log2_parallel_merge_level_minus2;
+       __u8    reserved;
+       __u64   flags;
+};
+
+#define V4L2_HEVC_DPB_ENTRY_LONG_TERM_REFERENCE        0x01
+
+#define V4L2_HEVC_SEI_PIC_STRUCT_FRAME                         0
+#define V4L2_HEVC_SEI_PIC_STRUCT_TOP_FIELD                     1
+#define V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_FIELD                  2
+#define V4L2_HEVC_SEI_PIC_STRUCT_TOP_BOTTOM                    3
+#define V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_TOP                    4
+#define V4L2_HEVC_SEI_PIC_STRUCT_TOP_BOTTOM_TOP                        5
+#define V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM             6
+#define V4L2_HEVC_SEI_PIC_STRUCT_FRAME_DOUBLING                        7
+#define V4L2_HEVC_SEI_PIC_STRUCT_FRAME_TRIPLING                        8
+#define V4L2_HEVC_SEI_PIC_STRUCT_TOP_PAIRED_PREVIOUS_BOTTOM    9
+#define V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_PAIRED_PREVIOUS_TOP    10
+#define V4L2_HEVC_SEI_PIC_STRUCT_TOP_PAIRED_NEXT_BOTTOM                11
+#define V4L2_HEVC_SEI_PIC_STRUCT_BOTTOM_PAIRED_NEXT_TOP                12
+
+#define V4L2_HEVC_DPB_ENTRIES_NUM_MAX          16
+
+/**
+ * struct v4l2_hevc_dpb_entry - HEVC decoded picture buffer entry
+ *
+ * @timestamp: timestamp of the V4L2 capture buffer to use as reference.
+ * @flags: long term flag for the reference frame
+ * @field_pic: whether the reference is a field picture or a frame.
+ * @reserved: padding field. Should be zeroed by applications.
+ * @pic_order_cnt_val: the picture order count of the current picture.
+ */
+struct v4l2_hevc_dpb_entry {
+       __u64   timestamp;
+       __u8    flags;
+       __u8    field_pic;
+       __u16   reserved;
+       __s32   pic_order_cnt_val;
+};
+
+/**
+ * struct v4l2_hevc_pred_weight_table - HEVC weighted prediction parameters
+ *
+ * @delta_luma_weight_l0: the difference of the weighting factor applied
+ *                       to the luma prediction value for list 0
+ * @luma_offset_l0: the additive offset applied to the luma prediction value
+ *                 for list 0
+ * @delta_chroma_weight_l0: the difference of the weighting factor applied
+ *                         to the chroma prediction values for list 0
+ * @chroma_offset_l0: the difference of the additive offset applied to
+ *                   the chroma prediction values for list 0
+ * @delta_luma_weight_l1: the difference of the weighting factor applied
+ *                       to the luma prediction value for list 1
+ * @luma_offset_l1: the additive offset applied to the luma prediction value
+ *                 for list 1
+ * @delta_chroma_weight_l1: the difference of the weighting factor applied
+ *                         to the chroma prediction values for list 1
+ * @chroma_offset_l1: the difference of the additive offset applied to
+ *                   the chroma prediction values for list 1
+ * @luma_log2_weight_denom: the base 2 logarithm of the denominator for
+ *                         all luma weighting factors
+ * @delta_chroma_log2_weight_denom: the difference of the base 2 logarithm
+ *                                 of the denominator for all chroma
+ *                                 weighting factors
+ */
+struct v4l2_hevc_pred_weight_table {
+       __s8    delta_luma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __s8    luma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __s8    delta_chroma_weight_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
+       __s8    chroma_offset_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
+
+       __s8    delta_luma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __s8    luma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __s8    delta_chroma_weight_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
+       __s8    chroma_offset_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX][2];
+
+       __u8    luma_log2_weight_denom;
+       __s8    delta_chroma_log2_weight_denom;
+};
+
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_LUMA             (1ULL << 0)
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_SAO_CHROMA           (1ULL << 1)
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_TEMPORAL_MVP_ENABLED (1ULL << 2)
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_MVD_L1_ZERO                        (1ULL << 3)
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_CABAC_INIT                 (1ULL << 4)
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_COLLOCATED_FROM_L0         (1ULL << 5)
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_USE_INTEGER_MV             (1ULL << 6)
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_DEBLOCKING_FILTER_DISABLED (1ULL << 7)
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_SLICE_LOOP_FILTER_ACROSS_SLICES_ENABLED (1ULL << 8)
+#define V4L2_HEVC_SLICE_PARAMS_FLAG_DEPENDENT_SLICE_SEGMENT    (1ULL << 9)
+
+/**
+ * struct v4l2_ctrl_hevc_slice_params - HEVC slice parameters
+ *
+ * This control is a dynamically sized 1-dimensional array,
+ * V4L2_CTRL_FLAG_DYNAMIC_ARRAY flag must be set when using it.
+ *
+ * @bit_size: size (in bits) of the current slice data
+ * @data_byte_offset: offset (in bytes) to the video data in the current slice data
+ * @num_entry_point_offsets: specifies the number of entry point offset syntax
+ *                          elements in the slice header.
+ * @nal_unit_type: specifies the coding type of the slice (B, P or I)
+ * @nuh_temporal_id_plus1: minus 1 specifies a temporal identifier for the NAL unit
+ * @slice_type: see V4L2_HEVC_SLICE_TYPE_{}
+ * @colour_plane_id: specifies the colour plane associated with the current slice
+ * @slice_pic_order_cnt: specifies the picture order count
+ * @num_ref_idx_l0_active_minus1: this value plus 1 specifies the maximum
+ *                                reference index for reference picture list 0
+ *                                that may be used to decode the slice
+ * @num_ref_idx_l1_active_minus1: this value plus 1 specifies the maximum
+ *                                reference index for reference picture list 1
+ *                                that may be used to decode the slice
+ * @collocated_ref_idx: specifies the reference index of the collocated picture used
+ *                     for temporal motion vector prediction
+ * @five_minus_max_num_merge_cand: specifies the maximum number of merging
+ *                                motion vector prediction candidates supported in
+ *                                the slice subtracted from 5
+ * @slice_qp_delta: specifies the initial value of QpY to be used for the coding
+ *                 blocks in the slice
+ * @slice_cb_qp_offset: specifies a difference to be added to the value of pps_cb_qp_offset
+ * @slice_cr_qp_offset: specifies a difference to be added to the value of pps_cr_qp_offset
+ * @slice_act_y_qp_offset: screen content extension parameters
+ * @slice_act_cb_qp_offset: screen content extension parameters
+ * @slice_act_cr_qp_offset: screen content extension parameters
+ * @slice_beta_offset_div2: specify the deblocking parameter offsets for beta divided by 2
+ * @slice_tc_offset_div2: specify the deblocking parameter offsets for tC divided by 2
+ * @pic_struct: indicates whether a picture should be displayed as a frame or as one or
+ *             more fields
+ * @reserved0: padding field. Should be zeroed by applications.
+ * @slice_segment_addr: specifies the address of the first coding tree block in
+ *                     the slice segment
+ * @ref_idx_l0: the list of L0 reference elements as indices in the DPB
+ * @ref_idx_l1: the list of L1 reference elements as indices in the DPB
+ * @short_term_ref_pic_set_size: specifies the size of short-term reference
+ *                              pictures set included in the SPS
+ * @long_term_ref_pic_set_size: specifies the size of long-term reference
+ *                             pictures set include in the SPS
+ * @pred_weight_table: the prediction weight coefficients for inter-picture
+ *                    prediction
+ * @reserved1: padding field. Should be zeroed by applications.
+ * @flags: see V4L2_HEVC_SLICE_PARAMS_FLAG_{}
+ */
+struct v4l2_ctrl_hevc_slice_params {
+       __u32   bit_size;
+       __u32   data_byte_offset;
+       __u32   num_entry_point_offsets;
+
+       /* ISO/IEC 23008-2, ITU-T Rec. H.265: NAL unit header */
+       __u8    nal_unit_type;
+       __u8    nuh_temporal_id_plus1;
+
+       /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
+       __u8    slice_type;
+       __u8    colour_plane_id;
+       __s32   slice_pic_order_cnt;
+       __u8    num_ref_idx_l0_active_minus1;
+       __u8    num_ref_idx_l1_active_minus1;
+       __u8    collocated_ref_idx;
+       __u8    five_minus_max_num_merge_cand;
+       __s8    slice_qp_delta;
+       __s8    slice_cb_qp_offset;
+       __s8    slice_cr_qp_offset;
+       __s8    slice_act_y_qp_offset;
+       __s8    slice_act_cb_qp_offset;
+       __s8    slice_act_cr_qp_offset;
+       __s8    slice_beta_offset_div2;
+       __s8    slice_tc_offset_div2;
+
+       /* ISO/IEC 23008-2, ITU-T Rec. H.265: Picture timing SEI message */
+       __u8    pic_struct;
+
+       __u8    reserved0[3];
+       /* ISO/IEC 23008-2, ITU-T Rec. H.265: General slice segment header */
+       __u32   slice_segment_addr;
+       __u8    ref_idx_l0[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u8    ref_idx_l1[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u16   short_term_ref_pic_set_size;
+       __u16   long_term_ref_pic_set_size;
+
+       /* ISO/IEC 23008-2, ITU-T Rec. H.265: Weighted prediction parameter */
+       struct v4l2_hevc_pred_weight_table pred_weight_table;
+
+       __u8    reserved1[2];
+       __u64   flags;
+};
+
+#define V4L2_HEVC_DECODE_PARAM_FLAG_IRAP_PIC           0x1
+#define V4L2_HEVC_DECODE_PARAM_FLAG_IDR_PIC            0x2
+#define V4L2_HEVC_DECODE_PARAM_FLAG_NO_OUTPUT_OF_PRIOR  0x4
+
+/**
+ * struct v4l2_ctrl_hevc_decode_params - HEVC decode parameters
+ *
+ * @pic_order_cnt_val: picture order count
+ * @short_term_ref_pic_set_size: specifies the size of short-term reference
+ *                              pictures set included in the SPS of the first slice
+ * @long_term_ref_pic_set_size: specifies the size of long-term reference
+ *                             pictures set include in the SPS of the first slice
+ * @num_active_dpb_entries: the number of entries in dpb
+ * @num_poc_st_curr_before: the number of reference pictures in the short-term
+ *                         set that come before the current frame
+ * @num_poc_st_curr_after: the number of reference pictures in the short-term
+ *                        set that come after the current frame
+ * @num_poc_lt_curr: the number of reference pictures in the long-term set
+ * @poc_st_curr_before: provides the index of the short term before references
+ *                     in DPB array
+ * @poc_st_curr_after: provides the index of the short term after references
+ *                    in DPB array
+ * @poc_lt_curr: provides the index of the long term references in DPB array
+ * @reserved: padding field. Should be zeroed by applications.
+ * @dpb: the decoded picture buffer, for meta-data about reference frames
+ * @flags: see V4L2_HEVC_DECODE_PARAM_FLAG_{}
+ */
+struct v4l2_ctrl_hevc_decode_params {
+       __s32   pic_order_cnt_val;
+       __u16   short_term_ref_pic_set_size;
+       __u16   long_term_ref_pic_set_size;
+       __u8    num_active_dpb_entries;
+       __u8    num_poc_st_curr_before;
+       __u8    num_poc_st_curr_after;
+       __u8    num_poc_lt_curr;
+       __u8    poc_st_curr_before[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u8    poc_st_curr_after[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u8    poc_lt_curr[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u8    reserved[4];
+       struct  v4l2_hevc_dpb_entry dpb[V4L2_HEVC_DPB_ENTRIES_NUM_MAX];
+       __u64   flags;
+};
+
+/**
+ * struct v4l2_ctrl_hevc_scaling_matrix - HEVC scaling lists parameters
+ *
+ * @scaling_list_4x4: scaling list is used for the scaling process for
+ *                   transform coefficients. The values on each scaling
+ *                   list are expected in raster scan order
+ * @scaling_list_8x8: scaling list is used for the scaling process for
+ *                   transform coefficients. The values on each scaling
+ *                   list are expected in raster scan order
+ * @scaling_list_16x16:        scaling list is used for the scaling process for
+ *                     transform coefficients. The values on each scaling
+ *                     list are expected in raster scan order
+ * @scaling_list_32x32:        scaling list is used for the scaling process for
+ *                     transform coefficients. The values on each scaling
+ *                     list are expected in raster scan order
+ * @scaling_list_dc_coef_16x16:        scaling list is used for the scaling process
+ *                             for transform coefficients. The values on each
+ *                             scaling list are expected in raster scan order.
+ * @scaling_list_dc_coef_32x32:        scaling list is used for the scaling process
+ *                             for transform coefficients. The values on each
+ *                             scaling list are expected in raster scan order.
+ */
+struct v4l2_ctrl_hevc_scaling_matrix {
+       __u8    scaling_list_4x4[6][16];
+       __u8    scaling_list_8x8[6][64];
+       __u8    scaling_list_16x16[6][64];
+       __u8    scaling_list_32x32[2][64];
+       __u8    scaling_list_dc_coef_16x16[6];
+       __u8    scaling_list_dc_coef_32x32[2];
+};
+
 #define V4L2_CID_COLORIMETRY_CLASS_BASE        (V4L2_CTRL_CLASS_COLORIMETRY | 0x900)
 #define V4L2_CID_COLORIMETRY_CLASS     (V4L2_CTRL_CLASS_COLORIMETRY | 1)
 
index 343b951..01e630f 100644 (file)
@@ -245,6 +245,14 @@ enum v4l2_colorspace {
 
        /* DCI-P3 colorspace, used by cinema projectors */
        V4L2_COLORSPACE_DCI_P3        = 12,
+
+#ifdef __KERNEL__
+       /*
+        * Largest supported colorspace value, assigned by the compiler, used
+        * by the framework to check for invalid values.
+        */
+       V4L2_COLORSPACE_LAST,
+#endif
 };
 
 /*
@@ -283,6 +291,13 @@ enum v4l2_xfer_func {
        V4L2_XFER_FUNC_NONE        = 5,
        V4L2_XFER_FUNC_DCI_P3      = 6,
        V4L2_XFER_FUNC_SMPTE2084   = 7,
+#ifdef __KERNEL__
+       /*
+        * Largest supported transfer function value, assigned by the compiler,
+        * used by the framework to check for invalid values.
+        */
+       V4L2_XFER_FUNC_LAST,
+#endif
 };
 
 /*
@@ -343,6 +358,13 @@ enum v4l2_ycbcr_encoding {
 
        /* SMPTE 240M -- Obsolete HDTV */
        V4L2_YCBCR_ENC_SMPTE240M      = 8,
+#ifdef __KERNEL__
+       /*
+        * Largest supported encoding value, assigned by the compiler, used by
+        * the framework to check for invalid values.
+        */
+       V4L2_YCBCR_ENC_LAST,
+#endif
 };
 
 /*
@@ -593,6 +615,8 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_XYUV32  v4l2_fourcc('X', 'Y', 'U', 'V') /* 32  XYUV-8-8-8-8  */
 #define V4L2_PIX_FMT_VUYA32  v4l2_fourcc('V', 'U', 'Y', 'A') /* 32  VUYA-8-8-8-8  */
 #define V4L2_PIX_FMT_VUYX32  v4l2_fourcc('V', 'U', 'Y', 'X') /* 32  VUYX-8-8-8-8  */
+#define V4L2_PIX_FMT_YUVA32  v4l2_fourcc('Y', 'U', 'V', 'A') /* 32  YUVA-8-8-8-8  */
+#define V4L2_PIX_FMT_YUVX32  v4l2_fourcc('Y', 'U', 'V', 'X') /* 32  YUVX-8-8-8-8  */
 #define V4L2_PIX_FMT_M420    v4l2_fourcc('M', '4', '2', '0') /* 12  YUV 4:2:0 2 lines y, 1 line uv interleaved */
 
 /* two planes -- one Y, one Cr + Cb interleaved  */
@@ -602,6 +626,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_NV61    v4l2_fourcc('N', 'V', '6', '1') /* 16  Y/CrCb 4:2:2  */
 #define V4L2_PIX_FMT_NV24    v4l2_fourcc('N', 'V', '2', '4') /* 24  Y/CbCr 4:4:4  */
 #define V4L2_PIX_FMT_NV42    v4l2_fourcc('N', 'V', '4', '2') /* 24  Y/CrCb 4:4:4  */
+#define V4L2_PIX_FMT_P010    v4l2_fourcc('P', '0', '1', '0') /* 24  Y/CbCr 4:2:0 10-bit per component */
 
 /* two non contiguous planes - one Y, one Cr + Cb interleaved  */
 #define V4L2_PIX_FMT_NV12M   v4l2_fourcc('N', 'M', '1', '2') /* 12  Y/CbCr 4:2:0  */
@@ -629,6 +654,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_NV12_4L4 v4l2_fourcc('V', 'T', '1', '2')   /* 12  Y/CbCr 4:2:0  4x4 tiles */
 #define V4L2_PIX_FMT_NV12_16L16 v4l2_fourcc('H', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 16x16 tiles */
 #define V4L2_PIX_FMT_NV12_32L32 v4l2_fourcc('S', 'T', '1', '2') /* 12  Y/CbCr 4:2:0 32x32 tiles */
+#define V4L2_PIX_FMT_P010_4L4 v4l2_fourcc('T', '0', '1', '0') /* 12  Y/CbCr 4:2:0 10-bit 4x4 macroblocks */
 
 /* Tiled YUV formats, non contiguous planes */
 #define V4L2_PIX_FMT_NV12MT  v4l2_fourcc('T', 'M', '1', '2') /* 12  Y/CbCr 4:2:0 64x32 tiles */
@@ -711,6 +737,7 @@ struct v4l2_pix_format {
 #define V4L2_PIX_FMT_FWHT     v4l2_fourcc('F', 'W', 'H', 'T') /* Fast Walsh Hadamard Transform (vicodec) */
 #define V4L2_PIX_FMT_FWHT_STATELESS     v4l2_fourcc('S', 'F', 'W', 'H') /* Stateless FWHT (vicodec) */
 #define V4L2_PIX_FMT_H264_SLICE v4l2_fourcc('S', '2', '6', '4') /* H264 parsed slices */
+#define V4L2_PIX_FMT_HEVC_SLICE v4l2_fourcc('S', '2', '6', '5') /* HEVC parsed slices */
 
 /*  Vendor-specific formats   */
 #define V4L2_PIX_FMT_CPIA1    v4l2_fourcc('C', 'P', 'I', 'A') /* cpia1 YUV */
@@ -1767,6 +1794,11 @@ struct v4l2_ext_control {
                struct v4l2_ctrl_mpeg2_quantisation __user *p_mpeg2_quantisation;
                struct v4l2_ctrl_vp9_compressed_hdr __user *p_vp9_compressed_hdr_probs;
                struct v4l2_ctrl_vp9_frame __user *p_vp9_frame;
+               struct v4l2_ctrl_hevc_sps __user *p_hevc_sps;
+               struct v4l2_ctrl_hevc_pps __user *p_hevc_pps;
+               struct v4l2_ctrl_hevc_slice_params __user *p_hevc_slice_params;
+               struct v4l2_ctrl_hevc_scaling_matrix __user *p_hevc_scaling_matrix;
+               struct v4l2_ctrl_hevc_decode_params __user *p_hevc_decode_params;
                void __user *ptr;
        };
 } __attribute__ ((packed));
@@ -1834,6 +1866,12 @@ enum v4l2_ctrl_type {
 
        V4L2_CTRL_TYPE_VP9_COMPRESSED_HDR       = 0x0260,
        V4L2_CTRL_TYPE_VP9_FRAME                = 0x0261,
+
+       V4L2_CTRL_TYPE_HEVC_SPS                 = 0x0270,
+       V4L2_CTRL_TYPE_HEVC_PPS                 = 0x0271,
+       V4L2_CTRL_TYPE_HEVC_SLICE_PARAMS        = 0x0272,
+       V4L2_CTRL_TYPE_HEVC_SCALING_MATRIX      = 0x0273,
+       V4L2_CTRL_TYPE_HEVC_DECODE_PARAMS       = 0x0274,
 };
 
 /*  Used in the VIDIOC_QUERYCTRL ioctl for querying controls */
@@ -1889,6 +1927,7 @@ struct v4l2_querymenu {
 #define V4L2_CTRL_FLAG_HAS_PAYLOAD     0x0100
 #define V4L2_CTRL_FLAG_EXECUTE_ON_WRITE        0x0200
 #define V4L2_CTRL_FLAG_MODIFY_LAYOUT   0x0400
+#define V4L2_CTRL_FLAG_DYNAMIC_ARRAY   0x0800
 
 /*  Query flags, to be ORed with the control ID */
 #define V4L2_CTRL_FLAG_NEXT_CTRL       0x80000000