summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/admin-guide/media/em28xx-cardlist.rst8
-rw-r--r--Documentation/admin-guide/media/ipu6-isys.rst14
-rw-r--r--Documentation/admin-guide/media/raspberrypi-pisp-be.dot20
-rw-r--r--Documentation/admin-guide/media/raspberrypi-pisp-be.rst109
-rw-r--r--Documentation/admin-guide/media/tuner-cardlist.rst2
-rw-r--r--Documentation/admin-guide/media/v4l-drivers.rst1
-rw-r--r--Documentation/admin-guide/media/vivid.rst185
-rw-r--r--Documentation/devicetree/bindings/media/i2c/galaxycore,gc05a2.yaml112
-rw-r--r--Documentation/devicetree/bindings/media/i2c/galaxycore,gc08a3.yaml112
-rw-r--r--Documentation/devicetree/bindings/media/i2c/maxim,max96714.yaml174
-rw-r--r--Documentation/devicetree/bindings/media/i2c/maxim,max96717.yaml157
-rw-r--r--Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml (renamed from Documentation/devicetree/bindings/media/i2c/imx258.yaml)11
-rw-r--r--Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml107
-rw-r--r--Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml75
-rw-r--r--Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml1
-rw-r--r--Documentation/devicetree/bindings/media/mediatek,mt7622-cir.yaml55
-rw-r--r--Documentation/devicetree/bindings/media/mtk-cir.txt28
-rw-r--r--Documentation/devicetree/bindings/media/qcom,msm8996-venus.yaml4
-rw-r--r--Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml63
-rw-r--r--Documentation/devicetree/bindings/media/rc.yaml1
-rw-r--r--Documentation/devicetree/bindings/media/rockchip-rga.yaml1
-rw-r--r--Documentation/driver-api/media/v4l2-core.rst1
-rw-r--r--Documentation/driver-api/media/v4l2-jpeg.rst10
-rw-r--r--Documentation/userspace-api/media/drivers/index.rst2
-rw-r--r--Documentation/userspace-api/media/drivers/vgxy61.rst (renamed from Documentation/userspace-api/media/drivers/st-vgxy61.rst)0
-rw-r--r--Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst4
-rw-r--r--Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst14
-rw-r--r--Documentation/userspace-api/media/v4l/meta-formats.rst1
-rw-r--r--Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst56
-rw-r--r--Documentation/userspace-api/media/v4l/pixfmt-bayer.rst1
-rw-r--r--Documentation/userspace-api/media/v4l/pixfmt-rgb.rst54
-rw-r--r--Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst74
-rw-r--r--Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst4
-rw-r--r--MAINTAINERS63
-rw-r--r--drivers/media/common/siano/smscoreapi.c10
-rw-r--r--drivers/media/common/siano/smscoreapi.h18
-rw-r--r--drivers/media/common/siano/smsdvb-main.c4
-rw-r--r--drivers/media/common/siano/smsendian.c8
-rw-r--r--drivers/media/common/uvc.c1
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c1
-rw-r--r--drivers/media/common/videobuf2/videobuf2-dvb.c1
-rw-r--r--drivers/media/dvb-frontends/au8522_decoder.c1
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c5
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c7
-rw-r--r--drivers/media/dvb-frontends/mb86a16.c1
-rw-r--r--drivers/media/dvb-frontends/mxl5xx_defs.h4
-rw-r--r--drivers/media/dvb-frontends/stv090x.c37
-rw-r--r--drivers/media/dvb-frontends/stv0910.c5
-rw-r--r--drivers/media/i2c/Kconfig68
-rw-r--r--drivers/media/i2c/Makefile7
-rw-r--r--drivers/media/i2c/adv748x/adv748x-afe.c4
-rw-r--r--drivers/media/i2c/adv748x/adv748x-csi2.c145
-rw-r--r--drivers/media/i2c/adv748x/adv748x.h1
-rw-r--r--drivers/media/i2c/adv7511-v4l2.c5
-rw-r--r--drivers/media/i2c/alvium-csi2.c65
-rw-r--r--drivers/media/i2c/alvium-csi2.h16
-rw-r--r--drivers/media/i2c/dw9768.c5
-rw-r--r--drivers/media/i2c/gc05a2.c1359
-rw-r--r--drivers/media/i2c/gc08a3.c1339
-rw-r--r--drivers/media/i2c/gc2145.c90
-rw-r--r--drivers/media/i2c/hi846.c2
-rw-r--r--drivers/media/i2c/imx219.c2
-rw-r--r--drivers/media/i2c/imx258.c1424
-rw-r--r--drivers/media/i2c/imx283.c1612
-rw-r--r--drivers/media/i2c/imx412.c9
-rw-r--r--drivers/media/i2c/ks0127.c8
-rw-r--r--drivers/media/i2c/max9286.c181
-rw-r--r--drivers/media/i2c/max96714.c1024
-rw-r--r--drivers/media/i2c/max96717.c927
-rw-r--r--drivers/media/i2c/ov2680.c2
-rw-r--r--drivers/media/i2c/ov5647.c11
-rw-r--r--drivers/media/i2c/ov5693.c10
-rw-r--r--drivers/media/i2c/tw9910.c5
-rw-r--r--drivers/media/i2c/uda1342.c1
-rw-r--r--drivers/media/i2c/vgxy61.c (renamed from drivers/media/i2c/st-vgxy61.c)2
-rw-r--r--drivers/media/pci/bt8xx/bt878.c9
-rw-r--r--drivers/media/pci/bt8xx/bt878.h3
-rw-r--r--drivers/media/pci/bt8xx/dvb-bt8xx.c8
-rw-r--r--drivers/media/pci/cx18/cx18-scb.h2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge.h2
-rw-r--r--drivers/media/pci/intel/ipu-bridge.c40
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-buttress.c4
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c98
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h2
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-queue.c3
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-video.c43
-rw-r--r--drivers/media/pci/intel/ivsc/mei_csi.c24
-rw-r--r--drivers/media/pci/ivtv/ivtv-driver.c93
-rw-r--r--drivers/media/pci/ivtv/ivtv-fileops.c66
-rw-r--r--drivers/media/pci/ivtv/ivtv-udma.c8
-rw-r--r--drivers/media/pci/ivtv/ivtv-yuv.c6
-rw-r--r--drivers/media/pci/ivtv/ivtvfb.c7
-rw-r--r--drivers/media/pci/mantis/hopper_cards.c2
-rw-r--r--drivers/media/pci/mantis/mantis_cards.c2
-rw-r--r--drivers/media/pci/mantis/mantis_common.h2
-rw-r--r--drivers/media/pci/mantis/mantis_dma.c4
-rw-r--r--drivers/media/pci/mantis/mantis_dma.h2
-rw-r--r--drivers/media/pci/mantis/mantis_dvb.c12
-rw-r--r--drivers/media/pci/ngene/ngene-core.c22
-rw-r--r--drivers/media/pci/ngene/ngene.h5
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c1
-rw-r--r--drivers/media/pci/saa7134/saa7134-dvb.c9
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c1
-rw-r--r--drivers/media/pci/saa7134/saa7134-go7007.c1
-rw-r--r--drivers/media/pci/smipcie/smipcie-main.c18
-rw-r--r--drivers/media/pci/smipcie/smipcie.h3
-rw-r--r--drivers/media/pci/ttpci/budget-av.c3
-rw-r--r--drivers/media/pci/ttpci/budget-ci.c27
-rw-r--r--drivers/media/pci/ttpci/budget-core.c11
-rw-r--r--drivers/media/pci/ttpci/budget.h5
-rw-r--r--drivers/media/pci/tw5864/tw5864-core.c2
-rw-r--r--drivers/media/pci/tw5864/tw5864-video.c13
-rw-r--r--drivers/media/pci/tw5864/tw5864.h7
-rw-r--r--drivers/media/platform/Kconfig2
-rw-r--r--drivers/media/platform/Makefile2
-rw-r--r--drivers/media/platform/allegro-dvt/nal-hevc.h7
-rw-r--r--drivers/media/platform/amphion/vdec.c2
-rw-r--r--drivers/media/platform/amphion/venc.c6
-rw-r--r--drivers/media/platform/amphion/vpu.h1
-rw-r--r--drivers/media/platform/amphion/vpu_defs.h1
-rw-r--r--drivers/media/platform/amphion/vpu_malone.c5
-rw-r--r--drivers/media/platform/amphion/vpu_v4l2.c16
-rw-r--r--drivers/media/platform/amphion/vpu_v4l2.h1
-rw-r--r--drivers/media/platform/amphion/vpu_windsor.c2
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-helper.c8
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-hw.c395
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-regdefine.h5
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vdi.c27
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c51
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c2
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu.c35
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuapi.h3
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h16
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5.h6
-rw-r--r--drivers/media/platform/imagination/Kconfig13
-rw-r--r--drivers/media/platform/imagination/Makefile3
-rw-r--r--drivers/media/platform/imagination/e5010-core-regs.h585
-rw-r--r--drivers/media/platform/imagination/e5010-jpeg-enc-hw.c267
-rw-r--r--drivers/media/platform/imagination/e5010-jpeg-enc-hw.h42
-rw-r--r--drivers/media/platform/imagination/e5010-jpeg-enc.c1632
-rw-r--r--drivers/media/platform/imagination/e5010-jpeg-enc.h168
-rw-r--r--drivers/media/platform/imagination/e5010-mmu-regs.h311
-rw-r--r--drivers/media/platform/intel/pxa_camera.c15
-rw-r--r--drivers/media/platform/m2m-deinterlace.c4
-rw-r--r--drivers/media/platform/marvell/mcam-core.c9
-rw-r--r--drivers/media/platform/marvell/mcam-core.h3
-rw-r--r--drivers/media/platform/marvell/mmp-driver.c1
-rw-r--r--drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c280
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h1
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h1
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c3
-rw-r--r--drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c3
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c60
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c2
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c6
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/h264.c5
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/vde.h1
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c14
-rw-r--r--drivers/media/platform/nxp/imx-mipi-csis.c22
-rw-r--r--drivers/media/platform/nxp/imx-pxp.c3
-rw-r--r--drivers/media/platform/qcom/camss/Makefile1
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid-4-1.c132
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid-4-7.c160
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid-gen2.c407
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid.c512
-rw-r--r--drivers/media/platform/qcom/camss/camss-csid.h32
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy.c74
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy.h23
-rw-r--r--drivers/media/platform/qcom/camss/camss-format.c91
-rw-r--r--drivers/media/platform/qcom/camss/camss-format.h62
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-17x.c10
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-4-1.c4
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-4-7.c6
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-4-8.c6
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-gen1.c8
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.c483
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.h22
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.c294
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.h4
-rw-r--r--drivers/media/platform/qcom/camss/camss.c683
-rw-r--r--drivers/media/platform/qcom/camss/camss.h20
-rw-r--r--drivers/media/platform/qcom/venus/core.c45
-rw-r--r--drivers/media/platform/qcom/venus/core.h2
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c3
-rw-r--r--drivers/media/platform/raspberrypi/Kconfig5
-rw-r--r--drivers/media/platform/raspberrypi/Makefile3
-rw-r--r--drivers/media/platform/raspberrypi/pisp_be/Kconfig12
-rw-r--r--drivers/media/platform/raspberrypi/pisp_be/Makefile6
-rw-r--r--drivers/media/platform/raspberrypi/pisp_be/pisp_be.c1797
-rw-r--r--drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h519
-rw-r--r--drivers/media/platform/renesas/rcar-csi2.c155
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-dma.c16
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_brx.c31
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_clu.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_drm.c27
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_drm.h2
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_entity.c66
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_entity.h48
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_hgo.c28
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_hgt.c20
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_histo.c76
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_hsit.c6
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_lif.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_lut.c1
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_pipe.c103
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_pipe.h48
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_rpf.c56
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_rwpf.c26
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_rwpf.h3
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_sru.c37
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_uds.c51
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_uif.c15
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_video.c200
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_wpf.c43
-rw-r--r--drivers/media/platform/rockchip/rga/rga-buf.c5
-rw-r--r--drivers/media/platform/rockchip/rga/rga.c4
-rw-r--r--drivers/media/platform/rockchip/rga/rga.h3
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c8
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c8
-rw-r--r--drivers/media/platform/samsung/exynos4-is/common.c1
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is.c1
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-lite.c1
-rw-r--r--drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c14
-rw-r--r--drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.h2
-rw-r--r--drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.h4
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c4
-rw-r--r--drivers/media/platform/ti/vpe/vpdma.c1
-rw-r--r--drivers/media/platform/verisilicon/Kconfig1
-rw-r--r--drivers/media/platform/verisilicon/hantro_jpeg.c129
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c4
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.h2
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c1
-rw-r--r--drivers/media/radio/wl128x/fmdrv.h5
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c40
-rw-r--r--drivers/media/rc/imon.c5
-rw-r--r--drivers/media/rc/keymaps/Makefile1
-rw-r--r--drivers/media/rc/keymaps/rc-mygica-utv3.c69
-rw-r--r--drivers/media/rc/mceusb.c13
-rw-r--r--drivers/media/rc/rc-main.c1
-rw-r--r--drivers/media/spi/gs1662.c8
-rw-r--r--drivers/media/test-drivers/vimc/vimc-capture.c2
-rw-r--r--drivers/media/test-drivers/vimc/vimc-common.c25
-rw-r--r--drivers/media/test-drivers/vimc/vimc-common.h14
-rw-r--r--drivers/media/test-drivers/vimc/vimc-core.c2
-rw-r--r--drivers/media/test-drivers/vimc/vimc-debayer.c201
-rw-r--r--drivers/media/test-drivers/vimc/vimc-lens.c5
-rw-r--r--drivers/media/test-drivers/vimc/vimc-scaler.c134
-rw-r--r--drivers/media/test-drivers/vimc/vimc-sensor.c125
-rw-r--r--drivers/media/test-drivers/vivid/vivid-cec.c88
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.c250
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.h125
-rw-r--r--drivers/media/test-drivers/vivid/vivid-ctrls.c262
-rw-r--r--drivers/media/test-drivers/vivid/vivid-kthread-cap.c86
-rw-r--r--drivers/media/test-drivers/vivid/vivid-sdr-cap.c7
-rw-r--r--drivers/media/test-drivers/vivid/vivid-touch-cap.c6
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vbi-cap.c7
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vbi-out.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.c120
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.h2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-common.c134
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-common.h5
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-out.c41
-rw-r--r--drivers/media/tuners/tda9887.c1
-rw-r--r--drivers/media/tuners/tuner-types.c21
-rw-r--r--drivers/media/tuners/xc2028.c9
-rw-r--r--drivers/media/usb/b2c2/flexcop-usb.c7
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c2
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-common.c1
-rw-r--r--drivers/media/usb/dvb-usb/dibusb-mc-common.c1
-rw-r--r--drivers/media/usb/dvb-usb/dvb-usb-init.c35
-rw-r--r--drivers/media/usb/dvb-usb/opera1.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c52
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c3
-rw-r--r--drivers/media/usb/em28xx/em28xx.h1
-rw-r--r--drivers/media/usb/go7007/go7007-driver.c1
-rw-r--r--drivers/media/usb/go7007/go7007-i2c.c30
-rw-r--r--drivers/media/usb/go7007/go7007-usb.c1
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-debugifc.c5
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c21
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c193
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c160
-rw-r--r--drivers/media/usb/uvc/uvc_video.c169
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h10
-rw-r--r--drivers/media/v4l2-core/v4l2-async.c8
-rw-r--r--drivers/media/v4l2-core/v4l2-cci.c9
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c2
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-defs.c5
-rw-r--r--drivers/media/v4l2-core/v4l2-fwnode.c1
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c13
-rw-r--r--drivers/media/v4l2-core/v4l2-jpeg.c116
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c393
-rw-r--r--drivers/staging/media/atomisp/TODO31
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c1
-rw-r--r--drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c1
-rw-r--r--drivers/staging/media/atomisp/include/linux/atomisp_platform.h27
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_common.h1
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c14
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_ioctl.c2
-rw-r--r--drivers/staging/media/atomisp/pci/atomisp_v4l2.c41
-rw-r--r--drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h6
-rw-r--r--drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h11
-rw-r--r--drivers/staging/media/atomisp/pci/camera/util/src/util.c25
-rw-r--r--drivers/staging/media/atomisp/pci/gpio_block_defs.h17
-rw-r--r--drivers/staging/media/atomisp/pci/hive_isp_css_common/gpio_global.h23
-rw-r--r--drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_local.h21
-rw-r--r--drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_private.h9
-rw-r--r--drivers/staging/media/atomisp/pci/hive_isp_css_include/assert_support.h23
-rw-r--r--drivers/staging/media/atomisp/pci/hive_isp_css_include/gpio.h46
-rw-r--r--drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gpio_public.h46
-rw-r--r--drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h110
-rw-r--r--drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h5
-rw-r--r--drivers/staging/media/atomisp/pci/hmm/hmm_bo.c4
-rw-r--r--drivers/staging/media/atomisp/pci/ia_css_3a.h5
-rw-r--r--drivers/staging/media/atomisp/pci/ia_css_dvs.h4
-rw-r--r--drivers/staging/media/atomisp/pci/ia_css_metadata.h4
-rw-r--r--drivers/staging/media/atomisp/pci/ia_css_types.h2
-rw-r--r--drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.c2
-rw-r--r--drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.c6
-rw-r--r--drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c2
-rw-r--r--drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c4
-rw-r--r--drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h4
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css.c48
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_frac.h4
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_internal.h19
-rw-r--r--drivers/staging/media/atomisp/pci/sh_css_sp.c24
-rw-r--r--drivers/staging/media/av7110/Kconfig22
-rw-r--r--drivers/staging/media/av7110/Makefile2
-rw-r--r--drivers/staging/media/av7110/TODO3
-rw-r--r--drivers/staging/media/av7110/audio-bilingual-channel-select.rst58
-rw-r--r--drivers/staging/media/av7110/audio-channel-select.rst57
-rw-r--r--drivers/staging/media/av7110/audio-clear-buffer.rst48
-rw-r--r--drivers/staging/media/av7110/audio-continue.rst48
-rw-r--r--drivers/staging/media/av7110/audio-fclose.rst51
-rw-r--r--drivers/staging/media/av7110/audio-fopen.rst103
-rw-r--r--drivers/staging/media/av7110/audio-fwrite.rst79
-rw-r--r--drivers/staging/media/av7110/audio-get-capabilities.rst54
-rw-r--r--drivers/staging/media/av7110/audio-get-status.rst54
-rw-r--r--drivers/staging/media/av7110/audio-pause.rst49
-rw-r--r--drivers/staging/media/av7110/audio-play.rst48
-rw-r--r--drivers/staging/media/av7110/audio-select-source.rst56
-rw-r--r--drivers/staging/media/av7110/audio-set-av-sync.rst58
-rw-r--r--drivers/staging/media/av7110/audio-set-bypass-mode.rst62
-rw-r--r--drivers/staging/media/av7110/audio-set-id.rst59
-rw-r--r--drivers/staging/media/av7110/audio-set-mixer.rst53
-rw-r--r--drivers/staging/media/av7110/audio-set-mute.rst62
-rw-r--r--drivers/staging/media/av7110/audio-set-streamtype.rst66
-rw-r--r--drivers/staging/media/av7110/audio-stop.rst48
-rw-r--r--drivers/staging/media/av7110/audio.rst27
-rw-r--r--drivers/staging/media/av7110/audio_data_types.rst116
-rw-r--r--drivers/staging/media/av7110/audio_function_calls.rst30
-rw-r--r--drivers/staging/media/av7110/av7110.c496
-rw-r--r--drivers/staging/media/av7110/av7110.h50
-rw-r--r--drivers/staging/media/av7110/av7110_av.c234
-rw-r--r--drivers/staging/media/av7110/av7110_av.h37
-rw-r--r--drivers/staging/media/av7110/av7110_ca.c43
-rw-r--r--drivers/staging/media/av7110/av7110_ca.h12
-rw-r--r--drivers/staging/media/av7110/av7110_hw.c230
-rw-r--r--drivers/staging/media/av7110/av7110_hw.h79
-rw-r--r--drivers/staging/media/av7110/av7110_ipack.c282
-rw-r--r--drivers/staging/media/av7110/av7110_ipack.h12
-rw-r--r--drivers/staging/media/av7110/av7110_ir.c3
-rw-r--r--drivers/staging/media/av7110/av7110_v4l.c102
-rw-r--r--drivers/staging/media/av7110/budget-patch.c665
-rw-r--r--drivers/staging/media/av7110/dvb_filter.c116
-rw-r--r--drivers/staging/media/av7110/dvb_filter.h22
-rw-r--r--drivers/staging/media/av7110/sp8870.c200
-rw-r--r--drivers/staging/media/av7110/sp8870.h24
-rw-r--r--drivers/staging/media/av7110/video-clear-buffer.rst54
-rw-r--r--drivers/staging/media/av7110/video-command.rst96
-rw-r--r--drivers/staging/media/av7110/video-continue.rst57
-rw-r--r--drivers/staging/media/av7110/video-fast-forward.rst72
-rw-r--r--drivers/staging/media/av7110/video-fclose.rst51
-rw-r--r--drivers/staging/media/av7110/video-fopen.rst111
-rw-r--r--drivers/staging/media/av7110/video-freeze.rst61
-rw-r--r--drivers/staging/media/av7110/video-fwrite.rst79
-rw-r--r--drivers/staging/media/av7110/video-get-capabilities.rst61
-rw-r--r--drivers/staging/media/av7110/video-get-event.rst105
-rw-r--r--drivers/staging/media/av7110/video-get-frame-count.rst65
-rw-r--r--drivers/staging/media/av7110/video-get-pts.rst69
-rw-r--r--drivers/staging/media/av7110/video-get-size.rst69
-rw-r--r--drivers/staging/media/av7110/video-get-status.rst72
-rw-r--r--drivers/staging/media/av7110/video-play.rst57
-rw-r--r--drivers/staging/media/av7110/video-select-source.rst76
-rw-r--r--drivers/staging/media/av7110/video-set-blank.rst64
-rw-r--r--drivers/staging/media/av7110/video-set-display-format.rst60
-rw-r--r--drivers/staging/media/av7110/video-set-format.rst82
-rw-r--r--drivers/staging/media/av7110/video-set-streamtype.rst61
-rw-r--r--drivers/staging/media/av7110/video-slowmotion.rst72
-rw-r--r--drivers/staging/media/av7110/video-stillpicture.rst61
-rw-r--r--drivers/staging/media/av7110/video-stop.rst74
-rw-r--r--drivers/staging/media/av7110/video-try-command.rst66
-rw-r--r--drivers/staging/media/av7110/video.rst36
-rw-r--r--drivers/staging/media/av7110/video_function_calls.rst35
-rw-r--r--drivers/staging/media/av7110/video_types.rst248
-rw-r--r--drivers/staging/media/max96712/max96712.c37
-rw-r--r--include/media/ipu-bridge.h1
-rw-r--r--include/media/rc-map.h1
-rw-r--r--include/media/tuner.h1
-rw-r--r--include/media/v4l2-jpeg.h32
-rw-r--r--include/media/v4l2-subdev.h92
-rw-r--r--include/uapi/linux/media/raspberrypi/pisp_be_config.h968
-rw-r--r--include/uapi/linux/media/raspberrypi/pisp_common.h202
-rw-r--r--include/uapi/linux/v4l2-controls.h2
-rw-r--r--include/uapi/linux/videodev2.h17
405 files changed, 21983 insertions, 10210 deletions
diff --git a/Documentation/admin-guide/media/em28xx-cardlist.rst b/Documentation/admin-guide/media/em28xx-cardlist.rst
index ace65718ea22..7dac07986d91 100644
--- a/Documentation/admin-guide/media/em28xx-cardlist.rst
+++ b/Documentation/admin-guide/media/em28xx-cardlist.rst
@@ -438,3 +438,11 @@ EM28xx cards list
- MyGica iGrabber
- em2860
- 1f4d:1abe
+ * - 106
+ - Hauppauge USB QuadHD ATSC
+ - em28274
+ - 2040:846d
+ * - 107
+ - MyGica UTV3 Analog USB2.0 TV Box
+ - em2860
+ - eb1a:2860
diff --git a/Documentation/admin-guide/media/ipu6-isys.rst b/Documentation/admin-guide/media/ipu6-isys.rst
index 0721e920b5e6..d05086824a74 100644
--- a/Documentation/admin-guide/media/ipu6-isys.rst
+++ b/Documentation/admin-guide/media/ipu6-isys.rst
@@ -135,16 +135,16 @@ sensor ov2740 on Lenovo X1 Yoga laptop.
.. code-block:: none
media-ctl -l "\"ov2740 14-0036\":0 -> \"Intel IPU6 CSI2 1\":0[1]"
- media-ctl -l "\"Intel IPU6 CSI2 1\":1 -> \"Intel IPU6 ISYS Capture 0\":0[5]"
- media-ctl -l "\"Intel IPU6 CSI2 1\":2 -> \"Intel IPU6 ISYS Capture 1\":0[5]"
+ media-ctl -l "\"Intel IPU6 CSI2 1\":1 -> \"Intel IPU6 ISYS Capture 0\":0[1]"
+ media-ctl -l "\"Intel IPU6 CSI2 1\":2 -> \"Intel IPU6 ISYS Capture 1\":0[1]"
# set routing
- media-ctl -v -R "\"Intel IPU6 CSI2 1\" [0/0->1/0[1],0/1->2/1[1]]"
+ media-ctl -R "\"Intel IPU6 CSI2 1\" [0/0->1/0[1],0/1->2/1[1]]"
- media-ctl -v "\"Intel IPU6 CSI2 1\":0/0 [fmt:SGRBG10/1932x1092]"
- media-ctl -v "\"Intel IPU6 CSI2 1\":0/1 [fmt:GENERIC_8/97x1]"
- media-ctl -v "\"Intel IPU6 CSI2 1\":1/0 [fmt:SGRBG10/1932x1092]"
- media-ctl -v "\"Intel IPU6 CSI2 1\":2/1 [fmt:GENERIC_8/97x1]"
+ media-ctl -V "\"Intel IPU6 CSI2 1\":0/0 [fmt:SGRBG10/1932x1092]"
+ media-ctl -V "\"Intel IPU6 CSI2 1\":0/1 [fmt:GENERIC_8/97x1]"
+ media-ctl -V "\"Intel IPU6 CSI2 1\":1/0 [fmt:SGRBG10/1932x1092]"
+ media-ctl -V "\"Intel IPU6 CSI2 1\":2/1 [fmt:GENERIC_8/97x1]"
CAPTURE_DEV=$(media-ctl -e "Intel IPU6 ISYS Capture 0")
./yavta --data-prefix -c100 -n5 -I -s1932x1092 --file=/tmp/frame-#.bin \
diff --git a/Documentation/admin-guide/media/raspberrypi-pisp-be.dot b/Documentation/admin-guide/media/raspberrypi-pisp-be.dot
new file mode 100644
index 000000000000..55671dc1d443
--- /dev/null
+++ b/Documentation/admin-guide/media/raspberrypi-pisp-be.dot
@@ -0,0 +1,20 @@
+digraph board {
+ rankdir=TB
+ n00000001 [label="{{<port0> 0 | <port1> 1 | <port2> 2 | <port7> 7} | pispbe\n | {<port3> 3 | <port4> 4 | <port5> 5 | <port6> 6}}", shape=Mrecord, style=filled, fillcolor=green]
+ n00000001:port3 -> n0000001c [style=bold]
+ n00000001:port4 -> n00000022 [style=bold]
+ n00000001:port5 -> n00000028 [style=bold]
+ n00000001:port6 -> n0000002e [style=bold]
+ n0000000a [label="pispbe-input\n/dev/video0", shape=box, style=filled, fillcolor=yellow]
+ n0000000a -> n00000001:port0 [style=bold]
+ n00000010 [label="pispbe-tdn_input\n/dev/video1", shape=box, style=filled, fillcolor=yellow]
+ n00000010 -> n00000001:port1 [style=bold]
+ n00000016 [label="pispbe-stitch_input\n/dev/video2", shape=box, style=filled, fillcolor=yellow]
+ n00000016 -> n00000001:port2 [style=bold]
+ n0000001c [label="pispbe-output0\n/dev/video3", shape=box, style=filled, fillcolor=yellow]
+ n00000022 [label="pispbe-output1\n/dev/video4", shape=box, style=filled, fillcolor=yellow]
+ n00000028 [label="pispbe-tdn_output\n/dev/video5", shape=box, style=filled, fillcolor=yellow]
+ n0000002e [label="pispbe-stitch_output\n/dev/video6", shape=box, style=filled, fillcolor=yellow]
+ n00000034 [label="pispbe-config\n/dev/video7", shape=box, style=filled, fillcolor=yellow]
+ n00000034 -> n00000001:port7 [style=bold]
+}
diff --git a/Documentation/admin-guide/media/raspberrypi-pisp-be.rst b/Documentation/admin-guide/media/raspberrypi-pisp-be.rst
new file mode 100644
index 000000000000..0fcf46f26276
--- /dev/null
+++ b/Documentation/admin-guide/media/raspberrypi-pisp-be.rst
@@ -0,0 +1,109 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+=========================================================
+Raspberry Pi PiSP Back End Memory-to-Memory ISP (pisp-be)
+=========================================================
+
+The PiSP Back End
+=================
+
+The PiSP Back End is a memory-to-memory Image Signal Processor (ISP) which reads
+image data from DRAM memory and performs image processing as specified by the
+application through the parameters in a configuration buffer, before writing
+pixel data back to memory through two distinct output channels.
+
+The ISP registers and programming model are documented in the `Raspberry Pi
+Image Signal Processor (PiSP) Specification document`_
+
+The PiSP Back End ISP processes images in tiles. The handling of image
+tessellation and the computation of low-level configuration parameters is
+realized by a free software library called `libpisp
+<https://github.com/raspberrypi/libpisp>`_.
+
+The full image processing pipeline, which involves capturing RAW Bayer data from
+an image sensor through a MIPI CSI-2 compatible capture interface, storing them
+in DRAM memory and processing them in the PiSP Back End to obtain images usable
+by an application is implemented in `libcamera <https://libcamera.org>`_ as
+part of the Raspberry Pi platform support.
+
+The pisp-be driver
+==================
+
+The Raspberry Pi PiSP Back End (pisp-be) driver is located under
+drivers/media/platform/raspberrypi/pisp-be. It uses the `V4L2 API` to register
+a number of video capture and output devices, the `V4L2 subdev API` to register
+a subdevice for the ISP that connects the video devices in a single media graph
+realized using the `Media Controller (MC) API`.
+
+The media topology registered by the `pisp-be` driver is represented below:
+
+.. _pips-be-topology:
+
+.. kernel-figure:: raspberrypi-pisp-be.dot
+ :alt: Diagram of the default media pipeline topology
+ :align: center
+
+
+The media graph registers the following video device nodes:
+
+- pispbe-input: output device for images to be submitted to the ISP for
+ processing.
+- pispbe-tdn_input: output device for temporal denoise.
+- pispbe-stitch_input: output device for image stitching (HDR).
+- pispbe-output0: first capture device for processed images.
+- pispbe-output1: second capture device for processed images.
+- pispbe-tdn_output: capture device for temporal denoise.
+- pispbe-stitch_output: capture device for image stitching (HDR).
+- pispbe-config: output device for ISP configuration parameters.
+
+pispbe-input
+------------
+
+Images to be processed by the ISP are queued to the `pispbe-input` output device
+node. For a list of image formats supported as input to the ISP refer to the
+`Raspberry Pi Image Signal Processor (PiSP) Specification document`_.
+
+pispbe-tdn_input, pispbe-tdn_output
+-----------------------------------
+
+The `pispbe-tdn_input` output video device receives images to be processed by
+the temporal denoise block which are captured from the `pispbe-tdn_output`
+capture video device. Userspace is responsible for maintaining queues on both
+devices, and ensuring that buffers completed on the output are queued to the
+input.
+
+pispbe-stitch_input, pispbe-stitch_output
+-----------------------------------------
+
+To realize HDR (high dynamic range) image processing the image stitching and
+tonemapping blocks are used. The `pispbe-stitch_output` writes images to memory
+and the `pispbe-stitch_input` receives the previously written frame to process
+it along with the current input image. Userspace is responsible for maintaining
+queues on both devices, and ensuring that buffers completed on the output are
+queued to the input.
+
+pispbe-output0, pispbe-output1
+------------------------------
+
+The two capture devices write to memory the pixel data as processed by the ISP.
+
+pispbe-config
+-------------
+
+The `pispbe-config` output video devices receives a buffer of configuration
+parameters that define the desired image processing to be performed by the ISP.
+
+The format of the ISP configuration parameter is defined by
+:c:type:`pisp_be_tiles_config` C structure and the meaning of each parameter is
+described in the `Raspberry Pi Image Signal Processor (PiSP) Specification
+document`_.
+
+ISP configuration
+=================
+
+The ISP configuration is described solely by the content of the parameters
+buffer. The only parameter that userspace needs to configure using the V4L2 API
+is the image format on the output and capture video devices for validation of
+the content of the parameters buffer.
+
+.. _Raspberry Pi Image Signal Processor (PiSP) Specification document: https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
diff --git a/Documentation/admin-guide/media/tuner-cardlist.rst b/Documentation/admin-guide/media/tuner-cardlist.rst
index 362617c59c5d..65ecf48ddf24 100644
--- a/Documentation/admin-guide/media/tuner-cardlist.rst
+++ b/Documentation/admin-guide/media/tuner-cardlist.rst
@@ -97,4 +97,6 @@ Tuner number Card name
89 Sony BTF-PG472Z PAL/SECAM
90 Sony BTF-PK467Z NTSC-M-JP
91 Sony BTF-PB463Z NTSC-M
+92 Silicon Labs Si2157 tuner
+93 Tena TNF931D-DFDR1
============ =====================================================
diff --git a/Documentation/admin-guide/media/v4l-drivers.rst b/Documentation/admin-guide/media/v4l-drivers.rst
index 4120eded9a13..b6af448b9fe9 100644
--- a/Documentation/admin-guide/media/v4l-drivers.rst
+++ b/Documentation/admin-guide/media/v4l-drivers.rst
@@ -23,6 +23,7 @@ Video4Linux (V4L) driver-specific documentation
omap4_camera
philips
qcom_camss
+ raspberrypi-pisp-be
rcar-fdp1
rkisp1
saa7134
diff --git a/Documentation/admin-guide/media/vivid.rst b/Documentation/admin-guide/media/vivid.rst
index b6f658c0997e..1306f19ecb5a 100644
--- a/Documentation/admin-guide/media/vivid.rst
+++ b/Documentation/admin-guide/media/vivid.rst
@@ -302,6 +302,15 @@ all configurable using the following module options:
- 0: forbid hints
- 1: allow hints
+- supports_requests:
+
+ specifies if the device should support the Request API. There are
+ three possible values, default is 1:
+
+ - 0: no request
+ - 1: supports requests
+ - 2: requires requests
+
Taken together, all these module options allow you to precisely customize
the driver behavior and test your application with all sorts of permutations.
It is also very suitable to emulate hardware that is not yet available, e.g.
@@ -313,10 +322,10 @@ Video Capture
This is probably the most frequently used feature. The video capture device
can be configured by using the module options num_inputs, input_types and
-ccs_cap_mode (see section 1 for more detailed information), but by default
-four inputs are configured: a webcam, a TV tuner, an S-Video and an HDMI
-input, one input for each input type. Those are described in more detail
-below.
+ccs_cap_mode (see "Configuring the driver" for more detailed information),
+but by default four inputs are configured: a webcam, a TV tuner, an S-Video
+and an HDMI input, one input for each input type. Those are described in more
+detail below.
Special attention has been given to the rate at which new frames become
available. The jitter will be around 1 jiffie (that depends on the HZ
@@ -434,10 +443,10 @@ Video Output
------------
The video output device can be configured by using the module options
-num_outputs, output_types and ccs_out_mode (see section 1 for more detailed
-information), but by default two outputs are configured: an S-Video and an
-HDMI input, one output for each output type. Those are described in more detail
-below.
+num_outputs, output_types and ccs_out_mode (see "Configuring the driver"
+for more detailed information), but by default two outputs are configured:
+an S-Video and an HDMI input, one output for each output type. Those are
+described in more detail below.
Like with video capture the framerate is also exact in the long term.
@@ -1011,11 +1020,6 @@ Digital Video Controls
affects the reported colorspace since DVI_D outputs will always use
sRGB.
-- Display Present:
-
- sets the presence of a "display" on the HDMI output. This affects
- the tx_edid_present, tx_hotplug and tx_rxsense controls.
-
FM Radio Receiver Controls
~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -1130,35 +1134,34 @@ Metadata Capture Controls
if set, then the generated metadata stream contains Source Clock information.
-Video, VBI and RDS Looping
---------------------------
-The vivid driver supports looping of video output to video input, VBI output
-to VBI input and RDS output to RDS input. For video/VBI looping this emulates
-as if a cable was hooked up between the output and input connector. So video
-and VBI looping is only supported between S-Video and HDMI inputs and outputs.
-VBI is only valid for S-Video as it makes no sense for HDMI.
+Video, Sliced VBI and HDMI CEC Looping
+--------------------------------------
-Since radio is wireless this looping always happens if the radio receiver
-frequency is close to the radio transmitter frequency. In that case the radio
-transmitter will 'override' the emulated radio stations.
-
-Looping is currently supported only between devices created by the same
-vivid driver instance.
+Video Looping functionality is supported for devices created by the same
+vivid driver instance, as well as across multiple instances of the vivid driver.
+The vivid driver supports looping of video and Sliced VBI data between an S-Video output
+and an S-Video input. It also supports looping of video and HDMI CEC data between an
+HDMI output and an HDMI input.
+To enable looping, set the 'HDMI/S-Video XXX-N Is Connected To' control(s) to select
+whether an input uses the Test Pattern Generator, or is disconnected, or is connected
+to an output. An input can be connected to an output from any vivid instance.
+The inputs and outputs are numbered XXX-N where XXX is the vivid instance number
+(see module option n_devs). If there is only one vivid instance (the default), then
+XXX will be 000. And N is the Nth S-Video/HDMI input or output of that instance.
+If vivid is loaded without module options, then you can connect the S-Video 000-0 input
+to the S-Video 000-0 output, or the HDMI 000-0 input to the HDMI 000-0 output.
+This is the equivalent of connecting or disconnecting a cable between an input and an
+output in a physical device.
-Video and Sliced VBI looping
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+If an 'HDMI/S-Video XXX-N Is Connected To' control selected an output, then the video
+output will be looped to the video input provided that:
-The way to enable video/VBI looping is currently fairly crude. A 'Loop Video'
-control is available in the "Vivid" control class of the video
-capture and VBI capture devices. When checked the video looping will be enabled.
-Once enabled any video S-Video or HDMI input will show a static test pattern
-until the video output has started. At that time the video output will be
-looped to the video input provided that:
+- the currently selected input matches the input indicated by the control name.
-- the input type matches the output type. So the HDMI input cannot receive
- video from the S-Video output.
+- in the vivid instance of the output connector, the currently selected output matches
+ the output indicated by the control's value.
- the video resolution of the video input must match that of the video output.
So it is not possible to loop a 50 Hz (720x576) S-Video output to a 60 Hz
@@ -1185,6 +1188,8 @@ looped to the video input provided that:
"DV Timings Signal Mode" for the HDMI input should be configured so that a
valid signal is passed to the video input.
+If any condition is not valid, then the 'Noise' test pattern is shown.
+
The framerates do not have to match, although this might change in the future.
By default you will see the OSD text superimposed on top of the looped video.
@@ -1198,17 +1203,26 @@ and WSS (50 Hz formats) VBI data is looped. Teletext VBI data is not looped.
Radio & RDS Looping
-~~~~~~~~~~~~~~~~~~~
-
-As mentioned in section 6 the radio receiver emulates stations are regular
-frequency intervals. Depending on the frequency of the radio receiver a
-signal strength value is calculated (this is returned by VIDIOC_G_TUNER).
-However, it will also look at the frequency set by the radio transmitter and
-if that results in a higher signal strength than the settings of the radio
-transmitter will be used as if it was a valid station. This also includes
-the RDS data (if any) that the transmitter 'transmits'. This is received
-faithfully on the receiver side. Note that when the driver is loaded the
-frequencies of the radio receiver and transmitter are not identical, so
+-------------------
+
+The vivid driver supports looping of RDS output to RDS input.
+
+Since radio is wireless this looping always happens if the radio receiver
+frequency is close to the radio transmitter frequency. In that case the radio
+transmitter will 'override' the emulated radio stations.
+
+RDS looping is currently supported only between devices created by the same
+vivid driver instance.
+
+As mentioned in the "Radio Receiver" section, the radio receiver emulates
+stations at regular frequency intervals. Depending on the frequency of the
+radio receiver a signal strength value is calculated (this is returned by
+VIDIOC_G_TUNER). However, it will also look at the frequency set by the radio
+transmitter and if that results in a higher signal strength than the settings
+of the radio transmitter will be used as if it was a valid station. This also
+includes the RDS data (if any) that the transmitter 'transmits'. This is
+received faithfully on the receiver side. Note that when the driver is loaded
+the frequencies of the radio receiver and transmitter are not identical, so
initially no looping takes place.
@@ -1218,8 +1232,8 @@ Cropping, Composing, Scaling
This driver supports cropping, composing and scaling in any combination. Normally
which features are supported can be selected through the Vivid controls,
but it is also possible to hardcode it when the module is loaded through the
-ccs_cap_mode and ccs_out_mode module options. See section 1 on the details of
-these module options.
+ccs_cap_mode and ccs_out_mode module options. See "Configuring the driver" on
+the details of these module options.
This allows you to test your application for all these variations.
@@ -1260,7 +1274,8 @@ is set, then the alpha component is only used for the color red and set to
The driver has to be configured to support the multiplanar formats. By default
the driver instances are single-planar. This can be changed by setting the
-multiplanar module option, see section 1 for more details on that option.
+multiplanar module option, see "Configuring the driver" for more details on that
+option.
If the driver instance is using the multiplanar formats/API, then the first
single planar format (YUYV) and the multiplanar NV16M and NV61M formats the
@@ -1270,74 +1285,6 @@ data_offset to be non-zero, so this is a useful feature for testing applications
Video output will also honor any data_offset that the application set.
-Capture Overlay
----------------
-
-Note: capture overlay support is implemented primarily to test the existing
-V4L2 capture overlay API. In practice few if any GPUs support such overlays
-anymore, and neither are they generally needed anymore since modern hardware
-is so much more capable. By setting flag 0x10000 in the node_types module
-option the vivid driver will create a simple framebuffer device that can be
-used for testing this API. Whether this API should be used for new drivers is
-questionable.
-
-This driver has support for a destructive capture overlay with bitmap clipping
-and list clipping (up to 16 rectangles) capabilities. Overlays are not
-supported for multiplanar formats. It also honors the struct v4l2_window field
-setting: if it is set to FIELD_TOP or FIELD_BOTTOM and the capture setting is
-FIELD_ALTERNATE, then only the top or bottom fields will be copied to the overlay.
-
-The overlay only works if you are also capturing at that same time. This is a
-vivid limitation since it copies from a buffer to the overlay instead of
-filling the overlay directly. And if you are not capturing, then no buffers
-are available to fill.
-
-In addition, the pixelformat of the capture format and that of the framebuffer
-must be the same for the overlay to work. Otherwise VIDIOC_OVERLAY will return
-an error.
-
-In order to really see what it going on you will need to create two vivid
-instances: the first with a framebuffer enabled. You configure the capture
-overlay of the second instance to use the framebuffer of the first, then
-you start capturing in the second instance. For the first instance you setup
-the output overlay for the video output, turn on video looping and capture
-to see the blended framebuffer overlay that's being written to by the second
-instance. This setup would require the following commands:
-
-.. code-block:: none
-
- $ sudo modprobe vivid n_devs=2 node_types=0x10101,0x1
- $ v4l2-ctl -d1 --find-fb
- /dev/fb1 is the framebuffer associated with base address 0x12800000
- $ sudo v4l2-ctl -d2 --set-fbuf fb=1
- $ v4l2-ctl -d1 --set-fbuf fb=1
- $ v4l2-ctl -d0 --set-fmt-video=pixelformat='AR15'
- $ v4l2-ctl -d1 --set-fmt-video-out=pixelformat='AR15'
- $ v4l2-ctl -d2 --set-fmt-video=pixelformat='AR15'
- $ v4l2-ctl -d0 -i2
- $ v4l2-ctl -d2 -i2
- $ v4l2-ctl -d2 -c horizontal_movement=4
- $ v4l2-ctl -d1 --overlay=1
- $ v4l2-ctl -d0 -c loop_video=1
- $ v4l2-ctl -d2 --stream-mmap --overlay=1
-
-And from another console:
-
-.. code-block:: none
-
- $ v4l2-ctl -d1 --stream-out-mmap
-
-And yet another console:
-
-.. code-block:: none
-
- $ qv4l2
-
-and start streaming.
-
-As you can see, this is not for the faint of heart...
-
-
Output Overlay
--------------
@@ -1405,8 +1352,6 @@ Just as a reminder and in no particular order:
- Add ARGB888 overlay support: better testing of the alpha channel
- Improve pixel aspect support in the tpg code by passing a real v4l2_fract
- Use per-queue locks and/or per-device locks to improve throughput
-- Add support to loop from a specific output to a specific input across
- vivid instances
- The SDR radio should use the same 'frequencies' for stations as the normal
radio receiver, and give back noise if the frequency doesn't match up with
a station frequency
diff --git a/Documentation/devicetree/bindings/media/i2c/galaxycore,gc05a2.yaml b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc05a2.yaml
new file mode 100644
index 000000000000..0e7a7b5ac89f
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc05a2.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (c) 2023 MediaTek Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc05a2.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GalaxyCore gc05a2 1/5" 5M Pixel MIPI CSI-2 sensor
+
+maintainers:
+ - Zhi Mao <zhi.mao@mediatek.com>
+
+description:
+ The gc05a2 is a raw image sensor with an MIPI CSI-2 image data
+ interface and CCI (I2C compatible) control bus. The output format
+ is raw Bayer.
+
+properties:
+ compatible:
+ const: galaxycore,gc05a2
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ dovdd-supply: true
+
+ avdd-supply: true
+
+ dvdd-supply: true
+
+ reset-gpios:
+ description: Reference to the GPIO connected to the RESETB pin.
+ maxItems: 1
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+ description:
+ Output port node, single endpoint describing the CSI-2 transmitter.
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ oneOf:
+ - items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+ - items:
+ - const: 1
+ - const: 2
+
+ link-frequencies: true
+
+ required:
+ - data-lanes
+ - link-frequencies
+
+ required:
+ - endpoint
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - dovdd-supply
+ - avdd-supply
+ - dvdd-supply
+ - reset-gpios
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@37 {
+ compatible = "galaxycore,gc05a2";
+ reg = <0x37>;
+
+ clocks = <&gc05a2_clk>;
+
+ reset-gpios = <&pio 21 GPIO_ACTIVE_LOW>;
+
+ avdd-supply = <&gc05a2_avdd>;
+ dovdd-supply = <&gc05a2_dovdd>;
+ dvdd-supply = <&gc05a2_dvdd>;
+
+ port {
+ sensor_out: endpoint {
+ data-lanes = <1 2>;
+ link-frequencies = /bits/ 64 <448000000 224000000>;
+ remote-endpoint = <&seninf_csi_port_1_in>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/galaxycore,gc08a3.yaml b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc08a3.yaml
new file mode 100644
index 000000000000..51b8ece09c72
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/galaxycore,gc08a3.yaml
@@ -0,0 +1,112 @@
+# SPDX-License-Identifier: (GPL-2.0 OR BSD-2-Clause)
+# Copyright (c) 2023 MediaTek Inc.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/galaxycore,gc08a3.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: GalaxyCore gc08a3 1/4" 8M Pixel MIPI CSI-2 sensor
+
+maintainers:
+ - Zhi Mao <zhi.mao@mediatek.com>
+
+description:
+ The gc08a3 is a raw image sensor with an MIPI CSI-2 image data
+ interface and CCI (I2C compatible) control bus. The output format
+ is raw Bayer.
+
+properties:
+ compatible:
+ const: galaxycore,gc08a3
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ dovdd-supply: true
+
+ avdd-supply: true
+
+ dvdd-supply: true
+
+ reset-gpios:
+ description: Reference to the GPIO connected to the RESETB pin.
+ maxItems: 1
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+ description:
+ Output port node, single endpoint describing the CSI-2 transmitter.
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ oneOf:
+ - items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+ - items:
+ - const: 1
+ - const: 2
+
+ link-frequencies: true
+
+ required:
+ - data-lanes
+ - link-frequencies
+
+ required:
+ - endpoint
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - dovdd-supply
+ - avdd-supply
+ - dvdd-supply
+ - reset-gpios
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sensor@31 {
+ compatible = "galaxycore,gc08a3";
+ reg = <0x31>;
+
+ clocks = <&gc08a3_clk>;
+
+ reset-gpios = <&pio 19 GPIO_ACTIVE_LOW>;
+
+ avdd-supply = <&gc08a3_avdd>;
+ dovdd-supply = <&gc08a3_dovdd>;
+ dvdd-supply = <&gc08a3_dvdd>;
+
+ port {
+ sensor_out: endpoint {
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <336000000 207000000>;
+ remote-endpoint = <&seninf_csi_port_0_in>;
+ };
+ };
+ };
+ };
+
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max96714.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max96714.yaml
new file mode 100644
index 000000000000..3ace50e11921
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/maxim,max96714.yaml
@@ -0,0 +1,174 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2024 Collabora Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/maxim,max96714.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Maxim MAX96714 GMSL2 to CSI-2 Deserializer
+
+maintainers:
+ - Julien Massot <julien.massot@collabora.com>
+
+description:
+ The MAX96714 deserializer converts GMSL2 serial inputs into MIPI
+ CSI-2 D-PHY formatted output. The device allows the GMSL2 link to
+ simultaneously transmit bidirectional control-channel data while forward
+ video transmissions are in progress. The MAX96714 can connect to one
+ remotely located serializer using industry-standard coax or STP
+ interconnects. The device cans operate in pixel or tunnel mode. In pixel mode
+ the MAX96714 can select individual video stream, while the tunnel mode forward all
+ the MIPI data received by the serializer.
+
+ The GMSL2 serial link operates at a fixed rate of 3Gbps or 6Gbps in the
+ forward direction and 187.5Mbps in the reverse direction.
+ MAX96714F only supports a fixed rate of 3Gbps in the forward direction.
+
+properties:
+ compatible:
+ oneOf:
+ - const: maxim,max96714f
+ - items:
+ - enum:
+ - maxim,max96714
+ - const: maxim,max96714f
+
+ reg:
+ maxItems: 1
+
+ powerdown-gpios:
+ maxItems: 1
+ description:
+ Specifier for the GPIO connected to the PWDNB pin.
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/properties/port
+ unevaluatedProperties: false
+ description: GMSL Input
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+ description:
+ Endpoint for GMSL2-Link port.
+
+ port@1:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: CSI-2 Output port
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 4
+
+ lane-polarities:
+ minItems: 1
+ maxItems: 5
+
+ link-frequencies:
+ maxItems: 1
+
+ required:
+ - data-lanes
+
+ required:
+ - port@1
+
+ i2c-gate:
+ $ref: /schemas/i2c/i2c-gate.yaml
+ unevaluatedProperties: false
+ description:
+ The MAX96714 will pass through and forward the I2C requests from the
+ incoming I2C bus over the GMSL2 link. Therefore it supports an i2c-gate
+ subnode to configure a serializer.
+
+ port0-poc-supply:
+ description: Regulator providing Power over Coax for the GMSL port
+
+required:
+ - compatible
+ - reg
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/media/video-interfaces.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ deserializer@28 {
+ compatible = "maxim,max96714f";
+ reg = <0x28>;
+ powerdown-gpios = <&main_gpio0 37 GPIO_ACTIVE_LOW>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ max96714_gmsl_in: endpoint {
+ remote-endpoint = <&max96917f_gmsl_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ max96714_csi_out: endpoint {
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <400000000>;
+ remote-endpoint = <&csi_in>;
+ };
+ };
+ };
+
+ i2c-gate {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ serializer@40 {
+ compatible = "maxim,max96717f";
+ reg = <0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #clock-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ max96717f_csi_in: endpoint {
+ data-lanes = <1 2>;
+ lane-polarities = <1 0 1>;
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ max96917f_gmsl_out: endpoint {
+ remote-endpoint = <&max96714_gmsl_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/maxim,max96717.yaml b/Documentation/devicetree/bindings/media/i2c/maxim,max96717.yaml
new file mode 100644
index 000000000000..d1e8ba6e368e
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/maxim,max96717.yaml
@@ -0,0 +1,157 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2024 Collabora Ltd.
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/maxim,max96717.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MAX96717 CSI-2 to GMSL2 Serializer
+
+maintainers:
+ - Julien Massot <julien.massot@collabora.com>
+
+description:
+ The MAX96717 serializer converts MIPI CSI-2 D-PHY formatted input
+ into GMSL2 serial outputs. The device allows the GMSL2 link to
+ simultaneously transmit bidirectional control-channel data while forward
+ video transmissions are in progress. The MAX96717 can connect to one
+ remotely located deserializer using industry-standard coax or STP
+ interconnects. The device cans operate in pixel or tunnel mode. In pixel mode
+ the MAX96717 can select the MIPI datatype, while the tunnel mode forward all the MIPI
+ data received by the serializer.
+ The MAX96717 supports Reference Over Reverse (channel),
+ to generate a clock output for the sensor from the GMSL reverse channel.
+
+ The GMSL2 serial link operates at a fixed rate of 3Gbps or 6Gbps in the
+ forward direction and 187.5Mbps in the reverse direction.
+ MAX96717F only supports a fixed rate of 3Gbps in the forward direction.
+
+properties:
+ compatible:
+ oneOf:
+ - const: maxim,max96717f
+ - items:
+ - enum:
+ - maxim,max96717
+ - const: maxim,max96717f
+
+ '#gpio-cells':
+ const: 2
+ description:
+ First cell is the GPIO pin number, second cell is the flags. The GPIO pin
+ number must be in range of [0, 10].
+
+ gpio-controller: true
+
+ '#clock-cells':
+ const: 0
+
+ reg:
+ maxItems: 1
+
+ ports:
+ $ref: /schemas/graph.yaml#/properties/ports
+
+ properties:
+ port@0:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ unevaluatedProperties: false
+ description: CSI-2 Input port
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ minItems: 1
+ maxItems: 4
+
+ lane-polarities:
+ minItems: 1
+ maxItems: 5
+
+ required:
+ - data-lanes
+
+ port@1:
+ $ref: /schemas/graph.yaml#/properties/port
+ unevaluatedProperties: false
+ description: GMSL Output port
+
+ required:
+ - port@1
+
+ i2c-gate:
+ $ref: /schemas/i2c/i2c-gate.yaml
+ unevaluatedProperties: false
+ description:
+ The MAX96717 will forward the I2C requests from the
+ incoming GMSL2 link. Therefore, it supports an i2c-gate
+ subnode to configure a sensor.
+
+required:
+ - compatible
+ - reg
+ - ports
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/gpio/gpio.h>
+ #include <dt-bindings/media/video-interfaces.h>
+
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ serializer: serializer@40 {
+ compatible = "maxim,max96717f";
+ reg = <0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ #clock-cells = <0>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ max96717f_csi_in: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&sensor_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+ max96917f_gmsl_out: endpoint {
+ remote-endpoint = <&deser_gmsl_in>;
+ };
+ };
+ };
+
+ i2c-gate {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ sensor@10 {
+ compatible = "st,st-vgxy61";
+ reg = <0x10>;
+ reset-gpios = <&serializer 0 GPIO_ACTIVE_LOW>;
+ clocks = <&serializer>;
+ VCORE-supply = <&v1v2>;
+ VDDIO-supply = <&v1v8>;
+ VANA-supply = <&v2v8>;
+ port {
+ sensor_out: endpoint {
+ data-lanes = <1 2 3 4>;
+ remote-endpoint = <&max96717f_csi_in>;
+ };
+ };
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/i2c/imx258.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
index 80d24220baa0..c978abc0cdb3 100644
--- a/Documentation/devicetree/bindings/media/i2c/imx258.yaml
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
@@ -1,7 +1,7 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
-$id: http://devicetree.org/schemas/media/i2c/imx258.yaml#
+$id: http://devicetree.org/schemas/media/i2c/sony,imx258.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Sony IMX258 13 Mpixel CMOS Digital Image Sensor
@@ -13,11 +13,16 @@ description: |-
IMX258 is a diagonal 5.867mm (Type 1/3.06) 13 Mega-pixel CMOS active pixel
type stacked image sensor with a square pixel array of size 4208 x 3120. It
is programmable through I2C interface. Image data is sent through MIPI
- CSI-2.
+ CSI-2. The sensor exists in two different models, a standard variant
+ (IMX258) and a variant with phase detection autofocus (IMX258-PDAF).
+ The camera module does not expose the model through registers, so the
+ exact model needs to be specified.
properties:
compatible:
- const: sony,imx258
+ enum:
+ - sony,imx258
+ - sony,imx258-pdaf
assigned-clocks: true
assigned-clock-parents: true
diff --git a/Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml b/Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml
new file mode 100644
index 000000000000..e4f49f1435a5
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml
@@ -0,0 +1,107 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+# Copyright (C) 2024 Ideas on Board Oy
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/i2c/sony,imx283.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Sony IMX283 Sensor
+
+maintainers:
+ - Kieran Bingham <kieran.bingham@ideasonboard.com>
+ - Umang Jain <umang.jain@ideasonboard.com>
+
+description:
+ IMX283 sensor is a Sony CMOS active pixel digital image sensor with an active
+ array size of 5472H x 3648V. It is programmable through I2C interface. The
+ I2C client address is fixed to 0x1a as per sensor data sheet. Image data is
+ sent through MIPI CSI-2.
+
+properties:
+ compatible:
+ const: sony,imx283
+
+ reg:
+ maxItems: 1
+
+ clocks:
+ description: Clock frequency from 6 to 24 MHz.
+ maxItems: 1
+
+ vadd-supply:
+ description: Analog power supply (2.9V)
+
+ vdd1-supply:
+ description: Interface power supply (1.8V)
+
+ vdd2-supply:
+ description: Digital power supply (1.2V)
+
+ reset-gpios:
+ description: Sensor reset (XCLR) GPIO
+ maxItems: 1
+
+ port:
+ $ref: /schemas/graph.yaml#/$defs/port-base
+ additionalProperties: false
+
+ properties:
+ endpoint:
+ $ref: /schemas/media/video-interfaces.yaml#
+ unevaluatedProperties: false
+
+ properties:
+ data-lanes:
+ anyOf:
+ - items:
+ - const: 1
+ - const: 2
+ - const: 3
+ - const: 4
+
+ link-frequencies: true
+
+ required:
+ - data-lanes
+ - link-frequencies
+
+ required:
+ - endpoint
+
+required:
+ - compatible
+ - reg
+ - clocks
+ - port
+
+additionalProperties: false
+
+examples:
+ - |
+ i2c {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ camera@1a {
+ compatible = "sony,imx283";
+ reg = <0x1a>;
+ clocks = <&imx283_clk>;
+
+ assigned-clocks = <&imx283_clk>;
+ assigned-clock-parents = <&imx283_clk_parent>;
+ assigned-clock-rates = <12000000>;
+
+ vadd-supply = <&camera_vadd_2v9>;
+ vdd1-supply = <&camera_vdd1_1v8>;
+ vdd2-supply = <&camera_vdd2_1v2>;
+
+ port {
+ imx283: endpoint {
+ remote-endpoint = <&cam>;
+ data-lanes = <1 2 3 4>;
+ link-frequencies = /bits/ 64 <360000000>;
+ };
+ };
+ };
+ };
+...
diff --git a/Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml b/Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml
new file mode 100644
index 000000000000..085020cb9e61
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml
@@ -0,0 +1,75 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/img,e5010-jpeg-enc.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Imagination E5010 JPEG Encoder
+
+maintainers:
+ - Devarsh Thakkar <devarsht@ti.com>
+
+description: |
+ The E5010 is a JPEG encoder from Imagination Technologies implemented on
+ TI's AM62A SoC. It is capable of real time encoding of YUV420 and YUV422
+ inputs to JPEG and M-JPEG. It supports baseline JPEG Encoding up to
+ 8Kx8K resolution.
+
+properties:
+ compatible:
+ oneOf:
+ - items:
+ - const: ti,am62a-jpeg-enc
+ - const: img,e5010-jpeg-enc
+ - const: img,e5010-jpeg-enc
+
+ reg:
+ items:
+ - description: The E5010 core register region
+ - description: The E5010 mmu register region
+
+ reg-names:
+ items:
+ - const: core
+ - const: mmu
+
+ power-domains:
+ maxItems: 1
+
+ resets:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - reg-names
+ - interrupts
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/soc/ti,sci_pm_domain.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+ #include <dt-bindings/interrupt-controller/irq.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ jpeg-encoder@fd20000 {
+ compatible = "img,e5010-jpeg-enc";
+ reg = <0x00 0xfd20000 0x00 0x100>,
+ <0x00 0xfd20200 0x00 0x200>;
+ reg-names = "core", "mmu";
+ clocks = <&k3_clks 201 0>;
+ power-domains = <&k3_pds 201 TI_SCI_PD_EXCLUSIVE>;
+ interrupts = <GIC_SPI 98 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml b/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml
index 59db8306485b..18603f6c5e06 100644
--- a/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml
+++ b/Documentation/devicetree/bindings/media/mediatek,mdp3-rdma.yaml
@@ -23,6 +23,7 @@ properties:
oneOf:
- enum:
- mediatek,mt8183-mdp3-rdma
+ - mediatek,mt8188-mdp3-rdma
- mediatek,mt8195-mdp3-rdma
- mediatek,mt8195-vdo1-rdma
- items:
diff --git a/Documentation/devicetree/bindings/media/mediatek,mt7622-cir.yaml b/Documentation/devicetree/bindings/media/mediatek,mt7622-cir.yaml
new file mode 100644
index 000000000000..c01210e053f9
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek,mt7622-cir.yaml
@@ -0,0 +1,55 @@
+# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/mediatek,mt7622-cir.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: MediaTek Consumer Infrared Receiver on-SoC Controller
+
+maintainers:
+ - Sean Wang <sean.wang@mediatek.com>
+
+allOf:
+ - $ref: rc.yaml#
+
+properties:
+ compatible:
+ enum:
+ - mediatek,mt7622-cir
+ - mediatek,mt7623-cir
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 2
+
+ clock-names:
+ items:
+ - const: clk
+ - const: bus
+
+required:
+ - reg
+ - interrupts
+ - clocks
+ - clock-names
+
+unevaluatedProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/clock/mt2701-clk.h>
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ ir@10013000 {
+ compatible = "mediatek,mt7623-cir";
+ reg = <0x10013000 0x1000>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&infracfg CLK_INFRA_IRRX>, <&topckgen CLK_TOP_AXI_SEL>;
+ clock-names = "clk", "bus";
+ linux,rc-map-name = "rc-rc6-mce";
+ };
diff --git a/Documentation/devicetree/bindings/media/mtk-cir.txt b/Documentation/devicetree/bindings/media/mtk-cir.txt
deleted file mode 100644
index 5e18087ce11f..000000000000
--- a/Documentation/devicetree/bindings/media/mtk-cir.txt
+++ /dev/null
@@ -1,28 +0,0 @@
-Device-Tree bindings for Mediatek consumer IR controller
-found in Mediatek SoC family
-
-Required properties:
-- compatible : Should be
- "mediatek,mt7623-cir": for MT7623 SoC
- "mediatek,mt7622-cir": for MT7622 SoC
-- clocks : list of clock specifiers, corresponding to
- entries in clock-names property;
-- clock-names : should contain
- - "clk" entries: for MT7623 SoC
- - "clk", "bus" entries: for MT7622 SoC
-- interrupts : should contain IR IRQ number;
-- reg : should contain IO map address for IR.
-
-Optional properties:
-- linux,rc-map-name : see rc.txt file in the same directory.
-
-Example:
-
-cir: cir@10013000 {
- compatible = "mediatek,mt7623-cir";
- reg = <0 0x10013000 0 0x1000>;
- interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_LOW>;
- clocks = <&infracfg CLK_INFRA_IRRX>;
- clock-names = "clk";
- linux,rc-map-name = "rc-rc6-mce";
-};
diff --git a/Documentation/devicetree/bindings/media/qcom,msm8996-venus.yaml b/Documentation/devicetree/bindings/media/qcom,msm8996-venus.yaml
index 3a4d817e544e..56c16458e3bb 100644
--- a/Documentation/devicetree/bindings/media/qcom,msm8996-venus.yaml
+++ b/Documentation/devicetree/bindings/media/qcom,msm8996-venus.yaml
@@ -18,7 +18,9 @@ allOf:
properties:
compatible:
- const: qcom,msm8996-venus
+ enum:
+ - qcom,msm8996-venus
+ - qcom,msm8998-venus
power-domains:
maxItems: 1
diff --git a/Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml b/Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
new file mode 100644
index 000000000000..1fc62a1d8eda
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
@@ -0,0 +1,63 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/media/raspberrypi,pispbe.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Raspberry Pi PiSP Image Signal Processor (ISP) Back End
+
+maintainers:
+ - Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
+ - Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+
+description: |
+ The Raspberry Pi PiSP Image Signal Processor (ISP) Back End is an image
+ processor that fetches images in Bayer or Grayscale format from DRAM memory
+ in tiles and produces images consumable by applications.
+
+ The full ISP documentation is available at
+ https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf
+
+properties:
+ compatible:
+ items:
+ - enum:
+ - brcm,bcm2712-pispbe
+ - const: raspberrypi,pispbe
+
+ reg:
+ maxItems: 1
+
+ interrupts:
+ maxItems: 1
+
+ clocks:
+ maxItems: 1
+
+ iommus:
+ maxItems: 1
+
+required:
+ - compatible
+ - reg
+ - interrupts
+ - clocks
+
+additionalProperties: false
+
+examples:
+ - |
+ #include <dt-bindings/interrupt-controller/arm-gic.h>
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ isp@880000 {
+ compatible = "brcm,bcm2712-pispbe", "raspberrypi,pispbe";
+ reg = <0x10 0x00880000 0x0 0x4000>;
+ interrupts = <GIC_SPI 72 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&firmware_clocks 7>;
+ iommus = <&iommu2>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/media/rc.yaml b/Documentation/devicetree/bindings/media/rc.yaml
index 7bbe580c80f7..dedc5a4b81ec 100644
--- a/Documentation/devicetree/bindings/media/rc.yaml
+++ b/Documentation/devicetree/bindings/media/rc.yaml
@@ -103,6 +103,7 @@ properties:
- rc-msi-digivox-iii
- rc-msi-tvanywhere
- rc-msi-tvanywhere-plus
+ - rc-mygica-utv3
- rc-nebula
- rc-nec-terratec-cinergy-xs
- rc-norwood
diff --git a/Documentation/devicetree/bindings/media/rockchip-rga.yaml b/Documentation/devicetree/bindings/media/rockchip-rga.yaml
index ea2342222408..ac17cda65191 100644
--- a/Documentation/devicetree/bindings/media/rockchip-rga.yaml
+++ b/Documentation/devicetree/bindings/media/rockchip-rga.yaml
@@ -24,6 +24,7 @@ properties:
- enum:
- rockchip,rk3228-rga
- rockchip,rk3568-rga
+ - rockchip,rk3588-rga
- const: rockchip,rk3288-rga
reg:
diff --git a/Documentation/driver-api/media/v4l2-core.rst b/Documentation/driver-api/media/v4l2-core.rst
index 58cba831ade5..ad987c34ad2a 100644
--- a/Documentation/driver-api/media/v4l2-core.rst
+++ b/Documentation/driver-api/media/v4l2-core.rst
@@ -26,3 +26,4 @@ Video4Linux devices
v4l2-tuner
v4l2-common
v4l2-tveeprom
+ v4l2-jpeg
diff --git a/Documentation/driver-api/media/v4l2-jpeg.rst b/Documentation/driver-api/media/v4l2-jpeg.rst
new file mode 100644
index 000000000000..af3bc52f865b
--- /dev/null
+++ b/Documentation/driver-api/media/v4l2-jpeg.rst
@@ -0,0 +1,10 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+V4L2 JPEG header related functions and data structures
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+.. kernel-doc:: include/media/v4l2-jpeg.h
+ :internal:
+
+.. kernel-doc:: drivers/media/v4l2-core/v4l2-jpeg.c
+ :export:
diff --git a/Documentation/userspace-api/media/drivers/index.rst b/Documentation/userspace-api/media/drivers/index.rst
index 2252063593bf..d706cb47b112 100644
--- a/Documentation/userspace-api/media/drivers/index.rst
+++ b/Documentation/userspace-api/media/drivers/index.rst
@@ -35,6 +35,6 @@ For more details see the file COPYING in the source distribution of Linux.
max2175
npcm-video
omap3isp-uapi
- st-vgxy61
thp7312
uvcvideo
+ vgxy61
diff --git a/Documentation/userspace-api/media/drivers/st-vgxy61.rst b/Documentation/userspace-api/media/drivers/vgxy61.rst
index 17ac15afa77c..17ac15afa77c 100644
--- a/Documentation/userspace-api/media/drivers/st-vgxy61.rst
+++ b/Documentation/userspace-api/media/drivers/vgxy61.rst
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
index 786127b1e206..22bde00d42df 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec-stateless.rst
@@ -971,8 +971,8 @@ FWHT Flags
- ``horizontal_scale``
- Horizontal scaling factor.
* - __u8
- - ``vertical_scaling factor``
- - Vertical scale.
+ - ``vertical_scale``
+ - Vertical scaling factor.
* - __u8
- ``version``
- Bitstream version.
diff --git a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
index 2a165ae063fb..4a379bd9e3fb 100644
--- a/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
+++ b/Documentation/userspace-api/media/v4l/ext-ctrls-codec.rst
@@ -1653,6 +1653,20 @@ enum v4l2_mpeg_video_h264_hierarchical_coding_type -
Quantization parameter for a P frame for FWHT. Valid range: from 1
to 31.
+``V4L2_CID_MPEG_VIDEO_AVERAGE_QP (integer)``
+ This read-only control returns the average QP value of the currently
+ encoded frame. The value applies to the last dequeued capture buffer
+ (VIDIOC_DQBUF). Its valid range depends on the encoding format and parameters.
+ For H264, its valid range is from 0 to 51.
+ For HEVC, its valid range is from 0 to 51 for 8 bit and
+ from 0 to 63 for 10 bit.
+ For H263 and MPEG4, its valid range is from 1 to 31.
+ For VP8, its valid range is from 0 to 127.
+ For VP9, its valid range is from 0 to 255.
+ If the codec's MIN_QP and MAX_QP are set, then the QP will meet both requirements.
+ Codecs need to always use the specified range, rather then a HW custom range.
+ Applicable to encoders
+
.. raw:: latex
\normalsize
diff --git a/Documentation/userspace-api/media/v4l/meta-formats.rst b/Documentation/userspace-api/media/v4l/meta-formats.rst
index c23aac823d2c..c6e56b5888bc 100644
--- a/Documentation/userspace-api/media/v4l/meta-formats.rst
+++ b/Documentation/userspace-api/media/v4l/meta-formats.rst
@@ -15,6 +15,7 @@ These formats are used for the :ref:`metadata` interface only.
metafmt-d4xx
metafmt-generic
metafmt-intel-ipu3
+ metafmt-pisp-be
metafmt-rkisp1
metafmt-uvc
metafmt-vivid
diff --git a/Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst b/Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst
new file mode 100644
index 000000000000..3281fe366c86
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/metafmt-pisp-be.rst
@@ -0,0 +1,56 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+.. _v4l2-meta-fmt-rpi-be-cfg:
+
+************************
+V4L2_META_FMT_RPI_BE_CFG
+************************
+
+Raspberry Pi PiSP Back End configuration format
+===============================================
+
+The Raspberry Pi PiSP Back End memory-to-memory image signal processor is
+configured by userspace by providing a buffer of configuration parameters
+to the `pispbe-config` output video device node using the
+:c:type:`v4l2_meta_format` interface.
+
+The PiSP Back End processes images in tiles, and its configuration requires
+specifying two different sets of parameters by populating the members of
+:c:type:`pisp_be_tiles_config` defined in the ``pisp_be_config.h`` header file.
+
+The `Raspberry Pi PiSP technical specification
+<https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf>`_
+provide detailed description of the ISP back end configuration and programming
+model.
+
+Global configuration data
+-------------------------
+
+The global configuration data describe how the pixels in a particular image are
+to be processed and is therefore shared across all the tiles of the image. So
+for example, LSC (Lens Shading Correction) or Denoise parameters would be common
+across all tiles from the same frame.
+
+Global configuration data are passed to the ISP by populating the member of
+:c:type:`pisp_be_config`.
+
+Tile parameters
+---------------
+
+As the ISP processes images in tiles, each set of tiles parameters describe how
+a single tile in an image is going to be processed. A single set of tile
+parameters consist of 160 bytes of data and to process a batch of tiles several
+sets of tiles parameters are required.
+
+Tiles parameters are passed to the ISP by populating the member of
+``pisp_tile`` and the ``num_tiles`` fields of :c:type:`pisp_be_tiles_config`.
+
+Raspberry Pi PiSP Back End uAPI data types
+==========================================
+
+This section describes the data types exposed to userspace by the Raspberry Pi
+PiSP Back End. The section is informative only, for a detailed description of
+each field refer to the `Raspberry Pi PiSP technical specification
+<https://datasheets.raspberrypi.com/camera/raspberry-pi-image-signal-processor-specification.pdf>`_.
+
+.. kernel-doc:: include/uapi/linux/media/raspberrypi/pisp_be_config.h
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst b/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst
index 2500413e5f43..ed3eb432967d 100644
--- a/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-bayer.rst
@@ -20,6 +20,7 @@ orders. See also `the Wikipedia article on Bayer filter
:maxdepth: 1
pixfmt-srggb8
+ pixfmt-srggb8-pisp-comp
pixfmt-srggb10
pixfmt-srggb10p
pixfmt-srggb10alaw8
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst
index b71b80d634d6..5ed4d62df909 100644
--- a/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-rgb.rst
@@ -996,6 +996,60 @@ arranged in little endian order.
\normalsize
+16 Bits Per Component
+=====================
+
+These formats store an RGB triplet in six bytes, with 16 bits per component
+stored in memory in little endian byte order. They are named based on the order
+of the RGB components as stored in memory. For instance, RGB48 stores R\
+:sub:`7:0` and R\ :sub:`15:8` in bytes 0 and 1 respectively. This differs from
+the DRM format nomenclature that instead uses the order of components as seen in
+the 48-bits little endian word.
+
+.. raw:: latex
+
+ \small
+
+.. flat-table:: RGB Formats With 16 Bits Per Component
+ :header-rows: 1
+
+ * - Identifier
+ - Code
+ - Byte 0
+ - Byte 1
+ - Byte 2
+ - Byte 3
+ - Byte 4
+ - Byte 5
+
+ * .. _V4L2-PIX-FMT-BGR48:
+
+ - ``V4L2_PIX_FMT_BGR48``
+ - 'BGR6'
+
+ - B\ :sub:`7-0`
+ - B\ :sub:`15-8`
+ - G\ :sub:`7-0`
+ - G\ :sub:`15-8`
+ - R\ :sub:`7-0`
+ - R\ :sub:`15-8`
+
+ * .. _V4L2-PIX-FMT-RGB48:
+
+ - ``V4L2_PIX_FMT_RGB48``
+ - 'RGB6'
+
+ - R\ :sub:`7-0`
+ - R\ :sub:`15-8`
+ - G\ :sub:`7-0`
+ - G\ :sub:`15-8`
+ - B\ :sub:`7-0`
+ - B\ :sub:`15-8`
+
+.. raw:: latex
+
+ \normalsize
+
Deprecated RGB Formats
======================
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst b/Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst
new file mode 100644
index 000000000000..5a82a15559d6
--- /dev/null
+++ b/Documentation/userspace-api/media/v4l/pixfmt-srggb8-pisp-comp.rst
@@ -0,0 +1,74 @@
+.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
+
+.. _v4l2-pix-fmt-pisp-comp1-rggb:
+.. _v4l2-pix-fmt-pisp-comp1-grbg:
+.. _v4l2-pix-fmt-pisp-comp1-gbrg:
+.. _v4l2-pix-fmt-pisp-comp1-bggr:
+.. _v4l2-pix-fmt-pisp-comp1-mono:
+.. _v4l2-pix-fmt-pisp-comp2-rggb:
+.. _v4l2-pix-fmt-pisp-comp2-grbg:
+.. _v4l2-pix-fmt-pisp-comp2-gbrg:
+.. _v4l2-pix-fmt-pisp-comp2-bggr:
+.. _v4l2-pix-fmt-pisp-comp2-mono:
+
+**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
+V4L2_PIX_FMT_PISP_COMP1_RGGB ('PC1R'), V4L2_PIX_FMT_PISP_COMP1_GRBG ('PC1G'), V4L2_PIX_FMT_PISP_COMP1_GBRG ('PC1g'), V4L2_PIX_FMT_PISP_COMP1_BGGR ('PC1B), V4L2_PIX_FMT_PISP_COMP1_MONO ('PC1M'), V4L2_PIX_FMT_PISP_COMP2_RGGB ('PC2R'), V4L2_PIX_FMT_PISP_COMP2_GRBG ('PC2G'), V4L2_PIX_FMT_PISP_COMP2_GBRG ('PC2g'), V4L2_PIX_FMT_PISP_COMP2_BGGR ('PC2B), V4L2_PIX_FMT_PISP_COMP2_MONO ('PC2M')
+**************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************
+
+================================================
+Raspberry Pi PiSP compressed 8-bit Bayer formats
+================================================
+
+Description
+===========
+
+The Raspberry Pi ISP (PiSP) uses a family of three fixed-rate compressed Bayer
+formats. A black-level offset may be subtracted to improve compression
+efficiency; the nominal black level and amount of offset must be signalled out
+of band. Each scanline is padded to a multiple of 8 pixels wide, and each block
+of 8 horizontally-contiguous pixels is coded using 8 bytes.
+
+Mode 1 uses a quantization and delta-based coding scheme which preserves up to
+12 significant bits. Mode 2 is a simple sqrt-like companding scheme with 6 PWL
+chords, preserving up to 12 significant bits. Mode 3 combines both companding
+(with 4 chords) and the delta scheme, preserving up to 14 significant bits.
+
+The remainder of this description applies to Modes 1 and 3.
+
+Each block of 8 pixels is separated into even and odd phases of 4 pixels,
+coded independently by 32-bit words at successive locations in memory.
+The two LS bits of each 32-bit word give its "quantization mode".
+
+In quantization mode 0, the lowest 321 quantization levels are multiples of
+FSD/4096 and the remaining levels are successive multiples of FSD/2048.
+Quantization modes 1 and 2 use linear quantization with step sizes of
+FSD/1024 and FSD/512 respectively. Each of the four pixels is quantized
+independently, with rounding to the nearest level.
+In quantization mode 2 where the middle two samples have quantized values
+(q1,q2) both in the range [384..511], they are coded using 9 bits for q1
+followed by 7 bits for (q2 & 127). Otherwise, for quantization modes
+0, 1 and 2: a 9-bit field encodes MIN(q1,q2) which must be in the range
+[0..511] and a 7-bit field encodes (q2-q1+64) which must be in [0..127].
+
+Each of the outer samples (q0,q3) is encoded using a 7-bit field based
+on its inner neighbour q1 or q2. In quantization mode 2 where the inner
+sample has a quantized value in the range [448..511], the field value is
+(q0-384). Otherwise for quantization modes 0, 1 and 2: The outer sample
+is encoded as (q0-MAX(0,q1-64)). q3 is likewise coded based on q2.
+Each of these values must be in the range [0..127]. All these fields
+of 2, 9, 7, 7, 7 bits respectively are packed in little-endian order
+to give a 32-bit word with LE byte order.
+
+Quantization mode 3 has a "7.5-bit" escape, used when none of the above
+encodings will fit. Each pixel value is quantized to the nearest of 176
+levels, where the lowest 95 levels are multiples of FSD/256 and the
+remaining levels are multiples of FSD/128 (level 175 represents values
+very close to FSD and may require saturating arithmetic to decode).
+
+Each pair of quantized pixels (q0,q1) or (q2,q3) is jointly coded
+by a 15-bit field: 2816*(q0>>4) + 16*q1 + (q0&15).
+Three fields of 2, 15, 15 bits are packed in LE order {15,15,2}.
+
+An implementation of a software decoder of compressed formats is available
+in `Raspberry Pi camera applications code base
+<https://github.com/raspberrypi/rpicam-apps/blob/main/image/dng.cpp>`_.
diff --git a/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst b/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst
index b3c5779521d8..f02e6cf3516a 100644
--- a/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst
+++ b/Documentation/userspace-api/media/v4l/pixfmt-yuv-luma.rst
@@ -209,3 +209,7 @@ are often referred to as greyscale formats.
For Y012 and Y12 formats, Y012 places its data in the 12 high bits, with
padding zeros in the 4 low bits, in contrast to the Y12 format, which has
its padding located in the most significant bits of the 16 bit word.
+
+ The 'P' variations of the Y10, Y12 and Y14 formats are packed according to
+ the RAW10, RAW12 and RAW14 packing scheme as defined by the MIPI CSI-2
+ specification.
diff --git a/MAINTAINERS b/MAINTAINERS
index 8f4593ce9663..f04ddcf9d078 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -9190,6 +9190,20 @@ S: Maintained
F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc0308.yaml
F: drivers/media/i2c/gc0308.c
+GALAXYCORE GC05a2 CAMERA SENSOR DRIVER
+M: Zhi Mao <zhi.mao@mediatek.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc05a2.yaml
+F: drivers/media/i2c/gc05a2.c
+
+GALAXYCORE GC08A3 CAMERA SENSOR DRIVER
+M: Zhi Mao <zhi.mao@mediatek.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/media/i2c/galaxycore,gc08a3.yaml
+F: drivers/media/i2c/gc08a3.c
+
GALAXYCORE GC2145 SENSOR DRIVER
M: Alain Volmat <alain.volmat@foss.st.com>
L: linux-media@vger.kernel.org
@@ -10872,6 +10886,13 @@ S: Maintained
F: Documentation/devicetree/bindings/auxdisplay/img,ascii-lcd.yaml
F: drivers/auxdisplay/img-ascii-lcd.c
+IMGTEC JPEG ENCODER DRIVER
+M: Devarsh Thakkar <devarsht@ti.com>
+L: linux-media@vger.kernel.org
+S: Supported
+F: Documentation/devicetree/bindings/media/img,e5010-jpeg-enc.yaml
+F: drivers/media/platform/imagination/e5010*
+
IMGTEC IR DECODER DRIVER
S: Orphan
F: drivers/media/rc/img-ir/
@@ -13632,6 +13653,20 @@ S: Maintained
F: Documentation/devicetree/bindings/media/i2c/maxim,max96712.yaml
F: drivers/staging/media/max96712/max96712.c
+MAX96714 GMSL2 DESERIALIZER DRIVER
+M: Julien Massot <julien.massot@collabora.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/media/i2c/maxim,max96714.yaml
+F: drivers/media/i2c/max96714.c
+
+MAX96717 GMSL2 SERIALIZER DRIVER
+M: Julien Massot <julien.massot@collabora.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/media/i2c/maxim,max96717.yaml
+F: drivers/media/i2c/max96717.c
+
MAX9860 MONO AUDIO VOICE CODEC DRIVER
M: Peter Rosin <peda@axentia.se>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
@@ -18948,6 +18983,15 @@ L: linux-edac@vger.kernel.org
S: Maintained
F: drivers/ras/amd/fmpm.c
+RASPBERRY PI PISP BACK END
+M: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
+L: Raspberry Pi Kernel Maintenance <kernel-list@raspberrypi.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/media/raspberrypi,pispbe.yaml
+F: drivers/media/platform/raspberrypi/pisp_be/
+F: include/uapi/linux/media/raspberrypi/
+
RC-CORE / LIRC FRAMEWORK
M: Sean Young <sean@mess.org>
L: linux-media@vger.kernel.org
@@ -20898,7 +20942,6 @@ F: include/uapi/rdma/rdma_user_rxe.h
SOFTLOGIC 6x10 MPEG CODEC
M: Bluecherry Maintainers <maintainers@bluecherrydvr.com>
-M: Anton Sviridenko <anton@corp.bluecherry.net>
M: Andrey Utkin <andrey_utkin@fastmail.com>
M: Ismael Luceno <ismael@iodev.co.uk>
L: linux-media@vger.kernel.org
@@ -20994,7 +21037,7 @@ M: Sakari Ailus <sakari.ailus@linux.intel.com>
L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
-F: Documentation/devicetree/bindings/media/i2c/imx258.yaml
+F: Documentation/devicetree/bindings/media/i2c/sony,imx258.yaml
F: drivers/media/i2c/imx258.c
SONY IMX274 SENSOR DRIVER
@@ -21005,6 +21048,15 @@ T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/sony,imx274.yaml
F: drivers/media/i2c/imx274.c
+SONY IMX283 SENSOR DRIVER
+M: Kieran Bingham <kieran.bingham@ideasonboard.com>
+M: Umang Jain <umang.jain@ideasonboard.com>
+L: linux-media@vger.kernel.org
+S: Maintained
+T: git git://linuxtv.org/media_tree.git
+F: Documentation/devicetree/bindings/media/i2c/sony,imx283.yaml
+F: drivers/media/i2c/imx283.c
+
SONY IMX290 SENSOR DRIVER
M: Manivannan Sadhasivam <manivannan.sadhasivam@linaro.org>
L: linux-media@vger.kernel.org
@@ -21381,8 +21433,8 @@ L: linux-media@vger.kernel.org
S: Maintained
T: git git://linuxtv.org/media_tree.git
F: Documentation/devicetree/bindings/media/i2c/st,st-vgxy61.yaml
-F: Documentation/userspace-api/media/drivers/st-vgxy61.rst
-F: drivers/media/i2c/st-vgxy61.c
+F: Documentation/userspace-api/media/drivers/vgxy61.rst
+F: drivers/media/i2c/vgxy61.c
ST VL53L0X ToF RANGER(I2C) IIO DRIVER
M: Song Qiang <songqiang1304521@gmail.com>
@@ -23108,7 +23160,6 @@ F: tools/testing/selftests/turbostat/
TW5864 VIDEO4LINUX DRIVER
M: Bluecherry Maintainers <maintainers@bluecherrydvr.com>
-M: Anton Sviridenko <anton@corp.bluecherry.net>
M: Andrey Utkin <andrey.utkin@corp.bluecherry.net>
M: Andrey Utkin <andrey_utkin@fastmail.com>
L: linux-media@vger.kernel.org
@@ -23725,7 +23776,7 @@ F: drivers/media/i2c/mt*
F: drivers/media/i2c/og*
F: drivers/media/i2c/ov*
F: drivers/media/i2c/s5*
-F: drivers/media/i2c/st-vgxy61.c
+F: drivers/media/i2c/vgxy61.c
VF610 NAND DRIVER
M: Stefan Agner <stefan@agner.ch>
diff --git a/drivers/media/common/siano/smscoreapi.c b/drivers/media/common/siano/smscoreapi.c
index 7ebcb10126c9..b6f1eb5dbbdf 100644
--- a/drivers/media/common/siano/smscoreapi.c
+++ b/drivers/media/common/siano/smscoreapi.c
@@ -839,7 +839,7 @@ static int smscore_configure_board(struct smscore_device_t *coredev)
mtu_msg.x_msg_header.msg_flags = 0;
mtu_msg.x_msg_header.msg_type = MSG_SMS_SET_MAX_TX_MSG_LEN_REQ;
mtu_msg.x_msg_header.msg_length = sizeof(mtu_msg);
- mtu_msg.msg_data[0] = board->mtu;
+ mtu_msg.msg_data = board->mtu;
coredev->sendrequest_handler(coredev->context, &mtu_msg,
sizeof(mtu_msg));
@@ -852,7 +852,7 @@ static int smscore_configure_board(struct smscore_device_t *coredev)
SMS_INIT_MSG(&crys_msg.x_msg_header,
MSG_SMS_NEW_CRYSTAL_REQ,
sizeof(crys_msg));
- crys_msg.msg_data[0] = board->crystal;
+ crys_msg.msg_data = board->crystal;
coredev->sendrequest_handler(coredev->context, &crys_msg,
sizeof(crys_msg));
@@ -1306,7 +1306,7 @@ static int smscore_init_device(struct smscore_device_t *coredev, int mode)
msg = (struct sms_msg_data *)SMS_ALIGN_ADDRESS(buffer);
SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ,
sizeof(struct sms_msg_data));
- msg->msg_data[0] = mode;
+ msg->msg_data = mode;
rc = smscore_sendrequest_and_wait(coredev, msg,
msg->x_msg_header. msg_length,
@@ -1394,7 +1394,7 @@ int smscore_set_device_mode(struct smscore_device_t *coredev, int mode)
SMS_INIT_MSG(&msg->x_msg_header, MSG_SMS_INIT_DEVICE_REQ,
sizeof(struct sms_msg_data));
- msg->msg_data[0] = mode;
+ msg->msg_data = mode;
rc = smscore_sendrequest_and_wait(
coredev, msg, msg->x_msg_header.msg_length,
@@ -1554,7 +1554,7 @@ void smscore_onresponse(struct smscore_device_t *coredev,
struct sms_msg_data *validity = (struct sms_msg_data *) phdr;
pr_debug("MSG_SMS_DATA_VALIDITY_RES, checksum = 0x%x\n",
- validity->msg_data[0]);
+ validity->msg_data);
complete(&coredev->data_validity_done);
break;
}
diff --git a/drivers/media/common/siano/smscoreapi.h b/drivers/media/common/siano/smscoreapi.h
index f8789ee0d554..82d9f8a64d99 100644
--- a/drivers/media/common/siano/smscoreapi.h
+++ b/drivers/media/common/siano/smscoreapi.h
@@ -616,7 +616,7 @@ struct sms_msg_hdr {
struct sms_msg_data {
struct sms_msg_hdr x_msg_header;
- u32 msg_data[1];
+ u32 msg_data;
};
struct sms_msg_data2 {
@@ -666,7 +666,7 @@ struct sms_firmware {
u32 check_sum;
u32 length;
u32 start_address;
- u8 payload[1];
+ u8 payload[];
};
/* statistics information returned as response for
@@ -1042,20 +1042,6 @@ struct sms_srvm_signal_status {
u32 request_id;
};
-struct sms_i2c_req {
- u32 device_address; /* I2c device address */
- u32 write_count; /* number of bytes to write */
- u32 read_count; /* number of bytes to read */
- u8 Data[1];
-};
-
-struct sms_i2c_res {
- u32 status; /* non-zero value in case of failure */
- u32 read_count; /* number of bytes read */
- u8 Data[1];
-};
-
-
struct smscore_config_gpio {
#define SMS_GPIO_DIRECTION_INPUT 0
#define SMS_GPIO_DIRECTION_OUTPUT 1
diff --git a/drivers/media/common/siano/smsdvb-main.c b/drivers/media/common/siano/smsdvb-main.c
index d893a0e4672b..44d8fe8b220e 100644
--- a/drivers/media/common/siano/smsdvb-main.c
+++ b/drivers/media/common/siano/smsdvb-main.c
@@ -689,7 +689,7 @@ static int smsdvb_start_feed(struct dvb_demux_feed *feed)
pid_msg.x_msg_header.msg_flags = 0;
pid_msg.x_msg_header.msg_type = MSG_SMS_ADD_PID_FILTER_REQ;
pid_msg.x_msg_header.msg_length = sizeof(pid_msg);
- pid_msg.msg_data[0] = feed->pid;
+ pid_msg.msg_data = feed->pid;
return smsclient_sendrequest(client->smsclient,
&pid_msg, sizeof(pid_msg));
@@ -711,7 +711,7 @@ static int smsdvb_stop_feed(struct dvb_demux_feed *feed)
pid_msg.x_msg_header.msg_flags = 0;
pid_msg.x_msg_header.msg_type = MSG_SMS_REMOVE_PID_FILTER_REQ;
pid_msg.x_msg_header.msg_length = sizeof(pid_msg);
- pid_msg.msg_data[0] = feed->pid;
+ pid_msg.msg_data = feed->pid;
return smsclient_sendrequest(client->smsclient,
&pid_msg, sizeof(pid_msg));
diff --git a/drivers/media/common/siano/smsendian.c b/drivers/media/common/siano/smsendian.c
index a3573814919b..b957970c7d97 100644
--- a/drivers/media/common/siano/smsendian.c
+++ b/drivers/media/common/siano/smsendian.c
@@ -20,11 +20,12 @@ void smsendian_handle_tx_message(void *buffer)
struct sms_msg_data *msg = buffer;
int i;
int msg_words;
+ u32 *msg_data = &msg->msg_data;
switch (msg->x_msg_header.msg_type) {
case MSG_SMS_DATA_DOWNLOAD_REQ:
{
- msg->msg_data[0] = le32_to_cpu((__force __le32)(msg->msg_data[0]));
+ msg->msg_data = le32_to_cpu((__force __le32)(msg->msg_data));
break;
}
@@ -33,7 +34,7 @@ void smsendian_handle_tx_message(void *buffer)
sizeof(struct sms_msg_hdr))/4;
for (i = 0; i < msg_words; i++)
- msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]);
+ msg_data[i] = le32_to_cpu((__force __le32)msg_data[i]);
break;
}
@@ -66,11 +67,12 @@ void smsendian_handle_rx_message(void *buffer)
default:
{
+ u32 *msg_data = &msg->msg_data;
msg_words = (msg->x_msg_header.msg_length -
sizeof(struct sms_msg_hdr))/4;
for (i = 0; i < msg_words; i++)
- msg->msg_data[i] = le32_to_cpu((__force __le32)msg->msg_data[i]);
+ msg_data[i] = le32_to_cpu((__force __le32)msg_data[i]);
break;
}
diff --git a/drivers/media/common/uvc.c b/drivers/media/common/uvc.c
index 9c0ba7a6c185..c54c2268fee6 100644
--- a/drivers/media/common/uvc.c
+++ b/drivers/media/common/uvc.c
@@ -180,4 +180,5 @@ const struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16])
}
EXPORT_SYMBOL_GPL(uvc_format_by_guid);
+MODULE_DESCRIPTION("USB Video Class common code");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 358f1fe42975..0217392fcc0d 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -199,7 +199,6 @@ module_param(debug, int, 0644);
})
static void __vb2_queue_cancel(struct vb2_queue *q);
-static void __enqueue_in_driver(struct vb2_buffer *vb);
static const char *vb2_state_name(enum vb2_buffer_state s)
{
diff --git a/drivers/media/common/videobuf2/videobuf2-dvb.c b/drivers/media/common/videobuf2/videobuf2-dvb.c
index 8c15bcd07eef..3746bf6d1c15 100644
--- a/drivers/media/common/videobuf2/videobuf2-dvb.c
+++ b/drivers/media/common/videobuf2/videobuf2-dvb.c
@@ -19,6 +19,7 @@
/* ------------------------------------------------------------------ */
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_DESCRIPTION("Videobuf2 helper library for simple DVB cards");
MODULE_LICENSE("GPL");
/* ------------------------------------------------------------------ */
diff --git a/drivers/media/dvb-frontends/au8522_decoder.c b/drivers/media/dvb-frontends/au8522_decoder.c
index acc27376c246..d02a92a81c60 100644
--- a/drivers/media/dvb-frontends/au8522_decoder.c
+++ b/drivers/media/dvb-frontends/au8522_decoder.c
@@ -25,6 +25,7 @@
#include "au8522_priv.h"
MODULE_AUTHOR("Devin Heitmueller");
+MODULE_DESCRIPTION("Auvitek AU8522 QAM/8VSB demodulator driver and video decoder");
MODULE_LICENSE("GPL");
static int au8522_analog_debug;
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index 444fe1c4bf2d..c5582d4fa5be 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -32,11 +32,6 @@ MODULE_PARM_DESC(buggy_sfn_workaround, "Enable work-around for buggy SFNs (defau
__func__, ##arg); \
} while (0)
-struct i2c_device {
- struct i2c_adapter *i2c_adap;
- u8 i2c_addr;
-};
-
struct dib7000p_state {
struct dvb_frontend demod;
struct dib7000p_config cfg;
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index 6fcaf07e1b82..779cce93e94a 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -976,13 +976,6 @@ static struct drx_aud_data drxj_default_aud_data_g = {
/*-----------------------------------------------------------------------------
STRUCTURES
----------------------------------------------------------------------------*/
-struct drxjeq_stat {
- u16 eq_mse;
- u8 eq_mode;
- u8 eq_ctrl;
- u8 eq_stat;
-};
-
/* HI command */
struct drxj_hi_cmd {
u16 cmd;
diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c
index 0fc45896e7b8..9033e39d75f4 100644
--- a/drivers/media/dvb-frontends/mb86a16.c
+++ b/drivers/media/dvb-frontends/mb86a16.c
@@ -1854,5 +1854,6 @@ error:
return NULL;
}
EXPORT_SYMBOL_GPL(mb86a16_attach);
+MODULE_DESCRIPTION("Fujitsu MB86A16 DVB-S/DSS DC Receiver driver");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Manu Abraham");
diff --git a/drivers/media/dvb-frontends/mxl5xx_defs.h b/drivers/media/dvb-frontends/mxl5xx_defs.h
index 097271f73740..bf08d82ba2cc 100644
--- a/drivers/media/dvb-frontends/mxl5xx_defs.h
+++ b/drivers/media/dvb-frontends/mxl5xx_defs.h
@@ -168,7 +168,7 @@ struct MBIN_FILE_HEADER_T {
struct MBIN_FILE_T {
struct MBIN_FILE_HEADER_T header;
- u8 data[1];
+ u8 data[];
};
struct MBIN_SEGMENT_HEADER_T {
@@ -179,7 +179,7 @@ struct MBIN_SEGMENT_HEADER_T {
struct MBIN_SEGMENT_T {
struct MBIN_SEGMENT_HEADER_T header;
- u8 data[1];
+ u8 data[];
};
enum MXL_CMD_TYPE_E { MXL_CMD_WRITE = 0, MXL_CMD_READ };
diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
index cc45139057ba..3b02d504941f 100644
--- a/drivers/media/dvb-frontends/stv090x.c
+++ b/drivers/media/dvb-frontends/stv090x.c
@@ -748,6 +748,22 @@ static int stv090x_write_reg(struct stv090x_state *state, unsigned int reg, u8 d
return stv090x_write_regs(state, reg, &tmp, 1);
}
+static inline void stv090x_tuner_i2c_lock(struct stv090x_state *state)
+{
+ if (state->config->tuner_i2c_lock)
+ state->config->tuner_i2c_lock(&state->frontend, 1);
+ else
+ mutex_lock(&state->internal->tuner_lock);
+}
+
+static inline void stv090x_tuner_i2c_unlock(struct stv090x_state *state)
+{
+ if (state->config->tuner_i2c_lock)
+ state->config->tuner_i2c_lock(&state->frontend, 0);
+ else
+ mutex_unlock(&state->internal->tuner_lock);
+}
+
static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
{
u32 reg;
@@ -761,12 +777,8 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
* In case of any error, the lock is unlocked and exit within the
* relevant operations themselves.
*/
- if (enable) {
- if (state->config->tuner_i2c_lock)
- state->config->tuner_i2c_lock(&state->frontend, 1);
- else
- mutex_lock(&state->internal->tuner_lock);
- }
+ if (enable)
+ stv090x_tuner_i2c_lock(state);
reg = STV090x_READ_DEMOD(state, I2CRPT);
if (enable) {
@@ -782,20 +794,13 @@ static int stv090x_i2c_gate_ctrl(struct stv090x_state *state, int enable)
goto err;
}
- if (!enable) {
- if (state->config->tuner_i2c_lock)
- state->config->tuner_i2c_lock(&state->frontend, 0);
- else
- mutex_unlock(&state->internal->tuner_lock);
- }
+ if (!enable)
+ stv090x_tuner_i2c_unlock(state);
return 0;
err:
dprintk(FE_ERROR, 1, "I/O error");
- if (state->config->tuner_i2c_lock)
- state->config->tuner_i2c_lock(&state->frontend, 0);
- else
- mutex_unlock(&state->internal->tuner_lock);
+ stv090x_tuner_i2c_unlock(state);
return -1;
}
diff --git a/drivers/media/dvb-frontends/stv0910.c b/drivers/media/dvb-frontends/stv0910.c
index e517ff757744..069dec75129c 100644
--- a/drivers/media/dvb-frontends/stv0910.c
+++ b/drivers/media/dvb-frontends/stv0910.c
@@ -119,11 +119,6 @@ struct stv {
u8 vth[6];
};
-struct sinit_table {
- u16 address;
- u8 data;
-};
-
struct slookup {
s16 value;
u32 reg_value;
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index c6d3ee472d81..8ba096b8ebca 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -70,6 +70,26 @@ config VIDEO_GC0308
To compile this driver as a module, choose M here: the
module will be called gc0308.
+config VIDEO_GC05A2
+ tristate "GalaxyCore gc05a2 sensor support"
+ select V4L2_CCI_I2C
+ help
+ This is a Video4Linux2 sensor driver for the GalaxyCore gc05a2
+ camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gc05a2.
+
+config VIDEO_GC08A3
+ tristate "GalaxyCore gc08a3 sensor support"
+ select V4L2_CCI_I2C
+ help
+ This is a Video4Linux2 sensor driver for the GalaxyCore gc08a3
+ camera.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gc08a3.
+
config VIDEO_GC2145
select V4L2_CCI_I2C
tristate "GalaxyCore GC2145 sensor support"
@@ -139,6 +159,7 @@ config VIDEO_IMX219
config VIDEO_IMX258
tristate "Sony IMX258 sensor support"
+ select V4L2_CCI_I2C
help
This is a Video4Linux2 sensor driver for the Sony
IMX258 camera.
@@ -153,6 +174,16 @@ config VIDEO_IMX274
This is a V4L2 sensor driver for the Sony IMX274
CMOS image sensor.
+config VIDEO_IMX283
+ tristate "Sony IMX283 sensor support"
+ select V4L2_CCI_I2C
+ help
+ This is a V4L2 sensor driver for the Sony IMX283
+ CMOS image sensor.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imx283.
+
config VIDEO_IMX290
tristate "Sony IMX290 sensor support"
select REGMAP_I2C
@@ -659,7 +690,7 @@ config VIDEO_S5K6A3
This is a V4L2 sensor driver for Samsung S5K6A3 raw
camera sensor.
-config VIDEO_ST_VGXY61
+config VIDEO_VGXY61
tristate "ST VGXY61 sensor support"
select V4L2_CCI_I2C
depends on OF && GPIOLIB
@@ -679,6 +710,7 @@ config VIDEO_THP7312
tristate "THine THP7312 support"
depends on I2C
select FW_LOADER
+ select FW_UPLOAD
select MEDIA_CONTROLLER
select V4L2_CCI_I2C
select V4L2_FWNODE
@@ -1575,6 +1607,40 @@ config VIDEO_DS90UB960
Device driver for the Texas Instruments DS90UB960
FPD-Link III Deserializer and DS90UB9702 FPD-Link IV Deserializer.
+config VIDEO_MAX96714
+ tristate "Maxim MAX96714 GMSL2 deserializer"
+ depends on OF && I2C && VIDEO_DEV
+ select I2C_MUX
+ select MEDIA_CONTROLLER
+ select GPIOLIB
+ select V4L2_CCI_I2C
+ select V4L2_FWNODE
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ Device driver for the Maxim MAX96714 GMSL2 Deserializer.
+ MAX96714 deserializers convert a GMSL2 input to MIPI CSI-2
+ output.
+
+ To compile this driver as a module, choose M here: the
+ module will be called max96714.
+
+config VIDEO_MAX96717
+ tristate "Maxim MAX96717 GMSL2 Serializer support"
+ depends on OF && I2C && VIDEO_DEV && COMMON_CLK
+ select I2C_MUX
+ select MEDIA_CONTROLLER
+ select GPIOLIB
+ select V4L2_CCI_I2C
+ select V4L2_FWNODE
+ select VIDEO_V4L2_SUBDEV_API
+ help
+ Device driver for the Maxim MAX96717 GMSL2 Serializer.
+ MAX96717 serializers convert video on a MIPI CSI-2
+ input to a GMSL2 output.
+
+ To compile this driver as a module, choose M here: the
+ module will be called max96717.
+
endmenu
endif # VIDEO_DEV
diff --git a/drivers/media/i2c/Makefile b/drivers/media/i2c/Makefile
index dfbe6448b549..fbb988bd067a 100644
--- a/drivers/media/i2c/Makefile
+++ b/drivers/media/i2c/Makefile
@@ -38,6 +38,8 @@ obj-$(CONFIG_VIDEO_DW9768) += dw9768.o
obj-$(CONFIG_VIDEO_DW9807_VCM) += dw9807-vcm.o
obj-$(CONFIG_VIDEO_ET8EK8) += et8ek8/
obj-$(CONFIG_VIDEO_GC0308) += gc0308.o
+obj-$(CONFIG_VIDEO_GC05A2) += gc05a2.o
+obj-$(CONFIG_VIDEO_GC08A3) += gc08a3.o
obj-$(CONFIG_VIDEO_GC2145) += gc2145.o
obj-$(CONFIG_VIDEO_HI556) += hi556.o
obj-$(CONFIG_VIDEO_HI846) += hi846.o
@@ -48,6 +50,7 @@ obj-$(CONFIG_VIDEO_IMX214) += imx214.o
obj-$(CONFIG_VIDEO_IMX219) += imx219.o
obj-$(CONFIG_VIDEO_IMX258) += imx258.o
obj-$(CONFIG_VIDEO_IMX274) += imx274.o
+obj-$(CONFIG_VIDEO_IMX283) += imx283.o
obj-$(CONFIG_VIDEO_IMX290) += imx290.o
obj-$(CONFIG_VIDEO_IMX296) += imx296.o
obj-$(CONFIG_VIDEO_IMX319) += imx319.o
@@ -64,6 +67,8 @@ obj-$(CONFIG_VIDEO_LM3646) += lm3646.o
obj-$(CONFIG_VIDEO_M52790) += m52790.o
obj-$(CONFIG_VIDEO_MAX9271_LIB) += max9271.o
obj-$(CONFIG_VIDEO_MAX9286) += max9286.o
+obj-$(CONFIG_VIDEO_MAX96714) += max96714.o
+obj-$(CONFIG_VIDEO_MAX96717) += max96717.o
obj-$(CONFIG_VIDEO_ML86V7667) += ml86v7667.o
obj-$(CONFIG_VIDEO_MSP3400) += msp3400.o
obj-$(CONFIG_VIDEO_MT9M001) += mt9m001.o
@@ -124,7 +129,6 @@ obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
obj-$(CONFIG_VIDEO_SONY_BTF_MPX) += sony-btf-mpx.o
obj-$(CONFIG_VIDEO_ST_MIPID02) += st-mipid02.o
-obj-$(CONFIG_VIDEO_ST_VGXY61) += st-vgxy61.o
obj-$(CONFIG_VIDEO_TC358743) += tc358743.o
obj-$(CONFIG_VIDEO_TC358746) += tc358746.o
obj-$(CONFIG_VIDEO_TDA1997X) += tda1997x.o
@@ -148,6 +152,7 @@ obj-$(CONFIG_VIDEO_TW9910) += tw9910.o
obj-$(CONFIG_VIDEO_UDA1342) += uda1342.o
obj-$(CONFIG_VIDEO_UPD64031A) += upd64031a.o
obj-$(CONFIG_VIDEO_UPD64083) += upd64083.o
+obj-$(CONFIG_VIDEO_VGXY61) += vgxy61.o
obj-$(CONFIG_VIDEO_VP27SMPX) += vp27smpx.o
obj-$(CONFIG_VIDEO_VPX3220) += vpx3220.o
obj-$(CONFIG_VIDEO_WM8739) += wm8739.o
diff --git a/drivers/media/i2c/adv748x/adv748x-afe.c b/drivers/media/i2c/adv748x/adv748x-afe.c
index 50d9fbadbe38..5edb3295dc58 100644
--- a/drivers/media/i2c/adv748x/adv748x-afe.c
+++ b/drivers/media/i2c/adv748x/adv748x-afe.c
@@ -114,7 +114,7 @@ static void adv748x_afe_fill_format(struct adv748x_afe *afe,
{
memset(fmt, 0, sizeof(*fmt));
- fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->field = V4L2_FIELD_ALTERNATE;
@@ -337,7 +337,7 @@ static int adv748x_afe_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0)
return -EINVAL;
- code->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ code->code = MEDIA_BUS_FMT_UYVY8_1X16;
return 0;
}
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 5b265b722394..ebe7da8ebed7 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -6,7 +6,6 @@
*/
#include <linux/module.h>
-#include <linux/mutex.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -14,6 +13,15 @@
#include "adv748x.h"
+static const unsigned int adv748x_csi2_txa_fmts[] = {
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ MEDIA_BUS_FMT_RGB888_1X24,
+};
+
+static const unsigned int adv748x_csi2_txb_fmts[] = {
+ MEDIA_BUS_FMT_UYVY8_1X16,
+};
+
int adv748x_csi2_set_virtual_channel(struct adv748x_csi2 *tx, unsigned int vc)
{
return tx_write(tx, ADV748X_CSI_VC_REF, vc << ADV748X_CSI_VC_REF_SHIFT);
@@ -59,7 +67,33 @@ static int adv748x_csi2_register_link(struct adv748x_csi2 *tx,
/* -----------------------------------------------------------------------------
* v4l2_subdev_internal_ops
- *
+ */
+
+static int adv748x_csi2_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ static const struct v4l2_mbus_framefmt adv748x_csi2_default_fmt = {
+ .width = 1280,
+ .height = 720,
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .field = V4L2_FIELD_NONE,
+ .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+ .quantization = V4L2_QUANTIZATION_DEFAULT,
+ .xfer_func = V4L2_XFER_FUNC_DEFAULT,
+ };
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SINK);
+ *fmt = adv748x_csi2_default_fmt;
+
+ fmt = v4l2_subdev_state_get_format(state, ADV748X_CSI2_SOURCE);
+ *fmt = adv748x_csi2_default_fmt;
+
+ return 0;
+}
+
+/*
* We use the internal registered operation to be able to ensure that our
* incremental subdevices (not connected in the forward path) can be registered
* against the resulting video path and media device.
@@ -109,6 +143,7 @@ static int adv748x_csi2_registered(struct v4l2_subdev *sd)
}
static const struct v4l2_subdev_internal_ops adv748x_csi2_internal_ops = {
+ .init_state = adv748x_csi2_init_state,
.registered = adv748x_csi2_registered,
};
@@ -139,39 +174,55 @@ static const struct v4l2_subdev_video_ops adv748x_csi2_video_ops = {
* But we must support setting the pad formats for format propagation.
*/
-static struct v4l2_mbus_framefmt *
-adv748x_csi2_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, u32 which)
+static int adv748x_csi2_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
{
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
+ const unsigned int *codes = is_txa(tx) ?
+ adv748x_csi2_txa_fmts :
+ adv748x_csi2_txb_fmts;
+ size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts)
+ : ARRAY_SIZE(adv748x_csi2_txb_fmts);
- if (which == V4L2_SUBDEV_FORMAT_TRY)
- return v4l2_subdev_state_get_format(sd_state, pad);
+ /*
+ * The format available on the source pad is the one applied on the sink
+ * pad.
+ */
+ if (code->pad == ADV748X_CSI2_SOURCE) {
+ struct v4l2_mbus_framefmt *fmt;
- return &tx->format;
-}
+ if (code->index)
+ return -EINVAL;
-static int adv748x_csi2_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *sdformat)
-{
- struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
- struct adv748x_state *state = tx->state;
- struct v4l2_mbus_framefmt *mbusformat;
+ fmt = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SINK);
+ code->code = fmt->code;
- mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
- sdformat->which);
- if (!mbusformat)
+ return 0;
+ }
+
+ if (code->index >= num_fmts)
return -EINVAL;
- mutex_lock(&state->mutex);
+ code->code = codes[code->index];
- sdformat->format = *mbusformat;
+ return 0;
+}
- mutex_unlock(&state->mutex);
+static bool adv748x_csi2_is_fmt_supported(struct adv748x_csi2 *tx, u32 code)
+{
+ const unsigned int *codes = is_txa(tx) ?
+ adv748x_csi2_txa_fmts :
+ adv748x_csi2_txb_fmts;
+ size_t num_fmts = is_txa(tx) ? ARRAY_SIZE(adv748x_csi2_txa_fmts)
+ : ARRAY_SIZE(adv748x_csi2_txb_fmts);
+
+ for (unsigned int i = 0; i < num_fmts; i++) {
+ if (codes[i] == code)
+ return true;
+ }
- return 0;
+ return false;
}
static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
@@ -179,38 +230,26 @@ static int adv748x_csi2_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_format *sdformat)
{
struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
- struct adv748x_state *state = tx->state;
struct v4l2_mbus_framefmt *mbusformat;
- int ret = 0;
-
- mbusformat = adv748x_csi2_get_pad_format(sd, sd_state, sdformat->pad,
- sdformat->which);
- if (!mbusformat)
- return -EINVAL;
-
- mutex_lock(&state->mutex);
- if (sdformat->pad == ADV748X_CSI2_SOURCE) {
- const struct v4l2_mbus_framefmt *sink_fmt;
+ if (sdformat->pad == ADV748X_CSI2_SOURCE)
+ return v4l2_subdev_get_fmt(sd, sd_state, sdformat);
- sink_fmt = adv748x_csi2_get_pad_format(sd, sd_state,
- ADV748X_CSI2_SINK,
- sdformat->which);
-
- if (!sink_fmt) {
- ret = -EINVAL;
- goto unlock;
- }
-
- sdformat->format = *sink_fmt;
- }
+ /*
+ * Make sure the format is supported, if not default it to
+ * UYVY8 as it's supported by both TXes.
+ */
+ if (!adv748x_csi2_is_fmt_supported(tx, sdformat->format.code))
+ sdformat->format.code = MEDIA_BUS_FMT_UYVY8_1X16;
+ mbusformat = v4l2_subdev_state_get_format(sd_state, sdformat->pad);
*mbusformat = sdformat->format;
-unlock:
- mutex_unlock(&state->mutex);
+ /* Propagate format to the source pad. */
+ mbusformat = v4l2_subdev_state_get_format(sd_state, ADV748X_CSI2_SOURCE);
+ *mbusformat = sdformat->format;
- return ret;
+ return 0;
}
static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
@@ -228,7 +267,8 @@ static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad
}
static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
- .get_fmt = adv748x_csi2_get_format,
+ .enum_mbus_code = adv748x_csi2_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = adv748x_csi2_set_format,
.get_mbus_config = adv748x_csi2_get_mbus_config,
};
@@ -320,6 +360,11 @@ int adv748x_csi2_init(struct adv748x_state *state, struct adv748x_csi2 *tx)
if (ret)
goto err_cleanup_subdev;
+ tx->sd.state_lock = &state->mutex;
+ ret = v4l2_subdev_init_finalize(&tx->sd);
+ if (ret)
+ goto err_free_ctrl;
+
ret = v4l2_async_register_subdev(&tx->sd);
if (ret)
goto err_free_ctrl;
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index d2b5e722e997..9bc0121d0eff 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -75,7 +75,6 @@ enum adv748x_csi2_pads {
struct adv748x_csi2 {
struct adv748x_state *state;
- struct v4l2_mbus_framefmt format;
unsigned int page;
unsigned int port;
unsigned int num_lanes;
diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c
index 79946e9c7401..261871be833f 100644
--- a/drivers/media/i2c/adv7511-v4l2.c
+++ b/drivers/media/i2c/adv7511-v4l2.c
@@ -62,11 +62,6 @@ MODULE_LICENSE("GPL v2");
**********************************************************************
*/
-struct i2c_reg_value {
- unsigned char reg;
- unsigned char value;
-};
-
struct adv7511_state_edid {
/* total number of blocks */
u32 blocks;
diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c
index e65702e3f73e..5ddfd3dcb188 100644
--- a/drivers/media/i2c/alvium-csi2.c
+++ b/drivers/media/i2c/alvium-csi2.c
@@ -403,21 +403,22 @@ static int alvium_get_bcrm_vers(struct alvium_dev *alvium)
static int alvium_get_fw_version(struct alvium_dev *alvium)
{
struct device *dev = &alvium->i2c_client->dev;
- u64 spec, maj, min, pat;
- int ret = 0;
+ u64 val;
+ int ret;
- ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_SPEC_VERSION_R,
- &spec, &ret);
- ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_MAJOR_VERSION_R,
- &maj, &ret);
- ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_MINOR_VERSION_R,
- &min, &ret);
- ret = alvium_read(alvium, REG_BCRM_DEVICE_FW_PATCH_VERSION_R,
- &pat, &ret);
+ ret = alvium_read(alvium, REG_BCRM_DEVICE_FW, &val, NULL);
if (ret)
return ret;
- dev_info(dev, "fw version: %llu.%llu.%llu.%llu\n", spec, maj, min, pat);
+ dev_info(dev, "fw version: %02u.%02u.%04u.%08x\n",
+ (u8)((val & BCRM_DEVICE_FW_SPEC_MASK) >>
+ BCRM_DEVICE_FW_SPEC_SHIFT),
+ (u8)((val & BCRM_DEVICE_FW_MAJOR_MASK) >>
+ BCRM_DEVICE_FW_MAJOR_SHIFT),
+ (u16)((val & BCRM_DEVICE_FW_MINOR_MASK) >>
+ BCRM_DEVICE_FW_MINOR_SHIFT),
+ (u32)((val & BCRM_DEVICE_FW_PATCH_MASK) >>
+ BCRM_DEVICE_FW_PATCH_SHIFT));
return 0;
}
@@ -1188,6 +1189,20 @@ static int alvium_set_frame_rate(struct alvium_dev *alvium, u64 fr)
struct device *dev = &alvium->i2c_client->dev;
int ret;
+ ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_EN_RW,
+ 1);
+ if (ret) {
+ dev_err(dev, "Fail to set acquisition frame rate enable reg\n");
+ return ret;
+ }
+
+ ret = alvium_write_hshake(alvium, REG_BCRM_FRAME_START_TRIGGER_MODE_RW,
+ 0);
+ if (ret) {
+ dev_err(dev, "Fail to set frame start trigger mode reg\n");
+ return ret;
+ }
+
ret = alvium_write_hshake(alvium, REG_BCRM_ACQUISITION_FRAME_RATE_RW,
fr);
if (ret) {
@@ -1707,6 +1722,27 @@ alvium_code_to_pixfmt(struct alvium_dev *alvium, u32 code)
return &alvium->alvium_csi2_fmt[0];
}
+static int alvium_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ struct alvium_dev *alvium = sd_to_alvium(sd);
+ const struct alvium_pixfmt *alvium_csi2_fmt;
+
+ if (fse->index)
+ return -EINVAL;
+
+ alvium_csi2_fmt = alvium_code_to_pixfmt(alvium, fse->code);
+ if (fse->code != alvium_csi2_fmt->code)
+ return -EINVAL;
+
+ fse->min_width = alvium->img_min_width;
+ fse->max_width = alvium->img_max_width;
+ fse->min_height = alvium->img_min_height;
+ fse->max_height = alvium->img_max_height;
+ return 0;
+}
+
static int alvium_set_mode(struct alvium_dev *alvium,
struct v4l2_subdev_state *state)
{
@@ -1962,7 +1998,7 @@ static int alvium_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
int val;
switch (ctrl->id) {
- case V4L2_CID_GAIN:
+ case V4L2_CID_ANALOGUE_GAIN:
val = alvium_get_gain(alvium);
if (val < 0)
return val;
@@ -1994,7 +2030,7 @@ static int alvium_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
switch (ctrl->id) {
- case V4L2_CID_GAIN:
+ case V4L2_CID_ANALOGUE_GAIN:
ret = alvium_set_ctrl_gain(alvium, ctrl->val);
break;
case V4L2_CID_AUTOGAIN:
@@ -2123,7 +2159,7 @@ static int alvium_ctrl_init(struct alvium_dev *alvium)
if (alvium->avail_ft.gain) {
ctrls->gain = v4l2_ctrl_new_std(hdl, ops,
- V4L2_CID_GAIN,
+ V4L2_CID_ANALOGUE_GAIN,
alvium->min_gain,
alvium->max_gain,
alvium->inc_gain,
@@ -2214,6 +2250,7 @@ static const struct v4l2_subdev_video_ops alvium_video_ops = {
static const struct v4l2_subdev_pad_ops alvium_pad_ops = {
.enum_mbus_code = alvium_enum_mbus_code,
+ .enum_frame_size = alvium_enum_frame_size,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = alvium_set_fmt,
.get_selection = alvium_get_selection,
diff --git a/drivers/media/i2c/alvium-csi2.h b/drivers/media/i2c/alvium-csi2.h
index 9463f8604fbc..978af44f76c7 100644
--- a/drivers/media/i2c/alvium-csi2.h
+++ b/drivers/media/i2c/alvium-csi2.h
@@ -31,10 +31,7 @@
#define REG_BCRM_REG_ADDR_R CCI_REG16(0x0014)
#define REG_BCRM_FEATURE_INQUIRY_R REG_BCRM_V4L2_64BIT(0x0008)
-#define REG_BCRM_DEVICE_FW_SPEC_VERSION_R REG_BCRM_V4L2_8BIT(0x0010)
-#define REG_BCRM_DEVICE_FW_MAJOR_VERSION_R REG_BCRM_V4L2_8BIT(0x0011)
-#define REG_BCRM_DEVICE_FW_MINOR_VERSION_R REG_BCRM_V4L2_16BIT(0x0012)
-#define REG_BCRM_DEVICE_FW_PATCH_VERSION_R REG_BCRM_V4L2_32BIT(0x0014)
+#define REG_BCRM_DEVICE_FW REG_BCRM_V4L2_64BIT(0x0010)
#define REG_BCRM_WRITE_HANDSHAKE_RW REG_BCRM_V4L2_8BIT(0x0018)
/* Streaming Control Registers */
@@ -66,7 +63,7 @@
#define REG_BCRM_ACQUISITION_FRAME_RATE_MIN_R REG_BCRM_V4L2_64BIT(0x0098)
#define REG_BCRM_ACQUISITION_FRAME_RATE_MAX_R REG_BCRM_V4L2_64BIT(0x00a0)
#define REG_BCRM_ACQUISITION_FRAME_RATE_INC_R REG_BCRM_V4L2_64BIT(0x00a8)
-#define REG_BCRM_ACQUISITION_FRAME_RATE_ENABLE_RW REG_BCRM_V4L2_8BIT(0x00b0)
+#define REG_BCRM_ACQUISITION_FRAME_RATE_EN_RW REG_BCRM_V4L2_8BIT(0x00b0)
#define REG_BCRM_FRAME_START_TRIGGER_MODE_RW REG_BCRM_V4L2_8BIT(0x00b4)
#define REG_BCRM_FRAME_START_TRIGGER_SOURCE_RW REG_BCRM_V4L2_8BIT(0x00b8)
@@ -205,6 +202,15 @@
#define ALVIUM_LP2HS_DELAY_MS 100
+#define BCRM_DEVICE_FW_MAJOR_MASK GENMASK_ULL(15, 8)
+#define BCRM_DEVICE_FW_MAJOR_SHIFT 8
+#define BCRM_DEVICE_FW_MINOR_MASK GENMASK_ULL(31, 16)
+#define BCRM_DEVICE_FW_MINOR_SHIFT 16
+#define BCRM_DEVICE_FW_PATCH_MASK GENMASK_ULL(63, 32)
+#define BCRM_DEVICE_FW_PATCH_SHIFT 32
+#define BCRM_DEVICE_FW_SPEC_MASK GENMASK_ULL(7, 0)
+#define BCRM_DEVICE_FW_SPEC_SHIFT 0
+
enum alvium_bcrm_mode {
ALVIUM_BCM_MODE,
ALVIUM_GENCP_MODE,
diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c
index daabbece8c7e..18ef2b35c9aa 100644
--- a/drivers/media/i2c/dw9768.c
+++ b/drivers/media/i2c/dw9768.c
@@ -115,11 +115,6 @@ static inline struct dw9768 *sd_to_dw9768(struct v4l2_subdev *subdev)
return container_of(subdev, struct dw9768, sd);
}
-struct regval_list {
- u8 reg_num;
- u8 value;
-};
-
struct dw9768_aac_mode_ot_multi {
u32 aac_mode_enum;
u32 ot_multi_base100;
diff --git a/drivers/media/i2c/gc05a2.c b/drivers/media/i2c/gc05a2.c
new file mode 100644
index 000000000000..dcba29ee725c
--- /dev/null
+++ b/drivers/media/i2c/gc05a2.c
@@ -0,0 +1,1359 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for GalaxyCore gc05a2 image sensor
+ *
+ * Copyright 2024 MediaTek
+ *
+ * Zhi Mao <zhi.mao@mediatek.com>
+ */
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/container_of.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/math64.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define GC05A2_REG_TEST_PATTERN_EN CCI_REG8(0x008c)
+#define GC05A2_REG_TEST_PATTERN_IDX CCI_REG8(0x008d)
+#define GC05A2_TEST_PATTERN_EN 0x01
+
+#define GC05A2_STREAMING_REG CCI_REG8(0x0100)
+
+#define GC05A2_FLIP_REG CCI_REG8(0x0101)
+#define GC05A2_FLIP_H_MASK BIT(0)
+#define GC05A2_FLIP_V_MASK BIT(1)
+
+#define GC05A2_EXP_REG CCI_REG16(0x0202)
+#define GC05A2_EXP_MARGIN 16
+#define GC05A2_EXP_MIN 4
+#define GC05A2_EXP_STEP 1
+
+#define GC05A2_AGAIN_REG CCI_REG16(0x0204)
+#define GC05A2_AGAIN_MIN 1024
+#define GC05A2_AGAIN_MAX (1024 * 16)
+#define GC05A2_AGAIN_STEP 1
+
+#define GC05A2_FRAME_LENGTH_REG CCI_REG16(0x0340)
+#define GC05A2_VTS_MAX 0xffff
+
+#define GC05A2_REG_CHIP_ID CCI_REG16(0x03f0)
+#define GC05A2_CHIP_ID 0x05a2
+
+#define GC05A2_NATIVE_WIDTH 2592
+#define GC05A2_NATIVE_HEIGHT 1944
+
+#define GC05A2_DEFAULT_CLK_FREQ (24 * HZ_PER_MHZ)
+#define GC05A2_MBUS_CODE MEDIA_BUS_FMT_SGRBG10_1X10
+#define GC05A2_DATA_LANES 2
+#define GC05A2_RGB_DEPTH 10
+#define GC05A2_SLEEP_US (2 * USEC_PER_MSEC)
+
+static const char *const gc05a2_test_pattern_menu[] = {
+ "No Pattern", "Fade_to_gray_Color Bar", "Color Bar",
+ "PN9", "Horizental_gradient", "Checkboard Pattern",
+ "Slant", "Resolution", "Solid Black",
+ "Solid White",
+};
+
+static const s64 gc05a2_link_freq_menu_items[] = {
+ (448 * HZ_PER_MHZ),
+ (224 * HZ_PER_MHZ),
+};
+
+static const char *const gc05a2_supply_name[] = {
+ "avdd",
+ "dvdd",
+ "dovdd",
+};
+
+struct gc05a2 {
+ struct device *dev;
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ struct clk *xclk;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(gc05a2_supply_name)];
+ struct gpio_desc *reset_gpio;
+
+ struct v4l2_ctrl_handler ctrls;
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+
+ struct regmap *regmap;
+ unsigned long link_freq_bitmap;
+
+ /* True if the device has been identified */
+ bool identified;
+ const struct gc05a2_mode *cur_mode;
+};
+
+struct gc05a2_reg_list {
+ u32 num_of_regs;
+ const struct cci_reg_sequence *regs;
+};
+
+static const struct cci_reg_sequence mode_2592x1944[] = {
+ /* system */
+ { CCI_REG8(0x0135), 0x01 },
+ { CCI_REG8(0x0084), 0x21 },
+ { CCI_REG8(0x0d05), 0xcc },
+ { CCI_REG8(0x0218), 0x00 },
+ { CCI_REG8(0x005e), 0x48 },
+ { CCI_REG8(0x0d06), 0x01 },
+ { CCI_REG8(0x0007), 0x16 },
+ { CCI_REG8(0x0101), 0x00 },
+
+ /* analog */
+ { CCI_REG8(0x0342), 0x07 },
+ { CCI_REG8(0x0343), 0x28 },
+ { CCI_REG8(0x0220), 0x07 },
+ { CCI_REG8(0x0221), 0xd0 },
+ { CCI_REG8(0x0202), 0x07 },
+ { CCI_REG8(0x0203), 0x32 },
+ { CCI_REG8(0x0340), 0x07 },
+ { CCI_REG8(0x0341), 0xf0 },
+ { CCI_REG8(0x0219), 0x00 },
+ { CCI_REG8(0x0346), 0x00 },
+ { CCI_REG8(0x0347), 0x04 },
+ { CCI_REG8(0x0d14), 0x00 },
+ { CCI_REG8(0x0d13), 0x05 },
+ { CCI_REG8(0x0d16), 0x05 },
+ { CCI_REG8(0x0d15), 0x1d },
+ { CCI_REG8(0x00c0), 0x0a },
+ { CCI_REG8(0x00c1), 0x30 },
+ { CCI_REG8(0x034a), 0x07 },
+ { CCI_REG8(0x034b), 0xa8 },
+ { CCI_REG8(0x0e0a), 0x00 },
+ { CCI_REG8(0x0e0b), 0x00 },
+ { CCI_REG8(0x0e0e), 0x03 },
+ { CCI_REG8(0x0e0f), 0x00 },
+ { CCI_REG8(0x0e06), 0x0a },
+ { CCI_REG8(0x0e23), 0x15 },
+ { CCI_REG8(0x0e24), 0x15 },
+ { CCI_REG8(0x0e2a), 0x10 },
+ { CCI_REG8(0x0e2b), 0x10 },
+ { CCI_REG8(0x0e17), 0x49 },
+ { CCI_REG8(0x0e1b), 0x1c },
+ { CCI_REG8(0x0e3a), 0x36 },
+ { CCI_REG8(0x0d11), 0x84 },
+ { CCI_REG8(0x0e52), 0x14 },
+ { CCI_REG8(0x000b), 0x10 },
+ { CCI_REG8(0x0008), 0x08 },
+ { CCI_REG8(0x0223), 0x17 },
+ { CCI_REG8(0x0d27), 0x39 },
+ { CCI_REG8(0x0d22), 0x00 },
+ { CCI_REG8(0x03f6), 0x0d },
+ { CCI_REG8(0x0d04), 0x07 },
+ { CCI_REG8(0x03f3), 0x72 },
+ { CCI_REG8(0x03f4), 0xb8 },
+ { CCI_REG8(0x03f5), 0xbc },
+ { CCI_REG8(0x0d02), 0x73 },
+
+ /* auto load start */
+ { CCI_REG8(0x00cb), 0x00 },
+
+ /* OUT 2592*1944 */
+ { CCI_REG8(0x0350), 0x01 },
+ { CCI_REG8(0x0353), 0x00 },
+ { CCI_REG8(0x0354), 0x08 },
+ { CCI_REG16(0x034c), 2592 }, /* Width */
+ { CCI_REG8(0x021f), 0x14 },
+
+ /* MIPI */
+ { CCI_REG8(0x0107), 0x05 },
+ { CCI_REG8(0x0117), 0x01 },
+ { CCI_REG8(0x0d81), 0x00 },
+ { CCI_REG8(0x0d84), 0x0c },
+ { CCI_REG8(0x0d85), 0xa8 },
+ { CCI_REG8(0x0d86), 0x06 },
+ { CCI_REG8(0x0d87), 0x55 },
+ { CCI_REG8(0x0db3), 0x06 },
+ { CCI_REG8(0x0db4), 0x08 },
+ { CCI_REG8(0x0db5), 0x1e },
+ { CCI_REG8(0x0db6), 0x02 },
+ { CCI_REG8(0x0db8), 0x12 },
+ { CCI_REG8(0x0db9), 0x0a },
+ { CCI_REG8(0x0d93), 0x06 },
+ { CCI_REG8(0x0d94), 0x09 },
+ { CCI_REG8(0x0d95), 0x0d },
+ { CCI_REG8(0x0d99), 0x0b },
+ { CCI_REG8(0x0084), 0x01 },
+ { CCI_REG8(0x0110), 0x01 },
+};
+
+static const struct cci_reg_sequence mode_1280x720[] = {
+ /* system */
+ { CCI_REG8(0x0135), 0x05 },
+ { CCI_REG8(0x0084), 0x21 },
+ { CCI_REG8(0x0d05), 0xcc },
+ { CCI_REG8(0x0218), 0x80 },
+ { CCI_REG8(0x005e), 0x49 },
+ { CCI_REG8(0x0d06), 0x81 },
+ { CCI_REG8(0x0007), 0x16 },
+ { CCI_REG8(0x0101), 0x00 },
+
+ /* analog */
+ { CCI_REG8(0x0342), 0x07 },
+ { CCI_REG8(0x0343), 0x10 },
+ { CCI_REG8(0x0220), 0x07 },
+ { CCI_REG8(0x0221), 0xd0 },
+ { CCI_REG8(0x0202), 0x03 },
+ { CCI_REG8(0x0203), 0x32 },
+ { CCI_REG8(0x0340), 0x04 },
+ { CCI_REG8(0x0341), 0x08 },
+ { CCI_REG8(0x0219), 0x00 },
+ { CCI_REG8(0x0346), 0x01 },
+ { CCI_REG8(0x0347), 0x00 },
+ { CCI_REG8(0x0d14), 0x00 },
+ { CCI_REG8(0x0d13), 0x05 },
+ { CCI_REG8(0x0d16), 0x05 },
+ { CCI_REG8(0x0d15), 0x1d },
+ { CCI_REG8(0x00c0), 0x0a },
+ { CCI_REG8(0x00c1), 0x30 },
+ { CCI_REG8(0x034a), 0x05 },
+ { CCI_REG8(0x034b), 0xb0 },
+ { CCI_REG8(0x0e0a), 0x00 },
+ { CCI_REG8(0x0e0b), 0x00 },
+ { CCI_REG8(0x0e0e), 0x03 },
+ { CCI_REG8(0x0e0f), 0x00 },
+ { CCI_REG8(0x0e06), 0x0a },
+ { CCI_REG8(0x0e23), 0x15 },
+ { CCI_REG8(0x0e24), 0x15 },
+ { CCI_REG8(0x0e2a), 0x10 },
+ { CCI_REG8(0x0e2b), 0x10 },
+ { CCI_REG8(0x0e17), 0x49 },
+ { CCI_REG8(0x0e1b), 0x1c },
+ { CCI_REG8(0x0e3a), 0x36 },
+ { CCI_REG8(0x0d11), 0x84 },
+ { CCI_REG8(0x0e52), 0x14 },
+ { CCI_REG8(0x000b), 0x0e },
+ { CCI_REG8(0x0008), 0x03 },
+ { CCI_REG8(0x0223), 0x16 },
+ { CCI_REG8(0x0d27), 0x39 },
+ { CCI_REG8(0x0d22), 0x00 },
+ { CCI_REG8(0x03f6), 0x0d },
+ { CCI_REG8(0x0d04), 0x07 },
+ { CCI_REG8(0x03f3), 0x72 },
+ { CCI_REG8(0x03f4), 0xb8 },
+ { CCI_REG8(0x03f5), 0xbc },
+ { CCI_REG8(0x0d02), 0x73 },
+
+ /* auto load start */
+ { CCI_REG8(0x00cb), 0xfc },
+
+ /* OUT 1280x720 */
+ { CCI_REG8(0x0350), 0x01 },
+ { CCI_REG8(0x0353), 0x00 },
+ { CCI_REG8(0x0354), 0x0c },
+ { CCI_REG16(0x034c), 1280 }, /* Width */
+ { CCI_REG8(0x021f), 0x14 },
+
+ /* MIPI */
+ { CCI_REG8(0x0107), 0x05 },
+ { CCI_REG8(0x0117), 0x01 },
+ { CCI_REG8(0x0d81), 0x00 },
+ { CCI_REG8(0x0d84), 0x06 },
+ { CCI_REG8(0x0d85), 0x40 },
+ { CCI_REG8(0x0d86), 0x03 },
+ { CCI_REG8(0x0d87), 0x21 },
+ { CCI_REG8(0x0db3), 0x03 },
+ { CCI_REG8(0x0db4), 0x04 },
+ { CCI_REG8(0x0db5), 0x0d },
+ { CCI_REG8(0x0db6), 0x01 },
+ { CCI_REG8(0x0db8), 0x04 },
+ { CCI_REG8(0x0db9), 0x06 },
+ { CCI_REG8(0x0d93), 0x03 },
+ { CCI_REG8(0x0d94), 0x04 },
+ { CCI_REG8(0x0d95), 0x05 },
+ { CCI_REG8(0x0d99), 0x06 },
+ { CCI_REG8(0x0084), 0x01 },
+ { CCI_REG8(0x0110), 0x01 },
+};
+
+static const struct cci_reg_sequence mode_table_common[] = {
+ { GC05A2_STREAMING_REG, 0x00 },
+ /* system */
+ { CCI_REG8(0x0315), 0xd4 },
+ { CCI_REG8(0x0d06), 0x01 },
+ { CCI_REG8(0x0a70), 0x80 },
+ { CCI_REG8(0x031a), 0x00 },
+ { CCI_REG8(0x0314), 0x00 },
+ { CCI_REG8(0x0130), 0x08 },
+ { CCI_REG8(0x0132), 0x01 },
+ { CCI_REG8(0x0136), 0x38 },
+ { CCI_REG8(0x0137), 0x03 },
+ { CCI_REG8(0x0134), 0x5b },
+ { CCI_REG8(0x031c), 0xe0 },
+ { CCI_REG8(0x0d82), 0x14 },
+ { CCI_REG8(0x0dd1), 0x56 },
+ { CCI_REG8(0x0af4), 0x01 },
+ { CCI_REG8(0x0002), 0x10 },
+ { CCI_REG8(0x00c3), 0x34 },
+ { CCI_REG8(0x00c4), 0x00 },
+ { CCI_REG8(0x00c5), 0x01 },
+ { CCI_REG8(0x0af6), 0x00 },
+ { CCI_REG8(0x0ba0), 0x17 },
+ { CCI_REG8(0x0ba1), 0x00 },
+ { CCI_REG8(0x0ba2), 0x00 },
+ { CCI_REG8(0x0ba3), 0x00 },
+ { CCI_REG8(0x0ba4), 0x03 },
+ { CCI_REG8(0x0ba5), 0x00 },
+ { CCI_REG8(0x0ba6), 0x00 },
+ { CCI_REG8(0x0ba7), 0x00 },
+ { CCI_REG8(0x0ba8), 0x40 },
+ { CCI_REG8(0x0ba9), 0x00 },
+ { CCI_REG8(0x0baa), 0x00 },
+ { CCI_REG8(0x0bab), 0x00 },
+ { CCI_REG8(0x0bac), 0x40 },
+ { CCI_REG8(0x0bad), 0x00 },
+ { CCI_REG8(0x0bae), 0x00 },
+ { CCI_REG8(0x0baf), 0x00 },
+ { CCI_REG8(0x0bb0), 0x02 },
+ { CCI_REG8(0x0bb1), 0x00 },
+ { CCI_REG8(0x0bb2), 0x00 },
+ { CCI_REG8(0x0bb3), 0x00 },
+ { CCI_REG8(0x0bb8), 0x02 },
+ { CCI_REG8(0x0bb9), 0x00 },
+ { CCI_REG8(0x0bba), 0x00 },
+ { CCI_REG8(0x0bbb), 0x00 },
+ { CCI_REG8(0x0a70), 0x80 },
+ { CCI_REG8(0x0a71), 0x00 },
+ { CCI_REG8(0x0a72), 0x00 },
+ { CCI_REG8(0x0a66), 0x00 },
+ { CCI_REG8(0x0a67), 0x80 },
+ { CCI_REG8(0x0a4d), 0x4e },
+ { CCI_REG8(0x0a50), 0x00 },
+ { CCI_REG8(0x0a4f), 0x0c },
+ { CCI_REG8(0x0a66), 0x00 },
+ { CCI_REG8(0x00ca), 0x00 },
+ { CCI_REG8(0x00cc), 0x00 },
+ { CCI_REG8(0x00cd), 0x00 },
+ { CCI_REG8(0x0aa1), 0x00 },
+ { CCI_REG8(0x0aa2), 0xe0 },
+ { CCI_REG8(0x0aa3), 0x00 },
+ { CCI_REG8(0x0aa4), 0x40 },
+ { CCI_REG8(0x0a90), 0x03 },
+ { CCI_REG8(0x0a91), 0x0e },
+ { CCI_REG8(0x0a94), 0x80 },
+ { CCI_REG8(0x0af6), 0x20 },
+ { CCI_REG8(0x0b00), 0x91 },
+ { CCI_REG8(0x0b01), 0x17 },
+ { CCI_REG8(0x0b02), 0x01 },
+ { CCI_REG8(0x0b03), 0x00 },
+ { CCI_REG8(0x0b04), 0x01 },
+ { CCI_REG8(0x0b05), 0x17 },
+ { CCI_REG8(0x0b06), 0x01 },
+ { CCI_REG8(0x0b07), 0x00 },
+ { CCI_REG8(0x0ae9), 0x01 },
+ { CCI_REG8(0x0aea), 0x02 },
+ { CCI_REG8(0x0ae8), 0x53 },
+ { CCI_REG8(0x0ae8), 0x43 },
+ { CCI_REG8(0x0af6), 0x30 },
+ { CCI_REG8(0x0b00), 0x08 },
+ { CCI_REG8(0x0b01), 0x0f },
+ { CCI_REG8(0x0b02), 0x00 },
+ { CCI_REG8(0x0b04), 0x1c },
+ { CCI_REG8(0x0b05), 0x24 },
+ { CCI_REG8(0x0b06), 0x00 },
+ { CCI_REG8(0x0b08), 0x30 },
+ { CCI_REG8(0x0b09), 0x40 },
+ { CCI_REG8(0x0b0a), 0x00 },
+ { CCI_REG8(0x0b0c), 0x0e },
+ { CCI_REG8(0x0b0d), 0x2a },
+ { CCI_REG8(0x0b0e), 0x00 },
+ { CCI_REG8(0x0b10), 0x0e },
+ { CCI_REG8(0x0b11), 0x2b },
+ { CCI_REG8(0x0b12), 0x00 },
+ { CCI_REG8(0x0b14), 0x0e },
+ { CCI_REG8(0x0b15), 0x23 },
+ { CCI_REG8(0x0b16), 0x00 },
+ { CCI_REG8(0x0b18), 0x0e },
+ { CCI_REG8(0x0b19), 0x24 },
+ { CCI_REG8(0x0b1a), 0x00 },
+ { CCI_REG8(0x0b1c), 0x0c },
+ { CCI_REG8(0x0b1d), 0x0c },
+ { CCI_REG8(0x0b1e), 0x00 },
+ { CCI_REG8(0x0b20), 0x03 },
+ { CCI_REG8(0x0b21), 0x03 },
+ { CCI_REG8(0x0b22), 0x00 },
+ { CCI_REG8(0x0b24), 0x0e },
+ { CCI_REG8(0x0b25), 0x0e },
+ { CCI_REG8(0x0b26), 0x00 },
+ { CCI_REG8(0x0b28), 0x03 },
+ { CCI_REG8(0x0b29), 0x03 },
+ { CCI_REG8(0x0b2a), 0x00 },
+ { CCI_REG8(0x0b2c), 0x12 },
+ { CCI_REG8(0x0b2d), 0x12 },
+ { CCI_REG8(0x0b2e), 0x00 },
+ { CCI_REG8(0x0b30), 0x08 },
+ { CCI_REG8(0x0b31), 0x08 },
+ { CCI_REG8(0x0b32), 0x00 },
+ { CCI_REG8(0x0b34), 0x14 },
+ { CCI_REG8(0x0b35), 0x14 },
+ { CCI_REG8(0x0b36), 0x00 },
+ { CCI_REG8(0x0b38), 0x10 },
+ { CCI_REG8(0x0b39), 0x10 },
+ { CCI_REG8(0x0b3a), 0x00 },
+ { CCI_REG8(0x0b3c), 0x16 },
+ { CCI_REG8(0x0b3d), 0x16 },
+ { CCI_REG8(0x0b3e), 0x00 },
+ { CCI_REG8(0x0b40), 0x10 },
+ { CCI_REG8(0x0b41), 0x10 },
+ { CCI_REG8(0x0b42), 0x00 },
+ { CCI_REG8(0x0b44), 0x19 },
+ { CCI_REG8(0x0b45), 0x19 },
+ { CCI_REG8(0x0b46), 0x00 },
+ { CCI_REG8(0x0b48), 0x16 },
+ { CCI_REG8(0x0b49), 0x16 },
+ { CCI_REG8(0x0b4a), 0x00 },
+ { CCI_REG8(0x0b4c), 0x19 },
+ { CCI_REG8(0x0b4d), 0x19 },
+ { CCI_REG8(0x0b4e), 0x00 },
+ { CCI_REG8(0x0b50), 0x16 },
+ { CCI_REG8(0x0b51), 0x16 },
+ { CCI_REG8(0x0b52), 0x00 },
+ { CCI_REG8(0x0b80), 0x01 },
+ { CCI_REG8(0x0b81), 0x00 },
+ { CCI_REG8(0x0b82), 0x00 },
+ { CCI_REG8(0x0b84), 0x00 },
+ { CCI_REG8(0x0b85), 0x00 },
+ { CCI_REG8(0x0b86), 0x00 },
+ { CCI_REG8(0x0b88), 0x01 },
+ { CCI_REG8(0x0b89), 0x6a },
+ { CCI_REG8(0x0b8a), 0x00 },
+ { CCI_REG8(0x0b8c), 0x00 },
+ { CCI_REG8(0x0b8d), 0x01 },
+ { CCI_REG8(0x0b8e), 0x00 },
+ { CCI_REG8(0x0b90), 0x01 },
+ { CCI_REG8(0x0b91), 0xf6 },
+ { CCI_REG8(0x0b92), 0x00 },
+ { CCI_REG8(0x0b94), 0x00 },
+ { CCI_REG8(0x0b95), 0x02 },
+ { CCI_REG8(0x0b96), 0x00 },
+ { CCI_REG8(0x0b98), 0x02 },
+ { CCI_REG8(0x0b99), 0xc4 },
+ { CCI_REG8(0x0b9a), 0x00 },
+ { CCI_REG8(0x0b9c), 0x00 },
+ { CCI_REG8(0x0b9d), 0x03 },
+ { CCI_REG8(0x0b9e), 0x00 },
+ { CCI_REG8(0x0ba0), 0x03 },
+ { CCI_REG8(0x0ba1), 0xd8 },
+ { CCI_REG8(0x0ba2), 0x00 },
+ { CCI_REG8(0x0ba4), 0x00 },
+ { CCI_REG8(0x0ba5), 0x04 },
+ { CCI_REG8(0x0ba6), 0x00 },
+ { CCI_REG8(0x0ba8), 0x05 },
+ { CCI_REG8(0x0ba9), 0x4d },
+ { CCI_REG8(0x0baa), 0x00 },
+ { CCI_REG8(0x0bac), 0x00 },
+ { CCI_REG8(0x0bad), 0x05 },
+ { CCI_REG8(0x0bae), 0x00 },
+ { CCI_REG8(0x0bb0), 0x07 },
+ { CCI_REG8(0x0bb1), 0x3e },
+ { CCI_REG8(0x0bb2), 0x00 },
+ { CCI_REG8(0x0bb4), 0x00 },
+ { CCI_REG8(0x0bb5), 0x06 },
+ { CCI_REG8(0x0bb6), 0x00 },
+ { CCI_REG8(0x0bb8), 0x0a },
+ { CCI_REG8(0x0bb9), 0x1a },
+ { CCI_REG8(0x0bba), 0x00 },
+ { CCI_REG8(0x0bbc), 0x09 },
+ { CCI_REG8(0x0bbd), 0x36 },
+ { CCI_REG8(0x0bbe), 0x00 },
+ { CCI_REG8(0x0bc0), 0x0e },
+ { CCI_REG8(0x0bc1), 0x66 },
+ { CCI_REG8(0x0bc2), 0x00 },
+ { CCI_REG8(0x0bc4), 0x10 },
+ { CCI_REG8(0x0bc5), 0x06 },
+ { CCI_REG8(0x0bc6), 0x00 },
+ { CCI_REG8(0x02c1), 0xe0 },
+ { CCI_REG8(0x0207), 0x04 },
+ { CCI_REG8(0x02c2), 0x10 },
+ { CCI_REG8(0x02c3), 0x74 },
+ { CCI_REG8(0x02c5), 0x09 },
+ { CCI_REG8(0x02c1), 0xe0 },
+ { CCI_REG8(0x0207), 0x04 },
+ { CCI_REG8(0x02c2), 0x10 },
+ { CCI_REG8(0x02c5), 0x09 },
+ { CCI_REG8(0x02c1), 0xe0 },
+ { CCI_REG8(0x0207), 0x04 },
+ { CCI_REG8(0x02c2), 0x10 },
+ { CCI_REG8(0x02c5), 0x09 },
+ { CCI_REG8(0x0aa1), 0x15 },
+ { CCI_REG8(0x0aa2), 0x50 },
+ { CCI_REG8(0x0aa3), 0x00 },
+ { CCI_REG8(0x0aa4), 0x09 },
+ { CCI_REG8(0x0a90), 0x25 },
+ { CCI_REG8(0x0a91), 0x0e },
+ { CCI_REG8(0x0a94), 0x80 },
+
+ /* ISP */
+ { CCI_REG8(0x0050), 0x00 },
+ { CCI_REG8(0x0089), 0x83 },
+ { CCI_REG8(0x005a), 0x40 },
+ { CCI_REG8(0x00c3), 0x35 },
+ { CCI_REG8(0x00c4), 0x80 },
+ { CCI_REG8(0x0080), 0x10 },
+ { CCI_REG8(0x0040), 0x12 },
+ { CCI_REG8(0x0053), 0x0a },
+ { CCI_REG8(0x0054), 0x44 },
+ { CCI_REG8(0x0055), 0x32 },
+ { CCI_REG8(0x0058), 0x89 },
+ { CCI_REG8(0x004a), 0x03 },
+ { CCI_REG8(0x0048), 0xf0 },
+ { CCI_REG8(0x0049), 0x0f },
+ { CCI_REG8(0x0041), 0x20 },
+ { CCI_REG8(0x0043), 0x0a },
+ { CCI_REG8(0x009d), 0x08 },
+ { CCI_REG8(0x0236), 0x40 },
+ { CCI_REG8(0x0204), 0x04 },
+ { CCI_REG8(0x0205), 0x00 },
+ { CCI_REG8(0x02b3), 0x00 },
+ { CCI_REG8(0x02b4), 0x00 },
+ { CCI_REG8(0x009e), 0x01 },
+ { CCI_REG8(0x009f), 0x94 },
+
+ /* auto load REG */
+ { CCI_REG8(0x0aa1), 0x10 },
+ { CCI_REG8(0x0aa2), 0xf8 },
+ { CCI_REG8(0x0aa3), 0x00 },
+ { CCI_REG8(0x0aa4), 0x1f },
+ { CCI_REG8(0x0a90), 0x11 },
+ { CCI_REG8(0x0a91), 0x0e },
+ { CCI_REG8(0x0a94), 0x80 },
+ { CCI_REG8(0x03fe), 0x00 },
+ { CCI_REG8(0x0a90), 0x00 },
+ { CCI_REG8(0x0a70), 0x00 },
+ { CCI_REG8(0x0a67), 0x00 },
+ { CCI_REG8(0x0af4), 0x29 },
+
+ /* DPHY */
+ { CCI_REG8(0x0d80), 0x07 },
+ { CCI_REG8(0x0dd3), 0x18 },
+
+ /* CISCTL_Reset */
+ { CCI_REG8(0x031c), 0x80 },
+ { CCI_REG8(0x03fe), 0x30 },
+ { CCI_REG8(0x0d17), 0x06 },
+ { CCI_REG8(0x03fe), 0x00 },
+ { CCI_REG8(0x0d17), 0x00 },
+ { CCI_REG8(0x031c), 0x93 },
+ { CCI_REG8(0x03fe), 0x00 },
+ { CCI_REG8(0x031c), 0x80 },
+ { CCI_REG8(0x03fe), 0x30 },
+ { CCI_REG8(0x0d17), 0x06 },
+ { CCI_REG8(0x03fe), 0x00 },
+ { CCI_REG8(0x0d17), 0x00 },
+ { CCI_REG8(0x031c), 0x93 },
+};
+
+struct gc05a2_mode {
+ u32 width;
+ u32 height;
+ const struct gc05a2_reg_list reg_list;
+
+ u32 hts; /* Horizontal timining size */
+ u32 vts_def; /* Default vertical timining size */
+ u32 vts_min; /* Min vertical timining size */
+};
+
+/* Declare modes in order, from biggest to smallest height. */
+static const struct gc05a2_mode gc05a2_modes[] = {
+ {
+ /* 2592*1944@30fps */
+ .width = GC05A2_NATIVE_WIDTH,
+ .height = GC05A2_NATIVE_HEIGHT,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_2592x1944),
+ .regs = mode_2592x1944,
+ },
+ .hts = 3664,
+ .vts_def = 2032,
+ .vts_min = 2032,
+ },
+ {
+ /* 1280*720@60fps */
+ .width = 1280,
+ .height = 720,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1280x720),
+ .regs = mode_1280x720,
+ },
+ .hts = 3616,
+ .vts_def = 1032,
+ .vts_min = 1032,
+ },
+};
+
+static inline struct gc05a2 *to_gc05a2(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct gc05a2, sd);
+}
+
+static int gc05a2_power_on(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct gc05a2 *gc05a2 = to_gc05a2(sd);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(gc05a2_supply_name),
+ gc05a2->supplies);
+ if (ret < 0) {
+ dev_err(gc05a2->dev, "failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(gc05a2->xclk);
+ if (ret < 0) {
+ regulator_bulk_disable(ARRAY_SIZE(gc05a2_supply_name),
+ gc05a2->supplies);
+ dev_err(gc05a2->dev, "clk prepare enable failed\n");
+ return ret;
+ }
+
+ fsleep(GC05A2_SLEEP_US);
+
+ gpiod_set_value_cansleep(gc05a2->reset_gpio, 0);
+ fsleep(GC05A2_SLEEP_US);
+
+ return 0;
+}
+
+static int gc05a2_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct gc05a2 *gc05a2 = to_gc05a2(sd);
+
+ clk_disable_unprepare(gc05a2->xclk);
+ gpiod_set_value_cansleep(gc05a2->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(gc05a2_supply_name),
+ gc05a2->supplies);
+
+ return 0;
+}
+
+static int gc05a2_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = GC05A2_MBUS_CODE;
+
+ return 0;
+}
+
+static int gc05a2_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->code != GC05A2_MBUS_CODE)
+ return -EINVAL;
+
+ if (fse->index >= ARRAY_SIZE(gc05a2_modes))
+ return -EINVAL;
+
+ fse->min_width = gc05a2_modes[fse->index].width;
+ fse->max_width = gc05a2_modes[fse->index].width;
+ fse->min_height = gc05a2_modes[fse->index].height;
+ fse->max_height = gc05a2_modes[fse->index].height;
+
+ return 0;
+}
+
+static int gc05a2_update_cur_mode_controls(struct gc05a2 *gc05a2,
+ const struct gc05a2_mode *mode)
+{
+ s64 exposure_max, h_blank;
+ int ret;
+
+ ret = __v4l2_ctrl_modify_range(gc05a2->vblank,
+ mode->vts_min - mode->height,
+ GC05A2_VTS_MAX - mode->height, 1,
+ mode->vts_def - mode->height);
+ if (ret) {
+ dev_err(gc05a2->dev, "VB ctrl range update failed\n");
+ return ret;
+ }
+
+ h_blank = mode->hts - mode->width;
+ ret = __v4l2_ctrl_modify_range(gc05a2->hblank, h_blank, h_blank, 1,
+ h_blank);
+ if (ret) {
+ dev_err(gc05a2->dev, "HB ctrl range update failed\n");
+ return ret;
+ }
+
+ exposure_max = mode->vts_def - GC05A2_EXP_MARGIN;
+ ret = __v4l2_ctrl_modify_range(gc05a2->exposure, GC05A2_EXP_MIN,
+ exposure_max, GC05A2_EXP_STEP,
+ exposure_max);
+ if (ret) {
+ dev_err(gc05a2->dev, "exposure ctrl range update failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void gc05a2_update_pad_format(struct gc05a2 *gc08a3,
+ const struct gc05a2_mode *mode,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->code = GC05A2_MBUS_CODE;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_RAW;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->xfer_func = V4L2_XFER_FUNC_NONE;
+}
+
+static int gc05a2_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct gc05a2 *gc05a2 = to_gc05a2(sd);
+ struct v4l2_mbus_framefmt *mbus_fmt;
+ struct v4l2_rect *crop;
+ const struct gc05a2_mode *mode;
+
+ mode = v4l2_find_nearest_size(gc05a2_modes, ARRAY_SIZE(gc05a2_modes),
+ width, height, fmt->format.width,
+ fmt->format.height);
+
+ /* update crop info to subdev state */
+ crop = v4l2_subdev_state_get_crop(state, 0);
+ crop->width = mode->width;
+ crop->height = mode->height;
+
+ /* update fmt info to subdev state */
+ gc05a2_update_pad_format(gc05a2, mode, &fmt->format);
+ mbus_fmt = v4l2_subdev_state_get_format(state, 0);
+ *mbus_fmt = fmt->format;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+ gc05a2->cur_mode = mode;
+ gc05a2_update_cur_mode_controls(gc05a2, mode);
+
+ return 0;
+}
+
+static int gc05a2_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *v4l2_subdev_state_get_crop(state, 0);
+ break;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = GC05A2_NATIVE_WIDTH;
+ sel->r.height = GC05A2_NATIVE_HEIGHT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int gc05a2_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ .pad = 0,
+ .format = {
+ .code = GC05A2_MBUS_CODE,
+ .width = gc05a2_modes[0].width,
+ .height = gc05a2_modes[0].height,
+ },
+ };
+
+ gc05a2_set_format(sd, state, &fmt);
+
+ return 0;
+}
+
+static int gc05a2_set_ctrl_hflip(struct gc05a2 *gc05a2, u32 ctrl_val)
+{
+ int ret;
+ u64 val;
+
+ ret = cci_read(gc05a2->regmap, GC05A2_FLIP_REG, &val, NULL);
+ if (ret) {
+ dev_err(gc05a2->dev, "read hflip register failed: %d\n", ret);
+ return ret;
+ }
+
+ return cci_update_bits(gc05a2->regmap, GC05A2_FLIP_REG,
+ GC05A2_FLIP_H_MASK,
+ ctrl_val ? GC05A2_FLIP_H_MASK : 0, NULL);
+}
+
+static int gc05a2_set_ctrl_vflip(struct gc05a2 *gc05a2, u32 ctrl_val)
+{
+ int ret;
+ u64 val;
+
+ ret = cci_read(gc05a2->regmap, GC05A2_FLIP_REG, &val, NULL);
+ if (ret) {
+ dev_err(gc05a2->dev, "read vflip register failed: %d\n", ret);
+ return ret;
+ }
+
+ return cci_update_bits(gc05a2->regmap, GC05A2_FLIP_REG,
+ GC05A2_FLIP_V_MASK,
+ ctrl_val ? GC05A2_FLIP_V_MASK : 0, NULL);
+}
+
+static int gc05a2_test_pattern(struct gc05a2 *gc05a2, u32 pattern_menu)
+{
+ u32 pattern;
+ int ret;
+
+ if (pattern_menu) {
+ switch (pattern_menu) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ pattern = pattern_menu << 4;
+ break;
+
+ case 8:
+ pattern = 0;
+ break;
+
+ case 9:
+ pattern = 4;
+ break;
+
+ default:
+ /* Set pattern to 0, it's a safe default. */
+ pattern = 0;
+ break;
+ }
+
+ ret = cci_write(gc05a2->regmap, GC05A2_REG_TEST_PATTERN_IDX,
+ pattern, NULL);
+ if (ret)
+ return ret;
+
+ return cci_write(gc05a2->regmap, GC05A2_REG_TEST_PATTERN_EN,
+ GC05A2_TEST_PATTERN_EN, NULL);
+ } else {
+ return cci_write(gc05a2->regmap, GC05A2_REG_TEST_PATTERN_EN,
+ 0x00, NULL);
+ }
+}
+
+static int gc05a2_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gc05a2 *gc05a2 =
+ container_of(ctrl->handler, struct gc05a2, ctrls);
+ int ret = 0;
+ s64 exposure_max;
+ struct v4l2_subdev_state *state;
+ const struct v4l2_mbus_framefmt *format;
+
+ state = v4l2_subdev_get_locked_active_state(&gc05a2->sd);
+ format = v4l2_subdev_state_get_format(state, 0);
+
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ /* Update max exposure while meeting expected vblanking */
+ exposure_max = format->height + ctrl->val - GC05A2_EXP_MARGIN;
+ __v4l2_ctrl_modify_range(gc05a2->exposure,
+ gc05a2->exposure->minimum,
+ exposure_max, gc05a2->exposure->step,
+ exposure_max);
+ }
+
+ /*
+ * Applying V4L2 control value only happens
+ * when power is on for streaming.
+ */
+ if (!pm_runtime_get_if_active(gc05a2->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ ret = cci_write(gc05a2->regmap, GC05A2_EXP_REG,
+ ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = cci_write(gc05a2->regmap, GC05A2_AGAIN_REG,
+ ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_VBLANK:
+ ret = cci_write(gc05a2->regmap, GC05A2_FRAME_LENGTH_REG,
+ gc05a2->cur_mode->height + ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_HFLIP:
+ ret = gc05a2_set_ctrl_hflip(gc05a2, ctrl->val);
+ break;
+
+ case V4L2_CID_VFLIP:
+ ret = gc05a2_set_ctrl_vflip(gc05a2, ctrl->val);
+ break;
+
+ case V4L2_CID_TEST_PATTERN:
+ ret = gc05a2_test_pattern(gc05a2, ctrl->val);
+ break;
+
+ default:
+ break;
+ }
+
+ pm_runtime_put(gc05a2->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops gc05a2_ctrl_ops = {
+ .s_ctrl = gc05a2_set_ctrl,
+};
+
+static int gc05a2_identify_module(struct gc05a2 *gc05a2)
+{
+ u64 val;
+ int ret;
+
+ if (gc05a2->identified)
+ return 0;
+
+ ret = cci_read(gc05a2->regmap, GC05A2_REG_CHIP_ID, &val, NULL);
+ if (ret)
+ return ret;
+
+ if (val != GC05A2_CHIP_ID) {
+ dev_err(gc05a2->dev, "chip id mismatch: 0x%x!=0x%llx",
+ GC05A2_CHIP_ID, val);
+ return -ENXIO;
+ }
+
+ gc05a2->identified = true;
+
+ return 0;
+}
+
+static int gc05a2_start_streaming(struct gc05a2 *gc05a2)
+{
+ const struct gc05a2_mode *mode;
+ const struct gc05a2_reg_list *reg_list;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(gc05a2->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = gc05a2_identify_module(gc05a2);
+ if (ret)
+ goto err_rpm_put;
+
+ ret = cci_multi_reg_write(gc05a2->regmap,
+ mode_table_common,
+ ARRAY_SIZE(mode_table_common), NULL);
+ if (ret)
+ goto err_rpm_put;
+
+ mode = gc05a2->cur_mode;
+ reg_list = &mode->reg_list;
+
+ ret = cci_multi_reg_write(gc05a2->regmap,
+ reg_list->regs, reg_list->num_of_regs, NULL);
+ if (ret < 0)
+ goto err_rpm_put;
+
+ ret = __v4l2_ctrl_handler_setup(&gc05a2->ctrls);
+ if (ret < 0) {
+ dev_err(gc05a2->dev, "could not sync v4l2 controls\n");
+ goto err_rpm_put;
+ }
+
+ ret = cci_write(gc05a2->regmap, GC05A2_STREAMING_REG, 1, NULL);
+ if (ret < 0) {
+ dev_err(gc05a2->dev, "write STREAMING_REG failed: %d\n", ret);
+ goto err_rpm_put;
+ }
+
+ return 0;
+
+err_rpm_put:
+ pm_runtime_put(gc05a2->dev);
+ return ret;
+}
+
+static int gc05a2_stop_streaming(struct gc05a2 *gc05a2)
+{
+ int ret;
+
+ ret = cci_write(gc05a2->regmap, GC05A2_STREAMING_REG, 0, NULL);
+ if (ret < 0)
+ dev_err(gc05a2->dev, "could not sent stop streaming %d\n", ret);
+
+ pm_runtime_put(gc05a2->dev);
+ return ret;
+}
+
+static int gc05a2_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct gc05a2 *gc05a2 = to_gc05a2(subdev);
+ struct v4l2_subdev_state *state;
+ int ret;
+
+ state = v4l2_subdev_lock_and_get_active_state(subdev);
+
+ if (enable)
+ ret = gc05a2_start_streaming(gc05a2);
+ else
+ ret = gc05a2_stop_streaming(gc05a2);
+
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops gc05a2_video_ops = {
+ .s_stream = gc05a2_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops gc05a2_subdev_pad_ops = {
+ .enum_mbus_code = gc05a2_enum_mbus_code,
+ .enum_frame_size = gc05a2_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = gc05a2_set_format,
+ .get_selection = gc05a2_get_selection,
+};
+
+static const struct v4l2_subdev_core_ops gc05a2_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_ops gc05a2_subdev_ops = {
+ .core = &gc05a2_core_ops,
+ .video = &gc05a2_video_ops,
+ .pad = &gc05a2_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops gc05a2_internal_ops = {
+ .init_state = gc05a2_init_state,
+};
+
+static int gc05a2_get_regulators(struct device *dev, struct gc05a2 *gc05a2)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(gc05a2_supply_name); i++)
+ gc05a2->supplies[i].supply = gc05a2_supply_name[i];
+
+ return devm_regulator_bulk_get(dev, ARRAY_SIZE(gc05a2_supply_name),
+ gc05a2->supplies);
+}
+
+static int gc05a2_parse_fwnode(struct gc05a2 *gc05a2)
+{
+ struct fwnode_handle *endpoint;
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY,
+ };
+ int ret;
+ struct device *dev = gc05a2->dev;
+
+ endpoint =
+ fwnode_graph_get_endpoint_by_id(dev_fwnode(dev), 0, 0,
+ FWNODE_GRAPH_ENDPOINT_NEXT);
+ if (!endpoint)
+ return dev_err_probe(dev, -EINVAL, "Missing endpoint node\n");
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &bus_cfg);
+ if (ret) {
+ dev_err_probe(dev, ret, "parsing endpoint node failed\n");
+ goto done;
+ }
+
+ ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies,
+ bus_cfg.nr_of_link_frequencies,
+ gc05a2_link_freq_menu_items,
+ ARRAY_SIZE(gc05a2_link_freq_menu_items),
+ &gc05a2->link_freq_bitmap);
+ if (ret)
+ goto done;
+
+done:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+ fwnode_handle_put(endpoint);
+ return ret;
+}
+
+static u64 gc05a2_to_pixel_rate(u32 f_index)
+{
+ u64 pixel_rate =
+ gc05a2_link_freq_menu_items[f_index] * 2 * GC05A2_DATA_LANES;
+
+ return div_u64(pixel_rate, GC05A2_RGB_DEPTH);
+}
+
+static int gc05a2_init_controls(struct gc05a2 *gc05a2)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&gc05a2->sd);
+ const struct gc05a2_mode *mode = &gc05a2_modes[0];
+ const struct v4l2_ctrl_ops *ops = &gc05a2_ctrl_ops;
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ s64 exposure_max, h_blank;
+ int ret;
+
+ ctrl_hdlr = &gc05a2->ctrls;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9);
+ if (ret)
+ return ret;
+
+ gc05a2->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ gc05a2->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_cluster(2, &gc05a2->hflip);
+
+ gc05a2->link_freq =
+ v4l2_ctrl_new_int_menu(ctrl_hdlr,
+ &gc05a2_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(gc05a2_link_freq_menu_items) - 1,
+ 0,
+ gc05a2_link_freq_menu_items);
+ if (gc05a2->link_freq)
+ gc05a2->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ gc05a2->pixel_rate =
+ v4l2_ctrl_new_std(ctrl_hdlr,
+ &gc05a2_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, 0,
+ gc05a2_to_pixel_rate(0),
+ 1,
+ gc05a2_to_pixel_rate(0));
+
+ gc05a2->vblank =
+ v4l2_ctrl_new_std(ctrl_hdlr,
+ &gc05a2_ctrl_ops, V4L2_CID_VBLANK,
+ mode->vts_min - mode->height,
+ GC05A2_VTS_MAX - mode->height, 1,
+ mode->vts_def - mode->height);
+
+ h_blank = mode->hts - mode->width;
+ gc05a2->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops,
+ V4L2_CID_HBLANK, h_blank, h_blank, 1,
+ h_blank);
+ if (gc05a2->hblank)
+ gc05a2->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, GC05A2_AGAIN_MIN,
+ GC05A2_AGAIN_MAX, GC05A2_AGAIN_STEP,
+ GC05A2_AGAIN_MIN);
+
+ exposure_max = mode->vts_def - GC05A2_EXP_MARGIN;
+ gc05a2->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &gc05a2_ctrl_ops,
+ V4L2_CID_EXPOSURE, GC05A2_EXP_MIN,
+ exposure_max, GC05A2_EXP_STEP,
+ exposure_max);
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &gc05a2_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(gc05a2_test_pattern_menu) - 1,
+ 0, 0, gc05a2_test_pattern_menu);
+
+ /* register properties to fwnode (e.g. rotation, orientation) */
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto error_ctrls;
+
+ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, ops, &props);
+ if (ret)
+ goto error_ctrls;
+
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ goto error_ctrls;
+ }
+
+ gc05a2->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+
+error_ctrls:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+
+ return ret;
+}
+
+static int gc05a2_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct gc05a2 *gc05a2;
+ int ret;
+
+ gc05a2 = devm_kzalloc(dev, sizeof(*gc05a2), GFP_KERNEL);
+ if (!gc05a2)
+ return -ENOMEM;
+
+ gc05a2->dev = dev;
+
+ ret = gc05a2_parse_fwnode(gc05a2);
+ if (ret)
+ return ret;
+
+ gc05a2->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(gc05a2->regmap))
+ return dev_err_probe(dev, PTR_ERR(gc05a2->regmap),
+ "failed to init CCI\n");
+
+ gc05a2->xclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(gc05a2->xclk))
+ return dev_err_probe(dev, PTR_ERR(gc05a2->xclk),
+ "failed to get xclk\n");
+
+ ret = clk_set_rate(gc05a2->xclk, GC05A2_DEFAULT_CLK_FREQ);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to set xclk frequency\n");
+
+ ret = gc05a2_get_regulators(dev, gc05a2);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to get regulators\n");
+
+ gc05a2->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(gc05a2->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(gc05a2->reset_gpio),
+ "failed to get gpio\n");
+
+ v4l2_i2c_subdev_init(&gc05a2->sd, client, &gc05a2_subdev_ops);
+ gc05a2->sd.internal_ops = &gc05a2_internal_ops;
+ gc05a2->cur_mode = &gc05a2_modes[0];
+
+ ret = gc05a2_init_controls(gc05a2);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to init controls\n");
+
+ gc05a2->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+ gc05a2->pad.flags = MEDIA_PAD_FL_SOURCE;
+ gc05a2->sd.dev = &client->dev;
+ gc05a2->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ ret = media_entity_pads_init(&gc05a2->sd.entity, 1, &gc05a2->pad);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "could not register media entity\n");
+ goto err_v4l2_ctrl_handler_free;
+ }
+
+ gc05a2->sd.state_lock = gc05a2->ctrls.lock;
+ ret = v4l2_subdev_init_finalize(&gc05a2->sd);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "v4l2 subdev init error\n");
+ goto err_media_entity_cleanup;
+ }
+
+ pm_runtime_enable(gc05a2->dev);
+ pm_runtime_set_autosuspend_delay(gc05a2->dev, 1000);
+ pm_runtime_use_autosuspend(gc05a2->dev);
+ pm_runtime_idle(gc05a2->dev);
+
+ ret = v4l2_async_register_subdev_sensor(&gc05a2->sd);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "could not register v4l2 device\n");
+ goto err_rpm;
+ }
+
+ return 0;
+
+err_rpm:
+ pm_runtime_disable(gc05a2->dev);
+ v4l2_subdev_cleanup(&gc05a2->sd);
+
+err_media_entity_cleanup:
+ media_entity_cleanup(&gc05a2->sd.entity);
+
+err_v4l2_ctrl_handler_free:
+ v4l2_ctrl_handler_free(&gc05a2->ctrls);
+
+ return ret;
+}
+
+static void gc05a2_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct gc05a2 *gc05a2 = to_gc05a2(sd);
+
+ v4l2_async_unregister_subdev(&gc05a2->sd);
+ v4l2_subdev_cleanup(sd);
+ media_entity_cleanup(&gc05a2->sd.entity);
+ v4l2_ctrl_handler_free(&gc05a2->ctrls);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ gc05a2_power_off(gc05a2->dev);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct of_device_id gc05a2_of_match[] = {
+ { .compatible = "galaxycore,gc05a2" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, gc05a2_of_match);
+
+static DEFINE_RUNTIME_DEV_PM_OPS(gc05a2_pm_ops,
+ gc05a2_power_off,
+ gc05a2_power_on,
+ NULL);
+
+static struct i2c_driver gc05a2_i2c_driver = {
+ .driver = {
+ .of_match_table = gc05a2_of_match,
+ .pm = pm_ptr(&gc05a2_pm_ops),
+ .name = "gc05a2",
+ },
+ .probe = gc05a2_probe,
+ .remove = gc05a2_remove,
+};
+module_i2c_driver(gc05a2_i2c_driver);
+
+MODULE_DESCRIPTION("GalaxyCore gc05a2 Camera driver");
+MODULE_AUTHOR("Zhi Mao <zhi.mao@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/gc08a3.c b/drivers/media/i2c/gc08a3.c
new file mode 100644
index 000000000000..7680d807e7a5
--- /dev/null
+++ b/drivers/media/i2c/gc08a3.c
@@ -0,0 +1,1339 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Driver for GalaxyCore gc08a3 image sensor
+ *
+ * Copyright 2024 MediaTek
+ *
+ * Zhi Mao <zhi.mao@mediatek.com>
+ */
+#include <linux/array_size.h>
+#include <linux/bits.h>
+#include <linux/clk.h>
+#include <linux/container_of.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/math64.h>
+#include <linux/mod_devicetable.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/units.h>
+
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define GC08A3_REG_TEST_PATTERN_EN CCI_REG8(0x008c)
+#define GC08A3_REG_TEST_PATTERN_IDX CCI_REG8(0x008d)
+#define GC08A3_TEST_PATTERN_EN 0x01
+
+#define GC08A3_STREAMING_REG CCI_REG8(0x0100)
+
+#define GC08A3_FLIP_REG CCI_REG8(0x0101)
+#define GC08A3_FLIP_H_MASK BIT(0)
+#define GC08A3_FLIP_V_MASK BIT(1)
+
+#define GC08A3_EXP_REG CCI_REG16(0x0202)
+#define GC08A3_EXP_MARGIN 16
+#define GC08A3_EXP_MIN 4
+#define GC08A3_EXP_STEP 1
+
+#define GC08A3_AGAIN_REG CCI_REG16(0x0204)
+#define GC08A3_AGAIN_MIN 1024
+#define GC08A3_AGAIN_MAX (1024 * 16)
+#define GC08A3_AGAIN_STEP 1
+
+#define GC08A3_FRAME_LENGTH_REG CCI_REG16(0x0340)
+#define GC08A3_VTS_MAX 0xfff0
+
+#define GC08A3_REG_CHIP_ID CCI_REG16(0x03f0)
+#define GC08A3_CHIP_ID 0x08a3
+
+#define GC08A3_NATIVE_WIDTH 3264
+#define GC08A3_NATIVE_HEIGHT 2448
+
+#define GC08A3_DEFAULT_CLK_FREQ (24 * HZ_PER_MHZ)
+#define GC08A3_MBUS_CODE MEDIA_BUS_FMT_SRGGB10_1X10
+#define GC08A3_DATA_LANES 4
+
+#define GC08A3_RGB_DEPTH 10
+
+#define GC08A3_SLEEP_US (2 * USEC_PER_MSEC)
+
+static const char *const gc08a3_test_pattern_menu[] = {
+ "No Pattern", "Solid Black", "Colour Bar", "Solid White",
+ "Solid Red", "Solid Green", "Solid Blue", "Solid Yellow",
+};
+
+static const s64 gc08a3_link_freq_menu_items[] = {
+ (336 * HZ_PER_MHZ),
+ (207 * HZ_PER_MHZ),
+};
+
+static const char *const gc08a3_supply_name[] = {
+ "avdd",
+ "dvdd",
+ "dovdd",
+};
+
+struct gc08a3 {
+ struct device *dev;
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ struct clk *xclk;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(gc08a3_supply_name)];
+ struct gpio_desc *reset_gpio;
+
+ struct v4l2_ctrl_handler ctrls;
+ struct v4l2_ctrl *pixel_rate;
+ struct v4l2_ctrl *link_freq;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
+
+ struct regmap *regmap;
+ unsigned long link_freq_bitmap;
+ const struct gc08a3_mode *cur_mode;
+};
+
+struct gc08a3_reg_list {
+ u32 num_of_regs;
+ const struct cci_reg_sequence *regs;
+};
+
+static const struct cci_reg_sequence mode_3264x2448[] = {
+ /* system */
+ { CCI_REG8(0x0336), 0x70 },
+ { CCI_REG8(0x0383), 0xbb },
+ { CCI_REG8(0x0344), 0x00 },
+ { CCI_REG8(0x0345), 0x06 },
+ { CCI_REG8(0x0346), 0x00 },
+ { CCI_REG8(0x0347), 0x04 },
+ { CCI_REG8(0x0348), 0x0c },
+ { CCI_REG8(0x0349), 0xd0 },
+ { CCI_REG8(0x034a), 0x09 },
+ { CCI_REG8(0x034b), 0x9c },
+ { CCI_REG8(0x0202), 0x09 },
+ { CCI_REG8(0x0203), 0x04 },
+ { CCI_REG8(0x0340), 0x09 },
+ { CCI_REG8(0x0341), 0xf4 },
+ { CCI_REG8(0x0342), 0x07 },
+ { CCI_REG8(0x0343), 0x1c },
+
+ { CCI_REG8(0x0226), 0x00 },
+ { CCI_REG8(0x0227), 0x28 },
+ { CCI_REG8(0x0e38), 0x49 },
+ { CCI_REG8(0x0210), 0x13 },
+ { CCI_REG8(0x0218), 0x00 },
+ { CCI_REG8(0x0241), 0x88 },
+ { CCI_REG8(0x0392), 0x60 },
+
+ /* ISP */
+ { CCI_REG8(0x00a2), 0x00 },
+ { CCI_REG8(0x00a3), 0x00 },
+ { CCI_REG8(0x00ab), 0x00 },
+ { CCI_REG8(0x00ac), 0x00 },
+
+ /* GAIN */
+ { CCI_REG8(0x0204), 0x04 },
+ { CCI_REG8(0x0205), 0x00 },
+ { CCI_REG8(0x0050), 0x5c },
+ { CCI_REG8(0x0051), 0x44 },
+
+ /* out window */
+ { CCI_REG8(0x009a), 0x66 },
+ { CCI_REG8(0x0351), 0x00 },
+ { CCI_REG8(0x0352), 0x06 },
+ { CCI_REG8(0x0353), 0x00 },
+ { CCI_REG8(0x0354), 0x08 },
+ { CCI_REG8(0x034c), 0x0c },
+ { CCI_REG8(0x034d), 0xc0 },
+ { CCI_REG8(0x034e), 0x09 },
+ { CCI_REG8(0x034f), 0x90 },
+
+ /* MIPI */
+ { CCI_REG8(0x0114), 0x03 },
+ { CCI_REG8(0x0180), 0x65 },
+ { CCI_REG8(0x0181), 0xf0 },
+ { CCI_REG8(0x0185), 0x01 },
+ { CCI_REG8(0x0115), 0x30 },
+ { CCI_REG8(0x011b), 0x12 },
+ { CCI_REG8(0x011c), 0x12 },
+ { CCI_REG8(0x0121), 0x06 },
+ { CCI_REG8(0x0122), 0x06 },
+ { CCI_REG8(0x0123), 0x15 },
+ { CCI_REG8(0x0124), 0x01 },
+ { CCI_REG8(0x0125), 0x0b },
+ { CCI_REG8(0x0126), 0x08 },
+ { CCI_REG8(0x0129), 0x06 },
+ { CCI_REG8(0x012a), 0x08 },
+ { CCI_REG8(0x012b), 0x08 },
+
+ { CCI_REG8(0x0a73), 0x60 },
+ { CCI_REG8(0x0a70), 0x11 },
+ { CCI_REG8(0x0313), 0x80 },
+ { CCI_REG8(0x0aff), 0x00 },
+ { CCI_REG8(0x0a70), 0x00 },
+ { CCI_REG8(0x00a4), 0x80 },
+ { CCI_REG8(0x0316), 0x01 },
+ { CCI_REG8(0x0a67), 0x00 },
+ { CCI_REG8(0x0084), 0x10 },
+ { CCI_REG8(0x0102), 0x09 },
+};
+
+static const struct cci_reg_sequence mode_1920x1080[] = {
+ /* system */
+ { CCI_REG8(0x0336), 0x45 },
+ { CCI_REG8(0x0383), 0x8b },
+ { CCI_REG8(0x0344), 0x02 },
+ { CCI_REG8(0x0345), 0xa6 },
+ { CCI_REG8(0x0346), 0x02 },
+ { CCI_REG8(0x0347), 0xb0 },
+ { CCI_REG8(0x0348), 0x07 },
+ { CCI_REG8(0x0349), 0x90 },
+ { CCI_REG8(0x034a), 0x04 },
+ { CCI_REG8(0x034b), 0x44 },
+ { CCI_REG8(0x0202), 0x03 },
+ { CCI_REG8(0x0203), 0x00 },
+ { CCI_REG8(0x0340), 0x04 },
+ { CCI_REG8(0x0341), 0xfc },
+ { CCI_REG8(0x0342), 0x07 },
+ { CCI_REG8(0x0343), 0x1c },
+ { CCI_REG8(0x0226), 0x00 },
+ { CCI_REG8(0x0227), 0x88 },
+ { CCI_REG8(0x0e38), 0x49 },
+ { CCI_REG8(0x0210), 0x13 },
+ { CCI_REG8(0x0218), 0x00 },
+ { CCI_REG8(0x0241), 0x88 },
+ { CCI_REG8(0x0392), 0x60 },
+
+ /* ISP */
+ { CCI_REG8(0x00a2), 0xac },
+ { CCI_REG8(0x00a3), 0x02 },
+ { CCI_REG8(0x00ab), 0xa0 },
+ { CCI_REG8(0x00ac), 0x02 },
+
+ /* GAIN */
+ { CCI_REG8(0x0204), 0x04 },
+ { CCI_REG8(0x0205), 0x00 },
+ { CCI_REG8(0x0050), 0x38 },
+ { CCI_REG8(0x0051), 0x20 },
+
+ /* out window */
+ { CCI_REG8(0x009a), 0x66 },
+ { CCI_REG8(0x0351), 0x00 },
+ { CCI_REG8(0x0352), 0x06 },
+ { CCI_REG8(0x0353), 0x00 },
+ { CCI_REG8(0x0354), 0x08 },
+ { CCI_REG8(0x034c), 0x07 },
+ { CCI_REG8(0x034d), 0x80 },
+ { CCI_REG8(0x034e), 0x04 },
+ { CCI_REG8(0x034f), 0x38 },
+
+ /* MIPI */
+ { CCI_REG8(0x0114), 0x03 },
+ { CCI_REG8(0x0180), 0x65 },
+ { CCI_REG8(0x0181), 0xf0 },
+ { CCI_REG8(0x0185), 0x01 },
+ { CCI_REG8(0x0115), 0x30 },
+ { CCI_REG8(0x011b), 0x12 },
+ { CCI_REG8(0x011c), 0x12 },
+ { CCI_REG8(0x0121), 0x02 },
+ { CCI_REG8(0x0122), 0x03 },
+ { CCI_REG8(0x0123), 0x0c },
+ { CCI_REG8(0x0124), 0x00 },
+ { CCI_REG8(0x0125), 0x09 },
+ { CCI_REG8(0x0126), 0x06 },
+ { CCI_REG8(0x0129), 0x04 },
+ { CCI_REG8(0x012a), 0x03 },
+ { CCI_REG8(0x012b), 0x06 },
+
+ { CCI_REG8(0x0a73), 0x60 },
+ { CCI_REG8(0x0a70), 0x11 },
+ { CCI_REG8(0x0313), 0x80 },
+ { CCI_REG8(0x0aff), 0x00 },
+ { CCI_REG8(0x0a70), 0x00 },
+ { CCI_REG8(0x00a4), 0x80 },
+ { CCI_REG8(0x0316), 0x01 },
+ { CCI_REG8(0x0a67), 0x00 },
+ { CCI_REG8(0x0084), 0x10 },
+ { CCI_REG8(0x0102), 0x09 },
+};
+
+static const struct cci_reg_sequence mode_table_common[] = {
+ { GC08A3_STREAMING_REG, 0x00 },
+ /* system */
+ { CCI_REG8(0x031c), 0x60 },
+ { CCI_REG8(0x0337), 0x04 },
+ { CCI_REG8(0x0335), 0x51 },
+ { CCI_REG8(0x0336), 0x70 },
+ { CCI_REG8(0x0383), 0xbb },
+ { CCI_REG8(0x031a), 0x00 },
+ { CCI_REG8(0x0321), 0x10 },
+ { CCI_REG8(0x0327), 0x03 },
+ { CCI_REG8(0x0325), 0x40 },
+ { CCI_REG8(0x0326), 0x23 },
+ { CCI_REG8(0x0314), 0x11 },
+ { CCI_REG8(0x0315), 0xd6 },
+ { CCI_REG8(0x0316), 0x01 },
+ { CCI_REG8(0x0334), 0x40 },
+ { CCI_REG8(0x0324), 0x42 },
+ { CCI_REG8(0x031c), 0x00 },
+ { CCI_REG8(0x031c), 0x9f },
+ { CCI_REG8(0x039a), 0x13 },
+ { CCI_REG8(0x0084), 0x30 },
+ { CCI_REG8(0x02b3), 0x08 },
+ { CCI_REG8(0x0057), 0x0c },
+ { CCI_REG8(0x05c3), 0x50 },
+ { CCI_REG8(0x0311), 0x90 },
+ { CCI_REG8(0x05a0), 0x02 },
+ { CCI_REG8(0x0074), 0x0a },
+ { CCI_REG8(0x0059), 0x11 },
+ { CCI_REG8(0x0070), 0x05 },
+ { CCI_REG8(0x0101), 0x00 },
+
+ /* analog */
+ { CCI_REG8(0x0344), 0x00 },
+ { CCI_REG8(0x0345), 0x06 },
+ { CCI_REG8(0x0346), 0x00 },
+ { CCI_REG8(0x0347), 0x04 },
+ { CCI_REG8(0x0348), 0x0c },
+ { CCI_REG8(0x0349), 0xd0 },
+ { CCI_REG8(0x034a), 0x09 },
+ { CCI_REG8(0x034b), 0x9c },
+ { CCI_REG8(0x0202), 0x09 },
+ { CCI_REG8(0x0203), 0x04 },
+
+ { CCI_REG8(0x0219), 0x05 },
+ { CCI_REG8(0x0226), 0x00 },
+ { CCI_REG8(0x0227), 0x28 },
+ { CCI_REG8(0x0e0a), 0x00 },
+ { CCI_REG8(0x0e0b), 0x00 },
+ { CCI_REG8(0x0e24), 0x04 },
+ { CCI_REG8(0x0e25), 0x04 },
+ { CCI_REG8(0x0e26), 0x00 },
+ { CCI_REG8(0x0e27), 0x10 },
+ { CCI_REG8(0x0e01), 0x74 },
+ { CCI_REG8(0x0e03), 0x47 },
+ { CCI_REG8(0x0e04), 0x33 },
+ { CCI_REG8(0x0e05), 0x44 },
+ { CCI_REG8(0x0e06), 0x44 },
+ { CCI_REG8(0x0e0c), 0x1e },
+ { CCI_REG8(0x0e17), 0x3a },
+ { CCI_REG8(0x0e18), 0x3c },
+ { CCI_REG8(0x0e19), 0x40 },
+ { CCI_REG8(0x0e1a), 0x42 },
+ { CCI_REG8(0x0e28), 0x21 },
+ { CCI_REG8(0x0e2b), 0x68 },
+ { CCI_REG8(0x0e2c), 0x0d },
+ { CCI_REG8(0x0e2d), 0x08 },
+ { CCI_REG8(0x0e34), 0xf4 },
+ { CCI_REG8(0x0e35), 0x44 },
+ { CCI_REG8(0x0e36), 0x07 },
+ { CCI_REG8(0x0e38), 0x49 },
+ { CCI_REG8(0x0210), 0x13 },
+ { CCI_REG8(0x0218), 0x00 },
+ { CCI_REG8(0x0241), 0x88 },
+ { CCI_REG8(0x0e32), 0x00 },
+ { CCI_REG8(0x0e33), 0x18 },
+ { CCI_REG8(0x0e42), 0x03 },
+ { CCI_REG8(0x0e43), 0x80 },
+ { CCI_REG8(0x0e44), 0x04 },
+ { CCI_REG8(0x0e45), 0x00 },
+ { CCI_REG8(0x0e4f), 0x04 },
+ { CCI_REG8(0x057a), 0x20 },
+ { CCI_REG8(0x0381), 0x7c },
+ { CCI_REG8(0x0382), 0x9b },
+ { CCI_REG8(0x0384), 0xfb },
+ { CCI_REG8(0x0389), 0x38 },
+ { CCI_REG8(0x038a), 0x03 },
+ { CCI_REG8(0x0390), 0x6a },
+ { CCI_REG8(0x0391), 0x0b },
+ { CCI_REG8(0x0392), 0x60 },
+ { CCI_REG8(0x0393), 0xc1 },
+ { CCI_REG8(0x0396), 0xff },
+ { CCI_REG8(0x0398), 0x62 },
+
+ /* cisctl reset */
+ { CCI_REG8(0x031c), 0x80 },
+ { CCI_REG8(0x03fe), 0x10 },
+ { CCI_REG8(0x03fe), 0x00 },
+ { CCI_REG8(0x031c), 0x9f },
+ { CCI_REG8(0x03fe), 0x00 },
+ { CCI_REG8(0x03fe), 0x00 },
+ { CCI_REG8(0x03fe), 0x00 },
+ { CCI_REG8(0x03fe), 0x00 },
+ { CCI_REG8(0x031c), 0x80 },
+ { CCI_REG8(0x03fe), 0x10 },
+ { CCI_REG8(0x03fe), 0x00 },
+ { CCI_REG8(0x031c), 0x9f },
+ { CCI_REG8(0x0360), 0x01 },
+ { CCI_REG8(0x0360), 0x00 },
+ { CCI_REG8(0x0316), 0x09 },
+ { CCI_REG8(0x0a67), 0x80 },
+ { CCI_REG8(0x0313), 0x00 },
+ { CCI_REG8(0x0a53), 0x0e },
+ { CCI_REG8(0x0a65), 0x17 },
+ { CCI_REG8(0x0a68), 0xa1 },
+ { CCI_REG8(0x0a58), 0x00 },
+ { CCI_REG8(0x0ace), 0x0c },
+ { CCI_REG8(0x00a4), 0x00 },
+ { CCI_REG8(0x00a5), 0x01 },
+ { CCI_REG8(0x00a7), 0x09 },
+ { CCI_REG8(0x00a8), 0x9c },
+ { CCI_REG8(0x00a9), 0x0c },
+ { CCI_REG8(0x00aa), 0xd0 },
+ { CCI_REG8(0x0a8a), 0x00 },
+ { CCI_REG8(0x0a8b), 0xe0 },
+ { CCI_REG8(0x0a8c), 0x13 },
+ { CCI_REG8(0x0a8d), 0xe8 },
+ { CCI_REG8(0x0a90), 0x0a },
+ { CCI_REG8(0x0a91), 0x10 },
+ { CCI_REG8(0x0a92), 0xf8 },
+ { CCI_REG8(0x0a71), 0xf2 },
+ { CCI_REG8(0x0a72), 0x12 },
+ { CCI_REG8(0x0a73), 0x64 },
+ { CCI_REG8(0x0a75), 0x41 },
+ { CCI_REG8(0x0a70), 0x07 },
+ { CCI_REG8(0x0313), 0x80 },
+
+ /* ISP */
+ { CCI_REG8(0x00a0), 0x01 },
+ { CCI_REG8(0x0080), 0xd2 },
+ { CCI_REG8(0x0081), 0x3f },
+ { CCI_REG8(0x0087), 0x51 },
+ { CCI_REG8(0x0089), 0x03 },
+ { CCI_REG8(0x009b), 0x40 },
+ { CCI_REG8(0x05a0), 0x82 },
+ { CCI_REG8(0x05ac), 0x00 },
+ { CCI_REG8(0x05ad), 0x01 },
+ { CCI_REG8(0x05ae), 0x00 },
+ { CCI_REG8(0x0800), 0x0a },
+ { CCI_REG8(0x0801), 0x14 },
+ { CCI_REG8(0x0802), 0x28 },
+ { CCI_REG8(0x0803), 0x34 },
+ { CCI_REG8(0x0804), 0x0e },
+ { CCI_REG8(0x0805), 0x33 },
+ { CCI_REG8(0x0806), 0x03 },
+ { CCI_REG8(0x0807), 0x8a },
+ { CCI_REG8(0x0808), 0x50 },
+ { CCI_REG8(0x0809), 0x00 },
+ { CCI_REG8(0x080a), 0x34 },
+ { CCI_REG8(0x080b), 0x03 },
+ { CCI_REG8(0x080c), 0x26 },
+ { CCI_REG8(0x080d), 0x03 },
+ { CCI_REG8(0x080e), 0x18 },
+ { CCI_REG8(0x080f), 0x03 },
+ { CCI_REG8(0x0810), 0x10 },
+ { CCI_REG8(0x0811), 0x03 },
+ { CCI_REG8(0x0812), 0x00 },
+ { CCI_REG8(0x0813), 0x00 },
+ { CCI_REG8(0x0814), 0x01 },
+ { CCI_REG8(0x0815), 0x00 },
+ { CCI_REG8(0x0816), 0x01 },
+ { CCI_REG8(0x0817), 0x00 },
+ { CCI_REG8(0x0818), 0x00 },
+ { CCI_REG8(0x0819), 0x0a },
+ { CCI_REG8(0x081a), 0x01 },
+ { CCI_REG8(0x081b), 0x6c },
+ { CCI_REG8(0x081c), 0x00 },
+ { CCI_REG8(0x081d), 0x0b },
+ { CCI_REG8(0x081e), 0x02 },
+ { CCI_REG8(0x081f), 0x00 },
+ { CCI_REG8(0x0820), 0x00 },
+ { CCI_REG8(0x0821), 0x0c },
+ { CCI_REG8(0x0822), 0x02 },
+ { CCI_REG8(0x0823), 0xd9 },
+ { CCI_REG8(0x0824), 0x00 },
+ { CCI_REG8(0x0825), 0x0d },
+ { CCI_REG8(0x0826), 0x03 },
+ { CCI_REG8(0x0827), 0xf0 },
+ { CCI_REG8(0x0828), 0x00 },
+ { CCI_REG8(0x0829), 0x0e },
+ { CCI_REG8(0x082a), 0x05 },
+ { CCI_REG8(0x082b), 0x94 },
+ { CCI_REG8(0x082c), 0x09 },
+ { CCI_REG8(0x082d), 0x6e },
+ { CCI_REG8(0x082e), 0x07 },
+ { CCI_REG8(0x082f), 0xe6 },
+ { CCI_REG8(0x0830), 0x10 },
+ { CCI_REG8(0x0831), 0x0e },
+ { CCI_REG8(0x0832), 0x0b },
+ { CCI_REG8(0x0833), 0x2c },
+ { CCI_REG8(0x0834), 0x14 },
+ { CCI_REG8(0x0835), 0xae },
+ { CCI_REG8(0x0836), 0x0f },
+ { CCI_REG8(0x0837), 0xc4 },
+ { CCI_REG8(0x0838), 0x18 },
+ { CCI_REG8(0x0839), 0x0e },
+ { CCI_REG8(0x05ac), 0x01 },
+ { CCI_REG8(0x059a), 0x00 },
+ { CCI_REG8(0x059b), 0x00 },
+ { CCI_REG8(0x059c), 0x01 },
+ { CCI_REG8(0x0598), 0x00 },
+ { CCI_REG8(0x0597), 0x14 },
+ { CCI_REG8(0x05ab), 0x09 },
+ { CCI_REG8(0x05a4), 0x02 },
+ { CCI_REG8(0x05a3), 0x05 },
+ { CCI_REG8(0x05a0), 0xc2 },
+ { CCI_REG8(0x0207), 0xc4 },
+
+ /* GAIN */
+ { CCI_REG8(0x0208), 0x01 },
+ { CCI_REG8(0x0209), 0x72 },
+ { CCI_REG8(0x0204), 0x04 },
+ { CCI_REG8(0x0205), 0x00 },
+
+ { CCI_REG8(0x0040), 0x22 },
+ { CCI_REG8(0x0041), 0x20 },
+ { CCI_REG8(0x0043), 0x10 },
+ { CCI_REG8(0x0044), 0x00 },
+ { CCI_REG8(0x0046), 0x08 },
+ { CCI_REG8(0x0047), 0xf0 },
+ { CCI_REG8(0x0048), 0x0f },
+ { CCI_REG8(0x004b), 0x0f },
+ { CCI_REG8(0x004c), 0x00 },
+ { CCI_REG8(0x0050), 0x5c },
+ { CCI_REG8(0x0051), 0x44 },
+ { CCI_REG8(0x005b), 0x03 },
+ { CCI_REG8(0x00c0), 0x00 },
+ { CCI_REG8(0x00c1), 0x80 },
+ { CCI_REG8(0x00c2), 0x31 },
+ { CCI_REG8(0x00c3), 0x00 },
+ { CCI_REG8(0x0460), 0x04 },
+ { CCI_REG8(0x0462), 0x08 },
+ { CCI_REG8(0x0464), 0x0e },
+ { CCI_REG8(0x0466), 0x0a },
+ { CCI_REG8(0x0468), 0x12 },
+ { CCI_REG8(0x046a), 0x12 },
+ { CCI_REG8(0x046c), 0x10 },
+ { CCI_REG8(0x046e), 0x0c },
+ { CCI_REG8(0x0461), 0x03 },
+ { CCI_REG8(0x0463), 0x03 },
+ { CCI_REG8(0x0465), 0x03 },
+ { CCI_REG8(0x0467), 0x03 },
+ { CCI_REG8(0x0469), 0x04 },
+ { CCI_REG8(0x046b), 0x04 },
+ { CCI_REG8(0x046d), 0x04 },
+ { CCI_REG8(0x046f), 0x04 },
+ { CCI_REG8(0x0470), 0x04 },
+ { CCI_REG8(0x0472), 0x10 },
+ { CCI_REG8(0x0474), 0x26 },
+ { CCI_REG8(0x0476), 0x38 },
+ { CCI_REG8(0x0478), 0x20 },
+ { CCI_REG8(0x047a), 0x30 },
+ { CCI_REG8(0x047c), 0x38 },
+ { CCI_REG8(0x047e), 0x60 },
+ { CCI_REG8(0x0471), 0x05 },
+ { CCI_REG8(0x0473), 0x05 },
+ { CCI_REG8(0x0475), 0x05 },
+ { CCI_REG8(0x0477), 0x05 },
+ { CCI_REG8(0x0479), 0x04 },
+ { CCI_REG8(0x047b), 0x04 },
+ { CCI_REG8(0x047d), 0x04 },
+ { CCI_REG8(0x047f), 0x04 },
+};
+
+struct gc08a3_mode {
+ u32 width;
+ u32 height;
+ const struct gc08a3_reg_list reg_list;
+
+ u32 hts; /* Horizontal timining size */
+ u32 vts_def; /* Default vertical timining size */
+ u32 vts_min; /* Min vertical timining size */
+};
+
+/* Declare modes in order, from biggest to smallest height. */
+static const struct gc08a3_mode gc08a3_modes[] = {
+ {
+ /* 3264*2448@30fps */
+ .width = GC08A3_NATIVE_WIDTH,
+ .height = GC08A3_NATIVE_HEIGHT,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3264x2448),
+ .regs = mode_3264x2448,
+ },
+ .hts = 3640,
+ .vts_def = 2548,
+ .vts_min = 2548,
+ },
+ {
+ /* 1920*1080@60fps */
+ .width = 1920,
+ .height = 1080,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1920x1080),
+ .regs = mode_1920x1080,
+ },
+ .hts = 3640,
+ .vts_def = 1276,
+ .vts_min = 1276,
+ },
+};
+
+static inline struct gc08a3 *to_gc08a3(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct gc08a3, sd);
+}
+
+static int gc08a3_power_on(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct gc08a3 *gc08a3 = to_gc08a3(sd);
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(gc08a3_supply_name),
+ gc08a3->supplies);
+ if (ret < 0) {
+ dev_err(gc08a3->dev, "failed to enable regulators: %d\n", ret);
+ return ret;
+ }
+
+ ret = clk_prepare_enable(gc08a3->xclk);
+ if (ret < 0) {
+ regulator_bulk_disable(ARRAY_SIZE(gc08a3_supply_name),
+ gc08a3->supplies);
+ dev_err(gc08a3->dev, "clk prepare enable failed\n");
+ return ret;
+ }
+
+ fsleep(GC08A3_SLEEP_US);
+
+ gpiod_set_value_cansleep(gc08a3->reset_gpio, 0);
+ fsleep(GC08A3_SLEEP_US);
+
+ return 0;
+}
+
+static int gc08a3_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct gc08a3 *gc08a3 = to_gc08a3(sd);
+
+ clk_disable_unprepare(gc08a3->xclk);
+ gpiod_set_value_cansleep(gc08a3->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(gc08a3_supply_name),
+ gc08a3->supplies);
+
+ return 0;
+}
+
+static int gc08a3_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index > 0)
+ return -EINVAL;
+
+ code->code = GC08A3_MBUS_CODE;
+
+ return 0;
+}
+
+static int gc08a3_enum_frame_size(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ if (fse->code != GC08A3_MBUS_CODE)
+ return -EINVAL;
+
+ if (fse->index >= ARRAY_SIZE(gc08a3_modes))
+ return -EINVAL;
+
+ fse->min_width = gc08a3_modes[fse->index].width;
+ fse->max_width = gc08a3_modes[fse->index].width;
+ fse->min_height = gc08a3_modes[fse->index].height;
+ fse->max_height = gc08a3_modes[fse->index].height;
+
+ return 0;
+}
+
+static int gc08a3_update_cur_mode_controls(struct gc08a3 *gc08a3,
+ const struct gc08a3_mode *mode)
+{
+ s64 exposure_max, h_blank;
+ int ret;
+
+ ret = __v4l2_ctrl_modify_range(gc08a3->vblank,
+ mode->vts_min - mode->height,
+ GC08A3_VTS_MAX - mode->height, 1,
+ mode->vts_def - mode->height);
+ if (ret) {
+ dev_err(gc08a3->dev, "VB ctrl range update failed\n");
+ return ret;
+ }
+
+ h_blank = mode->hts - mode->width;
+ ret = __v4l2_ctrl_modify_range(gc08a3->hblank, h_blank, h_blank, 1,
+ h_blank);
+ if (ret) {
+ dev_err(gc08a3->dev, "HB ctrl range update failed\n");
+ return ret;
+ }
+
+ exposure_max = mode->vts_def - GC08A3_EXP_MARGIN;
+ ret = __v4l2_ctrl_modify_range(gc08a3->exposure, GC08A3_EXP_MIN,
+ exposure_max, GC08A3_EXP_STEP,
+ exposure_max);
+ if (ret) {
+ dev_err(gc08a3->dev, "exposure ctrl range update failed\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static void gc08a3_update_pad_format(struct gc08a3 *gc08a3,
+ const struct gc08a3_mode *mode,
+ struct v4l2_mbus_framefmt *fmt)
+{
+ fmt->width = mode->width;
+ fmt->height = mode->height;
+ fmt->code = GC08A3_MBUS_CODE;
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_RAW;
+ fmt->ycbcr_enc = V4L2_MAP_YCBCR_ENC_DEFAULT(fmt->colorspace);
+ fmt->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->xfer_func = V4L2_XFER_FUNC_NONE;
+}
+
+static int gc08a3_set_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct gc08a3 *gc08a3 = to_gc08a3(sd);
+ struct v4l2_mbus_framefmt *mbus_fmt;
+ struct v4l2_rect *crop;
+ const struct gc08a3_mode *mode;
+
+ mode = v4l2_find_nearest_size(gc08a3_modes, ARRAY_SIZE(gc08a3_modes),
+ width, height, fmt->format.width,
+ fmt->format.height);
+
+ /* update crop info to subdev state */
+ crop = v4l2_subdev_state_get_crop(state, 0);
+ crop->width = mode->width;
+ crop->height = mode->height;
+
+ /* update fmt info to subdev state */
+ gc08a3_update_pad_format(gc08a3, mode, &fmt->format);
+ mbus_fmt = v4l2_subdev_state_get_format(state, 0);
+ *mbus_fmt = fmt->format;
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
+ return 0;
+
+ gc08a3->cur_mode = mode;
+ gc08a3_update_cur_mode_controls(gc08a3, mode);
+
+ return 0;
+}
+
+static int gc08a3_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP:
+ sel->r = *v4l2_subdev_state_get_crop(state, 0);
+ break;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.top = 0;
+ sel->r.left = 0;
+ sel->r.width = GC08A3_NATIVE_WIDTH;
+ sel->r.height = GC08A3_NATIVE_HEIGHT;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int gc08a3_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ .pad = 0,
+ .format = {
+ .code = GC08A3_MBUS_CODE,
+ .width = gc08a3_modes[0].width,
+ .height = gc08a3_modes[0].height,
+ },
+ };
+
+ gc08a3_set_format(sd, state, &fmt);
+
+ return 0;
+}
+
+static int gc08a3_set_ctrl_hflip(struct gc08a3 *gc08a3, u32 ctrl_val)
+{
+ int ret;
+ u64 val;
+
+ ret = cci_read(gc08a3->regmap, GC08A3_FLIP_REG, &val, NULL);
+ if (ret) {
+ dev_err(gc08a3->dev, "read hflip register failed: %d\n", ret);
+ return ret;
+ }
+
+ return cci_update_bits(gc08a3->regmap, GC08A3_FLIP_REG,
+ GC08A3_FLIP_H_MASK,
+ ctrl_val ? GC08A3_FLIP_H_MASK : 0, NULL);
+}
+
+static int gc08a3_set_ctrl_vflip(struct gc08a3 *gc08a3, u32 ctrl_val)
+{
+ int ret;
+ u64 val;
+
+ ret = cci_read(gc08a3->regmap, GC08A3_FLIP_REG, &val, NULL);
+ if (ret) {
+ dev_err(gc08a3->dev, "read vflip register failed: %d\n", ret);
+ return ret;
+ }
+
+ return cci_update_bits(gc08a3->regmap, GC08A3_FLIP_REG,
+ GC08A3_FLIP_V_MASK,
+ ctrl_val ? GC08A3_FLIP_V_MASK : 0, NULL);
+}
+
+static int gc08a3_test_pattern(struct gc08a3 *gc08a3, u32 pattern_menu)
+{
+ u32 pattern;
+ int ret;
+
+ if (pattern_menu) {
+ switch (pattern_menu) {
+ case 1:
+ pattern = 0x00;
+ break;
+ case 2:
+ pattern = 0x10;
+ break;
+ case 3:
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ pattern = pattern_menu + 1;
+ break;
+ default:
+ pattern = 0x00;
+ break;
+ }
+
+ ret = cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_IDX,
+ pattern, NULL);
+ if (ret)
+ return ret;
+
+ return cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_EN,
+ GC08A3_TEST_PATTERN_EN, NULL);
+ } else {
+ return cci_write(gc08a3->regmap, GC08A3_REG_TEST_PATTERN_EN,
+ 0x00, NULL);
+ }
+}
+
+static int gc08a3_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct gc08a3 *gc08a3 =
+ container_of(ctrl->handler, struct gc08a3, ctrls);
+ int ret = 0;
+ s64 exposure_max;
+ struct v4l2_subdev_state *state;
+ const struct v4l2_mbus_framefmt *format;
+
+ state = v4l2_subdev_get_locked_active_state(&gc08a3->sd);
+ format = v4l2_subdev_state_get_format(state, 0);
+
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ /* Update max exposure while meeting expected vblanking */
+ exposure_max = format->height + ctrl->val - GC08A3_EXP_MARGIN;
+ __v4l2_ctrl_modify_range(gc08a3->exposure,
+ gc08a3->exposure->minimum,
+ exposure_max, gc08a3->exposure->step,
+ exposure_max);
+ }
+
+ /*
+ * Applying V4L2 control value only happens
+ * when power is on for streaming.
+ */
+ if (!pm_runtime_get_if_active(gc08a3->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ ret = cci_write(gc08a3->regmap, GC08A3_EXP_REG,
+ ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = cci_write(gc08a3->regmap, GC08A3_AGAIN_REG,
+ ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_VBLANK:
+ ret = cci_write(gc08a3->regmap, GC08A3_FRAME_LENGTH_REG,
+ gc08a3->cur_mode->height + ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_HFLIP:
+ ret = gc08a3_set_ctrl_hflip(gc08a3, ctrl->val);
+ break;
+
+ case V4L2_CID_VFLIP:
+ ret = gc08a3_set_ctrl_vflip(gc08a3, ctrl->val);
+ break;
+
+ case V4L2_CID_TEST_PATTERN:
+ ret = gc08a3_test_pattern(gc08a3, ctrl->val);
+ break;
+
+ default:
+ break;
+ }
+
+ pm_runtime_put(gc08a3->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops gc08a3_ctrl_ops = {
+ .s_ctrl = gc08a3_set_ctrl,
+};
+
+static int gc08a3_start_streaming(struct gc08a3 *gc08a3)
+{
+ const struct gc08a3_mode *mode;
+ const struct gc08a3_reg_list *reg_list;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(gc08a3->dev);
+ if (ret < 0)
+ return ret;
+
+ ret = cci_multi_reg_write(gc08a3->regmap,
+ mode_table_common,
+ ARRAY_SIZE(mode_table_common), NULL);
+ if (ret)
+ goto err_rpm_put;
+
+ mode = gc08a3->cur_mode;
+ reg_list = &mode->reg_list;
+ ret = cci_multi_reg_write(gc08a3->regmap,
+ reg_list->regs, reg_list->num_of_regs, NULL);
+ if (ret < 0)
+ goto err_rpm_put;
+
+ ret = __v4l2_ctrl_handler_setup(&gc08a3->ctrls);
+ if (ret < 0) {
+ dev_err(gc08a3->dev, "could not sync v4l2 controls\n");
+ goto err_rpm_put;
+ }
+
+ ret = cci_write(gc08a3->regmap, GC08A3_STREAMING_REG, 1, NULL);
+ if (ret < 0) {
+ dev_err(gc08a3->dev, "write STRAEMING_REG failed: %d\n", ret);
+ goto err_rpm_put;
+ }
+
+ return 0;
+
+err_rpm_put:
+ pm_runtime_put(gc08a3->dev);
+ return ret;
+}
+
+static int gc08a3_stop_streaming(struct gc08a3 *gc08a3)
+{
+ int ret;
+
+ ret = cci_write(gc08a3->regmap, GC08A3_STREAMING_REG, 0, NULL);
+ if (ret < 0)
+ dev_err(gc08a3->dev, "could not sent stop streaming %d\n", ret);
+
+ pm_runtime_put(gc08a3->dev);
+ return ret;
+}
+
+static int gc08a3_s_stream(struct v4l2_subdev *subdev, int enable)
+{
+ struct gc08a3 *gc08a3 = to_gc08a3(subdev);
+ struct v4l2_subdev_state *state;
+ int ret;
+
+ state = v4l2_subdev_lock_and_get_active_state(subdev);
+
+ if (enable)
+ ret = gc08a3_start_streaming(gc08a3);
+ else
+ ret = gc08a3_stop_streaming(gc08a3);
+
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static const struct v4l2_subdev_video_ops gc08a3_video_ops = {
+ .s_stream = gc08a3_s_stream,
+};
+
+static const struct v4l2_subdev_pad_ops gc08a3_subdev_pad_ops = {
+ .enum_mbus_code = gc08a3_enum_mbus_code,
+ .enum_frame_size = gc08a3_enum_frame_size,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = gc08a3_set_format,
+ .get_selection = gc08a3_get_selection,
+};
+
+static const struct v4l2_subdev_core_ops gc08a3_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_ops gc08a3_subdev_ops = {
+ .core = &gc08a3_core_ops,
+ .video = &gc08a3_video_ops,
+ .pad = &gc08a3_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops gc08a3_internal_ops = {
+ .init_state = gc08a3_init_state,
+};
+
+static int gc08a3_get_regulators(struct device *dev, struct gc08a3 *gc08a3)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(gc08a3_supply_name); i++)
+ gc08a3->supplies[i].supply = gc08a3_supply_name[i];
+
+ return devm_regulator_bulk_get(dev, ARRAY_SIZE(gc08a3_supply_name),
+ gc08a3->supplies);
+}
+
+static int gc08a3_parse_fwnode(struct gc08a3 *gc08a3)
+{
+ struct fwnode_handle *endpoint;
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY,
+ };
+ int ret;
+ struct device *dev = gc08a3->dev;
+
+ 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_alloc_parse(endpoint, &bus_cfg);
+ if (ret) {
+ dev_err(dev, "parsing endpoint node failed\n");
+ goto done;
+ }
+
+ ret = v4l2_link_freq_to_bitmap(dev, bus_cfg.link_frequencies,
+ bus_cfg.nr_of_link_frequencies,
+ gc08a3_link_freq_menu_items,
+ ARRAY_SIZE(gc08a3_link_freq_menu_items),
+ &gc08a3->link_freq_bitmap);
+ if (ret)
+ goto done;
+
+done:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+ fwnode_handle_put(endpoint);
+ return ret;
+}
+
+static u64 gc08a3_to_pixel_rate(u32 f_index)
+{
+ u64 pixel_rate =
+ gc08a3_link_freq_menu_items[f_index] * 2 * GC08A3_DATA_LANES;
+
+ return div_u64(pixel_rate, GC08A3_RGB_DEPTH);
+}
+
+static int gc08a3_init_controls(struct gc08a3 *gc08a3)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&gc08a3->sd);
+ const struct gc08a3_mode *mode = &gc08a3_modes[0];
+ const struct v4l2_ctrl_ops *ops = &gc08a3_ctrl_ops;
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ s64 exposure_max, h_blank;
+ int ret;
+
+ ctrl_hdlr = &gc08a3->ctrls;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 9);
+ if (ret)
+ return ret;
+
+ gc08a3->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ gc08a3->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_cluster(2, &gc08a3->hflip);
+
+ gc08a3->link_freq =
+ v4l2_ctrl_new_int_menu(ctrl_hdlr,
+ &gc08a3_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ ARRAY_SIZE(gc08a3_link_freq_menu_items) - 1,
+ 0,
+ gc08a3_link_freq_menu_items);
+ if (gc08a3->link_freq)
+ gc08a3->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ gc08a3->pixel_rate =
+ v4l2_ctrl_new_std(ctrl_hdlr,
+ &gc08a3_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, 0,
+ gc08a3_to_pixel_rate(0),
+ 1,
+ gc08a3_to_pixel_rate(0));
+
+ gc08a3->vblank =
+ v4l2_ctrl_new_std(ctrl_hdlr,
+ &gc08a3_ctrl_ops, V4L2_CID_VBLANK,
+ mode->vts_min - mode->height,
+ GC08A3_VTS_MAX - mode->height, 1,
+ mode->vts_def - mode->height);
+
+ h_blank = mode->hts - mode->width;
+ gc08a3->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
+ V4L2_CID_HBLANK, h_blank, h_blank, 1,
+ h_blank);
+ if (gc08a3->hblank)
+ gc08a3->hblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
+ V4L2_CID_ANALOGUE_GAIN, GC08A3_AGAIN_MIN,
+ GC08A3_AGAIN_MAX, GC08A3_AGAIN_STEP,
+ GC08A3_AGAIN_MIN);
+
+ exposure_max = mode->vts_def - GC08A3_EXP_MARGIN;
+ gc08a3->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &gc08a3_ctrl_ops,
+ V4L2_CID_EXPOSURE, GC08A3_EXP_MIN,
+ exposure_max, GC08A3_EXP_STEP,
+ exposure_max);
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &gc08a3_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(gc08a3_test_pattern_menu) - 1,
+ 0, 0, gc08a3_test_pattern_menu);
+
+ /* register properties to fwnode (e.g. rotation, orientation) */
+ ret = v4l2_fwnode_device_parse(&client->dev, &props);
+ if (ret)
+ goto error_ctrls;
+
+ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, ops, &props);
+ if (ret)
+ goto error_ctrls;
+
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ goto error_ctrls;
+ }
+
+ gc08a3->sd.ctrl_handler = ctrl_hdlr;
+
+ return 0;
+
+error_ctrls:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+
+ return ret;
+}
+
+static int gc08a3_identify_module(struct gc08a3 *gc08a3)
+{
+ u64 val;
+ int ret;
+
+ ret = cci_read(gc08a3->regmap, GC08A3_REG_CHIP_ID, &val, NULL);
+ if (ret) {
+ dev_err(gc08a3->dev, "failed to read chip id");
+ return ret;
+ }
+
+ if (val != GC08A3_CHIP_ID) {
+ dev_err(gc08a3->dev, "chip id mismatch: 0x%x!=0x%llx",
+ GC08A3_CHIP_ID, val);
+ return -ENXIO;
+ }
+
+ return 0;
+}
+
+static int gc08a3_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct gc08a3 *gc08a3;
+ int ret;
+
+ gc08a3 = devm_kzalloc(dev, sizeof(*gc08a3), GFP_KERNEL);
+ if (!gc08a3)
+ return -ENOMEM;
+
+ gc08a3->dev = dev;
+
+ ret = gc08a3_parse_fwnode(gc08a3);
+ if (ret)
+ return ret;
+
+ gc08a3->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(gc08a3->regmap))
+ return dev_err_probe(dev, PTR_ERR(gc08a3->regmap),
+ "failed to init CCI\n");
+
+ gc08a3->xclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(gc08a3->xclk))
+ return dev_err_probe(dev, PTR_ERR(gc08a3->xclk),
+ "failed to get xclk\n");
+
+ ret = clk_set_rate(gc08a3->xclk, GC08A3_DEFAULT_CLK_FREQ);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to set xclk frequency\n");
+
+ ret = gc08a3_get_regulators(dev, gc08a3);
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "failed to get regulators\n");
+
+ gc08a3->reset_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_LOW);
+ if (IS_ERR(gc08a3->reset_gpio))
+ return dev_err_probe(dev, PTR_ERR(gc08a3->reset_gpio),
+ "failed to get gpio\n");
+
+ v4l2_i2c_subdev_init(&gc08a3->sd, client, &gc08a3_subdev_ops);
+ gc08a3->sd.internal_ops = &gc08a3_internal_ops;
+ gc08a3->cur_mode = &gc08a3_modes[0];
+
+ ret = gc08a3_power_on(gc08a3->dev);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "failed to sensor power on\n");
+
+ ret = gc08a3_identify_module(gc08a3);
+ if (ret) {
+ dev_err(&client->dev, "failed to find sensor: %d\n", ret);
+ goto err_power_off;
+ }
+
+ ret = gc08a3_init_controls(gc08a3);
+ if (ret) {
+ dev_err(&client->dev, "failed to init controls: %d", ret);
+ goto err_power_off;
+ }
+
+ gc08a3->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+ gc08a3->pad.flags = MEDIA_PAD_FL_SOURCE;
+ gc08a3->sd.dev = &client->dev;
+ gc08a3->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+
+ ret = media_entity_pads_init(&gc08a3->sd.entity, 1, &gc08a3->pad);
+ if (ret < 0) {
+ dev_err(dev, "could not register media entity\n");
+ goto err_v4l2_ctrl_handler_free;
+ }
+
+ gc08a3->sd.state_lock = gc08a3->ctrls.lock;
+ ret = v4l2_subdev_init_finalize(&gc08a3->sd);
+ if (ret < 0) {
+ dev_err(dev, "v4l2 subdev init error: %d\n", ret);
+ goto err_media_entity_cleanup;
+ }
+
+ pm_runtime_set_active(gc08a3->dev);
+ pm_runtime_enable(gc08a3->dev);
+ pm_runtime_set_autosuspend_delay(gc08a3->dev, 1000);
+ pm_runtime_use_autosuspend(gc08a3->dev);
+ pm_runtime_idle(gc08a3->dev);
+
+ ret = v4l2_async_register_subdev_sensor(&gc08a3->sd);
+ if (ret < 0) {
+ dev_err(dev, "could not register v4l2 device\n");
+ goto err_rpm;
+ }
+
+ return 0;
+
+err_rpm:
+ pm_runtime_disable(gc08a3->dev);
+ v4l2_subdev_cleanup(&gc08a3->sd);
+
+err_media_entity_cleanup:
+ media_entity_cleanup(&gc08a3->sd.entity);
+
+err_v4l2_ctrl_handler_free:
+ v4l2_ctrl_handler_free(gc08a3->sd.ctrl_handler);
+
+err_power_off:
+ gc08a3_power_off(gc08a3->dev);
+
+ return ret;
+}
+
+static void gc08a3_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct gc08a3 *gc08a3 = to_gc08a3(sd);
+
+ v4l2_async_unregister_subdev(&gc08a3->sd);
+ v4l2_subdev_cleanup(sd);
+ media_entity_cleanup(&gc08a3->sd.entity);
+ v4l2_ctrl_handler_free(&gc08a3->ctrls);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ gc08a3_power_off(gc08a3->dev);
+ pm_runtime_set_suspended(&client->dev);
+}
+
+static const struct of_device_id gc08a3_of_match[] = {
+ { .compatible = "galaxycore,gc08a3" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, gc08a3_of_match);
+
+static DEFINE_RUNTIME_DEV_PM_OPS(gc08a3_pm_ops,
+ gc08a3_power_off,
+ gc08a3_power_on,
+ NULL);
+
+static struct i2c_driver gc08a3_i2c_driver = {
+ .driver = {
+ .of_match_table = gc08a3_of_match,
+ .pm = pm_ptr(&gc08a3_pm_ops),
+ .name = "gc08a3",
+ },
+ .probe = gc08a3_probe,
+ .remove = gc08a3_remove,
+};
+module_i2c_driver(gc08a3_i2c_driver);
+
+MODULE_DESCRIPTION("GalaxyCore gc08a3 Camera driver");
+MODULE_AUTHOR("Zhi Mao <zhi.mao@mediatek.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c
index bef7b0e056a8..667bb756d056 100644
--- a/drivers/media/i2c/gc2145.c
+++ b/drivers/media/i2c/gc2145.c
@@ -68,8 +68,7 @@
#define GC2145_DPHY_CLK_DELAY BIT(4)
#define GC2145_DPHY_LANE0_DELAY BIT(5)
#define GC2145_DPHY_LANE1_DELAY BIT(6)
-#define GC2145_REG_FIFO_FULL_LVL_LOW CCI_REG8(0x04)
-#define GC2145_REG_FIFO_FULL_LVL_HIGH CCI_REG8(0x05)
+#define GC2145_REG_FIFO_FULL_LVL CCI_REG16_LE(0x04)
#define GC2145_REG_FIFO_MODE CCI_REG8(0x06)
#define GC2145_FIFO_MODE_READ_GATE BIT(3)
#define GC2145_FIFO_MODE_MIPI_CLK_MODULE BIT(7)
@@ -79,8 +78,7 @@
#define GC2145_CSI2_MODE_MIPI_EN BIT(4)
#define GC2145_CSI2_MODE_EN BIT(7)
#define GC2145_REG_MIPI_DT CCI_REG8(0x11)
-#define GC2145_REG_LWC_LOW CCI_REG8(0x12)
-#define GC2145_REG_LWC_HIGH CCI_REG8(0x13)
+#define GC2145_REG_LWC CCI_REG16_LE(0x12)
#define GC2145_REG_DPHY_MODE CCI_REG8(0x15)
#define GC2145_DPHY_MODE_TRIGGER_PROG BIT(4)
#define GC2145_REG_FIFO_GATE_MODE CCI_REG8(0x17)
@@ -542,45 +540,82 @@ static const struct gc2145_mode supported_modes[] = {
/**
* struct gc2145_format - GC2145 pixel format description
* @code: media bus (MBUS) associated code
+ * @colorspace: V4L2 colorspace
* @datatype: MIPI CSI2 data type
* @output_fmt: GC2145 output format
* @switch_bit: GC2145 first/second switch
+ * @row_col_switch: GC2145 switch row and/or column
*/
struct gc2145_format {
unsigned int code;
+ unsigned int colorspace;
unsigned char datatype;
unsigned char output_fmt;
bool switch_bit;
+ unsigned char row_col_switch;
};
/* All supported formats */
static const struct gc2145_format supported_formats[] = {
{
.code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.datatype = MIPI_CSI2_DT_YUV422_8B,
.output_fmt = 0x00,
},
{
.code = MEDIA_BUS_FMT_VYUY8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.datatype = MIPI_CSI2_DT_YUV422_8B,
.output_fmt = 0x01,
},
{
.code = MEDIA_BUS_FMT_YUYV8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.datatype = MIPI_CSI2_DT_YUV422_8B,
.output_fmt = 0x02,
},
{
.code = MEDIA_BUS_FMT_YVYU8_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.datatype = MIPI_CSI2_DT_YUV422_8B,
.output_fmt = 0x03,
},
{
.code = MEDIA_BUS_FMT_RGB565_1X16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.datatype = MIPI_CSI2_DT_RGB565,
.output_fmt = 0x06,
.switch_bit = true,
},
+ {
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .output_fmt = 0x17,
+ .row_col_switch = GC2145_SYNC_MODE_COL_SWITCH,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .output_fmt = 0x17,
+ .row_col_switch = GC2145_SYNC_MODE_COL_SWITCH | GC2145_SYNC_MODE_ROW_SWITCH,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .output_fmt = 0x17,
+ .row_col_switch = 0,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .output_fmt = 0x17,
+ .row_col_switch = GC2145_SYNC_MODE_ROW_SWITCH,
+ },
};
struct gc2145_ctrls {
@@ -641,7 +676,8 @@ gc2145_get_format_code(struct gc2145 *gc2145, u32 code)
static void gc2145_update_pad_format(struct gc2145 *gc2145,
const struct gc2145_mode *mode,
- struct v4l2_mbus_framefmt *fmt, u32 code)
+ struct v4l2_mbus_framefmt *fmt, u32 code,
+ u32 colorspace)
{
fmt->code = code;
fmt->width = mode->width;
@@ -663,7 +699,8 @@ static int gc2145_init_state(struct v4l2_subdev *sd,
/* Initialize pad format */
format = v4l2_subdev_state_get_format(state, 0);
gc2145_update_pad_format(gc2145, &supported_modes[0], format,
- MEDIA_BUS_FMT_RGB565_1X16);
+ MEDIA_BUS_FMT_RGB565_1X16,
+ V4L2_COLORSPACE_SRGB);
/* Initialize crop rectangle. */
crop = v4l2_subdev_state_get_crop(state, 0);
@@ -754,7 +791,13 @@ static int gc2145_set_pad_format(struct v4l2_subdev *sd,
width, height,
fmt->format.width, fmt->format.height);
- gc2145_update_pad_format(gc2145, mode, &fmt->format, gc2145_fmt->code);
+ /* In RAW mode, VGA is not possible so use 720p instead */
+ if (gc2145_fmt->colorspace == V4L2_COLORSPACE_RAW &&
+ mode == &supported_modes[GC2145_MODE_640X480])
+ mode = &supported_modes[GC2145_MODE_1280X720];
+
+ gc2145_update_pad_format(gc2145, mode, &fmt->format, gc2145_fmt->code,
+ gc2145_fmt->colorspace);
framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
gc2145->mode = mode;
@@ -811,9 +854,12 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145,
* For RAW8, LWC = image width
* For RAW10, LWC = image width * 1.25
*/
- lwc = gc2145->mode->width * 2;
- cci_write(gc2145->regmap, GC2145_REG_LWC_HIGH, lwc >> 8, &ret);
- cci_write(gc2145->regmap, GC2145_REG_LWC_LOW, lwc & 0xff, &ret);
+ if (gc2145_format->colorspace != V4L2_COLORSPACE_RAW)
+ lwc = gc2145->mode->width * 2;
+ else
+ lwc = gc2145->mode->width;
+
+ cci_write(gc2145->regmap, GC2145_REG_LWC, lwc, &ret);
/*
* Adjust the MIPI FIFO Full Level
@@ -821,21 +867,25 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145,
* 1280x720 / 1600x1200 (aka no scaler) non RAW: 0x0001
* 1600x1200 RAW: 0x0190
*/
- if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600)
- fifo_full_lvl = 0x0001;
- else
+ if (gc2145_format->colorspace != V4L2_COLORSPACE_RAW) {
+ if (gc2145->mode->width == 1280 || gc2145->mode->width == 1600)
+ fifo_full_lvl = 0x0001;
+ else
+ fifo_full_lvl = 0x0190;
+ } else {
fifo_full_lvl = 0x0190;
+ }
- cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_HIGH,
- fifo_full_lvl >> 8, &ret);
- cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL_LOW,
- fifo_full_lvl & 0xff, &ret);
+ cci_write(gc2145->regmap, GC2145_REG_FIFO_FULL_LVL,
+ fifo_full_lvl, &ret);
/*
* Set the FIFO gate mode / MIPI wdiv set:
* 0xf1 in case of RAW mode and 0xf0 otherwise
*/
- cci_write(gc2145->regmap, GC2145_REG_FIFO_GATE_MODE, 0xf0, &ret);
+ cci_write(gc2145->regmap, GC2145_REG_FIFO_GATE_MODE,
+ gc2145_format->colorspace == V4L2_COLORSPACE_RAW ?
+ 0xf1 : 0xf0, &ret);
/* Set the MIPI data type */
cci_write(gc2145->regmap, GC2145_REG_MIPI_DT,
@@ -883,6 +933,10 @@ static int gc2145_start_streaming(struct gc2145 *gc2145,
GC2145_BYPASS_MODE_SWITCH,
gc2145_format->switch_bit ? GC2145_BYPASS_MODE_SWITCH
: 0, &ret);
+ cci_update_bits(gc2145->regmap, GC2145_REG_SYNC_MODE,
+ GC2145_SYNC_MODE_COL_SWITCH |
+ GC2145_SYNC_MODE_ROW_SWITCH,
+ gc2145_format->row_col_switch, &ret);
if (ret) {
dev_err(&client->dev, "%s failed to write regs\n", __func__);
goto err_rpm_put;
diff --git a/drivers/media/i2c/hi846.c b/drivers/media/i2c/hi846.c
index 9c565ec033d4..52d9ca68a86c 100644
--- a/drivers/media/i2c/hi846.c
+++ b/drivers/media/i2c/hi846.c
@@ -1851,7 +1851,7 @@ static int hi846_get_selection(struct v4l2_subdev *sd,
mutex_lock(&hi846->mutex);
switch (sel->which) {
case V4L2_SUBDEV_FORMAT_TRY:
- v4l2_subdev_state_get_crop(sd_state, sel->pad);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, sel->pad);
break;
case V4L2_SUBDEV_FORMAT_ACTIVE:
sel->r = hi846->cur_mode->crop;
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index 51ebf5453fce..e78a80b2bb2e 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -162,8 +162,8 @@ static const struct cci_reg_sequence imx219_common_regs[] = {
{ IMX219_REG_MODE_SELECT, 0x00 }, /* Mode Select */
/* To Access Addresses 3000-5fff, send the following commands */
- { CCI_REG8(0x30eb), 0x0c },
{ CCI_REG8(0x30eb), 0x05 },
+ { CCI_REG8(0x30eb), 0x0c },
{ CCI_REG8(0x300a), 0xff },
{ CCI_REG8(0x300b), 0xff },
{ CCI_REG8(0x30eb), 0x05 },
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index a577afb530b7..1a99eaaff21a 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -7,97 +7,150 @@
#include <linux/i2c.h>
#include <linux/module.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
+#include <media/v4l2-cci.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
#include <asm/unaligned.h>
-#define IMX258_REG_VALUE_08BIT 1
-#define IMX258_REG_VALUE_16BIT 2
-
-#define IMX258_REG_MODE_SELECT 0x0100
+#define IMX258_REG_MODE_SELECT CCI_REG8(0x0100)
#define IMX258_MODE_STANDBY 0x00
#define IMX258_MODE_STREAMING 0x01
+#define IMX258_REG_RESET CCI_REG8(0x0103)
+
/* Chip ID */
-#define IMX258_REG_CHIP_ID 0x0016
+#define IMX258_REG_CHIP_ID CCI_REG16(0x0016)
#define IMX258_CHIP_ID 0x0258
/* V_TIMING internal */
#define IMX258_VTS_30FPS 0x0c50
#define IMX258_VTS_30FPS_2K 0x0638
#define IMX258_VTS_30FPS_VGA 0x034c
-#define IMX258_VTS_MAX 0xffff
-
-/*Frame Length Line*/
-#define IMX258_FLL_MIN 0x08a6
-#define IMX258_FLL_MAX 0xffff
-#define IMX258_FLL_STEP 1
-#define IMX258_FLL_DEFAULT 0x0c98
+#define IMX258_VTS_MAX 65525
/* HBLANK control - read only */
#define IMX258_PPL_DEFAULT 5352
/* Exposure control */
-#define IMX258_REG_EXPOSURE 0x0202
+#define IMX258_REG_EXPOSURE CCI_REG16(0x0202)
+#define IMX258_EXPOSURE_OFFSET 10
#define IMX258_EXPOSURE_MIN 4
#define IMX258_EXPOSURE_STEP 1
#define IMX258_EXPOSURE_DEFAULT 0x640
-#define IMX258_EXPOSURE_MAX 65535
+#define IMX258_EXPOSURE_MAX (IMX258_VTS_MAX - IMX258_EXPOSURE_OFFSET)
/* Analog gain control */
-#define IMX258_REG_ANALOG_GAIN 0x0204
+#define IMX258_REG_ANALOG_GAIN CCI_REG16(0x0204)
#define IMX258_ANA_GAIN_MIN 0
#define IMX258_ANA_GAIN_MAX 480
#define IMX258_ANA_GAIN_STEP 1
#define IMX258_ANA_GAIN_DEFAULT 0x0
/* Digital gain control */
-#define IMX258_REG_GR_DIGITAL_GAIN 0x020e
-#define IMX258_REG_R_DIGITAL_GAIN 0x0210
-#define IMX258_REG_B_DIGITAL_GAIN 0x0212
-#define IMX258_REG_GB_DIGITAL_GAIN 0x0214
+#define IMX258_REG_GR_DIGITAL_GAIN CCI_REG16(0x020e)
+#define IMX258_REG_R_DIGITAL_GAIN CCI_REG16(0x0210)
+#define IMX258_REG_B_DIGITAL_GAIN CCI_REG16(0x0212)
+#define IMX258_REG_GB_DIGITAL_GAIN CCI_REG16(0x0214)
#define IMX258_DGTL_GAIN_MIN 0
#define IMX258_DGTL_GAIN_MAX 4096 /* Max = 0xFFF */
#define IMX258_DGTL_GAIN_DEFAULT 1024
#define IMX258_DGTL_GAIN_STEP 1
/* HDR control */
-#define IMX258_REG_HDR 0x0220
+#define IMX258_REG_HDR CCI_REG8(0x0220)
#define IMX258_HDR_ON BIT(0)
-#define IMX258_REG_HDR_RATIO 0x0222
+#define IMX258_REG_HDR_RATIO CCI_REG8(0x0222)
#define IMX258_HDR_RATIO_MIN 0
#define IMX258_HDR_RATIO_MAX 5
#define IMX258_HDR_RATIO_STEP 1
#define IMX258_HDR_RATIO_DEFAULT 0x0
/* Test Pattern Control */
-#define IMX258_REG_TEST_PATTERN 0x0600
+#define IMX258_REG_TEST_PATTERN CCI_REG16(0x0600)
+
+#define IMX258_CLK_BLANK_STOP CCI_REG8(0x4040)
/* Orientation */
-#define REG_MIRROR_FLIP_CONTROL 0x0101
-#define REG_CONFIG_MIRROR_FLIP 0x03
-#define REG_CONFIG_FLIP_TEST_PATTERN 0x02
+#define REG_MIRROR_FLIP_CONTROL CCI_REG8(0x0101)
+#define REG_CONFIG_MIRROR_HFLIP 0x01
+#define REG_CONFIG_MIRROR_VFLIP 0x02
+
+/* IMX258 native and active pixel array size. */
+#define IMX258_NATIVE_WIDTH 4224U
+#define IMX258_NATIVE_HEIGHT 3192U
+#define IMX258_PIXEL_ARRAY_LEFT 8U
+#define IMX258_PIXEL_ARRAY_TOP 16U
+#define IMX258_PIXEL_ARRAY_WIDTH 4208U
+#define IMX258_PIXEL_ARRAY_HEIGHT 3120U
+
+/* regs */
+#define IMX258_REG_PLL_MULT_DRIV CCI_REG8(0x0310)
+#define IMX258_REG_IVTPXCK_DIV CCI_REG8(0x0301)
+#define IMX258_REG_IVTSYCK_DIV CCI_REG8(0x0303)
+#define IMX258_REG_PREPLLCK_VT_DIV CCI_REG8(0x0305)
+#define IMX258_REG_IOPPXCK_DIV CCI_REG8(0x0309)
+#define IMX258_REG_IOPSYCK_DIV CCI_REG8(0x030b)
+#define IMX258_REG_PREPLLCK_OP_DIV CCI_REG8(0x030d)
+#define IMX258_REG_PHASE_PIX_OUTEN CCI_REG8(0x3030)
+#define IMX258_REG_PDPIX_DATA_RATE CCI_REG8(0x3032)
+#define IMX258_REG_SCALE_MODE CCI_REG8(0x0401)
+#define IMX258_REG_SCALE_MODE_EXT CCI_REG8(0x3038)
+#define IMX258_REG_AF_WINDOW_MODE CCI_REG8(0x7bcd)
+#define IMX258_REG_FRM_LENGTH_CTL CCI_REG8(0x0350)
+#define IMX258_REG_CSI_LANE_MODE CCI_REG8(0x0114)
+#define IMX258_REG_X_EVN_INC CCI_REG8(0x0381)
+#define IMX258_REG_X_ODD_INC CCI_REG8(0x0383)
+#define IMX258_REG_Y_EVN_INC CCI_REG8(0x0385)
+#define IMX258_REG_Y_ODD_INC CCI_REG8(0x0387)
+#define IMX258_REG_BINNING_MODE CCI_REG8(0x0900)
+#define IMX258_REG_BINNING_TYPE_V CCI_REG8(0x0901)
+#define IMX258_REG_FORCE_FD_SUM CCI_REG8(0x300d)
+#define IMX258_REG_DIG_CROP_X_OFFSET CCI_REG16(0x0408)
+#define IMX258_REG_DIG_CROP_Y_OFFSET CCI_REG16(0x040a)
+#define IMX258_REG_DIG_CROP_IMAGE_WIDTH CCI_REG16(0x040c)
+#define IMX258_REG_DIG_CROP_IMAGE_HEIGHT CCI_REG16(0x040e)
+#define IMX258_REG_SCALE_M CCI_REG16(0x0404)
+#define IMX258_REG_X_OUT_SIZE CCI_REG16(0x034c)
+#define IMX258_REG_Y_OUT_SIZE CCI_REG16(0x034e)
+#define IMX258_REG_X_ADD_STA CCI_REG16(0x0344)
+#define IMX258_REG_Y_ADD_STA CCI_REG16(0x0346)
+#define IMX258_REG_X_ADD_END CCI_REG16(0x0348)
+#define IMX258_REG_Y_ADD_END CCI_REG16(0x034a)
+#define IMX258_REG_EXCK_FREQ CCI_REG16(0x0136)
+#define IMX258_REG_CSI_DT_FMT CCI_REG16(0x0112)
+#define IMX258_REG_LINE_LENGTH_PCK CCI_REG16(0x0342)
+#define IMX258_REG_SCALE_M_EXT CCI_REG16(0x303a)
+#define IMX258_REG_FRM_LENGTH_LINES CCI_REG16(0x0340)
+#define IMX258_REG_FINE_INTEG_TIME CCI_REG8(0x0200)
+#define IMX258_REG_PLL_IVT_MPY CCI_REG16(0x0306)
+#define IMX258_REG_PLL_IOP_MPY CCI_REG16(0x030e)
+#define IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H CCI_REG16(0x0820)
+#define IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L CCI_REG16(0x0822)
-/* Input clock frequency in Hz */
-#define IMX258_INPUT_CLOCK_FREQ 19200000
+struct imx258_reg_list {
+ u32 num_of_regs;
+ const struct cci_reg_sequence *regs;
+};
-struct imx258_reg {
- u16 address;
- u8 val;
+struct imx258_link_cfg {
+ unsigned int lf_to_pix_rate_factor;
+ struct imx258_reg_list reg_list;
};
-struct imx258_reg_list {
- u32 num_of_regs;
- const struct imx258_reg *regs;
+enum {
+ IMX258_2_LANE_MODE,
+ IMX258_4_LANE_MODE,
+ IMX258_LANE_CONFIGS,
};
/* Link frequency config */
struct imx258_link_freq_config {
u32 pixels_per_line;
- /* PLL registers for this link frequency */
- struct imx258_reg_list reg_list;
+ /* Configuration for this link frequency / num lanes selection */
+ struct imx258_link_cfg link_cfg[IMX258_LANE_CONFIGS];
};
/* Mode : resolution and related config&values */
@@ -115,400 +168,307 @@ struct imx258_mode {
u32 link_freq_index;
/* Default register values */
struct imx258_reg_list reg_list;
+
+ /* Analog crop rectangle */
+ struct v4l2_rect crop;
+};
+
+/*
+ * 4208x3120 @ 30 fps needs 1267Mbps/lane, 4 lanes.
+ * To avoid further computation of clock settings, adopt the same per
+ * lane data rate when using 2 lanes, thus allowing a maximum of 15fps.
+ */
+static const struct cci_reg_sequence mipi_1267mbps_19_2mhz_2l[] = {
+ { IMX258_REG_EXCK_FREQ, 0x1333 },
+ { IMX258_REG_IVTPXCK_DIV, 10 },
+ { IMX258_REG_IVTSYCK_DIV, 2 },
+ { IMX258_REG_PREPLLCK_VT_DIV, 3 },
+ { IMX258_REG_PLL_IVT_MPY, 198 },
+ { IMX258_REG_IOPPXCK_DIV, 10 },
+ { IMX258_REG_IOPSYCK_DIV, 1 },
+ { IMX258_REG_PREPLLCK_OP_DIV, 2 },
+ { IMX258_REG_PLL_IOP_MPY, 216 },
+ { IMX258_REG_PLL_MULT_DRIV, 0 },
+
+ { IMX258_REG_CSI_LANE_MODE, 1 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1267 * 2 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 },
+};
+
+static const struct cci_reg_sequence mipi_1267mbps_19_2mhz_4l[] = {
+ { IMX258_REG_EXCK_FREQ, 0x1333 },
+ { IMX258_REG_IVTPXCK_DIV, 5 },
+ { IMX258_REG_IVTSYCK_DIV, 2 },
+ { IMX258_REG_PREPLLCK_VT_DIV, 3 },
+ { IMX258_REG_PLL_IVT_MPY, 198 },
+ { IMX258_REG_IOPPXCK_DIV, 10 },
+ { IMX258_REG_IOPSYCK_DIV, 1 },
+ { IMX258_REG_PREPLLCK_OP_DIV, 2 },
+ { IMX258_REG_PLL_IOP_MPY, 216 },
+ { IMX258_REG_PLL_MULT_DRIV, 0 },
+
+ { IMX258_REG_CSI_LANE_MODE, 3 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1267 * 4 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 },
+};
+
+static const struct cci_reg_sequence mipi_1272mbps_24mhz_2l[] = {
+ { IMX258_REG_EXCK_FREQ, 0x1800 },
+ { IMX258_REG_IVTPXCK_DIV, 10 },
+ { IMX258_REG_IVTSYCK_DIV, 2 },
+ { IMX258_REG_PREPLLCK_VT_DIV, 4 },
+ { IMX258_REG_PLL_IVT_MPY, 212 },
+ { IMX258_REG_IOPPXCK_DIV, 10 },
+ { IMX258_REG_IOPSYCK_DIV, 1 },
+ { IMX258_REG_PREPLLCK_OP_DIV, 2 },
+ { IMX258_REG_PLL_IOP_MPY, 216 },
+ { IMX258_REG_PLL_MULT_DRIV, 0 },
+
+ { IMX258_REG_CSI_LANE_MODE, 1 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1272 * 2 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 },
+};
+
+static const struct cci_reg_sequence mipi_1272mbps_24mhz_4l[] = {
+ { IMX258_REG_EXCK_FREQ, 0x1800 },
+ { IMX258_REG_IVTPXCK_DIV, 5 },
+ { IMX258_REG_IVTSYCK_DIV, 2 },
+ { IMX258_REG_PREPLLCK_VT_DIV, 4 },
+ { IMX258_REG_PLL_IVT_MPY, 212 },
+ { IMX258_REG_IOPPXCK_DIV, 10 },
+ { IMX258_REG_IOPSYCK_DIV, 1 },
+ { IMX258_REG_PREPLLCK_OP_DIV, 2 },
+ { IMX258_REG_PLL_IOP_MPY, 216 },
+ { IMX258_REG_PLL_MULT_DRIV, 0 },
+
+ { IMX258_REG_CSI_LANE_MODE, 3 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 1272 * 4 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 },
+};
+
+static const struct cci_reg_sequence mipi_640mbps_19_2mhz_2l[] = {
+ { IMX258_REG_EXCK_FREQ, 0x1333 },
+ { IMX258_REG_IVTPXCK_DIV, 5 },
+ { IMX258_REG_IVTSYCK_DIV, 2 },
+ { IMX258_REG_PREPLLCK_VT_DIV, 3 },
+ { IMX258_REG_PLL_IVT_MPY, 100 },
+ { IMX258_REG_IOPPXCK_DIV, 10 },
+ { IMX258_REG_IOPSYCK_DIV, 1 },
+ { IMX258_REG_PREPLLCK_OP_DIV, 2 },
+ { IMX258_REG_PLL_IOP_MPY, 216 },
+ { IMX258_REG_PLL_MULT_DRIV, 0 },
+
+ { IMX258_REG_CSI_LANE_MODE, 1 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 640 * 2 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 },
+};
+
+static const struct cci_reg_sequence mipi_640mbps_19_2mhz_4l[] = {
+ { IMX258_REG_EXCK_FREQ, 0x1333 },
+ { IMX258_REG_IVTPXCK_DIV, 5 },
+ { IMX258_REG_IVTSYCK_DIV, 2 },
+ { IMX258_REG_PREPLLCK_VT_DIV, 3 },
+ { IMX258_REG_PLL_IVT_MPY, 100 },
+ { IMX258_REG_IOPPXCK_DIV, 10 },
+ { IMX258_REG_IOPSYCK_DIV, 1 },
+ { IMX258_REG_PREPLLCK_OP_DIV, 2 },
+ { IMX258_REG_PLL_IOP_MPY, 216 },
+ { IMX258_REG_PLL_MULT_DRIV, 0 },
+
+ { IMX258_REG_CSI_LANE_MODE, 3 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 640 * 4 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 },
};
-/* 4208x3118 needs 1267Mbps/lane, 4 lanes */
-static const struct imx258_reg mipi_data_rate_1267mbps[] = {
- { 0x0301, 0x05 },
- { 0x0303, 0x02 },
- { 0x0305, 0x03 },
- { 0x0306, 0x00 },
- { 0x0307, 0xC6 },
- { 0x0309, 0x0A },
- { 0x030B, 0x01 },
- { 0x030D, 0x02 },
- { 0x030E, 0x00 },
- { 0x030F, 0xD8 },
- { 0x0310, 0x00 },
- { 0x0820, 0x13 },
- { 0x0821, 0x4C },
- { 0x0822, 0xCC },
- { 0x0823, 0xCC },
+static const struct cci_reg_sequence mipi_642mbps_24mhz_2l[] = {
+ { IMX258_REG_EXCK_FREQ, 0x1800 },
+ { IMX258_REG_IVTPXCK_DIV, 5 },
+ { IMX258_REG_IVTSYCK_DIV, 2 },
+ { IMX258_REG_PREPLLCK_VT_DIV, 4 },
+ { IMX258_REG_PLL_IVT_MPY, 107 },
+ { IMX258_REG_IOPPXCK_DIV, 10 },
+ { IMX258_REG_IOPSYCK_DIV, 1 },
+ { IMX258_REG_PREPLLCK_OP_DIV, 2 },
+ { IMX258_REG_PLL_IOP_MPY, 216 },
+ { IMX258_REG_PLL_MULT_DRIV, 0 },
+
+ { IMX258_REG_CSI_LANE_MODE, 1 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 642 * 2 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 },
};
-static const struct imx258_reg mipi_data_rate_640mbps[] = {
- { 0x0301, 0x05 },
- { 0x0303, 0x02 },
- { 0x0305, 0x03 },
- { 0x0306, 0x00 },
- { 0x0307, 0x64 },
- { 0x0309, 0x0A },
- { 0x030B, 0x01 },
- { 0x030D, 0x02 },
- { 0x030E, 0x00 },
- { 0x030F, 0xD8 },
- { 0x0310, 0x00 },
- { 0x0820, 0x0A },
- { 0x0821, 0x00 },
- { 0x0822, 0x00 },
- { 0x0823, 0x00 },
+static const struct cci_reg_sequence mipi_642mbps_24mhz_4l[] = {
+ { IMX258_REG_EXCK_FREQ, 0x1800 },
+ { IMX258_REG_IVTPXCK_DIV, 5 },
+ { IMX258_REG_IVTSYCK_DIV, 2 },
+ { IMX258_REG_PREPLLCK_VT_DIV, 4 },
+ { IMX258_REG_PLL_IVT_MPY, 107 },
+ { IMX258_REG_IOPPXCK_DIV, 10 },
+ { IMX258_REG_IOPSYCK_DIV, 1 },
+ { IMX258_REG_PREPLLCK_OP_DIV, 2 },
+ { IMX258_REG_PLL_IOP_MPY, 216 },
+ { IMX258_REG_PLL_MULT_DRIV, 0 },
+
+ { IMX258_REG_CSI_LANE_MODE, 3 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_H, 642 * 4 },
+ { IMX258_REG_REQ_LINK_BIT_RATE_MBPS_L, 0 },
};
-static const struct imx258_reg mode_4208x3118_regs[] = {
- { 0x0136, 0x13 },
- { 0x0137, 0x33 },
- { 0x3051, 0x00 },
- { 0x3052, 0x00 },
- { 0x4E21, 0x14 },
- { 0x6B11, 0xCF },
- { 0x7FF0, 0x08 },
- { 0x7FF1, 0x0F },
- { 0x7FF2, 0x08 },
- { 0x7FF3, 0x1B },
- { 0x7FF4, 0x23 },
- { 0x7FF5, 0x60 },
- { 0x7FF6, 0x00 },
- { 0x7FF7, 0x01 },
- { 0x7FF8, 0x00 },
- { 0x7FF9, 0x78 },
- { 0x7FFA, 0x00 },
- { 0x7FFB, 0x00 },
- { 0x7FFC, 0x00 },
- { 0x7FFD, 0x00 },
- { 0x7FFE, 0x00 },
- { 0x7FFF, 0x03 },
- { 0x7F76, 0x03 },
- { 0x7F77, 0xFE },
- { 0x7FA8, 0x03 },
- { 0x7FA9, 0xFE },
- { 0x7B24, 0x81 },
- { 0x7B25, 0x00 },
- { 0x6564, 0x07 },
- { 0x6B0D, 0x41 },
- { 0x653D, 0x04 },
- { 0x6B05, 0x8C },
- { 0x6B06, 0xF9 },
- { 0x6B08, 0x65 },
- { 0x6B09, 0xFC },
- { 0x6B0A, 0xCF },
- { 0x6B0B, 0xD2 },
- { 0x6700, 0x0E },
- { 0x6707, 0x0E },
- { 0x9104, 0x00 },
- { 0x4648, 0x7F },
- { 0x7420, 0x00 },
- { 0x7421, 0x1C },
- { 0x7422, 0x00 },
- { 0x7423, 0xD7 },
- { 0x5F04, 0x00 },
- { 0x5F05, 0xED },
- { 0x0112, 0x0A },
- { 0x0113, 0x0A },
- { 0x0114, 0x03 },
- { 0x0342, 0x14 },
- { 0x0343, 0xE8 },
- { 0x0340, 0x0C },
- { 0x0341, 0x50 },
- { 0x0344, 0x00 },
- { 0x0345, 0x00 },
- { 0x0346, 0x00 },
- { 0x0347, 0x00 },
- { 0x0348, 0x10 },
- { 0x0349, 0x6F },
- { 0x034A, 0x0C },
- { 0x034B, 0x2E },
- { 0x0381, 0x01 },
- { 0x0383, 0x01 },
- { 0x0385, 0x01 },
- { 0x0387, 0x01 },
- { 0x0900, 0x00 },
- { 0x0901, 0x11 },
- { 0x0401, 0x00 },
- { 0x0404, 0x00 },
- { 0x0405, 0x10 },
- { 0x0408, 0x00 },
- { 0x0409, 0x00 },
- { 0x040A, 0x00 },
- { 0x040B, 0x00 },
- { 0x040C, 0x10 },
- { 0x040D, 0x70 },
- { 0x040E, 0x0C },
- { 0x040F, 0x30 },
- { 0x3038, 0x00 },
- { 0x303A, 0x00 },
- { 0x303B, 0x10 },
- { 0x300D, 0x00 },
- { 0x034C, 0x10 },
- { 0x034D, 0x70 },
- { 0x034E, 0x0C },
- { 0x034F, 0x30 },
- { 0x0350, 0x01 },
- { 0x0202, 0x0C },
- { 0x0203, 0x46 },
- { 0x0204, 0x00 },
- { 0x0205, 0x00 },
- { 0x020E, 0x01 },
- { 0x020F, 0x00 },
- { 0x0210, 0x01 },
- { 0x0211, 0x00 },
- { 0x0212, 0x01 },
- { 0x0213, 0x00 },
- { 0x0214, 0x01 },
- { 0x0215, 0x00 },
- { 0x7BCD, 0x00 },
- { 0x94DC, 0x20 },
- { 0x94DD, 0x20 },
- { 0x94DE, 0x20 },
- { 0x95DC, 0x20 },
- { 0x95DD, 0x20 },
- { 0x95DE, 0x20 },
- { 0x7FB0, 0x00 },
- { 0x9010, 0x3E },
- { 0x9419, 0x50 },
- { 0x941B, 0x50 },
- { 0x9519, 0x50 },
- { 0x951B, 0x50 },
- { 0x3030, 0x00 },
- { 0x3032, 0x00 },
- { 0x0220, 0x00 },
+static const struct cci_reg_sequence mode_common_regs[] = {
+ { CCI_REG8(0x3051), 0x00 },
+ { CCI_REG8(0x6B11), 0xCF },
+ { CCI_REG8(0x7FF0), 0x08 },
+ { CCI_REG8(0x7FF1), 0x0F },
+ { CCI_REG8(0x7FF2), 0x08 },
+ { CCI_REG8(0x7FF3), 0x1B },
+ { CCI_REG8(0x7FF4), 0x23 },
+ { CCI_REG8(0x7FF5), 0x60 },
+ { CCI_REG8(0x7FF6), 0x00 },
+ { CCI_REG8(0x7FF7), 0x01 },
+ { CCI_REG8(0x7FF8), 0x00 },
+ { CCI_REG8(0x7FF9), 0x78 },
+ { CCI_REG8(0x7FFA), 0x00 },
+ { CCI_REG8(0x7FFB), 0x00 },
+ { CCI_REG8(0x7FFC), 0x00 },
+ { CCI_REG8(0x7FFD), 0x00 },
+ { CCI_REG8(0x7FFE), 0x00 },
+ { CCI_REG8(0x7FFF), 0x03 },
+ { CCI_REG8(0x7F76), 0x03 },
+ { CCI_REG8(0x7F77), 0xFE },
+ { CCI_REG8(0x7FA8), 0x03 },
+ { CCI_REG8(0x7FA9), 0xFE },
+ { CCI_REG8(0x7B24), 0x81 },
+ { CCI_REG8(0x6564), 0x07 },
+ { CCI_REG8(0x6B0D), 0x41 },
+ { CCI_REG8(0x653D), 0x04 },
+ { CCI_REG8(0x6B05), 0x8C },
+ { CCI_REG8(0x6B06), 0xF9 },
+ { CCI_REG8(0x6B08), 0x65 },
+ { CCI_REG8(0x6B09), 0xFC },
+ { CCI_REG8(0x6B0A), 0xCF },
+ { CCI_REG8(0x6B0B), 0xD2 },
+ { CCI_REG8(0x6700), 0x0E },
+ { CCI_REG8(0x6707), 0x0E },
+ { CCI_REG8(0x9104), 0x00 },
+ { CCI_REG8(0x4648), 0x7F },
+ { CCI_REG8(0x7420), 0x00 },
+ { CCI_REG8(0x7421), 0x1C },
+ { CCI_REG8(0x7422), 0x00 },
+ { CCI_REG8(0x7423), 0xD7 },
+ { CCI_REG8(0x5F04), 0x00 },
+ { CCI_REG8(0x5F05), 0xED },
+ {IMX258_REG_CSI_DT_FMT, 0x0a0a},
+ {IMX258_REG_LINE_LENGTH_PCK, 5352},
+ {IMX258_REG_X_ADD_STA, 0},
+ {IMX258_REG_Y_ADD_STA, 0},
+ {IMX258_REG_X_ADD_END, 4207},
+ {IMX258_REG_Y_ADD_END, 3119},
+ {IMX258_REG_X_EVN_INC, 1},
+ {IMX258_REG_X_ODD_INC, 1},
+ {IMX258_REG_Y_EVN_INC, 1},
+ {IMX258_REG_Y_ODD_INC, 1},
+ {IMX258_REG_DIG_CROP_X_OFFSET, 0},
+ {IMX258_REG_DIG_CROP_Y_OFFSET, 0},
+ {IMX258_REG_DIG_CROP_IMAGE_WIDTH, 4208},
+ {IMX258_REG_SCALE_MODE_EXT, 0},
+ {IMX258_REG_SCALE_M_EXT, 16},
+ {IMX258_REG_FORCE_FD_SUM, 0},
+ {IMX258_REG_FRM_LENGTH_CTL, 0},
+ {IMX258_REG_ANALOG_GAIN, 0},
+ {IMX258_REG_GR_DIGITAL_GAIN, 256},
+ {IMX258_REG_R_DIGITAL_GAIN, 256},
+ {IMX258_REG_B_DIGITAL_GAIN, 256},
+ {IMX258_REG_GB_DIGITAL_GAIN, 256},
+ {IMX258_REG_AF_WINDOW_MODE, 0},
+ { CCI_REG8(0x94DC), 0x20 },
+ { CCI_REG8(0x94DD), 0x20 },
+ { CCI_REG8(0x94DE), 0x20 },
+ { CCI_REG8(0x95DC), 0x20 },
+ { CCI_REG8(0x95DD), 0x20 },
+ { CCI_REG8(0x95DE), 0x20 },
+ { CCI_REG8(0x7FB0), 0x00 },
+ { CCI_REG8(0x9010), 0x3E },
+ { CCI_REG8(0x9419), 0x50 },
+ { CCI_REG8(0x941B), 0x50 },
+ { CCI_REG8(0x9519), 0x50 },
+ { CCI_REG8(0x951B), 0x50 },
+ {IMX258_REG_PHASE_PIX_OUTEN, 0},
+ {IMX258_REG_PDPIX_DATA_RATE, 0},
+ {IMX258_REG_HDR, 0},
};
-static const struct imx258_reg mode_2104_1560_regs[] = {
- { 0x0136, 0x13 },
- { 0x0137, 0x33 },
- { 0x3051, 0x00 },
- { 0x3052, 0x00 },
- { 0x4E21, 0x14 },
- { 0x6B11, 0xCF },
- { 0x7FF0, 0x08 },
- { 0x7FF1, 0x0F },
- { 0x7FF2, 0x08 },
- { 0x7FF3, 0x1B },
- { 0x7FF4, 0x23 },
- { 0x7FF5, 0x60 },
- { 0x7FF6, 0x00 },
- { 0x7FF7, 0x01 },
- { 0x7FF8, 0x00 },
- { 0x7FF9, 0x78 },
- { 0x7FFA, 0x00 },
- { 0x7FFB, 0x00 },
- { 0x7FFC, 0x00 },
- { 0x7FFD, 0x00 },
- { 0x7FFE, 0x00 },
- { 0x7FFF, 0x03 },
- { 0x7F76, 0x03 },
- { 0x7F77, 0xFE },
- { 0x7FA8, 0x03 },
- { 0x7FA9, 0xFE },
- { 0x7B24, 0x81 },
- { 0x7B25, 0x00 },
- { 0x6564, 0x07 },
- { 0x6B0D, 0x41 },
- { 0x653D, 0x04 },
- { 0x6B05, 0x8C },
- { 0x6B06, 0xF9 },
- { 0x6B08, 0x65 },
- { 0x6B09, 0xFC },
- { 0x6B0A, 0xCF },
- { 0x6B0B, 0xD2 },
- { 0x6700, 0x0E },
- { 0x6707, 0x0E },
- { 0x9104, 0x00 },
- { 0x4648, 0x7F },
- { 0x7420, 0x00 },
- { 0x7421, 0x1C },
- { 0x7422, 0x00 },
- { 0x7423, 0xD7 },
- { 0x5F04, 0x00 },
- { 0x5F05, 0xED },
- { 0x0112, 0x0A },
- { 0x0113, 0x0A },
- { 0x0114, 0x03 },
- { 0x0342, 0x14 },
- { 0x0343, 0xE8 },
- { 0x0340, 0x06 },
- { 0x0341, 0x38 },
- { 0x0344, 0x00 },
- { 0x0345, 0x00 },
- { 0x0346, 0x00 },
- { 0x0347, 0x00 },
- { 0x0348, 0x10 },
- { 0x0349, 0x6F },
- { 0x034A, 0x0C },
- { 0x034B, 0x2E },
- { 0x0381, 0x01 },
- { 0x0383, 0x01 },
- { 0x0385, 0x01 },
- { 0x0387, 0x01 },
- { 0x0900, 0x01 },
- { 0x0901, 0x12 },
- { 0x0401, 0x01 },
- { 0x0404, 0x00 },
- { 0x0405, 0x20 },
- { 0x0408, 0x00 },
- { 0x0409, 0x02 },
- { 0x040A, 0x00 },
- { 0x040B, 0x00 },
- { 0x040C, 0x10 },
- { 0x040D, 0x6A },
- { 0x040E, 0x06 },
- { 0x040F, 0x18 },
- { 0x3038, 0x00 },
- { 0x303A, 0x00 },
- { 0x303B, 0x10 },
- { 0x300D, 0x00 },
- { 0x034C, 0x08 },
- { 0x034D, 0x38 },
- { 0x034E, 0x06 },
- { 0x034F, 0x18 },
- { 0x0350, 0x01 },
- { 0x0202, 0x06 },
- { 0x0203, 0x2E },
- { 0x0204, 0x00 },
- { 0x0205, 0x00 },
- { 0x020E, 0x01 },
- { 0x020F, 0x00 },
- { 0x0210, 0x01 },
- { 0x0211, 0x00 },
- { 0x0212, 0x01 },
- { 0x0213, 0x00 },
- { 0x0214, 0x01 },
- { 0x0215, 0x00 },
- { 0x7BCD, 0x01 },
- { 0x94DC, 0x20 },
- { 0x94DD, 0x20 },
- { 0x94DE, 0x20 },
- { 0x95DC, 0x20 },
- { 0x95DD, 0x20 },
- { 0x95DE, 0x20 },
- { 0x7FB0, 0x00 },
- { 0x9010, 0x3E },
- { 0x9419, 0x50 },
- { 0x941B, 0x50 },
- { 0x9519, 0x50 },
- { 0x951B, 0x50 },
- { 0x3030, 0x00 },
- { 0x3032, 0x00 },
- { 0x0220, 0x00 },
+static const struct cci_reg_sequence mode_4208x3120_regs[] = {
+ {IMX258_REG_BINNING_MODE, 0},
+ {IMX258_REG_BINNING_TYPE_V, 0x11},
+ {IMX258_REG_SCALE_MODE, 0},
+ {IMX258_REG_SCALE_M, 16},
+ {IMX258_REG_DIG_CROP_IMAGE_HEIGHT, 3120},
+ {IMX258_REG_X_OUT_SIZE, 4208},
+ {IMX258_REG_Y_OUT_SIZE, 3120},
};
-static const struct imx258_reg mode_1048_780_regs[] = {
- { 0x0136, 0x13 },
- { 0x0137, 0x33 },
- { 0x3051, 0x00 },
- { 0x3052, 0x00 },
- { 0x4E21, 0x14 },
- { 0x6B11, 0xCF },
- { 0x7FF0, 0x08 },
- { 0x7FF1, 0x0F },
- { 0x7FF2, 0x08 },
- { 0x7FF3, 0x1B },
- { 0x7FF4, 0x23 },
- { 0x7FF5, 0x60 },
- { 0x7FF6, 0x00 },
- { 0x7FF7, 0x01 },
- { 0x7FF8, 0x00 },
- { 0x7FF9, 0x78 },
- { 0x7FFA, 0x00 },
- { 0x7FFB, 0x00 },
- { 0x7FFC, 0x00 },
- { 0x7FFD, 0x00 },
- { 0x7FFE, 0x00 },
- { 0x7FFF, 0x03 },
- { 0x7F76, 0x03 },
- { 0x7F77, 0xFE },
- { 0x7FA8, 0x03 },
- { 0x7FA9, 0xFE },
- { 0x7B24, 0x81 },
- { 0x7B25, 0x00 },
- { 0x6564, 0x07 },
- { 0x6B0D, 0x41 },
- { 0x653D, 0x04 },
- { 0x6B05, 0x8C },
- { 0x6B06, 0xF9 },
- { 0x6B08, 0x65 },
- { 0x6B09, 0xFC },
- { 0x6B0A, 0xCF },
- { 0x6B0B, 0xD2 },
- { 0x6700, 0x0E },
- { 0x6707, 0x0E },
- { 0x9104, 0x00 },
- { 0x4648, 0x7F },
- { 0x7420, 0x00 },
- { 0x7421, 0x1C },
- { 0x7422, 0x00 },
- { 0x7423, 0xD7 },
- { 0x5F04, 0x00 },
- { 0x5F05, 0xED },
- { 0x0112, 0x0A },
- { 0x0113, 0x0A },
- { 0x0114, 0x03 },
- { 0x0342, 0x14 },
- { 0x0343, 0xE8 },
- { 0x0340, 0x03 },
- { 0x0341, 0x4C },
- { 0x0344, 0x00 },
- { 0x0345, 0x00 },
- { 0x0346, 0x00 },
- { 0x0347, 0x00 },
- { 0x0348, 0x10 },
- { 0x0349, 0x6F },
- { 0x034A, 0x0C },
- { 0x034B, 0x2E },
- { 0x0381, 0x01 },
- { 0x0383, 0x01 },
- { 0x0385, 0x01 },
- { 0x0387, 0x01 },
- { 0x0900, 0x01 },
- { 0x0901, 0x14 },
- { 0x0401, 0x01 },
- { 0x0404, 0x00 },
- { 0x0405, 0x40 },
- { 0x0408, 0x00 },
- { 0x0409, 0x06 },
- { 0x040A, 0x00 },
- { 0x040B, 0x00 },
- { 0x040C, 0x10 },
- { 0x040D, 0x64 },
- { 0x040E, 0x03 },
- { 0x040F, 0x0C },
- { 0x3038, 0x00 },
- { 0x303A, 0x00 },
- { 0x303B, 0x10 },
- { 0x300D, 0x00 },
- { 0x034C, 0x04 },
- { 0x034D, 0x18 },
- { 0x034E, 0x03 },
- { 0x034F, 0x0C },
- { 0x0350, 0x01 },
- { 0x0202, 0x03 },
- { 0x0203, 0x42 },
- { 0x0204, 0x00 },
- { 0x0205, 0x00 },
- { 0x020E, 0x01 },
- { 0x020F, 0x00 },
- { 0x0210, 0x01 },
- { 0x0211, 0x00 },
- { 0x0212, 0x01 },
- { 0x0213, 0x00 },
- { 0x0214, 0x01 },
- { 0x0215, 0x00 },
- { 0x7BCD, 0x00 },
- { 0x94DC, 0x20 },
- { 0x94DD, 0x20 },
- { 0x94DE, 0x20 },
- { 0x95DC, 0x20 },
- { 0x95DD, 0x20 },
- { 0x95DE, 0x20 },
- { 0x7FB0, 0x00 },
- { 0x9010, 0x3E },
- { 0x9419, 0x50 },
- { 0x941B, 0x50 },
- { 0x9519, 0x50 },
- { 0x951B, 0x50 },
- { 0x3030, 0x00 },
- { 0x3032, 0x00 },
- { 0x0220, 0x00 },
+static const struct cci_reg_sequence mode_2104_1560_regs[] = {
+ {IMX258_REG_BINNING_MODE, 1},
+ {IMX258_REG_BINNING_TYPE_V, 0x12},
+ {IMX258_REG_SCALE_MODE, 1},
+ {IMX258_REG_SCALE_M, 32},
+ {IMX258_REG_DIG_CROP_IMAGE_HEIGHT, 1560},
+ {IMX258_REG_X_OUT_SIZE, 2104},
+ {IMX258_REG_Y_OUT_SIZE, 1560},
+};
+
+static const struct cci_reg_sequence mode_1048_780_regs[] = {
+ {IMX258_REG_BINNING_MODE, 1},
+ {IMX258_REG_BINNING_TYPE_V, 0x14},
+ {IMX258_REG_SCALE_MODE, 1},
+ {IMX258_REG_SCALE_M, 64},
+ {IMX258_REG_DIG_CROP_IMAGE_HEIGHT, 780},
+ {IMX258_REG_X_OUT_SIZE, 1048},
+ {IMX258_REG_Y_OUT_SIZE, 780},
+};
+
+struct imx258_variant_cfg {
+ const struct cci_reg_sequence *regs;
+ unsigned int num_regs;
+};
+
+static const struct cci_reg_sequence imx258_cfg_regs[] = {
+ { CCI_REG8(0x3052), 0x00 },
+ { CCI_REG8(0x4E21), 0x14 },
+ { CCI_REG8(0x7B25), 0x00 },
+};
+
+static const struct imx258_variant_cfg imx258_cfg = {
+ .regs = imx258_cfg_regs,
+ .num_regs = ARRAY_SIZE(imx258_cfg_regs),
+};
+
+static const struct cci_reg_sequence imx258_pdaf_cfg_regs[] = {
+ { CCI_REG8(0x3052), 0x01 },
+ { CCI_REG8(0x4E21), 0x10 },
+ { CCI_REG8(0x7B25), 0x01 },
+};
+
+static const struct imx258_variant_cfg imx258_pdaf_cfg = {
+ .regs = imx258_pdaf_cfg_regs,
+ .num_regs = ARRAY_SIZE(imx258_pdaf_cfg_regs),
+};
+
+/*
+ * The supported formats.
+ * This table MUST contain 4 entries per format, to cover the various flip
+ * combinations in the order
+ * - no flip
+ * - h flip
+ * - v flip
+ * - h&v flips
+ */
+static const u32 codes[] = {
+ /* 10-bit modes. */
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10
};
static const char * const imx258_test_pattern_menu[] = {
@@ -519,9 +479,15 @@ static const char * const imx258_test_pattern_menu[] = {
"Pseudorandom Sequence (PN9)",
};
-/* Configurations for supported link frequencies */
-#define IMX258_LINK_FREQ_634MHZ 633600000ULL
-#define IMX258_LINK_FREQ_320MHZ 320000000ULL
+/* regulator supplies */
+static const char * const imx258_supply_name[] = {
+ /* Supplies can be enabled in any order */
+ "vana", /* Analog (2.8V) supply */
+ "vdig", /* Digital Core (1.2V) supply */
+ "vif", /* IF (1.8V) supply */
+};
+
+#define IMX258_NUM_SUPPLIES ARRAY_SIZE(imx258_supply_name)
enum {
IMX258_LINK_FREQ_1267MBPS,
@@ -529,37 +495,96 @@ enum {
};
/*
- * pixel_rate = link_freq * data-rate * nr_of_lanes / bits_per_sample
- * data rate => double data rate; number of lanes => 4; bits per pixel => 10
+ * Pixel rate does not necessarily relate to link frequency on this sensor as
+ * there is a FIFO between the pixel array pipeline and the MIPI serializer.
+ * The recommendation from Sony is that the pixel array is always run with a
+ * line length of 5352 pixels, which means that there is a large amount of
+ * blanking time for the 1048x780 mode. There is no need to replicate this
+ * blanking on the CSI2 bus, and the configuration of register 0x0301 allows the
+ * divider to be altered.
+ *
+ * The actual factor between link frequency and pixel rate is in the
+ * imx258_link_cfg, so use this to convert between the two.
+ * bits per pixel being 10, and D-PHY being DDR is assumed by this function, so
+ * the value is only the combination of number of lanes and pixel clock divider.
*/
-static u64 link_freq_to_pixel_rate(u64 f)
+static u64 link_freq_to_pixel_rate(u64 f, const struct imx258_link_cfg *link_cfg)
{
- f *= 2 * 4;
+ f *= 2 * link_cfg->lf_to_pix_rate_factor;
do_div(f, 10);
return f;
}
/* Menu items for LINK_FREQ V4L2 control */
-static const s64 link_freq_menu_items[] = {
- IMX258_LINK_FREQ_634MHZ,
- IMX258_LINK_FREQ_320MHZ,
+/* Configurations for supported link frequencies */
+static const s64 link_freq_menu_items_19_2[] = {
+ 633600000ULL,
+ 320000000ULL,
};
+static const s64 link_freq_menu_items_24[] = {
+ 636000000ULL,
+ 321000000ULL,
+};
+
+#define REGS(_list) { .num_of_regs = ARRAY_SIZE(_list), .regs = _list, }
+
/* Link frequency configs */
-static const struct imx258_link_freq_config link_freq_configs[] = {
+static const struct imx258_link_freq_config link_freq_configs_19_2[] = {
[IMX258_LINK_FREQ_1267MBPS] = {
.pixels_per_line = IMX258_PPL_DEFAULT,
- .reg_list = {
- .num_of_regs = ARRAY_SIZE(mipi_data_rate_1267mbps),
- .regs = mipi_data_rate_1267mbps,
+ .link_cfg = {
+ [IMX258_2_LANE_MODE] = {
+ .lf_to_pix_rate_factor = 2 * 2,
+ .reg_list = REGS(mipi_1267mbps_19_2mhz_2l),
+ },
+ [IMX258_4_LANE_MODE] = {
+ .lf_to_pix_rate_factor = 4,
+ .reg_list = REGS(mipi_1267mbps_19_2mhz_4l),
+ },
}
},
[IMX258_LINK_FREQ_640MBPS] = {
.pixels_per_line = IMX258_PPL_DEFAULT,
- .reg_list = {
- .num_of_regs = ARRAY_SIZE(mipi_data_rate_640mbps),
- .regs = mipi_data_rate_640mbps,
+ .link_cfg = {
+ [IMX258_2_LANE_MODE] = {
+ .lf_to_pix_rate_factor = 2,
+ .reg_list = REGS(mipi_640mbps_19_2mhz_2l),
+ },
+ [IMX258_4_LANE_MODE] = {
+ .lf_to_pix_rate_factor = 4,
+ .reg_list = REGS(mipi_640mbps_19_2mhz_4l),
+ },
+ }
+ },
+};
+
+static const struct imx258_link_freq_config link_freq_configs_24[] = {
+ [IMX258_LINK_FREQ_1267MBPS] = {
+ .pixels_per_line = IMX258_PPL_DEFAULT,
+ .link_cfg = {
+ [IMX258_2_LANE_MODE] = {
+ .lf_to_pix_rate_factor = 2,
+ .reg_list = REGS(mipi_1272mbps_24mhz_2l),
+ },
+ [IMX258_4_LANE_MODE] = {
+ .lf_to_pix_rate_factor = 4,
+ .reg_list = REGS(mipi_1272mbps_24mhz_4l),
+ },
+ }
+ },
+ [IMX258_LINK_FREQ_640MBPS] = {
+ .pixels_per_line = IMX258_PPL_DEFAULT,
+ .link_cfg = {
+ [IMX258_2_LANE_MODE] = {
+ .lf_to_pix_rate_factor = 2 * 2,
+ .reg_list = REGS(mipi_642mbps_24mhz_2l),
+ },
+ [IMX258_4_LANE_MODE] = {
+ .lf_to_pix_rate_factor = 4,
+ .reg_list = REGS(mipi_642mbps_24mhz_4l),
+ },
}
},
};
@@ -568,14 +593,20 @@ static const struct imx258_link_freq_config link_freq_configs[] = {
static const struct imx258_mode supported_modes[] = {
{
.width = 4208,
- .height = 3118,
+ .height = 3120,
.vts_def = IMX258_VTS_30FPS,
.vts_min = IMX258_VTS_30FPS,
.reg_list = {
- .num_of_regs = ARRAY_SIZE(mode_4208x3118_regs),
- .regs = mode_4208x3118_regs,
+ .num_of_regs = ARRAY_SIZE(mode_4208x3120_regs),
+ .regs = mode_4208x3120_regs,
},
.link_freq_index = IMX258_LINK_FREQ_1267MBPS,
+ .crop = {
+ .left = IMX258_PIXEL_ARRAY_LEFT,
+ .top = IMX258_PIXEL_ARRAY_TOP,
+ .width = 4208,
+ .height = 3120,
+ },
},
{
.width = 2104,
@@ -587,6 +618,12 @@ static const struct imx258_mode supported_modes[] = {
.regs = mode_2104_1560_regs,
},
.link_freq_index = IMX258_LINK_FREQ_640MBPS,
+ .crop = {
+ .left = IMX258_PIXEL_ARRAY_LEFT,
+ .top = IMX258_PIXEL_ARRAY_TOP,
+ .width = 4208,
+ .height = 3120,
+ },
},
{
.width = 1048,
@@ -598,12 +635,21 @@ static const struct imx258_mode supported_modes[] = {
.regs = mode_1048_780_regs,
},
.link_freq_index = IMX258_LINK_FREQ_640MBPS,
+ .crop = {
+ .left = IMX258_PIXEL_ARRAY_LEFT,
+ .top = IMX258_PIXEL_ARRAY_TOP,
+ .width = 4208,
+ .height = 3120,
+ },
},
};
struct imx258 {
struct v4l2_subdev sd;
struct media_pad pad;
+ struct regmap *regmap;
+
+ const struct imx258_variant_cfg *variant_cfg;
struct v4l2_ctrl_handler ctrl_handler;
/* V4L2 Controls */
@@ -612,10 +658,18 @@ struct imx258 {
struct v4l2_ctrl *vblank;
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *hflip;
+ struct v4l2_ctrl *vflip;
/* Current mode */
const struct imx258_mode *cur_mode;
+ unsigned long link_freq_bitmap;
+ const struct imx258_link_freq_config *link_freq_configs;
+ const s64 *link_freq_menu_items;
+ unsigned int lane_mode_idx;
+ unsigned int csi2_flags;
+
/*
* Mutex for serialized access:
* Protect sensor module set pad format and start/stop streaming safely.
@@ -623,6 +677,7 @@ struct imx258 {
struct mutex mutex;
struct clk *clk;
+ struct regulator_bulk_data supplies[IMX258_NUM_SUPPLIES];
};
static inline struct imx258 *to_imx258(struct v4l2_subdev *_sd)
@@ -630,120 +685,66 @@ static inline struct imx258 *to_imx258(struct v4l2_subdev *_sd)
return container_of(_sd, struct imx258, sd);
}
-/* Read registers up to 2 at a time */
-static int imx258_read_reg(struct imx258 *imx258, u16 reg, u32 len, u32 *val)
+/* Get bayer order based on flip setting. */
+static u32 imx258_get_format_code(const struct imx258 *imx258)
{
- struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
- struct i2c_msg msgs[2];
- u8 addr_buf[2] = { reg >> 8, reg & 0xff };
- u8 data_buf[4] = { 0, };
- int ret;
-
- if (len > 4)
- return -EINVAL;
-
- /* Write register address */
- msgs[0].addr = client->addr;
- msgs[0].flags = 0;
- msgs[0].len = ARRAY_SIZE(addr_buf);
- msgs[0].buf = addr_buf;
-
- /* Read data from register */
- msgs[1].addr = client->addr;
- msgs[1].flags = I2C_M_RD;
- msgs[1].len = len;
- msgs[1].buf = &data_buf[4 - len];
-
- ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
- if (ret != ARRAY_SIZE(msgs))
- return -EIO;
-
- *val = get_unaligned_be32(data_buf);
-
- return 0;
-}
-
-/* Write registers up to 2 at a time */
-static int imx258_write_reg(struct imx258 *imx258, u16 reg, u32 len, u32 val)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
- u8 buf[6];
-
- if (len > 4)
- return -EINVAL;
-
- put_unaligned_be16(reg, buf);
- put_unaligned_be32(val << (8 * (4 - len)), buf + 2);
- if (i2c_master_send(client, buf, len + 2) != len + 2)
- return -EIO;
-
- return 0;
-}
-
-/* Write a list of registers */
-static int imx258_write_regs(struct imx258 *imx258,
- const struct imx258_reg *regs, u32 len)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
unsigned int i;
- int ret;
- for (i = 0; i < len; i++) {
- ret = imx258_write_reg(imx258, regs[i].address, 1,
- regs[i].val);
- if (ret) {
- dev_err_ratelimited(
- &client->dev,
- "Failed to write reg 0x%4.4x. error = %d\n",
- regs[i].address, ret);
+ lockdep_assert_held(&imx258->mutex);
- return ret;
- }
- }
+ i = (imx258->vflip->val ? 2 : 0) |
+ (imx258->hflip->val ? 1 : 0);
- return 0;
+ return codes[i];
}
/* Open sub-device */
static int imx258_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
+ struct imx258 *imx258 = to_imx258(sd);
struct v4l2_mbus_framefmt *try_fmt =
v4l2_subdev_state_get_format(fh->state, 0);
+ struct v4l2_rect *try_crop;
/* Initialize try_fmt */
try_fmt->width = supported_modes[0].width;
try_fmt->height = supported_modes[0].height;
- try_fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+ try_fmt->code = imx258_get_format_code(imx258);
try_fmt->field = V4L2_FIELD_NONE;
+ /* Initialize try_crop */
+ try_crop = v4l2_subdev_state_get_crop(fh->state, 0);
+ try_crop->left = IMX258_PIXEL_ARRAY_LEFT;
+ try_crop->top = IMX258_PIXEL_ARRAY_TOP;
+ try_crop->width = IMX258_PIXEL_ARRAY_WIDTH;
+ try_crop->height = IMX258_PIXEL_ARRAY_HEIGHT;
+
return 0;
}
-static int imx258_update_digital_gain(struct imx258 *imx258, u32 len, u32 val)
+static int imx258_update_digital_gain(struct imx258 *imx258, u32 val)
{
- int ret;
+ int ret = 0;
- ret = imx258_write_reg(imx258, IMX258_REG_GR_DIGITAL_GAIN,
- IMX258_REG_VALUE_16BIT,
- val);
- if (ret)
- return ret;
- ret = imx258_write_reg(imx258, IMX258_REG_GB_DIGITAL_GAIN,
- IMX258_REG_VALUE_16BIT,
- val);
- if (ret)
- return ret;
- ret = imx258_write_reg(imx258, IMX258_REG_R_DIGITAL_GAIN,
- IMX258_REG_VALUE_16BIT,
- val);
- if (ret)
- return ret;
- ret = imx258_write_reg(imx258, IMX258_REG_B_DIGITAL_GAIN,
- IMX258_REG_VALUE_16BIT,
- val);
- if (ret)
- return ret;
- return 0;
+ cci_write(imx258->regmap, IMX258_REG_GR_DIGITAL_GAIN, val, &ret);
+ cci_write(imx258->regmap, IMX258_REG_GB_DIGITAL_GAIN, val, &ret);
+ cci_write(imx258->regmap, IMX258_REG_R_DIGITAL_GAIN, val, &ret);
+ cci_write(imx258->regmap, IMX258_REG_B_DIGITAL_GAIN, val, &ret);
+
+ return ret;
+}
+
+static void imx258_adjust_exposure_range(struct imx258 *imx258)
+{
+ int exposure_max, exposure_def;
+
+ /* Honour the VBLANK limits when setting exposure. */
+ exposure_max = imx258->cur_mode->height + imx258->vblank->val -
+ IMX258_EXPOSURE_OFFSET;
+ exposure_def = min(exposure_max, imx258->exposure->val);
+ __v4l2_ctrl_modify_range(imx258->exposure, imx258->exposure->minimum,
+ exposure_max, imx258->exposure->step,
+ exposure_def);
}
static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
@@ -754,6 +755,13 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
int ret = 0;
/*
+ * The VBLANK control may change the limits of usable exposure, so check
+ * and adjust if necessary.
+ */
+ if (ctrl->id == V4L2_CID_VBLANK)
+ imx258_adjust_exposure_range(imx258);
+
+ /*
* Applying V4L2 control value only happens
* when power is up for streaming
*/
@@ -762,44 +770,46 @@ static int imx258_set_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case V4L2_CID_ANALOGUE_GAIN:
- ret = imx258_write_reg(imx258, IMX258_REG_ANALOG_GAIN,
- IMX258_REG_VALUE_16BIT,
- ctrl->val);
+ ret = cci_write(imx258->regmap, IMX258_REG_ANALOG_GAIN,
+ ctrl->val, NULL);
break;
case V4L2_CID_EXPOSURE:
- ret = imx258_write_reg(imx258, IMX258_REG_EXPOSURE,
- IMX258_REG_VALUE_16BIT,
- ctrl->val);
+ ret = cci_write(imx258->regmap, IMX258_REG_EXPOSURE,
+ ctrl->val, NULL);
break;
case V4L2_CID_DIGITAL_GAIN:
- ret = imx258_update_digital_gain(imx258, IMX258_REG_VALUE_16BIT,
- ctrl->val);
+ ret = imx258_update_digital_gain(imx258, ctrl->val);
break;
case V4L2_CID_TEST_PATTERN:
- ret = imx258_write_reg(imx258, IMX258_REG_TEST_PATTERN,
- IMX258_REG_VALUE_16BIT,
- ctrl->val);
- ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
- IMX258_REG_VALUE_08BIT,
- !ctrl->val ? REG_CONFIG_MIRROR_FLIP :
- REG_CONFIG_FLIP_TEST_PATTERN);
+ ret = cci_write(imx258->regmap, IMX258_REG_TEST_PATTERN,
+ ctrl->val, NULL);
break;
case V4L2_CID_WIDE_DYNAMIC_RANGE:
if (!ctrl->val) {
- ret = imx258_write_reg(imx258, IMX258_REG_HDR,
- IMX258_REG_VALUE_08BIT,
- IMX258_HDR_RATIO_MIN);
+ ret = cci_write(imx258->regmap, IMX258_REG_HDR,
+ IMX258_HDR_RATIO_MIN, NULL);
} else {
- ret = imx258_write_reg(imx258, IMX258_REG_HDR,
- IMX258_REG_VALUE_08BIT,
- IMX258_HDR_ON);
+ ret = cci_write(imx258->regmap, IMX258_REG_HDR,
+ IMX258_HDR_ON, NULL);
if (ret)
break;
- ret = imx258_write_reg(imx258, IMX258_REG_HDR_RATIO,
- IMX258_REG_VALUE_08BIT,
- BIT(IMX258_HDR_RATIO_MAX));
+ ret = cci_write(imx258->regmap, IMX258_REG_HDR_RATIO,
+ BIT(IMX258_HDR_RATIO_MAX), NULL);
}
break;
+ case V4L2_CID_VBLANK:
+ ret = cci_write(imx258->regmap, IMX258_REG_FRM_LENGTH_LINES,
+ imx258->cur_mode->height + ctrl->val, NULL);
+ break;
+ case V4L2_CID_VFLIP:
+ case V4L2_CID_HFLIP:
+ ret = cci_write(imx258->regmap, REG_MIRROR_FLIP_CONTROL,
+ (imx258->hflip->val ?
+ REG_CONFIG_MIRROR_HFLIP : 0) |
+ (imx258->vflip->val ?
+ REG_CONFIG_MIRROR_VFLIP : 0),
+ NULL);
+ break;
default:
dev_info(&client->dev,
"ctrl(id:0x%x,val:0x%x) is not handled\n",
@@ -821,11 +831,13 @@ static int imx258_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- /* Only one bayer order(GRBG) is supported */
+ struct imx258 *imx258 = to_imx258(sd);
+
+ /* Only one bayer format (10 bit) is supported */
if (code->index > 0)
return -EINVAL;
- code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
+ code->code = imx258_get_format_code(imx258);
return 0;
}
@@ -834,10 +846,11 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_size_enum *fse)
{
+ struct imx258 *imx258 = to_imx258(sd);
if (fse->index >= ARRAY_SIZE(supported_modes))
return -EINVAL;
- if (fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
+ if (fse->code != imx258_get_format_code(imx258))
return -EINVAL;
fse->min_width = supported_modes[fse->index].width;
@@ -848,12 +861,13 @@ static int imx258_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static void imx258_update_pad_format(const struct imx258_mode *mode,
+static void imx258_update_pad_format(struct imx258 *imx258,
+ const struct imx258_mode *mode,
struct v4l2_subdev_format *fmt)
{
fmt->format.width = mode->width;
fmt->format.height = mode->height;
- fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
+ fmt->format.code = imx258_get_format_code(imx258);
fmt->format.field = V4L2_FIELD_NONE;
}
@@ -865,7 +879,7 @@ static int __imx258_get_pad_format(struct imx258 *imx258,
fmt->format = *v4l2_subdev_state_get_format(sd_state,
fmt->pad);
else
- imx258_update_pad_format(imx258->cur_mode, fmt);
+ imx258_update_pad_format(imx258, imx258->cur_mode, fmt);
return 0;
}
@@ -889,8 +903,10 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
struct v4l2_subdev_format *fmt)
{
struct imx258 *imx258 = to_imx258(sd);
- const struct imx258_mode *mode;
+ const struct imx258_link_freq_config *link_freq_cfgs;
+ const struct imx258_link_cfg *link_cfg;
struct v4l2_mbus_framefmt *framefmt;
+ const struct imx258_mode *mode;
s32 vblank_def;
s32 vblank_min;
s64 h_blank;
@@ -899,13 +915,12 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
mutex_lock(&imx258->mutex);
- /* Only one raw bayer(GBRG) order is supported */
- fmt->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
+ fmt->format.code = imx258_get_format_code(imx258);
mode = v4l2_find_nearest_size(supported_modes,
ARRAY_SIZE(supported_modes), width, height,
fmt->format.width, fmt->format.height);
- imx258_update_pad_format(mode, fmt);
+ imx258_update_pad_format(imx258, mode, fmt);
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) {
framefmt = v4l2_subdev_state_get_format(sd_state, fmt->pad);
*framefmt = fmt->format;
@@ -913,9 +928,14 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
imx258->cur_mode = mode;
__v4l2_ctrl_s_ctrl(imx258->link_freq, mode->link_freq_index);
- link_freq = link_freq_menu_items[mode->link_freq_index];
- pixel_rate = link_freq_to_pixel_rate(link_freq);
- __v4l2_ctrl_s_ctrl_int64(imx258->pixel_rate, pixel_rate);
+ link_freq = imx258->link_freq_menu_items[mode->link_freq_index];
+ link_freq_cfgs =
+ &imx258->link_freq_configs[mode->link_freq_index];
+
+ link_cfg = &link_freq_cfgs->link_cfg[imx258->lane_mode_idx];
+ pixel_rate = link_freq_to_pixel_rate(link_freq, link_cfg);
+ __v4l2_ctrl_modify_range(imx258->pixel_rate, pixel_rate,
+ pixel_rate, 1, pixel_rate);
/* Update limits and set FPS to default */
vblank_def = imx258->cur_mode->vts_def -
imx258->cur_mode->height;
@@ -927,7 +947,7 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
vblank_def);
__v4l2_ctrl_s_ctrl(imx258->vblank, vblank_def);
h_blank =
- link_freq_configs[mode->link_freq_index].pixels_per_line
+ imx258->link_freq_configs[mode->link_freq_index].pixels_per_line
- imx258->cur_mode->width;
__v4l2_ctrl_modify_range(imx258->hblank, h_blank,
h_blank, 1, h_blank);
@@ -938,48 +958,125 @@ static int imx258_set_pad_format(struct v4l2_subdev *sd,
return 0;
}
+static const struct v4l2_rect *
+__imx258_get_pad_crop(struct imx258 *imx258,
+ struct v4l2_subdev_state *sd_state,
+ unsigned int pad, enum v4l2_subdev_format_whence which)
+{
+ switch (which) {
+ case V4L2_SUBDEV_FORMAT_TRY:
+ return v4l2_subdev_state_get_crop(sd_state, pad);
+ case V4L2_SUBDEV_FORMAT_ACTIVE:
+ return &imx258->cur_mode->crop;
+ }
+
+ return NULL;
+}
+
+static int imx258_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ struct imx258 *imx258 = to_imx258(sd);
+
+ mutex_lock(&imx258->mutex);
+ sel->r = *__imx258_get_pad_crop(imx258, sd_state, sel->pad,
+ sel->which);
+ mutex_unlock(&imx258->mutex);
+
+ return 0;
+ }
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r.left = 0;
+ sel->r.top = 0;
+ sel->r.width = IMX258_NATIVE_WIDTH;
+ sel->r.height = IMX258_NATIVE_HEIGHT;
+
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r.left = IMX258_PIXEL_ARRAY_LEFT;
+ sel->r.top = IMX258_PIXEL_ARRAY_TOP;
+ sel->r.width = IMX258_PIXEL_ARRAY_WIDTH;
+ sel->r.height = IMX258_PIXEL_ARRAY_HEIGHT;
+
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
/* Start streaming */
static int imx258_start_streaming(struct imx258 *imx258)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
const struct imx258_reg_list *reg_list;
+ const struct imx258_link_freq_config *link_freq_cfg;
int ret, link_freq_index;
+ ret = cci_write(imx258->regmap, IMX258_REG_RESET, 0x01, NULL);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to reset sensor\n", __func__);
+ return ret;
+ }
+
+ /* 12ms is required from poweron to standby */
+ fsleep(12000);
+
/* Setup PLL */
link_freq_index = imx258->cur_mode->link_freq_index;
- reg_list = &link_freq_configs[link_freq_index].reg_list;
- ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
+ link_freq_cfg = &imx258->link_freq_configs[link_freq_index];
+
+ reg_list = &link_freq_cfg->link_cfg[imx258->lane_mode_idx].reg_list;
+ ret = cci_multi_reg_write(imx258->regmap, reg_list->regs, reg_list->num_of_regs, NULL);
if (ret) {
dev_err(&client->dev, "%s failed to set plls\n", __func__);
return ret;
}
- /* Apply default values of current mode */
- reg_list = &imx258->cur_mode->reg_list;
- ret = imx258_write_regs(imx258, reg_list->regs, reg_list->num_of_regs);
+ ret = cci_multi_reg_write(imx258->regmap, mode_common_regs,
+ ARRAY_SIZE(mode_common_regs), NULL);
if (ret) {
- dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ dev_err(&client->dev, "%s failed to set common regs\n", __func__);
return ret;
}
- /* Set Orientation be 180 degree */
- ret = imx258_write_reg(imx258, REG_MIRROR_FLIP_CONTROL,
- IMX258_REG_VALUE_08BIT, REG_CONFIG_MIRROR_FLIP);
+ ret = cci_multi_reg_write(imx258->regmap, imx258->variant_cfg->regs,
+ imx258->variant_cfg->num_regs, NULL);
if (ret) {
- dev_err(&client->dev, "%s failed to set orientation\n",
+ dev_err(&client->dev, "%s failed to set variant config\n",
__func__);
return ret;
}
+ ret = cci_write(imx258->regmap, IMX258_CLK_BLANK_STOP,
+ !!(imx258->csi2_flags & V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK),
+ NULL);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set clock lane mode\n", __func__);
+ return ret;
+ }
+
+ /* Apply default values of current mode */
+ reg_list = &imx258->cur_mode->reg_list;
+ ret = cci_multi_reg_write(imx258->regmap, reg_list->regs, reg_list->num_of_regs, NULL);
+ if (ret) {
+ dev_err(&client->dev, "%s failed to set mode\n", __func__);
+ return ret;
+ }
+
/* Apply customized values from user */
ret = __v4l2_ctrl_handler_setup(imx258->sd.ctrl_handler);
if (ret)
return ret;
/* set stream on register */
- return imx258_write_reg(imx258, IMX258_REG_MODE_SELECT,
- IMX258_REG_VALUE_08BIT,
- IMX258_MODE_STREAMING);
+ return cci_write(imx258->regmap, IMX258_REG_MODE_SELECT,
+ IMX258_MODE_STREAMING, NULL);
}
/* Stop streaming */
@@ -989,8 +1086,8 @@ static int imx258_stop_streaming(struct imx258 *imx258)
int ret;
/* set stream off register */
- ret = imx258_write_reg(imx258, IMX258_REG_MODE_SELECT,
- IMX258_REG_VALUE_08BIT, IMX258_MODE_STANDBY);
+ ret = cci_write(imx258->regmap, IMX258_REG_MODE_SELECT,
+ IMX258_MODE_STANDBY, NULL);
if (ret)
dev_err(&client->dev, "%s failed to set stream\n", __func__);
@@ -1007,9 +1104,19 @@ static int imx258_power_on(struct device *dev)
struct imx258 *imx258 = to_imx258(sd);
int ret;
+ ret = regulator_bulk_enable(IMX258_NUM_SUPPLIES,
+ imx258->supplies);
+ if (ret) {
+ dev_err(dev, "%s: failed to enable regulators\n",
+ __func__);
+ return ret;
+ }
+
ret = clk_prepare_enable(imx258->clk);
- if (ret)
+ if (ret) {
dev_err(dev, "failed to enable clock\n");
+ regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies);
+ }
return ret;
}
@@ -1020,6 +1127,7 @@ static int imx258_power_off(struct device *dev)
struct imx258 *imx258 = to_imx258(sd);
clk_disable_unprepare(imx258->clk);
+ regulator_bulk_disable(IMX258_NUM_SUPPLIES, imx258->supplies);
return 0;
}
@@ -1066,10 +1174,10 @@ static int imx258_identify_module(struct imx258 *imx258)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
int ret;
- u32 val;
+ u64 val;
- ret = imx258_read_reg(imx258, IMX258_REG_CHIP_ID,
- IMX258_REG_VALUE_16BIT, &val);
+ ret = cci_read(imx258->regmap, IMX258_REG_CHIP_ID,
+ &val, NULL);
if (ret) {
dev_err(&client->dev, "failed to read chip id %x\n",
IMX258_CHIP_ID);
@@ -1077,7 +1185,7 @@ static int imx258_identify_module(struct imx258 *imx258)
}
if (val != IMX258_CHIP_ID) {
- dev_err(&client->dev, "chip id mismatch: %x!=%x\n",
+ dev_err(&client->dev, "chip id mismatch: %x!=%llx\n",
IMX258_CHIP_ID, val);
return -EIO;
}
@@ -1094,6 +1202,7 @@ static const struct v4l2_subdev_pad_ops imx258_pad_ops = {
.get_fmt = imx258_get_pad_format,
.set_fmt = imx258_set_pad_format,
.enum_frame_size = imx258_enum_frame_size,
+ .get_selection = imx258_get_selection,
};
static const struct v4l2_subdev_ops imx258_subdev_ops = {
@@ -1109,13 +1218,13 @@ static const struct v4l2_subdev_internal_ops imx258_internal_ops = {
static int imx258_init_controls(struct imx258 *imx258)
{
struct i2c_client *client = v4l2_get_subdevdata(&imx258->sd);
+ const struct imx258_link_freq_config *link_freq_cfgs;
struct v4l2_fwnode_device_properties props;
struct v4l2_ctrl_handler *ctrl_hdlr;
- struct v4l2_ctrl *vflip, *hflip;
+ const struct imx258_link_cfg *link_cfg;
s64 vblank_def;
s64 vblank_min;
- s64 pixel_rate_min;
- s64 pixel_rate_max;
+ s64 pixel_rate;
int ret;
ctrl_hdlr = &imx258->ctrl_handler;
@@ -1128,32 +1237,33 @@ static int imx258_init_controls(struct imx258 *imx258)
imx258->link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr,
&imx258_ctrl_ops,
V4L2_CID_LINK_FREQ,
- ARRAY_SIZE(link_freq_menu_items) - 1,
+ ARRAY_SIZE(link_freq_menu_items_19_2) - 1,
0,
- link_freq_menu_items);
+ imx258->link_freq_menu_items);
if (imx258->link_freq)
imx258->link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- /* The driver only supports one bayer order and flips by default. */
- hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
- V4L2_CID_HFLIP, 1, 1, 1, 1);
- if (hflip)
- hflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ imx258->hflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 1);
+ if (imx258->hflip)
+ imx258->hflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ imx258->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 1);
+ if (imx258->vflip)
+ imx258->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
- vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
- V4L2_CID_VFLIP, 1, 1, 1, 1);
- if (vflip)
- vflip->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ link_freq_cfgs = &imx258->link_freq_configs[0];
+ link_cfg = link_freq_cfgs[imx258->lane_mode_idx].link_cfg;
+ pixel_rate = link_freq_to_pixel_rate(imx258->link_freq_menu_items[0],
+ link_cfg);
- pixel_rate_max = link_freq_to_pixel_rate(link_freq_menu_items[0]);
- pixel_rate_min = link_freq_to_pixel_rate(link_freq_menu_items[1]);
/* By default, PIXEL_RATE is read only */
imx258->pixel_rate = v4l2_ctrl_new_std(ctrl_hdlr, &imx258_ctrl_ops,
V4L2_CID_PIXEL_RATE,
- pixel_rate_min, pixel_rate_max,
- 1, pixel_rate_max);
-
+ pixel_rate, pixel_rate,
+ 1, pixel_rate);
vblank_def = imx258->cur_mode->vts_def - imx258->cur_mode->height;
vblank_min = imx258->cur_mode->vts_min - imx258->cur_mode->height;
@@ -1163,9 +1273,6 @@ static int imx258_init_controls(struct imx258 *imx258)
IMX258_VTS_MAX - imx258->cur_mode->height, 1,
vblank_def);
- if (imx258->vblank)
- imx258->vblank->flags |= V4L2_CTRL_FLAG_READ_ONLY;
-
imx258->hblank = v4l2_ctrl_new_std(
ctrl_hdlr, &imx258_ctrl_ops, V4L2_CID_HBLANK,
IMX258_PPL_DEFAULT - imx258->cur_mode->width,
@@ -1232,9 +1339,25 @@ static void imx258_free_controls(struct imx258 *imx258)
mutex_destroy(&imx258->mutex);
}
+static int imx258_get_regulators(struct imx258 *imx258,
+ struct i2c_client *client)
+{
+ unsigned int i;
+
+ for (i = 0; i < IMX258_NUM_SUPPLIES; i++)
+ imx258->supplies[i].supply = imx258_supply_name[i];
+
+ return devm_regulator_bulk_get(&client->dev,
+ IMX258_NUM_SUPPLIES, imx258->supplies);
+}
+
static int imx258_probe(struct i2c_client *client)
{
struct imx258 *imx258;
+ struct fwnode_handle *endpoint;
+ struct v4l2_fwnode_endpoint ep = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
int ret;
u32 val = 0;
@@ -1242,6 +1365,18 @@ static int imx258_probe(struct i2c_client *client)
if (!imx258)
return -ENOMEM;
+ imx258->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(imx258->regmap)) {
+ ret = PTR_ERR(imx258->regmap);
+ dev_err(&client->dev, "failed to initialize CCI: %d\n", ret);
+ return ret;
+ }
+
+ ret = imx258_get_regulators(imx258, client);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "failed to get regulators\n");
+
imx258->clk = devm_clk_get_optional(&client->dev, NULL);
if (IS_ERR(imx258->clk))
return dev_err_probe(&client->dev, PTR_ERR(imx258->clk),
@@ -1254,18 +1389,74 @@ static int imx258_probe(struct i2c_client *client)
} else {
val = clk_get_rate(imx258->clk);
}
- if (val != IMX258_INPUT_CLOCK_FREQ) {
- dev_err(&client->dev, "input clock frequency not supported\n");
+
+ switch (val) {
+ case 19200000:
+ imx258->link_freq_configs = link_freq_configs_19_2;
+ imx258->link_freq_menu_items = link_freq_menu_items_19_2;
+ break;
+ case 24000000:
+ imx258->link_freq_configs = link_freq_configs_24;
+ imx258->link_freq_menu_items = link_freq_menu_items_24;
+ break;
+ default:
+ dev_err(&client->dev, "input clock frequency of %u not supported\n",
+ val);
return -EINVAL;
}
+ endpoint = fwnode_graph_get_next_endpoint(dev_fwnode(&client->dev), NULL);
+ if (!endpoint) {
+ dev_err(&client->dev, "Endpoint node not found\n");
+ return -EINVAL;
+ }
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(endpoint, &ep);
+ fwnode_handle_put(endpoint);
+ if (ret) {
+ dev_err(&client->dev, "Parsing endpoint node failed\n");
+ return ret;
+ }
+
+ ret = v4l2_link_freq_to_bitmap(&client->dev,
+ ep.link_frequencies,
+ ep.nr_of_link_frequencies,
+ imx258->link_freq_menu_items,
+ ARRAY_SIZE(link_freq_menu_items_19_2),
+ &imx258->link_freq_bitmap);
+ if (ret) {
+ dev_err(&client->dev, "Link frequency not supported\n");
+ goto error_endpoint_free;
+ }
+
+ /* Get number of data lanes */
+ switch (ep.bus.mipi_csi2.num_data_lanes) {
+ case 2:
+ imx258->lane_mode_idx = IMX258_2_LANE_MODE;
+ break;
+ case 4:
+ imx258->lane_mode_idx = IMX258_4_LANE_MODE;
+ break;
+ default:
+ dev_err(&client->dev, "Invalid data lanes: %u\n",
+ ep.bus.mipi_csi2.num_data_lanes);
+ ret = -EINVAL;
+ goto error_endpoint_free;
+ }
+
+ imx258->csi2_flags = ep.bus.mipi_csi2.flags;
+
+ imx258->variant_cfg = device_get_match_data(&client->dev);
+ if (!imx258->variant_cfg)
+ imx258->variant_cfg = &imx258_cfg;
+
/* Initialize subdev */
v4l2_i2c_subdev_init(&imx258->sd, client, &imx258_subdev_ops);
/* Will be powered off via pm_runtime_idle */
ret = imx258_power_on(&client->dev);
if (ret)
- return ret;
+ goto error_endpoint_free;
/* Check module identity */
ret = imx258_identify_module(imx258);
@@ -1298,6 +1489,7 @@ static int imx258_probe(struct i2c_client *client)
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
pm_runtime_idle(&client->dev);
+ v4l2_fwnode_endpoint_free(&ep);
return 0;
@@ -1310,6 +1502,9 @@ error_handler_free:
error_identify:
imx258_power_off(&client->dev);
+error_endpoint_free:
+ v4l2_fwnode_endpoint_free(&ep);
+
return ret;
}
@@ -1342,7 +1537,8 @@ MODULE_DEVICE_TABLE(acpi, imx258_acpi_ids);
#endif
static const struct of_device_id imx258_dt_ids[] = {
- { .compatible = "sony,imx258" },
+ { .compatible = "sony,imx258", .data = &imx258_cfg },
+ { .compatible = "sony,imx258-pdaf", .data = &imx258_pdaf_cfg },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, imx258_dt_ids);
diff --git a/drivers/media/i2c/imx283.c b/drivers/media/i2c/imx283.c
new file mode 100644
index 000000000000..8490618c5071
--- /dev/null
+++ b/drivers/media/i2c/imx283.c
@@ -0,0 +1,1612 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * V4L2 Support for the IMX283
+ *
+ * Diagonal 15.86 mm (Type 1) CMOS Image Sensor with Square Pixel for Color
+ * Cameras.
+ *
+ * Copyright (C) 2024 Ideas on Board Oy.
+ *
+ * Based on Sony IMX283 driver prepared by Will Whang
+ *
+ * Based on Sony imx477 camera driver
+ * Copyright (C) 2019-2020 Raspberry Pi (Trading) Ltd
+ */
+
+#include <linux/array_size.h>
+#include <linux/bitops.h>
+#include <linux/container_of.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/minmax.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+#include <linux/units.h>
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-mediabus.h>
+
+/* Chip ID */
+#define IMX283_REG_CHIP_ID CCI_REG8(0x3000)
+#define IMX283_CHIP_ID 0x0b // Default power on state
+
+#define IMX283_REG_STANDBY CCI_REG8(0x3000)
+#define IMX283_ACTIVE 0
+#define IMX283_STANDBY BIT(0)
+#define IMX283_STBLOGIC BIT(1)
+#define IMX283_STBMIPI BIT(2)
+#define IMX283_STBDV BIT(3)
+#define IMX283_SLEEP BIT(4)
+
+#define IMX283_REG_CLAMP CCI_REG8(0x3001)
+#define IMX283_CLPSQRST BIT(4)
+
+#define IMX283_REG_PLSTMG08 CCI_REG8(0x3003)
+#define IMX283_PLSTMG08_VAL 0x77
+
+#define IMX283_REG_MDSEL1 CCI_REG8(0x3004)
+#define IMX283_REG_MDSEL2 CCI_REG8(0x3005)
+#define IMX283_REG_MDSEL3 CCI_REG8(0x3006)
+#define IMX283_MDSEL3_VCROP_EN BIT(5)
+#define IMX283_REG_MDSEL4 CCI_REG8(0x3007)
+#define IMX283_MDSEL4_VCROP_EN (BIT(4) | BIT(6))
+
+#define IMX283_REG_SVR CCI_REG16_LE(0x3009)
+
+#define IMX283_REG_HTRIMMING CCI_REG8(0x300b)
+#define IMX283_MDVREV BIT(0) /* VFLIP */
+#define IMX283_HTRIMMING_EN BIT(4)
+
+#define IMX283_REG_VWINPOS CCI_REG16_LE(0x300f)
+#define IMX283_REG_VWIDCUT CCI_REG16_LE(0x3011)
+
+#define IMX283_REG_MDSEL7 CCI_REG16_LE(0x3013)
+
+/* CSI Clock Configuration */
+#define IMX283_REG_TCLKPOST CCI_REG8(0x3018)
+#define IMX283_REG_THSPREPARE CCI_REG8(0x301a)
+#define IMX283_REG_THSZERO CCI_REG8(0x301c)
+#define IMX283_REG_THSTRAIL CCI_REG8(0x301e)
+#define IMX283_REG_TCLKTRAIL CCI_REG8(0x3020)
+#define IMX283_REG_TCLKPREPARE CCI_REG8(0x3022)
+#define IMX283_REG_TCLKZERO CCI_REG16_LE(0x3024)
+#define IMX283_REG_TLPX CCI_REG8(0x3026)
+#define IMX283_REG_THSEXIT CCI_REG8(0x3028)
+#define IMX283_REG_TCLKPRE CCI_REG8(0x302a)
+#define IMX283_REG_SYSMODE CCI_REG8(0x3104)
+
+#define IMX283_REG_Y_OUT_SIZE CCI_REG16_LE(0x302f)
+#define IMX283_REG_WRITE_VSIZE CCI_REG16_LE(0x3031)
+#define IMX283_REG_OB_SIZE_V CCI_REG8(0x3033)
+
+/* HMAX internal HBLANK */
+#define IMX283_REG_HMAX CCI_REG16_LE(0x3036)
+#define IMX283_HMAX_MAX (BIT(16) - 1)
+
+/* VMAX internal VBLANK */
+#define IMX283_REG_VMAX CCI_REG24_LE(0x3038)
+#define IMX283_VMAX_MAX (BIT(16) - 1)
+
+/* SHR internal */
+#define IMX283_REG_SHR CCI_REG16_LE(0x303b)
+#define IMX283_SHR_MIN 11
+
+/*
+ * Analog gain control
+ * Gain [dB] = -20log{(2048 - value [10:0]) /2048}
+ * Range: 0dB to approximately +27dB
+ */
+#define IMX283_REG_ANALOG_GAIN CCI_REG16_LE(0x3042)
+#define IMX283_ANA_GAIN_MIN 0
+#define IMX283_ANA_GAIN_MAX 1957
+#define IMX283_ANA_GAIN_STEP 1
+#define IMX283_ANA_GAIN_DEFAULT 0x0
+
+/*
+ * Digital gain control
+ * Gain [dB] = value * 6
+ * Range: 0dB to +18db
+ */
+#define IMX283_REG_DIGITAL_GAIN CCI_REG8(0x3044)
+#define IMX283_DGTL_GAIN_MIN 0
+#define IMX283_DGTL_GAIN_MAX 3
+#define IMX283_DGTL_GAIN_DEFAULT 0
+#define IMX283_DGTL_GAIN_STEP 1
+
+#define IMX283_REG_HTRIMMING_START CCI_REG16_LE(0x3058)
+#define IMX283_REG_HTRIMMING_END CCI_REG16_LE(0x305a)
+
+#define IMX283_REG_MDSEL18 CCI_REG16_LE(0x30f6)
+
+/* Master Mode Operation Control */
+#define IMX283_REG_XMSTA CCI_REG8(0x3105)
+#define IMX283_XMSTA BIT(0)
+
+#define IMX283_REG_SYNCDRV CCI_REG8(0x3107)
+#define IMX283_SYNCDRV_XHS_XVS (0xa0 | 0x02)
+#define IMX283_SYNCDRV_HIZ (0xa0 | 0x03)
+
+/* PLL Standby */
+#define IMX283_REG_STBPL CCI_REG8(0x320b)
+#define IMX283_STBPL_NORMAL 0x00
+#define IMX283_STBPL_STANDBY 0x03
+
+/* Input Frequency Setting */
+#define IMX283_REG_PLRD1 CCI_REG8(0x36c1)
+#define IMX283_REG_PLRD2 CCI_REG16_LE(0x36c2)
+#define IMX283_REG_PLRD3 CCI_REG8(0x36f7)
+#define IMX283_REG_PLRD4 CCI_REG8(0x36f8)
+
+#define IMX283_REG_PLSTMG02 CCI_REG8(0x36aa)
+#define IMX283_PLSTMG02_VAL 0x00
+
+#define IMX283_REG_EBD_X_OUT_SIZE CCI_REG16_LE(0x3a54)
+
+/* Test pattern generator */
+#define IMX283_REG_TPG_CTRL CCI_REG8(0x3156)
+#define IMX283_TPG_CTRL_CLKEN BIT(0)
+#define IMX283_TPG_CTRL_PATEN BIT(4)
+
+#define IMX283_REG_TPG_PAT CCI_REG8(0x3157)
+#define IMX283_TPG_PAT_ALL_000 0x00
+#define IMX283_TPG_PAT_ALL_FFF 0x01
+#define IMX283_TPG_PAT_ALL_555 0x02
+#define IMX283_TPG_PAT_ALL_AAA 0x03
+#define IMX283_TPG_PAT_H_COLOR_BARS 0x0a
+#define IMX283_TPG_PAT_V_COLOR_BARS 0x0b
+
+/* Exposure control */
+#define IMX283_EXPOSURE_MIN 52
+#define IMX283_EXPOSURE_STEP 1
+#define IMX283_EXPOSURE_DEFAULT 1000
+#define IMX283_EXPOSURE_MAX 49865
+
+#define IMAGE_PAD 0
+
+#define IMX283_XCLR_MIN_DELAY_US (1 * USEC_PER_MSEC)
+#define IMX283_XCLR_DELAY_RANGE_US (1 * USEC_PER_MSEC)
+
+/* IMX283 native and active pixel array size. */
+static const struct v4l2_rect imx283_native_area = {
+ .top = 0,
+ .left = 0,
+ .width = 5592,
+ .height = 3710,
+};
+
+static const struct v4l2_rect imx283_active_area = {
+ .top = 40,
+ .left = 108,
+ .width = 5472,
+ .height = 3648,
+};
+
+struct imx283_reg_list {
+ unsigned int num_of_regs;
+ const struct cci_reg_sequence *regs;
+};
+
+/* Mode : resolution and related config values */
+struct imx283_mode {
+ unsigned int mode;
+
+ /* Bits per pixel */
+ unsigned int bpp;
+
+ /* Frame width */
+ unsigned int width;
+
+ /* Frame height */
+ unsigned int height;
+
+ /*
+ * Minimum horizontal timing in pixel-units
+ *
+ * Note that HMAX is written in 72MHz units, and the datasheet assumes a
+ * 720MHz link frequency. Convert datasheet values with the following:
+ *
+ * For 12 bpp modes (480Mbps) convert with:
+ * hmax = [hmax in 72MHz units] * 480 / 72
+ *
+ * For 10 bpp modes (576Mbps) convert with:
+ * hmax = [hmax in 72MHz units] * 576 / 72
+ */
+ u32 min_hmax;
+
+ /* minimum V-timing in lines */
+ u32 min_vmax;
+
+ /* default H-timing */
+ u32 default_hmax;
+
+ /* default V-timing */
+ u32 default_vmax;
+
+ /* minimum SHR */
+ u32 min_shr;
+
+ /*
+ * Per-mode vertical crop constants used to calculate values
+ * of IMX283REG_WIDCUT and IMX283_REG_VWINPOS.
+ */
+ u32 veff;
+ u32 vst;
+ u32 vct;
+
+ /* Horizontal and vertical binning ratio */
+ u8 hbin_ratio;
+ u8 vbin_ratio;
+
+ /* Optical Blanking */
+ u32 horizontal_ob;
+ u32 vertical_ob;
+
+ /* Analog crop rectangle. */
+ struct v4l2_rect crop;
+};
+
+struct imx283_input_frequency {
+ unsigned int mhz;
+ unsigned int reg_count;
+ struct cci_reg_sequence regs[4];
+};
+
+static const struct imx283_input_frequency imx283_frequencies[] = {
+ {
+ .mhz = 6 * HZ_PER_MHZ,
+ .reg_count = 4,
+ .regs = {
+ { IMX283_REG_PLRD1, 0x00 },
+ { IMX283_REG_PLRD2, 0x00f0 },
+ { IMX283_REG_PLRD3, 0x00 },
+ { IMX283_REG_PLRD4, 0xc0 },
+ },
+ },
+ {
+ .mhz = 12 * HZ_PER_MHZ,
+ .reg_count = 4,
+ .regs = {
+ { IMX283_REG_PLRD1, 0x01 },
+ { IMX283_REG_PLRD2, 0x00f0 },
+ { IMX283_REG_PLRD3, 0x01 },
+ { IMX283_REG_PLRD4, 0xc0 },
+ },
+ },
+ {
+ .mhz = 18 * HZ_PER_MHZ,
+ .reg_count = 4,
+ .regs = {
+ { IMX283_REG_PLRD1, 0x01 },
+ { IMX283_REG_PLRD2, 0x00a0 },
+ { IMX283_REG_PLRD3, 0x01 },
+ { IMX283_REG_PLRD4, 0x80 },
+ },
+ },
+ {
+ .mhz = 24 * HZ_PER_MHZ,
+ .reg_count = 4,
+ .regs = {
+ { IMX283_REG_PLRD1, 0x02 },
+ { IMX283_REG_PLRD2, 0x00f0 },
+ { IMX283_REG_PLRD3, 0x02 },
+ { IMX283_REG_PLRD4, 0xc0 },
+ },
+ },
+};
+
+enum imx283_modes {
+ IMX283_MODE_0,
+ IMX283_MODE_1,
+ IMX283_MODE_1A,
+ IMX283_MODE_1S,
+ IMX283_MODE_2,
+ IMX283_MODE_2A,
+ IMX283_MODE_3,
+ IMX283_MODE_4,
+ IMX283_MODE_5,
+ IMX283_MODE_6,
+};
+
+struct imx283_readout_mode {
+ u8 mdsel1;
+ u8 mdsel2;
+ u8 mdsel3;
+ u8 mdsel4;
+};
+
+static const struct imx283_readout_mode imx283_readout_modes[] = {
+ /* All pixel scan modes */
+ [IMX283_MODE_0] = { 0x04, 0x03, 0x10, 0x00 }, /* 12 bit */
+ [IMX283_MODE_1] = { 0x04, 0x01, 0x00, 0x00 }, /* 10 bit */
+ [IMX283_MODE_1A] = { 0x04, 0x01, 0x20, 0x50 }, /* 10 bit */
+ [IMX283_MODE_1S] = { 0x04, 0x41, 0x20, 0x50 }, /* 10 bit */
+
+ /* Horizontal / Vertical 2/2-line binning */
+ [IMX283_MODE_2] = { 0x0d, 0x11, 0x50, 0x00 }, /* 12 bit */
+ [IMX283_MODE_2A] = { 0x0d, 0x11, 0x70, 0x50 }, /* 12 bit */
+
+ /* Horizontal / Vertical 3/3-line binning */
+ [IMX283_MODE_3] = { 0x1e, 0x18, 0x10, 0x00 }, /* 12 bit */
+
+ /* Vertical 2/9 subsampling, horizontal 3 binning cropping */
+ [IMX283_MODE_4] = { 0x29, 0x18, 0x30, 0x50 }, /* 12 bit */
+
+ /* Vertical 2/19 subsampling binning, horizontal 3 binning */
+ [IMX283_MODE_5] = { 0x2d, 0x18, 0x10, 0x00 }, /* 12 bit */
+
+ /* Vertical 2 binning horizontal 2/4, subsampling 16:9 cropping */
+ [IMX283_MODE_6] = { 0x18, 0x21, 0x00, 0x09 }, /* 10 bit */
+
+ /*
+ * New modes should make sure the offset period is complied.
+ * See imx283_exposure() for reference.
+ */
+};
+
+static const struct cci_reg_sequence mipi_data_rate_1440Mbps[] = {
+ /* The default register settings provide the 1440Mbps rate */
+ { CCI_REG8(0x36c5), 0x00 }, /* Undocumented */
+ { CCI_REG8(0x3ac4), 0x00 }, /* Undocumented */
+
+ { IMX283_REG_STBPL, 0x00 },
+ { IMX283_REG_TCLKPOST, 0xa7 },
+ { IMX283_REG_THSPREPARE, 0x6f },
+ { IMX283_REG_THSZERO, 0x9f },
+ { IMX283_REG_THSTRAIL, 0x5f },
+ { IMX283_REG_TCLKTRAIL, 0x5f },
+ { IMX283_REG_TCLKPREPARE, 0x6f },
+ { IMX283_REG_TCLKZERO, 0x017f },
+ { IMX283_REG_TLPX, 0x4f },
+ { IMX283_REG_THSEXIT, 0x47 },
+ { IMX283_REG_TCLKPRE, 0x07 },
+ { IMX283_REG_SYSMODE, 0x02 },
+};
+
+static const struct cci_reg_sequence mipi_data_rate_720Mbps[] = {
+ /* Undocumented Additions "For 720MBps" Setting */
+ { CCI_REG8(0x36c5), 0x01 }, /* Undocumented */
+ { CCI_REG8(0x3ac4), 0x01 }, /* Undocumented */
+
+ { IMX283_REG_STBPL, 0x00 },
+ { IMX283_REG_TCLKPOST, 0x77 },
+ { IMX283_REG_THSPREPARE, 0x37 },
+ { IMX283_REG_THSZERO, 0x67 },
+ { IMX283_REG_THSTRAIL, 0x37 },
+ { IMX283_REG_TCLKTRAIL, 0x37 },
+ { IMX283_REG_TCLKPREPARE, 0x37 },
+ { IMX283_REG_TCLKZERO, 0xdf },
+ { IMX283_REG_TLPX, 0x2f },
+ { IMX283_REG_THSEXIT, 0x47 },
+ { IMX283_REG_TCLKPRE, 0x0f },
+ { IMX283_REG_SYSMODE, 0x02 },
+};
+
+static const s64 link_frequencies[] = {
+ 720 * HZ_PER_MHZ, /* 1440 Mbps lane data rate */
+ 360 * HZ_PER_MHZ, /* 720 Mbps data lane rate */
+};
+
+static const struct imx283_reg_list link_freq_reglist[] = {
+ { /* 720 MHz */
+ .num_of_regs = ARRAY_SIZE(mipi_data_rate_1440Mbps),
+ .regs = mipi_data_rate_1440Mbps,
+ },
+ { /* 360 MHz */
+ .num_of_regs = ARRAY_SIZE(mipi_data_rate_720Mbps),
+ .regs = mipi_data_rate_720Mbps,
+ },
+};
+
+/* Mode configs */
+static const struct imx283_mode supported_modes_12bit[] = {
+ {
+ /* 20MPix 21.40 fps readout mode 0 */
+ .mode = IMX283_MODE_0,
+ .bpp = 12,
+ .width = 5472,
+ .height = 3648,
+ .min_hmax = 5914, /* 887 @ 480MHz/72MHz */
+ .min_vmax = 3793, /* Lines */
+
+ .veff = 3694,
+ .vst = 0,
+ .vct = 0,
+
+ .hbin_ratio = 1,
+ .vbin_ratio = 1,
+
+ /* 20.00 FPS */
+ .default_hmax = 6000, /* 900 @ 480MHz/72MHz */
+ .default_vmax = 4000,
+
+ .min_shr = 11,
+ .horizontal_ob = 96,
+ .vertical_ob = 16,
+ .crop = {
+ .top = 40,
+ .left = 108,
+ .width = 5472,
+ .height = 3648,
+ },
+ },
+ {
+ /*
+ * Readout mode 2 : 2/2 binned mode (2736x1824)
+ */
+ .mode = IMX283_MODE_2,
+ .bpp = 12,
+ .width = 2736,
+ .height = 1824,
+ .min_hmax = 2414, /* Pixels (362 * 480MHz/72MHz + padding) */
+ .min_vmax = 3840, /* Lines */
+
+ /* 50.00 FPS */
+ .default_hmax = 2500, /* 375 @ 480MHz/72Mhz */
+ .default_vmax = 3840,
+
+ .veff = 1824,
+ .vst = 0,
+ .vct = 0,
+
+ .hbin_ratio = 2,
+ .vbin_ratio = 2,
+
+ .min_shr = 12,
+ .horizontal_ob = 48,
+ .vertical_ob = 4,
+
+ .crop = {
+ .top = 40,
+ .left = 108,
+ .width = 5472,
+ .height = 3648,
+ },
+ },
+};
+
+static const struct imx283_mode supported_modes_10bit[] = {
+ {
+ /* 20MPix 25.48 fps readout mode 1 */
+ .mode = IMX283_MODE_1,
+ .bpp = 10,
+ .width = 5472,
+ .height = 3648,
+ .min_hmax = 5960, /* 745 @ 576MHz / 72MHz */
+ .min_vmax = 3793,
+
+ /* 25.00 FPS */
+ .default_hmax = 6000, /* 750 @ 576MHz / 72MHz */
+ .default_vmax = 3840,
+
+ .min_shr = 10,
+ .horizontal_ob = 96,
+ .vertical_ob = 16,
+ .crop = {
+ .top = 40,
+ .left = 108,
+ .width = 5472,
+ .height = 3648,
+ },
+ },
+};
+
+static const u32 imx283_mbus_codes[] = {
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+};
+
+/* regulator supplies */
+static const char *const imx283_supply_name[] = {
+ "vadd", /* Analog (2.9V) supply */
+ "vdd1", /* Supply Voltage 2 (1.8V) supply */
+ "vdd2", /* Supply Voltage 3 (1.2V) supply */
+};
+
+struct imx283 {
+ struct device *dev;
+ struct regmap *cci;
+
+ const struct imx283_input_frequency *freq;
+
+ struct v4l2_subdev sd;
+ struct media_pad pad;
+
+ struct clk *xclk;
+
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(imx283_supply_name)];
+
+ /* V4L2 Controls */
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_ctrl *exposure;
+ struct v4l2_ctrl *vblank;
+ struct v4l2_ctrl *hblank;
+ struct v4l2_ctrl *vflip;
+
+ unsigned long link_freq_bitmap;
+
+ u16 hmax;
+ u32 vmax;
+};
+
+static inline struct imx283 *to_imx283(struct v4l2_subdev *sd)
+{
+ return container_of_const(sd, struct imx283, sd);
+}
+
+static inline void get_mode_table(unsigned int code,
+ const struct imx283_mode **mode_list,
+ unsigned int *num_modes)
+{
+ switch (code) {
+ case MEDIA_BUS_FMT_SRGGB12_1X12:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SGBRG12_1X12:
+ case MEDIA_BUS_FMT_SBGGR12_1X12:
+ *mode_list = supported_modes_12bit;
+ *num_modes = ARRAY_SIZE(supported_modes_12bit);
+ break;
+
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ *mode_list = supported_modes_10bit;
+ *num_modes = ARRAY_SIZE(supported_modes_10bit);
+ break;
+ default:
+ *mode_list = NULL;
+ *num_modes = 0;
+ break;
+ }
+}
+
+/* Calculate the Pixel Rate based on the current mode */
+static u64 imx283_pixel_rate(struct imx283 *imx283,
+ const struct imx283_mode *mode)
+{
+ u64 link_frequency = link_frequencies[__ffs(imx283->link_freq_bitmap)];
+ unsigned int bpp = mode->bpp;
+ const unsigned int ddr = 2; /* Double Data Rate */
+ const unsigned int lanes = 4; /* Only 4 lane support */
+ u64 numerator = link_frequency * ddr * lanes;
+
+ do_div(numerator, bpp);
+
+ return numerator;
+}
+
+/* Convert from a variable pixel_rate to 72 MHz clock cycles */
+static u64 imx283_internal_clock(unsigned int pixel_rate, unsigned int pixels)
+{
+ /*
+ * Determine the following operation without overflow:
+ * pixels = 72 Mhz / pixel_rate
+ *
+ * The internal clock at 72MHz and Pixel Rate (between 240 and 576MHz)
+ * can easily overflow this calculation, so pre-divide to simplify.
+ */
+ const u32 iclk_pre = 72;
+ const u32 pclk_pre = pixel_rate / HZ_PER_MHZ;
+ u64 numerator = pixels * iclk_pre;
+
+ do_div(numerator, pclk_pre);
+
+ return numerator;
+}
+
+/* Internal clock (72MHz) to Pixel Rate clock (Variable) */
+static u64 imx283_iclk_to_pix(unsigned int pixel_rate, unsigned int cycles)
+{
+ /*
+ * Determine the following operation without overflow:
+ * cycles * pixel_rate / 72 MHz
+ *
+ * The internal clock at 72MHz and Pixel Rate (between 240 and 576MHz)
+ * can easily overflow this calculation, so pre-divide to simplify.
+ */
+ const u32 iclk_pre = 72;
+ const u32 pclk_pre = pixel_rate / HZ_PER_MHZ;
+ u64 numerator = cycles * pclk_pre;
+
+ do_div(numerator, iclk_pre);
+
+ return numerator;
+}
+
+/* Determine the exposure based on current hmax, vmax and a given SHR */
+static u32 imx283_exposure(struct imx283 *imx283,
+ const struct imx283_mode *mode, u64 shr)
+{
+ u32 svr = 0; /* SVR feature is not currently supported */
+ u32 offset;
+ u64 numerator;
+
+ /* Number of clocks per internal offset period */
+ offset = mode->mode == IMX283_MODE_0 ? 209 : 157;
+ numerator = (imx283->vmax * (svr + 1) - shr) * imx283->hmax + offset;
+
+ do_div(numerator, imx283->hmax);
+
+ return clamp(numerator, 0, U32_MAX);
+}
+
+static void imx283_exposure_limits(struct imx283 *imx283,
+ const struct imx283_mode *mode,
+ s64 *min_exposure, s64 *max_exposure)
+{
+ u32 svr = 0; /* SVR feature is not currently supported */
+ u64 min_shr = mode->min_shr;
+ /* Global Shutter is not supported */
+ u64 max_shr = (svr + 1) * imx283->vmax - 4;
+
+ max_shr = min(max_shr, BIT(16) - 1);
+
+ *min_exposure = imx283_exposure(imx283, mode, max_shr);
+ *max_exposure = imx283_exposure(imx283, mode, min_shr);
+}
+
+/*
+ * Integration Time [s] = [ {VMAX x (SVR + 1) – (SHR)} x HMAX + offset ]
+ * / [ 72 x 10^6 ]
+ */
+static u32 imx283_shr(struct imx283 *imx283, const struct imx283_mode *mode,
+ u32 exposure)
+{
+ u32 svr = 0; /* SVR feature is not currently supported */
+ u32 offset;
+ u64 temp;
+
+ /* Number of clocks per internal offset period */
+ offset = mode->mode == IMX283_MODE_0 ? 209 : 157;
+ temp = ((u64)exposure * imx283->hmax - offset);
+ do_div(temp, imx283->hmax);
+
+ return (imx283->vmax * (svr + 1) - temp);
+}
+
+static const char * const imx283_tpg_menu[] = {
+ "Disabled",
+ "All 000h",
+ "All FFFh",
+ "All 555h",
+ "All AAAh",
+ "Horizontal color bars",
+ "Vertical color bars",
+};
+
+static const int imx283_tpg_val[] = {
+ IMX283_TPG_PAT_ALL_000,
+ IMX283_TPG_PAT_ALL_000,
+ IMX283_TPG_PAT_ALL_FFF,
+ IMX283_TPG_PAT_ALL_555,
+ IMX283_TPG_PAT_ALL_AAA,
+ IMX283_TPG_PAT_H_COLOR_BARS,
+ IMX283_TPG_PAT_V_COLOR_BARS,
+};
+
+static int imx283_update_test_pattern(struct imx283 *imx283, u32 pattern_index)
+{
+ int ret;
+
+ if (pattern_index >= ARRAY_SIZE(imx283_tpg_val))
+ return -EINVAL;
+
+ if (!pattern_index)
+ return cci_write(imx283->cci, IMX283_REG_TPG_CTRL, 0x00, NULL);
+
+ ret = cci_write(imx283->cci, IMX283_REG_TPG_PAT,
+ imx283_tpg_val[pattern_index], NULL);
+ if (ret)
+ return ret;
+
+ return cci_write(imx283->cci, IMX283_REG_TPG_CTRL,
+ IMX283_TPG_CTRL_CLKEN | IMX283_TPG_CTRL_PATEN, NULL);
+}
+
+static int imx283_set_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct imx283 *imx283 = container_of(ctrl->handler, struct imx283,
+ ctrl_handler);
+ const struct imx283_mode *mode;
+ struct v4l2_mbus_framefmt *fmt;
+ const struct imx283_mode *mode_list;
+ struct v4l2_subdev_state *state;
+ unsigned int num_modes;
+ u64 shr, pixel_rate;
+ int ret = 0;
+
+ state = v4l2_subdev_get_locked_active_state(&imx283->sd);
+ fmt = v4l2_subdev_state_get_format(state, 0);
+
+ get_mode_table(fmt->code, &mode_list, &num_modes);
+ mode = v4l2_find_nearest_size(mode_list, num_modes, width, height,
+ fmt->width, fmt->height);
+
+ /*
+ * The VBLANK control may change the limits of usable exposure, so check
+ * and adjust if necessary.
+ */
+ if (ctrl->id == V4L2_CID_VBLANK) {
+ /* Honour the VBLANK limits when setting exposure. */
+ s64 current_exposure, max_exposure, min_exposure;
+
+ imx283->vmax = mode->height + ctrl->val;
+
+ imx283_exposure_limits(imx283, mode,
+ &min_exposure, &max_exposure);
+
+ current_exposure = imx283->exposure->val;
+ current_exposure = clamp(current_exposure, min_exposure,
+ max_exposure);
+
+ __v4l2_ctrl_modify_range(imx283->exposure, min_exposure,
+ max_exposure, 1, current_exposure);
+ }
+
+ /*
+ * Applying V4L2 control value only happens
+ * when power is up for streaming
+ */
+ if (!pm_runtime_get_if_active(imx283->dev))
+ return 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_EXPOSURE:
+ shr = imx283_shr(imx283, mode, ctrl->val);
+ dev_dbg(imx283->dev, "V4L2_CID_EXPOSURE : %d - SHR: %lld\n",
+ ctrl->val, shr);
+ ret = cci_write(imx283->cci, IMX283_REG_SHR, shr, NULL);
+ break;
+
+ case V4L2_CID_HBLANK:
+ pixel_rate = imx283_pixel_rate(imx283, mode);
+ imx283->hmax = imx283_internal_clock(pixel_rate, mode->width + ctrl->val);
+ dev_dbg(imx283->dev, "V4L2_CID_HBLANK : %d HMAX : %u\n",
+ ctrl->val, imx283->hmax);
+ ret = cci_write(imx283->cci, IMX283_REG_HMAX, imx283->hmax, NULL);
+ break;
+
+ case V4L2_CID_VBLANK:
+ imx283->vmax = mode->height + ctrl->val;
+ dev_dbg(imx283->dev, "V4L2_CID_VBLANK : %d VMAX : %u\n",
+ ctrl->val, imx283->vmax);
+ ret = cci_write(imx283->cci, IMX283_REG_VMAX, imx283->vmax, NULL);
+ break;
+
+ case V4L2_CID_ANALOGUE_GAIN:
+ ret = cci_write(imx283->cci, IMX283_REG_ANALOG_GAIN, ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_DIGITAL_GAIN:
+ ret = cci_write(imx283->cci, IMX283_REG_DIGITAL_GAIN, ctrl->val, NULL);
+ break;
+
+ case V4L2_CID_VFLIP:
+ /*
+ * VFLIP is managed by BIT(0) of IMX283_REG_HTRIMMING address, hence
+ * both need to be set simultaneously.
+ */
+ if (ctrl->val) {
+ cci_write(imx283->cci, IMX283_REG_HTRIMMING,
+ IMX283_HTRIMMING_EN | IMX283_MDVREV, &ret);
+ } else {
+ cci_write(imx283->cci, IMX283_REG_HTRIMMING,
+ IMX283_HTRIMMING_EN, &ret);
+ }
+ break;
+
+ case V4L2_CID_TEST_PATTERN:
+ ret = imx283_update_test_pattern(imx283, ctrl->val);
+ break;
+
+ default:
+ dev_err(imx283->dev, "ctrl(id:0x%x, val:0x%x) is not handled\n",
+ ctrl->id, ctrl->val);
+ break;
+ }
+
+ pm_runtime_put(imx283->dev);
+
+ return ret;
+}
+
+static const struct v4l2_ctrl_ops imx283_ctrl_ops = {
+ .s_ctrl = imx283_set_ctrl,
+};
+
+static int imx283_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->index >= ARRAY_SIZE(imx283_mbus_codes))
+ return -EINVAL;
+
+ code->code = imx283_mbus_codes[code->index];
+
+ return 0;
+}
+
+static int imx283_enum_frame_size(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_frame_size_enum *fse)
+{
+ const struct imx283_mode *mode_list;
+ unsigned int num_modes;
+
+ get_mode_table(fse->code, &mode_list, &num_modes);
+
+ if (fse->index >= num_modes)
+ return -EINVAL;
+
+ fse->min_width = mode_list[fse->index].width;
+ fse->max_width = fse->min_width;
+ fse->min_height = mode_list[fse->index].height;
+ fse->max_height = fse->min_height;
+
+ return 0;
+}
+
+static void imx283_update_image_pad_format(struct imx283 *imx283,
+ const struct imx283_mode *mode,
+ struct v4l2_mbus_framefmt *format)
+{
+ format->width = mode->width;
+ format->height = mode->height;
+ format->field = V4L2_FIELD_NONE;
+ format->colorspace = V4L2_COLORSPACE_RAW;
+ format->ycbcr_enc = V4L2_YCBCR_ENC_601;
+ format->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ format->xfer_func = V4L2_XFER_FUNC_NONE;
+}
+
+static int imx283_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct imx283 *imx283 = to_imx283(sd);
+ struct v4l2_mbus_framefmt *format;
+ const struct imx283_mode *mode;
+ struct v4l2_rect *crop;
+
+ /* Initialize try_fmt */
+ format = v4l2_subdev_state_get_format(state, IMAGE_PAD);
+
+ mode = &supported_modes_12bit[0];
+ format->code = MEDIA_BUS_FMT_SRGGB12_1X12;
+ imx283_update_image_pad_format(imx283, mode, format);
+
+ /* Initialize crop rectangle to mode default */
+ crop = v4l2_subdev_state_get_crop(state, IMAGE_PAD);
+ *crop = mode->crop;
+
+ return 0;
+}
+
+static void imx283_set_framing_limits(struct imx283 *imx283,
+ const struct imx283_mode *mode)
+{
+ u64 pixel_rate = imx283_pixel_rate(imx283, mode);
+ u64 min_hblank, max_hblank, def_hblank;
+
+ /* Initialise hmax and vmax for exposure calculations */
+ imx283->hmax = imx283_internal_clock(pixel_rate, mode->default_hmax);
+ imx283->vmax = mode->default_vmax;
+
+ /*
+ * Horizontal Blanking
+ * Convert the HMAX_MAX (72MHz) to Pixel rate values for HBLANK_MAX
+ */
+ min_hblank = mode->min_hmax - mode->width;
+ max_hblank = imx283_iclk_to_pix(pixel_rate, IMX283_HMAX_MAX) - mode->width;
+ def_hblank = mode->default_hmax - mode->width;
+ __v4l2_ctrl_modify_range(imx283->hblank, min_hblank, max_hblank, 1,
+ def_hblank);
+ __v4l2_ctrl_s_ctrl(imx283->hblank, def_hblank);
+
+ /* Vertical Blanking */
+ __v4l2_ctrl_modify_range(imx283->vblank, mode->min_vmax - mode->height,
+ IMX283_VMAX_MAX - mode->height, 1,
+ mode->default_vmax - mode->height);
+ __v4l2_ctrl_s_ctrl(imx283->vblank, mode->default_vmax - mode->height);
+}
+
+static int imx283_set_pad_format(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_format *fmt)
+{
+ struct v4l2_mbus_framefmt *format;
+ const struct imx283_mode *mode;
+ struct imx283 *imx283 = to_imx283(sd);
+ const struct imx283_mode *mode_list;
+ unsigned int num_modes;
+
+ get_mode_table(fmt->format.code, &mode_list, &num_modes);
+
+ mode = v4l2_find_nearest_size(mode_list, num_modes, width, height,
+ fmt->format.width, fmt->format.height);
+
+ fmt->format.width = mode->width;
+ fmt->format.height = mode->height;
+ fmt->format.field = V4L2_FIELD_NONE;
+ fmt->format.colorspace = V4L2_COLORSPACE_RAW;
+ fmt->format.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ fmt->format.quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ fmt->format.xfer_func = V4L2_XFER_FUNC_NONE;
+
+ format = v4l2_subdev_state_get_format(sd_state, 0);
+
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE)
+ imx283_set_framing_limits(imx283, mode);
+
+ *format = fmt->format;
+
+ return 0;
+}
+
+static int imx283_standby_cancel(struct imx283 *imx283)
+{
+ unsigned int link_freq_idx;
+ int ret = 0;
+
+ cci_write(imx283->cci, IMX283_REG_STANDBY,
+ IMX283_STBLOGIC | IMX283_STBDV, &ret);
+
+ /* Configure PLL clocks based on the xclk */
+ cci_multi_reg_write(imx283->cci, imx283->freq->regs,
+ imx283->freq->reg_count, &ret);
+
+ dev_dbg(imx283->dev, "Using clk freq %ld MHz",
+ imx283->freq->mhz / HZ_PER_MHZ);
+
+ /* Initialise communication */
+ cci_write(imx283->cci, IMX283_REG_PLSTMG08, IMX283_PLSTMG08_VAL, &ret);
+ cci_write(imx283->cci, IMX283_REG_PLSTMG02, IMX283_PLSTMG02_VAL, &ret);
+
+ /* Enable PLL */
+ cci_write(imx283->cci, IMX283_REG_STBPL, IMX283_STBPL_NORMAL, &ret);
+
+ /* Configure the MIPI link speed */
+ link_freq_idx = __ffs(imx283->link_freq_bitmap);
+ cci_multi_reg_write(imx283->cci, link_freq_reglist[link_freq_idx].regs,
+ link_freq_reglist[link_freq_idx].num_of_regs,
+ &ret);
+
+ /* 1st Stabilisation period of 1 ms or more */
+ usleep_range(1000, 2000);
+
+ /* Activate */
+ cci_write(imx283->cci, IMX283_REG_STANDBY, IMX283_ACTIVE, &ret);
+
+ /* 2nd Stabilisation period of 19ms or more */
+ usleep_range(19000, 20000);
+
+ cci_write(imx283->cci, IMX283_REG_CLAMP, IMX283_CLPSQRST, &ret);
+ cci_write(imx283->cci, IMX283_REG_XMSTA, 0, &ret);
+ cci_write(imx283->cci, IMX283_REG_SYNCDRV, IMX283_SYNCDRV_XHS_XVS, &ret);
+
+ return ret;
+}
+
+/* Start streaming */
+static int imx283_start_streaming(struct imx283 *imx283,
+ struct v4l2_subdev_state *state)
+{
+ const struct imx283_readout_mode *readout;
+ const struct imx283_mode *mode;
+ const struct v4l2_mbus_framefmt *fmt;
+ const struct imx283_mode *mode_list;
+ unsigned int num_modes;
+ u32 v_widcut;
+ s32 v_pos;
+ u32 write_v_size;
+ u32 y_out_size;
+ int ret = 0;
+
+ fmt = v4l2_subdev_state_get_format(state, 0);
+ get_mode_table(fmt->code, &mode_list, &num_modes);
+ mode = v4l2_find_nearest_size(mode_list, num_modes, width, height,
+ fmt->width, fmt->height);
+
+ ret = imx283_standby_cancel(imx283);
+ if (ret) {
+ dev_err(imx283->dev, "failed to cancel standby\n");
+ return ret;
+ }
+
+ /*
+ * Set the readout mode registers.
+ * MDSEL3 and MDSEL4 are updated to enable Arbitrary Vertical Cropping.
+ */
+ readout = &imx283_readout_modes[mode->mode];
+ cci_write(imx283->cci, IMX283_REG_MDSEL1, readout->mdsel1, &ret);
+ cci_write(imx283->cci, IMX283_REG_MDSEL2, readout->mdsel2, &ret);
+ cci_write(imx283->cci, IMX283_REG_MDSEL3,
+ readout->mdsel3 | IMX283_MDSEL3_VCROP_EN, &ret);
+ cci_write(imx283->cci, IMX283_REG_MDSEL4,
+ readout->mdsel4 | IMX283_MDSEL4_VCROP_EN, &ret);
+
+ /* Mode 1S specific entries from the Readout Drive Mode Tables */
+ if (mode->mode == IMX283_MODE_1S) {
+ cci_write(imx283->cci, IMX283_REG_MDSEL7, 0x01, &ret);
+ cci_write(imx283->cci, IMX283_REG_MDSEL18, 0x1098, &ret);
+ }
+
+ if (ret) {
+ dev_err(imx283->dev, "failed to set readout\n");
+ return ret;
+ }
+
+ /* Initialise SVR. Unsupported for now - Always 0 */
+ cci_write(imx283->cci, IMX283_REG_SVR, 0x00, &ret);
+
+ dev_dbg(imx283->dev, "Mode: Size %d x %d\n", mode->width, mode->height);
+ dev_dbg(imx283->dev, "Analogue Crop (in the mode) %d,%d %dx%d\n",
+ mode->crop.left,
+ mode->crop.top,
+ mode->crop.width,
+ mode->crop.height);
+
+ y_out_size = mode->crop.height / mode->vbin_ratio;
+ write_v_size = y_out_size + mode->vertical_ob;
+ /*
+ * cropping start position = (VWINPOS – Vst) × 2
+ * cropping width = Veff – (VWIDCUT – Vct) × 2
+ */
+ v_pos = imx283->vflip->val ?
+ ((-mode->crop.top / mode->vbin_ratio) / 2) + mode->vst :
+ ((mode->crop.top / mode->vbin_ratio) / 2) + mode->vst;
+ v_widcut = ((mode->veff - y_out_size) / 2) + mode->vct;
+
+ cci_write(imx283->cci, IMX283_REG_Y_OUT_SIZE, y_out_size, &ret);
+ cci_write(imx283->cci, IMX283_REG_WRITE_VSIZE, write_v_size, &ret);
+ cci_write(imx283->cci, IMX283_REG_VWIDCUT, v_widcut, &ret);
+ cci_write(imx283->cci, IMX283_REG_VWINPOS, v_pos, &ret);
+
+ cci_write(imx283->cci, IMX283_REG_OB_SIZE_V, mode->vertical_ob, &ret);
+
+ /* TODO: Validate mode->crop is fully contained within imx283_native_area */
+ cci_write(imx283->cci, IMX283_REG_HTRIMMING_START, mode->crop.left, &ret);
+ cci_write(imx283->cci, IMX283_REG_HTRIMMING_END,
+ mode->crop.left + mode->crop.width, &ret);
+
+ /* Disable embedded data */
+ cci_write(imx283->cci, IMX283_REG_EBD_X_OUT_SIZE, 0, &ret);
+
+ /* Apply customized values from controls (HMAX/VMAX/SHR) */
+ ret = __v4l2_ctrl_handler_setup(imx283->sd.ctrl_handler);
+
+ return ret;
+}
+
+static int imx283_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
+{
+ struct imx283 *imx283 = to_imx283(sd);
+ int ret;
+
+ if (pad != IMAGE_PAD)
+ return -EINVAL;
+
+ ret = pm_runtime_get_sync(imx283->dev);
+ if (ret < 0) {
+ pm_runtime_put_noidle(imx283->dev);
+ return ret;
+ }
+
+ ret = imx283_start_streaming(imx283, state);
+ if (ret)
+ goto err_rpm_put;
+
+ return 0;
+
+err_rpm_put:
+ pm_runtime_mark_last_busy(imx283->dev);
+ pm_runtime_put_autosuspend(imx283->dev);
+
+ return ret;
+}
+
+static int imx283_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
+{
+ struct imx283 *imx283 = to_imx283(sd);
+ int ret;
+
+ if (pad != IMAGE_PAD)
+ return -EINVAL;
+
+ ret = cci_write(imx283->cci, IMX283_REG_STANDBY, IMX283_STBLOGIC, NULL);
+ if (ret)
+ dev_err(imx283->dev, "Failed to stop stream\n");
+
+ pm_runtime_mark_last_busy(imx283->dev);
+ pm_runtime_put_autosuspend(imx283->dev);
+
+ return ret;
+}
+
+/* Power/clock management functions */
+static int imx283_power_on(struct imx283 *imx283)
+{
+ int ret;
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(imx283_supply_name),
+ imx283->supplies);
+ if (ret) {
+ dev_err(imx283->dev, "failed to enable regulators\n");
+ return ret;
+ }
+
+ ret = clk_prepare_enable(imx283->xclk);
+ if (ret) {
+ dev_err(imx283->dev, "failed to enable clock\n");
+ goto reg_off;
+ }
+
+ gpiod_set_value_cansleep(imx283->reset_gpio, 0);
+
+ usleep_range(IMX283_XCLR_MIN_DELAY_US,
+ IMX283_XCLR_MIN_DELAY_US + IMX283_XCLR_DELAY_RANGE_US);
+
+ return 0;
+
+reg_off:
+ regulator_bulk_disable(ARRAY_SIZE(imx283_supply_name), imx283->supplies);
+ return ret;
+}
+
+static int imx283_power_off(struct imx283 *imx283)
+{
+ gpiod_set_value_cansleep(imx283->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(imx283_supply_name), imx283->supplies);
+ clk_disable_unprepare(imx283->xclk);
+
+ return 0;
+}
+
+static int imx283_runtime_resume(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx283 *imx283 = to_imx283(sd);
+
+ return imx283_power_on(imx283);
+}
+
+static int imx283_runtime_suspend(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct imx283 *imx283 = to_imx283(sd);
+
+ imx283_power_off(imx283);
+
+ return 0;
+}
+
+static int imx283_get_regulators(struct imx283 *imx283)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx283_supply_name); i++)
+ imx283->supplies[i].supply = imx283_supply_name[i];
+
+ return devm_regulator_bulk_get(imx283->dev,
+ ARRAY_SIZE(imx283_supply_name),
+ imx283->supplies);
+}
+
+/* Verify chip ID */
+static int imx283_identify_module(struct imx283 *imx283)
+{
+ int ret;
+ u64 val;
+
+ ret = cci_read(imx283->cci, IMX283_REG_CHIP_ID, &val, NULL);
+ if (ret) {
+ dev_err(imx283->dev, "failed to read chip id %x, with error %d\n",
+ IMX283_CHIP_ID, ret);
+ return ret;
+ }
+
+ if (val != IMX283_CHIP_ID) {
+ dev_err(imx283->dev, "chip id mismatch: %x!=%llx\n",
+ IMX283_CHIP_ID, val);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int imx283_get_selection(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_selection *sel)
+{
+ switch (sel->target) {
+ case V4L2_SEL_TGT_CROP: {
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, 0);
+ return 0;
+ }
+
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ sel->r = imx283_native_area;
+ return 0;
+
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ sel->r = imx283_active_area;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static const struct v4l2_subdev_core_ops imx283_core_ops = {
+ .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
+ .unsubscribe_event = v4l2_event_subdev_unsubscribe,
+};
+
+static const struct v4l2_subdev_video_ops imx283_video_ops = {
+ .s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_pad_ops imx283_pad_ops = {
+ .enum_mbus_code = imx283_enum_mbus_code,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = imx283_set_pad_format,
+ .get_selection = imx283_get_selection,
+ .enum_frame_size = imx283_enum_frame_size,
+ .enable_streams = imx283_enable_streams,
+ .disable_streams = imx283_disable_streams,
+};
+
+static const struct v4l2_subdev_internal_ops imx283_internal_ops = {
+ .init_state = imx283_init_state,
+};
+
+static const struct v4l2_subdev_ops imx283_subdev_ops = {
+ .core = &imx283_core_ops,
+ .video = &imx283_video_ops,
+ .pad = &imx283_pad_ops,
+};
+
+/* Initialize control handlers */
+static int imx283_init_controls(struct imx283 *imx283)
+{
+ struct v4l2_ctrl_handler *ctrl_hdlr;
+ struct v4l2_fwnode_device_properties props;
+ struct v4l2_ctrl *link_freq;
+ const struct imx283_mode *mode = &supported_modes_12bit[0];
+ u64 min_hblank, max_hblank, def_hblank;
+ u64 pixel_rate;
+ int ret;
+
+ ctrl_hdlr = &imx283->ctrl_handler;
+ ret = v4l2_ctrl_handler_init(ctrl_hdlr, 16);
+ if (ret)
+ return ret;
+
+ /*
+ * Create the controls here, but mode specific limits are setup
+ * in the imx283_set_framing_limits() call below.
+ */
+
+ /* By default, PIXEL_RATE is read only */
+ pixel_rate = imx283_pixel_rate(imx283, mode);
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops,
+ V4L2_CID_PIXEL_RATE, pixel_rate,
+ pixel_rate, 1, pixel_rate);
+
+ link_freq = v4l2_ctrl_new_int_menu(ctrl_hdlr, &imx283_ctrl_ops,
+ V4L2_CID_LINK_FREQ,
+ __fls(imx283->link_freq_bitmap),
+ __ffs(imx283->link_freq_bitmap),
+ link_frequencies);
+ if (link_freq)
+ link_freq->flags |= V4L2_CTRL_FLAG_READ_ONLY;
+
+ /* Initialise vblank/hblank/exposure based on the current mode. */
+ imx283->vblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops,
+ V4L2_CID_VBLANK,
+ mode->min_vmax - mode->height,
+ IMX283_VMAX_MAX, 1,
+ mode->default_vmax - mode->height);
+
+ min_hblank = mode->min_hmax - mode->width;
+ max_hblank = imx283_iclk_to_pix(pixel_rate, IMX283_HMAX_MAX) - mode->width;
+ def_hblank = mode->default_hmax - mode->width;
+ imx283->hblank = v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops,
+ V4L2_CID_HBLANK, min_hblank, max_hblank,
+ 1, def_hblank);
+
+ imx283->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops,
+ V4L2_CID_EXPOSURE,
+ IMX283_EXPOSURE_MIN,
+ IMX283_EXPOSURE_MAX,
+ IMX283_EXPOSURE_STEP,
+ IMX283_EXPOSURE_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops, V4L2_CID_ANALOGUE_GAIN,
+ IMX283_ANA_GAIN_MIN, IMX283_ANA_GAIN_MAX,
+ IMX283_ANA_GAIN_STEP, IMX283_ANA_GAIN_DEFAULT);
+
+ v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
+ IMX283_DGTL_GAIN_MIN, IMX283_DGTL_GAIN_MAX,
+ IMX283_DGTL_GAIN_STEP, IMX283_DGTL_GAIN_DEFAULT);
+
+ imx283->vflip = v4l2_ctrl_new_std(ctrl_hdlr, &imx283_ctrl_ops, V4L2_CID_VFLIP,
+ 0, 1, 1, 0);
+ if (imx283->vflip)
+ imx283->vflip->flags |= V4L2_CTRL_FLAG_MODIFY_LAYOUT;
+
+ v4l2_ctrl_new_std_menu_items(ctrl_hdlr, &imx283_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(imx283_tpg_menu) - 1,
+ 0, 0, imx283_tpg_menu);
+
+ if (ctrl_hdlr->error) {
+ ret = ctrl_hdlr->error;
+ dev_err(imx283->dev, "control init failed (%d)\n", ret);
+ goto error;
+ }
+
+ ret = v4l2_fwnode_device_parse(imx283->dev, &props);
+ if (ret)
+ goto error;
+
+ ret = v4l2_ctrl_new_fwnode_properties(ctrl_hdlr, &imx283_ctrl_ops,
+ &props);
+ if (ret)
+ goto error;
+
+ imx283->sd.ctrl_handler = ctrl_hdlr;
+
+ mutex_lock(imx283->ctrl_handler.lock);
+
+ /* Setup exposure and frame/line length limits. */
+ imx283_set_framing_limits(imx283, mode);
+
+ mutex_unlock(imx283->ctrl_handler.lock);
+
+ return 0;
+
+error:
+ v4l2_ctrl_handler_free(ctrl_hdlr);
+
+ return ret;
+}
+
+static int imx283_parse_endpoint(struct imx283 *imx283)
+{
+ struct fwnode_handle *fwnode;
+ struct v4l2_fwnode_endpoint bus_cfg = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ struct fwnode_handle *ep;
+ int ret;
+
+ fwnode = dev_fwnode(imx283->dev);
+ ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
+ if (!ep) {
+ dev_err(imx283->dev, "Failed to get next endpoint\n");
+ return -ENXIO;
+ }
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(ep, &bus_cfg);
+ fwnode_handle_put(ep);
+ if (ret)
+ return ret;
+
+ if (bus_cfg.bus.mipi_csi2.num_data_lanes != 4) {
+ dev_err(imx283->dev,
+ "number of CSI2 data lanes %d is not supported\n",
+ bus_cfg.bus.mipi_csi2.num_data_lanes);
+ ret = -EINVAL;
+ goto done_endpoint_free;
+ }
+
+ ret = v4l2_link_freq_to_bitmap(imx283->dev, bus_cfg.link_frequencies,
+ bus_cfg.nr_of_link_frequencies,
+ link_frequencies, ARRAY_SIZE(link_frequencies),
+ &imx283->link_freq_bitmap);
+
+done_endpoint_free:
+ v4l2_fwnode_endpoint_free(&bus_cfg);
+
+ return ret;
+};
+
+static int imx283_probe(struct i2c_client *client)
+{
+ struct imx283 *imx283;
+ unsigned int i;
+ unsigned int xclk_freq;
+ int ret;
+
+ imx283 = devm_kzalloc(&client->dev, sizeof(*imx283), GFP_KERNEL);
+ if (!imx283)
+ return -ENOMEM;
+
+ imx283->dev = &client->dev;
+
+ v4l2_i2c_subdev_init(&imx283->sd, client, &imx283_subdev_ops);
+
+ imx283->cci = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(imx283->cci)) {
+ ret = PTR_ERR(imx283->cci);
+ dev_err(imx283->dev, "failed to initialize CCI: %d\n", ret);
+ return ret;
+ }
+
+ /* Get system clock (xclk) */
+ imx283->xclk = devm_clk_get(imx283->dev, NULL);
+ if (IS_ERR(imx283->xclk)) {
+ return dev_err_probe(imx283->dev, PTR_ERR(imx283->xclk),
+ "failed to get xclk\n");
+ }
+
+ xclk_freq = clk_get_rate(imx283->xclk);
+ for (i = 0; i < ARRAY_SIZE(imx283_frequencies); i++) {
+ if (xclk_freq == imx283_frequencies[i].mhz) {
+ imx283->freq = &imx283_frequencies[i];
+ break;
+ }
+ }
+ if (!imx283->freq) {
+ dev_err(imx283->dev, "xclk frequency unsupported: %d Hz\n", xclk_freq);
+ return -EINVAL;
+ }
+
+ ret = imx283_get_regulators(imx283);
+ if (ret) {
+ return dev_err_probe(imx283->dev, ret,
+ "failed to get regulators\n");
+ }
+
+ ret = imx283_parse_endpoint(imx283);
+ if (ret) {
+ dev_err(imx283->dev, "failed to parse endpoint configuration\n");
+ return ret;
+ }
+
+ /* Request optional enable pin */
+ imx283->reset_gpio = devm_gpiod_get_optional(imx283->dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(imx283->reset_gpio))
+ return dev_err_probe(imx283->dev, PTR_ERR(imx283->reset_gpio),
+ "failed to get reset GPIO\n");
+
+ /*
+ * The sensor must be powered for imx283_identify_module()
+ * to be able to read the CHIP_ID register
+ */
+ ret = imx283_power_on(imx283);
+ if (ret)
+ return ret;
+
+ ret = imx283_identify_module(imx283);
+ if (ret)
+ goto error_power_off;
+
+ /*
+ * Enable runtime PM with autosuspend. As the device has been powered
+ * manually, mark it as active, and increase the usage count without
+ * resuming the device.
+ */
+ pm_runtime_set_active(imx283->dev);
+ pm_runtime_get_noresume(imx283->dev);
+ pm_runtime_enable(imx283->dev);
+ pm_runtime_set_autosuspend_delay(imx283->dev, 1000);
+ pm_runtime_use_autosuspend(imx283->dev);
+
+ /* This needs the pm runtime to be registered. */
+ ret = imx283_init_controls(imx283);
+ if (ret)
+ goto error_pm;
+
+ /* Initialize subdev */
+ imx283->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
+ V4L2_SUBDEV_FL_HAS_EVENTS;
+ imx283->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
+ imx283->sd.internal_ops = &imx283_internal_ops;
+
+ /* Initialize source pads */
+ imx283->pad.flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&imx283->sd.entity, 1, &imx283->pad);
+ if (ret) {
+ dev_err(imx283->dev, "failed to init entity pads: %d\n", ret);
+ goto error_handler_free;
+ }
+
+ imx283->sd.state_lock = imx283->ctrl_handler.lock;
+ ret = v4l2_subdev_init_finalize(&imx283->sd);
+ if (ret < 0) {
+ dev_err(imx283->dev, "subdev init error: %d\n", ret);
+ goto error_media_entity;
+ }
+
+ ret = v4l2_async_register_subdev_sensor(&imx283->sd);
+ if (ret < 0) {
+ dev_err(imx283->dev, "failed to register sensor sub-device: %d\n", ret);
+ goto error_subdev_cleanup;
+ }
+
+ /*
+ * Decrease the PM usage count. The device will get suspended after the
+ * autosuspend delay, turning the power off.
+ */
+ pm_runtime_mark_last_busy(imx283->dev);
+ pm_runtime_put_autosuspend(imx283->dev);
+
+ return 0;
+
+error_subdev_cleanup:
+ v4l2_subdev_cleanup(&imx283->sd);
+
+error_media_entity:
+ media_entity_cleanup(&imx283->sd.entity);
+
+error_handler_free:
+ v4l2_ctrl_handler_free(imx283->sd.ctrl_handler);
+
+error_pm:
+ pm_runtime_disable(imx283->dev);
+ pm_runtime_set_suspended(imx283->dev);
+error_power_off:
+ imx283_power_off(imx283);
+
+ return ret;
+}
+
+static void imx283_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct imx283 *imx283 = to_imx283(sd);
+
+ v4l2_async_unregister_subdev(sd);
+ v4l2_subdev_cleanup(&imx283->sd);
+ media_entity_cleanup(&sd->entity);
+ v4l2_ctrl_handler_free(imx283->sd.ctrl_handler);
+
+ pm_runtime_disable(imx283->dev);
+ if (!pm_runtime_status_suspended(imx283->dev))
+ imx283_power_off(imx283);
+ pm_runtime_set_suspended(imx283->dev);
+}
+
+static DEFINE_RUNTIME_DEV_PM_OPS(imx283_pm_ops, imx283_runtime_suspend,
+ imx283_runtime_resume, NULL);
+
+static const struct of_device_id imx283_dt_ids[] = {
+ { .compatible = "sony,imx283" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, imx283_dt_ids);
+
+static struct i2c_driver imx283_i2c_driver = {
+ .driver = {
+ .name = "imx283",
+ .pm = pm_ptr(&imx283_pm_ops),
+ .of_match_table = imx283_dt_ids,
+ },
+ .probe = imx283_probe,
+ .remove = imx283_remove,
+};
+module_i2c_driver(imx283_i2c_driver);
+
+MODULE_AUTHOR("Will Whang <will@willwhang.com>");
+MODULE_AUTHOR("Kieran Bingham <kieran.bingham@ideasonboard.com>");
+MODULE_AUTHOR("Umang Jain <umang.jain@ideasonboard.com>");
+MODULE_DESCRIPTION("Sony IMX283 Sensor Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/imx412.c b/drivers/media/i2c/imx412.c
index 0efce329525e..7d1f7af0a9df 100644
--- a/drivers/media/i2c/imx412.c
+++ b/drivers/media/i2c/imx412.c
@@ -542,14 +542,13 @@ static int imx412_update_controls(struct imx412 *imx412,
*/
static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain)
{
- u32 lpfr, shutter;
+ u32 lpfr;
int ret;
lpfr = imx412->vblank + imx412->cur_mode->height;
- shutter = lpfr - exposure;
- dev_dbg(imx412->dev, "Set exp %u, analog gain %u, shutter %u, lpfr %u",
- exposure, gain, shutter, lpfr);
+ dev_dbg(imx412->dev, "Set exp %u, analog gain %u, lpfr %u",
+ exposure, gain, lpfr);
ret = imx412_write_reg(imx412, IMX412_REG_HOLD, 1, 1);
if (ret)
@@ -559,7 +558,7 @@ static int imx412_update_exp_gain(struct imx412 *imx412, u32 exposure, u32 gain)
if (ret)
goto error_release_group_hold;
- ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, shutter);
+ ret = imx412_write_reg(imx412, IMX412_REG_EXPOSURE_CIT, 2, exposure);
if (ret)
goto error_release_group_hold;
diff --git a/drivers/media/i2c/ks0127.c b/drivers/media/i2c/ks0127.c
index 5c583f57e3f3..9d0a763cd503 100644
--- a/drivers/media/i2c/ks0127.c
+++ b/drivers/media/i2c/ks0127.c
@@ -175,14 +175,6 @@ MODULE_LICENSE("GPL");
* mga_dev : represents one ks0127 chip.
****************************************************************************/
-struct adjust {
- int contrast;
- int bright;
- int hue;
- int ugain;
- int vgain;
-};
-
struct ks0127 {
struct v4l2_subdev sd;
v4l2_std_id norm;
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index dfcb3fc03350..9fc4e130a273 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -19,7 +19,6 @@
#include <linux/i2c.h>
#include <linux/i2c-mux.h>
#include <linux/module.h>
-#include <linux/mutex.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
@@ -198,12 +197,6 @@ struct max9286_priv {
struct v4l2_ctrl *pixelrate_ctrl;
unsigned int pixelrate;
- struct v4l2_mbus_framefmt fmt[MAX9286_N_SINKS];
- struct v4l2_fract interval;
-
- /* Protects controls and fmt structures */
- struct mutex mutex;
-
unsigned int nsources;
unsigned int source_mask;
unsigned int route_mask;
@@ -576,11 +569,14 @@ static void max9286_set_video_format(struct max9286_priv *priv,
MAX9286_INVVS | MAX9286_HVSRC_D14);
}
-static void max9286_set_fsync_period(struct max9286_priv *priv)
+static void max9286_set_fsync_period(struct max9286_priv *priv,
+ struct v4l2_subdev_state *state)
{
+ const struct v4l2_fract *interval;
u32 fsync;
- if (!priv->interval.numerator || !priv->interval.denominator) {
+ interval = v4l2_subdev_state_get_interval(state, MAX9286_SRC_PAD);
+ if (!interval->numerator || !interval->denominator) {
/*
* Special case, a null interval enables automatic FRAMESYNC
* mode. FRAMESYNC is taken from the slowest link.
@@ -596,8 +592,8 @@ static void max9286_set_fsync_period(struct max9286_priv *priv)
* The FRAMESYNC generator is configured with a period expressed as a
* number of PCLK periods.
*/
- fsync = div_u64((u64)priv->pixelrate * priv->interval.numerator,
- priv->interval.denominator);
+ fsync = div_u64((u64)priv->pixelrate * interval->numerator,
+ interval->denominator);
dev_dbg(&priv->client->dev, "fsync period %u (pclk %u)\n", fsync,
priv->pixelrate);
@@ -788,22 +784,25 @@ static void max9286_v4l2_notifier_unregister(struct max9286_priv *priv)
static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
{
struct max9286_priv *priv = sd_to_max9286(sd);
+ struct v4l2_subdev_state *state;
struct max9286_source *source;
unsigned int i;
bool sync = false;
- int ret;
+ int ret = 0;
+
+ state = v4l2_subdev_lock_and_get_active_state(sd);
if (enable) {
const struct v4l2_mbus_framefmt *format;
/*
- * Get the format from the first used sink pad, as all sink
- * formats must be identical.
+ * Get the format from the source pad, as all formats must be
+ * identical.
*/
- format = &priv->fmt[__ffs(priv->bound_sources)];
+ format = v4l2_subdev_state_get_format(state, MAX9286_SRC_PAD);
max9286_set_video_format(priv, format);
- max9286_set_fsync_period(priv);
+ max9286_set_fsync_period(priv, state);
/*
* The frame sync between cameras is transmitted across the
@@ -816,12 +815,12 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
for_each_source(priv, source) {
ret = v4l2_subdev_call(source->sd, video, s_stream, 1);
if (ret)
- return ret;
+ goto unlock;
}
ret = max9286_check_video_links(priv);
if (ret)
- return ret;
+ goto unlock;
/*
* Wait until frame synchronization is locked.
@@ -842,7 +841,8 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
if (!sync) {
dev_err(&priv->client->dev,
"Failed to get frame synchronization\n");
- return -EXDEV; /* Invalid cross-device link */
+ ret = -EXDEV; /* Invalid cross-device link */
+ goto unlock;
}
/*
@@ -865,26 +865,21 @@ static int max9286_s_stream(struct v4l2_subdev *sd, int enable)
max9286_i2c_mux_close(priv);
}
- return 0;
+unlock:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
}
static int max9286_get_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval *interval)
{
- struct max9286_priv *priv = sd_to_max9286(sd);
-
- /*
- * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
- * subdev active state API.
- */
- if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
- return -EINVAL;
-
if (interval->pad != MAX9286_SRC_PAD)
return -EINVAL;
- interval->interval = priv->interval;
+ interval->interval = *v4l2_subdev_state_get_interval(sd_state,
+ interval->pad);
return 0;
}
@@ -893,19 +888,11 @@ static int max9286_set_frame_interval(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_frame_interval *interval)
{
- struct max9286_priv *priv = sd_to_max9286(sd);
-
- /*
- * FIXME: Implement support for V4L2_SUBDEV_FORMAT_TRY, using the V4L2
- * subdev active state API.
- */
- if (interval->which != V4L2_SUBDEV_FORMAT_ACTIVE)
- return -EINVAL;
-
if (interval->pad != MAX9286_SRC_PAD)
return -EINVAL;
- priv->interval = interval->interval;
+ *v4l2_subdev_state_get_interval(sd_state,
+ interval->pad) = interval->interval;
return 0;
}
@@ -914,39 +901,28 @@ static int max9286_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_mbus_code_enum *code)
{
- if (code->pad || code->index > 0)
+ if (code->pad || code->index >= ARRAY_SIZE(max9286_formats))
return -EINVAL;
- code->code = MEDIA_BUS_FMT_UYVY8_1X16;
+ code->code = max9286_formats[code->index].code;
return 0;
}
-static struct v4l2_mbus_framefmt *
-max9286_get_pad_format(struct max9286_priv *priv,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, u32 which)
-{
- switch (which) {
- case V4L2_SUBDEV_FORMAT_TRY:
- return v4l2_subdev_state_get_format(sd_state, pad);
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &priv->fmt[pad];
- default:
- return NULL;
- }
-}
-
static int max9286_set_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
struct max9286_priv *priv = sd_to_max9286(sd);
- struct v4l2_mbus_framefmt *cfg_fmt;
+ struct max9286_source *source;
unsigned int i;
+ /*
+ * Disable setting format on the source pad: format is propagated
+ * from the sinks.
+ */
if (format->pad == MAX9286_SRC_PAD)
- return -EINVAL;
+ return v4l2_subdev_get_fmt(sd, state, format);
/* Validate the format. */
for (i = 0; i < ARRAY_SIZE(max9286_formats); ++i) {
@@ -957,42 +933,17 @@ static int max9286_set_fmt(struct v4l2_subdev *sd,
if (i == ARRAY_SIZE(max9286_formats))
format->format.code = max9286_formats[0].code;
- cfg_fmt = max9286_get_pad_format(priv, sd_state, format->pad,
- format->which);
- if (!cfg_fmt)
- return -EINVAL;
-
- mutex_lock(&priv->mutex);
- *cfg_fmt = format->format;
- mutex_unlock(&priv->mutex);
-
- return 0;
-}
-
-static int max9286_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct max9286_priv *priv = sd_to_max9286(sd);
- struct v4l2_mbus_framefmt *cfg_fmt;
- unsigned int pad = format->pad;
-
/*
- * Multiplexed Stream Support: Support link validation by returning the
- * format of the first bound link. All links must have the same format,
- * as we do not support mixing and matching of cameras connected to the
- * max9286.
+ * Apply the same format on all the other pad as all links must have the
+ * same format.
*/
- if (pad == MAX9286_SRC_PAD)
- pad = __ffs(priv->bound_sources);
+ for_each_source(priv, source) {
+ unsigned int index = to_index(priv, source);
- cfg_fmt = max9286_get_pad_format(priv, sd_state, pad, format->which);
- if (!cfg_fmt)
- return -EINVAL;
+ *v4l2_subdev_state_get_format(state, index) = format->format;
+ }
- mutex_lock(&priv->mutex);
- format->format = *cfg_fmt;
- mutex_unlock(&priv->mutex);
+ *v4l2_subdev_state_get_format(state, MAX9286_SRC_PAD) = format->format;
return 0;
}
@@ -1003,7 +954,7 @@ static const struct v4l2_subdev_video_ops max9286_video_ops = {
static const struct v4l2_subdev_pad_ops max9286_pad_ops = {
.enum_mbus_code = max9286_enum_mbus_code,
- .get_fmt = max9286_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = max9286_set_fmt,
.get_frame_interval = max9286_get_frame_interval,
.set_frame_interval = max9286_set_frame_interval,
@@ -1025,26 +976,29 @@ static const struct v4l2_mbus_framefmt max9286_default_format = {
.xfer_func = V4L2_XFER_FUNC_DEFAULT,
};
-static void max9286_init_format(struct v4l2_mbus_framefmt *fmt)
+static int max9286_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
- *fmt = max9286_default_format;
-}
+ struct v4l2_fract *interval;
-static int max9286_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
-{
- struct v4l2_mbus_framefmt *format;
- unsigned int i;
+ for (unsigned int i = 0; i < MAX9286_N_PADS; i++)
+ *v4l2_subdev_state_get_format(state, i) = max9286_default_format;
- for (i = 0; i < MAX9286_N_SINKS; i++) {
- format = v4l2_subdev_state_get_format(fh->state, i);
- max9286_init_format(format);
- }
+ /*
+ * Special case: a null interval enables automatic FRAMESYNC mode.
+ *
+ * FRAMESYNC is taken from the slowest link. See register 0x01
+ * configuration.
+ */
+ interval = v4l2_subdev_state_get_interval(state, MAX9286_SRC_PAD);
+ interval->numerator = 0;
+ interval->denominator = 0;
return 0;
}
static const struct v4l2_subdev_internal_ops max9286_subdev_internal_ops = {
- .open = max9286_open,
+ .init_state = max9286_init_state,
};
static const struct media_entity_operations max9286_media_ops = {
@@ -1079,10 +1033,6 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
}
/* Configure V4L2 for the MAX9286 itself */
-
- for (i = 0; i < MAX9286_N_SINKS; i++)
- max9286_init_format(&priv->fmt[i]);
-
v4l2_i2c_subdev_init(&priv->sd, priv->client, &max9286_subdev_ops);
priv->sd.internal_ops = &max9286_subdev_internal_ops;
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
@@ -1109,14 +1059,21 @@ static int max9286_v4l2_register(struct max9286_priv *priv)
if (ret)
goto err_async;
+ priv->sd.state_lock = priv->ctrls.lock;
+ ret = v4l2_subdev_init_finalize(&priv->sd);
+ if (ret)
+ goto err_async;
+
ret = v4l2_async_register_subdev(&priv->sd);
if (ret < 0) {
dev_err(dev, "Unable to register subdevice\n");
- goto err_async;
+ goto err_subdev;
}
return 0;
+err_subdev:
+ v4l2_subdev_cleanup(&priv->sd);
err_async:
v4l2_ctrl_handler_free(&priv->ctrls);
max9286_v4l2_notifier_unregister(priv);
@@ -1126,6 +1083,7 @@ err_async:
static void max9286_v4l2_unregister(struct max9286_priv *priv)
{
+ v4l2_subdev_cleanup(&priv->sd);
v4l2_ctrl_handler_free(&priv->ctrls);
v4l2_async_unregister_subdev(&priv->sd);
max9286_v4l2_notifier_unregister(priv);
@@ -1182,7 +1140,6 @@ static int max9286_setup(struct max9286_priv *priv)
max9286_write(priv, 0x69, (0xf & ~priv->route_mask));
max9286_set_video_format(priv, &max9286_default_format);
- max9286_set_fsync_period(priv);
cfg = max9286_read(priv, 0x1c);
if (cfg < 0)
@@ -1629,8 +1586,6 @@ static int max9286_probe(struct i2c_client *client)
if (!priv)
return -ENOMEM;
- mutex_init(&priv->mutex);
-
priv->client = client;
/* GPIO values default to high */
diff --git a/drivers/media/i2c/max96714.c b/drivers/media/i2c/max96714.c
new file mode 100644
index 000000000000..c97de66631e0
--- /dev/null
+++ b/drivers/media/i2c/max96714.c
@@ -0,0 +1,1024 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Maxim GMSL2 Deserializer Driver
+ *
+ * Copyright (C) 2024 Collabora Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/bitops.h>
+#include <linux/fwnode.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+
+#include <media/v4l2-cci.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define MAX96714_DEVICE_ID 0xc9
+#define MAX96714F_DEVICE_ID 0xca
+#define MAX96714_NPORTS 2
+#define MAX96714_PAD_SINK 0
+#define MAX96714_PAD_SOURCE 1
+
+/* DEV */
+#define MAX96714_REG13 CCI_REG8(0x0d)
+#define MAX96714_DEV_REV CCI_REG8(0x0e)
+#define MAX96714_DEV_REV_MASK GENMASK(3, 0)
+#define MAX96714_LINK_LOCK CCI_REG8(0x13)
+#define MAX96714_LINK_LOCK_BIT BIT(3)
+#define MAX96714_IO_CHK0 CCI_REG8(0x38)
+#define MAX96714_PATTERN_CLK_FREQ GENMASK(1, 0)
+/* VID_RX */
+#define MAX96714_VIDEO_RX8 CCI_REG8(0x11a)
+#define MAX96714_VID_LOCK BIT(6)
+
+/* VRX_PATGEN_0 */
+#define MAX96714_PATGEN_0 CCI_REG8(0x240)
+#define MAX96714_PATGEN_1 CCI_REG8(0x241)
+#define MAX96714_PATGEN_MODE GENMASK(5, 4)
+#define MAX96714_PATGEN_VS_DLY CCI_REG24(0x242)
+#define MAX96714_PATGEN_VS_HIGH CCI_REG24(0x245)
+#define MAX96714_PATGEN_VS_LOW CCI_REG24(0x248)
+#define MAX96714_PATGEN_V2H CCI_REG24(0x24b)
+#define MAX96714_PATGEN_HS_HIGH CCI_REG16(0x24e)
+#define MAX96714_PATGEN_HS_LOW CCI_REG16(0x250)
+#define MAX96714_PATGEN_HS_CNT CCI_REG16(0x252)
+#define MAX96714_PATGEN_V2D CCI_REG24(0x254)
+#define MAX96714_PATGEN_DE_HIGH CCI_REG16(0x257)
+#define MAX96714_PATGEN_DE_LOW CCI_REG16(0x259)
+#define MAX96714_PATGEN_DE_CNT CCI_REG16(0x25B)
+#define MAX96714_PATGEN_GRAD_INC CCI_REG8(0x25d)
+#define MAX96714_PATGEN_CHKB_COLOR_A CCI_REG24(0x25E)
+#define MAX96714_PATGEN_CHKB_COLOR_B CCI_REG24(0x261)
+#define MAX96714_PATGEN_CHKB_RPT_CNT_A CCI_REG8(0x264)
+#define MAX96714_PATGEN_CHKB_RPT_CNT_B CCI_REG8(0x265)
+#define MAX96714_PATGEN_CHKB_ALT CCI_REG8(0x266)
+/* BACKTOP */
+#define MAX96714_BACKTOP25 CCI_REG8(0x320)
+#define CSI_DPLL_FREQ_MASK GENMASK(4, 0)
+
+/* MIPI_PHY */
+#define MAX96714_MIPI_PHY0 CCI_REG8(0x330)
+#define MAX96714_FORCE_CSI_OUT BIT(7)
+#define MAX96714_MIPI_STDBY_N CCI_REG8(0x332)
+#define MAX96714_MIPI_STDBY_MASK GENMASK(5, 4)
+#define MAX96714_MIPI_LANE_MAP CCI_REG8(0x333)
+#define MAX96714_MIPI_POLARITY CCI_REG8(0x335)
+#define MAX96714_MIPI_POLARITY_MASK GENMASK(5, 0)
+
+/* MIPI_TX */
+#define MAX96714_MIPI_LANE_CNT CCI_REG8(0x44a)
+#define MAX96714_CSI2_LANE_CNT_MASK GENMASK(7, 6)
+#define MAX96714_MIPI_TX52 CCI_REG8(0x474)
+#define MAX96714_TUN_EN BIT(0)
+
+#define MHZ(v) ((u32)((v) * 1000000U))
+
+enum max96714_vpg_mode {
+ MAX96714_VPG_DISABLED = 0,
+ MAX96714_VPG_CHECKERBOARD = 1,
+ MAX96714_VPG_GRADIENT = 2,
+};
+
+struct max96714_rxport {
+ struct {
+ struct v4l2_subdev *sd;
+ u16 pad;
+ struct fwnode_handle *ep_fwnode;
+ } source;
+ struct regulator *poc;
+};
+
+struct max96714_txport {
+ struct v4l2_fwnode_endpoint vep;
+};
+
+struct max96714_priv {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct gpio_desc *pd_gpio;
+ struct max96714_rxport rxport;
+ struct i2c_mux_core *mux;
+ u64 enabled_source_streams;
+ struct v4l2_subdev sd;
+ struct media_pad pads[MAX96714_NPORTS];
+ struct v4l2_mbus_config_mipi_csi2 mipi_csi2;
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_async_notifier notifier;
+ s64 tx_link_freq;
+ enum max96714_vpg_mode pattern;
+};
+
+static inline struct max96714_priv *sd_to_max96714(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct max96714_priv, sd);
+}
+
+static int max96714_enable_tx_port(struct max96714_priv *priv)
+{
+ return cci_update_bits(priv->regmap, MAX96714_MIPI_STDBY_N,
+ MAX96714_MIPI_STDBY_MASK,
+ MAX96714_MIPI_STDBY_MASK, NULL);
+}
+
+static int max96714_disable_tx_port(struct max96714_priv *priv)
+{
+ return cci_update_bits(priv->regmap, MAX96714_MIPI_STDBY_N,
+ MAX96714_MIPI_STDBY_MASK, 0, NULL);
+}
+
+static bool max96714_tx_port_enabled(struct max96714_priv *priv)
+{
+ u64 val;
+
+ cci_read(priv->regmap, MAX96714_MIPI_STDBY_N, &val, NULL);
+
+ return val & MAX96714_MIPI_STDBY_MASK;
+}
+
+static int max96714_apply_patgen_timing(struct max96714_priv *priv,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *fmt =
+ v4l2_subdev_state_get_format(state, MAX96714_PAD_SOURCE);
+ const u32 h_active = fmt->width;
+ const u32 h_fp = 88;
+ const u32 h_sw = 44;
+ const u32 h_bp = 148;
+ u32 h_tot;
+ const u32 v_active = fmt->height;
+ const u32 v_fp = 4;
+ const u32 v_sw = 5;
+ const u32 v_bp = 36;
+ u32 v_tot;
+ int ret = 0;
+
+ h_tot = h_active + h_fp + h_sw + h_bp;
+ v_tot = v_active + v_fp + v_sw + v_bp;
+
+ /* 75 Mhz pixel clock */
+ cci_update_bits(priv->regmap, MAX96714_IO_CHK0,
+ MAX96714_PATTERN_CLK_FREQ, 1, &ret);
+
+ dev_info(&priv->client->dev, "height: %d width: %d\n", fmt->height,
+ fmt->width);
+
+ cci_write(priv->regmap, MAX96714_PATGEN_VS_DLY, 0, &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_VS_HIGH, v_sw * h_tot, &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_VS_LOW,
+ (v_active + v_fp + v_bp) * h_tot, &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_HS_HIGH, h_sw, &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_HS_LOW, h_active + h_fp + h_bp,
+ &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_V2D,
+ h_tot * (v_sw + v_bp) + (h_sw + h_bp), &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_HS_CNT, v_tot, &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_DE_HIGH, h_active, &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_DE_LOW, h_fp + h_sw + h_bp,
+ &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_DE_CNT, v_active, &ret);
+ /* B G R */
+ cci_write(priv->regmap, MAX96714_PATGEN_CHKB_COLOR_A, 0xfecc00, &ret);
+ /* B G R */
+ cci_write(priv->regmap, MAX96714_PATGEN_CHKB_COLOR_B, 0x006aa7, &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_CHKB_RPT_CNT_A, 0x3c, &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_CHKB_RPT_CNT_B, 0x3c, &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_CHKB_ALT, 0x3c, &ret);
+ cci_write(priv->regmap, MAX96714_PATGEN_GRAD_INC, 0x10, &ret);
+
+ return ret;
+}
+
+static int max96714_apply_patgen(struct max96714_priv *priv,
+ struct v4l2_subdev_state *state)
+{
+ unsigned int val;
+ int ret = 0;
+
+ if (priv->pattern)
+ ret = max96714_apply_patgen_timing(priv, state);
+
+ cci_write(priv->regmap, MAX96714_PATGEN_0, priv->pattern ? 0xfb : 0,
+ &ret);
+
+ val = FIELD_PREP(MAX96714_PATGEN_MODE, priv->pattern);
+ cci_update_bits(priv->regmap, MAX96714_PATGEN_1, MAX96714_PATGEN_MODE,
+ val, &ret);
+ return ret;
+}
+
+static int max96714_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct max96714_priv *priv =
+ container_of(ctrl->handler, struct max96714_priv, ctrl_handler);
+ int ret;
+
+ switch (ctrl->id) {
+ case V4L2_CID_TEST_PATTERN:
+ if (priv->enabled_source_streams)
+ return -EBUSY;
+ priv->pattern = ctrl->val;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = cci_update_bits(priv->regmap, MAX96714_MIPI_PHY0,
+ MAX96714_FORCE_CSI_OUT,
+ priv->pattern ? MAX96714_FORCE_CSI_OUT : 0, NULL);
+
+ /* Pattern generator doesn't work with tunnel mode */
+ return cci_update_bits(priv->regmap, MAX96714_MIPI_TX52,
+ MAX96714_TUN_EN,
+ priv->pattern ? 0 : MAX96714_TUN_EN, &ret);
+}
+
+static const char * const max96714_test_pattern[] = {
+ "Disabled",
+ "Checkerboard",
+ "Gradient"
+};
+
+static const struct v4l2_ctrl_ops max96714_ctrl_ops = {
+ .s_ctrl = max96714_s_ctrl,
+};
+
+static int max96714_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 source_pad, u64 streams_mask)
+{
+ struct max96714_priv *priv = sd_to_max96714(sd);
+ u64 sink_streams;
+ int ret;
+
+ if (!priv->enabled_source_streams)
+ max96714_enable_tx_port(priv);
+
+ ret = max96714_apply_patgen(priv, state);
+ if (ret)
+ goto err;
+
+ if (!priv->pattern) {
+ if (!priv->rxport.source.sd) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ sink_streams =
+ v4l2_subdev_state_xlate_streams(state,
+ MAX96714_PAD_SOURCE,
+ MAX96714_PAD_SINK,
+ &streams_mask);
+
+ ret = v4l2_subdev_enable_streams(priv->rxport.source.sd,
+ priv->rxport.source.pad,
+ sink_streams);
+ if (ret)
+ goto err;
+ }
+
+ priv->enabled_source_streams |= streams_mask;
+
+ return 0;
+
+err:
+ if (!priv->enabled_source_streams)
+ max96714_disable_tx_port(priv);
+
+ return ret;
+}
+
+static int max96714_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 source_pad, u64 streams_mask)
+{
+ struct max96714_priv *priv = sd_to_max96714(sd);
+ u64 sink_streams;
+
+ if (!priv->pattern) {
+ int ret;
+
+ sink_streams =
+ v4l2_subdev_state_xlate_streams(state,
+ MAX96714_PAD_SOURCE,
+ MAX96714_PAD_SINK,
+ &streams_mask);
+
+ ret = v4l2_subdev_disable_streams(priv->rxport.source.sd,
+ priv->rxport.source.pad,
+ sink_streams);
+ if (ret)
+ return ret;
+ }
+
+ priv->enabled_source_streams &= ~streams_mask;
+
+ if (!priv->enabled_source_streams)
+ max96714_disable_tx_port(priv);
+
+ return 0;
+}
+
+static int max96714_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct max96714_priv *priv = sd_to_max96714(sd);
+ struct v4l2_mbus_framefmt *fmt;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+ priv->enabled_source_streams)
+ return -EBUSY;
+
+ /* No transcoding, source and sink formats must match. */
+ if (format->pad == MAX96714_PAD_SOURCE)
+ return v4l2_subdev_get_fmt(sd, state, format);
+
+ fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
+ if (!fmt)
+ return -EINVAL;
+
+ *fmt = format->format;
+
+ fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
+ format->stream);
+ if (!fmt)
+ return -EINVAL;
+
+ *fmt = format->format;
+
+ return 0;
+}
+
+static int _max96714_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ static const struct v4l2_mbus_framefmt format = {
+ .width = 1280,
+ .height = 1080,
+ .code = MEDIA_BUS_FMT_Y8_1X8,
+ .field = V4L2_FIELD_NONE,
+ };
+ int ret;
+
+ /*
+ * Note: we can only support up to V4L2_FRAME_DESC_ENTRY_MAX, until
+ * frame desc is made dynamically allocated.
+ */
+ if (routing->num_routes > V4L2_FRAME_DESC_ENTRY_MAX)
+ return -EINVAL;
+
+ ret = v4l2_subdev_routing_validate(sd, routing,
+ V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
+ if (ret)
+ return ret;
+
+ return v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
+}
+
+static int max96714_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct max96714_priv *priv = sd_to_max96714(sd);
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->enabled_source_streams)
+ return -EBUSY;
+
+ return _max96714_set_routing(sd, state, which, routing);
+}
+
+static int max96714_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_route routes[] = {
+ {
+ .sink_pad = MAX96714_PAD_SINK,
+ .sink_stream = 0,
+ .source_pad = MAX96714_PAD_SOURCE,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ }
+ };
+ struct v4l2_subdev_krouting routing = {
+ .num_routes = ARRAY_SIZE(routes),
+ .routes = routes,
+ };
+
+ return _max96714_set_routing(sd, state, V4L2_SUBDEV_FORMAT_ACTIVE,
+ &routing);
+}
+
+static const struct v4l2_subdev_pad_ops max96714_pad_ops = {
+ .enable_streams = max96714_enable_streams,
+ .disable_streams = max96714_disable_streams,
+
+ .set_routing = max96714_set_routing,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = max96714_set_fmt,
+};
+
+static bool max96714_link_locked(struct max96714_priv *priv)
+{
+ u64 val = 0;
+
+ cci_read(priv->regmap, MAX96714_LINK_LOCK, &val, NULL);
+
+ return val & MAX96714_LINK_LOCK_BIT;
+}
+
+static void max96714_link_status(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+
+ dev_info(dev, "Link locked:%d\n", max96714_link_locked(priv));
+}
+
+static bool max96714_pipe_locked(struct max96714_priv *priv)
+{
+ u64 val;
+
+ cci_read(priv->regmap, MAX96714_VIDEO_RX8, &val, NULL);
+
+ return val & MAX96714_VID_LOCK;
+}
+
+static void max96714_pipe_status(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+
+ dev_info(dev, "Pipe vidlock:%d\n", max96714_pipe_locked(priv));
+}
+
+static void max96714_csi_status(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ u64 freq = 0;
+
+ cci_read(priv->regmap, MAX96714_BACKTOP25, &freq, NULL);
+ freq = FIELD_GET(CSI_DPLL_FREQ_MASK, freq);
+
+ dev_info(dev, "CSI controller DPLL freq:%u00MHz CSIPHY enabled:%d\n",
+ (u8)freq, max96714_tx_port_enabled(priv));
+}
+
+static int max96714_log_status(struct v4l2_subdev *sd)
+{
+ struct max96714_priv *priv = sd_to_max96714(sd);
+ struct device *dev = &priv->client->dev;
+
+ dev_info(dev, "Deserializer: max96714\n");
+
+ max96714_link_status(priv);
+ max96714_pipe_status(priv);
+ max96714_csi_status(priv);
+
+ return 0;
+}
+
+static const struct v4l2_subdev_core_ops max96714_subdev_core_ops = {
+ .log_status = max96714_log_status,
+};
+
+static const struct v4l2_subdev_video_ops max96714_video_ops = {
+ .s_stream = v4l2_subdev_s_stream_helper,
+};
+
+static const struct v4l2_subdev_internal_ops max96714_internal_ops = {
+ .init_state = max96714_init_state,
+};
+
+static const struct v4l2_subdev_ops max96714_subdev_ops = {
+ .video = &max96714_video_ops,
+ .core = &max96714_subdev_core_ops,
+ .pad = &max96714_pad_ops,
+};
+
+static const struct media_entity_operations max96714_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int max96714_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_connection *asd)
+{
+ struct max96714_priv *priv = sd_to_max96714(notifier->sd);
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ret = media_entity_get_fwnode_pad(&subdev->entity,
+ priv->rxport.source.ep_fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (ret < 0) {
+ dev_err(dev, "Failed to find pad for %s\n", subdev->name);
+ return ret;
+ }
+
+ priv->rxport.source.sd = subdev;
+ priv->rxport.source.pad = ret;
+
+ ret = media_create_pad_link(&priv->rxport.source.sd->entity,
+ priv->rxport.source.pad, &priv->sd.entity,
+ MAX96714_PAD_SINK,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret) {
+ dev_err(dev, "Unable to link %s:%u -> %s:%u\n",
+ priv->rxport.source.sd->name, priv->rxport.source.pad,
+ priv->sd.name, MAX96714_PAD_SINK);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations max96714_notify_ops = {
+ .bound = max96714_notify_bound,
+};
+
+static int max96714_v4l2_notifier_register(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct max96714_rxport *rxport = &priv->rxport;
+ struct v4l2_async_connection *asd;
+ int ret;
+
+ if (!rxport->source.ep_fwnode)
+ return 0;
+
+ v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd);
+
+ asd = v4l2_async_nf_add_fwnode(&priv->notifier,
+ rxport->source.ep_fwnode,
+ struct v4l2_async_connection);
+ if (IS_ERR(asd)) {
+ dev_err(dev, "Failed to add subdev: %pe", asd);
+ v4l2_async_nf_cleanup(&priv->notifier);
+ return PTR_ERR(asd);
+ }
+
+ priv->notifier.ops = &max96714_notify_ops;
+
+ ret = v4l2_async_nf_register(&priv->notifier);
+ if (ret) {
+ dev_err(dev, "Failed to register subdev_notifier");
+ v4l2_async_nf_cleanup(&priv->notifier);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max96714_create_subdev(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ v4l2_i2c_subdev_init(&priv->sd, priv->client, &max96714_subdev_ops);
+ priv->sd.internal_ops = &max96714_internal_ops;
+
+ v4l2_ctrl_handler_init(&priv->ctrl_handler, 1);
+ priv->sd.ctrl_handler = &priv->ctrl_handler;
+
+ v4l2_ctrl_new_int_menu(&priv->ctrl_handler, NULL, V4L2_CID_LINK_FREQ,
+ 0, 0, &priv->tx_link_freq);
+ v4l2_ctrl_new_std_menu_items(&priv->ctrl_handler,
+ &max96714_ctrl_ops,
+ V4L2_CID_TEST_PATTERN,
+ ARRAY_SIZE(max96714_test_pattern) - 1,
+ 0, 0, max96714_test_pattern);
+ if (priv->ctrl_handler.error) {
+ ret = priv->ctrl_handler.error;
+ goto err_free_ctrl;
+ }
+
+ priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
+ priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ priv->sd.entity.ops = &max96714_entity_ops;
+
+ priv->pads[MAX96714_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ priv->pads[MAX96714_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&priv->sd.entity,
+ MAX96714_NPORTS,
+ priv->pads);
+ if (ret)
+ goto err_free_ctrl;
+
+ priv->sd.state_lock = priv->sd.ctrl_handler->lock;
+
+ ret = v4l2_subdev_init_finalize(&priv->sd);
+ if (ret)
+ goto err_entity_cleanup;
+
+ ret = max96714_v4l2_notifier_register(priv);
+ if (ret) {
+ dev_err(dev, "v4l2 subdev notifier register failed: %d\n", ret);
+ goto err_subdev_cleanup;
+ }
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret) {
+ dev_err(dev, "v4l2_async_register_subdev error: %d\n", ret);
+ goto err_unreg_notif;
+ }
+
+ return 0;
+
+err_unreg_notif:
+ v4l2_async_nf_unregister(&priv->notifier);
+ v4l2_async_nf_cleanup(&priv->notifier);
+err_subdev_cleanup:
+ v4l2_subdev_cleanup(&priv->sd);
+err_entity_cleanup:
+ media_entity_cleanup(&priv->sd.entity);
+err_free_ctrl:
+ v4l2_ctrl_handler_free(&priv->ctrl_handler);
+
+ return ret;
+};
+
+static void max96714_destroy_subdev(struct max96714_priv *priv)
+{
+ v4l2_async_nf_unregister(&priv->notifier);
+ v4l2_async_nf_cleanup(&priv->notifier);
+ v4l2_async_unregister_subdev(&priv->sd);
+
+ v4l2_subdev_cleanup(&priv->sd);
+
+ media_entity_cleanup(&priv->sd.entity);
+ v4l2_ctrl_handler_free(&priv->ctrl_handler);
+}
+
+static int max96714_i2c_mux_select(struct i2c_mux_core *mux, u32 chan)
+{
+ return 0;
+}
+
+static int max96714_i2c_mux_init(struct max96714_priv *priv)
+{
+ priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev,
+ 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
+ max96714_i2c_mux_select, NULL);
+ if (!priv->mux)
+ return -ENOMEM;
+
+ return i2c_mux_add_adapter(priv->mux, 0, 0);
+}
+
+static int max96714_init_tx_port(struct max96714_priv *priv)
+{
+ struct v4l2_mbus_config_mipi_csi2 *mipi;
+ unsigned long lanes_used = 0;
+ unsigned int val, lane;
+ int ret;
+
+ ret = max96714_disable_tx_port(priv);
+
+ mipi = &priv->mipi_csi2;
+ val = div_u64(priv->tx_link_freq * 2, MHZ(100));
+
+ cci_update_bits(priv->regmap, MAX96714_BACKTOP25,
+ CSI_DPLL_FREQ_MASK, val, &ret);
+
+ val = FIELD_PREP(MAX96714_CSI2_LANE_CNT_MASK, mipi->num_data_lanes - 1);
+ cci_update_bits(priv->regmap, MAX96714_MIPI_LANE_CNT,
+ MAX96714_CSI2_LANE_CNT_MASK, val, &ret);
+
+ /* lanes polarity */
+ val = 0;
+ for (lane = 0; lane < mipi->num_data_lanes + 1; lane++) {
+ if (!mipi->lane_polarities[lane])
+ continue;
+ if (lane == 0)
+ /* clock lane */
+ val |= BIT(5);
+ else if (lane < 3)
+ /* Lane D0 and D1 */
+ val |= BIT(lane - 1);
+ else
+ /* D2 and D3 */
+ val |= BIT(lane);
+ }
+
+ cci_update_bits(priv->regmap, MAX96714_MIPI_POLARITY,
+ MAX96714_MIPI_POLARITY_MASK, val, &ret);
+
+ /* lanes mapping */
+ val = 0;
+ for (lane = 0; lane < mipi->num_data_lanes; lane++) {
+ val |= (mipi->data_lanes[lane] - 1) << (lane * 2);
+ lanes_used |= BIT(mipi->data_lanes[lane] - 1);
+ }
+
+ /*
+ * Unused lanes need to be mapped as well to not have
+ * the same lanes mapped twice.
+ */
+ for (; lane < 4; lane++) {
+ unsigned int idx = find_first_zero_bit(&lanes_used, 4);
+
+ val |= idx << (lane * 2);
+ lanes_used |= BIT(idx);
+ }
+
+ return cci_write(priv->regmap, MAX96714_MIPI_LANE_MAP, val, &ret);
+}
+
+static int max96714_rxport_enable_poc(struct max96714_priv *priv)
+{
+ struct max96714_rxport *rxport = &priv->rxport;
+
+ if (!rxport->poc)
+ return 0;
+
+ return regulator_enable(rxport->poc);
+}
+
+static int max96714_rxport_disable_poc(struct max96714_priv *priv)
+{
+ struct max96714_rxport *rxport = &priv->rxport;
+
+ if (!rxport->poc)
+ return 0;
+
+ return regulator_disable(rxport->poc);
+}
+
+static int max96714_parse_dt_txport(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct v4l2_fwnode_endpoint vep = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ struct fwnode_handle *ep_fwnode;
+ u32 num_data_lanes;
+ int ret;
+
+ ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
+ MAX96714_PAD_SOURCE, 0, 0);
+ if (!ep_fwnode)
+ return -EINVAL;
+
+ ret = v4l2_fwnode_endpoint_alloc_parse(ep_fwnode, &vep);
+ fwnode_handle_put(ep_fwnode);
+ if (ret) {
+ dev_err(dev, "tx: failed to parse endpoint data\n");
+ return -EINVAL;
+ }
+
+ if (vep.nr_of_link_frequencies != 1) {
+ ret = -EINVAL;
+ goto err_free_vep;
+ }
+
+ priv->tx_link_freq = vep.link_frequencies[0];
+ /* Min 50MHz, Max 1250MHz, 50MHz step */
+ if (priv->tx_link_freq < MHZ(50) || priv->tx_link_freq > MHZ(1250) ||
+ (u32)priv->tx_link_freq % MHZ(50)) {
+ dev_err(dev, "tx: invalid link frequency\n");
+ ret = -EINVAL;
+ goto err_free_vep;
+ }
+
+ num_data_lanes = vep.bus.mipi_csi2.num_data_lanes;
+ if (num_data_lanes < 1 || num_data_lanes > 4) {
+ dev_err(dev,
+ "tx: invalid number of data lanes must be 1 to 4\n");
+ ret = -EINVAL;
+ goto err_free_vep;
+ }
+
+ memcpy(&priv->mipi_csi2, &vep.bus.mipi_csi2, sizeof(priv->mipi_csi2));
+
+err_free_vep:
+ v4l2_fwnode_endpoint_free(&vep);
+
+ return ret;
+}
+
+static int max96714_parse_dt_rxport(struct max96714_priv *priv)
+{
+ static const char *poc_name = "port0-poc";
+ struct max96714_rxport *rxport = &priv->rxport;
+ struct device *dev = &priv->client->dev;
+ struct fwnode_handle *ep_fwnode;
+ int ret;
+
+ ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
+ MAX96714_PAD_SINK, 0, 0);
+ if (!ep_fwnode)
+ return -ENOENT;
+
+ rxport->source.ep_fwnode = fwnode_graph_get_remote_endpoint(ep_fwnode);
+ fwnode_handle_put(ep_fwnode);
+
+ if (!rxport->source.ep_fwnode) {
+ dev_err(dev, "rx: no remote endpoint\n");
+ return -EINVAL;
+ }
+
+ rxport->poc = devm_regulator_get_optional(dev, poc_name);
+ if (IS_ERR(rxport->poc)) {
+ ret = PTR_ERR(rxport->poc);
+ if (ret == -ENODEV) {
+ rxport->poc = NULL;
+ } else {
+ dev_err(dev, "rx: failed to get POC supply: %d\n", ret);
+ goto err_put_source_ep_fwnode;
+ }
+ }
+
+ return 0;
+
+err_put_source_ep_fwnode:
+ fwnode_handle_put(rxport->source.ep_fwnode);
+ return ret;
+}
+
+static int max96714_parse_dt(struct max96714_priv *priv)
+{
+ int ret;
+
+ ret = max96714_parse_dt_txport(priv);
+ if (ret)
+ return ret;
+
+ ret = max96714_parse_dt_rxport(priv);
+ /*
+ * The deserializer can create a test pattern even if the
+ * rx port is not connected to a serializer.
+ */
+ if (ret && ret == -ENOENT)
+ ret = 0;
+
+ return ret;
+}
+
+static int max96714_enable_core_hw(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ u64 val;
+ int ret;
+
+ if (priv->pd_gpio) {
+ /* wait min 2 ms for reset to complete */
+ gpiod_set_value_cansleep(priv->pd_gpio, 1);
+ fsleep(2000);
+ gpiod_set_value_cansleep(priv->pd_gpio, 0);
+ /* wait min 2 ms for power up to finish */
+ fsleep(2000);
+ }
+
+ ret = cci_read(priv->regmap, MAX96714_REG13, &val, NULL);
+ if (ret) {
+ dev_err_probe(dev, ret, "Cannot read first register, abort\n");
+ goto err_pd_gpio;
+ }
+
+ if (val != MAX96714_DEVICE_ID && val != MAX96714F_DEVICE_ID) {
+ dev_err(dev, "Unsupported device id expected %x got %x\n",
+ MAX96714F_DEVICE_ID, (u8)val);
+ ret = -EOPNOTSUPP;
+ goto err_pd_gpio;
+ }
+
+ ret = cci_read(priv->regmap, MAX96714_DEV_REV, &val, NULL);
+ if (ret)
+ goto err_pd_gpio;
+
+ dev_dbg(dev, "Found %x (rev %lx)\n", MAX96714F_DEVICE_ID,
+ (u8)val & MAX96714_DEV_REV_MASK);
+
+ ret = cci_read(priv->regmap, MAX96714_MIPI_TX52, &val, NULL);
+ if (ret)
+ goto err_pd_gpio;
+
+ if (!(val & MAX96714_TUN_EN)) {
+ dev_err(dev, "Only supporting tunnel mode");
+ ret = -EOPNOTSUPP;
+ goto err_pd_gpio;
+ }
+
+ return 0;
+
+err_pd_gpio:
+ gpiod_set_value_cansleep(priv->pd_gpio, 1);
+ return ret;
+}
+
+static void max96714_disable_core_hw(struct max96714_priv *priv)
+{
+ gpiod_set_value_cansleep(priv->pd_gpio, 1);
+}
+
+static int max96714_get_hw_resources(struct max96714_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+
+ priv->regmap = devm_cci_regmap_init_i2c(priv->client, 16);
+ if (IS_ERR(priv->regmap))
+ return PTR_ERR(priv->regmap);
+
+ priv->pd_gpio =
+ devm_gpiod_get_optional(dev, "powerdown", GPIOD_OUT_HIGH);
+ if (IS_ERR(priv->pd_gpio))
+ return dev_err_probe(dev, PTR_ERR(priv->pd_gpio),
+ "Cannot get powerdown GPIO\n");
+ return 0;
+}
+
+static int max96714_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct max96714_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+
+ ret = max96714_get_hw_resources(priv);
+ if (ret)
+ return ret;
+
+ ret = max96714_enable_core_hw(priv);
+ if (ret)
+ return ret;
+
+ ret = max96714_parse_dt(priv);
+ if (ret)
+ goto err_disable_core_hw;
+
+ max96714_init_tx_port(priv);
+
+ ret = max96714_rxport_enable_poc(priv);
+ if (ret)
+ goto err_free_ports;
+
+ ret = max96714_i2c_mux_init(priv);
+ if (ret)
+ goto err_disable_poc;
+
+ ret = max96714_create_subdev(priv);
+ if (ret)
+ goto err_del_mux;
+
+ return 0;
+
+err_del_mux:
+ i2c_mux_del_adapters(priv->mux);
+err_disable_poc:
+ max96714_rxport_disable_poc(priv);
+err_free_ports:
+ fwnode_handle_put(priv->rxport.source.ep_fwnode);
+err_disable_core_hw:
+ max96714_disable_core_hw(priv);
+
+ return ret;
+}
+
+static void max96714_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct max96714_priv *priv = sd_to_max96714(sd);
+
+ max96714_destroy_subdev(priv);
+ i2c_mux_del_adapters(priv->mux);
+ max96714_rxport_disable_poc(priv);
+ fwnode_handle_put(priv->rxport.source.ep_fwnode);
+ max96714_disable_core_hw(priv);
+ gpiod_set_value_cansleep(priv->pd_gpio, 1);
+}
+
+static const struct of_device_id max96714_of_ids[] = {
+ { .compatible = "maxim,max96714f" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max96714_of_ids);
+
+static struct i2c_driver max96714_i2c_driver = {
+ .driver = {
+ .name = "max96714",
+ .of_match_table = max96714_of_ids,
+ },
+ .probe = max96714_probe,
+ .remove = max96714_remove,
+};
+
+module_i2c_driver(max96714_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Maxim Integrated GMSL2 Deserializers Driver");
+MODULE_AUTHOR("Julien Massot <julien.massot@collabora.com>");
diff --git a/drivers/media/i2c/max96717.c b/drivers/media/i2c/max96717.c
new file mode 100644
index 000000000000..949306485873
--- /dev/null
+++ b/drivers/media/i2c/max96717.c
@@ -0,0 +1,927 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Maxim GMSL2 Serializer Driver
+ *
+ * Copyright (C) 2024 Collabora Ltd.
+ */
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/delay.h>
+#include <linux/fwnode.h>
+#include <linux/gpio/driver.h>
+#include <linux/i2c-mux.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+
+#include <media/v4l2-cci.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
+
+#define MAX96717_DEVICE_ID 0xbf
+#define MAX96717F_DEVICE_ID 0xc8
+#define MAX96717_PORTS 2
+#define MAX96717_PAD_SINK 0
+#define MAX96717_PAD_SOURCE 1
+
+#define MAX96717_DEFAULT_CLKOUT_RATE 24000000UL
+
+/* DEV */
+#define MAX96717_REG3 CCI_REG8(0x3)
+#define MAX96717_RCLKSEL GENMASK(1, 0)
+#define RCLKSEL_REF_PLL CCI_REG8(0x3)
+#define MAX96717_REG6 CCI_REG8(0x6)
+#define RCLKEN BIT(5)
+#define MAX96717_DEV_ID CCI_REG8(0xd)
+#define MAX96717_DEV_REV CCI_REG8(0xe)
+#define MAX96717_DEV_REV_MASK GENMASK(3, 0)
+
+/* VID_TX Z */
+#define MAX96717_VIDEO_TX2 CCI_REG8(0x112)
+#define MAX96717_VIDEO_PCLKDET BIT(7)
+
+/* GPIO */
+#define MAX96717_NUM_GPIO 11
+#define MAX96717_GPIO_REG_A(gpio) CCI_REG8(0x2be + (gpio) * 3)
+#define MAX96717_GPIO_OUT BIT(4)
+#define MAX96717_GPIO_IN BIT(3)
+#define MAX96717_GPIO_RX_EN BIT(2)
+#define MAX96717_GPIO_TX_EN BIT(1)
+#define MAX96717_GPIO_OUT_DIS BIT(0)
+
+/* FRONTTOP */
+/* MAX96717 only have CSI port 'B' */
+#define MAX96717_FRONTOP0 CCI_REG8(0x308)
+#define MAX96717_START_PORT_B BIT(5)
+
+/* MIPI_RX */
+#define MAX96717_MIPI_RX1 CCI_REG8(0x331)
+#define MAX96717_MIPI_LANES_CNT GENMASK(5, 4)
+#define MAX96717_MIPI_RX2 CCI_REG8(0x332) /* phy1 Lanes map */
+#define MAX96717_PHY2_LANES_MAP GENMASK(7, 4)
+#define MAX96717_MIPI_RX3 CCI_REG8(0x333) /* phy2 Lanes map */
+#define MAX96717_PHY1_LANES_MAP GENMASK(3, 0)
+#define MAX96717_MIPI_RX4 CCI_REG8(0x334) /* phy1 lane polarities */
+#define MAX96717_PHY1_LANES_POL GENMASK(6, 4)
+#define MAX96717_MIPI_RX5 CCI_REG8(0x335) /* phy2 lane polarities */
+#define MAX96717_PHY2_LANES_POL GENMASK(2, 0)
+
+/* MIPI_RX_EXT */
+#define MAX96717_MIPI_RX_EXT11 CCI_REG8(0x383)
+#define MAX96717_TUN_MODE BIT(7)
+
+/* REF_VTG */
+#define REF_VTG0 CCI_REG8(0x3f0)
+#define REFGEN_PREDEF_EN BIT(6)
+#define REFGEN_PREDEF_FREQ_MASK GENMASK(5, 4)
+#define REFGEN_PREDEF_FREQ_ALT BIT(3)
+#define REFGEN_RST BIT(1)
+#define REFGEN_EN BIT(0)
+
+/* MISC */
+#define PIO_SLEW_1 CCI_REG8(0x570)
+
+struct max96717_priv {
+ struct i2c_client *client;
+ struct regmap *regmap;
+ struct i2c_mux_core *mux;
+ struct v4l2_mbus_config_mipi_csi2 mipi_csi2;
+ struct v4l2_subdev sd;
+ struct media_pad pads[MAX96717_PORTS];
+ struct v4l2_async_notifier notifier;
+ struct v4l2_subdev *source_sd;
+ u16 source_sd_pad;
+ u64 enabled_source_streams;
+ u8 pll_predef_index;
+ struct clk_hw clk_hw;
+ struct gpio_chip gpio_chip;
+};
+
+static inline struct max96717_priv *sd_to_max96717(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct max96717_priv, sd);
+}
+
+static inline struct max96717_priv *clk_hw_to_max96717(struct clk_hw *hw)
+{
+ return container_of(hw, struct max96717_priv, clk_hw);
+}
+
+static int max96717_i2c_mux_select(struct i2c_mux_core *mux, u32 chan)
+{
+ return 0;
+}
+
+static int max96717_i2c_mux_init(struct max96717_priv *priv)
+{
+ priv->mux = i2c_mux_alloc(priv->client->adapter, &priv->client->dev,
+ 1, 0, I2C_MUX_LOCKED | I2C_MUX_GATE,
+ max96717_i2c_mux_select, NULL);
+ if (!priv->mux)
+ return -ENOMEM;
+
+ return i2c_mux_add_adapter(priv->mux, 0, 0);
+}
+
+static inline int max96717_start_csi(struct max96717_priv *priv, bool start)
+{
+ return cci_update_bits(priv->regmap, MAX96717_FRONTOP0,
+ MAX96717_START_PORT_B,
+ start ? MAX96717_START_PORT_B : 0, NULL);
+}
+
+static int max96717_gpiochip_get(struct gpio_chip *gpiochip,
+ unsigned int offset)
+{
+ struct max96717_priv *priv = gpiochip_get_data(gpiochip);
+ u64 val;
+ int ret;
+
+ ret = cci_read(priv->regmap, MAX96717_GPIO_REG_A(offset),
+ &val, NULL);
+ if (ret)
+ return ret;
+
+ if (val & MAX96717_GPIO_OUT_DIS)
+ return !!(val & MAX96717_GPIO_IN);
+ else
+ return !!(val & MAX96717_GPIO_OUT);
+}
+
+static void max96717_gpiochip_set(struct gpio_chip *gpiochip,
+ unsigned int offset, int value)
+{
+ struct max96717_priv *priv = gpiochip_get_data(gpiochip);
+
+ cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset),
+ MAX96717_GPIO_OUT, MAX96717_GPIO_OUT, NULL);
+}
+
+static int max96717_gpio_get_direction(struct gpio_chip *gpiochip,
+ unsigned int offset)
+{
+ struct max96717_priv *priv = gpiochip_get_data(gpiochip);
+ u64 val;
+ int ret;
+
+ ret = cci_read(priv->regmap, MAX96717_GPIO_REG_A(offset), &val, NULL);
+ if (ret < 0)
+ return ret;
+
+ return !!(val & MAX96717_GPIO_OUT_DIS);
+}
+
+static int max96717_gpio_direction_out(struct gpio_chip *gpiochip,
+ unsigned int offset, int value)
+{
+ struct max96717_priv *priv = gpiochip_get_data(gpiochip);
+
+ return cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset),
+ MAX96717_GPIO_OUT_DIS | MAX96717_GPIO_OUT,
+ value ? MAX96717_GPIO_OUT : 0, NULL);
+}
+
+static int max96717_gpio_direction_in(struct gpio_chip *gpiochip,
+ unsigned int offset)
+{
+ struct max96717_priv *priv = gpiochip_get_data(gpiochip);
+
+ return cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(offset),
+ MAX96717_GPIO_OUT_DIS, MAX96717_GPIO_OUT_DIS,
+ NULL);
+}
+
+static int max96717_gpiochip_probe(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct gpio_chip *gc = &priv->gpio_chip;
+ int i, ret = 0;
+
+ gc->label = dev_name(dev);
+ gc->parent = dev;
+ gc->owner = THIS_MODULE;
+ gc->ngpio = MAX96717_NUM_GPIO;
+ gc->base = -1;
+ gc->can_sleep = true;
+ gc->get_direction = max96717_gpio_get_direction;
+ gc->direction_input = max96717_gpio_direction_in;
+ gc->direction_output = max96717_gpio_direction_out;
+ gc->set = max96717_gpiochip_set;
+ gc->get = max96717_gpiochip_get;
+ gc->of_gpio_n_cells = 2;
+
+ /* Disable GPIO forwarding */
+ for (i = 0; i < gc->ngpio; i++)
+ cci_update_bits(priv->regmap, MAX96717_GPIO_REG_A(i),
+ MAX96717_GPIO_RX_EN | MAX96717_GPIO_TX_EN,
+ 0, &ret);
+
+ if (ret)
+ return ret;
+
+ ret = devm_gpiochip_add_data(dev, gc, priv);
+ if (ret) {
+ dev_err(dev, "Unable to create gpio_chip\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int _max96717_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_krouting *routing)
+{
+ static const struct v4l2_mbus_framefmt format = {
+ .width = 1280,
+ .height = 1080,
+ .code = MEDIA_BUS_FMT_Y8_1X8,
+ .field = V4L2_FIELD_NONE,
+ };
+ int ret;
+
+ ret = v4l2_subdev_routing_validate(sd, routing,
+ V4L2_SUBDEV_ROUTING_ONLY_1_TO_1);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing, &format);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int max96717_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ struct max96717_priv *priv = sd_to_max96717(sd);
+
+ if (which == V4L2_SUBDEV_FORMAT_ACTIVE && priv->enabled_source_streams)
+ return -EBUSY;
+
+ return _max96717_set_routing(sd, state, routing);
+}
+
+static int max96717_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct max96717_priv *priv = sd_to_max96717(sd);
+ struct v4l2_mbus_framefmt *fmt;
+ u64 stream_source_mask;
+
+ if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE &&
+ priv->enabled_source_streams)
+ return -EBUSY;
+
+ /* No transcoding, source and sink formats must match. */
+ if (format->pad == MAX96717_PAD_SOURCE)
+ return v4l2_subdev_get_fmt(sd, state, format);
+
+ /* Set sink format */
+ fmt = v4l2_subdev_state_get_format(state, format->pad, format->stream);
+ if (!fmt)
+ return -EINVAL;
+
+ *fmt = format->format;
+
+ /* Propagate to source format */
+ fmt = v4l2_subdev_state_get_opposite_stream_format(state, format->pad,
+ format->stream);
+ if (!fmt)
+ return -EINVAL;
+ *fmt = format->format;
+
+ stream_source_mask = BIT(format->stream);
+
+ return v4l2_subdev_state_xlate_streams(state, MAX96717_PAD_SOURCE,
+ MAX96717_PAD_SINK,
+ &stream_source_mask);
+}
+
+static int max96717_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_route routes[] = {
+ {
+ .sink_pad = MAX96717_PAD_SINK,
+ .sink_stream = 0,
+ .source_pad = MAX96717_PAD_SOURCE,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ },
+ };
+ struct v4l2_subdev_krouting routing = {
+ .num_routes = ARRAY_SIZE(routes),
+ .routes = routes,
+ };
+
+ return _max96717_set_routing(sd, state, &routing);
+}
+
+static bool max96717_pipe_pclkdet(struct max96717_priv *priv)
+{
+ u64 val = 0;
+
+ cci_read(priv->regmap, MAX96717_VIDEO_TX2, &val, NULL);
+
+ return val & MAX96717_VIDEO_PCLKDET;
+}
+
+static int max96717_log_status(struct v4l2_subdev *sd)
+{
+ struct max96717_priv *priv = sd_to_max96717(sd);
+ struct device *dev = &priv->client->dev;
+
+ dev_info(dev, "Serializer: max96717\n");
+ dev_info(dev, "Pipe: pclkdet:%d\n", max96717_pipe_pclkdet(priv));
+
+ return 0;
+}
+
+static int max96717_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
+{
+ struct max96717_priv *priv = sd_to_max96717(sd);
+ struct device *dev = &priv->client->dev;
+ u64 sink_streams;
+ int ret;
+
+ sink_streams = v4l2_subdev_state_xlate_streams(state,
+ MAX96717_PAD_SOURCE,
+ MAX96717_PAD_SINK,
+ &streams_mask);
+
+ if (!priv->enabled_source_streams)
+ max96717_start_csi(priv, true);
+
+ ret = v4l2_subdev_enable_streams(priv->source_sd, priv->source_sd_pad,
+ sink_streams);
+ if (ret) {
+ dev_err(dev, "Fail to start streams:%llu on remote subdev\n",
+ sink_streams);
+ goto stop_csi;
+ }
+
+ priv->enabled_source_streams |= streams_mask;
+
+ return 0;
+
+stop_csi:
+ if (!priv->enabled_source_streams)
+ max96717_start_csi(priv, false);
+ return ret;
+}
+
+static int max96717_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
+{
+ struct max96717_priv *priv = sd_to_max96717(sd);
+ u64 sink_streams;
+
+ /*
+ * Stop the CSI receiver first then the source,
+ * otherwise the device may become unresponsive
+ * while holding the I2C bus low.
+ */
+ priv->enabled_source_streams &= ~streams_mask;
+ if (!priv->enabled_source_streams)
+ max96717_start_csi(priv, false);
+
+ sink_streams = v4l2_subdev_state_xlate_streams(state,
+ MAX96717_PAD_SOURCE,
+ MAX96717_PAD_SINK,
+ &streams_mask);
+
+ return v4l2_subdev_disable_streams(priv->source_sd, priv->source_sd_pad,
+ sink_streams);
+}
+
+static const struct v4l2_subdev_pad_ops max96717_pad_ops = {
+ .enable_streams = max96717_enable_streams,
+ .disable_streams = max96717_disable_streams,
+ .set_routing = max96717_set_routing,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = max96717_set_fmt,
+};
+
+static const struct v4l2_subdev_core_ops max96717_subdev_core_ops = {
+ .log_status = max96717_log_status,
+};
+
+static const struct v4l2_subdev_internal_ops max96717_internal_ops = {
+ .init_state = max96717_init_state,
+};
+
+static const struct v4l2_subdev_ops max96717_subdev_ops = {
+ .core = &max96717_subdev_core_ops,
+ .pad = &max96717_pad_ops,
+};
+
+static const struct media_entity_operations max96717_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+};
+
+static int max96717_notify_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *source_subdev,
+ struct v4l2_async_connection *asd)
+{
+ struct max96717_priv *priv = sd_to_max96717(notifier->sd);
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ ret = media_entity_get_fwnode_pad(&source_subdev->entity,
+ source_subdev->fwnode,
+ MEDIA_PAD_FL_SOURCE);
+ if (ret < 0) {
+ dev_err(dev, "Failed to find pad for %s\n",
+ source_subdev->name);
+ return ret;
+ }
+
+ priv->source_sd = source_subdev;
+ priv->source_sd_pad = ret;
+
+ ret = media_create_pad_link(&source_subdev->entity, priv->source_sd_pad,
+ &priv->sd.entity, 0,
+ MEDIA_LNK_FL_ENABLED |
+ MEDIA_LNK_FL_IMMUTABLE);
+ if (ret) {
+ dev_err(dev, "Unable to link %s:%u -> %s:0\n",
+ source_subdev->name, priv->source_sd_pad,
+ priv->sd.name);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_async_notifier_operations max96717_notify_ops = {
+ .bound = max96717_notify_bound,
+};
+
+static int max96717_v4l2_notifier_register(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct v4l2_async_connection *asd;
+ struct fwnode_handle *ep_fwnode;
+ int ret;
+
+ ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
+ MAX96717_PAD_SINK, 0, 0);
+ if (!ep_fwnode) {
+ dev_err(dev, "No graph endpoint\n");
+ return -ENODEV;
+ }
+
+ v4l2_async_subdev_nf_init(&priv->notifier, &priv->sd);
+
+ asd = v4l2_async_nf_add_fwnode_remote(&priv->notifier, ep_fwnode,
+ struct v4l2_async_connection);
+
+ fwnode_handle_put(ep_fwnode);
+
+ if (IS_ERR(asd)) {
+ dev_err(dev, "Failed to add subdev: %ld", PTR_ERR(asd));
+ v4l2_async_nf_cleanup(&priv->notifier);
+ return PTR_ERR(asd);
+ }
+
+ priv->notifier.ops = &max96717_notify_ops;
+
+ ret = v4l2_async_nf_register(&priv->notifier);
+ if (ret) {
+ dev_err(dev, "Failed to register subdev_notifier");
+ v4l2_async_nf_cleanup(&priv->notifier);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int max96717_subdev_init(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ int ret;
+
+ v4l2_i2c_subdev_init(&priv->sd, priv->client, &max96717_subdev_ops);
+ priv->sd.internal_ops = &max96717_internal_ops;
+
+ priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
+ priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ priv->sd.entity.ops = &max96717_entity_ops;
+
+ priv->pads[MAX96717_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+ priv->pads[MAX96717_PAD_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&priv->sd.entity, 2, priv->pads);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to init pads\n");
+
+ ret = v4l2_subdev_init_finalize(&priv->sd);
+ if (ret) {
+ dev_err_probe(dev, ret,
+ "v4l2 subdev init finalized failed\n");
+ goto err_entity_cleanup;
+ }
+ ret = max96717_v4l2_notifier_register(priv);
+ if (ret) {
+ dev_err_probe(dev, ret,
+ "v4l2 subdev notifier register failed\n");
+ goto err_free_state;
+ }
+
+ ret = v4l2_async_register_subdev(&priv->sd);
+ if (ret) {
+ dev_err_probe(dev, ret, "v4l2_async_register_subdev error\n");
+ goto err_unreg_notif;
+ }
+
+ return 0;
+
+err_unreg_notif:
+ v4l2_async_nf_unregister(&priv->notifier);
+ v4l2_async_nf_cleanup(&priv->notifier);
+err_free_state:
+ v4l2_subdev_cleanup(&priv->sd);
+err_entity_cleanup:
+ media_entity_cleanup(&priv->sd.entity);
+
+ return ret;
+}
+
+static void max96717_subdev_uninit(struct max96717_priv *priv)
+{
+ v4l2_async_unregister_subdev(&priv->sd);
+ v4l2_async_nf_unregister(&priv->notifier);
+ v4l2_async_nf_cleanup(&priv->notifier);
+ v4l2_subdev_cleanup(&priv->sd);
+ media_entity_cleanup(&priv->sd.entity);
+}
+
+struct max96717_pll_predef_freq {
+ unsigned long freq;
+ bool is_alt;
+ u8 val;
+};
+
+static const struct max96717_pll_predef_freq max96717_predef_freqs[] = {
+ { 13500000, true, 0 }, { 19200000, false, 0 },
+ { 24000000, true, 1 }, { 27000000, false, 1 },
+ { 37125000, false, 2 }, { 74250000, false, 3 },
+};
+
+static unsigned long
+max96717_clk_recalc_rate(struct clk_hw *hw, unsigned long parent_rate)
+{
+ struct max96717_priv *priv = clk_hw_to_max96717(hw);
+
+ return max96717_predef_freqs[priv->pll_predef_index].freq;
+}
+
+static unsigned int max96717_clk_find_best_index(struct max96717_priv *priv,
+ unsigned long rate)
+{
+ unsigned int i, idx;
+ unsigned long diff_new, diff_old;
+
+ diff_old = U32_MAX;
+ idx = 0;
+
+ for (i = 0; i < ARRAY_SIZE(max96717_predef_freqs); i++) {
+ diff_new = abs(rate - max96717_predef_freqs[i].freq);
+ if (diff_new < diff_old) {
+ diff_old = diff_new;
+ idx = i;
+ }
+ }
+
+ return idx;
+}
+
+static long max96717_clk_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *parent_rate)
+{
+ struct max96717_priv *priv = clk_hw_to_max96717(hw);
+ struct device *dev = &priv->client->dev;
+ unsigned int idx;
+
+ idx = max96717_clk_find_best_index(priv, rate);
+
+ if (rate != max96717_predef_freqs[idx].freq) {
+ dev_warn(dev, "Request CLK freq:%lu, found CLK freq:%lu\n",
+ rate, max96717_predef_freqs[idx].freq);
+ }
+
+ return max96717_predef_freqs[idx].freq;
+}
+
+static int max96717_clk_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct max96717_priv *priv = clk_hw_to_max96717(hw);
+ unsigned int val, idx;
+ int ret = 0;
+
+ idx = max96717_clk_find_best_index(priv, rate);
+
+ val = FIELD_PREP(REFGEN_PREDEF_FREQ_MASK,
+ max96717_predef_freqs[idx].val);
+
+ if (max96717_predef_freqs[idx].is_alt)
+ val |= REFGEN_PREDEF_FREQ_ALT;
+
+ val |= REFGEN_RST | REFGEN_PREDEF_EN;
+
+ cci_write(priv->regmap, REF_VTG0, val, &ret);
+ cci_update_bits(priv->regmap, REF_VTG0, REFGEN_RST | REFGEN_EN,
+ REFGEN_EN, &ret);
+ if (ret)
+ return ret;
+
+ priv->pll_predef_index = idx;
+
+ return 0;
+}
+
+static int max96717_clk_prepare(struct clk_hw *hw)
+{
+ struct max96717_priv *priv = clk_hw_to_max96717(hw);
+
+ return cci_update_bits(priv->regmap, MAX96717_REG6, RCLKEN,
+ RCLKEN, NULL);
+}
+
+static void max96717_clk_unprepare(struct clk_hw *hw)
+{
+ struct max96717_priv *priv = clk_hw_to_max96717(hw);
+
+ cci_update_bits(priv->regmap, MAX96717_REG6, RCLKEN, 0, NULL);
+}
+
+static const struct clk_ops max96717_clk_ops = {
+ .prepare = max96717_clk_prepare,
+ .unprepare = max96717_clk_unprepare,
+ .set_rate = max96717_clk_set_rate,
+ .recalc_rate = max96717_clk_recalc_rate,
+ .round_rate = max96717_clk_round_rate,
+};
+
+static int max96717_register_clkout(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct clk_init_data init = { .ops = &max96717_clk_ops };
+ int ret;
+
+ init.name = kasprintf(GFP_KERNEL, "max96717.%s.clk_out",
+ dev_name(dev));
+ if (!init.name)
+ return -ENOMEM;
+
+ /* RCLKSEL Reference PLL output */
+ ret = cci_update_bits(priv->regmap, MAX96717_REG3, MAX96717_RCLKSEL,
+ MAX96717_RCLKSEL, NULL);
+ /* MFP4 fastest slew rate */
+ cci_update_bits(priv->regmap, PIO_SLEW_1, BIT(5) | BIT(4), 0, &ret);
+ if (ret)
+ goto free_init_name;
+
+ priv->clk_hw.init = &init;
+
+ /* Initialize to 24 MHz */
+ ret = max96717_clk_set_rate(&priv->clk_hw,
+ MAX96717_DEFAULT_CLKOUT_RATE, 0);
+ if (ret < 0)
+ goto free_init_name;
+
+ ret = devm_clk_hw_register(dev, &priv->clk_hw);
+ kfree(init.name);
+ if (ret)
+ return dev_err_probe(dev, ret, "Cannot register clock HW\n");
+
+ ret = devm_of_clk_add_hw_provider(dev, of_clk_hw_simple_get,
+ &priv->clk_hw);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Cannot add OF clock provider\n");
+
+ return 0;
+
+free_init_name:
+ kfree(init.name);
+ return ret;
+}
+
+static int max96717_init_csi_lanes(struct max96717_priv *priv)
+{
+ struct v4l2_mbus_config_mipi_csi2 *mipi = &priv->mipi_csi2;
+ unsigned long lanes_used = 0;
+ unsigned int nlanes, lane, val = 0;
+ int ret;
+
+ nlanes = mipi->num_data_lanes;
+
+ ret = cci_update_bits(priv->regmap, MAX96717_MIPI_RX1,
+ MAX96717_MIPI_LANES_CNT,
+ FIELD_PREP(MAX96717_MIPI_LANES_CNT,
+ nlanes - 1), NULL);
+
+ /* lanes polarity */
+ for (lane = 0; lane < nlanes + 1; lane++) {
+ if (!mipi->lane_polarities[lane])
+ continue;
+ /* Clock lane */
+ if (lane == 0)
+ val |= BIT(2);
+ else if (lane < 3)
+ val |= BIT(lane - 1);
+ else
+ val |= BIT(lane);
+ }
+
+ cci_update_bits(priv->regmap, MAX96717_MIPI_RX5,
+ MAX96717_PHY2_LANES_POL,
+ FIELD_PREP(MAX96717_PHY2_LANES_POL, val), &ret);
+
+ cci_update_bits(priv->regmap, MAX96717_MIPI_RX4,
+ MAX96717_PHY1_LANES_POL,
+ FIELD_PREP(MAX96717_PHY1_LANES_POL,
+ val >> 3), &ret);
+ /* lanes mapping */
+ for (lane = 0, val = 0; lane < nlanes; lane++) {
+ val |= (mipi->data_lanes[lane] - 1) << (lane * 2);
+ lanes_used |= BIT(mipi->data_lanes[lane] - 1);
+ }
+
+ /*
+ * Unused lanes need to be mapped as well to not have
+ * the same lanes mapped twice.
+ */
+ for (; lane < 4; lane++) {
+ unsigned int idx = find_first_zero_bit(&lanes_used, 4);
+
+ val |= idx << (lane * 2);
+ lanes_used |= BIT(idx);
+ }
+
+ cci_update_bits(priv->regmap, MAX96717_MIPI_RX3,
+ MAX96717_PHY1_LANES_MAP,
+ FIELD_PREP(MAX96717_PHY1_LANES_MAP, val), &ret);
+
+ return cci_update_bits(priv->regmap, MAX96717_MIPI_RX2,
+ MAX96717_PHY2_LANES_MAP,
+ FIELD_PREP(MAX96717_PHY2_LANES_MAP, val >> 4),
+ &ret);
+}
+
+static int max96717_hw_init(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ u64 dev_id, val;
+ int ret;
+
+ ret = cci_read(priv->regmap, MAX96717_DEV_ID, &dev_id, NULL);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Fail to read the device id\n");
+
+ if (dev_id != MAX96717_DEVICE_ID && dev_id != MAX96717F_DEVICE_ID)
+ return dev_err_probe(dev, -EOPNOTSUPP,
+ "Unsupported device id got %x\n", (u8)dev_id);
+
+ ret = cci_read(priv->regmap, MAX96717_DEV_REV, &val, NULL);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Fail to read device revision");
+
+ dev_dbg(dev, "Found %x (rev %lx)\n", (u8)dev_id,
+ (u8)val & MAX96717_DEV_REV_MASK);
+
+ ret = cci_read(priv->regmap, MAX96717_MIPI_RX_EXT11, &val, NULL);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Fail to read mipi rx extension");
+
+ if (!(val & MAX96717_TUN_MODE))
+ return dev_err_probe(dev, -EOPNOTSUPP,
+ "Only supporting tunnel mode");
+
+ return max96717_init_csi_lanes(priv);
+}
+
+static int max96717_parse_dt(struct max96717_priv *priv)
+{
+ struct device *dev = &priv->client->dev;
+ struct v4l2_fwnode_endpoint vep = {
+ .bus_type = V4L2_MBUS_CSI2_DPHY
+ };
+ struct fwnode_handle *ep_fwnode;
+ unsigned char num_data_lanes;
+ int ret;
+
+ ep_fwnode = fwnode_graph_get_endpoint_by_id(dev_fwnode(dev),
+ MAX96717_PAD_SINK, 0, 0);
+ if (!ep_fwnode)
+ return dev_err_probe(dev, -ENOENT, "no endpoint found\n");
+
+ ret = v4l2_fwnode_endpoint_parse(ep_fwnode, &vep);
+
+ fwnode_handle_put(ep_fwnode);
+
+ if (ret < 0)
+ return dev_err_probe(dev, ret, "Failed to parse sink endpoint");
+
+ num_data_lanes = vep.bus.mipi_csi2.num_data_lanes;
+ if (num_data_lanes < 1 || num_data_lanes > 4)
+ return dev_err_probe(dev, -EINVAL,
+ "Invalid data lanes must be 1 to 4\n");
+
+ memcpy(&priv->mipi_csi2, &vep.bus.mipi_csi2, sizeof(priv->mipi_csi2));
+
+ return 0;
+}
+
+static int max96717_probe(struct i2c_client *client)
+{
+ struct device *dev = &client->dev;
+ struct max96717_priv *priv;
+ int ret;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->client = client;
+ priv->regmap = devm_cci_regmap_init_i2c(client, 16);
+ if (IS_ERR(priv->regmap)) {
+ ret = PTR_ERR(priv->regmap);
+ return dev_err_probe(dev, ret, "Failed to init regmap\n");
+ }
+
+ ret = max96717_parse_dt(priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to parse the dt\n");
+
+ ret = max96717_hw_init(priv);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to initialize the hardware\n");
+
+ ret = max96717_gpiochip_probe(priv);
+ if (ret)
+ return dev_err_probe(&client->dev, ret,
+ "Failed to init gpiochip\n");
+
+ ret = max96717_register_clkout(priv);
+ if (ret)
+ return dev_err_probe(dev, ret, "Failed to register clkout\n");
+
+ ret = max96717_subdev_init(priv);
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "Failed to initialize v4l2 subdev\n");
+
+ ret = max96717_i2c_mux_init(priv);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to add remote i2c adapter\n");
+ max96717_subdev_uninit(priv);
+ }
+
+ return ret;
+}
+
+static void max96717_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct max96717_priv *priv = sd_to_max96717(sd);
+
+ max96717_subdev_uninit(priv);
+ i2c_mux_del_adapters(priv->mux);
+}
+
+static const struct of_device_id max96717_of_ids[] = {
+ { .compatible = "maxim,max96717f" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, max96717_of_ids);
+
+static struct i2c_driver max96717_i2c_driver = {
+ .driver = {
+ .name = "max96717",
+ .of_match_table = max96717_of_ids,
+ },
+ .probe = max96717_probe,
+ .remove = max96717_remove,
+};
+
+module_i2c_driver(max96717_i2c_driver);
+
+MODULE_DESCRIPTION("Maxim GMSL2 MAX96717 Serializer Driver");
+MODULE_AUTHOR("Julien Massot <julien.massot@collabora.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/i2c/ov2680.c b/drivers/media/i2c/ov2680.c
index 3ae0ea58668d..7237fb27ecd0 100644
--- a/drivers/media/i2c/ov2680.c
+++ b/drivers/media/i2c/ov2680.c
@@ -971,7 +971,7 @@ static int ov2680_v4l2_register(struct ov2680_dev *sensor)
if (ret < 0)
return ret;
- v4l2_ctrl_handler_init(hdl, 5);
+ v4l2_ctrl_handler_init(hdl, 11);
hdl->lock = &sensor->lock;
diff --git a/drivers/media/i2c/ov5647.c b/drivers/media/i2c/ov5647.c
index 7e1ecdf2485f..0fb4d7bff9d1 100644
--- a/drivers/media/i2c/ov5647.c
+++ b/drivers/media/i2c/ov5647.c
@@ -1360,24 +1360,21 @@ static int ov5647_parse_dt(struct ov5647 *sensor, struct device_node *np)
struct v4l2_fwnode_endpoint bus_cfg = {
.bus_type = V4L2_MBUS_CSI2_DPHY,
};
- struct device_node *ep;
+ struct device_node *ep __free(device_node) =
+ of_graph_get_endpoint_by_regs(np, 0, -1);
int ret;
- ep = of_graph_get_endpoint_by_regs(np, 0, -1);
if (!ep)
return -EINVAL;
ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &bus_cfg);
if (ret)
- goto out;
+ return ret;
sensor->clock_ncont = bus_cfg.bus.mipi_csi2.flags &
V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK;
-out:
- of_node_put(ep);
-
- return ret;
+ return 0;
}
static int ov5647_probe(struct i2c_client *client)
diff --git a/drivers/media/i2c/ov5693.c b/drivers/media/i2c/ov5693.c
index 8deb28b55983..46b9ce111676 100644
--- a/drivers/media/i2c/ov5693.c
+++ b/drivers/media/i2c/ov5693.c
@@ -141,7 +141,6 @@ struct ov5693_device {
struct gpio_desc *reset;
struct gpio_desc *powerdown;
- struct gpio_desc *privacy_led;
struct regulator_bulk_data supplies[OV5693_NUM_SUPPLIES];
struct clk *xvclk;
@@ -657,7 +656,6 @@ static int ov5693_sensor_init(struct ov5693_device *ov5693)
static void ov5693_sensor_powerdown(struct ov5693_device *ov5693)
{
- gpiod_set_value_cansleep(ov5693->privacy_led, 0);
gpiod_set_value_cansleep(ov5693->reset, 1);
gpiod_set_value_cansleep(ov5693->powerdown, 1);
@@ -687,7 +685,6 @@ static int ov5693_sensor_powerup(struct ov5693_device *ov5693)
gpiod_set_value_cansleep(ov5693->powerdown, 0);
gpiod_set_value_cansleep(ov5693->reset, 0);
- gpiod_set_value_cansleep(ov5693->privacy_led, 1);
usleep_range(5000, 7500);
@@ -1201,13 +1198,6 @@ static int ov5693_configure_gpios(struct ov5693_device *ov5693)
return PTR_ERR(ov5693->powerdown);
}
- ov5693->privacy_led = devm_gpiod_get_optional(ov5693->dev, "privacy-led",
- GPIOD_OUT_LOW);
- if (IS_ERR(ov5693->privacy_led)) {
- dev_err(ov5693->dev, "Error fetching privacy-led GPIO\n");
- return PTR_ERR(ov5693->privacy_led);
- }
-
return 0;
}
diff --git a/drivers/media/i2c/tw9910.c b/drivers/media/i2c/tw9910.c
index 905af98c7d53..6dffaaa9ed56 100644
--- a/drivers/media/i2c/tw9910.c
+++ b/drivers/media/i2c/tw9910.c
@@ -212,11 +212,6 @@
* structure
*/
-struct regval_list {
- unsigned char reg_num;
- unsigned char value;
-};
-
struct tw9910_scale_ctrl {
char *name;
unsigned short width;
diff --git a/drivers/media/i2c/uda1342.c b/drivers/media/i2c/uda1342.c
index da7bc4700bed..abd052a44bd7 100644
--- a/drivers/media/i2c/uda1342.c
+++ b/drivers/media/i2c/uda1342.c
@@ -95,4 +95,5 @@ static struct i2c_driver uda1342_driver = {
module_i2c_driver(uda1342_driver);
+MODULE_DESCRIPTION("Philips UDA1342 audio codec driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/st-vgxy61.c b/drivers/media/i2c/vgxy61.c
index b9e7c57027b1..30378e962016 100644
--- a/drivers/media/i2c/st-vgxy61.c
+++ b/drivers/media/i2c/vgxy61.c
@@ -1878,7 +1878,7 @@ static const struct dev_pm_ops vgxy61_pm_ops = {
static struct i2c_driver vgxy61_i2c_driver = {
.driver = {
- .name = "st-vgxy61",
+ .name = "vgxy61",
.of_match_table = vgxy61_dt_ids,
.pm = &vgxy61_pm_ops,
},
diff --git a/drivers/media/pci/bt8xx/bt878.c b/drivers/media/pci/bt8xx/bt878.c
index 90972d6952f1..62a6c4a80bed 100644
--- a/drivers/media/pci/bt8xx/bt878.c
+++ b/drivers/media/pci/bt8xx/bt878.c
@@ -300,8 +300,8 @@ static irqreturn_t bt878_irq(int irq, void *dev_id)
}
if (astat & BT878_ARISCI) {
bt->finished_block = (stat & BT878_ARISCS) >> 28;
- if (bt->tasklet.callback)
- tasklet_schedule(&bt->tasklet);
+ if (bt->bh_work.func)
+ queue_work(system_bh_wq, &bt->bh_work);
break;
}
count++;
@@ -478,8 +478,8 @@ static int bt878_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
btwrite(0, BT878_AINT_MASK);
bt878_num++;
- if (!bt->tasklet.func)
- tasklet_disable(&bt->tasklet);
+ if (!bt->bh_work.func)
+ disable_work_sync(&bt->bh_work);
return 0;
@@ -563,4 +563,5 @@ static void __exit bt878_cleanup_module(void)
module_init(bt878_init_module);
module_exit(bt878_cleanup_module);
+MODULE_DESCRIPTION("DVB/ATSC Support for bt878 based TV cards");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/bt8xx/bt878.h b/drivers/media/pci/bt8xx/bt878.h
index fde8db293c54..5b1c7f56e553 100644
--- a/drivers/media/pci/bt8xx/bt878.h
+++ b/drivers/media/pci/bt8xx/bt878.h
@@ -14,6 +14,7 @@
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include "bt848.h"
#include "bttv.h"
@@ -120,7 +121,7 @@ struct bt878 {
dma_addr_t risc_dma;
u32 risc_pos;
- struct tasklet_struct tasklet;
+ struct work_struct bh_work;
int shutdown;
};
diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c
index 390cbba6c065..f0fbb468aea2 100644
--- a/drivers/media/pci/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c
@@ -39,9 +39,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
-static void dvb_bt8xx_task(struct tasklet_struct *t)
+static void dvb_bt8xx_work(struct work_struct *t)
{
- struct bt878 *bt = from_tasklet(bt, t, tasklet);
+ struct bt878 *bt = from_work(bt, t, bh_work);
struct dvb_bt8xx_card *card = dev_get_drvdata(&bt->adapter->dev);
dprintk("%d\n", card->bt->finished_block);
@@ -782,7 +782,7 @@ static int dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
goto err_disconnect_frontend;
}
- tasklet_setup(&card->bt->tasklet, dvb_bt8xx_task);
+ INIT_WORK(&card->bt->bh_work, dvb_bt8xx_work);
frontend_init(card, type);
@@ -922,7 +922,7 @@ static void dvb_bt8xx_remove(struct bttv_sub_device *sub)
dprintk("dvb_bt8xx: unloading card%d\n", card->bttv_nr);
bt878_stop(card->bt);
- tasklet_kill(&card->bt->tasklet);
+ cancel_work_sync(&card->bt->bh_work);
dvb_net_release(&card->dvbnet);
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_mem);
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
diff --git a/drivers/media/pci/cx18/cx18-scb.h b/drivers/media/pci/cx18/cx18-scb.h
index f7105421dd25..841edc0712ab 100644
--- a/drivers/media/pci/cx18/cx18-scb.h
+++ b/drivers/media/pci/cx18/cx18-scb.h
@@ -258,7 +258,7 @@ struct cx18_scb {
struct cx18_mailbox ppu2epu_mb;
struct cx18_mdl_ack cpu_mdl_ack[CX18_MAX_STREAMS][CX18_MAX_MDL_ACKS];
- struct cx18_mdl_ent cpu_mdl[1];
+ struct cx18_mdl_ent cpu_mdl[];
};
void cx18_init_scb(struct cx18 *cx);
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index f3699dbd193f..f01ecdb0b627 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -298,7 +298,7 @@ struct ddb_link {
spinlock_t lock; /* lock link access */
struct mutex flash_mutex; /* lock flash access */
struct ddb_lnb lnb;
- struct tasklet_struct tasklet;
+ struct work_struct bh_work;
struct ddb_ids ids;
spinlock_t temp_lock; /* lock temp chip access */
diff --git a/drivers/media/pci/intel/ipu-bridge.c b/drivers/media/pci/intel/ipu-bridge.c
index 61750cc98d70..a0e9a71580b5 100644
--- a/drivers/media/pci/intel/ipu-bridge.c
+++ b/drivers/media/pci/intel/ipu-bridge.c
@@ -43,28 +43,46 @@
* becoming apparent in the future.
*
* Do not add an entry for a sensor that is not actually supported.
+ *
+ * Please keep the list sorted by ACPI HID.
*/
static const struct ipu_sensor_config ipu_supported_sensors[] = {
+ /* Himax HM11B1 */
+ IPU_SENSOR_CONFIG("HIMX11B1", 1, 384000000),
+ /* Himax HM2170 */
+ IPU_SENSOR_CONFIG("HIMX2170", 1, 384000000),
+ /* Himax HM2172 */
+ IPU_SENSOR_CONFIG("HIMX2172", 1, 384000000),
+ /* GalaxyCore GC0310 */
+ IPU_SENSOR_CONFIG("INT0310", 0),
/* Omnivision OV5693 */
IPU_SENSOR_CONFIG("INT33BE", 1, 419200000),
+ /* Omnivision OV2740 */
+ IPU_SENSOR_CONFIG("INT3474", 1, 180000000),
/* Omnivision OV8865 */
IPU_SENSOR_CONFIG("INT347A", 1, 360000000),
/* Omnivision OV7251 */
IPU_SENSOR_CONFIG("INT347E", 1, 319200000),
+ /* Hynix Hi-556 */
+ IPU_SENSOR_CONFIG("INT3537", 1, 437000000),
+ /* Omnivision OV01A10 / OV01A1S */
+ IPU_SENSOR_CONFIG("OVTI01A0", 1, 400000000),
+ IPU_SENSOR_CONFIG("OVTI01AS", 1, 400000000),
+ /* Omnivision OV02C10 */
+ IPU_SENSOR_CONFIG("OVTI02C1", 1, 400000000),
+ /* Omnivision OV02E10 */
+ IPU_SENSOR_CONFIG("OVTI02E1", 1, 360000000),
+ /* Omnivision OV08A10 */
+ IPU_SENSOR_CONFIG("OVTI08A1", 1, 500000000),
+ /* Omnivision OV08x40 */
+ IPU_SENSOR_CONFIG("OVTI08F4", 1, 400000000),
+ /* Omnivision OV13B10 */
+ IPU_SENSOR_CONFIG("OVTI13B1", 1, 560000000),
+ IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000),
/* Omnivision OV2680 */
IPU_SENSOR_CONFIG("OVTI2680", 1, 331200000),
- /* Omnivision ov8856 */
+ /* Omnivision OV8856 */
IPU_SENSOR_CONFIG("OVTI8856", 3, 180000000, 360000000, 720000000),
- /* Omnivision ov2740 */
- IPU_SENSOR_CONFIG("INT3474", 1, 180000000),
- /* Hynix hi556 */
- IPU_SENSOR_CONFIG("INT3537", 1, 437000000),
- /* Omnivision ov13b10 */
- IPU_SENSOR_CONFIG("OVTIDB10", 1, 560000000),
- /* GalaxyCore GC0310 */
- IPU_SENSOR_CONFIG("INT0310", 0),
- /* Omnivision ov01a10 */
- IPU_SENSOR_CONFIG("OVTI01A0", 1, 400000000),
};
static const struct ipu_property_names prop_names = {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index 23c537e7ce1e..e47f84c30e10 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -163,8 +163,8 @@ int ipu6_buttress_ipc_reset(struct ipu6_device *isp,
writel(ENTRY, isp->base + ipc->csr_out);
break;
default:
- dev_warn_ratelimited(&isp->pdev->dev,
- "Unexpected CSR 0x%x\n", val);
+ dev_dbg_ratelimited(&isp->pdev->dev,
+ "Unexpected CSR 0x%x\n", val);
break;
}
} while (retries--);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
index b9ce4324996d..051898ce53f4 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
@@ -345,42 +345,61 @@ static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
return ret;
}
-static int set_stream(struct v4l2_subdev *sd, int enable)
+static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
{
struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
struct ipu6_isys_csi2 *csi2 = to_ipu6_isys_csi2(asd);
- struct device *dev = &csi2->isys->adev->auxdev.dev;
struct ipu6_isys_csi2_timing timing = { };
- unsigned int nlanes;
+ struct v4l2_subdev *remote_sd;
+ struct media_pad *remote_pad;
+ u64 sink_streams;
int ret;
- dev_dbg(dev, "csi2 stream %s callback\n", enable ? "on" : "off");
-
- if (!enable) {
- csi2->stream_count--;
- if (csi2->stream_count)
- return 0;
-
- ipu6_isys_csi2_set_stream(sd, &timing, 0, enable);
- return 0;
- }
-
- if (csi2->stream_count) {
- csi2->stream_count++;
- return 0;
- }
+ remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
+ remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
- nlanes = csi2->nlanes;
+ sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC,
+ CSI2_PAD_SINK,
+ &streams_mask);
ret = ipu6_isys_csi2_calc_timing(csi2, &timing, CSI2_ACCINV);
if (ret)
return ret;
- ret = ipu6_isys_csi2_set_stream(sd, &timing, nlanes, enable);
+ ret = ipu6_isys_csi2_set_stream(sd, &timing, csi2->nlanes, true);
if (ret)
return ret;
- csi2->stream_count++;
+ ret = v4l2_subdev_enable_streams(remote_sd, remote_pad->index,
+ sink_streams);
+ if (ret) {
+ ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask)
+{
+ struct v4l2_subdev *remote_sd;
+ struct media_pad *remote_pad;
+ u64 sink_streams;
+
+ sink_streams = v4l2_subdev_state_xlate_streams(state, CSI2_PAD_SRC,
+ CSI2_PAD_SINK,
+ &streams_mask);
+
+ remote_pad = media_pad_remote_pad_first(&sd->entity.pads[CSI2_PAD_SINK]);
+ remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
+
+ ipu6_isys_csi2_set_stream(sd, NULL, 0, false);
+
+ v4l2_subdev_disable_streams(remote_sd, remote_pad->index, sink_streams);
return 0;
}
@@ -475,10 +494,6 @@ static int ipu6_isys_csi2_get_sel(struct v4l2_subdev *sd,
return ret;
}
-static const struct v4l2_subdev_video_ops csi2_sd_video_ops = {
- .s_stream = set_stream,
-};
-
static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = {
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = ipu6_isys_subdev_set_fmt,
@@ -486,11 +501,12 @@ static const struct v4l2_subdev_pad_ops csi2_sd_pad_ops = {
.set_selection = ipu6_isys_csi2_set_sel,
.enum_mbus_code = ipu6_isys_subdev_enum_mbus_code,
.set_routing = ipu6_isys_subdev_set_routing,
+ .enable_streams = ipu6_isys_csi2_enable_streams,
+ .disable_streams = ipu6_isys_csi2_disable_streams,
};
static const struct v4l2_subdev_ops csi2_sd_ops = {
.core = &csi2_sd_core_ops,
- .video = &csi2_sd_video_ops,
.pad = &csi2_sd_pad_ops,
};
@@ -631,33 +647,3 @@ int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
return 0;
}
-
-void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status)
-{
- struct ipu6_isys_stream *stream = av->stream;
- struct v4l2_subdev *sd = &stream->asd->sd;
- struct v4l2_subdev_state *state;
- struct media_pad *r_pad;
- unsigned int i;
- u32 r_stream;
-
- r_pad = media_pad_remote_pad_first(&av->pad);
- r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
-
- state = v4l2_subdev_lock_and_get_active_state(sd);
-
- for (i = 0; i < state->stream_configs.num_configs; i++) {
- struct v4l2_subdev_stream_config *cfg =
- &state->stream_configs.configs[i];
-
- if (cfg->pad == r_pad->index && r_stream == cfg->stream) {
- dev_dbg(&av->isys->adev->auxdev.dev,
- "%s: pad:%u, stream:%u, status:%u\n",
- sd->entity.name, r_pad->index, r_stream,
- status);
- cfg->enabled = status;
- }
- }
-
- v4l2_subdev_unlock_state(state);
-}
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
index eba6b29386ea..bc8594c94f99 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.h
@@ -45,7 +45,6 @@ struct ipu6_isys_csi2 {
u32 receiver_errors;
unsigned int nlanes;
unsigned int port;
- unsigned int stream_count;
};
struct ipu6_isys_csi2_timing {
@@ -77,6 +76,5 @@ int ipu6_isys_csi2_get_remote_desc(u32 source_stream,
struct ipu6_isys_csi2 *csi2,
struct media_entity *source_entity,
struct v4l2_mbus_frame_desc_entry *entry);
-void ipu6_isys_set_csi2_streams_status(struct ipu6_isys_video *av, bool status);
#endif /* IPU6_ISYS_CSI2_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index 4bd4e324abc9..03dbb0e0ea79 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -551,7 +551,6 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
stream->nr_queues);
list_add(&aq->node, &stream->queues);
- ipu6_isys_set_csi2_streams_status(av, true);
ipu6_isys_configure_stream_watermark(av, true);
ipu6_isys_update_stream_watermark(av, true);
@@ -598,8 +597,6 @@ static void stop_streaming(struct vb2_queue *q)
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
struct ipu6_isys_stream *stream = av->stream;
- ipu6_isys_set_csi2_streams_status(av, false);
-
mutex_lock(&stream->mutex);
ipu6_isys_update_stream_watermark(av, false);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index 06090cc0a476..b37561352ead 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -990,9 +990,7 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
struct v4l2_subdev_state *subdev_state;
struct device *dev = &av->isys->adev->auxdev.dev;
struct v4l2_subdev *sd;
- struct v4l2_subdev *ssd;
struct media_pad *r_pad;
- struct media_pad *s_pad;
u32 sink_pad, sink_stream;
u64 r_stream;
u64 stream_mask = 0;
@@ -1003,7 +1001,6 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
if (WARN(!stream->source_entity, "No source entity for stream\n"))
return -ENODEV;
- ssd = media_entity_to_v4l2_subdev(stream->source_entity);
sd = &stream->asd->sd;
r_pad = media_pad_remote_pad_first(&av->pad);
r_stream = ipu6_isys_get_src_stream_by_src_pad(sd, r_pad->index);
@@ -1017,27 +1014,15 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
if (ret)
return ret;
- s_pad = media_pad_remote_pad_first(&stream->asd->pad[sink_pad]);
-
stream_mask = get_stream_mask_by_pipeline(av);
if (!state) {
stop_streaming_firmware(av);
- /* stop external sub-device now. */
- dev_dbg(dev, "disable streams 0x%llx of %s\n", stream_mask,
- ssd->name);
- ret = v4l2_subdev_disable_streams(ssd, s_pad->index,
- stream_mask);
- if (ret) {
- dev_err(dev, "disable streams of %s failed with %d\n",
- ssd->name, ret);
- return ret;
- }
-
/* stop sub-device which connects with video */
- dev_dbg(dev, "stream off entity %s pad:%d\n", sd->name,
- r_pad->index);
- ret = v4l2_subdev_call(sd, video, s_stream, state);
+ dev_dbg(dev, "stream off entity %s pad:%d mask:0x%llx\n",
+ sd->name, r_pad->index, stream_mask);
+ ret = v4l2_subdev_disable_streams(sd, r_pad->index,
+ stream_mask);
if (ret) {
dev_err(dev, "stream off %s failed with %d\n", sd->name,
ret);
@@ -1052,34 +1037,20 @@ int ipu6_isys_video_set_streaming(struct ipu6_isys_video *av, int state,
}
/* start sub-device which connects with video */
- dev_dbg(dev, "stream on %s pad %d\n", sd->name, r_pad->index);
- ret = v4l2_subdev_call(sd, video, s_stream, state);
+ dev_dbg(dev, "stream on %s pad %d mask 0x%llx\n", sd->name,
+ r_pad->index, stream_mask);
+ ret = v4l2_subdev_enable_streams(sd, r_pad->index, stream_mask);
if (ret) {
dev_err(dev, "stream on %s failed with %d\n", sd->name,
ret);
goto out_media_entity_stop_streaming_firmware;
}
-
- /* start external sub-device now. */
- dev_dbg(dev, "enable streams 0x%llx of %s\n", stream_mask,
- ssd->name);
- ret = v4l2_subdev_enable_streams(ssd, s_pad->index,
- stream_mask);
- if (ret) {
- dev_err(dev,
- "enable streams 0x%llx of %s failed with %d\n",
- stream_mask, stream->source_entity->name, ret);
- goto out_media_entity_stop_streaming;
- }
}
av->streaming = state;
return 0;
-out_media_entity_stop_streaming:
- v4l2_subdev_disable_streams(sd, r_pad->index, BIT(r_stream));
-
out_media_entity_stop_streaming_firmware:
stop_streaming_firmware(av);
diff --git a/drivers/media/pci/intel/ivsc/mei_csi.c b/drivers/media/pci/intel/ivsc/mei_csi.c
index f04a89584334..2a9c12c975ca 100644
--- a/drivers/media/pci/intel/ivsc/mei_csi.c
+++ b/drivers/media/pci/intel/ivsc/mei_csi.c
@@ -126,6 +126,8 @@ struct mei_csi {
struct v4l2_ctrl_handler ctrl_handler;
struct v4l2_ctrl *freq_ctrl;
struct v4l2_ctrl *privacy_ctrl;
+ /* lock for v4l2 controls */
+ struct mutex ctrl_lock;
unsigned int remote_pad;
/* start streaming or not */
int streaming;
@@ -136,9 +138,6 @@ struct mei_csi {
u32 nr_of_lanes;
/* frequency of the CSI-2 link */
u64 link_freq;
-
- /* privacy status */
- enum ivsc_privacy_status status;
};
static const struct v4l2_mbus_framefmt mei_csi_format_mbus_default = {
@@ -190,7 +189,11 @@ static int mei_csi_send(struct mei_csi *csi, u8 *buf, size_t len)
/* command response status */
ret = csi->cmd_response.status;
- if (ret) {
+ if (ret == -1) {
+ /* notify privacy on instead of reporting error */
+ ret = 0;
+ v4l2_ctrl_s_ctrl(csi->privacy_ctrl, 1);
+ } else if (ret) {
ret = -EINVAL;
goto out;
}
@@ -265,10 +268,9 @@ static void mei_csi_rx(struct mei_cl_device *cldev)
switch (notif.cmd_id) {
case CSI_PRIVACY_NOTIF:
- if (notif.cont.cont < CSI_PRIVACY_MAX) {
- csi->status = notif.cont.cont;
- v4l2_ctrl_s_ctrl(csi->privacy_ctrl, csi->status);
- }
+ if (notif.cont.cont < CSI_PRIVACY_MAX)
+ v4l2_ctrl_s_ctrl(csi->privacy_ctrl,
+ notif.cont.cont == CSI_PRIVACY_ON);
break;
case CSI_SET_OWNER:
case CSI_SET_CONF:
@@ -559,11 +561,13 @@ static int mei_csi_init_controls(struct mei_csi *csi)
u32 max;
int ret;
+ mutex_init(&csi->ctrl_lock);
+
ret = v4l2_ctrl_handler_init(&csi->ctrl_handler, 2);
if (ret)
return ret;
- csi->ctrl_handler.lock = &csi->lock;
+ csi->ctrl_handler.lock = &csi->ctrl_lock;
max = ARRAY_SIZE(link_freq_menu_items) - 1;
csi->freq_ctrl = v4l2_ctrl_new_int_menu(&csi->ctrl_handler,
@@ -755,6 +759,7 @@ err_entity:
err_ctrl_handler:
v4l2_ctrl_handler_free(&csi->ctrl_handler);
+ mutex_destroy(&csi->ctrl_lock);
v4l2_async_nf_unregister(&csi->notifier);
v4l2_async_nf_cleanup(&csi->notifier);
@@ -774,6 +779,7 @@ static void mei_csi_remove(struct mei_cl_device *cldev)
v4l2_async_nf_unregister(&csi->notifier);
v4l2_async_nf_cleanup(&csi->notifier);
v4l2_ctrl_handler_free(&csi->ctrl_handler);
+ mutex_destroy(&csi->ctrl_lock);
v4l2_async_unregister_subdev(&csi->subdev);
v4l2_subdev_cleanup(&csi->subdev);
media_entity_cleanup(&csi->subdev.entity);
diff --git a/drivers/media/pci/ivtv/ivtv-driver.c b/drivers/media/pci/ivtv/ivtv-driver.c
index ba503d820e48..ecc20cd89926 100644
--- a/drivers/media/pci/ivtv/ivtv-driver.c
+++ b/drivers/media/pci/ivtv/ivtv-driver.c
@@ -371,33 +371,6 @@ int ivtv_msleep_timeout(unsigned int msecs, int intr)
return 0;
}
-/* Release ioremapped memory */
-static void ivtv_iounmap(struct ivtv *itv)
-{
- if (itv == NULL)
- return;
-
- /* Release registers memory */
- if (itv->reg_mem != NULL) {
- IVTV_DEBUG_INFO("releasing reg_mem\n");
- iounmap(itv->reg_mem);
- itv->reg_mem = NULL;
- }
- /* Release io memory */
- if (itv->has_cx23415 && itv->dec_mem != NULL) {
- IVTV_DEBUG_INFO("releasing dec_mem\n");
- iounmap(itv->dec_mem);
- }
- itv->dec_mem = NULL;
-
- /* Release io memory */
- if (itv->enc_mem != NULL) {
- IVTV_DEBUG_INFO("releasing enc_mem\n");
- iounmap(itv->enc_mem);
- itv->enc_mem = NULL;
- }
-}
-
/* Hauppauge card? get values from tveeprom */
void ivtv_read_eeprom(struct ivtv *itv, struct tveeprom *tv)
{
@@ -833,7 +806,7 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
IVTV_DEBUG_INFO("Enabling pci device\n");
- if (pci_enable_device(pdev)) {
+ if (pcim_enable_device(pdev)) {
IVTV_ERR("Can't enable device!\n");
return -EIO;
}
@@ -841,24 +814,24 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
IVTV_ERR("No suitable DMA available.\n");
return -EIO;
}
- if (!request_mem_region(itv->base_addr, IVTV_ENCODER_SIZE, "ivtv encoder")) {
+ if (!devm_request_mem_region(&pdev->dev, itv->base_addr,
+ IVTV_ENCODER_SIZE, "ivtv encoder")) {
IVTV_ERR("Cannot request encoder memory region.\n");
return -EIO;
}
- if (!request_mem_region(itv->base_addr + IVTV_REG_OFFSET,
- IVTV_REG_SIZE, "ivtv registers")) {
+ if (!devm_request_mem_region(&pdev->dev,
+ itv->base_addr + IVTV_REG_OFFSET,
+ IVTV_REG_SIZE, "ivtv registers")) {
IVTV_ERR("Cannot request register memory region.\n");
- release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
return -EIO;
}
if (itv->has_cx23415 &&
- !request_mem_region(itv->base_addr + IVTV_DECODER_OFFSET,
- IVTV_DECODER_SIZE, "ivtv decoder")) {
+ !devm_request_mem_region(&pdev->dev,
+ itv->base_addr + IVTV_DECODER_OFFSET,
+ IVTV_DECODER_SIZE, "ivtv decoder")) {
IVTV_ERR("Cannot request decoder memory region.\n");
- release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
- release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
return -EIO;
}
@@ -870,11 +843,6 @@ static int ivtv_setup_pci(struct ivtv *itv, struct pci_dev *pdev,
pci_read_config_word(pdev, PCI_COMMAND, &cmd);
if (!(cmd & PCI_COMMAND_MASTER)) {
IVTV_ERR("Bus Mastering is not enabled\n");
- if (itv->has_cx23415)
- release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET,
- IVTV_DECODER_SIZE);
- release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
- release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
return -ENXIO;
}
}
@@ -1033,37 +1001,37 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
/* PCI Device Setup */
retval = ivtv_setup_pci(itv, pdev, pci_id);
- if (retval == -EIO)
+ if (retval == -EIO || retval == -ENXIO)
goto free_worker;
- if (retval == -ENXIO)
- goto free_mem;
/* map io memory */
IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
(u64)itv->base_addr + IVTV_ENCODER_OFFSET, IVTV_ENCODER_SIZE);
- itv->enc_mem = ioremap(itv->base_addr + IVTV_ENCODER_OFFSET,
- IVTV_ENCODER_SIZE);
+ itv->enc_mem = devm_ioremap(&pdev->dev,
+ itv->base_addr + IVTV_ENCODER_OFFSET,
+ IVTV_ENCODER_SIZE);
if (!itv->enc_mem) {
IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 encoder memory\n");
IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of vmalloc address space for this window\n");
IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n");
retval = -ENOMEM;
- goto free_mem;
+ goto free_worker;
}
if (itv->has_cx23415) {
IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
(u64)itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
- itv->dec_mem = ioremap(itv->base_addr + IVTV_DECODER_OFFSET,
- IVTV_DECODER_SIZE);
+ itv->dec_mem = devm_ioremap(&pdev->dev,
+ itv->base_addr + IVTV_DECODER_OFFSET,
+ IVTV_DECODER_SIZE);
if (!itv->dec_mem) {
IVTV_ERR("ioremap failed. Can't get a window into CX23415 decoder memory\n");
IVTV_ERR("Each capture card with a CX23415 needs 8 MB of vmalloc address space for this window\n");
IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n");
retval = -ENOMEM;
- goto free_mem;
+ goto free_worker;
}
}
else {
@@ -1073,26 +1041,27 @@ static int ivtv_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
/* map registers memory */
IVTV_DEBUG_INFO("attempting ioremap at 0x%llx len 0x%08x\n",
(u64)itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
- itv->reg_mem =
- ioremap(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
+ itv->reg_mem = devm_ioremap(&pdev->dev,
+ itv->base_addr + IVTV_REG_OFFSET,
+ IVTV_REG_SIZE);
if (!itv->reg_mem) {
IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 register space\n");
IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of vmalloc address space for this window\n");
IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
IVTV_ERR("Use the vmalloc= kernel command line option to set VmallocTotal to a larger value\n");
retval = -ENOMEM;
- goto free_io;
+ goto free_worker;
}
retval = ivtv_gpio_init(itv);
if (retval)
- goto free_io;
+ goto free_worker;
/* active i2c */
IVTV_DEBUG_INFO("activating i2c...\n");
if (init_ivtv_i2c(itv)) {
IVTV_ERR("Could not initialize i2c\n");
- goto free_io;
+ goto free_worker;
}
if (itv->card->hw_all & IVTV_HW_TVEEPROM) {
@@ -1277,13 +1246,6 @@ free_irq:
free_i2c:
v4l2_ctrl_handler_free(&itv->cxhdl.hdl);
exit_ivtv_i2c(itv);
-free_io:
- ivtv_iounmap(itv);
-free_mem:
- release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
- release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
- if (itv->has_cx23415)
- release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
free_worker:
kthread_stop(itv->irq_worker_task);
err:
@@ -1439,14 +1401,7 @@ static void ivtv_remove(struct pci_dev *pdev)
exit_ivtv_i2c(itv);
free_irq(itv->pdev->irq, (void *)itv);
- ivtv_iounmap(itv);
-
- release_mem_region(itv->base_addr, IVTV_ENCODER_SIZE);
- release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
- if (itv->has_cx23415)
- release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
- pci_disable_device(itv->pdev);
for (i = 0; i < IVTV_VBI_FRAMES; i++)
kfree(itv->vbi.sliced_mpeg_data[i]);
diff --git a/drivers/media/pci/ivtv/ivtv-fileops.c b/drivers/media/pci/ivtv/ivtv-fileops.c
index 4202c3a47d33..cfa28d035586 100644
--- a/drivers/media/pci/ivtv/ivtv-fileops.c
+++ b/drivers/media/pci/ivtv/ivtv-fileops.c
@@ -21,6 +21,7 @@
#include "ivtv-ioctl.h"
#include "ivtv-cards.h"
#include "ivtv-firmware.h"
+#include <linux/lockdep.h>
#include <media/v4l2-event.h>
#include <media/i2c/saa7115.h>
@@ -190,12 +191,27 @@ static void ivtv_update_pgm_info(struct ivtv *itv)
itv->pgm_info_write_idx = (itv->pgm_info_write_idx + i) % itv->pgm_info_num;
}
+static void ivtv_schedule(struct ivtv_stream *s)
+{
+ struct ivtv *itv = s->itv;
+ DEFINE_WAIT(wait);
+
+ lockdep_assert_held(&itv->serialize_lock);
+
+ mutex_unlock(&itv->serialize_lock);
+ prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
+ /* New buffers might have become free before we were added to the waitqueue */
+ if (!s->q_free.buffers)
+ schedule();
+ finish_wait(&s->waitq, &wait);
+ mutex_lock(&itv->serialize_lock);
+}
+
static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block, int *err)
{
struct ivtv *itv = s->itv;
struct ivtv_stream *s_vbi = &itv->streams[IVTV_ENC_STREAM_TYPE_VBI];
struct ivtv_buffer *buf;
- DEFINE_WAIT(wait);
*err = 0;
while (1) {
@@ -258,13 +274,7 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
}
/* wait for more data to arrive */
- mutex_unlock(&itv->serialize_lock);
- prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
- /* New buffers might have become available before we were added to the waitqueue */
- if (!s->q_full.buffers)
- schedule();
- finish_wait(&s->waitq, &wait);
- mutex_lock(&itv->serialize_lock);
+ ivtv_schedule(s);
if (signal_pending(current)) {
/* return if a signal was received */
IVTV_DEBUG_INFO("User stopped %s\n", s->name);
@@ -533,6 +543,25 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
return 0;
}
+static int ivtv_schedule_dma(struct ivtv_stream *s)
+{
+ struct ivtv *itv = s->itv;
+ int got_sig;
+ DEFINE_WAIT(wait);
+
+ lockdep_assert_held(&itv->serialize_lock);
+
+ mutex_unlock(&itv->serialize_lock);
+ prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
+ while (!(got_sig = signal_pending(current)) &&
+ test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags))
+ schedule();
+ finish_wait(&itv->dma_waitq, &wait);
+ mutex_lock(&itv->serialize_lock);
+
+ return got_sig;
+}
+
static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t count, loff_t *pos)
{
struct ivtv_open_id *id = fh2id(filp->private_data);
@@ -544,7 +573,6 @@ static ssize_t ivtv_write(struct file *filp, const char __user *user_buf, size_t
int bytes_written = 0;
int mode;
int rc;
- DEFINE_WAIT(wait);
IVTV_DEBUG_HI_FILE("write %zd bytes to %s\n", count, s->name);
@@ -618,13 +646,7 @@ retry:
break;
if (filp->f_flags & O_NONBLOCK)
return -EAGAIN;
- mutex_unlock(&itv->serialize_lock);
- prepare_to_wait(&s->waitq, &wait, TASK_INTERRUPTIBLE);
- /* New buffers might have become free before we were added to the waitqueue */
- if (!s->q_free.buffers)
- schedule();
- finish_wait(&s->waitq, &wait);
- mutex_lock(&itv->serialize_lock);
+ ivtv_schedule(s);
if (signal_pending(current)) {
IVTV_DEBUG_INFO("User stopped %s\n", s->name);
return -EINTR;
@@ -674,20 +696,10 @@ retry:
if (test_bit(IVTV_F_S_NEEDS_DATA, &s->s_flags)) {
if (s->q_full.length >= itv->dma_data_req_size) {
- int got_sig;
-
if (mode == OUT_YUV)
ivtv_yuv_setup_stream_frame(itv);
- mutex_unlock(&itv->serialize_lock);
- prepare_to_wait(&itv->dma_waitq, &wait, TASK_INTERRUPTIBLE);
- while (!(got_sig = signal_pending(current)) &&
- test_bit(IVTV_F_S_DMA_PENDING, &s->s_flags)) {
- schedule();
- }
- finish_wait(&itv->dma_waitq, &wait);
- mutex_lock(&itv->serialize_lock);
- if (got_sig) {
+ if (ivtv_schedule_dma(s)) {
IVTV_DEBUG_INFO("User interrupted %s\n", s->name);
return -EINTR;
}
diff --git a/drivers/media/pci/ivtv/ivtv-udma.c b/drivers/media/pci/ivtv/ivtv-udma.c
index 99b9f55ca829..f467a00492f4 100644
--- a/drivers/media/pci/ivtv/ivtv-udma.c
+++ b/drivers/media/pci/ivtv/ivtv-udma.c
@@ -131,6 +131,8 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
/* Fill SG List with new values */
if (ivtv_udma_fill_sg_list(dma, &user_dma, 0) < 0) {
+ IVTV_DEBUG_WARN("%s: could not allocate bounce buffers for highmem userspace buffers\n",
+ __func__);
unpin_user_pages(dma->map, dma->page_count);
dma->page_count = 0;
return -ENOMEM;
@@ -139,6 +141,12 @@ int ivtv_udma_setup(struct ivtv *itv, unsigned long ivtv_dest_addr,
/* Map SG List */
dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist,
dma->page_count, DMA_TO_DEVICE);
+ if (!dma->SG_length) {
+ IVTV_DEBUG_WARN("%s: DMA map error, SG_length is 0\n", __func__);
+ unpin_user_pages(dma->map, dma->page_count);
+ dma->page_count = 0;
+ return -EINVAL;
+ }
/* Fill SG Array with new values */
ivtv_udma_fill_sg_array (dma, ivtv_dest_addr, 0, -1);
diff --git a/drivers/media/pci/ivtv/ivtv-yuv.c b/drivers/media/pci/ivtv/ivtv-yuv.c
index 582146f8d70d..2d9274537725 100644
--- a/drivers/media/pci/ivtv/ivtv-yuv.c
+++ b/drivers/media/pci/ivtv/ivtv-yuv.c
@@ -114,6 +114,12 @@ static int ivtv_yuv_prep_user_dma(struct ivtv *itv, struct ivtv_user_dma *dma,
}
dma->SG_length = dma_map_sg(&itv->pdev->dev, dma->SGlist,
dma->page_count, DMA_TO_DEVICE);
+ if (!dma->SG_length) {
+ IVTV_DEBUG_WARN("%s: DMA map error, SG_length is 0\n", __func__);
+ unpin_user_pages(dma->map, dma->page_count);
+ dma->page_count = 0;
+ return -EINVAL;
+ }
/* Fill SG Array with new values */
ivtv_udma_fill_sg_array(dma, y_buffer_offset, uv_buffer_offset, y_size);
diff --git a/drivers/media/pci/ivtv/ivtvfb.c b/drivers/media/pci/ivtv/ivtvfb.c
index 410477e3e621..90c584cf97c2 100644
--- a/drivers/media/pci/ivtv/ivtvfb.c
+++ b/drivers/media/pci/ivtv/ivtvfb.c
@@ -104,6 +104,7 @@ MODULE_PARM_DESC(osd_xres,
"\t\t\tdefault 640");
MODULE_AUTHOR("Kevin Thayer, Chris Kennedy, Hans Verkuil, John Harvey, Ian Armstrong");
+MODULE_DESCRIPTION("Conexant cx23415 framebuffer support");
MODULE_LICENSE("GPL");
/* --------------------------------------------------------------------- */
@@ -281,10 +282,10 @@ static int ivtvfb_prep_dec_dma_to_device(struct ivtv *itv,
/* Map User DMA */
if (ivtv_udma_setup(itv, ivtv_dest_addr, userbuf, size_in_bytes) <= 0) {
mutex_unlock(&itv->udma.lock);
- IVTVFB_WARN("ivtvfb_prep_dec_dma_to_device, Error with pin_user_pages: %d bytes, %d pages returned\n",
- size_in_bytes, itv->udma.page_count);
+ IVTVFB_WARN("%s, Error in ivtv_udma_setup: %d bytes, %d pages returned\n",
+ __func__, size_in_bytes, itv->udma.page_count);
- /* pin_user_pages must have failed completely */
+ /* pin_user_pages or DMA must have failed completely */
return -EIO;
}
diff --git a/drivers/media/pci/mantis/hopper_cards.c b/drivers/media/pci/mantis/hopper_cards.c
index c0bd5d7e148b..b85aef4e2b24 100644
--- a/drivers/media/pci/mantis/hopper_cards.c
+++ b/drivers/media/pci/mantis/hopper_cards.c
@@ -116,7 +116,7 @@ static irqreturn_t hopper_irq_handler(int irq, void *dev_id)
if (stat & MANTIS_INT_RISCI) {
dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
- tasklet_schedule(&mantis->tasklet);
+ queue_work(system_bh_wq, &mantis->bh_work);
}
if (stat & MANTIS_INT_I2CDONE) {
dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
diff --git a/drivers/media/pci/mantis/mantis_cards.c b/drivers/media/pci/mantis/mantis_cards.c
index 906e4500d87d..b44b4cf42f86 100644
--- a/drivers/media/pci/mantis/mantis_cards.c
+++ b/drivers/media/pci/mantis/mantis_cards.c
@@ -125,7 +125,7 @@ static irqreturn_t mantis_irq_handler(int irq, void *dev_id)
if (stat & MANTIS_INT_RISCI) {
dprintk(MANTIS_DEBUG, 0, "<%s>", label[8]);
mantis->busy_block = (stat & MANTIS_INT_RISCSTAT) >> 28;
- tasklet_schedule(&mantis->tasklet);
+ queue_work(system_bh_wq, &mantis->bh_work);
}
if (stat & MANTIS_INT_I2CDONE) {
dprintk(MANTIS_DEBUG, 0, "<%s>", label[9]);
diff --git a/drivers/media/pci/mantis/mantis_common.h b/drivers/media/pci/mantis/mantis_common.h
index d88ac280226c..6e563ecd94e8 100644
--- a/drivers/media/pci/mantis/mantis_common.h
+++ b/drivers/media/pci/mantis/mantis_common.h
@@ -125,7 +125,7 @@ struct mantis_pci {
__le32 *risc_cpu;
dma_addr_t risc_dma;
- struct tasklet_struct tasklet;
+ struct work_struct bh_work;
spinlock_t intmask_lock;
struct i2c_adapter adapter;
diff --git a/drivers/media/pci/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c
index 80c843936493..eeb210a2862f 100644
--- a/drivers/media/pci/mantis/mantis_dma.c
+++ b/drivers/media/pci/mantis/mantis_dma.c
@@ -200,9 +200,9 @@ void mantis_dma_stop(struct mantis_pci *mantis)
}
-void mantis_dma_xfer(struct tasklet_struct *t)
+void mantis_dma_xfer(struct work_struct *t)
{
- struct mantis_pci *mantis = from_tasklet(mantis, t, tasklet);
+ struct mantis_pci *mantis = from_work(mantis, t, bh_work);
struct mantis_hwconfig *config = mantis->hwconfig;
while (mantis->last_block != mantis->busy_block) {
diff --git a/drivers/media/pci/mantis/mantis_dma.h b/drivers/media/pci/mantis/mantis_dma.h
index 37da982c9c29..5db0d3728f15 100644
--- a/drivers/media/pci/mantis/mantis_dma.h
+++ b/drivers/media/pci/mantis/mantis_dma.h
@@ -13,6 +13,6 @@ extern int mantis_dma_init(struct mantis_pci *mantis);
extern int mantis_dma_exit(struct mantis_pci *mantis);
extern void mantis_dma_start(struct mantis_pci *mantis);
extern void mantis_dma_stop(struct mantis_pci *mantis);
-extern void mantis_dma_xfer(struct tasklet_struct *t);
+extern void mantis_dma_xfer(struct work_struct *t);
#endif /* __MANTIS_DMA_H */
diff --git a/drivers/media/pci/mantis/mantis_dvb.c b/drivers/media/pci/mantis/mantis_dvb.c
index c7ba4a76e608..398e32f44692 100644
--- a/drivers/media/pci/mantis/mantis_dvb.c
+++ b/drivers/media/pci/mantis/mantis_dvb.c
@@ -105,7 +105,7 @@ static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
if (mantis->feeds == 1) {
dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
mantis_dma_start(mantis);
- tasklet_enable(&mantis->tasklet);
+ enable_and_queue_work(system_bh_wq, &mantis->bh_work);
}
return mantis->feeds;
@@ -125,7 +125,7 @@ static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
mantis->feeds--;
if (mantis->feeds == 0) {
dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
- tasklet_disable(&mantis->tasklet);
+ disable_work_sync(&mantis->bh_work);
mantis_dma_stop(mantis);
}
@@ -205,8 +205,8 @@ int mantis_dvb_init(struct mantis_pci *mantis)
}
dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
- tasklet_setup(&mantis->tasklet, mantis_dma_xfer);
- tasklet_disable(&mantis->tasklet);
+ INIT_WORK(&mantis->bh_work, mantis_dma_xfer);
+ disable_work_sync(&mantis->bh_work);
if (mantis->hwconfig) {
result = config->frontend_init(mantis, mantis->fe);
if (result < 0) {
@@ -235,7 +235,7 @@ int mantis_dvb_init(struct mantis_pci *mantis)
/* Error conditions .. */
err5:
- tasklet_kill(&mantis->tasklet);
+ cancel_work_sync(&mantis->bh_work);
dvb_net_release(&mantis->dvbnet);
if (mantis->fe) {
dvb_unregister_frontend(mantis->fe);
@@ -273,7 +273,7 @@ int mantis_dvb_exit(struct mantis_pci *mantis)
dvb_frontend_detach(mantis->fe);
}
- tasklet_kill(&mantis->tasklet);
+ cancel_work_sync(&mantis->bh_work);
dvb_net_release(&mantis->dvbnet);
mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
index 24ec576dc3bf..db6796240bce 100644
--- a/drivers/media/pci/ngene/ngene-core.c
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -50,9 +50,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* nGene interrupt handler **************************************************/
/****************************************************************************/
-static void event_tasklet(struct tasklet_struct *t)
+static void event_bh_work(struct work_struct *t)
{
- struct ngene *dev = from_tasklet(dev, t, event_tasklet);
+ struct ngene *dev = from_work(dev, t, event_bh_work);
while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
struct EVENT_BUFFER Event =
@@ -68,9 +68,9 @@ static void event_tasklet(struct tasklet_struct *t)
}
}
-static void demux_tasklet(struct tasklet_struct *t)
+static void demux_bh_work(struct work_struct *t)
{
- struct ngene_channel *chan = from_tasklet(chan, t, demux_tasklet);
+ struct ngene_channel *chan = from_work(chan, t, demux_bh_work);
struct device *pdev = &chan->dev->pci_dev->dev;
struct SBufferHeader *Cur = chan->nextBuffer;
@@ -204,7 +204,7 @@ static irqreturn_t irq_handler(int irq, void *dev_id)
dev->EventQueueOverflowFlag = 1;
}
dev->EventBuffer->EventStatus &= ~0x80;
- tasklet_schedule(&dev->event_tasklet);
+ queue_work(system_bh_wq, &dev->event_bh_work);
rc = IRQ_HANDLED;
}
@@ -217,8 +217,8 @@ static irqreturn_t irq_handler(int irq, void *dev_id)
ngeneBuffer.SR.Flags & 0xC0) == 0x80) {
dev->channel[i].nextBuffer->
ngeneBuffer.SR.Flags |= 0x40;
- tasklet_schedule(
- &dev->channel[i].demux_tasklet);
+ queue_work(system_bh_wq,
+ &dev->channel[i].demux_bh_work);
rc = IRQ_HANDLED;
}
}
@@ -1181,7 +1181,7 @@ static void ngene_init(struct ngene *dev)
struct device *pdev = &dev->pci_dev->dev;
int i;
- tasklet_setup(&dev->event_tasklet, event_tasklet);
+ INIT_WORK(&dev->event_bh_work, event_bh_work);
memset_io(dev->iomem + 0xc000, 0x00, 0x220);
memset_io(dev->iomem + 0xc400, 0x00, 0x100);
@@ -1395,7 +1395,7 @@ static void release_channel(struct ngene_channel *chan)
if (chan->running)
set_transfer(chan, 0);
- tasklet_kill(&chan->demux_tasklet);
+ cancel_work_sync(&chan->demux_bh_work);
if (chan->ci_dev) {
dvb_unregister_device(chan->ci_dev);
@@ -1445,7 +1445,7 @@ static int init_channel(struct ngene_channel *chan)
struct ngene_info *ni = dev->card_info;
int io = ni->io_type[nr];
- tasklet_setup(&chan->demux_tasklet, demux_tasklet);
+ INIT_WORK(&chan->demux_bh_work, demux_bh_work);
chan->users = 0;
chan->type = io;
chan->mode = chan->type; /* for now only one mode */
@@ -1649,7 +1649,7 @@ void ngene_remove(struct pci_dev *pdev)
struct ngene *dev = pci_get_drvdata(pdev);
int i;
- tasklet_kill(&dev->event_tasklet);
+ cancel_work_sync(&dev->event_bh_work);
for (i = MAX_STREAM - 1; i >= 0; i--)
release_channel(&dev->channel[i]);
if (dev->ci.en)
diff --git a/drivers/media/pci/ngene/ngene.h b/drivers/media/pci/ngene/ngene.h
index d1d7da84cd9d..9f989420b9e7 100644
--- a/drivers/media/pci/ngene/ngene.h
+++ b/drivers/media/pci/ngene/ngene.h
@@ -16,6 +16,7 @@
#include <linux/scatterlist.h>
#include <linux/dvb/frontend.h>
+#include <linux/workqueue.h>
#include <media/dmxdev.h>
#include <media/dvbdev.h>
@@ -621,7 +622,7 @@ struct ngene_channel {
int users;
struct video_device *v4l_dev;
struct dvb_device *ci_dev;
- struct tasklet_struct demux_tasklet;
+ struct work_struct demux_bh_work;
struct SBufferHeader *nextBuffer;
enum KSSTATE State;
@@ -717,7 +718,7 @@ struct ngene {
struct EVENT_BUFFER EventQueue[EVENT_QUEUE_SIZE];
int EventQueueOverflowCount;
int EventQueueOverflowFlag;
- struct tasklet_struct event_tasklet;
+ struct work_struct event_bh_work;
struct EVENT_BUFFER *EventBuffer;
int EventQueueWriteIndex;
int EventQueueReadIndex;
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
index dd2236c5c4a1..f86a44dfe6e3 100644
--- a/drivers/media/pci/saa7134/saa7134-alsa.c
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -1254,5 +1254,6 @@ static void saa7134_alsa_exit(void)
/* We initialize this late, to make sure the sound system is up and running */
late_initcall(saa7134_alsa_init);
module_exit(saa7134_alsa_exit);
+MODULE_DESCRIPTION("Philips SAA7134 DMA audio support");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Ricardo Cerqueira");
diff --git a/drivers/media/pci/saa7134/saa7134-dvb.c b/drivers/media/pci/saa7134/saa7134-dvb.c
index 9c6cfef03331..6de8a02314af 100644
--- a/drivers/media/pci/saa7134/saa7134-dvb.c
+++ b/drivers/media/pci/saa7134/saa7134-dvb.c
@@ -52,6 +52,7 @@
#include "s5h1411.h"
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_DESCRIPTION("DVB/ATSC Support for saa7134 based TV cards");
MODULE_LICENSE("GPL");
static unsigned int antenna_pwr;
@@ -466,7 +467,9 @@ static int philips_europa_tuner_sleep(struct dvb_frontend *fe)
/* switch the board to analog mode */
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- i2c_transfer(&dev->i2c_adap, &analog_msg, 1);
+ if (i2c_transfer(&dev->i2c_adap, &analog_msg, 1) != 1)
+ return -EIO;
+
return 0;
}
@@ -1018,7 +1021,9 @@ static int md8800_set_voltage2(struct dvb_frontend *fe,
else
wbuf[1] = rbuf & 0xef;
msg[0].len = 2;
- i2c_transfer(&dev->i2c_adap, msg, 1);
+ if (i2c_transfer(&dev->i2c_adap, msg, 1) != 1)
+ return -EIO;
+
return 0;
}
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 434fa1ee1c33..bbf480ab31ca 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -19,6 +19,7 @@
/* ------------------------------------------------------------------ */
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
+MODULE_DESCRIPTION("Philips SAA7134 empress support");
MODULE_LICENSE("GPL");
static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c
index da83893ffee9..bd37db5ce363 100644
--- a/drivers/media/pci/saa7134/saa7134-go7007.c
+++ b/drivers/media/pci/saa7134/saa7134-go7007.c
@@ -516,4 +516,5 @@ static void __exit saa7134_go7007_mod_cleanup(void)
module_init(saa7134_go7007_mod_init);
module_exit(saa7134_go7007_mod_cleanup);
+MODULE_DESCRIPTION("go7007 support for saa7134 based TV cards");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/pci/smipcie/smipcie-main.c b/drivers/media/pci/smipcie/smipcie-main.c
index 0c300d019d9c..7db6d443fc54 100644
--- a/drivers/media/pci/smipcie/smipcie-main.c
+++ b/drivers/media/pci/smipcie/smipcie-main.c
@@ -279,10 +279,10 @@ static void smi_port_clearInterrupt(struct smi_port *port)
(port->_dmaInterruptCH0 | port->_dmaInterruptCH1));
}
-/* tasklet handler: DMA data to dmx.*/
-static void smi_dma_xfer(struct tasklet_struct *t)
+/* BH work handler: DMA data to dmx.*/
+static void smi_dma_xfer(struct work_struct *t)
{
- struct smi_port *port = from_tasklet(port, t, tasklet);
+ struct smi_port *port = from_work(port, t, bh_work);
struct smi_dev *dev = port->dev;
u32 intr_status, finishedData, dmaManagement;
u8 dmaChan0State, dmaChan1State;
@@ -426,8 +426,8 @@ static int smi_port_init(struct smi_port *port, int dmaChanUsed)
}
smi_port_disableInterrupt(port);
- tasklet_setup(&port->tasklet, smi_dma_xfer);
- tasklet_disable(&port->tasklet);
+ INIT_WORK(&port->bh_work, smi_dma_xfer);
+ disable_work_sync(&port->bh_work);
port->enable = 1;
return 0;
err:
@@ -438,7 +438,7 @@ err:
static void smi_port_exit(struct smi_port *port)
{
smi_port_disableInterrupt(port);
- tasklet_kill(&port->tasklet);
+ cancel_work_sync(&port->bh_work);
smi_port_dma_free(port);
port->enable = 0;
}
@@ -452,7 +452,7 @@ static int smi_port_irq(struct smi_port *port, u32 int_status)
smi_port_disableInterrupt(port);
port->_int_status = int_status;
smi_port_clearInterrupt(port);
- tasklet_schedule(&port->tasklet);
+ queue_work(system_bh_wq, &port->bh_work);
handled = 1;
}
return handled;
@@ -823,7 +823,7 @@ static int smi_start_feed(struct dvb_demux_feed *dvbdmxfeed)
smi_port_clearInterrupt(port);
smi_port_enableInterrupt(port);
smi_write(port->DMA_MANAGEMENT, dmaManagement);
- tasklet_enable(&port->tasklet);
+ enable_and_queue_work(system_bh_wq, &port->bh_work);
}
return port->users;
}
@@ -837,7 +837,7 @@ static int smi_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
if (--port->users)
return port->users;
- tasklet_disable(&port->tasklet);
+ disable_work_sync(&port->bh_work);
smi_port_disableInterrupt(port);
smi_clear(port->DMA_MANAGEMENT, 0x30003);
return 0;
diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h
index 2b5e0154814c..98e44edaab9e 100644
--- a/drivers/media/pci/smipcie/smipcie.h
+++ b/drivers/media/pci/smipcie/smipcie.h
@@ -17,6 +17,7 @@
#include <linux/pci.h>
#include <linux/dma-mapping.h>
#include <linux/slab.h>
+#include <linux/workqueue.h>
#include <media/rc-core.h>
#include <media/demux.h>
@@ -257,7 +258,7 @@ struct smi_port {
u32 _dmaInterruptCH0;
u32 _dmaInterruptCH1;
u32 _int_status;
- struct tasklet_struct tasklet;
+ struct work_struct bh_work;
/* dvb */
struct dmx_frontend hw_frontend;
struct dmx_frontend mem_frontend;
diff --git a/drivers/media/pci/ttpci/budget-av.c b/drivers/media/pci/ttpci/budget-av.c
index 2e62c938e2cb..69f5e810f9b5 100644
--- a/drivers/media/pci/ttpci/budget-av.c
+++ b/drivers/media/pci/ttpci/budget-av.c
@@ -36,6 +36,7 @@
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include <media/dvb_ca_en50221.h>
@@ -54,7 +55,7 @@ struct budget_av {
struct video_device vd;
int cur_input;
int has_saa7113;
- struct tasklet_struct ciintf_irq_tasklet;
+ struct work_struct ciintf_irq_bh_work;
int slot_status;
struct dvb_ca_en50221 ca;
u8 reinitialise_demod:1;
diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index 76de40e3c802..33f08adf4feb 100644
--- a/drivers/media/pci/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
@@ -18,6 +18,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
+#include <linux/workqueue.h>
#include <media/rc-core.h>
#include "budget.h"
@@ -81,7 +82,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct budget_ci_ir {
struct rc_dev *dev;
- struct tasklet_struct msp430_irq_tasklet;
+ struct work_struct msp430_irq_bh_work;
char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
char phys[32];
int rc5_device;
@@ -92,7 +93,7 @@ struct budget_ci_ir {
struct budget_ci {
struct budget budget;
- struct tasklet_struct ciintf_irq_tasklet;
+ struct work_struct ciintf_irq_bh_work;
int slot_status;
int ci_irq;
struct dvb_ca_en50221 ca;
@@ -100,9 +101,9 @@ struct budget_ci {
u8 tuner_pll_address; /* used for philips_tdm1316l configs */
};
-static void msp430_ir_interrupt(struct tasklet_struct *t)
+static void msp430_ir_interrupt(struct work_struct *t)
{
- struct budget_ci_ir *ir = from_tasklet(ir, t, msp430_irq_tasklet);
+ struct budget_ci_ir *ir = from_work(ir, t, msp430_irq_bh_work);
struct budget_ci *budget_ci = container_of(ir, typeof(*budget_ci), ir);
struct rc_dev *dev = budget_ci->ir.dev;
u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
@@ -231,7 +232,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
budget_ci->ir.dev = dev;
- tasklet_setup(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt);
+ INIT_WORK(&budget_ci->ir.msp430_irq_bh_work, msp430_ir_interrupt);
SAA7146_IER_ENABLE(saa, MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
@@ -245,7 +246,7 @@ static void msp430_ir_deinit(struct budget_ci *budget_ci)
SAA7146_IER_DISABLE(saa, MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
- tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
+ cancel_work_sync(&budget_ci->ir.msp430_irq_bh_work);
rc_unregister_device(budget_ci->ir.dev);
}
@@ -349,10 +350,10 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
return 0;
}
-static void ciintf_interrupt(struct tasklet_struct *t)
+static void ciintf_interrupt(struct work_struct *t)
{
- struct budget_ci *budget_ci = from_tasklet(budget_ci, t,
- ciintf_irq_tasklet);
+ struct budget_ci *budget_ci = from_work(budget_ci, t,
+ ciintf_irq_bh_work);
struct saa7146_dev *saa = budget_ci->budget.dev;
unsigned int flags;
@@ -491,7 +492,7 @@ static int ciintf_init(struct budget_ci *budget_ci)
// Setup CI slot IRQ
if (budget_ci->ci_irq) {
- tasklet_setup(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt);
+ INIT_WORK(&budget_ci->ciintf_irq_bh_work, ciintf_interrupt);
if (budget_ci->slot_status != SLOTSTATUS_NONE)
saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
else
@@ -530,7 +531,7 @@ static void ciintf_deinit(struct budget_ci *budget_ci)
if (budget_ci->ci_irq) {
SAA7146_IER_DISABLE(saa, MASK_03);
saa7146_setgpio(saa, 0, SAA7146_GPIO_INPUT);
- tasklet_kill(&budget_ci->ciintf_irq_tasklet);
+ cancel_work_sync(&budget_ci->ciintf_irq_bh_work);
}
// reset interface
@@ -556,13 +557,13 @@ static void budget_ci_irq(struct saa7146_dev *dev, u32 *isr)
dprintk(8, "dev: %p, budget_ci: %p\n", dev, budget_ci);
if (*isr & MASK_06)
- tasklet_schedule(&budget_ci->ir.msp430_irq_tasklet);
+ queue_work(system_bh_wq, &budget_ci->ir.msp430_irq_bh_work);
if (*isr & MASK_10)
ttpci_budget_irq10_handler(dev, isr);
if ((*isr & MASK_03) && (budget_ci->budget.ci_present) && (budget_ci->ci_irq))
- tasklet_schedule(&budget_ci->ciintf_irq_tasklet);
+ queue_work(system_bh_wq, &budget_ci->ciintf_irq_bh_work);
}
static u8 philips_su1278_tt_inittab[] = {
diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c
index d33adeca196f..29531d9c9db0 100644
--- a/drivers/media/pci/ttpci/budget-core.c
+++ b/drivers/media/pci/ttpci/budget-core.c
@@ -172,9 +172,9 @@ static int budget_read_fe_status(struct dvb_frontend *fe,
return ret;
}
-static void vpeirq(struct tasklet_struct *t)
+static void vpeirq(struct work_struct *t)
{
- struct budget *budget = from_tasklet(budget, t, vpe_tasklet);
+ struct budget *budget = from_work(budget, t, vpe_bh_work);
u8 *mem = (u8 *) (budget->grabbing);
u32 olddma = budget->ttbp;
u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
@@ -525,7 +525,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
/* upload all */
saa7146_write(dev, GPIO_CTRL, 0x000000);
- tasklet_setup(&budget->vpe_tasklet, vpeirq);
+ INIT_WORK(&budget->vpe_bh_work, vpeirq);
/* frontend power on */
if (bi->type != BUDGET_FS_ACTIVY)
@@ -565,7 +565,7 @@ int ttpci_budget_deinit(struct budget *budget)
budget_unregister(budget);
- tasklet_kill(&budget->vpe_tasklet);
+ cancel_work_sync(&budget->vpe_bh_work);
saa7146_vfree_destroy_pgtable(dev->pci, budget->grabbing, &budget->pt);
@@ -584,7 +584,7 @@ void ttpci_budget_irq10_handler(struct saa7146_dev *dev, u32 *isr)
dprintk(8, "dev: %p, budget: %p\n", dev, budget);
if (*isr & MASK_10)
- tasklet_schedule(&budget->vpe_tasklet);
+ queue_work(system_bh_wq, &budget->vpe_bh_work);
}
EXPORT_SYMBOL_GPL(ttpci_budget_irq10_handler);
@@ -602,4 +602,5 @@ void ttpci_budget_set_video_port(struct saa7146_dev *dev, int video_port)
}
EXPORT_SYMBOL_GPL(ttpci_budget_set_video_port);
+MODULE_DESCRIPTION("base driver for the SAA7146 based Budget DVB cards");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/ttpci/budget.h b/drivers/media/pci/ttpci/budget.h
index 83ead34dc766..e933764ac4e3 100644
--- a/drivers/media/pci/ttpci/budget.h
+++ b/drivers/media/pci/ttpci/budget.h
@@ -18,6 +18,7 @@
#include <linux/module.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <media/drv-intf/saa7146.h>
@@ -54,8 +55,8 @@ struct budget {
unsigned char *grabbing;
struct saa7146_pgtable pt;
- struct tasklet_struct fidb_tasklet;
- struct tasklet_struct vpe_tasklet;
+ struct work_struct fidb_bh_work;
+ struct work_struct vpe_bh_work;
struct dmxdev dmxdev;
struct dvb_demux demux;
diff --git a/drivers/media/pci/tw5864/tw5864-core.c b/drivers/media/pci/tw5864/tw5864-core.c
index 560ff1ddcc83..4d33caf83307 100644
--- a/drivers/media/pci/tw5864/tw5864-core.c
+++ b/drivers/media/pci/tw5864/tw5864-core.c
@@ -144,7 +144,7 @@ static void tw5864_h264_isr(struct tw5864_dev *dev)
cur_frame->gop_seqno = input->frame_gop_seqno;
dev->h264_buf_w_index = next_frame_index;
- tasklet_schedule(&dev->tasklet);
+ queue_work(system_bh_wq, &dev->bh_work);
cur_frame = next_frame;
diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c
index 8b1aae4b6319..4f35c159efe5 100644
--- a/drivers/media/pci/tw5864/tw5864-video.c
+++ b/drivers/media/pci/tw5864/tw5864-video.c
@@ -6,6 +6,7 @@
*/
#include <linux/module.h>
+#include <linux/workqueue.h>
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
#include <media/videobuf2-dma-contig.h>
@@ -175,7 +176,7 @@ static const unsigned int intra4x4_lambda3[] = {
static v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std);
static enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std);
-static void tw5864_handle_frame_task(struct tasklet_struct *t);
+static void tw5864_handle_frame_work(struct work_struct *t);
static void tw5864_handle_frame(struct tw5864_h264_frame *frame);
static void tw5864_frame_interval_set(struct tw5864_input *input);
@@ -1062,7 +1063,7 @@ int tw5864_video_init(struct tw5864_dev *dev, int *video_nr)
dev->irqmask |= TW5864_INTR_VLC_DONE | TW5864_INTR_TIMER;
tw5864_irqmask_apply(dev);
- tasklet_setup(&dev->tasklet, tw5864_handle_frame_task);
+ INIT_WORK(&dev->bh_work, tw5864_handle_frame_work);
for (i = 0; i < TW5864_INPUTS; i++) {
dev->inputs[i].root = dev;
@@ -1079,7 +1080,7 @@ fini_video_inputs:
for (i = last_input_nr_registered; i >= 0; i--)
tw5864_video_input_fini(&dev->inputs[i]);
- tasklet_kill(&dev->tasklet);
+ cancel_work_sync(&dev->bh_work);
free_dma:
for (i = last_dma_allocated; i >= 0; i--) {
@@ -1198,7 +1199,7 @@ void tw5864_video_fini(struct tw5864_dev *dev)
{
int i;
- tasklet_kill(&dev->tasklet);
+ cancel_work_sync(&dev->bh_work);
for (i = 0; i < TW5864_INPUTS; i++)
tw5864_video_input_fini(&dev->inputs[i]);
@@ -1315,9 +1316,9 @@ static int tw5864_is_motion_triggered(struct tw5864_h264_frame *frame)
return detected;
}
-static void tw5864_handle_frame_task(struct tasklet_struct *t)
+static void tw5864_handle_frame_work(struct work_struct *t)
{
- struct tw5864_dev *dev = from_tasklet(dev, t, tasklet);
+ struct tw5864_dev *dev = from_work(dev, t, bh_work);
unsigned long flags;
int batch_size = H264_BUF_CNT;
diff --git a/drivers/media/pci/tw5864/tw5864.h b/drivers/media/pci/tw5864/tw5864.h
index a8b6fbd5b710..2da5f4215fd9 100644
--- a/drivers/media/pci/tw5864/tw5864.h
+++ b/drivers/media/pci/tw5864/tw5864.h
@@ -12,6 +12,7 @@
#include <linux/mutex.h>
#include <linux/io.h>
#include <linux/interrupt.h>
+#include <linux/workqueue.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
@@ -85,7 +86,7 @@ struct tw5864_input {
int nr; /* input number */
struct tw5864_dev *root;
struct mutex lock; /* used for vidq and vdev */
- spinlock_t slock; /* used for sync between ISR, tasklet & V4L2 API */
+ spinlock_t slock; /* used for sync between ISR, bh_work & V4L2 API */
struct video_device vdev;
struct v4l2_ctrl_handler hdl;
struct vb2_queue vidq;
@@ -142,7 +143,7 @@ struct tw5864_h264_frame {
/* global device status */
struct tw5864_dev {
- spinlock_t slock; /* used for sync between ISR, tasklet & V4L2 API */
+ spinlock_t slock; /* used for sync between ISR, bh_work & V4L2 API */
struct v4l2_device v4l2_dev;
struct tw5864_input inputs[TW5864_INPUTS];
#define H264_BUF_CNT 4
@@ -150,7 +151,7 @@ struct tw5864_dev {
int h264_buf_r_index;
int h264_buf_w_index;
- struct tasklet_struct tasklet;
+ struct work_struct bh_work;
int encoder_busy;
/* Input number to check next for ready raw picture (in RR fashion) */
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 2d79bfc68c15..85d2627776b6 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -70,6 +70,7 @@ source "drivers/media/platform/atmel/Kconfig"
source "drivers/media/platform/broadcom/Kconfig"
source "drivers/media/platform/cadence/Kconfig"
source "drivers/media/platform/chips-media/Kconfig"
+source "drivers/media/platform/imagination/Kconfig"
source "drivers/media/platform/intel/Kconfig"
source "drivers/media/platform/marvell/Kconfig"
source "drivers/media/platform/mediatek/Kconfig"
@@ -78,6 +79,7 @@ source "drivers/media/platform/nuvoton/Kconfig"
source "drivers/media/platform/nvidia/Kconfig"
source "drivers/media/platform/nxp/Kconfig"
source "drivers/media/platform/qcom/Kconfig"
+source "drivers/media/platform/raspberrypi/Kconfig"
source "drivers/media/platform/renesas/Kconfig"
source "drivers/media/platform/rockchip/Kconfig"
source "drivers/media/platform/samsung/Kconfig"
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index da17301f7439..ace4e34483dd 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -13,6 +13,7 @@ obj-y += atmel/
obj-y += broadcom/
obj-y += cadence/
obj-y += chips-media/
+obj-y += imagination/
obj-y += intel/
obj-y += marvell/
obj-y += mediatek/
@@ -21,6 +22,7 @@ obj-y += nuvoton/
obj-y += nvidia/
obj-y += nxp/
obj-y += qcom/
+obj-y += raspberrypi/
obj-y += renesas/
obj-y += rockchip/
obj-y += samsung/
diff --git a/drivers/media/platform/allegro-dvt/nal-hevc.h b/drivers/media/platform/allegro-dvt/nal-hevc.h
index eb46f12aae80..361e2f55c254 100644
--- a/drivers/media/platform/allegro-dvt/nal-hevc.h
+++ b/drivers/media/platform/allegro-dvt/nal-hevc.h
@@ -96,10 +96,11 @@ struct nal_hevc_vps {
unsigned int extension_data_flag;
};
+#define N_HRD_PARAMS 1
struct nal_hevc_sub_layer_hrd_parameters {
- unsigned int bit_rate_value_minus1[1];
- unsigned int cpb_size_value_minus1[1];
- unsigned int cbr_flag[1];
+ unsigned int bit_rate_value_minus1[N_HRD_PARAMS];
+ unsigned int cpb_size_value_minus1[N_HRD_PARAMS];
+ unsigned int cbr_flag[N_HRD_PARAMS];
};
struct nal_hevc_hrd_parameters {
diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c
index a57f9f4f3b87..6a38a0fa0e2d 100644
--- a/drivers/media/platform/amphion/vdec.c
+++ b/drivers/media/platform/amphion/vdec.c
@@ -195,7 +195,6 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
struct vdec_t *vdec = inst->priv;
int ret = 0;
- vpu_inst_lock(inst);
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_DEC_DISPLAY_DELAY_ENABLE:
vdec->params.display_delay_enable = ctrl->val;
@@ -207,7 +206,6 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
ret = -EINVAL;
break;
}
- vpu_inst_unlock(inst);
return ret;
}
diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c
index 4eb57d793a9c..351b4edc8742 100644
--- a/drivers/media/platform/amphion/venc.c
+++ b/drivers/media/platform/amphion/venc.c
@@ -518,7 +518,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
struct venc_t *venc = inst->priv;
int ret = 0;
- vpu_inst_lock(inst);
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
venc->params.profile = ctrl->val;
@@ -579,7 +578,6 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
ret = -EINVAL;
break;
}
- vpu_inst_unlock(inst);
return ret;
}
@@ -680,6 +678,9 @@ static int venc_ctrl_init(struct vpu_inst *inst)
~(1 << V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME),
V4L2_MPEG_VIDEO_HEADER_MODE_JOINED_WITH_1ST_FRAME);
+ v4l2_ctrl_new_std(&inst->ctrl_handler, NULL,
+ V4L2_CID_MPEG_VIDEO_AVERAGE_QP, 0, 51, 1, 0);
+
if (inst->ctrl_handler.error) {
ret = inst->ctrl_handler.error;
v4l2_ctrl_handler_free(&inst->ctrl_handler);
@@ -819,6 +820,7 @@ static int venc_get_one_encoded_frame(struct vpu_inst *inst,
vbuf->field = inst->cap_format.field;
vbuf->flags |= frame->info.pic_type;
vpu_set_buffer_state(vbuf, VPU_BUF_STATE_IDLE);
+ vpu_set_buffer_average_qp(vbuf, frame->info.average_qp);
dev_dbg(inst->dev, "[%d][OUTPUT TS]%32lld\n", inst->id, vbuf->vb2_buf.timestamp);
v4l2_m2m_buf_done(vbuf, VB2_BUF_STATE_DONE);
venc->ready_count++;
diff --git a/drivers/media/platform/amphion/vpu.h b/drivers/media/platform/amphion/vpu.h
index 0246cf0ac3a8..22f0da26ccec 100644
--- a/drivers/media/platform/amphion/vpu.h
+++ b/drivers/media/platform/amphion/vpu.h
@@ -306,6 +306,7 @@ struct vpu_vb2_buffer {
dma_addr_t chroma_v;
unsigned int state;
u32 tag;
+ u32 average_qp;
};
void vpu_writel(struct vpu_dev *vpu, u32 reg, u32 val);
diff --git a/drivers/media/platform/amphion/vpu_defs.h b/drivers/media/platform/amphion/vpu_defs.h
index 7320852668d6..428d988cf2f7 100644
--- a/drivers/media/platform/amphion/vpu_defs.h
+++ b/drivers/media/platform/amphion/vpu_defs.h
@@ -114,6 +114,7 @@ struct vpu_enc_pic_info {
u32 wptr;
u32 crc;
s64 timestamp;
+ u32 average_qp;
};
struct vpu_dec_codec_info {
diff --git a/drivers/media/platform/amphion/vpu_malone.c b/drivers/media/platform/amphion/vpu_malone.c
index d3425de7bccd..4769c053c6c2 100644
--- a/drivers/media/platform/amphion/vpu_malone.c
+++ b/drivers/media/platform/amphion/vpu_malone.c
@@ -207,11 +207,6 @@ struct vpu_malone_dbglog_desc {
u32 reserved;
};
-struct vpu_malone_frame_buffer {
- u32 addr;
- u32 size;
-};
-
struct vpu_malone_udata {
u32 base;
u32 total_size;
diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c
index c88738e8fff7..83db57bc80b7 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.c
+++ b/drivers/media/platform/amphion/vpu_v4l2.c
@@ -63,6 +63,13 @@ unsigned int vpu_get_buffer_state(struct vb2_v4l2_buffer *vbuf)
return vpu_buf->state;
}
+void vpu_set_buffer_average_qp(struct vb2_v4l2_buffer *vbuf, u32 qp)
+{
+ struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf);
+
+ vpu_buf->average_qp = qp;
+}
+
void vpu_v4l2_set_error(struct vpu_inst *inst)
{
vpu_inst_lock(inst);
@@ -539,6 +546,15 @@ static void vpu_vb2_buf_finish(struct vb2_buffer *vb)
struct vpu_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_queue *q = vb->vb2_queue;
+ if (V4L2_TYPE_IS_CAPTURE(vb->type)) {
+ struct vpu_vb2_buffer *vpu_buf = to_vpu_vb2_buffer(vbuf);
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(&inst->ctrl_handler,
+ V4L2_CID_MPEG_VIDEO_AVERAGE_QP);
+
+ if (ctrl)
+ v4l2_ctrl_s_ctrl(ctrl, vpu_buf->average_qp);
+ }
+
if (vbuf->flags & V4L2_BUF_FLAG_LAST)
vpu_notify_eos(inst);
diff --git a/drivers/media/platform/amphion/vpu_v4l2.h b/drivers/media/platform/amphion/vpu_v4l2.h
index 60f43056a7a2..56f2939fa84d 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.h
+++ b/drivers/media/platform/amphion/vpu_v4l2.h
@@ -12,6 +12,7 @@ void vpu_inst_lock(struct vpu_inst *inst);
void vpu_inst_unlock(struct vpu_inst *inst);
void vpu_set_buffer_state(struct vb2_v4l2_buffer *vbuf, unsigned int state);
unsigned int vpu_get_buffer_state(struct vb2_v4l2_buffer *vbuf);
+void vpu_set_buffer_average_qp(struct vb2_v4l2_buffer *vbuf, u32 qp);
int vpu_v4l2_open(struct file *file, struct vpu_inst *inst);
int vpu_v4l2_close(struct file *file);
diff --git a/drivers/media/platform/amphion/vpu_windsor.c b/drivers/media/platform/amphion/vpu_windsor.c
index 5f1101d7cf9e..e7d37aa4b826 100644
--- a/drivers/media/platform/amphion/vpu_windsor.c
+++ b/drivers/media/platform/amphion/vpu_windsor.c
@@ -499,6 +499,7 @@ struct windsor_pic_info {
u32 proc_dacc_rng_wr_cnt;
s32 tv_s;
u32 tv_ns;
+ u32 average_qp;
};
u32 vpu_windsor_get_data_size(void)
@@ -734,6 +735,7 @@ static void vpu_windsor_unpack_pic_info(struct vpu_rpc_event *pkt, void *data)
info->wptr = get_ptr(windsor->str_buff_wptr);
info->crc = windsor->frame_crc;
info->timestamp = timespec64_to_ns(&ts);
+ info->average_qp = windsor->average_qp;
}
static void vpu_windsor_unpack_mem_req(struct vpu_rpc_event *pkt, void *data)
diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c
index 7e0f34bfa5be..d60841c54a80 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-helper.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c
@@ -29,7 +29,13 @@ void wave5_cleanup_instance(struct vpu_instance *inst)
{
int i;
- if (list_is_singular(&inst->list))
+ /*
+ * For Wave515 SRAM memory is allocated at
+ * wave5_vpu_dec_register_device() and freed at
+ * wave5_vpu_dec_unregister_device().
+ */
+ if (list_is_singular(&inst->list) &&
+ inst->dev->product_code != WAVE515_CODE)
wave5_vdi_free_sram(inst->dev);
for (i = 0; i < inst->fbc_buf_count; i++)
diff --git a/drivers/media/platform/chips-media/wave5/wave5-hw.c b/drivers/media/platform/chips-media/wave5/wave5-hw.c
index 2d82791f575e..c89aafabc742 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-hw.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c
@@ -18,18 +18,20 @@
#define QUEUE_REPORT_MASK 0xffff
/* Encoder support fields */
-#define FEATURE_HEVC10BIT_ENC BIT(3)
-#define FEATURE_AVC10BIT_ENC BIT(11)
-#define FEATURE_AVC_ENCODER BIT(1)
-#define FEATURE_HEVC_ENCODER BIT(0)
+#define W521_FEATURE_HEVC10BIT_ENC BIT(3)
+#define W521_FEATURE_AVC10BIT_ENC BIT(11)
+#define W521_FEATURE_AVC_ENCODER BIT(1)
+#define W521_FEATURE_HEVC_ENCODER BIT(0)
/* Decoder support fields */
-#define FEATURE_AVC_DECODER BIT(3)
-#define FEATURE_HEVC_DECODER BIT(2)
+#define W521_FEATURE_AVC_DECODER BIT(3)
+#define W521_FEATURE_HEVC_DECODER BIT(2)
+#define W515_FEATURE_HEVC10BIT_DEC BIT(1)
+#define W515_FEATURE_HEVC_DECODER BIT(0)
-#define FEATURE_BACKBONE BIT(16)
-#define FEATURE_VCORE_BACKBONE BIT(22)
-#define FEATURE_VCPU_BACKBONE BIT(28)
+#define W521_FEATURE_BACKBONE BIT(16)
+#define W521_FEATURE_VCORE_BACKBONE BIT(22)
+#define W521_FEATURE_VCPU_BACKBONE BIT(28)
#define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff)
#define REMAP_CTRL_REGISTER_VALUE(index) ( \
@@ -155,6 +157,8 @@ static int wave5_wait_bus_busy(struct vpu_device *vpu_dev, unsigned int addr)
{
u32 gdi_status_check_value = 0x3f;
+ if (vpu_dev->product_code == WAVE515_CODE)
+ gdi_status_check_value = 0x0738;
if (vpu_dev->product_code == WAVE521C_CODE ||
vpu_dev->product_code == WAVE521_CODE ||
vpu_dev->product_code == WAVE521E1_CODE)
@@ -186,6 +190,8 @@ unsigned int wave5_vpu_get_product_id(struct vpu_device *vpu_dev)
u32 val = vpu_read_reg(vpu_dev, W5_PRODUCT_NUMBER);
switch (val) {
+ case WAVE515_CODE:
+ return PRODUCT_ID_515;
case WAVE521C_CODE:
return PRODUCT_ID_521;
case WAVE521_CODE:
@@ -299,6 +305,27 @@ static int wave5_send_query(struct vpu_device *vpu_dev, struct vpu_instance *ins
return wave5_vpu_firmware_command_queue_error_check(vpu_dev, NULL);
}
+static void setup_wave5_interrupts(struct vpu_device *vpu_dev)
+{
+ u32 reg_val = 0;
+
+ if (vpu_dev->attr.support_encoders) {
+ /* Encoder interrupt */
+ reg_val |= BIT(INT_WAVE5_ENC_SET_PARAM);
+ reg_val |= BIT(INT_WAVE5_ENC_PIC);
+ reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
+ }
+
+ if (vpu_dev->attr.support_decoders) {
+ /* Decoder interrupt */
+ reg_val |= BIT(INT_WAVE5_INIT_SEQ);
+ reg_val |= BIT(INT_WAVE5_DEC_PIC);
+ reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
+ }
+
+ return vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+}
+
static int setup_wave5_properties(struct device *dev)
{
struct vpu_device *vpu_dev = dev_get_drvdata(dev);
@@ -328,17 +355,35 @@ static int setup_wave5_properties(struct device *dev)
hw_config_def1 = vpu_read_reg(vpu_dev, W5_RET_STD_DEF1);
hw_config_feature = vpu_read_reg(vpu_dev, W5_RET_CONF_FEATURE);
- p_attr->support_hevc10bit_enc = FIELD_GET(FEATURE_HEVC10BIT_ENC, hw_config_feature);
- p_attr->support_avc10bit_enc = FIELD_GET(FEATURE_AVC10BIT_ENC, hw_config_feature);
-
- p_attr->support_decoders = FIELD_GET(FEATURE_AVC_DECODER, hw_config_def1) << STD_AVC;
- p_attr->support_decoders |= FIELD_GET(FEATURE_HEVC_DECODER, hw_config_def1) << STD_HEVC;
- p_attr->support_encoders = FIELD_GET(FEATURE_AVC_ENCODER, hw_config_def1) << STD_AVC;
- p_attr->support_encoders |= FIELD_GET(FEATURE_HEVC_ENCODER, hw_config_def1) << STD_HEVC;
-
- p_attr->support_backbone = FIELD_GET(FEATURE_BACKBONE, hw_config_def0);
- p_attr->support_vcpu_backbone = FIELD_GET(FEATURE_VCPU_BACKBONE, hw_config_def0);
- p_attr->support_vcore_backbone = FIELD_GET(FEATURE_VCORE_BACKBONE, hw_config_def0);
+ if (vpu_dev->product_code == WAVE515_CODE) {
+ p_attr->support_hevc10bit_dec = FIELD_GET(W515_FEATURE_HEVC10BIT_DEC,
+ hw_config_feature);
+ p_attr->support_decoders = FIELD_GET(W515_FEATURE_HEVC_DECODER,
+ hw_config_def1) << STD_HEVC;
+ } else {
+ p_attr->support_hevc10bit_enc = FIELD_GET(W521_FEATURE_HEVC10BIT_ENC,
+ hw_config_feature);
+ p_attr->support_avc10bit_enc = FIELD_GET(W521_FEATURE_AVC10BIT_ENC,
+ hw_config_feature);
+
+ p_attr->support_decoders = FIELD_GET(W521_FEATURE_AVC_DECODER,
+ hw_config_def1) << STD_AVC;
+ p_attr->support_decoders |= FIELD_GET(W521_FEATURE_HEVC_DECODER,
+ hw_config_def1) << STD_HEVC;
+ p_attr->support_encoders = FIELD_GET(W521_FEATURE_AVC_ENCODER,
+ hw_config_def1) << STD_AVC;
+ p_attr->support_encoders |= FIELD_GET(W521_FEATURE_HEVC_ENCODER,
+ hw_config_def1) << STD_HEVC;
+
+ p_attr->support_backbone = FIELD_GET(W521_FEATURE_BACKBONE,
+ hw_config_def0);
+ p_attr->support_vcpu_backbone = FIELD_GET(W521_FEATURE_VCPU_BACKBONE,
+ hw_config_def0);
+ p_attr->support_vcore_backbone = FIELD_GET(W521_FEATURE_VCORE_BACKBONE,
+ hw_config_def0);
+ }
+
+ setup_wave5_interrupts(vpu_dev);
return 0;
}
@@ -380,12 +425,18 @@ int wave5_vpu_init(struct device *dev, u8 *fw, size_t size)
common_vb = &vpu_dev->common_mem;
code_base = common_vb->daddr;
+
+ if (vpu_dev->product_code == WAVE515_CODE)
+ code_size = WAVE515_MAX_CODE_BUF_SIZE;
+ else
+ code_size = WAVE521_MAX_CODE_BUF_SIZE;
+
/* ALIGN TO 4KB */
- code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff);
+ code_size &= ~0xfff;
if (code_size < size * 2)
return -EINVAL;
- temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET;
+ temp_base = code_base + code_size;
temp_size = WAVE5_TEMPBUF_SIZE;
ret = wave5_vdi_write_memory(vpu_dev, common_vb, 0, fw, size);
@@ -413,22 +464,15 @@ int wave5_vpu_init(struct device *dev, u8 *fw, size_t size)
/* These register must be reset explicitly */
vpu_write_reg(vpu_dev, W5_HW_OPTION, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
- vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
-
- /* Encoder interrupt */
- reg_val = BIT(INT_WAVE5_ENC_SET_PARAM);
- reg_val |= BIT(INT_WAVE5_ENC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
- /* Decoder interrupt */
- reg_val |= BIT(INT_WAVE5_INIT_SEQ);
- reg_val |= BIT(INT_WAVE5_DEC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
- vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+
+ if (vpu_dev->product_code != WAVE515_CODE) {
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
+ vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
+ }
reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
- if (FIELD_GET(FEATURE_BACKBONE, reg_val)) {
+ if (FIELD_GET(W521_FEATURE_BACKBONE, reg_val)) {
reg_val = ((WAVE5_PROC_AXI_ID << 28) |
(WAVE5_PRP_AXI_ID << 24) |
(WAVE5_FBD_Y_AXI_ID << 20) |
@@ -440,6 +484,24 @@ int wave5_vpu_init(struct device *dev, u8 *fw, size_t size)
wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val);
}
+ if (vpu_dev->product_code == WAVE515_CODE) {
+ dma_addr_t task_buf_base;
+
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_NUM_TASK_BUF, WAVE515_COMMAND_QUEUE_DEPTH);
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_TASK_BUF_SIZE, WAVE515_ONE_TASKBUF_SIZE);
+
+ for (i = 0; i < WAVE515_COMMAND_QUEUE_DEPTH; i++) {
+ task_buf_base = temp_base + temp_size +
+ (i * WAVE515_ONE_TASKBUF_SIZE);
+ vpu_write_reg(vpu_dev,
+ W5_CMD_INIT_ADDR_TASK_BUF0 + (i * 4),
+ task_buf_base);
+ }
+
+ vpu_write_reg(vpu_dev, W515_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr);
+ vpu_write_reg(vpu_dev, W515_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size);
+ }
+
vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU);
vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1);
@@ -480,29 +542,40 @@ int wave5_vpu_build_up_dec_param(struct vpu_instance *inst,
return -EINVAL;
}
- p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE;
+ if (vpu_dev->product == PRODUCT_ID_515)
+ p_dec_info->vb_work.size = WAVE515DEC_WORKBUF_SIZE;
+ else
+ p_dec_info->vb_work.size = WAVE521DEC_WORKBUF_SIZE;
+
ret = wave5_vdi_allocate_dma_memory(inst->dev, &p_dec_info->vb_work);
if (ret)
return ret;
- vpu_write_reg(inst->dev, W5_CMD_DEC_VCORE_INFO, 1);
+ if (inst->dev->product_code != WAVE515_CODE)
+ vpu_write_reg(inst->dev, W5_CMD_DEC_VCORE_INFO, 1);
wave5_vdi_clear_memory(inst->dev, &p_dec_info->vb_work);
vpu_write_reg(inst->dev, W5_ADDR_WORK_BASE, p_dec_info->vb_work.daddr);
vpu_write_reg(inst->dev, W5_WORK_SIZE, p_dec_info->vb_work.size);
- vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr);
- vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size);
+ if (inst->dev->product_code != WAVE515_CODE) {
+ vpu_write_reg(inst->dev, W5_CMD_ADDR_SEC_AXI, vpu_dev->sram_buf.daddr);
+ vpu_write_reg(inst->dev, W5_CMD_SEC_AXI_SIZE, vpu_dev->sram_buf.size);
+ }
vpu_write_reg(inst->dev, W5_CMD_DEC_BS_START_ADDR, p_dec_info->stream_buf_start_addr);
vpu_write_reg(inst->dev, W5_CMD_DEC_BS_SIZE, p_dec_info->stream_buf_size);
/* NOTE: SDMA reads MSB first */
vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, BITSTREAM_ENDIANNESS_BIG_ENDIAN);
- /* This register must be reset explicitly */
- vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0);
- vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1));
+
+ if (inst->dev->product_code != WAVE515_CODE) {
+ /* This register must be reset explicitly */
+ vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0);
+ vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1,
+ WAVE521_COMMAND_QUEUE_DEPTH - 1);
+ }
ret = send_firmware_command(inst, W5_CREATE_INSTANCE, true, NULL, NULL);
if (ret) {
@@ -553,7 +626,7 @@ static u32 get_bitstream_options(struct dec_info *info)
int wave5_vpu_dec_init_seq(struct vpu_instance *inst)
{
struct dec_info *p_dec_info = &inst->codec_info->dec_info;
- u32 cmd_option = INIT_SEQ_NORMAL;
+ u32 bs_option, cmd_option = INIT_SEQ_NORMAL;
u32 reg_val, fail_res;
int ret;
@@ -563,7 +636,13 @@ int wave5_vpu_dec_init_seq(struct vpu_instance *inst)
vpu_write_reg(inst->dev, W5_BS_RD_PTR, p_dec_info->stream_rd_ptr);
vpu_write_reg(inst->dev, W5_BS_WR_PTR, p_dec_info->stream_wr_ptr);
- vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info));
+ bs_option = get_bitstream_options(p_dec_info);
+
+ /* Without RD_PTR_VALID_FLAG Wave515 ignores RD_PTR value */
+ if (inst->dev->product_code == WAVE515_CODE)
+ bs_option |= BSOPTION_RD_PTR_VALID_FLAG;
+
+ vpu_write_reg(inst->dev, W5_BS_OPTION, bs_option);
vpu_write_reg(inst->dev, W5_COMMAND_OPTION, cmd_option);
vpu_write_reg(inst->dev, W5_CMD_DEC_USER_MASK, p_dec_info->user_data_enable);
@@ -629,10 +708,12 @@ static void wave5_get_dec_seq_result(struct vpu_instance *inst, struct dec_initi
info->profile = FIELD_GET(SEQ_PARAM_PROFILE_MASK, reg_val);
}
- info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE);
- info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE);
- p_dec_info->vlc_buf_size = info->vlc_buf_size;
- p_dec_info->param_buf_size = info->param_buf_size;
+ if (inst->dev->product_code != WAVE515_CODE) {
+ info->vlc_buf_size = vpu_read_reg(inst->dev, W5_RET_VLC_BUF_SIZE);
+ info->param_buf_size = vpu_read_reg(inst->dev, W5_RET_PARAM_BUF_SIZE);
+ p_dec_info->vlc_buf_size = info->vlc_buf_size;
+ p_dec_info->param_buf_size = info->param_buf_size;
+ }
}
int wave5_vpu_dec_get_seq_info(struct vpu_instance *inst, struct dec_initial_info *info)
@@ -734,22 +815,27 @@ int wave5_vpu_dec_register_framebuffer(struct vpu_instance *inst, struct frame_b
pic_size = (init_info->pic_width << 16) | (init_info->pic_height);
- vb_buf.size = (p_dec_info->vlc_buf_size * VLC_BUF_NUM) +
- (p_dec_info->param_buf_size * COMMAND_QUEUE_DEPTH);
- vb_buf.daddr = 0;
+ if (inst->dev->product_code != WAVE515_CODE) {
+ vb_buf.size = (p_dec_info->vlc_buf_size * VLC_BUF_NUM) +
+ (p_dec_info->param_buf_size * WAVE521_COMMAND_QUEUE_DEPTH);
+ vb_buf.daddr = 0;
- if (vb_buf.size != p_dec_info->vb_task.size) {
- wave5_vdi_free_dma_memory(inst->dev, &p_dec_info->vb_task);
- ret = wave5_vdi_allocate_dma_memory(inst->dev, &vb_buf);
- if (ret)
- goto free_fbc_c_tbl_buffers;
+ if (vb_buf.size != p_dec_info->vb_task.size) {
+ wave5_vdi_free_dma_memory(inst->dev,
+ &p_dec_info->vb_task);
+ ret = wave5_vdi_allocate_dma_memory(inst->dev,
+ &vb_buf);
+ if (ret)
+ goto free_fbc_c_tbl_buffers;
- p_dec_info->vb_task = vb_buf;
- }
+ p_dec_info->vb_task = vb_buf;
+ }
- vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF,
- p_dec_info->vb_task.daddr);
- vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE, vb_buf.size);
+ vpu_write_reg(inst->dev, W5_CMD_SET_FB_ADDR_TASK_BUF,
+ p_dec_info->vb_task.daddr);
+ vpu_write_reg(inst->dev, W5_CMD_SET_FB_TASK_BUF_SIZE,
+ vb_buf.size);
+ }
} else {
pic_size = (init_info->pic_width << 16) | (init_info->pic_height);
@@ -830,6 +916,43 @@ free_mv_buffers:
return ret;
}
+static u32 wave5_vpu_dec_validate_sec_axi(struct vpu_instance *inst)
+{
+ u32 bitdepth = inst->codec_info->dec_info.initial_info.luma_bitdepth;
+ struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ u32 bit_size = 0, ip_size = 0, lf_size = 0, ret = 0;
+ u32 sram_size = inst->dev->sram_size;
+ u32 width = inst->src_fmt.width;
+
+ if (!sram_size)
+ return 0;
+
+ /*
+ * TODO: calculate bit_size, ip_size, lf_size from width and bitdepth
+ * for Wave521.
+ */
+ if (inst->dev->product_code == WAVE515_CODE) {
+ bit_size = DIV_ROUND_UP(width, 16) * 5 * 8;
+ ip_size = ALIGN(width, 16) * 2 * bitdepth / 8;
+ lf_size = ALIGN(width, 16) * 10 * bitdepth / 8;
+ }
+
+ if (p_dec_info->sec_axi_info.use_bit_enable && sram_size >= bit_size) {
+ ret |= BIT(0);
+ sram_size -= bit_size;
+ }
+
+ if (p_dec_info->sec_axi_info.use_ip_enable && sram_size >= ip_size) {
+ ret |= BIT(9);
+ sram_size -= ip_size;
+ }
+
+ if (p_dec_info->sec_axi_info.use_lf_row_enable && sram_size >= lf_size)
+ ret |= BIT(15);
+
+ return ret;
+}
+
int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res)
{
u32 reg_val;
@@ -842,9 +965,7 @@ int wave5_vpu_decode(struct vpu_instance *inst, u32 *fail_res)
vpu_write_reg(inst->dev, W5_BS_OPTION, get_bitstream_options(p_dec_info));
/* secondary AXI */
- reg_val = p_dec_info->sec_axi_info.use_bit_enable |
- (p_dec_info->sec_axi_info.use_ip_enable << 9) |
- (p_dec_info->sec_axi_info.use_lf_row_enable << 15);
+ reg_val = wave5_vpu_dec_validate_sec_axi(inst);
vpu_write_reg(inst->dev, W5_USE_SEC_AXI, reg_val);
/* set attributes of user buffer */
@@ -992,11 +1113,18 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size)
common_vb = &vpu_dev->common_mem;
code_base = common_vb->daddr;
+
+ if (vpu_dev->product_code == WAVE515_CODE)
+ code_size = WAVE515_MAX_CODE_BUF_SIZE;
+ else
+ code_size = WAVE521_MAX_CODE_BUF_SIZE;
+
/* ALIGN TO 4KB */
- code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff);
+ code_size &= ~0xfff;
if (code_size < size * 2)
return -EINVAL;
- temp_base = common_vb->daddr + WAVE5_TEMPBUF_OFFSET;
+
+ temp_base = code_base + code_size;
temp_size = WAVE5_TEMPBUF_SIZE;
old_code_base = vpu_read_reg(vpu_dev, W5_VPU_REMAP_PADDR);
@@ -1030,22 +1158,15 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size)
/* These register must be reset explicitly */
vpu_write_reg(vpu_dev, W5_HW_OPTION, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
- vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
- /* Encoder interrupt */
- reg_val = BIT(INT_WAVE5_ENC_SET_PARAM);
- reg_val |= BIT(INT_WAVE5_ENC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
- /* Decoder interrupt */
- reg_val |= BIT(INT_WAVE5_INIT_SEQ);
- reg_val |= BIT(INT_WAVE5_DEC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
- vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+ if (vpu_dev->product_code != WAVE515_CODE) {
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
+ vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
+ }
reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
- if (FIELD_GET(FEATURE_BACKBONE, reg_val)) {
+ if (FIELD_GET(W521_FEATURE_BACKBONE, reg_val)) {
reg_val = ((WAVE5_PROC_AXI_ID << 28) |
(WAVE5_PRP_AXI_ID << 24) |
(WAVE5_FBD_Y_AXI_ID << 20) |
@@ -1057,6 +1178,29 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size)
wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val);
}
+ if (vpu_dev->product_code == WAVE515_CODE) {
+ dma_addr_t task_buf_base;
+ u32 i;
+
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_NUM_TASK_BUF,
+ WAVE515_COMMAND_QUEUE_DEPTH);
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_TASK_BUF_SIZE,
+ WAVE515_ONE_TASKBUF_SIZE);
+
+ for (i = 0; i < WAVE515_COMMAND_QUEUE_DEPTH; i++) {
+ task_buf_base = temp_base + temp_size +
+ (i * WAVE515_ONE_TASKBUF_SIZE);
+ vpu_write_reg(vpu_dev,
+ W5_CMD_INIT_ADDR_TASK_BUF0 + (i * 4),
+ task_buf_base);
+ }
+
+ vpu_write_reg(vpu_dev, W515_CMD_ADDR_SEC_AXI,
+ vpu_dev->sram_buf.daddr);
+ vpu_write_reg(vpu_dev, W515_CMD_SEC_AXI_SIZE,
+ vpu_dev->sram_buf.size);
+ }
+
vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
vpu_write_reg(vpu_dev, W5_COMMAND, W5_INIT_VPU);
vpu_write_reg(vpu_dev, W5_VPU_REMAP_CORE_START, 1);
@@ -1080,8 +1224,8 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin
{
u32 reg_val;
struct vpu_buf *common_vb;
- dma_addr_t code_base;
- u32 code_size, reason_code;
+ dma_addr_t code_base, temp_base;
+ u32 code_size, temp_size, reason_code;
struct vpu_device *vpu_dev = dev_get_drvdata(dev);
int ret;
@@ -1111,13 +1255,22 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin
common_vb = &vpu_dev->common_mem;
code_base = common_vb->daddr;
+
+ if (vpu_dev->product_code == WAVE515_CODE)
+ code_size = WAVE515_MAX_CODE_BUF_SIZE;
+ else
+ code_size = WAVE521_MAX_CODE_BUF_SIZE;
+
/* ALIGN TO 4KB */
- code_size = (WAVE5_MAX_CODE_BUF_SIZE & ~0xfff);
+ code_size &= ~0xfff;
if (code_size < size * 2) {
dev_err(dev, "size too small\n");
return -EINVAL;
}
+ temp_base = code_base + code_size;
+ temp_size = WAVE5_TEMPBUF_SIZE;
+
/* Power on without DEBUG mode */
vpu_write_reg(vpu_dev, W5_PO_CONF, 0);
@@ -1130,22 +1283,17 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin
/* These register must be reset explicitly */
vpu_write_reg(vpu_dev, W5_HW_OPTION, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
- wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
- vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
- /* Encoder interrupt */
- reg_val = BIT(INT_WAVE5_ENC_SET_PARAM);
- reg_val |= BIT(INT_WAVE5_ENC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_FULL);
- /* Decoder interrupt */
- reg_val |= BIT(INT_WAVE5_INIT_SEQ);
- reg_val |= BIT(INT_WAVE5_DEC_PIC);
- reg_val |= BIT(INT_WAVE5_BSBUF_EMPTY);
- vpu_write_reg(vpu_dev, W5_VPU_VINT_ENABLE, reg_val);
+ if (vpu_dev->product_code != WAVE515_CODE) {
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_PROC_EXT_ADDR, 0);
+ wave5_fio_writel(vpu_dev, W5_BACKBONE_AXI_PARAM, 0);
+ vpu_write_reg(vpu_dev, W5_SEC_AXI_PARAM, 0);
+ }
+
+ setup_wave5_interrupts(vpu_dev);
reg_val = vpu_read_reg(vpu_dev, W5_VPU_RET_VPU_CONFIG0);
- if (FIELD_GET(FEATURE_BACKBONE, reg_val)) {
+ if (FIELD_GET(W521_FEATURE_BACKBONE, reg_val)) {
reg_val = ((WAVE5_PROC_AXI_ID << 28) |
(WAVE5_PRP_AXI_ID << 24) |
(WAVE5_FBD_Y_AXI_ID << 20) |
@@ -1157,6 +1305,29 @@ static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uin
wave5_fio_writel(vpu_dev, W5_BACKBONE_PROG_AXI_ID, reg_val);
}
+ if (vpu_dev->product_code == WAVE515_CODE) {
+ dma_addr_t task_buf_base;
+ u32 i;
+
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_NUM_TASK_BUF,
+ WAVE515_COMMAND_QUEUE_DEPTH);
+ vpu_write_reg(vpu_dev, W5_CMD_INIT_TASK_BUF_SIZE,
+ WAVE515_ONE_TASKBUF_SIZE);
+
+ for (i = 0; i < WAVE515_COMMAND_QUEUE_DEPTH; i++) {
+ task_buf_base = temp_base + temp_size +
+ (i * WAVE515_ONE_TASKBUF_SIZE);
+ vpu_write_reg(vpu_dev,
+ W5_CMD_INIT_ADDR_TASK_BUF0 + (i * 4),
+ task_buf_base);
+ }
+
+ vpu_write_reg(vpu_dev, W515_CMD_ADDR_SEC_AXI,
+ vpu_dev->sram_buf.daddr);
+ vpu_write_reg(vpu_dev, W515_CMD_SEC_AXI_SIZE,
+ vpu_dev->sram_buf.size);
+ }
+
vpu_write_reg(vpu_dev, W5_VPU_BUSY_STATUS, 1);
vpu_write_reg(vpu_dev, W5_COMMAND, W5_WAKEUP_VPU);
/* Start VPU after settings */
@@ -1401,7 +1572,7 @@ int wave5_vpu_build_up_enc_param(struct device *dev, struct vpu_instance *inst,
reg_val = (open_param->line_buf_int_en << 6) | BITSTREAM_ENDIANNESS_BIG_ENDIAN;
vpu_write_reg(inst->dev, W5_CMD_BS_PARAM, reg_val);
vpu_write_reg(inst->dev, W5_CMD_EXT_ADDR, 0);
- vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, (COMMAND_QUEUE_DEPTH - 1));
+ vpu_write_reg(inst->dev, W5_CMD_NUM_CQ_DEPTH_M1, WAVE521_COMMAND_QUEUE_DEPTH - 1);
/* This register must be reset explicitly */
vpu_write_reg(inst->dev, W5_CMD_ENC_SRC_OPTIONS, 0);
@@ -1855,7 +2026,7 @@ int wave5_vpu_enc_register_framebuffer(struct device *dev, struct vpu_instance *
p_enc_info->vb_sub_sam_buf = vb_sub_sam_buf;
vb_task.size = (p_enc_info->vlc_buf_size * VLC_BUF_NUM) +
- (p_enc_info->param_buf_size * COMMAND_QUEUE_DEPTH);
+ (p_enc_info->param_buf_size * WAVE521_COMMAND_QUEUE_DEPTH);
vb_task.daddr = 0;
if (p_enc_info->vb_task.size == 0) {
ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vb_task);
@@ -1943,6 +2114,31 @@ free_vb_fbc_y_tbl:
return ret;
}
+static u32 wave5_vpu_enc_validate_sec_axi(struct vpu_instance *inst)
+{
+ struct enc_info *p_enc_info = &inst->codec_info->enc_info;
+ u32 rdo_size = 0, lf_size = 0, ret = 0;
+ u32 sram_size = inst->dev->sram_size;
+
+ if (!sram_size)
+ return 0;
+
+ /*
+ * TODO: calculate rdo_size and lf_size from inst->src_fmt.width and
+ * inst->codec_info->enc_info.open_param.wave_param.internal_bit_depth
+ */
+
+ if (p_enc_info->sec_axi_info.use_enc_rdo_enable && sram_size >= rdo_size) {
+ ret |= BIT(11);
+ sram_size -= rdo_size;
+ }
+
+ if (p_enc_info->sec_axi_info.use_enc_lf_enable && sram_size >= lf_size)
+ ret |= BIT(15);
+
+ return ret;
+}
+
int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *fail_res)
{
u32 src_frame_format;
@@ -1964,8 +2160,7 @@ int wave5_vpu_encode(struct vpu_instance *inst, struct enc_param *option, u32 *f
vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_SRC_AXI_SEL, DEFAULT_SRC_AXI);
/* secondary AXI */
- reg_val = (p_enc_info->sec_axi_info.use_enc_rdo_enable << 11) |
- (p_enc_info->sec_axi_info.use_enc_lf_enable << 15);
+ reg_val = wave5_vpu_enc_validate_sec_axi(inst);
vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_USE_SEC_AXI, reg_val);
vpu_write_reg(inst->dev, W5_CMD_ENC_PIC_REPORT_PARAM, 0);
diff --git a/drivers/media/platform/chips-media/wave5/wave5-regdefine.h b/drivers/media/platform/chips-media/wave5/wave5-regdefine.h
index a15c6b2c3d8b..557344754c4c 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-regdefine.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-regdefine.h
@@ -205,6 +205,9 @@ enum query_opt {
#define W5_ADDR_TEMP_BASE (W5_REG_BASE + 0x011C)
#define W5_TEMP_SIZE (W5_REG_BASE + 0x0120)
#define W5_HW_OPTION (W5_REG_BASE + 0x012C)
+#define W5_CMD_INIT_NUM_TASK_BUF (W5_REG_BASE + 0x0134)
+#define W5_CMD_INIT_ADDR_TASK_BUF0 (W5_REG_BASE + 0x0138)
+#define W5_CMD_INIT_TASK_BUF_SIZE (W5_REG_BASE + 0x0178)
#define W5_SEC_AXI_PARAM (W5_REG_BASE + 0x0180)
/************************************************************************/
@@ -216,7 +219,9 @@ enum query_opt {
#define W5_CMD_DEC_BS_SIZE (W5_REG_BASE + 0x0120)
#define W5_CMD_BS_PARAM (W5_REG_BASE + 0x0124)
#define W5_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0130)
+#define W515_CMD_ADDR_SEC_AXI (W5_REG_BASE + 0x0124)
#define W5_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0134)
+#define W515_CMD_SEC_AXI_SIZE (W5_REG_BASE + 0x0128)
#define W5_CMD_EXT_ADDR (W5_REG_BASE + 0x0138)
#define W5_CMD_NUM_CQ_DEPTH_M1 (W5_REG_BASE + 0x013C)
#define W5_CMD_ERR_CONCEAL (W5_REG_BASE + 0x0140)
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vdi.c b/drivers/media/platform/chips-media/wave5/wave5-vdi.c
index 3809f70bc0b4..bb13267ced38 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vdi.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vdi.c
@@ -18,7 +18,11 @@ static int wave5_vdi_allocate_common_memory(struct device *dev)
if (!vpu_dev->common_mem.vaddr) {
int ret;
- vpu_dev->common_mem.size = SIZE_COMMON;
+ if (vpu_dev->product_code == WAVE515_CODE)
+ vpu_dev->common_mem.size = WAVE515_SIZE_COMMON;
+ else
+ vpu_dev->common_mem.size = WAVE521_SIZE_COMMON;
+
ret = wave5_vdi_allocate_dma_memory(vpu_dev, &vpu_dev->common_mem);
if (ret) {
dev_err(dev, "unable to allocate common buffer\n");
@@ -174,16 +178,19 @@ int wave5_vdi_allocate_array(struct vpu_device *vpu_dev, struct vpu_buf *array,
void wave5_vdi_allocate_sram(struct vpu_device *vpu_dev)
{
struct vpu_buf *vb = &vpu_dev->sram_buf;
+ dma_addr_t daddr;
+ void *vaddr;
+ size_t size;
- if (!vpu_dev->sram_pool || !vpu_dev->sram_size)
+ if (!vpu_dev->sram_pool || vb->vaddr)
return;
- if (!vb->vaddr) {
- vb->size = vpu_dev->sram_size;
- vb->vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, vb->size,
- &vb->daddr);
- if (!vb->vaddr)
- vb->size = 0;
+ size = min_t(size_t, vpu_dev->sram_size, gen_pool_avail(vpu_dev->sram_pool));
+ vaddr = gen_pool_dma_alloc(vpu_dev->sram_pool, size, &daddr);
+ if (vaddr) {
+ vb->vaddr = vaddr;
+ vb->daddr = daddr;
+ vb->size = size;
}
dev_dbg(vpu_dev->dev, "%s: sram daddr: %pad, size: %zu, vaddr: 0x%p\n",
@@ -197,9 +204,7 @@ void wave5_vdi_free_sram(struct vpu_device *vpu_dev)
if (!vb->size || !vb->vaddr)
return;
- if (vb->vaddr)
- gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr,
- vb->size);
+ gen_pool_free(vpu_dev->sram_pool, (unsigned long)vb->vaddr, vb->size);
memset(vb, 0, sizeof(*vb));
}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
index c8624c681fa6..0c5c9a8de91f 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
@@ -1055,6 +1055,22 @@ static int wave5_prepare_fb(struct vpu_instance *inst)
int ret, i;
struct v4l2_m2m_buffer *buf, *n;
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
+ u32 bitdepth = inst->codec_info->dec_info.initial_info.luma_bitdepth;
+
+ switch (bitdepth) {
+ case 8:
+ break;
+ case 10:
+ if (inst->std == W_HEVC_DEC &&
+ inst->dev->attr.support_hevc10bit_dec)
+ break;
+
+ fallthrough;
+ default:
+ dev_err(inst->dev->dev, "no support for %d bit depth\n", bitdepth);
+
+ return -EINVAL;
+ }
linear_num = v4l2_m2m_num_dst_bufs_ready(m2m_ctx);
non_linear_num = inst->fbc_buf_count;
@@ -1063,7 +1079,7 @@ static int wave5_prepare_fb(struct vpu_instance *inst)
struct frame_buffer *frame = &inst->frame_buf[i];
struct vpu_buf *vframe = &inst->frame_vbuf[i];
- fb_stride = inst->dst_fmt.width;
+ fb_stride = ALIGN(inst->dst_fmt.width * bitdepth / 8, 32);
fb_height = ALIGN(inst->dst_fmt.height, 32);
luma_size = fb_stride * fb_height;
@@ -1408,22 +1424,10 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count
if (ret)
goto free_bitstream_vbuf;
} else if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
- struct dec_initial_info *initial_info =
- &inst->codec_info->dec_info.initial_info;
-
if (inst->state == VPU_INST_STATE_STOP)
ret = switch_state(inst, VPU_INST_STATE_INIT_SEQ);
if (ret)
goto return_buffers;
-
- if (inst->state == VPU_INST_STATE_INIT_SEQ) {
- if (initial_info->luma_bitdepth != 8) {
- dev_info(inst->dev->dev, "%s: no support for %d bit depth",
- __func__, initial_info->luma_bitdepth);
- ret = -EINVAL;
- goto return_buffers;
- }
- }
}
return ret;
@@ -1864,7 +1868,12 @@ static int wave5_vpu_open_dec(struct file *filp)
goto cleanup_inst;
}
- wave5_vdi_allocate_sram(inst->dev);
+ /*
+ * For Wave515 SRAM memory was already allocated
+ * at wave5_vpu_dec_register_device()
+ */
+ if (inst->dev->product_code != WAVE515_CODE)
+ wave5_vdi_allocate_sram(inst->dev);
ret = mutex_lock_interruptible(&dev->dev_lock);
if (ret)
@@ -1904,6 +1913,13 @@ int wave5_vpu_dec_register_device(struct vpu_device *dev)
struct video_device *vdev_dec;
int ret;
+ /*
+ * Secondary AXI setup for Wave515 is done by INIT_VPU command,
+ * i.e. wave5_vpu_init(), that's why we allocate SRAM memory early.
+ */
+ if (dev->product_code == WAVE515_CODE)
+ wave5_vdi_allocate_sram(dev);
+
vdev_dec = devm_kzalloc(dev->v4l2_dev.dev, sizeof(*vdev_dec), GFP_KERNEL);
if (!vdev_dec)
return -ENOMEM;
@@ -1937,6 +1953,13 @@ int wave5_vpu_dec_register_device(struct vpu_device *dev)
void wave5_vpu_dec_unregister_device(struct vpu_device *dev)
{
+ /*
+ * Here is a freeing pair for Wave515 SRAM memory allocation
+ * happened at wave5_vpu_dec_register_device().
+ */
+ if (dev->product_code == WAVE515_CODE)
+ wave5_vdi_free_sram(dev);
+
video_unregister_device(dev->video_dev_dec);
if (dev->v4l2_m2m_dec_dev)
v4l2_m2m_release(dev->v4l2_m2m_dec_dev);
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
index a45a2f699000..3e35a05c2d8d 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
@@ -1247,7 +1247,7 @@ static int initialize_sequence(struct vpu_instance *inst)
__func__, initial_info.min_frame_buffer_count,
initial_info.min_src_frame_count);
inst->min_src_buf_count = initial_info.min_src_frame_count +
- COMMAND_QUEUE_DEPTH;
+ WAVE521_COMMAND_QUEUE_DEPTH;
ctrl = v4l2_ctrl_find(&inst->v4l2_ctrl_hdl,
V4L2_CID_MIN_BUFFERS_FOR_OUTPUT);
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
index 68a519ac412d..7273254ecb03 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
@@ -10,6 +10,7 @@
#include <linux/clk.h>
#include <linux/firmware.h>
#include <linux/interrupt.h>
+#include <linux/reset.h>
#include "wave5-vpu.h"
#include "wave5-regdefine.h"
#include "wave5-vpuconfig.h"
@@ -24,6 +25,7 @@
struct wave5_match_data {
int flags;
const char *fw_name;
+ u32 sram_size;
};
static int vpu_poll_interval = 5;
@@ -61,7 +63,13 @@ static void wave5_vpu_handle_irq(void *dev_id)
if (irq_reason & BIT(INT_WAVE5_INIT_SEQ) ||
irq_reason & BIT(INT_WAVE5_ENC_SET_PARAM)) {
- if (seq_done & BIT(inst->id)) {
+ if (dev->product_code == WAVE515_CODE &&
+ (cmd_done & BIT(inst->id))) {
+ cmd_done &= ~BIT(inst->id);
+ wave5_vdi_write_register(dev, W5_RET_QUEUE_CMD_DONE_INST,
+ cmd_done);
+ complete(&inst->irq_done);
+ } else if (seq_done & BIT(inst->id)) {
seq_done &= ~BIT(inst->id);
wave5_vdi_write_register(dev, W5_RET_SEQ_DONE_INSTANCE_INFO,
seq_done);
@@ -179,6 +187,16 @@ static int wave5_vpu_probe(struct platform_device *pdev)
dev_set_drvdata(&pdev->dev, dev);
dev->dev = &pdev->dev;
+ dev->resets = devm_reset_control_array_get_optional_exclusive(&pdev->dev);
+ if (IS_ERR(dev->resets)) {
+ return dev_err_probe(&pdev->dev, PTR_ERR(dev->resets),
+ "Failed to get reset control\n");
+ }
+
+ ret = reset_control_deassert(dev->resets);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "Failed to deassert resets\n");
+
ret = devm_clk_bulk_get_all(&pdev->dev, &dev->clks);
/* continue without clock, assume externally managed */
@@ -191,20 +209,15 @@ static int wave5_vpu_probe(struct platform_device *pdev)
ret = clk_bulk_prepare_enable(dev->num_clks, dev->clks);
if (ret) {
dev_err(&pdev->dev, "Enabling clocks, fail: %d\n", ret);
- return ret;
- }
-
- ret = of_property_read_u32(pdev->dev.of_node, "sram-size",
- &dev->sram_size);
- if (ret) {
- dev_warn(&pdev->dev, "sram-size not found\n");
- dev->sram_size = 0;
+ goto err_reset_assert;
}
dev->sram_pool = of_gen_pool_get(pdev->dev.of_node, "sram", 0);
if (!dev->sram_pool)
dev_warn(&pdev->dev, "sram node not found\n");
+ dev->sram_size = match_data->sram_size;
+
dev->product_code = wave5_vdi_read_register(dev, VPU_PRODUCT_CODE_REGISTER);
ret = wave5_vdi_init(&pdev->dev);
if (ret < 0) {
@@ -282,6 +295,8 @@ err_vdi_release:
wave5_vdi_release(&pdev->dev);
err_clk_dis:
clk_bulk_disable_unprepare(dev->num_clks, dev->clks);
+err_reset_assert:
+ reset_control_assert(dev->resets);
return ret;
}
@@ -297,6 +312,7 @@ static void wave5_vpu_remove(struct platform_device *pdev)
mutex_destroy(&dev->dev_lock);
mutex_destroy(&dev->hw_lock);
+ reset_control_assert(dev->resets);
clk_bulk_disable_unprepare(dev->num_clks, dev->clks);
wave5_vpu_enc_unregister_device(dev);
wave5_vpu_dec_unregister_device(dev);
@@ -308,6 +324,7 @@ static void wave5_vpu_remove(struct platform_device *pdev)
static const struct wave5_match_data ti_wave521c_data = {
.flags = WAVE5_IS_ENC | WAVE5_IS_DEC,
.fw_name = "cnm/wave521c_k3_codec_fw.bin",
+ .sram_size = (64 * 1024),
};
static const struct of_device_id wave5_dt_ids[] = {
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
index edc50450ddb8..d2370511faf8 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
@@ -18,6 +18,7 @@
#include "wave5-vdi.h"
enum product_id {
+ PRODUCT_ID_515,
PRODUCT_ID_521,
PRODUCT_ID_511,
PRODUCT_ID_517,
@@ -327,6 +328,7 @@ struct vpu_attr {
u32 support_backbone: 1;
u32 support_avc10bit_enc: 1;
u32 support_hevc10bit_enc: 1;
+ u32 support_hevc10bit_dec: 1;
u32 support_vcore_backbone: 1;
u32 support_vcpu_backbone: 1;
};
@@ -761,6 +763,7 @@ struct vpu_device {
struct kthread_worker *worker;
int vpu_poll_interval;
int num_clks;
+ struct reset_control *resets;
};
struct vpu_instance;
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
index d9751eedb0f9..e4bc2e467cb5 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
@@ -8,6 +8,7 @@
#ifndef _VPU_CONFIG_H_
#define _VPU_CONFIG_H_
+#define WAVE515_CODE 0x5150
#define WAVE517_CODE 0x5170
#define WAVE537_CODE 0x5370
#define WAVE511_CODE 0x5110
@@ -21,12 +22,13 @@
((c) == WAVE517_CODE || (c) == WAVE537_CODE || \
(c) == WAVE511_CODE || (c) == WAVE521_CODE || \
(c) == WAVE521E1_CODE || (c) == WAVE521C_CODE || \
- (c) == WAVE521C_DUAL_CODE); \
+ (c) == WAVE521C_DUAL_CODE) || (c) == WAVE515_CODE; \
})
#define WAVE517_WORKBUF_SIZE (2 * 1024 * 1024)
#define WAVE521ENC_WORKBUF_SIZE (128 * 1024) //HEVC 128K, AVC 40K
#define WAVE521DEC_WORKBUF_SIZE (1784 * 1024)
+#define WAVE515DEC_WORKBUF_SIZE (2 * 1024 * 1024)
#define MAX_NUM_INSTANCE 32
@@ -49,17 +51,21 @@
/************************************************************************/
#define VLC_BUF_NUM (2)
-#define COMMAND_QUEUE_DEPTH (2)
+#define WAVE521_COMMAND_QUEUE_DEPTH (2)
+#define WAVE515_COMMAND_QUEUE_DEPTH (4)
#define W5_REMAP_INDEX0 0
#define W5_REMAP_INDEX1 1
#define W5_REMAP_MAX_SIZE (1024 * 1024)
-#define WAVE5_MAX_CODE_BUF_SIZE (2 * 1024 * 1024)
-#define WAVE5_TEMPBUF_OFFSET WAVE5_MAX_CODE_BUF_SIZE
+#define WAVE521_MAX_CODE_BUF_SIZE (2 * 1024 * 1024)
+#define WAVE515_MAX_CODE_BUF_SIZE (1024 * 1024)
#define WAVE5_TEMPBUF_SIZE (1024 * 1024)
-#define SIZE_COMMON (WAVE5_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE)
+#define WAVE521_SIZE_COMMON (WAVE521_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE)
+#define WAVE515_ONE_TASKBUF_SIZE (8 * 1024 * 1024)
+#define WAVE515_SIZE_COMMON (WAVE515_MAX_CODE_BUF_SIZE + WAVE5_TEMPBUF_SIZE + \
+ WAVE515_COMMAND_QUEUE_DEPTH * WAVE515_ONE_TASKBUF_SIZE)
//=====4. VPU REPORT MEMORY ======================//
diff --git a/drivers/media/platform/chips-media/wave5/wave5.h b/drivers/media/platform/chips-media/wave5/wave5.h
index 063028eccd3b..2a29b9164f97 100644
--- a/drivers/media/platform/chips-media/wave5/wave5.h
+++ b/drivers/media/platform/chips-media/wave5/wave5.h
@@ -22,6 +22,12 @@
*/
#define BSOPTION_ENABLE_EXPLICIT_END BIT(0)
#define BSOPTION_HIGHLIGHT_STREAM_END BIT(1)
+/*
+ * When RD_PTR_VALID_FLAG is 0 Wave515 ignores RD_PTR value and starts to
+ * decode from the access unit end position of the last decoded picture in
+ * bitstream buffer.
+ */
+#define BSOPTION_RD_PTR_VALID_FLAG BIT(31)
/*
* Currently the driver only supports hardware with little endian but for source
diff --git a/drivers/media/platform/imagination/Kconfig b/drivers/media/platform/imagination/Kconfig
new file mode 100644
index 000000000000..7139ae22219b
--- /dev/null
+++ b/drivers/media/platform/imagination/Kconfig
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: GPL-2.0
+config VIDEO_E5010_JPEG_ENC
+ tristate "Imagination E5010 JPEG Encoder Driver"
+ depends on VIDEO_DEV
+ select VIDEOBUF2_DMA_CONTIG
+ select VIDEOBUF2_VMALLOC
+ select V4L2_MEM2MEM_DEV
+ select V4L2_JPEG_HELPER
+ help
+ This is a video4linux2 M2M driver for Imagination E5010 JPEG encoder,
+ which supports JPEG and MJPEG baseline encoding of YUV422 and YUV420
+ semiplanar video formats, with resolution ranging from 64x64 to 8K x 8K
+ pixels. The module will be named as e5010_jpeg_enc.
diff --git a/drivers/media/platform/imagination/Makefile b/drivers/media/platform/imagination/Makefile
new file mode 100644
index 000000000000..d45b85b88575
--- /dev/null
+++ b/drivers/media/platform/imagination/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+e5010_jpeg_enc-objs := e5010-jpeg-enc-hw.o e5010-jpeg-enc.o
+obj-$(CONFIG_VIDEO_E5010_JPEG_ENC) += e5010_jpeg_enc.o
diff --git a/drivers/media/platform/imagination/e5010-core-regs.h b/drivers/media/platform/imagination/e5010-core-regs.h
new file mode 100644
index 000000000000..aaec498fe83f
--- /dev/null
+++ b/drivers/media/platform/imagination/e5010-core-regs.h
@@ -0,0 +1,585 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Imagination E5010 JPEG Encoder driver.
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * Author: David Huang <d-huang@ti.com>
+ * Author: Devarsh Thakkar <devarsht@ti.com>
+ */
+
+#ifndef _E5010_CORE_REGS_H
+#define _E5010_CORE_REGS_H
+
+#define JASPER_CORE_ID_OFFSET (0x0000)
+#define JASPER_CORE_ID_CR_GROUP_ID_MASK (0xFF000000)
+#define JASPER_CORE_ID_CR_GROUP_ID_SHIFT (24)
+#define JASPER_CORE_ID_CR_CORE_ID_MASK (0x00FF0000)
+#define JASPER_CORE_ID_CR_CORE_ID_SHIFT (16)
+#define JASPER_CORE_ID_CR_UNIQUE_NUM_MASK (0x0000FFF8)
+#define JASPER_CORE_ID_CR_UNIQUE_NUM_SHIFT (3)
+#define JASPER_CORE_ID_CR_PELS_PER_CYCLE_MASK (0x00000007)
+#define JASPER_CORE_ID_CR_PELS_PER_CYCLE_SHIFT (0)
+
+#define JASPER_CORE_REV_OFFSET (0x0004)
+#define JASPER_CORE_REV_CR_JASPER_DESIGNER_MASK (0xFF000000)
+#define JASPER_CORE_REV_CR_JASPER_DESIGNER_SHIFT (24)
+#define JASPER_CORE_REV_CR_JASPER_MAJOR_REV_MASK (0x00FF0000)
+#define JASPER_CORE_REV_CR_JASPER_MAJOR_REV_SHIFT (16)
+#define JASPER_CORE_REV_CR_JASPER_MINOR_REV_MASK (0x0000FF00)
+#define JASPER_CORE_REV_CR_JASPER_MINOR_REV_SHIFT (8)
+#define JASPER_CORE_REV_CR_JASPER_MAINT_REV_MASK (0x000000FF)
+#define JASPER_CORE_REV_CR_JASPER_MAINT_REV_SHIFT (0)
+
+#define JASPER_INTERRUPT_MASK_OFFSET (0x0008)
+#define JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_MASK (0x00000002)
+#define JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_SHIFT (1)
+#define JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_MASK (0x00000001)
+#define JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_SHIFT (0)
+
+#define JASPER_INTERRUPT_STATUS_OFFSET (0x000C)
+#define JASPER_INTERRUPT_STATUS_CR_OUTPUT_ADDRESS_ERROR_IRQ_MASK (0x00000002)
+#define JASPER_INTERRUPT_STATUS_CR_OUTPUT_ADDRESS_ERROR_IRQ_SHIFT (1)
+#define JASPER_INTERRUPT_STATUS_CR_PICTURE_DONE_IRQ_MASK (0x00000001)
+#define JASPER_INTERRUPT_STATUS_CR_PICTURE_DONE_IRQ_SHIFT (0)
+
+#define JASPER_INTERRUPT_CLEAR_OFFSET (0x0010)
+#define JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_MASK (0x00000002)
+#define JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_SHIFT (1)
+#define JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_MASK (0x00000001)
+#define JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_SHIFT (0)
+
+#define JASPER_CLK_CONTROL_OFFSET (0x0014)
+#define JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_MASK (0x00000002)
+#define JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_SHIFT (1)
+#define JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_MASK (0x00000001)
+#define JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_SHIFT (0)
+
+#define JASPER_CLK_STATUS_OFFSET (0x0018)
+#define JASPER_CLK_STATUS_CR_JASPER_CLKG_STATUS_MASK (0x00000001)
+#define JASPER_CLK_STATUS_CR_JASPER_CLKG_STATUS_SHIFT (0)
+
+#define JASPER_RESET_OFFSET (0x001C)
+#define JASPER_RESET_CR_SYS_RESET_MASK (0x00000002)
+#define JASPER_RESET_CR_SYS_RESET_SHIFT (1)
+#define JASPER_RESET_CR_CORE_RESET_MASK (0x00000001)
+#define JASPER_RESET_CR_CORE_RESET_SHIFT (0)
+
+#define JASPER_CORE_CTRL_OFFSET (0x0020)
+#define JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_MASK (0x00000001)
+#define JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_SHIFT (0)
+
+#define JASPER_STATUS_OFFSET (0x0024)
+#define JASPER_STATUS_CR_FLUSH_MODE_MASK (0x00000002)
+#define JASPER_STATUS_CR_FLUSH_MODE_SHIFT (1)
+#define JASPER_STATUS_CR_JASPER_BUSY_MASK (0x00000001)
+#define JASPER_STATUS_CR_JASPER_BUSY_SHIFT (0)
+
+#define JASPER_CRC_CLEAR_OFFSET (0x0028)
+#define JASPER_CRC_CLEAR_CR_FRONT_END_CRC_CLEAR_MASK (0x00000001)
+#define JASPER_CRC_CLEAR_CR_FRONT_END_CRC_CLEAR_SHIFT (0)
+#define JASPER_CRC_CLEAR_CR_DCT_CRC_CLEAR_MASK (0x00000002)
+#define JASPER_CRC_CLEAR_CR_DCT_CRC_CLEAR_SHIFT (1)
+#define JASPER_CRC_CLEAR_CR_ZZ_CRC_CLEAR_MASK (0x00000004)
+#define JASPER_CRC_CLEAR_CR_ZZ_CRC_CLEAR_SHIFT (2)
+#define JASPER_CRC_CLEAR_CR_QUANT_CRC_CLEAR_MASK (0x00000008)
+#define JASPER_CRC_CLEAR_CR_QUANT_CRC_CLEAR_SHIFT (3)
+#define JASPER_CRC_CLEAR_CR_ENTROPY_ENCODER_CRC_CLEAR_MASK (0x00000010)
+#define JASPER_CRC_CLEAR_CR_ENTROPY_ENCODER_CRC_CLEAR_SHIFT (4)
+#define JASPER_CRC_CLEAR_CR_PACKING_BUFFER_CRC_CLEAR_MASK (0x00000020)
+#define JASPER_CRC_CLEAR_CR_PACKING_BUFFER_CRC_CLEAR_SHIFT (5)
+
+#define JASPER_INPUT_CTRL0_OFFSET (0x002C)
+#define JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_MASK (0x01000000)
+#define JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_SHIFT (24)
+#define JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_MASK (0x00030000)
+#define JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_SHIFT (16)
+#define JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_MASK (0x00000004)
+#define JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_SHIFT (2)
+
+#define JASPER_INPUT_CTRL1_OFFSET (0x0030)
+#define JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_MASK (0x1FC00000)
+#define JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_SHIFT (22)
+#define JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_MASK (0x00001FC0)
+#define JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_SHIFT (6)
+
+#define JASPER_MMU_CTRL_OFFSET (0x0034)
+#define JASPER_MMU_CTRL_CR_JASPER_TILING_SCHEME_MASK (0x00000002)
+#define JASPER_MMU_CTRL_CR_JASPER_TILING_SCHEME_SHIFT (1)
+#define JASPER_MMU_CTRL_CR_JASPER_TILING_ENABLE_MASK (0x00000001)
+#define JASPER_MMU_CTRL_CR_JASPER_TILING_ENABLE_SHIFT (0)
+
+#define JASPER_IMAGE_SIZE_OFFSET (0x0038)
+#define JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_MASK (0x1FFF0000)
+#define JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_SHIFT (16)
+#define JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_MASK (0x00001FFF)
+#define JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_SHIFT (0)
+
+#define INPUT_LUMA_BASE_OFFSET (0x003C)
+#define INPUT_LUMA_BASE_CR_INPUT_LUMA_BASE_MASK (0xFFFFFFC0)
+#define INPUT_LUMA_BASE_CR_INPUT_LUMA_BASE_SHIFT (6)
+
+#define INPUT_CHROMA_BASE_OFFSET (0x0040)
+#define INPUT_CHROMA_BASE_CR_INPUT_CHROMA_BASE_MASK (0xFFFFFFC0)
+#define INPUT_CHROMA_BASE_CR_INPUT_CHROMA_BASE_SHIFT (6)
+
+#define JASPER_OUTPUT_BASE_OFFSET (0x0044)
+#define JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_MASK (0xFFFFFFFF)
+#define JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_SHIFT (0)
+
+#define JASPER_OUTPUT_SIZE_OFFSET (0x0048)
+#define JASPER_OUTPUT_SIZE_CR_OUTPUT_SIZE_MASK (0xFFFFFFFF)
+#define JASPER_OUTPUT_SIZE_CR_OUTPUT_SIZE_SHIFT (0)
+#define JASPER_OUTPUT_MAX_SIZE_OFFSET (0x004C)
+#define JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_MASK (0xFFFFFFFF)
+#define JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE0_OFFSET (0x0050)
+#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_03_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_03_SHIFT (24)
+#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_02_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_02_SHIFT (16)
+#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_01_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_01_SHIFT (8)
+#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_00_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE0_CR_LUMA_QUANTIZATION_TABLE_00_SHIFT (0)
+#define JASPER_LUMA_QUANTIZATION_TABLE1_OFFSET (0x0054)
+#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_07_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_07_SHIFT (24)
+#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_06_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_06_SHIFT (16)
+#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_05_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_05_SHIFT (8)
+#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_04_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE1_CR_LUMA_QUANTIZATION_TABLE_04_SHIFT (0)
+#define JASPER_LUMA_QUANTIZATION_TABLE2_OFFSET (0x0058)
+#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_13_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_13_SHIFT (24)
+#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_12_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_12_SHIFT (16)
+#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_11_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_11_SHIFT (8)
+#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_10_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE2_CR_LUMA_QUANTIZATION_TABLE_10_SHIFT (0)
+#define JASPER_LUMA_QUANTIZATION_TABLE3_OFFSET (0x005C)
+#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_17_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_17_SHIFT (24)
+#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_16_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_16_SHIFT (16)
+#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_15_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_15_SHIFT (8)
+#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_14_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE3_CR_LUMA_QUANTIZATION_TABLE_14_SHIFT (0)
+#define JASPER_LUMA_QUANTIZATION_TABLE4_OFFSET (0x0060)
+#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_21_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_21_SHIFT (8)
+#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_20_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE4_CR_LUMA_QUANTIZATION_TABLE_20_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE5_OFFSET (0x0064)
+#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_27_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_27_SHIFT (24)
+#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_26_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_26_SHIFT (16)
+#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_25_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_25_SHIFT (8)
+#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_24_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE5_CR_LUMA_QUANTIZATION_TABLE_24_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE6_OFFSET (0x0068)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_33_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_33_SHIFT (24)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_32_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_32_SHIFT (16)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_31_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_31_SHIFT (8)
+#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_30_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE6_CR_LUMA_QUANTIZATION_TABLE_30_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE7_OFFSET (0x006C)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_37_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_37_SHIFT (24)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_36_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_36_SHIFT (16)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_35_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_35_SHIFT (8)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_34_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE7_CR_LUMA_QUANTIZATION_TABLE_34_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE8_OFFSET (0x0070)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_43_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_43_SHIFT (24)
+#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_42_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_42_SHIFT (16)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_41_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_41_SHIFT (8)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_40_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE8_CR_LUMA_QUANTIZATION_TABLE_40_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE9_OFFSET (0x0074)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_47_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_47_SHIFT (24)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_46_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_46_SHIFT (16)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_45_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_45_SHIFT (8)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_44_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE9_CR_LUMA_QUANTIZATION_TABLE_44_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE10_OFFSET (0x0078)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_53_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_53_SHIFT (24)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_52_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_52_SHIFT (16)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_51_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_51_SHIFT (8)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_50_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE10_CR_LUMA_QUANTIZATION_TABLE_50_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE11_OFFSET (0x007C)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_57_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_57_SHIFT (24)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_56_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_56_SHIFT (16)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_55_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_55_SHIFT (8)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_54_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE11_CR_LUMA_QUANTIZATION_TABLE_54_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE12_OFFSET (0x0080)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_63_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_63_SHIFT (24)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_62_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_62_SHIFT (16)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_61_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_61_SHIFT (8)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_60_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE12_CR_LUMA_QUANTIZATION_TABLE_60_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE13_OFFSET (0x0084)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_67_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_67_SHIFT (24)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_66_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_66_SHIFT (16)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_65_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_65_SHIFT (8)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_64_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE13_CR_LUMA_QUANTIZATION_TABLE_64_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE14_OFFSET (0x0088)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_73_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_73_SHIFT (24)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_72_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_72_SHIFT (16)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_71_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_71_SHIFT (8)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_70_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE14_CR_LUMA_QUANTIZATION_TABLE_70_SHIFT (0)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE15_OFFSET (0x008C)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_77_MASK (0xFF000000)
+#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_77_SHIFT (24)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_76_MASK (0x00FF0000)
+#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_76_SHIFT (16)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_75_MASK (0x0000FF00)
+#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_75_SHIFT (8)
+
+#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_74_MASK (0x000000FF)
+#define JASPER_LUMA_QUANTIZATION_TABLE15_CR_LUMA_QUANTIZATION_TABLE_74_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE0_OFFSET (0x0090)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_03_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_03_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_02_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_02_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_01_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_01_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_00_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE0_CR_CHROMA_QUANTIZATION_TABLE_00_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE1_OFFSET (0x0094)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_07_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_07_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_06_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_06_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_05_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_05_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_04_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE1_CR_CHROMA_QUANTIZATION_TABLE_04_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE2_OFFSET (0x0098)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_13_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_13_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_12_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_12_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_11_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_11_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_10_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE2_CR_CHROMA_QUANTIZATION_TABLE_10_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE3_OFFSET (0x009C)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_17_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_17_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_16_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_16_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_15_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_15_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_14_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE3_CR_CHROMA_QUANTIZATION_TABLE_14_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE4_OFFSET (0x00A0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_23_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_23_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_22_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_22_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_21_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_21_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_20_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE4_CR_CHROMA_QUANTIZATION_TABLE_20_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE5_OFFSET (0x00A4)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_27_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_27_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_26_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_26_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_25_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_25_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_24_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE5_CR_CHROMA_QUANTIZATION_TABLE_24_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE6_OFFSET (0x00A8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_33_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_33_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_32_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_32_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_31_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_31_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_30_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE6_CR_CHROMA_QUANTIZATION_TABLE_30_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE7_OFFSET (0x00AC)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_37_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_37_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_36_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_36_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_35_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_35_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_34_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE7_CR_CHROMA_QUANTIZATION_TABLE_34_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE8_OFFSET (0x00B0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_43_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_43_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_42_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_42_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_41_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_41_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_40_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE8_CR_CHROMA_QUANTIZATION_TABLE_40_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE9_OFFSET (0x00B4)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_47_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_47_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_46_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_46_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_45_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_45_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_44_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE9_CR_CHROMA_QUANTIZATION_TABLE_44_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE10_OFFSET (0x00B8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_53_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_53_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_52_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_52_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_51_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_51_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_50_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE10_CR_CHROMA_QUANTIZATION_TABLE_50_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE11_OFFSET (0x00BC)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_57_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_57_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_56_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_56_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_55_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_55_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_54_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE11_CR_CHROMA_QUANTIZATION_TABLE_54_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE12_OFFSET (0x00C0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_63_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_63_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_62_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_62_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_61_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_61_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_60_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE12_CR_CHROMA_QUANTIZATION_TABLE_60_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE13_OFFSET (0x00C4)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_67_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_67_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_66_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_66_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_65_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_65_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_64_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE13_CR_CHROMA_QUANTIZATION_TABLE_64_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE14_OFFSET (0x00C8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_73_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_73_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_72_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_72_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_71_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_71_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_70_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE14_CR_CHROMA_QUANTIZATION_TABLE_70_SHIFT (0)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE15_OFFSET (0x00CC)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_77_MASK (0xFF000000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_77_SHIFT (24)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_76_MASK (0x00FF0000)
+#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_76_SHIFT (16)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_75_MASK (0x0000FF00)
+#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_75_SHIFT (8)
+
+#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_74_MASK (0x000000FF)
+#define JASPER_CHROMA_QUANTIZATION_TABLE15_CR_CHROMA_QUANTIZATION_TABLE_74_SHIFT (0)
+
+#define JASPER_CRC_CTRL_OFFSET (0x00D0)
+#define JASPER_CRC_CTRL_JASPER_CRC_ENABLE_MASK (0x00000001)
+#define JASPER_CRC_CTRL_JASPER_CRC_ENABLE_SHIFT (0)
+
+#define JASPER_FRONT_END_CRC_OFFSET (0x00D4)
+#define JASPER_FRONT_END_CRC_CR_JASPER_FRONT_END_CRC_OUT_MASK (0xFFFFFFFF)
+#define JASPER_FRONT_END_CRC_CR_JASPER_FRONT_END_CRC_OUT_SHIFT (0)
+
+#define JASPER_DCT_CRC_OFFSET (0x00D8)
+#define JASPER_DCT_CRC_CR_JASPER_DCT_CRC_OUT_MASK (0xFFFFFFFF)
+#define JASPER_DCT_CRC_CR_JASPER_DCT_CRC_OUT_SHIFT (0)
+
+#define JASPER_ZZ_CRC_OFFSET (0x00DC)
+#define JASPER_ZZ_CRC_CR_JASPER_ZZ_CRC_OUT_MASK (0xFFFFFFFF)
+#define JASPER_ZZ_CRC_CR_JASPER_ZZ_CRC_OUT_SHIFT (0)
+
+#define JASPER_QUANT_CRC_OFFSET (0x00E0)
+#define JASPER_QUANT_CRC_CR_JASPER_QUANT_CRC_OUT_MASK (0xFFFFFFFF)
+#define JASPER_QUANT_CRC_CR_JASPER_QUANT_CRC_OUT_SHIFT (0)
+
+#define JASPER_ENTROPY_ENCODER_CRC_OFFSET (0x00E4)
+#define JASPER_ENTROPY_ENCODER_CRC_CR_JASPER_ENTROPY_CRC_OUT_MASK (0xFFFFFFFF)
+#define JASPER_ENTROPY_ENCODER_CRC_CR_JASPER_ENTROPY_CRC_OUT_SHIFT (0)
+
+#define JASPER_PACKING_BUFFER_DATA_CRC_OFFSET (0x00E8)
+#define JASPER_PACKING_BUFFER_DATA_CRC_CR_JASPER_PACKING_DATA_CRC_OUT_MASK (0xFFFFFFFF)
+#define JASPER_PACKING_BUFFER_DATA_CRC_CR_JASPER_PACKING_DATA_CRC_OUT_SHIFT (0)
+
+#define JASPER_PACKING_BUFFER_ADDR_CRC_OFFSET (0x00EC)
+#define JASPER_PACKING_BUFFER_ADDR_CRC_CR_JASPER_PACKING_ADDR_OUT_CRC_MASK (0xFFFFFFFF)
+#define JASPER_PACKING_BUFFER_ADDR_CRC_CR_JASPER_PACKING_ADDR_OUT_CRC_SHIFT (0)
+
+#define JASPER_CORE_BYTE_SIZE (0x00F0)
+
+#endif
diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc-hw.c b/drivers/media/platform/imagination/e5010-jpeg-enc-hw.c
new file mode 100644
index 000000000000..56d5941020fa
--- /dev/null
+++ b/drivers/media/platform/imagination/e5010-jpeg-enc-hw.c
@@ -0,0 +1,267 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Imagination E5010 JPEG Encoder driver.
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * Author: David Huang <d-huang@ti.com>
+ * Author: Devarsh Thakkar <devarsht@ti.com>
+ */
+
+#include <linux/io.h>
+#include <linux/iopoll.h>
+#include <linux/dev_printk.h>
+#include "e5010-jpeg-enc-hw.h"
+
+static void write_reg_field(void __iomem *base, unsigned int offset, u32 mask,
+ unsigned int shift, u32 value)
+{
+ u32 reg;
+
+ value <<= shift;
+ if (mask != 0xffffffff) {
+ reg = readl(base + offset);
+ value = (value & mask) | (reg & ~mask);
+ }
+ writel(value, (base + offset));
+}
+
+static int write_reg_field_not_busy(void __iomem *jasper_base, void __iomem *wr_base,
+ unsigned int offset, u32 mask, unsigned int shift,
+ u32 value)
+{
+ int ret;
+ u32 val;
+
+ ret = readl_poll_timeout_atomic(jasper_base + JASPER_STATUS_OFFSET, val,
+ (val & JASPER_STATUS_CR_JASPER_BUSY_MASK) == 0,
+ 2000, 50000);
+ if (ret)
+ return ret;
+
+ write_reg_field(wr_base, offset, mask, shift, value);
+
+ return 0;
+}
+
+void e5010_reset(struct device *dev, void __iomem *core_base, void __iomem *mmu_base)
+{
+ int ret = 0;
+ u32 val;
+
+ write_reg_field(core_base, JASPER_RESET_OFFSET,
+ JASPER_RESET_CR_CORE_RESET_MASK,
+ JASPER_RESET_CR_CORE_RESET_SHIFT, 1);
+
+ write_reg_field(mmu_base, MMU_MMU_CONTROL1_OFFSET,
+ MMU_MMU_CONTROL1_MMU_SOFT_RESET_MASK,
+ MMU_MMU_CONTROL1_MMU_SOFT_RESET_SHIFT, 1);
+
+ ret = readl_poll_timeout_atomic(mmu_base + MMU_MMU_CONTROL1_OFFSET, val,
+ (val & MMU_MMU_CONTROL1_MMU_SOFT_RESET_MASK) == 0,
+ 2000, 50000);
+ if (ret)
+ dev_warn(dev, "MMU soft reset timed out, forcing system soft reset\n");
+
+ write_reg_field(core_base, JASPER_RESET_OFFSET,
+ JASPER_RESET_CR_SYS_RESET_MASK,
+ JASPER_RESET_CR_SYS_RESET_SHIFT, 1);
+}
+
+void e5010_hw_bypass_mmu(void __iomem *mmu_base, u32 enable)
+{
+ /* Bypass MMU */
+ write_reg_field(mmu_base,
+ MMU_MMU_ADDRESS_CONTROL_OFFSET,
+ MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_MASK,
+ MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_SHIFT,
+ enable);
+}
+
+int e5010_hw_enable_output_address_error_irq(void __iomem *core_base, u32 enable)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_INTERRUPT_MASK_OFFSET,
+ JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_MASK,
+ JASPER_INTERRUPT_MASK_CR_OUTPUT_ADDRESS_ERROR_ENABLE_SHIFT,
+ enable);
+}
+
+bool e5010_hw_pic_done_irq(void __iomem *core_base)
+{
+ u32 reg;
+
+ reg = readl(core_base + JASPER_INTERRUPT_STATUS_OFFSET);
+ return reg & JASPER_INTERRUPT_STATUS_CR_PICTURE_DONE_IRQ_MASK;
+}
+
+bool e5010_hw_output_address_irq(void __iomem *core_base)
+{
+ u32 reg;
+
+ reg = readl(core_base + JASPER_INTERRUPT_STATUS_OFFSET);
+ return reg & JASPER_INTERRUPT_STATUS_CR_OUTPUT_ADDRESS_ERROR_IRQ_MASK;
+}
+
+int e5010_hw_enable_picture_done_irq(void __iomem *core_base, u32 enable)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_INTERRUPT_MASK_OFFSET,
+ JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_MASK,
+ JASPER_INTERRUPT_MASK_CR_PICTURE_DONE_ENABLE_SHIFT,
+ enable);
+}
+
+int e5010_hw_enable_auto_clock_gating(void __iomem *core_base, u32 enable)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_CLK_CONTROL_OFFSET,
+ JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_MASK,
+ JASPER_CLK_CONTROL_CR_JASPER_AUTO_CLKG_ENABLE_SHIFT,
+ enable);
+}
+
+int e5010_hw_enable_manual_clock_gating(void __iomem *core_base, u32 enable)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_CLK_CONTROL_OFFSET,
+ JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_MASK,
+ JASPER_CLK_CONTROL_CR_JASPER_MAN_CLKG_ENABLE_SHIFT, 0);
+}
+
+int e5010_hw_enable_crc_check(void __iomem *core_base, u32 enable)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_CRC_CTRL_OFFSET,
+ JASPER_CRC_CTRL_JASPER_CRC_ENABLE_MASK,
+ JASPER_CRC_CTRL_JASPER_CRC_ENABLE_SHIFT, enable);
+}
+
+int e5010_hw_set_input_source_to_memory(void __iomem *core_base, u32 set)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_INPUT_CTRL0_OFFSET,
+ JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_MASK,
+ JASPER_INPUT_CTRL0_CR_INPUT_SOURCE_SHIFT, set);
+}
+
+int e5010_hw_set_input_luma_addr(void __iomem *core_base, u32 val)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ INPUT_LUMA_BASE_OFFSET,
+ INPUT_LUMA_BASE_CR_INPUT_LUMA_BASE_MASK, 0, val);
+}
+
+int e5010_hw_set_input_chroma_addr(void __iomem *core_base, u32 val)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ INPUT_CHROMA_BASE_OFFSET,
+ INPUT_CHROMA_BASE_CR_INPUT_CHROMA_BASE_MASK, 0, val);
+}
+
+int e5010_hw_set_output_base_addr(void __iomem *core_base, u32 val)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_OUTPUT_BASE_OFFSET,
+ JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_MASK,
+ JASPER_OUTPUT_BASE_CR_OUTPUT_BASE_SHIFT, val);
+}
+
+int e5010_hw_set_horizontal_size(void __iomem *core_base, u32 val)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_IMAGE_SIZE_OFFSET,
+ JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_MASK,
+ JASPER_IMAGE_SIZE_CR_IMAGE_HORIZONTAL_SIZE_SHIFT,
+ val);
+}
+
+int e5010_hw_set_vertical_size(void __iomem *core_base, u32 val)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_IMAGE_SIZE_OFFSET,
+ JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_MASK,
+ JASPER_IMAGE_SIZE_CR_IMAGE_VERTICAL_SIZE_SHIFT,
+ val);
+}
+
+int e5010_hw_set_luma_stride(void __iomem *core_base, u32 bytesperline)
+{
+ u32 val = bytesperline / 64;
+
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_INPUT_CTRL1_OFFSET,
+ JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_MASK,
+ JASPER_INPUT_CTRL1_CR_INPUT_LUMA_STRIDE_SHIFT,
+ val);
+}
+
+int e5010_hw_set_chroma_stride(void __iomem *core_base, u32 bytesperline)
+{
+ u32 val = bytesperline / 64;
+
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_INPUT_CTRL1_OFFSET,
+ JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_MASK,
+ JASPER_INPUT_CTRL1_CR_INPUT_CHROMA_STRIDE_SHIFT,
+ val);
+}
+
+int e5010_hw_set_input_subsampling(void __iomem *core_base, u32 val)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_INPUT_CTRL0_OFFSET,
+ JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_MASK,
+ JASPER_INPUT_CTRL0_CR_INPUT_SUBSAMPLING_SHIFT,
+ val);
+}
+
+int e5010_hw_set_chroma_order(void __iomem *core_base, u32 val)
+{
+ return write_reg_field_not_busy(core_base, core_base,
+ JASPER_INPUT_CTRL0_OFFSET,
+ JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_MASK,
+ JASPER_INPUT_CTRL0_CR_INPUT_CHROMA_ORDER_SHIFT,
+ val);
+}
+
+void e5010_hw_set_output_max_size(void __iomem *core_base, u32 val)
+{
+ write_reg_field(core_base, JASPER_OUTPUT_MAX_SIZE_OFFSET,
+ JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_MASK,
+ JASPER_OUTPUT_MAX_SIZE_CR_OUTPUT_MAX_SIZE_SHIFT,
+ val);
+}
+
+int e5010_hw_set_qpvalue(void __iomem *core_base, u32 offset, u32 val)
+{
+ return write_reg_field_not_busy(core_base, core_base, offset, 0xffffffff, 0, val);
+}
+
+void e5010_hw_clear_output_error(void __iomem *core_base, u32 clear)
+{
+ /* Make sure interrupts are clear */
+ write_reg_field(core_base, JASPER_INTERRUPT_CLEAR_OFFSET,
+ JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_MASK,
+ JASPER_INTERRUPT_CLEAR_CR_OUTPUT_ERROR_CLEAR_SHIFT, clear);
+}
+
+void e5010_hw_clear_picture_done(void __iomem *core_base, u32 clear)
+{
+ write_reg_field(core_base,
+ JASPER_INTERRUPT_CLEAR_OFFSET,
+ JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_MASK,
+ JASPER_INTERRUPT_CLEAR_CR_PICTURE_DONE_CLEAR_SHIFT, clear);
+}
+
+int e5010_hw_get_output_size(void __iomem *core_base)
+{
+ return readl(core_base + JASPER_OUTPUT_SIZE_OFFSET);
+}
+
+void e5010_hw_encode_start(void __iomem *core_base, u32 start)
+{
+ write_reg_field(core_base, JASPER_CORE_CTRL_OFFSET,
+ JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_MASK,
+ JASPER_CORE_CTRL_CR_JASPER_ENCODE_START_SHIFT, start);
+}
diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc-hw.h b/drivers/media/platform/imagination/e5010-jpeg-enc-hw.h
new file mode 100644
index 000000000000..781d353c3226
--- /dev/null
+++ b/drivers/media/platform/imagination/e5010-jpeg-enc-hw.h
@@ -0,0 +1,42 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Imagination E5010 JPEG Encoder driver.
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * Author: David Huang <d-huang@ti.com>
+ * Author: Devarsh Thakkar <devarsht@ti.com>
+ */
+
+#ifndef _E5010_JPEG_ENC_HW_H
+#define _E5010_JPEG_ENC_HW_H
+
+#include "e5010-core-regs.h"
+#include "e5010-mmu-regs.h"
+
+int e5010_hw_enable_output_address_error_irq(void __iomem *core_offset, u32 enable);
+int e5010_hw_enable_picture_done_irq(void __iomem *core_offset, u32 enable);
+int e5010_hw_enable_auto_clock_gating(void __iomem *core_offset, u32 enable);
+int e5010_hw_enable_manual_clock_gating(void __iomem *core_offset, u32 enable);
+int e5010_hw_enable_crc_check(void __iomem *core_offset, u32 enable);
+int e5010_hw_set_input_source_to_memory(void __iomem *core_offset, u32 set);
+int e5010_hw_set_input_luma_addr(void __iomem *core_offset, u32 val);
+int e5010_hw_set_input_chroma_addr(void __iomem *core_offset, u32 val);
+int e5010_hw_set_output_base_addr(void __iomem *core_offset, u32 val);
+int e5010_hw_get_output_size(void __iomem *core_offset);
+int e5010_hw_set_horizontal_size(void __iomem *core_offset, u32 val);
+int e5010_hw_set_vertical_size(void __iomem *core_offset, u32 val);
+int e5010_hw_set_luma_stride(void __iomem *core_offset, u32 bytesperline);
+int e5010_hw_set_chroma_stride(void __iomem *core_offset, u32 bytesperline);
+int e5010_hw_set_input_subsampling(void __iomem *core_offset, u32 val);
+int e5010_hw_set_chroma_order(void __iomem *core_offset, u32 val);
+int e5010_hw_set_qpvalue(void __iomem *core_offset, u32 offset, u32 value);
+void e5010_reset(struct device *dev, void __iomem *core_offset, void __iomem *mmu_offset);
+void e5010_hw_set_output_max_size(void __iomem *core_offset, u32 val);
+void e5010_hw_clear_picture_done(void __iomem *core_offset, u32 clear);
+void e5010_hw_encode_start(void __iomem *core_offset, u32 start);
+void e5010_hw_clear_output_error(void __iomem *core_offset, u32 clear);
+void e5010_hw_bypass_mmu(void __iomem *mmu_base, u32 enable);
+bool e5010_hw_pic_done_irq(void __iomem *core_base);
+bool e5010_hw_output_address_irq(void __iomem *core_base);
+#endif
diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010-jpeg-enc.c
new file mode 100644
index 000000000000..187f2d8abfbb
--- /dev/null
+++ b/drivers/media/platform/imagination/e5010-jpeg-enc.c
@@ -0,0 +1,1632 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Imagination E5010 JPEG Encoder driver.
+ *
+ * TODO: Add MMU and memory tiling support
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * Author: David Huang <d-huang@ti.com>
+ * Author: Devarsh Thakkar <devarsht@ti.com>
+ */
+
+#include <linux/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/ioctl.h>
+#include <linux/module.h>
+#include <linux/of_device.h>
+#include <linux/pm_runtime.h>
+#include <media/jpeg.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-jpeg.h>
+#include <media/v4l2-rect.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-v4l2.h>
+#include "e5010-jpeg-enc.h"
+#include "e5010-jpeg-enc-hw.h"
+
+/* forward declarations */
+static const struct of_device_id e5010_of_match[];
+
+static const struct v4l2_file_operations e5010_fops;
+
+static const struct v4l2_ioctl_ops e5010_ioctl_ops;
+
+static const struct vb2_ops e5010_video_ops;
+
+static const struct v4l2_m2m_ops e5010_m2m_ops;
+
+static struct e5010_fmt e5010_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .num_planes = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ .chroma_order = CHROMA_ORDER_CB_CR,
+ .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,
+ MIN_DIMENSION, MAX_DIMENSION, 8 },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .num_planes = 2,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ .chroma_order = CHROMA_ORDER_CB_CR,
+ .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,
+ MIN_DIMENSION, MAX_DIMENSION, 8 },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .num_planes = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ .chroma_order = CHROMA_ORDER_CR_CB,
+ .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,
+ MIN_DIMENSION, MAX_DIMENSION, 8 },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .num_planes = 2,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420,
+ .chroma_order = CHROMA_ORDER_CR_CB,
+ .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,
+ MIN_DIMENSION, MAX_DIMENSION, 8 },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .num_planes = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+ .chroma_order = CHROMA_ORDER_CB_CR,
+ .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,
+ MIN_DIMENSION, MAX_DIMENSION, 8 },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV16M,
+ .num_planes = 2,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+ .chroma_order = CHROMA_ORDER_CB_CR,
+ .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,
+ MIN_DIMENSION, MAX_DIMENSION, 8 },
+
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .num_planes = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+ .chroma_order = CHROMA_ORDER_CR_CB,
+ .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,
+ MIN_DIMENSION, MAX_DIMENSION, 8 },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV61M,
+ .num_planes = 2,
+ .type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422,
+ .chroma_order = CHROMA_ORDER_CR_CB,
+ .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 64,
+ MIN_DIMENSION, MAX_DIMENSION, 8 },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .num_planes = 1,
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .subsampling = 0,
+ .chroma_order = 0,
+ .frmsize = { MIN_DIMENSION, MAX_DIMENSION, 16,
+ MIN_DIMENSION, MAX_DIMENSION, 8 },
+ },
+};
+
+static unsigned int debug;
+module_param(debug, uint, 0644);
+MODULE_PARM_DESC(debug, "debug level");
+
+#define dprintk(dev, lvl, fmt, arg...) \
+ v4l2_dbg(lvl, debug, &(dev)->v4l2_dev, "%s: " fmt, __func__, ## arg)
+
+static const struct v4l2_event e5010_eos_event = {
+ .type = V4L2_EVENT_EOS
+};
+
+static const char *type_name(enum v4l2_buf_type type)
+{
+ switch (type) {
+ case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
+ return "Output";
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
+ return "Capture";
+ default:
+ return "Invalid";
+ }
+}
+
+static struct e5010_q_data *get_queue(struct e5010_context *ctx, enum v4l2_buf_type type)
+{
+ return (type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? &ctx->out_queue : &ctx->cap_queue;
+}
+
+static void calculate_qp_tables(struct e5010_context *ctx)
+{
+ long long luminosity, contrast;
+ int quality, i;
+
+ quality = 50 - ctx->quality;
+
+ luminosity = LUMINOSITY * quality / 50;
+ contrast = CONTRAST * quality / 50;
+
+ if (quality > 0) {
+ luminosity *= INCREASE;
+ contrast *= INCREASE;
+ }
+
+ for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++) {
+ long long delta = v4l2_jpeg_ref_table_chroma_qt[i] * contrast + luminosity;
+ int val = (int)(v4l2_jpeg_ref_table_chroma_qt[i] + delta);
+
+ clamp(val, 1, 255);
+ ctx->chroma_qp[i] = quality == -50 ? 1 : val;
+
+ delta = v4l2_jpeg_ref_table_luma_qt[i] * contrast + luminosity;
+ val = (int)(v4l2_jpeg_ref_table_luma_qt[i] + delta);
+ clamp(val, 1, 255);
+ ctx->luma_qp[i] = quality == -50 ? 1 : val;
+ }
+
+ ctx->update_qp = true;
+}
+
+static int update_qp_tables(struct e5010_context *ctx)
+{
+ struct e5010_dev *e5010 = ctx->e5010;
+ int i, ret = 0;
+ u32 lvalue, cvalue;
+
+ lvalue = 0;
+ cvalue = 0;
+
+ for (i = 0; i < QP_TABLE_SIZE; i++) {
+ lvalue |= ctx->luma_qp[i] << (8 * (i % 4));
+ cvalue |= ctx->chroma_qp[i] << (8 * (i % 4));
+ if (i % 4 == 3) {
+ ret |= e5010_hw_set_qpvalue(e5010->core_base,
+ JASPER_LUMA_QUANTIZATION_TABLE0_OFFSET
+ + QP_TABLE_FIELD_OFFSET * ((i - 3) / 4),
+ lvalue);
+ ret |= e5010_hw_set_qpvalue(e5010->core_base,
+ JASPER_CHROMA_QUANTIZATION_TABLE0_OFFSET
+ + QP_TABLE_FIELD_OFFSET * ((i - 3) / 4),
+ cvalue);
+ lvalue = 0;
+ cvalue = 0;
+ }
+ }
+
+ return ret;
+}
+
+static int e5010_set_input_subsampling(void __iomem *core_base, int subsampling)
+{
+ switch (subsampling) {
+ case V4L2_JPEG_CHROMA_SUBSAMPLING_420:
+ return e5010_hw_set_input_subsampling(core_base, SUBSAMPLING_420);
+ case V4L2_JPEG_CHROMA_SUBSAMPLING_422:
+ return e5010_hw_set_input_subsampling(core_base, SUBSAMPLING_422);
+ default:
+ return -EINVAL;
+ };
+}
+
+static int e5010_querycap(struct file *file, void *priv, struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, E5010_MODULE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, E5010_MODULE_NAME, sizeof(cap->card));
+
+ return 0;
+}
+
+static struct e5010_fmt *find_format(struct v4l2_format *f)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(e5010_formats); ++i) {
+ if (e5010_formats[i].fourcc == f->fmt.pix_mp.pixelformat &&
+ e5010_formats[i].type == f->type)
+ return &e5010_formats[i];
+ }
+
+ return NULL;
+}
+
+static int e5010_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f)
+{
+ int i, index = 0;
+ struct e5010_fmt *fmt = NULL;
+ struct e5010_context *ctx = file->private_data;
+
+ if (!V4L2_TYPE_IS_MULTIPLANAR(f->type)) {
+ v4l2_err(&ctx->e5010->v4l2_dev, "ENUMFMT with Invalid type: %d\n", f->type);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(e5010_formats); ++i) {
+ if (e5010_formats[i].type == f->type) {
+ if (index == f->index) {
+ fmt = &e5010_formats[i];
+ break;
+ }
+ index++;
+ }
+ }
+
+ if (!fmt)
+ return -EINVAL;
+
+ f->pixelformat = fmt->fourcc;
+ return 0;
+}
+
+static int e5010_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct e5010_context *ctx = file->private_data;
+ struct e5010_q_data *queue;
+ int i;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt;
+
+ queue = get_queue(ctx, f->type);
+
+ pix_mp->flags = 0;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->pixelformat = queue->fmt->fourcc;
+ pix_mp->width = queue->width_adjusted;
+ pix_mp->height = queue->height_adjusted;
+ pix_mp->num_planes = queue->fmt->num_planes;
+
+ if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+ if (!pix_mp->colorspace)
+ pix_mp->colorspace = V4L2_COLORSPACE_SRGB;
+
+ for (i = 0; i < queue->fmt->num_planes; i++) {
+ plane_fmt[i].sizeimage = queue->sizeimage[i];
+ plane_fmt[i].bytesperline = queue->bytesperline[i];
+ }
+
+ } else {
+ pix_mp->colorspace = V4L2_COLORSPACE_JPEG;
+ plane_fmt[0].bytesperline = 0;
+ plane_fmt[0].sizeimage = queue->sizeimage[0];
+ }
+ pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT;
+
+ return 0;
+}
+
+static int e5010_jpeg_try_fmt(struct v4l2_format *f, struct e5010_context *ctx)
+{
+ struct e5010_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt;
+
+ fmt = find_format(f);
+ if (!fmt) {
+ if (V4L2_TYPE_IS_OUTPUT(f->type))
+ pix_mp->pixelformat = V4L2_PIX_FMT_NV12;
+ else
+ pix_mp->pixelformat = V4L2_PIX_FMT_JPEG;
+ fmt = find_format(f);
+ if (!fmt)
+ return -EINVAL;
+ }
+
+ if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+ if (!pix_mp->colorspace)
+ pix_mp->colorspace = V4L2_COLORSPACE_JPEG;
+ if (!pix_mp->ycbcr_enc)
+ pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ if (!pix_mp->quantization)
+ pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT;
+ if (!pix_mp->xfer_func)
+ pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+ v4l2_apply_frmsize_constraints(&pix_mp->width,
+ &pix_mp->height,
+ &fmt->frmsize);
+
+ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
+ pix_mp->width, pix_mp->height);
+
+ } else {
+ pix_mp->colorspace = V4L2_COLORSPACE_JPEG;
+ pix_mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ pix_mp->quantization = V4L2_QUANTIZATION_DEFAULT;
+ pix_mp->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ v4l2_apply_frmsize_constraints(&pix_mp->width,
+ &pix_mp->height,
+ &fmt->frmsize);
+ plane_fmt[0].sizeimage = pix_mp->width * pix_mp->height * JPEG_MAX_BYTES_PER_PIXEL;
+ plane_fmt[0].sizeimage += HEADER_SIZE;
+ plane_fmt[0].bytesperline = 0;
+ pix_mp->pixelformat = fmt->fourcc;
+ pix_mp->num_planes = fmt->num_planes;
+ }
+ pix_mp->flags = 0;
+ pix_mp->field = V4L2_FIELD_NONE;
+
+ dprintk(ctx->e5010, 2,
+ "ctx: 0x%p: format type %s:, wxh: %dx%d (plane0 : %d bytes, plane1 : %d bytes),fmt: %c%c%c%c\n",
+ ctx, type_name(f->type), pix_mp->width, pix_mp->height,
+ plane_fmt[0].sizeimage, plane_fmt[1].sizeimage,
+ (fmt->fourcc & 0xff),
+ (fmt->fourcc >> 8) & 0xff,
+ (fmt->fourcc >> 16) & 0xff,
+ (fmt->fourcc >> 24) & 0xff);
+
+ return 0;
+}
+
+static int e5010_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct e5010_context *ctx = file->private_data;
+
+ return e5010_jpeg_try_fmt(f, ctx);
+}
+
+static int e5010_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct e5010_context *ctx = file->private_data;
+ struct vb2_queue *vq;
+ int ret = 0, i = 0;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt;
+ struct e5010_q_data *queue;
+ struct e5010_fmt *fmt;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&ctx->e5010->v4l2_dev, "queue busy\n");
+ return -EBUSY;
+ }
+
+ ret = e5010_jpeg_try_fmt(f, ctx);
+ if (ret)
+ return ret;
+
+ fmt = find_format(f);
+ queue = get_queue(ctx, f->type);
+
+ queue->fmt = fmt;
+ queue->width = pix_mp->width;
+ queue->height = pix_mp->height;
+
+ if (V4L2_TYPE_IS_OUTPUT(f->type)) {
+ for (i = 0; i < fmt->num_planes; i++) {
+ queue->bytesperline[i] = plane_fmt[i].bytesperline;
+ queue->sizeimage[i] = plane_fmt[i].sizeimage;
+ }
+ queue->crop.left = 0;
+ queue->crop.top = 0;
+ queue->crop.width = queue->width;
+ queue->crop.height = queue->height;
+ } else {
+ queue->sizeimage[0] = plane_fmt[0].sizeimage;
+ queue->sizeimage[1] = 0;
+ queue->bytesperline[0] = 0;
+ queue->bytesperline[1] = 0;
+ }
+
+ return 0;
+}
+
+static int e5010_enum_framesizes(struct file *file, void *priv, struct v4l2_frmsizeenum *fsize)
+{
+ struct v4l2_format f;
+ struct e5010_fmt *fmt;
+
+ if (fsize->index != 0)
+ return -EINVAL;
+
+ f.fmt.pix_mp.pixelformat = fsize->pixel_format;
+ if (f.fmt.pix_mp.pixelformat == V4L2_PIX_FMT_JPEG)
+ f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ else
+ f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+
+ fmt = find_format(&f);
+ if (!fmt)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise = fmt->frmsize;
+ fsize->reserved[0] = 0;
+ fsize->reserved[1] = 0;
+
+ return 0;
+}
+
+static int e5010_g_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct e5010_context *ctx = file->private_data;
+ struct e5010_q_data *queue;
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = queue->width;
+ s->r.height = queue->height;
+ break;
+ case V4L2_SEL_TGT_CROP:
+ memcpy(&s->r, &queue->crop, sizeof(s->r));
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int e5010_s_selection(struct file *file, void *fh, struct v4l2_selection *s)
+{
+ struct e5010_context *ctx = file->private_data;
+ struct e5010_q_data *queue;
+ struct vb2_queue *vq;
+ struct v4l2_rect base_rect;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, s->type);
+ if (!vq)
+ return -EINVAL;
+
+ if (vb2_is_streaming(vq))
+ return -EBUSY;
+
+ if (s->target != V4L2_SEL_TGT_CROP ||
+ s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
+ base_rect.top = 0;
+ base_rect.left = 0;
+ base_rect.width = queue->width;
+ base_rect.height = queue->height;
+
+ switch (s->flags) {
+ case 0:
+ s->r.width = round_down(s->r.width, queue->fmt->frmsize.step_width);
+ s->r.height = round_down(s->r.height, queue->fmt->frmsize.step_height);
+ s->r.left = round_down(s->r.left, queue->fmt->frmsize.step_width);
+ s->r.top = round_down(s->r.top, 2);
+
+ if (s->r.left + s->r.width > queue->width)
+ s->r.width = round_down(s->r.width + s->r.left - queue->width,
+ queue->fmt->frmsize.step_width);
+ if (s->r.top + s->r.height > queue->height)
+ s->r.top = round_down(s->r.top + s->r.height - queue->height, 2);
+ break;
+ case V4L2_SEL_FLAG_GE:
+ s->r.width = round_up(s->r.width, queue->fmt->frmsize.step_width);
+ s->r.height = round_up(s->r.height, queue->fmt->frmsize.step_height);
+ s->r.left = round_up(s->r.left, queue->fmt->frmsize.step_width);
+ s->r.top = round_up(s->r.top, 2);
+ break;
+ case V4L2_SEL_FLAG_LE:
+ s->r.width = round_down(s->r.width, queue->fmt->frmsize.step_width);
+ s->r.height = round_down(s->r.height, queue->fmt->frmsize.step_height);
+ s->r.left = round_down(s->r.left, queue->fmt->frmsize.step_width);
+ s->r.top = round_down(s->r.top, 2);
+ break;
+ case V4L2_SEL_FLAG_LE | V4L2_SEL_FLAG_GE:
+ if (!IS_ALIGNED(s->r.width, queue->fmt->frmsize.step_width) ||
+ !IS_ALIGNED(s->r.height, queue->fmt->frmsize.step_height) ||
+ !IS_ALIGNED(s->r.left, queue->fmt->frmsize.step_width) ||
+ !IS_ALIGNED(s->r.top, 2))
+ return -ERANGE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!v4l2_rect_enclosed(&s->r, &base_rect))
+ return -ERANGE;
+
+ memcpy(&queue->crop, &s->r, sizeof(s->r));
+
+ if (!v4l2_rect_equal(&s->r, &base_rect))
+ queue->crop_set = true;
+
+ dprintk(ctx->e5010, 2, "ctx: 0x%p: crop rectangle: w: %d, h : %d, l : %d, t : %d\n",
+ ctx, queue->crop.width, queue->crop.height, queue->crop.left, queue->crop.top);
+
+ return 0;
+}
+
+static int e5010_subscribe_event(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_EOS:
+ return v4l2_event_subscribe(fh, sub, 0, NULL);
+ case V4L2_EVENT_CTRL:
+ return v4l2_ctrl_subscribe_event(fh, sub);
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
+{
+ struct e5010_context *ctx = priv;
+ struct e5010_dev *e5010 = ctx->e5010;
+ int ret = 0;
+
+ /* src_vq */
+ memset(src_vq, 0, sizeof(*src_vq));
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct e5010_buffer);
+ src_vq->ops = &e5010_video_ops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &e5010->mutex;
+ src_vq->dev = e5010->v4l2_dev.dev;
+
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ /* dst_vq */
+ memset(dst_vq, 0, sizeof(*dst_vq));
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_MMAP | VB2_DMABUF;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct e5010_buffer);
+ dst_vq->ops = &e5010_video_ops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &e5010->mutex;
+ dst_vq->dev = e5010->v4l2_dev.dev;
+
+ ret = vb2_queue_init(dst_vq);
+ if (ret) {
+ vb2_queue_release(src_vq);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int e5010_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct e5010_context *ctx =
+ container_of(ctrl->handler, struct e5010_context, ctrl_handler);
+
+ switch (ctrl->id) {
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ ctx->quality = ctrl->val;
+ calculate_qp_tables(ctx);
+ dprintk(ctx->e5010, 2, "ctx: 0x%p compression quality set to : %d\n", ctx,
+ ctx->quality);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops e5010_ctrl_ops = {
+ .s_ctrl = e5010_s_ctrl,
+};
+
+static void e5010_encode_ctrls(struct e5010_context *ctx)
+{
+ v4l2_ctrl_new_std(&ctx->ctrl_handler, &e5010_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 1, 100, 1, 75);
+}
+
+static int e5010_ctrls_setup(struct e5010_context *ctx)
+{
+ int err;
+
+ v4l2_ctrl_handler_init(&ctx->ctrl_handler, 1);
+
+ e5010_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 void e5010_jpeg_set_default_params(struct e5010_context *ctx)
+{
+ struct e5010_q_data *queue;
+ struct v4l2_format f;
+ struct e5010_fmt *fmt;
+ struct v4l2_pix_format_mplane *pix_mp = &f.fmt.pix_mp;
+ struct v4l2_plane_pix_format *plane_fmt = pix_mp->plane_fmt;
+ int i = 0;
+
+ f.type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_NV12;
+ fmt = find_format(&f);
+ queue = &ctx->out_queue;
+ queue->fmt = fmt;
+ queue->width = DEFAULT_WIDTH;
+ queue->height = DEFAULT_HEIGHT;
+ pix_mp->width = queue->width;
+ pix_mp->height = queue->height;
+ queue->crop.left = 0;
+ queue->crop.top = 0;
+ queue->crop.width = queue->width;
+ queue->crop.height = queue->height;
+ v4l2_apply_frmsize_constraints(&pix_mp->width,
+ &pix_mp->height,
+ &fmt->frmsize);
+ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat,
+ pix_mp->width, pix_mp->height);
+ for (i = 0; i < fmt->num_planes; i++) {
+ queue->bytesperline[i] = plane_fmt[i].bytesperline;
+ queue->sizeimage[i] = plane_fmt[i].sizeimage;
+ }
+ queue->width_adjusted = pix_mp->width;
+ queue->height_adjusted = pix_mp->height;
+
+ f.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ f.fmt.pix_mp.pixelformat = V4L2_PIX_FMT_JPEG;
+ fmt = find_format(&f);
+ queue = &ctx->cap_queue;
+ queue->fmt = fmt;
+ queue->width = DEFAULT_WIDTH;
+ queue->height = DEFAULT_HEIGHT;
+ pix_mp->width = queue->width;
+ pix_mp->height = queue->height;
+ v4l2_apply_frmsize_constraints(&pix_mp->width,
+ &pix_mp->height,
+ &fmt->frmsize);
+ queue->sizeimage[0] = pix_mp->width * pix_mp->height * JPEG_MAX_BYTES_PER_PIXEL;
+ queue->sizeimage[0] += HEADER_SIZE;
+ queue->sizeimage[1] = 0;
+ queue->bytesperline[0] = 0;
+ queue->bytesperline[1] = 0;
+ queue->width_adjusted = pix_mp->width;
+ queue->height_adjusted = pix_mp->height;
+}
+
+static int e5010_open(struct file *file)
+{
+ struct e5010_dev *e5010 = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
+ struct e5010_context *ctx;
+ int ret = 0;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ if (mutex_lock_interruptible(&e5010->mutex)) {
+ ret = -ERESTARTSYS;
+ goto free;
+ }
+
+ v4l2_fh_init(&ctx->fh, vdev);
+ file->private_data = ctx;
+ v4l2_fh_add(&ctx->fh);
+
+ ctx->e5010 = e5010;
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(e5010->m2m_dev, ctx, queue_init);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ v4l2_err(&e5010->v4l2_dev, "failed to init m2m ctx\n");
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
+ goto exit;
+ }
+
+ ret = e5010_ctrls_setup(ctx);
+ if (ret) {
+ v4l2_err(&e5010->v4l2_dev, "failed to setup e5010 jpeg controls\n");
+ goto err_ctrls_setup;
+ }
+ ctx->fh.ctrl_handler = &ctx->ctrl_handler;
+
+ e5010_jpeg_set_default_params(ctx);
+
+ dprintk(e5010, 1, "Created instance: 0x%p, m2m_ctx: 0x%p\n", ctx, ctx->fh.m2m_ctx);
+
+ mutex_unlock(&e5010->mutex);
+ return 0;
+
+err_ctrls_setup:
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+exit:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ mutex_unlock(&e5010->mutex);
+free:
+ kfree(ctx);
+ return ret;
+}
+
+static int e5010_release(struct file *file)
+{
+ struct e5010_dev *e5010 = video_drvdata(file);
+ struct e5010_context *ctx = file->private_data;
+
+ dprintk(e5010, 1, "Releasing instance: 0x%p, m2m_ctx: 0x%p\n", ctx, ctx->fh.m2m_ctx);
+ mutex_lock(&e5010->mutex);
+ 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);
+ kfree(ctx);
+ mutex_unlock(&e5010->mutex);
+
+ return 0;
+}
+
+static void header_write(struct e5010_context *ctx, u8 *addr, unsigned int *offset,
+ unsigned int no_bytes, unsigned long bits)
+{
+ u8 *w_addr = addr + *offset;
+ int i;
+
+ if ((*offset + no_bytes) > HEADER_SIZE) {
+ v4l2_warn(&ctx->e5010->v4l2_dev, "%s: %s: %d: Problem writing header. %d > HEADER_SIZE %d\n",
+ __FILE__, __func__, __LINE__, *offset + no_bytes, HEADER_SIZE);
+ return;
+ }
+
+ for (i = no_bytes - 1; i >= 0; i--)
+ *(w_addr++) = ((u8 *)&bits)[i];
+
+ *offset += no_bytes;
+}
+
+static void encode_marker_segment(struct e5010_context *ctx, void *addr, unsigned int *offset)
+{
+ u8 *buffer = (u8 *)addr;
+ int i;
+
+ header_write(ctx, buffer, offset, 2, START_OF_IMAGE);
+ header_write(ctx, buffer, offset, 2, DQT_MARKER);
+ header_write(ctx, buffer, offset, 3, LQPQ << 4);
+ for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++)
+ header_write(ctx, buffer, offset, 1, ctx->luma_qp[v4l2_jpeg_zigzag_scan_index[i]]);
+
+ header_write(ctx, buffer, offset, 2, DQT_MARKER);
+ header_write(ctx, buffer, offset, 3, (LQPQ << 4) | 1);
+ for (i = 0; i < V4L2_JPEG_PIXELS_IN_BLOCK; i++)
+ header_write(ctx, buffer, offset, 1,
+ ctx->chroma_qp[v4l2_jpeg_zigzag_scan_index[i]]);
+
+ /* Huffman tables */
+ header_write(ctx, buffer, offset, 2, DHT_MARKER);
+ header_write(ctx, buffer, offset, 2, LH_DC);
+ header_write(ctx, buffer, offset, 1, V4L2_JPEG_LUM_HT | V4L2_JPEG_DC_HT);
+ for (i = 0 ; i < V4L2_JPEG_REF_HT_DC_LEN; i++)
+ header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_luma_dc_ht[i]);
+
+ header_write(ctx, buffer, offset, 2, DHT_MARKER);
+ header_write(ctx, buffer, offset, 2, LH_AC);
+ header_write(ctx, buffer, offset, 1, V4L2_JPEG_LUM_HT | V4L2_JPEG_AC_HT);
+ for (i = 0 ; i < V4L2_JPEG_REF_HT_AC_LEN; i++)
+ header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_luma_ac_ht[i]);
+
+ header_write(ctx, buffer, offset, 2, DHT_MARKER);
+ header_write(ctx, buffer, offset, 2, LH_DC);
+ header_write(ctx, buffer, offset, 1, V4L2_JPEG_CHR_HT | V4L2_JPEG_DC_HT);
+ for (i = 0 ; i < V4L2_JPEG_REF_HT_DC_LEN; i++)
+ header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_chroma_dc_ht[i]);
+
+ header_write(ctx, buffer, offset, 2, DHT_MARKER);
+ header_write(ctx, buffer, offset, 2, LH_AC);
+ header_write(ctx, buffer, offset, 1, V4L2_JPEG_CHR_HT | V4L2_JPEG_AC_HT);
+ for (i = 0 ; i < V4L2_JPEG_REF_HT_AC_LEN; i++)
+ header_write(ctx, buffer, offset, 1, v4l2_jpeg_ref_table_chroma_ac_ht[i]);
+}
+
+static void encode_frame_header(struct e5010_context *ctx, void *addr, unsigned int *offset)
+{
+ u8 *buffer = (u8 *)addr;
+
+ header_write(ctx, buffer, offset, 2, SOF_BASELINE_DCT);
+ header_write(ctx, buffer, offset, 2, 8 + (3 * UC_NUM_COMP));
+ header_write(ctx, buffer, offset, 1, PRECISION);
+ header_write(ctx, buffer, offset, 2, ctx->out_queue.crop.height);
+ header_write(ctx, buffer, offset, 2, ctx->out_queue.crop.width);
+ header_write(ctx, buffer, offset, 1, UC_NUM_COMP);
+
+ /* Luma details */
+ header_write(ctx, buffer, offset, 1, 1);
+ if (ctx->out_queue.fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422)
+ header_write(ctx, buffer, offset, 1,
+ HORZ_SAMPLING_FACTOR | (VERT_SAMPLING_FACTOR_422));
+ else
+ header_write(ctx, buffer, offset, 1,
+ HORZ_SAMPLING_FACTOR | (VERT_SAMPLING_FACTOR_420));
+ header_write(ctx, buffer, offset, 1, 0);
+ /* Chroma details */
+ header_write(ctx, buffer, offset, 1, 2);
+ header_write(ctx, buffer, offset, 1, (HORZ_SAMPLING_FACTOR >> 1) | 1);
+ header_write(ctx, buffer, offset, 1, 1);
+ header_write(ctx, buffer, offset, 1, 3);
+ header_write(ctx, buffer, offset, 1, (HORZ_SAMPLING_FACTOR >> 1) | 1);
+ header_write(ctx, buffer, offset, 1, 1);
+}
+
+static void jpg_encode_sos_header(struct e5010_context *ctx, void *addr, unsigned int *offset)
+{
+ u8 *buffer = (u8 *)addr;
+ int i;
+
+ header_write(ctx, buffer, offset, 2, START_OF_SCAN);
+ header_write(ctx, buffer, offset, 2, 6 + (COMPONENTS_IN_SCAN << 1));
+ header_write(ctx, buffer, offset, 1, COMPONENTS_IN_SCAN);
+
+ for (i = 0; i < COMPONENTS_IN_SCAN; i++) {
+ header_write(ctx, buffer, offset, 1, i + 1);
+ if (i == 0)
+ header_write(ctx, buffer, offset, 1, 0);
+ else
+ header_write(ctx, buffer, offset, 1, 17);
+ }
+
+ header_write(ctx, buffer, offset, 1, 0);
+ header_write(ctx, buffer, offset, 1, 63);
+ header_write(ctx, buffer, offset, 1, 0);
+}
+
+static void write_header(struct e5010_context *ctx, void *addr)
+{
+ unsigned int offset = 0;
+
+ encode_marker_segment(ctx, addr, &offset);
+ encode_frame_header(ctx, addr, &offset);
+ jpg_encode_sos_header(ctx, addr, &offset);
+}
+
+static irqreturn_t e5010_irq(int irq, void *data)
+{
+ struct e5010_dev *e5010 = data;
+ struct e5010_context *ctx;
+ int output_size;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ bool pic_done, out_addr_err;
+
+ spin_lock(&e5010->hw_lock);
+ pic_done = e5010_hw_pic_done_irq(e5010->core_base);
+ out_addr_err = e5010_hw_output_address_irq(e5010->core_base);
+
+ if (!pic_done && !out_addr_err) {
+ spin_unlock(&e5010->hw_lock);
+ return IRQ_NONE;
+ }
+
+ ctx = v4l2_m2m_get_curr_priv(e5010->m2m_dev);
+ if (WARN_ON(!ctx))
+ goto job_unlock;
+
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ if (!dst_buf || !src_buf) {
+ v4l2_err(&e5010->v4l2_dev, "ctx: 0x%p No source or destination buffer\n", ctx);
+ goto job_unlock;
+ }
+
+ if (out_addr_err) {
+ e5010_hw_clear_output_error(e5010->core_base, 1);
+ v4l2_warn(&e5010->v4l2_dev,
+ "ctx: 0x%p Output bitstream size exceeded max size\n", ctx);
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, dst_buf->planes[0].length);
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+ 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);
+ v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event);
+ dprintk(e5010, 2, "ctx: 0x%p Sending EOS\n", ctx);
+ }
+ }
+
+ if (pic_done) {
+ e5010_hw_clear_picture_done(e5010->core_base, 1);
+ dprintk(e5010, 3, "ctx: 0x%p Got output bitstream of size %d bytes\n",
+ ctx, readl(e5010->core_base + JASPER_OUTPUT_SIZE_OFFSET));
+
+ 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);
+ v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event);
+ dprintk(e5010, 2, "ctx: 0x%p Sending EOS\n", ctx);
+ }
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
+ output_size = e5010_hw_get_output_size(e5010->core_base);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, output_size + HEADER_SIZE);
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+ dprintk(e5010, 3,
+ "ctx: 0x%p frame done for dst_buf->sequence: %d src_buf->sequence: %d\n",
+ ctx, dst_buf->sequence, src_buf->sequence);
+ }
+
+ v4l2_m2m_job_finish(e5010->m2m_dev, ctx->fh.m2m_ctx);
+ dprintk(e5010, 3, "ctx: 0x%p Finish job\n", ctx);
+
+job_unlock:
+ spin_unlock(&e5010->hw_lock);
+ return IRQ_HANDLED;
+}
+
+static int e5010_init_device(struct e5010_dev *e5010)
+{
+ int ret = 0;
+
+ /*TODO: Set MMU in bypass mode until support for the same is added in driver*/
+ e5010_hw_bypass_mmu(e5010->mmu_base, 1);
+
+ if (e5010_hw_enable_auto_clock_gating(e5010->core_base, 1))
+ v4l2_warn(&e5010->v4l2_dev, "failed to enable auto clock gating\n");
+
+ if (e5010_hw_enable_manual_clock_gating(e5010->core_base, 0))
+ v4l2_warn(&e5010->v4l2_dev, "failed to disable manual clock gating\n");
+
+ if (e5010_hw_enable_crc_check(e5010->core_base, 0))
+ v4l2_warn(&e5010->v4l2_dev, "failed to disable CRC check\n");
+
+ if (e5010_hw_enable_output_address_error_irq(e5010->core_base, 1))
+ v4l2_err(&e5010->v4l2_dev, "failed to enable Output Address Error interrupts\n");
+
+ ret = e5010_hw_set_input_source_to_memory(e5010->core_base, 1);
+ if (ret) {
+ v4l2_err(&e5010->v4l2_dev, "failed to set input source to memory\n");
+ return ret;
+ }
+
+ ret = e5010_hw_enable_picture_done_irq(e5010->core_base, 1);
+ if (ret)
+ v4l2_err(&e5010->v4l2_dev, "failed to enable Picture Done interrupts\n");
+
+ return ret;
+}
+
+static int e5010_probe(struct platform_device *pdev)
+{
+ struct e5010_dev *e5010;
+ int irq, ret = 0;
+ struct device *dev = &pdev->dev;
+
+ ret = dma_set_mask(dev, DMA_BIT_MASK(32));
+ if (ret)
+ return dev_err_probe(dev, ret, "32-bit consistent DMA enable failed\n");
+
+ e5010 = devm_kzalloc(dev, sizeof(*e5010), GFP_KERNEL);
+ if (!e5010)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, e5010);
+
+ e5010->dev = dev;
+
+ mutex_init(&e5010->mutex);
+ spin_lock_init(&e5010->hw_lock);
+
+ e5010->vdev = video_device_alloc();
+ if (!e5010->vdev) {
+ dev_err(dev, "failed to allocate video device\n");
+ return -ENOMEM;
+ }
+
+ snprintf(e5010->vdev->name, sizeof(e5010->vdev->name), "%s", E5010_MODULE_NAME);
+ e5010->vdev->fops = &e5010_fops;
+ e5010->vdev->ioctl_ops = &e5010_ioctl_ops;
+ e5010->vdev->minor = -1;
+ e5010->vdev->release = video_device_release;
+ e5010->vdev->vfl_dir = VFL_DIR_M2M;
+ e5010->vdev->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ e5010->vdev->v4l2_dev = &e5010->v4l2_dev;
+ e5010->vdev->lock = &e5010->mutex;
+
+ ret = v4l2_device_register(dev, &e5010->v4l2_dev);
+ if (ret)
+ return dev_err_probe(dev, ret, "failed to register v4l2 device\n");
+
+ e5010->m2m_dev = v4l2_m2m_init(&e5010_m2m_ops);
+ if (IS_ERR(e5010->m2m_dev)) {
+ ret = PTR_ERR(e5010->m2m_dev);
+ e5010->m2m_dev = NULL;
+ dev_err_probe(dev, ret, "failed to init mem2mem device\n");
+ goto fail_after_v4l2_register;
+ }
+
+ video_set_drvdata(e5010->vdev, e5010);
+
+ e5010->core_base = devm_platform_ioremap_resource_byname(pdev, "core");
+ if (IS_ERR(e5010->core_base)) {
+ ret = PTR_ERR(e5010->core_base);
+ dev_err_probe(dev, ret, "Missing 'core' resources area\n");
+ goto fail_after_v4l2_register;
+ }
+
+ e5010->mmu_base = devm_platform_ioremap_resource_byname(pdev, "mmu");
+ if (IS_ERR(e5010->mmu_base)) {
+ ret = PTR_ERR(e5010->mmu_base);
+ dev_err_probe(dev, ret, "Missing 'mmu' resources area\n");
+ goto fail_after_v4l2_register;
+ }
+
+ e5010->last_context_run = NULL;
+
+ irq = platform_get_irq(pdev, 0);
+ ret = devm_request_irq(dev, irq, e5010_irq, 0,
+ E5010_MODULE_NAME, e5010);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to register IRQ %d\n", irq);
+ goto fail_after_v4l2_register;
+ }
+
+ e5010->clk = devm_clk_get(dev, NULL);
+ if (IS_ERR(e5010->clk)) {
+ ret = PTR_ERR(e5010->clk);
+ dev_err_probe(dev, ret, "failed to get clock\n");
+ goto fail_after_v4l2_register;
+ }
+
+ pm_runtime_enable(dev);
+
+ ret = video_register_device(e5010->vdev, VFL_TYPE_VIDEO, 0);
+ if (ret) {
+ dev_err_probe(dev, ret, "failed to register video device\n");
+ goto fail_after_video_register_device;
+ }
+
+ v4l2_info(&e5010->v4l2_dev, "Device registered as /dev/video%d\n",
+ e5010->vdev->num);
+
+ return 0;
+
+fail_after_video_register_device:
+ v4l2_m2m_release(e5010->m2m_dev);
+fail_after_v4l2_register:
+ v4l2_device_unregister(&e5010->v4l2_dev);
+ return ret;
+}
+
+static void e5010_remove(struct platform_device *pdev)
+{
+ struct e5010_dev *e5010 = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(e5010->dev);
+ video_unregister_device(e5010->vdev);
+ v4l2_m2m_release(e5010->m2m_dev);
+ v4l2_device_unregister(&e5010->v4l2_dev);
+}
+
+static void e5010_vb2_buffers_return(struct vb2_queue *q, enum vb2_buffer_state state)
+{
+ struct vb2_v4l2_buffer *vbuf;
+ struct e5010_context *ctx = vb2_get_drv_priv(q);
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ while ((vbuf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx))) {
+ dprintk(ctx->e5010, 2, "ctx: 0x%p, buf type %s | index %d\n",
+ ctx, type_name(vbuf->vb2_buf.type), vbuf->vb2_buf.index);
+ v4l2_m2m_buf_done(vbuf, state);
+ }
+ } else {
+ while ((vbuf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx))) {
+ dprintk(ctx->e5010, 2, "ctx: 0x%p, buf type %s | index %d\n",
+ ctx, type_name(vbuf->vb2_buf.type), vbuf->vb2_buf.index);
+ vb2_set_plane_payload(&vbuf->vb2_buf, 0, 0);
+ v4l2_m2m_buf_done(vbuf, state);
+ }
+ }
+}
+
+static int e5010_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers, unsigned int *nplanes,
+ unsigned int sizes[], struct device *alloc_devs[])
+{
+ struct e5010_context *ctx = vb2_get_drv_priv(vq);
+ struct e5010_q_data *queue;
+ int i;
+
+ queue = get_queue(ctx, vq->type);
+
+ if (*nplanes) {
+ if (*nplanes != queue->fmt->num_planes)
+ return -EINVAL;
+ for (i = 0; i < *nplanes; i++) {
+ if (sizes[i] < queue->sizeimage[i])
+ return -EINVAL;
+ }
+ return 0;
+ }
+
+ *nplanes = queue->fmt->num_planes;
+ for (i = 0; i < *nplanes; i++)
+ sizes[i] = queue->sizeimage[i];
+
+ dprintk(ctx->e5010, 2,
+ "ctx: 0x%p, type %s, buffer(s): %d, planes %d, plane1: bytes %d plane2: %d bytes\n",
+ ctx, type_name(vq->type), *nbuffers, *nplanes, sizes[0], sizes[1]);
+
+ return 0;
+}
+
+static void e5010_buf_finish(struct vb2_buffer *vb)
+{
+ struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ void *d_addr;
+
+ if (vb->state != VB2_BUF_STATE_DONE || V4L2_TYPE_IS_OUTPUT(vb->vb2_queue->type))
+ return;
+
+ d_addr = vb2_plane_vaddr(vb, 0);
+ write_header(ctx, d_addr);
+}
+
+static int e5010_buf_out_validate(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue);
+
+ if (vbuf->field != V4L2_FIELD_NONE)
+ dprintk(ctx->e5010, 1, "ctx: 0x%p, field isn't supported\n", ctx);
+
+ vbuf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int e5010_buf_prepare(struct vb2_buffer *vb)
+{
+ struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct e5010_q_data *queue;
+ int i;
+
+ vbuf->field = V4L2_FIELD_NONE;
+
+ queue = get_queue(ctx, vb->vb2_queue->type);
+
+ for (i = 0; i < queue->fmt->num_planes; i++) {
+ if (vb2_plane_size(vb, i) < (unsigned long)queue->sizeimage[i]) {
+ v4l2_err(&ctx->e5010->v4l2_dev, "plane %d too small (%lu < %lu)", i,
+ vb2_plane_size(vb, i), (unsigned long)queue->sizeimage[i]);
+
+ return -EINVAL;
+ }
+ }
+
+ 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 void e5010_buf_queue(struct vb2_buffer *vb)
+{
+ struct e5010_context *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ 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 e5010_q_data *queue = get_queue(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+ vbuf->sequence = queue->sequence++;
+ v4l2_m2m_last_buffer_done(ctx->fh.m2m_ctx, vbuf);
+ v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event);
+ return;
+ }
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vbuf);
+}
+
+static int e5010_encoder_cmd(struct file *file, void *priv,
+ struct v4l2_encoder_cmd *cmd)
+{
+ struct e5010_context *ctx = file->private_data;
+ int ret;
+ struct vb2_queue *cap_vq;
+
+ cap_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE);
+
+ ret = v4l2_m2m_ioctl_try_encoder_cmd(file, &ctx->fh, cmd);
+ if (ret < 0)
+ return ret;
+
+ if (!vb2_is_streaming(v4l2_m2m_get_src_vq(ctx->fh.m2m_ctx)) ||
+ !vb2_is_streaming(v4l2_m2m_get_dst_vq(ctx->fh.m2m_ctx)))
+ return 0;
+
+ ret = v4l2_m2m_ioctl_encoder_cmd(file, &ctx->fh, cmd);
+ if (ret < 0)
+ return ret;
+
+ if (cmd->cmd == V4L2_ENC_CMD_STOP &&
+ v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
+ v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event);
+
+ if (cmd->cmd == V4L2_ENC_CMD_START &&
+ v4l2_m2m_has_stopped(ctx->fh.m2m_ctx))
+ vb2_clear_last_buffer_dequeued(cap_vq);
+
+ return 0;
+}
+
+static int e5010_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct e5010_context *ctx = vb2_get_drv_priv(q);
+ int ret;
+
+ struct e5010_q_data *queue = get_queue(ctx, q->type);
+
+ v4l2_m2m_update_start_streaming_state(ctx->fh.m2m_ctx, q);
+ queue->sequence = 0;
+
+ ret = pm_runtime_resume_and_get(ctx->e5010->dev);
+ if (ret < 0) {
+ v4l2_err(&ctx->e5010->v4l2_dev, "failed to power up jpeg\n");
+ goto fail;
+ }
+
+ ret = e5010_init_device(ctx->e5010);
+ if (ret) {
+ v4l2_err(&ctx->e5010->v4l2_dev, "failed to Enable e5010 device\n");
+ goto fail;
+ }
+
+ return 0;
+
+fail:
+ e5010_vb2_buffers_return(q, VB2_BUF_STATE_QUEUED);
+
+ return ret;
+}
+
+static void e5010_stop_streaming(struct vb2_queue *q)
+{
+ struct e5010_context *ctx = vb2_get_drv_priv(q);
+
+ e5010_vb2_buffers_return(q, VB2_BUF_STATE_ERROR);
+
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ 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)) {
+ v4l2_event_queue_fh(&ctx->fh, &e5010_eos_event);
+ }
+
+ pm_runtime_put_sync(ctx->e5010->dev);
+}
+
+static void e5010_device_run(void *priv)
+{
+ struct e5010_context *ctx = priv;
+ struct e5010_dev *e5010 = ctx->e5010;
+ struct vb2_v4l2_buffer *s_vb, *d_vb;
+ u32 reg = 0;
+ int ret = 0, luma_crop_offset = 0, chroma_crop_offset = 0;
+ unsigned long flags;
+ int num_planes = ctx->out_queue.fmt->num_planes;
+
+ spin_lock_irqsave(&e5010->hw_lock, flags);
+ s_vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ WARN_ON(!s_vb);
+ d_vb = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ WARN_ON(!d_vb);
+ if (!s_vb || !d_vb)
+ goto no_ready_buf_err;
+
+ s_vb->sequence = ctx->out_queue.sequence++;
+ d_vb->sequence = ctx->cap_queue.sequence++;
+
+ v4l2_m2m_buf_copy_metadata(s_vb, d_vb, false);
+
+ if (ctx != e5010->last_context_run || ctx->update_qp) {
+ dprintk(e5010, 1, "ctx updated: 0x%p -> 0x%p, updating qp tables\n",
+ e5010->last_context_run, ctx);
+ ret = update_qp_tables(ctx);
+ }
+
+ if (ret) {
+ ctx->update_qp = true;
+ v4l2_err(&e5010->v4l2_dev, "failed to update QP tables\n");
+ goto device_busy_err;
+ } else {
+ e5010->last_context_run = ctx;
+ ctx->update_qp = false;
+ }
+
+ /* Set I/O Buffer addresses */
+ reg = (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 0);
+
+ if (ctx->out_queue.crop_set) {
+ luma_crop_offset = ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top +
+ ctx->out_queue.crop.left;
+
+ if (ctx->out_queue.fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_422) {
+ chroma_crop_offset =
+ ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top
+ + ctx->out_queue.crop.left;
+ } else {
+ chroma_crop_offset =
+ ctx->out_queue.bytesperline[0] * ctx->out_queue.crop.top / 2
+ + ctx->out_queue.crop.left;
+ }
+
+ dprintk(e5010, 1, "Luma crop offset : %x, chroma crop offset : %x\n",
+ luma_crop_offset, chroma_crop_offset);
+ }
+
+ ret = e5010_hw_set_input_luma_addr(e5010->core_base, reg + luma_crop_offset);
+ if (ret || !reg) {
+ v4l2_err(&e5010->v4l2_dev, "failed to set input luma address\n");
+ goto device_busy_err;
+ }
+
+ if (num_planes == 1)
+ reg += (ctx->out_queue.bytesperline[0]) * (ctx->out_queue.height);
+ else
+ reg = (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 1);
+
+ dprintk(e5010, 3,
+ "ctx: 0x%p, luma_addr: 0x%x, chroma_addr: 0x%x, out_addr: 0x%x\n",
+ ctx, (u32)vb2_dma_contig_plane_dma_addr(&s_vb->vb2_buf, 0) + luma_crop_offset,
+ reg + chroma_crop_offset, (u32)vb2_dma_contig_plane_dma_addr(&d_vb->vb2_buf, 0));
+
+ dprintk(e5010, 3,
+ "ctx: 0x%p, buf indices: src_index: %d, dst_index: %d\n",
+ ctx, s_vb->vb2_buf.index, d_vb->vb2_buf.index);
+
+ ret = e5010_hw_set_input_chroma_addr(e5010->core_base, reg + chroma_crop_offset);
+ if (ret || !reg) {
+ v4l2_err(&e5010->v4l2_dev, "failed to set input chroma address\n");
+ goto device_busy_err;
+ }
+
+ reg = (u32)vb2_dma_contig_plane_dma_addr(&d_vb->vb2_buf, 0);
+ reg += HEADER_SIZE;
+ ret = e5010_hw_set_output_base_addr(e5010->core_base, reg);
+ if (ret || !reg) {
+ v4l2_err(&e5010->v4l2_dev, "failed to set output base address\n");
+ goto device_busy_err;
+ }
+
+ /* Set input settings */
+ ret = e5010_hw_set_horizontal_size(e5010->core_base, ctx->out_queue.crop.width - 1);
+ if (ret) {
+ v4l2_err(&e5010->v4l2_dev, "failed to set input width\n");
+ goto device_busy_err;
+ }
+
+ ret = e5010_hw_set_vertical_size(e5010->core_base, ctx->out_queue.crop.height - 1);
+ if (ret) {
+ v4l2_err(&e5010->v4l2_dev, "failed to set input width\n");
+ goto device_busy_err;
+ }
+
+ ret = e5010_hw_set_luma_stride(e5010->core_base, ctx->out_queue.bytesperline[0]);
+ if (ret) {
+ v4l2_err(&e5010->v4l2_dev, "failed to set luma stride\n");
+ goto device_busy_err;
+ }
+
+ ret = e5010_hw_set_chroma_stride(e5010->core_base, ctx->out_queue.bytesperline[0]);
+ if (ret) {
+ v4l2_err(&e5010->v4l2_dev, "failed to set chroma stride\n");
+ goto device_busy_err;
+ }
+
+ ret = e5010_set_input_subsampling(e5010->core_base, ctx->out_queue.fmt->subsampling);
+ if (ret) {
+ v4l2_err(&e5010->v4l2_dev, "failed to set input subsampling\n");
+ goto device_busy_err;
+ }
+
+ ret = e5010_hw_set_chroma_order(e5010->core_base, ctx->out_queue.fmt->chroma_order);
+ if (ret) {
+ v4l2_err(&e5010->v4l2_dev, "failed to set chroma order\n");
+ goto device_busy_err;
+ }
+
+ e5010_hw_set_output_max_size(e5010->core_base, d_vb->planes[0].length);
+ e5010_hw_encode_start(e5010->core_base, 1);
+
+ spin_unlock_irqrestore(&e5010->hw_lock, flags);
+
+ return;
+
+device_busy_err:
+ e5010_reset(e5010->dev, e5010->core_base, e5010->mmu_base);
+
+no_ready_buf_err:
+ if (s_vb) {
+ v4l2_m2m_src_buf_remove_by_buf(ctx->fh.m2m_ctx, s_vb);
+ v4l2_m2m_buf_done(s_vb, VB2_BUF_STATE_ERROR);
+ }
+
+ if (d_vb) {
+ v4l2_m2m_dst_buf_remove_by_buf(ctx->fh.m2m_ctx, d_vb);
+ /* Payload set to 1 since 0 payload can trigger EOS */
+ vb2_set_plane_payload(&d_vb->vb2_buf, 0, 1);
+ v4l2_m2m_buf_done(d_vb, VB2_BUF_STATE_ERROR);
+ }
+ v4l2_m2m_job_finish(e5010->m2m_dev, ctx->fh.m2m_ctx);
+ spin_unlock_irqrestore(&e5010->hw_lock, flags);
+}
+
+#ifdef CONFIG_PM
+static int e5010_runtime_resume(struct device *dev)
+{
+ struct e5010_dev *e5010 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(e5010->clk);
+ if (ret < 0) {
+ v4l2_err(&e5010->v4l2_dev, "failed to enable clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int e5010_runtime_suspend(struct device *dev)
+{
+ struct e5010_dev *e5010 = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(e5010->clk);
+
+ return 0;
+}
+#endif
+
+#ifdef CONFIG_PM_SLEEP
+static int e5010_suspend(struct device *dev)
+{
+ struct e5010_dev *e5010 = dev_get_drvdata(dev);
+
+ v4l2_m2m_suspend(e5010->m2m_dev);
+
+ return pm_runtime_force_suspend(dev);
+}
+
+static int e5010_resume(struct device *dev)
+{
+ struct e5010_dev *e5010 = dev_get_drvdata(dev);
+ int ret;
+
+ ret = pm_runtime_force_resume(dev);
+ if (ret < 0)
+ return ret;
+
+ ret = e5010_init_device(e5010);
+ if (ret) {
+ dev_err(dev, "Failed to re-enable e5010 device\n");
+ return ret;
+ }
+
+ v4l2_m2m_resume(e5010->m2m_dev);
+
+ return ret;
+}
+#endif
+
+static const struct dev_pm_ops e5010_pm_ops = {
+ SET_RUNTIME_PM_OPS(e5010_runtime_suspend,
+ e5010_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(e5010_suspend, e5010_resume)
+};
+
+static const struct v4l2_ioctl_ops e5010_ioctl_ops = {
+ .vidioc_querycap = e5010_querycap,
+
+ .vidioc_enum_fmt_vid_cap = e5010_enum_fmt,
+ .vidioc_g_fmt_vid_cap_mplane = e5010_g_fmt,
+ .vidioc_try_fmt_vid_cap_mplane = e5010_try_fmt,
+ .vidioc_s_fmt_vid_cap_mplane = e5010_s_fmt,
+
+ .vidioc_enum_fmt_vid_out = e5010_enum_fmt,
+ .vidioc_g_fmt_vid_out_mplane = e5010_g_fmt,
+ .vidioc_try_fmt_vid_out_mplane = e5010_try_fmt,
+ .vidioc_s_fmt_vid_out_mplane = e5010_s_fmt,
+
+ .vidioc_g_selection = e5010_g_selection,
+ .vidioc_s_selection = e5010_s_selection,
+
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+ .vidioc_log_status = v4l2_ctrl_log_status,
+
+ .vidioc_subscribe_event = e5010_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
+ .vidioc_encoder_cmd = e5010_encoder_cmd,
+
+ .vidioc_enum_framesizes = e5010_enum_framesizes,
+};
+
+static const struct vb2_ops e5010_video_ops = {
+ .queue_setup = e5010_queue_setup,
+ .buf_queue = e5010_buf_queue,
+ .buf_finish = e5010_buf_finish,
+ .buf_prepare = e5010_buf_prepare,
+ .buf_out_validate = e5010_buf_out_validate,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = e5010_start_streaming,
+ .stop_streaming = e5010_stop_streaming,
+};
+
+static const struct v4l2_file_operations e5010_fops = {
+ .owner = THIS_MODULE,
+ .open = e5010_open,
+ .release = e5010_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static const struct v4l2_m2m_ops e5010_m2m_ops = {
+ .device_run = e5010_device_run,
+};
+
+static const struct of_device_id e5010_of_match[] = {
+ {.compatible = "img,e5010-jpeg-enc"}, { /* end */},
+};
+MODULE_DEVICE_TABLE(of, e5010_of_match);
+
+static struct platform_driver e5010_driver = {
+ .probe = e5010_probe,
+ .remove_new = e5010_remove,
+ .driver = {
+ .name = E5010_MODULE_NAME,
+ .of_match_table = e5010_of_match,
+ .pm = &e5010_pm_ops,
+ },
+};
+module_platform_driver(e5010_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Imagination E5010 JPEG encoder driver");
diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.h b/drivers/media/platform/imagination/e5010-jpeg-enc.h
new file mode 100644
index 000000000000..71f49ead6898
--- /dev/null
+++ b/drivers/media/platform/imagination/e5010-jpeg-enc.h
@@ -0,0 +1,168 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Imagination E5010 JPEG Encoder driver.
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * Author: David Huang <d-huang@ti.com>
+ * Author: Devarsh Thakkar <devarsht@ti.com>
+ */
+
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+
+#ifndef _E5010_JPEG_ENC_H
+#define _E5010_JPEG_ENC_H
+
+#define MAX_PLANES 2
+#define HEADER_SIZE 0x025D
+#define MIN_DIMENSION 64
+#define MAX_DIMENSION 8192
+#define DEFAULT_WIDTH 640
+#define DEFAULT_HEIGHT 480
+#define E5010_MODULE_NAME "e5010"
+#define JPEG_MAX_BYTES_PER_PIXEL 2
+
+/* JPEG marker definitions */
+#define START_OF_IMAGE 0xFFD8
+#define SOF_BASELINE_DCT 0xFFC0
+#define END_OF_IMAGE 0xFFD9
+#define START_OF_SCAN 0xFFDA
+
+/* Definitions for the huffman table specification in the Marker segment */
+#define DHT_MARKER 0xFFC4
+#define LH_DC 0x001F
+#define LH_AC 0x00B5
+
+/* Definitions for the quantization table specification in the Marker segment */
+#define DQT_MARKER 0xFFDB
+#define ACMAX 0x03FF
+#define DCMAX 0x07FF
+
+/* Length and precision of the quantization table parameters */
+#define LQPQ 0x00430
+#define QMAX 255
+
+/* Misc JPEG header definitions */
+#define UC_NUM_COMP 3
+#define PRECISION 8
+#define HORZ_SAMPLING_FACTOR (2 << 4)
+#define VERT_SAMPLING_FACTOR_422 1
+#define VERT_SAMPLING_FACTOR_420 2
+#define COMPONENTS_IN_SCAN 3
+#define PELS_IN_BLOCK 64
+
+/* Used for Qp table generation */
+#define LUMINOSITY 10
+#define CONTRAST 1
+#define INCREASE 2
+#define QP_TABLE_SIZE (8 * 8)
+#define QP_TABLE_FIELD_OFFSET 0x04
+
+/*
+ * vb2 queue structure
+ * contains queue data information
+ *
+ * @fmt: format info
+ * @width: frame width
+ * @height: frame height
+ * @bytesperline: bytes per line in memory
+ * @size_image: image size in memory
+ */
+struct e5010_q_data {
+ struct e5010_fmt *fmt;
+ u32 width;
+ u32 height;
+ u32 width_adjusted;
+ u32 height_adjusted;
+ u32 sizeimage[MAX_PLANES];
+ u32 bytesperline[MAX_PLANES];
+ u32 sequence;
+ struct v4l2_rect crop;
+ bool crop_set;
+};
+
+/*
+ * Driver device structure
+ * Holds all memory handles and global parameters
+ * Shared by all instances
+ */
+struct e5010_dev {
+ struct device *dev;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct video_device *vdev;
+ void __iomem *core_base;
+ void __iomem *mmu_base;
+ struct clk *clk;
+ struct e5010_context *last_context_run;
+ /* Protect access to device data */
+ struct mutex mutex;
+ /* Protect access to hardware*/
+ spinlock_t hw_lock;
+};
+
+/*
+ * Driver context structure
+ * One of these exists for every m2m context
+ * Holds context specific data
+ */
+struct e5010_context {
+ struct v4l2_fh fh;
+ struct e5010_dev *e5010;
+ struct e5010_q_data out_queue;
+ struct e5010_q_data cap_queue;
+ int quality;
+ bool update_qp;
+ struct v4l2_ctrl_handler ctrl_handler;
+ u8 luma_qp[QP_TABLE_SIZE];
+ u8 chroma_qp[QP_TABLE_SIZE];
+};
+
+/*
+ * Buffer structure
+ * Contains info for all buffers
+ */
+struct e5010_buffer {
+ struct v4l2_m2m_buffer buffer;
+};
+
+enum {
+ CHROMA_ORDER_CB_CR = 0, //UV ordering
+ CHROMA_ORDER_CR_CB = 1, //VU ordering
+};
+
+enum {
+ SUBSAMPLING_420 = 1,
+ SUBSAMPLING_422 = 2,
+};
+
+/*
+ * e5010 format structure
+ * contains format information
+ */
+struct e5010_fmt {
+ u32 fourcc;
+ unsigned int num_planes;
+ unsigned int type;
+ u32 subsampling;
+ u32 chroma_order;
+ const struct v4l2_frmsize_stepwise frmsize;
+};
+
+/*
+ * struct e5010_ctrl - contains info for each supported v4l2 control
+ */
+struct e5010_ctrl {
+ unsigned int cid;
+ enum v4l2_ctrl_type type;
+ unsigned char name[32];
+ int minimum;
+ int maximum;
+ int step;
+ int default_value;
+ unsigned char compound;
+};
+
+#endif
diff --git a/drivers/media/platform/imagination/e5010-mmu-regs.h b/drivers/media/platform/imagination/e5010-mmu-regs.h
new file mode 100644
index 000000000000..bfba06956cf2
--- /dev/null
+++ b/drivers/media/platform/imagination/e5010-mmu-regs.h
@@ -0,0 +1,311 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Imagination E5010 JPEG Encoder driver.
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ *
+ * Author: David Huang <d-huang@ti.com>
+ * Author: Devarsh Thakkar <devarsht@ti.com>
+ */
+
+#ifndef _E5010_MMU_REGS_H
+#define _E5010_MMU_REGS_H
+
+#define MMU_MMU_DIR_BASE_ADDR_OFFSET (0x0020)
+#define MMU_MMU_DIR_BASE_ADDR_STRIDE (4)
+#define MMU_MMU_DIR_BASE_ADDR_NO_ENTRIES (4)
+
+#define MMU_MMU_DIR_BASE_ADDR_MMU_DIR_BASE_ADDR_MASK (0xFFFFFFFF)
+#define MMU_MMU_DIR_BASE_ADDR_MMU_DIR_BASE_ADDR_SHIFT (0)
+
+#define MMU_MMU_TILE_CFG_OFFSET (0x0040)
+#define MMU_MMU_TILE_CFG_STRIDE (4)
+#define MMU_MMU_TILE_CFG_NO_ENTRIES (4)
+
+#define MMU_MMU_TILE_CFG_TILE_128INTERLEAVE_MASK (0x00000010)
+#define MMU_MMU_TILE_CFG_TILE_128INTERLEAVE_SHIFT (4)
+
+#define MMU_MMU_TILE_CFG_TILE_ENABLE_MASK (0x00000008)
+#define MMU_MMU_TILE_CFG_TILE_ENABLE_SHIFT (3)
+
+#define MMU_MMU_TILE_CFG_TILE_STRIDE_MASK (0x00000007)
+#define MMU_MMU_TILE_CFG_TILE_STRIDE_SHIFT (0)
+
+#define MMU_MMU_TILE_MIN_ADDR_OFFSET (0x0050)
+#define MMU_MMU_TILE_MIN_ADDR_STRIDE (4)
+#define MMU_MMU_TILE_MIN_ADDR_NO_ENTRIES (4)
+
+#define MMU_MMU_TILE_MIN_ADDR_TILE_MIN_ADDR_MASK (0xFFFFFFFF)
+#define MMU_MMU_TILE_MIN_ADDR_TILE_MIN_ADDR_SHIFT (0)
+
+#define MMU_MMU_TILE_MAX_ADDR_OFFSET (0x0060)
+#define MMU_MMU_TILE_MAX_ADDR_STRIDE (4)
+#define MMU_MMU_TILE_MAX_ADDR_NO_ENTRIES (4)
+
+#define MMU_MMU_TILE_MAX_ADDR_TILE_MAX_ADDR_MASK (0xFFFFFFFF)
+#define MMU_MMU_TILE_MAX_ADDR_TILE_MAX_ADDR_SHIFT (0)
+
+#define MMU_MMU_CONTROL0_OFFSET (0x0000)
+
+#define MMU_MMU_CONTROL0_MMU_TILING_SCHEME_MASK (0x00000001)
+#define MMU_MMU_CONTROL0_MMU_TILING_SCHEME_SHIFT (0)
+
+#define MMU_MMU_CONTROL0_MMU_CACHE_POLICY_MASK (0x00000100)
+#define MMU_MMU_CONTROL0_MMU_CACHE_POLICY_SHIFT (8)
+
+#define MMU_MMU_CONTROL0_FORCE_CACHE_POLICY_BYPASS_MASK (0x00000200)
+#define MMU_MMU_CONTROL0_FORCE_CACHE_POLICY_BYPASS_SHIFT (9)
+
+#define MMU_MMU_CONTROL0_STALL_ON_PROTOCOL_FAULT_MASK (0x00001000)
+#define MMU_MMU_CONTROL0_STALL_ON_PROTOCOL_FAULT_SHIFT (12)
+
+#define MMU_MMU_CONTROL1_OFFSET (0x0008)
+
+#define MMU_MMU_CONTROL1_MMU_FLUSH_MASK (0x00000008)
+#define MMU_MMU_CONTROL1_MMU_FLUSH_SHIFT (3)
+#define MMU_MMU_CONTROL1_MMU_FLUSH_NO_REPS (4)
+#define MMU_MMU_CONTROL1_MMU_FLUSH_SIZE (1)
+
+#define MMU_MMU_CONTROL1_MMU_INVALDC_MASK (0x00000800)
+#define MMU_MMU_CONTROL1_MMU_INVALDC_SHIFT (11)
+#define MMU_MMU_CONTROL1_MMU_INVALDC_NO_REPS (4)
+#define MMU_MMU_CONTROL1_MMU_INVALDC_SIZE (1)
+
+#define MMU_MMU_CONTROL1_MMU_FAULT_CLEAR_MASK (0x00010000)
+#define MMU_MMU_CONTROL1_MMU_FAULT_CLEAR_SHIFT (16)
+
+#define MMU_MMU_CONTROL1_PROTOCOL_FAULT_CLEAR_MASK (0x00100000)
+#define MMU_MMU_CONTROL1_PROTOCOL_FAULT_CLEAR_SHIFT (20)
+
+#define MMU_MMU_CONTROL1_MMU_PAUSE_SET_MASK (0x01000000)
+#define MMU_MMU_CONTROL1_MMU_PAUSE_SET_SHIFT (24)
+
+#define MMU_MMU_CONTROL1_MMU_PAUSE_CLEAR_MASK (0x02000000)
+#define MMU_MMU_CONTROL1_MMU_PAUSE_CLEAR_SHIFT (25)
+
+#define MMU_MMU_CONTROL1_MMU_SOFT_RESET_MASK (0x10000000)
+#define MMU_MMU_CONTROL1_MMU_SOFT_RESET_SHIFT (28)
+
+#define MMU_MMU_BANK_INDEX_OFFSET (0x0010)
+
+#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_MASK (0xC0000000)
+#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_SHIFT (30)
+#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_NO_REPS (16)
+#define MMU_MMU_BANK_INDEX_MMU_BANK_INDEX_SIZE (2)
+
+#define MMU_REQUEST_PRIORITY_ENABLE_OFFSET (0x0018)
+
+#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_MASK (0x00008000)
+#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_SHIFT (15)
+#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_NO_REPS (16)
+#define MMU_REQUEST_PRIORITY_ENABLE_CMD_PRIORITY_ENABLE_SIZE (1)
+
+#define MMU_REQUEST_PRIORITY_ENABLE_CMD_MMU_PRIORITY_ENABLE_MASK (0x00010000)
+#define MMU_REQUEST_PRIORITY_ENABLE_CMD_MMU_PRIORITY_ENABLE_SHIFT (16)
+
+#define MMU_REQUEST_LIMITED_THROUGHPUT_OFFSET (0x001C)
+
+#define MMU_REQUEST_LIMITED_THROUGHPUT_LIMITED_WORDS_MASK (0x000003FF)
+#define MMU_REQUEST_LIMITED_THROUGHPUT_LIMITED_WORDS_SHIFT (0)
+
+#define MMU_REQUEST_LIMITED_THROUGHPUT_REQUEST_GAP_MASK (0x0FFF0000)
+#define MMU_REQUEST_LIMITED_THROUGHPUT_REQUEST_GAP_SHIFT (16)
+
+#define MMU_MMU_ADDRESS_CONTROL_OFFSET (0x0070)
+#define MMU_MMU_ADDRESS_CONTROL_TRUSTED (IMG_TRUE)
+
+#define MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_MASK (0x00000001)
+#define MMU_MMU_ADDRESS_CONTROL_MMU_BYPASS_SHIFT (0)
+
+#define MMU_MMU_ADDRESS_CONTROL_MMU_ENABLE_EXT_ADDRESSING_MASK (0x00000010)
+#define MMU_MMU_ADDRESS_CONTROL_MMU_ENABLE_EXT_ADDRESSING_SHIFT (4)
+
+#define MMU_MMU_ADDRESS_CONTROL_UPPER_ADDRESS_FIXED_MASK (0x00FF0000)
+#define MMU_MMU_ADDRESS_CONTROL_UPPER_ADDRESS_FIXED_SHIFT (16)
+
+#define MMU_MMU_CONFIG0_OFFSET (0x0080)
+
+#define MMU_MMU_CONFIG0_NUM_REQUESTORS_MASK (0x0000000F)
+#define MMU_MMU_CONFIG0_NUM_REQUESTORS_SHIFT (0)
+
+#define MMU_MMU_CONFIG0_EXTENDED_ADDR_RANGE_MASK (0x000000F0)
+#define MMU_MMU_CONFIG0_EXTENDED_ADDR_RANGE_SHIFT (4)
+
+#define MMU_MMU_CONFIG0_GROUP_OVERRIDE_SIZE_MASK (0x00000700)
+#define MMU_MMU_CONFIG0_GROUP_OVERRIDE_SIZE_SHIFT (8)
+
+#define MMU_MMU_CONFIG0_ADDR_COHERENCY_SUPPORTED_MASK (0x00001000)
+#define MMU_MMU_CONFIG0_ADDR_COHERENCY_SUPPORTED_SHIFT (12)
+
+#define MMU_MMU_CONFIG0_MMU_SUPPORTED_MASK (0x00002000)
+#define MMU_MMU_CONFIG0_MMU_SUPPORTED_SHIFT (13)
+
+#define MMU_MMU_CONFIG0_TILE_ADDR_GRANULARITY_MASK (0x001F0000)
+#define MMU_MMU_CONFIG0_TILE_ADDR_GRANULARITY_SHIFT (16)
+
+#define MMU_MMU_CONFIG0_NO_READ_REORDER_MASK (0x00200000)
+#define MMU_MMU_CONFIG0_NO_READ_REORDER_SHIFT (21)
+
+#define MMU_MMU_CONFIG0_TAGS_SUPPORTED_MASK (0xFFC00000)
+#define MMU_MMU_CONFIG0_TAGS_SUPPORTED_SHIFT (22)
+
+#define MMU_MMU_CONFIG1_OFFSET (0x0084)
+
+#define MMU_MMU_CONFIG1_PAGE_SIZE_MASK (0x0000000F)
+#define MMU_MMU_CONFIG1_PAGE_SIZE_SHIFT (0)
+
+#define MMU_MMU_CONFIG1_PAGE_CACHE_ENTRIES_MASK (0x0000FF00)
+#define MMU_MMU_CONFIG1_PAGE_CACHE_ENTRIES_SHIFT (8)
+
+#define MMU_MMU_CONFIG1_DIR_CACHE_ENTRIES_MASK (0x001F0000)
+#define MMU_MMU_CONFIG1_DIR_CACHE_ENTRIES_SHIFT (16)
+
+#define MMU_MMU_CONFIG1_BANDWIDTH_COUNT_SUPPORTED_MASK (0x01000000)
+#define MMU_MMU_CONFIG1_BANDWIDTH_COUNT_SUPPORTED_SHIFT (24)
+
+#define MMU_MMU_CONFIG1_STALL_COUNT_SUPPORTED_MASK (0x02000000)
+#define MMU_MMU_CONFIG1_STALL_COUNT_SUPPORTED_SHIFT (25)
+
+#define MMU_MMU_CONFIG1_LATENCY_COUNT_SUPPORTED_MASK (0x04000000)
+#define MMU_MMU_CONFIG1_LATENCY_COUNT_SUPPORTED_SHIFT (26)
+
+#define MMU_MMU_STATUS0_OFFSET (0x0088)
+
+#define MMU_MMU_STATUS0_MMU_PF_N_RW_MASK (0x00000001)
+#define MMU_MMU_STATUS0_MMU_PF_N_RW_SHIFT (0)
+
+#define MMU_MMU_STATUS0_MMU_FAULT_ADDR_MASK (0xFFFFF000)
+#define MMU_MMU_STATUS0_MMU_FAULT_ADDR_SHIFT (12)
+
+#define MMU_MMU_STATUS1_OFFSET (0x008C)
+
+#define MMU_MMU_STATUS1_MMU_FAULT_REQ_STAT_MASK (0x0000FFFF)
+#define MMU_MMU_STATUS1_MMU_FAULT_REQ_STAT_SHIFT (0)
+
+#define MMU_MMU_STATUS1_MMU_FAULT_REQ_ID_MASK (0x000F0000)
+#define MMU_MMU_STATUS1_MMU_FAULT_REQ_ID_SHIFT (16)
+
+#define MMU_MMU_STATUS1_MMU_FAULT_INDEX_MASK (0x03000000)
+#define MMU_MMU_STATUS1_MMU_FAULT_INDEX_SHIFT (24)
+
+#define MMU_MMU_STATUS1_MMU_FAULT_RNW_MASK (0x10000000)
+#define MMU_MMU_STATUS1_MMU_FAULT_RNW_SHIFT (28)
+
+#define MMU_MMU_MEM_REQ_OFFSET (0x0090)
+
+#define MMU_MMU_MEM_REQ_TAG_OUTSTANDING_MASK (0x000003FF)
+#define MMU_MMU_MEM_REQ_TAG_OUTSTANDING_SHIFT (0)
+
+#define MMU_MMU_MEM_REQ_EXT_WRRESP_FAULT_MASK (0x00001000)
+#define MMU_MMU_MEM_REQ_EXT_WRRESP_FAULT_SHIFT (12)
+
+#define MMU_MMU_MEM_REQ_EXT_RDRESP_FAULT_MASK (0x00002000)
+#define MMU_MMU_MEM_REQ_EXT_RDRESP_FAULT_SHIFT (13)
+
+#define MMU_MMU_MEM_REQ_EXT_READ_BURST_FAULT_MASK (0x00004000)
+#define MMU_MMU_MEM_REQ_EXT_READ_BURST_FAULT_SHIFT (14)
+
+#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_MASK (0x80000000)
+#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_SHIFT (31)
+#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_NO_REPS (16)
+#define MMU_MMU_MEM_REQ_INT_PROTOCOL_FAULT_SIZE (1)
+
+#define MMU_MMU_FAULT_SELECT_OFFSET (0x00A0)
+
+#define MMU_MMU_FAULT_SELECT_MMU_FAULT_SELECT_MASK (0x0000000F)
+#define MMU_MMU_FAULT_SELECT_MMU_FAULT_SELECT_SHIFT (0)
+
+#define MMU_PROTOCOL_FAULT_OFFSET (0x00A8)
+
+#define MMU_PROTOCOL_FAULT_FAULT_PAGE_BREAK_MASK (0x00000001)
+#define MMU_PROTOCOL_FAULT_FAULT_PAGE_BREAK_SHIFT (0)
+
+#define MMU_PROTOCOL_FAULT_FAULT_WRITE_MASK (0x00000010)
+#define MMU_PROTOCOL_FAULT_FAULT_WRITE_SHIFT (4)
+
+#define MMU_PROTOCOL_FAULT_FAULT_READ_MASK (0x00000020)
+#define MMU_PROTOCOL_FAULT_FAULT_READ_SHIFT (5)
+
+#define MMU_TOTAL_READ_REQ_OFFSET (0x0100)
+
+#define MMU_TOTAL_READ_REQ_TOTAL_READ_REQ_MASK (0xFFFFFFFF)
+#define MMU_TOTAL_READ_REQ_TOTAL_READ_REQ_SHIFT (0)
+
+#define MMU_TOTAL_WRITE_REQ_OFFSET (0x0104)
+
+#define MMU_TOTAL_WRITE_REQ_TOTAL_WRITE_REQ_MASK (0xFFFFFFFF)
+#define MMU_TOTAL_WRITE_REQ_TOTAL_WRITE_REQ_SHIFT (0)
+
+#define MMU_READS_LESS_64_REQ_OFFSET (0x0108)
+
+#define MMU_READS_LESS_64_REQ_READS_LESS_64_REQ_MASK (0xFFFFFFFF)
+#define MMU_READS_LESS_64_REQ_READS_LESS_64_REQ_SHIFT (0)
+
+#define MMU_WRITES_LESS_64_REQ_OFFSET (0x010C)
+
+#define MMU_WRITES_LESS_64_REQ_WRITES_LESS_64_REQ_MASK (0xFFFFFFFF)
+#define MMU_WRITES_LESS_64_REQ_WRITES_LESS_64_REQ_SHIFT (0)
+
+#define MMU_EXT_CMD_STALL_OFFSET (0x0120)
+
+#define MMU_EXT_CMD_STALL_EXT_CMD_STALL_MASK (0xFFFFFFFF)
+#define MMU_EXT_CMD_STALL_EXT_CMD_STALL_SHIFT (0)
+
+#define MMU_WRITE_REQ_STALL_OFFSET (0x0124)
+
+#define MMU_WRITE_REQ_STALL_WRITE_REQ_STALL_MASK (0xFFFFFFFF)
+#define MMU_WRITE_REQ_STALL_WRITE_REQ_STALL_SHIFT (0)
+
+#define MMU_MMU_MISS_STALL_OFFSET (0x0128)
+
+#define MMU_MMU_MISS_STALL_MMU_MISS_STALL_MASK (0xFFFFFFFF)
+#define MMU_MMU_MISS_STALL_MMU_MISS_STALL_SHIFT (0)
+
+#define MMU_ADDRESS_STALL_OFFSET (0x012C)
+
+#define MMU_ADDRESS_STALL_ADDRESS_STALL_MASK (0xFFFFFFFF)
+#define MMU_ADDRESS_STALL_ADDRESS_STALL_SHIFT (0)
+
+#define MMU_TAG_STALL_OFFSET (0x0130)
+
+#define MMU_TAG_STALL_TAG_STALL_MASK (0xFFFFFFFF)
+#define MMU_TAG_STALL_TAG_STALL_SHIFT (0)
+
+#define MMU_PEAK_READ_OUTSTANDING_OFFSET (0x0140)
+
+#define MMU_PEAK_READ_OUTSTANDING_PEAK_TAG_OUTSTANDING_MASK (0x000003FF)
+#define MMU_PEAK_READ_OUTSTANDING_PEAK_TAG_OUTSTANDING_SHIFT (0)
+
+#define MMU_PEAK_READ_OUTSTANDING_PEAK_READ_LATENCY_MASK (0xFFFF0000)
+#define MMU_PEAK_READ_OUTSTANDING_PEAK_READ_LATENCY_SHIFT (16)
+
+#define MMU_AVERAGE_READ_LATENCY_OFFSET (0x0144)
+
+#define MMU_AVERAGE_READ_LATENCY_AVERAGE_READ_LATENCY_MASK (0xFFFFFFFF)
+#define MMU_AVERAGE_READ_LATENCY_AVERAGE_READ_LATENCY_SHIFT (0)
+
+#define MMU_STATISTICS_CONTROL_OFFSET (0x0160)
+
+#define MMU_STATISTICS_CONTROL_BANDWIDTH_STATS_INIT_MASK (0x00000001)
+#define MMU_STATISTICS_CONTROL_BANDWIDTH_STATS_INIT_SHIFT (0)
+
+#define MMU_STATISTICS_CONTROL_STALL_STATS_INIT_MASK (0x00000002)
+#define MMU_STATISTICS_CONTROL_STALL_STATS_INIT_SHIFT (1)
+
+#define MMU_STATISTICS_CONTROL_LATENCY_STATS_INIT_MASK (0x00000004)
+#define MMU_STATISTICS_CONTROL_LATENCY_STATS_INIT_SHIFT (2)
+
+#define MMU_MMU_VERSION_OFFSET (0x01D0)
+
+#define MMU_MMU_VERSION_MMU_MAJOR_REV_MASK (0x00FF0000)
+#define MMU_MMU_VERSION_MMU_MAJOR_REV_SHIFT (16)
+
+#define MMU_MMU_VERSION_MMU_MINOR_REV_MASK (0x0000FF00)
+#define MMU_MMU_VERSION_MMU_MINOR_REV_SHIFT (8)
+
+#define MMU_MMU_VERSION_MMU_MAINT_REV_MASK (0x000000FF)
+#define MMU_MMU_VERSION_MMU_MAINT_REV_SHIFT (0)
+
+#define MMU_BYTE_SIZE (0x01D4)
+
+#endif
diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c
index d904952bf00e..f118aaac0b38 100644
--- a/drivers/media/platform/intel/pxa_camera.c
+++ b/drivers/media/platform/intel/pxa_camera.c
@@ -43,6 +43,7 @@
#include <linux/videodev2.h>
#include <linux/platform_data/media/camera-pxa.h>
+#include <linux/workqueue.h>
#define PXA_CAM_VERSION "0.0.6"
#define PXA_CAM_DRV_NAME "pxa27x-camera"
@@ -683,7 +684,7 @@ struct pxa_camera_dev {
unsigned int buf_sequence;
struct pxa_buffer *active;
- struct tasklet_struct task_eof;
+ struct work_struct eof_bh_work;
u32 save_cicr[5];
};
@@ -1146,9 +1147,9 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
clk_disable_unprepare(pcdev->clk);
}
-static void pxa_camera_eof(struct tasklet_struct *t)
+static void pxa_camera_eof_bh_work(struct work_struct *t)
{
- struct pxa_camera_dev *pcdev = from_tasklet(pcdev, t, task_eof);
+ struct pxa_camera_dev *pcdev = from_work(pcdev, t, eof_bh_work);
unsigned long cifr;
struct pxa_buffer *buf;
@@ -1185,7 +1186,7 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
if (status & CISR_EOF) {
cicr0 = __raw_readl(pcdev->base + CICR0) | CICR0_EOFM;
__raw_writel(cicr0, pcdev->base + CICR0);
- tasklet_schedule(&pcdev->task_eof);
+ queue_work(system_bh_wq, &pcdev->eof_bh_work);
}
return IRQ_HANDLED;
@@ -2383,7 +2384,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
}
}
- tasklet_setup(&pcdev->task_eof, pxa_camera_eof);
+ INIT_WORK(&pcdev->eof_bh_work, pxa_camera_eof_bh_work);
pxa_camera_activate(pcdev);
@@ -2409,7 +2410,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
return 0;
exit_deactivate:
pxa_camera_deactivate(pcdev);
- tasklet_kill(&pcdev->task_eof);
+ cancel_work_sync(&pcdev->eof_bh_work);
exit_free_dma:
dma_release_channel(pcdev->dma_chans[2]);
exit_free_dma_u:
@@ -2428,7 +2429,7 @@ static void pxa_camera_remove(struct platform_device *pdev)
struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev);
pxa_camera_deactivate(pcdev);
- tasklet_kill(&pcdev->task_eof);
+ cancel_work_sync(&pcdev->eof_bh_work);
dma_release_channel(pcdev->dma_chans[0]);
dma_release_channel(pcdev->dma_chans[1]);
dma_release_channel(pcdev->dma_chans[2]);
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 96b35a5d6174..5adcef80c698 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -724,10 +724,6 @@ static const struct v4l2_ioctl_ops deinterlace_ioctl_ops = {
/*
* Queue operations
*/
-struct vb2_dc_conf {
- struct device *dev;
-};
-
static int deinterlace_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], struct device *alloc_devs[])
diff --git a/drivers/media/platform/marvell/mcam-core.c b/drivers/media/platform/marvell/mcam-core.c
index 66688b4aece5..c81593c969e0 100644
--- a/drivers/media/platform/marvell/mcam-core.c
+++ b/drivers/media/platform/marvell/mcam-core.c
@@ -439,9 +439,9 @@ static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam)
/*
* Copy data out to user space in the vmalloc case
*/
-static void mcam_frame_tasklet(struct tasklet_struct *t)
+static void mcam_frame_work(struct work_struct *t)
{
- struct mcam_camera *cam = from_tasklet(cam, t, s_tasklet);
+ struct mcam_camera *cam = from_work(cam, t, s_bh_work);
int i;
unsigned long flags;
struct mcam_vb_buffer *buf;
@@ -493,7 +493,7 @@ static int mcam_check_dma_buffers(struct mcam_camera *cam)
static void mcam_vmalloc_done(struct mcam_camera *cam, int frame)
{
- tasklet_schedule(&cam->s_tasklet);
+ queue_work(system_bh_wq, &cam->s_bh_work);
}
#else /* MCAM_MODE_VMALLOC */
@@ -1305,7 +1305,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam)
break;
case B_vmalloc:
#ifdef MCAM_MODE_VMALLOC
- tasklet_setup(&cam->s_tasklet, mcam_frame_tasklet);
+ INIT_WORK(&cam->s_bh_work, mcam_frame_work);
vq->ops = &mcam_vb2_ops;
vq->mem_ops = &vb2_vmalloc_memops;
cam->dma_setup = mcam_ctlr_dma_vmalloc;
@@ -1981,5 +1981,6 @@ int mccic_resume(struct mcam_camera *cam)
}
EXPORT_SYMBOL_GPL(mccic_resume);
+MODULE_DESCRIPTION("Marvell camera core driver");
MODULE_LICENSE("GPL v2");
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
diff --git a/drivers/media/platform/marvell/mcam-core.h b/drivers/media/platform/marvell/mcam-core.h
index 51e66db45af6..989dc6859a53 100644
--- a/drivers/media/platform/marvell/mcam-core.h
+++ b/drivers/media/platform/marvell/mcam-core.h
@@ -9,6 +9,7 @@
#include <linux/list.h>
#include <linux/clk-provider.h>
+#include <linux/workqueue.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dev.h>
@@ -167,7 +168,7 @@ struct mcam_camera {
unsigned int dma_buf_size; /* allocated size */
void *dma_bufs[MAX_DMA_BUFS]; /* Internal buffer addresses */
dma_addr_t dma_handles[MAX_DMA_BUFS]; /* Buffer bus addresses */
- struct tasklet_struct s_tasklet;
+ struct work_struct s_bh_work;
#endif
unsigned int sequence; /* Frame sequence number */
unsigned int buf_seq[MAX_DMA_BUFS]; /* Sequence for individual bufs */
diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c
index 170907cc1885..ff9d151121d5 100644
--- a/drivers/media/platform/marvell/mmp-driver.c
+++ b/drivers/media/platform/marvell/mmp-driver.c
@@ -30,6 +30,7 @@
MODULE_ALIAS("platform:mmp-camera");
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("Support for the camera device found on Marvell MMP processors");
MODULE_LICENSE("GPL");
static char *mcam_clks[] = {"axi", "func", "phy"};
diff --git a/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c b/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c
index ecca52b45307..0b4c50bc1776 100644
--- a/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c
+++ b/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c
@@ -46,6 +46,53 @@ enum mt8183_mdp_comp_id {
MT8183_MDP_COMP_WROT1, /* 25 */
};
+enum mt8188_mdp_comp_id {
+ /* MT8188 Comp id */
+ /* ISP */
+ MT8188_MDP_COMP_WPEI = 0,
+ MT8188_MDP_COMP_WPEO, /* 1 */
+
+ /* MDP */
+ MT8188_MDP_COMP_CAMIN, /* 2 */
+ MT8188_MDP_COMP_RDMA0, /* 3 */
+ MT8188_MDP_COMP_RDMA2, /* 4 */
+ MT8188_MDP_COMP_RDMA3, /* 5 */
+ MT8188_MDP_COMP_FG0, /* 6 */
+ MT8188_MDP_COMP_FG2, /* 7 */
+ MT8188_MDP_COMP_FG3, /* 8 */
+ MT8188_MDP_COMP_TO_SVPP2MOUT, /* 9 */
+ MT8188_MDP_COMP_TO_SVPP3MOUT, /* 10 */
+ MT8188_MDP_COMP_TO_WARP0MOUT, /* 11 */
+ MT8188_MDP_COMP_VPP0_SOUT, /* 12 */
+ MT8188_MDP_COMP_VPP1_SOUT, /* 13 */
+ MT8188_MDP_COMP_PQ0_SOUT, /* 14 */
+ MT8188_MDP_COMP_HDR0, /* 15 */
+ MT8188_MDP_COMP_HDR2, /* 16 */
+ MT8188_MDP_COMP_HDR3, /* 17 */
+ MT8188_MDP_COMP_AAL0, /* 18 */
+ MT8188_MDP_COMP_AAL2, /* 19 */
+ MT8188_MDP_COMP_AAL3, /* 20 */
+ MT8188_MDP_COMP_RSZ0, /* 21 */
+ MT8188_MDP_COMP_RSZ2, /* 22 */
+ MT8188_MDP_COMP_RSZ3, /* 23 */
+ MT8188_MDP_COMP_TDSHP0, /* 24 */
+ MT8188_MDP_COMP_TDSHP2, /* 25 */
+ MT8188_MDP_COMP_TDSHP3, /* 26 */
+ MT8188_MDP_COMP_COLOR0, /* 27 */
+ MT8188_MDP_COMP_COLOR2, /* 28 */
+ MT8188_MDP_COMP_COLOR3, /* 29 */
+ MT8188_MDP_COMP_OVL0, /* 30 */
+ MT8188_MDP_COMP_PAD0, /* 31 */
+ MT8188_MDP_COMP_PAD2, /* 32 */
+ MT8188_MDP_COMP_PAD3, /* 33 */
+ MT8188_MDP_COMP_TCC0, /* 34 */
+ MT8188_MDP_COMP_WROT0, /* 35 */
+ MT8188_MDP_COMP_WROT2, /* 36 */
+ MT8188_MDP_COMP_WROT3, /* 37 */
+ MT8188_MDP_COMP_MERGE2, /* 38 */
+ MT8188_MDP_COMP_MERGE3, /* 39 */
+};
+
enum mt8195_mdp_comp_id {
/* MT8195 Comp id */
/* ISP */
@@ -123,6 +170,13 @@ static const struct of_device_id mt8183_mdp_probe_infra[MDP_INFRA_MAX] = {
[MDP_INFRA_SCP] = { .compatible = "mediatek,mt8183-scp" }
};
+static const struct of_device_id mt8188_mdp_probe_infra[MDP_INFRA_MAX] = {
+ [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8188-vppsys0" },
+ [MDP_INFRA_MMSYS2] = { .compatible = "mediatek,mt8188-vppsys1" },
+ [MDP_INFRA_MUTEX] = { .compatible = "mediatek,mt8188-vpp-mutex" },
+ [MDP_INFRA_MUTEX2] = { .compatible = "mediatek,mt8188-vpp-mutex" },
+};
+
static const struct of_device_id mt8195_mdp_probe_infra[MDP_INFRA_MAX] = {
[MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8195-vppsys0" },
[MDP_INFRA_MMSYS2] = { .compatible = "mediatek,mt8195-vppsys1" },
@@ -167,6 +221,40 @@ static const u32 mt8183_mutex_idx[MDP_MAX_COMP_COUNT] = {
[MDP_COMP_CCORR0] = MUTEX_MOD_IDX_MDP_CCORR0,
};
+static const u32 mt8188_mutex_idx[MDP_MAX_COMP_COUNT] = {
+ [MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0,
+ [MDP_COMP_RDMA2] = MUTEX_MOD_IDX_MDP_RDMA2,
+ [MDP_COMP_RDMA3] = MUTEX_MOD_IDX_MDP_RDMA3,
+ [MDP_COMP_FG0] = MUTEX_MOD_IDX_MDP_FG0,
+ [MDP_COMP_FG2] = MUTEX_MOD_IDX_MDP_FG2,
+ [MDP_COMP_FG3] = MUTEX_MOD_IDX_MDP_FG3,
+ [MDP_COMP_HDR0] = MUTEX_MOD_IDX_MDP_HDR0,
+ [MDP_COMP_HDR2] = MUTEX_MOD_IDX_MDP_HDR2,
+ [MDP_COMP_HDR3] = MUTEX_MOD_IDX_MDP_HDR3,
+ [MDP_COMP_AAL0] = MUTEX_MOD_IDX_MDP_AAL0,
+ [MDP_COMP_AAL2] = MUTEX_MOD_IDX_MDP_AAL2,
+ [MDP_COMP_AAL3] = MUTEX_MOD_IDX_MDP_AAL3,
+ [MDP_COMP_RSZ0] = MUTEX_MOD_IDX_MDP_RSZ0,
+ [MDP_COMP_RSZ2] = MUTEX_MOD_IDX_MDP_RSZ2,
+ [MDP_COMP_RSZ3] = MUTEX_MOD_IDX_MDP_RSZ3,
+ [MDP_COMP_MERGE2] = MUTEX_MOD_IDX_MDP_MERGE2,
+ [MDP_COMP_MERGE3] = MUTEX_MOD_IDX_MDP_MERGE3,
+ [MDP_COMP_TDSHP0] = MUTEX_MOD_IDX_MDP_TDSHP0,
+ [MDP_COMP_TDSHP2] = MUTEX_MOD_IDX_MDP_TDSHP2,
+ [MDP_COMP_TDSHP3] = MUTEX_MOD_IDX_MDP_TDSHP3,
+ [MDP_COMP_COLOR0] = MUTEX_MOD_IDX_MDP_COLOR0,
+ [MDP_COMP_COLOR2] = MUTEX_MOD_IDX_MDP_COLOR2,
+ [MDP_COMP_COLOR3] = MUTEX_MOD_IDX_MDP_COLOR3,
+ [MDP_COMP_OVL0] = MUTEX_MOD_IDX_MDP_OVL0,
+ [MDP_COMP_PAD0] = MUTEX_MOD_IDX_MDP_PAD0,
+ [MDP_COMP_PAD2] = MUTEX_MOD_IDX_MDP_PAD2,
+ [MDP_COMP_PAD3] = MUTEX_MOD_IDX_MDP_PAD3,
+ [MDP_COMP_TCC0] = MUTEX_MOD_IDX_MDP_TCC0,
+ [MDP_COMP_WROT0] = MUTEX_MOD_IDX_MDP_WROT0,
+ [MDP_COMP_WROT2] = MUTEX_MOD_IDX_MDP_WROT2,
+ [MDP_COMP_WROT3] = MUTEX_MOD_IDX_MDP_WROT3,
+};
+
static const u32 mt8195_mutex_idx[MDP_MAX_COMP_COUNT] = {
[MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0,
[MDP_COMP_RDMA1] = MUTEX_MOD_IDX_MDP_RDMA1,
@@ -288,6 +376,171 @@ static const struct mdp_comp_data mt8183_mdp_comp_data[MDP_MAX_COMP_COUNT] = {
},
};
+static const struct mdp_comp_data mt8188_mdp_comp_data[MDP_MAX_COMP_COUNT] = {
+ [MDP_COMP_WPEI] = {
+ {MDP_COMP_TYPE_WPEI, 0, MT8188_MDP_COMP_WPEI, MDP_MM_SUBSYS_0},
+ {0, 0, 0}
+ },
+ [MDP_COMP_WPEO] = {
+ {MDP_COMP_TYPE_EXTO, 0, MT8188_MDP_COMP_WPEO, MDP_MM_SUBSYS_0},
+ {0, 0, 0}
+ },
+ [MDP_COMP_CAMIN] = {
+ {MDP_COMP_TYPE_DL_PATH, 0, MT8188_MDP_COMP_CAMIN, MDP_MM_SUBSYS_0},
+ {3, 3, 0}
+ },
+ [MDP_COMP_RDMA0] = {
+ {MDP_COMP_TYPE_RDMA, 0, MT8188_MDP_COMP_RDMA0, MDP_MM_SUBSYS_0},
+ {3, 0, 0}
+ },
+ [MDP_COMP_RDMA2] = {
+ {MDP_COMP_TYPE_RDMA, 1, MT8188_MDP_COMP_RDMA2, MDP_MM_SUBSYS_1},
+ {3, 0, 0}
+ },
+ [MDP_COMP_RDMA3] = {
+ {MDP_COMP_TYPE_RDMA, 2, MT8188_MDP_COMP_RDMA3, MDP_MM_SUBSYS_1},
+ {3, 0, 0}
+ },
+ [MDP_COMP_FG0] = {
+ {MDP_COMP_TYPE_FG, 0, MT8188_MDP_COMP_FG0, MDP_MM_SUBSYS_0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_FG2] = {
+ {MDP_COMP_TYPE_FG, 1, MT8188_MDP_COMP_FG2, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_FG3] = {
+ {MDP_COMP_TYPE_FG, 2, MT8188_MDP_COMP_FG3, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_HDR0] = {
+ {MDP_COMP_TYPE_HDR, 0, MT8188_MDP_COMP_HDR0, MDP_MM_SUBSYS_0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_HDR2] = {
+ {MDP_COMP_TYPE_HDR, 1, MT8188_MDP_COMP_HDR2, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_HDR3] = {
+ {MDP_COMP_TYPE_HDR, 2, MT8188_MDP_COMP_HDR3, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_AAL0] = {
+ {MDP_COMP_TYPE_AAL, 0, MT8188_MDP_COMP_AAL0, MDP_MM_SUBSYS_0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_AAL2] = {
+ {MDP_COMP_TYPE_AAL, 1, MT8188_MDP_COMP_AAL2, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_AAL3] = {
+ {MDP_COMP_TYPE_AAL, 2, MT8188_MDP_COMP_AAL3, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_RSZ0] = {
+ {MDP_COMP_TYPE_RSZ, 0, MT8188_MDP_COMP_RSZ0, MDP_MM_SUBSYS_0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_RSZ2] = {
+ {MDP_COMP_TYPE_RSZ, 1, MT8188_MDP_COMP_RSZ2, MDP_MM_SUBSYS_1},
+ {2, 0, 0},
+ {MDP_COMP_MERGE2, true, true}
+ },
+ [MDP_COMP_RSZ3] = {
+ {MDP_COMP_TYPE_RSZ, 2, MT8188_MDP_COMP_RSZ3, MDP_MM_SUBSYS_1},
+ {2, 0, 0},
+ {MDP_COMP_MERGE3, true, true}
+ },
+ [MDP_COMP_TDSHP0] = {
+ {MDP_COMP_TYPE_TDSHP, 0, MT8188_MDP_COMP_TDSHP0, MDP_MM_SUBSYS_0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_TDSHP2] = {
+ {MDP_COMP_TYPE_TDSHP, 1, MT8188_MDP_COMP_TDSHP2, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_TDSHP3] = {
+ {MDP_COMP_TYPE_TDSHP, 2, MT8188_MDP_COMP_TDSHP3, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_COLOR0] = {
+ {MDP_COMP_TYPE_COLOR, 0, MT8188_MDP_COMP_COLOR0, MDP_MM_SUBSYS_0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_COLOR2] = {
+ {MDP_COMP_TYPE_COLOR, 1, MT8188_MDP_COMP_COLOR2, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_COLOR3] = {
+ {MDP_COMP_TYPE_COLOR, 2, MT8188_MDP_COMP_COLOR3, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_OVL0] = {
+ {MDP_COMP_TYPE_OVL, 0, MT8188_MDP_COMP_OVL0, MDP_MM_SUBSYS_0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_PAD0] = {
+ {MDP_COMP_TYPE_PAD, 0, MT8188_MDP_COMP_PAD0, MDP_MM_SUBSYS_0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_PAD2] = {
+ {MDP_COMP_TYPE_PAD, 1, MT8188_MDP_COMP_PAD2, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_PAD3] = {
+ {MDP_COMP_TYPE_PAD, 2, MT8188_MDP_COMP_PAD3, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_TCC0] = {
+ {MDP_COMP_TYPE_TCC, 0, MT8188_MDP_COMP_TCC0, MDP_MM_SUBSYS_0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_WROT0] = {
+ {MDP_COMP_TYPE_WROT, 0, MT8188_MDP_COMP_WROT0, MDP_MM_SUBSYS_0},
+ {1, 0, 0}
+ },
+ [MDP_COMP_WROT2] = {
+ {MDP_COMP_TYPE_WROT, 1, MT8188_MDP_COMP_WROT2, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_WROT3] = {
+ {MDP_COMP_TYPE_WROT, 2, MT8188_MDP_COMP_WROT3, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_MERGE2] = {
+ {MDP_COMP_TYPE_MERGE, 0, MT8188_MDP_COMP_MERGE2, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_MERGE3] = {
+ {MDP_COMP_TYPE_MERGE, 1, MT8188_MDP_COMP_MERGE3, MDP_MM_SUBSYS_1},
+ {1, 0, 0}
+ },
+ [MDP_COMP_PQ0_SOUT] = {
+ {MDP_COMP_TYPE_DUMMY, 0, MT8188_MDP_COMP_PQ0_SOUT, MDP_MM_SUBSYS_0},
+ {0, 0, 0}
+ },
+ [MDP_COMP_TO_WARP0MOUT] = {
+ {MDP_COMP_TYPE_DUMMY, 1, MT8188_MDP_COMP_TO_WARP0MOUT, MDP_MM_SUBSYS_0},
+ {0, 0, 0}
+ },
+ [MDP_COMP_TO_SVPP2MOUT] = {
+ {MDP_COMP_TYPE_DUMMY, 2, MT8188_MDP_COMP_TO_SVPP2MOUT, MDP_MM_SUBSYS_1},
+ {0, 0, 0}
+ },
+ [MDP_COMP_TO_SVPP3MOUT] = {
+ {MDP_COMP_TYPE_DUMMY, 3, MT8188_MDP_COMP_TO_SVPP3MOUT, MDP_MM_SUBSYS_1},
+ {0, 0, 0}
+ },
+ [MDP_COMP_VPP0_SOUT] = {
+ {MDP_COMP_TYPE_PATH, 0, MT8188_MDP_COMP_VPP0_SOUT, MDP_MM_SUBSYS_1},
+ {2, 6, 0}
+ },
+ [MDP_COMP_VPP1_SOUT] = {
+ {MDP_COMP_TYPE_PATH, 1, MT8188_MDP_COMP_VPP1_SOUT, MDP_MM_SUBSYS_0},
+ {2, 8, 0}
+ },
+};
+
static const struct mdp_comp_data mt8195_mdp_comp_data[MDP_MAX_COMP_COUNT] = {
[MDP_COMP_WPEI] = {
{MDP_COMP_TYPE_WPEI, 0, MT8195_MDP_COMP_WPEI, MDP_MM_SUBSYS_0},
@@ -1046,6 +1299,15 @@ static const struct mdp_pipe_info mt8183_pipe_info[] = {
[MDP_PIPE_RDMA0] = {MDP_PIPE_RDMA0, MDP_MM_SUBSYS_0, 3}
};
+static const struct mdp_pipe_info mt8188_pipe_info[] = {
+ [MDP_PIPE_WPEI] = {MDP_PIPE_WPEI, MDP_MM_SUBSYS_0, 0},
+ [MDP_PIPE_RDMA0] = {MDP_PIPE_RDMA0, MDP_MM_SUBSYS_0, 1},
+ [MDP_PIPE_RDMA2] = {MDP_PIPE_RDMA2, MDP_MM_SUBSYS_1, 0},
+ [MDP_PIPE_RDMA3] = {MDP_PIPE_RDMA3, MDP_MM_SUBSYS_1, 1},
+ [MDP_PIPE_VPP1_SOUT] = {MDP_PIPE_VPP1_SOUT, MDP_MM_SUBSYS_0, 2},
+ [MDP_PIPE_VPP0_SOUT] = {MDP_PIPE_VPP0_SOUT, MDP_MM_SUBSYS_1, 2},
+};
+
static const struct mdp_pipe_info mt8195_pipe_info[] = {
[MDP_PIPE_WPEI] = {MDP_PIPE_WPEI, MDP_MM_SUBSYS_0, 0},
[MDP_PIPE_WPEI2] = {MDP_PIPE_WPEI2, MDP_MM_SUBSYS_0, 1},
@@ -1082,6 +1344,24 @@ const struct mtk_mdp_driver_data mt8183_mdp_driver_data = {
.pp_used = MDP_PP_USED_1,
};
+const struct mtk_mdp_driver_data mt8188_mdp_driver_data = {
+ .mdp_plat_id = MT8188,
+ .mdp_con_res = 0x14001000,
+ .mdp_probe_infra = mt8188_mdp_probe_infra,
+ .mdp_sub_comp_dt_ids = mt8195_sub_comp_dt_ids,
+ .mdp_cfg = &mt8195_plat_cfg,
+ .mdp_mutex_table_idx = mt8188_mutex_idx,
+ .comp_data = mt8188_mdp_comp_data,
+ .comp_data_len = ARRAY_SIZE(mt8188_mdp_comp_data),
+ .format = mt8195_formats,
+ .format_len = ARRAY_SIZE(mt8195_formats),
+ .def_limit = &mt8195_mdp_def_limit,
+ .pipe_info = mt8188_pipe_info,
+ .pipe_info_len = ARRAY_SIZE(mt8188_pipe_info),
+ .pp_criteria = &mt8195_mdp_pp_criteria,
+ .pp_used = MDP_PP_USED_2,
+};
+
const struct mtk_mdp_driver_data mt8195_mdp_driver_data = {
.mdp_plat_id = MT8195,
.mdp_con_res = 0x14001000,
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
index f83ac408306e..4764c5b5107b 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
+++ b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h
@@ -116,6 +116,7 @@ struct img_frameparam {
/* Platform config indicator */
#define MT8183 8183
+#define MT8188 8195
#define MT8195 8195
#define CFG_CHECK(plat, p_id) ((plat) == (p_id))
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h
index 49cdf45f6e59..7f7625299ce7 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h
@@ -10,6 +10,7 @@
#include <linux/types.h>
extern const struct mtk_mdp_driver_data mt8183_mdp_driver_data;
+extern const struct mtk_mdp_driver_data mt8188_mdp_driver_data;
extern const struct mtk_mdp_driver_data mt8195_mdp_driver_data;
struct mdp_dev;
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
index c1f3bf98120a..37e7b985d52c 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
@@ -21,6 +21,9 @@ static const struct of_device_id mdp_of_ids[] = {
{ .compatible = "mediatek,mt8183-mdp3-rdma",
.data = &mt8183_mdp_driver_data,
},
+ { .compatible = "mediatek,mt8188-mdp3-rdma",
+ .data = &mt8188_mdp_driver_data,
+ },
{ .compatible = "mediatek,mt8195-mdp3-rdma",
.data = &mt8195_mdp_driver_data,
},
diff --git a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c
index c60e4c193b25..fc4e34c29192 100644
--- a/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c
+++ b/drivers/media/platform/mediatek/vcodec/common/mtk_vcodec_util.c
@@ -63,7 +63,8 @@ int mtk_vcodec_mem_alloc(void *priv, struct mtk_vcodec_mem *mem)
id = dec_ctx->id;
}
- mem->va = dma_alloc_coherent(&plat_dev->dev, mem->size, &mem->dma_addr, GFP_KERNEL);
+ mem->va = dma_alloc_attrs(&plat_dev->dev, mem->size, &mem->dma_addr,
+ GFP_KERNEL, DMA_ATTR_ALLOC_SINGLE_PAGES);
if (!mem->va) {
mtk_v4l2_err(plat_dev, "%s dma_alloc size=0x%zx failed!",
__func__, mem->size);
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c
index 9107707de6c4..98838217b97d 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.c
@@ -80,21 +80,18 @@ static struct mtk_q_data *mtk_vdec_get_q_data(struct mtk_vcodec_dec_ctx *ctx,
return &ctx->q_data[MTK_Q_DATA_DST];
}
-static int vidioc_try_decoder_cmd(struct file *file, void *priv,
- struct v4l2_decoder_cmd *cmd)
+static int stateful_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
{
return v4l2_m2m_ioctl_try_decoder_cmd(file, priv, cmd);
}
-
-static int vidioc_decoder_cmd(struct file *file, void *priv,
- struct v4l2_decoder_cmd *cmd)
+static int stateful_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
{
struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv);
struct vb2_queue *src_vq, *dst_vq;
int ret;
- ret = vidioc_try_decoder_cmd(file, priv, cmd);
+ ret = stateful_try_decoder_cmd(file, priv, cmd);
if (ret)
return ret;
@@ -128,6 +125,57 @@ static int vidioc_decoder_cmd(struct file *file, void *priv,
return 0;
}
+static int stateless_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
+{
+ return v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, cmd);
+}
+
+static int stateless_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
+{
+ struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv);
+ int ret;
+
+ ret = v4l2_m2m_ioctl_stateless_try_decoder_cmd(file, priv, cmd);
+ if (ret)
+ return ret;
+
+ mtk_v4l2_vdec_dbg(3, ctx, "decoder cmd=%u", cmd->cmd);
+ switch (cmd->cmd) {
+ case V4L2_DEC_CMD_FLUSH:
+ /*
+ * If the flag of the output buffer is equals V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF,
+ * this command will prevent dequeueing the capture buffer containing the last
+ * decoded frame. Or do nothing
+ */
+ break;
+ default:
+ mtk_v4l2_vdec_err(ctx, "invalid stateless decoder cmd=%u", cmd->cmd);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vidioc_try_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
+{
+ struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv);
+
+ if (ctx->dev->vdec_pdata->uses_stateless_api)
+ return stateless_try_decoder_cmd(file, priv, cmd);
+
+ return stateful_try_decoder_cmd(file, priv, cmd);
+}
+
+static int vidioc_decoder_cmd(struct file *file, void *priv, struct v4l2_decoder_cmd *cmd)
+{
+ struct mtk_vcodec_dec_ctx *ctx = fh_to_dec_ctx(priv);
+
+ if (ctx->dev->vdec_pdata->uses_stateless_api)
+ return stateless_decoder_cmd(file, priv, cmd);
+
+ return stateful_decoder_cmd(file, priv, cmd);
+}
+
void mtk_vdec_unlock(struct mtk_vcodec_dec_ctx *ctx)
{
mutex_unlock(&ctx->dev->dec_mutex[ctx->hw_id]);
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c
index 4bc89c8644fe..5f848691cea4 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c
@@ -449,7 +449,7 @@ static int vdec_vp8_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
inst->frm_cnt, y_fb_dma, c_fb_dma, fb);
inst->cur_fb = fb;
- dec->bs_dma = (uint64_t)bs->dma_addr;
+ dec->bs_dma = bs->dma_addr;
dec->bs_sz = bs->size;
dec->cur_y_fb_dma = y_fb_dma;
dec->cur_c_fb_dma = c_fb_dma;
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c
index da6be556727b..145958206e38 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.c
@@ -233,6 +233,12 @@ int vpu_dec_init(struct vdec_vpu_inst *vpu)
mtk_vdec_debug(vpu->ctx, "vdec_inst=%p", vpu);
err = vcodec_vpu_send_msg(vpu, (void *)&msg, sizeof(msg));
+
+ if (IS_ERR_OR_NULL(vpu->vsi)) {
+ mtk_vdec_err(vpu->ctx, "invalid vdec vsi, status=%d", err);
+ return -EINVAL;
+ }
+
mtk_vdec_debug(vpu->ctx, "- ret=%d", err);
return err;
}
diff --git a/drivers/media/platform/nvidia/tegra-vde/h264.c b/drivers/media/platform/nvidia/tegra-vde/h264.c
index cfea5572a1b8..d8812fc06c67 100644
--- a/drivers/media/platform/nvidia/tegra-vde/h264.c
+++ b/drivers/media/platform/nvidia/tegra-vde/h264.c
@@ -19,11 +19,6 @@
#define FLAG_B_FRAME 0x1
#define FLAG_REFERENCE 0x2
-struct tegra_vde_h264_frame {
- unsigned int frame_num;
- unsigned int flags;
-};
-
struct tegra_vde_h264_decoder_ctx {
unsigned int dpb_frames_nb;
unsigned int dpb_ref_frames_with_earlier_poc_nb;
diff --git a/drivers/media/platform/nvidia/tegra-vde/vde.h b/drivers/media/platform/nvidia/tegra-vde/vde.h
index 0fbb1f3d2c88..b2890484b7c3 100644
--- a/drivers/media/platform/nvidia/tegra-vde/vde.h
+++ b/drivers/media/platform/nvidia/tegra-vde/vde.h
@@ -47,7 +47,6 @@ struct iommu_group;
struct iommu_domain;
struct reset_control;
struct dma_buf_attachment;
-struct tegra_vde_h264_frame;
struct tegra_vde_h264_decoder_ctx;
struct tegra_video_frame {
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index cc97790ed30f..1d8913813037 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -1634,6 +1634,9 @@ static int mxc_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
dev_dbg(ctx->mxc_jpeg->dev, "Start streaming ctx=%p", ctx);
q_data->sequence = 0;
+ if (V4L2_TYPE_IS_CAPTURE(q->type))
+ ctx->need_initial_source_change_evt = false;
+
ret = pm_runtime_resume_and_get(ctx->mxc_jpeg->dev);
if (ret < 0) {
dev_err(ctx->mxc_jpeg->dev, "Failed to power up jpeg\n");
@@ -1840,17 +1843,6 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb)
q_data_out = mxc_jpeg_get_q_data(ctx,
V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE);
- if (q_data_out->w == 0 && q_data_out->h == 0) {
- dev_warn(dev, "Invalid user resolution 0x0");
- dev_warn(dev, "Keeping resolution from JPEG: %dx%d",
- header.frame.width, header.frame.height);
- } else if (header.frame.width != q_data_out->w ||
- header.frame.height != q_data_out->h) {
- dev_err(dev,
- "Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)",
- header.frame.width, header.frame.height,
- q_data_out->w, q_data_out->h);
- }
q_data_out->w = header.frame.width;
q_data_out->h = header.frame.height;
if (header.frame.width > MXC_JPEG_MAX_WIDTH ||
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index f49b06978f14..b9729a8883d6 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -320,7 +320,11 @@ struct mipi_csis_device {
struct v4l2_subdev sd;
struct media_pad pads[CSIS_PADS_NUM];
struct v4l2_async_notifier notifier;
- struct v4l2_subdev *src_sd;
+
+ struct {
+ struct v4l2_subdev *sd;
+ const struct media_pad *pad;
+ } source;
struct v4l2_mbus_config_mipi_csi2 bus;
u32 clk_frequency;
@@ -597,7 +601,7 @@ static int mipi_csis_calculate_params(struct mipi_csis_device *csis,
u32 lane_rate;
/* Calculate the line rate from the pixel rate. */
- link_freq = v4l2_get_link_freq(csis->src_sd->ctrl_handler,
+ link_freq = v4l2_get_link_freq(csis->source.sd->ctrl_handler,
csis_fmt->width,
csis->bus.num_data_lanes * 2);
if (link_freq < 0) {
@@ -958,7 +962,8 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable)
int ret;
if (!enable) {
- v4l2_subdev_call(csis->src_sd, video, s_stream, 0);
+ v4l2_subdev_disable_streams(csis->source.sd,
+ csis->source.pad->index, BIT(0));
mipi_csis_stop_stream(csis);
if (csis->debug.enable)
@@ -986,7 +991,8 @@ static int mipi_csis_s_stream(struct v4l2_subdev *sd, int enable)
mipi_csis_start_stream(csis, format, csis_fmt);
- ret = v4l2_subdev_call(csis->src_sd, video, s_stream, 1);
+ ret = v4l2_subdev_enable_streams(csis->source.sd,
+ csis->source.pad->index, BIT(0));
if (ret < 0)
goto err_stop;
@@ -1233,12 +1239,14 @@ static int mipi_csis_link_setup(struct media_entity *entity,
remote_sd = media_entity_to_v4l2_subdev(remote_pad->entity);
if (flags & MEDIA_LNK_FL_ENABLED) {
- if (csis->src_sd)
+ if (csis->source.sd)
return -EBUSY;
- csis->src_sd = remote_sd;
+ csis->source.sd = remote_sd;
+ csis->source.pad = remote_pad;
} else {
- csis->src_sd = NULL;
+ csis->source.sd = NULL;
+ csis->source.pad = NULL;
}
return 0;
diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c
index e62dc5c1a4ae..e4427e6487fb 100644
--- a/drivers/media/platform/nxp/imx-pxp.c
+++ b/drivers/media/platform/nxp/imx-pxp.c
@@ -1805,6 +1805,9 @@ static int pxp_probe(struct platform_device *pdev)
return PTR_ERR(mmio);
dev->regmap = devm_regmap_init_mmio(&pdev->dev, mmio,
&pxp_regmap_config);
+ if (IS_ERR(dev->regmap))
+ return dev_err_probe(&pdev->dev, PTR_ERR(dev->regmap),
+ "Failed to init regmap\n");
irq = platform_get_irq(pdev, 0);
if (irq < 0)
diff --git a/drivers/media/platform/qcom/camss/Makefile b/drivers/media/platform/qcom/camss/Makefile
index 0d4389ab312d..e636968a1126 100644
--- a/drivers/media/platform/qcom/camss/Makefile
+++ b/drivers/media/platform/qcom/camss/Makefile
@@ -19,5 +19,6 @@ qcom-camss-objs += \
camss-vfe-gen1.o \
camss-vfe.o \
camss-video.o \
+ camss-format.o \
obj-$(CONFIG_VIDEO_QCOM_CAMSS) += qcom-camss.o
diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-1.c b/drivers/media/platform/qcom/camss/camss-csid-4-1.c
index dd49a40e6a70..c95861420502 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-4-1.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-4-1.c
@@ -45,128 +45,6 @@
#define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b0 + 0xc * (n))
#define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0b4 + 0xc * (n))
-static const struct csid_format csid_formats[] = {
- {
- MEDIA_BUS_FMT_UYVY8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_VYUY8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_YUYV8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_YVYU8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_SBGGR8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SBGGR10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SBGGR12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_Y10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
-};
-
static void csid_configure_stream(struct csid_device *csid, u8 enable)
{
struct csid_testgen_config *tg = &csid->testgen;
@@ -174,7 +52,7 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
if (enable) {
struct v4l2_mbus_framefmt *input_format;
- const struct csid_format *format;
+ const struct csid_format_info *format;
u8 vc = 0; /* Virtual Channel 0 */
u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
u8 dt_shift;
@@ -184,7 +62,8 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
u32 num_lines, num_bytes_per_line;
input_format = &csid->fmt[MSM_CSID_PAD_SRC];
- format = csid_get_fmt_entry(csid->formats, csid->nformats,
+ format = csid_get_fmt_entry(csid->res->formats->formats,
+ csid->res->formats->nformats,
input_format->code);
num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
num_lines = input_format->height;
@@ -211,7 +90,8 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
struct csid_phy_config *phy = &csid->phy;
input_format = &csid->fmt[MSM_CSID_PAD_SINK];
- format = csid_get_fmt_entry(csid->formats, csid->nformats,
+ format = csid_get_fmt_entry(csid->res->formats->formats,
+ csid->res->formats->nformats,
input_format->code);
val = phy->lane_cnt - 1;
@@ -311,8 +191,6 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
static void csid_subdev_init(struct csid_device *csid)
{
- csid->formats = csid_formats;
- csid->nformats = ARRAY_SIZE(csid_formats);
csid->testgen.modes = csid_testgen_modes;
csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1;
}
diff --git a/drivers/media/platform/qcom/camss/camss-csid-4-7.c b/drivers/media/platform/qcom/camss/camss-csid-4-7.c
index 6b26e036294e..08578a143688 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-4-7.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-4-7.c
@@ -44,156 +44,6 @@
#define CAMSS_CSID_TG_DT_n_CGG_1(n) (0x0b8 + 0xc * (n))
#define CAMSS_CSID_TG_DT_n_CGG_2(n) (0x0bc + 0xc * (n))
-static const struct csid_format csid_formats[] = {
- {
- MEDIA_BUS_FMT_UYVY8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_VYUY8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_YUYV8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_YVYU8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_SBGGR8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SBGGR10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SBGGR12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SBGGR14_1X14,
- DATA_TYPE_RAW_14BIT,
- DECODE_FORMAT_UNCOMPRESSED_14_BIT,
- 14,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG14_1X14,
- DATA_TYPE_RAW_14BIT,
- DECODE_FORMAT_UNCOMPRESSED_14_BIT,
- 14,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG14_1X14,
- DATA_TYPE_RAW_14BIT,
- DECODE_FORMAT_UNCOMPRESSED_14_BIT,
- 14,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB14_1X14,
- DATA_TYPE_RAW_14BIT,
- DECODE_FORMAT_UNCOMPRESSED_14_BIT,
- 14,
- 1,
- },
- {
- MEDIA_BUS_FMT_Y10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
-};
-
static void csid_configure_stream(struct csid_device *csid, u8 enable)
{
struct csid_testgen_config *tg = &csid->testgen;
@@ -203,7 +53,7 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
if (enable) {
struct v4l2_mbus_framefmt *input_format;
- const struct csid_format *format;
+ const struct csid_format_info *format;
u8 vc = 0; /* Virtual Channel 0 */
u8 cid = vc * 4; /* id of Virtual Channel and Data Type set */
u8 dt_shift;
@@ -213,7 +63,8 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
u32 num_bytes_per_line, num_lines;
input_format = &csid->fmt[MSM_CSID_PAD_SRC];
- format = csid_get_fmt_entry(csid->formats, csid->nformats,
+ format = csid_get_fmt_entry(csid->res->formats->formats,
+ csid->res->formats->nformats,
input_format->code);
num_bytes_per_line = input_format->width * format->bpp * format->spp / 8;
num_lines = input_format->height;
@@ -240,7 +91,8 @@ static void csid_configure_stream(struct csid_device *csid, u8 enable)
struct csid_phy_config *phy = &csid->phy;
input_format = &csid->fmt[MSM_CSID_PAD_SINK];
- format = csid_get_fmt_entry(csid->formats, csid->nformats,
+ format = csid_get_fmt_entry(csid->res->formats->formats,
+ csid->res->formats->nformats,
input_format->code);
val = phy->lane_cnt - 1;
@@ -387,8 +239,6 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
static void csid_subdev_init(struct csid_device *csid)
{
- csid->formats = csid_formats;
- csid->nformats = ARRAY_SIZE(csid_formats);
csid->testgen.modes = csid_testgen_modes;
csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN1;
}
diff --git a/drivers/media/platform/qcom/camss/camss-csid-gen2.c b/drivers/media/platform/qcom/camss/camss-csid-gen2.c
index b11de4797cca..e1c757933e27 100644
--- a/drivers/media/platform/qcom/camss/camss-csid-gen2.c
+++ b/drivers/media/platform/qcom/camss/camss-csid-gen2.c
@@ -176,306 +176,171 @@
#define TPG_COLOR_BOX_CFG_MODE 0
#define TPG_COLOR_BOX_PATTERN_SEL 2
-static const struct csid_format csid_formats[] = {
- {
- MEDIA_BUS_FMT_UYVY8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_VYUY8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_YUYV8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_YVYU8_1X16,
- DATA_TYPE_YUV422_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 2,
- },
- {
- MEDIA_BUS_FMT_SBGGR8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_SBGGR10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_Y8_1X8,
- DATA_TYPE_RAW_8BIT,
- DECODE_FORMAT_UNCOMPRESSED_8_BIT,
- 8,
- 1,
- },
- {
- MEDIA_BUS_FMT_Y10_1X10,
- DATA_TYPE_RAW_10BIT,
- DECODE_FORMAT_UNCOMPRESSED_10_BIT,
- 10,
- 1,
- },
- {
- MEDIA_BUS_FMT_SBGGR12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB12_1X12,
- DATA_TYPE_RAW_12BIT,
- DECODE_FORMAT_UNCOMPRESSED_12_BIT,
- 12,
- 1,
- },
- {
- MEDIA_BUS_FMT_SBGGR14_1X14,
- DATA_TYPE_RAW_14BIT,
- DECODE_FORMAT_UNCOMPRESSED_14_BIT,
- 14,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGBRG14_1X14,
- DATA_TYPE_RAW_14BIT,
- DECODE_FORMAT_UNCOMPRESSED_14_BIT,
- 14,
- 1,
- },
- {
- MEDIA_BUS_FMT_SGRBG14_1X14,
- DATA_TYPE_RAW_14BIT,
- DECODE_FORMAT_UNCOMPRESSED_14_BIT,
- 14,
- 1,
- },
- {
- MEDIA_BUS_FMT_SRGGB14_1X14,
- DATA_TYPE_RAW_14BIT,
- DECODE_FORMAT_UNCOMPRESSED_14_BIT,
- 14,
- 1,
- },
-};
-
-static void __csid_configure_stream(struct csid_device *csid, u8 enable, u8 vc)
+static void __csid_configure_rx(struct csid_device *csid,
+ struct csid_phy_config *phy, int vc)
{
- struct csid_testgen_config *tg = &csid->testgen;
- u32 val;
- u32 phy_sel = 0;
u8 lane_cnt = csid->phy.lane_cnt;
- /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */
- struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc];
- const struct csid_format *format = csid_get_fmt_entry(csid->formats, csid->nformats,
- input_format->code);
+ int val;
if (!lane_cnt)
lane_cnt = 4;
- if (!tg->enabled)
- phy_sel = csid->phy.csiphy_id;
-
- if (enable) {
- /*
- * DT_ID is a two bit bitfield that is concatenated with
- * the four least significant bits of the five bit VC
- * bitfield to generate an internal CID value.
- *
- * CSID_RDI_CFG0(vc)
- * DT_ID : 28:27
- * VC : 26:22
- * DT : 21:16
- *
- * CID : VC 3:0 << 2 | DT_ID 1:0
- */
- u8 dt_id = vc & 0x03;
-
- if (tg->enabled) {
- /* configure one DT, infinite frames */
- val = vc << TPG_VC_CFG0_VC_NUM;
- val |= INTELEAVING_MODE_ONE_SHOT << TPG_VC_CFG0_LINE_INTERLEAVING_MODE;
- val |= 0 << TPG_VC_CFG0_NUM_FRAMES;
- writel_relaxed(val, csid->base + CSID_TPG_VC_CFG0);
-
- val = 0x740 << TPG_VC_CFG1_H_BLANKING_COUNT;
- val |= 0x3ff << TPG_VC_CFG1_V_BLANKING_COUNT;
- writel_relaxed(val, csid->base + CSID_TPG_VC_CFG1);
-
- writel_relaxed(0x12345678, csid->base + CSID_TPG_LFSR_SEED);
-
- val = (input_format->height & 0x1fff) << TPG_DT_n_CFG_0_FRAME_HEIGHT;
- val |= (input_format->width & 0x1fff) << TPG_DT_n_CFG_0_FRAME_WIDTH;
- writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_0(0));
-
- val = format->data_type << TPG_DT_n_CFG_1_DATA_TYPE;
- writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_1(0));
-
- val = (tg->mode - 1) << TPG_DT_n_CFG_2_PAYLOAD_MODE;
- val |= 0xBE << TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD;
- val |= format->decode_format << TPG_DT_n_CFG_2_ENCODE_FORMAT;
- writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_2(0));
-
- writel_relaxed(0, csid->base + CSID_TPG_COLOR_BARS_CFG);
-
- writel_relaxed(0, csid->base + CSID_TPG_COLOR_BOX_CFG);
- }
+ val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES;
+ val |= phy->lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL;
+ val |= phy->csiphy_id << CSI2_RX_CFG0_PHY_NUM_SEL;
+ writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0);
- val = 1 << RDI_CFG0_BYTE_CNTR_EN;
- val |= 1 << RDI_CFG0_FORMAT_MEASURE_EN;
- val |= 1 << RDI_CFG0_TIMESTAMP_EN;
- /* note: for non-RDI path, this should be format->decode_format */
- val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT;
- val |= format->data_type << RDI_CFG0_DATA_TYPE;
- val |= vc << RDI_CFG0_VIRTUAL_CHANNEL;
- val |= dt_id << RDI_CFG0_DT_ID;
- writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc));
+ val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN;
+ if (vc > 3)
+ val |= 1 << CSI2_RX_CFG1_VC_MODE;
+ val |= 1 << CSI2_RX_CFG1_MISR_EN;
+ writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1);
+}
- /* CSID_TIMESTAMP_STB_POST_IRQ */
- val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL;
- writel_relaxed(val, csid->base + CSID_RDI_CFG1(vc));
+static void __csid_ctrl_rdi(struct csid_device *csid, int enable, u8 rdi)
+{
+ int val;
- val = 1;
- writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc));
+ if (enable)
+ val = HALT_CMD_RESUME_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD;
+ else
+ val = HALT_CMD_HALT_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD;
+ writel_relaxed(val, csid->base + CSID_RDI_CTRL(rdi));
+}
- val = 0;
- writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(vc));
+static void __csid_configure_testgen(struct csid_device *csid, u8 enable, u8 vc)
+{
+ struct csid_testgen_config *tg = &csid->testgen;
+ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc];
+ const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats,
+ csid->res->formats->nformats,
+ input_format->code);
+ u8 lane_cnt = csid->phy.lane_cnt;
+ u32 val;
- val = 1;
- writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc));
+ if (!lane_cnt)
+ lane_cnt = 4;
- val = 0;
- writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc));
+ /* configure one DT, infinite frames */
+ val = vc << TPG_VC_CFG0_VC_NUM;
+ val |= INTELEAVING_MODE_ONE_SHOT << TPG_VC_CFG0_LINE_INTERLEAVING_MODE;
+ val |= 0 << TPG_VC_CFG0_NUM_FRAMES;
+ writel_relaxed(val, csid->base + CSID_TPG_VC_CFG0);
- val = 1;
- writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(vc));
+ val = 0x740 << TPG_VC_CFG1_H_BLANKING_COUNT;
+ val |= 0x3ff << TPG_VC_CFG1_V_BLANKING_COUNT;
+ writel_relaxed(val, csid->base + CSID_TPG_VC_CFG1);
- val = 0;
- writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(vc));
+ writel_relaxed(0x12345678, csid->base + CSID_TPG_LFSR_SEED);
- val = 1;
- writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(vc));
+ val = (input_format->height & 0x1fff) << TPG_DT_n_CFG_0_FRAME_HEIGHT;
+ val |= (input_format->width & 0x1fff) << TPG_DT_n_CFG_0_FRAME_WIDTH;
+ writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_0(0));
- val = 0;
- writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(vc));
+ val = format->data_type << TPG_DT_n_CFG_1_DATA_TYPE;
+ writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_1(0));
- val = 0;
- writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc));
+ val = (tg->mode - 1) << TPG_DT_n_CFG_2_PAYLOAD_MODE;
+ val |= 0xBE << TPG_DT_n_CFG_2_USER_SPECIFIED_PAYLOAD;
+ val |= format->decode_format << TPG_DT_n_CFG_2_ENCODE_FORMAT;
+ writel_relaxed(val, csid->base + CSID_TPG_DT_n_CFG_2(0));
- val = readl_relaxed(csid->base + CSID_RDI_CFG0(vc));
- val |= 1 << RDI_CFG0_ENABLE;
- writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc));
- }
+ writel_relaxed(0, csid->base + CSID_TPG_COLOR_BARS_CFG);
- if (tg->enabled) {
- val = enable << TPG_CTRL_TEST_EN;
- val |= 1 << TPG_CTRL_FS_PKT_EN;
- val |= 1 << TPG_CTRL_FE_PKT_EN;
- val |= (lane_cnt - 1) << TPG_CTRL_NUM_ACTIVE_LANES;
- val |= 0x64 << TPG_CTRL_CYCLES_BETWEEN_PKTS;
- val |= 0xA << TPG_CTRL_NUM_TRAIL_BYTES;
- writel_relaxed(val, csid->base + CSID_TPG_CTRL);
- }
+ writel_relaxed(0, csid->base + CSID_TPG_COLOR_BOX_CFG);
- val = (lane_cnt - 1) << CSI2_RX_CFG0_NUM_ACTIVE_LANES;
- val |= csid->phy.lane_assign << CSI2_RX_CFG0_DL0_INPUT_SEL;
- val |= phy_sel << CSI2_RX_CFG0_PHY_NUM_SEL;
- writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG0);
+ val = enable << TPG_CTRL_TEST_EN;
+ val |= 1 << TPG_CTRL_FS_PKT_EN;
+ val |= 1 << TPG_CTRL_FE_PKT_EN;
+ val |= (lane_cnt - 1) << TPG_CTRL_NUM_ACTIVE_LANES;
+ val |= 0x64 << TPG_CTRL_CYCLES_BETWEEN_PKTS;
+ val |= 0xA << TPG_CTRL_NUM_TRAIL_BYTES;
+ writel_relaxed(val, csid->base + CSID_TPG_CTRL);
+}
- val = 1 << CSI2_RX_CFG1_PACKET_ECC_CORRECTION_EN;
- if (vc > 3)
- val |= 1 << CSI2_RX_CFG1_VC_MODE;
- val |= 1 << CSI2_RX_CFG1_MISR_EN;
- writel_relaxed(val, csid->base + CSID_CSI2_RX_CFG1);
+static void __csid_configure_rdi_stream(struct csid_device *csid, u8 enable, u8 vc)
+{
+ /* Source pads matching RDI channels on hardware. Pad 1 -> RDI0, Pad 2 -> RDI1, etc. */
+ struct v4l2_mbus_framefmt *input_format = &csid->fmt[MSM_CSID_PAD_FIRST_SRC + vc];
+ const struct csid_format_info *format = csid_get_fmt_entry(csid->res->formats->formats,
+ csid->res->formats->nformats,
+ input_format->code);
+ u32 val;
- if (enable)
- val = HALT_CMD_RESUME_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD;
- else
- val = HALT_CMD_HALT_AT_FRAME_BOUNDARY << RDI_CTRL_HALT_CMD;
+ /*
+ * DT_ID is a two bit bitfield that is concatenated with
+ * the four least significant bits of the five bit VC
+ * bitfield to generate an internal CID value.
+ *
+ * CSID_RDI_CFG0(vc)
+ * DT_ID : 28:27
+ * VC : 26:22
+ * DT : 21:16
+ *
+ * CID : VC 3:0 << 2 | DT_ID 1:0
+ */
+ u8 dt_id = vc & 0x03;
+
+ val = 1 << RDI_CFG0_BYTE_CNTR_EN;
+ val |= 1 << RDI_CFG0_FORMAT_MEASURE_EN;
+ val |= 1 << RDI_CFG0_TIMESTAMP_EN;
+ /* note: for non-RDI path, this should be format->decode_format */
+ val |= DECODE_FORMAT_PAYLOAD_ONLY << RDI_CFG0_DECODE_FORMAT;
+ val |= format->data_type << RDI_CFG0_DATA_TYPE;
+ val |= vc << RDI_CFG0_VIRTUAL_CHANNEL;
+ val |= dt_id << RDI_CFG0_DT_ID;
+ writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc));
+
+ /* CSID_TIMESTAMP_STB_POST_IRQ */
+ val = 2 << RDI_CFG1_TIMESTAMP_STB_SEL;
+ writel_relaxed(val, csid->base + CSID_RDI_CFG1(vc));
+
+ val = 1;
+ writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PERIOD(vc));
+
+ val = 0;
+ writel_relaxed(val, csid->base + CSID_RDI_FRM_DROP_PATTERN(vc));
+
+ val = 1;
+ writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PERIOD(vc));
+
+ val = 0;
+ writel_relaxed(val, csid->base + CSID_RDI_IRQ_SUBSAMPLE_PATTERN(vc));
+
+ val = 1;
+ writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PERIOD(vc));
+
+ val = 0;
+ writel_relaxed(val, csid->base + CSID_RDI_RPP_PIX_DROP_PATTERN(vc));
+
+ val = 1;
+ writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PERIOD(vc));
+
+ val = 0;
+ writel_relaxed(val, csid->base + CSID_RDI_RPP_LINE_DROP_PATTERN(vc));
+
+ val = 0;
writel_relaxed(val, csid->base + CSID_RDI_CTRL(vc));
+
+ val = readl_relaxed(csid->base + CSID_RDI_CFG0(vc));
+ val |= enable << RDI_CFG0_ENABLE;
+ writel_relaxed(val, csid->base + CSID_RDI_CFG0(vc));
}
static void csid_configure_stream(struct csid_device *csid, u8 enable)
{
+ struct csid_testgen_config *tg = &csid->testgen;
u8 i;
/* Loop through all enabled VCs and configure stream for each */
for (i = 0; i < MSM_CSID_MAX_SRC_STREAMS; i++)
- if (csid->phy.en_vc & BIT(i))
- __csid_configure_stream(csid, enable, i);
+ if (csid->phy.en_vc & BIT(i)) {
+ if (tg->enabled)
+ __csid_configure_testgen(csid, enable, i);
+
+ __csid_configure_rdi_stream(csid, enable, i);
+ __csid_configure_rx(csid, &csid->phy, i);
+ __csid_ctrl_rdi(csid, enable, i);
+ }
}
static int csid_configure_testgen_pattern(struct csid_device *csid, s32 val)
@@ -612,8 +477,6 @@ static u32 csid_src_pad_code(struct csid_device *csid, u32 sink_code,
static void csid_subdev_init(struct csid_device *csid)
{
- csid->formats = csid_formats;
- csid->nformats = ARRAY_SIZE(csid_formats);
csid->testgen.modes = csid_testgen_modes;
csid->testgen.nmodes = CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2;
}
diff --git a/drivers/media/platform/qcom/camss/camss-csid.c b/drivers/media/platform/qcom/camss/camss-csid.c
index eb27d69e89a1..858db5d4ca75 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.c
+++ b/drivers/media/platform/qcom/camss/camss-csid.c
@@ -45,6 +45,450 @@ const char * const csid_testgen_modes[] = {
NULL
};
+static const struct csid_format_info formats_4_1[] = {
+ {
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_VYUY8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_YUYV8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_YVYU8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_Y10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+};
+
+static const struct csid_format_info formats_4_7[] = {
+ {
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_VYUY8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_YUYV8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_YVYU8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR14_1X14,
+ DATA_TYPE_RAW_14BIT,
+ DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+ 14,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG14_1X14,
+ DATA_TYPE_RAW_14BIT,
+ DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+ 14,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG14_1X14,
+ DATA_TYPE_RAW_14BIT,
+ DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+ 14,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB14_1X14,
+ DATA_TYPE_RAW_14BIT,
+ DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+ 14,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_Y10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+};
+
+static const struct csid_format_info formats_gen2[] = {
+ {
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_VYUY8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_YUYV8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_YVYU8_1X16,
+ DATA_TYPE_YUV422_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 2,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_Y8_1X8,
+ DATA_TYPE_RAW_8BIT,
+ DECODE_FORMAT_UNCOMPRESSED_8_BIT,
+ 8,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_Y10_1X10,
+ DATA_TYPE_RAW_10BIT,
+ DECODE_FORMAT_UNCOMPRESSED_10_BIT,
+ 10,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+ DATA_TYPE_RAW_12BIT,
+ DECODE_FORMAT_UNCOMPRESSED_12_BIT,
+ 12,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SBGGR14_1X14,
+ DATA_TYPE_RAW_14BIT,
+ DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+ 14,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGBRG14_1X14,
+ DATA_TYPE_RAW_14BIT,
+ DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+ 14,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SGRBG14_1X14,
+ DATA_TYPE_RAW_14BIT,
+ DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+ 14,
+ 1,
+ },
+ {
+ MEDIA_BUS_FMT_SRGGB14_1X14,
+ DATA_TYPE_RAW_14BIT,
+ DECODE_FORMAT_UNCOMPRESSED_14_BIT,
+ 14,
+ 1,
+ },
+};
+
+const struct csid_formats csid_formats_4_1 = {
+ .nformats = ARRAY_SIZE(formats_4_1),
+ .formats = formats_4_1
+};
+
+const struct csid_formats csid_formats_4_7 = {
+ .nformats = ARRAY_SIZE(formats_4_7),
+ .formats = formats_4_7
+};
+
+const struct csid_formats csid_formats_gen2 = {
+ .nformats = ARRAY_SIZE(formats_gen2),
+ .formats = formats_gen2
+};
+
u32 csid_find_code(u32 *codes, unsigned int ncodes,
unsigned int match_format_idx, u32 match_code)
{
@@ -65,9 +509,9 @@ u32 csid_find_code(u32 *codes, unsigned int ncodes,
return codes[0];
}
-const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats,
- unsigned int nformats,
- u32 code)
+const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info *formats,
+ unsigned int nformats,
+ u32 code)
{
unsigned int i;
@@ -87,12 +531,12 @@ const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats,
static int csid_set_clock_rates(struct csid_device *csid)
{
struct device *dev = csid->camss->dev;
- const struct csid_format *fmt;
+ const struct csid_format_info *fmt;
s64 link_freq;
int i, j;
int ret;
- fmt = csid_get_fmt_entry(csid->formats, csid->nformats,
+ fmt = csid_get_fmt_entry(csid->res->formats->formats, csid->res->formats->nformats,
csid->fmt[MSM_CSIPHY_PAD_SINK].code);
link_freq = camss_get_link_freq(&csid->subdev.entity, fmt->bpp,
csid->phy.lane_cnt);
@@ -158,7 +602,6 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
struct csid_device *csid = v4l2_get_subdevdata(sd);
struct camss *camss = csid->camss;
struct device *dev = camss->dev;
- struct vfe_device *vfe = &camss->vfe[csid->id];
int ret = 0;
if (on) {
@@ -167,7 +610,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
* switching on the CSID. Do so unconditionally, as there is no
* drawback in following the same powering order on older SoCs.
*/
- ret = vfe_get(vfe);
+ ret = csid->res->parent_dev_ops->get(camss, csid->id);
if (ret < 0)
return ret;
@@ -202,7 +645,7 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
enable_irq(csid->irq);
- ret = csid->ops->reset(csid);
+ ret = csid->res->hw_ops->reset(csid);
if (ret < 0) {
disable_irq(csid->irq);
camss_disable_clocks(csid->nclocks, csid->clock);
@@ -212,14 +655,14 @@ static int csid_set_power(struct v4l2_subdev *sd, int on)
return ret;
}
- csid->ops->hw_version(csid);
+ csid->res->hw_ops->hw_version(csid);
} else {
disable_irq(csid->irq);
camss_disable_clocks(csid->nclocks, csid->clock);
regulator_bulk_disable(csid->num_supplies,
csid->supplies);
pm_runtime_put_sync(dev);
- vfe_put(vfe);
+ csid->res->parent_dev_ops->put(camss, csid->id);
}
return ret;
@@ -253,7 +696,7 @@ static int csid_set_stream(struct v4l2_subdev *sd, int enable)
}
if (csid->phy.need_vc_update) {
- csid->ops->configure_stream(csid, enable);
+ csid->res->hw_ops->configure_stream(csid, enable);
csid->phy.need_vc_update = false;
}
@@ -301,12 +744,12 @@ static void csid_try_format(struct csid_device *csid,
case MSM_CSID_PAD_SINK:
/* Set format on sink pad */
- for (i = 0; i < csid->nformats; i++)
- if (fmt->code == csid->formats[i].code)
+ for (i = 0; i < csid->res->formats->nformats; i++)
+ if (fmt->code == csid->res->formats->formats[i].code)
break;
/* If not found, use UYVY as default */
- if (i >= csid->nformats)
+ if (i >= csid->res->formats->nformats)
fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
fmt->width = clamp_t(u32, fmt->width, 1, 8191);
@@ -325,17 +768,17 @@ static void csid_try_format(struct csid_device *csid,
*fmt = *__csid_get_format(csid, sd_state,
MSM_CSID_PAD_SINK, which);
- fmt->code = csid->ops->src_pad_code(csid, fmt->code, 0, code);
+ fmt->code = csid->res->hw_ops->src_pad_code(csid, fmt->code, 0, code);
} else {
/* Test generator is enabled, set format on source */
/* pad to allow test generator usage */
- for (i = 0; i < csid->nformats; i++)
- if (csid->formats[i].code == fmt->code)
+ for (i = 0; i < csid->res->formats->nformats; i++)
+ if (csid->res->formats->formats[i].code == fmt->code)
break;
/* If not found, use UYVY as default */
- if (i >= csid->nformats)
+ if (i >= csid->res->formats->nformats)
fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
fmt->width = clamp_t(u32, fmt->width, 1, 8191);
@@ -363,10 +806,10 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,
struct csid_device *csid = v4l2_get_subdevdata(sd);
if (code->pad == MSM_CSID_PAD_SINK) {
- if (code->index >= csid->nformats)
+ if (code->index >= csid->res->formats->nformats)
return -EINVAL;
- code->code = csid->formats[code->index].code;
+ code->code = csid->res->formats->formats[code->index].code;
} else {
if (csid->testgen_mode->cur.val == 0) {
struct v4l2_mbus_framefmt *sink_fmt;
@@ -375,15 +818,15 @@ static int csid_enum_mbus_code(struct v4l2_subdev *sd,
MSM_CSID_PAD_SINK,
code->which);
- code->code = csid->ops->src_pad_code(csid, sink_fmt->code,
- code->index, 0);
+ code->code = csid->res->hw_ops->src_pad_code(csid, sink_fmt->code,
+ code->index, 0);
if (!code->code)
return -EINVAL;
} else {
- if (code->index >= csid->nformats)
+ if (code->index >= csid->res->formats->nformats)
return -EINVAL;
- code->code = csid->formats[code->index].code;
+ code->code = csid->res->formats->formats[code->index].code;
}
}
@@ -529,7 +972,7 @@ static int csid_set_test_pattern(struct csid_device *csid, s32 value)
tg->enabled = !!value;
- return csid->ops->configure_testgen_pattern(csid, value);
+ return csid->res->hw_ops->configure_testgen_pattern(csid, value);
}
/*
@@ -575,9 +1018,14 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
csid->camss = camss;
csid->id = id;
- csid->ops = res->ops;
+ csid->res = &res->csid;
+
+ if (dev_WARN_ONCE(dev, !csid->res->parent_dev_ops,
+ "Error: CSID depends on VFE/IFE device ops!\n")) {
+ return -EINVAL;
+ }
- csid->ops->subdev_init(csid);
+ csid->res->hw_ops->subdev_init(csid);
/* Memory */
@@ -587,9 +1035,11 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
* VFE to be initialized before CSID
*/
if (id >= 2) /* VFE/CSID lite */
- csid->base = camss->vfe[id].base + VFE_480_LITE_CSID_OFFSET;
+ csid->base = csid->res->parent_dev_ops->get_base_address(camss, id)
+ + VFE_480_LITE_CSID_OFFSET;
else
- csid->base = camss->vfe[id].base + VFE_480_CSID_OFFSET;
+ csid->base = csid->res->parent_dev_ops->get_base_address(camss, id)
+ + VFE_480_CSID_OFFSET;
} else {
csid->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
if (IS_ERR(csid->base))
@@ -605,7 +1055,7 @@ int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
csid->irq = ret;
snprintf(csid->irq_name, sizeof(csid->irq_name), "%s_%s%d",
dev_name(dev), MSM_CSID_NAME, csid->id);
- ret = devm_request_irq(dev, csid->irq, csid->ops->isr,
+ ret = devm_request_irq(dev, csid->irq, csid->res->hw_ops->isr,
IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
csid->irq_name, csid);
if (ret < 0) {
@@ -899,5 +1349,5 @@ void msm_csid_unregister_entity(struct csid_device *csid)
inline bool csid_is_lite(struct csid_device *csid)
{
- return csid->camss->res->csid_res[csid->id].is_lite;
+ return csid->camss->res->csid_res[csid->id].csid.is_lite;
}
diff --git a/drivers/media/platform/qcom/camss/camss-csid.h b/drivers/media/platform/qcom/camss/camss-csid.h
index fddccb69da13..8cdae98e4dca 100644
--- a/drivers/media/platform/qcom/camss/camss-csid.h
+++ b/drivers/media/platform/qcom/camss/camss-csid.h
@@ -67,7 +67,7 @@ enum csid_testgen_mode {
CSID_PAYLOAD_MODE_NUM_SUPPORTED_GEN2 = 9, /* excluding disabled */
};
-struct csid_format {
+struct csid_format_info {
u32 code;
u8 data_type;
u8 decode_format;
@@ -75,6 +75,11 @@ struct csid_format {
u8 spp; /* bus samples per pixel */
};
+struct csid_formats {
+ unsigned int nformats;
+ const struct csid_format_info *formats;
+};
+
struct csid_testgen_config {
enum csid_testgen_mode mode;
const char * const*modes;
@@ -149,6 +154,13 @@ struct csid_hw_ops {
void (*subdev_init)(struct csid_device *csid);
};
+struct csid_subdev_resources {
+ bool is_lite;
+ const struct csid_hw_ops *hw_ops;
+ const struct parent_dev_ops *parent_dev_ops;
+ const struct csid_formats *formats;
+};
+
struct csid_device {
struct camss *camss;
u8 id;
@@ -167,9 +179,7 @@ struct csid_device {
struct v4l2_mbus_framefmt fmt[MSM_CSID_PADS_NUM];
struct v4l2_ctrl_handler ctrls;
struct v4l2_ctrl *testgen_mode;
- const struct csid_format *formats;
- unsigned int nformats;
- const struct csid_hw_ops *ops;
+ const struct csid_subdev_resources *res;
};
struct camss_subdev_resources;
@@ -188,16 +198,16 @@ u32 csid_find_code(u32 *codes, unsigned int ncode,
unsigned int match_format_idx, u32 match_code);
/*
- * csid_get_fmt_entry - Find csid_format entry with matching format code
- * @formats: Array of format csid_format entries
+ * csid_get_fmt_entry - Find csid_format_info entry with matching format code
+ * @formats: Array of format csid_format_info entries
* @nformats: Length of @nformats array
* @code: Desired format code
*
* Return formats[0] on failure to find code
*/
-const struct csid_format *csid_get_fmt_entry(const struct csid_format *formats,
- unsigned int nformats,
- u32 code);
+const struct csid_format_info *csid_get_fmt_entry(const struct csid_format_info *formats,
+ unsigned int nformats,
+ u32 code);
int msm_csid_subdev_init(struct camss *camss, struct csid_device *csid,
const struct camss_subdev_resources *res, u8 id);
@@ -211,6 +221,10 @@ void msm_csid_get_csid_id(struct media_entity *entity, u8 *id);
extern const char * const csid_testgen_modes[];
+extern const struct csid_formats csid_formats_4_1;
+extern const struct csid_formats csid_formats_4_7;
+extern const struct csid_formats csid_formats_gen2;
+
extern const struct csid_hw_ops csid_ops_4_1;
extern const struct csid_hw_ops csid_ops_4_7;
extern const struct csid_hw_ops csid_ops_gen2;
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index 45b3a8e5dea4..2f7361dfd461 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -24,12 +24,7 @@
#define MSM_CSIPHY_NAME "msm_csiphy"
-struct csiphy_format {
- u32 code;
- u8 bpp;
-};
-
-static const struct csiphy_format csiphy_formats_8x16[] = {
+static const struct csiphy_format_info formats_8x16[] = {
{ MEDIA_BUS_FMT_UYVY8_1X16, 8 },
{ MEDIA_BUS_FMT_VYUY8_1X16, 8 },
{ MEDIA_BUS_FMT_YUYV8_1X16, 8 },
@@ -49,7 +44,7 @@ static const struct csiphy_format csiphy_formats_8x16[] = {
{ MEDIA_BUS_FMT_Y10_1X10, 10 },
};
-static const struct csiphy_format csiphy_formats_8x96[] = {
+static const struct csiphy_format_info formats_8x96[] = {
{ MEDIA_BUS_FMT_UYVY8_1X16, 8 },
{ MEDIA_BUS_FMT_VYUY8_1X16, 8 },
{ MEDIA_BUS_FMT_YUYV8_1X16, 8 },
@@ -73,7 +68,7 @@ static const struct csiphy_format csiphy_formats_8x96[] = {
{ MEDIA_BUS_FMT_Y10_1X10, 10 },
};
-static const struct csiphy_format csiphy_formats_sdm845[] = {
+static const struct csiphy_format_info formats_sdm845[] = {
{ MEDIA_BUS_FMT_UYVY8_1X16, 8 },
{ MEDIA_BUS_FMT_VYUY8_1X16, 8 },
{ MEDIA_BUS_FMT_YUYV8_1X16, 8 },
@@ -98,6 +93,21 @@ static const struct csiphy_format csiphy_formats_sdm845[] = {
{ MEDIA_BUS_FMT_Y10_1X10, 10 },
};
+const struct csiphy_formats csiphy_formats_8x16 = {
+ .nformats = ARRAY_SIZE(formats_8x16),
+ .formats = formats_8x16
+};
+
+const struct csiphy_formats csiphy_formats_8x96 = {
+ .nformats = ARRAY_SIZE(formats_8x96),
+ .formats = formats_8x96
+};
+
+const struct csiphy_formats csiphy_formats_sdm845 = {
+ .nformats = ARRAY_SIZE(formats_sdm845),
+ .formats = formats_sdm845
+};
+
/*
* csiphy_get_bpp - map media bus format to bits per pixel
* @formats: supported media bus formats array
@@ -106,7 +116,7 @@ static const struct csiphy_format csiphy_formats_sdm845[] = {
*
* Return number of bits per pixel
*/
-static u8 csiphy_get_bpp(const struct csiphy_format *formats,
+static u8 csiphy_get_bpp(const struct csiphy_format_info *formats,
unsigned int nformats, u32 code)
{
unsigned int i;
@@ -131,7 +141,7 @@ static int csiphy_set_clock_rates(struct csiphy_device *csiphy)
int i, j;
int ret;
- u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats,
+ u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats,
csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data;
@@ -216,9 +226,9 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on)
enable_irq(csiphy->irq);
- csiphy->ops->reset(csiphy);
+ csiphy->res->hw_ops->reset(csiphy);
- csiphy->ops->hw_version_read(csiphy, dev);
+ csiphy->res->hw_ops->hw_version_read(csiphy, dev);
} else {
disable_irq(csiphy->irq);
@@ -243,8 +253,8 @@ static int csiphy_stream_on(struct csiphy_device *csiphy)
{
struct csiphy_config *cfg = &csiphy->cfg;
s64 link_freq;
- u8 lane_mask = csiphy->ops->get_lane_mask(&cfg->csi2->lane_cfg);
- u8 bpp = csiphy_get_bpp(csiphy->formats, csiphy->nformats,
+ u8 lane_mask = csiphy->res->hw_ops->get_lane_mask(&cfg->csi2->lane_cfg);
+ u8 bpp = csiphy_get_bpp(csiphy->res->formats->formats, csiphy->res->formats->nformats,
csiphy->fmt[MSM_CSIPHY_PAD_SINK].code);
u8 num_lanes = csiphy->cfg.csi2->lane_cfg.num_data;
u8 val;
@@ -272,7 +282,7 @@ static int csiphy_stream_on(struct csiphy_device *csiphy)
wmb();
}
- csiphy->ops->lanes_enable(csiphy, cfg, link_freq, lane_mask);
+ csiphy->res->hw_ops->lanes_enable(csiphy, cfg, link_freq, lane_mask);
return 0;
}
@@ -285,7 +295,7 @@ static int csiphy_stream_on(struct csiphy_device *csiphy)
*/
static void csiphy_stream_off(struct csiphy_device *csiphy)
{
- csiphy->ops->lanes_disable(csiphy, &csiphy->cfg);
+ csiphy->res->hw_ops->lanes_disable(csiphy, &csiphy->cfg);
}
@@ -350,12 +360,12 @@ static void csiphy_try_format(struct csiphy_device *csiphy,
case MSM_CSIPHY_PAD_SINK:
/* Set format on sink pad */
- for (i = 0; i < csiphy->nformats; i++)
- if (fmt->code == csiphy->formats[i].code)
+ for (i = 0; i < csiphy->res->formats->nformats; i++)
+ if (fmt->code == csiphy->res->formats->formats[i].code)
break;
/* If not found, use UYVY as default */
- if (i >= csiphy->nformats)
+ if (i >= csiphy->res->formats->nformats)
fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
fmt->width = clamp_t(u32, fmt->width, 1, 8191);
@@ -392,10 +402,10 @@ static int csiphy_enum_mbus_code(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *format;
if (code->pad == MSM_CSIPHY_PAD_SINK) {
- if (code->index >= csiphy->nformats)
+ if (code->index >= csiphy->res->formats->nformats)
return -EINVAL;
- code->code = csiphy->formats[code->index].code;
+ code->code = csiphy->res->formats->formats[code->index].code;
} else {
if (code->index > 0)
return -EINVAL;
@@ -564,25 +574,7 @@ int msm_csiphy_subdev_init(struct camss *camss,
csiphy->camss = camss;
csiphy->id = id;
csiphy->cfg.combo_mode = 0;
- csiphy->ops = res->ops;
-
- switch (camss->res->version) {
- case CAMSS_8x16:
- csiphy->formats = csiphy_formats_8x16;
- csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x16);
- break;
- case CAMSS_8x96:
- case CAMSS_660:
- csiphy->formats = csiphy_formats_8x96;
- csiphy->nformats = ARRAY_SIZE(csiphy_formats_8x96);
- break;
- case CAMSS_845:
- case CAMSS_8250:
- case CAMSS_8280XP:
- csiphy->formats = csiphy_formats_sdm845;
- csiphy->nformats = ARRAY_SIZE(csiphy_formats_sdm845);
- break;
- }
+ csiphy->res = &res->csiphy;
/* Memory */
@@ -610,7 +602,7 @@ int msm_csiphy_subdev_init(struct camss *camss,
snprintf(csiphy->irq_name, sizeof(csiphy->irq_name), "%s_%s%d",
dev_name(dev), MSM_CSIPHY_NAME, csiphy->id);
- ret = devm_request_irq(dev, csiphy->irq, csiphy->ops->isr,
+ ret = devm_request_irq(dev, csiphy->irq, csiphy->res->hw_ops->isr,
IRQF_TRIGGER_RISING | IRQF_NO_AUTOEN,
csiphy->irq_name, csiphy);
if (ret < 0) {
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h
index c9b7fe82b1f0..47f0b6b09eba 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.h
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.h
@@ -42,6 +42,16 @@ struct csiphy_config {
struct csiphy_csi2_cfg *csi2;
};
+struct csiphy_format_info {
+ u32 code;
+ u8 bpp;
+};
+
+struct csiphy_formats {
+ unsigned int nformats;
+ const struct csiphy_format_info *formats;
+};
+
struct csiphy_device;
struct csiphy_hw_ops {
@@ -63,6 +73,11 @@ struct csiphy_hw_ops {
irqreturn_t (*isr)(int irq, void *dev);
};
+struct csiphy_subdev_resources {
+ const struct csiphy_hw_ops *hw_ops;
+ const struct csiphy_formats *formats;
+};
+
struct csiphy_device {
struct camss *camss;
u8 id;
@@ -78,9 +93,7 @@ struct csiphy_device {
u32 timer_clk_rate;
struct csiphy_config cfg;
struct v4l2_mbus_framefmt fmt[MSM_CSIPHY_PADS_NUM];
- const struct csiphy_hw_ops *ops;
- const struct csiphy_format *formats;
- unsigned int nformats;
+ const struct csiphy_subdev_resources *res;
};
struct camss_subdev_resources;
@@ -94,6 +107,10 @@ int msm_csiphy_register_entity(struct csiphy_device *csiphy,
void msm_csiphy_unregister_entity(struct csiphy_device *csiphy);
+extern const struct csiphy_formats csiphy_formats_8x16;
+extern const struct csiphy_formats csiphy_formats_8x96;
+extern const struct csiphy_formats csiphy_formats_sdm845;
+
extern const struct csiphy_hw_ops csiphy_ops_2ph_1_0;
extern const struct csiphy_hw_ops csiphy_ops_3ph_1_0;
diff --git a/drivers/media/platform/qcom/camss/camss-format.c b/drivers/media/platform/qcom/camss/camss-format.c
new file mode 100644
index 000000000000..4a3d5549615c
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-format.c
@@ -0,0 +1,91 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * camss-format.c
+ *
+ * Qualcomm MSM Camera Subsystem - Format helpers
+ *
+ * Copyright (c) 2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Technologies, Inc.
+ */
+#include <linux/bug.h>
+#include <linux/errno.h>
+
+#include "camss-format.h"
+
+/*
+ * camss_format_get_bpp - Map media bus format to bits per pixel
+ * @formats: supported media bus formats array
+ * @nformats: size of @formats array
+ * @code: media bus format code
+ *
+ * Return number of bits per pixel
+ */
+u8 camss_format_get_bpp(const struct camss_format_info *formats, unsigned int nformats, u32 code)
+{
+ unsigned int i;
+
+ for (i = 0; i < nformats; i++)
+ if (code == formats[i].code)
+ return formats[i].mbus_bpp;
+
+ WARN(1, "Unknown format\n");
+
+ return formats[0].mbus_bpp;
+}
+
+/*
+ * camss_format_find_code - Find a format code in an array
+ * @code: a pointer to media bus format codes array
+ * @n_code: size of @code array
+ * @index: index of code in the array
+ * @req_code: required code
+ *
+ * Return media bus format code
+ */
+u32 camss_format_find_code(u32 *code, unsigned int n_code, unsigned int index, u32 req_code)
+{
+ unsigned int i;
+
+ if (!req_code && index >= n_code)
+ return 0;
+
+ for (i = 0; i < n_code; i++) {
+ if (req_code) {
+ if (req_code == code[i])
+ return req_code;
+ } else {
+ if (i == index)
+ return code[i];
+ }
+ }
+
+ return code[0];
+}
+
+/*
+ * camss_format_find_format - Find a format in an array
+ * @code: media bus format code
+ * @pixelformat: V4L2 pixel format FCC identifier
+ * @formats: a pointer to formats array
+ * @nformats: size of @formats array
+ *
+ * Return index of a format or a negative error code otherwise
+ */
+int camss_format_find_format(u32 code, u32 pixelformat, const struct camss_format_info *formats,
+ unsigned int nformats)
+{
+ unsigned int i;
+
+ for (i = 0; i < nformats; i++) {
+ if (formats[i].code == code &&
+ formats[i].pixelformat == pixelformat)
+ return i;
+ }
+
+ for (i = 0; i < nformats; i++) {
+ if (formats[i].code == code)
+ return i;
+ }
+
+ return -EINVAL;
+}
diff --git a/drivers/media/platform/qcom/camss/camss-format.h b/drivers/media/platform/qcom/camss/camss-format.h
new file mode 100644
index 000000000000..923a48c9c3fb
--- /dev/null
+++ b/drivers/media/platform/qcom/camss/camss-format.h
@@ -0,0 +1,62 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * camss-format.h
+ *
+ * Qualcomm MSM Camera Subsystem - Format helpers
+ *
+ * Copyright (c) 2023, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2023 Qualcomm Technologies, Inc.
+ */
+#ifndef __CAMSS_FORMAT_H__
+#define __CAMSS_FORMAT_H__
+
+#include <linux/types.h>
+
+#define PER_PLANE_DATA(plane, h_fract_num, h_fract_den, v_fract_num, v_fract_den, _bpp) \
+ .hsub[(plane)].numerator = (h_fract_num), \
+ .hsub[(plane)].denominator = (h_fract_den), \
+ .vsub[(plane)].numerator = (v_fract_num), \
+ .vsub[(plane)].denominator = (v_fract_den), \
+ .bpp[(plane)] = (_bpp)
+
+/*
+ * struct fract - Represents a fraction
+ * @numerator: Store the numerator part of the fraction
+ * @denominator: Store the denominator part of the fraction
+ */
+struct fract {
+ u8 numerator;
+ u8 denominator;
+};
+
+/*
+ * struct camss_format_info - ISP media bus format information
+ * @code: V4L2 media bus format code
+ * @mbus_bpp: Media bus bits per pixel
+ * @pixelformat: V4L2 pixel format FCC identifier
+ * @planes: Number of planes
+ * @hsub: Horizontal subsampling (for each plane)
+ * @vsub: Vertical subsampling (for each plane)
+ * @bpp: Bits per pixel when stored in memory (for each plane)
+ */
+struct camss_format_info {
+ u32 code;
+ u32 mbus_bpp;
+ u32 pixelformat;
+ u8 planes;
+ struct fract hsub[3];
+ struct fract vsub[3];
+ unsigned int bpp[3];
+};
+
+struct camss_formats {
+ unsigned int nformats;
+ const struct camss_format_info *formats;
+};
+
+u8 camss_format_get_bpp(const struct camss_format_info *formats, unsigned int nformats, u32 code);
+u32 camss_format_find_code(u32 *code, unsigned int n_code, unsigned int index, u32 req_code);
+int camss_format_find_format(u32 code, u32 pixelformat, const struct camss_format_info *formats,
+ unsigned int nformats);
+
+#endif /* __CAMSS_FORMAT_H__ */
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-17x.c b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
index 795ac3815339..380c99321030 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-17x.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-17x.c
@@ -353,7 +353,7 @@ static irqreturn_t vfe_isr(int irq, void *dev)
writel_relaxed(status0, vfe->base + VFE_IRQ_CLEAR_0);
writel_relaxed(status1, vfe->base + VFE_IRQ_CLEAR_1);
- for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) {
+ for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {
vfe_bus_status[i] = readl_relaxed(vfe->base + VFE_BUS_IRQ_STATUS(i));
writel_relaxed(vfe_bus_status[i], vfe->base + VFE_BUS_IRQ_CLEAR(i));
}
@@ -367,11 +367,11 @@ static irqreturn_t vfe_isr(int irq, void *dev)
if (status0 & STATUS_0_RESET_ACK)
vfe->isr_ops.reset_ack(vfe);
- for (i = VFE_LINE_RDI0; i < vfe->line_num; i++)
+ for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++)
if (status0 & STATUS_0_RDI_REG_UPDATE(i))
vfe->isr_ops.reg_update(vfe, i);
- for (i = VFE_LINE_RDI0; i < vfe->line_num; i++)
+ for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++)
if (status0 & STATUS_1_RDI_SOF(i))
vfe->isr_ops.sof(vfe, i);
@@ -442,7 +442,7 @@ static int vfe_enable_output(struct vfe_line *line)
{
struct vfe_device *vfe = to_vfe(line);
struct vfe_output *output = &line->output;
- const struct vfe_hw_ops *ops = vfe->ops;
+ const struct vfe_hw_ops *ops = vfe->res->hw_ops;
struct media_entity *sensor;
unsigned long flags;
unsigned int frame_skip = 0;
@@ -560,7 +560,7 @@ static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
unsigned long flags;
spin_lock_irqsave(&vfe->output_lock, flags);
- vfe->ops->reg_update_clear(vfe, line_id);
+ vfe->res->hw_ops->reg_update_clear(vfe, line_id);
output = &vfe->line[line_id].output;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
index ef6b34c915df..1bd3a6ef1d04 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
@@ -892,7 +892,7 @@ static irqreturn_t vfe_isr(int irq, void *dev)
u32 value0, value1;
int i, j;
- vfe->ops->isr_read(vfe, &value0, &value1);
+ vfe->res->hw_ops->isr_read(vfe, &value0, &value1);
dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n",
value0, value1);
@@ -901,7 +901,7 @@ static irqreturn_t vfe_isr(int irq, void *dev)
vfe->isr_ops.reset_ack(vfe);
if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION)
- vfe->ops->violation_read(vfe);
+ vfe->res->hw_ops->violation_read(vfe);
if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK)
vfe->isr_ops.halt_ack(vfe);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
index 7655d22a9fda..ce0719106bd3 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-7.c
@@ -1050,7 +1050,7 @@ static irqreturn_t vfe_isr(int irq, void *dev)
u32 value0, value1;
int i, j;
- vfe->ops->isr_read(vfe, &value0, &value1);
+ vfe->res->hw_ops->isr_read(vfe, &value0, &value1);
dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n",
value0, value1);
@@ -1059,12 +1059,12 @@ static irqreturn_t vfe_isr(int irq, void *dev)
vfe->isr_ops.reset_ack(vfe);
if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION)
- vfe->ops->violation_read(vfe);
+ vfe->res->hw_ops->violation_read(vfe);
if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK)
vfe->isr_ops.halt_ack(vfe);
- for (i = VFE_LINE_RDI0; i < vfe->line_num; i++)
+ for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++)
if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i))
vfe->isr_ops.reg_update(vfe, i);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
index f52fa30f3853..6b59c8107a3c 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-8.c
@@ -980,7 +980,7 @@ static irqreturn_t vfe_isr(int irq, void *dev)
u32 value0, value1;
int i, j;
- vfe->ops->isr_read(vfe, &value0, &value1);
+ vfe->res->hw_ops->isr_read(vfe, &value0, &value1);
dev_dbg(vfe->camss->dev, "VFE: status0 = 0x%08x, status1 = 0x%08x\n",
value0, value1);
@@ -989,12 +989,12 @@ static irqreturn_t vfe_isr(int irq, void *dev)
vfe->isr_ops.reset_ack(vfe);
if (value1 & VFE_0_IRQ_STATUS_1_VIOLATION)
- vfe->ops->violation_read(vfe);
+ vfe->res->hw_ops->violation_read(vfe);
if (value1 & VFE_0_IRQ_STATUS_1_BUS_BDG_HALT_ACK)
vfe->isr_ops.halt_ack(vfe);
- for (i = VFE_LINE_RDI0; i < vfe->line_num; i++)
+ for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++)
if (value0 & VFE_0_IRQ_STATUS_0_line_n_REG_UPDATE(i))
vfe->isr_ops.reg_update(vfe, i);
diff --git a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
index 239d3d4ac666..eb33c03df27e 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-gen1.c
@@ -37,7 +37,7 @@ static int vfe_disable_output(struct vfe_line *line)
{
struct vfe_device *vfe = to_vfe(line);
struct vfe_output *output = &line->output;
- const struct vfe_hw_ops *ops = vfe->ops;
+ const struct vfe_hw_ops *ops = vfe->res->hw_ops;
unsigned long flags;
unsigned long time;
unsigned int i;
@@ -162,14 +162,14 @@ static void vfe_output_frame_drop(struct vfe_device *vfe,
vfe->ops_gen1->wm_set_framedrop_pattern(vfe, output->wm_idx[i], drop_pattern);
}
- vfe->ops->reg_update(vfe, container_of(output, struct vfe_line, output)->id);
+ vfe->res->hw_ops->reg_update(vfe, container_of(output, struct vfe_line, output)->id);
}
static int vfe_enable_output(struct vfe_line *line)
{
struct vfe_device *vfe = to_vfe(line);
struct vfe_output *output = &line->output;
- const struct vfe_hw_ops *ops = vfe->ops;
+ const struct vfe_hw_ops *ops = vfe->res->hw_ops;
struct media_entity *sensor;
unsigned long flags;
unsigned int frame_skip = 0;
@@ -545,7 +545,7 @@ static void vfe_isr_reg_update(struct vfe_device *vfe, enum vfe_line_id line_id)
unsigned long flags;
spin_lock_irqsave(&vfe->output_lock, flags);
- vfe->ops->reg_update_clear(vfe, line_id);
+ vfe->res->hw_ops->reg_update_clear(vfe, line_id);
output = &line->output;
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index d875237cf244..83c5a36d071f 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -32,139 +32,251 @@
#define SCALER_RATIO_MAX 16
-struct vfe_format {
- u32 code;
- u8 bpp;
+static const struct camss_format_info formats_rdi_8x16[] = {
+ { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_UYVY, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_VYUY, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_YUYV, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_YVYU, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8, V4L2_PIX_FMT_SBGGR8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8, V4L2_PIX_FMT_SGBRG8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8, V4L2_PIX_FMT_SGRBG8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8, V4L2_PIX_FMT_SRGGB8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10, V4L2_PIX_FMT_SBGGR10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10, V4L2_PIX_FMT_SGBRG10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10, V4L2_PIX_FMT_SGRBG10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10, V4L2_PIX_FMT_SRGGB10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12, V4L2_PIX_FMT_SBGGR12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12, V4L2_PIX_FMT_SGBRG12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12, V4L2_PIX_FMT_SGRBG12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12, V4L2_PIX_FMT_SRGGB12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_Y10_1X10, 10, V4L2_PIX_FMT_Y10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
};
-static const struct vfe_format formats_rdi_8x16[] = {
- { MEDIA_BUS_FMT_UYVY8_1X16, 8 },
- { MEDIA_BUS_FMT_VYUY8_1X16, 8 },
- { MEDIA_BUS_FMT_YUYV8_1X16, 8 },
- { MEDIA_BUS_FMT_YVYU8_1X16, 8 },
- { MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
- { MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
- { MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
- { MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
- { MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
- { MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
- { MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
- { MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
- { MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
- { MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
- { MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
- { MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
- { MEDIA_BUS_FMT_Y10_1X10, 10 },
+static const struct camss_format_info formats_rdi_8x96[] = {
+ { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_UYVY, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_VYUY, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_YUYV, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_YVYU, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8, V4L2_PIX_FMT_SBGGR8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8, V4L2_PIX_FMT_SGBRG8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8, V4L2_PIX_FMT_SGRBG8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8, V4L2_PIX_FMT_SRGGB8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10, V4L2_PIX_FMT_SBGGR10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10, V4L2_PIX_FMT_SGBRG10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10, V4L2_PIX_FMT_SGRBG10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10, V4L2_PIX_FMT_SRGGB10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16, V4L2_PIX_FMT_SBGGR10, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12, V4L2_PIX_FMT_SBGGR12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12, V4L2_PIX_FMT_SGBRG12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12, V4L2_PIX_FMT_SGRBG12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12, V4L2_PIX_FMT_SRGGB12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SBGGR14_1X14, 14, V4L2_PIX_FMT_SBGGR14P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+ { MEDIA_BUS_FMT_SGBRG14_1X14, 14, V4L2_PIX_FMT_SGBRG14P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+ { MEDIA_BUS_FMT_SGRBG14_1X14, 14, V4L2_PIX_FMT_SGRBG14P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+ { MEDIA_BUS_FMT_SRGGB14_1X14, 14, V4L2_PIX_FMT_SRGGB14P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+ { MEDIA_BUS_FMT_Y10_1X10, 10, V4L2_PIX_FMT_Y10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16, V4L2_PIX_FMT_Y10, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
};
-static const struct vfe_format formats_pix_8x16[] = {
- { MEDIA_BUS_FMT_UYVY8_1X16, 8 },
- { MEDIA_BUS_FMT_VYUY8_1X16, 8 },
- { MEDIA_BUS_FMT_YUYV8_1X16, 8 },
- { MEDIA_BUS_FMT_YVYU8_1X16, 8 },
+static const struct camss_format_info formats_rdi_845[] = {
+ { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_UYVY, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_VYUY, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_YUYV, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_YVYU, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8, V4L2_PIX_FMT_SBGGR8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8, V4L2_PIX_FMT_SGBRG8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8, V4L2_PIX_FMT_SGRBG8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8, V4L2_PIX_FMT_SRGGB8, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10, V4L2_PIX_FMT_SBGGR10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10, V4L2_PIX_FMT_SGBRG10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10, V4L2_PIX_FMT_SGRBG10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10, V4L2_PIX_FMT_SRGGB10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16, V4L2_PIX_FMT_SBGGR10, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12, V4L2_PIX_FMT_SBGGR12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12, V4L2_PIX_FMT_SGBRG12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12, V4L2_PIX_FMT_SGRBG12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12, V4L2_PIX_FMT_SRGGB12P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 12) },
+ { MEDIA_BUS_FMT_SBGGR14_1X14, 14, V4L2_PIX_FMT_SBGGR14P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+ { MEDIA_BUS_FMT_SGBRG14_1X14, 14, V4L2_PIX_FMT_SGBRG14P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+ { MEDIA_BUS_FMT_SGRBG14_1X14, 14, V4L2_PIX_FMT_SGRBG14P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+ { MEDIA_BUS_FMT_SRGGB14_1X14, 14, V4L2_PIX_FMT_SRGGB14P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 14) },
+ { MEDIA_BUS_FMT_Y8_1X8, 8, V4L2_PIX_FMT_GREY, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 8) },
+ { MEDIA_BUS_FMT_Y10_1X10, 10, V4L2_PIX_FMT_Y10P, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 10) },
+ { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16, V4L2_PIX_FMT_Y10, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
};
-static const struct vfe_format formats_rdi_8x96[] = {
- { MEDIA_BUS_FMT_UYVY8_1X16, 8 },
- { MEDIA_BUS_FMT_VYUY8_1X16, 8 },
- { MEDIA_BUS_FMT_YUYV8_1X16, 8 },
- { MEDIA_BUS_FMT_YVYU8_1X16, 8 },
- { MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
- { MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
- { MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
- { MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
- { MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
- { MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
- { MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
- { MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
- { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16 },
- { MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
- { MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
- { MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
- { MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
- { MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
- { MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
- { MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
- { MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
- { MEDIA_BUS_FMT_Y10_1X10, 10 },
- { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16 },
+static const struct camss_format_info formats_pix_8x16[] = {
+ { MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_YVYU8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_UYVY8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_VYUY8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_YVYU8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_UYVY8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_VYUY8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
};
-static const struct vfe_format formats_pix_8x96[] = {
- { MEDIA_BUS_FMT_UYVY8_1X16, 8 },
- { MEDIA_BUS_FMT_VYUY8_1X16, 8 },
- { MEDIA_BUS_FMT_YUYV8_1X16, 8 },
- { MEDIA_BUS_FMT_YVYU8_1X16, 8 },
+static const struct camss_format_info formats_pix_8x96[] = {
+ { MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_YVYU8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_UYVY8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_VYUY8_1_5X8, 8, V4L2_PIX_FMT_NV12, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_YUYV8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_YVYU8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_UYVY8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_VYUY8_1_5X8, 8, V4L2_PIX_FMT_NV21, 1,
+ PER_PLANE_DATA(0, 1, 1, 2, 3, 8) },
+ { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_NV16, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_NV61, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 2, 8) },
+ { MEDIA_BUS_FMT_UYVY8_1X16, 8, V4L2_PIX_FMT_UYVY, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_VYUY8_1X16, 8, V4L2_PIX_FMT_VYUY, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_YUYV8_1X16, 8, V4L2_PIX_FMT_YUYV, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
+ { MEDIA_BUS_FMT_YVYU8_1X16, 8, V4L2_PIX_FMT_YVYU, 1,
+ PER_PLANE_DATA(0, 1, 1, 1, 1, 16) },
};
-static const struct vfe_format formats_rdi_845[] = {
- { MEDIA_BUS_FMT_UYVY8_1X16, 8 },
- { MEDIA_BUS_FMT_VYUY8_1X16, 8 },
- { MEDIA_BUS_FMT_YUYV8_1X16, 8 },
- { MEDIA_BUS_FMT_YVYU8_1X16, 8 },
- { MEDIA_BUS_FMT_SBGGR8_1X8, 8 },
- { MEDIA_BUS_FMT_SGBRG8_1X8, 8 },
- { MEDIA_BUS_FMT_SGRBG8_1X8, 8 },
- { MEDIA_BUS_FMT_SRGGB8_1X8, 8 },
- { MEDIA_BUS_FMT_SBGGR10_1X10, 10 },
- { MEDIA_BUS_FMT_SGBRG10_1X10, 10 },
- { MEDIA_BUS_FMT_SGRBG10_1X10, 10 },
- { MEDIA_BUS_FMT_SRGGB10_1X10, 10 },
- { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, 16 },
- { MEDIA_BUS_FMT_SBGGR12_1X12, 12 },
- { MEDIA_BUS_FMT_SGBRG12_1X12, 12 },
- { MEDIA_BUS_FMT_SGRBG12_1X12, 12 },
- { MEDIA_BUS_FMT_SRGGB12_1X12, 12 },
- { MEDIA_BUS_FMT_SBGGR14_1X14, 14 },
- { MEDIA_BUS_FMT_SGBRG14_1X14, 14 },
- { MEDIA_BUS_FMT_SGRBG14_1X14, 14 },
- { MEDIA_BUS_FMT_SRGGB14_1X14, 14 },
- { MEDIA_BUS_FMT_Y8_1X8, 8 },
- { MEDIA_BUS_FMT_Y10_1X10, 10 },
- { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, 16 },
+const struct camss_formats vfe_formats_rdi_8x16 = {
+ .nformats = ARRAY_SIZE(formats_rdi_8x16),
+ .formats = formats_rdi_8x16
};
-/*
- * vfe_get_bpp - map media bus format to bits per pixel
- * @formats: supported media bus formats array
- * @nformats: size of @formats array
- * @code: media bus format code
- *
- * Return number of bits per pixel
- */
-static u8 vfe_get_bpp(const struct vfe_format *formats,
- unsigned int nformats, u32 code)
-{
- unsigned int i;
-
- for (i = 0; i < nformats; i++)
- if (code == formats[i].code)
- return formats[i].bpp;
-
- WARN(1, "Unknown format\n");
-
- return formats[0].bpp;
-}
+const struct camss_formats vfe_formats_pix_8x16 = {
+ .nformats = ARRAY_SIZE(formats_pix_8x16),
+ .formats = formats_pix_8x16
+};
-static u32 vfe_find_code(u32 *code, unsigned int n_code,
- unsigned int index, u32 req_code)
-{
- int i;
+const struct camss_formats vfe_formats_rdi_8x96 = {
+ .nformats = ARRAY_SIZE(formats_rdi_8x96),
+ .formats = formats_rdi_8x96
+};
- if (!req_code && (index >= n_code))
- return 0;
+const struct camss_formats vfe_formats_pix_8x96 = {
+ .nformats = ARRAY_SIZE(formats_pix_8x96),
+ .formats = formats_pix_8x96
+};
- for (i = 0; i < n_code; i++)
- if (req_code) {
- if (req_code == code[i])
- return req_code;
- } else {
- if (i == index)
- return code[i];
- }
+const struct camss_formats vfe_formats_rdi_845 = {
+ .nformats = ARRAY_SIZE(formats_rdi_845),
+ .formats = formats_rdi_845
+};
- return code[0];
-}
+/* TODO: Replace with pix formats */
+const struct camss_formats vfe_formats_pix_845 = {
+ .nformats = ARRAY_SIZE(formats_rdi_845),
+ .formats = formats_rdi_845
+};
static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
unsigned int index, u32 src_req_code)
@@ -181,8 +293,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
MEDIA_BUS_FMT_YUYV8_1_5X8,
};
- return vfe_find_code(src_code, ARRAY_SIZE(src_code),
- index, src_req_code);
+ return camss_format_find_code(src_code, ARRAY_SIZE(src_code),
+ index, src_req_code);
}
case MEDIA_BUS_FMT_YVYU8_1X16:
{
@@ -191,8 +303,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
MEDIA_BUS_FMT_YVYU8_1_5X8,
};
- return vfe_find_code(src_code, ARRAY_SIZE(src_code),
- index, src_req_code);
+ return camss_format_find_code(src_code, ARRAY_SIZE(src_code),
+ index, src_req_code);
}
case MEDIA_BUS_FMT_UYVY8_1X16:
{
@@ -201,8 +313,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
MEDIA_BUS_FMT_UYVY8_1_5X8,
};
- return vfe_find_code(src_code, ARRAY_SIZE(src_code),
- index, src_req_code);
+ return camss_format_find_code(src_code, ARRAY_SIZE(src_code),
+ index, src_req_code);
}
case MEDIA_BUS_FMT_VYUY8_1X16:
{
@@ -211,8 +323,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
MEDIA_BUS_FMT_VYUY8_1_5X8,
};
- return vfe_find_code(src_code, ARRAY_SIZE(src_code),
- index, src_req_code);
+ return camss_format_find_code(src_code, ARRAY_SIZE(src_code),
+ index, src_req_code);
}
default:
if (index > 0)
@@ -237,8 +349,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
MEDIA_BUS_FMT_YUYV8_1_5X8,
};
- return vfe_find_code(src_code, ARRAY_SIZE(src_code),
- index, src_req_code);
+ return camss_format_find_code(src_code, ARRAY_SIZE(src_code),
+ index, src_req_code);
}
case MEDIA_BUS_FMT_YVYU8_1X16:
{
@@ -250,8 +362,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
MEDIA_BUS_FMT_YVYU8_1_5X8,
};
- return vfe_find_code(src_code, ARRAY_SIZE(src_code),
- index, src_req_code);
+ return camss_format_find_code(src_code, ARRAY_SIZE(src_code),
+ index, src_req_code);
}
case MEDIA_BUS_FMT_UYVY8_1X16:
{
@@ -263,8 +375,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
MEDIA_BUS_FMT_UYVY8_1_5X8,
};
- return vfe_find_code(src_code, ARRAY_SIZE(src_code),
- index, src_req_code);
+ return camss_format_find_code(src_code, ARRAY_SIZE(src_code),
+ index, src_req_code);
}
case MEDIA_BUS_FMT_VYUY8_1X16:
{
@@ -276,8 +388,8 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
MEDIA_BUS_FMT_VYUY8_1_5X8,
};
- return vfe_find_code(src_code, ARRAY_SIZE(src_code),
- index, src_req_code);
+ return camss_format_find_code(src_code, ARRAY_SIZE(src_code),
+ index, src_req_code);
}
default:
if (index > 0)
@@ -296,7 +408,7 @@ int vfe_reset(struct vfe_device *vfe)
reinit_completion(&vfe->reset_complete);
- vfe->ops->global_reset(vfe);
+ vfe->res->hw_ops->global_reset(vfe);
time = wait_for_completion_timeout(&vfe->reset_complete,
msecs_to_jiffies(VFE_RESET_TIMEOUT_MS));
@@ -312,7 +424,7 @@ static void vfe_init_outputs(struct vfe_device *vfe)
{
int i;
- for (i = 0; i < vfe->line_num; i++) {
+ for (i = 0; i < vfe->res->line_num; i++) {
struct vfe_output *output = &vfe->line[i].output;
output->state = VFE_OUTPUT_OFF;
@@ -421,7 +533,7 @@ static int vfe_disable_output(struct vfe_line *line)
spin_lock_irqsave(&vfe->output_lock, flags);
for (i = 0; i < output->wm_num; i++)
- vfe->ops->vfe_wm_stop(vfe, output->wm_idx[i]);
+ vfe->res->hw_ops->vfe_wm_stop(vfe, output->wm_idx[i]);
output->gen2.active_num = 0;
spin_unlock_irqrestore(&vfe->output_lock, flags);
@@ -537,7 +649,7 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
int i, j;
int ret;
- for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) {
+ for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {
ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity,
&pixel_clock[i]);
if (ret)
@@ -551,7 +663,7 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
u64 min_rate = 0;
long rate;
- for (j = VFE_LINE_RDI0; j < vfe->line_num; j++) {
+ for (j = VFE_LINE_RDI0; j < vfe->res->line_num; j++) {
u32 tmp;
u8 bpp;
@@ -560,9 +672,9 @@ static int vfe_set_clock_rates(struct vfe_device *vfe)
} else {
struct vfe_line *l = &vfe->line[j];
- bpp = vfe_get_bpp(l->formats,
- l->nformats,
- l->fmt[MSM_VFE_PAD_SINK].code);
+ bpp = camss_format_get_bpp(l->formats,
+ l->nformats,
+ l->fmt[MSM_VFE_PAD_SINK].code);
tmp = pixel_clock[j] * bpp / 64;
}
@@ -618,7 +730,7 @@ static int vfe_check_clock_rates(struct vfe_device *vfe)
int i, j;
int ret;
- for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) {
+ for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {
ret = camss_get_pixel_clock(&vfe->line[i].subdev.entity,
&pixel_clock[i]);
if (ret)
@@ -632,7 +744,7 @@ static int vfe_check_clock_rates(struct vfe_device *vfe)
u64 min_rate = 0;
unsigned long rate;
- for (j = VFE_LINE_RDI0; j < vfe->line_num; j++) {
+ for (j = VFE_LINE_RDI0; j < vfe->res->line_num; j++) {
u32 tmp;
u8 bpp;
@@ -641,9 +753,9 @@ static int vfe_check_clock_rates(struct vfe_device *vfe)
} else {
struct vfe_line *l = &vfe->line[j];
- bpp = vfe_get_bpp(l->formats,
- l->nformats,
- l->fmt[MSM_VFE_PAD_SINK].code);
+ bpp = camss_format_get_bpp(l->formats,
+ l->nformats,
+ l->fmt[MSM_VFE_PAD_SINK].code);
tmp = pixel_clock[j] * bpp / 64;
}
@@ -675,7 +787,7 @@ int vfe_get(struct vfe_device *vfe)
mutex_lock(&vfe->power_lock);
if (vfe->power_count == 0) {
- ret = vfe->ops->pm_domain_on(vfe);
+ ret = vfe->res->hw_ops->pm_domain_on(vfe);
if (ret < 0)
goto error_pm_domain;
@@ -700,7 +812,7 @@ int vfe_get(struct vfe_device *vfe)
vfe_init_outputs(vfe);
- vfe->ops->hw_version(vfe);
+ vfe->res->hw_ops->hw_version(vfe);
} else {
ret = vfe_check_clock_rates(vfe);
if (ret < 0)
@@ -718,7 +830,7 @@ error_reset:
error_pm_runtime_get:
pm_runtime_put_sync(vfe->camss->dev);
error_domain_off:
- vfe->ops->pm_domain_off(vfe);
+ vfe->res->hw_ops->pm_domain_off(vfe);
error_pm_domain:
mutex_unlock(&vfe->power_lock);
@@ -740,11 +852,11 @@ void vfe_put(struct vfe_device *vfe)
} else if (vfe->power_count == 1) {
if (vfe->was_streaming) {
vfe->was_streaming = 0;
- vfe->ops->vfe_halt(vfe);
+ vfe->res->hw_ops->vfe_halt(vfe);
}
camss_disable_clocks(vfe->nclocks, vfe->clock);
pm_runtime_put_sync(vfe->camss->dev);
- vfe->ops->pm_domain_off(vfe);
+ vfe->res->hw_ops->pm_domain_off(vfe);
}
vfe->power_count--;
@@ -834,12 +946,12 @@ static int vfe_set_stream(struct v4l2_subdev *sd, int enable)
if (enable) {
line->output.state = VFE_OUTPUT_RESERVED;
- ret = vfe->ops->vfe_enable(line);
+ ret = vfe->res->hw_ops->vfe_enable(line);
if (ret < 0)
dev_err(vfe->camss->dev,
"Failed to enable vfe outputs\n");
} else {
- ret = vfe->ops->vfe_disable(line);
+ ret = vfe->res->hw_ops->vfe_disable(line);
if (ret < 0)
dev_err(vfe->camss->dev,
"Failed to disable vfe outputs\n");
@@ -1376,23 +1488,24 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
int i, j;
int ret;
- vfe->ops = res->ops;
-
- if (!res->line_num)
+ if (!res->vfe.line_num)
return -EINVAL;
+ vfe->res = &res->vfe;
+ vfe->res->hw_ops->subdev_init(dev, vfe);
+
/* Power domain */
- if (res->pd_name) {
+ if (res->vfe.pd_name) {
vfe->genpd = dev_pm_domain_attach_by_name(camss->dev,
- res->pd_name);
+ res->vfe.pd_name);
if (IS_ERR(vfe->genpd)) {
ret = PTR_ERR(vfe->genpd);
return ret;
}
}
- if (!vfe->genpd && res->has_pd) {
+ if (!vfe->genpd && res->vfe.has_pd) {
/*
* Legacy magic index.
* Requires
@@ -1409,9 +1522,6 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
return PTR_ERR(vfe->genpd);
}
- vfe->line_num = res->line_num;
- vfe->ops->subdev_init(dev, vfe);
-
/* Memory */
vfe->base = devm_platform_ioremap_resource_byname(pdev, res->reg[0]);
@@ -1429,7 +1539,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
vfe->irq = ret;
snprintf(vfe->irq_name, sizeof(vfe->irq_name), "%s_%s%d",
dev_name(dev), MSM_VFE_NAME, id);
- ret = devm_request_irq(dev, vfe->irq, vfe->ops->isr,
+ ret = devm_request_irq(dev, vfe->irq, vfe->res->hw_ops->isr,
IRQF_TRIGGER_RISING, vfe->irq_name, vfe);
if (ret < 0) {
dev_err(dev, "request_irq failed: %d\n", ret);
@@ -1488,7 +1598,7 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
vfe->id = id;
vfe->reg_update = 0;
- for (i = VFE_LINE_RDI0; i < vfe->line_num; i++) {
+ for (i = VFE_LINE_RDI0; i < vfe->res->line_num; i++) {
struct vfe_line *l = &vfe->line[i];
l->video_out.type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
@@ -1497,32 +1607,12 @@ int msm_vfe_subdev_init(struct camss *camss, struct vfe_device *vfe,
init_completion(&l->output.sof);
init_completion(&l->output.reg_update);
- switch (camss->res->version) {
- case CAMSS_8x16:
- if (i == VFE_LINE_PIX) {
- l->formats = formats_pix_8x16;
- l->nformats = ARRAY_SIZE(formats_pix_8x16);
- } else {
- l->formats = formats_rdi_8x16;
- l->nformats = ARRAY_SIZE(formats_rdi_8x16);
- }
- break;
- case CAMSS_8x96:
- case CAMSS_660:
- if (i == VFE_LINE_PIX) {
- l->formats = formats_pix_8x96;
- l->nformats = ARRAY_SIZE(formats_pix_8x96);
- } else {
- l->formats = formats_rdi_8x96;
- l->nformats = ARRAY_SIZE(formats_rdi_8x96);
- }
- break;
- case CAMSS_845:
- case CAMSS_8250:
- case CAMSS_8280XP:
- l->formats = formats_rdi_845;
- l->nformats = ARRAY_SIZE(formats_rdi_845);
- break;
+ if (i == VFE_LINE_PIX) {
+ l->nformats = res->vfe.formats_pix->nformats;
+ l->formats = res->vfe.formats_pix->formats;
+ } else {
+ l->nformats = res->vfe.formats_rdi->nformats;
+ l->formats = res->vfe.formats_rdi->formats;
}
}
@@ -1636,7 +1726,7 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
int ret;
int i;
- for (i = 0; i < vfe->line_num; i++) {
+ for (i = 0; i < vfe->res->line_num; i++) {
char name[32];
sd = &vfe->line[i].subdev;
@@ -1686,10 +1776,13 @@ int msm_vfe_register_entities(struct vfe_device *vfe,
video_out->bpl_alignment = 16;
video_out->line_based = 1;
}
+
+ video_out->nformats = vfe->line[i].nformats;
+ video_out->formats = vfe->line[i].formats;
+
snprintf(name, ARRAY_SIZE(name), "%s%d_%s%d",
MSM_VFE_NAME, vfe->id, "video", i);
- ret = msm_video_register(video_out, v4l2_dev, name,
- i == VFE_LINE_PIX ? 1 : 0);
+ ret = msm_video_register(video_out, v4l2_dev, name);
if (ret < 0) {
dev_err(dev, "Failed to register video node: %d\n",
ret);
@@ -1743,7 +1836,7 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe)
mutex_destroy(&vfe->power_lock);
mutex_destroy(&vfe->stream_lock);
- for (i = 0; i < vfe->line_num; i++) {
+ for (i = 0; i < vfe->res->line_num; i++) {
struct v4l2_subdev *sd = &vfe->line[i].subdev;
struct camss_video *video_out = &vfe->line[i].video_out;
@@ -1755,5 +1848,5 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe)
bool vfe_is_lite(struct vfe_device *vfe)
{
- return vfe->camss->res->vfe_res[vfe->id].is_lite;
+ return vfe->camss->res->vfe_res[vfe->id].vfe.is_lite;
}
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 0572c9b08e11..10e2cc3c0b83 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -92,7 +92,7 @@ struct vfe_line {
struct v4l2_rect crop;
struct camss_video video_out;
struct vfe_output output;
- const struct vfe_format *formats;
+ const struct camss_format_info *formats;
unsigned int nformats;
};
@@ -126,6 +126,16 @@ struct vfe_isr_ops {
void (*wm_done)(struct vfe_device *vfe, u8 wm);
};
+struct vfe_subdev_resources {
+ bool is_lite;
+ u8 line_num;
+ bool has_pd;
+ char *pd_name;
+ const struct vfe_hw_ops *hw_ops;
+ const struct camss_formats *formats_rdi;
+ const struct camss_formats *formats_pix;
+};
+
struct vfe_device {
struct camss *camss;
u8 id;
@@ -143,10 +153,9 @@ struct vfe_device {
spinlock_t output_lock;
enum vfe_line_id wm_output_map[MSM_VFE_IMAGE_MASTERS_NUM];
struct vfe_line line[VFE_LINE_NUM_MAX];
- u8 line_num;
u32 reg_update;
u8 was_streaming;
- const struct vfe_hw_ops *ops;
+ const struct vfe_subdev_resources *res;
const struct vfe_hw_ops_gen1 *ops_gen1;
struct vfe_isr_ops isr_ops;
struct camss_video_ops video_ops;
@@ -217,6 +226,13 @@ void vfe_pm_domain_off(struct vfe_device *vfe);
*/
int vfe_pm_domain_on(struct vfe_device *vfe);
+extern const struct camss_formats vfe_formats_rdi_8x16;
+extern const struct camss_formats vfe_formats_pix_8x16;
+extern const struct camss_formats vfe_formats_rdi_8x96;
+extern const struct camss_formats vfe_formats_pix_8x96;
+extern const struct camss_formats vfe_formats_rdi_845;
+extern const struct camss_formats vfe_formats_pix_845;
+
extern const struct vfe_hw_ops vfe_ops_4_1;
extern const struct vfe_hw_ops vfe_ops_4_7;
extern const struct vfe_hw_ops vfe_ops_4_8;
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index 54cd82f74115..cd72feca618c 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -24,269 +24,10 @@
#define CAMSS_FRAME_MAX_HEIGHT_RDI 8191
#define CAMSS_FRAME_MAX_HEIGHT_PIX 4096
-struct fract {
- u8 numerator;
- u8 denominator;
-};
-
-/*
- * struct camss_format_info - ISP media bus format information
- * @code: V4L2 media bus format code
- * @pixelformat: V4L2 pixel format FCC identifier
- * @planes: Number of planes
- * @hsub: Horizontal subsampling (for each plane)
- * @vsub: Vertical subsampling (for each plane)
- * @bpp: Bits per pixel when stored in memory (for each plane)
- */
-struct camss_format_info {
- u32 code;
- u32 pixelformat;
- u8 planes;
- struct fract hsub[3];
- struct fract vsub[3];
- unsigned int bpp[3];
-};
-
-static const struct camss_format_info formats_rdi_8x16[] = {
- { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
-};
-
-static const struct camss_format_info formats_rdi_8x96[] = {
- { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 14 } },
- { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 14 } },
- { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 14 } },
- { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 14 } },
- { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
-};
-
-static const struct camss_format_info formats_rdi_845[] = {
- { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_PIX_FMT_SBGGR8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SGBRG8_1X8, V4L2_PIX_FMT_SGBRG8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SGRBG8_1X8, V4L2_PIX_FMT_SGRBG8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SRGGB8_1X8, V4L2_PIX_FMT_SRGGB8, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_PIX_FMT_SBGGR10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SGBRG10_1X10, V4L2_PIX_FMT_SGBRG10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SGRBG10_1X10, V4L2_PIX_FMT_SGRBG10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SRGGB10_1X10, V4L2_PIX_FMT_SRGGB10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_PIX_FMT_SBGGR10, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_SBGGR12_1X12, V4L2_PIX_FMT_SBGGR12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SGBRG12_1X12, V4L2_PIX_FMT_SGBRG12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SGRBG12_1X12, V4L2_PIX_FMT_SGRBG12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SRGGB12_1X12, V4L2_PIX_FMT_SRGGB12P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 12 } },
- { MEDIA_BUS_FMT_SBGGR14_1X14, V4L2_PIX_FMT_SBGGR14P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 14 } },
- { MEDIA_BUS_FMT_SGBRG14_1X14, V4L2_PIX_FMT_SGBRG14P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 14 } },
- { MEDIA_BUS_FMT_SGRBG14_1X14, V4L2_PIX_FMT_SGRBG14P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 14 } },
- { MEDIA_BUS_FMT_SRGGB14_1X14, V4L2_PIX_FMT_SRGGB14P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 14 } },
- { MEDIA_BUS_FMT_Y8_1X8, V4L2_PIX_FMT_GREY, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 8 } },
- { MEDIA_BUS_FMT_Y10_1X10, V4L2_PIX_FMT_Y10P, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 10 } },
- { MEDIA_BUS_FMT_Y10_2X8_PADHI_LE, V4L2_PIX_FMT_Y10, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
-};
-
-static const struct camss_format_info formats_pix_8x16[] = {
- { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV16, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV16, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV16, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV16, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV61, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV61, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV61, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV61, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
-};
-
-static const struct camss_format_info formats_pix_8x96[] = {
- { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV12, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV12, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV12, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_YUYV8_1_5X8, V4L2_PIX_FMT_NV21, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_YVYU8_1_5X8, V4L2_PIX_FMT_NV21, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_UYVY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_VYUY8_1_5X8, V4L2_PIX_FMT_NV21, 1,
- { { 1, 1 } }, { { 2, 3 } }, { 8 } },
- { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV16, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV16, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV16, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV16, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_NV61, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_NV61, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_NV61, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_NV61, 1,
- { { 1, 1 } }, { { 1, 2 } }, { 8 } },
- { MEDIA_BUS_FMT_UYVY8_1X16, V4L2_PIX_FMT_UYVY, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_VYUY8_1X16, V4L2_PIX_FMT_VYUY, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_YUYV8_1X16, V4L2_PIX_FMT_YUYV, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
- { MEDIA_BUS_FMT_YVYU8_1X16, V4L2_PIX_FMT_YVYU, 1,
- { { 1, 1 } }, { { 1, 1 } }, { 16 } },
-};
-
/* -----------------------------------------------------------------------------
* Helper functions
*/
-static int video_find_format(u32 code, u32 pixelformat,
- const struct camss_format_info *formats,
- unsigned int nformats)
-{
- int i;
-
- for (i = 0; i < nformats; i++) {
- if (formats[i].code == code &&
- formats[i].pixelformat == pixelformat)
- return i;
- }
-
- for (i = 0; i < nformats; i++)
- if (formats[i].code == code)
- return i;
-
- WARN_ON(1);
-
- return -EINVAL;
-}
-
/*
* video_mbus_to_pix_mp - Convert v4l2_mbus_framefmt to v4l2_pix_format_mplane
* @mbus: v4l2_mbus_framefmt format (input)
@@ -359,9 +100,8 @@ static int video_get_subdev_format(struct camss_video *video,
if (ret)
return ret;
- ret = video_find_format(fmt.format.code,
- format->fmt.pix_mp.pixelformat,
- video->formats, video->nformats);
+ ret = camss_format_find_format(fmt.format.code, format->fmt.pix_mp.pixelformat,
+ video->formats, video->nformats);
if (ret < 0)
return ret;
@@ -969,7 +709,7 @@ static int msm_video_init_format(struct camss_video *video)
*/
int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
- const char *name, int is_pix)
+ const char *name)
{
struct media_pad *pad = &video->pad;
struct video_device *vdev;
@@ -1006,34 +746,6 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
mutex_init(&video->lock);
- switch (video->camss->res->version) {
- case CAMSS_8x16:
- if (is_pix) {
- video->formats = formats_pix_8x16;
- video->nformats = ARRAY_SIZE(formats_pix_8x16);
- } else {
- video->formats = formats_rdi_8x16;
- video->nformats = ARRAY_SIZE(formats_rdi_8x16);
- }
- break;
- case CAMSS_8x96:
- case CAMSS_660:
- if (is_pix) {
- video->formats = formats_pix_8x96;
- video->nformats = ARRAY_SIZE(formats_pix_8x96);
- } else {
- video->formats = formats_rdi_8x96;
- video->nformats = ARRAY_SIZE(formats_rdi_8x96);
- }
- break;
- case CAMSS_845:
- case CAMSS_8250:
- case CAMSS_8280XP:
- video->formats = formats_rdi_845;
- video->nformats = ARRAY_SIZE(formats_rdi_845);
- break;
- }
-
ret = msm_video_init_format(video);
if (ret < 0) {
dev_err(v4l2_dev->dev, "Failed to init format: %d\n", ret);
diff --git a/drivers/media/platform/qcom/camss/camss-video.h b/drivers/media/platform/qcom/camss/camss-video.h
index bdbae8424140..d3e56e240a88 100644
--- a/drivers/media/platform/qcom/camss/camss-video.h
+++ b/drivers/media/platform/qcom/camss/camss-video.h
@@ -33,8 +33,6 @@ struct camss_video_ops {
enum vb2_buffer_state state);
};
-struct camss_format_info;
-
struct camss_video {
struct camss *camss;
struct vb2_queue vb2_q;
@@ -53,7 +51,7 @@ struct camss_video {
};
int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
- const char *name, int is_pix);
+ const char *name);
void msm_video_unregister(struct camss_video *video);
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 1923615f0eea..51b1d3550421 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -32,6 +32,8 @@
#define CAMSS_CLOCK_MARGIN_NUMERATOR 105
#define CAMSS_CLOCK_MARGIN_DENOMINATOR 100
+static const struct parent_dev_ops vfe_parent_dev_ops;
+
static const struct camss_subdev_resources csiphy_res_8x16[] = {
/* CSIPHY0 */
{
@@ -43,7 +45,10 @@ static const struct camss_subdev_resources csiphy_res_8x16[] = {
{ 100000000, 200000000 } },
.reg = { "csiphy0", "csiphy0_clk_mux" },
.interrupt = { "csiphy0" },
- .ops = &csiphy_ops_2ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_2ph_1_0,
+ .formats = &csiphy_formats_8x16
+ }
},
/* CSIPHY1 */
@@ -56,7 +61,10 @@ static const struct camss_subdev_resources csiphy_res_8x16[] = {
{ 100000000, 200000000 } },
.reg = { "csiphy1", "csiphy1_clk_mux" },
.interrupt = { "csiphy1" },
- .ops = &csiphy_ops_2ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_2ph_1_0,
+ .formats = &csiphy_formats_8x16
+ }
}
};
@@ -76,7 +84,11 @@ static const struct camss_subdev_resources csid_res_8x16[] = {
{ 0 } },
.reg = { "csid0" },
.interrupt = { "csid0" },
- .ops = &csid_ops_4_1,
+ .csid = {
+ .hw_ops = &csid_ops_4_1,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_1
+ }
},
/* CSID1 */
@@ -94,7 +106,11 @@ static const struct camss_subdev_resources csid_res_8x16[] = {
{ 0 } },
.reg = { "csid1" },
.interrupt = { "csid1" },
- .ops = &csid_ops_4_1,
+ .csid = {
+ .hw_ops = &csid_ops_4_1,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_1
+ }
},
};
@@ -105,8 +121,7 @@ static const struct camss_subdev_resources ispif_res_8x16 = {
"csi1", "csi1_pix", "csi1_rdi" },
.clock_for_reset = { "vfe0", "csi_vfe0" },
.reg = { "ispif", "csi_clk_mux" },
- .interrupt = { "ispif" }
-
+ .interrupt = { "ispif" },
};
static const struct camss_subdev_resources vfe_res_8x16[] = {
@@ -128,8 +143,12 @@ static const struct camss_subdev_resources vfe_res_8x16[] = {
{ 0 } },
.reg = { "vfe0" },
.interrupt = { "vfe0" },
- .line_num = 3,
- .ops = &vfe_ops_4_1
+ .vfe = {
+ .line_num = 3,
+ .hw_ops = &vfe_ops_4_1,
+ .formats_rdi = &vfe_formats_rdi_8x16,
+ .formats_pix = &vfe_formats_pix_8x16
+ }
}
};
@@ -144,7 +163,10 @@ static const struct camss_subdev_resources csiphy_res_8x96[] = {
{ 100000000, 200000000, 266666667 } },
.reg = { "csiphy0", "csiphy0_clk_mux" },
.interrupt = { "csiphy0" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_8x96
+ }
},
/* CSIPHY1 */
@@ -157,7 +179,10 @@ static const struct camss_subdev_resources csiphy_res_8x96[] = {
{ 100000000, 200000000, 266666667 } },
.reg = { "csiphy1", "csiphy1_clk_mux" },
.interrupt = { "csiphy1" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_8x96
+ }
},
/* CSIPHY2 */
@@ -170,7 +195,10 @@ static const struct camss_subdev_resources csiphy_res_8x96[] = {
{ 100000000, 200000000, 266666667 } },
.reg = { "csiphy2", "csiphy2_clk_mux" },
.interrupt = { "csiphy2" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_8x96
+ }
}
};
@@ -190,7 +218,11 @@ static const struct camss_subdev_resources csid_res_8x96[] = {
{ 0 } },
.reg = { "csid0" },
.interrupt = { "csid0" },
- .ops = &csid_ops_4_7,
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
},
/* CSID1 */
@@ -208,7 +240,11 @@ static const struct camss_subdev_resources csid_res_8x96[] = {
{ 0 } },
.reg = { "csid1" },
.interrupt = { "csid1" },
- .ops = &csid_ops_4_7,
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
},
/* CSID2 */
@@ -226,7 +262,11 @@ static const struct camss_subdev_resources csid_res_8x96[] = {
{ 0 } },
.reg = { "csid2" },
.interrupt = { "csid2" },
- .ops = &csid_ops_4_7,
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
},
/* CSID3 */
@@ -244,7 +284,11 @@ static const struct camss_subdev_resources csid_res_8x96[] = {
{ 0 } },
.reg = { "csid3" },
.interrupt = { "csid3" },
- .ops = &csid_ops_4_7,
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
}
};
@@ -257,7 +301,7 @@ static const struct camss_subdev_resources ispif_res_8x96 = {
"csi3", "csi3_pix", "csi3_rdi" },
.clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" },
.reg = { "ispif", "csi_clk_mux" },
- .interrupt = { "ispif" }
+ .interrupt = { "ispif" },
};
static const struct camss_subdev_resources vfe_res_8x96[] = {
@@ -277,9 +321,13 @@ static const struct camss_subdev_resources vfe_res_8x96[] = {
{ 0 } },
.reg = { "vfe0" },
.interrupt = { "vfe0" },
- .line_num = 3,
- .has_pd = true,
- .ops = &vfe_ops_4_7
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .hw_ops = &vfe_ops_4_7,
+ .formats_rdi = &vfe_formats_rdi_8x96,
+ .formats_pix = &vfe_formats_pix_8x96
+ }
},
/* VFE1 */
@@ -298,9 +346,13 @@ static const struct camss_subdev_resources vfe_res_8x96[] = {
{ 0 } },
.reg = { "vfe1" },
.interrupt = { "vfe1" },
- .line_num = 3,
- .has_pd = true,
- .ops = &vfe_ops_4_7
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .hw_ops = &vfe_ops_4_7,
+ .formats_rdi = &vfe_formats_rdi_8x96,
+ .formats_pix = &vfe_formats_pix_8x96
+ }
}
};
@@ -317,7 +369,10 @@ static const struct camss_subdev_resources csiphy_res_660[] = {
{ 0 } },
.reg = { "csiphy0", "csiphy0_clk_mux" },
.interrupt = { "csiphy0" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_8x96
+ }
},
/* CSIPHY1 */
@@ -332,7 +387,10 @@ static const struct camss_subdev_resources csiphy_res_660[] = {
{ 0 } },
.reg = { "csiphy1", "csiphy1_clk_mux" },
.interrupt = { "csiphy1" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_8x96
+ }
},
/* CSIPHY2 */
@@ -347,7 +405,10 @@ static const struct camss_subdev_resources csiphy_res_660[] = {
{ 0 } },
.reg = { "csiphy2", "csiphy2_clk_mux" },
.interrupt = { "csiphy2" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_8x96
+ }
}
};
@@ -370,7 +431,11 @@ static const struct camss_subdev_resources csid_res_660[] = {
{ 0 } },
.reg = { "csid0" },
.interrupt = { "csid0" },
- .ops = &csid_ops_4_7,
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
},
/* CSID1 */
@@ -391,7 +456,11 @@ static const struct camss_subdev_resources csid_res_660[] = {
{ 0 } },
.reg = { "csid1" },
.interrupt = { "csid1" },
- .ops = &csid_ops_4_7,
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
},
/* CSID2 */
@@ -412,7 +481,11 @@ static const struct camss_subdev_resources csid_res_660[] = {
{ 0 } },
.reg = { "csid2" },
.interrupt = { "csid2" },
- .ops = &csid_ops_4_7,
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
},
/* CSID3 */
@@ -433,7 +506,11 @@ static const struct camss_subdev_resources csid_res_660[] = {
{ 0 } },
.reg = { "csid3" },
.interrupt = { "csid3" },
- .ops = &csid_ops_4_7,
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
}
};
@@ -446,7 +523,7 @@ static const struct camss_subdev_resources ispif_res_660 = {
"csi3", "csi3_pix", "csi3_rdi" },
.clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" },
.reg = { "ispif", "csi_clk_mux" },
- .interrupt = { "ispif" }
+ .interrupt = { "ispif" },
};
static const struct camss_subdev_resources vfe_res_660[] = {
@@ -469,9 +546,13 @@ static const struct camss_subdev_resources vfe_res_660[] = {
{ 0 } },
.reg = { "vfe0" },
.interrupt = { "vfe0" },
- .line_num = 3,
- .has_pd = true,
- .ops = &vfe_ops_4_8
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .hw_ops = &vfe_ops_4_8,
+ .formats_rdi = &vfe_formats_rdi_8x96,
+ .formats_pix = &vfe_formats_pix_8x96
+ }
},
/* VFE1 */
@@ -493,9 +574,13 @@ static const struct camss_subdev_resources vfe_res_660[] = {
{ 0 } },
.reg = { "vfe1" },
.interrupt = { "vfe1" },
- .line_num = 3,
- .has_pd = true,
- .ops = &vfe_ops_4_8
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .hw_ops = &vfe_ops_4_8,
+ .formats_rdi = &vfe_formats_rdi_8x96,
+ .formats_pix = &vfe_formats_pix_8x96
+ }
}
};
@@ -516,7 +601,10 @@ static const struct camss_subdev_resources csiphy_res_845[] = {
{ 19200000, 240000000, 269333333 } },
.reg = { "csiphy0" },
.interrupt = { "csiphy0" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY1 */
@@ -535,7 +623,10 @@ static const struct camss_subdev_resources csiphy_res_845[] = {
{ 19200000, 240000000, 269333333 } },
.reg = { "csiphy1" },
.interrupt = { "csiphy1" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY2 */
@@ -554,7 +645,10 @@ static const struct camss_subdev_resources csiphy_res_845[] = {
{ 19200000, 240000000, 269333333 } },
.reg = { "csiphy2" },
.interrupt = { "csiphy2" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY3 */
@@ -573,7 +667,10 @@ static const struct camss_subdev_resources csiphy_res_845[] = {
{ 19200000, 240000000, 269333333 } },
.reg = { "csiphy3" },
.interrupt = { "csiphy3" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
}
};
@@ -596,7 +693,11 @@ static const struct camss_subdev_resources csid_res_845[] = {
{ 384000000 } },
.reg = { "csid0" },
.interrupt = { "csid0" },
- .ops = &csid_ops_gen2
+ .csid = {
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID1 */
@@ -617,7 +718,11 @@ static const struct camss_subdev_resources csid_res_845[] = {
{ 384000000 } },
.reg = { "csid1" },
.interrupt = { "csid1" },
- .ops = &csid_ops_gen2
+ .csid = {
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID2 */
@@ -638,8 +743,12 @@ static const struct camss_subdev_resources csid_res_845[] = {
{ 384000000 } },
.reg = { "csid2" },
.interrupt = { "csid2" },
- .is_lite = true,
- .ops = &csid_ops_gen2
+ .csid = {
+ .is_lite = true,
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
}
};
@@ -662,9 +771,13 @@ static const struct camss_subdev_resources vfe_res_845[] = {
{ 384000000 } },
.reg = { "vfe0" },
.interrupt = { "vfe0" },
- .line_num = 4,
- .has_pd = true,
- .ops = &vfe_ops_170
+ .vfe = {
+ .line_num = 4,
+ .has_pd = true,
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE1 */
@@ -685,9 +798,13 @@ static const struct camss_subdev_resources vfe_res_845[] = {
{ 384000000 } },
.reg = { "vfe1" },
.interrupt = { "vfe1" },
- .line_num = 4,
- .has_pd = true,
- .ops = &vfe_ops_170
+ .vfe = {
+ .line_num = 4,
+ .has_pd = true,
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE-lite */
@@ -707,9 +824,13 @@ static const struct camss_subdev_resources vfe_res_845[] = {
{ 384000000 } },
.reg = { "vfe_lite" },
.interrupt = { "vfe_lite" },
- .is_lite = true,
- .line_num = 4,
- .ops = &vfe_ops_170
+ .vfe = {
+ .is_lite = true,
+ .line_num = 4,
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
}
};
@@ -722,7 +843,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
{ 300000000 } },
.reg = { "csiphy0" },
.interrupt = { "csiphy0" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY1 */
{
@@ -732,7 +856,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
{ 300000000 } },
.reg = { "csiphy1" },
.interrupt = { "csiphy1" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY2 */
{
@@ -742,7 +869,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
{ 300000000 } },
.reg = { "csiphy2" },
.interrupt = { "csiphy2" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY3 */
{
@@ -752,7 +882,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
{ 300000000 } },
.reg = { "csiphy3" },
.interrupt = { "csiphy3" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY4 */
{
@@ -762,7 +895,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
{ 300000000 } },
.reg = { "csiphy4" },
.interrupt = { "csiphy4" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY5 */
{
@@ -772,7 +908,10 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
{ 300000000 } },
.reg = { "csiphy5" },
.interrupt = { "csiphy5" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
}
};
@@ -788,7 +927,11 @@ static const struct camss_subdev_resources csid_res_8250[] = {
{ 0 } },
.reg = { "csid0" },
.interrupt = { "csid0" },
- .ops = &csid_ops_gen2
+ .csid = {
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID1 */
{
@@ -801,7 +944,11 @@ static const struct camss_subdev_resources csid_res_8250[] = {
{ 0 } },
.reg = { "csid1" },
.interrupt = { "csid1" },
- .ops = &csid_ops_gen2
+ .csid = {
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID2 */
{
@@ -813,8 +960,12 @@ static const struct camss_subdev_resources csid_res_8250[] = {
{ 0 } },
.reg = { "csid2" },
.interrupt = { "csid2" },
- .is_lite = true,
- .ops = &csid_ops_gen2
+ .csid = {
+ .is_lite = true,
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID3 */
{
@@ -826,8 +977,12 @@ static const struct camss_subdev_resources csid_res_8250[] = {
{ 0 } },
.reg = { "csid3" },
.interrupt = { "csid3" },
- .is_lite = true,
- .ops = &csid_ops_gen2
+ .csid = {
+ .is_lite = true,
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
}
};
@@ -849,10 +1004,14 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
{ 0 } },
.reg = { "vfe0" },
.interrupt = { "vfe0" },
- .pd_name = "ife0",
- .line_num = 3,
- .has_pd = true,
- .ops = &vfe_ops_480
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .pd_name = "ife0",
+ .hw_ops = &vfe_ops_480,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE1 */
{
@@ -871,10 +1030,14 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
{ 0 } },
.reg = { "vfe1" },
.interrupt = { "vfe1" },
- .pd_name = "ife1",
- .line_num = 3,
- .has_pd = true,
- .ops = &vfe_ops_480
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .pd_name = "ife1",
+ .hw_ops = &vfe_ops_480,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE2 (lite) */
{
@@ -892,9 +1055,13 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
{ 0 } },
.reg = { "vfe_lite0" },
.interrupt = { "vfe_lite0" },
- .is_lite = true,
- .line_num = 4,
- .ops = &vfe_ops_480
+ .vfe = {
+ .is_lite = true,
+ .line_num = 4,
+ .hw_ops = &vfe_ops_480,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE3 (lite) */
{
@@ -912,9 +1079,13 @@ static const struct camss_subdev_resources vfe_res_8250[] = {
{ 0 } },
.reg = { "vfe_lite1" },
.interrupt = { "vfe_lite1" },
- .is_lite = true,
- .line_num = 4,
- .ops = &vfe_ops_480
+ .vfe = {
+ .is_lite = true,
+ .line_num = 4,
+ .hw_ops = &vfe_ops_480,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
};
@@ -950,7 +1121,10 @@ static const struct camss_subdev_resources csiphy_res_sc8280xp[] = {
{ 300000000 } },
.reg = { "csiphy0" },
.interrupt = { "csiphy0" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY1 */
{
@@ -960,7 +1134,10 @@ static const struct camss_subdev_resources csiphy_res_sc8280xp[] = {
{ 300000000 } },
.reg = { "csiphy1" },
.interrupt = { "csiphy1" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY2 */
{
@@ -970,7 +1147,10 @@ static const struct camss_subdev_resources csiphy_res_sc8280xp[] = {
{ 300000000 } },
.reg = { "csiphy2" },
.interrupt = { "csiphy2" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
/* CSIPHY3 */
{
@@ -980,7 +1160,10 @@ static const struct camss_subdev_resources csiphy_res_sc8280xp[] = {
{ 300000000 } },
.reg = { "csiphy3" },
.interrupt = { "csiphy3" },
- .ops = &csiphy_ops_3ph_1_0
+ .csiphy = {
+ .hw_ops = &csiphy_ops_3ph_1_0,
+ .formats = &csiphy_formats_sdm845
+ }
},
};
@@ -995,7 +1178,11 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = {
{ 0 } },
.reg = { "csid0" },
.interrupt = { "csid0" },
- .ops = &csid_ops_gen2
+ .csid = {
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID1 */
{
@@ -1007,7 +1194,11 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = {
{ 0 } },
.reg = { "csid1" },
.interrupt = { "csid1" },
- .ops = &csid_ops_gen2
+ .csid = {
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID2 */
{
@@ -1019,7 +1210,11 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = {
{ 0 } },
.reg = { "csid2" },
.interrupt = { "csid2" },
- .ops = &csid_ops_gen2
+ .csid = {
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID3 */
{
@@ -1031,7 +1226,11 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = {
{ 0 } },
.reg = { "csid3" },
.interrupt = { "csid3" },
- .ops = &csid_ops_gen2
+ .csid = {
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID_LITE0 */
{
@@ -1042,8 +1241,12 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = {
{ 0 }, },
.reg = { "csid0_lite" },
.interrupt = { "csid0_lite" },
- .is_lite = true,
- .ops = &csid_ops_gen2
+ .csid = {
+ .is_lite = true,
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID_LITE1 */
{
@@ -1054,8 +1257,12 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = {
{ 0 }, },
.reg = { "csid1_lite" },
.interrupt = { "csid1_lite" },
- .is_lite = true,
- .ops = &csid_ops_gen2
+ .csid = {
+ .is_lite = true,
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID_LITE2 */
{
@@ -1066,8 +1273,12 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = {
{ 0 }, },
.reg = { "csid2_lite" },
.interrupt = { "csid2_lite" },
- .is_lite = true,
- .ops = &csid_ops_gen2
+ .csid = {
+ .is_lite = true,
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
},
/* CSID_LITE3 */
{
@@ -1078,8 +1289,12 @@ static const struct camss_subdev_resources csid_res_sc8280xp[] = {
{ 0 }, },
.reg = { "csid3_lite" },
.interrupt = { "csid3_lite" },
- .is_lite = true,
- .ops = &csid_ops_gen2
+ .csid = {
+ .is_lite = true,
+ .hw_ops = &csid_ops_gen2,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_gen2
+ }
}
};
@@ -1096,9 +1311,13 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
{ 0 }, },
.reg = { "vfe0" },
.interrupt = { "vfe0" },
- .pd_name = "ife0",
- .line_num = 4,
- .ops = &vfe_ops_170
+ .vfe = {
+ .line_num = 4,
+ .pd_name = "ife0",
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE1 */
{
@@ -1112,9 +1331,13 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
{ 0 }, },
.reg = { "vfe1" },
.interrupt = { "vfe1" },
- .pd_name = "ife1",
- .line_num = 4,
- .ops = &vfe_ops_170
+ .vfe = {
+ .line_num = 4,
+ .pd_name = "ife1",
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE2 */
{
@@ -1128,9 +1351,13 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
{ 0 }, },
.reg = { "vfe2" },
.interrupt = { "vfe2" },
- .pd_name = "ife2",
- .line_num = 4,
- .ops = &vfe_ops_170
+ .vfe = {
+ .line_num = 4,
+ .pd_name = "ife2",
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE3 */
{
@@ -1144,9 +1371,13 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
{ 0 }, },
.reg = { "vfe3" },
.interrupt = { "vfe3" },
- .pd_name = "ife3",
- .line_num = 4,
- .ops = &vfe_ops_170
+ .vfe = {
+ .line_num = 4,
+ .pd_name = "ife3",
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE_LITE_0 */
{
@@ -1159,9 +1390,13 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
{ 320000000, 400000000, 480000000, 600000000 }, },
.reg = { "vfe_lite0" },
.interrupt = { "vfe_lite0" },
- .is_lite = true,
- .line_num = 4,
- .ops = &vfe_ops_170
+ .vfe = {
+ .is_lite = true,
+ .line_num = 4,
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE_LITE_1 */
{
@@ -1174,9 +1409,13 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
{ 320000000, 400000000, 480000000, 600000000 }, },
.reg = { "vfe_lite1" },
.interrupt = { "vfe_lite1" },
- .is_lite = true,
- .line_num = 4,
- .ops = &vfe_ops_170
+ .vfe = {
+ .is_lite = true,
+ .line_num = 4,
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE_LITE_2 */
{
@@ -1189,9 +1428,13 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
{ 320000000, 400000000, 480000000, 600000000, }, },
.reg = { "vfe_lite2" },
.interrupt = { "vfe_lite2" },
- .is_lite = true,
- .line_num = 4,
- .ops = &vfe_ops_170
+ .vfe = {
+ .is_lite = true,
+ .line_num = 4,
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
/* VFE_LITE_3 */
{
@@ -1204,9 +1447,13 @@ static const struct camss_subdev_resources vfe_res_sc8280xp[] = {
{ 320000000, 400000000, 480000000, 600000000 }, },
.reg = { "vfe_lite3" },
.interrupt = { "vfe_lite3" },
- .is_lite = true,
- .line_num = 4,
- .ops = &vfe_ops_170
+ .vfe = {
+ .is_lite = true,
+ .line_num = 4,
+ .hw_ops = &vfe_ops_170,
+ .formats_rdi = &vfe_formats_rdi_845,
+ .formats_pix = &vfe_formats_pix_845
+ }
},
};
@@ -1375,7 +1622,7 @@ int camss_pm_domain_on(struct camss *camss, int id)
if (id < camss->res->vfe_num) {
struct vfe_device *vfe = &camss->vfe[id];
- ret = vfe->ops->pm_domain_on(vfe);
+ ret = vfe->res->hw_ops->pm_domain_on(vfe);
}
return ret;
@@ -1386,10 +1633,52 @@ void camss_pm_domain_off(struct camss *camss, int id)
if (id < camss->res->vfe_num) {
struct vfe_device *vfe = &camss->vfe[id];
- vfe->ops->pm_domain_off(vfe);
+ vfe->res->hw_ops->pm_domain_off(vfe);
+ }
+}
+
+static int vfe_parent_dev_ops_get(struct camss *camss, int id)
+{
+ int ret = -EINVAL;
+
+ if (id < camss->res->vfe_num) {
+ struct vfe_device *vfe = &camss->vfe[id];
+
+ ret = vfe_get(vfe);
}
+
+ return ret;
+}
+
+static int vfe_parent_dev_ops_put(struct camss *camss, int id)
+{
+ if (id < camss->res->vfe_num) {
+ struct vfe_device *vfe = &camss->vfe[id];
+
+ vfe_put(vfe);
+ }
+
+ return 0;
}
+static void __iomem
+*vfe_parent_dev_ops_get_base_address(struct camss *camss, int id)
+{
+ if (id < camss->res->vfe_num) {
+ struct vfe_device *vfe = &camss->vfe[id];
+
+ return vfe->base;
+ }
+
+ return NULL;
+}
+
+static const struct parent_dev_ops vfe_parent_dev_ops = {
+ .get = vfe_parent_dev_ops_get,
+ .put = vfe_parent_dev_ops_put,
+ .get_base_address = vfe_parent_dev_ops_get_base_address
+};
+
/*
* camss_of_parse_endpoint_node - Parse port endpoint node
* @dev: Device
@@ -1406,8 +1695,11 @@ static int camss_of_parse_endpoint_node(struct device *dev,
struct v4l2_mbus_config_mipi_csi2 *mipi_csi2;
struct v4l2_fwnode_endpoint vep = { { 0 } };
unsigned int i;
+ int ret;
- v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep);
+ ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(node), &vep);
+ if (ret)
+ return ret;
csd->interface.csiphy_id = vep.base.port;
@@ -1536,72 +1828,30 @@ static int camss_init_subdevices(struct camss *camss)
}
/*
- * camss_register_entities - Register subdev nodes and create links
+ * camss_link_entities - Register subdev nodes and create links
* @camss: CAMSS device
*
* Return 0 on success or a negative error code on failure
*/
-static int camss_register_entities(struct camss *camss)
+static int camss_link_entities(struct camss *camss)
{
int i, j, k;
int ret;
for (i = 0; i < camss->res->csiphy_num; i++) {
- ret = msm_csiphy_register_entity(&camss->csiphy[i],
- &camss->v4l2_dev);
- if (ret < 0) {
- dev_err(camss->dev,
- "Failed to register csiphy%d entity: %d\n",
- i, ret);
- goto err_reg_csiphy;
- }
- }
-
- for (i = 0; i < camss->res->csid_num; i++) {
- ret = msm_csid_register_entity(&camss->csid[i],
- &camss->v4l2_dev);
- if (ret < 0) {
- dev_err(camss->dev,
- "Failed to register csid%d entity: %d\n",
- i, ret);
- goto err_reg_csid;
- }
- }
-
- ret = msm_ispif_register_entities(camss->ispif,
- &camss->v4l2_dev);
- if (ret < 0) {
- dev_err(camss->dev, "Failed to register ispif entities: %d\n",
- ret);
- goto err_reg_ispif;
- }
-
- for (i = 0; i < camss->res->vfe_num; i++) {
- ret = msm_vfe_register_entities(&camss->vfe[i],
- &camss->v4l2_dev);
- if (ret < 0) {
- dev_err(camss->dev,
- "Failed to register vfe%d entities: %d\n",
- i, ret);
- goto err_reg_vfe;
- }
- }
-
- for (i = 0; i < camss->res->csiphy_num; i++) {
for (j = 0; j < camss->res->csid_num; j++) {
- ret = media_create_pad_link(
- &camss->csiphy[i].subdev.entity,
- MSM_CSIPHY_PAD_SRC,
- &camss->csid[j].subdev.entity,
- MSM_CSID_PAD_SINK,
- 0);
+ ret = media_create_pad_link(&camss->csiphy[i].subdev.entity,
+ MSM_CSIPHY_PAD_SRC,
+ &camss->csid[j].subdev.entity,
+ MSM_CSID_PAD_SINK,
+ 0);
if (ret < 0) {
dev_err(camss->dev,
"Failed to link %s->%s entities: %d\n",
camss->csiphy[i].subdev.entity.name,
camss->csid[j].subdev.entity.name,
ret);
- goto err_link;
+ return ret;
}
}
}
@@ -1609,26 +1859,25 @@ static int camss_register_entities(struct camss *camss)
if (camss->ispif) {
for (i = 0; i < camss->res->csid_num; i++) {
for (j = 0; j < camss->ispif->line_num; j++) {
- ret = media_create_pad_link(
- &camss->csid[i].subdev.entity,
- MSM_CSID_PAD_SRC,
- &camss->ispif->line[j].subdev.entity,
- MSM_ISPIF_PAD_SINK,
- 0);
+ ret = media_create_pad_link(&camss->csid[i].subdev.entity,
+ MSM_CSID_PAD_SRC,
+ &camss->ispif->line[j].subdev.entity,
+ MSM_ISPIF_PAD_SINK,
+ 0);
if (ret < 0) {
dev_err(camss->dev,
"Failed to link %s->%s entities: %d\n",
camss->csid[i].subdev.entity.name,
camss->ispif->line[j].subdev.entity.name,
ret);
- goto err_link;
+ return ret;
}
}
}
for (i = 0; i < camss->ispif->line_num; i++)
for (k = 0; k < camss->res->vfe_num; k++)
- for (j = 0; j < camss->vfe[k].line_num; j++) {
+ for (j = 0; j < camss->vfe[k].res->line_num; j++) {
struct v4l2_subdev *ispif = &camss->ispif->line[i].subdev;
struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev;
@@ -1643,13 +1892,13 @@ static int camss_register_entities(struct camss *camss)
ispif->entity.name,
vfe->entity.name,
ret);
- goto err_link;
+ return ret;
}
}
} else {
for (i = 0; i < camss->res->csid_num; i++)
for (k = 0; k < camss->res->vfe_num; k++)
- for (j = 0; j < camss->vfe[k].line_num; j++) {
+ for (j = 0; j < camss->vfe[k].res->line_num; j++) {
struct v4l2_subdev *csid = &camss->csid[i].subdev;
struct v4l2_subdev *vfe = &camss->vfe[k].line[j].subdev;
@@ -1664,15 +1913,67 @@ static int camss_register_entities(struct camss *camss)
csid->entity.name,
vfe->entity.name,
ret);
- goto err_link;
+ return ret;
}
}
}
return 0;
+}
+
+/*
+ * camss_register_entities - Register subdev nodes and create links
+ * @camss: CAMSS device
+ *
+ * Return 0 on success or a negative error code on failure
+ */
+static int camss_register_entities(struct camss *camss)
+{
+ int i;
+ int ret;
+
+ for (i = 0; i < camss->res->csiphy_num; i++) {
+ ret = msm_csiphy_register_entity(&camss->csiphy[i],
+ &camss->v4l2_dev);
+ if (ret < 0) {
+ dev_err(camss->dev,
+ "Failed to register csiphy%d entity: %d\n",
+ i, ret);
+ goto err_reg_csiphy;
+ }
+ }
+
+ for (i = 0; i < camss->res->csid_num; i++) {
+ ret = msm_csid_register_entity(&camss->csid[i],
+ &camss->v4l2_dev);
+ if (ret < 0) {
+ dev_err(camss->dev,
+ "Failed to register csid%d entity: %d\n",
+ i, ret);
+ goto err_reg_csid;
+ }
+ }
+
+ ret = msm_ispif_register_entities(camss->ispif,
+ &camss->v4l2_dev);
+ if (ret < 0) {
+ dev_err(camss->dev, "Failed to register ispif entities: %d\n", ret);
+ goto err_reg_ispif;
+ }
+
+ for (i = 0; i < camss->res->vfe_num; i++) {
+ ret = msm_vfe_register_entities(&camss->vfe[i],
+ &camss->v4l2_dev);
+ if (ret < 0) {
+ dev_err(camss->dev,
+ "Failed to register vfe%d entities: %d\n",
+ i, ret);
+ goto err_reg_vfe;
+ }
+ }
+
+ return 0;
-err_link:
- i = camss->res->vfe_num;
err_reg_vfe:
for (i--; i >= 0; i--)
msm_vfe_unregister_entities(&camss->vfe[i]);
@@ -1810,7 +2111,7 @@ static int camss_configure_pd(struct camss *camss)
/* count the # of VFEs which have flagged power-domain */
for (vfepd_num = i = 0; i < camss->res->vfe_num; i++) {
- if (res->vfe_res[i].has_pd)
+ if (res->vfe_res[i].vfe.has_pd)
vfepd_num++;
}
@@ -1992,6 +2293,10 @@ static int camss_probe(struct platform_device *pdev)
if (ret < 0)
goto err_v4l2_device_unregister;
+ ret = camss->res->link_entities(camss);
+ if (ret < 0)
+ goto err_register_subdevs;
+
if (num_subdevs) {
camss->notifier.ops = &camss_subdev_notifier_ops;
@@ -2071,6 +2376,7 @@ static const struct camss_resources msm8916_resources = {
.csiphy_num = ARRAY_SIZE(csiphy_res_8x16),
.csid_num = ARRAY_SIZE(csid_res_8x16),
.vfe_num = ARRAY_SIZE(vfe_res_8x16),
+ .link_entities = camss_link_entities
};
static const struct camss_resources msm8996_resources = {
@@ -2082,6 +2388,7 @@ static const struct camss_resources msm8996_resources = {
.csiphy_num = ARRAY_SIZE(csiphy_res_8x96),
.csid_num = ARRAY_SIZE(csid_res_8x96),
.vfe_num = ARRAY_SIZE(vfe_res_8x96),
+ .link_entities = camss_link_entities
};
static const struct camss_resources sdm660_resources = {
@@ -2093,6 +2400,7 @@ static const struct camss_resources sdm660_resources = {
.csiphy_num = ARRAY_SIZE(csiphy_res_660),
.csid_num = ARRAY_SIZE(csid_res_660),
.vfe_num = ARRAY_SIZE(vfe_res_660),
+ .link_entities = camss_link_entities
};
static const struct camss_resources sdm845_resources = {
@@ -2103,6 +2411,7 @@ static const struct camss_resources sdm845_resources = {
.csiphy_num = ARRAY_SIZE(csiphy_res_845),
.csid_num = ARRAY_SIZE(csid_res_845),
.vfe_num = ARRAY_SIZE(vfe_res_845),
+ .link_entities = camss_link_entities
};
static const struct camss_resources sm8250_resources = {
@@ -2116,6 +2425,7 @@ static const struct camss_resources sm8250_resources = {
.csiphy_num = ARRAY_SIZE(csiphy_res_8250),
.csid_num = ARRAY_SIZE(csid_res_8250),
.vfe_num = ARRAY_SIZE(vfe_res_8250),
+ .link_entities = camss_link_entities
};
static const struct camss_resources sc8280xp_resources = {
@@ -2130,6 +2440,7 @@ static const struct camss_resources sc8280xp_resources = {
.csiphy_num = ARRAY_SIZE(csiphy_res_sc8280xp),
.csid_num = ARRAY_SIZE(csid_res_sc8280xp),
.vfe_num = ARRAY_SIZE(vfe_res_sc8280xp),
+ .link_entities = camss_link_entities
};
static const struct of_device_id camss_dt_match[] = {
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index ac15fe23a702..73c47c07fc30 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -22,6 +22,7 @@
#include "camss-csiphy.h"
#include "camss-ispif.h"
#include "camss-vfe.h"
+#include "camss-format.h"
#define to_camss(ptr_module) \
container_of(ptr_module, struct camss, ptr_module)
@@ -48,11 +49,11 @@ struct camss_subdev_resources {
u32 clock_rate[CAMSS_RES_MAX][CAMSS_RES_MAX];
char *reg[CAMSS_RES_MAX];
char *interrupt[CAMSS_RES_MAX];
- char *pd_name;
- u8 line_num;
- bool has_pd;
- bool is_lite;
- const void *ops;
+ union {
+ struct csiphy_subdev_resources csiphy;
+ struct csid_subdev_resources csid;
+ struct vfe_subdev_resources vfe;
+ };
};
struct icc_bw_tbl {
@@ -97,6 +98,7 @@ struct camss_resources {
const unsigned int csiphy_num;
const unsigned int csid_num;
const unsigned int vfe_num;
+ int (*link_entities)(struct camss *camss);
};
struct camss {
@@ -133,6 +135,12 @@ struct camss_clock {
u32 nfreqs;
};
+struct parent_dev_ops {
+ int (*get)(struct camss *camss, int id);
+ int (*put)(struct camss *camss, int id);
+ void __iomem *(*get_base_address)(struct camss *camss, int id);
+};
+
void camss_add_clock_margin(u64 *rate);
int camss_enable_clocks(int nclocks, struct camss_clock *clock,
struct device *dev);
@@ -143,6 +151,8 @@ s64 camss_get_link_freq(struct media_entity *entity, unsigned int bpp,
int camss_get_pixel_clock(struct media_entity *entity, u64 *pixel_clock);
int camss_pm_domain_on(struct camss *camss, int id);
void camss_pm_domain_off(struct camss *camss, int id);
+int camss_vfe_get(struct camss *camss, int id);
+void camss_vfe_put(struct camss *camss, int id);
void camss_delete(struct camss *camss);
#endif /* QC_MSM_CAMSS_H */
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index ce206b709754..165c947a6703 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -68,6 +68,7 @@ static void venus_event_notify(struct venus_core *core, u32 event)
mutex_lock(&core->lock);
set_bit(0, &core->sys_error);
+ set_bit(0, &core->dump_core);
list_for_each_entry(inst, &core->instances, list)
inst->ops->event_notify(inst, EVT_SESSION_ERROR, NULL);
mutex_unlock(&core->lock);
@@ -110,7 +111,10 @@ static void venus_sys_error_handler(struct work_struct *work)
venus_shutdown(core);
- venus_coredump(core);
+ if (test_bit(0, &core->dump_core)) {
+ venus_coredump(core);
+ clear_bit(0, &core->dump_core);
+ }
pm_runtime_put_sync(core->dev);
@@ -587,6 +591,44 @@ static const struct venus_resources msm8996_res = {
.fwname = "qcom/venus-4.2/venus.mbn",
};
+static const struct freq_tbl msm8998_freq_table[] = {
+ { 1944000, 465000000 }, /* 4k UHD @ 60 (decode only) */
+ { 972000, 465000000 }, /* 4k UHD @ 30 */
+ { 489600, 360000000 }, /* 1080p @ 60 */
+ { 244800, 186000000 }, /* 1080p @ 30 */
+ { 108000, 100000000 }, /* 720p @ 30 */
+};
+
+static const struct reg_val msm8998_reg_preset[] = {
+ { 0x80124, 0x00000003 },
+ { 0x80550, 0x01111111 },
+ { 0x80560, 0x01111111 },
+ { 0x80568, 0x01111111 },
+ { 0x80570, 0x01111111 },
+ { 0x80580, 0x01111111 },
+ { 0x80588, 0x01111111 },
+ { 0xe2010, 0x00000000 },
+};
+
+static const struct venus_resources msm8998_res = {
+ .freq_tbl = msm8998_freq_table,
+ .freq_tbl_size = ARRAY_SIZE(msm8998_freq_table),
+ .reg_tbl = msm8998_reg_preset,
+ .reg_tbl_size = ARRAY_SIZE(msm8998_reg_preset),
+ .clks = { "core", "iface", "bus", "mbus" },
+ .clks_num = 4,
+ .vcodec0_clks = { "core" },
+ .vcodec1_clks = { "core" },
+ .vcodec_clks_num = 1,
+ .max_load = 2563200,
+ .hfi_version = HFI_VERSION_3XX,
+ .vmem_id = VIDC_RESOURCE_NONE,
+ .vmem_size = 0,
+ .vmem_addr = 0,
+ .dma_mask = 0xddc00000 - 1,
+ .fwname = "qcom/venus-4.4/venus.mbn",
+};
+
static const struct freq_tbl sdm660_freq_table[] = {
{ 979200, 518400000 },
{ 489600, 441600000 },
@@ -893,6 +935,7 @@ static const struct venus_resources sc7280_res = {
static const struct of_device_id venus_dt_match[] = {
{ .compatible = "qcom,msm8916-venus", .data = &msm8916_res, },
{ .compatible = "qcom,msm8996-venus", .data = &msm8996_res, },
+ { .compatible = "qcom,msm8998-venus", .data = &msm8998_res, },
{ .compatible = "qcom,sdm660-venus", .data = &sdm660_res, },
{ .compatible = "qcom,sdm845-venus", .data = &sdm845_res, },
{ .compatible = "qcom,sdm845-venus-v2", .data = &sdm845_res_v2, },
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index 6a77de374454..55202b89e1b9 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -169,6 +169,7 @@ struct venus_format {
* @core1_usage_count: usage counter for core1
* @root: debugfs root directory
* @venus_ver: the venus firmware version
+ * @dump_core: a flag indicating that a core dump is required
*/
struct venus_core {
void __iomem *base;
@@ -232,6 +233,7 @@ struct venus_core {
u32 minor;
u32 rev;
} venus_ver;
+ unsigned long dump_core;
};
struct vdec_controls {
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index 29130a9441e7..d12089370d91 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -1255,7 +1255,7 @@ static int vdec_stop_output(struct venus_inst *inst)
break;
case VENUS_DEC_STATE_INIT:
case VENUS_DEC_STATE_CAPTURE_SETUP:
- ret = hfi_session_flush(inst, HFI_FLUSH_INPUT, true);
+ ret = hfi_session_flush(inst, HFI_FLUSH_ALL, true);
break;
default:
break;
@@ -1747,6 +1747,7 @@ static int vdec_close(struct file *file)
vdec_pm_get(inst);
+ cancel_work_sync(&inst->delayed_process_work);
v4l2_m2m_ctx_release(inst->m2m_ctx);
v4l2_m2m_release(inst->m2m_dev);
vdec_ctrl_deinit(inst);
diff --git a/drivers/media/platform/raspberrypi/Kconfig b/drivers/media/platform/raspberrypi/Kconfig
new file mode 100644
index 000000000000..e928f979019e
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/Kconfig
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: GPL-2.0-only
+
+comment "Raspberry Pi media platform drivers"
+
+source "drivers/media/platform/raspberrypi/pisp_be/Kconfig"
diff --git a/drivers/media/platform/raspberrypi/Makefile b/drivers/media/platform/raspberrypi/Makefile
new file mode 100644
index 000000000000..c0d1a2dab486
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/Makefile
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: GPL-2.0
+
+obj-y += pisp_be/
diff --git a/drivers/media/platform/raspberrypi/pisp_be/Kconfig b/drivers/media/platform/raspberrypi/pisp_be/Kconfig
new file mode 100644
index 000000000000..38c0f8305d62
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/pisp_be/Kconfig
@@ -0,0 +1,12 @@
+config VIDEO_RASPBERRYPI_PISP_BE
+ tristate "Raspberry Pi PiSP Backend (BE) ISP driver"
+ depends on V4L_PLATFORM_DRIVERS
+ depends on VIDEO_DEV
+ select VIDEO_V4L2_SUBDEV_API
+ select MEDIA_CONTROLLER
+ select VIDEOBUF2_DMA_CONTIG
+ help
+ Say Y here to enable support for the PiSP Backend (BE) ISP driver.
+
+ To compile this driver as a module, choose M here. The module will be
+ called pisp-be.
diff --git a/drivers/media/platform/raspberrypi/pisp_be/Makefile b/drivers/media/platform/raspberrypi/pisp_be/Makefile
new file mode 100644
index 000000000000..a70bf5716824
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/pisp_be/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for Raspberry Pi PiSP Backend driver
+#
+pisp-be-objs := pisp_be.o
+obj-$(CONFIG_VIDEO_RASPBERRYPI_PISP_BE) += pisp-be.o
diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
new file mode 100644
index 000000000000..65ff2382cffe
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
@@ -0,0 +1,1797 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PiSP Back End driver.
+ * Copyright (c) 2021-2024 Raspberry Pi Limited.
+ *
+ */
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/lockdep.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-vmalloc.h>
+
+#include <uapi/linux/media/raspberrypi/pisp_be_config.h>
+
+#include "pisp_be_formats.h"
+
+/* Maximum number of config buffers possible */
+#define PISP_BE_NUM_CONFIG_BUFFERS VB2_MAX_FRAME
+
+#define PISPBE_NAME "pispbe"
+
+/* Some ISP-BE registers */
+#define PISP_BE_VERSION_REG 0x0
+#define PISP_BE_CONTROL_REG 0x4
+#define PISP_BE_CONTROL_COPY_CONFIG BIT(1)
+#define PISP_BE_CONTROL_QUEUE_JOB BIT(0)
+#define PISP_BE_CONTROL_NUM_TILES(n) ((n) << 16)
+#define PISP_BE_TILE_ADDR_LO_REG 0x8
+#define PISP_BE_TILE_ADDR_HI_REG 0xc
+#define PISP_BE_STATUS_REG 0x10
+#define PISP_BE_STATUS_QUEUED BIT(0)
+#define PISP_BE_BATCH_STATUS_REG 0x14
+#define PISP_BE_INTERRUPT_EN_REG 0x18
+#define PISP_BE_INTERRUPT_STATUS_REG 0x1c
+#define PISP_BE_AXI_REG 0x20
+#define PISP_BE_CONFIG_BASE_REG 0x40
+#define PISP_BE_IO_ADDR_LOW(n) (PISP_BE_CONFIG_BASE_REG + 8 * (n))
+#define PISP_BE_IO_ADDR_HIGH(n) (PISP_BE_IO_ADDR_LOW((n)) + 4)
+#define PISP_BE_GLOBAL_BAYER_ENABLE 0xb0
+#define PISP_BE_GLOBAL_RGB_ENABLE 0xb4
+#define N_HW_ADDRESSES 13
+#define N_HW_ENABLES 2
+
+#define PISP_BE_VERSION_2712 0x02252700
+#define PISP_BE_VERSION_MINOR_BITS 0xf
+
+/*
+ * This maps our nodes onto the inputs/outputs of the actual PiSP Back End.
+ * Be wary of the word "OUTPUT" which is used ambiguously here. In a V4L2
+ * context it means an input to the hardware (source image or metadata).
+ * Elsewhere it means an output from the hardware.
+ */
+enum pispbe_node_ids {
+ MAIN_INPUT_NODE,
+ TDN_INPUT_NODE,
+ STITCH_INPUT_NODE,
+ OUTPUT0_NODE,
+ OUTPUT1_NODE,
+ TDN_OUTPUT_NODE,
+ STITCH_OUTPUT_NODE,
+ CONFIG_NODE,
+ PISPBE_NUM_NODES
+};
+
+struct pispbe_node_description {
+ const char *ent_name;
+ enum v4l2_buf_type buf_type;
+ unsigned int caps;
+};
+
+static const struct pispbe_node_description node_desc[PISPBE_NUM_NODES] = {
+ /* MAIN_INPUT_NODE */
+ {
+ .ent_name = PISPBE_NAME "-input",
+ .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE,
+ },
+ /* TDN_INPUT_NODE */
+ {
+ .ent_name = PISPBE_NAME "-tdn_input",
+ .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE,
+ },
+ /* STITCH_INPUT_NODE */
+ {
+ .ent_name = PISPBE_NAME "-stitch_input",
+ .buf_type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE,
+ .caps = V4L2_CAP_VIDEO_OUTPUT_MPLANE,
+ },
+ /* OUTPUT0_NODE */
+ {
+ .ent_name = PISPBE_NAME "-output0",
+ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+ },
+ /* OUTPUT1_NODE */
+ {
+ .ent_name = PISPBE_NAME "-output1",
+ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+ },
+ /* TDN_OUTPUT_NODE */
+ {
+ .ent_name = PISPBE_NAME "-tdn_output",
+ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+ },
+ /* STITCH_OUTPUT_NODE */
+ {
+ .ent_name = PISPBE_NAME "-stitch_output",
+ .buf_type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE,
+ .caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE,
+ },
+ /* CONFIG_NODE */
+ {
+ .ent_name = PISPBE_NAME "-config",
+ .buf_type = V4L2_BUF_TYPE_META_OUTPUT,
+ .caps = V4L2_CAP_META_OUTPUT,
+ }
+};
+
+#define NODE_DESC_IS_OUTPUT(desc) ( \
+ ((desc)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \
+ ((desc)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT) || \
+ ((desc)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE))
+
+#define NODE_IS_META(node) ( \
+ ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT))
+#define NODE_IS_OUTPUT(node) ( \
+ ((node)->buf_type == V4L2_BUF_TYPE_META_OUTPUT) || \
+ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT) || \
+ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE))
+#define NODE_IS_CAPTURE(node) ( \
+ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE) || \
+ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
+#define NODE_IS_MPLANE(node) ( \
+ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) || \
+ ((node)->buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE))
+
+/*
+ * Structure to describe a single node /dev/video<N> which represents a single
+ * input or output queue to the PiSP Back End device.
+ */
+struct pispbe_node {
+ unsigned int id;
+ int vfl_dir;
+ enum v4l2_buf_type buf_type;
+ struct video_device vfd;
+ struct media_pad pad;
+ struct media_intf_devnode *intf_devnode;
+ struct media_link *intf_link;
+ struct pispbe_dev *pispbe;
+ /* Video device lock */
+ struct mutex node_lock;
+ /* vb2_queue lock */
+ struct mutex queue_lock;
+ /* Protect pispbe_node->ready_queue and pispbe_buffer->ready_list */
+ spinlock_t ready_lock;
+ struct list_head ready_queue;
+ struct vb2_queue queue;
+ struct v4l2_format format;
+ const struct pisp_be_format *pisp_format;
+};
+
+/* For logging only, use the entity name with "pispbe" and separator removed */
+#define NODE_NAME(node) \
+ (node_desc[(node)->id].ent_name + sizeof(PISPBE_NAME))
+
+/* Records details of the jobs currently running or queued on the h/w. */
+struct pispbe_job {
+ bool valid;
+ /*
+ * An array of buffer pointers - remember it's source buffers first,
+ * then captures, then metadata last.
+ */
+ struct pispbe_buffer *buf[PISPBE_NUM_NODES];
+};
+
+struct pispbe_hw_enables {
+ u32 bayer_enables;
+ u32 rgb_enables;
+};
+
+/* Records a job configuration and memory addresses. */
+struct pispbe_job_descriptor {
+ dma_addr_t hw_dma_addrs[N_HW_ADDRESSES];
+ struct pisp_be_tiles_config *config;
+ struct pispbe_hw_enables hw_enables;
+ dma_addr_t tiles;
+};
+
+/*
+ * Structure representing the entire PiSP Back End device, comprising several
+ * nodes which share platform resources and a mutex for the actual HW.
+ */
+struct pispbe_dev {
+ struct device *dev;
+ struct pispbe_dev *pispbe;
+ struct pisp_be_tiles_config *config;
+ void __iomem *be_reg_base;
+ struct clk *clk;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev sd;
+ struct media_device mdev;
+ struct media_pad pad[PISPBE_NUM_NODES]; /* output pads first */
+ struct pispbe_node node[PISPBE_NUM_NODES];
+ dma_addr_t config_dma_addr;
+ unsigned int sequence;
+ u32 streaming_map;
+ struct pispbe_job queued_job, running_job;
+ spinlock_t hw_lock; /* protects "hw_busy" flag and streaming_map */
+ bool hw_busy; /* non-zero if a job is queued or is being started */
+ int irq;
+ u32 hw_version;
+ u8 done, started;
+};
+
+static u32 pispbe_rd(struct pispbe_dev *pispbe, unsigned int offset)
+{
+ return readl(pispbe->be_reg_base + offset);
+}
+
+static void pispbe_wr(struct pispbe_dev *pispbe, unsigned int offset, u32 val)
+{
+ writel(val, pispbe->be_reg_base + offset);
+}
+
+/*
+ * Queue a job to the h/w. If the h/w is idle it will begin immediately.
+ * Caller must ensure it is "safe to queue", i.e. we don't already have a
+ * queued, unstarted job.
+ */
+static void pispbe_queue_job(struct pispbe_dev *pispbe,
+ struct pispbe_job_descriptor *job)
+{
+ unsigned int begin, end;
+
+ if (pispbe_rd(pispbe, PISP_BE_STATUS_REG) & PISP_BE_STATUS_QUEUED)
+ dev_err(pispbe->dev, "ERROR: not safe to queue new job!\n");
+
+ /*
+ * Write configuration to hardware. DMA addresses and enable flags
+ * are passed separately, because the driver needs to sanitize them,
+ * and we don't want to modify (or be vulnerable to modifications of)
+ * the mmap'd buffer.
+ */
+ for (unsigned int u = 0; u < N_HW_ADDRESSES; ++u) {
+ pispbe_wr(pispbe, PISP_BE_IO_ADDR_LOW(u),
+ lower_32_bits(job->hw_dma_addrs[u]));
+ pispbe_wr(pispbe, PISP_BE_IO_ADDR_HIGH(u),
+ upper_32_bits(job->hw_dma_addrs[u]));
+ }
+ pispbe_wr(pispbe, PISP_BE_GLOBAL_BAYER_ENABLE,
+ job->hw_enables.bayer_enables);
+ pispbe_wr(pispbe, PISP_BE_GLOBAL_RGB_ENABLE,
+ job->hw_enables.rgb_enables);
+
+ /* Everything else is as supplied by the user. */
+ begin = offsetof(struct pisp_be_config, global.bayer_order) /
+ sizeof(u32);
+ end = sizeof(struct pisp_be_config) / sizeof(u32);
+ for (unsigned int u = begin; u < end; u++)
+ pispbe_wr(pispbe, PISP_BE_CONFIG_BASE_REG + sizeof(u32) * u,
+ ((u32 *)job->config)[u]);
+
+ /* Read back the addresses -- an error here could be fatal */
+ for (unsigned int u = 0; u < N_HW_ADDRESSES; ++u) {
+ unsigned int offset = PISP_BE_IO_ADDR_LOW(u);
+ u64 along = pispbe_rd(pispbe, offset);
+
+ along += ((u64)pispbe_rd(pispbe, offset + 4)) << 32;
+ if (along != (u64)(job->hw_dma_addrs[u])) {
+ dev_dbg(pispbe->dev,
+ "ISP BE config error: check if ISP RAMs enabled?\n");
+ return;
+ }
+ }
+
+ /*
+ * Write tile pointer to hardware. The IOMMU should prevent
+ * out-of-bounds offsets reaching non-ISP buffers.
+ */
+ pispbe_wr(pispbe, PISP_BE_TILE_ADDR_LO_REG, lower_32_bits(job->tiles));
+ pispbe_wr(pispbe, PISP_BE_TILE_ADDR_HI_REG, upper_32_bits(job->tiles));
+
+ /* Enqueue the job */
+ pispbe_wr(pispbe, PISP_BE_CONTROL_REG,
+ PISP_BE_CONTROL_COPY_CONFIG | PISP_BE_CONTROL_QUEUE_JOB |
+ PISP_BE_CONTROL_NUM_TILES(job->config->num_tiles));
+}
+
+struct pispbe_buffer {
+ struct vb2_v4l2_buffer vb;
+ struct list_head ready_list;
+ unsigned int config_index;
+};
+
+static int pispbe_get_planes_addr(dma_addr_t addr[3], struct pispbe_buffer *buf,
+ struct pispbe_node *node)
+{
+ unsigned int num_planes = node->format.fmt.pix_mp.num_planes;
+ unsigned int plane_factor = 0;
+ unsigned int size;
+ unsigned int p;
+
+ if (!buf || !node->pisp_format)
+ return 0;
+
+ /*
+ * Determine the base plane size. This will not be the same
+ * as node->format.fmt.pix_mp.plane_fmt[0].sizeimage for a single
+ * plane buffer in an mplane format.
+ */
+ size = node->format.fmt.pix_mp.plane_fmt[0].bytesperline *
+ node->format.fmt.pix_mp.height;
+
+ for (p = 0; p < num_planes && p < PISPBE_MAX_PLANES; p++) {
+ addr[p] = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, p);
+ plane_factor += node->pisp_format->plane_factor[p];
+ }
+
+ for (; p < PISPBE_MAX_PLANES && node->pisp_format->plane_factor[p]; p++) {
+ /*
+ * Calculate the address offset of this plane as needed
+ * by the hardware. This is specifically for non-mplane
+ * buffer formats, where there are 3 image planes, e.g.
+ * for the V4L2_PIX_FMT_YUV420 format.
+ */
+ addr[p] = addr[0] + ((size * plane_factor) >> 3);
+ plane_factor += node->pisp_format->plane_factor[p];
+ }
+
+ return num_planes;
+}
+
+static dma_addr_t pispbe_get_addr(struct pispbe_buffer *buf)
+{
+ if (buf)
+ return vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+
+ return 0;
+}
+
+static void pispbe_xlate_addrs(struct pispbe_dev *pispbe,
+ struct pispbe_job_descriptor *job,
+ struct pispbe_buffer *buf[PISPBE_NUM_NODES])
+{
+ struct pispbe_hw_enables *hw_en = &job->hw_enables;
+ struct pisp_be_tiles_config *config = job->config;
+ dma_addr_t *addrs = job->hw_dma_addrs;
+ int ret;
+
+ /* Take a copy of the "enable" bitmaps so we can modify them. */
+ hw_en->bayer_enables = config->config.global.bayer_enables;
+ hw_en->rgb_enables = config->config.global.rgb_enables;
+
+ /*
+ * Main input first. There are 3 address pointers, corresponding to up
+ * to 3 planes.
+ */
+ ret = pispbe_get_planes_addr(addrs, buf[MAIN_INPUT_NODE],
+ &pispbe->node[MAIN_INPUT_NODE]);
+ if (ret <= 0) {
+ /*
+ * This shouldn't happen; pispbe_schedule_internal should insist
+ * on an input.
+ */
+ dev_warn(pispbe->dev, "ISP-BE missing input\n");
+ hw_en->bayer_enables = 0;
+ hw_en->rgb_enables = 0;
+ return;
+ }
+
+ /*
+ * Now TDN/Stitch inputs and outputs. These are single-plane and only
+ * used with Bayer input. Input enables must match the requirements
+ * of the processing stages, otherwise the hardware can lock up!
+ */
+ if (hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_INPUT) {
+ addrs[3] = pispbe_get_addr(buf[TDN_INPUT_NODE]);
+ if (addrs[3] == 0 ||
+ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_TDN_INPUT) ||
+ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_TDN) ||
+ (config->config.tdn.reset & 1)) {
+ hw_en->bayer_enables &=
+ ~(PISP_BE_BAYER_ENABLE_TDN_INPUT |
+ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS);
+ if (!(config->config.tdn.reset & 1))
+ hw_en->bayer_enables &=
+ ~PISP_BE_BAYER_ENABLE_TDN;
+ }
+
+ addrs[4] = pispbe_get_addr(buf[STITCH_INPUT_NODE]);
+ if (addrs[4] == 0 ||
+ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_INPUT) ||
+ !(hw_en->bayer_enables & PISP_BE_BAYER_ENABLE_STITCH)) {
+ hw_en->bayer_enables &=
+ ~(PISP_BE_BAYER_ENABLE_STITCH_INPUT |
+ PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS |
+ PISP_BE_BAYER_ENABLE_STITCH);
+ }
+
+ addrs[5] = pispbe_get_addr(buf[TDN_OUTPUT_NODE]);
+ if (addrs[5] == 0)
+ hw_en->bayer_enables &=
+ ~(PISP_BE_BAYER_ENABLE_TDN_COMPRESS |
+ PISP_BE_BAYER_ENABLE_TDN_OUTPUT);
+
+ addrs[6] = pispbe_get_addr(buf[STITCH_OUTPUT_NODE]);
+ if (addrs[6] == 0)
+ hw_en->bayer_enables &=
+ ~(PISP_BE_BAYER_ENABLE_STITCH_COMPRESS |
+ PISP_BE_BAYER_ENABLE_STITCH_OUTPUT);
+ } else {
+ /* No Bayer input? Disable entire Bayer pipe (else lockup) */
+ hw_en->bayer_enables = 0;
+ }
+
+ /* Main image output channels. */
+ for (unsigned int i = 0; i < PISP_BACK_END_NUM_OUTPUTS; i++) {
+ ret = pispbe_get_planes_addr(addrs + 7 + 3 * i,
+ buf[OUTPUT0_NODE + i],
+ &pispbe->node[OUTPUT0_NODE + i]);
+ if (ret <= 0)
+ hw_en->rgb_enables &= ~(PISP_BE_RGB_ENABLE_OUTPUT0 << i);
+ }
+}
+
+/*
+ * Prepare a job description to be submitted to the HW.
+ *
+ * To schedule a job, we need all streaming nodes (apart from Output0,
+ * Output1, Tdn and Stitch) to have a buffer ready, which must
+ * include at least a config buffer and a main input image.
+ *
+ * For Output0, Output1, Tdn and Stitch, a buffer only needs to be
+ * available if the blocks are enabled in the config.
+ *
+ * Needs to be called with hw_lock held.
+ *
+ * Returns 0 if a job has been successfully prepared, < 0 otherwise.
+ */
+static int pispbe_prepare_job(struct pispbe_dev *pispbe,
+ struct pispbe_job_descriptor *job)
+{
+ struct pispbe_buffer *buf[PISPBE_NUM_NODES] = {};
+ unsigned int config_index;
+ struct pispbe_node *node;
+ unsigned long flags;
+
+ lockdep_assert_held(&pispbe->hw_lock);
+
+ memset(job, 0, sizeof(struct pispbe_job_descriptor));
+
+ if (((BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)) &
+ pispbe->streaming_map) !=
+ (BIT(CONFIG_NODE) | BIT(MAIN_INPUT_NODE)))
+ return -ENODEV;
+
+ node = &pispbe->node[CONFIG_NODE];
+ spin_lock_irqsave(&node->ready_lock, flags);
+ buf[CONFIG_NODE] = list_first_entry_or_null(&node->ready_queue,
+ struct pispbe_buffer,
+ ready_list);
+ if (buf[CONFIG_NODE]) {
+ list_del(&buf[CONFIG_NODE]->ready_list);
+ pispbe->queued_job.buf[CONFIG_NODE] = buf[CONFIG_NODE];
+ }
+ spin_unlock_irqrestore(&node->ready_lock, flags);
+
+ /* Exit early if no config buffer has been queued. */
+ if (!buf[CONFIG_NODE])
+ return -ENODEV;
+
+ config_index = buf[CONFIG_NODE]->vb.vb2_buf.index;
+ job->config = &pispbe->config[config_index];
+ job->tiles = pispbe->config_dma_addr +
+ config_index * sizeof(struct pisp_be_tiles_config) +
+ offsetof(struct pisp_be_tiles_config, tiles);
+
+ /* remember: srcimages, captures then metadata */
+ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) {
+ unsigned int bayer_en =
+ job->config->config.global.bayer_enables;
+ unsigned int rgb_en =
+ job->config->config.global.rgb_enables;
+ bool ignore_buffers = false;
+
+ /* Config node is handled outside the loop above. */
+ if (i == CONFIG_NODE)
+ continue;
+
+ buf[i] = NULL;
+ if (!(pispbe->streaming_map & BIT(i)))
+ continue;
+
+ if ((!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT0) &&
+ i == OUTPUT0_NODE) ||
+ (!(rgb_en & PISP_BE_RGB_ENABLE_OUTPUT1) &&
+ i == OUTPUT1_NODE) ||
+ (!(bayer_en & PISP_BE_BAYER_ENABLE_TDN_INPUT) &&
+ i == TDN_INPUT_NODE) ||
+ (!(bayer_en & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) &&
+ i == TDN_OUTPUT_NODE) ||
+ (!(bayer_en & PISP_BE_BAYER_ENABLE_STITCH_INPUT) &&
+ i == STITCH_INPUT_NODE) ||
+ (!(bayer_en & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT) &&
+ i == STITCH_OUTPUT_NODE)) {
+ /*
+ * Ignore Output0/Output1/Tdn/Stitch buffer check if the
+ * global enables aren't set for these blocks. If a
+ * buffer has been provided, we dequeue it back to the
+ * user with the other in-use buffers.
+ */
+ ignore_buffers = true;
+ }
+
+ node = &pispbe->node[i];
+
+ /* Pull a buffer from each V4L2 queue to form the queued job */
+ spin_lock_irqsave(&node->ready_lock, flags);
+ buf[i] = list_first_entry_or_null(&node->ready_queue,
+ struct pispbe_buffer,
+ ready_list);
+ if (buf[i]) {
+ list_del(&buf[i]->ready_list);
+ pispbe->queued_job.buf[i] = buf[i];
+ }
+ spin_unlock_irqrestore(&node->ready_lock, flags);
+
+ if (!buf[i] && !ignore_buffers)
+ goto err_return_buffers;
+ }
+
+ pispbe->queued_job.valid = true;
+
+ /* Convert buffers to DMA addresses for the hardware */
+ pispbe_xlate_addrs(pispbe, job, buf);
+
+ return 0;
+
+err_return_buffers:
+ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) {
+ struct pispbe_node *n = &pispbe->node[i];
+
+ if (!buf[i])
+ continue;
+
+ /* Return the buffer to the ready_list queue */
+ spin_lock_irqsave(&n->ready_lock, flags);
+ list_add(&buf[i]->ready_list, &n->ready_queue);
+ spin_unlock_irqrestore(&n->ready_lock, flags);
+ }
+
+ memset(&pispbe->queued_job, 0, sizeof(pispbe->queued_job));
+
+ return -ENODEV;
+}
+
+static void pispbe_schedule(struct pispbe_dev *pispbe, bool clear_hw_busy)
+{
+ struct pispbe_job_descriptor job;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+
+ if (clear_hw_busy)
+ pispbe->hw_busy = false;
+
+ if (pispbe->hw_busy)
+ goto unlock_and_return;
+
+ ret = pispbe_prepare_job(pispbe, &job);
+ if (ret)
+ goto unlock_and_return;
+
+ /*
+ * We can kick the job off without the hw_lock, as this can
+ * never run again until hw_busy is cleared, which will happen
+ * only when the following job has been queued and an interrupt
+ * is rised.
+ */
+ pispbe->hw_busy = true;
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+
+ if (job.config->num_tiles <= 0 ||
+ job.config->num_tiles > PISP_BACK_END_NUM_TILES ||
+ !((job.hw_enables.bayer_enables | job.hw_enables.rgb_enables) &
+ PISP_BE_BAYER_ENABLE_INPUT)) {
+ /*
+ * Bad job. We can't let it proceed as it could lock up
+ * the hardware, or worse!
+ *
+ * For now, just force num_tiles to 0, which causes the
+ * H/W to do something bizarre but survivable. It
+ * increments (started,done) counters by more than 1,
+ * but we seem to survive...
+ */
+ dev_dbg(pispbe->dev, "Bad job: invalid number of tiles: %u\n",
+ job.config->num_tiles);
+ job.config->num_tiles = 0;
+ }
+
+ pispbe_queue_job(pispbe, &job);
+
+ return;
+
+unlock_and_return:
+ /* No job has been queued, just release the lock and return. */
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+}
+
+static void pispbe_isr_jobdone(struct pispbe_dev *pispbe,
+ struct pispbe_job *job)
+{
+ struct pispbe_buffer **buf = job->buf;
+ u64 ts = ktime_get_ns();
+
+ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++) {
+ if (buf[i]) {
+ buf[i]->vb.vb2_buf.timestamp = ts;
+ buf[i]->vb.sequence = pispbe->sequence;
+ vb2_buffer_done(&buf[i]->vb.vb2_buf,
+ VB2_BUF_STATE_DONE);
+ }
+ }
+
+ pispbe->sequence++;
+}
+
+static irqreturn_t pispbe_isr(int irq, void *dev)
+{
+ struct pispbe_dev *pispbe = (struct pispbe_dev *)dev;
+ bool can_queue_another = false;
+ u8 started, done;
+ u32 u;
+
+ u = pispbe_rd(pispbe, PISP_BE_INTERRUPT_STATUS_REG);
+ if (u == 0)
+ return IRQ_NONE;
+
+ pispbe_wr(pispbe, PISP_BE_INTERRUPT_STATUS_REG, u);
+ u = pispbe_rd(pispbe, PISP_BE_BATCH_STATUS_REG);
+ done = (uint8_t)u;
+ started = (uint8_t)(u >> 8);
+
+ /*
+ * Be aware that done can go up by 2 and started by 1 when: a job that
+ * we previously saw "start" now finishes, and we then queued a new job
+ * which we see both start and finish "simultaneously".
+ */
+ if (pispbe->running_job.valid && pispbe->done != done) {
+ pispbe_isr_jobdone(pispbe, &pispbe->running_job);
+ memset(&pispbe->running_job, 0, sizeof(pispbe->running_job));
+ pispbe->done++;
+ }
+
+ if (pispbe->started != started) {
+ pispbe->started++;
+ can_queue_another = 1;
+
+ if (pispbe->done != done && pispbe->queued_job.valid) {
+ pispbe_isr_jobdone(pispbe, &pispbe->queued_job);
+ pispbe->done++;
+ } else {
+ pispbe->running_job = pispbe->queued_job;
+ }
+
+ memset(&pispbe->queued_job, 0, sizeof(pispbe->queued_job));
+ }
+
+ if (pispbe->done != done || pispbe->started != started) {
+ dev_dbg(pispbe->dev,
+ "Job counters not matching: done = %u, expected %u - started = %u, expected %u\n",
+ pispbe->done, done, pispbe->started, started);
+ pispbe->started = started;
+ pispbe->done = done;
+ }
+
+ /* check if there's more to do before going to sleep */
+ pispbe_schedule(pispbe, can_queue_another);
+
+ return IRQ_HANDLED;
+}
+
+static int pisp_be_validate_config(struct pispbe_dev *pispbe,
+ struct pisp_be_tiles_config *config)
+{
+ u32 bayer_enables = config->config.global.bayer_enables;
+ u32 rgb_enables = config->config.global.rgb_enables;
+ struct device *dev = pispbe->dev;
+ struct v4l2_format *fmt;
+ unsigned int bpl, size;
+
+ if (!(bayer_enables & PISP_BE_BAYER_ENABLE_INPUT) ==
+ !(rgb_enables & PISP_BE_RGB_ENABLE_INPUT)) {
+ dev_dbg(dev, "%s: Not one input enabled\n", __func__);
+ return -EIO;
+ }
+
+ /* Ensure output config strides and buffer sizes match the V4L2 formats. */
+ fmt = &pispbe->node[TDN_OUTPUT_NODE].format;
+ if (bayer_enables & PISP_BE_BAYER_ENABLE_TDN_OUTPUT) {
+ bpl = config->config.tdn_output_format.stride;
+ size = bpl * config->config.tdn_output_format.height;
+
+ if (fmt->fmt.pix_mp.plane_fmt[0].bytesperline < bpl) {
+ dev_dbg(dev, "%s: bpl mismatch on tdn_output\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (fmt->fmt.pix_mp.plane_fmt[0].sizeimage < size) {
+ dev_dbg(dev, "%s: size mismatch on tdn_output\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ fmt = &pispbe->node[STITCH_OUTPUT_NODE].format;
+ if (bayer_enables & PISP_BE_BAYER_ENABLE_STITCH_OUTPUT) {
+ bpl = config->config.stitch_output_format.stride;
+ size = bpl * config->config.stitch_output_format.height;
+
+ if (fmt->fmt.pix_mp.plane_fmt[0].bytesperline < bpl) {
+ dev_dbg(dev, "%s: bpl mismatch on stitch_output\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ if (fmt->fmt.pix_mp.plane_fmt[0].sizeimage < size) {
+ dev_dbg(dev, "%s: size mismatch on stitch_output\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+
+ for (unsigned int j = 0; j < PISP_BACK_END_NUM_OUTPUTS; j++) {
+ if (!(rgb_enables & PISP_BE_RGB_ENABLE_OUTPUT(j)))
+ continue;
+
+ if (config->config.output_format[j].image.format &
+ PISP_IMAGE_FORMAT_WALLPAPER_ROLL)
+ continue; /* TODO: Size checks for wallpaper formats */
+
+ fmt = &pispbe->node[OUTPUT0_NODE + j].format;
+ for (unsigned int i = 0; i < fmt->fmt.pix_mp.num_planes; i++) {
+ bpl = !i ? config->config.output_format[j].image.stride
+ : config->config.output_format[j].image.stride2;
+ size = bpl * config->config.output_format[j].image.height;
+
+ if (config->config.output_format[j].image.format &
+ PISP_IMAGE_FORMAT_SAMPLING_420)
+ size >>= 1;
+
+ if (fmt->fmt.pix_mp.plane_fmt[i].bytesperline < bpl) {
+ dev_dbg(dev, "%s: bpl mismatch on output %d\n",
+ __func__, j);
+ return -EINVAL;
+ }
+
+ if (fmt->fmt.pix_mp.plane_fmt[i].sizeimage < size) {
+ dev_dbg(dev, "%s: size mismatch on output\n",
+ __func__);
+ return -EINVAL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int pispbe_node_queue_setup(struct vb2_queue *q, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct pispbe_node *node = vb2_get_drv_priv(q);
+ struct pispbe_dev *pispbe = node->pispbe;
+ unsigned int num_planes = NODE_IS_MPLANE(node) ?
+ node->format.fmt.pix_mp.num_planes : 1;
+
+ if (*nplanes) {
+ if (*nplanes != num_planes)
+ return -EINVAL;
+
+ for (unsigned int i = 0; i < *nplanes; i++) {
+ unsigned int size = NODE_IS_MPLANE(node) ?
+ node->format.fmt.pix_mp.plane_fmt[i].sizeimage :
+ node->format.fmt.meta.buffersize;
+
+ if (sizes[i] < size)
+ return -EINVAL;
+ }
+
+ return 0;
+ }
+
+ *nplanes = num_planes;
+ for (unsigned int i = 0; i < *nplanes; i++) {
+ unsigned int size = NODE_IS_MPLANE(node) ?
+ node->format.fmt.pix_mp.plane_fmt[i].sizeimage :
+ node->format.fmt.meta.buffersize;
+ sizes[i] = size;
+ }
+
+ dev_dbg(pispbe->dev,
+ "Image (or metadata) size %u, nbuffers %u for node %s\n",
+ sizes[0], *nbuffers, NODE_NAME(node));
+
+ return 0;
+}
+
+static int pispbe_node_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct pispbe_node *node = vb2_get_drv_priv(vb->vb2_queue);
+ struct pispbe_dev *pispbe = node->pispbe;
+ unsigned int num_planes = NODE_IS_MPLANE(node) ?
+ node->format.fmt.pix_mp.num_planes : 1;
+
+ for (unsigned int i = 0; i < num_planes; i++) {
+ unsigned long size = NODE_IS_MPLANE(node) ?
+ node->format.fmt.pix_mp.plane_fmt[i].sizeimage :
+ node->format.fmt.meta.buffersize;
+
+ if (vb2_plane_size(vb, i) < size) {
+ dev_dbg(pispbe->dev,
+ "data will not fit into plane %d (%lu < %lu)\n",
+ i, vb2_plane_size(vb, i), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(vb, i, size);
+ }
+
+ if (node->id == CONFIG_NODE) {
+ void *dst = &node->pispbe->config[vb->index];
+ void *src = vb2_plane_vaddr(vb, 0);
+
+ memcpy(dst, src, sizeof(struct pisp_be_tiles_config));
+
+ return pisp_be_validate_config(pispbe, dst);
+ }
+
+ return 0;
+}
+
+static void pispbe_node_buffer_queue(struct vb2_buffer *buf)
+{
+ struct vb2_v4l2_buffer *vbuf =
+ container_of(buf, struct vb2_v4l2_buffer, vb2_buf);
+ struct pispbe_buffer *buffer =
+ container_of(vbuf, struct pispbe_buffer, vb);
+ struct pispbe_node *node = vb2_get_drv_priv(buf->vb2_queue);
+ struct pispbe_dev *pispbe = node->pispbe;
+ unsigned long flags;
+
+ dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node));
+ spin_lock_irqsave(&node->ready_lock, flags);
+ list_add_tail(&buffer->ready_list, &node->ready_queue);
+ spin_unlock_irqrestore(&node->ready_lock, flags);
+
+ /*
+ * Every time we add a buffer, check if there's now some work for the hw
+ * to do.
+ */
+ pispbe_schedule(pispbe, false);
+}
+
+static int pispbe_node_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct pispbe_node *node = vb2_get_drv_priv(q);
+ struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_buffer *buf, *tmp;
+ unsigned long flags;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(pispbe->dev);
+ if (ret < 0)
+ goto err_return_buffers;
+
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+ node->pispbe->streaming_map |= BIT(node->id);
+ node->pispbe->sequence = 0;
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+
+ dev_dbg(pispbe->dev, "%s: for node %s (count %u)\n",
+ __func__, NODE_NAME(node), count);
+ dev_dbg(pispbe->dev, "Nodes streaming now 0x%x\n",
+ node->pispbe->streaming_map);
+
+ /* Maybe we're ready to run. */
+ pispbe_schedule(pispbe, false);
+
+ return 0;
+
+err_return_buffers:
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+ list_for_each_entry_safe(buf, tmp, &node->ready_queue, ready_list) {
+ list_del(&buf->ready_list);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_QUEUED);
+ }
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+
+ return ret;
+}
+
+static void pispbe_node_stop_streaming(struct vb2_queue *q)
+{
+ struct pispbe_node *node = vb2_get_drv_priv(q);
+ struct pispbe_dev *pispbe = node->pispbe;
+ struct pispbe_buffer *buf;
+ unsigned long flags;
+
+ /*
+ * Now this is a bit awkward. In a simple M2M device we could just wait
+ * for all queued jobs to complete, but here there's a risk that a
+ * partial set of buffers was queued and cannot be run. For now, just
+ * cancel all buffers stuck in the "ready queue", then wait for any
+ * running job.
+ *
+ * This may return buffers out of order.
+ */
+ dev_dbg(pispbe->dev, "%s: for node %s\n", __func__, NODE_NAME(node));
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+ do {
+ unsigned long flags1;
+
+ spin_lock_irqsave(&node->ready_lock, flags1);
+ buf = list_first_entry_or_null(&node->ready_queue,
+ struct pispbe_buffer,
+ ready_list);
+ if (buf) {
+ list_del(&buf->ready_list);
+ vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&node->ready_lock, flags1);
+ } while (buf);
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+
+ vb2_wait_for_all_buffers(&node->queue);
+
+ spin_lock_irqsave(&pispbe->hw_lock, flags);
+ pispbe->streaming_map &= ~BIT(node->id);
+ spin_unlock_irqrestore(&pispbe->hw_lock, flags);
+
+ pm_runtime_mark_last_busy(pispbe->dev);
+ pm_runtime_put_autosuspend(pispbe->dev);
+
+ dev_dbg(pispbe->dev, "Nodes streaming now 0x%x\n",
+ pispbe->streaming_map);
+}
+
+static const struct vb2_ops pispbe_node_queue_ops = {
+ .queue_setup = pispbe_node_queue_setup,
+ .buf_prepare = pispbe_node_buffer_prepare,
+ .buf_queue = pispbe_node_buffer_queue,
+ .start_streaming = pispbe_node_start_streaming,
+ .stop_streaming = pispbe_node_stop_streaming,
+};
+
+static const struct v4l2_file_operations pispbe_fops = {
+ .owner = THIS_MODULE,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .poll = vb2_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = vb2_fop_mmap
+};
+
+static int pispbe_node_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+
+ strscpy(cap->driver, PISPBE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, PISPBE_NAME, sizeof(cap->card));
+
+ dev_dbg(pispbe->dev, "Caps for node %s: %x and %x (dev %x)\n",
+ NODE_NAME(node), cap->capabilities, cap->device_caps,
+ node->vfd.device_caps);
+
+ return 0;
+}
+
+static int pispbe_node_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
+ dev_dbg(pispbe->dev,
+ "Cannot get capture fmt for output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
+
+ *f = node->format;
+ dev_dbg(pispbe->dev, "Get capture format for node %s\n",
+ NODE_NAME(node));
+
+ return 0;
+}
+
+static int pispbe_node_g_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
+ dev_dbg(pispbe->dev,
+ "Cannot get capture fmt for output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
+
+ *f = node->format;
+ dev_dbg(pispbe->dev, "Get output format for node %s\n",
+ NODE_NAME(node));
+
+ return 0;
+}
+
+static int pispbe_node_g_fmt_meta_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) {
+ dev_dbg(pispbe->dev,
+ "Cannot get capture fmt for meta output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
+
+ *f = node->format;
+ dev_dbg(pispbe->dev, "Get output format for meta node %s\n",
+ NODE_NAME(node));
+
+ return 0;
+}
+
+static const struct pisp_be_format *pispbe_find_fmt(unsigned int fourcc)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(supported_formats); i++) {
+ if (supported_formats[i].fourcc == fourcc)
+ return &supported_formats[i];
+ }
+
+ return NULL;
+}
+
+static void pispbe_set_plane_params(struct v4l2_format *f,
+ const struct pisp_be_format *fmt)
+{
+ unsigned int nplanes = f->fmt.pix_mp.num_planes;
+ unsigned int total_plane_factor = 0;
+
+ for (unsigned int i = 0; i < PISPBE_MAX_PLANES; i++)
+ total_plane_factor += fmt->plane_factor[i];
+
+ for (unsigned int i = 0; i < nplanes; i++) {
+ struct v4l2_plane_pix_format *p = &f->fmt.pix_mp.plane_fmt[i];
+ unsigned int bpl, plane_size;
+
+ bpl = (f->fmt.pix_mp.width * fmt->bit_depth) >> 3;
+ bpl = ALIGN(max(p->bytesperline, bpl), fmt->align);
+
+ plane_size = bpl * f->fmt.pix_mp.height *
+ (nplanes > 1 ? fmt->plane_factor[i] : total_plane_factor);
+ /*
+ * The shift is to divide out the plane_factor fixed point
+ * scaling of 8.
+ */
+ plane_size = max(p->sizeimage, plane_size >> 3);
+
+ p->bytesperline = bpl;
+ p->sizeimage = plane_size;
+ }
+}
+
+static void pispbe_try_format(struct v4l2_format *f, struct pispbe_node *node)
+{
+ struct pispbe_dev *pispbe = node->pispbe;
+ u32 pixfmt = f->fmt.pix_mp.pixelformat;
+ const struct pisp_be_format *fmt;
+ bool is_rgb;
+
+ dev_dbg(pispbe->dev,
+ "%s: [%s] req %ux%u %p4cc, planes %d\n",
+ __func__, NODE_NAME(node), f->fmt.pix_mp.width,
+ f->fmt.pix_mp.height, &pixfmt,
+ f->fmt.pix_mp.num_planes);
+
+ fmt = pispbe_find_fmt(pixfmt);
+ if (!fmt) {
+ dev_dbg(pispbe->dev,
+ "%s: [%s] Format not found, defaulting to YUV420\n",
+ __func__, NODE_NAME(node));
+ fmt = pispbe_find_fmt(V4L2_PIX_FMT_YUV420);
+ }
+
+ f->fmt.pix_mp.pixelformat = fmt->fourcc;
+ f->fmt.pix_mp.num_planes = fmt->num_planes;
+ f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ f->fmt.pix_mp.width = max(min(f->fmt.pix_mp.width, 65536u),
+ PISP_BACK_END_MIN_TILE_WIDTH);
+ f->fmt.pix_mp.height = max(min(f->fmt.pix_mp.height, 65536u),
+ PISP_BACK_END_MIN_TILE_HEIGHT);
+
+ /*
+ * Fill in the actual colour space when the requested one was
+ * not supported. This also catches the case when the "default"
+ * colour space was requested (as that's never in the mask).
+ */
+ if (!(V4L2_COLORSPACE_MASK(f->fmt.pix_mp.colorspace) &
+ fmt->colorspace_mask))
+ f->fmt.pix_mp.colorspace = fmt->colorspace_default;
+
+ /* In all cases, we only support the defaults for these: */
+ f->fmt.pix_mp.ycbcr_enc =
+ V4L2_MAP_YCBCR_ENC_DEFAULT(f->fmt.pix_mp.colorspace);
+ f->fmt.pix_mp.xfer_func =
+ V4L2_MAP_XFER_FUNC_DEFAULT(f->fmt.pix_mp.colorspace);
+
+ is_rgb = f->fmt.pix_mp.colorspace == V4L2_COLORSPACE_SRGB;
+ f->fmt.pix_mp.quantization =
+ V4L2_MAP_QUANTIZATION_DEFAULT(is_rgb, f->fmt.pix_mp.colorspace,
+ f->fmt.pix_mp.ycbcr_enc);
+
+ /* Set plane size and bytes/line for each plane. */
+ pispbe_set_plane_params(f, fmt);
+
+ for (unsigned int i = 0; i < f->fmt.pix_mp.num_planes; i++) {
+ dev_dbg(pispbe->dev,
+ "%s: [%s] calc plane %d, %ux%u, depth %u, bpl %u size %u\n",
+ __func__, NODE_NAME(node), i, f->fmt.pix_mp.width,
+ f->fmt.pix_mp.height, fmt->bit_depth,
+ f->fmt.pix_mp.plane_fmt[i].bytesperline,
+ f->fmt.pix_mp.plane_fmt[i].sizeimage);
+ }
+}
+
+static int pispbe_node_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (!NODE_IS_CAPTURE(node) || NODE_IS_META(node)) {
+ dev_dbg(pispbe->dev,
+ "Cannot set capture fmt for output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
+
+ pispbe_try_format(f, node);
+
+ return 0;
+}
+
+static int pispbe_node_try_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (!NODE_IS_OUTPUT(node) || NODE_IS_META(node)) {
+ dev_dbg(pispbe->dev,
+ "Cannot set capture fmt for output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
+
+ pispbe_try_format(f, node);
+
+ return 0;
+}
+
+static int pispbe_node_try_fmt_meta_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (!NODE_IS_META(node) || NODE_IS_CAPTURE(node)) {
+ dev_dbg(pispbe->dev,
+ "Cannot set capture fmt for meta output node %s\n",
+ NODE_NAME(node));
+ return -EINVAL;
+ }
+
+ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_BE_CFG;
+ f->fmt.meta.buffersize = sizeof(struct pisp_be_tiles_config);
+
+ return 0;
+}
+
+static int pispbe_node_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+ int ret;
+
+ ret = pispbe_node_try_fmt_vid_cap(file, priv, f);
+ if (ret < 0)
+ return ret;
+
+ if (vb2_is_busy(&node->queue))
+ return -EBUSY;
+
+ node->format = *f;
+ node->pisp_format = pispbe_find_fmt(f->fmt.pix_mp.pixelformat);
+
+ dev_dbg(pispbe->dev, "Set capture format for node %s to %p4cc\n",
+ NODE_NAME(node), &f->fmt.pix_mp.pixelformat);
+
+ return 0;
+}
+
+static int pispbe_node_s_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+ int ret;
+
+ ret = pispbe_node_try_fmt_vid_out(file, priv, f);
+ if (ret < 0)
+ return ret;
+
+ if (vb2_is_busy(&node->queue))
+ return -EBUSY;
+
+ node->format = *f;
+ node->pisp_format = pispbe_find_fmt(f->fmt.pix_mp.pixelformat);
+
+ dev_dbg(pispbe->dev, "Set output format for node %s to %p4cc\n",
+ NODE_NAME(node), &f->fmt.pix_mp.pixelformat);
+
+ return 0;
+}
+
+static int pispbe_node_s_fmt_meta_out(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+ int ret;
+
+ ret = pispbe_node_try_fmt_meta_out(file, priv, f);
+ if (ret < 0)
+ return ret;
+
+ if (vb2_is_busy(&node->queue))
+ return -EBUSY;
+
+ node->format = *f;
+ node->pisp_format = &meta_out_supported_formats[0];
+
+ dev_dbg(pispbe->dev, "Set output format for meta node %s to %p4cc\n",
+ NODE_NAME(node), &f->fmt.meta.dataformat);
+
+ return 0;
+}
+
+static int pispbe_node_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct pispbe_node *node = video_drvdata(file);
+
+ if (f->type != node->queue.type)
+ return -EINVAL;
+
+ if (NODE_IS_META(node)) {
+ if (f->index)
+ return -EINVAL;
+
+ f->pixelformat = V4L2_META_FMT_RPI_BE_CFG;
+ f->flags = 0;
+ return 0;
+ }
+
+ if (f->index >= ARRAY_SIZE(supported_formats))
+ return -EINVAL;
+
+ f->pixelformat = supported_formats[f->index].fourcc;
+ f->flags = 0;
+
+ return 0;
+}
+
+static int pispbe_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct pispbe_node *node = video_drvdata(file);
+ struct pispbe_dev *pispbe = node->pispbe;
+
+ if (NODE_IS_META(node) || fsize->index)
+ return -EINVAL;
+
+ if (!pispbe_find_fmt(fsize->pixel_format)) {
+ dev_dbg(pispbe->dev, "Invalid pixel code: %x\n",
+ fsize->pixel_format);
+ return -EINVAL;
+ }
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = 32;
+ fsize->stepwise.max_width = 65535;
+ fsize->stepwise.step_width = 2;
+
+ fsize->stepwise.min_height = 32;
+ fsize->stepwise.max_height = 65535;
+ fsize->stepwise.step_height = 2;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops pispbe_node_ioctl_ops = {
+ .vidioc_querycap = pispbe_node_querycap,
+ .vidioc_g_fmt_vid_cap_mplane = pispbe_node_g_fmt_vid_cap,
+ .vidioc_g_fmt_vid_out_mplane = pispbe_node_g_fmt_vid_out,
+ .vidioc_g_fmt_meta_out = pispbe_node_g_fmt_meta_out,
+ .vidioc_try_fmt_vid_cap_mplane = pispbe_node_try_fmt_vid_cap,
+ .vidioc_try_fmt_vid_out_mplane = pispbe_node_try_fmt_vid_out,
+ .vidioc_try_fmt_meta_out = pispbe_node_try_fmt_meta_out,
+ .vidioc_s_fmt_vid_cap_mplane = pispbe_node_s_fmt_vid_cap,
+ .vidioc_s_fmt_vid_out_mplane = pispbe_node_s_fmt_vid_out,
+ .vidioc_s_fmt_meta_out = pispbe_node_s_fmt_meta_out,
+ .vidioc_enum_fmt_vid_cap = pispbe_node_enum_fmt,
+ .vidioc_enum_fmt_vid_out = pispbe_node_enum_fmt,
+ .vidioc_enum_fmt_meta_out = pispbe_node_enum_fmt,
+ .vidioc_enum_framesizes = pispbe_enum_framesizes,
+ .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_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+};
+
+static const struct video_device pispbe_videodev = {
+ .name = PISPBE_NAME,
+ .vfl_dir = VFL_DIR_M2M, /* gets overwritten */
+ .fops = &pispbe_fops,
+ .ioctl_ops = &pispbe_node_ioctl_ops,
+ .minor = -1,
+ .release = video_device_release_empty,
+};
+
+static void pispbe_node_def_fmt(struct pispbe_node *node)
+{
+ if (NODE_IS_META(node) && NODE_IS_OUTPUT(node)) {
+ /* Config node */
+ struct v4l2_format *f = &node->format;
+
+ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_BE_CFG;
+ f->fmt.meta.buffersize = sizeof(struct pisp_be_tiles_config);
+ f->type = node->buf_type;
+ } else {
+ struct v4l2_format f = {
+ .fmt.pix_mp.pixelformat = V4L2_PIX_FMT_YUV420,
+ .fmt.pix_mp.width = 1920,
+ .fmt.pix_mp.height = 1080,
+ .type = node->buf_type,
+ };
+ pispbe_try_format(&f, node);
+ node->format = f;
+ }
+
+ node->pisp_format = pispbe_find_fmt(node->format.fmt.pix_mp.pixelformat);
+}
+
+/*
+ * Initialise a struct pispbe_node and register it as /dev/video<N>
+ * to represent one of the PiSP Back End's input or output streams.
+ */
+static int pispbe_init_node(struct pispbe_dev *pispbe, unsigned int id)
+{
+ bool output = NODE_DESC_IS_OUTPUT(&node_desc[id]);
+ struct pispbe_node *node = &pispbe->node[id];
+ struct media_entity *entity = &node->vfd.entity;
+ struct video_device *vdev = &node->vfd;
+ struct vb2_queue *q = &node->queue;
+ int ret;
+
+ node->id = id;
+ node->pispbe = pispbe;
+ node->buf_type = node_desc[id].buf_type;
+
+ mutex_init(&node->node_lock);
+ mutex_init(&node->queue_lock);
+ INIT_LIST_HEAD(&node->ready_queue);
+ spin_lock_init(&node->ready_lock);
+
+ node->format.type = node->buf_type;
+ pispbe_node_def_fmt(node);
+
+ q->type = node->buf_type;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->drv_priv = node;
+ q->ops = &pispbe_node_queue_ops;
+ q->buf_struct_size = sizeof(struct pispbe_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->dev = pispbe->dev;
+ /* get V4L2 to handle node->queue locking */
+ q->lock = &node->queue_lock;
+
+ ret = vb2_queue_init(q);
+ if (ret < 0) {
+ dev_err(pispbe->dev, "vb2_queue_init failed\n");
+ goto err_mutex_destroy;
+ }
+
+ *vdev = pispbe_videodev; /* default initialization */
+ strscpy(vdev->name, node_desc[id].ent_name, sizeof(vdev->name));
+ vdev->v4l2_dev = &pispbe->v4l2_dev;
+ vdev->vfl_dir = output ? VFL_DIR_TX : VFL_DIR_RX;
+ /* get V4L2 to serialise our ioctls */
+ vdev->lock = &node->node_lock;
+ vdev->queue = &node->queue;
+ vdev->device_caps = V4L2_CAP_STREAMING | node_desc[id].caps;
+
+ node->pad.flags = output ? MEDIA_PAD_FL_SOURCE : MEDIA_PAD_FL_SINK;
+ ret = media_entity_pads_init(entity, 1, &node->pad);
+ if (ret) {
+ dev_err(pispbe->dev,
+ "Failed to register media pads for %s device node\n",
+ NODE_NAME(node));
+ goto err_unregister_queue;
+ }
+
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ dev_err(pispbe->dev,
+ "Failed to register video %s device node\n",
+ NODE_NAME(node));
+ goto err_unregister_queue;
+ }
+ video_set_drvdata(vdev, node);
+
+ if (output)
+ ret = media_create_pad_link(entity, 0, &pispbe->sd.entity,
+ id, MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ else
+ ret = media_create_pad_link(&pispbe->sd.entity, id, entity,
+ 0, MEDIA_LNK_FL_IMMUTABLE |
+ MEDIA_LNK_FL_ENABLED);
+ if (ret)
+ goto err_unregister_video_dev;
+
+ dev_dbg(pispbe->dev, "%s device node registered as /dev/video%d\n",
+ NODE_NAME(node), node->vfd.num);
+
+ return 0;
+
+err_unregister_video_dev:
+ video_unregister_device(&node->vfd);
+err_unregister_queue:
+ vb2_queue_release(&node->queue);
+err_mutex_destroy:
+ mutex_destroy(&node->node_lock);
+ mutex_destroy(&node->queue_lock);
+ return ret;
+}
+
+static const struct v4l2_subdev_pad_ops pispbe_pad_ops = {
+ .link_validate = v4l2_subdev_link_validate_default,
+};
+
+static const struct v4l2_subdev_ops pispbe_sd_ops = {
+ .pad = &pispbe_pad_ops,
+};
+
+static int pispbe_init_subdev(struct pispbe_dev *pispbe)
+{
+ struct v4l2_subdev *sd = &pispbe->sd;
+ int ret;
+
+ v4l2_subdev_init(sd, &pispbe_sd_ops);
+ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+ sd->owner = THIS_MODULE;
+ sd->dev = pispbe->dev;
+ strscpy(sd->name, PISPBE_NAME, sizeof(sd->name));
+
+ for (unsigned int i = 0; i < PISPBE_NUM_NODES; i++)
+ pispbe->pad[i].flags =
+ NODE_DESC_IS_OUTPUT(&node_desc[i]) ?
+ MEDIA_PAD_FL_SINK : MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&sd->entity, PISPBE_NUM_NODES,
+ pispbe->pad);
+ if (ret)
+ goto error;
+
+ ret = v4l2_device_register_subdev(&pispbe->v4l2_dev, sd);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ media_entity_cleanup(&sd->entity);
+ return ret;
+}
+
+static int pispbe_init_devices(struct pispbe_dev *pispbe)
+{
+ struct v4l2_device *v4l2_dev;
+ struct media_device *mdev;
+ unsigned int num_regist;
+ int ret;
+
+ /* Register v4l2_device and media_device */
+ mdev = &pispbe->mdev;
+ mdev->hw_revision = pispbe->hw_version;
+ mdev->dev = pispbe->dev;
+ strscpy(mdev->model, PISPBE_NAME, sizeof(mdev->model));
+ media_device_init(mdev);
+
+ v4l2_dev = &pispbe->v4l2_dev;
+ v4l2_dev->mdev = &pispbe->mdev;
+ strscpy(v4l2_dev->name, PISPBE_NAME, sizeof(v4l2_dev->name));
+
+ ret = v4l2_device_register(pispbe->dev, v4l2_dev);
+ if (ret)
+ goto err_media_dev_cleanup;
+
+ /* Register the PISPBE subdevice. */
+ ret = pispbe_init_subdev(pispbe);
+ if (ret)
+ goto err_unregister_v4l2;
+
+ /* Create device video nodes */
+ for (num_regist = 0; num_regist < PISPBE_NUM_NODES; num_regist++) {
+ ret = pispbe_init_node(pispbe, num_regist);
+ if (ret)
+ goto err_unregister_nodes;
+ }
+
+ ret = media_device_register(mdev);
+ if (ret)
+ goto err_unregister_nodes;
+
+ pispbe->config =
+ dma_alloc_coherent(pispbe->dev,
+ sizeof(struct pisp_be_tiles_config) *
+ PISP_BE_NUM_CONFIG_BUFFERS,
+ &pispbe->config_dma_addr, GFP_KERNEL);
+ if (!pispbe->config) {
+ dev_err(pispbe->dev, "Unable to allocate cached config buffers.\n");
+ ret = -ENOMEM;
+ goto err_unregister_mdev;
+ }
+
+ return 0;
+
+err_unregister_mdev:
+ media_device_unregister(mdev);
+err_unregister_nodes:
+ while (num_regist-- > 0) {
+ video_unregister_device(&pispbe->node[num_regist].vfd);
+ vb2_queue_release(&pispbe->node[num_regist].queue);
+ }
+ v4l2_device_unregister_subdev(&pispbe->sd);
+ media_entity_cleanup(&pispbe->sd.entity);
+err_unregister_v4l2:
+ v4l2_device_unregister(v4l2_dev);
+err_media_dev_cleanup:
+ media_device_cleanup(mdev);
+ return ret;
+}
+
+static void pispbe_destroy_devices(struct pispbe_dev *pispbe)
+{
+ if (pispbe->config) {
+ dma_free_coherent(pispbe->dev,
+ sizeof(struct pisp_be_tiles_config) *
+ PISP_BE_NUM_CONFIG_BUFFERS,
+ pispbe->config,
+ pispbe->config_dma_addr);
+ }
+
+ dev_dbg(pispbe->dev, "Unregister from media controller\n");
+
+ v4l2_device_unregister_subdev(&pispbe->sd);
+ media_entity_cleanup(&pispbe->sd.entity);
+ media_device_unregister(&pispbe->mdev);
+
+ for (int i = PISPBE_NUM_NODES - 1; i >= 0; i--) {
+ video_unregister_device(&pispbe->node[i].vfd);
+ vb2_queue_release(&pispbe->node[i].queue);
+ mutex_destroy(&pispbe->node[i].node_lock);
+ mutex_destroy(&pispbe->node[i].queue_lock);
+ }
+
+ media_device_cleanup(&pispbe->mdev);
+ v4l2_device_unregister(&pispbe->v4l2_dev);
+}
+
+static int pispbe_runtime_suspend(struct device *dev)
+{
+ struct pispbe_dev *pispbe = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(pispbe->clk);
+
+ return 0;
+}
+
+static int pispbe_runtime_resume(struct device *dev)
+{
+ struct pispbe_dev *pispbe = dev_get_drvdata(dev);
+ int ret;
+
+ ret = clk_prepare_enable(pispbe->clk);
+ if (ret) {
+ dev_err(dev, "Unable to enable clock\n");
+ return ret;
+ }
+
+ dev_dbg(dev, "%s: Enabled clock, rate=%lu\n",
+ __func__, clk_get_rate(pispbe->clk));
+
+ return 0;
+}
+
+static int pispbe_hw_init(struct pispbe_dev *pispbe)
+{
+ u32 u;
+
+ /* Check the HW is present and has a known version */
+ u = pispbe_rd(pispbe, PISP_BE_VERSION_REG);
+ dev_dbg(pispbe->dev, "pispbe_probe: HW version: 0x%08x", u);
+ pispbe->hw_version = u;
+ if ((u & ~PISP_BE_VERSION_MINOR_BITS) != PISP_BE_VERSION_2712)
+ return -ENODEV;
+
+ /* Clear leftover interrupts */
+ pispbe_wr(pispbe, PISP_BE_INTERRUPT_STATUS_REG, 0xFFFFFFFFu);
+ u = pispbe_rd(pispbe, PISP_BE_BATCH_STATUS_REG);
+ dev_dbg(pispbe->dev, "pispbe_probe: BatchStatus: 0x%08x", u);
+
+ pispbe->done = (uint8_t)u;
+ pispbe->started = (uint8_t)(u >> 8);
+ u = pispbe_rd(pispbe, PISP_BE_STATUS_REG);
+ dev_dbg(pispbe->dev, "pispbe_probe: Status: 0x%08x", u);
+
+ if (u != 0 || pispbe->done != pispbe->started) {
+ dev_err(pispbe->dev, "pispbe_probe: HW is stuck or busy\n");
+ return -EBUSY;
+ }
+
+ /*
+ * AXI QOS=0, CACHE=4'b0010, PROT=3'b011
+ * Also set "chicken bits" 22:20 which enable sub-64-byte bursts
+ * and AXI AWID/BID variability (on versions which support this).
+ */
+ pispbe_wr(pispbe, PISP_BE_AXI_REG, 0x32703200u);
+
+ /* Enable both interrupt flags */
+ pispbe_wr(pispbe, PISP_BE_INTERRUPT_EN_REG, 0x00000003u);
+
+ return 0;
+}
+
+/* Probe the ISP-BE hardware block, as a single platform device. */
+static int pispbe_probe(struct platform_device *pdev)
+{
+ struct pispbe_dev *pispbe;
+ int ret;
+
+ pispbe = devm_kzalloc(&pdev->dev, sizeof(*pispbe), GFP_KERNEL);
+ if (!pispbe)
+ return -ENOMEM;
+
+ dev_set_drvdata(&pdev->dev, pispbe);
+ pispbe->dev = &pdev->dev;
+ platform_set_drvdata(pdev, pispbe);
+
+ pispbe->be_reg_base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(pispbe->be_reg_base)) {
+ dev_err(&pdev->dev, "Failed to get ISP-BE registers address\n");
+ return PTR_ERR(pispbe->be_reg_base);
+ }
+
+ pispbe->irq = platform_get_irq(pdev, 0);
+ if (pispbe->irq <= 0)
+ return -EINVAL;
+
+ ret = devm_request_irq(&pdev->dev, pispbe->irq, pispbe_isr, 0,
+ PISPBE_NAME, pispbe);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to request interrupt\n");
+ return ret;
+ }
+
+ ret = dma_set_mask_and_coherent(pispbe->dev, DMA_BIT_MASK(36));
+ if (ret)
+ return ret;
+
+ pispbe->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pispbe->clk))
+ return dev_err_probe(&pdev->dev, PTR_ERR(pispbe->clk),
+ "Failed to get clock");
+
+ /* Hardware initialisation */
+ pm_runtime_set_autosuspend_delay(pispbe->dev, 200);
+ pm_runtime_use_autosuspend(pispbe->dev);
+ pm_runtime_enable(pispbe->dev);
+
+ ret = pispbe_runtime_resume(pispbe->dev);
+ if (ret)
+ goto pm_runtime_disable_err;
+
+ pispbe->hw_busy = false;
+ spin_lock_init(&pispbe->hw_lock);
+ ret = pispbe_hw_init(pispbe);
+ if (ret)
+ goto pm_runtime_suspend_err;
+
+ ret = pispbe_init_devices(pispbe);
+ if (ret)
+ goto disable_devs_err;
+
+ pm_runtime_mark_last_busy(pispbe->dev);
+ pm_runtime_put_autosuspend(pispbe->dev);
+
+ return 0;
+
+disable_devs_err:
+ pispbe_destroy_devices(pispbe);
+pm_runtime_suspend_err:
+ pispbe_runtime_suspend(pispbe->dev);
+pm_runtime_disable_err:
+ pm_runtime_dont_use_autosuspend(pispbe->dev);
+ pm_runtime_disable(pispbe->dev);
+
+ return ret;
+}
+
+static void pispbe_remove(struct platform_device *pdev)
+{
+ struct pispbe_dev *pispbe = platform_get_drvdata(pdev);
+
+ pispbe_destroy_devices(pispbe);
+
+ pispbe_runtime_suspend(pispbe->dev);
+ pm_runtime_dont_use_autosuspend(pispbe->dev);
+ pm_runtime_disable(pispbe->dev);
+}
+
+static const struct dev_pm_ops pispbe_pm_ops = {
+ SET_RUNTIME_PM_OPS(pispbe_runtime_suspend, pispbe_runtime_resume, NULL)
+};
+
+static const struct of_device_id pispbe_of_match[] = {
+ {
+ .compatible = "raspberrypi,pispbe",
+ },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, pispbe_of_match);
+
+static struct platform_driver pispbe_pdrv = {
+ .probe = pispbe_probe,
+ .remove_new = pispbe_remove,
+ .driver = {
+ .name = PISPBE_NAME,
+ .of_match_table = pispbe_of_match,
+ .pm = &pispbe_pm_ops,
+ },
+};
+
+module_platform_driver(pispbe_pdrv);
+
+MODULE_DESCRIPTION("PiSP Back End driver");
+MODULE_AUTHOR("David Plowman <david.plowman@raspberrypi.com>");
+MODULE_AUTHOR("Nick Hollinghurst <nick.hollinghurst@raspberrypi.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h
new file mode 100644
index 000000000000..b5cb7b8c7531
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be_formats.h
@@ -0,0 +1,519 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PiSP Back End driver image format definitions.
+ *
+ * Copyright (c) 2021-2024 Raspberry Pi Ltd
+ */
+
+#ifndef _PISP_BE_FORMATS_
+#define _PISP_BE_FORMATS_
+
+#include <linux/bits.h>
+#include <linux/videodev2.h>
+
+#define PISPBE_MAX_PLANES 3
+#define P3(x) ((x) * 8)
+
+struct pisp_be_format {
+ unsigned int fourcc;
+ unsigned int align;
+ unsigned int bit_depth;
+ /* 0P3 factor for plane sizing */
+ unsigned int plane_factor[PISPBE_MAX_PLANES];
+ unsigned int num_planes;
+ unsigned int colorspace_mask;
+ enum v4l2_colorspace colorspace_default;
+};
+
+#define V4L2_COLORSPACE_MASK(colorspace) BIT(colorspace)
+
+#define V4L2_COLORSPACE_MASK_JPEG \
+ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_JPEG)
+#define V4L2_COLORSPACE_MASK_SMPTE170M \
+ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SMPTE170M)
+#define V4L2_COLORSPACE_MASK_REC709 \
+ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_REC709)
+#define V4L2_COLORSPACE_MASK_SRGB \
+ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_SRGB)
+#define V4L2_COLORSPACE_MASK_RAW \
+ V4L2_COLORSPACE_MASK(V4L2_COLORSPACE_RAW)
+
+/*
+ * All three colour spaces SRGB, SMPTE170M and REC709 are fundamentally sRGB
+ * underneath (as near as makes no difference to us), just with different YCbCr
+ * encodings. Therefore the ISP can generate sRGB on its main output and any of
+ * the others on its low resolution output. Applications should, when using both
+ * outputs, program the colour spaces on them to be the same, matching whatever
+ * is requested for the low resolution output, even if the main output is
+ * producing an RGB format. In turn this requires us to allow all these colour
+ * spaces for every YUV/RGB output format.
+ */
+#define V4L2_COLORSPACE_MASK_ALL_SRGB (V4L2_COLORSPACE_MASK_JPEG | \
+ V4L2_COLORSPACE_MASK_SRGB | \
+ V4L2_COLORSPACE_MASK_SMPTE170M | \
+ V4L2_COLORSPACE_MASK_REC709)
+
+static const struct pisp_be_format supported_formats[] = {
+ /* Single plane YUV formats */
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ /* 128 alignment to ensure U/V planes are 64 byte aligned. */
+ .align = 128,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.25), P3(0.25) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ /* 128 alignment to ensure U/V planes are 64 byte aligned. */
+ .align = 128,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.25), P3(0.25) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .align = 32,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.5) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21,
+ .align = 32,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.5) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .align = 64,
+ .bit_depth = 16,
+ .plane_factor = { P3(1) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .align = 64,
+ .bit_depth = 16,
+ .plane_factor = { P3(1) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .align = 64,
+ .bit_depth = 16,
+ .plane_factor = { P3(1) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .align = 64,
+ .bit_depth = 16,
+ .plane_factor = { P3(1) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ /* Multiplane YUV formats */
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .align = 64,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.25), P3(0.25) },
+ .num_planes = 3,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .align = 32,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.5) },
+ .num_planes = 2,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .align = 32,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.5) },
+ .num_planes = 2,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU420M,
+ .align = 64,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.25), P3(0.25) },
+ .num_planes = 3,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV422M,
+ .align = 64,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.5), P3(0.5) },
+ .num_planes = 3,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU422M,
+ .align = 64,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(0.5), P3(0.5) },
+ .num_planes = 3,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV444M,
+ .align = 64,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(1), P3(1) },
+ .num_planes = 3,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU444M,
+ .align = 64,
+ .bit_depth = 8,
+ .plane_factor = { P3(1), P3(1), P3(1) },
+ .num_planes = 3,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SMPTE170M,
+ },
+ /* RGB formats */
+ {
+ .fourcc = V4L2_PIX_FMT_RGB24,
+ .align = 32,
+ .bit_depth = 24,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SRGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGR24,
+ .align = 32,
+ .bit_depth = 24,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SRGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_XBGR32,
+ .align = 64,
+ .bit_depth = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SRGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGBX32,
+ .align = 64,
+ .bit_depth = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SRGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB48,
+ .align = 64,
+ .bit_depth = 48,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SRGB,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGR48,
+ .align = 64,
+ .bit_depth = 48,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_ALL_SRGB,
+ .colorspace_default = V4L2_COLORSPACE_SRGB,
+ },
+ /* Bayer formats - 8-bit */
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .bit_depth = 8,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .bit_depth = 8,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .bit_depth = 8,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .bit_depth = 8,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ /* Bayer formats - 16-bit */
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB16,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR16,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG16,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG16,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ /* Bayer formats unpacked to 16bpp */
+ /* 10 bit */
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ /* 12 bit */
+ .fourcc = V4L2_PIX_FMT_SRGGB12,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR12,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG12,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG12,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ /* 14 bit */
+ .fourcc = V4L2_PIX_FMT_SRGGB14,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR14,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG14,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG14,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ /* Bayer formats - 16-bit PiSP Compressed */
+ {
+ .fourcc = V4L2_PIX_FMT_PISP_COMP1_BGGR,
+ .bit_depth = 8,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_PISP_COMP1_RGGB,
+ .bit_depth = 8,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GRBG,
+ .bit_depth = 8,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GBRG,
+ .bit_depth = 8,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ /* Greyscale Formats */
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .bit_depth = 8,
+ .align = 32,
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y16,
+ .bit_depth = 16,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_PISP_COMP1_MONO,
+ .bit_depth = 8,
+ .align = 32,
+ .plane_factor = { P3(1.0) },
+ .num_planes = 1,
+ .colorspace_mask = V4L2_COLORSPACE_MASK_RAW,
+ .colorspace_default = V4L2_COLORSPACE_RAW,
+ },
+};
+
+static const struct pisp_be_format meta_out_supported_formats[] = {
+ /* Configuration buffer format. */
+ {
+ .fourcc = V4L2_META_FMT_RPI_BE_CFG,
+ },
+};
+
+#endif /* _PISP_BE_FORMATS_ */
diff --git a/drivers/media/platform/renesas/rcar-csi2.c b/drivers/media/platform/renesas/rcar-csi2.c
index 582d5e35db0e..c419ddb4c5a2 100644
--- a/drivers/media/platform/renesas/rcar-csi2.c
+++ b/drivers/media/platform/renesas/rcar-csi2.c
@@ -587,7 +587,8 @@ enum rcar_csi2_pads {
struct rcar_csi2_info {
int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps);
int (*phy_post_init)(struct rcar_csi2 *priv);
- int (*start_receiver)(struct rcar_csi2 *priv);
+ int (*start_receiver)(struct rcar_csi2 *priv,
+ struct v4l2_subdev_state *state);
void (*enter_standby)(struct rcar_csi2 *priv);
const struct rcsi2_mbps_reg *hsfreqrange;
unsigned int csi0clkfreqrange;
@@ -613,8 +614,6 @@ struct rcar_csi2 {
int channel_vc[4];
- struct mutex lock; /* Protects mf and stream_count. */
- struct v4l2_mbus_framefmt mf;
int stream_count;
bool cphy;
@@ -632,6 +631,16 @@ static inline struct rcar_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n)
return container_of(n, struct rcar_csi2, notifier);
}
+static unsigned int rcsi2_num_pads(const struct rcar_csi2 *priv)
+{
+ /* Used together with R-Car ISP: one sink and one source pad. */
+ if (priv->info->use_isp)
+ return 2;
+
+ /* Used together with R-Car VIN: one sink and four source pads. */
+ return 5;
+}
+
static u32 rcsi2_read(struct rcar_csi2 *priv, unsigned int reg)
{
return ioread32(priv->base + reg);
@@ -808,20 +817,25 @@ static int rcsi2_get_active_lanes(struct rcar_csi2 *priv,
return 0;
}
-static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv)
+static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv,
+ struct v4l2_subdev_state *state)
{
const struct rcar_csi2_format *format;
u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
+ const struct v4l2_mbus_framefmt *fmt;
unsigned int lanes;
unsigned int i;
int mbps, ret;
+ /* Use the format on the sink pad to compute the receiver config. */
+ fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK);
+
dev_dbg(priv->dev, "Input size (%ux%u%c)\n",
- priv->mf.width, priv->mf.height,
- priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i');
+ fmt->width, fmt->height,
+ fmt->field == V4L2_FIELD_NONE ? 'p' : 'i');
/* Code is validated in set_fmt. */
- format = rcsi2_code_to_fmt(priv->mf.code);
+ format = rcsi2_code_to_fmt(fmt->code);
if (!format)
return -EINVAL;
@@ -849,11 +863,11 @@ static int rcsi2_start_receiver_gen3(struct rcar_csi2 *priv)
vcdt2 |= vcdt_part << ((i % 2) * 16);
}
- if (priv->mf.field == V4L2_FIELD_ALTERNATE) {
+ if (fmt->field == V4L2_FIELD_ALTERNATE) {
fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2
| FLD_FLD_EN;
- if (priv->mf.height == 240)
+ if (fmt->height == 240)
fld |= FLD_FLD_NUM(0);
else
fld |= FLD_FLD_NUM(1);
@@ -1049,15 +1063,18 @@ static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps)
return 0;
}
-static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv)
+static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv,
+ struct v4l2_subdev_state *state)
{
const struct rcar_csi2_format *format;
+ const struct v4l2_mbus_framefmt *fmt;
unsigned int lanes;
int msps;
int ret;
- /* Calculate parameters */
- format = rcsi2_code_to_fmt(priv->mf.code);
+ /* Use the format on the sink pad to compute the receiver config. */
+ fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK);
+ format = rcsi2_code_to_fmt(fmt->code);
if (!format)
return -EINVAL;
@@ -1114,7 +1131,7 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv)
return 0;
}
-static int rcsi2_start(struct rcar_csi2 *priv)
+static int rcsi2_start(struct rcar_csi2 *priv, struct v4l2_subdev_state *state)
{
int ret;
@@ -1122,7 +1139,7 @@ static int rcsi2_start(struct rcar_csi2 *priv)
if (ret < 0)
return ret;
- ret = priv->info->start_receiver(priv);
+ ret = priv->info->start_receiver(priv, state);
if (ret) {
rcsi2_enter_standby(priv);
return ret;
@@ -1146,17 +1163,16 @@ static void rcsi2_stop(struct rcar_csi2 *priv)
static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable)
{
struct rcar_csi2 *priv = sd_to_csi2(sd);
+ struct v4l2_subdev_state *state;
int ret = 0;
- mutex_lock(&priv->lock);
+ if (!priv->remote)
+ return -ENODEV;
- if (!priv->remote) {
- ret = -ENODEV;
- goto out;
- }
+ state = v4l2_subdev_lock_and_get_active_state(&priv->subdev);
if (enable && priv->stream_count == 0) {
- ret = rcsi2_start(priv);
+ ret = rcsi2_start(priv, state);
if (ret)
goto out;
} else if (!enable && priv->stream_count == 1) {
@@ -1165,49 +1181,29 @@ static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable)
priv->stream_count += enable ? 1 : -1;
out:
- mutex_unlock(&priv->lock);
+ v4l2_subdev_unlock_state(state);
return ret;
}
static int rcsi2_set_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
+ struct v4l2_subdev_state *state,
struct v4l2_subdev_format *format)
{
struct rcar_csi2 *priv = sd_to_csi2(sd);
- struct v4l2_mbus_framefmt *framefmt;
+ unsigned int num_pads = rcsi2_num_pads(priv);
- mutex_lock(&priv->lock);
+ if (format->pad > RCAR_CSI2_SINK)
+ return v4l2_subdev_get_fmt(sd, state, format);
if (!rcsi2_code_to_fmt(format->format.code))
format->format.code = rcar_csi2_formats[0].code;
- if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- priv->mf = format->format;
- } else {
- framefmt = v4l2_subdev_state_get_format(sd_state, 0);
- *framefmt = format->format;
- }
+ *v4l2_subdev_state_get_format(state, format->pad) = format->format;
- mutex_unlock(&priv->lock);
-
- return 0;
-}
-
-static int rcsi2_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct rcar_csi2 *priv = sd_to_csi2(sd);
-
- mutex_lock(&priv->lock);
-
- if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE)
- format->format = priv->mf;
- else
- format->format = *v4l2_subdev_state_get_format(sd_state, 0);
-
- mutex_unlock(&priv->lock);
+ /* Propagate the format to the source pads. */
+ for (unsigned int i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++)
+ *v4l2_subdev_state_get_format(state, i) = format->format;
return 0;
}
@@ -1218,7 +1214,7 @@ static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = {
static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = {
.set_fmt = rcsi2_set_pad_format,
- .get_fmt = rcsi2_get_pad_format,
+ .get_fmt = v4l2_subdev_get_fmt,
};
static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
@@ -1226,6 +1222,33 @@ static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = {
.pad = &rcar_csi2_pad_ops,
};
+static int rcsi2_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct rcar_csi2 *priv = sd_to_csi2(sd);
+ unsigned int num_pads = rcsi2_num_pads(priv);
+
+ static const struct v4l2_mbus_framefmt rcar_csi2_default_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = MEDIA_BUS_FMT_RGB888_1X24,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .field = V4L2_FIELD_NONE,
+ .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+ .quantization = V4L2_QUANTIZATION_DEFAULT,
+ .xfer_func = V4L2_XFER_FUNC_DEFAULT,
+ };
+
+ for (unsigned int i = RCAR_CSI2_SINK; i < num_pads; i++)
+ *v4l2_subdev_state_get_format(state, i) = rcar_csi2_default_fmt;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_internal_ops rcar_csi2_internal_ops = {
+ .init_state = rcsi2_init_state,
+};
+
static irqreturn_t rcsi2_irq(int irq, void *data)
{
struct rcar_csi2 *priv = data;
@@ -1251,14 +1274,17 @@ static irqreturn_t rcsi2_irq(int irq, void *data)
static irqreturn_t rcsi2_irq_thread(int irq, void *data)
{
+ struct v4l2_subdev_state *state;
struct rcar_csi2 *priv = data;
- mutex_lock(&priv->lock);
+ state = v4l2_subdev_lock_and_get_active_state(&priv->subdev);
+
rcsi2_stop(priv);
usleep_range(1000, 2000);
- if (rcsi2_start(priv))
+ if (rcsi2_start(priv, state))
dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n");
- mutex_unlock(&priv->lock);
+
+ v4l2_subdev_unlock_state(state);
return IRQ_HANDLED;
}
@@ -1870,23 +1896,23 @@ static int rcsi2_probe(struct platform_device *pdev)
priv->dev = &pdev->dev;
- mutex_init(&priv->lock);
priv->stream_count = 0;
ret = rcsi2_probe_resources(priv, pdev);
if (ret) {
dev_err(priv->dev, "Failed to get resources\n");
- goto error_mutex;
+ return ret;
}
platform_set_drvdata(pdev, priv);
ret = rcsi2_parse_dt(priv);
if (ret)
- goto error_mutex;
+ return ret;
priv->subdev.owner = THIS_MODULE;
priv->subdev.dev = &pdev->dev;
+ priv->subdev.internal_ops = &rcar_csi2_internal_ops;
v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops);
v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s",
@@ -1896,7 +1922,7 @@ static int rcsi2_probe(struct platform_device *pdev)
priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
priv->subdev.entity.ops = &rcar_csi2_entity_ops;
- num_pads = priv->info->use_isp ? 2 : NR_OF_RCAR_CSI2_PAD;
+ num_pads = rcsi2_num_pads(priv);
priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++)
@@ -1912,19 +1938,25 @@ static int rcsi2_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
+ ret = v4l2_subdev_init_finalize(&priv->subdev);
+ if (ret)
+ goto error_pm_runtime;
+
ret = v4l2_async_register_subdev(&priv->subdev);
if (ret < 0)
- goto error_async;
+ goto error_subdev;
dev_info(priv->dev, "%d lanes found\n", priv->lanes);
return 0;
+error_subdev:
+ v4l2_subdev_cleanup(&priv->subdev);
+error_pm_runtime:
+ pm_runtime_disable(&pdev->dev);
error_async:
v4l2_async_nf_unregister(&priv->notifier);
v4l2_async_nf_cleanup(&priv->notifier);
-error_mutex:
- mutex_destroy(&priv->lock);
return ret;
}
@@ -1936,10 +1968,9 @@ static void rcsi2_remove(struct platform_device *pdev)
v4l2_async_nf_unregister(&priv->notifier);
v4l2_async_nf_cleanup(&priv->notifier);
v4l2_async_unregister_subdev(&priv->subdev);
+ v4l2_subdev_cleanup(&priv->subdev);
pm_runtime_disable(&pdev->dev);
-
- mutex_destroy(&priv->lock);
}
static struct platform_driver rcar_csi2_pdrv = {
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
index e2c40abc6d3d..21d5b2815e86 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
@@ -742,12 +742,22 @@ static int rvin_setup(struct rvin_dev *vin)
*/
switch (vin->mbus_code) {
case MEDIA_BUS_FMT_YUYV8_1X16:
- /* BT.601/BT.1358 16bit YCbCr422 */
- vnmc |= VNMC_INF_YUV16;
+ if (vin->is_csi)
+ /* YCbCr422 8-bit */
+ vnmc |= VNMC_INF_YUV8_BT601;
+ else
+ /* BT.601/BT.1358 16bit YCbCr422 */
+ vnmc |= VNMC_INF_YUV16;
input_is_yuv = true;
break;
case MEDIA_BUS_FMT_UYVY8_1X16:
- vnmc |= VNMC_INF_YUV16 | VNMC_YCAL;
+ if (vin->is_csi)
+ /* YCbCr422 8-bit */
+ vnmc |= VNMC_INF_YUV8_BT601;
+ else
+ /* BT.601/BT.1358 16bit YCbCr422 */
+ vnmc |= VNMC_INF_YUV16;
+ vnmc |= VNMC_YCAL;
input_is_yuv = true;
break;
case MEDIA_BUS_FMT_UYVY8_2X8:
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_brx.c b/drivers/media/platform/renesas/vsp1/vsp1_brx.c
index a8535c6e2c46..5dee0490c593 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_brx.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_brx.c
@@ -96,13 +96,6 @@ static int brx_enum_frame_size(struct v4l2_subdev *subdev,
return 0;
}
-static struct v4l2_rect *brx_get_compose(struct vsp1_brx *brx,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad)
-{
- return v4l2_subdev_state_get_compose(sd_state, pad);
-}
-
static void brx_try_format(struct vsp1_brx *brx,
struct v4l2_subdev_state *sd_state,
unsigned int pad, struct v4l2_mbus_framefmt *fmt)
@@ -119,8 +112,8 @@ static void brx_try_format(struct vsp1_brx *brx,
default:
/* The BRx can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&brx->entity, sd_state,
- BRX_PAD_SINK(0));
+ format = v4l2_subdev_state_get_format(sd_state,
+ BRX_PAD_SINK(0));
fmt->code = format->code;
break;
}
@@ -150,14 +143,14 @@ static int brx_set_format(struct v4l2_subdev *subdev,
brx_try_format(brx, state, fmt->pad, &fmt->format);
- format = vsp1_entity_get_pad_format(&brx->entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
*format = fmt->format;
/* Reset the compose rectangle. */
if (fmt->pad != brx->entity.source_pad) {
struct v4l2_rect *compose;
- compose = brx_get_compose(brx, state, fmt->pad);
+ compose = v4l2_subdev_state_get_compose(state, fmt->pad);
compose->left = 0;
compose->top = 0;
compose->width = format->width;
@@ -169,8 +162,7 @@ static int brx_set_format(struct v4l2_subdev *subdev,
unsigned int i;
for (i = 0; i <= brx->entity.source_pad; ++i) {
- format = vsp1_entity_get_pad_format(&brx->entity,
- state, i);
+ format = v4l2_subdev_state_get_format(state, i);
format->code = fmt->format.code;
}
}
@@ -205,7 +197,7 @@ static int brx_get_selection(struct v4l2_subdev *subdev,
return -EINVAL;
mutex_lock(&brx->entity.lock);
- sel->r = *brx_get_compose(brx, state, sel->pad);
+ sel->r = *v4l2_subdev_state_get_compose(state, sel->pad);
mutex_unlock(&brx->entity.lock);
return 0;
@@ -242,8 +234,7 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
* The compose rectangle top left corner must be inside the output
* frame.
*/
- format = vsp1_entity_get_pad_format(&brx->entity, state,
- brx->entity.source_pad);
+ format = v4l2_subdev_state_get_format(state, brx->entity.source_pad);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
@@ -251,11 +242,11 @@ static int brx_set_selection(struct v4l2_subdev *subdev,
* Scaling isn't supported, the compose rectangle size must be identical
* to the sink format size.
*/
- format = vsp1_entity_get_pad_format(&brx->entity, state, sel->pad);
+ format = v4l2_subdev_state_get_format(state, sel->pad);
sel->r.width = format->width;
sel->r.height = format->height;
- compose = brx_get_compose(brx, state, sel->pad);
+ compose = v4l2_subdev_state_get_compose(state, sel->pad);
*compose = sel->r;
done:
@@ -281,6 +272,7 @@ static const struct v4l2_subdev_ops brx_ops = {
*/
static void brx_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -290,8 +282,7 @@ static void brx_configure_stream(struct vsp1_entity *entity,
unsigned int flags;
unsigned int i;
- format = vsp1_entity_get_pad_format(&brx->entity, brx->entity.state,
- brx->entity.source_pad);
+ format = v4l2_subdev_state_get_format(state, brx->entity.source_pad);
/*
* The hardware is extremely flexible but we have no userspace API to
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_clu.c b/drivers/media/platform/renesas/vsp1/vsp1_clu.c
index 625776a9bda4..98645bd2a983 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_clu.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_clu.c
@@ -170,6 +170,7 @@ static const struct v4l2_subdev_ops clu_ops = {
*/
static void clu_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -181,8 +182,7 @@ static void clu_configure_stream(struct vsp1_entity *entity,
* The yuv_mode can't be changed during streaming. Cache it internally
* for future runtime configuration calls.
*/
- format = vsp1_entity_get_pad_format(&clu->entity, clu->entity.state,
- CLU_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, CLU_PAD_SINK);
clu->yuv_mode = format->code == MEDIA_BUS_FMT_AYUV8_1X32;
}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drm.c b/drivers/media/platform/renesas/vsp1/vsp1_drm.c
index 9b087bd8df7d..b5d1f238f7be 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drm.c
@@ -317,7 +317,10 @@ static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1,
list_add_tail(&released_brx->list_pipe,
&pipe->entities);
- /* Add the BRx to the pipeline. */
+ /*
+ * Add the BRx to the pipeline, inserting it just before the
+ * WPF.
+ */
dev_dbg(vsp1->dev, "%s: pipe %u: acquired %s\n",
__func__, pipe->lif->index, BRX_NAME(brx));
@@ -326,7 +329,8 @@ static int vsp1_du_pipeline_setup_brx(struct vsp1_device *vsp1,
pipe->brx->sink = &pipe->output->entity;
pipe->brx->sink_pad = 0;
- list_add_tail(&pipe->brx->list_pipe, &pipe->entities);
+ list_add_tail(&pipe->brx->list_pipe,
+ &pipe->output->entity.list_pipe);
}
/*
@@ -420,7 +424,7 @@ static int vsp1_du_pipeline_setup_inputs(struct vsp1_device *vsp1,
if (!rpf->entity.pipe) {
rpf->entity.pipe = pipe;
- list_add_tail(&rpf->entity.list_pipe, &pipe->entities);
+ list_add(&rpf->entity.list_pipe, &pipe->entities);
}
brx->inputs[i].rpf = rpf;
@@ -546,6 +550,9 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
struct vsp1_dl_body *dlb;
unsigned int dl_flags = 0;
+ vsp1_pipeline_calculate_partition(pipe, &pipe->part_table[0],
+ drm_pipe->width, 0);
+
if (drm_pipe->force_brx_release)
dl_flags |= VSP1_DL_FRAME_END_INTERNAL;
if (pipe->output->writeback)
@@ -567,9 +574,11 @@ static void vsp1_du_pipeline_configure(struct vsp1_pipeline *pipe)
}
vsp1_entity_route_setup(entity, pipe, dlb);
- vsp1_entity_configure_stream(entity, pipe, dl, dlb);
+ vsp1_entity_configure_stream(entity, entity->state, pipe,
+ dl, dlb);
vsp1_entity_configure_frame(entity, pipe, dl, dlb);
- vsp1_entity_configure_partition(entity, pipe, dl, dlb);
+ vsp1_entity_configure_partition(entity, pipe,
+ &pipe->part_table[0], dl, dlb);
}
vsp1_dl_list_commit(dl, dl_flags);
@@ -733,6 +742,8 @@ int vsp1_du_setup_lif(struct device *dev, unsigned int pipe_index,
if (ret < 0)
goto unlock;
+ vsp1_pipeline_dump(pipe, "LIF setup");
+
/* Enable the VSP1. */
ret = vsp1_device_get(vsp1);
if (ret < 0)
@@ -906,6 +917,9 @@ void vsp1_du_atomic_flush(struct device *dev, unsigned int pipe_index,
}
vsp1_du_pipeline_setup_inputs(vsp1, pipe);
+
+ vsp1_pipeline_dump(pipe, "atomic update");
+
vsp1_du_pipeline_configure(pipe);
done:
@@ -959,6 +973,9 @@ int vsp1_drm_init(struct vsp1_device *vsp1)
vsp1_pipeline_init(pipe);
+ pipe->partitions = 1;
+ pipe->part_table = &drm_pipe->partition;
+
pipe->frame_end = vsp1_du_pipeline_frame_end;
/*
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drm.h b/drivers/media/platform/renesas/vsp1/vsp1_drm.h
index ab8b7e3161a2..3fd95b53f27e 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drm.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drm.h
@@ -20,6 +20,7 @@
/**
* struct vsp1_drm_pipeline - State for the API exposed to the DRM driver
* @pipe: the VSP1 pipeline used for display
+ * @partition: the pre-calculated partition used by the pipeline
* @width: output display width
* @height: output display height
* @force_brx_release: when set, release the BRx during the next reconfiguration
@@ -31,6 +32,7 @@
*/
struct vsp1_drm_pipeline {
struct vsp1_pipeline pipe;
+ struct vsp1_partition partition;
unsigned int width;
unsigned int height;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.c b/drivers/media/platform/renesas/vsp1/vsp1_entity.c
index 0a5a7f9cc870..8b8945bd8f10 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.c
@@ -70,12 +70,13 @@ void vsp1_entity_route_setup(struct vsp1_entity *entity,
}
void vsp1_entity_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
if (entity->ops->configure_stream)
- entity->ops->configure_stream(entity, pipe, dl, dlb);
+ entity->ops->configure_stream(entity, state, pipe, dl, dlb);
}
void vsp1_entity_configure_frame(struct vsp1_entity *entity,
@@ -89,11 +90,13 @@ void vsp1_entity_configure_frame(struct vsp1_entity *entity,
void vsp1_entity_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
if (entity->ops->configure_partition)
- entity->ops->configure_partition(entity, pipe, dl, dlb);
+ entity->ops->configure_partition(entity, pipe, partition,
+ dl, dlb);
}
/* -----------------------------------------------------------------------------
@@ -127,49 +130,6 @@ vsp1_entity_get_state(struct vsp1_entity *entity,
}
}
-/**
- * vsp1_entity_get_pad_format - Get a pad format from storage for an entity
- * @entity: the entity
- * @sd_state: the state storage
- * @pad: the pad number
- *
- * Return the format stored in the given configuration for an entity's pad. The
- * configuration can be an ACTIVE or TRY configuration.
- */
-struct v4l2_mbus_framefmt *
-vsp1_entity_get_pad_format(struct vsp1_entity *entity,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad)
-{
- return v4l2_subdev_state_get_format(sd_state, pad);
-}
-
-/**
- * vsp1_entity_get_pad_selection - Get a pad selection from storage for entity
- * @entity: the entity
- * @sd_state: the state storage
- * @pad: the pad number
- * @target: the selection target
- *
- * Return the selection rectangle stored in the given configuration for an
- * entity's pad. The configuration can be an ACTIVE or TRY configuration. The
- * selection target can be COMPOSE or CROP.
- */
-struct v4l2_rect *
-vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, unsigned int target)
-{
- switch (target) {
- case V4L2_SEL_TGT_COMPOSE:
- return v4l2_subdev_state_get_compose(sd_state, pad);
- case V4L2_SEL_TGT_CROP:
- return v4l2_subdev_state_get_crop(sd_state, pad);
- default:
- return NULL;
- }
-}
-
/*
* vsp1_subdev_get_pad_format - Subdev pad get_fmt handler
* @subdev: V4L2 subdevice
@@ -191,7 +151,7 @@ int vsp1_subdev_get_pad_format(struct v4l2_subdev *subdev,
return -EINVAL;
mutex_lock(&entity->lock);
- fmt->format = *vsp1_entity_get_pad_format(entity, state, fmt->pad);
+ fmt->format = *v4l2_subdev_state_get_format(state, fmt->pad);
mutex_unlock(&entity->lock);
return 0;
@@ -238,7 +198,7 @@ int vsp1_subdev_enum_mbus_code(struct v4l2_subdev *subdev,
return -EINVAL;
mutex_lock(&entity->lock);
- format = vsp1_entity_get_pad_format(entity, state, 0);
+ format = v4l2_subdev_state_get_format(state, 0);
code->code = format->code;
mutex_unlock(&entity->lock);
}
@@ -276,7 +236,7 @@ int vsp1_subdev_enum_frame_size(struct v4l2_subdev *subdev,
if (!state)
return -EINVAL;
- format = vsp1_entity_get_pad_format(entity, state, fse->pad);
+ format = v4l2_subdev_state_get_format(state, fse->pad);
mutex_lock(&entity->lock);
@@ -346,7 +306,7 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
goto done;
}
- format = vsp1_entity_get_pad_format(entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
if (fmt->pad == entity->source_pad) {
/* The output format can't be modified. */
@@ -374,19 +334,17 @@ int vsp1_subdev_set_pad_format(struct v4l2_subdev *subdev,
fmt->format = *format;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(entity, state, entity->source_pad);
+ format = v4l2_subdev_state_get_format(state, entity->source_pad);
*format = fmt->format;
/* Reset the crop and compose rectangles. */
- selection = vsp1_entity_get_pad_selection(entity, state, fmt->pad,
- V4L2_SEL_TGT_CROP);
+ selection = v4l2_subdev_state_get_crop(state, fmt->pad);
selection->left = 0;
selection->top = 0;
selection->width = format->width;
selection->height = format->height;
- selection = vsp1_entity_get_pad_selection(entity, state, fmt->pad,
- V4L2_SEL_TGT_COMPOSE);
+ selection = v4l2_subdev_state_get_compose(state, fmt->pad);
selection->left = 0;
selection->top = 0;
selection->width = format->width;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_entity.h b/drivers/media/platform/renesas/vsp1/vsp1_entity.h
index 735f32dde4b5..1bcc9e27dfdc 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_entity.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_entity.h
@@ -19,7 +19,6 @@ struct vsp1_dl_body;
struct vsp1_dl_list;
struct vsp1_pipeline;
struct vsp1_partition;
-struct vsp1_partition_window;
enum vsp1_entity_type {
VSP1_ENTITY_BRS,
@@ -78,19 +77,30 @@ struct vsp1_route {
* configuration.
*/
struct vsp1_entity_operations {
- void (*destroy)(struct vsp1_entity *);
- void (*configure_stream)(struct vsp1_entity *, struct vsp1_pipeline *,
- struct vsp1_dl_list *, struct vsp1_dl_body *);
- void (*configure_frame)(struct vsp1_entity *, struct vsp1_pipeline *,
- struct vsp1_dl_list *, struct vsp1_dl_body *);
- void (*configure_partition)(struct vsp1_entity *,
- struct vsp1_pipeline *,
- struct vsp1_dl_list *,
- struct vsp1_dl_body *);
- unsigned int (*max_width)(struct vsp1_entity *, struct vsp1_pipeline *);
- void (*partition)(struct vsp1_entity *, struct vsp1_pipeline *,
- struct vsp1_partition *, unsigned int,
- struct vsp1_partition_window *);
+ void (*destroy)(struct vsp1_entity *entity);
+ void (*configure_stream)(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
+ struct vsp1_dl_body *dlb);
+ void (*configure_frame)(struct vsp1_entity *entity,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_dl_list *dl,
+ struct vsp1_dl_body *dlb);
+ void (*configure_partition)(struct vsp1_entity *entity,
+ struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
+ struct vsp1_dl_list *dl,
+ struct vsp1_dl_body *dlb);
+ unsigned int (*max_width)(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
+ struct vsp1_pipeline *pipe);
+ void (*partition)(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
+ struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int index,
+ struct v4l2_rect *window);
};
struct vsp1_entity {
@@ -138,20 +148,13 @@ struct v4l2_subdev_state *
vsp1_entity_get_state(struct vsp1_entity *entity,
struct v4l2_subdev_state *sd_state,
enum v4l2_subdev_format_whence which);
-struct v4l2_mbus_framefmt *
-vsp1_entity_get_pad_format(struct vsp1_entity *entity,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad);
-struct v4l2_rect *
-vsp1_entity_get_pad_selection(struct vsp1_entity *entity,
- struct v4l2_subdev_state *sd_state,
- unsigned int pad, unsigned int target);
void vsp1_entity_route_setup(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
struct vsp1_dl_body *dlb);
void vsp1_entity_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb);
@@ -163,6 +166,7 @@ void vsp1_entity_configure_frame(struct vsp1_entity *entity,
void vsp1_entity_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
index 40c571a987ef..2c8ce7175a4e 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_hgo.c
@@ -130,6 +130,7 @@ static const struct v4l2_ctrl_config hgo_num_bins_control = {
*/
static void hgo_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -140,11 +141,8 @@ static void hgo_configure_stream(struct vsp1_entity *entity,
unsigned int hratio;
unsigned int vratio;
- crop = vsp1_entity_get_pad_selection(entity, entity->state,
- HISTO_PAD_SINK, V4L2_SEL_TGT_CROP);
- compose = vsp1_entity_get_pad_selection(entity, entity->state,
- HISTO_PAD_SINK,
- V4L2_SEL_TGT_COMPOSE);
+ crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK);
+ compose = v4l2_subdev_state_get_compose(state, HISTO_PAD_SINK);
vsp1_hgo_write(hgo, dlb, VI6_HGO_REGRST, VI6_HGO_REGRST_RCLEA);
@@ -194,6 +192,16 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
if (hgo == NULL)
return ERR_PTR(-ENOMEM);
+ /* Initialize the video device and queue for statistics data. */
+ ret = vsp1_histogram_init(vsp1, &hgo->histo, VSP1_ENTITY_HGO, "hgo",
+ &hgo_entity_ops, hgo_mbus_formats,
+ ARRAY_SIZE(hgo_mbus_formats),
+ HGO_DATA_SIZE, V4L2_META_FMT_VSP1_HGO);
+ if (ret < 0) {
+ vsp1_entity_destroy(&hgo->histo.entity);
+ return ERR_PTR(ret);
+ }
+
/* Initialize the control handler. */
v4l2_ctrl_handler_init(&hgo->ctrls.handler,
vsp1->info->gen >= 3 ? 2 : 1);
@@ -209,15 +217,5 @@ struct vsp1_hgo *vsp1_hgo_create(struct vsp1_device *vsp1)
hgo->histo.entity.subdev.ctrl_handler = &hgo->ctrls.handler;
- /* Initialize the video device and queue for statistics data. */
- ret = vsp1_histogram_init(vsp1, &hgo->histo, VSP1_ENTITY_HGO, "hgo",
- &hgo_entity_ops, hgo_mbus_formats,
- ARRAY_SIZE(hgo_mbus_formats),
- HGO_DATA_SIZE, V4L2_META_FMT_VSP1_HGO);
- if (ret < 0) {
- vsp1_entity_destroy(&hgo->histo.entity);
- return ERR_PTR(ret);
- }
-
return hgo;
}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c
index 8281b86874ab..858f330d44fa 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_hgt.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_hgt.c
@@ -126,6 +126,7 @@ static const struct v4l2_ctrl_config hgt_hue_areas = {
*/
static void hgt_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -139,11 +140,8 @@ static void hgt_configure_stream(struct vsp1_entity *entity,
u8 upper;
unsigned int i;
- crop = vsp1_entity_get_pad_selection(entity, entity->state,
- HISTO_PAD_SINK, V4L2_SEL_TGT_CROP);
- compose = vsp1_entity_get_pad_selection(entity, entity->state,
- HISTO_PAD_SINK,
- V4L2_SEL_TGT_COMPOSE);
+ crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK);
+ compose = v4l2_subdev_state_get_compose(state, HISTO_PAD_SINK);
vsp1_hgt_write(hgt, dlb, VI6_HGT_REGRST, VI6_HGT_REGRST_RCLEA);
@@ -193,12 +191,6 @@ struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1)
if (hgt == NULL)
return ERR_PTR(-ENOMEM);
- /* Initialize the control handler. */
- v4l2_ctrl_handler_init(&hgt->ctrls, 1);
- v4l2_ctrl_new_custom(&hgt->ctrls, &hgt_hue_areas, NULL);
-
- hgt->histo.entity.subdev.ctrl_handler = &hgt->ctrls;
-
/* Initialize the video device and queue for statistics data. */
ret = vsp1_histogram_init(vsp1, &hgt->histo, VSP1_ENTITY_HGT, "hgt",
&hgt_entity_ops, hgt_mbus_formats,
@@ -209,6 +201,12 @@ struct vsp1_hgt *vsp1_hgt_create(struct vsp1_device *vsp1)
return ERR_PTR(ret);
}
+ /* Initialize the control handler. */
+ v4l2_ctrl_handler_init(&hgt->ctrls, 1);
+ v4l2_ctrl_new_custom(&hgt->ctrls, &hgt_hue_areas, NULL);
+
+ hgt->histo.entity.subdev.ctrl_handler = &hgt->ctrls;
+
v4l2_ctrl_handler_setup(&hgt->ctrls);
return hgt;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c
index 71155282ca11..9c2d4c91bfad 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c
@@ -36,9 +36,8 @@ struct vsp1_histogram_buffer *
vsp1_histogram_buffer_get(struct vsp1_histogram *histo)
{
struct vsp1_histogram_buffer *buf = NULL;
- unsigned long flags;
- spin_lock_irqsave(&histo->irqlock, flags);
+ spin_lock(&histo->irqlock);
if (list_empty(&histo->irqqueue))
goto done;
@@ -49,7 +48,7 @@ vsp1_histogram_buffer_get(struct vsp1_histogram *histo)
histo->readout = true;
done:
- spin_unlock_irqrestore(&histo->irqlock, flags);
+ spin_unlock(&histo->irqlock);
return buf;
}
@@ -58,7 +57,6 @@ void vsp1_histogram_buffer_complete(struct vsp1_histogram *histo,
size_t size)
{
struct vsp1_pipeline *pipe = histo->entity.pipe;
- unsigned long flags;
/*
* The pipeline pointer is guaranteed to be valid as this function is
@@ -70,10 +68,10 @@ void vsp1_histogram_buffer_complete(struct vsp1_histogram *histo,
vb2_set_plane_payload(&buf->buf.vb2_buf, 0, size);
vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_DONE);
- spin_lock_irqsave(&histo->irqlock, flags);
+ spin_lock(&histo->irqlock);
histo->readout = false;
wake_up(&histo->wait_queue);
- spin_unlock_irqrestore(&histo->irqlock, flags);
+ spin_unlock(&histo->irqlock);
}
/* -----------------------------------------------------------------------------
@@ -124,11 +122,10 @@ static void histo_buffer_queue(struct vb2_buffer *vb)
struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
struct vsp1_histogram *histo = vb2_get_drv_priv(vb->vb2_queue);
struct vsp1_histogram_buffer *buf = to_vsp1_histogram_buffer(vbuf);
- unsigned long flags;
- spin_lock_irqsave(&histo->irqlock, flags);
+ spin_lock_irq(&histo->irqlock);
list_add_tail(&buf->queue, &histo->irqqueue);
- spin_unlock_irqrestore(&histo->irqlock, flags);
+ spin_unlock_irq(&histo->irqlock);
}
static int histo_start_streaming(struct vb2_queue *vq, unsigned int count)
@@ -140,9 +137,8 @@ static void histo_stop_streaming(struct vb2_queue *vq)
{
struct vsp1_histogram *histo = vb2_get_drv_priv(vq);
struct vsp1_histogram_buffer *buffer;
- unsigned long flags;
- spin_lock_irqsave(&histo->irqlock, flags);
+ spin_lock_irq(&histo->irqlock);
/* Remove all buffers from the IRQ queue. */
list_for_each_entry(buffer, &histo->irqqueue, queue)
@@ -152,7 +148,7 @@ static void histo_stop_streaming(struct vb2_queue *vq)
/* Wait for the buffer being read out (if any) to complete. */
wait_event_lock_irq(histo->wait_queue, !histo->readout, histo->irqlock);
- spin_unlock_irqrestore(&histo->irqlock, flags);
+ spin_unlock_irq(&histo->irqlock);
}
static const struct vb2_ops histo_video_queue_qops = {
@@ -222,9 +218,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
- crop = vsp1_entity_get_pad_selection(&histo->entity, state,
- HISTO_PAD_SINK,
- V4L2_SEL_TGT_CROP);
+ crop = v4l2_subdev_state_get_crop(state, HISTO_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = crop->width;
@@ -233,8 +227,7 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
- format = vsp1_entity_get_pad_format(&histo->entity, state,
- HISTO_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, HISTO_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = format->width;
@@ -242,9 +235,11 @@ static int histo_get_selection(struct v4l2_subdev *subdev,
break;
case V4L2_SEL_TGT_COMPOSE:
+ sel->r = *v4l2_subdev_state_get_compose(state, sel->pad);
+ break;
+
case V4L2_SEL_TGT_CROP:
- sel->r = *vsp1_entity_get_pad_selection(&histo->entity, state,
- sel->pad, sel->target);
+ sel->r = *v4l2_subdev_state_get_crop(state, sel->pad);
break;
default:
@@ -261,13 +256,10 @@ static int histo_set_crop(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct vsp1_histogram *histo = subdev_to_histo(subdev);
struct v4l2_mbus_framefmt *format;
- struct v4l2_rect *selection;
/* The crop rectangle must be inside the input frame. */
- format = vsp1_entity_get_pad_format(&histo->entity, sd_state,
- HISTO_PAD_SINK);
+ format = v4l2_subdev_state_get_format(sd_state, HISTO_PAD_SINK);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
sel->r.width = clamp_t(unsigned int, sel->r.width, HISTO_MIN_SIZE,
@@ -276,14 +268,8 @@ static int histo_set_crop(struct v4l2_subdev *subdev,
format->height - sel->r.top);
/* Set the crop rectangle and reset the compose rectangle. */
- selection = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
- sel->pad, V4L2_SEL_TGT_CROP);
- *selection = sel->r;
-
- selection = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
- sel->pad,
- V4L2_SEL_TGT_COMPOSE);
- *selection = sel->r;
+ *v4l2_subdev_state_get_crop(sd_state, sel->pad) = sel->r;
+ *v4l2_subdev_state_get_compose(sd_state, sel->pad) = sel->r;
return 0;
}
@@ -292,7 +278,6 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct vsp1_histogram *histo = subdev_to_histo(subdev);
struct v4l2_rect *compose;
struct v4l2_rect *crop;
unsigned int ratio;
@@ -305,9 +290,7 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
sel->r.left = 0;
sel->r.top = 0;
- crop = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
- sel->pad,
- V4L2_SEL_TGT_CROP);
+ crop = v4l2_subdev_state_get_crop(sd_state, sel->pad);
/*
* Clamp the width and height to acceptable values first and then
@@ -332,9 +315,7 @@ static int histo_set_compose(struct v4l2_subdev *subdev,
ratio = 1 << (crop->height * 2 / sel->r.height / 3);
sel->r.height = crop->height / ratio;
- compose = vsp1_entity_get_pad_selection(&histo->entity, sd_state,
- sel->pad,
- V4L2_SEL_TGT_COMPOSE);
+ compose = v4l2_subdev_state_get_compose(sd_state, sel->pad);
*compose = sel->r;
return 0;
@@ -371,31 +352,22 @@ done:
return ret;
}
-static int histo_get_format(struct v4l2_subdev *subdev,
+static int histo_set_format(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *fmt)
{
+ struct vsp1_histogram *histo = subdev_to_histo(subdev);
+
if (fmt->pad == HISTO_PAD_SOURCE) {
fmt->format.code = MEDIA_BUS_FMT_FIXED;
fmt->format.width = 0;
fmt->format.height = 0;
fmt->format.field = V4L2_FIELD_NONE;
fmt->format.colorspace = V4L2_COLORSPACE_RAW;
+
return 0;
}
- return vsp1_subdev_get_pad_format(subdev, sd_state, fmt);
-}
-
-static int histo_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct vsp1_histogram *histo = subdev_to_histo(subdev);
-
- if (fmt->pad != HISTO_PAD_SINK)
- return histo_get_format(subdev, sd_state, fmt);
-
return vsp1_subdev_set_pad_format(subdev, sd_state, fmt,
histo->formats, histo->num_formats,
HISTO_MIN_SIZE, HISTO_MIN_SIZE,
@@ -405,7 +377,7 @@ static int histo_set_format(struct v4l2_subdev *subdev,
static const struct v4l2_subdev_pad_ops histo_pad_ops = {
.enum_mbus_code = histo_enum_mbus_code,
.enum_frame_size = histo_enum_frame_size,
- .get_fmt = histo_get_format,
+ .get_fmt = vsp1_subdev_get_pad_format,
.set_fmt = histo_set_format,
.get_selection = histo_get_selection,
.set_selection = histo_set_selection,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_hsit.c b/drivers/media/platform/renesas/vsp1/vsp1_hsit.c
index bc1299c29ac9..8ba2a7c7305c 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_hsit.c
@@ -78,7 +78,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
goto done;
}
- format = vsp1_entity_get_pad_format(&hsit->entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
if (fmt->pad == HSIT_PAD_SOURCE) {
/*
@@ -101,8 +101,7 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
fmt->format = *format;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&hsit->entity, state,
- HSIT_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, HSIT_PAD_SOURCE);
*format = fmt->format;
format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
: MEDIA_BUS_FMT_AHSV8888_1X32;
@@ -128,6 +127,7 @@ static const struct v4l2_subdev_ops hsit_ops = {
*/
static void hsit_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lif.c b/drivers/media/platform/renesas/vsp1/vsp1_lif.c
index b1d21a54837b..b3d83d1c5306 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_lif.c
@@ -83,6 +83,7 @@ static const struct v4l2_subdev_ops lif_ops = {
*/
static void lif_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -93,8 +94,7 @@ static void lif_configure_stream(struct vsp1_entity *entity,
unsigned int obth;
unsigned int lbth;
- format = vsp1_entity_get_pad_format(&lif->entity, lif->entity.state,
- LIF_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, LIF_PAD_SOURCE);
switch (entity->vsp1->version & VI6_IP_VERSION_MODEL_MASK) {
case VI6_IP_VERSION_MODEL_VSPD_GEN2:
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_lut.c b/drivers/media/platform/renesas/vsp1/vsp1_lut.c
index 451d24ab0b56..dd264e6532e0 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_lut.c
@@ -146,6 +146,7 @@ static const struct v4l2_subdev_ops lut_ops = {
*/
static void lut_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
index 68d05243c3ee..bb0739f684f3 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.c
@@ -301,6 +301,28 @@ void vsp1_pipeline_init(struct vsp1_pipeline *pipe)
pipe->state = VSP1_PIPELINE_STOPPED;
}
+void __vsp1_pipeline_dump(struct _ddebug *dbg, struct vsp1_pipeline *pipe,
+ const char *msg)
+{
+ struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+ struct vsp1_entity *entity;
+ bool first = true;
+
+ printk(KERN_DEBUG "%s: %s: pipe: ", dev_name(vsp1->dev), msg);
+
+ list_for_each_entry(entity, &pipe->entities, list_pipe) {
+ const char *name;
+
+ name = strchrnul(entity->subdev.name, ' ');
+ name = name ? name + 1 : entity->subdev.name;
+
+ pr_cont("%s%s", first ? "" : ", ", name);
+ first = false;
+ }
+
+ pr_cont("\n");
+}
+
/* Must be called with the pipe irqlock held. */
void vsp1_pipeline_run(struct vsp1_pipeline *pipe)
{
@@ -444,6 +466,10 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
vsp1_uds_set_alpha(pipe->uds, dlb, alpha);
}
+/* -----------------------------------------------------------------------------
+ * VSP1 Partition Algorithm support
+ */
+
/*
* Propagate the partition calculations through the pipeline
*
@@ -452,17 +478,82 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
* source. Each entity must produce the partition required for the previous
* entity in the pipeline.
*/
-void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
- struct vsp1_partition *partition,
- unsigned int index,
- struct vsp1_partition_window *window)
+static void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int index,
+ struct v4l2_rect *window)
{
struct vsp1_entity *entity;
list_for_each_entry_reverse(entity, &pipe->entities, list_pipe) {
if (entity->ops->partition)
- entity->ops->partition(entity, pipe, partition, index,
- window);
+ entity->ops->partition(entity, entity->state, pipe,
+ partition, index, window);
}
}
+/*
+ * vsp1_pipeline_calculate_partition - Calculate pipeline configuration for a
+ * partition
+ *
+ * @pipe: the pipeline
+ * @partition: partition that will hold the calculated values
+ * @div_size: pre-determined maximum partition division size
+ * @index: partition index
+ */
+void vsp1_pipeline_calculate_partition(struct vsp1_pipeline *pipe,
+ struct vsp1_partition *partition,
+ unsigned int div_size,
+ unsigned int index)
+{
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_rect window;
+ unsigned int modulus;
+
+ /*
+ * Partitions are computed on the size before rotation, use the format
+ * at the WPF sink.
+ */
+ format = v4l2_subdev_state_get_format(pipe->output->entity.state,
+ RWPF_PAD_SINK);
+
+ /* Initialise the partition with sane starting conditions. */
+ window.left = index * div_size;
+ window.width = div_size;
+ window.top = 0;
+ window.height = format->height;
+
+ modulus = format->width % div_size;
+
+ /*
+ * We need to prevent the last partition from being smaller than the
+ * *minimum* width of the hardware capabilities.
+ *
+ * If the modulus is less than half of the partition size,
+ * the penultimate partition is reduced to half, which is added
+ * to the final partition: |1234|1234|1234|12|341|
+ * to prevent this: |1234|1234|1234|1234|1|.
+ */
+ if (modulus) {
+ /*
+ * pipe->partitions is 1 based, whilst index is a 0 based index.
+ * Normalise this locally.
+ */
+ unsigned int partitions = pipe->partitions - 1;
+
+ if (modulus < div_size / 2) {
+ if (index == partitions - 1) {
+ /* Halve the penultimate partition. */
+ window.width = div_size / 2;
+ } else if (index == partitions) {
+ /* Increase the final partition. */
+ window.width = (div_size / 2) + modulus;
+ window.left -= div_size / 2;
+ }
+ } else if (index == partitions) {
+ window.width = modulus;
+ }
+ }
+
+ vsp1_pipeline_propagate_partition(pipe, partition, index, &window);
+}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_pipe.h b/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
index 674b5748d929..1ba7bdbad5a8 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_pipe.h
@@ -9,6 +9,7 @@
#ifndef __VSP1_PIPE_H__
#define __VSP1_PIPE_H__
+#include <linux/dynamic_debug.h>
#include <linux/kref.h>
#include <linux/list.h>
#include <linux/spinlock.h>
@@ -54,17 +55,6 @@ enum vsp1_pipeline_state {
};
/*
- * struct vsp1_partition_window - Partition window coordinates
- * @left: horizontal coordinate of the partition start in pixels relative to the
- * left edge of the image
- * @width: partition width in pixels
- */
-struct vsp1_partition_window {
- unsigned int left;
- unsigned int width;
-};
-
-/*
* struct vsp1_partition - A description of a slice for the partition algorithm
* @rpf: The RPF partition window configuration
* @uds_sink: The UDS input partition window configuration
@@ -73,11 +63,11 @@ struct vsp1_partition_window {
* @wpf: The WPF partition window configuration
*/
struct vsp1_partition {
- struct vsp1_partition_window rpf;
- struct vsp1_partition_window uds_sink;
- struct vsp1_partition_window uds_source;
- struct vsp1_partition_window sru;
- struct vsp1_partition_window wpf;
+ struct v4l2_rect rpf[VSP1_MAX_RPF];
+ struct v4l2_rect uds_sink;
+ struct v4l2_rect uds_source;
+ struct v4l2_rect sru;
+ struct v4l2_rect wpf;
};
/*
@@ -106,7 +96,6 @@ struct vsp1_partition {
* @configured: when false the @stream_config shall be written to the hardware
* @interlaced: True when the pipeline is configured in interlaced mode
* @partitions: The number of partitions used to process one frame
- * @partition: The current partition for configuration to process
* @part_table: The pre-calculated partitions used by the pipeline
*/
struct vsp1_pipeline {
@@ -146,7 +135,6 @@ struct vsp1_pipeline {
bool interlaced;
unsigned int partitions;
- struct vsp1_partition *partition;
struct vsp1_partition *part_table;
u32 underrun_count;
@@ -155,6 +143,24 @@ struct vsp1_pipeline {
void vsp1_pipeline_reset(struct vsp1_pipeline *pipe);
void vsp1_pipeline_init(struct vsp1_pipeline *pipe);
+void __vsp1_pipeline_dump(struct _ddebug *, struct vsp1_pipeline *pipe,
+ const char *msg);
+
+#if defined(CONFIG_DYNAMIC_DEBUG) || \
+ (defined(CONFIG_DYNAMIC_DEBUG_CORE) && defined(DYNAMIC_DEBUG_MODULE))
+#define vsp1_pipeline_dump(pipe, msg) \
+ _dynamic_func_call("vsp1_pipeline_dump()", __vsp1_pipeline_dump, pipe, msg)
+#elif defined(DEBUG)
+#define vsp1_pipeline_dump(pipe, msg) \
+ __vsp1_pipeline_dump(NULL, pipe, msg)
+#else
+#define vsp1_pipeline_dump(pipe, msg) \
+({ \
+ if (0) \
+ __vsp1_pipeline_dump(NULL, pipe, msg); \
+})
+#endif
+
void vsp1_pipeline_run(struct vsp1_pipeline *pipe);
bool vsp1_pipeline_stopped(struct vsp1_pipeline *pipe);
int vsp1_pipeline_stop(struct vsp1_pipeline *pipe);
@@ -166,10 +172,10 @@ void vsp1_pipeline_propagate_alpha(struct vsp1_pipeline *pipe,
struct vsp1_dl_body *dlb,
unsigned int alpha);
-void vsp1_pipeline_propagate_partition(struct vsp1_pipeline *pipe,
+void vsp1_pipeline_calculate_partition(struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
- unsigned int index,
- struct vsp1_partition_window *window);
+ unsigned int div_size,
+ unsigned int index);
const struct vsp1_format_info *vsp1_get_format_info(struct vsp1_device *vsp1,
u32 fourcc);
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
index c47579efc65f..5c8b3ba1bd3c 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_rpf.c
@@ -48,6 +48,7 @@ static inline void vsp1_rpf_write(struct vsp1_rwpf *rpf,
*/
static void rpf_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -80,12 +81,8 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
vsp1_rpf_write(rpf, dlb, VI6_RPF_SRCM_PSTRIDE, pstride);
/* Format */
- sink_format = vsp1_entity_get_pad_format(&rpf->entity,
- rpf->entity.state,
- RWPF_PAD_SINK);
- source_format = vsp1_entity_get_pad_format(&rpf->entity,
- rpf->entity.state,
- RWPF_PAD_SOURCE);
+ sink_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
+ source_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
infmt = VI6_RPF_INFMT_CIPM
| (fmtinfo->hwfmt << VI6_RPF_INFMT_RDFMT_SHIFT);
@@ -157,10 +154,8 @@ static void rpf_configure_stream(struct vsp1_entity *entity,
if (pipe->brx) {
const struct v4l2_rect *compose;
- compose = vsp1_entity_get_pad_selection(pipe->brx,
- pipe->brx->state,
- rpf->brx_input,
- V4L2_SEL_TGT_COMPOSE);
+ compose = v4l2_subdev_state_get_compose(pipe->brx->state,
+ rpf->brx_input);
left = compose->left;
top = compose->top;
}
@@ -284,6 +279,7 @@ static void rpf_configure_frame(struct vsp1_entity *entity,
static void rpf_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
@@ -292,7 +288,7 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
struct vsp1_device *vsp1 = rpf->entity.vsp1;
const struct vsp1_format_info *fmtinfo = rpf->fmtinfo;
const struct v4l2_pix_format_mplane *format = &rpf->format;
- struct v4l2_rect crop;
+ struct v4l2_rect crop = partition->rpf[rpf->entity.index];
/*
* Source size and crop offsets.
@@ -302,22 +298,6 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
* offsets are needed, as planes 2 and 3 always have identical
* strides.
*/
- crop = *vsp1_rwpf_get_crop(rpf, rpf->entity.state);
-
- /*
- * Partition Algorithm Control
- *
- * The partition algorithm can split this frame into multiple
- * slices. We must scale our partition window based on the pipe
- * configuration to match the destination partition window.
- * To achieve this, we adjust our crop to provide a 'sub-crop'
- * matching the expected partition window. Only 'left' and
- * 'width' need to be adjusted.
- */
- if (pipe->partitions > 1) {
- crop.width = pipe->partition->rpf.width;
- crop.left += pipe->partition->rpf.left;
- }
if (pipe->interlaced) {
crop.height = round_down(crop.height / 2, fmtinfo->vsub);
@@ -366,12 +346,30 @@ static void rpf_configure_partition(struct vsp1_entity *entity,
}
static void rpf_partition(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int partition_idx,
- struct vsp1_partition_window *window)
+ struct v4l2_rect *window)
{
- partition->rpf = *window;
+ struct vsp1_rwpf *rpf = to_rwpf(&entity->subdev);
+ struct v4l2_rect *rpf_rect = &partition->rpf[rpf->entity.index];
+
+ /*
+ * Partition Algorithm Control
+ *
+ * The partition algorithm can split this frame into multiple slices. We
+ * must adjust our partition window based on the pipe configuration to
+ * match the destination partition window. To achieve this, we adjust
+ * our crop to provide a 'sub-crop' matching the expected partition
+ * window.
+ */
+ *rpf_rect = *v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
+
+ if (pipe->partitions > 1) {
+ rpf_rect->width = window->width;
+ rpf_rect->left += window->left;
+ }
}
static const struct vsp1_entity_operations rpf_entity_ops = {
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c
index 09fb6ffa14e2..9d38203e73d0 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.c
@@ -16,12 +16,6 @@
#define RWPF_MIN_WIDTH 1
#define RWPF_MIN_HEIGHT 1
-struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
- struct v4l2_subdev_state *sd_state)
-{
- return v4l2_subdev_state_get_crop(sd_state, RWPF_PAD_SINK);
-}
-
/* -----------------------------------------------------------------------------
* V4L2 Subdevice Operations
*/
@@ -79,7 +73,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
- format = vsp1_entity_get_pad_format(&rwpf->entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
if (fmt->pad == RWPF_PAD_SOURCE) {
/*
@@ -105,7 +99,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
struct v4l2_rect *crop;
/* Update the sink crop rectangle. */
- crop = vsp1_rwpf_get_crop(rwpf, state);
+ crop = v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
crop->left = 0;
crop->top = 0;
crop->width = fmt->format.width;
@@ -113,8 +107,7 @@ static int vsp1_rwpf_set_format(struct v4l2_subdev *subdev,
}
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, state,
- RWPF_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
*format = fmt->format;
if (rwpf->flip.rotate) {
@@ -153,12 +146,11 @@ static int vsp1_rwpf_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- sel->r = *vsp1_rwpf_get_crop(rwpf, state);
+ sel->r = *v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
break;
case V4L2_SEL_TGT_CROP_BOUNDS:
- format = vsp1_entity_get_pad_format(&rwpf->entity, state,
- RWPF_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = format->width;
@@ -204,8 +196,7 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
}
/* Make sure the crop rectangle is entirely contained in the image. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, state,
- RWPF_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
/*
* Restrict the crop rectangle coordinates to multiples of 2 to avoid
@@ -225,12 +216,11 @@ static int vsp1_rwpf_set_selection(struct v4l2_subdev *subdev,
sel->r.height = min_t(unsigned int, sel->r.height,
format->height - sel->r.top);
- crop = vsp1_rwpf_get_crop(rwpf, state);
+ crop = v4l2_subdev_state_get_crop(state, RWPF_PAD_SINK);
*crop = sel->r;
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&rwpf->entity, state,
- RWPF_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
format->width = crop->width;
format->height = crop->height;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h
index e0d212c70b2f..5ac9f0a6fafc 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h
+++ b/drivers/media/platform/renesas/vsp1/vsp1_rwpf.h
@@ -85,7 +85,4 @@ int vsp1_rwpf_init_ctrls(struct vsp1_rwpf *rwpf, unsigned int ncontrols);
extern const struct v4l2_subdev_ops vsp1_rwpf_subdev_ops;
-struct v4l2_rect *vsp1_rwpf_get_crop(struct vsp1_rwpf *rwpf,
- struct v4l2_subdev_state *sd_state);
-
#endif /* __VSP1_RWPF_H__ */
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_sru.c b/drivers/media/platform/renesas/vsp1/vsp1_sru.c
index 11e008aa9f20..1759ce642e6e 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_sru.c
@@ -131,7 +131,7 @@ static int sru_enum_frame_size(struct v4l2_subdev *subdev,
if (!state)
return -EINVAL;
- format = vsp1_entity_get_pad_format(&sru->entity, state, SRU_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
mutex_lock(&sru->entity.lock);
@@ -184,8 +184,7 @@ static void sru_try_format(struct vsp1_sru *sru,
case SRU_PAD_SOURCE:
/* The SRU can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&sru->entity, sd_state,
- SRU_PAD_SINK);
+ format = v4l2_subdev_state_get_format(sd_state, SRU_PAD_SINK);
fmt->code = format->code;
/*
@@ -234,13 +233,12 @@ static int sru_set_format(struct v4l2_subdev *subdev,
sru_try_format(sru, state, fmt->pad, &fmt->format);
- format = vsp1_entity_get_pad_format(&sru->entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
*format = fmt->format;
if (fmt->pad == SRU_PAD_SINK) {
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&sru->entity, state,
- SRU_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
*format = fmt->format;
sru_try_format(sru, state, SRU_PAD_SOURCE, format);
@@ -267,6 +265,7 @@ static const struct v4l2_subdev_ops sru_ops = {
*/
static void sru_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -277,10 +276,8 @@ static void sru_configure_stream(struct vsp1_entity *entity,
struct v4l2_mbus_framefmt *output;
u32 ctrl0;
- input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SINK);
- output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
@@ -301,16 +298,14 @@ static void sru_configure_stream(struct vsp1_entity *entity,
}
static unsigned int sru_max_width(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe)
{
- struct vsp1_sru *sru = to_sru(&entity->subdev);
struct v4l2_mbus_framefmt *input;
struct v4l2_mbus_framefmt *output;
- input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SINK);
- output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
/*
* The maximum input width of the SRU is 288 input pixels, but 32
@@ -324,24 +319,24 @@ static unsigned int sru_max_width(struct vsp1_entity *entity,
}
static void sru_partition(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int partition_idx,
- struct vsp1_partition_window *window)
+ struct v4l2_rect *window)
{
- struct vsp1_sru *sru = to_sru(&entity->subdev);
struct v4l2_mbus_framefmt *input;
struct v4l2_mbus_framefmt *output;
- input = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SINK);
- output = vsp1_entity_get_pad_format(&sru->entity, sru->entity.state,
- SRU_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, SRU_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, SRU_PAD_SOURCE);
/* Adapt if SRUx2 is enabled. */
if (input->width != output->width) {
window->width /= 2;
window->left /= 2;
+ window->height /= 2;
+ window->top /= 2;
}
partition->sru = *window;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uds.c b/drivers/media/platform/renesas/vsp1/vsp1_uds.c
index d89f1197b86c..c5a38478cf8c 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_uds.c
@@ -136,7 +136,7 @@ static int uds_enum_frame_size(struct v4l2_subdev *subdev,
if (!state)
return -EINVAL;
- format = vsp1_entity_get_pad_format(&uds->entity, state, UDS_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
mutex_lock(&uds->entity.lock);
@@ -183,8 +183,7 @@ static void uds_try_format(struct vsp1_uds *uds,
case UDS_PAD_SOURCE:
/* The UDS scales but can't perform format conversion. */
- format = vsp1_entity_get_pad_format(&uds->entity, sd_state,
- UDS_PAD_SINK);
+ format = v4l2_subdev_state_get_format(sd_state, UDS_PAD_SINK);
fmt->code = format->code;
uds_output_limits(format->width, &minimum, &maximum);
@@ -217,13 +216,12 @@ static int uds_set_format(struct v4l2_subdev *subdev,
uds_try_format(uds, state, fmt->pad, &fmt->format);
- format = vsp1_entity_get_pad_format(&uds->entity, state, fmt->pad);
+ format = v4l2_subdev_state_get_format(state, fmt->pad);
*format = fmt->format;
if (fmt->pad == UDS_PAD_SINK) {
/* Propagate the format to the source pad. */
- format = vsp1_entity_get_pad_format(&uds->entity, state,
- UDS_PAD_SOURCE);
+ format = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
*format = fmt->format;
uds_try_format(uds, state, UDS_PAD_SOURCE, format);
@@ -254,6 +252,7 @@ static const struct v4l2_subdev_ops uds_ops = {
*/
static void uds_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -265,10 +264,8 @@ static void uds_configure_stream(struct vsp1_entity *entity,
unsigned int vscale;
bool multitap;
- input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SINK);
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
hscale = uds_compute_ratio(input->width, output->width);
vscale = uds_compute_ratio(input->height, output->height);
@@ -303,15 +300,11 @@ static void uds_configure_stream(struct vsp1_entity *entity,
static void uds_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_uds *uds = to_uds(&entity->subdev);
- struct vsp1_partition *partition = pipe->partition;
- const struct v4l2_mbus_framefmt *output;
-
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SOURCE);
/* Input size clipping. */
vsp1_uds_write(uds, dlb, VI6_UDS_HSZCLIP, VI6_UDS_HSZCLIP_HCEN |
@@ -323,22 +316,20 @@ static void uds_configure_partition(struct vsp1_entity *entity,
vsp1_uds_write(uds, dlb, VI6_UDS_CLIP_SIZE,
(partition->uds_source.width
<< VI6_UDS_CLIP_SIZE_HSIZE_SHIFT) |
- (output->height
+ (partition->uds_source.height
<< VI6_UDS_CLIP_SIZE_VSIZE_SHIFT));
}
static unsigned int uds_max_width(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe)
{
- struct vsp1_uds *uds = to_uds(&entity->subdev);
const struct v4l2_mbus_framefmt *output;
const struct v4l2_mbus_framefmt *input;
unsigned int hscale;
- input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SINK);
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
hscale = output->width / input->width;
/*
@@ -364,28 +355,26 @@ static unsigned int uds_max_width(struct vsp1_entity *entity,
*/
static void uds_partition(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int partition_idx,
- struct vsp1_partition_window *window)
+ struct v4l2_rect *window)
{
- struct vsp1_uds *uds = to_uds(&entity->subdev);
const struct v4l2_mbus_framefmt *output;
const struct v4l2_mbus_framefmt *input;
- /* Initialise the partition state. */
- partition->uds_sink = *window;
- partition->uds_source = *window;
-
- input = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SINK);
- output = vsp1_entity_get_pad_format(&uds->entity, uds->entity.state,
- UDS_PAD_SOURCE);
+ input = v4l2_subdev_state_get_format(state, UDS_PAD_SINK);
+ output = v4l2_subdev_state_get_format(state, UDS_PAD_SOURCE);
partition->uds_sink.width = window->width * input->width
/ output->width;
partition->uds_sink.left = window->left * input->width
/ output->width;
+ partition->uds_sink.height = input->height;
+ partition->uds_sink.top = 0;
+
+ partition->uds_source = *window;
*window = partition->uds_sink;
}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_uif.c b/drivers/media/platform/renesas/vsp1/vsp1_uif.c
index f66936a28a2a..edaf28b544d2 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_uif.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_uif.c
@@ -104,8 +104,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
- format = vsp1_entity_get_pad_format(&uif->entity, state,
- UIF_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, UIF_PAD_SINK);
sel->r.left = 0;
sel->r.top = 0;
sel->r.width = format->width;
@@ -113,8 +112,7 @@ static int uif_get_selection(struct v4l2_subdev *subdev,
break;
case V4L2_SEL_TGT_CROP:
- sel->r = *vsp1_entity_get_pad_selection(&uif->entity, state,
- sel->pad, sel->target);
+ sel->r = *v4l2_subdev_state_get_crop(state, sel->pad);
break;
default:
@@ -150,7 +148,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
}
/* The crop rectangle must be inside the input frame. */
- format = vsp1_entity_get_pad_format(&uif->entity, state, UIF_PAD_SINK);
+ format = v4l2_subdev_state_get_format(state, UIF_PAD_SINK);
sel->r.left = clamp_t(unsigned int, sel->r.left, 0, format->width - 1);
sel->r.top = clamp_t(unsigned int, sel->r.top, 0, format->height - 1);
@@ -160,8 +158,7 @@ static int uif_set_selection(struct v4l2_subdev *subdev,
format->height - sel->r.top);
/* Store the crop rectangle. */
- selection = vsp1_entity_get_pad_selection(&uif->entity, state,
- sel->pad, V4L2_SEL_TGT_CROP);
+ selection = v4l2_subdev_state_get_crop(state, sel->pad);
*selection = sel->r;
done:
@@ -191,6 +188,7 @@ static const struct v4l2_subdev_ops uif_ops = {
*/
static void uif_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -203,8 +201,7 @@ static void uif_configure_stream(struct vsp1_entity *entity,
vsp1_uif_write(uif, dlb, VI6_UIF_DISCOM_DOCMPMR,
VI6_UIF_DISCOM_DOCMPMR_SEL(9));
- crop = vsp1_entity_get_pad_selection(entity, entity->state,
- UIF_PAD_SINK, V4L2_SEL_TGT_CROP);
+ crop = v4l2_subdev_state_get_crop(state, UIF_PAD_SINK);
left = crop->left;
width = crop->width;
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c
index 5a9cb0e5640e..fdb46ec0c872 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_video.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c
@@ -78,8 +78,14 @@ static int vsp1_video_verify_format(struct vsp1_video *video)
if (video->rwpf->fmtinfo->mbus != fmt.format.code ||
video->rwpf->format.height != fmt.format.height ||
- video->rwpf->format.width != fmt.format.width)
- return -EINVAL;
+ video->rwpf->format.width != fmt.format.width) {
+ dev_dbg(video->vsp1->dev,
+ "Format mismatch: 0x%04x/%ux%u != 0x%04x/%ux%u\n",
+ video->rwpf->fmtinfo->mbus, video->rwpf->format.width,
+ video->rwpf->format.height, fmt.format.code,
+ fmt.format.width, fmt.format.height);
+ return -EPIPE;
+ }
return 0;
}
@@ -173,131 +179,6 @@ static int __vsp1_video_try_format(struct vsp1_video *video,
}
/* -----------------------------------------------------------------------------
- * VSP1 Partition Algorithm support
- */
-
-/**
- * vsp1_video_calculate_partition - Calculate the active partition output window
- *
- * @pipe: the pipeline
- * @partition: partition that will hold the calculated values
- * @div_size: pre-determined maximum partition division size
- * @index: partition index
- */
-static void vsp1_video_calculate_partition(struct vsp1_pipeline *pipe,
- struct vsp1_partition *partition,
- unsigned int div_size,
- unsigned int index)
-{
- const struct v4l2_mbus_framefmt *format;
- struct vsp1_partition_window window;
- unsigned int modulus;
-
- /*
- * Partitions are computed on the size before rotation, use the format
- * at the WPF sink.
- */
- format = vsp1_entity_get_pad_format(&pipe->output->entity,
- pipe->output->entity.state,
- RWPF_PAD_SINK);
-
- /* A single partition simply processes the output size in full. */
- if (pipe->partitions <= 1) {
- window.left = 0;
- window.width = format->width;
-
- vsp1_pipeline_propagate_partition(pipe, partition, index,
- &window);
- return;
- }
-
- /* Initialise the partition with sane starting conditions. */
- window.left = index * div_size;
- window.width = div_size;
-
- modulus = format->width % div_size;
-
- /*
- * We need to prevent the last partition from being smaller than the
- * *minimum* width of the hardware capabilities.
- *
- * If the modulus is less than half of the partition size,
- * the penultimate partition is reduced to half, which is added
- * to the final partition: |1234|1234|1234|12|341|
- * to prevent this: |1234|1234|1234|1234|1|.
- */
- if (modulus) {
- /*
- * pipe->partitions is 1 based, whilst index is a 0 based index.
- * Normalise this locally.
- */
- unsigned int partitions = pipe->partitions - 1;
-
- if (modulus < div_size / 2) {
- if (index == partitions - 1) {
- /* Halve the penultimate partition. */
- window.width = div_size / 2;
- } else if (index == partitions) {
- /* Increase the final partition. */
- window.width = (div_size / 2) + modulus;
- window.left -= div_size / 2;
- }
- } else if (index == partitions) {
- window.width = modulus;
- }
- }
-
- vsp1_pipeline_propagate_partition(pipe, partition, index, &window);
-}
-
-static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
-{
- struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
- const struct v4l2_mbus_framefmt *format;
- struct vsp1_entity *entity;
- unsigned int div_size;
- unsigned int i;
-
- /*
- * Partitions are computed on the size before rotation, use the format
- * at the WPF sink.
- */
- format = vsp1_entity_get_pad_format(&pipe->output->entity,
- pipe->output->entity.state,
- RWPF_PAD_SINK);
- div_size = format->width;
-
- /*
- * Only Gen3+ hardware requires image partitioning, Gen2 will operate
- * with a single partition that covers the whole output.
- */
- if (vsp1->info->gen >= 3) {
- list_for_each_entry(entity, &pipe->entities, list_pipe) {
- unsigned int entity_max;
-
- if (!entity->ops->max_width)
- continue;
-
- entity_max = entity->ops->max_width(entity, pipe);
- if (entity_max)
- div_size = min(div_size, entity_max);
- }
- }
-
- pipe->partitions = DIV_ROUND_UP(format->width, div_size);
- pipe->part_table = kcalloc(pipe->partitions, sizeof(*pipe->part_table),
- GFP_KERNEL);
- if (!pipe->part_table)
- return -ENOMEM;
-
- for (i = 0; i < pipe->partitions; ++i)
- vsp1_video_calculate_partition(pipe, &pipe->part_table[i],
- div_size, i);
-
- return 0;
-}
-
-/* -----------------------------------------------------------------------------
* Pipeline Management
*/
@@ -365,13 +246,12 @@ static void vsp1_video_pipeline_run_partition(struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
unsigned int partition)
{
+ struct vsp1_partition *part = &pipe->part_table[partition];
struct vsp1_dl_body *dlb = vsp1_dl_list_get_body0(dl);
struct vsp1_entity *entity;
- pipe->partition = &pipe->part_table[partition];
-
list_for_each_entry(entity, &pipe->entities, list_pipe)
- vsp1_entity_configure_partition(entity, pipe, dl, dlb);
+ vsp1_entity_configure_partition(entity, pipe, part, dl, dlb);
}
static void vsp1_video_pipeline_run(struct vsp1_pipeline *pipe)
@@ -646,11 +526,19 @@ static int vsp1_video_pipeline_build(struct vsp1_pipeline *pipe,
static int vsp1_video_pipeline_init(struct vsp1_pipeline *pipe,
struct vsp1_video *video)
{
+ int ret;
+
vsp1_pipeline_init(pipe);
pipe->frame_end = vsp1_video_pipeline_frame_end;
- return vsp1_video_pipeline_build(pipe, video);
+ ret = vsp1_video_pipeline_build(pipe, video);
+ if (ret)
+ return ret;
+
+ vsp1_pipeline_dump(pipe, "video");
+
+ return 0;
}
static struct vsp1_pipeline *vsp1_video_pipeline_get(struct vsp1_video *video)
@@ -784,6 +672,54 @@ static void vsp1_video_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&pipe->irqlock, flags);
}
+static int vsp1_video_pipeline_setup_partitions(struct vsp1_pipeline *pipe)
+{
+ struct vsp1_device *vsp1 = pipe->output->entity.vsp1;
+ const struct v4l2_mbus_framefmt *format;
+ struct vsp1_entity *entity;
+ unsigned int div_size;
+ unsigned int i;
+
+ /*
+ * Partitions are computed on the size before rotation, use the format
+ * at the WPF sink.
+ */
+ format = v4l2_subdev_state_get_format(pipe->output->entity.state,
+ RWPF_PAD_SINK);
+ div_size = format->width;
+
+ /*
+ * Only Gen3+ hardware requires image partitioning, Gen2 will operate
+ * with a single partition that covers the whole output.
+ */
+ if (vsp1->info->gen >= 3) {
+ list_for_each_entry(entity, &pipe->entities, list_pipe) {
+ unsigned int entity_max;
+
+ if (!entity->ops->max_width)
+ continue;
+
+ entity_max = entity->ops->max_width(entity,
+ entity->state,
+ pipe);
+ if (entity_max)
+ div_size = min(div_size, entity_max);
+ }
+ }
+
+ pipe->partitions = DIV_ROUND_UP(format->width, div_size);
+ pipe->part_table = kcalloc(pipe->partitions, sizeof(*pipe->part_table),
+ GFP_KERNEL);
+ if (!pipe->part_table)
+ return -ENOMEM;
+
+ for (i = 0; i < pipe->partitions; ++i)
+ vsp1_pipeline_calculate_partition(pipe, &pipe->part_table[i],
+ div_size, i);
+
+ return 0;
+}
+
static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
{
struct vsp1_entity *entity;
@@ -826,7 +762,7 @@ static int vsp1_video_setup_pipeline(struct vsp1_pipeline *pipe)
list_for_each_entry(entity, &pipe->entities, list_pipe) {
vsp1_entity_route_setup(entity, pipe, pipe->stream_config);
- vsp1_entity_configure_stream(entity, pipe, NULL,
+ vsp1_entity_configure_stream(entity, entity->state, pipe, NULL,
pipe->stream_config);
}
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
index 9693aeab1cac..f176750ccd98 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_wpf.c
@@ -65,12 +65,10 @@ static int vsp1_wpf_set_rotation(struct vsp1_rwpf *wpf, unsigned int rotation)
goto done;
}
- sink_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.state,
- RWPF_PAD_SINK);
- source_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.state,
- RWPF_PAD_SOURCE);
+ sink_format = v4l2_subdev_state_get_format(wpf->entity.state,
+ RWPF_PAD_SINK);
+ source_format = v4l2_subdev_state_get_format(wpf->entity.state,
+ RWPF_PAD_SOURCE);
mutex_lock(&wpf->entity.lock);
@@ -231,6 +229,7 @@ static int wpf_configure_writeback_chain(struct vsp1_rwpf *wpf,
}
static void wpf_configure_stream(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
@@ -245,12 +244,8 @@ static void wpf_configure_stream(struct vsp1_entity *entity,
u32 srcrpf = 0;
int ret;
- sink_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.state,
- RWPF_PAD_SINK);
- source_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.state,
- RWPF_PAD_SOURCE);
+ sink_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SINK);
+ source_format = v4l2_subdev_state_get_format(state, RWPF_PAD_SOURCE);
/* Format */
if (!pipe->lif || wpf->writeback) {
@@ -367,13 +362,13 @@ static void wpf_configure_frame(struct vsp1_entity *entity,
static void wpf_configure_partition(struct vsp1_entity *entity,
struct vsp1_pipeline *pipe,
+ const struct vsp1_partition *partition,
struct vsp1_dl_list *dl,
struct vsp1_dl_body *dlb)
{
struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
struct vsp1_device *vsp1 = wpf->entity.vsp1;
struct vsp1_rwpf_memory mem = wpf->mem;
- const struct v4l2_mbus_framefmt *sink_format;
const struct v4l2_pix_format_mplane *format = &wpf->format;
const struct vsp1_format_info *fmtinfo = wpf->fmtinfo;
unsigned int width;
@@ -383,21 +378,13 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
unsigned int flip;
unsigned int i;
- sink_format = vsp1_entity_get_pad_format(&wpf->entity,
- wpf->entity.state,
- RWPF_PAD_SINK);
- width = sink_format->width;
- height = sink_format->height;
- left = 0;
-
/*
- * Cropping. The partition algorithm can split the image into
- * multiple slices.
+ * Cropping. The partition algorithm can split the image into multiple
+ * slices.
*/
- if (pipe->partitions > 1) {
- width = pipe->partition->wpf.width;
- left = pipe->partition->wpf.left;
- }
+ width = partition->wpf.width;
+ left = partition->wpf.left;
+ height = partition->wpf.height;
vsp1_wpf_write(wpf, dlb, VI6_WPF_HSZCLIP, VI6_WPF_SZCLIP_EN |
(0 << VI6_WPF_SZCLIP_OFST_SHIFT) |
@@ -508,6 +495,7 @@ static void wpf_configure_partition(struct vsp1_entity *entity,
}
static unsigned int wpf_max_width(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe)
{
struct vsp1_rwpf *wpf = to_rwpf(&entity->subdev);
@@ -516,10 +504,11 @@ static unsigned int wpf_max_width(struct vsp1_entity *entity,
}
static void wpf_partition(struct vsp1_entity *entity,
+ struct v4l2_subdev_state *state,
struct vsp1_pipeline *pipe,
struct vsp1_partition *partition,
unsigned int partition_idx,
- struct vsp1_partition_window *window)
+ struct v4l2_rect *window)
{
partition->wpf = *window;
}
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 662c81b6d0b5..70808049d2e8 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -195,6 +195,11 @@ static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
return ret;
}
+ if (V4L2_TYPE_IS_OUTPUT(q->type))
+ ctx->osequence = 0;
+ else
+ ctx->csequence = 0;
+
return 0;
}
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 00fdfa9e10bc..0e768f3e9eda 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -43,6 +43,8 @@ static void device_run(void *prv)
rga->curr = ctx;
src = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ src->sequence = ctx->osequence++;
+
dst = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
rga_hw_start(rga, vb_to_rga(src), vb_to_rga(dst));
@@ -75,6 +77,8 @@ static irqreturn_t rga_isr(int irq, void *prv)
v4l2_m2m_buf_copy_metadata(src, dst, true);
+ dst->sequence = ctx->csequence++;
+
v4l2_m2m_buf_done(src, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
v4l2_m2m_job_finish(rga->m2m_dev, ctx->fh.m2m_ctx);
diff --git a/drivers/media/platform/rockchip/rga/rga.h b/drivers/media/platform/rockchip/rga/rga.h
index 3502dff6055c..8105bb2efe57 100644
--- a/drivers/media/platform/rockchip/rga/rga.h
+++ b/drivers/media/platform/rockchip/rga/rga.h
@@ -57,6 +57,9 @@ struct rga_ctx {
struct rga_frame out;
struct v4l2_ctrl_handler ctrl_handler;
+ int osequence;
+ int csequence;
+
/* Control values */
u32 op;
u32 hflip;
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
index e45a213baf49..91301d17d356 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c
@@ -173,7 +173,7 @@ static void rkisp1_gasket_disable(struct rkisp1_device *rkisp1)
* or at the frame end interrupt
*/
static void rkisp1_config_ism(struct rkisp1_isp *isp,
- struct v4l2_subdev_state *sd_state)
+ const struct v4l2_subdev_state *sd_state)
{
const struct v4l2_rect *src_crop =
v4l2_subdev_state_get_crop(sd_state,
@@ -201,7 +201,7 @@ static void rkisp1_config_ism(struct rkisp1_isp *isp,
* configure ISP blocks with input format, size......
*/
static int rkisp1_config_isp(struct rkisp1_isp *isp,
- struct v4l2_subdev_state *sd_state,
+ const struct v4l2_subdev_state *sd_state,
enum v4l2_mbus_type mbus_type, u32 mbus_flags)
{
struct rkisp1_device *rkisp1 = isp->rkisp1;
@@ -309,7 +309,7 @@ static int rkisp1_config_isp(struct rkisp1_isp *isp,
if (src_fmt->pixel_enc == V4L2_PIXEL_ENC_BAYER) {
rkisp1_params_disable(&rkisp1->params);
} else {
- struct v4l2_mbus_framefmt *src_frm;
+ const struct v4l2_mbus_framefmt *src_frm;
src_frm = v4l2_subdev_state_get_format(sd_state,
RKISP1_ISP_PAD_SOURCE_VIDEO);
@@ -429,7 +429,7 @@ static void rkisp1_config_clk(struct rkisp1_isp *isp)
}
static int rkisp1_isp_start(struct rkisp1_isp *isp,
- struct v4l2_subdev_state *sd_state,
+ const struct v4l2_subdev_state *sd_state,
struct media_pad *source)
{
struct rkisp1_device *rkisp1 = isp->rkisp1;
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
index 6f3931ca5b51..1fa991227fa9 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c
@@ -135,11 +135,11 @@ static void rkisp1_dcrop_disable(struct rkisp1_resizer *rsz,
/* configure dual-crop unit */
static void rkisp1_dcrop_config(struct rkisp1_resizer *rsz,
- struct v4l2_subdev_state *sd_state)
+ const struct v4l2_subdev_state *sd_state)
{
struct rkisp1_device *rkisp1 = rsz->rkisp1;
- struct v4l2_mbus_framefmt *sink_fmt;
- struct v4l2_rect *sink_crop;
+ const struct v4l2_mbus_framefmt *sink_fmt;
+ const struct v4l2_rect *sink_crop;
u32 dc_ctrl;
sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK);
@@ -264,7 +264,7 @@ static void rkisp1_rsz_config_regs(struct rkisp1_resizer *rsz,
}
static void rkisp1_rsz_config(struct rkisp1_resizer *rsz,
- struct v4l2_subdev_state *sd_state,
+ const struct v4l2_subdev_state *sd_state,
enum rkisp1_shadow_regs_when when)
{
const struct rkisp1_rsz_yuv_mbus_info *sink_yuv_info, *src_yuv_info;
diff --git a/drivers/media/platform/samsung/exynos4-is/common.c b/drivers/media/platform/samsung/exynos4-is/common.c
index e41333535eac..77007f1a909b 100644
--- a/drivers/media/platform/samsung/exynos4-is/common.c
+++ b/drivers/media/platform/samsung/exynos4-is/common.c
@@ -44,4 +44,5 @@ void __fimc_vidioc_querycap(struct device *dev, struct v4l2_capability *cap)
}
EXPORT_SYMBOL(__fimc_vidioc_querycap);
+MODULE_DESCRIPTION("Samsung S5P/EXYNOS4 SoC Camera Subsystem driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c
index 39aab667910d..0a4b58daf924 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c
@@ -999,4 +999,5 @@ module_exit(fimc_is_module_exit);
MODULE_ALIAS("platform:" FIMC_IS_DRV_NAME);
MODULE_AUTHOR("Younghwan Joo <yhwan.joo@samsung.com>");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("Samsung EXYNOS4x12 FIMC-IS (Imaging Subsystem) driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
index d1d860fa3454..1a4d75443215 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
@@ -1662,5 +1662,6 @@ static struct platform_driver fimc_lite_driver = {
}
};
module_platform_driver(fimc_lite_driver);
+MODULE_DESCRIPTION("Samsung EXYNOS FIMC-LITE (camera host interface) driver");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" FIMC_LITE_DRV_NAME);
diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
index 2f58a0d0df85..67d3d6e50d2e 100644
--- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
+++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
@@ -72,16 +72,16 @@ static void c8sectpfe_timer_interrupt(struct timer_list *t)
/* is this descriptor initialised and TP enabled */
if (channel->irec && readl(channel->irec + DMA_PRDS_TPENABLE))
- tasklet_schedule(&channel->tsklet);
+ queue_work(system_bh_wq, &channel->bh_work);
}
fei->timer.expires = jiffies + msecs_to_jiffies(POLL_MSECS);
add_timer(&fei->timer);
}
-static void channel_swdemux_tsklet(struct tasklet_struct *t)
+static void channel_swdemux_bh_work(struct work_struct *t)
{
- struct channel_info *channel = from_tasklet(channel, t, tsklet);
+ struct channel_info *channel = from_work(channel, t, bh_work);
struct c8sectpfei *fei;
unsigned long wp, rp;
int pos, num_packets, n, size;
@@ -210,7 +210,7 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed)
dev_dbg(fei->dev, "Starting channel=%p\n", channel);
- tasklet_setup(&channel->tsklet, channel_swdemux_tsklet);
+ INIT_WORK(&channel->bh_work, channel_swdemux_bh_work);
/* Reset the internal inputblock sram pointers */
writel(channel->fifo,
@@ -303,7 +303,7 @@ static int c8sectpfe_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
/* disable this channels descriptor */
writel(0, channel->irec + DMA_PRDS_TPENABLE);
- tasklet_disable(&channel->tsklet);
+ disable_work_sync(&channel->bh_work);
/* now request memdma channel goes idle */
idlereq = (1 << channel->tsin_id) | IDLEREQ;
@@ -630,8 +630,8 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei,
writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSWP_TP(0));
writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSRP_TP(0));
- /* initialize tasklet */
- tasklet_setup(&tsin->tsklet, channel_swdemux_tsklet);
+ /* initialize bh work */
+ INIT_WORK(&tsin->bh_work, channel_swdemux_bh_work);
return 0;
diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.h b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.h
index bf377cc82225..c1b124c6ef12 100644
--- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.h
+++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.h
@@ -51,7 +51,7 @@ struct channel_info {
unsigned long fifo;
struct completion idle_completion;
- struct tasklet_struct tsklet;
+ struct work_struct bh_work;
struct c8sectpfei *fei;
void __iomem *irec;
diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.h b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.h
index 8e1bfd860524..3fe177b59b16 100644
--- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.h
+++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-debugfs.h
@@ -16,8 +16,8 @@
void c8sectpfe_debugfs_init(struct c8sectpfei *);
void c8sectpfe_debugfs_exit(struct c8sectpfei *);
#else
-static inline void c8sectpfe_debugfs_init(struct c8sectpfei *) {};
-static inline void c8sectpfe_debugfs_exit(struct c8sectpfei *) {};
+static inline void c8sectpfe_debugfs_init(struct c8sectpfei *fei) {};
+static inline void c8sectpfe_debugfs_exit(struct c8sectpfei *fei) {};
#endif
#endif /* __C8SECTPFE_DEBUG_H */
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
index 4acc3b90d03a..7f771ea49b78 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
@@ -202,8 +202,8 @@ static int dcmipp_create_subdevs(struct dcmipp_device *dcmipp)
return 0;
err_init_entity:
- while (i > 0)
- dcmipp->pipe_cfg->ents[i - 1].release(dcmipp->entity[i - 1]);
+ while (i-- > 0)
+ dcmipp->pipe_cfg->ents[i].release(dcmipp->entity[i]);
return ret;
}
diff --git a/drivers/media/platform/ti/vpe/vpdma.c b/drivers/media/platform/ti/vpe/vpdma.c
index f8998a8ad371..da90d7f03f82 100644
--- a/drivers/media/platform/ti/vpe/vpdma.c
+++ b/drivers/media/platform/ti/vpe/vpdma.c
@@ -1173,4 +1173,5 @@ EXPORT_SYMBOL(vpdma_create);
MODULE_AUTHOR("Texas Instruments Inc.");
MODULE_FIRMWARE(VPDMA_FIRMWARE);
+MODULE_DESCRIPTION("TI VPDMA helper library");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/verisilicon/Kconfig b/drivers/media/platform/verisilicon/Kconfig
index 9a34d14c6e40..149d0b32c324 100644
--- a/drivers/media/platform/verisilicon/Kconfig
+++ b/drivers/media/platform/verisilicon/Kconfig
@@ -12,6 +12,7 @@ config VIDEO_HANTRO
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
select V4L2_H264
+ select V4L2_JPEG_HELPER
select V4L2_VP9
help
Support for the Hantro IP based Video Processing Units present on
diff --git a/drivers/media/platform/verisilicon/hantro_jpeg.c b/drivers/media/platform/verisilicon/hantro_jpeg.c
index d07b1b449b61..13a60638e43f 100644
--- a/drivers/media/platform/verisilicon/hantro_jpeg.c
+++ b/drivers/media/platform/verisilicon/hantro_jpeg.c
@@ -11,6 +11,7 @@
#include <linux/build_bug.h>
#include <linux/kernel.h>
#include <linux/string.h>
+#include <media/v4l2-jpeg.h>
#include "hantro_jpeg.h"
#include "hantro.h"
@@ -24,42 +25,6 @@
#define HUFF_CHROMA_DC_OFF 394
#define HUFF_CHROMA_AC_OFF 427
-/* Default tables from JPEG ITU-T.81
- * (ISO/IEC 10918-1) Annex K, tables K.1 and K.2
- */
-static const unsigned char luma_q_table[] = {
- 0x10, 0x0b, 0x0a, 0x10, 0x18, 0x28, 0x33, 0x3d,
- 0x0c, 0x0c, 0x0e, 0x13, 0x1a, 0x3a, 0x3c, 0x37,
- 0x0e, 0x0d, 0x10, 0x18, 0x28, 0x39, 0x45, 0x38,
- 0x0e, 0x11, 0x16, 0x1d, 0x33, 0x57, 0x50, 0x3e,
- 0x12, 0x16, 0x25, 0x38, 0x44, 0x6d, 0x67, 0x4d,
- 0x18, 0x23, 0x37, 0x40, 0x51, 0x68, 0x71, 0x5c,
- 0x31, 0x40, 0x4e, 0x57, 0x67, 0x79, 0x78, 0x65,
- 0x48, 0x5c, 0x5f, 0x62, 0x70, 0x64, 0x67, 0x63
-};
-
-static const unsigned char chroma_q_table[] = {
- 0x11, 0x12, 0x18, 0x2f, 0x63, 0x63, 0x63, 0x63,
- 0x12, 0x15, 0x1a, 0x42, 0x63, 0x63, 0x63, 0x63,
- 0x18, 0x1a, 0x38, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x2f, 0x42, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63,
- 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63, 0x63
-};
-
-static const unsigned char zigzag[] = {
- 0, 1, 8, 16, 9, 2, 3, 10,
- 17, 24, 32, 25, 18, 11, 4, 5,
- 12, 19, 26, 33, 40, 48, 41, 34,
- 27, 20, 13, 6, 7, 14, 21, 28,
- 35, 42, 49, 56, 57, 50, 43, 36,
- 29, 22, 15, 23, 30, 37, 44, 51,
- 58, 59, 52, 45, 38, 31, 39, 46,
- 53, 60, 61, 54, 47, 55, 62, 63
-};
-
static const u32 hw_reorder[] = {
0, 8, 16, 24, 1, 9, 17, 25,
32, 40, 48, 56, 33, 41, 49, 57,
@@ -71,73 +36,6 @@ static const u32 hw_reorder[] = {
38, 46, 54, 62, 39, 47, 55, 63
};
-/* Huffman tables are shared with CODA */
-static const unsigned char luma_dc_table[] = {
- 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b,
-};
-
-static const unsigned char chroma_dc_table[] = {
- 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
- 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
- 0x08, 0x09, 0x0a, 0x0b,
-};
-
-static const unsigned char luma_ac_table[] = {
- 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
- 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
- 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
- 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
- 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
- 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
- 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
- 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
- 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
- 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
- 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
- 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
- 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
- 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
- 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
- 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
- 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
- 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
- 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
- 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
- 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
- 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
- 0xf9, 0xfa,
-};
-
-static const unsigned char chroma_ac_table[] = {
- 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
- 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
- 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
- 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
- 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
- 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
- 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
- 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
- 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
- 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
- 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
- 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
- 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
- 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
- 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
- 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
- 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
- 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
- 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
- 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
- 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
- 0xf9, 0xfa,
-};
-
/* For simplicity, we keep a pre-formatted JPEG header,
* and we'll use fixed offsets to change the width, height
* quantization tables, etc.
@@ -292,11 +190,11 @@ jpeg_scale_quant_table(unsigned char *file_q_tab,
{
int i;
- BUILD_BUG_ON(ARRAY_SIZE(zigzag) != JPEG_QUANT_SIZE);
+ BUILD_BUG_ON(ARRAY_SIZE(v4l2_jpeg_zigzag_scan_index) != JPEG_QUANT_SIZE);
BUILD_BUG_ON(ARRAY_SIZE(hw_reorder) != JPEG_QUANT_SIZE);
for (i = 0; i < JPEG_QUANT_SIZE; i++) {
- file_q_tab[i] = jpeg_scale_qp(tab[zigzag[i]], scale);
+ file_q_tab[i] = jpeg_scale_qp(tab[v4l2_jpeg_zigzag_scan_index[i]], scale);
reordered_q_tab[i] = jpeg_scale_qp(tab[hw_reorder[i]], scale);
}
}
@@ -304,7 +202,6 @@ jpeg_scale_quant_table(unsigned char *file_q_tab,
static void jpeg_set_quality(struct hantro_jpeg_ctx *ctx)
{
int scale;
-
/*
* Non-linear scaling factor:
* [5,50] -> [1000..100], [51,100] -> [98..0]
@@ -314,15 +211,17 @@ static void jpeg_set_quality(struct hantro_jpeg_ctx *ctx)
else
scale = 200 - 2 * ctx->quality;
- BUILD_BUG_ON(ARRAY_SIZE(luma_q_table) != JPEG_QUANT_SIZE);
- BUILD_BUG_ON(ARRAY_SIZE(chroma_q_table) != JPEG_QUANT_SIZE);
+ BUILD_BUG_ON(ARRAY_SIZE(v4l2_jpeg_ref_table_luma_qt) != JPEG_QUANT_SIZE);
+ BUILD_BUG_ON(ARRAY_SIZE(v4l2_jpeg_ref_table_chroma_qt) != JPEG_QUANT_SIZE);
BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_luma_qtable) != JPEG_QUANT_SIZE);
BUILD_BUG_ON(ARRAY_SIZE(ctx->hw_chroma_qtable) != JPEG_QUANT_SIZE);
jpeg_scale_quant_table(ctx->buffer + LUMA_QUANT_OFF,
- ctx->hw_luma_qtable, luma_q_table, scale);
+ ctx->hw_luma_qtable,
+ (const unsigned char *)v4l2_jpeg_ref_table_luma_qt, scale);
jpeg_scale_quant_table(ctx->buffer + CHROMA_QUANT_OFF,
- ctx->hw_chroma_qtable, chroma_q_table, scale);
+ ctx->hw_chroma_qtable,
+ (const unsigned char *)v4l2_jpeg_ref_table_chroma_qt, scale);
}
void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx)
@@ -337,12 +236,10 @@ void hantro_jpeg_header_assemble(struct hantro_jpeg_ctx *ctx)
buf[WIDTH_OFF + 0] = ctx->width >> 8;
buf[WIDTH_OFF + 1] = ctx->width;
- memcpy(buf + HUFF_LUMA_DC_OFF, luma_dc_table, sizeof(luma_dc_table));
- memcpy(buf + HUFF_LUMA_AC_OFF, luma_ac_table, sizeof(luma_ac_table));
- memcpy(buf + HUFF_CHROMA_DC_OFF, chroma_dc_table,
- sizeof(chroma_dc_table));
- memcpy(buf + HUFF_CHROMA_AC_OFF, chroma_ac_table,
- sizeof(chroma_ac_table));
+ memcpy(buf + HUFF_LUMA_DC_OFF, v4l2_jpeg_ref_table_luma_dc_ht, V4L2_JPEG_REF_HT_DC_LEN);
+ memcpy(buf + HUFF_LUMA_AC_OFF, v4l2_jpeg_ref_table_luma_ac_ht, V4L2_JPEG_REF_HT_AC_LEN);
+ memcpy(buf + HUFF_CHROMA_DC_OFF, v4l2_jpeg_ref_table_chroma_dc_ht, V4L2_JPEG_REF_HT_DC_LEN);
+ memcpy(buf + HUFF_CHROMA_AC_OFF, v4l2_jpeg_ref_table_chroma_ac_ht, V4L2_JPEG_REF_HT_AC_LEN);
jpeg_set_quality(ctx);
}
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index a96de5d388a1..a1687b868a44 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -348,8 +348,8 @@ static void xvip_dma_buffer_queue(struct vb2_buffer *vb)
}
dma->xt.frame_size = 1;
- dma->sgl[0].size = dma->format.width * dma->fmtinfo->bpp;
- dma->sgl[0].icg = dma->format.bytesperline - dma->sgl[0].size;
+ dma->sgl.size = dma->format.width * dma->fmtinfo->bpp;
+ dma->sgl.icg = dma->format.bytesperline - dma->sgl.size;
dma->xt.numf = dma->format.height;
desc = dmaengine_prep_interleaved_dma(dma->dma, &dma->xt, flags);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.h b/drivers/media/platform/xilinx/xilinx-dma.h
index 9c6d4c18d1a9..18f77e1a7b39 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.h
+++ b/drivers/media/platform/xilinx/xilinx-dma.h
@@ -97,7 +97,7 @@ struct xvip_dma {
struct dma_chan *dma;
unsigned int align;
struct dma_interleaved_template xt;
- struct data_chunk sgl[1];
+ struct data_chunk sgl;
};
#define to_xvip_dma(vdev) container_of(vdev, struct xvip_dma, video)
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index dc0c1d8d23f0..af0a70910099 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -790,4 +790,5 @@ const struct video_device si470x_viddev_template = {
};
EXPORT_SYMBOL_GPL(si470x_viddev_template);
+MODULE_DESCRIPTION("Core radio driver for Si470x FM Radio Receivers");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/wl128x/fmdrv.h b/drivers/media/radio/wl128x/fmdrv.h
index da8920169df8..03117a41dbd4 100644
--- a/drivers/media/radio/wl128x/fmdrv.h
+++ b/drivers/media/radio/wl128x/fmdrv.h
@@ -15,6 +15,7 @@
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/timer.h>
+#include <linux/workqueue.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
@@ -200,10 +201,10 @@ struct fmdev {
int streg_cbdata; /* status of ST registration */
struct sk_buff_head rx_q; /* RX queue */
- struct tasklet_struct rx_task; /* RX Tasklet */
+ struct work_struct rx_bh_work; /* RX BH Work */
struct sk_buff_head tx_q; /* TX queue */
- struct tasklet_struct tx_task; /* TX Tasklet */
+ struct work_struct tx_bh_work; /* TX BH Work */
unsigned long last_tx_jiffies; /* Timestamp of last pkt sent */
atomic_t tx_cnt; /* Number of packets can send at a time */
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index 3da8e5102bec..3d36f323a8f8 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -9,7 +9,7 @@
* one Channel-8 command to be sent to the chip).
* 2) Sending each Channel-8 command to the chip and reading
* response back over Shared Transport.
- * 3) Managing TX and RX Queues and Tasklets.
+ * 3) Managing TX and RX Queues and BH bh Works.
* 4) Handling FM Interrupt packet and taking appropriate action.
* 5) Loading FM firmware to the chip (common, FM TX, and FM RX
* firmware files based on mode selection)
@@ -244,10 +244,10 @@ void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set)
}
/*
- * FM common sub-module will schedule this tasklet whenever it receives
+ * FM common sub-module will queue this bh work whenever it receives
* FM packet from ST driver.
*/
-static void recv_tasklet(struct tasklet_struct *t)
+static void recv_bh_work(struct work_struct *t)
{
struct fmdev *fmdev;
struct fm_irq *irq_info;
@@ -256,7 +256,7 @@ static void recv_tasklet(struct tasklet_struct *t)
u8 num_fm_hci_cmds;
unsigned long flags;
- fmdev = from_tasklet(fmdev, t, tx_task);
+ fmdev = from_work(fmdev, t, tx_bh_work);
irq_info = &fmdev->irq_info;
/* Process all packets in the RX queue */
while ((skb = skb_dequeue(&fmdev->rx_q))) {
@@ -322,22 +322,22 @@ static void recv_tasklet(struct tasklet_struct *t)
/*
* Check flow control field. If Num_FM_HCI_Commands field is
- * not zero, schedule FM TX tasklet.
+ * not zero, queue FM TX bh work.
*/
if (num_fm_hci_cmds && atomic_read(&fmdev->tx_cnt))
if (!skb_queue_empty(&fmdev->tx_q))
- tasklet_schedule(&fmdev->tx_task);
+ queue_work(system_bh_wq, &fmdev->tx_bh_work);
}
}
-/* FM send tasklet: is scheduled when FM packet has to be sent to chip */
-static void send_tasklet(struct tasklet_struct *t)
+/* FM send_bh_work: is scheduled when FM packet has to be sent to chip */
+static void send_bh_work(struct work_struct *t)
{
struct fmdev *fmdev;
struct sk_buff *skb;
int len;
- fmdev = from_tasklet(fmdev, t, tx_task);
+ fmdev = from_work(fmdev, t, tx_bh_work);
if (!atomic_read(&fmdev->tx_cnt))
return;
@@ -366,7 +366,7 @@ static void send_tasklet(struct tasklet_struct *t)
if (len < 0) {
kfree_skb(skb);
fmdev->resp_comp = NULL;
- fmerr("TX tasklet failed to send skb(%p)\n", skb);
+ fmerr("TX bh work failed to send skb(%p)\n", skb);
atomic_set(&fmdev->tx_cnt, 1);
} else {
fmdev->last_tx_jiffies = jiffies;
@@ -374,7 +374,7 @@ static void send_tasklet(struct tasklet_struct *t)
}
/*
- * Queues FM Channel-8 packet to FM TX queue and schedules FM TX tasklet for
+ * Queues FM Channel-8 packet to FM TX queue and schedules FM TX bh work for
* transmission
*/
static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
@@ -440,7 +440,7 @@ static int fm_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
fm_cb(skb)->completion = wait_completion;
skb_queue_tail(&fmdev->tx_q, skb);
- tasklet_schedule(&fmdev->tx_task);
+ queue_work(system_bh_wq, &fmdev->tx_bh_work);
return 0;
}
@@ -462,7 +462,7 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
if (!wait_for_completion_timeout(&fmdev->maintask_comp,
FM_DRV_TX_TIMEOUT)) {
- fmerr("Timeout(%d sec),didn't get regcompletion signal from RX tasklet\n",
+ fmerr("Timeout(%d sec),didn't get regcompletion signal from RX bh work\n",
jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
return -ETIMEDOUT;
}
@@ -1455,7 +1455,7 @@ static long fm_st_receive(void *arg, struct sk_buff *skb)
memcpy(skb_push(skb, 1), &skb->cb[0], 1);
skb_queue_tail(&fmdev->rx_q, skb);
- tasklet_schedule(&fmdev->rx_task);
+ queue_work(system_bh_wq, &fmdev->rx_bh_work);
return 0;
}
@@ -1537,13 +1537,13 @@ int fmc_prepare(struct fmdev *fmdev)
spin_lock_init(&fmdev->rds_buff_lock);
spin_lock_init(&fmdev->resp_skb_lock);
- /* Initialize TX queue and TX tasklet */
+ /* Initialize TX queue and TX bh work */
skb_queue_head_init(&fmdev->tx_q);
- tasklet_setup(&fmdev->tx_task, send_tasklet);
+ INIT_WORK(&fmdev->tx_bh_work, send_bh_work);
- /* Initialize RX Queue and RX tasklet */
+ /* Initialize RX Queue and RX bh work */
skb_queue_head_init(&fmdev->rx_q);
- tasklet_setup(&fmdev->rx_task, recv_tasklet);
+ INIT_WORK(&fmdev->rx_bh_work, recv_bh_work);
fmdev->irq_info.stage = 0;
atomic_set(&fmdev->tx_cnt, 1);
@@ -1589,8 +1589,8 @@ int fmc_release(struct fmdev *fmdev)
/* Service pending read */
wake_up_interruptible(&fmdev->rx.rds.read_queue);
- tasklet_kill(&fmdev->tx_task);
- tasklet_kill(&fmdev->rx_task);
+ cancel_work_sync(&fmdev->tx_bh_work);
+ cancel_work_sync(&fmdev->rx_bh_work);
skb_queue_purge(&fmdev->tx_q);
skb_queue_purge(&fmdev->rx_q);
diff --git a/drivers/media/rc/imon.c b/drivers/media/rc/imon.c
index 0b55314a8082..8f1361bcce3a 100644
--- a/drivers/media/rc/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1148,10 +1148,7 @@ static int imon_ir_change_protocol(struct rc_dev *rc, u64 *rc_proto)
memcpy(ictx->usb_tx_buf, &ir_proto_packet, sizeof(ir_proto_packet));
- if (!mutex_is_locked(&ictx->lock)) {
- unlock = true;
- mutex_lock(&ictx->lock);
- }
+ unlock = mutex_trylock(&ictx->lock);
retval = send_packet(ictx);
if (retval)
diff --git a/drivers/media/rc/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index f19558fdab0c..7fdf0d9edbfd 100644
--- a/drivers/media/rc/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_RC_MAP) += \
rc-msi-digivox-ii.o \
rc-msi-tvanywhere.o \
rc-msi-tvanywhere-plus.o \
+ rc-mygica-utv3.o \
rc-nebula.o \
rc-nec-terratec-cinergy-xs.o \
rc-norwood.o \
diff --git a/drivers/media/rc/keymaps/rc-mygica-utv3.c b/drivers/media/rc/keymaps/rc-mygica-utv3.c
new file mode 100644
index 000000000000..f32b8281459b
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-mygica-utv3.c
@@ -0,0 +1,69 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* rc-mygica-utv3.c - Keytable for the MyGica UTV3 Analog USB2.0 TV Box
+ *
+ * Copyright (c) 2024 by Nils Rothaug
+ */
+
+#include <media/rc-map.h>
+#include <linux/module.h>
+
+static struct rc_map_table mygica_utv3[] = {
+ { 0x0d, KEY_MUTE },
+ { 0x38, KEY_VIDEO }, /* Source */
+ { 0x14, KEY_RADIO }, /* FM Radio */
+ { 0x0c, KEY_POWER2 },
+
+ { 0x01, KEY_NUMERIC_1},
+ { 0x02, KEY_NUMERIC_2},
+ { 0x03, KEY_NUMERIC_3},
+ { 0x04, KEY_NUMERIC_4},
+ { 0x05, KEY_NUMERIC_5},
+ { 0x06, KEY_NUMERIC_6},
+ { 0x07, KEY_NUMERIC_7},
+ { 0x08, KEY_NUMERIC_8},
+ { 0x09, KEY_NUMERIC_9},
+ { 0x00, KEY_NUMERIC_0},
+
+ { 0x0a, KEY_DIGITS }, /* Single/double/triple digit */
+ { 0x0e, KEY_CAMERA }, /* Snapshot */
+ { 0x0f, KEY_ZOOM }, /* Full Screen */
+ { 0x29, KEY_LAST }, /* Recall (return to previous channel) */
+
+ { 0x17, KEY_PLAY },
+ { 0x1f, KEY_RECORD },
+ { 0x0b, KEY_STOP },
+ { 0x16, KEY_PAUSE },
+
+ { 0x20, KEY_CHANNELUP },
+ { 0x21, KEY_CHANNELDOWN },
+ { 0x10, KEY_VOLUMEUP },
+ { 0x11, KEY_VOLUMEDOWN },
+ { 0x26, KEY_REWIND },
+ { 0x27, KEY_FASTFORWARD },
+};
+
+static struct rc_map_list mygica_utv3_map = {
+ .map = {
+ .scan = mygica_utv3,
+ .size = ARRAY_SIZE(mygica_utv3),
+ .rc_proto = RC_PROTO_RC5,
+ .name = RC_MAP_MYGICA_UTV3,
+ }
+};
+
+static int __init init_rc_map_mygica_utv3(void)
+{
+ return rc_map_register(&mygica_utv3_map);
+}
+
+static void __exit exit_rc_map_mygica_utv3(void)
+{
+ rc_map_unregister(&mygica_utv3_map);
+}
+
+module_init(init_rc_map_mygica_utv3)
+module_exit(exit_rc_map_mygica_utv3)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Nils Rothaug");
+MODULE_DESCRIPTION("MyGica UTV3 Analog USB2.0 TV Box remote keytable");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index c76ba24c1f55..cd7af4d88b7f 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -494,7 +494,6 @@ struct mceusb_dev {
u32 carrier;
unsigned char tx_mask;
- char name[128];
char phys[64];
enum mceusb_model_type model;
@@ -774,7 +773,7 @@ static void mceusb_dev_printdata(struct mceusb_dev *ir, u8 *buf, int buf_len,
/*
* Schedule work that can't be done in interrupt handlers
- * (mceusb_dev_recv() and mce_write_callback()) nor tasklets.
+ * (mceusb_dev_recv() and mce_write_callback()) nor BH work.
* Invokes mceusb_deferred_kevent() for recovering from
* error events specified by the kevent bit field.
*/
@@ -1591,16 +1590,10 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
goto out;
}
- snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)",
- mceusb_model[ir->model].name ?
- mceusb_model[ir->model].name :
- "Media Center Ed. eHome Infrared Remote Transceiver",
- le16_to_cpu(ir->usbdev->descriptor.idVendor),
- le16_to_cpu(ir->usbdev->descriptor.idProduct));
-
usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys));
- rc->device_name = ir->name;
+ rc->device_name = mceusb_model[ir->model].name ? :
+ "Media Center Ed. eHome Infrared Remote Transceiver";
rc->input_phys = ir->phys;
usb_to_input_id(ir->usbdev, &rc->input_id);
rc->dev.parent = dev;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 6bdad6341844..a4c539b17cf3 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -2092,4 +2092,5 @@ subsys_initcall(rc_core_init);
module_exit(rc_core_exit);
MODULE_AUTHOR("Mauro Carvalho Chehab");
+MODULE_DESCRIPTION("Remote Controller core module");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/spi/gs1662.c b/drivers/media/spi/gs1662.c
index dc5c4c055d29..7adf55fd0707 100644
--- a/drivers/media/spi/gs1662.c
+++ b/drivers/media/spi/gs1662.c
@@ -55,14 +55,6 @@ struct gs_reg_fmt {
struct v4l2_dv_timings format;
};
-struct gs_reg_fmt_custom {
- u16 reg_value;
- __u32 width;
- __u32 height;
- __u64 pixelclock;
- __u32 interlaced;
-};
-
static const struct spi_device_id gs_id[] = {
{ "gs1662", 0 },
{ }
diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c
index ba7550b8ba7e..89506ae00901 100644
--- a/drivers/media/test-drivers/vimc/vimc-capture.c
+++ b/drivers/media/test-drivers/vimc/vimc-capture.c
@@ -494,7 +494,7 @@ err_free_vcapture:
return ERR_PTR(ret);
}
-struct vimc_ent_type vimc_capture_type = {
+const struct vimc_ent_type vimc_capture_type = {
.add = vimc_capture_add,
.unregister = vimc_capture_unregister,
.release = vimc_capture_release
diff --git a/drivers/media/test-drivers/vimc/vimc-common.c b/drivers/media/test-drivers/vimc/vimc-common.c
index 2e72974e35b4..4f4fcb26e236 100644
--- a/drivers/media/test-drivers/vimc/vimc-common.c
+++ b/drivers/media/test-drivers/vimc/vimc-common.c
@@ -8,6 +8,8 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <media/v4l2-ctrls.h>
+
#include "vimc-common.h"
/*
@@ -358,6 +360,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
u32 function,
u16 num_pads,
struct media_pad *pads,
+ const struct v4l2_subdev_internal_ops *int_ops,
const struct v4l2_subdev_ops *sd_ops)
{
int ret;
@@ -367,6 +370,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
/* Initialize the subdev */
v4l2_subdev_init(sd, sd_ops);
+ sd->internal_ops = int_ops;
sd->entity.function = function;
sd->entity.ops = &vimc_ent_sd_mops;
sd->owner = THIS_MODULE;
@@ -383,17 +387,36 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
if (ret)
return ret;
+ /*
+ * Finalize the subdev initialization if it supports active states. Use
+ * the control handler lock as the state lock if available.
+ */
+ if (int_ops && int_ops->init_state) {
+ if (sd->ctrl_handler)
+ sd->state_lock = sd->ctrl_handler->lock;
+
+ ret = v4l2_subdev_init_finalize(sd);
+ if (ret) {
+ dev_err(v4l2_dev->dev,
+ "%s: subdev initialization failed (err=%d)\n",
+ name, ret);
+ goto err_clean_m_ent;
+ }
+ }
+
/* Register the subdev with the v4l2 and the media framework */
ret = v4l2_device_register_subdev(v4l2_dev, sd);
if (ret) {
dev_err(v4l2_dev->dev,
"%s: subdev register failed (err=%d)\n",
name, ret);
- goto err_clean_m_ent;
+ goto err_clean_sd;
}
return 0;
+err_clean_sd:
+ v4l2_subdev_cleanup(sd);
err_clean_m_ent:
media_entity_cleanup(&sd->entity);
return ret;
diff --git a/drivers/media/test-drivers/vimc/vimc-common.h b/drivers/media/test-drivers/vimc/vimc-common.h
index 7641a101a728..7a45a2117748 100644
--- a/drivers/media/test-drivers/vimc/vimc-common.h
+++ b/drivers/media/test-drivers/vimc/vimc-common.h
@@ -156,7 +156,7 @@ struct vimc_ent_type {
*/
struct vimc_ent_config {
const char *name;
- struct vimc_ent_type *type;
+ const struct vimc_ent_type *type;
};
/**
@@ -167,11 +167,11 @@ struct vimc_ent_config {
*/
bool vimc_is_source(struct media_entity *ent);
-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;
+extern const struct vimc_ent_type vimc_sensor_type;
+extern const struct vimc_ent_type vimc_debayer_type;
+extern const struct vimc_ent_type vimc_scaler_type;
+extern const struct vimc_ent_type vimc_capture_type;
+extern const struct vimc_ent_type vimc_lens_type;
/**
* vimc_pix_map_by_index - get vimc_pix_map struct by its index
@@ -215,6 +215,7 @@ const struct vimc_pix_map *vimc_pix_map_by_pixelformat(u32 pixelformat);
* @num_pads: number of pads to initialize
* @pads: the array of pads of the entity, the caller should set the
* flags of the pads
+ * @int_ops: pointer to &struct v4l2_subdev_internal_ops.
* @sd_ops: pointer to &struct v4l2_subdev_ops.
*
* Helper function initialize and register the struct vimc_ent_device and struct
@@ -227,6 +228,7 @@ int vimc_ent_sd_register(struct vimc_ent_device *ved,
u32 function,
u16 num_pads,
struct media_pad *pads,
+ const struct v4l2_subdev_internal_ops *int_ops,
const struct v4l2_subdev_ops *sd_ops);
/**
diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c
index af127476e920..2083c60e34d6 100644
--- a/drivers/media/test-drivers/vimc/vimc-core.c
+++ b/drivers/media/test-drivers/vimc/vimc-core.c
@@ -81,7 +81,7 @@ struct vimc_pipeline_config {
* Topology Configuration
*/
-static struct vimc_ent_config ent_config[] = {
+static const struct vimc_ent_config ent_config[] = {
[SENSOR_A] = {
.name = "Sensor A",
.type = &vimc_sensor_type
diff --git a/drivers/media/test-drivers/vimc/vimc-debayer.c b/drivers/media/test-drivers/vimc/vimc-debayer.c
index d72ed086e00b..bbb7c7a86df0 100644
--- a/drivers/media/test-drivers/vimc/vimc-debayer.c
+++ b/drivers/media/test-drivers/vimc/vimc-debayer.c
@@ -15,6 +15,9 @@
#include "vimc-common.h"
+/* TODO: Add support for more output formats, we only support RGB888 for now. */
+#define VIMC_DEBAYER_SOURCE_MBUS_FMT MEDIA_BUS_FMT_RGB888_1X24
+
enum vimc_debayer_rgb_colors {
VIMC_DEBAYER_RED = 0,
VIMC_DEBAYER_GREEN = 1,
@@ -29,19 +32,26 @@ struct vimc_debayer_pix_map {
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;
+ struct v4l2_ctrl_handler hdl;
+ struct media_pad pads[2];
+
+ u8 *src_frame;
+
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_debayer_pix_map *sink_pix_map;
- unsigned int sink_bpp;
- unsigned int mean_win_size;
- struct v4l2_ctrl_handler hdl;
- struct media_pad pads[2];
+
+ /*
+ * Virtual "hardware" configuration, filled when the stream starts or
+ * when controls are set.
+ */
+ struct {
+ const struct vimc_debayer_pix_map *sink_pix_map;
+ unsigned int sink_bpp;
+ struct v4l2_area size;
+ unsigned int mean_win_size;
+ u32 src_code;
+ } hw;
};
static const struct v4l2_mbus_framefmt sink_fmt_default = {
@@ -153,18 +163,14 @@ static bool vimc_debayer_src_code_is_valid(u32 code)
static int vimc_debayer_init_state(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state)
{
- struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *mf;
- unsigned int i;
mf = v4l2_subdev_state_get_format(sd_state, 0);
*mf = sink_fmt_default;
- for (i = 1; i < sd->entity.num_pads; i++) {
- mf = v4l2_subdev_state_get_format(sd_state, i);
- *mf = sink_fmt_default;
- mf->code = vdebayer->src_code;
- }
+ mf = v4l2_subdev_state_get_format(sd_state, 1);
+ *mf = sink_fmt_default;
+ mf->code = VIMC_DEBAYER_SOURCE_MBUS_FMT;
return 0;
}
@@ -213,24 +219,6 @@ static int vimc_debayer_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static int vimc_debayer_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
-{
- struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
-
- /* Get the current sink format */
- fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
- *v4l2_subdev_state_get_format(sd_state, 0) :
- vdebayer->sink_fmt;
-
- /* Set the right code for the source pad */
- if (VIMC_IS_SRC(fmt->pad))
- fmt->format.code = vdebayer->src_code;
-
- return 0;
-}
-
static void vimc_debayer_adjust_sink_fmt(struct v4l2_mbus_framefmt *fmt)
{
const struct vimc_debayer_pix_map *vpix;
@@ -256,52 +244,42 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_format *fmt)
{
struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
- struct v4l2_mbus_framefmt *sink_fmt;
- u32 *src_code;
+ struct v4l2_mbus_framefmt *format;
- if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- /* Do not change the format while stream is on */
- if (vdebayer->src_frame)
- return -EBUSY;
-
- sink_fmt = &vdebayer->sink_fmt;
- src_code = &vdebayer->src_code;
- } else {
- sink_fmt = v4l2_subdev_state_get_format(sd_state, 0);
- src_code = &v4l2_subdev_state_get_format(sd_state, 1)->code;
- }
+ /* Do not change the format while stream is on. */
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && vdebayer->src_frame)
+ return -EBUSY;
/*
- * Do not change the format of the source pad,
- * it is propagated from the sink
+ * Do not change the format of the source pad, it is propagated from
+ * the sink.
*/
- if (VIMC_IS_SRC(fmt->pad)) {
- u32 code = fmt->format.code;
+ if (VIMC_IS_SRC(fmt->pad))
+ return v4l2_subdev_get_fmt(sd, sd_state, fmt);
- fmt->format = *sink_fmt;
+ /* Set the new format in the sink pad. */
+ vimc_debayer_adjust_sink_fmt(&fmt->format);
- if (vimc_debayer_src_code_is_valid(code))
- *src_code = code;
+ format = v4l2_subdev_state_get_format(sd_state, 0);
- fmt->format.code = *src_code;
- } else {
- /* Set the new format in the sink pad */
- vimc_debayer_adjust_sink_fmt(&fmt->format);
-
- 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", vdebayer->sd.name,
- /* old */
- sink_fmt->width, sink_fmt->height, sink_fmt->code,
- sink_fmt->colorspace, sink_fmt->quantization,
- sink_fmt->xfer_func, sink_fmt->ycbcr_enc,
- /* new */
- fmt->format.width, fmt->format.height, fmt->format.code,
- fmt->format.colorspace, fmt->format.quantization,
- fmt->format.xfer_func, fmt->format.ycbcr_enc);
-
- *sink_fmt = fmt->format;
- }
+ 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", vdebayer->sd.name,
+ /* old */
+ format->width, format->height, format->code,
+ format->colorspace, format->quantization,
+ format->xfer_func, format->ycbcr_enc,
+ /* new */
+ fmt->format.width, fmt->format.height, fmt->format.code,
+ fmt->format.colorspace, fmt->format.quantization,
+ fmt->format.xfer_func, fmt->format.ycbcr_enc);
+
+ *format = fmt->format;
+
+ /* Propagate the format to the source pad. */
+ format = v4l2_subdev_state_get_format(sd_state, 1);
+ *format = fmt->format;
+ format->code = VIMC_DEBAYER_SOURCE_MBUS_FMT;
return 0;
}
@@ -309,7 +287,7 @@ static int vimc_debayer_set_fmt(struct v4l2_subdev *sd,
static const struct v4l2_subdev_pad_ops vimc_debayer_pad_ops = {
.enum_mbus_code = vimc_debayer_enum_mbus_code,
.enum_frame_size = vimc_debayer_enum_frame_size,
- .get_fmt = vimc_debayer_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = vimc_debayer_set_fmt,
};
@@ -321,8 +299,8 @@ static void vimc_debayer_process_rgb_frame(struct vimc_debayer_device *vdebayer,
const struct vimc_pix_map *vpix;
unsigned int i, index;
- vpix = vimc_pix_map_by_code(vdebayer->src_code);
- index = VIMC_FRAME_INDEX(lin, col, vdebayer->sink_fmt.width, 3);
+ vpix = vimc_pix_map_by_code(vdebayer->hw.src_code);
+ index = VIMC_FRAME_INDEX(lin, col, vdebayer->hw.size.width, 3);
for (i = 0; i < 3; i++) {
switch (vpix->pixelformat) {
case V4L2_PIX_FMT_RGB24:
@@ -340,24 +318,37 @@ static int vimc_debayer_s_stream(struct v4l2_subdev *sd, int enable)
struct vimc_debayer_device *vdebayer = v4l2_get_subdevdata(sd);
if (enable) {
+ const struct v4l2_mbus_framefmt *sink_fmt;
+ const struct v4l2_mbus_framefmt *src_fmt;
+ struct v4l2_subdev_state *state;
const struct vimc_pix_map *vpix;
unsigned int frame_size;
if (vdebayer->src_frame)
return 0;
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+ sink_fmt = v4l2_subdev_state_get_format(state, 0);
+ src_fmt = v4l2_subdev_state_get_format(state, 1);
+
/* Calculate the frame size of the source pad */
- vpix = vimc_pix_map_by_code(vdebayer->src_code);
- frame_size = vdebayer->sink_fmt.width * vdebayer->sink_fmt.height *
- vpix->bpp;
+ vpix = vimc_pix_map_by_code(src_fmt->code);
+ frame_size = src_fmt->width * src_fmt->height * vpix->bpp;
/* Save the bytes per pixel of the sink */
- vpix = vimc_pix_map_by_code(vdebayer->sink_fmt.code);
- vdebayer->sink_bpp = vpix->bpp;
+ vpix = vimc_pix_map_by_code(sink_fmt->code);
+ vdebayer->hw.sink_bpp = vpix->bpp;
/* Get the corresponding pixel map from the table */
- vdebayer->sink_pix_map =
- vimc_debayer_pix_map_by_code(vdebayer->sink_fmt.code);
+ vdebayer->hw.sink_pix_map =
+ vimc_debayer_pix_map_by_code(sink_fmt->code);
+
+ vdebayer->hw.size.width = sink_fmt->width;
+ vdebayer->hw.size.height = sink_fmt->height;
+
+ vdebayer->hw.src_code = src_fmt->code;
+
+ v4l2_subdev_unlock_state(state);
/*
* Allocate the frame buffer. Use vmalloc to be able to
@@ -366,7 +357,6 @@ static int vimc_debayer_s_stream(struct v4l2_subdev *sd, int enable)
vdebayer->src_frame = vmalloc(frame_size);
if (!vdebayer->src_frame)
return -ENOMEM;
-
} else {
if (!vdebayer->src_frame)
return 0;
@@ -427,13 +417,13 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
* the top left corner of the mean window (considering the current
* pixel as the center)
*/
- seek = vdebayer->mean_win_size / 2;
+ seek = vdebayer->hw.mean_win_size / 2;
/* Sum the values of the colors in the mean window */
dev_dbg(vdebayer->ved.dev,
"deb: %s: --- Calc pixel %dx%d, window mean %d, seek %d ---\n",
- vdebayer->sd.name, lin, col, vdebayer->sink_fmt.height, seek);
+ vdebayer->sd.name, lin, col, vdebayer->hw.size.height, seek);
/*
* Iterate through all the lines in the mean window, start
@@ -442,7 +432,7 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
* frame
*/
for (wlin = seek > lin ? 0 : lin - seek;
- wlin < lin + seek + 1 && wlin < vdebayer->sink_fmt.height;
+ wlin < lin + seek + 1 && wlin < vdebayer->hw.size.height;
wlin++) {
/*
@@ -452,17 +442,17 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
* frame
*/
for (wcol = seek > col ? 0 : col - seek;
- wcol < col + seek + 1 && wcol < vdebayer->sink_fmt.width;
+ wcol < col + seek + 1 && wcol < vdebayer->hw.size.width;
wcol++) {
enum vimc_debayer_rgb_colors color;
unsigned int index;
/* Check which color this pixel is */
- color = vdebayer->sink_pix_map->order[wlin % 2][wcol % 2];
+ color = vdebayer->hw.sink_pix_map->order[wlin % 2][wcol % 2];
index = VIMC_FRAME_INDEX(wlin, wcol,
- vdebayer->sink_fmt.width,
- vdebayer->sink_bpp);
+ vdebayer->hw.size.width,
+ vdebayer->hw.sink_bpp);
dev_dbg(vdebayer->ved.dev,
"deb: %s: RGB CALC: frame index %d, win pos %dx%d, color %d\n",
@@ -471,7 +461,7 @@ static void vimc_debayer_calc_rgb_sink(struct vimc_debayer_device *vdebayer,
/* Get its value */
rgb[color] = rgb[color] +
vimc_debayer_get_val(&frame[index],
- vdebayer->sink_bpp);
+ vdebayer->hw.sink_bpp);
/* Save how many values we already added */
n_rgb[color]++;
@@ -509,8 +499,8 @@ static void *vimc_debayer_process_frame(struct vimc_ent_device *ved,
if (!vdebayer->src_frame)
return ERR_PTR(-EINVAL);
- for (i = 0; i < vdebayer->sink_fmt.height; i++)
- for (j = 0; j < vdebayer->sink_fmt.width; j++) {
+ for (i = 0; i < vdebayer->hw.size.height; i++)
+ for (j = 0; j < vdebayer->hw.size.width; j++) {
vimc_debayer_calc_rgb_sink(vdebayer, sink_frame, i, j, rgb);
vdebayer->set_rgb_src(vdebayer, i, j, rgb);
}
@@ -525,7 +515,7 @@ static int vimc_debayer_s_ctrl(struct v4l2_ctrl *ctrl)
switch (ctrl->id) {
case VIMC_CID_MEAN_WIN_SIZE:
- vdebayer->mean_win_size = ctrl->val;
+ vdebayer->hw.mean_win_size = ctrl->val;
break;
default:
return -EINVAL;
@@ -543,6 +533,7 @@ static void vimc_debayer_release(struct vimc_ent_device *ved)
container_of(ved, struct vimc_debayer_device, ved);
v4l2_ctrl_handler_free(&vdebayer->hdl);
+ v4l2_subdev_cleanup(&vdebayer->sd);
media_entity_cleanup(vdebayer->ved.ent);
kfree(vdebayer);
}
@@ -594,25 +585,15 @@ static struct vimc_ent_device *vimc_debayer_add(struct vimc_device *vimc,
ret = vimc_ent_sd_register(&vdebayer->ved, &vdebayer->sd, v4l2_dev,
vcfg_name,
MEDIA_ENT_F_PROC_VIDEO_PIXEL_ENC_CONV, 2,
- vdebayer->pads, &vimc_debayer_ops);
+ vdebayer->pads, &vimc_debayer_internal_ops,
+ &vimc_debayer_ops);
if (ret)
goto err_free_hdl;
- vdebayer->sd.internal_ops = &vimc_debayer_internal_ops;
-
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;
+ vdebayer->hw.mean_win_size = vimc_debayer_ctrl_mean_win_size.def;
- /* Initialize the frame format */
- 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
- */
- vdebayer->src_code = MEDIA_BUS_FMT_RGB888_1X24;
vdebayer->set_rgb_src = vimc_debayer_process_rgb_frame;
return &vdebayer->ved;
@@ -625,7 +606,7 @@ err_free_vdebayer:
return ERR_PTR(ret);
}
-struct vimc_ent_type vimc_debayer_type = {
+const 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
index 3ce7f4b4d2cc..96399057a2b5 100644
--- a/drivers/media/test-drivers/vimc/vimc-lens.c
+++ b/drivers/media/test-drivers/vimc/vimc-lens.c
@@ -72,7 +72,7 @@ static struct vimc_ent_device *vimc_lens_add(struct vimc_device *vimc,
ret = vimc_ent_sd_register(&vlens->ved, &vlens->sd, v4l2_dev,
vcfg_name, MEDIA_ENT_F_LENS, 0,
- NULL, &vimc_lens_ops);
+ NULL, NULL, &vimc_lens_ops);
if (ret)
goto err_free_hdl;
@@ -92,11 +92,12 @@ static void vimc_lens_release(struct vimc_ent_device *ved)
container_of(ved, struct vimc_lens_device, ved);
v4l2_ctrl_handler_free(&vlens->hdl);
+ v4l2_subdev_cleanup(&vlens->sd);
media_entity_cleanup(vlens->ved.ent);
kfree(vlens);
}
-struct vimc_ent_type vimc_lens_type = {
+const struct vimc_ent_type vimc_lens_type = {
.add = vimc_lens_add,
.release = vimc_lens_release
};
diff --git a/drivers/media/test-drivers/vimc/vimc-scaler.c b/drivers/media/test-drivers/vimc/vimc-scaler.c
index afe13d6af321..47d0d63865a0 100644
--- a/drivers/media/test-drivers/vimc/vimc-scaler.c
+++ b/drivers/media/test-drivers/vimc/vimc-scaler.c
@@ -15,7 +15,7 @@
#include "vimc-common.h"
/* Pad identifier */
-enum vic_sca_pad {
+enum vimc_scaler_pad {
VIMC_SCALER_SINK = 0,
VIMC_SCALER_SRC = 1,
};
@@ -26,13 +26,20 @@ enum vic_sca_pad {
struct vimc_scaler_device {
struct vimc_ent_device ved;
struct v4l2_subdev sd;
- struct v4l2_rect crop_rect;
- /* Frame format for both sink and src pad */
- struct v4l2_mbus_framefmt fmt[2];
- /* Values calculated when the stream starts */
- u8 *src_frame;
- unsigned int bpp;
struct media_pad pads[2];
+
+ u8 *src_frame;
+
+ /*
+ * Virtual "hardware" configuration, filled when the stream starts or
+ * when controls are set.
+ */
+ struct {
+ struct v4l2_mbus_framefmt sink_fmt;
+ struct v4l2_mbus_framefmt src_fmt;
+ struct v4l2_rect sink_crop;
+ unsigned int bpp;
+ } hw;
};
static const struct v4l2_mbus_framefmt fmt_default = {
@@ -132,39 +139,6 @@ static int vimc_scaler_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static struct v4l2_mbus_framefmt *
-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_state_get_format(sd_state, pad);
- else
- return &vscaler->fmt[pad];
-}
-
-static struct v4l2_rect *
-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_state_get_crop(sd_state, VIMC_SCALER_SINK);
- else
- return &vscaler->crop_rect;
-}
-
-static int vimc_scaler_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd);
-
- format->format = *vimc_scaler_pad_format(vscaler, sd_state, format->pad,
- format->which);
- return 0;
-}
-
static int vimc_scaler_set_fmt(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
@@ -176,7 +150,7 @@ static int vimc_scaler_set_fmt(struct v4l2_subdev *sd,
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE && vscaler->src_frame)
return -EBUSY;
- fmt = vimc_scaler_pad_format(vscaler, sd_state, format->pad, format->which);
+ fmt = v4l2_subdev_state_get_format(sd_state, format->pad);
/*
* The media bus code and colorspace can only be changed on the sink
@@ -214,14 +188,13 @@ static int vimc_scaler_set_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *src_fmt;
struct v4l2_rect *crop;
- crop = vimc_scaler_pad_crop(vscaler, sd_state, format->which);
+ crop = v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK);
crop->width = fmt->width;
crop->height = fmt->height;
crop->top = 0;
crop->left = 0;
- src_fmt = vimc_scaler_pad_format(vscaler, sd_state, VIMC_SCALER_SRC,
- format->which);
+ src_fmt = v4l2_subdev_state_get_format(sd_state, VIMC_SCALER_SRC);
*src_fmt = *fmt;
}
@@ -234,7 +207,6 @@ static int vimc_scaler_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd);
struct v4l2_mbus_framefmt *sink_fmt;
if (VIMC_IS_SRC(sel->pad))
@@ -242,11 +214,10 @@ static int vimc_scaler_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_CROP:
- sel->r = *vimc_scaler_pad_crop(vscaler, sd_state, sel->which);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK);
break;
case V4L2_SEL_TGT_CROP_BOUNDS:
- sink_fmt = vimc_scaler_pad_format(vscaler, sd_state, VIMC_SCALER_SINK,
- sel->which);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, VIMC_SCALER_SINK);
sel->r = vimc_scaler_get_crop_bound_sink(sink_fmt);
break;
default:
@@ -282,9 +253,8 @@ static int vimc_scaler_set_selection(struct v4l2_subdev *sd,
if (sel->which == V4L2_SUBDEV_FORMAT_ACTIVE && vscaler->src_frame)
return -EBUSY;
- 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);
+ crop_rect = v4l2_subdev_state_get_crop(sd_state, VIMC_SCALER_SINK);
+ sink_fmt = v4l2_subdev_state_get_format(sd_state, VIMC_SCALER_SINK);
vimc_scaler_adjust_sink_crop(&sel->r, sink_fmt);
*crop_rect = sel->r;
@@ -294,7 +264,7 @@ static int vimc_scaler_set_selection(struct v4l2_subdev *sd,
static const struct v4l2_subdev_pad_ops vimc_scaler_pad_ops = {
.enum_mbus_code = vimc_scaler_enum_mbus_code,
.enum_frame_size = vimc_scaler_enum_frame_size,
- .get_fmt = vimc_scaler_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = vimc_scaler_set_fmt,
.get_selection = vimc_scaler_get_selection,
.set_selection = vimc_scaler_set_selection,
@@ -305,27 +275,38 @@ static int vimc_scaler_s_stream(struct v4l2_subdev *sd, int enable)
struct vimc_scaler_device *vscaler = v4l2_get_subdevdata(sd);
if (enable) {
- const struct vimc_pix_map *vpix;
+ struct v4l2_subdev_state *state;
+ const struct v4l2_mbus_framefmt *format;
+ const struct v4l2_rect *rect;
unsigned int frame_size;
if (vscaler->src_frame)
return 0;
- /* Save the bytes per pixel of the sink */
- vpix = vimc_pix_map_by_code(vscaler->fmt[VIMC_SCALER_SINK].code);
- vscaler->bpp = vpix->bpp;
+ state = v4l2_subdev_lock_and_get_active_state(sd);
- /* Calculate the frame size of the source pad */
- frame_size = vscaler->fmt[VIMC_SCALER_SRC].width
- * vscaler->fmt[VIMC_SCALER_SRC].height * vscaler->bpp;
+ /* Save the bytes per pixel of the sink. */
+ format = v4l2_subdev_state_get_format(state, VIMC_SCALER_SINK);
+ vscaler->hw.sink_fmt = *format;
+ vscaler->hw.bpp = vimc_pix_map_by_code(format->code)->bpp;
- /* Allocate the frame buffer. Use vmalloc to be able to
- * allocate a large amount of memory
+ /* Calculate the frame size of the source pad. */
+ format = v4l2_subdev_state_get_format(state, VIMC_SCALER_SRC);
+ vscaler->hw.src_fmt = *format;
+ frame_size = format->width * format->height * vscaler->hw.bpp;
+
+ rect = v4l2_subdev_state_get_crop(state, VIMC_SCALER_SINK);
+ vscaler->hw.sink_crop = *rect;
+
+ v4l2_subdev_unlock_state(state);
+
+ /*
+ * Allocate the frame buffer. Use vmalloc to be able to allocate
+ * a large amount of memory.
*/
vscaler->src_frame = vmalloc(frame_size);
if (!vscaler->src_frame)
return -ENOMEM;
-
} else {
if (!vscaler->src_frame)
return 0;
@@ -353,9 +334,9 @@ static const struct v4l2_subdev_internal_ops vimc_scaler_internal_ops = {
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 = &vscaler->fmt[VIMC_SCALER_SRC];
- const struct v4l2_rect *r = &vscaler->crop_rect;
- unsigned int snk_width = vscaler->fmt[VIMC_SCALER_SINK].width;
+ const struct v4l2_mbus_framefmt *sink_fmt = &vscaler->hw.sink_fmt;
+ const struct v4l2_mbus_framefmt *src_fmt = &vscaler->hw.src_fmt;
+ const struct v4l2_rect *r = &vscaler->hw.sink_crop;
unsigned int src_x, src_y;
u8 *walker = vscaler->src_frame;
@@ -364,16 +345,16 @@ static void vimc_scaler_fill_src_frame(const struct vimc_scaler_device *const vs
unsigned int snk_y, y_offset;
snk_y = (src_y * r->height) / src_fmt->height + r->top;
- y_offset = snk_y * snk_width * vscaler->bpp;
+ y_offset = snk_y * sink_fmt->width * vscaler->hw.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 * vscaler->bpp;
+ x_offset = snk_x * vscaler->hw.bpp;
index = y_offset + x_offset;
- memcpy(walker, &sink_frame[index], vscaler->bpp);
- walker += vscaler->bpp;
+ memcpy(walker, &sink_frame[index], vscaler->hw.bpp);
+ walker += vscaler->hw.bpp;
}
}
}
@@ -398,6 +379,7 @@ static void vimc_scaler_release(struct vimc_ent_device *ved)
struct vimc_scaler_device *vscaler =
container_of(ved, struct vimc_scaler_device, ved);
+ v4l2_subdev_cleanup(&vscaler->sd);
media_entity_cleanup(vscaler->ved.ent);
kfree(vscaler);
}
@@ -421,28 +403,20 @@ static struct vimc_ent_device *vimc_scaler_add(struct vimc_device *vimc,
ret = vimc_ent_sd_register(&vscaler->ved, &vscaler->sd, v4l2_dev,
vcfg_name,
MEDIA_ENT_F_PROC_VIDEO_SCALER, 2,
- vscaler->pads, &vimc_scaler_ops);
+ vscaler->pads, &vimc_scaler_internal_ops,
+ &vimc_scaler_ops);
if (ret) {
kfree(vscaler);
return ERR_PTR(ret);
}
- vscaler->sd.internal_ops = &vimc_scaler_internal_ops;
-
vscaler->ved.process_frame = vimc_scaler_process_frame;
vscaler->ved.dev = vimc->mdev.dev;
- /* Initialize the frame format */
- vscaler->fmt[VIMC_SCALER_SINK] = fmt_default;
- vscaler->fmt[VIMC_SCALER_SRC] = fmt_default;
-
- /* Initialize the crop selection */
- vscaler->crop_rect = crop_rect_default;
-
return &vscaler->ved;
}
-struct vimc_ent_type vimc_scaler_type = {
+const struct vimc_ent_type vimc_scaler_type = {
.add = vimc_scaler_add,
.release = vimc_scaler_release
};
diff --git a/drivers/media/test-drivers/vimc/vimc-sensor.c b/drivers/media/test-drivers/vimc/vimc-sensor.c
index 5e34b1aed95e..027767777763 100644
--- a/drivers/media/test-drivers/vimc/vimc-sensor.c
+++ b/drivers/media/test-drivers/vimc/vimc-sensor.c
@@ -24,13 +24,20 @@ struct vimc_sensor_device {
struct vimc_ent_device ved;
struct v4l2_subdev sd;
struct tpg_data tpg;
- u8 *frame;
- enum vimc_sensor_osd_mode osd_value;
- u64 start_stream_ts;
- /* The active format */
- struct v4l2_mbus_framefmt mbus_format;
struct v4l2_ctrl_handler hdl;
struct media_pad pad;
+
+ u8 *frame;
+
+ /*
+ * Virtual "hardware" configuration, filled when the stream starts or
+ * when controls are set.
+ */
+ struct {
+ struct v4l2_area size;
+ enum vimc_sensor_osd_mode osd_value;
+ u64 start_stream_ts;
+ } hw;
};
static const struct v4l2_mbus_framefmt fmt_default = {
@@ -44,14 +51,10 @@ static const struct v4l2_mbus_framefmt fmt_default = {
static int vimc_sensor_init_state(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state)
{
- unsigned int i;
-
- for (i = 0; i < sd->entity.num_pads; i++) {
- struct v4l2_mbus_framefmt *mf;
+ struct v4l2_mbus_framefmt *mf;
- mf = v4l2_subdev_state_get_format(sd_state, i);
- *mf = fmt_default;
- }
+ mf = v4l2_subdev_state_get_format(sd_state, 0);
+ *mf = fmt_default;
return 0;
}
@@ -92,36 +95,22 @@ static int vimc_sensor_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
-static int vimc_sensor_get_fmt(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *fmt)
+static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor,
+ const struct v4l2_mbus_framefmt *format)
{
- struct vimc_sensor_device *vsensor =
- container_of(sd, struct vimc_sensor_device, sd);
-
- fmt->format = fmt->which == V4L2_SUBDEV_FORMAT_TRY ?
- *v4l2_subdev_state_get_format(sd_state, fmt->pad) :
- vsensor->mbus_format;
+ const struct vimc_pix_map *vpix = vimc_pix_map_by_code(format->code);
- return 0;
-}
-
-static void vimc_sensor_tpg_s_format(struct vimc_sensor_device *vsensor)
-{
- const struct vimc_pix_map *vpix =
- vimc_pix_map_by_code(vsensor->mbus_format.code);
-
- 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_reset_source(&vsensor->tpg, format->width, format->height,
+ format->field);
+ tpg_s_bytesperline(&vsensor->tpg, 0, format->width * vpix->bpp);
+ tpg_s_buf_height(&vsensor->tpg, format->height);
tpg_s_fourcc(&vsensor->tpg, vpix->pixelformat);
/* TODO: add support for V4L2_FIELD_ALTERNATE */
- 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);
+ tpg_s_field(&vsensor->tpg, format->field, false);
+ tpg_s_colorspace(&vsensor->tpg, format->colorspace);
+ tpg_s_ycbcr_enc(&vsensor->tpg, format->ycbcr_enc);
+ tpg_s_quantization(&vsensor->tpg, format->quantization);
+ tpg_s_xfer_func(&vsensor->tpg, format->xfer_func);
}
static void vimc_sensor_adjust_fmt(struct v4l2_mbus_framefmt *fmt)
@@ -152,15 +141,11 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *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 (vsensor->frame)
- return -EBUSY;
+ /* Do not change the format while stream is on */
+ if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE && vsensor->frame)
+ return -EBUSY;
- mf = &vsensor->mbus_format;
- } else {
- mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
- }
+ mf = v4l2_subdev_state_get_format(sd_state, fmt->pad);
/* Set the new format */
vimc_sensor_adjust_fmt(&fmt->format);
@@ -185,7 +170,7 @@ static int vimc_sensor_set_fmt(struct v4l2_subdev *sd,
static const struct v4l2_subdev_pad_ops vimc_sensor_pad_ops = {
.enum_mbus_code = vimc_sensor_enum_mbus_code,
.enum_frame_size = vimc_sensor_enum_frame_size,
- .get_fmt = vimc_sensor_get_fmt,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = vimc_sensor_set_fmt,
};
@@ -202,7 +187,7 @@ static void *vimc_sensor_process_frame(struct vimc_ent_device *ved,
tpg_fill_plane_buffer(&vsensor->tpg, 0, 0, vsensor->frame);
tpg_calc_text_basep(&vsensor->tpg, basep, 0, vsensor->frame);
- switch (vsensor->osd_value) {
+ switch (vsensor->hw.osd_value) {
case VIMC_SENSOR_OSD_SHOW_ALL: {
const char *order = tpg_g_color_order(&vsensor->tpg);
@@ -216,15 +201,14 @@ static void *vimc_sensor_process_frame(struct vimc_ent_device *ved,
vsensor->tpg.hue);
tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
snprintf(str, sizeof(str), "sensor size: %dx%d",
- vsensor->mbus_format.width,
- vsensor->mbus_format.height);
+ vsensor->hw.size.width, vsensor->hw.size.height);
tpg_gen_text(&vsensor->tpg, basep, line++ * line_height, 16, str);
fallthrough;
}
case VIMC_SENSOR_OSD_SHOW_COUNTERS: {
unsigned int ms;
- ms = div_u64(ktime_get_ns() - vsensor->start_stream_ts, 1000000);
+ ms = div_u64(ktime_get_ns() - vsensor->hw.start_stream_ts, 1000000);
snprintf(str, sizeof(str), "%02d:%02d:%02d:%03d",
(ms / (60 * 60 * 1000)) % 24,
(ms / (60 * 1000)) % 60,
@@ -247,15 +231,25 @@ static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable)
container_of(sd, struct vimc_sensor_device, sd);
if (enable) {
+ const struct v4l2_mbus_framefmt *format;
+ struct v4l2_subdev_state *state;
const struct vimc_pix_map *vpix;
unsigned int frame_size;
- vsensor->start_stream_ts = ktime_get_ns();
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+ format = v4l2_subdev_state_get_format(state, 0);
- /* Calculate the frame size */
- vpix = vimc_pix_map_by_code(vsensor->mbus_format.code);
- frame_size = vsensor->mbus_format.width * vpix->bpp *
- vsensor->mbus_format.height;
+ /* Configure the test pattern generator. */
+ vimc_sensor_tpg_s_format(vsensor, format);
+
+ /* Calculate the frame size. */
+ vpix = vimc_pix_map_by_code(format->code);
+ frame_size = format->width * vpix->bpp * format->height;
+
+ vsensor->hw.size.width = format->width;
+ vsensor->hw.size.height = format->height;
+
+ v4l2_subdev_unlock_state(state);
/*
* Allocate the frame buffer. Use vmalloc to be able to
@@ -265,9 +259,7 @@ static int vimc_sensor_s_stream(struct v4l2_subdev *sd, int enable)
if (!vsensor->frame)
return -ENOMEM;
- /* configure the test pattern generator */
- vimc_sensor_tpg_s_format(vsensor);
-
+ vsensor->hw.start_stream_ts = ktime_get_ns();
} else {
vfree(vsensor->frame);
@@ -325,7 +317,7 @@ static int vimc_sensor_s_ctrl(struct v4l2_ctrl *ctrl)
tpg_s_saturation(&vsensor->tpg, ctrl->val);
break;
case VIMC_CID_OSD_TEXT_MODE:
- vsensor->osd_value = ctrl->val;
+ vsensor->hw.osd_value = ctrl->val;
break;
default:
return -EINVAL;
@@ -344,6 +336,7 @@ static void vimc_sensor_release(struct vimc_ent_device *ved)
v4l2_ctrl_handler_free(&vsensor->hdl);
tpg_free(&vsensor->tpg);
+ v4l2_subdev_cleanup(&vsensor->sd);
media_entity_cleanup(vsensor->ved.ent);
kfree(vsensor);
}
@@ -417,8 +410,7 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc,
}
/* Initialize the test pattern generator */
- tpg_init(&vsensor->tpg, vsensor->mbus_format.width,
- vsensor->mbus_format.height);
+ tpg_init(&vsensor->tpg, fmt_default.width, fmt_default.height);
ret = tpg_alloc(&vsensor->tpg, VIMC_FRAME_MAX_WIDTH);
if (ret)
goto err_free_hdl;
@@ -428,18 +420,13 @@ static struct vimc_ent_device *vimc_sensor_add(struct vimc_device *vimc,
ret = vimc_ent_sd_register(&vsensor->ved, &vsensor->sd, v4l2_dev,
vcfg_name,
MEDIA_ENT_F_CAM_SENSOR, 1, &vsensor->pad,
- &vimc_sensor_ops);
+ &vimc_sensor_internal_ops, &vimc_sensor_ops);
if (ret)
goto err_free_tpg;
- vsensor->sd.internal_ops = &vimc_sensor_internal_ops;
-
vsensor->ved.process_frame = vimc_sensor_process_frame;
vsensor->ved.dev = vimc->mdev.dev;
- /* Initialize the frame format */
- vsensor->mbus_format = fmt_default;
-
return &vsensor->ved;
err_free_tpg:
@@ -452,7 +439,7 @@ err_free_vsensor:
return ERR_PTR(ret);
}
-struct vimc_ent_type vimc_sensor_type = {
+const struct vimc_ent_type vimc_sensor_type = {
.add = vimc_sensor_add,
.release = vimc_sensor_release
};
diff --git a/drivers/media/test-drivers/vivid/vivid-cec.c b/drivers/media/test-drivers/vivid/vivid-cec.c
index 1f7469ff04d5..941ef4263214 100644
--- a/drivers/media/test-drivers/vivid/vivid-cec.c
+++ b/drivers/media/test-drivers/vivid/vivid-cec.c
@@ -23,7 +23,7 @@ struct xfer_on_bus {
static bool find_dest_adap(struct vivid_dev *dev,
struct cec_adapter *adap, u8 dest)
{
- unsigned int i;
+ unsigned int i, j;
if (dest >= 0xf)
return false;
@@ -33,12 +33,29 @@ static bool find_dest_adap(struct vivid_dev *dev,
cec_has_log_addr(dev->cec_rx_adap, dest))
return true;
- for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++) {
- if (adap == dev->cec_tx_adap[i])
+ for (i = 0, j = 0; i < dev->num_inputs; i++) {
+ unsigned int menu_idx =
+ dev->input_is_connected_to_output[i];
+
+ if (dev->input_type[i] != HDMI)
+ continue;
+ j++;
+ if (menu_idx < FIXED_MENU_ITEMS)
+ continue;
+
+ struct vivid_dev *dev_tx = vivid_ctrl_hdmi_to_output_instance[menu_idx];
+ unsigned int output = vivid_ctrl_hdmi_to_output_index[menu_idx];
+
+ if (!dev_tx)
continue;
- if (!dev->cec_tx_adap[i]->is_configured)
+
+ unsigned int hdmi_output = dev_tx->output_to_iface_index[output];
+
+ if (adap == dev_tx->cec_tx_adap[hdmi_output])
+ continue;
+ if (!dev_tx->cec_tx_adap[hdmi_output]->is_configured)
continue;
- if (cec_has_log_addr(dev->cec_tx_adap[i], dest))
+ if (cec_has_log_addr(dev_tx->cec_tx_adap[hdmi_output], dest))
return true;
}
return false;
@@ -96,7 +113,7 @@ static void adjust_sfts(struct vivid_dev *dev)
int vivid_cec_bus_thread(void *_dev)
{
u32 last_sft;
- unsigned int i;
+ unsigned int i, j;
unsigned int dest;
ktime_t start, end;
s64 delta_us, retry_us;
@@ -193,9 +210,27 @@ int vivid_cec_bus_thread(void *_dev)
if (first_status == CEC_TX_STATUS_OK) {
if (xfers_on_bus[first_idx].adap != dev->cec_rx_adap)
cec_received_msg(dev->cec_rx_adap, &first_msg);
- for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++)
- if (xfers_on_bus[first_idx].adap != dev->cec_tx_adap[i])
- cec_received_msg(dev->cec_tx_adap[i], &first_msg);
+ for (i = 0, j = 0; i < dev->num_inputs; i++) {
+ unsigned int menu_idx =
+ dev->input_is_connected_to_output[i];
+
+ if (dev->input_type[i] != HDMI)
+ continue;
+ j++;
+ if (menu_idx < FIXED_MENU_ITEMS)
+ continue;
+
+ struct vivid_dev *dev_tx = vivid_ctrl_hdmi_to_output_instance[menu_idx];
+ unsigned int output = vivid_ctrl_hdmi_to_output_index[menu_idx];
+
+ if (!dev_tx)
+ continue;
+
+ unsigned int hdmi_output = dev_tx->output_to_iface_index[output];
+
+ if (xfers_on_bus[first_idx].adap != dev_tx->cec_tx_adap[hdmi_output])
+ cec_received_msg(dev_tx->cec_tx_adap[hdmi_output], &first_msg);
+ }
}
end = ktime_get();
/*
@@ -242,21 +277,36 @@ static int vivid_cec_adap_transmit(struct cec_adapter *adap, u8 attempts,
u32 signal_free_time, struct cec_msg *msg)
{
struct vivid_dev *dev = cec_get_drvdata(adap);
+ struct vivid_dev *dev_rx = dev;
u8 idx = cec_msg_initiator(msg);
+ u8 output = 0;
- spin_lock(&dev->cec_xfers_slock);
- dev->xfers[idx].adap = adap;
- memcpy(dev->xfers[idx].msg, msg->msg, CEC_MAX_MSG_SIZE);
- dev->xfers[idx].len = msg->len;
- dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_RETRY;
+ if (dev->cec_rx_adap != adap) {
+ int i;
+
+ for (i = 0; i < dev->num_hdmi_outputs; i++)
+ if (dev->cec_tx_adap[i] == adap)
+ break;
+ if (i == dev->num_hdmi_outputs)
+ return -ENONET;
+ output = dev->hdmi_index_to_output_index[i];
+ dev_rx = dev->output_to_input_instance[output];
+ if (!dev_rx)
+ return -ENONET;
+ }
+ spin_lock(&dev_rx->cec_xfers_slock);
+ dev_rx->xfers[idx].adap = adap;
+ memcpy(dev_rx->xfers[idx].msg, msg->msg, CEC_MAX_MSG_SIZE);
+ dev_rx->xfers[idx].len = msg->len;
+ dev_rx->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_RETRY;
if (signal_free_time > CEC_SIGNAL_FREE_TIME_RETRY) {
- if (idx == dev->last_initiator)
- dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
+ if (idx == dev_rx->last_initiator)
+ dev_rx->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEXT_XFER;
else
- dev->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
+ dev_rx->xfers[idx].sft = CEC_SIGNAL_FREE_TIME_NEW_INITIATOR;
}
- spin_unlock(&dev->cec_xfers_slock);
- wake_up_interruptible(&dev->kthread_waitq_cec);
+ spin_unlock(&dev_rx->cec_xfers_slock);
+ wake_up_interruptible(&dev_rx->kthread_waitq_cec);
return 0;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c
index 0273bc9863b0..00e0d08af357 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.c
+++ b/drivers/media/test-drivers/vivid/vivid-core.c
@@ -1,4 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
+
/*
* vivid-core.c - A Virtual Video Test Driver, core initialization
*
@@ -42,15 +43,13 @@
#include "vivid-touch-cap.h"
#define VIVID_MODULE_NAME "vivid"
-
-/* The maximum number of vivid devices */
-#define VIVID_MAX_DEVS CONFIG_VIDEO_VIVID_MAX_DEVS
+#define MAX_STRING_LENGTH 23
MODULE_DESCRIPTION("Virtual Video Test Driver");
MODULE_AUTHOR("Hans Verkuil");
MODULE_LICENSE("GPL");
-static unsigned n_devs = 1;
+unsigned int n_devs = 1;
module_param(n_devs, uint, 0444);
MODULE_PARM_DESC(n_devs, " number of driver instances to create");
@@ -186,7 +185,32 @@ MODULE_PARM_DESC(supports_requests, " support for requests, default is 1.\n"
"\t\t 1 == supports requests\n"
"\t\t 2 == requires requests");
-static struct vivid_dev *vivid_devs[VIVID_MAX_DEVS];
+struct vivid_dev *vivid_devs[VIVID_MAX_DEVS];
+
+DEFINE_SPINLOCK(hdmi_output_skip_mask_lock);
+struct workqueue_struct *update_hdmi_ctrls_workqueue;
+u64 hdmi_to_output_menu_skip_mask;
+u64 hdmi_input_update_outputs_mask;
+
+struct vivid_dev *vivid_ctrl_hdmi_to_output_instance[MAX_MENU_ITEMS];
+unsigned int vivid_ctrl_hdmi_to_output_index[MAX_MENU_ITEMS];
+
+char *vivid_ctrl_hdmi_to_output_strings[MAX_MENU_ITEMS + 1] = {
+ "Test Pattern Generator",
+ "None"
+};
+
+DEFINE_SPINLOCK(svid_output_skip_mask_lock);
+struct workqueue_struct *update_svid_ctrls_workqueue;
+u64 svid_to_output_menu_skip_mask;
+
+struct vivid_dev *vivid_ctrl_svid_to_output_instance[MAX_MENU_ITEMS];
+unsigned int vivid_ctrl_svid_to_output_index[MAX_MENU_ITEMS];
+
+char *vivid_ctrl_svid_to_output_strings[MAX_MENU_ITEMS + 1] = {
+ "Test Pattern Generator",
+ "None"
+};
const struct v4l2_rect vivid_min_rect = {
0, 0, MIN_WIDTH, MIN_HEIGHT
@@ -218,7 +242,7 @@ static const u8 vivid_hdmi_edid[256] = {
0x5e, 0x5d, 0x10, 0x1f, 0x04, 0x13, 0x22, 0x21,
0x20, 0x05, 0x14, 0x02, 0x11, 0x01, 0x23, 0x09,
0x07, 0x07, 0x83, 0x01, 0x00, 0x00, 0x6d, 0x03,
- 0x0c, 0x00, 0x10, 0x00, 0x00, 0x3c, 0x21, 0x00,
+ 0x0c, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x21, 0x00,
0x60, 0x01, 0x02, 0x03, 0x67, 0xd8, 0x5d, 0xc4,
0x01, 0x78, 0x00, 0x00, 0xe2, 0x00, 0xca, 0xe3,
0x05, 0x00, 0x00, 0xe3, 0x06, 0x01, 0x00, 0x4d,
@@ -229,7 +253,7 @@ static const u8 vivid_hdmi_edid[256] = {
0x00, 0x00, 0x1a, 0x1a, 0x1d, 0x00, 0x80, 0x51,
0xd0, 0x1c, 0x20, 0x40, 0x80, 0x35, 0x00, 0xc0,
0x1c, 0x32, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x82,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x92,
};
static int vidioc_querycap(struct file *file, void *priv,
@@ -827,6 +851,7 @@ static void vivid_dev_release(struct v4l2_device *v4l2_dev)
{
struct vivid_dev *dev = container_of(v4l2_dev, struct vivid_dev, v4l2_dev);
+ cancel_work_sync(&dev->update_hdmi_ctrl_work);
vivid_free_controls(dev);
v4l2_device_unregister(&dev->v4l2_dev);
#ifdef CONFIG_MEDIA_CONTROLLER
@@ -946,6 +971,7 @@ static int vivid_detect_feature_set(struct vivid_dev *dev, int inst,
dev->num_inputs--;
}
dev->num_hdmi_inputs = in_type_counter[HDMI];
+ dev->num_svid_inputs = in_type_counter[SVID];
/* how many outputs do we have and of what type? */
dev->num_outputs = num_outputs[inst];
@@ -960,7 +986,6 @@ static int vivid_detect_feature_set(struct vivid_dev *dev, int inst,
for (i = 0; i < dev->num_outputs; i++) {
dev->output_type[i] = ((output_types[inst] >> i) & 1) ? HDMI : SVID;
dev->output_name_counter[i] = out_type_counter[dev->output_type[i]]++;
- dev->display_present[i] = true;
}
dev->has_audio_outputs = out_type_counter[SVID];
if (out_type_counter[HDMI] == 16) {
@@ -1393,7 +1418,6 @@ static int vivid_create_queues(struct vivid_dev *dev)
static int vivid_create_devnodes(struct platform_device *pdev,
struct vivid_dev *dev, int inst,
- unsigned int cec_tx_bus_cnt,
v4l2_std_id tvnorms_cap,
v4l2_std_id tvnorms_out,
unsigned in_type_counter[4],
@@ -1437,7 +1461,7 @@ static int vivid_create_devnodes(struct platform_device *pdev,
return ret;
}
cec_s_phys_addr(dev->cec_rx_adap, 0, false);
- v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input 0\n",
+ v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input\n",
dev_name(&dev->cec_rx_adap->devnode.dev));
}
#endif
@@ -1480,10 +1504,10 @@ static int vivid_create_devnodes(struct platform_device *pdev,
#endif
#ifdef CONFIG_VIDEO_VIVID_CEC
- for (i = 0; i < cec_tx_bus_cnt; i++) {
+ for (i = 0; i < dev->num_hdmi_outputs; i++) {
ret = cec_register_adapter(dev->cec_tx_adap[i], &pdev->dev);
if (ret < 0) {
- for (; i < cec_tx_bus_cnt; i++) {
+ for (; i >= 0; i--) {
cec_delete_adapter(dev->cec_tx_adap[i]);
dev->cec_tx_adap[i] = NULL;
}
@@ -1491,10 +1515,6 @@ static int vivid_create_devnodes(struct platform_device *pdev,
}
v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n",
dev_name(&dev->cec_tx_adap[i]->devnode.dev), i);
- if (i < out_type_counter[HDMI])
- cec_s_phys_addr(dev->cec_tx_adap[i], (i + 1) << 12, false);
- else
- cec_s_phys_addr(dev->cec_tx_adap[i], 0x1000, false);
}
#endif
@@ -1734,6 +1754,47 @@ static int vivid_create_devnodes(struct platform_device *pdev,
return 0;
}
+static void update_hdmi_ctrls_work_handler(struct work_struct *work)
+{
+ u64 skip_mask;
+ u64 update_mask;
+
+ spin_lock(&hdmi_output_skip_mask_lock);
+ skip_mask = hdmi_to_output_menu_skip_mask;
+ update_mask = hdmi_input_update_outputs_mask;
+ hdmi_input_update_outputs_mask = 0;
+ spin_unlock(&hdmi_output_skip_mask_lock);
+ for (int i = 0; i < n_devs && vivid_devs[i]; i++) {
+ if (update_mask & (1 << i))
+ vivid_update_connected_outputs(vivid_devs[i]);
+ for (int j = 0; j < vivid_devs[i]->num_hdmi_inputs; j++) {
+ struct v4l2_ctrl *c = vivid_devs[i]->ctrl_hdmi_to_output[j];
+
+ v4l2_ctrl_modify_range(c, c->minimum, c->maximum,
+ skip_mask & ~(1ULL << c->cur.val),
+ c->default_value);
+ }
+ }
+}
+
+static void update_svid_ctrls_work_handler(struct work_struct *work)
+{
+ u64 skip_mask;
+
+ spin_lock(&svid_output_skip_mask_lock);
+ skip_mask = svid_to_output_menu_skip_mask;
+ spin_unlock(&svid_output_skip_mask_lock);
+ for (int i = 0; i < n_devs && vivid_devs[i]; i++) {
+ for (int j = 0; j < vivid_devs[i]->num_svid_inputs; j++) {
+ struct v4l2_ctrl *c = vivid_devs[i]->ctrl_svid_to_output[j];
+
+ v4l2_ctrl_modify_range(c, c->minimum, c->maximum,
+ skip_mask & ~(1ULL << c->cur.val),
+ c->default_value);
+ }
+ }
+}
+
static int vivid_create_instance(struct platform_device *pdev, int inst)
{
static const struct v4l2_dv_timings def_dv_timings =
@@ -1747,7 +1808,6 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
struct vivid_dev *dev;
unsigned node_type = node_types[inst];
v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0;
- unsigned int cec_tx_bus_cnt = 0;
int ret;
int i;
@@ -1850,6 +1910,22 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->edid_max_blocks = dev->edid_blocks = 2;
memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid));
dev->radio_rds_init_time = ktime_get();
+ INIT_WORK(&dev->update_hdmi_ctrl_work, update_hdmi_ctrls_work_handler);
+ INIT_WORK(&dev->update_svid_ctrl_work, update_svid_ctrls_work_handler);
+ for (int j = 0, k = 0; j < dev->num_inputs; ++j)
+ if (dev->input_type[j] == HDMI)
+ dev->hdmi_index_to_input_index[k++] = j;
+ for (int j = 0, k = 0; j < dev->num_outputs; ++j)
+ if (dev->output_type[j] == HDMI) {
+ dev->output_to_iface_index[j] = k;
+ dev->hdmi_index_to_output_index[k++] = j;
+ }
+ for (int j = 0, k = 0; j < dev->num_inputs; ++j)
+ if (dev->input_type[j] == SVID)
+ dev->svid_index_to_input_index[k++] = j;
+ for (int j = 0, k = 0; j < dev->num_outputs; ++j)
+ if (dev->output_type[j] == SVID)
+ dev->output_to_iface_index[j] = k++;
/* create all controls */
ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj,
@@ -1860,8 +1936,6 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
goto unreg_dev;
/* enable/disable interface specific controls */
- if (dev->num_outputs && dev->output_type[0] != HDMI)
- v4l2_ctrl_activate(dev->ctrl_display_present, false);
if (dev->num_inputs && dev->input_type[0] != HDMI) {
v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false);
v4l2_ctrl_activate(dev->ctrl_dv_timings, false);
@@ -1917,27 +1991,27 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
}
if (dev->has_vid_out) {
- for (i = 0; i < dev->num_outputs; i++) {
+ int j;
+
+ for (i = j = 0; i < dev->num_outputs; i++) {
struct cec_adapter *adap;
if (dev->output_type[i] != HDMI)
continue;
- dev->cec_output2bus_map[i] = cec_tx_bus_cnt;
- adap = vivid_cec_alloc_adap(dev, cec_tx_bus_cnt, true);
+ adap = vivid_cec_alloc_adap(dev, j, true);
ret = PTR_ERR_OR_ZERO(adap);
if (ret < 0) {
- for (i = 0; i < dev->num_outputs; i++)
- cec_delete_adapter(dev->cec_tx_adap[i]);
+ while (j--)
+ cec_delete_adapter(dev->cec_tx_adap[j]);
goto unreg_dev;
}
- dev->cec_tx_adap[cec_tx_bus_cnt] = adap;
- cec_tx_bus_cnt++;
+ dev->cec_tx_adap[j++] = adap;
}
}
- if (dev->cec_rx_adap || cec_tx_bus_cnt) {
+ if (dev->cec_rx_adap || dev->num_hdmi_outputs) {
init_waitqueue_head(&dev->kthread_waitq_cec);
dev->kthread_cec = kthread_run(vivid_cec_bus_thread, dev,
"vivid_cec-%s", dev->v4l2_dev.name);
@@ -1963,7 +2037,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap);
/* finally start creating the device nodes */
- ret = vivid_create_devnodes(pdev, dev, inst, cec_tx_bus_cnt,
+ ret = vivid_create_devnodes(pdev, dev, inst,
tvnorms_cap, tvnorms_out,
in_type_counter, out_type_counter);
if (ret)
@@ -1986,7 +2060,7 @@ unreg_dev:
vb2_video_unregister_device(&dev->vid_out_dev);
vb2_video_unregister_device(&dev->vid_cap_dev);
cec_unregister_adapter(dev->cec_rx_adap);
- for (i = 0; i < MAX_OUTPUTS; i++)
+ for (i = 0; i < MAX_HDMI_OUTPUTS; i++)
cec_unregister_adapter(dev->cec_tx_adap[i]);
if (dev->kthread_cec)
kthread_stop(dev->kthread_cec);
@@ -2033,6 +2107,42 @@ static int vivid_probe(struct platform_device *pdev)
/* n_devs will reflect the actual number of allocated devices */
n_devs = i;
+ /* Determine qmenu items actually in use */
+ int hdmi_count = FIXED_MENU_ITEMS;
+ int svid_count = FIXED_MENU_ITEMS;
+
+ for (int i = 0; i < n_devs; i++) {
+ struct vivid_dev *dev = vivid_devs[i];
+
+ if (!dev->has_vid_out)
+ continue;
+ for (int j = 0; j < dev->num_outputs && hdmi_count < MAX_MENU_ITEMS; ++j) {
+ if (dev->output_type[j] == HDMI) {
+ vivid_ctrl_hdmi_to_output_instance[hdmi_count] = vivid_devs[i];
+ vivid_ctrl_hdmi_to_output_index[hdmi_count++] = j;
+ }
+ }
+ for (int j = 0; j < dev->num_outputs && svid_count < MAX_MENU_ITEMS; ++j) {
+ if (dev->output_type[j] == SVID) {
+ vivid_ctrl_svid_to_output_instance[svid_count] = vivid_devs[i];
+ vivid_ctrl_svid_to_output_index[svid_count++] = j;
+ }
+ }
+ }
+ hdmi_count = min(hdmi_count, MAX_MENU_ITEMS);
+ svid_count = min(svid_count, MAX_MENU_ITEMS);
+ for (int i = 0; i < n_devs; i++) {
+ for (int j = 0; j < vivid_devs[i]->num_hdmi_inputs; j++) {
+ struct v4l2_ctrl *c = vivid_devs[i]->ctrl_hdmi_to_output[j];
+
+ v4l2_ctrl_modify_range(c, c->minimum, hdmi_count - 1, 0, c->default_value);
+ }
+ for (int j = 0; j < vivid_devs[i]->num_svid_inputs; j++) {
+ struct v4l2_ctrl *c = vivid_devs[i]->ctrl_svid_to_output[j];
+
+ v4l2_ctrl_modify_range(c, c->minimum, svid_count - 1, 0, c->default_value);
+ }
+ }
return ret;
}
@@ -2109,7 +2219,7 @@ static void vivid_remove(struct platform_device *pdev)
vb2_video_unregister_device(&dev->touch_cap_dev);
}
cec_unregister_adapter(dev->cec_rx_adap);
- for (j = 0; j < MAX_OUTPUTS; j++)
+ for (j = 0; j < MAX_HDMI_OUTPUTS; j++)
cec_unregister_adapter(dev->cec_tx_adap[j]);
if (dev->kthread_cec)
kthread_stop(dev->kthread_cec);
@@ -2137,21 +2247,91 @@ static struct platform_driver vivid_pdrv = {
static int __init vivid_init(void)
{
- int ret;
-
+ int hdmi_count = FIXED_MENU_ITEMS;
+ int svid_count = FIXED_MENU_ITEMS;
+ int ret = -ENOMEM;
+ unsigned int ndevs;
+
+ /* Sanity check, prevent insane number of vivid instances */
+ if (n_devs > 64)
+ n_devs = 64;
+ ndevs = clamp_t(unsigned int, n_devs, 1, VIVID_MAX_DEVS);
+
+ for (unsigned int i = 0; i < ndevs; i++) {
+ if (!(node_types[i] & (1 << 8)))
+ continue;
+ unsigned int n_outputs = min(num_outputs[i], MAX_OUTPUTS);
+
+ for (u8 j = 0, k = 0; j < n_outputs && hdmi_count < MAX_MENU_ITEMS &&
+ k < MAX_HDMI_OUTPUTS; ++j) {
+ if (output_types[i] & BIT(j)) {
+ vivid_ctrl_hdmi_to_output_strings[hdmi_count] =
+ kmalloc(MAX_STRING_LENGTH, GFP_KERNEL);
+ if (!vivid_ctrl_hdmi_to_output_strings[hdmi_count])
+ goto free_output_strings;
+ snprintf(vivid_ctrl_hdmi_to_output_strings[hdmi_count],
+ MAX_STRING_LENGTH, "Output HDMI %03d-%d",
+ i & 0xff, k);
+ k++;
+ hdmi_count++;
+ }
+ }
+ for (u8 j = 0, k = 0; j < n_outputs && svid_count < MAX_MENU_ITEMS; ++j) {
+ if (!(output_types[i] & BIT(j))) {
+ vivid_ctrl_svid_to_output_strings[svid_count] =
+ kmalloc(MAX_STRING_LENGTH, GFP_KERNEL);
+ if (!vivid_ctrl_svid_to_output_strings[svid_count])
+ goto free_output_strings;
+ snprintf(vivid_ctrl_svid_to_output_strings[svid_count],
+ MAX_STRING_LENGTH, "Output S-Video %03d-%d",
+ i & 0xff, k);
+ k++;
+ svid_count++;
+ }
+ }
+ }
ret = platform_device_register(&vivid_pdev);
if (ret)
- return ret;
-
+ goto free_output_strings;
ret = platform_driver_register(&vivid_pdrv);
if (ret)
- platform_device_unregister(&vivid_pdev);
+ goto unreg_device;
+ /* Initialize workqueue before module is loaded */
+ update_hdmi_ctrls_workqueue = create_workqueue("update_hdmi_ctrls_wq");
+ if (!update_hdmi_ctrls_workqueue) {
+ ret = -ENOMEM;
+ goto unreg_driver;
+ }
+ update_svid_ctrls_workqueue = create_workqueue("update_svid_ctrls_wq");
+ if (!update_svid_ctrls_workqueue) {
+ ret = -ENOMEM;
+ goto destroy_hdmi_wq;
+ }
+ return ret;
+
+destroy_hdmi_wq:
+ destroy_workqueue(update_hdmi_ctrls_workqueue);
+unreg_driver:
+ platform_driver_register(&vivid_pdrv);
+unreg_device:
+ platform_device_unregister(&vivid_pdev);
+free_output_strings:
+ for (int i = FIXED_MENU_ITEMS; i < MAX_MENU_ITEMS; i++) {
+ kfree(vivid_ctrl_hdmi_to_output_strings[i]);
+ kfree(vivid_ctrl_svid_to_output_strings[i]);
+ }
return ret;
}
static void __exit vivid_exit(void)
{
+ for (int i = FIXED_MENU_ITEMS; i < MAX_MENU_ITEMS; i++) {
+ kfree(vivid_ctrl_hdmi_to_output_strings[i]);
+ kfree(vivid_ctrl_svid_to_output_strings[i]);
+ }
+ destroy_workqueue(update_svid_ctrls_workqueue);
+ destroy_workqueue(update_hdmi_ctrls_workqueue);
platform_driver_unregister(&vivid_pdrv);
platform_device_unregister(&vivid_pdev);
}
diff --git a/drivers/media/test-drivers/vivid/vivid-core.h b/drivers/media/test-drivers/vivid/vivid-core.h
index cfb8e66083f6..cc18a3bc6dc0 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.h
+++ b/drivers/media/test-drivers/vivid/vivid-core.h
@@ -50,10 +50,95 @@
#define JIFFIES_PER_DAY (3600U * 24U * HZ)
#define JIFFIES_RESYNC (JIFFIES_PER_DAY * (0xf0000000U / JIFFIES_PER_DAY))
+/*
+ * Maximum number of HDMI inputs allowed by vivid, due to limitations
+ * of the Physical Address in the EDID and used by CEC we stop at 15
+ * inputs and outputs.
+ */
+#define MAX_HDMI_INPUTS 15
+#define MAX_HDMI_OUTPUTS 15
+
+/* Maximum number of S-Video inputs allowed by vivid */
+#define MAX_SVID_INPUTS 16
+
+/* The maximum number of items in a menu control */
+#define MAX_MENU_ITEMS BITS_PER_LONG_LONG
+
+/* Number of fixed menu items in the 'Connected To' menu controls */
+#define FIXED_MENU_ITEMS 2
+
+/* The maximum number of vivid devices */
+#define VIVID_MAX_DEVS CONFIG_VIDEO_VIVID_MAX_DEVS
+
extern const struct v4l2_rect vivid_min_rect;
extern const struct v4l2_rect vivid_max_rect;
extern unsigned vivid_debug;
+/*
+ * NULL-terminated string array for the HDMI 'Connected To' menu controls
+ * with the list of possible HDMI outputs.
+ *
+ * The first two items are fixed ("TPG" and "None").
+ */
+extern char *vivid_ctrl_hdmi_to_output_strings[1 + MAX_MENU_ITEMS];
+/* Menu control skip mask of all HDMI outputs that are in use */
+extern u64 hdmi_to_output_menu_skip_mask;
+/*
+ * Bitmask of which vivid instances need to update any connected
+ * HDMI outputs.
+ */
+extern u64 hdmi_input_update_outputs_mask;
+/*
+ * Spinlock for access to hdmi_to_output_menu_skip_mask and
+ * hdmi_input_update_outputs_mask.
+ */
+extern spinlock_t hdmi_output_skip_mask_lock;
+/*
+ * Workqueue that updates the menu controls whenever the HDMI menu skip mask
+ * changes.
+ */
+extern struct workqueue_struct *update_hdmi_ctrls_workqueue;
+
+/*
+ * The HDMI menu control value (index in the menu list) maps to an HDMI
+ * output that is part of the given vivid_dev instance and has the given
+ * output index (as returned by VIDIOC_G_OUTPUT).
+ *
+ * NULL/0 if not available.
+ */
+extern struct vivid_dev *vivid_ctrl_hdmi_to_output_instance[MAX_MENU_ITEMS];
+extern unsigned int vivid_ctrl_hdmi_to_output_index[MAX_MENU_ITEMS];
+
+/*
+ * NULL-terminated string array for the S-Video 'Connected To' menu controls
+ * with the list of possible S-Video outputs.
+ *
+ * The first two items are fixed ("TPG" and "None").
+ */
+extern char *vivid_ctrl_svid_to_output_strings[1 + MAX_MENU_ITEMS];
+/* Menu control skip mask of all S-Video outputs that are in use */
+extern u64 svid_to_output_menu_skip_mask;
+/* Spinlock for access to svid_to_output_menu_skip_mask */
+extern spinlock_t svid_output_skip_mask_lock;
+/*
+ * Workqueue that updates the menu controls whenever the S-Video menu skip mask
+ * changes.
+ */
+extern struct workqueue_struct *update_svid_ctrls_workqueue;
+
+/*
+ * The S-Video menu control value (index in the menu list) maps to an S-Video
+ * output that is part of the given vivid_dev instance and has the given
+ * output index (as returned by VIDIOC_G_OUTPUT).
+ *
+ * NULL/0 if not available.
+ */
+extern struct vivid_dev *vivid_ctrl_svid_to_output_instance[MAX_MENU_ITEMS];
+extern unsigned int vivid_ctrl_svid_to_output_index[MAX_MENU_ITEMS];
+
+extern struct vivid_dev *vivid_devs[VIVID_MAX_DEVS];
+extern unsigned int n_devs;
+
struct vivid_fmt {
u32 fourcc; /* v4l2 format id */
enum tgp_color_enc color_enc;
@@ -118,7 +203,7 @@ struct vivid_cec_xfer {
};
struct vivid_dev {
- unsigned inst;
+ u8 inst;
struct v4l2_device v4l2_dev;
#ifdef CONFIG_MEDIA_CONTROLLER
struct media_device mdev;
@@ -161,6 +246,8 @@ struct vivid_dev {
spinlock_t slock;
struct mutex mutex;
+ struct work_struct update_hdmi_ctrl_work;
+ struct work_struct update_svid_ctrl_work;
/* capabilities */
u32 vid_cap_caps;
@@ -176,12 +263,13 @@ struct vivid_dev {
/* supported features */
bool multiplanar;
- unsigned num_inputs;
- unsigned int num_hdmi_inputs;
+ u8 num_inputs;
+ u8 num_hdmi_inputs;
+ u8 num_svid_inputs;
u8 input_type[MAX_INPUTS];
u8 input_name_counter[MAX_INPUTS];
- unsigned num_outputs;
- unsigned int num_hdmi_outputs;
+ u8 num_outputs;
+ u8 num_hdmi_outputs;
u8 output_type[MAX_OUTPUTS];
u8 output_name_counter[MAX_OUTPUTS];
bool has_audio_inputs;
@@ -203,7 +291,20 @@ struct vivid_dev {
bool has_tv_tuner;
bool has_touch_cap;
- bool can_loop_video;
+ /* Output index (0-MAX_OUTPUTS) to vivid instance of connected input */
+ struct vivid_dev *output_to_input_instance[MAX_OUTPUTS];
+ /* Output index (0-MAX_OUTPUTS) to input index (0-MAX_INPUTS) of connected input */
+ u8 output_to_input_index[MAX_OUTPUTS];
+ /* Output index (0-MAX_OUTPUTS) to HDMI or S-Video output index (0-MAX_HDMI/SVID_OUTPUTS) */
+ u8 output_to_iface_index[MAX_OUTPUTS];
+ /* ctrl_hdmi_to_output or ctrl_svid_to_output control value for each input */
+ s32 input_is_connected_to_output[MAX_INPUTS];
+ /* HDMI index (0-MAX_HDMI_OUTPUTS) to output index (0-MAX_OUTPUTS) */
+ u8 hdmi_index_to_output_index[MAX_HDMI_OUTPUTS];
+ /* HDMI index (0-MAX_HDMI_INPUTS) to input index (0-MAX_INPUTS) */
+ u8 hdmi_index_to_input_index[MAX_HDMI_INPUTS];
+ /* S-Video index (0-MAX_SVID_INPUTS) to input index (0-MAX_INPUTS) */
+ u8 svid_index_to_input_index[MAX_SVID_INPUTS];
/* controls */
struct v4l2_ctrl *brightness;
@@ -242,7 +343,6 @@ struct vivid_dev {
struct v4l2_ctrl *ctrl_dv_timings_signal_mode;
struct v4l2_ctrl *ctrl_dv_timings;
};
- struct v4l2_ctrl *ctrl_display_present;
struct v4l2_ctrl *ctrl_has_crop_cap;
struct v4l2_ctrl *ctrl_has_compose_cap;
struct v4l2_ctrl *ctrl_has_scaler_cap;
@@ -276,6 +376,11 @@ struct vivid_dev {
struct v4l2_ctrl *radio_rx_rds_psname;
struct v4l2_ctrl *radio_rx_rds_radiotext;
+ struct v4l2_ctrl *ctrl_hdmi_to_output[MAX_HDMI_INPUTS];
+ char ctrl_hdmi_to_output_names[MAX_HDMI_INPUTS][32];
+ struct v4l2_ctrl *ctrl_svid_to_output[MAX_SVID_INPUTS];
+ char ctrl_svid_to_output_names[MAX_SVID_INPUTS][32];
+
unsigned input_brightness[MAX_INPUTS];
unsigned osd_mode;
unsigned button_pressed;
@@ -364,7 +469,6 @@ struct vivid_dev {
u8 *scaled_line;
u8 *blended_line;
unsigned cur_scaled_line;
- bool display_present[MAX_OUTPUTS];
/* Output Overlay */
void *fb_vbase_out;
@@ -544,11 +648,10 @@ struct vivid_dev {
/* CEC */
struct cec_adapter *cec_rx_adap;
- struct cec_adapter *cec_tx_adap[MAX_OUTPUTS];
- u8 cec_output2bus_map[MAX_OUTPUTS];
+ struct cec_adapter *cec_tx_adap[MAX_HDMI_OUTPUTS];
struct task_struct *kthread_cec;
wait_queue_head_t kthread_waitq_cec;
- struct vivid_cec_xfer xfers[MAX_OUTPUTS];
+ struct vivid_cec_xfer xfers[MAX_OUTPUTS];
spinlock_t cec_xfers_slock; /* read and write cec messages */
u32 cec_sft; /* bus signal free time, in bit periods */
u8 last_initiator;
diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c
index f2b20e25a7a4..8bb38bc7b8cc 100644
--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c
+++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c
@@ -18,7 +18,6 @@
#include "vivid-radio-common.h"
#include "vivid-osd.h"
#include "vivid-ctrls.h"
-#include "vivid-cec.h"
#define VIVID_CID_CUSTOM_BASE (V4L2_CID_USER_BASE | 0xf000)
#define VIVID_CID_BUTTON (VIVID_CID_CUSTOM_BASE + 0)
@@ -69,14 +68,12 @@
#define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 34)
#define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 35)
#define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 36)
-#define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 37)
#define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 38)
#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 39)
#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 40)
#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 41)
#define VIVID_CID_REDUCED_FPS (VIVID_CID_VIVID_BASE + 42)
#define VIVID_CID_HSV_ENC (VIVID_CID_VIVID_BASE + 43)
-#define VIVID_CID_DISPLAY_PRESENT (VIVID_CID_VIVID_BASE + 44)
#define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60)
#define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61)
@@ -104,6 +101,12 @@
#define VIVID_CID_META_CAP_GENERATE_PTS (VIVID_CID_VIVID_BASE + 111)
#define VIVID_CID_META_CAP_GENERATE_SCR (VIVID_CID_VIVID_BASE + 112)
+/* HDMI inputs are in the range 0-14. The next available CID is VIVID_CID_VIVID_BASE + 128 */
+#define VIVID_CID_HDMI_IS_CONNECTED_TO_OUTPUT(input) (VIVID_CID_VIVID_BASE + 113 + (input))
+
+/* S-Video inputs are in the range 0-15. The next available CID is VIVID_CID_VIVID_BASE + 144 */
+#define VIVID_CID_SVID_IS_CONNECTED_TO_OUTPUT(input) (VIVID_CID_VIVID_BASE + 128 + (input))
+
/* General User Controls */
static void vivid_unregister_dev(bool valid, struct video_device *vdev)
@@ -439,6 +442,33 @@ static const struct v4l2_ctrl_ops vivid_user_vid_ctrl_ops = {
/* Video Capture Controls */
+static void vivid_update_power_present(struct vivid_dev *dev)
+{
+ unsigned int i, j;
+
+ dev->power_present = 0;
+ for (i = 0, j = 0;
+ i < ARRAY_SIZE(dev->dv_timings_signal_mode); i++) {
+ if (dev->input_type[i] != HDMI)
+ continue;
+ /*
+ * If connected to TPG or HDMI output, and the signal
+ * mode is not NO_SIGNAL, then there is power present.
+ */
+ if (dev->input_is_connected_to_output[i] != 1 &&
+ dev->dv_timings_signal_mode[i] != NO_SIGNAL)
+ dev->power_present |= (1 << j);
+ j++;
+ }
+
+ __v4l2_ctrl_s_ctrl(dev->ctrl_rx_power_present,
+ dev->power_present);
+
+ v4l2_ctrl_activate(dev->ctrl_dv_timings,
+ dev->dv_timings_signal_mode[dev->input] ==
+ SELECTED_DV_TIMINGS);
+}
+
static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
{
static const u32 colorspaces[] = {
@@ -453,7 +483,11 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
V4L2_COLORSPACE_470_SYSTEM_BG,
};
struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap);
- unsigned int i, j;
+ unsigned int i;
+ struct vivid_dev *output_inst = NULL;
+ int index = 0;
+ int hdmi_index, svid_index;
+ s32 input_index = 0;
switch (ctrl->id) {
case VIVID_CID_TEST_PATTERN:
@@ -569,25 +603,9 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
dev->dv_timings_signal_mode[dev->input] =
dev->ctrl_dv_timings_signal_mode->val;
dev->query_dv_timings[dev->input] = dev->ctrl_dv_timings->val;
-
- dev->power_present = 0;
- for (i = 0, j = 0;
- i < ARRAY_SIZE(dev->dv_timings_signal_mode);
- i++)
- if (dev->input_type[i] == HDMI) {
- if (dev->dv_timings_signal_mode[i] != NO_SIGNAL)
- dev->power_present |= (1 << j);
- j++;
- }
- __v4l2_ctrl_s_ctrl(dev->ctrl_rx_power_present,
- dev->power_present);
-
- v4l2_ctrl_activate(dev->ctrl_dv_timings,
- dev->dv_timings_signal_mode[dev->input] ==
- SELECTED_DV_TIMINGS);
-
+ vivid_update_power_present(dev);
vivid_update_quality(dev);
- vivid_send_source_change(dev, HDMI);
+ vivid_send_input_source_change(dev, dev->input);
break;
case VIVID_CID_DV_TIMINGS_ASPECT_RATIO:
dev->dv_timings_aspect_ratio[dev->input] = ctrl->val;
@@ -604,6 +622,67 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
if (dev->edid_blocks > dev->edid_max_blocks)
dev->edid_blocks = dev->edid_max_blocks;
break;
+ case VIVID_CID_HDMI_IS_CONNECTED_TO_OUTPUT(0) ... VIVID_CID_HDMI_IS_CONNECTED_TO_OUTPUT(14):
+ hdmi_index = ctrl->id - VIVID_CID_HDMI_IS_CONNECTED_TO_OUTPUT(0);
+ output_inst = vivid_ctrl_hdmi_to_output_instance[ctrl->cur.val];
+ index = vivid_ctrl_hdmi_to_output_index[ctrl->cur.val];
+ input_index = dev->hdmi_index_to_input_index[hdmi_index];
+ dev->input_is_connected_to_output[input_index] = ctrl->val;
+
+ if (output_inst) {
+ output_inst->output_to_input_instance[index] = NULL;
+ vivid_update_outputs(output_inst);
+ cec_phys_addr_invalidate(output_inst->cec_tx_adap[index]);
+ }
+ if (ctrl->val >= FIXED_MENU_ITEMS) {
+ output_inst = vivid_ctrl_hdmi_to_output_instance[ctrl->val];
+ index = vivid_ctrl_hdmi_to_output_index[ctrl->val];
+ output_inst->output_to_input_instance[index] = dev;
+ output_inst->output_to_input_index[index] =
+ dev->hdmi_index_to_input_index[hdmi_index];
+ }
+ spin_lock(&hdmi_output_skip_mask_lock);
+ hdmi_to_output_menu_skip_mask &= ~(1ULL << ctrl->cur.val);
+ if (ctrl->val >= FIXED_MENU_ITEMS)
+ hdmi_to_output_menu_skip_mask |= 1ULL << ctrl->val;
+ spin_unlock(&hdmi_output_skip_mask_lock);
+ vivid_update_power_present(dev);
+ vivid_update_quality(dev);
+ vivid_send_input_source_change(dev, dev->hdmi_index_to_input_index[hdmi_index]);
+ if (ctrl->val < FIXED_MENU_ITEMS && ctrl->cur.val < FIXED_MENU_ITEMS)
+ break;
+ spin_lock(&hdmi_output_skip_mask_lock);
+ hdmi_input_update_outputs_mask |= 1 << dev->inst;
+ spin_unlock(&hdmi_output_skip_mask_lock);
+ queue_work(update_hdmi_ctrls_workqueue, &dev->update_hdmi_ctrl_work);
+ break;
+ case VIVID_CID_SVID_IS_CONNECTED_TO_OUTPUT(0) ... VIVID_CID_SVID_IS_CONNECTED_TO_OUTPUT(15):
+ svid_index = ctrl->id - VIVID_CID_SVID_IS_CONNECTED_TO_OUTPUT(0);
+ output_inst = vivid_ctrl_svid_to_output_instance[ctrl->cur.val];
+ index = vivid_ctrl_svid_to_output_index[ctrl->cur.val];
+ input_index = dev->svid_index_to_input_index[svid_index];
+ dev->input_is_connected_to_output[input_index] = ctrl->val;
+
+ if (output_inst)
+ output_inst->output_to_input_instance[index] = NULL;
+ if (ctrl->val >= FIXED_MENU_ITEMS) {
+ output_inst = vivid_ctrl_svid_to_output_instance[ctrl->val];
+ index = vivid_ctrl_svid_to_output_index[ctrl->val];
+ output_inst->output_to_input_instance[index] = dev;
+ output_inst->output_to_input_index[index] =
+ dev->svid_index_to_input_index[svid_index];
+ }
+ spin_lock(&svid_output_skip_mask_lock);
+ svid_to_output_menu_skip_mask &= ~(1ULL << ctrl->cur.val);
+ if (ctrl->val >= FIXED_MENU_ITEMS)
+ svid_to_output_menu_skip_mask |= 1ULL << ctrl->val;
+ spin_unlock(&svid_output_skip_mask_lock);
+ vivid_update_quality(dev);
+ vivid_send_input_source_change(dev, dev->svid_index_to_input_index[svid_index]);
+ if (ctrl->val < FIXED_MENU_ITEMS && ctrl->cur.val < FIXED_MENU_ITEMS)
+ break;
+ queue_work(update_svid_ctrls_workqueue, &dev->update_svid_ctrl_work);
+ break;
}
return 0;
}
@@ -966,37 +1045,6 @@ static const struct v4l2_ctrl_config vivid_ctrl_limited_rgb_range = {
};
-/* Video Loop Control */
-
-static int vivid_loop_cap_s_ctrl(struct v4l2_ctrl *ctrl)
-{
- struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_loop_cap);
-
- switch (ctrl->id) {
- case VIVID_CID_LOOP_VIDEO:
- dev->loop_video = ctrl->val;
- vivid_update_quality(dev);
- vivid_send_source_change(dev, SVID);
- vivid_send_source_change(dev, HDMI);
- break;
- }
- return 0;
-}
-
-static const struct v4l2_ctrl_ops vivid_loop_cap_ctrl_ops = {
- .s_ctrl = vivid_loop_cap_s_ctrl,
-};
-
-static const struct v4l2_ctrl_config vivid_ctrl_loop_video = {
- .ops = &vivid_loop_cap_ctrl_ops,
- .id = VIVID_CID_LOOP_VIDEO,
- .name = "Loop Video",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .max = 1,
- .step = 1,
-};
-
-
/* VBI Capture Control */
static int vivid_vbi_cap_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -1031,8 +1079,6 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_out);
struct v4l2_bt_timings *bt = &dev->dv_timings_out.bt;
- u32 display_present = 0;
- unsigned int i, j, bus_idx;
switch (ctrl->id) {
case VIVID_CID_HAS_CROP_OUT:
@@ -1063,39 +1109,11 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
V4L2_QUANTIZATION_LIM_RANGE :
V4L2_QUANTIZATION_DEFAULT;
}
- if (dev->loop_video)
- vivid_send_source_change(dev, HDMI);
- break;
- case VIVID_CID_DISPLAY_PRESENT:
- if (dev->output_type[dev->output] != HDMI)
- break;
-
- dev->display_present[dev->output] = ctrl->val;
- for (i = 0, j = 0; i < dev->num_outputs; i++)
- if (dev->output_type[i] == HDMI)
- display_present |=
- dev->display_present[i] << j++;
-
- __v4l2_ctrl_s_ctrl(dev->ctrl_tx_rxsense, display_present);
+ if (vivid_output_is_connected_to(dev)) {
+ struct vivid_dev *dev_rx = vivid_output_is_connected_to(dev);
- if (dev->edid_blocks) {
- __v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present,
- display_present);
- __v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug,
- display_present);
+ vivid_send_source_change(dev_rx, HDMI);
}
-
- bus_idx = dev->cec_output2bus_map[dev->output];
- if (!dev->cec_tx_adap[bus_idx])
- break;
-
- if (ctrl->val && dev->edid_blocks)
- cec_s_phys_addr(dev->cec_tx_adap[bus_idx],
- dev->cec_tx_adap[bus_idx]->phys_addr,
- false);
- else
- cec_phys_addr_invalidate(dev->cec_tx_adap[bus_idx]);
-
break;
}
return 0;
@@ -1135,16 +1153,6 @@ static const struct v4l2_ctrl_config vivid_ctrl_has_scaler_out = {
.step = 1,
};
-static const struct v4l2_ctrl_config vivid_ctrl_display_present = {
- .ops = &vivid_vid_out_ctrl_ops,
- .id = VIVID_CID_DISPLAY_PRESENT,
- .name = "Display Present",
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .max = 1,
- .def = 1,
- .step = 1,
-};
-
/* Streaming Controls */
static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -1710,6 +1718,48 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
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);
+
+ WARN_ON(dev->num_hdmi_inputs > MAX_HDMI_INPUTS);
+ WARN_ON(dev->num_svid_inputs > MAX_SVID_INPUTS);
+
+ for (u8 i = 0; i < dev->num_hdmi_inputs; i++) {
+ snprintf(dev->ctrl_hdmi_to_output_names[i],
+ sizeof(dev->ctrl_hdmi_to_output_names[i]),
+ "HDMI %03u-%u Is Connected To", dev->inst, i);
+ }
+
+ for (u8 i = 0; i < dev->num_hdmi_inputs; i++) {
+ struct v4l2_ctrl_config ctrl_config = {
+ .ops = &vivid_vid_cap_ctrl_ops,
+ .id = VIVID_CID_HDMI_IS_CONNECTED_TO_OUTPUT(i),
+ .name = dev->ctrl_hdmi_to_output_names[i],
+ .type = V4L2_CTRL_TYPE_MENU,
+ .max = 1,
+ .qmenu = (const char * const *)vivid_ctrl_hdmi_to_output_strings,
+ };
+ dev->ctrl_hdmi_to_output[i] = v4l2_ctrl_new_custom(hdl_vid_cap,
+ &ctrl_config, NULL);
+ }
+
+ for (u8 i = 0; i < dev->num_svid_inputs; i++) {
+ snprintf(dev->ctrl_svid_to_output_names[i],
+ sizeof(dev->ctrl_svid_to_output_names[i]),
+ "S-Video %03u-%u Is Connected To", dev->inst, i);
+ }
+
+ for (u8 i = 0; i < dev->num_svid_inputs; i++) {
+ struct v4l2_ctrl_config ctrl_config = {
+ .ops = &vivid_vid_cap_ctrl_ops,
+ .id = VIVID_CID_SVID_IS_CONNECTED_TO_OUTPUT(i),
+ .name = dev->ctrl_svid_to_output_names[i],
+ .type = V4L2_CTRL_TYPE_MENU,
+ .max = 1,
+ .qmenu = (const char * const *)vivid_ctrl_svid_to_output_strings,
+ };
+ dev->ctrl_svid_to_output[i] = v4l2_ctrl_new_custom(hdl_vid_cap,
+ &ctrl_config, NULL);
+ }
+
if (show_ccs_cap) {
dev->ctrl_has_crop_cap = v4l2_ctrl_new_custom(hdl_vid_cap,
&vivid_ctrl_has_crop_cap, NULL);
@@ -1812,21 +1862,13 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
dev->ctrl_tx_mode = v4l2_ctrl_new_std_menu(hdl_vid_out, NULL,
V4L2_CID_DV_TX_MODE, V4L2_DV_TX_MODE_HDMI,
0, V4L2_DV_TX_MODE_HDMI);
- dev->ctrl_display_present = v4l2_ctrl_new_custom(hdl_vid_out,
- &vivid_ctrl_display_present, NULL);
- dev->ctrl_tx_hotplug = v4l2_ctrl_new_std(hdl_vid_out,
- NULL, V4L2_CID_DV_TX_HOTPLUG, 0, hdmi_output_mask,
- 0, hdmi_output_mask);
- dev->ctrl_tx_rxsense = v4l2_ctrl_new_std(hdl_vid_out,
- NULL, V4L2_CID_DV_TX_RXSENSE, 0, hdmi_output_mask,
- 0, hdmi_output_mask);
- dev->ctrl_tx_edid_present = v4l2_ctrl_new_std(hdl_vid_out,
- NULL, V4L2_CID_DV_TX_EDID_PRESENT, 0, hdmi_output_mask,
- 0, hdmi_output_mask);
+ dev->ctrl_tx_hotplug = v4l2_ctrl_new_std(hdl_vid_out, NULL,
+ V4L2_CID_DV_TX_HOTPLUG, 0, hdmi_output_mask, 0, 0);
+ dev->ctrl_tx_rxsense = v4l2_ctrl_new_std(hdl_vid_out, NULL,
+ V4L2_CID_DV_TX_RXSENSE, 0, hdmi_output_mask, 0, 0);
+ dev->ctrl_tx_edid_present = v4l2_ctrl_new_std(hdl_vid_out, NULL,
+ V4L2_CID_DV_TX_EDID_PRESENT, 0, hdmi_output_mask, 0, 0);
}
- if ((dev->has_vid_cap && dev->has_vid_out) ||
- (dev->has_vbi_cap && dev->has_vbi_out))
- v4l2_ctrl_new_custom(hdl_loop_cap, &vivid_ctrl_loop_video, NULL);
if (dev->has_fb)
v4l2_ctrl_new_custom(hdl_fb, &vivid_ctrl_clear_fb, NULL);
diff --git a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
index 42048727d7ff..669bd96da4c7 100644
--- a/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-kthread-cap.c
@@ -142,7 +142,7 @@ static void scale_line(const u8 *src, u8 *dst, unsigned srcw, unsigned dstw, uns
* (loop_vid_overlay). Finally calculate the part of the capture buffer that
* will receive that overlaid video.
*/
-static void vivid_precalc_copy_rects(struct vivid_dev *dev)
+static void vivid_precalc_copy_rects(struct vivid_dev *dev, struct vivid_dev *out_dev)
{
/* Framebuffer rectangle */
struct v4l2_rect r_fb = {
@@ -150,16 +150,16 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev)
};
/* Overlay window rectangle in framebuffer coordinates */
struct v4l2_rect r_overlay = {
- dev->overlay_out_left, dev->overlay_out_top,
- dev->compose_out.width, dev->compose_out.height
+ out_dev->overlay_out_left, out_dev->overlay_out_top,
+ out_dev->compose_out.width, out_dev->compose_out.height
};
- v4l2_rect_intersect(&dev->loop_vid_copy, &dev->crop_cap, &dev->compose_out);
+ v4l2_rect_intersect(&dev->loop_vid_copy, &dev->crop_cap, &out_dev->compose_out);
dev->loop_vid_out = dev->loop_vid_copy;
- v4l2_rect_scale(&dev->loop_vid_out, &dev->compose_out, &dev->crop_out);
- dev->loop_vid_out.left += dev->crop_out.left;
- dev->loop_vid_out.top += dev->crop_out.top;
+ v4l2_rect_scale(&dev->loop_vid_out, &out_dev->compose_out, &out_dev->crop_out);
+ dev->loop_vid_out.left += out_dev->crop_out.left;
+ dev->loop_vid_out.top += out_dev->crop_out.top;
dev->loop_vid_cap = dev->loop_vid_copy;
v4l2_rect_scale(&dev->loop_vid_cap, &dev->crop_cap, &dev->compose_cap);
@@ -176,15 +176,15 @@ static void vivid_precalc_copy_rects(struct vivid_dev *dev)
v4l2_rect_intersect(&r_overlay, &r_fb, &r_overlay);
/* shift r_overlay to the same origin as compose_out */
- r_overlay.left += dev->compose_out.left - dev->overlay_out_left;
- r_overlay.top += dev->compose_out.top - dev->overlay_out_top;
+ r_overlay.left += out_dev->compose_out.left - out_dev->overlay_out_left;
+ r_overlay.top += out_dev->compose_out.top - out_dev->overlay_out_top;
v4l2_rect_intersect(&dev->loop_vid_overlay, &r_overlay, &dev->loop_vid_copy);
dev->loop_fb_copy = dev->loop_vid_overlay;
/* shift dev->loop_fb_copy back again to the fb origin */
- dev->loop_fb_copy.left -= dev->compose_out.left - dev->overlay_out_left;
- dev->loop_fb_copy.top -= dev->compose_out.top - dev->overlay_out_top;
+ dev->loop_fb_copy.left -= out_dev->compose_out.left - out_dev->overlay_out_left;
+ dev->loop_fb_copy.top -= out_dev->compose_out.top - out_dev->overlay_out_top;
dev->loop_vid_overlay_cap = dev->loop_vid_overlay;
v4l2_rect_scale(&dev->loop_vid_overlay_cap, &dev->crop_cap, &dev->compose_cap);
@@ -213,24 +213,25 @@ static void *plane_vaddr(struct tpg_data *tpg, struct vivid_buffer *buf,
return vbuf;
}
-static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned p,
- u8 *vcapbuf, struct vivid_buffer *vid_cap_buf)
+static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev,
+ struct vivid_dev *out_dev, unsigned p,
+ u8 *vcapbuf, struct vivid_buffer *vid_cap_buf)
{
bool blank = dev->must_blank[vid_cap_buf->vb.vb2_buf.index];
struct tpg_data *tpg = &dev->tpg;
struct vivid_buffer *vid_out_buf = NULL;
- unsigned vdiv = dev->fmt_out->vdownsampling[p];
+ unsigned vdiv = out_dev->fmt_out->vdownsampling[p];
unsigned twopixsize = tpg_g_twopixelsize(tpg, p);
unsigned img_width = tpg_hdiv(tpg, p, dev->compose_cap.width);
unsigned img_height = dev->compose_cap.height;
unsigned stride_cap = tpg->bytesperline[p];
- unsigned stride_out = dev->bytesperline_out[p];
+ unsigned stride_out = out_dev->bytesperline_out[p];
unsigned stride_osd = dev->display_byte_stride;
unsigned hmax = (img_height * tpg->perc_fill) / 100;
u8 *voutbuf;
u8 *vosdbuf = NULL;
unsigned y;
- bool blend = dev->fbuf_out_flags;
+ bool blend = out_dev->fbuf_out_flags;
/* Coarse scaling with Bresenham */
unsigned vid_out_int_part;
unsigned vid_out_fract_part;
@@ -247,8 +248,8 @@ static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned
vid_out_int_part = dev->loop_vid_out.height / dev->loop_vid_cap.height;
vid_out_fract_part = dev->loop_vid_out.height % dev->loop_vid_cap.height;
- if (!list_empty(&dev->vid_out_active))
- vid_out_buf = list_entry(dev->vid_out_active.next,
+ if (!list_empty(&out_dev->vid_out_active))
+ vid_out_buf = list_entry(out_dev->vid_out_active.next,
struct vivid_buffer, list);
if (vid_out_buf == NULL)
return -ENODATA;
@@ -256,8 +257,8 @@ static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned
vid_cap_buf->vb.field = vid_out_buf->vb.field;
voutbuf = plane_vaddr(tpg, vid_out_buf, p,
- dev->bytesperline_out, dev->fmt_out_rect.height);
- if (p < dev->fmt_out->buffers)
+ out_dev->bytesperline_out, out_dev->fmt_out_rect.height);
+ if (p < out_dev->fmt_out->buffers)
voutbuf += vid_out_buf->vb.vb2_buf.planes[p].data_offset;
voutbuf += tpg_hdiv(tpg, p, dev->loop_vid_out.left) +
(dev->loop_vid_out.top / vdiv) * stride_out;
@@ -274,7 +275,7 @@ static noinline_for_stack int vivid_copy_buffer(struct vivid_dev *dev, unsigned
return 0;
}
- if (dev->overlay_out_enabled &&
+ if (out_dev->overlay_out_enabled &&
dev->loop_vid_overlay.width && dev->loop_vid_overlay.height) {
vosdbuf = dev->video_vbase;
vosdbuf += (dev->loop_fb_copy.left * twopixsize) / 2 +
@@ -385,6 +386,7 @@ update_vid_out_y:
static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
{
+ struct vivid_dev *out_dev = NULL;
struct tpg_data *tpg = &dev->tpg;
unsigned factor = V4L2_FIELD_HAS_T_OR_B(dev->field_cap) ? 2 : 1;
unsigned line_height = 16 / factor;
@@ -396,14 +398,6 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
unsigned ms;
char str[100];
s32 gain;
- bool is_loop = false;
-
- if (dev->loop_video && dev->can_loop_video &&
- ((vivid_is_svid_cap(dev) &&
- !VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) ||
- (vivid_is_hdmi_cap(dev) &&
- !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input]))))
- is_loop = true;
buf->vb.sequence = dev->vid_cap_seq_count;
v4l2_ctrl_s_ctrl(dev->ro_int32, buf->vb.sequence & 0xff);
@@ -428,7 +422,34 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
dev->field_cap == V4L2_FIELD_ALTERNATE);
tpg_s_perc_fill_blank(tpg, dev->must_blank[buf->vb.vb2_buf.index]);
- vivid_precalc_copy_rects(dev);
+ if (vivid_vid_can_loop(dev) &&
+ ((vivid_is_svid_cap(dev) &&
+ !VIVID_INVALID_SIGNAL(dev->std_signal_mode[dev->input])) ||
+ (vivid_is_hdmi_cap(dev) &&
+ !VIVID_INVALID_SIGNAL(dev->dv_timings_signal_mode[dev->input])))) {
+ out_dev = vivid_input_is_connected_to(dev);
+ /*
+ * If the vivid instance of the output device is different
+ * from the vivid instance of this input device, then we
+ * must take care to properly serialize the output device to
+ * prevent that the buffer we are copying from is being freed.
+ *
+ * If the output device is part of the same instance, then the
+ * lock is already taken and there is no need to take the mutex.
+ *
+ * The problem with taking the mutex is that you can get
+ * deadlocked if instance A locks instance B and vice versa.
+ * It is not really worth trying to be very smart about this,
+ * so just try to take the lock, and if you can't, then just
+ * set out_dev to NULL and you will end up with a single frame
+ * of Noise (the default test pattern in this case).
+ */
+ if (out_dev && dev != out_dev && !mutex_trylock(&out_dev->mutex))
+ out_dev = NULL;
+ }
+
+ if (out_dev)
+ vivid_precalc_copy_rects(dev, out_dev);
for (p = 0; p < tpg_g_planes(tpg); p++) {
void *vbuf = plane_vaddr(tpg, buf, p,
@@ -445,10 +466,13 @@ static void vivid_fillbuff(struct vivid_dev *dev, struct vivid_buffer *buf)
vbuf += dev->fmt_cap->data_offset[p];
}
tpg_calc_text_basep(tpg, basep, p, vbuf);
- if (!is_loop || vivid_copy_buffer(dev, p, vbuf, buf))
+ if (!out_dev || vivid_copy_buffer(dev, out_dev, p, vbuf, buf))
tpg_fill_plane_buffer(tpg, vivid_get_std_cap(dev),
p, vbuf);
}
+ if (out_dev && dev != out_dev)
+ mutex_unlock(&out_dev->mutex);
+
dev->must_blank[buf->vb.vb2_buf.index] = false;
/* Updates stream time, only update at the start of a new frame. */
diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
index a81f26b76988..38cda33dffb2 100644
--- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
@@ -219,8 +219,13 @@ static int sdr_cap_queue_setup(struct vb2_queue *vq,
unsigned sizes[], struct device *alloc_devs[])
{
/* 2 = max 16-bit sample returned */
- sizes[0] = SDR_CAP_SAMPLES_PER_BUF * 2;
+ u32 size = SDR_CAP_SAMPLES_PER_BUF * 2;
+
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
+
*nplanes = 1;
+ sizes[0] = size;
return 0;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-touch-cap.c b/drivers/media/test-drivers/vivid/vivid-touch-cap.c
index 3888c21b4d0c..3600b084bca5 100644
--- a/drivers/media/test-drivers/vivid/vivid-touch-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-touch-cap.c
@@ -17,13 +17,13 @@ static int touch_cap_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
unsigned int size = f->sizeimage;
if (*nplanes) {
- if (sizes[0] < size)
+ if (*nplanes != 1)
return -EINVAL;
- } else {
- sizes[0] = size;
+ return sizes[0] < size ? -EINVAL : 0;
}
*nplanes = 1;
+ sizes[0] = size;
return 0;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
index 3840b3a664ac..99138f63585c 100644
--- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
@@ -14,6 +14,7 @@
#include "vivid-kthread-cap.h"
#include "vivid-vbi-cap.h"
#include "vivid-vbi-gen.h"
+#include "vivid-vid-common.h"
static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr)
{
@@ -23,7 +24,7 @@ static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr)
vivid_vbi_gen_sliced(vbi_gen, is_60hz, seqnr);
if (!is_60hz) {
- if (dev->loop_video) {
+ if (vivid_vid_can_loop(dev)) {
if (dev->vbi_out_have_wss) {
vbi_gen->data[12].data[0] = dev->vbi_out_wss[0];
vbi_gen->data[12].data[1] = dev->vbi_out_wss[1];
@@ -47,7 +48,7 @@ static void vivid_sliced_vbi_cap_fill(struct vivid_dev *dev, unsigned seqnr)
break;
}
}
- } else if (dev->loop_video && is_60hz) {
+ } else if (vivid_vid_can_loop(dev) && is_60hz) {
if (dev->vbi_out_have_cc[0]) {
vbi_gen->data[0].data[0] = dev->vbi_out_cc[0][0];
vbi_gen->data[0].data[1] = dev->vbi_out_cc[0][1];
@@ -132,6 +133,8 @@ static int vbi_cap_queue_setup(struct vb2_queue *vq,
if (!vivid_is_sdtv_cap(dev))
return -EINVAL;
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
sizes[0] = size;
*nplanes = 1;
diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-out.c b/drivers/media/test-drivers/vivid/vivid-vbi-out.c
index 434a10676417..871a56d93425 100644
--- a/drivers/media/test-drivers/vivid/vivid-vbi-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-vbi-out.c
@@ -28,6 +28,8 @@ static int vbi_out_queue_setup(struct vb2_queue *vq,
if (!vivid_is_svid_out(dev))
return -EINVAL;
+ if (*nplanes)
+ return sizes[0] < size ? -EINVAL : 0;
sizes[0] = size;
*nplanes = 1;
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
index 2804975fe278..69620e0a35a0 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
@@ -106,8 +106,9 @@ static int vid_cap_queue_setup(struct vb2_queue *vq,
if (*nplanes != buffers)
return -EINVAL;
for (p = 0; p < buffers; p++) {
- if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h +
- dev->fmt_cap->data_offset[p])
+ if (sizes[p] < tpg_g_line_width(&dev->tpg, p) * h /
+ dev->fmt_cap->vdownsampling[p] +
+ dev->fmt_cap->data_offset[p])
return -EINVAL;
}
} else {
@@ -210,9 +211,6 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
unsigned i;
int err;
- if (vb2_is_streaming(&dev->vb_vid_out_q))
- dev->can_loop_video = vivid_vid_can_loop(dev);
-
dev->vid_cap_seq_count = 0;
dprintk(dev, 1, "%s\n", __func__);
for (i = 0; i < VIDEO_MAX_FRAME; i++)
@@ -242,7 +240,6 @@ static void vid_cap_stop_streaming(struct vb2_queue *vq)
dprintk(dev, 1, "%s\n", __func__);
vivid_stop_generating_vid_cap(dev, &dev->vid_cap_streaming);
- dev->can_loop_video = false;
}
static void vid_cap_buf_request_complete(struct vb2_buffer *vb)
@@ -273,7 +270,7 @@ void vivid_update_quality(struct vivid_dev *dev)
{
unsigned freq_modulus;
- if (dev->loop_video && (vivid_is_svid_cap(dev) || vivid_is_hdmi_cap(dev))) {
+ if (dev->input_is_connected_to_output[dev->input]) {
/*
* The 'noise' will only be replaced by the actual video
* if the output video matches the input video settings.
@@ -487,35 +484,35 @@ static enum v4l2_field vivid_field_cap(struct vivid_dev *dev, enum v4l2_field fi
static unsigned vivid_colorspace_cap(struct vivid_dev *dev)
{
- if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ if (!vivid_input_is_connected_to(dev))
return tpg_g_colorspace(&dev->tpg);
return dev->colorspace_out;
}
static unsigned vivid_xfer_func_cap(struct vivid_dev *dev)
{
- if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ if (!vivid_input_is_connected_to(dev))
return tpg_g_xfer_func(&dev->tpg);
return dev->xfer_func_out;
}
static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev)
{
- if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ if (!vivid_input_is_connected_to(dev))
return tpg_g_ycbcr_enc(&dev->tpg);
return dev->ycbcr_enc_out;
}
static unsigned int vivid_hsv_enc_cap(struct vivid_dev *dev)
{
- if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ if (!vivid_input_is_connected_to(dev))
return tpg_g_hsv_enc(&dev->tpg);
return dev->hsv_enc_out;
}
static unsigned vivid_quantization_cap(struct vivid_dev *dev)
{
- if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ if (!vivid_input_is_connected_to(dev))
return tpg_g_quantization(&dev->tpg);
return dev->quantization_out;
}
@@ -1072,13 +1069,13 @@ int vidioc_enum_input(struct file *file, void *priv,
inp->type = V4L2_INPUT_TYPE_CAMERA;
switch (dev->input_type[inp->index]) {
case WEBCAM:
- snprintf(inp->name, sizeof(inp->name), "Webcam %u",
- dev->input_name_counter[inp->index]);
+ snprintf(inp->name, sizeof(inp->name), "Webcam %03u-%u",
+ dev->inst, dev->input_name_counter[inp->index]);
inp->capabilities = 0;
break;
case TV:
- snprintf(inp->name, sizeof(inp->name), "TV %u",
- dev->input_name_counter[inp->index]);
+ snprintf(inp->name, sizeof(inp->name), "TV %03u-%u",
+ dev->inst, dev->input_name_counter[inp->index]);
inp->type = V4L2_INPUT_TYPE_TUNER;
inp->std = V4L2_STD_ALL;
if (dev->has_audio_inputs)
@@ -1086,16 +1083,16 @@ int vidioc_enum_input(struct file *file, void *priv,
inp->capabilities = V4L2_IN_CAP_STD;
break;
case SVID:
- snprintf(inp->name, sizeof(inp->name), "S-Video %u",
- dev->input_name_counter[inp->index]);
+ snprintf(inp->name, sizeof(inp->name), "S-Video %03u-%u",
+ dev->inst, dev->input_name_counter[inp->index]);
inp->std = V4L2_STD_ALL;
if (dev->has_audio_inputs)
inp->audioset = (1 << ARRAY_SIZE(vivid_audio_inputs)) - 1;
inp->capabilities = V4L2_IN_CAP_STD;
break;
case HDMI:
- snprintf(inp->name, sizeof(inp->name), "HDMI %u",
- dev->input_name_counter[inp->index]);
+ snprintf(inp->name, sizeof(inp->name), "HDMI %03u-%u",
+ dev->inst, dev->input_name_counter[inp->index]);
inp->capabilities = V4L2_IN_CAP_DV_TIMINGS;
if (dev->edid_blocks == 0 ||
dev->dv_timings_signal_mode[dev->input] == NO_SIGNAL)
@@ -1537,13 +1534,65 @@ int vidioc_query_dv_timings(struct file *file, void *_fh,
return 0;
}
+void vivid_update_outputs(struct vivid_dev *dev)
+{
+ u32 edid_present = 0;
+
+ if (!dev || !dev->num_outputs)
+ return;
+ for (unsigned int i = 0, j = 0; i < dev->num_outputs; i++) {
+ if (dev->output_type[i] != HDMI)
+ continue;
+
+ struct vivid_dev *dev_rx = dev->output_to_input_instance[i];
+
+ if (dev_rx && dev_rx->edid_blocks)
+ edid_present |= 1 << j;
+ j++;
+ }
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, edid_present);
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, edid_present);
+ v4l2_ctrl_s_ctrl(dev->ctrl_tx_rxsense, edid_present);
+}
+
+void vivid_update_connected_outputs(struct vivid_dev *dev)
+{
+ u16 phys_addr = cec_get_edid_phys_addr(dev->edid, dev->edid_blocks * 128, NULL);
+
+ for (unsigned int i = 0, j = 0; i < dev->num_inputs; i++) {
+ unsigned int menu_idx =
+ dev->input_is_connected_to_output[i];
+
+ if (dev->input_type[i] != HDMI)
+ continue;
+ j++;
+ if (menu_idx < FIXED_MENU_ITEMS)
+ continue;
+
+ struct vivid_dev *dev_tx = vivid_ctrl_hdmi_to_output_instance[menu_idx];
+ unsigned int output = vivid_ctrl_hdmi_to_output_index[menu_idx];
+
+ if (!dev_tx)
+ continue;
+
+ unsigned int hdmi_output = dev_tx->output_to_iface_index[output];
+
+ vivid_update_outputs(dev_tx);
+ if (dev->edid_blocks) {
+ cec_s_phys_addr(dev_tx->cec_tx_adap[hdmi_output],
+ v4l2_phys_addr_for_input(phys_addr, j),
+ false);
+ } else {
+ cec_phys_addr_invalidate(dev_tx->cec_tx_adap[hdmi_output]);
+ }
+ }
+}
+
int vidioc_s_edid(struct file *file, void *_fh,
struct v4l2_edid *edid)
{
struct vivid_dev *dev = video_drvdata(file);
u16 phys_addr;
- u32 display_present = 0;
- unsigned int i, j;
int ret;
memset(edid->reserved, 0, sizeof(edid->reserved));
@@ -1552,11 +1601,11 @@ int vidioc_s_edid(struct file *file, void *_fh,
if (dev->input_type[edid->pad] != HDMI || edid->start_block)
return -EINVAL;
if (edid->blocks == 0) {
+ if (vb2_is_busy(&dev->vb_vid_cap_q))
+ return -EBUSY;
dev->edid_blocks = 0;
- v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, 0);
- v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, 0);
- phys_addr = CEC_PHYS_ADDR_INVALID;
- goto set_phys_addr;
+ vivid_update_connected_outputs(dev);
+ return 0;
}
if (edid->blocks > dev->edid_max_blocks) {
edid->blocks = dev->edid_max_blocks;
@@ -1573,24 +1622,7 @@ int vidioc_s_edid(struct file *file, void *_fh,
dev->edid_blocks = edid->blocks;
memcpy(dev->edid, edid->edid, edid->blocks * 128);
- for (i = 0, j = 0; i < dev->num_outputs; i++)
- if (dev->output_type[i] == HDMI)
- display_present |=
- dev->display_present[i] << j++;
-
- v4l2_ctrl_s_ctrl(dev->ctrl_tx_edid_present, display_present);
- v4l2_ctrl_s_ctrl(dev->ctrl_tx_hotplug, display_present);
-
-set_phys_addr:
- /* TODO: a proper hotplug detect cycle should be emulated here */
- cec_s_phys_addr(dev->cec_rx_adap, phys_addr, false);
-
- for (i = 0; i < MAX_OUTPUTS && dev->cec_tx_adap[i]; i++)
- cec_s_phys_addr(dev->cec_tx_adap[i],
- dev->display_present[i] ?
- v4l2_phys_addr_for_input(phys_addr, i + 1) :
- CEC_PHYS_ADDR_INVALID,
- false);
+ vivid_update_connected_outputs(dev);
return 0;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.h b/drivers/media/test-drivers/vivid/vivid-vid-cap.h
index 949768652d38..7a8daf0af2ca 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.h
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.h
@@ -10,6 +10,8 @@
void vivid_update_quality(struct vivid_dev *dev);
void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls);
+void vivid_update_outputs(struct vivid_dev *dev);
+void vivid_update_connected_outputs(struct vivid_dev *dev);
enum tpg_video_aspect vivid_get_video_aspect(const struct vivid_dev *dev);
extern const v4l2_std_id vivid_standard[];
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-common.c b/drivers/media/test-drivers/vivid/vivid-vid-common.c
index 38d788b5cf19..df7678db67fb 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-common.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-common.c
@@ -769,14 +769,55 @@ const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat)
return NULL;
}
+struct vivid_dev *vivid_output_is_connected_to(struct vivid_dev *dev)
+{
+ struct vivid_dev *input_inst = dev->output_to_input_instance[dev->output];
+
+ if (!input_inst)
+ return NULL;
+ if (input_inst->input != dev->output_to_input_index[dev->output])
+ return NULL;
+ return input_inst;
+}
+
+struct vivid_dev *vivid_input_is_connected_to(struct vivid_dev *dev)
+{
+ s32 connected_output = dev->input_is_connected_to_output[dev->input];
+
+ if (connected_output < FIXED_MENU_ITEMS)
+ return NULL;
+ struct vivid_dev *output_inst = NULL;
+
+ if (vivid_is_hdmi_cap(dev)) {
+ output_inst = vivid_ctrl_hdmi_to_output_instance[connected_output];
+ if (vivid_ctrl_hdmi_to_output_index[connected_output] != output_inst->output)
+ return NULL;
+ return output_inst;
+ } else if (vivid_is_svid_cap(dev)) {
+ output_inst = vivid_ctrl_svid_to_output_instance[connected_output];
+ if (vivid_ctrl_svid_to_output_index[connected_output] != output_inst->output)
+ return NULL;
+ return output_inst;
+ } else {
+ return NULL;
+ }
+ return output_inst;
+}
+
bool vivid_vid_can_loop(struct vivid_dev *dev)
{
- if (dev->src_rect.width != dev->sink_rect.width ||
- dev->src_rect.height != dev->sink_rect.height)
+ struct vivid_dev *output_inst = vivid_input_is_connected_to(dev);
+
+ if (!output_inst)
return false;
- if (dev->fmt_cap->fourcc != dev->fmt_out->fourcc)
+ if (!vb2_is_streaming(&output_inst->vb_vid_out_q))
return false;
- if (dev->field_cap != dev->field_out)
+ if (dev->src_rect.width != output_inst->sink_rect.width ||
+ dev->src_rect.height != output_inst->sink_rect.height)
+ return false;
+ if (dev->fmt_cap->fourcc != output_inst->fmt_out->fourcc)
+ return false;
+ if (dev->field_cap != output_inst->field_out)
return false;
/*
* While this can be supported, it is just too much work
@@ -785,34 +826,34 @@ bool vivid_vid_can_loop(struct vivid_dev *dev)
if (dev->field_cap == V4L2_FIELD_SEQ_TB ||
dev->field_cap == V4L2_FIELD_SEQ_BT)
return false;
- if (vivid_is_svid_cap(dev) && vivid_is_svid_out(dev)) {
- if (!(dev->std_cap[dev->input] & V4L2_STD_525_60) !=
- !(dev->std_out & V4L2_STD_525_60))
- return false;
+ if (vivid_is_hdmi_cap(dev))
return true;
- }
- if (vivid_is_hdmi_cap(dev) && vivid_is_hdmi_out(dev))
- return true;
- return false;
+ if (!(dev->std_cap[dev->input] & V4L2_STD_525_60) !=
+ !(output_inst->std_out & V4L2_STD_525_60))
+ return false;
+ return true;
}
-void vivid_send_source_change(struct vivid_dev *dev, unsigned type)
+void vivid_send_input_source_change(struct vivid_dev *dev, unsigned int input_index)
{
struct v4l2_event ev = {
.type = V4L2_EVENT_SOURCE_CHANGE,
.u.src_change.changes = V4L2_EVENT_SRC_CH_RESOLUTION,
};
- unsigned i;
+ ev.id = input_index;
- for (i = 0; i < dev->num_inputs; i++) {
- ev.id = i;
- if (dev->input_type[i] == type) {
- if (video_is_registered(&dev->vid_cap_dev) && dev->has_vid_cap)
- v4l2_event_queue(&dev->vid_cap_dev, &ev);
- if (video_is_registered(&dev->vbi_cap_dev) && dev->has_vbi_cap)
- v4l2_event_queue(&dev->vbi_cap_dev, &ev);
- }
- }
+ if (video_is_registered(&dev->vid_cap_dev) && dev->has_vid_cap)
+ v4l2_event_queue(&dev->vid_cap_dev, &ev);
+ if (dev->input_type[input_index] == TV || dev->input_type[input_index] == SVID)
+ if (video_is_registered(&dev->vbi_cap_dev) && dev->has_vbi_cap)
+ v4l2_event_queue(&dev->vbi_cap_dev, &ev);
+}
+
+void vivid_send_source_change(struct vivid_dev *dev, unsigned int type)
+{
+ for (int i = 0; i < dev->num_inputs; i++)
+ if (dev->input_type[i] == type)
+ vivid_send_input_source_change(dev, i);
}
/*
@@ -1036,8 +1077,10 @@ int vidioc_g_edid(struct file *file, void *_fh,
struct v4l2_edid *edid)
{
struct vivid_dev *dev = video_drvdata(file);
+ struct vivid_dev *dev_rx = dev;
struct video_device *vdev = video_devdata(file);
struct cec_adapter *adap;
+ unsigned int loc;
memset(edid->reserved, 0, sizeof(edid->reserved));
if (vdev->vfl_dir == VFL_DIR_RX) {
@@ -1047,29 +1090,48 @@ int vidioc_g_edid(struct file *file, void *_fh,
return -EINVAL;
adap = dev->cec_rx_adap;
} else {
- unsigned int bus_idx;
-
if (edid->pad >= dev->num_outputs)
return -EINVAL;
if (dev->output_type[edid->pad] != HDMI)
return -EINVAL;
- if (!dev->display_present[edid->pad])
+ dev_rx = dev->output_to_input_instance[edid->pad];
+ if (!dev_rx)
return -ENODATA;
- bus_idx = dev->cec_output2bus_map[edid->pad];
- adap = dev->cec_tx_adap[bus_idx];
+
+ unsigned int hdmi_output = dev->output_to_iface_index[edid->pad];
+
+ adap = dev->cec_tx_adap[hdmi_output];
}
if (edid->start_block == 0 && edid->blocks == 0) {
- edid->blocks = dev->edid_blocks;
+ edid->blocks = dev_rx->edid_blocks;
return 0;
}
- if (dev->edid_blocks == 0)
+ if (dev_rx->edid_blocks == 0)
return -ENODATA;
- if (edid->start_block >= dev->edid_blocks)
+ if (edid->start_block >= dev_rx->edid_blocks)
return -EINVAL;
- if (edid->blocks > dev->edid_blocks - edid->start_block)
- edid->blocks = dev->edid_blocks - edid->start_block;
- if (adap)
- v4l2_set_edid_phys_addr(dev->edid, dev->edid_blocks * 128, adap->phys_addr);
- memcpy(edid->edid, dev->edid + edid->start_block * 128, edid->blocks * 128);
+ if (edid->blocks > dev_rx->edid_blocks - edid->start_block)
+ edid->blocks = dev_rx->edid_blocks - edid->start_block;
+
+ memcpy(edid->edid, dev_rx->edid + edid->start_block * 128, edid->blocks * 128);
+
+ loc = cec_get_edid_spa_location(dev_rx->edid,
+ dev_rx->edid_blocks * 128);
+ if (vdev->vfl_dir == VFL_DIR_TX && adap && loc &&
+ loc >= edid->start_block * 128 &&
+ loc < (edid->start_block + edid->blocks) * 128) {
+ unsigned int i;
+ u8 sum = 0;
+
+ loc -= edid->start_block * 128;
+ edid->edid[loc] = adap->phys_addr >> 8;
+ edid->edid[loc + 1] = adap->phys_addr & 0xff;
+ loc &= ~0x7f;
+
+ /* update the checksum */
+ for (i = loc; i < loc + 127; i++)
+ sum += edid->edid[i];
+ edid->edid[i] = 256 - sum;
+ }
return 0;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-common.h b/drivers/media/test-drivers/vivid/vivid-vid-common.h
index d908d9725283..c49ac85abaed 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-common.h
+++ b/drivers/media/test-drivers/vivid/vivid-vid-common.h
@@ -22,8 +22,11 @@ extern const struct v4l2_dv_timings_cap vivid_dv_timings_cap;
const struct vivid_fmt *vivid_get_format(struct vivid_dev *dev, u32 pixelformat);
+struct vivid_dev *vivid_input_is_connected_to(struct vivid_dev *dev);
+struct vivid_dev *vivid_output_is_connected_to(struct vivid_dev *dev);
bool vivid_vid_can_loop(struct vivid_dev *dev);
-void vivid_send_source_change(struct vivid_dev *dev, unsigned type);
+void vivid_send_source_change(struct vivid_dev *dev, unsigned int type);
+void vivid_send_input_source_change(struct vivid_dev *dev, unsigned int input_index);
int vivid_vid_adjust_sel(unsigned flags, struct v4l2_rect *r);
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c
index 1653b2988f7e..60327f3612af 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c
@@ -63,14 +63,16 @@ static int vid_out_queue_setup(struct vb2_queue *vq,
if (sizes[0] < size)
return -EINVAL;
for (p = 1; p < planes; p++) {
- if (sizes[p] < dev->bytesperline_out[p] * h +
- vfmt->data_offset[p])
+ if (sizes[p] < dev->bytesperline_out[p] * h /
+ vfmt->vdownsampling[p] +
+ vfmt->data_offset[p])
return -EINVAL;
}
} else {
for (p = 0; p < planes; p++)
- sizes[p] = p ? dev->bytesperline_out[p] * h +
- vfmt->data_offset[p] : size;
+ sizes[p] = p ? dev->bytesperline_out[p] * h /
+ vfmt->vdownsampling[p] +
+ vfmt->data_offset[p] : size;
}
*nplanes = planes;
@@ -124,7 +126,7 @@ static int vid_out_buf_prepare(struct vb2_buffer *vb)
for (p = 0; p < planes; p++) {
if (p)
- size = dev->bytesperline_out[p] * h;
+ size = dev->bytesperline_out[p] * h / vfmt->vdownsampling[p];
size += vb->planes[p].data_offset;
if (vb2_get_plane_payload(vb, p) < size) {
@@ -155,9 +157,6 @@ static int vid_out_start_streaming(struct vb2_queue *vq, unsigned count)
struct vivid_dev *dev = vb2_get_drv_priv(vq);
int err;
- if (vb2_is_streaming(&dev->vb_vid_cap_q))
- dev->can_loop_video = vivid_vid_can_loop(dev);
-
dev->vid_out_seq_count = 0;
dprintk(dev, 1, "%s\n", __func__);
if (dev->start_streaming_error) {
@@ -185,7 +184,6 @@ static void vid_out_stop_streaming(struct vb2_queue *vq)
dprintk(dev, 1, "%s\n", __func__);
vivid_stop_generating_vid_out(dev, &dev->vid_out_streaming);
- dev->can_loop_video = false;
}
static void vid_out_buf_request_complete(struct vb2_buffer *vb)
@@ -331,8 +329,8 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv,
for (p = 0; p < mp->num_planes; p++) {
mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p];
mp->plane_fmt[p].sizeimage =
- mp->plane_fmt[p].bytesperline * mp->height +
- fmt->data_offset[p];
+ mp->plane_fmt[p].bytesperline * mp->height /
+ fmt->vdownsampling[p] + fmt->data_offset[p];
}
for (p = fmt->buffers; p < fmt->planes; p++) {
unsigned stride = dev->bytesperline_out[p];
@@ -562,9 +560,11 @@ set_colorspace:
dev->xfer_func_out = mp->xfer_func;
dev->ycbcr_enc_out = mp->ycbcr_enc;
dev->quantization_out = mp->quantization;
- if (dev->loop_video) {
- vivid_send_source_change(dev, SVID);
- vivid_send_source_change(dev, HDMI);
+ struct vivid_dev *in_dev = vivid_output_is_connected_to(dev);
+
+ if (in_dev) {
+ vivid_send_source_change(in_dev, SVID);
+ vivid_send_source_change(in_dev, HDMI);
}
return 0;
}
@@ -964,16 +964,16 @@ int vidioc_enum_output(struct file *file, void *priv,
out->type = V4L2_OUTPUT_TYPE_ANALOG;
switch (dev->output_type[out->index]) {
case SVID:
- snprintf(out->name, sizeof(out->name), "S-Video %u",
- dev->output_name_counter[out->index]);
+ snprintf(out->name, sizeof(out->name), "S-Video %03u-%u",
+ dev->inst, dev->output_name_counter[out->index]);
out->std = V4L2_STD_ALL;
if (dev->has_audio_outputs)
out->audioset = (1 << ARRAY_SIZE(vivid_audio_outputs)) - 1;
out->capabilities = V4L2_OUT_CAP_STD;
break;
case HDMI:
- snprintf(out->name, sizeof(out->name), "HDMI %u",
- dev->output_name_counter[out->index]);
+ snprintf(out->name, sizeof(out->name), "HDMI %03u-%u",
+ dev->inst, dev->output_name_counter[out->index]);
out->capabilities = V4L2_OUT_CAP_DV_TIMINGS;
break;
}
@@ -1014,11 +1014,6 @@ int vidioc_s_output(struct file *file, void *priv, unsigned o)
dev->meta_out_dev.tvnorms = dev->vid_out_dev.tvnorms;
vivid_update_format_out(dev);
- v4l2_ctrl_activate(dev->ctrl_display_present, vivid_is_hdmi_out(dev));
- if (vivid_is_hdmi_out(dev))
- v4l2_ctrl_s_ctrl(dev->ctrl_display_present,
- dev->display_present[dev->output]);
-
return 0;
}
diff --git a/drivers/media/tuners/tda9887.c b/drivers/media/tuners/tda9887.c
index dca2fc776e44..b2f7054c1832 100644
--- a/drivers/media/tuners/tda9887.c
+++ b/drivers/media/tuners/tda9887.c
@@ -707,4 +707,5 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
}
EXPORT_SYMBOL_GPL(tda9887_attach);
+MODULE_DESCRIPTION("NXP TDA9885/6/7 analog IF demodulator driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/tuner-types.c b/drivers/media/tuners/tuner-types.c
index ff5a6c0acdd4..c26f1296e18f 100644
--- a/drivers/media/tuners/tuner-types.c
+++ b/drivers/media/tuners/tuner-types.c
@@ -1434,6 +1434,22 @@ static struct tuner_params tuner_sony_btf_pg463z_params[] = {
},
};
+/* ------------- TUNER_TENA_TNF_931D_DFDR1 - NXP TDA6509A ------------- */
+
+static struct tuner_range tuner_tena_tnf_931d_dfdr1_ranges[] = {
+ { 16 * 161.15 /*MHz*/, 0x8e, 0x01, },
+ { 16 * 463.15 /*MHz*/, 0x8e, 0x02, },
+ { 16 * 999.99 , 0x8e, 0x08, },
+};
+
+static struct tuner_params tuner_tena_tnf_931d_dfdr1_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_PAL,
+ .ranges = tuner_tena_tnf_931d_dfdr1_ranges,
+ .count = ARRAY_SIZE(tuner_tena_tnf_931d_dfdr1_ranges),
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@@ -1946,6 +1962,11 @@ struct tunertype tuners[] = {
.name = "Silicon Labs Si2157 tuner",
/* see si2157.c for details */
},
+ [TUNER_TENA_TNF_931D_DFDR1] = {
+ .name = "Tena TNF931D-DFDR1",
+ .params = tuner_tena_tnf_931d_dfdr1_params,
+ .count = ARRAY_SIZE(tuner_tena_tnf_931d_dfdr1_params),
+ }
};
EXPORT_SYMBOL(tuners);
diff --git a/drivers/media/tuners/xc2028.c b/drivers/media/tuners/xc2028.c
index 5a967edceca9..352b8a3679b7 100644
--- a/drivers/media/tuners/xc2028.c
+++ b/drivers/media/tuners/xc2028.c
@@ -1361,9 +1361,16 @@ static void load_firmware_cb(const struct firmware *fw,
void *context)
{
struct dvb_frontend *fe = context;
- struct xc2028_data *priv = fe->tuner_priv;
+ struct xc2028_data *priv;
int rc;
+ if (!fe) {
+ pr_warn("xc2028: No frontend in %s\n", __func__);
+ return;
+ }
+
+ priv = fe->tuner_priv;
+
tuner_dbg("request_firmware_nowait(): %s\n", fw ? "OK" : "error");
if (!fw) {
tuner_err("Could not load firmware %s.\n", priv->fname);
diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c
index 90f1aea99dac..8033622543f2 100644
--- a/drivers/media/usb/b2c2/flexcop-usb.c
+++ b/drivers/media/usb/b2c2/flexcop-usb.c
@@ -179,7 +179,7 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
flexcop_usb_request_t req, flexcop_usb_mem_page_t page_start,
u32 addr, int extended, u8 *buf, u32 len)
{
- int i, ret = 0;
+ int ret = 0;
u16 wMax;
u32 pagechunk = 0;
@@ -196,7 +196,7 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
default:
return -EINVAL;
}
- for (i = 0; i < len;) {
+ while (len) {
pagechunk = min(wMax, bytes_left_to_read_on_page(addr, len));
deb_info("%x\n",
(addr & V8_MEMORY_PAGE_MASK) |
@@ -206,11 +206,12 @@ static int flexcop_usb_memory_req(struct flexcop_usb *fc_usb,
page_start + (addr / V8_MEMORY_PAGE_SIZE),
(addr & V8_MEMORY_PAGE_MASK) |
(V8_MEMORY_EXTENDED*extended),
- &buf[i], pagechunk);
+ buf, pagechunk);
if (ret < 0)
return ret;
addr += pagechunk;
+ buf += pagechunk;
len -= pagechunk;
}
return 0;
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 343a4433ed24..abb967c8bd35 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1453,7 +1453,7 @@ static void stop_streaming(struct vb2_queue *vq)
return_all_buffers(dev, VB2_BUF_STATE_ERROR);
}
-static struct vb2_ops cx231xx_video_qops = {
+static const struct vb2_ops cx231xx_video_qops = {
.queue_setup = queue_setup,
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 8f347bbeeb32..435eb0b32cb1 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -795,7 +795,7 @@ static void stop_streaming(struct vb2_queue *vq)
return_all_buffers(dev, VB2_BUF_STATE_ERROR);
}
-static struct vb2_ops cx231xx_video_qops = {
+static const struct vb2_ops cx231xx_video_qops = {
.queue_setup = queue_setup,
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
diff --git a/drivers/media/usb/dvb-usb/dibusb-common.c b/drivers/media/usb/dvb-usb/dibusb-common.c
index aff60c10cb0b..20f1ef3393a5 100644
--- a/drivers/media/usb/dvb-usb/dibusb-common.c
+++ b/drivers/media/usb/dvb-usb/dibusb-common.c
@@ -14,6 +14,7 @@
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info (|-able))." DVB_USB_DEBUG_STATUS);
+MODULE_DESCRIPTION("Common methods for dibusb-based receivers");
MODULE_LICENSE("GPL");
#define deb_info(args...) dprintk(debug,0x01,args)
diff --git a/drivers/media/usb/dvb-usb/dibusb-mc-common.c b/drivers/media/usb/dvb-usb/dibusb-mc-common.c
index b8cde4cded33..36bc7762acf4 100644
--- a/drivers/media/usb/dvb-usb/dibusb-mc-common.c
+++ b/drivers/media/usb/dvb-usb/dibusb-mc-common.c
@@ -8,6 +8,7 @@
#include "dibusb.h"
+MODULE_DESCRIPTION("Common methods for DIB3000MC");
MODULE_LICENSE("GPL");
/* 3000MC/P stuff */
diff --git a/drivers/media/usb/dvb-usb/dvb-usb-init.c b/drivers/media/usb/dvb-usb/dvb-usb-init.c
index fbf58012becd..22d83ac18eb7 100644
--- a/drivers/media/usb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/usb/dvb-usb/dvb-usb-init.c
@@ -23,11 +23,40 @@ static int dvb_usb_force_pid_filter_usage;
module_param_named(force_pid_filter_usage, dvb_usb_force_pid_filter_usage, int, 0444);
MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID filter, if any (default: 0).");
+static int dvb_usb_check_bulk_endpoint(struct dvb_usb_device *d, u8 endpoint)
+{
+ if (endpoint) {
+ int ret;
+
+ ret = usb_pipe_type_check(d->udev, usb_sndbulkpipe(d->udev, endpoint));
+ if (ret)
+ return ret;
+ ret = usb_pipe_type_check(d->udev, usb_rcvbulkpipe(d->udev, endpoint));
+ if (ret)
+ return ret;
+ }
+ return 0;
+}
+
+static void dvb_usb_clear_halt(struct dvb_usb_device *d, u8 endpoint)
+{
+ if (endpoint) {
+ usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, endpoint));
+ usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, endpoint));
+ }
+}
+
static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
{
struct dvb_usb_adapter *adap;
int ret, n, o;
+ ret = dvb_usb_check_bulk_endpoint(d, d->props.generic_bulk_ctrl_endpoint);
+ if (ret)
+ return ret;
+ ret = dvb_usb_check_bulk_endpoint(d, d->props.generic_bulk_ctrl_endpoint_response);
+ if (ret)
+ return ret;
for (n = 0; n < d->props.num_adapters; n++) {
adap = &d->adapter[n];
adap->dev = d;
@@ -103,10 +132,8 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
* when reloading the driver w/o replugging the device
* sometimes a timeout occurs, this helps
*/
- if (d->props.generic_bulk_ctrl_endpoint != 0) {
- usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
- usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
- }
+ dvb_usb_clear_halt(d, d->props.generic_bulk_ctrl_endpoint);
+ dvb_usb_clear_halt(d, d->props.generic_bulk_ctrl_endpoint_response);
return 0;
diff --git a/drivers/media/usb/dvb-usb/opera1.c b/drivers/media/usb/dvb-usb/opera1.c
index d269f8bb2dee..268f05fc8691 100644
--- a/drivers/media/usb/dvb-usb/opera1.c
+++ b/drivers/media/usb/dvb-usb/opera1.c
@@ -32,10 +32,6 @@
struct opera1_state {
u32 last_key_pressed;
};
-struct rc_map_opera_table {
- u32 keycode;
- u32 event;
-};
static int dvb_usb_opera1_debug;
module_param_named(debug, dvb_usb_opera1_debug, int, 0644);
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index bae76023cf71..a51cbcf429e1 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -555,6 +555,30 @@ static struct em28xx_reg_seq hauppauge_usb_quadhd_atsc_reg_seq[] = {
};
/*
+ * MyGica USB TV Box
+ * GPIO_1,0: 00=Composite audio
+ * 01=Tuner audio
+ * 10=Mute audio
+ * 11=FM radio? (if equipped)
+ * GPIO_2-6: Unused
+ * GPIO_7: ??
+ */
+static const struct em28xx_reg_seq mygica_utv3_composite_audio_gpio[] = {
+ {EM2820_R08_GPIO_CTRL, 0xfc, 0xff, 0},
+ { -1, -1, -1, -1},
+};
+
+static const struct em28xx_reg_seq mygica_utv3_tuner_audio_gpio[] = {
+ {EM2820_R08_GPIO_CTRL, 0xfd, 0xff, 0},
+ { -1, -1, -1, -1},
+};
+
+static const struct em28xx_reg_seq mygica_utv3_suspend_gpio[] = {
+ {EM2820_R08_GPIO_CTRL, 0xfe, 0xff, 0},
+ { -1, -1, -1, -1},
+};
+
+/*
* Button definitions
*/
static const struct em28xx_button std_snapshot_button[] = {
@@ -2578,6 +2602,32 @@ const struct em28xx_board em28xx_boards[] = {
.tuner_gpio = hauppauge_usb_quadhd_atsc_reg_seq,
.leds = hauppauge_usb_quadhd_leds,
},
+ /*
+ * eb1a:2860 MyGica UTV3 Analog USB2.0 TV Box
+ * Empia EM2860, Philips SAA7113, NXP TDA9801T demod,
+ * Tena TNF931D-DFDR1 tuner (contains NXP TDA6509A),
+ * ST HCF4052 demux (switches audio to line out),
+ * no audio over USB
+ */
+ [EM2860_BOARD_MYGICA_UTV3] = {
+ .name = "MyGica UTV3 Analog USB2.0 TV Box",
+ .xclk = EM28XX_XCLK_IR_RC5_MODE | EM28XX_XCLK_FREQUENCY_12MHZ,
+ .tuner_type = TUNER_TENA_TNF_931D_DFDR1,
+ .ir_codes = RC_MAP_MYGICA_UTV3,
+ .decoder = EM28XX_SAA711X,
+ .suspend_gpio = mygica_utv3_suspend_gpio,
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = mygica_utv3_composite_audio_gpio,
+ }, {
+ .type = EM28XX_VMUX_TELEVISION,
+ .vmux = SAA7115_COMPOSITE2,
+ .amux = EM28XX_AMUX_VIDEO,
+ .gpio = mygica_utv3_tuner_audio_gpio,
+ } },
+ },
};
EXPORT_SYMBOL_GPL(em28xx_boards);
@@ -2819,6 +2869,7 @@ static const struct em28xx_hash_table em28xx_eeprom_hash[] = {
{0x63f653bd, EM2870_BOARD_REDDO_DVB_C_USB_BOX, TUNER_ABSENT},
{0x4e913442, EM2882_BOARD_DIKOM_DK300, TUNER_XC2028},
{0x85dd871e, EM2882_BOARD_ZOLID_HYBRID_TV_STICK, TUNER_XC2028},
+ {0x8f597549, EM2860_BOARD_MYGICA_UTV3, TUNER_TENA_TNF_931D_DFDR1},
};
/* I2C devicelist hash table for devices with generic USB IDs */
@@ -2831,6 +2882,7 @@ static const struct em28xx_hash_table em28xx_i2c_hash[] = {
{0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
{0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT},
{0x27e10080, EM2882_BOARD_ZOLID_HYBRID_TV_STICK, TUNER_XC2028},
+ {0x840d0484, EM2860_BOARD_MYGICA_UTV3, TUNER_TENA_TNF_931D_DFDR1},
};
/* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 61d7bf701d57..29a7f3f19b56 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -416,8 +416,9 @@ int em28xx_audio_analog_set(struct em28xx *dev)
int ret, i;
u8 xclk;
+ /* Set GPIOs here for boards without audio */
if (dev->int_audio_type == EM28XX_INT_AUDIO_NONE)
- return 0;
+ return em28xx_gpio_set(dev, INPUT(dev->ctl_input)->gpio);
/*
* It is assumed that all devices use master volume for output.
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index db18dd814a67..f3449c240d21 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -143,6 +143,7 @@
#define EM28178_BOARD_PCTV_461E_V2 104
#define EM2860_BOARD_MYGICA_IGRABBER 105
#define EM2874_BOARD_HAUPPAUGE_USB_QUADHD 106
+#define EM2860_BOARD_MYGICA_UTV3 107
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c
index eb03f98b2ef1..468406302cd5 100644
--- a/drivers/media/usb/go7007/go7007-driver.c
+++ b/drivers/media/usb/go7007/go7007-driver.c
@@ -736,4 +736,5 @@ void go7007_update_board(struct go7007 *go)
}
EXPORT_SYMBOL(go7007_update_board);
+MODULE_DESCRIPTION("WIS GO7007 MPEG encoder support");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/usb/go7007/go7007-i2c.c b/drivers/media/usb/go7007/go7007-i2c.c
index 2880370e45c8..f6ce28a4a768 100644
--- a/drivers/media/usb/go7007/go7007-i2c.c
+++ b/drivers/media/usb/go7007/go7007-i2c.c
@@ -33,7 +33,21 @@
/* There is only one I2C port on the TW2804 that feeds all four GO7007 VIPs
* on the Adlink PCI-MPG24, so access is shared between all of them. */
-static DEFINE_MUTEX(adlink_mpg24_i2c_lock);
+static DEFINE_MUTEX(adlink_mpg24_i2c_mutex);
+
+static inline void adlink_mpg24_i2c_lock(struct go7007 *go)
+{
+ /* Bridge the I2C port on this GO7007 to the shared bus */
+ mutex_lock(&adlink_mpg24_i2c_mutex);
+ go7007_write_addr(go, 0x3c82, 0x0020);
+}
+
+static inline void adlink_mpg24_i2c_unlock(struct go7007 *go)
+{
+ /* Isolate the I2C port on this GO7007 from the shared bus */
+ go7007_write_addr(go, 0x3c82, 0x0000);
+ mutex_unlock(&adlink_mpg24_i2c_mutex);
+}
static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read,
u16 command, int flags, u8 *data)
@@ -56,11 +70,8 @@ static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read,
mutex_lock(&go->hw_lock);
- if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
- /* Bridge the I2C port on this GO7007 to the shared bus */
- mutex_lock(&adlink_mpg24_i2c_lock);
- go7007_write_addr(go, 0x3c82, 0x0020);
- }
+ if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
+ adlink_mpg24_i2c_lock(go);
/* Wait for I2C adapter to be ready */
for (i = 0; i < 10; ++i) {
@@ -116,11 +127,8 @@ static int go7007_i2c_xfer(struct go7007 *go, u16 addr, int read,
ret = 0;
i2c_done:
- if (go->board_id == GO7007_BOARDID_ADLINK_MPG24) {
- /* Isolate the I2C port on this GO7007 from the shared bus */
- go7007_write_addr(go, 0x3c82, 0x0000);
- mutex_unlock(&adlink_mpg24_i2c_lock);
- }
+ if (go->board_id == GO7007_BOARDID_ADLINK_MPG24)
+ adlink_mpg24_i2c_unlock(go);
mutex_unlock(&go->hw_lock);
return ret;
}
diff --git a/drivers/media/usb/go7007/go7007-usb.c b/drivers/media/usb/go7007/go7007-usb.c
index 762c13e49bfa..334cdde81a5c 100644
--- a/drivers/media/usb/go7007/go7007-usb.c
+++ b/drivers/media/usb/go7007/go7007-usb.c
@@ -1352,4 +1352,5 @@ static struct usb_driver go7007_usb_driver = {
};
module_usb_driver(go7007_usb_driver);
+MODULE_DESCRIPTION("WIS GO7007 USB support");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
index 84cfb5ce8b8d..81d711269ab5 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-debugifc.c
@@ -9,11 +9,6 @@
#include "pvrusb2-hdw.h"
#include "pvrusb2-debug.h"
-struct debugifc_mask_item {
- const char *name;
- unsigned long msk;
-};
-
static unsigned int debugifc_count_whitespace(const char *buf,
unsigned int count)
diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
index 79faa2560613..b4575fe89c95 100644
--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -19,6 +19,7 @@
#include <linux/input.h>
#include <linux/mutex.h>
+#include <linux/workqueue.h>
#include <media/dmxdev.h>
#include <media/dvb_demux.h>
@@ -139,7 +140,7 @@ struct ttusb_dec {
int v_pes_postbytes;
struct list_head urb_frame_list;
- struct tasklet_struct urb_tasklet;
+ struct work_struct urb_bh_work;
spinlock_t urb_frame_list_lock;
struct dvb_demux_filter *audio_filter;
@@ -766,9 +767,9 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b,
}
}
-static void ttusb_dec_process_urb_frame_list(struct tasklet_struct *t)
+static void ttusb_dec_process_urb_frame_list(struct work_struct *t)
{
- struct ttusb_dec *dec = from_tasklet(dec, t, urb_tasklet);
+ struct ttusb_dec *dec = from_work(dec, t, urb_bh_work);
struct list_head *item;
struct urb_frame *frame;
unsigned long flags;
@@ -822,7 +823,7 @@ static void ttusb_dec_process_urb(struct urb *urb)
spin_unlock_irqrestore(&dec->urb_frame_list_lock,
flags);
- tasklet_schedule(&dec->urb_tasklet);
+ queue_work(system_bh_wq, &dec->urb_bh_work);
}
}
} else {
@@ -1198,11 +1199,11 @@ static int ttusb_dec_alloc_iso_urbs(struct ttusb_dec *dec)
return 0;
}
-static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
+static void ttusb_dec_init_bh_work(struct ttusb_dec *dec)
{
spin_lock_init(&dec->urb_frame_list_lock);
INIT_LIST_HEAD(&dec->urb_frame_list);
- tasklet_setup(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list);
+ INIT_WORK(&dec->urb_bh_work, ttusb_dec_process_urb_frame_list);
}
static int ttusb_init_rc( struct ttusb_dec *dec)
@@ -1588,12 +1589,12 @@ static void ttusb_dec_exit_usb(struct ttusb_dec *dec)
ttusb_dec_free_iso_urbs(dec);
}
-static void ttusb_dec_exit_tasklet(struct ttusb_dec *dec)
+static void ttusb_dec_exit_bh_work(struct ttusb_dec *dec)
{
struct list_head *item;
struct urb_frame *frame;
- tasklet_kill(&dec->urb_tasklet);
+ cancel_work_sync(&dec->urb_bh_work);
while ((item = dec->urb_frame_list.next) != &dec->urb_frame_list) {
frame = list_entry(item, struct urb_frame, urb_frame_list);
@@ -1703,7 +1704,7 @@ static int ttusb_dec_probe(struct usb_interface *intf,
ttusb_dec_init_v_pes(dec);
ttusb_dec_init_filters(dec);
- ttusb_dec_init_tasklet(dec);
+ ttusb_dec_init_bh_work(dec);
dec->active = 1;
@@ -1729,7 +1730,7 @@ static void ttusb_dec_disconnect(struct usb_interface *intf)
dprintk("%s\n", __func__);
if (dec->active) {
- ttusb_dec_exit_tasklet(dec);
+ ttusb_dec_exit_bh_work(dec);
ttusb_dec_exit_filters(dec);
if(enable_rc)
ttusb_dec_exit_rc(dec);
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index 4b685f883e4d..0136df5732ba 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -459,6 +459,94 @@ static void uvc_ctrl_set_rel_speed(struct uvc_control_mapping *mapping,
data[first+1] = min_t(int, abs(value), 0xff);
}
+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_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ),
+};
+
+static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_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_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
+};
+
+static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_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_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
+};
+
+static const struct uvc_control_mapping *uvc_ctrl_filter_plf_mapping(
+ struct uvc_video_chain *chain, struct uvc_control *ctrl)
+{
+ const struct uvc_control_mapping *out_mapping =
+ &uvc_ctrl_power_line_mapping_uvc11;
+ u8 *buf __free(kfree) = NULL;
+ u8 init_val;
+ int ret;
+
+ buf = kmalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return NULL;
+
+ /* Save the current PLF value, so we can restore it. */
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+ /* If we cannot read the control skip it. */
+ if (ret)
+ return NULL;
+ init_val = *buf;
+
+ /* If PLF value cannot be set to off, it is limited. */
+ *buf = V4L2_CID_POWER_LINE_FREQUENCY_DISABLED;
+ ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+ if (ret)
+ return &uvc_ctrl_power_line_mapping_limited;
+
+ /* UVC 1.1 does not define auto, we can exit. */
+ if (chain->dev->uvc_version < 0x150)
+ goto end;
+
+ /* Check if the device supports auto. */
+ *buf = V4L2_CID_POWER_LINE_FREQUENCY_AUTO;
+ ret = uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+ if (!ret)
+ out_mapping = &uvc_ctrl_power_line_mapping_uvc15;
+
+end:
+ /* Restore initial value and add mapping. */
+ *buf = init_val;
+ uvc_query_ctrl(chain->dev, UVC_SET_CUR, ctrl->entity->id,
+ chain->dev->intfnum, ctrl->info.selector,
+ buf, sizeof(*buf));
+
+ return out_mapping;
+}
+
static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
{
.id = V4L2_CID_BRIGHTNESS,
@@ -748,52 +836,11 @@ static const struct uvc_control_mapping uvc_ctrl_mappings[] = {
.v4l2_type = V4L2_CTRL_TYPE_BOOLEAN,
.data_type = UVC_CTRL_DATA_TYPE_BOOLEAN,
},
-};
-
-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_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
- V4L2_CID_POWER_LINE_FREQUENCY_50HZ),
-};
-
-const struct uvc_control_mapping uvc_ctrl_power_line_mapping_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_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_60HZ,
- V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
-};
-
-static const struct uvc_control_mapping *uvc_ctrl_mappings_uvc11[] = {
- &uvc_ctrl_power_line_mapping_uvc11,
- NULL, /* Sentinel */
-};
-
-static const struct uvc_control_mapping uvc_ctrl_power_line_mapping_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_mask = GENMASK(V4L2_CID_POWER_LINE_FREQUENCY_AUTO,
- V4L2_CID_POWER_LINE_FREQUENCY_DISABLED),
-};
-
-static const struct uvc_control_mapping *uvc_ctrl_mappings_uvc15[] = {
- &uvc_ctrl_power_line_mapping_uvc15,
- NULL, /* Sentinel */
+ {
+ .entity = UVC_GUID_UVC_PROCESSING,
+ .selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
+ .filter_mapping = uvc_ctrl_filter_plf_mapping,
+ },
};
/* ------------------------------------------------------------------------
@@ -2031,7 +2078,13 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
else
ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
dev->intfnum, info->selector, data, 1);
- if (!ret)
+
+ if (!ret) {
+ info->flags &= ~(UVC_CTRL_FLAG_GET_CUR |
+ UVC_CTRL_FLAG_SET_CUR |
+ UVC_CTRL_FLAG_AUTO_UPDATE |
+ UVC_CTRL_FLAG_ASYNCHRONOUS);
+
info->flags |= (data[0] & UVC_CONTROL_CAP_GET ?
UVC_CTRL_FLAG_GET_CUR : 0)
| (data[0] & UVC_CONTROL_CAP_SET ?
@@ -2040,6 +2093,7 @@ static int uvc_ctrl_get_flags(struct uvc_device *dev,
UVC_CTRL_FLAG_AUTO_UPDATE : 0)
| (data[0] & UVC_CONTROL_CAP_ASYNCHRONOUS ?
UVC_CTRL_FLAG_ASYNCHRONOUS : 0);
+ }
kfree(data);
return ret;
@@ -2591,7 +2645,6 @@ static void uvc_ctrl_prune_entity(struct uvc_device *dev,
static void uvc_ctrl_init_ctrl(struct uvc_video_chain *chain,
struct uvc_control *ctrl)
{
- const struct uvc_control_mapping **mappings;
unsigned int i;
/*
@@ -2623,46 +2676,16 @@ 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;
-
- for (i = 0; chain->dev->info->mappings[i]; ++i) {
- const struct uvc_control_mapping *mapping =
- chain->dev->info->mappings[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. */
+ /* Process common mappings. */
for (i = 0; i < ARRAY_SIZE(uvc_ctrl_mappings); ++i) {
const struct uvc_control_mapping *mapping = &uvc_ctrl_mappings[i];
- 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. */
- mappings = chain->dev->uvc_version < 0x0150
- ? uvc_ctrl_mappings_uvc11 : uvc_ctrl_mappings_uvc15;
-
- for (i = 0; mappings[i]; ++i) {
- const struct uvc_control_mapping *mapping = mappings[i];
+ /* Let the device provide a custom mapping. */
+ if (mapping->filter_mapping) {
+ mapping = mapping->filter_mapping(chain, ctrl);
+ if (!mapping)
+ continue;
+ }
if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
ctrl->info.selector == mapping->selector)
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 8fe24c98087e..f0febdc08c2d 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -687,16 +687,26 @@ static int uvc_parse_streaming(struct uvc_device *dev,
goto error;
}
- size = nformats * sizeof(*format) + nframes * sizeof(*frame)
+ /*
+ * Allocate memory for the formats, the frames and the intervals,
+ * plus any required padding to guarantee that everything has the
+ * correct alignment.
+ */
+ size = nformats * sizeof(*format);
+ size = ALIGN(size, __alignof__(*frame)) + nframes * sizeof(*frame);
+ size = ALIGN(size, __alignof__(*interval))
+ nintervals * sizeof(*interval);
+
format = kzalloc(size, GFP_KERNEL);
- if (format == NULL) {
+ if (!format) {
ret = -ENOMEM;
goto error;
}
- frame = (struct uvc_frame *)&format[nformats];
- interval = (u32 *)&frame[nframes];
+ frame = (void *)format + nformats * sizeof(*format);
+ frame = PTR_ALIGN(frame, __alignof__(*frame));
+ interval = (void *)frame + nframes * sizeof(*frame);
+ interval = PTR_ALIGN(interval, __alignof__(*interval));
streaming->formats = format;
streaming->nformats = 0;
@@ -2390,20 +2400,6 @@ MODULE_PARM_DESC(timeout, "Streaming control requests timeout");
* Driver initialization and cleanup
*/
-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_ctrl_power_line_uvc11 = {
- .mappings = (const struct uvc_control_mapping *[]) {
- &uvc_ctrl_power_line_mapping_uvc11,
- NULL, /* Sentinel */
- },
-};
-
static const struct uvc_device_info uvc_quirk_probe_minmax = {
.quirks = UVC_QUIRK_PROBE_MINMAX,
};
@@ -2434,33 +2430,17 @@ 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 */
+ /* Quanta ACER HD User Facing */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0408,
- .idProduct = 0x4034,
+ .idProduct = 0x4035,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = UVC_PC_PROTOCOL_15,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
+ .driver_info = (kernel_ulong_t)&(const struct uvc_device_info){
+ .uvc_version = 0x010a,
+ } },
/* LogiLink Wireless Webcam */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2580,7 +2560,17 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
- .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTORE_CTRLS_ON_INIT) },
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_RESTORE_CTRLS_ON_INIT
+ | UVC_QUIRK_INVALID_DEVICE_SOF) },
+ /* Logitech HD Pro Webcam C922 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x046d,
+ .idProduct = 0x085c,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_INFO_QUIRK(UVC_QUIRK_INVALID_DEVICE_SOF) },
/* Logitech Rally Bar Huddle */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2617,42 +2607,6 @@ 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 Electronics Co., Ltd Integrated Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x04f2,
- .idProduct = 0xb67c,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 },
- /* 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,
@@ -3037,15 +2991,6 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_FORCE_BPP) },
- /* SunplusIT Inc HD Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x2b7e,
- .idProduct = 0xb752,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 },
/* Insta360 Link */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -3055,51 +3000,6 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_DISABLE_AUTOSUSPEND) },
- /* Lenovo Integrated Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x30c9,
- .idProduct = 0x0093,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 },
- /* Sonix Technology USB 2.0 Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x3277,
- .idProduct = 0x0072,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
- /* Shine-Optics Integrated Camera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x3277,
- .idProduct = 0x009e,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_uvc11 },
- /* 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 },
- /* Acer EasyCamera */
- { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
- | USB_DEVICE_ID_MATCH_INT_INFO,
- .idVendor = 0x5986,
- .idProduct = 0x1180,
- .bInterfaceClass = USB_CLASS_VIDEO,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 0,
- .driver_info = (kernel_ulong_t)&uvc_ctrl_power_line_limited },
/* Intel D410/ASR depth camera */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index 7cbf4692bd87..cd9c29532fb0 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -214,13 +214,13 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
* 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
- * (assumed to be 12 bytes long).
+ * high- and super-speed devices) per second and add the UVC
+ * header size (assumed to be 12 bytes long).
*/
bandwidth = frame->wWidth * frame->wHeight / 8 * format->bpp;
bandwidth *= 10000000 / interval + 1;
bandwidth /= 1000;
- if (stream->dev->udev->speed == USB_SPEED_HIGH)
+ if (stream->dev->udev->speed >= USB_SPEED_HIGH)
bandwidth /= 8;
bandwidth += 12;
@@ -466,18 +466,49 @@ static inline ktime_t uvc_video_get_time(void)
return ktime_get_real();
}
+static void uvc_video_clock_add_sample(struct uvc_clock *clock,
+ const struct uvc_clock_sample *sample)
+{
+ unsigned long flags;
+
+ /*
+ * If we write new data on the position where we had the last
+ * overflow, remove the overflow pointer. There is no SOF overflow
+ * in the whole circular buffer.
+ */
+ if (clock->head == clock->last_sof_overflow)
+ clock->last_sof_overflow = -1;
+
+ spin_lock_irqsave(&clock->lock, flags);
+
+ if (clock->count > 0 && clock->last_sof > sample->dev_sof) {
+ /*
+ * Remove data from the circular buffer that is older than the
+ * last SOF overflow. We only support one SOF overflow per
+ * circular buffer.
+ */
+ if (clock->last_sof_overflow != -1)
+ clock->count = (clock->head - clock->last_sof_overflow
+ + clock->size) % clock->size;
+ clock->last_sof_overflow = clock->head;
+ }
+
+ /* Add sample. */
+ clock->samples[clock->head] = *sample;
+ clock->head = (clock->head + 1) % clock->size;
+ clock->count = min(clock->count + 1, clock->size);
+
+ spin_unlock_irqrestore(&clock->lock, flags);
+}
+
static void
uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
const u8 *data, int len)
{
- struct uvc_clock_sample *sample;
+ struct uvc_clock_sample sample;
unsigned int header_size;
bool has_pts = false;
bool has_scr = false;
- unsigned long flags;
- ktime_t time;
- u16 host_sof;
- u16 dev_sof;
switch (data[1] & (UVC_STREAM_PTS | UVC_STREAM_SCR)) {
case UVC_STREAM_PTS | UVC_STREAM_SCR:
@@ -522,14 +553,51 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
* all the data packets of the same frame contains the same SOF. In that
* case only the first one will match the host_sof.
*/
- dev_sof = get_unaligned_le16(&data[header_size - 2]);
- if (dev_sof == stream->clock.last_sof)
+ sample.dev_sof = get_unaligned_le16(&data[header_size - 2]);
+ if (sample.dev_sof == stream->clock.last_sof)
return;
- stream->clock.last_sof = dev_sof;
+ sample.dev_stc = get_unaligned_le32(&data[header_size - 6]);
- host_sof = usb_get_current_frame_number(stream->dev->udev);
- time = uvc_video_get_time();
+ /*
+ * STC (Source Time Clock) is the clock used by the camera. The UVC 1.5
+ * standard states that it "must be captured when the first video data
+ * of a video frame is put on the USB bus". This is generally understood
+ * as requiring devices to clear the payload header's SCR bit before
+ * the first packet containing video data.
+ *
+ * Most vendors follow that interpretation, but some (namely SunplusIT
+ * on some devices) always set the `UVC_STREAM_SCR` bit, fill the SCR
+ * field with 0's,and expect that the driver only processes the SCR if
+ * there is data in the packet.
+ *
+ * Ignore all the hardware timestamp information if we haven't received
+ * any data for this frame yet, the packet contains no data, and both
+ * STC and SOF are zero. This heuristics should be safe on compliant
+ * devices. This should be safe with compliant devices, as in the very
+ * unlikely case where a UVC 1.1 device would send timing information
+ * only before the first packet containing data, and both STC and SOF
+ * happen to be zero for a particular frame, we would only miss one
+ * clock sample from many and the clock recovery algorithm wouldn't
+ * suffer from this condition.
+ */
+ if (buf && buf->bytesused == 0 && len == header_size &&
+ sample.dev_stc == 0 && sample.dev_sof == 0)
+ return;
+
+ sample.host_sof = usb_get_current_frame_number(stream->dev->udev);
+
+ /*
+ * On some devices, like the Logitech C922, the device SOF does not run
+ * at a stable rate of 1kHz. For those devices use the host SOF instead.
+ * In the tests performed so far, this improves the timestamp precision.
+ * This is probably explained by a small packet handling jitter from the
+ * host, but the exact reason hasn't been fully determined.
+ */
+ if (stream->dev->quirks & UVC_QUIRK_INVALID_DEVICE_SOF)
+ sample.dev_sof = sample.host_sof;
+
+ sample.host_time = uvc_video_get_time();
/*
* The UVC specification allows device implementations that can't obtain
@@ -552,46 +620,29 @@ uvc_video_clock_decode(struct uvc_streaming *stream, struct uvc_buffer *buf,
* the 8 LSBs of the delta are kept.
*/
if (stream->clock.sof_offset == (u16)-1) {
- u16 delta_sof = (host_sof - dev_sof) & 255;
+ u16 delta_sof = (sample.host_sof - sample.dev_sof) & 255;
if (delta_sof >= 10)
stream->clock.sof_offset = delta_sof;
else
stream->clock.sof_offset = 0;
}
- dev_sof = (dev_sof + stream->clock.sof_offset) & 2047;
-
- spin_lock_irqsave(&stream->clock.lock, flags);
-
- sample = &stream->clock.samples[stream->clock.head];
- sample->dev_stc = get_unaligned_le32(&data[header_size - 6]);
- sample->dev_sof = dev_sof;
- sample->host_sof = host_sof;
- sample->host_time = time;
-
- /* Update the sliding window head and count. */
- stream->clock.head = (stream->clock.head + 1) % stream->clock.size;
-
- if (stream->clock.count < stream->clock.size)
- stream->clock.count++;
-
- spin_unlock_irqrestore(&stream->clock.lock, flags);
+ sample.dev_sof = (sample.dev_sof + stream->clock.sof_offset) & 2047;
+ uvc_video_clock_add_sample(&stream->clock, &sample);
+ stream->clock.last_sof = sample.dev_sof;
}
-static void uvc_video_clock_reset(struct uvc_streaming *stream)
+static void uvc_video_clock_reset(struct uvc_clock *clock)
{
- struct uvc_clock *clock = &stream->clock;
-
clock->head = 0;
clock->count = 0;
clock->last_sof = -1;
+ clock->last_sof_overflow = -1;
clock->sof_offset = -1;
}
-static int uvc_video_clock_init(struct uvc_streaming *stream)
+static int uvc_video_clock_init(struct uvc_clock *clock)
{
- struct uvc_clock *clock = &stream->clock;
-
spin_lock_init(&clock->lock);
clock->size = 32;
@@ -600,15 +651,15 @@ static int uvc_video_clock_init(struct uvc_streaming *stream)
if (clock->samples == NULL)
return -ENOMEM;
- uvc_video_clock_reset(stream);
+ uvc_video_clock_reset(clock);
return 0;
}
-static void uvc_video_clock_cleanup(struct uvc_streaming *stream)
+static void uvc_video_clock_cleanup(struct uvc_clock *clock)
{
- kfree(stream->clock.samples);
- stream->clock.samples = NULL;
+ kfree(clock->samples);
+ clock->samples = NULL;
}
/*
@@ -709,11 +760,11 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
unsigned long flags;
u64 timestamp;
u32 delta_stc;
- u32 y1, y2;
+ u32 y1;
u32 x1, x2;
u32 mean;
u32 sof;
- u64 y;
+ u64 y, y2;
if (!uvc_hw_timestamps_param)
return;
@@ -728,11 +779,11 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
spin_lock_irqsave(&clock->lock, flags);
- if (clock->count < clock->size)
+ if (clock->count < 2)
goto done;
- first = &clock->samples[clock->head];
- last = &clock->samples[(clock->head - 1) % clock->size];
+ first = &clock->samples[(clock->head - clock->count + clock->size) % clock->size];
+ last = &clock->samples[(clock->head - 1 + clock->size) % clock->size];
/* First step, PTS to SOF conversion. */
delta_stc = buf->pts - (1UL << 31);
@@ -746,6 +797,18 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
if (y2 < y1)
y2 += 2048 << 16;
+ /*
+ * Have at least 1/4 of a second of timestamps before we
+ * try to do any calculation. Otherwise we do not have enough
+ * precision. This value was determined by running Android CTS
+ * on different devices.
+ *
+ * dev_sof runs at 1KHz, and we have a fixed point precision of
+ * 16 bits.
+ */
+ if ((y2 - y1) < ((1000 / 4) << 16))
+ goto done;
+
y = (u64)(y2 - y1) * (1ULL << 31) + (u64)y1 * (u64)x2
- (u64)y2 * (u64)x1;
y = div_u64(y, x2 - x1);
@@ -753,7 +816,7 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
sof = y;
uvc_dbg(stream->dev, CLOCK,
- "%s: PTS %u y %llu.%06llu SOF %u.%06llu (x1 %u x2 %u y1 %u y2 %u SOF offset %u)\n",
+ "%s: PTS %u y %llu.%06llu SOF %u.%06llu (x1 %u x2 %u y1 %u y2 %llu SOF offset %u)\n",
stream->dev->name, buf->pts,
y >> 16, div_u64((y & 0xffff) * 1000000, 65536),
sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
@@ -768,7 +831,7 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
goto done;
y1 = NSEC_PER_SEC;
- y2 = (u32)ktime_to_ns(ktime_sub(last->host_time, first->host_time)) + y1;
+ y2 = ktime_to_ns(ktime_sub(last->host_time, first->host_time)) + y1;
/*
* Interpolated and host SOF timestamps can wrap around at slightly
@@ -789,7 +852,7 @@ void uvc_video_clock_update(struct uvc_streaming *stream,
timestamp = ktime_to_ns(first->host_time) + y - y1;
uvc_dbg(stream->dev, CLOCK,
- "%s: SOF %u.%06llu y %llu ts %llu buf ts %llu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %u)\n",
+ "%s: SOF %u.%06llu y %llu ts %llu buf ts %llu (x1 %u/%u/%u x2 %u/%u/%u y1 %u y2 %llu)\n",
stream->dev->name,
sof >> 16, div_u64(((u64)sof & 0xffff) * 1000000LLU, 65536),
y, timestamp, vbuf->vb2_buf.timestamp,
@@ -2071,7 +2134,7 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset)
stream->frozen = 0;
- uvc_video_clock_reset(stream);
+ uvc_video_clock_reset(&stream->clock);
if (!uvc_queue_streaming(&stream->queue))
return 0;
@@ -2220,7 +2283,7 @@ int uvc_video_start_streaming(struct uvc_streaming *stream)
{
int ret;
- ret = uvc_video_clock_init(stream);
+ ret = uvc_video_clock_init(&stream->clock);
if (ret < 0)
return ret;
@@ -2238,7 +2301,7 @@ int uvc_video_start_streaming(struct uvc_streaming *stream)
error_video:
usb_set_interface(stream->dev->udev, stream->intfnum, 0);
error_commit:
- uvc_video_clock_cleanup(stream);
+ uvc_video_clock_cleanup(&stream->clock);
return ret;
}
@@ -2266,5 +2329,5 @@ void uvc_video_stop_streaming(struct uvc_streaming *stream)
usb_clear_halt(stream->dev->udev, pipe);
}
- uvc_video_clock_cleanup(stream);
+ uvc_video_clock_cleanup(&stream->clock);
}
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 3653b2c8a86c..b7d24a853ce4 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -75,6 +75,7 @@
#define UVC_QUIRK_WAKE_AUTOSUSPEND 0x00002000
#define UVC_QUIRK_NO_RESET_RESUME 0x00004000
#define UVC_QUIRK_DISABLE_AUTOSUSPEND 0x00008000
+#define UVC_QUIRK_INVALID_DEVICE_SOF 0x00010000
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@@ -86,7 +87,9 @@
struct gpio_desc;
struct sg_table;
+struct uvc_control;
struct uvc_device;
+struct uvc_video_chain;
/*
* TODO: Put the most frequently accessed fields at the beginning of
@@ -125,6 +128,9 @@ struct uvc_control_mapping {
s32 master_manual;
u32 slave_ids[2];
+ const struct uvc_control_mapping *(*filter_mapping)
+ (struct uvc_video_chain *chain,
+ struct uvc_control *ctrl);
s32 (*get)(struct uvc_control_mapping *mapping, u8 query,
const u8 *data);
void (*set)(struct uvc_control_mapping *mapping, s32 value,
@@ -500,6 +506,7 @@ struct uvc_streaming {
unsigned int head;
unsigned int count;
unsigned int size;
+ unsigned int last_sof_overflow;
u16 last_sof;
u16 sof_offset;
@@ -524,7 +531,6 @@ struct uvc_device_info {
u32 quirks;
u32 meta_format;
u16 uvc_version;
- const struct uvc_control_mapping **mappings;
};
struct uvc_status_streaming {
@@ -750,8 +756,6 @@ int uvc_status_start(struct uvc_device *dev, gfp_t flags);
void uvc_status_stop(struct uvc_device *dev);
/* Controls */
-extern const struct uvc_control_mapping uvc_ctrl_power_line_mapping_limited;
-extern const struct uvc_control_mapping uvc_ctrl_power_line_mapping_uvc11;
extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 222f01665f7c..ee884a8221fb 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -323,6 +323,13 @@ static int v4l2_async_create_ancillary_links(struct v4l2_async_notifier *n,
sd->entity.function != MEDIA_ENT_F_FLASH)
return 0;
+ if (!n->sd) {
+ dev_warn(notifier_dev(n),
+ "not a sub-device notifier, not creating an ancillary link for %s!\n",
+ dev_name(sd->dev));
+ return 0;
+ }
+
link = media_create_ancillary_link(&n->sd->entity, &sd->entity);
return IS_ERR(link) ? PTR_ERR(link) : 0;
@@ -965,4 +972,5 @@ module_exit(v4l2_async_exit);
MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
MODULE_AUTHOR("Ezequiel Garcia <ezequiel@collabora.com>");
+MODULE_DESCRIPTION("V4L2 asynchronous subdevice registration API");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/v4l2-core/v4l2-cci.c b/drivers/media/v4l2-core/v4l2-cci.c
index ee3475bed37f..1ff94affbaf3 100644
--- a/drivers/media/v4l2-core/v4l2-cci.c
+++ b/drivers/media/v4l2-core/v4l2-cci.c
@@ -23,6 +23,15 @@ int cci_read(struct regmap *map, u32 reg, u64 *val, int *err)
u8 buf[8];
int ret;
+ /*
+ * TODO: Fix smatch. Assign *val to 0 here in order to avoid
+ * failing a smatch check on caller when the caller proceeds to
+ * read *val without initialising it on caller's side. *val is set
+ * to a valid value whenever this function returns 0 but smatch
+ * can't figure that out currently.
+ */
+ *val = 0;
+
if (err && *err)
return *err;
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 4165c815faef..0a2f4f0d0a07 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -253,6 +253,8 @@ const struct v4l2_format_info *v4l2_format_info(u32 format)
{ .format = V4L2_PIX_FMT_RGB555, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 2, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGR666, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_BGR48_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_BGR48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
+ { .format = V4L2_PIX_FMT_RGB48, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 6, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_ABGR64_12, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 8, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGBA1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
{ .format = V4L2_PIX_FMT_RGBX1010102, .pixel_enc = V4L2_PIXEL_ENC_RGB, .mem_planes = 1, .comp_planes = 1, .bpp = { 4, 0, 0, 0 }, .bpp_div = { 1, 1, 1, 1 }, .hdiv = 1, .vdiv = 1 },
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-defs.c b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
index 8696eb1cdd61..1ea52011247a 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-defs.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-defs.c
@@ -970,6 +970,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_LTR_COUNT: return "LTR Count";
case V4L2_CID_MPEG_VIDEO_FRAME_LTR_INDEX: return "Frame LTR Index";
case V4L2_CID_MPEG_VIDEO_USE_LTR_FRAMES: return "Use LTR Frames";
+ case V4L2_CID_MPEG_VIDEO_AVERAGE_QP: return "Average QP Value";
case V4L2_CID_FWHT_I_FRAME_QP: return "FWHT I-Frame QP Value";
case V4L2_CID_FWHT_P_FRAME_QP: return "FWHT P-Frame QP Value";
@@ -1507,6 +1508,10 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
*max = 0xffffffffffffLL;
*step = 1;
break;
+ case V4L2_CID_MPEG_VIDEO_AVERAGE_QP:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ break;
case V4L2_CID_PIXEL_RATE:
*type = V4L2_CTRL_TYPE_INTEGER64;
*flags |= V4L2_CTRL_FLAG_READ_ONLY;
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 89c7192148df..f19c8adf2c61 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -1251,6 +1251,7 @@ out_cleanup:
}
EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor);
+MODULE_DESCRIPTION("V4L2 fwnode binding parsing library");
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 4c76d17b4629..5eb4d797d259 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1307,6 +1307,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_RGBX1010102: descr = "32-bit RGBX 10-10-10-2"; break;
case V4L2_PIX_FMT_RGBA1010102: descr = "32-bit RGBA 10-10-10-2"; break;
case V4L2_PIX_FMT_ARGB2101010: descr = "32-bit ARGB 2-10-10-10"; break;
+ case V4L2_PIX_FMT_BGR48: descr = "48-bit BGR 16-16-16"; break;
+ case V4L2_PIX_FMT_RGB48: descr = "48-bit RGB 16-16-16"; break;
case V4L2_PIX_FMT_BGR48_12: descr = "12-bit Depth BGR"; break;
case V4L2_PIX_FMT_ABGR64_12: descr = "12-bit Depth BGRA"; break;
case V4L2_PIX_FMT_GREY: descr = "8-bit Greyscale"; break;
@@ -1463,6 +1465,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_Y210: descr = "10-bit YUYV Packed"; break;
case V4L2_PIX_FMT_Y212: descr = "12-bit YUYV Packed"; break;
case V4L2_PIX_FMT_Y216: descr = "16-bit YUYV Packed"; break;
+ case V4L2_META_FMT_RPI_BE_CFG: descr = "RPi PiSP BE Config format"; break;
case V4L2_META_FMT_GENERIC_8: descr = "8-bit Generic Metadata"; break;
case V4L2_META_FMT_GENERIC_CSI2_10: descr = "8-bit Generic Meta, 10b CSI-2"; break;
case V4L2_META_FMT_GENERIC_CSI2_12: descr = "8-bit Generic Meta, 12b CSI-2"; break;
@@ -1529,6 +1532,16 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_MT2110T: descr = "Mediatek 10bit Tile Mode"; break;
case V4L2_PIX_FMT_MT2110R: descr = "Mediatek 10bit Raster Mode"; break;
case V4L2_PIX_FMT_HEXTILE: descr = "Hextile Compressed Format"; break;
+ case V4L2_PIX_FMT_PISP_COMP1_RGGB: descr = "PiSP 8b RGRG/GBGB mode1 compr"; break;
+ case V4L2_PIX_FMT_PISP_COMP1_GRBG: descr = "PiSP 8b GRGR/BGBG mode1 compr"; break;
+ case V4L2_PIX_FMT_PISP_COMP1_GBRG: descr = "PiSP 8b GBGB/RGRG mode1 compr"; break;
+ case V4L2_PIX_FMT_PISP_COMP1_BGGR: descr = "PiSP 8b BGBG/GRGR mode1 compr"; break;
+ case V4L2_PIX_FMT_PISP_COMP1_MONO: descr = "PiSP 8b monochrome mode1 compr"; break;
+ case V4L2_PIX_FMT_PISP_COMP2_RGGB: descr = "PiSP 8b RGRG/GBGB mode2 compr"; break;
+ case V4L2_PIX_FMT_PISP_COMP2_GRBG: descr = "PiSP 8b GRGR/BGBG mode2 compr"; break;
+ case V4L2_PIX_FMT_PISP_COMP2_GBRG: descr = "PiSP 8b GBGB/RGRG mode2 compr"; break;
+ case V4L2_PIX_FMT_PISP_COMP2_BGGR: descr = "PiSP 8b BGBG/GRGR mode2 compr"; break;
+ case V4L2_PIX_FMT_PISP_COMP2_MONO: descr = "PiSP 8b monochrome mode2 compr"; break;
default:
if (fmt->description[0])
return;
diff --git a/drivers/media/v4l2-core/v4l2-jpeg.c b/drivers/media/v4l2-core/v4l2-jpeg.c
index 94435a7b6816..b8bece739d07 100644
--- a/drivers/media/v4l2-core/v4l2-jpeg.c
+++ b/drivers/media/v4l2-core/v4l2-jpeg.c
@@ -52,6 +52,122 @@ MODULE_LICENSE("GPL");
#define COM 0xfffe /* comment */
#define TEM 0xff01 /* temporary */
+/* Luma and chroma qp tables to achieve 50% compression quality
+ * This is as per example in Annex K.1 of ITU-T.81
+ */
+const u8 v4l2_jpeg_ref_table_luma_qt[V4L2_JPEG_PIXELS_IN_BLOCK] = {
+ 16, 11, 10, 16, 24, 40, 51, 61,
+ 12, 12, 14, 19, 26, 58, 60, 55,
+ 14, 13, 16, 24, 40, 57, 69, 56,
+ 14, 17, 22, 29, 51, 87, 80, 62,
+ 18, 22, 37, 56, 68, 109, 103, 77,
+ 24, 35, 55, 64, 81, 104, 113, 92,
+ 49, 64, 78, 87, 103, 121, 120, 101,
+ 72, 92, 95, 98, 112, 100, 103, 99
+};
+EXPORT_SYMBOL_GPL(v4l2_jpeg_ref_table_luma_qt);
+
+const u8 v4l2_jpeg_ref_table_chroma_qt[V4L2_JPEG_PIXELS_IN_BLOCK] = {
+ 17, 18, 24, 47, 99, 99, 99, 99,
+ 18, 21, 26, 66, 99, 99, 99, 99,
+ 24, 26, 56, 99, 99, 99, 99, 99,
+ 47, 66, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99
+};
+EXPORT_SYMBOL_GPL(v4l2_jpeg_ref_table_chroma_qt);
+
+/* Zigzag scan pattern indexes */
+const u8 v4l2_jpeg_zigzag_scan_index[V4L2_JPEG_PIXELS_IN_BLOCK] = {
+ 0, 1, 8, 16, 9, 2, 3, 10,
+ 17, 24, 32, 25, 18, 11, 4, 5,
+ 12, 19, 26, 33, 40, 48, 41, 34,
+ 27, 20, 13, 6, 7, 14, 21, 28,
+ 35, 42, 49, 56, 57, 50, 43, 36,
+ 29, 22, 15, 23, 30, 37, 44, 51,
+ 58, 59, 52, 45, 38, 31, 39, 46,
+ 53, 60, 61, 54, 47, 55, 62, 63
+};
+EXPORT_SYMBOL_GPL(v4l2_jpeg_zigzag_scan_index);
+
+/*
+ * Contains the data that needs to be sent in the marker segment of an
+ * interchange format JPEG stream or an abbreviated format table specification
+ * data stream. Specifies the huffman table used for encoding the luminance DC
+ * coefficient differences. The table represents Table K.3 of ITU-T.81
+ */
+const u8 v4l2_jpeg_ref_table_luma_dc_ht[V4L2_JPEG_REF_HT_DC_LEN] = {
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
+};
+EXPORT_SYMBOL_GPL(v4l2_jpeg_ref_table_luma_dc_ht);
+
+/*
+ * Contains the data that needs to be sent in the marker segment of an
+ * interchange format JPEG stream or an abbreviated format table specification
+ * data stream. Specifies the huffman table used for encoding the luminance AC
+ * coefficients. The table represents Table K.5 of ITU-T.81
+ */
+const u8 v4l2_jpeg_ref_table_luma_ac_ht[V4L2_JPEG_REF_HT_AC_LEN] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, 0x05, 0x05, 0x04, 0x04,
+ 0x00, 0x00, 0x01, 0x7D, 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71, 0x14, 0x32,
+ 0x81, 0x91, 0xA1, 0x08, 0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16, 0x17, 0x18, 0x19, 0x1A,
+ 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54, 0x55,
+ 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x83, 0x84, 0x85,
+ 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2,
+ 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
+ 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8,
+ 0xD9, 0xDA, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
+ 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
+};
+EXPORT_SYMBOL_GPL(v4l2_jpeg_ref_table_luma_ac_ht);
+
+/*
+ * Contains the data that needs to be sent in the marker segment of an interchange format JPEG
+ * stream or an abbreviated format table specification data stream.
+ * Specifies the huffman table used for encoding the chrominance DC coefficient differences.
+ * The table represents Table K.4 of ITU-T.81
+ */
+const u8 v4l2_jpeg_ref_table_chroma_dc_ht[V4L2_JPEG_REF_HT_DC_LEN] = {
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B
+};
+EXPORT_SYMBOL_GPL(v4l2_jpeg_ref_table_chroma_dc_ht);
+
+/*
+ * Contains the data that needs to be sent in the marker segment of an
+ * interchange format JPEG stream or an abbreviated format table specification
+ * data stream. Specifies the huffman table used for encoding the chrominance
+ * AC coefficients. The table represents Table K.6 of ITU-T.81
+ */
+const u8 v4l2_jpeg_ref_table_chroma_ac_ht[V4L2_JPEG_REF_HT_AC_LEN] = {
+ 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, 0x07, 0x05, 0x04, 0x04,
+ 0x00, 0x01, 0x02, 0x77, 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22, 0x32, 0x81,
+ 0x08, 0x14, 0x42, 0x91, 0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0,
+ 0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34, 0xE1, 0x25, 0xF1, 0x17,
+ 0x18, 0x19, 0x1A, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x53, 0x54,
+ 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x82, 0x83,
+ 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9,
+ 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
+ 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
+ 0xD7, 0xD8, 0xD9, 0xDA, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,
+ 0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA
+};
+EXPORT_SYMBOL_GPL(v4l2_jpeg_ref_table_chroma_ac_ht);
+
/**
* struct jpeg_stream - JPEG byte stream
* @curr: current position in stream
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 8470d6eda9a3..7c5812d55315 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -148,6 +148,23 @@ static int subdev_close(struct file *file)
}
#endif /* CONFIG_VIDEO_V4L2_SUBDEV_API */
+static void v4l2_subdev_enable_privacy_led(struct v4l2_subdev *sd)
+{
+#if IS_REACHABLE(CONFIG_LEDS_CLASS)
+ if (!IS_ERR_OR_NULL(sd->privacy_led))
+ led_set_brightness(sd->privacy_led,
+ sd->privacy_led->max_brightness);
+#endif
+}
+
+static void v4l2_subdev_disable_privacy_led(struct v4l2_subdev *sd)
+{
+#if IS_REACHABLE(CONFIG_LEDS_CLASS)
+ if (!IS_ERR_OR_NULL(sd->privacy_led))
+ led_set_brightness(sd->privacy_led, 0);
+#endif
+}
+
static inline int check_which(u32 which)
{
if (which != V4L2_SUBDEV_FORMAT_TRY &&
@@ -434,12 +451,8 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable)
* The .s_stream() operation must never be called to start or stop an
* already started or stopped subdev. Catch offenders but don't return
* an error yet to avoid regressions.
- *
- * As .s_stream() is mutually exclusive with the .enable_streams() and
- * .disable_streams() operation, we can use the enabled_streams field
- * to store the subdev streaming state.
*/
- if (WARN_ON(!!sd->enabled_streams == !!enable))
+ if (WARN_ON(sd->s_stream_enabled == !!enable))
return 0;
ret = sd->ops->video->s_stream(sd, enable);
@@ -450,17 +463,12 @@ static int call_s_stream(struct v4l2_subdev *sd, int enable)
}
if (!ret) {
- sd->enabled_streams = enable ? BIT(0) : 0;
+ sd->s_stream_enabled = enable;
-#if IS_REACHABLE(CONFIG_LEDS_CLASS)
- if (!IS_ERR_OR_NULL(sd->privacy_led)) {
- if (enable)
- led_set_brightness(sd->privacy_led,
- sd->privacy_led->max_brightness);
- else
- led_set_brightness(sd->privacy_led, 0);
- }
-#endif
+ if (enable)
+ v4l2_subdev_enable_privacy_led(sd);
+ else
+ v4l2_subdev_disable_privacy_led(sd);
}
return ret;
@@ -1261,14 +1269,6 @@ v4l2_subdev_link_validate_get_format(struct media_pad *pad, u32 stream,
struct v4l2_subdev *sd;
int ret;
- if (!is_media_entity_v4l2_subdev(pad->entity)) {
- WARN(pad->entity->function != MEDIA_ENT_F_IO_V4L,
- "Driver bug! Wrong media entity type 0x%08x, entity %s\n",
- pad->entity->function, pad->entity->name);
-
- return -EINVAL;
- }
-
sd = media_entity_to_v4l2_subdev(pad->entity);
fmt->which = V4L2_SUBDEV_FORMAT_ACTIVE;
@@ -1576,6 +1576,33 @@ int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name,
struct lock_class_key *key)
{
struct v4l2_subdev_state *state;
+ struct device *dev = sd->dev;
+ bool has_disable_streams;
+ bool has_enable_streams;
+ bool has_s_stream;
+
+ /* Check that the subdevice implements the required features */
+
+ has_s_stream = v4l2_subdev_has_op(sd, video, s_stream);
+ has_enable_streams = v4l2_subdev_has_op(sd, pad, enable_streams);
+ has_disable_streams = v4l2_subdev_has_op(sd, pad, disable_streams);
+
+ if (has_enable_streams != has_disable_streams) {
+ dev_err(dev,
+ "subdev '%s' must implement both or neither of .enable_streams() and .disable_streams()\n",
+ sd->name);
+ return -EINVAL;
+ }
+
+ if (sd->flags & V4L2_SUBDEV_FL_STREAMS) {
+ if (has_s_stream && !has_enable_streams) {
+ dev_err(dev,
+ "subdev '%s' must implement .enable/disable_streams()\n",
+ sd->name);
+
+ return -EINVAL;
+ }
+ }
state = __v4l2_subdev_state_alloc(sd, name, key);
if (IS_ERR(state))
@@ -2120,43 +2147,55 @@ out:
}
EXPORT_SYMBOL_GPL(v4l2_subdev_routing_validate);
-static int v4l2_subdev_enable_streams_fallback(struct v4l2_subdev *sd, u32 pad,
- u64 streams_mask)
+static void v4l2_subdev_collect_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask,
+ u64 *found_streams,
+ u64 *enabled_streams)
{
- struct device *dev = sd->entity.graph_obj.mdev->dev;
- unsigned int i;
- int ret;
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) {
+ *found_streams = BIT_ULL(0);
+ *enabled_streams =
+ (sd->enabled_pads & BIT_ULL(pad)) ? BIT_ULL(0) : 0;
+ return;
+ }
- /*
- * The subdev doesn't implement pad-based stream enable, fall back
- * on the .s_stream() operation. This can only be done for subdevs that
- * have a single source pad, as sd->enabled_streams is global to the
- * subdev.
- */
- if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
- return -EOPNOTSUPP;
+ *found_streams = 0;
+ *enabled_streams = 0;
- for (i = 0; i < sd->entity.num_pads; ++i) {
- if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE)
- return -EOPNOTSUPP;
- }
+ for (unsigned int i = 0; i < state->stream_configs.num_configs; ++i) {
+ const struct v4l2_subdev_stream_config *cfg =
+ &state->stream_configs.configs[i];
- if (sd->enabled_streams & streams_mask) {
- dev_dbg(dev, "set of streams %#llx already enabled on %s:%u\n",
- streams_mask, sd->entity.name, pad);
- return -EALREADY;
+ if (cfg->pad != pad || !(streams_mask & BIT_ULL(cfg->stream)))
+ continue;
+
+ *found_streams |= BIT_ULL(cfg->stream);
+ if (cfg->enabled)
+ *enabled_streams |= BIT_ULL(cfg->stream);
}
+}
- /* Start streaming when the first streams are enabled. */
- if (!sd->enabled_streams) {
- ret = v4l2_subdev_call(sd, video, s_stream, 1);
- if (ret)
- return ret;
+static void v4l2_subdev_set_streams_enabled(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ u32 pad, u64 streams_mask,
+ bool enabled)
+{
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS)) {
+ if (enabled)
+ sd->enabled_pads |= BIT_ULL(pad);
+ else
+ sd->enabled_pads &= ~BIT_ULL(pad);
+ return;
}
- sd->enabled_streams |= streams_mask;
+ for (unsigned int i = 0; i < state->stream_configs.num_configs; ++i) {
+ struct v4l2_subdev_stream_config *cfg =
+ &state->stream_configs.configs[i];
- return 0;
+ if (cfg->pad == pad && (streams_mask & BIT_ULL(cfg->stream)))
+ cfg->enabled = enabled;
+ }
}
int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad,
@@ -2164,44 +2203,44 @@ int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad,
{
struct device *dev = sd->entity.graph_obj.mdev->dev;
struct v4l2_subdev_state *state;
- u64 found_streams = 0;
- unsigned int i;
+ bool already_streaming;
+ u64 enabled_streams;
+ u64 found_streams;
+ bool use_s_stream;
int ret;
/* A few basic sanity checks first. */
if (pad >= sd->entity.num_pads)
return -EINVAL;
+ if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
+ return -EOPNOTSUPP;
+
+ /*
+ * We use a 64-bit bitmask for tracking enabled pads, so only subdevices
+ * with 64 pads or less can be supported.
+ */
+ if (pad >= sizeof(sd->enabled_pads) * BITS_PER_BYTE)
+ return -EOPNOTSUPP;
+
if (!streams_mask)
return 0;
/* Fallback on .s_stream() if .enable_streams() isn't available. */
- if (!sd->ops->pad || !sd->ops->pad->enable_streams)
- return v4l2_subdev_enable_streams_fallback(sd, pad,
- streams_mask);
+ use_s_stream = !v4l2_subdev_has_op(sd, pad, enable_streams);
- state = v4l2_subdev_lock_and_get_active_state(sd);
+ if (!use_s_stream)
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+ else
+ state = NULL;
/*
* Verify that the requested streams exist and that they are not
* already enabled.
*/
- for (i = 0; i < state->stream_configs.num_configs; ++i) {
- struct v4l2_subdev_stream_config *cfg =
- &state->stream_configs.configs[i];
-
- if (cfg->pad != pad || !(streams_mask & BIT_ULL(cfg->stream)))
- continue;
- found_streams |= BIT_ULL(cfg->stream);
-
- if (cfg->enabled) {
- dev_dbg(dev, "stream %u already enabled on %s:%u\n",
- cfg->stream, sd->entity.name, pad);
- ret = -EALREADY;
- goto done;
- }
- }
+ v4l2_subdev_collect_streams(sd, state, pad, streams_mask,
+ &found_streams, &enabled_streams);
if (found_streams != streams_mask) {
dev_dbg(dev, "streams 0x%llx not found on %s:%u\n",
@@ -2210,11 +2249,29 @@ int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad,
goto done;
}
+ if (enabled_streams) {
+ dev_dbg(dev, "streams 0x%llx already enabled on %s:%u\n",
+ enabled_streams, sd->entity.name, pad);
+ ret = -EALREADY;
+ goto done;
+ }
+
dev_dbg(dev, "enable streams %u:%#llx\n", pad, streams_mask);
- /* Call the .enable_streams() operation. */
- ret = v4l2_subdev_call(sd, pad, enable_streams, state, pad,
- streams_mask);
+ already_streaming = v4l2_subdev_is_streaming(sd);
+
+ if (!use_s_stream) {
+ /* Call the .enable_streams() operation. */
+ ret = v4l2_subdev_call(sd, pad, enable_streams, state, pad,
+ streams_mask);
+ } else {
+ /* Start streaming when the first pad is enabled. */
+ if (!already_streaming)
+ ret = v4l2_subdev_call(sd, video, s_stream, 1);
+ else
+ ret = 0;
+ }
+
if (ret) {
dev_dbg(dev, "enable streams %u:%#llx failed: %d\n", pad,
streams_mask, ret);
@@ -2222,103 +2279,68 @@ int v4l2_subdev_enable_streams(struct v4l2_subdev *sd, u32 pad,
}
/* Mark the streams as enabled. */
- for (i = 0; i < state->stream_configs.num_configs; ++i) {
- struct v4l2_subdev_stream_config *cfg =
- &state->stream_configs.configs[i];
+ v4l2_subdev_set_streams_enabled(sd, state, pad, streams_mask, true);
- if (cfg->pad == pad && (streams_mask & BIT_ULL(cfg->stream)))
- cfg->enabled = true;
- }
+ /*
+ * TODO: When all the drivers have been changed to use
+ * v4l2_subdev_enable_streams() and v4l2_subdev_disable_streams(),
+ * instead of calling .s_stream() operation directly, we can remove
+ * the privacy LED handling from call_s_stream() and do it here
+ * for all cases.
+ */
+ if (!use_s_stream && !already_streaming)
+ v4l2_subdev_enable_privacy_led(sd);
done:
- v4l2_subdev_unlock_state(state);
+ if (!use_s_stream)
+ v4l2_subdev_unlock_state(state);
return ret;
}
EXPORT_SYMBOL_GPL(v4l2_subdev_enable_streams);
-static int v4l2_subdev_disable_streams_fallback(struct v4l2_subdev *sd, u32 pad,
- u64 streams_mask)
-{
- struct device *dev = sd->entity.graph_obj.mdev->dev;
- unsigned int i;
- int ret;
-
- /*
- * If the subdev doesn't implement pad-based stream enable, fall back
- * on the .s_stream() operation. This can only be done for subdevs that
- * have a single source pad, as sd->enabled_streams is global to the
- * subdev.
- */
- if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
- return -EOPNOTSUPP;
-
- for (i = 0; i < sd->entity.num_pads; ++i) {
- if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE)
- return -EOPNOTSUPP;
- }
-
- if ((sd->enabled_streams & streams_mask) != streams_mask) {
- dev_dbg(dev, "set of streams %#llx already disabled on %s:%u\n",
- streams_mask, sd->entity.name, pad);
- return -EALREADY;
- }
-
- /* Stop streaming when the last streams are disabled. */
- if (!(sd->enabled_streams & ~streams_mask)) {
- ret = v4l2_subdev_call(sd, video, s_stream, 0);
- if (ret)
- return ret;
- }
-
- sd->enabled_streams &= ~streams_mask;
-
- return 0;
-}
-
int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad,
u64 streams_mask)
{
struct device *dev = sd->entity.graph_obj.mdev->dev;
struct v4l2_subdev_state *state;
- u64 found_streams = 0;
- unsigned int i;
+ u64 enabled_streams;
+ u64 found_streams;
+ bool use_s_stream;
int ret;
/* A few basic sanity checks first. */
if (pad >= sd->entity.num_pads)
return -EINVAL;
+ if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
+ return -EOPNOTSUPP;
+
+ /*
+ * We use a 64-bit bitmask for tracking enabled pads, so only subdevices
+ * with 64 pads or less can be supported.
+ */
+ if (pad >= sizeof(sd->enabled_pads) * BITS_PER_BYTE)
+ return -EOPNOTSUPP;
+
if (!streams_mask)
return 0;
/* Fallback on .s_stream() if .disable_streams() isn't available. */
- if (!sd->ops->pad || !sd->ops->pad->disable_streams)
- return v4l2_subdev_disable_streams_fallback(sd, pad,
- streams_mask);
+ use_s_stream = !v4l2_subdev_has_op(sd, pad, disable_streams);
- state = v4l2_subdev_lock_and_get_active_state(sd);
+ if (!use_s_stream)
+ state = v4l2_subdev_lock_and_get_active_state(sd);
+ else
+ state = NULL;
/*
* Verify that the requested streams exist and that they are not
* already disabled.
*/
- for (i = 0; i < state->stream_configs.num_configs; ++i) {
- struct v4l2_subdev_stream_config *cfg =
- &state->stream_configs.configs[i];
- if (cfg->pad != pad || !(streams_mask & BIT_ULL(cfg->stream)))
- continue;
-
- found_streams |= BIT_ULL(cfg->stream);
-
- if (!cfg->enabled) {
- dev_dbg(dev, "stream %u already disabled on %s:%u\n",
- cfg->stream, sd->entity.name, pad);
- ret = -EALREADY;
- goto done;
- }
- }
+ v4l2_subdev_collect_streams(sd, state, pad, streams_mask,
+ &found_streams, &enabled_streams);
if (found_streams != streams_mask) {
dev_dbg(dev, "streams 0x%llx not found on %s:%u\n",
@@ -2327,28 +2349,43 @@ int v4l2_subdev_disable_streams(struct v4l2_subdev *sd, u32 pad,
goto done;
}
+ if (enabled_streams != streams_mask) {
+ dev_dbg(dev, "streams 0x%llx already disabled on %s:%u\n",
+ streams_mask & ~enabled_streams, sd->entity.name, pad);
+ ret = -EALREADY;
+ goto done;
+ }
+
dev_dbg(dev, "disable streams %u:%#llx\n", pad, streams_mask);
- /* Call the .disable_streams() operation. */
- ret = v4l2_subdev_call(sd, pad, disable_streams, state, pad,
- streams_mask);
+ if (!use_s_stream) {
+ /* Call the .disable_streams() operation. */
+ ret = v4l2_subdev_call(sd, pad, disable_streams, state, pad,
+ streams_mask);
+ } else {
+ /* Stop streaming when the last streams are disabled. */
+
+ if (!(sd->enabled_pads & ~BIT_ULL(pad)))
+ ret = v4l2_subdev_call(sd, video, s_stream, 0);
+ else
+ ret = 0;
+ }
+
if (ret) {
dev_dbg(dev, "disable streams %u:%#llx failed: %d\n", pad,
streams_mask, ret);
goto done;
}
- /* Mark the streams as disabled. */
- for (i = 0; i < state->stream_configs.num_configs; ++i) {
- struct v4l2_subdev_stream_config *cfg =
- &state->stream_configs.configs[i];
-
- if (cfg->pad == pad && (streams_mask & BIT_ULL(cfg->stream)))
- cfg->enabled = false;
- }
+ v4l2_subdev_set_streams_enabled(sd, state, pad, streams_mask, false);
done:
- v4l2_subdev_unlock_state(state);
+ if (!use_s_stream) {
+ if (!v4l2_subdev_is_streaming(sd))
+ v4l2_subdev_disable_privacy_led(sd);
+
+ v4l2_subdev_unlock_state(state);
+ }
return ret;
}
@@ -2377,15 +2414,24 @@ int v4l2_subdev_s_stream_helper(struct v4l2_subdev *sd, int enable)
if (WARN_ON(pad_index == -1))
return -EINVAL;
- /*
- * As there's a single source pad, just collect all the source streams.
- */
- state = v4l2_subdev_lock_and_get_active_state(sd);
+ if (sd->flags & V4L2_SUBDEV_FL_STREAMS) {
+ /*
+ * As there's a single source pad, just collect all the source
+ * streams.
+ */
+ state = v4l2_subdev_lock_and_get_active_state(sd);
- for_each_active_route(&state->routing, route)
- source_mask |= BIT_ULL(route->source_stream);
+ for_each_active_route(&state->routing, route)
+ source_mask |= BIT_ULL(route->source_stream);
- v4l2_subdev_unlock_state(state);
+ v4l2_subdev_unlock_state(state);
+ } else {
+ /*
+ * For non-streams subdevices, there's a single implicit stream
+ * per pad.
+ */
+ source_mask = BIT_ULL(0);
+ }
if (enable)
return v4l2_subdev_enable_streams(sd, pad_index, source_mask);
@@ -2427,6 +2473,31 @@ void v4l2_subdev_notify_event(struct v4l2_subdev *sd,
}
EXPORT_SYMBOL_GPL(v4l2_subdev_notify_event);
+bool v4l2_subdev_is_streaming(struct v4l2_subdev *sd)
+{
+ struct v4l2_subdev_state *state;
+
+ if (!v4l2_subdev_has_op(sd, pad, enable_streams))
+ return sd->s_stream_enabled;
+
+ if (!(sd->flags & V4L2_SUBDEV_FL_STREAMS))
+ return !!sd->enabled_pads;
+
+ state = v4l2_subdev_get_locked_active_state(sd);
+
+ for (unsigned int i = 0; i < state->stream_configs.num_configs; ++i) {
+ const struct v4l2_subdev_stream_config *cfg;
+
+ cfg = &state->stream_configs.configs[i];
+
+ if (cfg->enabled)
+ return true;
+ }
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(v4l2_subdev_is_streaming);
+
int v4l2_subdev_get_privacy_led(struct v4l2_subdev *sd)
{
#if IS_REACHABLE(CONFIG_LEDS_CLASS)
diff --git a/drivers/staging/media/atomisp/TODO b/drivers/staging/media/atomisp/TODO
index bfef99997a1d..27cbbde93b1e 100644
--- a/drivers/staging/media/atomisp/TODO
+++ b/drivers/staging/media/atomisp/TODO
@@ -1,29 +1,3 @@
-Required firmware
-=================
-
-The atomisp driver requires the following firmware:
-
-- for BYT: /lib/firmware/shisp_2400b0_v21.bin
-
- With a version of "irci_stable_candrpv_0415_20150423_1753" to check
- the version run: "strings shisp_2400b0_v21.bin | head -n1", sha256sum:
-
- 3847b95fb9f1f8352c595ba7394d55b33176751372baae17f89aa483ec02a21b shisp_2400b0_v21.bin
-
- The shisp_2400b0_v21.bin file with this version can be found on
- the Android factory images of various X86 Android tablets such as
- e.g. the Chuwi Hi8 Pro.
-
-- for CHT: /lib/firmware/shisp_2401a0_v21.bin
-
- With a version of "irci_stable_candrpv_0415_20150521_0458", sha256sum:
-
- e89359f4e4934c410c83d525e283f34c5fcce9cb5caa75ad8a32d66d3842d95c shisp_2401a0_v21.bin
-
- This can be found here:
- https://github.com/intel-aero/meta-intel-aero-base/blob/master/recipes-kernel/linux/linux-yocto/shisp_2401a0_v21.bin
-
-
TODO
====
@@ -35,6 +9,8 @@ TODO
* Remove custom sysfs files created by atomisp_drvfs.c
+* Remove unnecessary/unwanted module parameters
+
* Remove abuse of priv field in various v4l2 userspace API structs
* Without a 3A library the capture behaviour is not very good. To take a good
@@ -61,9 +37,6 @@ TODO
* Fix not all v4l2 apps working, e.g. cheese does not work
-* Get manufacturer's authorization to redistribute the binaries for
- the firmware files
-
* The atomisp code still has a lot of cruft which needs cleaning up
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c
index 7a20d918a9d5..3499353f8ea5 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-libmsrlisthelper.c
@@ -207,4 +207,5 @@ module_init(init_msrlisthelper);
module_exit(exit_msrlisthelper);
MODULE_AUTHOR("Jukka Kaartinen <jukka.o.kaartinen@intel.com>");
+MODULE_DESCRIPTION("Helper library to load, parse and apply large register lists");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
index 23b1001c2a55..918ea4fa9f6b 100644
--- a/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
+++ b/drivers/staging/media/atomisp/i2c/atomisp-mt9m114.c
@@ -1614,4 +1614,5 @@ static struct i2c_driver mt9m114_driver = {
module_i2c_driver(mt9m114_driver);
MODULE_AUTHOR("Shuguang Gong <Shuguang.gong@intel.com>");
+MODULE_DESCRIPTION("Aptina mt9m114 sensor support module");
MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h
index 0e3f6fb78483..fdeb247036b0 100644
--- a/drivers/staging/media/atomisp/include/linux/atomisp_platform.h
+++ b/drivers/staging/media/atomisp/include/linux/atomisp_platform.h
@@ -18,7 +18,7 @@
#ifndef ATOMISP_PLATFORM_H_
#define ATOMISP_PLATFORM_H_
-#include <asm/intel-family.h>
+#include <asm/cpu_device_id.h>
#include <asm/processor.h>
#include <linux/i2c.h>
@@ -178,22 +178,17 @@ void atomisp_unregister_subdev(struct v4l2_subdev *subdev);
int v4l2_get_acpi_sensor_info(struct device *dev, char **module_id_str);
/* API from old platform_camera.h, new CPUID implementation */
-#define __IS_SOC(x) (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && \
- boot_cpu_data.x86 == 6 && \
- boot_cpu_data.x86_model == (x))
-#define __IS_SOCS(x,y) (boot_cpu_data.x86_vendor == X86_VENDOR_INTEL && \
- boot_cpu_data.x86 == 6 && \
- (boot_cpu_data.x86_model == (x) || \
- boot_cpu_data.x86_model == (y)))
-
-#define IS_MFLD __IS_SOC(INTEL_FAM6_ATOM_SALTWELL_MID)
-#define IS_BYT __IS_SOC(INTEL_FAM6_ATOM_SILVERMONT)
-#define IS_CHT __IS_SOC(INTEL_FAM6_ATOM_AIRMONT)
-#define IS_MRFD __IS_SOC(INTEL_FAM6_ATOM_SILVERMONT_MID)
-#define IS_MOFD __IS_SOC(INTEL_FAM6_ATOM_AIRMONT_MID)
+#define __IS_SOC(x) (boot_cpu_data.x86_vfm == x)
+#define __IS_SOCS(x, y) (boot_cpu_data.x86_vfm == x || boot_cpu_data.x86_vfm == y)
+
+#define IS_MFLD __IS_SOC(INTEL_ATOM_SALTWELL_MID)
+#define IS_BYT __IS_SOC(INTEL_ATOM_SILVERMONT)
+#define IS_CHT __IS_SOC(INTEL_ATOM_AIRMONT)
+#define IS_MRFD __IS_SOC(INTEL_ATOM_SILVERMONT_MID)
+#define IS_MOFD __IS_SOC(INTEL_ATOM_AIRMONT_MID)
/* Both CHT and MOFD come with ISP2401 */
-#define IS_ISP2401 __IS_SOCS(INTEL_FAM6_ATOM_AIRMONT, \
- INTEL_FAM6_ATOM_AIRMONT_MID)
+#define IS_ISP2401 __IS_SOCS(INTEL_ATOM_AIRMONT, \
+ INTEL_ATOM_AIRMONT_MID)
#endif /* ATOMISP_PLATFORM_H_ */
diff --git a/drivers/staging/media/atomisp/pci/atomisp_common.h b/drivers/staging/media/atomisp/pci/atomisp_common.h
index 9d23a6ccfc33..2d0a77df6c88 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_common.h
+++ b/drivers/staging/media/atomisp/pci/atomisp_common.h
@@ -33,7 +33,6 @@
extern int dbg_level;
extern int dbg_func;
-extern int mipicsi_flag;
extern int pad_w;
extern int pad_h;
diff --git a/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c b/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c
index 2483eaeeac73..d789d38ef689 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_csi2_bridge.c
@@ -106,6 +106,12 @@ static struct gmin_cfg_var lenovo_ideapad_miix_310_vars[] = {
{}
};
+static struct gmin_cfg_var xiaomi_mipad2_vars[] = {
+ /* _DSM contains the wrong CsiPort for the front facing OV5693 sensor */
+ { "INT33BE:00", "CsiPort", "0" },
+ {}
+};
+
static const struct dmi_system_id gmin_cfg_dmi_overrides[] = {
{
/* Lenovo Ideapad Miix 310 */
@@ -115,6 +121,14 @@ static const struct dmi_system_id gmin_cfg_dmi_overrides[] = {
},
.driver_data = lenovo_ideapad_miix_310_vars,
},
+ {
+ /* Xiaomi Mipad2 */
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "Xiaomi Inc"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "Mipad2"),
+ },
+ .driver_data = xiaomi_mipad2_vars,
+ },
{}
};
diff --git a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
index effc71b5a439..d7e8a9871522 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_ioctl.c
@@ -894,7 +894,7 @@ int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count)
ret = __media_pipeline_start(&asd->video_out.vdev.entity.pads[0], &asd->video_out.pipe);
mutex_unlock(&isp->media_dev.graph_mutex);
if (ret) {
- dev_err(isp->dev, "Error starting mc pipline: %d\n", ret);
+ dev_err(isp->dev, "Error starting mc pipeline: %d\n", ret);
goto out_unlock;
}
diff --git a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
index 9df0eb7044b7..c9984f1557b0 100644
--- a/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
+++ b/drivers/staging/media/atomisp/pci/atomisp_v4l2.c
@@ -66,14 +66,6 @@ module_param(dbg_func, int, 0644);
MODULE_PARM_DESC(dbg_func,
"log function switch non/printk (default:printk)");
-int mipicsi_flag;
-module_param(mipicsi_flag, int, 0644);
-MODULE_PARM_DESC(mipicsi_flag, "mipi csi compression predictor algorithm");
-
-static char firmware_name[256];
-module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
-MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the default firmware name.");
-
/*
* Set to 16x16 since this is the amount of lines and pixels the sensor
* exports extra. If these are kept at the 10x8 that they were on, in yuv
@@ -1105,23 +1097,19 @@ atomisp_load_firmware(struct atomisp_device *isp)
int rc;
char *fw_path = NULL;
- if (firmware_name[0] != '\0') {
- fw_path = firmware_name;
- } else {
- if ((isp->media_dev.hw_revision >> ATOMISP_HW_REVISION_SHIFT)
- == ATOMISP_HW_REVISION_ISP2401)
- fw_path = "shisp_2401a0_v21.bin";
-
- if (isp->media_dev.hw_revision ==
- ((ATOMISP_HW_REVISION_ISP2401_LEGACY << ATOMISP_HW_REVISION_SHIFT)
- | ATOMISP_HW_STEPPING_A0))
- fw_path = "shisp_2401a0_legacy_v21.bin";
-
- if (isp->media_dev.hw_revision ==
- ((ATOMISP_HW_REVISION_ISP2400 << ATOMISP_HW_REVISION_SHIFT)
- | ATOMISP_HW_STEPPING_B0))
- fw_path = "shisp_2400b0_v21.bin";
- }
+ if ((isp->media_dev.hw_revision >> ATOMISP_HW_REVISION_SHIFT) ==
+ ATOMISP_HW_REVISION_ISP2401)
+ fw_path = "intel/ipu/shisp_2401a0_v21.bin";
+
+ if (isp->media_dev.hw_revision ==
+ ((ATOMISP_HW_REVISION_ISP2401_LEGACY << ATOMISP_HW_REVISION_SHIFT) |
+ ATOMISP_HW_STEPPING_A0))
+ fw_path = "intel/ipu/shisp_2401a0_legacy_v21.bin";
+
+ if (isp->media_dev.hw_revision ==
+ ((ATOMISP_HW_REVISION_ISP2400 << ATOMISP_HW_REVISION_SHIFT) |
+ ATOMISP_HW_STEPPING_B0))
+ fw_path = "intel/ipu/shisp_2400b0_v21.bin";
if (!fw_path) {
dev_err(isp->dev, "Unsupported hw_revision 0x%x\n",
@@ -1130,6 +1118,9 @@ atomisp_load_firmware(struct atomisp_device *isp)
}
rc = request_firmware(&fw, fw_path, isp->dev);
+ /* Fallback to old fw_path without "intel/ipu/" prefix */
+ if (rc)
+ rc = request_firmware(&fw, kbasename(fw_path), isp->dev);
if (rc) {
dev_err(isp->dev,
"atomisp: Error %d while requesting firmware %s\n",
diff --git a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h
index 6fa6da859158..b0f20563c3a3 100644
--- a/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h
+++ b/drivers/staging/media/atomisp/pci/base/circbuf/interface/ia_css_circbuf_comm.h
@@ -16,6 +16,8 @@
#ifndef _IA_CSS_CIRCBUF_COMM_H
#define _IA_CSS_CIRCBUF_COMM_H
+#include <linux/build_bug.h>
+
#include <type_support.h> /* uint8_t, uint32_t */
#define IA_CSS_CIRCBUF_PADDING 1 /* The circular buffer is implemented in lock-less manner, wherein
@@ -45,6 +47,8 @@ struct ia_css_circbuf_desc_s {
#define SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT \
(4 * sizeof(uint8_t))
+static_assert(sizeof(struct ia_css_circbuf_desc_s) == SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT);
+
/**
* @brief Data structure for the circular buffer element.
*/
@@ -56,4 +60,6 @@ struct ia_css_circbuf_elem_s {
#define SIZE_OF_IA_CSS_CIRCBUF_ELEM_S_STRUCT \
(sizeof(uint32_t))
+static_assert(sizeof(struct ia_css_circbuf_elem_s) == SIZE_OF_IA_CSS_CIRCBUF_ELEM_S_STRUCT);
+
#endif /*_IA_CSS_CIRCBUF_COMM_H*/
diff --git a/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h b/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h
index 59df44d696a0..d4de1e9293a1 100644
--- a/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h
+++ b/drivers/staging/media/atomisp/pci/camera/util/interface/ia_css_util.h
@@ -100,17 +100,6 @@ bool ia_css_util_res_leq(
bool ia_css_util_resolution_is_zero(
const struct ia_css_resolution resolution);
-/* ISP2401 */
-/**
- * @brief Check if resolution is even
- *
- * @param[in] resolution The resolution to check
- *
- * @returns true if resolution is even
- */
-bool ia_css_util_resolution_is_even(
- const struct ia_css_resolution resolution);
-
/* @brief check width and height
*
* @param[in] stream_format
diff --git a/drivers/staging/media/atomisp/pci/camera/util/src/util.c b/drivers/staging/media/atomisp/pci/camera/util/src/util.c
index 40a71e37cc4e..9d7025a00beb 100644
--- a/drivers/staging/media/atomisp/pci/camera/util/src/util.c
+++ b/drivers/staging/media/atomisp/pci/camera/util/src/util.c
@@ -119,17 +119,6 @@ int ia_css_util_check_vf_out_info(
return 0;
}
-int ia_css_util_check_res(unsigned int width, unsigned int height)
-{
- /* height can be odd number for jpeg/embedded data from ISYS2401 */
- if (((width == 0) ||
- (height == 0) ||
- IS_ODD(width))) {
- return -EINVAL;
- }
- return 0;
-}
-
/* ISP2401 */
bool ia_css_util_res_leq(struct ia_css_resolution a, struct ia_css_resolution b)
{
@@ -142,10 +131,18 @@ bool ia_css_util_resolution_is_zero(const struct ia_css_resolution resolution)
return (resolution.width == 0) || (resolution.height == 0);
}
-/* ISP2401 */
-bool ia_css_util_resolution_is_even(const struct ia_css_resolution resolution)
+int ia_css_util_check_res(unsigned int width, unsigned int height)
{
- return IS_EVEN(resolution.height) && IS_EVEN(resolution.width);
+ const struct ia_css_resolution resolution = { .width = width, .height = height };
+
+ if (ia_css_util_resolution_is_zero(resolution))
+ return -EINVAL;
+
+ /* height can be odd number for jpeg/embedded data from ISYS2401 */
+ if (width & 1)
+ return -EINVAL;
+
+ return 0;
}
bool ia_css_util_is_input_format_raw(enum atomisp_input_format format)
diff --git a/drivers/staging/media/atomisp/pci/gpio_block_defs.h b/drivers/staging/media/atomisp/pci/gpio_block_defs.h
index e1bd638d344a..55c39067a9bf 100644
--- a/drivers/staging/media/atomisp/pci/gpio_block_defs.h
+++ b/drivers/staging/media/atomisp/pci/gpio_block_defs.h
@@ -16,27 +16,10 @@
#ifndef _gpio_block_defs_h_
#define _gpio_block_defs_h_
-#define _HRT_GPIO_BLOCK_REG_ALIGN 4
-
/* R/W registers */
#define _gpio_block_reg_do_e 0
#define _gpio_block_reg_do_select 1
#define _gpio_block_reg_do_0 2
#define _gpio_block_reg_do_1 3
-#define _gpio_block_reg_do_pwm_cnt_0 4
-#define _gpio_block_reg_do_pwm_cnt_1 5
-#define _gpio_block_reg_do_pwm_cnt_2 6
-#define _gpio_block_reg_do_pwm_cnt_3 7
-#define _gpio_block_reg_do_pwm_main_cnt 8
-#define _gpio_block_reg_do_pwm_enable 9
-#define _gpio_block_reg_di_debounce_sel 10
-#define _gpio_block_reg_di_debounce_cnt_0 11
-#define _gpio_block_reg_di_debounce_cnt_1 12
-#define _gpio_block_reg_di_debounce_cnt_2 13
-#define _gpio_block_reg_di_debounce_cnt_3 14
-#define _gpio_block_reg_di_active_level 15
-
-/* read-only registers */
-#define _gpio_block_reg_di 16
#endif /* _gpio_block_defs_h_ */
diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/gpio_global.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/gpio_global.h
index b5f017482f89..06b6cb3842f4 100644
--- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/gpio_global.h
+++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/gpio_global.h
@@ -16,31 +16,8 @@
#ifndef __GPIO_GLOBAL_H_INCLUDED__
#define __GPIO_GLOBAL_H_INCLUDED__
-#define IS_GPIO_VERSION_1
-
#include <gpio_block_defs.h>
-/* pqiao: following part only defines in hive_isp_css_defs.h in fpga system.
- port it here
-*/
-
-/* GPIO pin defines */
-/*#define HIVE_GPIO_CAMERA_BOARD_RESET_PIN_NR 0
-#define HIVE_GPIO_LCD_CLOCK_SELECT_PIN_NR 7
-#define HIVE_GPIO_HDMI_CLOCK_SELECT_PIN_NR 8
-#define HIVE_GPIO_LCD_VERT_FLIP_PIN_NR 8
-#define HIVE_GPIO_LCD_HOR_FLIP_PIN_NR 9
-#define HIVE_GPIO_AS3683_GPIO_P0_PIN_NR 1
-#define HIVE_GPIO_AS3683_DATA_P1_PIN_NR 2
-#define HIVE_GPIO_AS3683_CLK_P2_PIN_NR 3
-#define HIVE_GPIO_AS3683_T1_F0_PIN_NR 4
-#define HIVE_GPIO_AS3683_SFL_F1_PIN_NR 5
-#define HIVE_GPIO_AS3683_STROBE_F2_PIN_NR 6
-#define HIVE_GPIO_MAX1577_EN1_PIN_NR 1
-#define HIVE_GPIO_MAX1577_EN2_PIN_NR 2
-#define HIVE_GPIO_MAX8685A_EN_PIN_NR 3
-#define HIVE_GPIO_MAX8685A_TRIG_PIN_NR 4*/
-
#define HIVE_GPIO_STROBE_TRIGGER_PIN 2
#endif /* __GPIO_GLOBAL_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_local.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_local.h
deleted file mode 100644
index 14013733f826..000000000000
--- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_local.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * Copyright (c) 2010-2015, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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 __GPIO_LOCAL_H_INCLUDED__
-#define __GPIO_LOCAL_H_INCLUDED__
-
-#include "gpio_global.h"
-
-#endif /* __GPIO_LOCAL_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_private.h b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_private.h
index cc60bed71ddb..85fcde0b8615 100644
--- a/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_private.h
+++ b/drivers/staging/media/atomisp/pci/hive_isp_css_common/host/gpio_private.h
@@ -16,13 +16,10 @@
#ifndef __GPIO_PRIVATE_H_INCLUDED__
#define __GPIO_PRIVATE_H_INCLUDED__
-#include "gpio_public.h"
-
-#include "device_access.h"
-
#include "assert_support.h"
+#include "device_access.h"
-STORAGE_CLASS_GPIO_C void gpio_reg_store(
+static inline void gpio_reg_store(
const gpio_ID_t ID,
const unsigned int reg,
const hrt_data value)
@@ -33,7 +30,7 @@ STORAGE_CLASS_GPIO_C void gpio_reg_store(
return;
}
-STORAGE_CLASS_GPIO_C hrt_data gpio_reg_load(
+static inline hrt_data gpio_reg_load(
const gpio_ID_t ID,
const unsigned int reg)
{
diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/assert_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/assert_support.h
index 7382c0bbf7cb..d294ac402de8 100644
--- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/assert_support.h
+++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/assert_support.h
@@ -16,29 +16,6 @@
#ifndef __ASSERT_SUPPORT_H_INCLUDED__
#define __ASSERT_SUPPORT_H_INCLUDED__
-/**
- * The following macro can help to test the size of a struct at compile
- * time rather than at run-time. It does not work for all compilers; see
- * below.
- *
- * Depending on the value of 'condition', the following macro is expanded to:
- * - condition==true:
- * an expression containing an array declaration with negative size,
- * usually resulting in a compilation error
- * - condition==false:
- * (void) 1; // C statement with no effect
- *
- * example:
- * COMPILATION_ERROR_IF( sizeof(struct host_sp_queues) != SIZE_OF_HOST_SP_QUEUES_STRUCT);
- *
- * verify that the macro indeed triggers a compilation error with your compiler:
- * COMPILATION_ERROR_IF( sizeof(struct host_sp_queues) != (sizeof(struct host_sp_queues)+1) );
- *
- * Not all compilers will trigger an error with this macro; use a search engine to search for
- * BUILD_BUG_ON to find other methods.
- */
-#define COMPILATION_ERROR_IF(condition) ((void)sizeof(char[1 - 2 * !!(condition)]))
-
/* Compile time assertion */
#ifndef CT_ASSERT
#define CT_ASSERT(cnd) ((void)sizeof(char[(cnd) ? 1 : -1]))
diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/gpio.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/gpio.h
deleted file mode 100644
index 6f16ca77cf75..000000000000
--- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/gpio.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * Copyright (c) 2015, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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 __GPIO_H_INCLUDED__
-#define __GPIO_H_INCLUDED__
-
-/*
- * This file is included on every cell {SP,ISP,host} and on every system
- * that uses the input system device(s). It defines the API to DLI bridge
- *
- * System and cell specific interfaces and inline code are included
- * conditionally through Makefile path settings.
- *
- * - . system and cell agnostic interfaces, constants and identifiers
- * - public: system agnostic, cell specific interfaces
- * - private: system dependent, cell specific interfaces & inline implementations
- * - global: system specific constants and identifiers
- * - local: system and cell specific constants and identifiers
- */
-
-#include "system_local.h"
-#include "gpio_local.h"
-
-#ifndef __INLINE_GPIO__
-#define STORAGE_CLASS_GPIO_H extern
-#define STORAGE_CLASS_GPIO_C
-#include "gpio_public.h"
-#else /* __INLINE_GPIO__ */
-#define STORAGE_CLASS_GPIO_H static inline
-#define STORAGE_CLASS_GPIO_C static inline
-#include "gpio_private.h"
-#endif /* __INLINE_GPIO__ */
-
-#endif /* __GPIO_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gpio_public.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gpio_public.h
deleted file mode 100644
index 13df9b57a5fb..000000000000
--- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/host/gpio_public.h
+++ /dev/null
@@ -1,46 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0 */
-/*
- * Support for Intel Camera Imaging ISP subsystem.
- * Copyright (c) 2015, Intel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope 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 __GPIO_PUBLIC_H_INCLUDED__
-#define __GPIO_PUBLIC_H_INCLUDED__
-
-#include "system_local.h"
-
-/*! Write to a control register of GPIO[ID]
-
- \param ID[in] GPIO identifier
- \param reg_addr[in] register byte address
- \param value[in] The data to be written
-
- \return none, GPIO[ID].ctrl[reg] = value
- */
-STORAGE_CLASS_GPIO_H void gpio_reg_store(
- const gpio_ID_t ID,
- const unsigned int reg_addr,
- const hrt_data value);
-
-/*! Read from a control register of GPIO[ID]
-
- \param ID[in] GPIO identifier
- \param reg_addr[in] register byte address
- \param value[in] The data to be written
-
- \return GPIO[ID].ctrl[reg]
- */
-STORAGE_CLASS_GPIO_H hrt_data gpio_reg_load(
- const gpio_ID_t ID,
- const unsigned int reg_addr);
-
-#endif /* __GPIO_PUBLIC_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h
index a444ec14ff9d..7349943bba2b 100644
--- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h
+++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/math_support.h
@@ -16,133 +16,27 @@
#ifndef __MATH_SUPPORT_H
#define __MATH_SUPPORT_H
-#include <linux/kernel.h> /* Override the definition of max/min from linux kernel*/
-
-#define IS_ODD(a) ((a) & 0x1)
-#define IS_EVEN(a) (!IS_ODD(a))
+/* Override the definition of max/min from Linux kernel */
+#include <linux/minmax.h>
/* force a value to a lower even value */
#define EVEN_FLOOR(x) ((x) & ~1)
-/* ISP2401 */
-/* If the number is odd, find the next even number */
-#define EVEN_CEIL(x) ((IS_ODD(x)) ? ((x) + 1) : (x))
-
-/* A => B */
-#define IMPLIES(a, b) (!(a) || (b))
-
/* for preprocessor and array sizing use MIN and MAX
otherwise use min and max */
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#define ROUND_DIV(a, b) (((b) != 0) ? ((a) + ((b) >> 1)) / (b) : 0)
#define CEIL_DIV(a, b) (((b) != 0) ? ((a) + (b) - 1) / (b) : 0)
#define CEIL_MUL(a, b) (CEIL_DIV(a, b) * (b))
#define CEIL_MUL2(a, b) (((a) + (b) - 1) & ~((b) - 1))
#define CEIL_SHIFT(a, b) (((a) + (1 << (b)) - 1) >> (b))
#define CEIL_SHIFT_MUL(a, b) (CEIL_SHIFT(a, b) << (b))
-#define ROUND_HALF_DOWN_DIV(a, b) (((b) != 0) ? ((a) + (b / 2) - 1) / (b) : 0)
-#define ROUND_HALF_DOWN_MUL(a, b) (ROUND_HALF_DOWN_DIV(a, b) * (b))
-
-/*To Find next power of 2 number from x */
-#define bit2(x) ((x) | ((x) >> 1))
-#define bit4(x) (bit2(x) | (bit2(x) >> 2))
-#define bit8(x) (bit4(x) | (bit4(x) >> 4))
-#define bit16(x) (bit8(x) | (bit8(x) >> 8))
-#define bit32(x) (bit16(x) | (bit16(x) >> 16))
-#define NEXT_POWER_OF_2(x) (bit32(x - 1) + 1)
-
-/* min and max should not be macros as they will evaluate their arguments twice.
- if you really need a macro (e.g. for CPP or for initializing an array)
- use MIN() and MAX(), otherwise use min() and max().
-
-*/
#if !defined(PIPE_GENERATION)
-/*
-This macro versions are added back as we are mixing types in usage of inline.
-This causes corner cases of calculations to be incorrect due to conversions
-between signed and unsigned variables or overflows.
-Before the addition of the inline functions, max, min and ceil_div were macros
-and therefore adding them back.
-
-Leaving out the other math utility functions as they are newly added
-*/
-
#define ceil_div(a, b) (CEIL_DIV(a, b))
-static inline unsigned int ceil_mul(unsigned int a, unsigned int b)
-{
- return CEIL_MUL(a, b);
-}
-
-static inline unsigned int ceil_mul2(unsigned int a, unsigned int b)
-{
- return CEIL_MUL2(a, b);
-}
-
-static inline unsigned int ceil_shift(unsigned int a, unsigned int b)
-{
- return CEIL_SHIFT(a, b);
-}
-
-static inline unsigned int ceil_shift_mul(unsigned int a, unsigned int b)
-{
- return CEIL_SHIFT_MUL(a, b);
-}
-
-/* ISP2401 */
-static inline unsigned int round_half_down_div(unsigned int a, unsigned int b)
-{
- return ROUND_HALF_DOWN_DIV(a, b);
-}
-
-/* ISP2401 */
-static inline unsigned int round_half_down_mul(unsigned int a, unsigned int b)
-{
- return ROUND_HALF_DOWN_MUL(a, b);
-}
-
-/* @brief Next Power of Two
- *
- * @param[in] unsigned number
- *
- * @return next power of two
- *
- * This function rounds input to the nearest power of 2 (2^x)
- * towards infinity
- *
- * Input Range: 0 .. 2^(8*sizeof(int)-1)
- *
- * IF input is a power of 2
- * out = in
- * OTHERWISE
- * out = 2^(ceil(log2(in))
- *
- */
-
-static inline unsigned int ceil_pow2(unsigned int a)
-{
- if (a == 0) {
- return 1;
- }
- /* IF input is already a power of two*/
- else if ((!((a) & ((a) - 1)))) {
- return a;
- } else {
- unsigned int v = a;
-
- v |= v >> 1;
- v |= v >> 2;
- v |= v >> 4;
- v |= v >> 8;
- v |= v >> 16;
- return (v + 1);
- }
-}
-
#endif /* !defined(PIPE_GENERATION) */
/*
diff --git a/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h b/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h
index b996ee54d4a5..9a640f18eed9 100644
--- a/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h
+++ b/drivers/staging/media/atomisp/pci/hive_isp_css_include/type_support.h
@@ -33,9 +33,10 @@
#define CHAR_BIT (8)
-#include <linux/types.h>
-#include <linux/limits.h>
#include <linux/errno.h>
+#include <linux/limits.h>
+#include <linux/types.h>
+
#define HOST_ADDRESS(x) (unsigned long)(x)
#endif /* __TYPE_SUPPORT_H_INCLUDED__ */
diff --git a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
index 095cd0ba8c21..b90efac771e2 100644
--- a/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
+++ b/drivers/staging/media/atomisp/pci/hmm/hmm_bo.c
@@ -288,7 +288,7 @@ static void __bo_take_off_handling(struct hmm_buffer_object *bo)
/* 3. when bo->prev != NULL && bo->next == NULL, bo is not a rbtree
* node, bo is the last element of the linked list after rbtree
* node, to take off this bo, we just need set the "prev/next"
- * pointers to NULL, the free rbtree stays unchaged
+ * pointers to NULL, the free rbtree stays unchanged
*/
} else if (bo->prev && !bo->next) {
bo->prev->next = NULL;
@@ -296,7 +296,7 @@ static void __bo_take_off_handling(struct hmm_buffer_object *bo)
/* 4. when bo->prev != NULL && bo->next != NULL ,bo is not a rbtree
* node, bo is in the middle of the linked list after rbtree node,
* to take off this bo, we just set take the "prev/next" pointers
- * to NULL, the free rbtree stays unchaged
+ * to NULL, the free rbtree stays unchanged
*/
} else if (bo->prev && bo->next) {
bo->next->prev = bo->prev;
diff --git a/drivers/staging/media/atomisp/pci/ia_css_3a.h b/drivers/staging/media/atomisp/pci/ia_css_3a.h
index 70cfc915cc56..fc2075c7bd01 100644
--- a/drivers/staging/media/atomisp/pci/ia_css_3a.h
+++ b/drivers/staging/media/atomisp/pci/ia_css_3a.h
@@ -20,6 +20,9 @@
* This file contains types used for 3A statistics
*/
+#include <linux/build_bug.h>
+
+#include <math_support.h>
#include <type_support.h>
#include "ia_css_types.h"
#include "ia_css_err.h"
@@ -79,6 +82,8 @@ struct ia_css_isp_3a_statistics {
SIZE_OF_IA_CSS_PTR + \
4 * sizeof(uint32_t))
+static_assert(sizeof(struct ia_css_isp_3a_statistics) == SIZE_OF_IA_CSS_ISP_3A_STATISTICS_STRUCT);
+
/* Map with host-side pointers to ISP-format statistics.
* These pointers can either be copies of ISP data or memory mapped
* ISP pointers.
diff --git a/drivers/staging/media/atomisp/pci/ia_css_dvs.h b/drivers/staging/media/atomisp/pci/ia_css_dvs.h
index 3367dfd64050..41a81561bbef 100644
--- a/drivers/staging/media/atomisp/pci/ia_css_dvs.h
+++ b/drivers/staging/media/atomisp/pci/ia_css_dvs.h
@@ -20,6 +20,8 @@
* This file contains types for DVS statistics
*/
+#include <linux/build_bug.h>
+
#include <type_support.h>
#include "ia_css_types.h"
#include "ia_css_err.h"
@@ -55,6 +57,8 @@ struct ia_css_isp_skc_dvs_statistics;
((3 * SIZE_OF_IA_CSS_PTR) + \
(4 * sizeof(uint32_t)))
+static_assert(sizeof(struct ia_css_isp_dvs_statistics) == SIZE_OF_IA_CSS_ISP_DVS_STATISTICS_STRUCT);
+
/* Map with host-side pointers to ISP-format statistics.
* These pointers can either be copies of ISP data or memory mapped
* ISP pointers.
diff --git a/drivers/staging/media/atomisp/pci/ia_css_metadata.h b/drivers/staging/media/atomisp/pci/ia_css_metadata.h
index 9eb1b76a3b2a..a3e759a3eee7 100644
--- a/drivers/staging/media/atomisp/pci/ia_css_metadata.h
+++ b/drivers/staging/media/atomisp/pci/ia_css_metadata.h
@@ -20,6 +20,8 @@
* This file contains structure for processing sensor metadata.
*/
+#include <linux/build_bug.h>
+
#include <type_support.h>
#include "ia_css_types.h"
#include "ia_css_stream_format.h"
@@ -50,6 +52,8 @@ struct ia_css_metadata {
#define SIZE_OF_IA_CSS_METADATA_STRUCT sizeof(struct ia_css_metadata)
+static_assert(sizeof(struct ia_css_metadata) == SIZE_OF_IA_CSS_METADATA_STRUCT);
+
/* @brief Allocate a metadata buffer.
* @param[in] metadata_info Metadata info struct, contains details on metadata buffers.
* @return Pointer of metadata buffer or NULL (if error)
diff --git a/drivers/staging/media/atomisp/pci/ia_css_types.h b/drivers/staging/media/atomisp/pci/ia_css_types.h
index 6e34d401f9df..f5df564c86e8 100644
--- a/drivers/staging/media/atomisp/pci/ia_css_types.h
+++ b/drivers/staging/media/atomisp/pci/ia_css_types.h
@@ -84,6 +84,8 @@ struct ia_css_state_memory_offsets;
/* Virtual address within the CSS address space. */
typedef u32 ia_css_ptr;
+#define SIZE_OF_IA_CSS_PTR sizeof(uint32_t)
+
/* Generic resolution structure.
*/
struct ia_css_resolution {
diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.c
index bfea78171f7c..e4fc90f88e24 100644
--- a/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.c
+++ b/drivers/staging/media/atomisp/pci/isp/kernels/eed1_8/ia_css_eed1_8.host.c
@@ -161,7 +161,7 @@ ia_css_eed1_8_vmem_encode(
assert(fcinv_x[j] > fcinv_x[j - 1]);
}
- /* The implementation of the calulating 1/x is based on the availability
+ /* The implementation of the calculating 1/x is based on the availability
* of the OP_vec_shuffle16 operation.
* A 64 element vector is split up in 4 blocks of 16 element. Each array is copied to
* a vector 4 times, (starting at 0, 16, 32 and 48). All array elements are copied or
diff --git a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.c b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.c
index 9c9d9b9a453e..70132d955e9b 100644
--- a/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.c
+++ b/drivers/staging/media/atomisp/pci/isp/kernels/xnr/xnr_3.0/ia_css_xnr3.host.c
@@ -13,6 +13,8 @@
* more details.
*/
+#include <linux/log2.h>
+
#include "type_support.h"
#include "math_support.h"
#include "sh_css_defs.h"
@@ -137,9 +139,7 @@ ia_css_xnr3_encode(
unsigned int size)
{
int kernel_size = XNR_FILTER_SIZE;
- /* The adjust factor is the next power of 2
- w.r.t. the kernel size*/
- int adjust_factor = ceil_pow2(kernel_size);
+ int adjust_factor = roundup_pow_of_two(kernel_size);
s32 max_diff = (1 << (ISP_VEC_ELEMBITS - 1)) - 1;
s32 min_diff = -(1 << (ISP_VEC_ELEMBITS - 1));
diff --git a/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c b/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c
index 130662f8e768..b0f904a5e442 100644
--- a/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c
+++ b/drivers/staging/media/atomisp/pci/runtime/binary/src/binary.c
@@ -43,8 +43,6 @@
#include "assert_support.h"
-#define IMPLIES(a, b) (!(a) || (b)) /* A => B */
-
static struct ia_css_binary_xinfo *all_binaries; /* ISP binaries only (no SP) */
static struct ia_css_binary_xinfo
*binary_infos[IA_CSS_BINARY_NUM_MODES] = { NULL, };
diff --git a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c
index 9982e77716a7..35c98fb8d6e8 100644
--- a/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c
+++ b/drivers/staging/media/atomisp/pci/runtime/debug/src/ia_css_debug.c
@@ -848,7 +848,7 @@ void ia_css_debug_enable_sp_sleep_mode(enum ia_css_sp_sleep_mode mode)
fw = &sh_css_sp_fw;
HIVE_ADDR_sp_sleep_mode = fw->info.sp.sleep_mode;
- (void)HIVE_ADDR_sp_sleep_mode; /* Suppres warnings in CRUN */
+ (void)HIVE_ADDR_sp_sleep_mode; /* Suppress warnings in CRUN */
sp_dmem_store_uint32(SP0_ID,
(unsigned int)sp_address_of(sp_sleep_mode),
@@ -1334,7 +1334,7 @@ ia_css_debug_pipe_graph_dump_stage(
if (stage->stage_num == 0) {
/*
- * There are some implicite assumptions about which bin is the
+ * There are some implicit assumptions about which bin is the
* input binary e.g. which one is connected to the input system
* Priority:
* 1) sp_raw_copy bin has highest priority
diff --git a/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h b/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h
index 78e0f3096f60..de68616482f0 100644
--- a/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h
+++ b/drivers/staging/media/atomisp/pci/runtime/spctrl/interface/ia_css_spctrl_comm.h
@@ -16,6 +16,8 @@
#ifndef __IA_CSS_SPCTRL_COMM_H__
#define __IA_CSS_SPCTRL_COMM_H__
+#include <linux/build_bug.h>
+
#include <type_support.h>
/* state of SP */
@@ -43,4 +45,6 @@ struct ia_css_sp_init_dmem_cfg {
(4 * sizeof(uint32_t)) + \
(1 * sizeof(sp_ID_t))
+static_assert(sizeof(struct ia_css_sp_init_dmem_cfg) == SIZE_OF_IA_CSS_SP_INIT_DMEM_CFG_STRUCT);
+
#endif /* __IA_CSS_SPCTRL_COMM_H__ */
diff --git a/drivers/staging/media/atomisp/pci/sh_css.c b/drivers/staging/media/atomisp/pci/sh_css.c
index 42a69b26db01..01f0b8a33c99 100644
--- a/drivers/staging/media/atomisp/pci/sh_css.c
+++ b/drivers/staging/media/atomisp/pci/sh_css.c
@@ -66,8 +66,8 @@
#include "sp.h" /* cnd_sp_irq_enable() */
#include "isp.h" /* cnd_isp_irq_enable, ISP_VEC_NELEMS */
#include "gp_device.h" /* gp_device_reg_store() */
-#define __INLINE_GPIO__
-#include "gpio.h"
+#include <gpio_global.h>
+#include <gpio_private.h>
#include "timed_ctrl.h"
#include "ia_css_inputfifo.h"
#define WITH_PC_MONITORING 0
@@ -1345,47 +1345,9 @@ ia_css_init(struct device *dev, const struct ia_css_env *env,
{
int err;
ia_css_spctrl_cfg spctrl_cfg;
-
void (*flush_func)(struct ia_css_acc_fw *fw);
hrt_data select, enable;
- /*
- * The C99 standard does not specify the exact object representation of structs;
- * the representation is compiler dependent.
- *
- * The structs that are communicated between host and SP/ISP should have the
- * exact same object representation. The compiler that is used to compile the
- * firmware is hivecc.
- *
- * To check if a different compiler, used to compile a host application, uses
- * another object representation, macros are defined specifying the size of
- * the structs as expected by the firmware.
- *
- * A host application shall verify that a sizeof( ) of the struct is equal to
- * the SIZE_OF_XXX macro of the corresponding struct. If they are not
- * equal, functionality will break.
- */
-
- /* Check struct sh_css_ddr_address_map */
- COMPILATION_ERROR_IF(sizeof(struct sh_css_ddr_address_map) != SIZE_OF_SH_CSS_DDR_ADDRESS_MAP_STRUCT);
- /* Check struct host_sp_queues */
- COMPILATION_ERROR_IF(sizeof(struct host_sp_queues) != SIZE_OF_HOST_SP_QUEUES_STRUCT);
- COMPILATION_ERROR_IF(sizeof(struct ia_css_circbuf_desc_s) != SIZE_OF_IA_CSS_CIRCBUF_DESC_S_STRUCT);
- COMPILATION_ERROR_IF(sizeof(struct ia_css_circbuf_elem_s) != SIZE_OF_IA_CSS_CIRCBUF_ELEM_S_STRUCT);
-
- /* Check struct host_sp_communication */
- COMPILATION_ERROR_IF(sizeof(struct host_sp_communication) != SIZE_OF_HOST_SP_COMMUNICATION_STRUCT);
- COMPILATION_ERROR_IF(sizeof(struct sh_css_event_irq_mask) != SIZE_OF_SH_CSS_EVENT_IRQ_MASK_STRUCT);
-
- /* Check struct sh_css_hmm_buffer */
- COMPILATION_ERROR_IF(sizeof(struct sh_css_hmm_buffer) != SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT);
- COMPILATION_ERROR_IF(sizeof(struct ia_css_isp_3a_statistics) != SIZE_OF_IA_CSS_ISP_3A_STATISTICS_STRUCT);
- COMPILATION_ERROR_IF(sizeof(struct ia_css_isp_dvs_statistics) != SIZE_OF_IA_CSS_ISP_DVS_STATISTICS_STRUCT);
- COMPILATION_ERROR_IF(sizeof(struct ia_css_metadata) != SIZE_OF_IA_CSS_METADATA_STRUCT);
-
- /* Check struct ia_css_init_dmem_cfg */
- COMPILATION_ERROR_IF(sizeof(struct ia_css_sp_init_dmem_cfg) != SIZE_OF_IA_CSS_SP_INIT_DMEM_CFG_STRUCT);
-
if (!env)
return -EINVAL;
@@ -1401,10 +1363,8 @@ ia_css_init(struct device *dev, const struct ia_css_env *env,
ia_css_device_access_init(&env->hw_access_env);
- select = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_select)
- & (~GPIO_FLASH_PIN_MASK);
- enable = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_e)
- | GPIO_FLASH_PIN_MASK;
+ select = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_select) & ~GPIO_FLASH_PIN_MASK;
+ enable = gpio_reg_load(GPIO0_ID, _gpio_block_reg_do_e) | GPIO_FLASH_PIN_MASK;
sh_css_mmu_set_page_table_base_index(mmu_l1_base);
my_css_save.mmu_base = mmu_l1_base;
diff --git a/drivers/staging/media/atomisp/pci/sh_css_frac.h b/drivers/staging/media/atomisp/pci/sh_css_frac.h
index 8f08df5c88cc..b90b5b330dfa 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_frac.h
+++ b/drivers/staging/media/atomisp/pci/sh_css_frac.h
@@ -16,7 +16,9 @@
#ifndef __SH_CSS_FRAC_H
#define __SH_CSS_FRAC_H
-#include <math_support.h>
+#include <linux/minmax.h>
+
+#include "mamoiada_params.h"
#define sISP_REG_BIT ISP_VEC_ELEMBITS
#define uISP_REG_BIT ((unsigned int)(sISP_REG_BIT - 1))
diff --git a/drivers/staging/media/atomisp/pci/sh_css_internal.h b/drivers/staging/media/atomisp/pci/sh_css_internal.h
index bef2b8c5132b..a2d972ea3fa0 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_internal.h
+++ b/drivers/staging/media/atomisp/pci/sh_css_internal.h
@@ -16,11 +16,13 @@
#ifndef _SH_CSS_INTERNAL_H_
#define _SH_CSS_INTERNAL_H_
+#include <linux/build_bug.h>
+#include <linux/stdarg.h>
+
#include <system_global.h>
#include <math_support.h>
#include <type_support.h>
#include <platform_support.h>
-#include <linux/stdarg.h>
#include "input_formatter.h"
#include "input_system.h"
@@ -104,7 +106,6 @@
*/
#define CALC_ALIGNMENT_MEMBER(x, y) (CEIL_MUL(x, y) - x)
#define SIZE_OF_HRT_VADDRESS sizeof(hive_uint32)
-#define SIZE_OF_IA_CSS_PTR sizeof(uint32_t)
/* Number of SP's */
#define NUM_OF_SPS 1
@@ -202,6 +203,8 @@ struct sh_css_ddr_address_map {
(SH_CSS_MAX_STAGES * IA_CSS_NUM_MEMORIES * SIZE_OF_HRT_VADDRESS) + \
(16 * SIZE_OF_HRT_VADDRESS))
+static_assert(sizeof(struct sh_css_ddr_address_map) == SIZE_OF_SH_CSS_DDR_ADDRESS_MAP_STRUCT);
+
/* xmem address map allocation per pipeline */
struct sh_css_ddr_address_map_size {
size_t isp_param;
@@ -508,7 +511,7 @@ struct sh_css_sp_pipeline {
* of the associated pipe. Dynamic means that the data address can
* change with every (frame) iteration of the associated pipe
*
- * s3a and dis are now also dynamic but (stil) handled separately
+ * s3a and dis are now also dynamic but (still) handled separately
*/
#define SH_CSS_NUM_DYNAMIC_FRAME_IDS (3)
@@ -596,7 +599,7 @@ struct sh_css_sp_stage {
/*
* Time: 2012-07-19, 17:40.
- * Note: Add a new data memeber "debug" in "sh_css_sp_group". This
+ * Note: Add a new data member "debug" in "sh_css_sp_group". This
* data member is used to pass the debugging command from the
* Host to the SP.
*
@@ -705,6 +708,8 @@ struct sh_css_hmm_buffer {
SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT + \
CALC_ALIGNMENT_MEMBER(SIZE_OF_IA_CSS_CLOCK_TICK_STRUCT, 8))
+static_assert(sizeof(struct sh_css_hmm_buffer) == SIZE_OF_SH_CSS_HMM_BUFFER_STRUCT);
+
enum sh_css_queue_type {
sh_css_invalid_queue_type = -1,
sh_css_host2sp_buffer_queue,
@@ -724,6 +729,8 @@ struct sh_css_event_irq_mask {
#define SIZE_OF_SH_CSS_EVENT_IRQ_MASK_STRUCT \
(2 * sizeof(uint16_t))
+static_assert(sizeof(struct sh_css_event_irq_mask) == SIZE_OF_SH_CSS_EVENT_IRQ_MASK_STRUCT);
+
struct host_sp_communication {
/*
* Don't use enum host2sp_commands, because the sizeof an enum is
@@ -761,6 +768,8 @@ struct host_sp_communication {
((3 + N_CSI_PORTS) * sizeof(uint32_t)) + \
(NR_OF_PIPELINES * SIZE_OF_SH_CSS_EVENT_IRQ_MASK_STRUCT))
+static_assert(sizeof(struct host_sp_communication) == SIZE_OF_HOST_SP_COMMUNICATION_STRUCT);
+
struct host_sp_queues {
/*
* Queues for the dynamic frame information,
@@ -831,6 +840,8 @@ struct host_sp_queues {
#define SIZE_OF_HOST_SP_QUEUES_STRUCT \
(SIZE_OF_QUEUES_ELEMS + SIZE_OF_QUEUES_DESC)
+static_assert(sizeof(struct host_sp_queues) == SIZE_OF_HOST_SP_QUEUES_STRUCT);
+
extern int __printf(1, 0) (*sh_css_printf)(const char *fmt, va_list args);
static inline void __printf(1, 2) sh_css_print(const char *fmt, ...)
diff --git a/drivers/staging/media/atomisp/pci/sh_css_sp.c b/drivers/staging/media/atomisp/pci/sh_css_sp.c
index 29e5bee78c20..c2ab70f8fafe 100644
--- a/drivers/staging/media/atomisp/pci/sh_css_sp.c
+++ b/drivers/staging/media/atomisp/pci/sh_css_sp.c
@@ -1022,8 +1022,10 @@ sh_css_sp_init_stage(struct ia_css_binary *binary,
*/
if (binary->info->sp.pipeline.mode == IA_CSS_BINARY_MODE_PREVIEW &&
(binary->vf_downscale_log2 > 0)) {
- /* TODO: Remove this after preview output decimation is fixed
- * by configuring out&vf info fiels properly */
+ /*
+ * TODO: Remove this after preview output decimation is fixed
+ * by configuring out&vf info fields properly.
+ */
sh_css_sp_stage.frames.out[0].info.padded_width
<<= binary->vf_downscale_log2;
sh_css_sp_stage.frames.out[0].info.res.width
@@ -1325,7 +1327,7 @@ bool sh_css_write_host2sp_command(enum host2sp_commands host2sp_command)
host2sp_command)
/ sizeof(int);
enum host2sp_commands last_cmd = host2sp_cmd_error;
- (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */
+ (void)HIVE_ADDR_host_sp_com; /* Suppress warnings in CRUN */
/* Previous command must be handled by SP (by design) */
last_cmd = load_sp_array_uint(host_sp_com, offset);
@@ -1343,7 +1345,7 @@ sh_css_read_host2sp_command(void)
unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
unsigned int offset = (unsigned int)offsetof(struct host_sp_communication, host2sp_command)
/ sizeof(int);
- (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */
+ (void)HIVE_ADDR_host_sp_com; /* Suppress warnings in CRUN */
return (enum host2sp_commands)load_sp_array_uint(host_sp_com, offset);
}
@@ -1351,7 +1353,7 @@ sh_css_read_host2sp_command(void)
* Frame data is no longer part of the sp_stage structure but part of a
* separate structure. The aim is to make the sp_data struct static
* (it defines a pipeline) and that the dynamic (per frame) data is stored
- * separetly.
+ * separately.
*
* This function must be called first every where were you start constructing
* a new pipeline by defining one or more stages with use of variable
@@ -1364,7 +1366,7 @@ sh_css_init_host2sp_frame_data(void)
/* Clean table */
unsigned int HIVE_ADDR_host_sp_com = sh_css_sp_fw.info.sp.host_sp_com;
- (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */
+ (void)HIVE_ADDR_host_sp_com; /* Suppress warnings in CRUN */
/*
* rvanimme: don't clean it to save static frame info line ref_in
* ref_out, and tnr_frames. Once this static data is in a
@@ -1544,7 +1546,7 @@ ia_css_pipe_set_irq_mask(struct ia_css_pipe *pipe,
* - different assert for Linux and Windows
*/
- (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */
+ (void)HIVE_ADDR_host_sp_com; /* Suppress warnings in CRUN */
IA_CSS_LOG("or_mask=%x, and_mask=%x", or_mask, and_mask);
event_irq_mask.or_mask = (uint16_t)or_mask;
@@ -1573,7 +1575,7 @@ ia_css_event_get_irq_mask(const struct ia_css_pipe *pipe,
struct sh_css_event_irq_mask event_irq_mask;
unsigned int pipe_num;
- (void)HIVE_ADDR_host_sp_com; /* Suppres warnings in CRUN */
+ (void)HIVE_ADDR_host_sp_com; /* Suppress warnings in CRUN */
IA_CSS_ENTER_LEAVE("");
@@ -1623,7 +1625,7 @@ sh_css_sp_start_isp(void)
if (sp_running)
return;
- (void)HIVE_ADDR_sp_sw_state; /* Suppres warnings in CRUN */
+ (void)HIVE_ADDR_sp_sw_state; /* Suppress warnings in CRUN */
/* no longer here, sp started immediately */
/*ia_css_debug_pipe_graph_dump_epilogue();*/
@@ -1664,7 +1666,7 @@ ia_css_isp_has_started(void)
{
const struct ia_css_fw_info *fw = &sh_css_sp_fw;
unsigned int HIVE_ADDR_ia_css_ispctrl_sp_isp_started = fw->info.sp.isp_started;
- (void)HIVE_ADDR_ia_css_ispctrl_sp_isp_started; /* Suppres warnings in CRUN */
+ (void)HIVE_ADDR_ia_css_ispctrl_sp_isp_started; /* Suppress warnings in CRUN */
return (bool)load_sp_uint(ia_css_ispctrl_sp_isp_started);
}
@@ -1719,7 +1721,7 @@ sh_css_sp_set_dma_sw_reg(int dma_id,
sw_reg =
sh_css_sp_group.debug.dma_sw_reg;
- /* get the offest of the target bit */
+ /* get the offset of the target bit */
bit_offset = (8 * request_type) + channel_id;
/* clear the value of the target bit */
diff --git a/drivers/staging/media/av7110/Kconfig b/drivers/staging/media/av7110/Kconfig
index 9faf9d2d4001..0722df9e6a41 100644
--- a/drivers/staging/media/av7110/Kconfig
+++ b/drivers/staging/media/av7110/Kconfig
@@ -51,28 +51,6 @@ config DVB_AV7110_OSD
All other people say N.
-config DVB_BUDGET_PATCH
- tristate "AV7110 cards with Budget Patch"
- depends on DVB_BUDGET_CORE && I2C
- depends on DVB_AV7110
- select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_VES1X93 if MEDIA_SUBDRV_AUTOSELECT
- select DVB_TDA8083 if MEDIA_SUBDRV_AUTOSELECT
- help
- Support for Budget Patch (full TS) modification on
- SAA7146+AV7110 based cards (DVB-S cards). This
- driver doesn't use onboard MPEG2 decoder. The
- card is driven in Budget-only mode. Card is
- required to have loaded firmware to tune properly.
- Firmware can be loaded by insertion and removal of
- standard AV7110 driver prior to loading this
- driver.
-
- Say Y if you own such a card and want to use it.
-
- To compile this driver as a module, choose M here: the
- module will be called budget-patch.
-
if DVB_AV7110
# Frontend driver that it is used only by AV7110 driver
diff --git a/drivers/staging/media/av7110/Makefile b/drivers/staging/media/av7110/Makefile
index 307b267598ea..f4bbb535d988 100644
--- a/drivers/staging/media/av7110/Makefile
+++ b/drivers/staging/media/av7110/Makefile
@@ -10,8 +10,6 @@ ifdef CONFIG_DVB_AV7110_IR
dvb-ttpci-objs += av7110_ir.o
endif
-obj-$(CONFIG_DVB_BUDGET_PATCH) += budget-patch.o
-
obj-$(CONFIG_DVB_AV7110) += dvb-ttpci.o
obj-$(CONFIG_DVB_SP8870) += sp8870.o
diff --git a/drivers/staging/media/av7110/TODO b/drivers/staging/media/av7110/TODO
deleted file mode 100644
index 60062d8441b3..000000000000
--- a/drivers/staging/media/av7110/TODO
+++ /dev/null
@@ -1,3 +0,0 @@
-- This driver is too old and relies on a different API.
- Drop it from Kernel on a couple of versions.
-- Cleanup patches for the drivers here won't be accepted.
diff --git a/drivers/staging/media/av7110/audio-bilingual-channel-select.rst b/drivers/staging/media/av7110/audio-bilingual-channel-select.rst
deleted file mode 100644
index 33b5363317f1..000000000000
--- a/drivers/staging/media/av7110/audio-bilingual-channel-select.rst
+++ /dev/null
@@ -1,58 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_BILINGUAL_CHANNEL_SELECT:
-
-==============================
-AUDIO_BILINGUAL_CHANNEL_SELECT
-==============================
-
-Name
-----
-
-AUDIO_BILINGUAL_CHANNEL_SELECT
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_BILINGUAL_CHANNEL_SELECT
-
-``int ioctl(int fd, AUDIO_BILINGUAL_CHANNEL_SELECT, struct audio_channel_select *select)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - audio_channel_select_t ch
-
- - Select the output format of the audio (mono left/right, stereo).
-
-Description
------------
-
-This ioctl is obsolete. Do not use in new drivers. It has been replaced
-by the V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_MULTILINGUAL_PLAYBACK`` control
-for MPEG decoders controlled through V4L2.
-
-This ioctl call asks the Audio Device to select the requested channel
-for bilingual streams if possible.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-channel-select.rst b/drivers/staging/media/av7110/audio-channel-select.rst
deleted file mode 100644
index 74093df92a68..000000000000
--- a/drivers/staging/media/av7110/audio-channel-select.rst
+++ /dev/null
@@ -1,57 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_CHANNEL_SELECT:
-
-====================
-AUDIO_CHANNEL_SELECT
-====================
-
-Name
-----
-
-AUDIO_CHANNEL_SELECT
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_CHANNEL_SELECT
-
-``int ioctl(int fd, AUDIO_CHANNEL_SELECT, struct audio_channel_select *select)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - audio_channel_select_t ch
-
- - Select the output format of the audio (mono left/right, stereo).
-
-Description
------------
-
-This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
-V4L2 ``V4L2_CID_MPEG_AUDIO_DEC_PLAYBACK`` control instead.
-
-This ioctl call asks the Audio Device to select the requested channel if
-possible.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-clear-buffer.rst b/drivers/staging/media/av7110/audio-clear-buffer.rst
deleted file mode 100644
index a0ebb0278260..000000000000
--- a/drivers/staging/media/av7110/audio-clear-buffer.rst
+++ /dev/null
@@ -1,48 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_CLEAR_BUFFER:
-
-==================
-AUDIO_CLEAR_BUFFER
-==================
-
-Name
-----
-
-AUDIO_CLEAR_BUFFER
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_CLEAR_BUFFER
-
-``int ioctl(int fd, AUDIO_CLEAR_BUFFER)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
-Description
------------
-
-This ioctl call asks the Audio Device to clear all software and hardware
-buffers of the audio decoder device.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-continue.rst b/drivers/staging/media/av7110/audio-continue.rst
deleted file mode 100644
index a2e9850f37f2..000000000000
--- a/drivers/staging/media/av7110/audio-continue.rst
+++ /dev/null
@@ -1,48 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_CONTINUE:
-
-==============
-AUDIO_CONTINUE
-==============
-
-Name
-----
-
-AUDIO_CONTINUE
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_CONTINUE
-
-``int ioctl(int fd, AUDIO_CONTINUE)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
-Description
------------
-
-This ioctl restarts the decoding and playing process previously paused
-with AUDIO_PAUSE command.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-fclose.rst b/drivers/staging/media/av7110/audio-fclose.rst
deleted file mode 100644
index 77857d578e83..000000000000
--- a/drivers/staging/media/av7110/audio-fclose.rst
+++ /dev/null
@@ -1,51 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _audio_fclose:
-
-========================
-Digital TV audio close()
-========================
-
-Name
-----
-
-Digital TV audio close()
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:function:: int close(int fd)
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
-Description
------------
-
-This system call closes a previously opened audio device.
-
-Return Value
-------------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``EBADF``
-
- - fd is not a valid open file descriptor.
diff --git a/drivers/staging/media/av7110/audio-fopen.rst b/drivers/staging/media/av7110/audio-fopen.rst
deleted file mode 100644
index 774daaab3bad..000000000000
--- a/drivers/staging/media/av7110/audio-fopen.rst
+++ /dev/null
@@ -1,103 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _audio_fopen:
-
-=======================
-Digital TV audio open()
-=======================
-
-Name
-----
-
-Digital TV audio open()
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:function:: int open(const char *deviceName, int flags)
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - const char \*deviceName
-
- - Name of specific audio device.
-
- - .. row 2
-
- - int flags
-
- - A bit-wise OR of the following flags:
-
- - .. row 3
-
- -
- - O_RDONLY read-only access
-
- - .. row 4
-
- -
- - O_RDWR read/write access
-
- - .. row 5
-
- -
- - O_NONBLOCK open in non-blocking mode
-
- - .. row 6
-
- -
- - (blocking mode is the default)
-
-Description
------------
-
-This system call opens a named audio device (e.g.
-/dev/dvb/adapter0/audio0) for subsequent use. When an open() call has
-succeeded, the device will be ready for use. The significance of
-blocking or non-blocking mode is described in the documentation for
-functions where there is a difference. It does not affect the semantics
-of the open() call itself. A device opened in blocking mode can later be
-put into non-blocking mode (and vice versa) using the F_SETFL command
-of the fcntl system call. This is a standard system call, documented in
-the Linux manual page for fcntl. Only one user can open the Audio Device
-in O_RDWR mode. All other attempts to open the device in this mode will
-fail, and an error code will be returned. If the Audio Device is opened
-in O_RDONLY mode, the only ioctl call that can be used is
-AUDIO_GET_STATUS. All other call will return with an error code.
-
-Return Value
-------------
-
-.. tabularcolumns:: |p{2.5cm}|p{15.0cm}|
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``ENODEV``
-
- - Device driver not loaded/available.
-
- - .. row 2
-
- - ``EBUSY``
-
- - Device or resource busy.
-
- - .. row 3
-
- - ``EINVAL``
-
- - Invalid argument.
diff --git a/drivers/staging/media/av7110/audio-fwrite.rst b/drivers/staging/media/av7110/audio-fwrite.rst
deleted file mode 100644
index 7b096ac2b6c4..000000000000
--- a/drivers/staging/media/av7110/audio-fwrite.rst
+++ /dev/null
@@ -1,79 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _audio_fwrite:
-
-=========================
-Digital TV audio write()
-=========================
-
-Name
-----
-
-Digital TV audio write()
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:function:: size_t write(int fd, const void *buf, size_t count)
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - void \*buf
-
- - Pointer to the buffer containing the PES data.
-
- - .. row 3
-
- - size_t count
-
- - Size of buf.
-
-Description
------------
-
-This system call can only be used if AUDIO_SOURCE_MEMORY is selected
-in the ioctl call AUDIO_SELECT_SOURCE. The data provided shall be in
-PES format. If O_NONBLOCK is not specified the function will block
-until buffer space is available. The amount of data to be transferred is
-implied by count.
-
-Return Value
-------------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``EPERM``
-
- - Mode AUDIO_SOURCE_MEMORY not selected.
-
- - .. row 2
-
- - ``ENOMEM``
-
- - Attempted to write more data than the internal buffer can hold.
-
- - .. row 3
-
- - ``EBADF``
-
- - fd is not a valid open file descriptor.
diff --git a/drivers/staging/media/av7110/audio-get-capabilities.rst b/drivers/staging/media/av7110/audio-get-capabilities.rst
deleted file mode 100644
index 6d9eb71dad17..000000000000
--- a/drivers/staging/media/av7110/audio-get-capabilities.rst
+++ /dev/null
@@ -1,54 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_GET_CAPABILITIES:
-
-======================
-AUDIO_GET_CAPABILITIES
-======================
-
-Name
-----
-
-AUDIO_GET_CAPABILITIES
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_GET_CAPABILITIES
-
-``int ioctl(int fd, AUDIO_GET_CAPABILITIES, unsigned int *cap)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - unsigned int \*cap
-
- - Returns a bit array of supported sound formats.
-
-Description
------------
-
-This ioctl call asks the Audio Device to tell us about the decoding
-capabilities of the audio hardware.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-get-status.rst b/drivers/staging/media/av7110/audio-get-status.rst
deleted file mode 100644
index 7ae8db2e65e9..000000000000
--- a/drivers/staging/media/av7110/audio-get-status.rst
+++ /dev/null
@@ -1,54 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_GET_STATUS:
-
-================
-AUDIO_GET_STATUS
-================
-
-Name
-----
-
-AUDIO_GET_STATUS
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_GET_STATUS
-
-``int ioctl(int fd, AUDIO_GET_STATUS, struct audio_status *status)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - struct audio_status \*status
-
- - Returns the current state of Audio Device.
-
-Description
------------
-
-This ioctl call asks the Audio Device to return the current state of the
-Audio Device.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-pause.rst b/drivers/staging/media/av7110/audio-pause.rst
deleted file mode 100644
index d37d1ddce4df..000000000000
--- a/drivers/staging/media/av7110/audio-pause.rst
+++ /dev/null
@@ -1,49 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_PAUSE:
-
-===========
-AUDIO_PAUSE
-===========
-
-Name
-----
-
-AUDIO_PAUSE
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_PAUSE
-
-``int ioctl(int fd, AUDIO_PAUSE)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
-Description
------------
-
-This ioctl call suspends the audio stream being played. Decoding and
-playing are paused. It is then possible to restart again decoding and
-playing process of the audio stream using AUDIO_CONTINUE command.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-play.rst b/drivers/staging/media/av7110/audio-play.rst
deleted file mode 100644
index e591930b6ca7..000000000000
--- a/drivers/staging/media/av7110/audio-play.rst
+++ /dev/null
@@ -1,48 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_PLAY:
-
-==========
-AUDIO_PLAY
-==========
-
-Name
-----
-
-AUDIO_PLAY
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_PLAY
-
-``int ioctl(int fd, AUDIO_PLAY)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
-Description
------------
-
-This ioctl call asks the Audio Device to start playing an audio stream
-from the selected source.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-select-source.rst b/drivers/staging/media/av7110/audio-select-source.rst
deleted file mode 100644
index 6a0c0f365eb1..000000000000
--- a/drivers/staging/media/av7110/audio-select-source.rst
+++ /dev/null
@@ -1,56 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_SELECT_SOURCE:
-
-===================
-AUDIO_SELECT_SOURCE
-===================
-
-Name
-----
-
-AUDIO_SELECT_SOURCE
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_SELECT_SOURCE
-
-``int ioctl(int fd, AUDIO_SELECT_SOURCE, struct audio_stream_source *source)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - audio_stream_source_t source
-
- - Indicates the source that shall be used for the Audio stream.
-
-Description
------------
-
-This ioctl call informs the audio device which source shall be used for
-the input data. The possible sources are demux or memory. If
-AUDIO_SOURCE_MEMORY is selected, the data is fed to the Audio Device
-through the write command.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-av-sync.rst b/drivers/staging/media/av7110/audio-set-av-sync.rst
deleted file mode 100644
index 85a8016bf025..000000000000
--- a/drivers/staging/media/av7110/audio-set-av-sync.rst
+++ /dev/null
@@ -1,58 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_SET_AV_SYNC:
-
-=================
-AUDIO_SET_AV_SYNC
-=================
-
-Name
-----
-
-AUDIO_SET_AV_SYNC
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_SET_AV_SYNC
-
-``int ioctl(int fd, AUDIO_SET_AV_SYNC, boolean state)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - boolean state
-
- - Tells the Digital TV subsystem if A/V synchronization shall be ON or OFF.
-
- TRUE: AV-sync ON
-
- FALSE: AV-sync OFF
-
-Description
------------
-
-This ioctl call asks the Audio Device to turn ON or OFF A/V
-synchronization.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-bypass-mode.rst b/drivers/staging/media/av7110/audio-set-bypass-mode.rst
deleted file mode 100644
index 80d551a2053a..000000000000
--- a/drivers/staging/media/av7110/audio-set-bypass-mode.rst
+++ /dev/null
@@ -1,62 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_SET_BYPASS_MODE:
-
-=====================
-AUDIO_SET_BYPASS_MODE
-=====================
-
-Name
-----
-
-AUDIO_SET_BYPASS_MODE
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_SET_BYPASS_MODE
-
-``int ioctl(int fd, AUDIO_SET_BYPASS_MODE, boolean mode)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - boolean mode
-
- - Enables or disables the decoding of the current Audio stream in
- the Digital TV subsystem.
-
- TRUE: Bypass is disabled
-
- FALSE: Bypass is enabled
-
-Description
------------
-
-This ioctl call asks the Audio Device to bypass the Audio decoder and
-forward the stream without decoding. This mode shall be used if streams
-that can't be handled by the Digital TV system shall be decoded. Dolby
-DigitalTM streams are automatically forwarded by the Digital TV subsystem if
-the hardware can handle it.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-id.rst b/drivers/staging/media/av7110/audio-set-id.rst
deleted file mode 100644
index 39ad846d412d..000000000000
--- a/drivers/staging/media/av7110/audio-set-id.rst
+++ /dev/null
@@ -1,59 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_SET_ID:
-
-============
-AUDIO_SET_ID
-============
-
-Name
-----
-
-AUDIO_SET_ID
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_SET_ID
-
-``int ioctl(int fd, AUDIO_SET_ID, int id)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - int id
-
- - audio sub-stream id
-
-Description
------------
-
-This ioctl selects which sub-stream is to be decoded if a program or
-system stream is sent to the video device. If no audio stream type is
-set the id has to be in [0xC0,0xDF] for MPEG sound, in [0x80,0x87] for
-AC3 and in [0xA0,0xA7] for LPCM. More specifications may follow for
-other stream types. If the stream type is set the id just specifies the
-substream id of the audio stream and only the first 5 bits are
-recognized.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-mixer.rst b/drivers/staging/media/av7110/audio-set-mixer.rst
deleted file mode 100644
index 45dbdf4801e0..000000000000
--- a/drivers/staging/media/av7110/audio-set-mixer.rst
+++ /dev/null
@@ -1,53 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_SET_MIXER:
-
-===============
-AUDIO_SET_MIXER
-===============
-
-Name
-----
-
-AUDIO_SET_MIXER
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_SET_MIXER
-
-``int ioctl(int fd, AUDIO_SET_MIXER, struct audio_mixer *mix)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - audio_mixer_t \*mix
-
- - mixer settings.
-
-Description
------------
-
-This ioctl lets you adjust the mixer settings of the audio decoder.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-mute.rst b/drivers/staging/media/av7110/audio-set-mute.rst
deleted file mode 100644
index 987751f92967..000000000000
--- a/drivers/staging/media/av7110/audio-set-mute.rst
+++ /dev/null
@@ -1,62 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_SET_MUTE:
-
-==============
-AUDIO_SET_MUTE
-==============
-
-Name
-----
-
-AUDIO_SET_MUTE
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_SET_MUTE
-
-``int ioctl(int fd, AUDIO_SET_MUTE, boolean state)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - boolean state
-
- - Indicates if audio device shall mute or not.
-
- TRUE: Audio Mute
-
- FALSE: Audio Un-mute
-
-Description
------------
-
-This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
-V4L2 :ref:`VIDIOC_DECODER_CMD` with the
-``V4L2_DEC_CMD_START_MUTE_AUDIO`` flag instead.
-
-This ioctl call asks the audio device to mute the stream that is
-currently being played.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio-set-streamtype.rst b/drivers/staging/media/av7110/audio-set-streamtype.rst
deleted file mode 100644
index 77d73c74882f..000000000000
--- a/drivers/staging/media/av7110/audio-set-streamtype.rst
+++ /dev/null
@@ -1,66 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_SET_STREAMTYPE:
-
-====================
-AUDIO_SET_STREAMTYPE
-====================
-
-Name
-----
-
-AUDIO_SET_STREAMTYPE
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_SET_STREAMTYPE
-
-``int ioctl(fd, AUDIO_SET_STREAMTYPE, int type)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- -
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- -
-
- - int type
-
- - stream type
-
-Description
------------
-
-This ioctl tells the driver which kind of audio stream to expect. This
-is useful if the stream offers several audio sub-streams like LPCM and
-AC3.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
-
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``EINVAL``
-
- - type is not a valid or supported stream type.
diff --git a/drivers/staging/media/av7110/audio-stop.rst b/drivers/staging/media/av7110/audio-stop.rst
deleted file mode 100644
index d77f786fd797..000000000000
--- a/drivers/staging/media/av7110/audio-stop.rst
+++ /dev/null
@@ -1,48 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.audio
-
-.. _AUDIO_STOP:
-
-==========
-AUDIO_STOP
-==========
-
-Name
-----
-
-AUDIO_STOP
-
-.. attention:: This ioctl is deprecated
-
-Synopsis
---------
-
-.. c:macro:: AUDIO_STOP
-
-``int ioctl(int fd, AUDIO_STOP)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
-Description
------------
-
-This ioctl call asks the Audio Device to stop playing the current
-stream.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/audio.rst b/drivers/staging/media/av7110/audio.rst
deleted file mode 100644
index aa753336b31f..000000000000
--- a/drivers/staging/media/av7110/audio.rst
+++ /dev/null
@@ -1,27 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-
-.. _dvb_audio:
-
-#######################
-Digital TV Audio Device
-#######################
-
-The Digital TV audio device controls the MPEG2 audio decoder of the Digital
-TV hardware. It can be accessed through ``/dev/dvb/adapter?/audio?``. Data
-types and ioctl definitions can be accessed by including
-``linux/dvb/audio.h`` in your application.
-
-Please note that some Digital TV cards don't have their own MPEG decoder, which
-results in the omission of the audio and video device.
-
-These ioctls were also used by V4L2 to control MPEG decoders implemented
-in V4L2. The use of these ioctls for that purpose has been made obsolete
-and proper V4L2 ioctls or controls have been created to replace that
-functionality.
-
-
-.. toctree::
- :maxdepth: 1
-
- audio_data_types
- audio_function_calls
diff --git a/drivers/staging/media/av7110/audio_data_types.rst b/drivers/staging/media/av7110/audio_data_types.rst
deleted file mode 100644
index 4744529136a8..000000000000
--- a/drivers/staging/media/av7110/audio_data_types.rst
+++ /dev/null
@@ -1,116 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-
-.. _audio_data_types:
-
-****************
-Audio Data Types
-****************
-
-This section describes the structures, data types and defines used when
-talking to the audio device.
-
-.. c:type:: audio_stream_source
-
-The audio stream source is set through the AUDIO_SELECT_SOURCE call
-and can take the following values, depending on whether we are replaying
-from an internal (demux) or external (user write) source.
-
-
-.. code-block:: c
-
- typedef enum {
- AUDIO_SOURCE_DEMUX,
- AUDIO_SOURCE_MEMORY
- } audio_stream_source_t;
-
-AUDIO_SOURCE_DEMUX selects the demultiplexer (fed either by the
-frontend or the DVR device) as the source of the video stream. If
-AUDIO_SOURCE_MEMORY is selected the stream comes from the application
-through the ``write()`` system call.
-
-
-.. c:type:: audio_play_state
-
-The following values can be returned by the AUDIO_GET_STATUS call
-representing the state of audio playback.
-
-
-.. code-block:: c
-
- typedef enum {
- AUDIO_STOPPED,
- AUDIO_PLAYING,
- AUDIO_PAUSED
- } audio_play_state_t;
-
-
-.. c:type:: audio_channel_select
-
-The audio channel selected via AUDIO_CHANNEL_SELECT is determined by
-the following values.
-
-
-.. code-block:: c
-
- typedef enum {
- AUDIO_STEREO,
- AUDIO_MONO_LEFT,
- AUDIO_MONO_RIGHT,
- AUDIO_MONO,
- AUDIO_STEREO_SWAPPED
- } audio_channel_select_t;
-
-
-.. c:type:: audio_status
-
-The AUDIO_GET_STATUS call returns the following structure informing
-about various states of the playback operation.
-
-
-.. code-block:: c
-
- typedef struct audio_status {
- boolean AV_sync_state;
- boolean mute_state;
- audio_play_state_t play_state;
- audio_stream_source_t stream_source;
- audio_channel_select_t channel_select;
- boolean bypass_mode;
- audio_mixer_t mixer_state;
- } audio_status_t;
-
-
-.. c:type:: audio_mixer
-
-The following structure is used by the AUDIO_SET_MIXER call to set the
-audio volume.
-
-
-.. code-block:: c
-
- typedef struct audio_mixer {
- unsigned int volume_left;
- unsigned int volume_right;
- } audio_mixer_t;
-
-
-.. _audio_encodings:
-
-audio encodings
-===============
-
-A call to AUDIO_GET_CAPABILITIES returns an unsigned integer with the
-following bits set according to the hardwares capabilities.
-
-
-.. code-block:: c
-
- #define AUDIO_CAP_DTS 1
- #define AUDIO_CAP_LPCM 2
- #define AUDIO_CAP_MP1 4
- #define AUDIO_CAP_MP2 8
- #define AUDIO_CAP_MP3 16
- #define AUDIO_CAP_AAC 32
- #define AUDIO_CAP_OGG 64
- #define AUDIO_CAP_SDDS 128
- #define AUDIO_CAP_AC3 256
diff --git a/drivers/staging/media/av7110/audio_function_calls.rst b/drivers/staging/media/av7110/audio_function_calls.rst
deleted file mode 100644
index fa5ba9539caf..000000000000
--- a/drivers/staging/media/av7110/audio_function_calls.rst
+++ /dev/null
@@ -1,30 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-
-.. _audio_function_calls:
-
-********************
-Audio Function Calls
-********************
-
-.. toctree::
- :maxdepth: 1
-
- audio-fopen
- audio-fclose
- audio-fwrite
- audio-stop
- audio-play
- audio-pause
- audio-continue
- audio-select-source
- audio-set-mute
- audio-set-av-sync
- audio-set-bypass-mode
- audio-channel-select
- audio-bilingual-channel-select
- audio-get-status
- audio-get-capabilities
- audio-clear-buffer
- audio-set-id
- audio-set-mixer
- audio-set-streamtype
diff --git a/drivers/staging/media/av7110/av7110.c b/drivers/staging/media/av7110/av7110.c
index a5a431c14ea7..728b3892a20c 100644
--- a/drivers/staging/media/av7110/av7110.c
+++ b/drivers/staging/media/av7110/av7110.c
@@ -1,7 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* driver for the SAA7146 based AV110 cards (like the Fujitsu-Siemens DVB)
- * av7110.c: initialization and demux stuff
+ * - initialization and demux stuff
*
* Copyright (C) 1999-2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
@@ -12,7 +12,6 @@
* the project's page is at https://linuxtv.org
*/
-
#include <linux/module.h>
#include <linux/kmod.h>
#include <linux/delay.h>
@@ -36,7 +35,6 @@
#include <asm/unaligned.h>
#include <asm/byteorder.h>
-
#include <linux/dvb/frontend.h>
#include <media/dvb_frontend.h>
@@ -54,9 +52,8 @@
#define TS_WIDTH 376
#define TS_HEIGHT 512
-#define TS_BUFLEN (TS_WIDTH*TS_HEIGHT)
-#define TS_MAX_PACKETS (TS_BUFLEN/TS_SIZE)
-
+#define TS_BUFLEN (TS_WIDTH * TS_HEIGHT)
+#define TS_MAX_PACKETS (TS_BUFLEN / TS_SIZE)
int av7110_debug;
@@ -75,11 +72,11 @@ static int full_ts;
module_param_named(debug, av7110_debug, int, 0644);
MODULE_PARM_DESC(debug, "debug level (bitmask, default 0)");
module_param(vidmode, int, 0444);
-MODULE_PARM_DESC(vidmode,"analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC");
+MODULE_PARM_DESC(vidmode, "analog video out: 0 off, 1 CVBS+RGB (default), 2 CVBS+YC, 3 YC");
module_param(pids_off, int, 0444);
-MODULE_PARM_DESC(pids_off,"clear video/audio/PCR PID filters when demux is closed");
+MODULE_PARM_DESC(pids_off, "clear video/audio/PCR PID filters when demux is closed");
module_param(adac, int, 0444);
-MODULE_PARM_DESC(adac,"audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)");
+MODULE_PARM_DESC(adac, "audio DAC type: 0 TI, 1 CRYSTAL, 2 MSP (use if autodetection fails)");
module_param(hw_sections, int, 0444);
MODULE_PARM_DESC(hw_sections, "0 use software section filter, 1 use hardware");
module_param(rgb_on, int, 0444);
@@ -107,12 +104,11 @@ static int av7110_num;
#define FE_FUNC_OVERRIDE(fe_func, av7110_copy, av7110_func) \
{\
- if (fe_func != NULL) { \
+ if (fe_func) { \
av7110_copy = fe_func; \
fe_func = av7110_func; \
} \
-}
-
+} /* Macro argument reuse of 'fe_func' is intentional! */
static void init_av7110_av(struct av7110 *av7110)
{
@@ -123,27 +119,27 @@ static void init_av7110_av(struct av7110 *av7110)
av7110->adac_type = DVB_ADAC_TI;
ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
if (ret < 0)
- printk("dvb-ttpci:cannot set internal volume to maximum:%d\n",ret);
+ pr_err("cannot set internal volume to maximum:%d\n", ret);
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
- 1, (u16) av7110->display_ar);
+ 1, (u16)av7110->display_ar);
if (ret < 0)
- printk("dvb-ttpci: unable to set aspect ratio\n");
+ pr_err("unable to set aspect ratio\n");
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetPanScanType,
1, av7110->display_panscan);
if (ret < 0)
- printk("dvb-ttpci: unable to set pan scan\n");
+ pr_err("unable to set pan scan\n");
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 2, wss_cfg_4_3);
if (ret < 0)
- printk("dvb-ttpci: unable to configure 4:3 wss\n");
+ pr_err("unable to configure 4:3 wss\n");
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetWSSConfig, 2, 3, wss_cfg_16_9);
if (ret < 0)
- printk("dvb-ttpci: unable to configure 16:9 wss\n");
+ pr_err("unable to configure 16:9 wss\n");
ret = av7710_set_video_mode(av7110, vidmode);
if (ret < 0)
- printk("dvb-ttpci:cannot set video mode:%d\n",ret);
+ pr_err("cannot set video mode:%d\n", ret);
/* handle different card types */
/* remaining inits according to card and frontend type */
@@ -152,8 +148,7 @@ static void init_av7110_av(struct av7110 *av7110)
if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a)
av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on
if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) {
- printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n",
- av7110->dvb_adapter.num);
+ pr_info("Crystal audio DAC @ card %d detected\n", av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_CRYSTAL;
i2c_writereg(av7110, 0x20, 0x01, 0xd2);
i2c_writereg(av7110, 0x20, 0x02, 0x49);
@@ -163,28 +158,24 @@ static void init_av7110_av(struct av7110 *av7110)
/**
* some special handling for the Siemens DVB-C cards...
*/
- } else if (0 == av7110_init_analog_module(av7110)) {
+ } else if (av7110_init_analog_module(av7110) == 0) {
/* done. */
- }
- else if (dev->pci->subsystem_vendor == 0x110a) {
- printk("dvb-ttpci: DVB-C w/o analog module @ card %d detected\n",
- av7110->dvb_adapter.num);
+ } else if (dev->pci->subsystem_vendor == 0x110a) {
+ pr_info("DVB-C w/o analog module @ card %d detected\n", av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_NONE;
- }
- else {
+ } else {
av7110->adac_type = adac;
- printk("dvb-ttpci: adac type set to %d @ card %d\n",
- av7110->adac_type, av7110->dvb_adapter.num);
+ pr_info("adac type set to %d @ card %d\n", av7110->adac_type, av7110->dvb_adapter.num);
}
if (av7110->adac_type == DVB_ADAC_NONE || av7110->adac_type == DVB_ADAC_MSP34x0) {
// switch DVB SCART on
ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, MainSwitch, 1, 0);
if (ret < 0)
- printk("dvb-ttpci:cannot switch on SCART(Main):%d\n",ret);
+ pr_err("cannot switch on SCART(Main):%d\n", ret);
ret = av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 1);
if (ret < 0)
- printk("dvb-ttpci:cannot switch on SCART(AD):%d\n",ret);
+ pr_err("cannot switch on SCART(AD):%d\n", ret);
if (rgb_on &&
((av7110->dev->pci->subsystem_vendor == 0x110a) ||
(av7110->dev->pci->subsystem_vendor == 0x13c2)) &&
@@ -199,12 +190,12 @@ static void init_av7110_av(struct av7110 *av7110)
ret = av7110_set_volume(av7110, av7110->mixer.volume_left, av7110->mixer.volume_right);
if (ret < 0)
- printk("dvb-ttpci:cannot set volume :%d\n",ret);
+ pr_err("cannot set volume :%d\n", ret);
}
static void recover_arm(struct av7110 *av7110)
{
- dprintk(4, "%p\n",av7110);
+ dprintk(4, "%p\n", av7110);
av7110_bootarm(av7110);
msleep(100);
@@ -236,11 +227,11 @@ static int arm_thread(void *data)
u16 newloops = 0;
int timeout;
- dprintk(4, "%p\n",av7110);
+ dprintk(4, "%p\n", av7110);
for (;;) {
timeout = wait_event_interruptible_timeout(av7110->arm_wait,
- kthread_should_stop(), 5 * HZ);
+ kthread_should_stop(), 5 * HZ);
if (-ERESTARTSYS == timeout || kthread_should_stop()) {
/* got signal or told to quit*/
@@ -256,8 +247,7 @@ static int arm_thread(void *data)
mutex_unlock(&av7110->dcomlock);
if (newloops == av7110->arm_loops || av7110->arm_errors > 3) {
- printk(KERN_ERR "dvb-ttpci: ARM crashed @ card %d\n",
- av7110->dvb_adapter.num);
+ pr_err("ARM crashed @ card %d\n", av7110->dvb_adapter.num);
recover_arm(av7110);
@@ -273,7 +263,6 @@ static int arm_thread(void *data)
return 0;
}
-
/****************************************************************************
* IRQ handling
****************************************************************************/
@@ -325,14 +314,14 @@ static int DvbDmxFilterCallback(u8 *buffer1, size_t buffer1_len,
}
}
-
//#define DEBUG_TIMING
static inline void print_time(char *s)
{
#ifdef DEBUG_TIMING
struct timespec64 ts;
+
ktime_get_real_ts64(&ts);
- printk("%s: %lld.%09ld\n", s, (s64)ts.tv_sec, ts.tv_nsec);
+ pr_info("%s(): %lld.%09ld\n", s, (s64)ts.tv_sec, ts.tv_nsec);
#endif
}
@@ -343,7 +332,7 @@ static inline void start_debi_dma(struct av7110 *av7110, int dir,
{
dprintk(8, "%c %08lx %u\n", dir == DEBI_READ ? 'R' : 'W', addr, len);
if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
- printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__);
+ pr_err("%s(): saa7146_wait_for_debi_done timed out\n", __func__);
return;
}
@@ -368,18 +357,16 @@ static void debiirq(struct tasklet_struct *t)
dprintk(4, "type 0x%04x\n", type);
if (type == -1) {
- printk("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",
- jiffies, saa7146_read(av7110->dev, PSR),
- saa7146_read(av7110->dev, SSR));
+ pr_err("DEBI irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", jiffies,
+ saa7146_read(av7110->dev, PSR), saa7146_read(av7110->dev, SSR));
goto debi_done;
}
av7110->debitype = -1;
switch (type & 0xff) {
-
case DATA_TS_RECORD:
dvb_dmx_swfilter_packets(&av7110->demux,
- (const u8 *) av7110->debi_virt,
+ (const u8 *)av7110->debi_virt,
av7110->debilen / 188);
xfer = RX_BUFF;
break;
@@ -387,7 +374,7 @@ static void debiirq(struct tasklet_struct *t)
case DATA_PES_RECORD:
if (av7110->demux.recording)
av7110_record_cb(&av7110->p2t[handle],
- (u8 *) av7110->debi_virt,
+ (u8 *)av7110->debi_virt,
av7110->debilen);
xfer = RX_BUFF;
break;
@@ -410,15 +397,17 @@ static void debiirq(struct tasklet_struct *t)
if (data_0 < 2 && data[2] == 0xff) {
int flags = 0;
+
if (data[5] > 0)
flags |= CA_CI_MODULE_PRESENT;
if (data[5] > 5)
flags |= CA_CI_MODULE_READY;
av7110->ci_slot[data_0].flags = flags;
- } else
+ } else {
ci_get_data(&av7110->ci_rbuffer,
av7110->debi_virt,
av7110->debilen);
+ }
xfer = RX_BUFF;
break;
}
@@ -429,8 +418,8 @@ static void debiirq(struct tasklet_struct *t)
break;
case DATA_DEBUG_MESSAGE:
- ((s8*)av7110->debi_virt)[Reserved_SIZE - 1] = 0;
- printk("%s\n", (s8 *) av7110->debi_virt);
+ ((s8 *)av7110->debi_virt)[Reserved_SIZE - 1] = 0;
+ pr_info("%s\n", (s8 *)av7110->debi_virt);
xfer = RX_BUFF;
break;
@@ -466,12 +455,11 @@ static void gpioirq(struct tasklet_struct *t)
if (av7110->debitype != -1)
/* we shouldn't get any irq while a debi xfer is running */
- printk("dvb-ttpci: GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n",
- jiffies, saa7146_read(av7110->dev, PSR),
- saa7146_read(av7110->dev, SSR));
+ pr_err("GPIO0 irq oops @ %ld, psr:0x%08x, ssr:0x%08x\n", jiffies,
+ saa7146_read(av7110->dev, PSR), saa7146_read(av7110->dev, SSR));
if (saa7146_wait_for_debi_done(av7110->dev, 0)) {
- printk(KERN_ERR "%s: saa7146_wait_for_debi_done timed out\n", __func__);
+ pr_err("%s(): saa7146_wait_for_debi_done timed out\n", __func__);
BUG(); /* maybe we should try resetting the debi? */
}
@@ -489,7 +477,6 @@ static void gpioirq(struct tasklet_struct *t)
dprintk(8, "GPIO0 irq 0x%04x %d\n", av7110->debitype, av7110->debilen);
switch (av7110->debitype & 0xff) {
-
case DATA_TS_PLAY:
case DATA_PES_PLAY:
break;
@@ -510,8 +497,7 @@ static void gpioirq(struct tasklet_struct *t)
event.type = VIDEO_EVENT_SIZE_CHANGED;
event.u.size.w = av7110->video_size.w;
event.u.size.h = av7110->video_size.h;
- switch ((h_ar >> 12) & 0xf)
- {
+ switch ((h_ar >> 12) & 0xf) {
case 3:
av7110->video_size.aspect_ratio = VIDEO_FORMAT_16_9;
event.u.size.aspect_ratio = VIDEO_FORMAT_16_9;
@@ -582,8 +568,8 @@ static void gpioirq(struct tasklet_struct *t)
len = av7110_pes_play(av7110->debi_virt, &av7110->aout, 2048);
spin_unlock(&av7110->aout.lock);
}
- if (len <= 0 && (av7110->debitype & 0x200)
- &&av7110->videostate.play_state != VIDEO_FREEZED) {
+ if (len <= 0 && (av7110->debitype & 0x200) &&
+ av7110->videostate.play_state != VIDEO_FREEZED) {
spin_lock(&av7110->avout.lock);
len = av7110_pes_play(av7110->debi_virt, &av7110->avout, 2048);
spin_unlock(&av7110->avout.lock);
@@ -620,11 +606,11 @@ static void gpioirq(struct tasklet_struct *t)
len = 2 * 1024;
iwdebi(av7110, DEBINOSWAP, TX_LEN, len, 2);
iwdebi(av7110, DEBINOSWAP, IRQ_STATE_EXT, len, 2);
- memcpy(av7110->debi_virt, av7110->bmpbuf+av7110->bmpp, len);
+ memcpy(av7110->debi_virt, av7110->bmpbuf + av7110->bmpp, len);
av7110->bmpp += len;
av7110->bmplen -= len;
dprintk(8, "gpio DATA_BMP_LOAD DMA len %d\n", len);
- start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE+txbuf, len);
+ start_debi_dma(av7110, DEBI_WRITE, DPRAM_BASE + txbuf, len);
spin_unlock(&av7110->debilock);
return;
@@ -642,7 +628,7 @@ static void gpioirq(struct tasklet_struct *t)
case DATA_TS_RECORD:
case DATA_PES_RECORD:
dprintk(8, "DMA: TS_REC etc.\n");
- start_debi_dma(av7110, DEBI_READ, DPRAM_BASE+rxbuf, len);
+ start_debi_dma(av7110, DEBI_READ, DPRAM_BASE + rxbuf, len);
spin_unlock(&av7110->debilock);
return;
@@ -665,7 +651,7 @@ static void gpioirq(struct tasklet_struct *t)
break;
default:
- printk("dvb-ttpci: gpioirq unknown type=%d len=%d\n",
+ pr_err("%s(): unknown irq: type=%d len=%d\n", __func__,
av7110->debitype, av7110->debilen);
break;
}
@@ -674,7 +660,6 @@ static void gpioirq(struct tasklet_struct *t)
spin_unlock(&av7110->debilock);
}
-
#ifdef CONFIG_DVB_AV7110_OSD
static int dvb_osd_ioctl(struct file *file,
unsigned int cmd, void *parg)
@@ -685,14 +670,13 @@ static int dvb_osd_ioctl(struct file *file,
dprintk(4, "%p\n", av7110);
if (cmd == OSD_SEND_CMD)
- return av7110_osd_cmd(av7110, (osd_cmd_t *) parg);
+ return av7110_osd_cmd(av7110, (osd_cmd_t *)parg);
if (cmd == OSD_GET_CAPABILITY)
- return av7110_osd_capability(av7110, (osd_cap_t *) parg);
+ return av7110_osd_capability(av7110, (osd_cap_t *)parg);
return -EINVAL;
}
-
static const struct file_operations dvb_osd_fops = {
.owner = THIS_MODULE,
.unlocked_ioctl = dvb_generic_ioctl,
@@ -710,7 +694,6 @@ static struct dvb_device dvbdev_osd = {
};
#endif /* CONFIG_DVB_AV7110_OSD */
-
static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
u16 subpid, u16 pcrpid)
{
@@ -720,7 +703,11 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
if (vpid == 0x1fff || apid == 0x1fff ||
ttpid == 0x1fff || subpid == 0x1fff || pcrpid == 0x1fff) {
- vpid = apid = ttpid = subpid = pcrpid = 0;
+ vpid = 0;
+ apid = 0;
+ ttpid = 0;
+ subpid = 0;
+ pcrpid = 0;
av7110->pids[DMX_PES_VIDEO] = 0;
av7110->pids[DMX_PES_AUDIO] = 0;
av7110->pids[DMX_PES_TELETEXT] = 0;
@@ -735,9 +722,10 @@ static inline int SetPIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
}
int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
- u16 subpid, u16 pcrpid)
+ u16 subpid, u16 pcrpid)
{
int ret = 0;
+
dprintk(4, "%p\n", av7110);
if (mutex_lock_interruptible(&av7110->pid_mutex))
@@ -763,7 +751,6 @@ int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
return ret;
}
-
/******************************************************************************
* hardware filter functions
******************************************************************************/
@@ -805,9 +792,8 @@ static int StartHWFilter(struct dvb_demux_filter *dvbdmxfilter)
ret = av7110_fw_request(av7110, buf, 20, &handle, 1);
if (ret != 0 || handle >= 32) {
- printk(KERN_ERR "dvb-ttpci: %s error buf %04x %04x %04x %04x ret %d handle %04x\n",
- __func__, buf[0], buf[1], buf[2], buf[3],
- ret, handle);
+ pr_err("%s(): error buf %04x %04x %04x %04x ret %d handle %04x\n",
+ __func__, buf[0], buf[1], buf[2], buf[3], ret, handle);
dvbdmxfilter->hw_handle = 0xffff;
if (!ret)
ret = -1;
@@ -835,8 +821,8 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
handle = dvbdmxfilter->hw_handle;
if (handle >= 32) {
- printk("%s tried to stop invalid filter %04x, filter type = %x\n",
- __func__, handle, dvbdmxfilter->type);
+ pr_err("%s(): tried to stop invalid filter %04x, filter type = %x\n",
+ __func__, handle, dvbdmxfilter->type);
return -EINVAL;
}
@@ -847,16 +833,14 @@ static int StopHWFilter(struct dvb_demux_filter *dvbdmxfilter)
buf[2] = handle;
ret = av7110_fw_request(av7110, buf, 3, answ, 2);
if (ret != 0 || answ[1] != handle) {
- printk(KERN_ERR "dvb-ttpci: %s error cmd %04x %04x %04x ret %x resp %04x %04x pid %d\n",
- __func__, buf[0], buf[1], buf[2], ret,
- answ[0], answ[1], dvbdmxfilter->feed->pid);
+ pr_err("%s(): error cmd %04x %04x %04x ret %x resp %04x %04x pid %d\n", __func__,
+ buf[0], buf[1], buf[2], ret, answ[0], answ[1], dvbdmxfilter->feed->pid);
if (!ret)
ret = -1;
}
return ret;
}
-
static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
@@ -867,9 +851,13 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
dprintk(4, "%p\n", av7110);
- npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff;
+ npids[0] = 0xffff;
+ npids[1] = 0xffff;
+ npids[2] = 0xffff;
+ npids[3] = 0xffff;
+ npids[4] = 0xffff;
i = dvbdmxfeed->pes_type;
- npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
+ npids[i] = (pid[i] & 0x8000) ? 0 : pid[i];
if ((i == 2) && npids[i] && (dvbdmxfeed->ts_type & TS_PACKET)) {
npids[i] = 0;
ret = ChangePIDs(av7110, npids[1], npids[0], npids[2], npids[3], npids[4]);
@@ -884,8 +872,7 @@ static int dvb_feed_start_pid(struct dvb_demux_feed *dvbdmxfeed)
}
if (dvbdmxfeed->pes_type < 2 && npids[0])
- if (av7110->fe_synced)
- {
+ if (av7110->fe_synced) {
ret = av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, Scan, 0);
if (ret)
return ret;
@@ -920,7 +907,11 @@ static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
if (!av7110->playing)
dvbdmx->playing = 0;
}
- npids[0] = npids[1] = npids[2] = npids[3] = npids[4] = 0xffff;
+ npids[0] = 0xffff;
+ npids[1] = 0xffff;
+ npids[2] = 0xffff;
+ npids[3] = 0xffff;
+ npids[4] = 0xffff;
i = dvbdmxfeed->pes_type;
switch (i) {
case 2: //teletext
@@ -933,7 +924,7 @@ static int dvb_feed_stop_pid(struct dvb_demux_feed *dvbdmxfeed)
case 4:
if (!pids_off)
return 0;
- npids[i] = (pid[i]&0x8000) ? 0 : pid[i];
+ npids[i] = (pid[i] & 0x8000) ? 0 : pid[i];
break;
}
if (!ret)
@@ -961,14 +952,14 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
switch (demux->dmx.frontend->source) {
case DMX_MEMORY_FE:
if (feed->ts_type & TS_DECODER)
- if (feed->pes_type < 2 &&
- !(demux->pids[0] & 0x8000) &&
- !(demux->pids[1] & 0x8000)) {
- dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
- dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
- ret = av7110_av_start_play(av7110,RP_AV);
- if (!ret)
- demux->playing = 1;
+ if (feed->pes_type < 2 &&
+ !(demux->pids[0] & 0x8000) &&
+ !(demux->pids[1] & 0x8000)) {
+ dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
+ dvb_ringbuffer_flush_spinlock_wakeup(&av7110->aout);
+ ret = av7110_av_start_play(av7110, RP_AV);
+ if (!ret)
+ demux->playing = 1;
}
break;
default:
@@ -1008,12 +999,12 @@ static int av7110_start_feed(struct dvb_demux_feed *feed)
return ret;
}
-
static int av7110_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
struct av7110 *av7110 = demux->priv;
int i, rc, ret = 0;
+
dprintk(4, "%p\n", av7110);
if (feed->type == DMX_TYPE_TS) {
@@ -1024,10 +1015,9 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
demux->pids[feed->pes_type] |= 0x8000;
demux->pesfilter[feed->pes_type] = NULL;
}
- if (feed->ts_type & TS_DECODER &&
- feed->pes_type < DMX_PES_OTHER) {
+ if (feed->ts_type & TS_DECODER && feed->pes_type < DMX_PES_OTHER)
ret = dvb_feed_stop_pid(feed);
- } else
+ else
if ((feed->ts_type & TS_PACKET) &&
(demux->dmx.frontend->source != DMX_MEMORY_FE))
ret = StopHWFilter(feed->filter);
@@ -1039,7 +1029,7 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
}
if (feed->type == DMX_TYPE_SEC) {
- for (i = 0; i<demux->filternum; i++) {
+ for (i = 0; i < demux->filternum; i++) {
if (demux->filter[i].state == DMX_STATE_GO &&
demux->filter[i].filter.parent == &feed->feed.sec) {
demux->filter[i].state = DMX_STATE_READY;
@@ -1056,7 +1046,6 @@ static int av7110_stop_feed(struct dvb_demux_feed *feed)
return ret;
}
-
static void restart_feeds(struct av7110 *av7110)
{
struct dvb_demux *dvbdmx = &av7110->demux;
@@ -1097,7 +1086,7 @@ static void restart_feeds(struct av7110 *av7110)
}
static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
- uint64_t *stc, unsigned int *base)
+ u64 *stc, unsigned int *base)
{
int ret;
u16 fwstc[4];
@@ -1120,14 +1109,13 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
ret = av7110_fw_request(av7110, &tag, 0, fwstc, 4);
if (ret) {
- printk(KERN_ERR "%s: av7110_fw_request error\n", __func__);
+ pr_err("%s(): av7110_fw_request error\n", __func__);
return ret;
}
- dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n",
- fwstc[0], fwstc[1], fwstc[2], fwstc[3]);
+ dprintk(2, "fwstc = %04hx %04hx %04hx %04hx\n", fwstc[0], fwstc[1], fwstc[2], fwstc[3]);
- *stc = (((uint64_t) ((fwstc[3] & 0x8000) >> 15)) << 32) |
- (((uint64_t) fwstc[1]) << 16) | ((uint64_t) fwstc[0]);
+ *stc = (((uint64_t)((fwstc[3] & 0x8000) >> 15)) << 32) |
+ (((uint64_t)fwstc[1]) << 16) | ((uint64_t)fwstc[0]);
*base = 1;
dprintk(4, "stc = %lu\n", (unsigned long)*stc);
@@ -1135,15 +1123,13 @@ static int dvb_get_stc(struct dmx_demux *demux, unsigned int num,
return 0;
}
-
/******************************************************************************
* SEC device file operations
******************************************************************************/
-
static int av7110_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
switch (tone) {
case SEC_TONE_ON:
@@ -1157,18 +1143,18 @@ static int av7110_set_tone(struct dvb_frontend *fe, enum fe_sec_tone_mode tone)
}
}
-static int av7110_diseqc_send_master_cmd(struct dvb_frontend* fe,
- struct dvb_diseqc_master_cmd* cmd)
+static int av7110_diseqc_send_master_cmd(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *cmd)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
return av7110_diseqc_send(av7110, cmd->msg_len, cmd->msg, -1);
}
-static int av7110_diseqc_send_burst(struct dvb_frontend* fe,
+static int av7110_diseqc_send_burst(struct dvb_frontend *fe,
enum fe_sec_mini_cmd minicmd)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
return av7110_diseqc_send(av7110, 0, NULL, minicmd);
}
@@ -1188,7 +1174,7 @@ static int stop_ts_capture(struct av7110 *budget)
static int start_ts_capture(struct av7110 *budget)
{
- unsigned y;
+ unsigned int y;
dprintk(2, "budget: %p\n", budget);
@@ -1235,7 +1221,7 @@ static int budget_stop_feed(struct dvb_demux_feed *feed)
static void vpeirq(struct tasklet_struct *t)
{
struct av7110 *budget = from_tasklet(budget, t, vpe_tasklet);
- u8 *mem = (u8 *) (budget->grabbing);
+ u8 *mem = (u8 *)(budget->grabbing);
u32 olddma = budget->ttbp;
u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
struct dvb_demux *demux = budget->full_ts ? &budget->demux : &budget->demux1;
@@ -1255,17 +1241,16 @@ static void vpeirq(struct tasklet_struct *t)
dma_sync_sg_for_cpu(&budget->dev->pci->dev, budget->pt.slist,
budget->pt.nents, DMA_FROM_DEVICE);
-#if 0
+#ifdef RPS_DEBUG
/* track rps1 activity */
- printk("vpeirq: %02x Event Counter 1 0x%04x\n",
- mem[olddma],
- saa7146_read(budget->dev, EC1R) & 0x3fff);
+ pr_info("%s(): %02x Event Counter 1 0x%04x\n", __func__, mem[olddma],
+ saa7146_read(budget->dev, EC1R) & 0x3fff);
#endif
- if (newdma > olddma)
+ if (newdma > olddma) {
/* no wraparound, dump olddma..newdma */
dvb_dmx_swfilter_packets(demux, mem + olddma, (newdma - olddma) / 188);
- else {
+ } else {
/* wraparound, dump olddma..buflen and 0..newdma */
dvb_dmx_swfilter_packets(demux, mem + olddma, (TS_BUFLEN - olddma) / 188);
dvb_dmx_swfilter_packets(demux, mem, newdma / 188);
@@ -1285,7 +1270,7 @@ static int av7110_register(struct av7110 *av7110)
av7110->registered = 1;
- dvbdemux->priv = (void *) av7110;
+ dvbdemux->priv = (void *)av7110;
for (i = 0; i < 32; i++)
av7110->handle2filter[i] = NULL;
@@ -1340,7 +1325,7 @@ static int av7110_register(struct av7110 *av7110)
/* initialize software demux1 without its own frontend
* demux1 hardware is connected to frontend0 of demux0
*/
- dvbdemux1->priv = (void *) av7110;
+ dvbdemux1->priv = (void *)av7110;
dvbdemux1->filternum = 256;
dvbdemux1->feednum = 256;
@@ -1360,12 +1345,11 @@ static int av7110_register(struct av7110 *av7110)
dvb_dmxdev_init(&av7110->dmxdev1, &av7110->dvb_adapter);
dvb_net_init(&av7110->dvb_adapter, &av7110->dvb_net1, &dvbdemux1->dmx);
- printk("dvb-ttpci: additional demux1 for budget-patch registered\n");
+ pr_info("additional demux1 for budget-patch registered\n");
}
return 0;
}
-
static void dvb_unregister(struct av7110 *av7110)
{
struct dvb_demux *dvbdemux = &av7110->demux;
@@ -1392,7 +1376,7 @@ static void dvb_unregister(struct av7110 *av7110)
dvb_dmxdev_release(&av7110->dmxdev);
dvb_dmx_release(&av7110->demux);
- if (av7110->fe != NULL) {
+ if (av7110->fe) {
dvb_unregister_frontend(av7110->fe);
dvb_frontend_detach(av7110->fe);
}
@@ -1401,7 +1385,6 @@ static void dvb_unregister(struct av7110 *av7110)
av7110_ca_unregister(av7110);
}
-
/****************************************************************************
* I2C client commands
****************************************************************************/
@@ -1426,10 +1409,13 @@ u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
msgs[0].flags = 0;
msgs[1].flags = I2C_M_RD;
- msgs[0].addr = msgs[1].addr = id / 2;
+ msgs[0].addr = id / 2;
+ msgs[1].addr = id / 2;
mm1[0] = reg;
- msgs[0].len = 1; msgs[1].len = 1;
- msgs[0].buf = mm1; msgs[1].buf = mm2;
+ msgs[0].len = 1;
+ msgs[1].len = 1;
+ msgs[0].buf = mm1;
+ msgs[1].buf = mm2;
i2c_transfer(&av7110->i2c_adap, msgs, 2);
return mm2[0];
@@ -1439,8 +1425,7 @@ u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg)
* INITIALIZATION
****************************************************************************/
-
-static int check_firmware(struct av7110* av7110)
+static int check_firmware(struct av7110 *av7110)
{
u32 crc = 0, len = 0;
unsigned char *ptr;
@@ -1449,7 +1434,7 @@ static int check_firmware(struct av7110* av7110)
ptr = av7110->bin_fw;
if (ptr[0] != 'A' || ptr[1] != 'V' ||
ptr[2] != 'F' || ptr[3] != 'W') {
- printk("dvb-ttpci: this is not an av7110 firmware\n");
+ pr_err("this is not an av7110 firmware\n");
return -EINVAL;
}
ptr += 4;
@@ -1460,11 +1445,11 @@ static int check_firmware(struct av7110* av7110)
len = get_unaligned_be32(ptr);
ptr += 4;
if (len >= 512) {
- printk("dvb-ttpci: dpram file is way too big.\n");
+ pr_err("dpram file is way too big.\n");
return -EINVAL;
}
if (crc != crc32_le(0, ptr, len)) {
- printk("dvb-ttpci: crc32 of dpram file does not match.\n");
+ pr_err("crc32 of dpram file does not match.\n");
return -EINVAL;
}
av7110->bin_dpram = ptr;
@@ -1479,11 +1464,11 @@ static int check_firmware(struct av7110* av7110)
if (len <= 200000 || len >= 300000 ||
len > ((av7110->bin_fw + av7110->size_fw) - ptr)) {
- printk("dvb-ttpci: root file has strange size (%d). aborting.\n", len);
+ pr_err("root file has strange size (%d). aborting.\n", len);
return -EINVAL;
}
- if( crc != crc32_le(0, ptr, len)) {
- printk("dvb-ttpci: crc32 of root file does not match.\n");
+ if (crc != crc32_le(0, ptr, len)) {
+ pr_err("crc32 of root file does not match.\n");
return -EINVAL;
}
av7110->bin_root = ptr;
@@ -1491,12 +1476,12 @@ static int check_firmware(struct av7110* av7110)
return 0;
}
-static void put_firmware(struct av7110* av7110)
+static void put_firmware(struct av7110 *av7110)
{
vfree(av7110->bin_fw);
}
-static int get_firmware(struct av7110* av7110)
+static int get_firmware(struct av7110 *av7110)
{
int ret;
const struct firmware *fw;
@@ -1505,24 +1490,24 @@ static int get_firmware(struct av7110* av7110)
ret = request_firmware(&fw, "dvb-ttpci-01.fw", &av7110->dev->pci->dev);
if (ret) {
if (ret == -ENOENT) {
- printk(KERN_ERR "dvb-ttpci: could not load firmware, file not found: dvb-ttpci-01.fw\n");
- printk(KERN_ERR "dvb-ttpci: usually this should be in /usr/lib/hotplug/firmware or /lib/firmware\n");
- printk(KERN_ERR "dvb-ttpci: and can be downloaded from https://linuxtv.org/download/dvb/firmware/\n");
- } else
- printk(KERN_ERR "dvb-ttpci: cannot request firmware (error %i)\n",
- ret);
+ pr_err("could not load firmware, file not found: dvb-ttpci-01.fw\n");
+ pr_err("usually this should be in /usr/lib/hotplug/firmware or /lib/firmware\n");
+ pr_err("and can be downloaded from https://linuxtv.org/download/dvb/firmware/\n");
+ } else {
+ pr_err("cannot request firmware (error %i)\n", ret);
+ }
return -EINVAL;
}
if (fw->size <= 200000) {
- printk("dvb-ttpci: this firmware is way too small.\n");
+ pr_err("this firmware is way too small.\n");
release_firmware(fw);
return -EINVAL;
}
/* check if the firmware is available */
av7110->bin_fw = vmalloc(fw->size);
- if (NULL == av7110->bin_fw) {
+ if (!av7110->bin_fw) {
dprintk(1, "out of memory\n");
release_firmware(fw);
return -ENOMEM;
@@ -1530,7 +1515,8 @@ static int get_firmware(struct av7110* av7110)
memcpy(av7110->bin_fw, fw->data, fw->size);
av7110->size_fw = fw->size;
- if ((ret = check_firmware(av7110)))
+ ret = check_firmware(av7110);
+ if (ret)
vfree(av7110->bin_fw);
release_firmware(fw);
@@ -1540,7 +1526,7 @@ static int get_firmware(struct av7110* av7110)
static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
u8 pwr = 0;
u8 buf[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
@@ -1569,7 +1555,7 @@ static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1)
+ if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
}
@@ -1583,7 +1569,7 @@ static struct ves1x93_config alps_bsrv2_config = {
static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
u32 div;
u8 data[4];
struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };
@@ -1609,13 +1595,10 @@ static struct ves1820_config alps_tdbe2_config = {
.selagc = VES1820_SELAGC_SIGNAMPERR,
};
-
-
-
static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
u32 div;
u8 data[4];
struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
@@ -1637,12 +1620,10 @@ static struct tda8083_config grundig_29504_451_config = {
.demod_address = 0x68,
};
-
-
static int philips_cd1516_tuner_set_params(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
u32 div;
u32 f = p->frequency;
u8 data[4];
@@ -1669,12 +1650,10 @@ static struct ves1820_config philips_cd1516_config = {
.selagc = VES1820_SELAGC_SIGNAMPERR,
};
-
-
static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
u32 div, pwr;
u8 data[4];
struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) };
@@ -1698,10 +1677,10 @@ static int alps_tdlb7_tuner_set_params(struct dvb_frontend *fe)
return 0;
}
-static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
+static int alps_tdlb7_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name)
{
#if IS_ENABLED(CONFIG_DVB_SP8870)
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
return request_firmware(fw, name, &av7110->dev->pci->dev);
#else
@@ -1710,12 +1689,10 @@ static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct fir
}
static const struct sp8870_config alps_tdlb7_config = {
-
.demod_address = 0x71,
.request_firmware = alps_tdlb7_request_firmware,
};
-
static u8 nexusca_stv0297_inittab[] = {
0x80, 0x01,
0x80, 0x00,
@@ -1812,7 +1789,7 @@ static u8 nexusca_stv0297_inittab[] = {
static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
u32 div;
u8 data[4];
struct i2c_msg msg = { .addr = 0x63, .flags = 0, .buf = data, .len = sizeof(data) };
@@ -1839,16 +1816,17 @@ static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe)
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) {
- printk("nexusca: pll transfer failed!\n");
+ pr_err("nexusca: pll transfer failed!\n");
return -EIO;
}
// wait for PLL lock
- for(i = 0; i < 20; i++) {
+ for (i = 0; i < 20; i++) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1)
- if (data[0] & 0x40) break;
+ if (data[0] & 0x40)
+ break;
msleep(10);
}
@@ -1856,19 +1834,16 @@ static int nexusca_stv0297_tuner_set_params(struct dvb_frontend *fe)
}
static struct stv0297_config nexusca_stv0297_config = {
-
.demod_address = 0x1C,
.inittab = nexusca_stv0297_inittab,
.invert = 1,
.stop_during_read = 1,
};
-
-
static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
u32 div;
u8 cfg, cpump, band_select;
u8 data[4];
@@ -1903,7 +1878,8 @@ static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO;
+ if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
+ return -EIO;
return 0;
}
@@ -1911,8 +1887,6 @@ static struct l64781_config grundig_29504_401_config = {
.demod_address = 0x55,
};
-
-
static int av7110_fe_lock_fix(struct av7110 *av7110, enum fe_status status)
{
int ret = 0;
@@ -1933,7 +1907,7 @@ static int av7110_fe_lock_fix(struct av7110 *av7110, enum fe_status status)
if (synced) {
ret = SetPIDs(av7110, av7110->pids[DMX_PES_VIDEO],
- av7110->pids[DMX_PES_AUDIO],
+ av7110->pids[DMX_PES_AUDIO],
av7110->pids[DMX_PES_TELETEXT], 0,
av7110->pids[DMX_PES_PCR]);
if (!ret)
@@ -1956,20 +1930,22 @@ static int av7110_fe_lock_fix(struct av7110 *av7110, enum fe_status status)
static int av7110_fe_set_frontend(struct dvb_frontend *fe)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
+
if (!ret)
ret = av7110->fe_set_frontend(fe);
return ret;
}
-static int av7110_fe_init(struct dvb_frontend* fe)
+static int av7110_fe_init(struct dvb_frontend *fe)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
+
if (!ret)
ret = av7110->fe_init(fe);
return ret;
@@ -1978,32 +1954,35 @@ static int av7110_fe_init(struct dvb_frontend* fe)
static int av7110_fe_read_status(struct dvb_frontend *fe,
enum fe_status *status)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
/* call the real implementation */
int ret = av7110->fe_read_status(fe, status);
+
if (!ret)
if (((*status ^ av7110->fe_status) & FE_HAS_LOCK) && (*status & FE_HAS_LOCK))
ret = av7110_fe_lock_fix(av7110, *status);
return ret;
}
-static int av7110_fe_diseqc_reset_overload(struct dvb_frontend* fe)
+static int av7110_fe_diseqc_reset_overload(struct dvb_frontend *fe)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
+
if (!ret)
ret = av7110->fe_diseqc_reset_overload(fe);
return ret;
}
-static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
- struct dvb_diseqc_master_cmd* cmd)
+static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *cmd)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
+
if (!ret) {
av7110->saved_master_cmd = *cmd;
ret = av7110->fe_diseqc_send_master_cmd(fe, cmd);
@@ -2014,9 +1993,10 @@ static int av7110_fe_diseqc_send_master_cmd(struct dvb_frontend* fe,
static int av7110_fe_diseqc_send_burst(struct dvb_frontend *fe,
enum fe_sec_mini_cmd minicmd)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
+
if (!ret) {
av7110->saved_minicmd = minicmd;
ret = av7110->fe_diseqc_send_burst(fe, minicmd);
@@ -2027,9 +2007,10 @@ static int av7110_fe_diseqc_send_burst(struct dvb_frontend *fe,
static int av7110_fe_set_tone(struct dvb_frontend *fe,
enum fe_sec_tone_mode tone)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
+
if (!ret) {
av7110->saved_tone = tone;
ret = av7110->fe_set_tone(fe, tone);
@@ -2040,9 +2021,10 @@ static int av7110_fe_set_tone(struct dvb_frontend *fe,
static int av7110_fe_set_voltage(struct dvb_frontend *fe,
enum fe_sec_voltage voltage)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
+
if (!ret) {
av7110->saved_voltage = voltage;
ret = av7110->fe_set_voltage(fe, voltage);
@@ -2050,17 +2032,18 @@ static int av7110_fe_set_voltage(struct dvb_frontend *fe,
return ret;
}
-static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend* fe, unsigned long cmd)
+static int av7110_fe_dishnetwork_send_legacy_command(struct dvb_frontend *fe, unsigned long cmd)
{
- struct av7110* av7110 = fe->dvb->priv;
+ struct av7110 *av7110 = fe->dvb->priv;
int ret = av7110_fe_lock_fix(av7110, 0);
+
if (!ret)
ret = av7110->fe_dishnetwork_send_legacy_command(fe, cmd);
return ret;
}
-static void dvb_s_recover(struct av7110* av7110)
+static void dvb_s_recover(struct av7110 *av7110)
{
av7110_fe_init(av7110->fe);
@@ -2077,12 +2060,12 @@ static void dvb_s_recover(struct av7110* av7110)
av7110_fe_set_frontend(av7110->fe);
}
-static u8 read_pwm(struct av7110* av7110)
+static u8 read_pwm(struct av7110 *av7110)
{
u8 b = 0xff;
u8 pwm;
- struct i2c_msg msg[] = { { .addr = 0x50,.flags = 0,.buf = &b,.len = 1 },
- { .addr = 0x50,.flags = I2C_M_RD,.buf = &pwm,.len = 1} };
+ struct i2c_msg msg[] = { { .addr = 0x50, .flags = 0, .buf = &b, .len = 1 },
+ { .addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} };
if ((i2c_transfer(&av7110->i2c_adap, msg, 2) != 2) || (pwm == 0xff))
pwm = 0x48;
@@ -2095,18 +2078,17 @@ static int frontend_init(struct av7110 *av7110)
int ret;
if (av7110->dev->pci->subsystem_vendor == 0x110a) {
- switch(av7110->dev->pci->subsystem_device) {
+ switch (av7110->dev->pci->subsystem_device) {
case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??))
av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config,
- &av7110->i2c_adap, read_pwm(av7110));
- if (av7110->fe) {
+ &av7110->i2c_adap, read_pwm(av7110));
+ if (av7110->fe)
av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
- }
break;
}
} else if (av7110->dev->pci->subsystem_vendor == 0x13c2) {
- switch(av7110->dev->pci->subsystem_device) {
+ switch (av7110->dev->pci->subsystem_device) {
case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
case 0x0003: // Hauppauge/TT WinTV Nexus-S Rev 2.X
case 0x1002: // Hauppauge/TT WinTV DVB-S rev1.3SE
@@ -2147,22 +2129,20 @@ static int frontend_init(struct av7110 *av7110)
}
/* Try DVB-C cards */
- switch(av7110->dev->pci->subsystem_device) {
+ switch (av7110->dev->pci->subsystem_device) {
case 0x0000:
/* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */
av7110->fe = dvb_attach(ves1820_attach, &philips_cd1516_config, &av7110->i2c_adap,
read_pwm(av7110));
- if (av7110->fe) {
+ if (av7110->fe)
av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params;
- }
break;
case 0x0003:
/* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */
av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap,
read_pwm(av7110));
- if (av7110->fe) {
+ if (av7110->fe)
av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
- }
break;
}
break;
@@ -2191,9 +2171,8 @@ static int frontend_init(struct av7110 *av7110)
case 0x0002: // Hauppauge/TT DVB-C premium rev2.X
av7110->fe = dvb_attach(ves1820_attach, &alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110));
- if (av7110->fe) {
+ if (av7110->fe)
av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;
- }
break;
case 0x0004: // Galaxis DVB-S rev1.3
@@ -2243,8 +2222,8 @@ static int frontend_init(struct av7110 *av7110)
av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;
av7110->fe->tuner_priv = &av7110->i2c_adap;
- if (dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0) == NULL) {
- printk("dvb-ttpci: LNBP21 not found!\n");
+ if (!dvb_attach(lnbp21_attach, av7110->fe, &av7110->i2c_adap, 0, 0)) {
+ pr_err("LNBP21 not found!\n");
if (av7110->fe->ops.release)
av7110->fe->ops.release(av7110->fe);
av7110->fe = NULL;
@@ -2260,11 +2239,9 @@ static int frontend_init(struct av7110 *av7110)
if (!av7110->fe) {
/* FIXME: propagate the failure code from the lower layers */
ret = -ENOMEM;
- printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
- av7110->dev->pci->vendor,
- av7110->dev->pci->device,
- av7110->dev->pci->subsystem_vendor,
- av7110->dev->pci->subsystem_device);
+ pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
+ av7110->dev->pci->vendor, av7110->dev->pci->device,
+ av7110->dev->pci->subsystem_vendor, av7110->dev->pci->subsystem_device);
} else {
FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init);
FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status);
@@ -2278,7 +2255,7 @@ static int frontend_init(struct av7110 *av7110)
ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe);
if (ret < 0) {
- printk("av7110: Frontend registration failed!\n");
+ pr_err("av7110: Frontend registration failed!\n");
dvb_frontend_detach(av7110->fe);
av7110->fe = NULL;
}
@@ -2346,7 +2323,7 @@ static int frontend_init(struct av7110 *av7110)
* The same behaviour of missing VSYNC can be duplicated on budget
* cards, by setting DD1_INIT trigger mode 7 in 3rd nibble.
*/
-static int av7110_attach(struct saa7146_dev* dev,
+static int av7110_attach(struct saa7146_dev *dev,
struct saa7146_pci_extension_data *pci_ext)
{
const int length = TS_WIDTH * TS_HEIGHT;
@@ -2402,9 +2379,9 @@ static int av7110_attach(struct saa7146_dev* dev,
/* RPS1 timeout disable */
saa7146_write(dev, RPS_TOV1, 0);
WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
- WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+ WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL >> 2));
WRITE_RPS1(GPIO3_MSK);
- WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
+ WRITE_RPS1(SAA7146_GPIO_OUTLO << 24);
#if RPS_IRQ
/* issue RPS1 interrupt to increment counter */
WRITE_RPS1(CMD_INTERRUPT);
@@ -2419,14 +2396,14 @@ static int av7110_attach(struct saa7146_dev* dev,
* use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
* use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
*/
- saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
+ saa7146_write(dev, EC1SSR, (0x03 << 2) | 3);
/* set event counter 1 threshold to maximum allowed value (rEC p55) */
- saa7146_write(dev, ECT1R, 0x3fff );
+ saa7146_write(dev, ECT1R, 0x3fff);
#endif
/* Set RPS1 Address register to point to RPS code (r108 p42) */
saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
/* Enable RPS1, (rFC p33) */
- saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
+ saa7146_write(dev, MC1, (MASK_13 | MASK_29));
mdelay(10);
/* now send VSYNC_B to rps1 by rising GPIO3 */
@@ -2437,23 +2414,23 @@ static int av7110_attach(struct saa7146_dev* dev,
*/
if ((saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) {
budgetpatch = 1;
- printk("dvb-ttpci: BUDGET-PATCH DETECTED.\n");
+ pr_info("BUDGET-PATCH DETECTED.\n");
}
/* Disable RPS1 */
- saa7146_write(dev, MC1, ( MASK_29 ));
+ saa7146_write(dev, MC1, (MASK_29));
#if RPS_IRQ
- printk("dvb-ttpci: Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
+ pr_info("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff);
#endif
}
/* prepare the av7110 device struct */
- av7110 = kzalloc(sizeof(struct av7110), GFP_KERNEL);
+ av7110 = kzalloc(sizeof(*av7110), GFP_KERNEL);
if (!av7110) {
dprintk(1, "out of memory\n");
return -ENOMEM;
}
- av7110->card_name = (char*) pci_ext->ext_priv;
+ av7110->card_name = (char *)pci_ext->ext_priv;
av7110->dev = dev;
dev->ext_priv = av7110;
@@ -2467,7 +2444,8 @@ static int av7110_attach(struct saa7146_dev* dev,
goto err_put_firmware_1;
/* the Siemens DVB needs this if you want to have the i2c chips
- get recognized before the main driver is fully loaded */
+ * get recognized before the main driver is fully loaded
+ */
saa7146_write(dev, GPIO_CTRL, 0x500000);
strscpy(av7110->i2c_adap.name, pci_ext->ext_priv,
@@ -2490,12 +2468,13 @@ static int av7110_attach(struct saa7146_dev* dev,
/* check for full-ts flag in eeprom */
if (i2c_readreg(av7110, 0xaa, 0) == 0x4f && i2c_readreg(av7110, 0xaa, 1) == 0x45) {
u8 flags = i2c_readreg(av7110, 0xaa, 2);
+
if (flags != 0xff && (flags & 0x01))
av7110->full_ts = true;
}
if (av7110->full_ts) {
- printk(KERN_INFO "dvb-ttpci: full-ts mode enabled for saa7146 port B\n");
+ pr_info("full-ts mode enabled for saa7146 port B\n");
spin_lock_init(&av7110->feedlock1);
av7110->grabbing = saa7146_vmalloc_build_pgtable(pdev, length,
&av7110->pt);
@@ -2553,9 +2532,9 @@ static int av7110_attach(struct saa7146_dev* dev,
* use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
* use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
*/
- saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
+ saa7146_write(dev, EC1SSR, (0x03 << 2) | 3);
/* set event counter 1 threshold to maximum allowed value (rEC p55) */
- saa7146_write(dev, ECT1R, 0x3fff );
+ saa7146_write(dev, ECT1R, 0x3fff);
#endif
/* Setup BUDGETPATCH MAIN RPS1 "program" (p35) */
count = 0;
@@ -2563,9 +2542,9 @@ static int av7110_attach(struct saa7146_dev* dev,
/* Wait Source Line Counter Threshold (p36) */
WRITE_RPS1(CMD_PAUSE | EVT_HS);
/* Set GPIO3=1 (p42) */
- WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+ WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL >> 2));
WRITE_RPS1(GPIO3_MSK);
- WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
+ WRITE_RPS1(SAA7146_GPIO_OUTHI << 24);
#if RPS_IRQ
/* issue RPS1 interrupt */
WRITE_RPS1(CMD_INTERRUPT);
@@ -2573,9 +2552,9 @@ static int av7110_attach(struct saa7146_dev* dev,
/* Wait reset Source Line Counter Threshold (p36) */
WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
/* Set GPIO3=0 (p42) */
- WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
+ WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL >> 2));
WRITE_RPS1(GPIO3_MSK);
- WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
+ WRITE_RPS1(SAA7146_GPIO_OUTLO << 24);
#if RPS_IRQ
/* issue RPS1 interrupt */
WRITE_RPS1(CMD_INTERRUPT);
@@ -2596,7 +2575,7 @@ static int av7110_attach(struct saa7146_dev* dev,
* then RPS_THRESH1 should be set to trigger
* every TS_HEIGHT (512) lines.
*/
- saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT*1) | MASK_12 );
+ saa7146_write(dev, RPS_THRESH1, (TS_HEIGHT * 1) | MASK_12);
/* Enable RPS1 (rFC p33) */
saa7146_write(dev, MC1, (MASK_13 | MASK_29));
@@ -2645,8 +2624,7 @@ static int av7110_attach(struct saa7146_dev* dev,
if (!av7110->debi_virt)
goto err_saa71466_vfree_4;
-
- av7110->iobuf = vmalloc(AVOUTLEN+AOUTLEN+BMPLEN+4*IPACKS);
+ av7110->iobuf = vmalloc(AVOUTLEN + AOUTLEN + BMPLEN + 4 * IPACKS);
if (!av7110->iobuf)
goto err_pci_free_5;
@@ -2655,7 +2633,7 @@ static int av7110_attach(struct saa7146_dev* dev,
goto err_iobuf_vfree_6;
/* init BMP buffer */
- av7110->bmpbuf = av7110->iobuf+AVOUTLEN+AOUTLEN;
+ av7110->bmpbuf = av7110->iobuf + AVOUTLEN + AOUTLEN;
init_waitqueue_head(&av7110->bmpq);
ret = av7110_ca_init(av7110);
@@ -2671,12 +2649,11 @@ static int av7110_attach(struct saa7146_dev* dev,
if (ret < 0)
goto err_stop_arm_9;
- if (FW_VERSION(av7110->arm_app)<0x2501)
- printk(KERN_WARNING
- "dvb-ttpci: Warning, firmware version 0x%04x is too old. System might be unstable!\n",
- FW_VERSION(av7110->arm_app));
+ if (FW_VERSION(av7110->arm_app) < 0x2501)
+ pr_warn("Warning, firmware version 0x%04x is too old. System might be unstable!\n",
+ FW_VERSION(av7110->arm_app));
- thread = kthread_run(arm_thread, (void *) av7110, "arm_mon");
+ thread = kthread_run(arm_thread, (void *)av7110, "arm_mon");
if (IS_ERR(thread)) {
ret = PTR_ERR(thread);
goto err_stop_arm_9;
@@ -2694,8 +2671,9 @@ static int av7110_attach(struct saa7146_dev* dev,
init_av7110_av(av7110);
/* special case DVB-C: these cards have an analog tuner
- plus need some special handling, so we have separate
- saa7146_ext_vv data for these... */
+ * plus need some special handling, so we have separate
+ * saa7146_ext_vv data for these...
+ */
ret = av7110_init_v4l(av7110);
if (ret < 0)
goto err_av7110_unregister_11;
@@ -2710,7 +2688,7 @@ static int av7110_attach(struct saa7146_dev* dev,
#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
av7110_ir_init(av7110);
#endif
- printk(KERN_INFO "dvb-ttpci: found av7110-%d.\n", av7110_num);
+ pr_info("found av7110-%d.\n", av7110_num);
av7110_num++;
out:
return ret;
@@ -2746,9 +2724,10 @@ err_kfree_0:
goto out;
}
-static int av7110_detach(struct saa7146_dev* saa)
+static int av7110_detach(struct saa7146_dev *saa)
{
struct av7110 *av7110 = saa->ext_priv;
+
dprintk(4, "%p\n", av7110);
#if IS_ENABLED(CONFIG_DVB_AV7110_IR)
@@ -2789,7 +2768,7 @@ static int av7110_detach(struct saa7146_dev* saa)
i2c_del_adapter(&av7110->i2c_adap);
- dvb_unregister_adapter (&av7110->dvb_adapter);
+ dvb_unregister_adapter(&av7110->dvb_adapter);
av7110_num--;
@@ -2802,8 +2781,7 @@ static int av7110_detach(struct saa7146_dev* saa)
return 0;
}
-
-static void av7110_irq(struct saa7146_dev* dev, u32 *isr)
+static void av7110_irq(struct saa7146_dev *dev, u32 *isr)
{
struct av7110 *av7110 = dev->ext_priv;
@@ -2844,15 +2822,14 @@ static void av7110_irq(struct saa7146_dev* dev, u32 *isr)
tasklet_schedule(&av7110->vpe_tasklet);
}
-
static struct saa7146_extension av7110_extension_driver;
-#define MAKE_AV7110_INFO(x_var,x_name) \
+#define MAKE_AV7110_INFO(x_var, x_name) \
static struct saa7146_pci_extension_data x_var = { \
.ext_priv = x_name, \
.ext = &av7110_extension_driver }
-MAKE_AV7110_INFO(tts_1_X_fsc,"Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C");
+MAKE_AV7110_INFO(tts_1_X_fsc, "Technotrend/Hauppauge WinTV DVB-S rev1.X or Fujitsu Siemens DVB-C");
MAKE_AV7110_INFO(ttt_1_X, "Technotrend/Hauppauge WinTV DVB-T rev1.X");
MAKE_AV7110_INFO(ttc_1_X, "Technotrend/Hauppauge WinTV Nexus-CA rev1.X");
MAKE_AV7110_INFO(ttc_2_X, "Technotrend/Hauppauge WinTV DVB-C rev2.X");
@@ -2877,8 +2854,8 @@ static const struct pci_device_id pci_tbl[] = {
MAKE_EXTENSION_PCI(tts_2_3, 0x13c2, 0x000e),
MAKE_EXTENSION_PCI(tts_1_3se, 0x13c2, 0x1002),
-/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD */ // Technisat SkyStar1
-/* MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD */ // TT/Hauppauge WinTV Nexus-CA v????
+// MAKE_EXTENSION_PCI(???, 0x13c2, 0x0005), UNDEFINED CARD // Technisat SkyStar1
+// MAKE_EXTENSION_PCI(???, 0x13c2, 0x0009), UNDEFINED CARD // TT/Hauppauge WinTV Nexus-CA v???
{
.vendor = 0,
@@ -2887,7 +2864,6 @@ static const struct pci_device_id pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, pci_tbl);
-
static struct saa7146_extension av7110_extension_driver = {
.name = "av7110",
.flags = SAA7146_USE_I2C_IRQ,
@@ -2901,13 +2877,11 @@ static struct saa7146_extension av7110_extension_driver = {
.irq_func = av7110_irq,
};
-
static int __init av7110_init(void)
{
return saa7146_register_extension(&av7110_extension_driver);
}
-
static void __exit av7110_exit(void)
{
saa7146_unregister_extension(&av7110_extension_driver);
diff --git a/drivers/staging/media/av7110/av7110.h b/drivers/staging/media/av7110/av7110.h
index 809d938ae166..ec461fd187af 100644
--- a/drivers/staging/media/av7110/av7110.h
+++ b/drivers/staging/media/av7110/av7110.h
@@ -35,16 +35,19 @@
#include <media/drv-intf/saa7146_vv.h>
-
#define ANALOG_TUNER_VES1820 1
#define ANALOG_TUNER_STV0297 2
extern int av7110_debug;
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define dprintk(level, fmt, arg...) do { \
- if (level & av7110_debug) \
- printk(KERN_DEBUG KBUILD_MODNAME ": %s(): " fmt, \
- __func__, ##arg); \
+ if ((level) & av7110_debug) \
+ pr_info("%s(): " fmt, __func__, ##arg); \
} while (0)
#define MAXFILT 32
@@ -59,7 +62,7 @@ enum av7110_video_mode {
struct av7110_p2t {
u8 pes[TS_SIZE];
u8 counter;
- long int pos;
+ long pos;
int frags;
struct dvb_demux_feed *feed;
};
@@ -76,7 +79,6 @@ struct dvb_video_events {
spinlock_t lock;
};
-
struct av7110;
/* infrared remote control */
@@ -88,7 +90,6 @@ struct infrared {
/* place to store all the necessary device information */
struct av7110 {
-
/* devices */
struct dvb_device dvb_dev;
@@ -118,16 +119,15 @@ struct av7110 {
#define DVB_ADAC_MSP34x5 3
#define DVB_ADAC_NONE -1
-
/* buffers */
void *iobuf; /* memory for all buffers */
struct dvb_ringbuffer avout; /* buffer for video or A/V mux */
-#define AVOUTLEN (128*1024)
+#define AVOUTLEN (128 * 1024)
struct dvb_ringbuffer aout; /* buffer for audio */
-#define AOUTLEN (64*1024)
+#define AOUTLEN (64 * 1024)
void *bmpbuf;
-#define BMPLEN (8*32768+1024)
+#define BMPLEN (8 * 32768 + 1024)
/* bitmap buffers and states */
@@ -139,7 +139,6 @@ struct av7110 {
#define BMP_LOADED 2
wait_queue_head_t bmpq;
-
/* DEBI and polled command interface */
spinlock_t debilock;
@@ -147,7 +146,6 @@ struct av7110 {
volatile int debitype;
volatile int debilen;
-
/* Recording and playback flags */
int rec_mode;
@@ -157,7 +155,6 @@ struct av7110 {
#define RP_AUDIO 2
#define RP_AV 3
-
/* OSD */
int osdwin; /* currently active window */
@@ -213,7 +210,6 @@ struct av7110 {
int arm_errors;
int registered;
-
/* AV711X */
u32 arm_fw;
@@ -260,19 +256,19 @@ struct av7110 {
unsigned char *bin_root;
unsigned long size_root;
- struct dvb_frontend* fe;
+ struct dvb_frontend *fe;
enum fe_status fe_status;
struct mutex ioctl_mutex;
/* crash recovery */
- void (*recover)(struct av7110* av7110);
+ void (*recover)(struct av7110 *av7110);
enum fe_sec_voltage saved_voltage;
enum fe_sec_tone_mode saved_tone;
struct dvb_diseqc_master_cmd saved_master_cmd;
enum fe_sec_mini_cmd saved_minicmd;
- int (*fe_init)(struct dvb_frontend* fe);
+ int (*fe_init)(struct dvb_frontend *fe);
int (*fe_read_status)(struct dvb_frontend *fe, enum fe_status *status);
int (*fe_diseqc_reset_overload)(struct dvb_frontend *fe);
int (*fe_diseqc_send_master_cmd)(struct dvb_frontend *fe,
@@ -288,9 +284,8 @@ struct av7110 {
int (*fe_set_frontend)(struct dvb_frontend *fe);
};
-
-extern int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
- u16 subpid, u16 pcrpid);
+int ChangePIDs(struct av7110 *av7110, u16 vpid, u16 apid, u16 ttpid,
+ u16 subpid, u16 pcrpid);
void av7110_ir_handler(struct av7110 *av7110, u32 ircom);
int av7110_set_ir_config(struct av7110 *av7110);
@@ -303,13 +298,12 @@ void av7110_ir_exit(struct av7110 *av7110);
#define MSP_WR_DSP 0x12
#define MSP_RD_DSP 0x13
-extern int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val);
-extern u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg);
-extern int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val);
-
+int i2c_writereg(struct av7110 *av7110, u8 id, u8 reg, u8 val);
+u8 i2c_readreg(struct av7110 *av7110, u8 id, u8 reg);
+int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val);
-extern int av7110_init_analog_module(struct av7110 *av7110);
-extern int av7110_init_v4l(struct av7110 *av7110);
-extern int av7110_exit_v4l(struct av7110 *av7110);
+int av7110_init_analog_module(struct av7110 *av7110);
+int av7110_init_v4l(struct av7110 *av7110);
+int av7110_exit_v4l(struct av7110 *av7110);
#endif /* _AV7110_H_ */
diff --git a/drivers/staging/media/av7110/av7110_av.c b/drivers/staging/media/av7110/av7110_av.c
index 00dd6a7fea64..2993ac43c49c 100644
--- a/drivers/staging/media/av7110/av7110_av.c
+++ b/drivers/staging/media/av7110/av7110_av.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * av7110_av.c: audio and video MPEG decoder stuff
+ * driver for the SAA7146 based AV110 cards
+ * - audio and video MPEG decoder stuff
*
* Copyright (C) 1999-2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
@@ -70,20 +71,20 @@
#define PIECE_RATE 0x40
#define SEAM_SPLICE 0x20
-
-static void p_to_t(u8 const *buf, long int length, u16 pid,
+static void p_to_t(u8 const *buf, long length, u16 pid,
u8 *counter, struct dvb_demux_feed *feed);
static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len);
-
int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
{
struct dvb_demux_feed *dvbdmxfeed = p2t->priv;
if (!(dvbdmxfeed->ts_type & TS_PACKET))
return 0;
- if (buf[3] == 0xe0) // video PES do not have a length in TS
- buf[4] = buf[5] = 0;
+ if (buf[3] == 0xe0) { // video PES do not have a length in TS
+ buf[4] = 0;
+ buf[5] = 0;
+ }
if (dvbdmxfeed->ts_type & TS_PAYLOAD_ONLY)
return dvbdmxfeed->cb.ts(buf, len, NULL, 0,
&dvbdmxfeed->feed.ts, NULL);
@@ -93,7 +94,7 @@ int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len)
static int dvb_filter_pes2ts_cb(void *priv, unsigned char *data)
{
- struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *) priv;
+ struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)priv;
dvbdmxfeed->cb.ts(data, 188, NULL, 0,
&dvbdmxfeed->feed.ts, NULL);
@@ -119,7 +120,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av,
dvb_filter_pes2ts_init(&av7110->p2t[0],
dvbdmx->pesfilter[0]->pid,
dvb_filter_pes2ts_cb,
- (void *) dvbdmx->pesfilter[0]);
+ (void *)dvbdmx->pesfilter[0]);
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AudioPES, 0);
break;
@@ -127,7 +128,7 @@ int av7110_av_start_record(struct av7110 *av7110, int av,
dvb_filter_pes2ts_init(&av7110->p2t[1],
dvbdmx->pesfilter[1]->pid,
dvb_filter_pes2ts_cb,
- (void *) dvbdmx->pesfilter[1]);
+ (void *)dvbdmx->pesfilter[1]);
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, VideoPES, 0);
break;
@@ -135,11 +136,11 @@ int av7110_av_start_record(struct av7110 *av7110, int av,
dvb_filter_pes2ts_init(&av7110->p2t[0],
dvbdmx->pesfilter[0]->pid,
dvb_filter_pes2ts_cb,
- (void *) dvbdmx->pesfilter[0]);
+ (void *)dvbdmx->pesfilter[0]);
dvb_filter_pes2ts_init(&av7110->p2t[1],
dvbdmx->pesfilter[1]->pid,
dvb_filter_pes2ts_cb,
- (void *) dvbdmx->pesfilter[1]);
+ (void *)dvbdmx->pesfilter[1]);
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Record, 2, AV_PES, 0);
break;
}
@@ -149,7 +150,8 @@ int av7110_av_start_record(struct av7110 *av7110, int av,
int av7110_av_start_play(struct av7110 *av7110, int av)
{
int ret = 0;
- dprintk(2, "av7110:%p, \n", av7110);
+
+ dprintk(2, "av7110:%p\n", av7110);
if (av7110->rec_mode)
return -EBUSY;
@@ -183,7 +185,8 @@ int av7110_av_start_play(struct av7110 *av7110, int av)
int av7110_av_stop(struct av7110 *av7110, int av)
{
int ret = 0;
- dprintk(2, "av7110:%p, \n", av7110);
+
+ dprintk(2, "av7110:%p\n", av7110);
if (!(av7110->playing & av) && !(av7110->rec_mode & av))
return 0;
@@ -217,7 +220,6 @@ int av7110_av_stop(struct av7110 *av7110, int av)
return ret;
}
-
int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
{
int len;
@@ -239,38 +241,37 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8;
sync |= DVB_RINGBUFFER_PEEK(buf, 3);
- if (((sync &~ 0x0f) == 0x000001e0) ||
- ((sync &~ 0x1f) == 0x000001c0) ||
+ if (((sync & ~0x0f) == 0x000001e0) ||
+ ((sync & ~0x1f) == 0x000001c0) ||
(sync == 0x000001bd))
break;
- printk("resync\n");
+ pr_info("resync\n");
DVB_RINGBUFFER_SKIP(buf, 1);
}
blen = DVB_RINGBUFFER_PEEK(buf, 4) << 8;
blen |= DVB_RINGBUFFER_PEEK(buf, 5);
blen += 6;
if (len < blen || blen > dlen) {
- //printk("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen);
+ //pr_info("buffer empty - avail %d blen %u dlen %d\n", len, blen, dlen);
wake_up(&buf->queue);
return -1;
}
- dvb_ringbuffer_read(buf, dest, (size_t) blen);
+ dvb_ringbuffer_read(buf, dest, (size_t)blen);
dprintk(2, "pread=0x%08lx, pwrite=0x%08lx\n",
- (unsigned long) buf->pread, (unsigned long) buf->pwrite);
+ (unsigned long)buf->pread, (unsigned long)buf->pwrite);
wake_up(&buf->queue);
return blen;
}
-
int av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
unsigned int volright)
{
unsigned int vol, val, balance = 0;
int err;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
av7110->mixer.volume_left = volleft;
av7110->mixer.volume_right = volright;
@@ -283,7 +284,8 @@ int av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
volleft = 0x3f;
if (volright > 0x3f)
volright = 0x3f;
- if ((err = SendDAC(av7110, 3, 0x80 + volleft)))
+ err = SendDAC(av7110, 3, 0x80 + volleft);
+ if (err)
return err;
return SendDAC(av7110, 4, volright);
@@ -298,7 +300,7 @@ int av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
vol = (volleft > volright) ? volleft : volright;
val = (vol * 0x73 / 255) << 8;
if (vol > 0)
- balance = ((volright - volleft) * 127) / vol;
+ balance = ((volright - volleft) * 127) / vol;
msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8);
msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */
msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */
@@ -320,13 +322,14 @@ int av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)
{
int ret;
- dprintk(2, "av7110:%p, \n", av7110);
+
+ dprintk(2, "av7110:%p\n", av7110);
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, LoadVidCode, 1, mode);
if (!ret && !av7110->playing) {
ret = ChangePIDs(av7110, av7110->pids[DMX_PES_VIDEO],
- av7110->pids[DMX_PES_AUDIO],
+ av7110->pids[DMX_PES_AUDIO],
av7110->pids[DMX_PES_TELETEXT],
0, av7110->pids[DMX_PES_PCR]);
if (!ret)
@@ -335,7 +338,6 @@ int av7110_set_vidmode(struct av7110 *av7110, enum av7110_video_mode mode)
return ret;
}
-
static enum av7110_video_mode sw2mode[16] = {
AV7110_VIDEO_MODE_PAL, AV7110_VIDEO_MODE_NTSC,
AV7110_VIDEO_MODE_NTSC, AV7110_VIDEO_MODE_PAL,
@@ -355,7 +357,7 @@ static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
u8 *p;
int ret = 0;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
if (av7110->sinfo)
return 0;
@@ -364,8 +366,8 @@ static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
if (p[0] || p[1] || p[2] != 0x01 || p[3] != 0xb3)
continue;
p += 4;
- hsize = ((p[1] &0xF0) >> 4) | (p[0] << 4);
- vsize = ((p[1] &0x0F) << 8) | (p[2]);
+ hsize = ((p[1] & 0xF0) >> 4) | (p[0] << 4);
+ vsize = ((p[1] & 0x0F) << 8) | (p[2]);
sw = (p[3] & 0x0F);
ret = av7110_set_vidmode(av7110, sw2mode[sw]);
if (!ret) {
@@ -377,7 +379,6 @@ static int get_video_format(struct av7110 *av7110, u8 *buf, int count)
return ret;
}
-
/****************************************************************************
* I/O buffer management and control
****************************************************************************/
@@ -407,25 +408,27 @@ static inline long aux_ring_buffer_write(struct dvb_ringbuffer *rbuf,
static void play_video_cb(u8 *buf, int count, void *priv)
{
- struct av7110 *av7110 = (struct av7110 *) priv;
- dprintk(2, "av7110:%p, \n", av7110);
+ struct av7110 *av7110 = (struct av7110 *)priv;
+
+ dprintk(2, "av7110:%p\n", av7110);
if ((buf[3] & 0xe0) == 0xe0) {
get_video_format(av7110, buf, count);
aux_ring_buffer_write(&av7110->avout, buf, count);
- } else
+ } else {
aux_ring_buffer_write(&av7110->aout, buf, count);
+ }
}
static void play_audio_cb(u8 *buf, int count, void *priv)
{
- struct av7110 *av7110 = (struct av7110 *) priv;
- dprintk(2, "av7110:%p, \n", av7110);
+ struct av7110 *av7110 = (struct av7110 *)priv;
+
+ dprintk(2, "av7110:%p\n", av7110);
aux_ring_buffer_write(&av7110->aout, buf, count);
}
-
#define FREE_COND_TS (dvb_ringbuffer_free(rb) >= 4096)
static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
@@ -435,7 +438,7 @@ static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
u8 *kb;
unsigned long todo = count;
- dprintk(2, "%s: type %d cnt %lu\n", __func__, type, count);
+ dprintk(2, "type %d cnt %lu\n", type, count);
rb = (type) ? &av7110->avout : &av7110->aout;
kb = av7110->kbuf[type];
@@ -463,7 +466,6 @@ static ssize_t ts_play(struct av7110 *av7110, const char __user *buf,
return count - todo;
}
-
#define FREE_COND (dvb_ringbuffer_free(&av7110->avout) >= 20 * 1024 && \
dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
@@ -471,7 +473,8 @@ static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
- dprintk(2, "av7110:%p, \n", av7110);
+
+ dprintk(2, "av7110:%p\n", av7110);
if (!av7110->kbuf[type])
return -ENOBUFS;
@@ -501,10 +504,11 @@ static ssize_t dvb_play(struct av7110 *av7110, const char __user *buf,
}
static ssize_t dvb_play_kernel(struct av7110 *av7110, const u8 *buf,
- unsigned long count, int nonblock, int type)
+ unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
- dprintk(2, "av7110:%p, \n", av7110);
+
+ dprintk(2, "av7110:%p\n", av7110);
if (!av7110->kbuf[type])
return -ENOBUFS;
@@ -534,7 +538,8 @@ static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
unsigned long count, int nonblock, int type)
{
unsigned long todo = count, n;
- dprintk(2, "av7110:%p, \n", av7110);
+
+ dprintk(2, "av7110:%p\n", av7110);
if (!av7110->kbuf[type])
return -ENOBUFS;
@@ -546,8 +551,8 @@ static ssize_t dvb_aplay(struct av7110 *av7110, const char __user *buf,
if (nonblock)
return count - todo;
if (wait_event_interruptible(av7110->aout.queue,
- (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)))
- return count-todo;
+ (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)))
+ return count - todo;
}
n = todo;
if (n > IPACKS * 2)
@@ -580,8 +585,7 @@ static void clear_p2t(struct av7110_p2t *p)
p->frags = 0;
}
-
-static int find_pes_header(u8 const *buf, long int length, int *frags)
+static int find_pes_header(u8 const *buf, long length, int *frags)
{
int c = 0;
int found = 0;
@@ -591,7 +595,7 @@ static int find_pes_header(u8 const *buf, long int length, int *frags)
while (c < length - 3 && !found) {
if (buf[c] == 0x00 && buf[c + 1] == 0x00 &&
buf[c + 2] == 0x01) {
- switch ( buf[c + 3] ) {
+ switch (buf[c + 3]) {
case PROG_STREAM_MAP:
case PRIVATE_STREAM2:
case PROG_STREAM_DIR:
@@ -610,8 +614,9 @@ static int find_pes_header(u8 const *buf, long int length, int *frags)
c++;
break;
}
- } else
+ } else {
c++;
+ }
}
if (c == length - 3 && !found) {
if (buf[length - 1] == 0x00)
@@ -629,16 +634,16 @@ static int find_pes_header(u8 const *buf, long int length, int *frags)
return c;
}
-void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p)
+void av7110_p2t_write(u8 const *buf, long length, u16 pid, struct av7110_p2t *p)
{
int c, c2, l, add;
int check, rest;
c = 0;
c2 = 0;
- if (p->frags){
+ if (p->frags) {
check = 0;
- switch(p->frags) {
+ switch (p->frags) {
case 1:
if (buf[c] == 0x00 && buf[c + 1] == 0x01) {
check = 1;
@@ -689,7 +694,7 @@ void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t
if (p->pos) {
c2 = find_pes_header(buf + c, length - c, &p->frags);
if (c2 >= 0 && c2 < (TS_SIZE - 4) - p->pos)
- l = c2+c;
+ l = c2 + c;
else
l = (TS_SIZE - 4) - p->pos;
memcpy(p->pes + p->pos, buf, l);
@@ -704,13 +709,14 @@ void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t
c2 = find_pes_header(buf + c + add, length - c - add, &p->frags);
if (c2 >= 0) {
c2 += c + add;
- if (c2 > c){
+ if (c2 > c) {
p_to_t(buf + c, c2 - c, pid, &p->counter, p->feed);
c = c2;
clear_p2t(p);
add = 0;
- } else
+ } else {
add = 1;
+ }
} else {
l = length - c;
rest = l % (TS_SIZE - 4);
@@ -723,7 +729,6 @@ void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t
}
}
-
static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 length)
{
int i;
@@ -758,8 +763,7 @@ static int write_ts_header2(u16 pid, u8 *counter, int pes_start, u8 *buf, u8 len
return c;
}
-
-static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
+static void p_to_t(u8 const *buf, long length, u16 pid, u8 *counter,
struct dvb_demux_feed *feed)
{
int l, pes_start;
@@ -768,7 +772,7 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
pes_start = 0;
if (length > 3 &&
- buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01)
+ buf[0] == 0x00 && buf[1] == 0x00 && buf[2] == 0x01)
switch (buf[3]) {
case PROG_STREAM_MAP:
case PRIVATE_STREAM2:
@@ -790,7 +794,7 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
while (c < length) {
memset(obuf, 0, TS_SIZE);
- if (length - c >= (TS_SIZE - 4)){
+ if (length - c >= (TS_SIZE - 4)) {
l = write_ts_header2(pid, counter, pes_start,
obuf, (TS_SIZE - 4));
memcpy(obuf + l, buf + c, TS_SIZE - l);
@@ -806,7 +810,6 @@ static void p_to_t(u8 const *buf, long int length, u16 pid, u8 *counter,
}
}
-
static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, size_t len)
{
struct ipack *ipack = &av7110->ipack[type];
@@ -833,13 +836,12 @@ static int write_ts_to_decoder(struct av7110 *av7110, int type, const u8 *buf, s
return 0;
}
-
int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len)
{
struct dvb_demux *demux = feed->demux;
struct av7110 *av7110 = demux->priv;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
if (av7110->full_ts && demux->dmx.frontend->source != DMX_MEMORY_FE)
return 0;
@@ -860,8 +862,6 @@ int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t l
return write_ts_to_decoder(av7110, feed->pes_type, buf, len);
}
-
-
/******************************************************************************
* Video MPEG decoder events
******************************************************************************/
@@ -887,8 +887,7 @@ void dvb_video_add_event(struct av7110 *av7110, struct video_event *event)
wake_up_interruptible(&events->wait_queue);
}
-
-static int dvb_video_get_event (struct av7110 *av7110, struct video_event *event, int flags)
+static int dvb_video_get_event(struct av7110 *av7110, struct video_event *event, int flags)
{
struct dvb_video_events *events = &av7110->video_events;
@@ -929,7 +928,7 @@ static __poll_t dvb_video_poll(struct file *file, poll_table *wait)
struct av7110 *av7110 = dvbdev->priv;
__poll_t mask = 0;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
if ((file->f_flags & O_ACCMODE) != O_RDONLY)
poll_wait(file, &av7110->avout.queue, wait);
@@ -959,7 +958,7 @@ static ssize_t dvb_video_write(struct file *file, const char __user *buf,
struct av7110 *av7110 = dvbdev->priv;
unsigned char c;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
return -EPERM;
@@ -981,15 +980,17 @@ static __poll_t dvb_audio_poll(struct file *file, poll_table *wait)
struct av7110 *av7110 = dvbdev->priv;
__poll_t mask = 0;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
poll_wait(file, &av7110->aout.queue, wait);
if (av7110->playing) {
if (dvb_ringbuffer_free(&av7110->aout) >= 20 * 1024)
mask |= (EPOLLOUT | EPOLLWRNORM);
- } else /* if not playing: may play if asked for */
+ } else {
+ /* if not playing: may play if asked for */
mask = (EPOLLOUT | EPOLLWRNORM);
+ }
return mask;
}
@@ -1001,10 +1002,10 @@ static ssize_t dvb_audio_write(struct file *file, const char __user *buf,
struct av7110 *av7110 = dvbdev->priv;
unsigned char c;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
if (av7110->audiostate.stream_source != AUDIO_SOURCE_MEMORY) {
- printk(KERN_ERR "not audio source memory\n");
+ pr_err("not audio source memory\n");
return -EPERM;
}
@@ -1022,11 +1023,11 @@ static u8 iframe_header[] = { 0x00, 0x00, 0x01, 0xe0, 0x00, 0x00, 0x80, 0x00, 0x
static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len, int nonblock)
{
- unsigned i, n;
+ unsigned int i, n;
int progressive = 0;
int match = 0;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
if (len == 0)
return 0;
@@ -1039,6 +1040,7 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
/* search in buf for instances of 00 00 01 b5 1? */
for (i = 0; i < len; i++) {
unsigned char c;
+
if (get_user(c, buf + i))
return -EFAULT;
if (match == 5) {
@@ -1050,13 +1052,16 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
continue;
}
switch (match++) {
- case 2: if (c == 0x01)
+ case 2:
+ if (c == 0x01)
continue;
break;
- case 3: if (c == 0xb5)
+ case 3:
+ if (c == 0xb5)
continue;
break;
- case 4: if ((c & 0xf0) == 0x10)
+ case 4:
+ if ((c & 0xf0) == 0x10)
continue;
break;
}
@@ -1064,7 +1069,8 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
}
/* setting n always > 1, fixes problems when playing stillframes
- consisting of I- and P-Frames */
+ * consisting of I- and P-Frames
+ */
n = MIN_IFRAME / len + 1;
/* FIXME: nonblock? */
@@ -1084,8 +1090,9 @@ static int play_iframe(struct av7110 *av7110, char __user *buf, unsigned int len
#ifdef CONFIG_COMPAT
struct compat_video_still_picture {
compat_uptr_t iFrame;
- int32_t size;
+ s32 size;
};
+
#define VIDEO_STILLPICTURE32 _IOW('o', 30, struct compat_video_still_picture)
struct compat_video_event {
@@ -1098,6 +1105,7 @@ struct compat_video_event {
unsigned char vsync_field; /* unknown/odd/even/progressive */
} u;
};
+
#define VIDEO_GET_EVENT32 _IOR('o', 28, struct compat_video_event)
static int dvb_compat_video_get_event(struct av7110 *av7110,
@@ -1123,14 +1131,14 @@ static int dvb_video_ioctl(struct file *file,
{
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
- unsigned long arg = (unsigned long) parg;
+ unsigned long arg = (unsigned long)parg;
int ret = 0;
- dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
+ dprintk(1, "av7110:%p, cmd=%04x\n", av7110, cmd);
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
- if ( cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT &&
- cmd != VIDEO_GET_SIZE ) {
+ if (cmd != VIDEO_GET_STATUS && cmd != VIDEO_GET_EVENT &&
+ cmd != VIDEO_GET_SIZE) {
return -EPERM;
}
}
@@ -1145,7 +1153,7 @@ static int dvb_video_ioctl(struct file *file,
ret = av7110_av_stop(av7110, RP_VIDEO);
else
ret = vidcom(av7110, AV_VIDEO_CMD_STOP,
- av7110->videostate.video_blank ? 0 : 1);
+ av7110->videostate.video_blank ? 0 : 1);
if (!ret)
av7110->trickmode = TRICK_NONE;
break;
@@ -1195,11 +1203,11 @@ static int dvb_video_ioctl(struct file *file,
break;
case VIDEO_SELECT_SOURCE:
- av7110->videostate.stream_source = (video_stream_source_t) arg;
+ av7110->videostate.stream_source = (video_stream_source_t)arg;
break;
case VIDEO_SET_BLANK:
- av7110->videostate.video_blank = (int) arg;
+ av7110->videostate.video_blank = (int)arg;
break;
case VIDEO_GET_STATUS:
@@ -1222,7 +1230,8 @@ static int dvb_video_ioctl(struct file *file,
case VIDEO_SET_DISPLAY_FORMAT:
{
- video_displayformat_t format = (video_displayformat_t) arg;
+ video_displayformat_t format = (video_displayformat_t)arg;
+
switch (format) {
case VIDEO_PAN_SCAN:
av7110->display_panscan = VID_PAN_SCAN_PREF;
@@ -1251,14 +1260,14 @@ static int dvb_video_ioctl(struct file *file,
}
av7110->display_ar = arg;
ret = av7110_fw_cmd(av7110, COMTYPE_ENCODER, SetMonitorType,
- 1, (u16) arg);
+ 1, (u16)arg);
break;
#ifdef CONFIG_COMPAT
case VIDEO_STILLPICTURE32:
{
struct compat_video_still_picture *pic =
- (struct compat_video_still_picture *) parg;
+ (struct compat_video_still_picture *)parg;
av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY;
dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
ret = play_iframe(av7110, compat_ptr(pic->iFrame),
@@ -1270,7 +1279,7 @@ static int dvb_video_ioctl(struct file *file,
case VIDEO_STILLPICTURE:
{
struct video_still_picture *pic =
- (struct video_still_picture *) parg;
+ (struct video_still_picture *)parg;
av7110->videostate.stream_source = VIDEO_SOURCE_MEMORY;
dvb_ringbuffer_flush_spinlock_wakeup(&av7110->avout);
ret = play_iframe(av7110, pic->iFrame, pic->size,
@@ -1292,7 +1301,7 @@ static int dvb_video_ioctl(struct file *file,
break;
case VIDEO_SLOWMOTION:
- if (av7110->playing&RP_VIDEO) {
+ if (av7110->playing & RP_VIDEO) {
if (av7110->trickmode != TRICK_SLOW)
ret = av7110_fw_cmd(av7110, COMTYPE_REC_PLAY, __Slow, 2, 0, 0);
if (!ret)
@@ -1354,10 +1363,10 @@ static int dvb_audio_ioctl(struct file *file,
{
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
- unsigned long arg = (unsigned long) parg;
+ unsigned long arg = (unsigned long)parg;
int ret = 0;
- dprintk(1, "av7110:%p, cmd=%04x\n", av7110,cmd);
+ dprintk(1, "av7110:%p, cmd=%04x\n", av7110, cmd);
if (((file->f_flags & O_ACCMODE) == O_RDONLY) &&
(cmd != AUDIO_GET_STATUS))
@@ -1399,19 +1408,19 @@ static int dvb_audio_ioctl(struct file *file,
break;
case AUDIO_SELECT_SOURCE:
- av7110->audiostate.stream_source = (audio_stream_source_t) arg;
+ av7110->audiostate.stream_source = (audio_stream_source_t)arg;
break;
case AUDIO_SET_MUTE:
{
ret = audcom(av7110, arg ? AUDIO_CMD_MUTE : AUDIO_CMD_UNMUTE);
if (!ret)
- av7110->audiostate.mute_state = (int) arg;
+ av7110->audiostate.mute_state = (int)arg;
break;
}
case AUDIO_SET_AV_SYNC:
- av7110->audiostate.AV_sync_state = (int) arg;
+ av7110->audiostate.AV_sync_state = (int)arg;
ret = audcom(av7110, arg ? AUDIO_CMD_SYNC_ON : AUDIO_CMD_SYNC_OFF);
break;
@@ -1422,8 +1431,8 @@ static int dvb_audio_ioctl(struct file *file,
break;
case AUDIO_CHANNEL_SELECT:
- av7110->audiostate.channel_select = (audio_channel_select_t) arg;
- switch(av7110->audiostate.channel_select) {
+ av7110->audiostate.channel_select = (audio_channel_select_t)arg;
+ switch (av7110->audiostate.channel_select) {
case AUDIO_STEREO:
ret = audcom(av7110, AUDIO_CMD_STEREO);
if (!ret) {
@@ -1483,6 +1492,7 @@ static int dvb_audio_ioctl(struct file *file,
case AUDIO_SET_MIXER:
{
struct audio_mixer *amix = (struct audio_mixer *)parg;
+
ret = av7110_set_volume(av7110, amix->volume_left, amix->volume_right);
break;
}
@@ -1498,16 +1508,16 @@ static int dvb_audio_ioctl(struct file *file,
return ret;
}
-
static int dvb_video_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
int err;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
- if ((err = dvb_generic_open(inode, file)) < 0)
+ err = dvb_generic_open(inode, file);
+ if (err < 0)
return err;
if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
@@ -1518,7 +1528,8 @@ static int dvb_video_open(struct inode *inode, struct file *file)
av7110->videostate.stream_source = VIDEO_SOURCE_DEMUX;
/* empty event queue */
- av7110->video_events.eventr = av7110->video_events.eventw = 0;
+ av7110->video_events.eventr = 0;
+ av7110->video_events.eventw = 0;
}
return 0;
@@ -1529,11 +1540,10 @@ static int dvb_video_release(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
- if ((file->f_flags & O_ACCMODE) != O_RDONLY) {
+ if ((file->f_flags & O_ACCMODE) != O_RDONLY)
av7110_av_stop(av7110, RP_VIDEO);
- }
return dvb_generic_release(inode, file);
}
@@ -1544,7 +1554,7 @@ static int dvb_audio_open(struct inode *inode, struct file *file)
struct av7110 *av7110 = dvbdev->priv;
int err = dvb_generic_open(inode, file);
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
if (err < 0)
return err;
@@ -1558,14 +1568,12 @@ static int dvb_audio_release(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
- dprintk(2, "av7110:%p, \n", av7110);
+ dprintk(2, "av7110:%p\n", av7110);
av7110_av_stop(av7110, RP_AUDIO);
return dvb_generic_release(inode, file);
}
-
-
/******************************************************************************
* driver registration
******************************************************************************/
@@ -1609,7 +1617,6 @@ static struct dvb_device dvbdev_audio = {
.kernel_ioctl = dvb_audio_ioctl,
};
-
int av7110_av_register(struct av7110 *av7110)
{
av7110->audiostate.AV_sync_state = 0;
@@ -1629,9 +1636,10 @@ int av7110_av_register(struct av7110 *av7110)
init_waitqueue_head(&av7110->video_events.wait_queue);
spin_lock_init(&av7110->video_events.lock);
- av7110->video_events.eventw = av7110->video_events.eventr = 0;
+ av7110->video_events.eventw = 0;
+ av7110->video_events.eventr = 0;
av7110->video_events.overflow = 0;
- memset(&av7110->video_size, 0, sizeof (video_size_t));
+ memset(&av7110->video_size, 0, sizeof(video_size_t));
dvb_register_device(&av7110->dvb_adapter, &av7110->video_dev,
&dvbdev_video, av7110, DVB_DEVICE_VIDEO, 0);
diff --git a/drivers/staging/media/av7110/av7110_av.h b/drivers/staging/media/av7110/av7110_av.h
index 71bbd4391f57..eebaf59c7585 100644
--- a/drivers/staging/media/av7110/av7110_av.h
+++ b/drivers/staging/media/av7110/av7110_av.h
@@ -4,29 +4,28 @@
struct av7110;
-extern int av7110_set_vidmode(struct av7110 *av7110,
- enum av7110_video_mode mode);
+int av7110_set_vidmode(struct av7110 *av7110,
+ enum av7110_video_mode mode);
-extern int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
-extern int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
-extern int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len);
+int av7110_record_cb(struct dvb_filter_pes2ts *p2t, u8 *buf, size_t len);
+int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen);
+int av7110_write_to_decoder(struct dvb_demux_feed *feed, const u8 *buf, size_t len);
-extern int av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
- unsigned int volright);
-extern int av7110_av_stop(struct av7110 *av7110, int av);
-extern int av7110_av_start_record(struct av7110 *av7110, int av,
- struct dvb_demux_feed *dvbdmxfeed);
-extern int av7110_av_start_play(struct av7110 *av7110, int av);
+int av7110_set_volume(struct av7110 *av7110, unsigned int volleft,
+ unsigned int volright);
+int av7110_av_stop(struct av7110 *av7110, int av);
+int av7110_av_start_record(struct av7110 *av7110, int av,
+ struct dvb_demux_feed *dvbdmxfeed);
+int av7110_av_start_play(struct av7110 *av7110, int av);
-extern void dvb_video_add_event(struct av7110 *av7110, struct video_event *event);
+void dvb_video_add_event(struct av7110 *av7110, struct video_event *event);
-extern void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed);
-extern void av7110_p2t_write(u8 const *buf, long int length, u16 pid, struct av7110_p2t *p);
-
-extern int av7110_av_register(struct av7110 *av7110);
-extern void av7110_av_unregister(struct av7110 *av7110);
-extern int av7110_av_init(struct av7110 *av7110);
-extern void av7110_av_exit(struct av7110 *av7110);
+void av7110_p2t_init(struct av7110_p2t *p, struct dvb_demux_feed *feed);
+void av7110_p2t_write(u8 const *buf, long length, u16 pid, struct av7110_p2t *p);
+int av7110_av_register(struct av7110 *av7110);
+void av7110_av_unregister(struct av7110 *av7110);
+int av7110_av_init(struct av7110 *av7110);
+void av7110_av_exit(struct av7110 *av7110);
#endif /* _AV7110_AV_H_ */
diff --git a/drivers/staging/media/av7110/av7110_ca.c b/drivers/staging/media/av7110/av7110_ca.c
index c1338e074a3d..6ce212c64e5d 100644
--- a/drivers/staging/media/av7110/av7110_ca.c
+++ b/drivers/staging/media/av7110/av7110_ca.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * av7110_ca.c: CA and CI stuff
+ * driver for the SAA7146 based AV110 cards
+ * - CA and CI stuff
*
* Copyright (C) 1999-2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
@@ -23,10 +24,9 @@
#include "av7110_hw.h"
#include "av7110_ca.h"
-
void CI_handle(struct av7110 *av7110, u8 *data, u16 len)
{
- dprintk(8, "av7110:%p\n",av7110);
+ dprintk(8, "av7110:%p\n", av7110);
if (len < 3)
return;
@@ -54,7 +54,6 @@ void CI_handle(struct av7110 *av7110, u8 *data, u16 len)
}
}
-
void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len)
{
if (dvb_ringbuffer_free(cibuf) < len + 2)
@@ -66,7 +65,6 @@ void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len)
wake_up_interruptible(&cibuf->queue);
}
-
/******************************************************************************
* CI link layer file ops
******************************************************************************/
@@ -201,7 +199,7 @@ static int dvb_ca_open(struct inode *inode, struct file *file)
struct av7110 *av7110 = dvbdev->priv;
int err = dvb_generic_open(inode, file);
- dprintk(8, "av7110:%p\n",av7110);
+ dprintk(8, "av7110:%p\n", av7110);
if (err < 0)
return err;
@@ -209,7 +207,7 @@ static int dvb_ca_open(struct inode *inode, struct file *file)
return 0;
}
-static __poll_t dvb_ca_poll (struct file *file, poll_table *wait)
+static __poll_t dvb_ca_poll(struct file *file, poll_table *wait)
{
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
@@ -217,7 +215,7 @@ static __poll_t dvb_ca_poll (struct file *file, poll_table *wait)
struct dvb_ringbuffer *wbuf = &av7110->ci_wbuffer;
__poll_t mask = 0;
- dprintk(8, "av7110:%p\n",av7110);
+ dprintk(8, "av7110:%p\n", av7110);
poll_wait(file, &rbuf->queue, wait);
poll_wait(file, &wbuf->queue, wait);
@@ -235,10 +233,10 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
{
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
- unsigned long arg = (unsigned long) parg;
+ unsigned long arg = (unsigned long)parg;
int ret = 0;
- dprintk(8, "av7110:%p\n",av7110);
+ dprintk(8, "av7110:%p\n", av7110);
if (mutex_lock_interruptible(&av7110->ioctl_mutex))
return -ERESTARTSYS;
@@ -263,7 +261,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
case CA_GET_SLOT_INFO:
{
- struct ca_slot_info *info=(struct ca_slot_info *)parg;
+ struct ca_slot_info *info = (struct ca_slot_info *)parg;
if (info->num < 0 || info->num > 1) {
mutex_unlock(&av7110->ioctl_mutex);
@@ -288,24 +286,24 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
info.num = 16;
info.type = CA_ECD;
- memcpy(parg, &info, sizeof (info));
+ memcpy(parg, &info, sizeof(info));
break;
}
case CA_SET_DESCR:
{
- struct ca_descr *descr = (struct ca_descr*) parg;
+ struct ca_descr *descr = (struct ca_descr *)parg;
if (descr->index >= 16 || descr->parity > 1) {
mutex_unlock(&av7110->ioctl_mutex);
return -EINVAL;
}
av7110_fw_cmd(av7110, COMTYPE_PIDFILTER, SetDescr, 5,
- (descr->index<<8)|descr->parity,
- (descr->cw[0]<<8)|descr->cw[1],
- (descr->cw[2]<<8)|descr->cw[3],
- (descr->cw[4]<<8)|descr->cw[5],
- (descr->cw[6]<<8)|descr->cw[7]);
+ (descr->index << 8) | descr->parity,
+ (descr->cw[0] << 8) | descr->cw[1],
+ (descr->cw[2] << 8) | descr->cw[3],
+ (descr->cw[4] << 8) | descr->cw[5],
+ (descr->cw[6] << 8) | descr->cw[7]);
break;
}
@@ -324,7 +322,7 @@ static ssize_t dvb_ca_write(struct file *file, const char __user *buf,
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
- dprintk(8, "av7110:%p\n",av7110);
+ dprintk(8, "av7110:%p\n", av7110);
return ci_ll_write(&av7110->ci_wbuffer, file, buf, count, ppos);
}
@@ -334,7 +332,7 @@ static ssize_t dvb_ca_read(struct file *file, char __user *buf,
struct dvb_device *dvbdev = file->private_data;
struct av7110 *av7110 = dvbdev->priv;
- dprintk(8, "av7110:%p\n",av7110);
+ dprintk(8, "av7110:%p\n", av7110);
return ci_ll_read(&av7110->ci_rbuffer, file, buf, count, ppos);
}
@@ -357,7 +355,6 @@ static struct dvb_device dvbdev_ca = {
.kernel_ioctl = dvb_ca_ioctl,
};
-
int av7110_ca_register(struct av7110 *av7110)
{
return dvb_register_device(&av7110->dvb_adapter, &av7110->ca_dev,
@@ -369,12 +366,12 @@ void av7110_ca_unregister(struct av7110 *av7110)
dvb_unregister_device(av7110->ca_dev);
}
-int av7110_ca_init(struct av7110* av7110)
+int av7110_ca_init(struct av7110 *av7110)
{
return ci_ll_init(&av7110->ci_rbuffer, &av7110->ci_wbuffer, 8192);
}
-void av7110_ca_exit(struct av7110* av7110)
+void av7110_ca_exit(struct av7110 *av7110)
{
ci_ll_release(&av7110->ci_rbuffer, &av7110->ci_wbuffer);
}
diff --git a/drivers/staging/media/av7110/av7110_ca.h b/drivers/staging/media/av7110/av7110_ca.h
index a6e3f2955730..d3521944b97c 100644
--- a/drivers/staging/media/av7110/av7110_ca.h
+++ b/drivers/staging/media/av7110/av7110_ca.h
@@ -4,12 +4,12 @@
struct av7110;
-extern void CI_handle(struct av7110 *av7110, u8 *data, u16 len);
-extern void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len);
+void CI_handle(struct av7110 *av7110, u8 *data, u16 len);
+void ci_get_data(struct dvb_ringbuffer *cibuf, u8 *data, int len);
-extern int av7110_ca_register(struct av7110 *av7110);
-extern void av7110_ca_unregister(struct av7110 *av7110);
-extern int av7110_ca_init(struct av7110* av7110);
-extern void av7110_ca_exit(struct av7110* av7110);
+int av7110_ca_register(struct av7110 *av7110);
+void av7110_ca_unregister(struct av7110 *av7110);
+int av7110_ca_init(struct av7110 *av7110);
+void av7110_ca_exit(struct av7110 *av7110);
#endif /* _AV7110_CA_H_ */
diff --git a/drivers/staging/media/av7110/av7110_hw.c b/drivers/staging/media/av7110/av7110_hw.c
index a0be37717259..bf8e6dca40e5 100644
--- a/drivers/staging/media/av7110/av7110_hw.c
+++ b/drivers/staging/media/av7110/av7110_hw.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * av7110_hw.c: av7110 low level hardware access and firmware interface
+ * driver for the SAA7146 based AV110 cards
+ * - av7110 low level hardware access and firmware interface
*
* Copyright (C) 1999-2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
@@ -38,7 +39,8 @@
****************************************************************************/
/* This DEBI code is based on the Stradis driver
- by Nathan Laredo <laredo@gnu.org> */
+ * by Nathan Laredo <laredo@gnu.org>
+ */
int av7110_debiwrite(struct av7110 *av7110, u32 config,
int addr, u32 val, unsigned int count)
@@ -46,11 +48,11 @@ int av7110_debiwrite(struct av7110 *av7110, u32 config,
struct saa7146_dev *dev = av7110->dev;
if (count > 32764) {
- printk("%s: invalid count %d\n", __func__, count);
+ pr_err("%s(): invalid count %d\n", __func__, count);
return -1;
}
if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
- printk("%s: wait_for_debi_done failed\n", __func__);
+ pr_err("%s(): wait_for_debi_done failed\n", __func__);
return -1;
}
saa7146_write(dev, DEBI_CONFIG, config);
@@ -69,11 +71,11 @@ u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int co
u32 result = 0;
if (count > 32764) {
- printk("%s: invalid count %d\n", __func__, count);
+ pr_err("%s(): invalid count %d\n", __func__, count);
return 0;
}
if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
- printk("%s: wait_for_debi_done #1 failed\n", __func__);
+ pr_err("%s(): wait_for_debi_done #1 failed\n", __func__);
return 0;
}
saa7146_write(dev, DEBI_AD, av7110->debi_bus);
@@ -84,7 +86,7 @@ u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int co
if (count > 4)
return count;
if (saa7146_wait_for_debi_done(av7110->dev, 0) < 0) {
- printk("%s: wait_for_debi_done #2 failed\n", __func__);
+ pr_err("%s(): wait_for_debi_done #2 failed\n", __func__);
return 0;
}
@@ -93,8 +95,6 @@ u32 av7110_debiread(struct av7110 *av7110, u32 config, int addr, unsigned int co
return result;
}
-
-
/* av7110 ARM core boot stuff */
#if 0
void av7110_reset_arm(struct av7110 *av7110)
@@ -146,7 +146,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
for (i = 0; i < blocks; i++) {
if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
- printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at block %d\n", i);
+ pr_err("%s(): timeout at block %d\n", __func__, i);
return -ETIMEDOUT;
}
dprintk(4, "writing DRAM block %d\n", i);
@@ -161,7 +161,7 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
if (rest > 0) {
if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
- printk(KERN_ERR "dvb-ttpci: load_dram(): timeout at last block\n");
+ pr_err("%s(): timeout at last block\n", __func__);
return -ETIMEDOUT;
}
if (rest > 4)
@@ -176,21 +176,21 @@ static int load_dram(struct av7110 *av7110, u32 *data, int len)
iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
}
if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_EMPTY) < 0) {
- printk(KERN_ERR "dvb-ttpci: load_dram(): timeout after last block\n");
+ pr_err("%s(): timeout after last block\n", __func__);
return -ETIMEDOUT;
}
iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_SIZE, 0, 2);
iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
if (waitdebi(av7110, AV7110_BOOT_STATE, BOOTSTATE_AV7110_BOOT_COMPLETE) < 0) {
- printk(KERN_ERR "dvb-ttpci: load_dram(): final handshake timeout\n");
+ pr_err("%s(): final handshake timeout\n", __func__);
return -ETIMEDOUT;
}
return 0;
}
-
/* we cannot write av7110 DRAM directly, so load a bootloader into
- * the DPRAM which implements a simple boot protocol */
+ * the DPRAM which implements a simple boot protocol
+ */
int av7110_bootarm(struct av7110 *av7110)
{
const struct firmware *fw;
@@ -219,9 +219,10 @@ int av7110_bootarm(struct av7110 *av7110)
/* FIXME: Why does Nexus CA require 2x iwdebi for first init? */
iwdebi(av7110, DEBISWAP, DPRAM_BASE, 0x76543210, 4);
- if ((ret=irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4)) != 0x10325476) {
- printk(KERN_ERR "dvb-ttpci: debi test in av7110_bootarm() failed: %08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
- ret, 0x10325476);
+ ret = irdebi(av7110, DEBINOSWAP, DPRAM_BASE, 0, 4);
+ if (ret != 0x10325476) {
+ pr_err("debi test in %s() failed: %08x != %08x (check your BIOS 'Plug&Play OS' settings)\n",
+ __func__, ret, 0x10325476);
return -1;
}
for (i = 0; i < 8192; i += 4)
@@ -236,8 +237,7 @@ int av7110_bootarm(struct av7110 *av7110)
ret = request_firmware(&fw, fw_name, &dev->pci->dev);
if (ret) {
- printk(KERN_ERR "dvb-ttpci: Failed to load firmware \"%s\"\n",
- fw_name);
+ pr_err("Failed to load firmware \"%s\"\n", fw_name);
return ret;
}
@@ -246,7 +246,7 @@ int av7110_bootarm(struct av7110 *av7110)
iwdebi(av7110, DEBINOSWAP, AV7110_BOOT_STATE, BOOTSTATE_BUFFER_FULL, 2);
if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
- printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out\n");
+ pr_err("%s(): saa7146_wait_for_debi_done() timed out\n", __func__);
return -ETIMEDOUT;
}
saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
@@ -254,7 +254,7 @@ int av7110_bootarm(struct av7110 *av7110)
dprintk(1, "load dram code\n");
if (load_dram(av7110, (u32 *)av7110->bin_root, av7110->size_root) < 0) {
- printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): load_dram() failed\n");
+ pr_err("%s(): load_dram() failed\n", __func__);
return -1;
}
@@ -265,7 +265,7 @@ int av7110_bootarm(struct av7110 *av7110)
mwdebi(av7110, DEBISWAB, DPRAM_BASE, av7110->bin_dpram, av7110->size_dpram);
if (saa7146_wait_for_debi_done(av7110->dev, 1)) {
- printk(KERN_ERR "dvb-ttpci: av7110_bootarm(): saa7146_wait_for_debi_done() timed out after loading DRAM\n");
+ pr_err("%s(): saa7146_wait_for_debi_done() timed out after loading DRAM\n", __func__);
return -ETIMEDOUT;
}
saa7146_setgpio(dev, RESET_LINE, SAA7146_GPIO_OUTHI);
@@ -309,8 +309,7 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
if ((stat & flags) == 0)
break;
if (err) {
- printk(KERN_ERR "%s: timeout waiting for MSGSTATE %04x\n",
- __func__, stat & flags);
+ pr_err("%s(): timeout waiting for MSGSTATE %04x\n", __func__, stat & flags);
return -ETIMEDOUT;
}
msleep(1);
@@ -318,7 +317,7 @@ int av7110_wait_msgstate(struct av7110 *av7110, u16 flags)
return 0;
}
-static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
+static int __av7110_send_fw_cmd(struct av7110 *av7110, u16 *buf, int length)
{
int i;
unsigned long start;
@@ -340,7 +339,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
break;
if (err) {
- printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND idle\n", __func__);
+ pr_err("%s(): timeout waiting for COMMAND idle\n", __func__);
av7110->arm_errors++;
return -ETIMEDOUT;
}
@@ -357,7 +356,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
break;
if (err) {
- printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for HANDSHAKE_REG\n", __func__);
+ pr_err("%s(): timeout waiting for HANDSHAKE_REG\n", __func__);
return -ETIMEDOUT;
}
msleep(1);
@@ -389,22 +388,20 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
break;
}
- if (type != NULL) {
+ if (type) {
/* non-immediate COMMAND type */
start = jiffies;
for (;;) {
err = time_after(jiffies, start + ARM_WAIT_FREE);
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
if (stat & flags[0]) {
- printk(KERN_ERR "%s: %s QUEUE overflow\n",
- __func__, type);
+ pr_err("%s(): %s QUEUE overflow\n", __func__, type);
return -1;
}
if ((stat & flags[1]) == 0)
break;
if (err) {
- printk(KERN_ERR "%s: timeout waiting on busy %s QUEUE\n",
- __func__, type);
+ pr_err("%s(): timeout waiting on busy %s QUEUE\n", __func__, type);
av7110->arm_errors++;
return -ETIMEDOUT;
}
@@ -413,14 +410,14 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
}
for (i = 2; i < length; i++)
- wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32) buf[i], 2);
+ wdebi(av7110, DEBINOSWAP, COMMAND + 2 * i, (u32)buf[i], 2);
if (length)
- wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32) buf[1], 2);
+ wdebi(av7110, DEBINOSWAP, COMMAND + 2, (u32)buf[1], 2);
else
wdebi(av7110, DEBINOSWAP, COMMAND + 2, 0, 2);
- wdebi(av7110, DEBINOSWAP, COMMAND, (u32) buf[0], 2);
+ wdebi(av7110, DEBINOSWAP, COMMAND, (u32)buf[0], 2);
if (FW_VERSION(av7110->arm_app) <= 0x261f)
wdebi(av7110, DEBINOSWAP, COM_IF_LOCK, 0x0000, 2);
@@ -432,7 +429,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
break;
if (err) {
- printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for COMMAND %d to complete\n",
+ pr_err("%s(): timeout waiting for COMMAND %d to complete\n",
__func__, (buf[0] >> 8) & 0xff);
return -ETIMEDOUT;
}
@@ -441,11 +438,10 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
if (stat & GPMQOver) {
- printk(KERN_ERR "dvb-ttpci: %s(): GPMQOver\n", __func__);
+ pr_err("%s(): GPMQOver\n", __func__);
return -ENOSPC;
- }
- else if (stat & OSDQOver) {
- printk(KERN_ERR "dvb-ttpci: %s(): OSDQOver\n", __func__);
+ } else if (stat & OSDQOver) {
+ pr_err("%s(): OSDQOver\n", __func__);
return -ENOSPC;
}
#endif
@@ -453,7 +449,7 @@ static int __av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
return 0;
}
-static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
+static int av7110_send_fw_cmd(struct av7110 *av7110, u16 *buf, int length)
{
int ret;
@@ -468,9 +464,8 @@ static int av7110_send_fw_cmd(struct av7110 *av7110, u16* buf, int length)
ret = __av7110_send_fw_cmd(av7110, buf, length);
mutex_unlock(&av7110->dcomlock);
- if (ret && ret!=-ERESTARTSYS)
- printk(KERN_ERR "dvb-ttpci: %s(): av7110_send_fw_cmd error %d\n",
- __func__, ret);
+ if (ret && ret != -ERESTARTSYS)
+ pr_err("%s(): error %d\n", __func__, ret);
return ret;
}
@@ -483,9 +478,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
// dprintk(4, "%p\n", av7110);
if (2 + num > ARRAY_SIZE(buf)) {
- printk(KERN_WARNING
- "%s: %s len=%d is too big!\n",
- KBUILD_MODNAME, __func__, num);
+ pr_warn("%s(): len=%d is too big!\n", __func__, num);
return -EINVAL;
}
@@ -501,7 +494,7 @@ int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...)
ret = av7110_send_fw_cmd(av7110, buf, num + 2);
if (ret && ret != -ERESTARTSYS)
- printk(KERN_ERR "dvb-ttpci: av7110_fw_cmd error %d\n", ret);
+ pr_err("%s(): error %d\n", __func__, ret);
return ret;
}
@@ -514,9 +507,8 @@ int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
dprintk(4, "%p\n", av7110);
- for(i = 0; i < len && i < 32; i++)
- {
- if(i % 2 == 0)
+ for (i = 0; i < len && i < 32; i++) {
+ if (i % 2 == 0)
cmd[(i / 2) + 2] = (u16)(buf[i]) << 8;
else
cmd[(i / 2) + 2] |= buf[i];
@@ -524,7 +516,7 @@ int av7110_send_ci_cmd(struct av7110 *av7110, u8 subcom, u8 *buf, u8 len)
ret = av7110_send_fw_cmd(av7110, cmd, 18);
if (ret && ret != -ERESTARTSYS)
- printk(KERN_ERR "dvb-ttpci: av7110_send_ci_cmd error %d\n", ret);
+ pr_err("%s(): error %d\n", __func__, ret);
return ret;
}
#endif /* 0 */
@@ -549,9 +541,10 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
if (mutex_lock_interruptible(&av7110->dcomlock))
return -ERESTARTSYS;
- if ((err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len)) < 0) {
+ err = __av7110_send_fw_cmd(av7110, request_buf, request_buf_len);
+ if (err < 0) {
mutex_unlock(&av7110->dcomlock);
- printk(KERN_ERR "dvb-ttpci: av7110_fw_request error %d\n", err);
+ pr_err("%s(): error %d\n", __func__, err);
return err;
}
@@ -561,7 +554,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
if (rdebi(av7110, DEBINOSWAP, COMMAND, 0, 2) == 0)
break;
if (err) {
- printk(KERN_ERR "%s: timeout waiting for COMMAND to complete\n", __func__);
+ pr_err("%s(): timeout waiting for COMMAND to complete\n", __func__);
mutex_unlock(&av7110->dcomlock);
return -ETIMEDOUT;
}
@@ -577,7 +570,7 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
break;
if (err) {
- printk(KERN_ERR "%s: timeout waiting for HANDSHAKE_REG\n", __func__);
+ pr_err("%s(): timeout waiting for HANDSHAKE_REG\n", __func__);
mutex_unlock(&av7110->dcomlock);
return -ETIMEDOUT;
}
@@ -588,12 +581,11 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
#ifdef COM_DEBUG
stat = rdebi(av7110, DEBINOSWAP, MSGSTATE, 0, 2);
if (stat & GPMQOver) {
- printk(KERN_ERR "%s: GPMQOver\n", __func__);
+ pr_err("%s(): GPMQOver\n", __func__);
mutex_unlock(&av7110->dcomlock);
return -1;
- }
- else if (stat & OSDQOver) {
- printk(KERN_ERR "%s: OSDQOver\n", __func__);
+ } else if (stat & OSDQOver) {
+ pr_err("%s(): OSDQOver\n", __func__);
mutex_unlock(&av7110->dcomlock);
return -1;
}
@@ -606,16 +598,16 @@ int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
return 0;
}
-static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16* buf, s16 length)
+static int av7110_fw_query(struct av7110 *av7110, u16 tag, u16 *buf, s16 length)
{
int ret;
+
ret = av7110_fw_request(av7110, &tag, 0, buf, length);
if (ret)
- printk(KERN_ERR "dvb-ttpci: av7110_fw_query error %d\n", ret);
+ pr_err("%s(): error %d\n", __func__, ret);
return ret;
}
-
/****************************************************************************
* Firmware commands
****************************************************************************/
@@ -629,8 +621,7 @@ int av7110_firmversion(struct av7110 *av7110)
dprintk(4, "%p\n", av7110);
if (av7110_fw_query(av7110, tag, buf, 16)) {
- printk("dvb-ttpci: failed to boot firmware @ card %d\n",
- av7110->dvb_adapter.num);
+ pr_err("failed to boot firmware @ card %d\n", av7110->dvb_adapter.num);
return -EIO;
}
@@ -640,22 +631,21 @@ int av7110_firmversion(struct av7110 *av7110)
av7110->arm_app = (buf[6] << 16) + buf[7];
av7110->avtype = (buf[8] << 16) + buf[9];
- printk("dvb-ttpci: info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
- av7110->dvb_adapter.num, av7110->arm_fw,
- av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
+ pr_info("info @ card %d: firm %08x, rtsl %08x, vid %08x, app %08x\n",
+ av7110->dvb_adapter.num, av7110->arm_fw,
+ av7110->arm_rtsl, av7110->arm_vid, av7110->arm_app);
/* print firmware capabilities */
if (FW_CI_LL_SUPPORT(av7110->arm_app))
- printk("dvb-ttpci: firmware @ card %d supports CI link layer interface\n",
- av7110->dvb_adapter.num);
+ pr_info("firmware @ card %d supports CI link layer interface\n",
+ av7110->dvb_adapter.num);
else
- printk("dvb-ttpci: no firmware support for CI link layer interface @ card %d\n",
- av7110->dvb_adapter.num);
+ pr_info("no firmware support for CI link layer interface @ card %d\n",
+ av7110->dvb_adapter.num);
return 0;
}
-
int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst)
{
int i, ret;
@@ -679,12 +669,11 @@ int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long bu
buf[i + 4] = msg[i];
ret = av7110_send_fw_cmd(av7110, buf, 18);
- if (ret && ret!=-ERESTARTSYS)
- printk(KERN_ERR "dvb-ttpci: av7110_diseqc_send error %d\n", ret);
+ if (ret && ret != -ERESTARTSYS)
+ pr_err("%s(): error %d\n", __func__, ret);
return ret;
}
-
#ifdef CONFIG_DVB_AV7110_OSD
static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
@@ -693,14 +682,14 @@ static inline int SetColorBlend(struct av7110 *av7110, u8 windownr)
}
static inline int SetBlend_(struct av7110 *av7110, u8 windownr,
- enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
+ enum av7110_osd_palette_type colordepth, u16 index, u8 blending)
{
return av7110_fw_cmd(av7110, COMTYPE_OSD, SetBlend, 4,
windownr, colordepth, index, blending);
}
static inline int SetColor_(struct av7110 *av7110, u8 windownr,
- enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
+ enum av7110_osd_palette_type colordepth, u16 index, u16 colorhi, u16 colorlo)
{
return av7110_fw_cmd(av7110, COMTYPE_OSD, SetColor, 5,
windownr, colordepth, index, colorhi, colorlo);
@@ -726,8 +715,7 @@ static int FlushText(struct av7110 *av7110)
if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
break;
if (err) {
- printk(KERN_ERR "dvb-ttpci: %s(): timeout waiting for BUFF1_BASE == 0\n",
- __func__);
+ pr_err("%s(): timeout waiting for BUFF1_BASE == 0\n", __func__);
mutex_unlock(&av7110->dcomlock);
return -ETIMEDOUT;
}
@@ -753,8 +741,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
if (rdebi(av7110, DEBINOSWAP, BUFF1_BASE, 0, 2) == 0)
break;
if (ret) {
- printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for BUFF1_BASE == 0\n",
- __func__);
+ pr_err("%s(): timeout waiting for BUFF1_BASE == 0\n", __func__);
mutex_unlock(&av7110->dcomlock);
return -ETIMEDOUT;
}
@@ -767,8 +754,7 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
if (rdebi(av7110, DEBINOSWAP, HANDSHAKE_REG, 0, 2) == 0)
break;
if (ret) {
- printk(KERN_ERR "dvb-ttpci: %s: timeout waiting for HANDSHAKE_REG\n",
- __func__);
+ pr_err("%s(): timeout waiting for HANDSHAKE_REG\n", __func__);
mutex_unlock(&av7110->dcomlock);
return -ETIMEDOUT;
}
@@ -782,8 +768,8 @@ static int WriteText(struct av7110 *av7110, u8 win, u16 x, u16 y, char *buf)
wdebi(av7110, DEBINOSWAP, BUFF1_BASE + i * 2, 0, 2);
ret = __av7110_send_fw_cmd(av7110, cbuf, 5);
mutex_unlock(&av7110->dcomlock);
- if (ret && ret!=-ERESTARTSYS)
- printk(KERN_ERR "dvb-ttpci: WriteText error %d\n", ret);
+ if (ret && ret != -ERESTARTSYS)
+ pr_err("%s(): error %d\n", __func__, ret);
return ret;
}
@@ -829,10 +815,10 @@ static inline int CreateOSDWindow(struct av7110 *av7110, u8 windownr,
windownr, disptype, width, height);
}
-
static enum av7110_osd_palette_type bpp2pal[8] = {
Pal1Bit, Pal2Bit, 0, Pal4Bit, 0, 0, 0, Pal8Bit
};
+
static osd_raw_window_t bpp2bit[8] = {
OSD_BITMAP1, OSD_BITMAP2, 0, OSD_BITMAP4, 0, 0, 0, OSD_BITMAP8
};
@@ -840,10 +826,9 @@ static osd_raw_window_t bpp2bit[8] = {
static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
{
int ret = wait_event_timeout(av7110->bmpq,
- av7110->bmp_state != BMP_LOADING, 10*HZ);
+ av7110->bmp_state != BMP_LOADING, 10 * HZ);
if (ret == 0) {
- printk("dvb-ttpci: warning: timeout waiting in LoadBitmap: %d, %d\n",
- ret, av7110->bmp_state);
+ pr_warn("warning: timeout waiting in LoadBitmap: %d, %d\n", ret, av7110->bmp_state);
av7110->bmp_state = BMP_NONE;
return -ETIMEDOUT;
}
@@ -851,7 +836,7 @@ static inline int WaitUntilBmpLoaded(struct av7110 *av7110)
}
static inline int LoadBitmap(struct av7110 *av7110,
- u16 dx, u16 dy, int inc, u8 __user * data)
+ u16 dx, u16 dy, int inc, u8 __user *data)
{
u16 format;
int bpp;
@@ -866,13 +851,13 @@ static inline int LoadBitmap(struct av7110 *av7110,
av7110->bmp_state = BMP_LOADING;
if (format == OSD_BITMAP8) {
- bpp=8; delta = 1;
+ bpp = 8; delta = 1;
} else if (format == OSD_BITMAP4) {
- bpp=4; delta = 2;
+ bpp = 4; delta = 2;
} else if (format == OSD_BITMAP2) {
- bpp=2; delta = 4;
+ bpp = 2; delta = 4;
} else if (format == OSD_BITMAP1) {
- bpp=1; delta = 8;
+ bpp = 1; delta = 8;
} else {
av7110->bmp_state = BMP_NONE;
return -EINVAL;
@@ -900,7 +885,7 @@ static inline int LoadBitmap(struct av7110 *av7110,
}
}
av7110->bmplen += 1024;
- dprintk(4, "av7110_fw_cmd: LoadBmp size %d\n", av7110->bmplen);
+ dprintk(4, "av7110_fw_cmd(): LoadBmp size %d\n", av7110->bmplen);
ret = av7110_fw_cmd(av7110, COMTYPE_OSD, LoadBmp, 3, format, dx, dy);
if (!ret)
ret = WaitUntilBmpLoaded(av7110);
@@ -921,7 +906,7 @@ static inline int ReleaseBitmap(struct av7110 *av7110)
if (av7110->bmp_state != BMP_LOADED && FW_VERSION(av7110->arm_app) < 0x261e)
return -1;
if (av7110->bmp_state == BMP_LOADING)
- dprintk(1,"ReleaseBitmap called while BMP_LOADING\n");
+ dprintk(1, "%s called while BMP_LOADING\n", __func__);
av7110->bmp_state = BMP_NONE;
return av7110_fw_cmd(av7110, COMTYPE_OSD, ReleaseBmp, 0);
}
@@ -932,8 +917,8 @@ static u32 RGB2YUV(u16 R, u16 G, u16 B)
u16 Y, Cr, Cb;
y = R * 77 + G * 150 + B * 29; /* Luma=0.299R+0.587G+0.114B 0..65535 */
- u = 2048 + B * 8 -(y >> 5); /* Cr 0..4095 */
- v = 2048 + R * 8 -(y >> 5); /* Cb 0..4095 */
+ u = 2048 + B * 8 - (y >> 5); /* Cr 0..4095 */
+ v = 2048 + R * 8 - (y >> 5); /* Cb 0..4095 */
Y = y / 256;
Cb = u / 16;
@@ -949,7 +934,7 @@ static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 ble
u16 ch, cl;
u32 yuv;
- yuv = blend ? RGB2YUV(r,g,b) : 0;
+ yuv = blend ? RGB2YUV(r, g, b) : 0;
cl = (yuv & 0xffff);
ch = ((yuv >> 16) & 0xffff);
ret = SetColor_(av7110, av7110->osdwin, bpp2pal[av7110->osdbpp[av7110->osdwin]],
@@ -960,7 +945,7 @@ static int OSDSetColor(struct av7110 *av7110, u8 color, u8 r, u8 g, u8 b, u8 ble
return ret;
}
-static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u8 last)
+static int OSDSetPalette(struct av7110 *av7110, u32 __user *colors, u8 first, u8 last)
{
int i;
int length = last - first + 1;
@@ -986,11 +971,11 @@ static int OSDSetPalette(struct av7110 *av7110, u32 __user * colors, u8 first, u
}
static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
- int x1, int y1, int inc, u8 __user * data)
+ int x1, int y1, int inc, u8 __user *data)
{
uint w, h, bpp, bpl, size, lpb, bnum, brest;
int i;
- int rc,release_rc;
+ int rc, release_rc;
w = x1 - x0 + 1;
h = y1 - y0 + 1;
@@ -1036,7 +1021,7 @@ static int OSDSetBlock(struct av7110 *av7110, int x0, int y0,
if (!rc)
rc = release_rc;
if (rc)
- dprintk(1,"returns %d\n",rc);
+ dprintk(1, "returns %d\n", rc);
return rc;
}
@@ -1054,7 +1039,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
case OSD_Open:
av7110->osdbpp[av7110->osdwin] = (dc->color - 1) & 7;
ret = CreateOSDWindow(av7110, av7110->osdwin,
- bpp2bit[av7110->osdbpp[av7110->osdwin]],
+ bpp2bit[av7110->osdbpp[av7110->osdwin]],
dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
if (ret)
break;
@@ -1081,21 +1066,22 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
ret = OSDSetColor(av7110, dc->color, dc->x0, dc->y0, dc->x1, dc->y1);
break;
case OSD_SetPalette:
- if (FW_VERSION(av7110->arm_app) >= 0x2618)
+ if (FW_VERSION(av7110->arm_app) >= 0x2618) {
ret = OSDSetPalette(av7110, dc->data, dc->color, dc->x0);
- else {
- int i, len = dc->x0-dc->color+1;
+ } else {
+ int i, len = dc->x0 - dc->color + 1;
u8 __user *colors = (u8 __user *)dc->data;
u8 r, g = 0, b = 0, blend = 0;
+
ret = 0;
- for (i = 0; i<len; i++) {
+ for (i = 0; i < len; i++) {
if (get_user(r, colors + i * 4) ||
get_user(g, colors + i * 4 + 1) ||
get_user(b, colors + i * 4 + 2) ||
get_user(blend, colors + i * 4 + 3)) {
ret = -EFAULT;
break;
- }
+ }
ret = OSDSetColor(av7110, dc->color + i, r, g, b, blend);
if (ret)
break;
@@ -1104,7 +1090,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
break;
case OSD_SetPixel:
ret = DrawLine(av7110, av7110->osdwin,
- dc->x0, dc->y0, 0, 0, dc->color);
+ dc->x0, dc->y0, 0, 0, dc->color);
break;
case OSD_SetRow:
dc->y1 = dc->y0;
@@ -1114,15 +1100,15 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
break;
case OSD_FillRow:
ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
- dc->x1-dc->x0+1, dc->y1, dc->color);
+ dc->x1 - dc->x0 + 1, dc->y1, dc->color);
break;
case OSD_FillBlock:
ret = DrawBlock(av7110, av7110->osdwin, dc->x0, dc->y0,
- dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
+ dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1, dc->color);
break;
case OSD_Line:
ret = DrawLine(av7110, av7110->osdwin,
- dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
+ dc->x0, dc->y0, dc->x1 - dc->x0, dc->y1 - dc->y0, dc->color);
break;
case OSD_Text:
{
@@ -1136,7 +1122,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
if (dc->x1 > 3)
dc->x1 = 3;
ret = SetFont(av7110, av7110->osdwin, dc->x1,
- (u16) (dc->color & 0xffff), (u16) (dc->color >> 16));
+ (u16)(dc->color & 0xffff), (u16)(dc->color >> 16));
if (!ret)
ret = FlushText(av7110);
if (!ret)
@@ -1144,9 +1130,9 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
break;
}
case OSD_SetWindow:
- if (dc->x0 < 1 || dc->x0 > 7)
+ if (dc->x0 < 1 || dc->x0 > 7) {
ret = -EINVAL;
- else {
+ } else {
av7110->osdwin = dc->x0;
ret = 0;
}
@@ -1166,7 +1152,7 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
else
av7110->osdbpp[av7110->osdwin] = 0;
ret = CreateOSDWindow(av7110, av7110->osdwin, (osd_raw_window_t)dc->color,
- dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
+ dc->x1 - dc->x0 + 1, dc->y1 - dc->y0 + 1);
if (ret)
break;
if (!dc->data) {
@@ -1181,10 +1167,10 @@ int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc)
}
mutex_unlock(&av7110->osd_mutex);
- if (ret==-ERESTARTSYS)
- dprintk(1, "av7110_osd_cmd(%d) returns with -ERESTARTSYS\n",dc->cmd);
+ if (ret == -ERESTARTSYS)
+ dprintk(1, "%s(%d) returns with -ERESTARTSYS\n", __func__, dc->cmd);
else if (ret)
- dprintk(1, "av7110_osd_cmd(%d) returns with %d\n",dc->cmd,ret);
+ dprintk(1, "%s(%d) returns with %d\n", __func__, dc->cmd, ret);
return ret;
}
diff --git a/drivers/staging/media/av7110/av7110_hw.h b/drivers/staging/media/av7110/av7110_hw.h
index 6380d8950c69..d4579f411c56 100644
--- a/drivers/staging/media/av7110/av7110_hw.h
+++ b/drivers/staging/media/av7110/av7110_hw.h
@@ -11,19 +11,17 @@
#define DEBISWAP 0x002e0000
#define ARM_WAIT_FREE (HZ)
-#define ARM_WAIT_SHAKE (HZ/5)
+#define ARM_WAIT_SHAKE (HZ / 5)
#define ARM_WAIT_OSD (HZ)
-
-enum av7110_bootstate
-{
+enum av7110_bootstate {
BOOTSTATE_BUFFER_EMPTY = 0,
BOOTSTATE_BUFFER_FULL = 1,
BOOTSTATE_AV7110_BOOT_COMPLETE = 2
};
-enum av7110_type_rec_play_format
-{ RP_None,
+enum av7110_type_rec_play_format {
+ RP_None,
AudioPES,
AudioMp2,
AudioPCM,
@@ -31,8 +29,7 @@ enum av7110_type_rec_play_format
AV_PES
};
-enum av7110_osd_palette_type
-{
+enum av7110_osd_palette_type {
NoPalet = 0, /* No palette */
Pal1Bit = 2, /* 2 colors for 1 Bit Palette */
Pal2Bit = 4, /* 4 colors for 2 bit palette */
@@ -51,8 +48,7 @@ enum av7110_osd_palette_type
#define FB_ON SAA7146_GPIO_OUTHI /* FastBlank on (RGB-Mode) */
#define FB_LOOP SAA7146_GPIO_INPUT /* FastBlank loop-through (PC graphics ???) */
-enum av7110_video_output_mode
-{
+enum av7110_video_output_mode {
NO_OUT = 0, /* disable analog output */
CVBS_RGB_OUT = 1,
CVBS_YC_OUT = 2,
@@ -90,7 +86,6 @@ enum av7110_video_output_mode
#define PBUFSIZE_16K 0x0700
#define PBUFSIZE_32K 0x0800
-
/* firmware command codes */
enum av7110_osd_command {
WCreate,
@@ -255,7 +250,8 @@ enum av7110_command_type {
#define DATA_TS_PLAY 0x13
/* ancient CI command codes, only two are actually still used
- * by the link level CI firmware */
+ * by the link level CI firmware
+ */
#define CI_CMD_ERROR 0x00
#define CI_CMD_ACK 0x01
#define CI_CMD_SYSTEM_READY 0x02
@@ -289,10 +285,10 @@ enum av7110_command_type {
#define CI_MSG_CA_PMT 0xe0
#define CI_MSG_ERROR 0xf0
-
/* base address of the dual ported RAM which serves as communication
* area between PCI bus and av7110,
- * as seen by the DEBI bus of the saa7146 */
+ * as seen by the DEBI bus of the saa7146
+ */
#define DPRAM_BASE 0x4000
/* boot protocol area */
@@ -317,19 +313,18 @@ enum av7110_command_type {
#define DATA_BUFF0_BASE (DPRAM_BASE + 0x200)
#define DATA_BUFF0_SIZE 0x0800
-#define DATA_BUFF1_BASE (DATA_BUFF0_BASE+DATA_BUFF0_SIZE)
+#define DATA_BUFF1_BASE (DATA_BUFF0_BASE + DATA_BUFF0_SIZE)
#define DATA_BUFF1_SIZE 0x0800
-#define DATA_BUFF2_BASE (DATA_BUFF1_BASE+DATA_BUFF1_SIZE)
+#define DATA_BUFF2_BASE (DATA_BUFF1_BASE + DATA_BUFF1_SIZE)
#define DATA_BUFF2_SIZE 0x0800
-#define DATA_BUFF3_BASE (DATA_BUFF2_BASE+DATA_BUFF2_SIZE)
+#define DATA_BUFF3_BASE (DATA_BUFF2_BASE + DATA_BUFF2_SIZE)
#define DATA_BUFF3_SIZE 0x0400
#define Reserved (DPRAM_BASE + 0x1E00)
#define Reserved_SIZE 0x1C0
-
/* firmware status area */
#define STATUS_BASE (DPRAM_BASE + 0x1FC0)
#define STATUS_LOOPS (STATUS_BASE + 0x08)
@@ -362,26 +357,22 @@ enum av7110_command_type {
#define DEBI_DONE_LINE 1
#define ARM_IRQ_LINE 0
-
-
-extern int av7110_bootarm(struct av7110 *av7110);
-extern int av7110_firmversion(struct av7110 *av7110);
+int av7110_bootarm(struct av7110 *av7110);
+int av7110_firmversion(struct av7110 *av7110);
#define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000)
#define FW_4M_SDRAM(arm_app) ((arm_app) & 0x40000000)
#define FW_VERSION(arm_app) ((arm_app) & 0x0000FFFF)
-extern int av7110_wait_msgstate(struct av7110 *av7110, u16 flags);
-extern int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...);
-extern int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
- int request_buf_len, u16 *reply_buf, int reply_buf_len);
-
+int av7110_wait_msgstate(struct av7110 *av7110, u16 flags);
+int av7110_fw_cmd(struct av7110 *av7110, int type, int com, int num, ...);
+int av7110_fw_request(struct av7110 *av7110, u16 *request_buf,
+ int request_buf_len, u16 *reply_buf, int reply_buf_len);
/* DEBI (saa7146 data extension bus interface) access */
-extern int av7110_debiwrite(struct av7110 *av7110, u32 config,
- int addr, u32 val, unsigned int count);
-extern u32 av7110_debiread(struct av7110 *av7110, u32 config,
- int addr, unsigned int count);
-
+int av7110_debiwrite(struct av7110 *av7110, u32 config,
+ int addr, u32 val, unsigned int count);
+u32 av7110_debiread(struct av7110 *av7110, u32 config,
+ int addr, unsigned int count);
/* DEBI during interrupt */
/* single word writes */
@@ -402,9 +393,9 @@ static inline u32 irdebi(struct av7110 *av7110, u32 config, int addr, u32 val, u
{
u32 res;
- res=av7110_debiread(av7110, config, addr, count);
- if (count<=4)
- memcpy(av7110->debi_virt, (char *) &res, count);
+ res = av7110_debiread(av7110, config, addr, count);
+ if (count <= 4)
+ memcpy(av7110->debi_virt, (char *)&res, count);
return res;
}
@@ -424,7 +415,7 @@ static inline u32 rdebi(struct av7110 *av7110, u32 config, int addr, u32 val, un
u32 res;
spin_lock_irqsave(&av7110->debilock, flags);
- res=av7110_debiread(av7110, config, addr, count);
+ res = av7110_debiread(av7110, config, addr, count);
spin_unlock_irqrestore(&av7110->debilock, flags);
return res;
}
@@ -467,14 +458,14 @@ static inline int av7710_set_video_mode(struct av7110 *av7110, int mode)
static inline int vidcom(struct av7110 *av7110, u32 com, u32 arg)
{
return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_VIDEO_COMMAND, 4,
- (com>>16), (com&0xffff),
- (arg>>16), (arg&0xffff));
+ (com >> 16), (com & 0xffff),
+ (arg >> 16), (arg & 0xffff));
}
static inline int audcom(struct av7110 *av7110, u32 com)
{
return av7110_fw_cmd(av7110, COMTYPE_MISC, AV7110_FW_AUDIO_COMMAND, 2,
- (com>>16), (com&0xffff));
+ (com >> 16), (com & 0xffff));
}
static inline int Set22K(struct av7110 *av7110, int state)
@@ -482,15 +473,11 @@ static inline int Set22K(struct av7110 *av7110, int state)
return av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, (state ? ON22K : OFF22K), 0);
}
-
-extern int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst);
-
+int av7110_diseqc_send(struct av7110 *av7110, int len, u8 *msg, unsigned long burst);
#ifdef CONFIG_DVB_AV7110_OSD
-extern int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc);
-extern int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap);
+int av7110_osd_cmd(struct av7110 *av7110, osd_cmd_t *dc);
+int av7110_osd_capability(struct av7110 *av7110, osd_cap_t *cap);
#endif /* CONFIG_DVB_AV7110_OSD */
-
-
#endif /* _AV7110_HW_H_ */
diff --git a/drivers/staging/media/av7110/av7110_ipack.c b/drivers/staging/media/av7110/av7110_ipack.c
index 30330ed01ce8..4be6e225f08e 100644
--- a/drivers/staging/media/av7110/av7110_ipack.c
+++ b/drivers/staging/media/av7110/av7110_ipack.c
@@ -4,7 +4,6 @@
#include <linux/string.h> /* for memcpy() */
#include <linux/vmalloc.h>
-
void av7110_ipack_reset(struct ipack *p)
{
p->found = 0;
@@ -20,14 +19,12 @@ void av7110_ipack_reset(struct ipack *p)
p->count = 0;
}
-
int av7110_ipack_init(struct ipack *p, int size,
void (*func)(u8 *buf, int size, void *priv))
{
- if (!(p->buf = vmalloc(size))) {
- printk(KERN_WARNING "Couldn't allocate memory for ipack\n");
+ p->buf = vmalloc(size);
+ if (!p->buf)
return -ENOMEM;
- }
p->size = size;
p->func = func;
p->repack_subids = 0;
@@ -35,13 +32,11 @@ int av7110_ipack_init(struct ipack *p, int size,
return 0;
}
-
void av7110_ipack_free(struct ipack *p)
{
vfree(p->buf);
}
-
static void send_ipack(struct ipack *p)
{
int off;
@@ -63,7 +58,7 @@ static void send_ipack(struct ipack *p)
streamid = p->buf[off];
if ((streamid & 0xf8) == 0x80) {
ai.off = 0;
- ac3_off = ((p->buf[off + 2] << 8)|
+ ac3_off = ((p->buf[off + 2] << 8) |
p->buf[off + 3]);
if (ac3_off < p->count)
f = dvb_filter_get_ac3info(p->buf + off + 3 + ac3_off,
@@ -84,8 +79,8 @@ static void send_ipack(struct ipack *p)
p->buf[7] = 0x00;
p->buf[8] = 0x00;
p->count = 9;
- if (p->repack_subids && p->cid == PRIVATE_STREAM1
- && (streamid & 0xf8) == 0x80) {
+ if (p->repack_subids && p->cid == PRIVATE_STREAM1 &&
+ (streamid & 0xf8) == 0x80) {
p->count += 4;
p->buf[9] = streamid;
p->buf[10] = (ac3_off >> 8) & 0xff;
@@ -108,7 +103,6 @@ static void send_ipack(struct ipack *p)
}
}
-
void av7110_ipack_flush(struct ipack *p)
{
if (p->plength != MMAX_PLENGTH - 6 || p->found <= 6)
@@ -119,7 +113,6 @@ void av7110_ipack_flush(struct ipack *p)
av7110_ipack_reset(p);
}
-
static void write_ipack(struct ipack *p, const u8 *data, int count)
{
u8 headr[3] = { 0x00, 0x00, 0x01 };
@@ -129,12 +122,13 @@ static void write_ipack(struct ipack *p, const u8 *data, int count)
p->count = 6;
}
- if (p->count + count < p->size){
- memcpy(p->buf+p->count, data, count);
+ if (p->count + count < p->size) {
+ memcpy(p->buf + p->count, data, count);
p->count += count;
} else {
int rest = p->size - p->count;
- memcpy(p->buf+p->count, data, rest);
+
+ memcpy(p->buf + p->count, data, rest);
p->count += rest;
send_ipack(p);
if (count - rest > 0)
@@ -142,16 +136,15 @@ static void write_ipack(struct ipack *p, const u8 *data, int count)
}
}
-
-int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
+int av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p)
{
int l;
int c = 0;
while (c < count && (p->mpeg == 0 ||
(p->mpeg == 1 && p->found < 7) ||
- (p->mpeg == 2 && p->found < 9))
- && (p->found < 5 || !p->done)) {
+ (p->mpeg == 2 && p->found < 9)) &&
+ (p->found < 5 || !p->done)) {
switch (p->found) {
case 0:
case 1:
@@ -176,10 +169,10 @@ int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
case PROG_STREAM_MAP:
case PRIVATE_STREAM2:
case PROG_STREAM_DIR:
- case ECM_STREAM :
- case EMM_STREAM :
- case PADDING_STREAM :
- case DSM_CC_STREAM :
+ case ECM_STREAM:
+ case EMM_STREAM:
+ case PADDING_STREAM:
+ case DSM_CC_STREAM:
case ISO13522_STREAM:
p->done = 1;
fallthrough;
@@ -197,7 +190,7 @@ int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
break;
case 4:
- if (count-c > 1) {
+ if (count - c > 1) {
p->plen[0] = buf[c];
c++;
p->plen[1] = buf[c];
@@ -221,9 +214,9 @@ int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
p->flag1 = buf[c];
c++;
p->found++;
- if ((p->flag1 & 0xc0) == 0x80)
+ if ((p->flag1 & 0xc0) == 0x80) {
p->mpeg = 2;
- else {
+ } else {
p->hlength = 0;
p->which = 0;
p->mpeg = 1;
@@ -256,149 +249,146 @@ int av7110_ipack_instant_repack (const u8 *buf, int count, struct ipack *p)
if (!p->plength)
p->plength = MMAX_PLENGTH - 6;
- if (p->done || ((p->mpeg == 2 && p->found >= 9) ||
- (p->mpeg == 1 && p->found >= 7))) {
- switch (p->cid) {
- case AUDIO_STREAM_S ... AUDIO_STREAM_E:
- case VIDEO_STREAM_S ... VIDEO_STREAM_E:
- case PRIVATE_STREAM1:
- if (p->mpeg == 2 && p->found == 9) {
- write_ipack(p, &p->flag1, 1);
- write_ipack(p, &p->flag2, 1);
- write_ipack(p, &p->hlength, 1);
- }
+ if (!(p->done || ((p->mpeg == 2 && p->found >= 9) ||
+ (p->mpeg == 1 && p->found >= 7))))
+ return count;
- if (p->mpeg == 1 && p->found == 7)
- write_ipack(p, &p->flag1, 1);
+ switch (p->cid) {
+ case AUDIO_STREAM_S ... AUDIO_STREAM_E:
+ case VIDEO_STREAM_S ... VIDEO_STREAM_E:
+ case PRIVATE_STREAM1:
+ if (p->mpeg == 2 && p->found == 9) {
+ write_ipack(p, &p->flag1, 1);
+ write_ipack(p, &p->flag2, 1);
+ write_ipack(p, &p->hlength, 1);
+ }
- if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) &&
- p->found < 14) {
- while (c < count && p->found < 14) {
- p->pts[p->found - 9] = buf[c];
- write_ipack(p, buf + c, 1);
- c++;
- p->found++;
- }
- if (c == count)
- return count;
+ if (p->mpeg == 1 && p->found == 7)
+ write_ipack(p, &p->flag1, 1);
+
+ if (p->mpeg == 2 && (p->flag2 & PTS_ONLY) && p->found < 14) {
+ while (c < count && p->found < 14) {
+ p->pts[p->found - 9] = buf[c];
+ write_ipack(p, buf + c, 1);
+ c++;
+ p->found++;
}
+ if (c == count)
+ return count;
+ }
- if (p->mpeg == 1 && p->which < 2000) {
+ if (p->mpeg == 1 && p->which < 2000) {
+ if (p->found == 7) {
+ p->check = p->flag1;
+ p->hlength = 1;
+ }
- if (p->found == 7) {
- p->check = p->flag1;
- p->hlength = 1;
- }
+ while (!p->which && c < count && p->check == 0xff) {
+ p->check = buf[c];
+ write_ipack(p, buf + c, 1);
+ c++;
+ p->found++;
+ p->hlength++;
+ }
- while (!p->which && c < count &&
- p->check == 0xff){
- p->check = buf[c];
- write_ipack(p, buf + c, 1);
- c++;
- p->found++;
- p->hlength++;
- }
+ if (c == count)
+ return count;
+ if ((p->check & 0xc0) == 0x40 && !p->which) {
+ p->check = buf[c];
+ write_ipack(p, buf + c, 1);
+ c++;
+ p->found++;
+ p->hlength++;
+
+ p->which = 1;
+ if (c == count)
+ return count;
+ p->check = buf[c];
+ write_ipack(p, buf + c, 1);
+ c++;
+ p->found++;
+ p->hlength++;
+ p->which = 2;
if (c == count)
return count;
+ }
- if ((p->check & 0xc0) == 0x40 && !p->which) {
- p->check = buf[c];
- write_ipack(p, buf + c, 1);
- c++;
- p->found++;
- p->hlength++;
+ if (p->which == 1) {
+ p->check = buf[c];
+ write_ipack(p, buf + c, 1);
+ c++;
+ p->found++;
+ p->hlength++;
+ p->which = 2;
+ if (c == count)
+ return count;
+ }
- p->which = 1;
- if (c == count)
- return count;
- p->check = buf[c];
- write_ipack(p, buf + c, 1);
- c++;
- p->found++;
- p->hlength++;
- p->which = 2;
- if (c == count)
- return count;
- }
+ if ((p->check & 0x30) && p->check != 0xff) {
+ p->flag2 = (p->check & 0xf0) << 2;
+ p->pts[0] = p->check;
+ p->which = 3;
+ }
- if (p->which == 1) {
- p->check = buf[c];
- write_ipack(p, buf + c, 1);
- c++;
- p->found++;
- p->hlength++;
- p->which = 2;
+ if (c == count)
+ return count;
+ if (p->which > 2) {
+ if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) {
+ while (c < count && p->which < 7) {
+ p->pts[p->which - 2] = buf[c];
+ write_ipack(p, buf + c, 1);
+ c++;
+ p->found++;
+ p->which++;
+ p->hlength++;
+ }
if (c == count)
return count;
- }
-
- if ((p->check & 0x30) && p->check != 0xff) {
- p->flag2 = (p->check & 0xf0) << 2;
- p->pts[0] = p->check;
- p->which = 3;
- }
-
- if (c == count)
- return count;
- if (p->which > 2){
- if ((p->flag2 & PTS_DTS_FLAGS) == PTS_ONLY) {
- while (c < count && p->which < 7) {
+ } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) {
+ while (c < count && p->which < 12) {
+ if (p->which < 7)
p->pts[p->which - 2] = buf[c];
- write_ipack(p, buf + c, 1);
- c++;
- p->found++;
- p->which++;
- p->hlength++;
- }
- if (c == count)
- return count;
- } else if ((p->flag2 & PTS_DTS_FLAGS) == PTS_DTS) {
- while (c < count && p->which < 12) {
- if (p->which < 7)
- p->pts[p->which - 2] = buf[c];
- write_ipack(p, buf + c, 1);
- c++;
- p->found++;
- p->which++;
- p->hlength++;
- }
- if (c == count)
- return count;
+ write_ipack(p, buf + c, 1);
+ c++;
+ p->found++;
+ p->which++;
+ p->hlength++;
}
- p->which = 2000;
+ if (c == count)
+ return count;
}
-
+ p->which = 2000;
}
-
- while (c < count && p->found < p->plength + 6) {
- l = count - c;
- if (l + p->found > p->plength + 6)
- l = p->plength + 6 - p->found;
- write_ipack(p, buf + c, l);
- p->found += l;
- c += l;
- }
- break;
}
-
- if (p->done) {
- if (p->found + count - c < p->plength + 6) {
- p->found += count - c;
- c = count;
- } else {
- c += p->plength + 6 - p->found;
- p->found = p->plength + 6;
- }
+ while (c < count && p->found < p->plength + 6) {
+ l = count - c;
+ if (l + p->found > p->plength + 6)
+ l = p->plength + 6 - p->found;
+ write_ipack(p, buf + c, l);
+ p->found += l;
+ c += l;
}
+ break;
+ }
- if (p->plength && p->found == p->plength + 6) {
- send_ipack(p);
- av7110_ipack_reset(p);
- if (c < count)
- av7110_ipack_instant_repack(buf + c, count - c, p);
+ if (p->done) {
+ if (p->found + count - c < p->plength + 6) {
+ p->found += count - c;
+ c = count;
+ } else {
+ c += p->plength + 6 - p->found;
+ p->found = p->plength + 6;
}
}
+
+ if (p->plength && p->found == p->plength + 6) {
+ send_ipack(p);
+ av7110_ipack_reset(p);
+ if (c < count)
+ av7110_ipack_instant_repack(buf + c, count - c, p);
+ }
+
return count;
}
diff --git a/drivers/staging/media/av7110/av7110_ipack.h b/drivers/staging/media/av7110/av7110_ipack.h
index 943ec899bb93..55296421d52f 100644
--- a/drivers/staging/media/av7110/av7110_ipack.h
+++ b/drivers/staging/media/av7110/av7110_ipack.h
@@ -2,12 +2,12 @@
#ifndef _AV7110_IPACK_H_
#define _AV7110_IPACK_H_
-extern int av7110_ipack_init(struct ipack *p, int size,
- void (*func)(u8 *buf, int size, void *priv));
+int av7110_ipack_init(struct ipack *p, int size,
+ void (*func)(u8 *buf, int size, void *priv));
-extern void av7110_ipack_reset(struct ipack *p);
-extern int av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p);
-extern void av7110_ipack_free(struct ipack * p);
-extern void av7110_ipack_flush(struct ipack *p);
+void av7110_ipack_reset(struct ipack *p);
+int av7110_ipack_instant_repack(const u8 *buf, int count, struct ipack *p);
+void av7110_ipack_free(struct ipack *p);
+void av7110_ipack_flush(struct ipack *p);
#endif
diff --git a/drivers/staging/media/av7110/av7110_ir.c b/drivers/staging/media/av7110/av7110_ir.c
index a851ba328e4a..68b3979ba5f2 100644
--- a/drivers/staging/media/av7110/av7110_ir.c
+++ b/drivers/staging/media/av7110/av7110_ir.c
@@ -59,8 +59,7 @@ void av7110_ir_handler(struct av7110 *av7110, u32 ircom)
proto = RC_PROTO_RC5;
break;
default:
- dprintk(2, "unknown ir config %d\n",
- av7110->ir.ir_config);
+ dprintk(2, "unknown ir config %d\n", av7110->ir.ir_config);
return;
}
diff --git a/drivers/staging/media/av7110/av7110_v4l.c b/drivers/staging/media/av7110/av7110_v4l.c
index ed2c605808e8..04e659243f02 100644
--- a/drivers/staging/media/av7110/av7110_v4l.c
+++ b/drivers/staging/media/av7110/av7110_v4l.c
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- * av7110_v4l.c: av7110 video4linux interface for DVB and Siemens DVB-C analog module
+ * driver for the SAA7146 based AV110 cards
+ * - video4linux interface for DVB and Siemens DVB-C analog module
*
* Copyright (C) 1999-2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH
@@ -26,7 +27,7 @@
int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
{
- u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff };
+ u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8, val & 0xff };
struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg };
switch (av7110->adac_type) {
@@ -41,8 +42,7 @@ int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val)
}
if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) {
- dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n",
- av7110->dvb_adapter.num, reg, val);
+ dprintk(1, "failed @ card %d, %u = %u\n", av7110->dvb_adapter.num, reg, val);
return -EIO;
}
return 0;
@@ -53,7 +53,7 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
u8 msg1[3] = { dev, reg >> 8, reg & 0xff };
u8 msg2[2];
struct i2c_msg msgs[2] = {
- { .flags = 0 , .len = 3, .buf = msg1 },
+ { .flags = 0, .len = 3, .buf = msg1 },
{ .flags = I2C_M_RD, .len = 2, .buf = msg2 }
};
@@ -71,8 +71,7 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val)
}
if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) {
- dprintk(1, "dvb-ttpci: failed @ card %d, %u\n",
- av7110->dvb_adapter.num, reg);
+ dprintk(1, "failed @ card %d, %u\n", av7110->dvb_adapter.num, reg);
return -EIO;
}
*val = (msg2[0] << 8) | msg2[1];
@@ -86,7 +85,7 @@ static struct v4l2_input inputs[4] = {
.type = V4L2_INPUT_TYPE_CAMERA,
.audioset = 1,
.tuner = 0, /* ignored */
- .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
+ .std = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,
.status = 0,
.capabilities = V4L2_IN_CAP_STD,
}, {
@@ -95,7 +94,7 @@ static struct v4l2_input inputs[4] = {
.type = V4L2_INPUT_TYPE_TUNER,
.audioset = 1,
.tuner = 0,
- .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
+ .std = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,
.status = 0,
.capabilities = V4L2_IN_CAP_STD,
}, {
@@ -104,7 +103,7 @@ static struct v4l2_input inputs[4] = {
.type = V4L2_INPUT_TYPE_CAMERA,
.audioset = 0,
.tuner = 0,
- .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
+ .std = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,
.status = 0,
.capabilities = V4L2_IN_CAP_STD,
}, {
@@ -113,7 +112,7 @@ static struct v4l2_input inputs[4] = {
.type = V4L2_INPUT_TYPE_CAMERA,
.audioset = 0,
.tuner = 0,
- .std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
+ .std = V4L2_STD_PAL_BG | V4L2_STD_NTSC_M,
.status = 0,
.capabilities = V4L2_IN_CAP_STD,
}
@@ -127,19 +126,19 @@ static int ves1820_writereg(struct saa7146_dev *dev, u8 addr, u8 reg, u8 data)
dprintk(4, "dev: %p\n", dev);
- if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
+ if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -1;
return 0;
}
-static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data [4])
+static int tuner_write(struct saa7146_dev *dev, u8 addr, u8 data[4])
{
struct av7110 *av7110 = dev->ext_priv;
struct i2c_msg msg = { .addr = addr, .flags = 0, .buf = data, .len = 4 };
dprintk(4, "dev: %p\n", dev);
- if (1 != i2c_transfer(&av7110->i2c_adap, &msg, 1))
+ if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1)
return -1;
return 0;
}
@@ -153,7 +152,8 @@ static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
dprintk(4, "freq: 0x%08x\n", freq);
/* magic number: 614. tuning with the frequency given by v4l2
- is always off by 614*62.5 = 38375 kHz...*/
+ * is always off by 614*62.5 = 38375 kHz...
+ */
div = freq + 614;
buf[0] = (div >> 8) & 0x7f;
@@ -175,7 +175,7 @@ static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
{
- struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
u32 div;
u8 data[4];
@@ -201,8 +201,6 @@ static int stv0297_set_tv_freq(struct saa7146_dev *dev, u32 freq)
return tuner_write(dev, 0x63, data);
}
-
-
static struct saa7146_standard analog_standard[];
static struct saa7146_standard dvb_standard[];
static struct saa7146_standard standard[];
@@ -215,13 +213,13 @@ static const struct v4l2_audio msp3400_v4l2_audio = {
static int av7110_dvb_c_switch(struct saa7146_dev *dev)
{
- struct av7110 *av7110 = (struct av7110*)dev->ext_priv;
+ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
u16 adswitch;
int source, sync;
dprintk(4, "%p\n", av7110);
- if (0 != av7110->current_input) {
+ if (av7110->current_input != 0) {
dprintk(1, "switching to analog TV:\n");
adswitch = 1;
source = SAA7146_HPS_SOURCE_PORT_B;
@@ -330,8 +328,10 @@ static int vidioc_g_tuner(struct file *file, void *fh, struct v4l2_tuner *t)
/* bilingual */
t->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_LANG2;
t->audmode = V4L2_TUNER_MODE_LANG1;
- } else /* mono */
+ } else {
+ /* mono */
t->rxsubchans = V4L2_TUNER_SUB_MONO;
+ }
return 0;
}
@@ -341,6 +341,7 @@ static int vidioc_s_tuner(struct file *file, void *fh, const struct v4l2_tuner *
struct saa7146_dev *dev = video_drvdata(file);
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
u16 fm_matrix, src;
+
dprintk(2, "VIDIOC_S_TUNER: %d\n", t->index);
if (!av7110->analog_tuner_flags || av7110->current_input != 1)
@@ -406,7 +407,7 @@ static int vidioc_s_frequency(struct file *file, void *fh, const struct v4l2_fre
if (!av7110->analog_tuner_flags || av7110->current_input != 1)
return -EINVAL;
- if (V4L2_TUNER_ANALOG_TV != f->type)
+ if (f->type != V4L2_TUNER_ANALOG_TV)
return -EINVAL;
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0xffe0); /* fast mute */
@@ -530,7 +531,7 @@ static int vidioc_s_audio(struct file *file, void *fh, const struct v4l2_audio *
}
static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
- struct v4l2_sliced_vbi_cap *cap)
+ struct v4l2_sliced_vbi_cap *cap)
{
struct saa7146_dev *dev = video_drvdata(file);
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
@@ -546,7 +547,7 @@ static int vidioc_g_sliced_vbi_cap(struct file *file, void *fh,
}
static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct saa7146_dev *dev = video_drvdata(file);
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
@@ -554,7 +555,7 @@ static int vidioc_g_fmt_sliced_vbi_out(struct file *file, void *fh,
dprintk(2, "VIDIOC_G_FMT:\n");
if (FW_VERSION(av7110->arm_app) < 0x2623)
return -EINVAL;
- memset(&f->fmt.sliced, 0, sizeof f->fmt.sliced);
+ memset(&f->fmt.sliced, 0, sizeof(f->fmt.sliced));
if (av7110->wssMode) {
f->fmt.sliced.service_set = V4L2_SLICED_WSS_625;
f->fmt.sliced.service_lines[0][23] = V4L2_SLICED_WSS_625;
@@ -585,7 +586,7 @@ static int vidioc_try_fmt_sliced_vbi_out(struct file *file, void *fh,
}
static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct saa7146_dev *dev = video_drvdata(file);
struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
@@ -610,12 +611,12 @@ static int vidioc_s_fmt_sliced_vbi_out(struct file *file, void *fh,
static ssize_t av7110_vbi_write(struct file *file, const char __user *data, size_t count, loff_t *ppos)
{
struct saa7146_dev *dev = video_drvdata(file);
- struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
struct v4l2_sliced_vbi_data d;
int rc;
- dprintk(2, "%s\n", __func__);
- if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof d)
+ dprintk(2, "\n");
+ if (FW_VERSION(av7110->arm_app) < 0x2623 || !av7110->wssMode || count != sizeof(d))
return -EINVAL;
if (copy_from_user(&d, data, count))
return -EFAULT;
@@ -691,7 +692,6 @@ static u8 saa7113_init_regs[] = {
0xff
};
-
static struct saa7146_ext_vv av7110_vv_data_st;
static struct saa7146_ext_vv av7110_vv_data_c;
@@ -709,13 +709,14 @@ int av7110_init_analog_module(struct av7110 *av7110)
pr_info("DVB-C analog module @ card %d detected, initializing MSP3415\n",
av7110->dvb_adapter.num);
av7110->adac_type = DVB_ADAC_MSP34x5;
- } else
+ } else {
return -ENODEV;
+ }
msleep(100); // the probing above resets the msp...
msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1);
msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2);
- dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n",
+ dprintk(1, "@ card %d MSP34xx version 0x%04x 0x%04x\n",
av7110->dvb_adapter.num, version1, version2);
msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00);
msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone
@@ -726,18 +727,21 @@ int av7110_init_analog_module(struct av7110 *av7110)
msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume
msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART
- if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) {
+ if (i2c_writereg(av7110, 0x48, 0x01, 0x00) != 1) {
pr_info("saa7113 not accessible\n");
} else {
u8 *i = saa7113_init_regs;
- if ((av7110->dev->pci->subsystem_vendor == 0x110a) && (av7110->dev->pci->subsystem_device == 0x0000)) {
+ if ((av7110->dev->pci->subsystem_vendor == 0x110a) &&
+ (av7110->dev->pci->subsystem_device == 0x0000)) {
/* Fujitsu/Siemens DVB-Cable */
av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
- } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x0002)) {
+ } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) &&
+ (av7110->dev->pci->subsystem_device == 0x0002)) {
/* Hauppauge/TT DVB-C premium */
av7110->analog_tuner_flags |= ANALOG_TUNER_VES1820;
- } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) && (av7110->dev->pci->subsystem_device == 0x000A)) {
+ } else if ((av7110->dev->pci->subsystem_vendor == 0x13c2) &&
+ (av7110->dev->pci->subsystem_device == 0x000A)) {
/* Hauppauge/TT DVB-C premium */
av7110->analog_tuner_flags |= ANALOG_TUNER_STV0297;
}
@@ -795,13 +799,14 @@ int av7110_init_analog_module(struct av7110 *av7110)
int av7110_init_v4l(struct av7110 *av7110)
{
- struct saa7146_dev* dev = av7110->dev;
+ struct saa7146_dev *dev = av7110->dev;
struct saa7146_ext_vv *vv_data;
int ret;
/* special case DVB-C: these cards have an analog tuner
- plus need some special handling, so we have separate
- saa7146_ext_vv data for these... */
+ * plus need some special handling, so we have separate
+ * saa7146_ext_vv data for these...
+ */
if (av7110->analog_tuner_flags)
vv_data = &av7110_vv_data_c;
else
@@ -853,7 +858,7 @@ int av7110_init_v4l(struct av7110 *av7110)
int av7110_exit_v4l(struct av7110 *av7110)
{
- struct saa7146_dev* dev = av7110->dev;
+ struct saa7146_dev *dev = av7110->dev;
saa7146_unregister_device(&av7110->v4l_dev, av7110->dev);
saa7146_unregister_device(&av7110->vbi_dev, av7110->dev);
@@ -863,10 +868,9 @@ int av7110_exit_v4l(struct av7110 *av7110)
return 0;
}
-
-
/* FIXME: these values are experimental values that look better than the
- values from the latest "official" driver -- at least for me... (MiHu) */
+ * values from the latest "official" driver -- at least for me... (MiHu)
+ */
static struct saa7146_standard standard[] = {
{
.name = "PAL", .id = V4L2_STD_PAL_BG,
@@ -909,25 +913,23 @@ static struct saa7146_standard dvb_standard[] = {
}
};
-static int std_callback(struct saa7146_dev* dev, struct saa7146_standard *std)
+static int std_callback(struct saa7146_dev *dev, struct saa7146_standard *std)
{
- struct av7110 *av7110 = (struct av7110*) dev->ext_priv;
+ struct av7110 *av7110 = (struct av7110 *)dev->ext_priv;
if (std->id & V4L2_STD_PAL) {
av7110->vidmode = AV7110_VIDEO_MODE_PAL;
av7110_set_vidmode(av7110, av7110->vidmode);
- }
- else if (std->id & V4L2_STD_NTSC) {
+ } else if (std->id & V4L2_STD_NTSC) {
av7110->vidmode = AV7110_VIDEO_MODE_NTSC;
av7110_set_vidmode(av7110, av7110->vidmode);
- }
- else
+ } else {
return -1;
+ }
return 0;
}
-
static struct saa7146_ext_vv av7110_vv_data_st = {
.inputs = 1,
.audios = 1,
diff --git a/drivers/staging/media/av7110/budget-patch.c b/drivers/staging/media/av7110/budget-patch.c
deleted file mode 100644
index d173c8ade6a7..000000000000
--- a/drivers/staging/media/av7110/budget-patch.c
+++ /dev/null
@@ -1,665 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-/*
- * budget-patch.c: driver for Budget Patch,
- * hardware modification of DVB-S cards enabling full TS
- *
- * Written by Emard <emard@softhome.net>
- *
- * Original idea by Roberto Deza <rdeza@unav.es>
- *
- * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic
- * and Metzlerbros
- *
- * the project's page is at https://linuxtv.org
- */
-
-#include "av7110.h"
-#include "av7110_hw.h"
-#include "budget.h"
-#include "stv0299.h"
-#include "ves1x93.h"
-#include "tda8083.h"
-
-#include "bsru6.h"
-
-DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-
-#define budget_patch budget
-
-static struct saa7146_extension budget_extension;
-
-MAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH);
-//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC);
-
-static const struct pci_device_id pci_tbl[] = {
- MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000),
-// MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),
- {
- .vendor = 0,
- }
-};
-
-/* those lines are for budget-patch to be tried
-** on a true budget card and observe the
-** behaviour of VSYNC generated by rps1.
-** this code was shamelessly copy/pasted from budget.c
-*/
-static void gpio_Set22K (struct budget *budget, int state)
-{
- struct saa7146_dev *dev=budget->dev;
- dprintk(2, "budget: %p\n", budget);
- saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));
-}
-
-/* Diseqc functions only for TT Budget card */
-/* taken from the Skyvision DVB driver by
- Ralph Metzler <rjkm@metzlerbros.de> */
-
-static void DiseqcSendBit (struct budget *budget, int data)
-{
- struct saa7146_dev *dev=budget->dev;
- dprintk(2, "budget: %p\n", budget);
-
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- udelay(data ? 500 : 1000);
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
- udelay(data ? 1000 : 500);
-}
-
-static void DiseqcSendByte (struct budget *budget, int data)
-{
- int i, par=1, d;
-
- dprintk(2, "budget: %p\n", budget);
-
- for (i=7; i>=0; i--) {
- d = (data>>i)&1;
- par ^= d;
- DiseqcSendBit(budget, d);
- }
-
- DiseqcSendBit(budget, par);
-}
-
-static int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst)
-{
- struct saa7146_dev *dev=budget->dev;
- int i;
-
- dprintk(2, "budget: %p\n", budget);
-
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
- mdelay(16);
-
- for (i=0; i<len; i++)
- DiseqcSendByte(budget, msg[i]);
-
- mdelay(16);
-
- if (burst!=-1) {
- if (burst)
- DiseqcSendByte(budget, 0xff);
- else {
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- mdelay(12);
- udelay(500);
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
- }
- msleep(20);
- }
-
- return 0;
-}
-
-/* shamelessly copy/pasted from budget.c */
-static int budget_set_tone(struct dvb_frontend *fe,
- enum fe_sec_tone_mode tone)
-{
- struct budget* budget = (struct budget*) fe->dvb->priv;
-
- switch (tone) {
- case SEC_TONE_ON:
- gpio_Set22K (budget, 1);
- break;
-
- case SEC_TONE_OFF:
- gpio_Set22K (budget, 0);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
-{
- struct budget* budget = (struct budget*) fe->dvb->priv;
-
- SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0);
-
- return 0;
-}
-
-static int budget_diseqc_send_burst(struct dvb_frontend *fe,
- enum fe_sec_mini_cmd minicmd)
-{
- struct budget* budget = (struct budget*) fe->dvb->priv;
-
- SendDiSEqCMsg (budget, 0, NULL, minicmd);
-
- return 0;
-}
-
-static int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length)
-{
- int i;
-
- dprintk(2, "budget: %p\n", budget);
-
- for (i = 2; i < length; i++)
- {
- ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0);
- msleep(5);
- }
- if (length)
- ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0);
- else
- ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0);
- msleep(5);
- ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0);
- msleep(5);
- return 0;
-}
-
-static void av7110_set22k(struct budget_patch *budget, int state)
-{
- u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0};
-
- dprintk(2, "budget: %p\n", budget);
- budget_av7110_send_fw_cmd(budget, buf, 2);
-}
-
-static int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst)
-{
- int i;
- u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC),
- 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-
- dprintk(2, "budget: %p\n", budget);
-
- if (len>10)
- len=10;
-
- buf[1] = len+2;
- buf[2] = len;
-
- if (burst != -1)
- buf[3]=burst ? 0x01 : 0x00;
- else
- buf[3]=0xffff;
-
- for (i=0; i<len; i++)
- buf[i+4]=msg[i];
-
- budget_av7110_send_fw_cmd(budget, buf, 18);
- return 0;
-}
-
-static int budget_patch_set_tone(struct dvb_frontend *fe,
- enum fe_sec_tone_mode tone)
-{
- struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
-
- switch (tone) {
- case SEC_TONE_ON:
- av7110_set22k (budget, 1);
- break;
-
- case SEC_TONE_OFF:
- av7110_set22k (budget, 0);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
-{
- struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
-
- av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0);
-
- return 0;
-}
-
-static int budget_patch_diseqc_send_burst(struct dvb_frontend *fe,
- enum fe_sec_mini_cmd minicmd)
-{
- struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
-
- av7110_send_diseqc_msg (budget, 0, NULL, minicmd);
-
- return 0;
-}
-
-static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
- u8 pwr = 0;
- u8 buf[4];
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };
- u32 div = (p->frequency + 479500) / 125;
-
- if (p->frequency > 2000000)
- pwr = 3;
- else if (p->frequency > 1800000)
- pwr = 2;
- else if (p->frequency > 1600000)
- pwr = 1;
- else if (p->frequency > 1200000)
- pwr = 0;
- else if (p->frequency >= 1100000)
- pwr = 1;
- else pwr = 2;
-
- buf[0] = (div >> 8) & 0x7f;
- buf[1] = div & 0xff;
- buf[2] = ((div & 0x18000) >> 10) | 0x95;
- buf[3] = (pwr << 6) | 0x30;
-
- // NOTE: since we're using a prescaler of 2, we set the
- // divisor frequency to 62.5kHz and divide by 125 above
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
- return -EIO;
- return 0;
-}
-
-static struct ves1x93_config alps_bsrv2_config = {
- .demod_address = 0x08,
- .xin = 90100000UL,
- .invert_pwm = 0,
-};
-
-static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)
-{
- struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv;
- u32 div;
- u8 data[4];
- struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };
-
- div = p->frequency / 125;
- data[0] = (div >> 8) & 0x7f;
- data[1] = div & 0xff;
- data[2] = 0x8e;
- data[3] = 0x00;
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1)
- return -EIO;
- return 0;
-}
-
-static struct tda8083_config grundig_29504_451_config = {
- .demod_address = 0x68,
-};
-
-static void frontend_init(struct budget_patch* budget)
-{
- switch(budget->dev->pci->subsystem_device) {
- case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X
- case 0x1013: // SATELCO Multimedia PCI
-
- // try the ALPS BSRV2 first of all
- budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;
- budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd;
- budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst;
- budget->dvb_frontend->ops.set_tone = budget_patch_set_tone;
- break;
- }
-
- // try the ALPS BSRU6 now
- budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;
- budget->dvb_frontend->tuner_priv = &budget->i2c_adap;
-
- budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops.set_tone = budget_set_tone;
- break;
- }
-
- // Try the grundig 29504-451
- budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);
- if (budget->dvb_frontend) {
- budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;
- budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;
- budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;
- budget->dvb_frontend->ops.set_tone = budget_set_tone;
- break;
- }
- break;
- }
-
- if (budget->dvb_frontend == NULL) {
- printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",
- budget->dev->pci->vendor,
- budget->dev->pci->device,
- budget->dev->pci->subsystem_vendor,
- budget->dev->pci->subsystem_device);
- } else {
- if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) {
- printk("budget-av: Frontend registration failed!\n");
- dvb_frontend_detach(budget->dvb_frontend);
- budget->dvb_frontend = NULL;
- }
- }
-}
-
-/* written by Emard */
-static int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info)
-{
- struct budget_patch *budget;
- int err;
- int count = 0;
- int detected = 0;
-
-#define PATCH_RESET 0
-#define RPS_IRQ 0
-#define HPS_SETUP 0
-#if PATCH_RESET
- saa7146_write(dev, MC1, MASK_31);
- msleep(40);
-#endif
-#if HPS_SETUP
- // initialize registers. Better to have it like this
- // than leaving something unconfigured
- saa7146_write(dev, DD1_STREAM_B, 0);
- // port B VSYNC at rising edge
- saa7146_write(dev, DD1_INIT, 0x00000200); // have this in budget-core too!
- saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI
-
- // debi config
- // saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18);
-
- // zero all HPS registers
- saa7146_write(dev, HPS_H_PRESCALE, 0); // r68
- saa7146_write(dev, HPS_H_SCALE, 0); // r6c
- saa7146_write(dev, BCS_CTRL, 0); // r70
- saa7146_write(dev, HPS_V_SCALE, 0); // r60
- saa7146_write(dev, HPS_V_GAIN, 0); // r64
- saa7146_write(dev, CHROMA_KEY_RANGE, 0); // r74
- saa7146_write(dev, CLIP_FORMAT_CTRL, 0); // r78
- // Set HPS prescaler for port B input
- saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) );
- saa7146_write(dev, MC2,
- 0 * (MASK_08 | MASK_24) | // BRS control
- 0 * (MASK_09 | MASK_25) | // a
- 0 * (MASK_10 | MASK_26) | // b
- 1 * (MASK_06 | MASK_22) | // HPS_CTRL1
- 1 * (MASK_05 | MASK_21) | // HPS_CTRL2
- 0 * (MASK_01 | MASK_15) // DEBI
- );
-#endif
- // Disable RPS1 and RPS0
- saa7146_write(dev, MC1, ( MASK_29 | MASK_28));
- // RPS1 timeout disable
- saa7146_write(dev, RPS_TOV1, 0);
-
- // code for autodetection
- // will wait for VBI_B event (vertical blank at port B)
- // and will reset GPIO3 after VBI_B is detected.
- // (GPIO3 should be raised high by CPU to
- // test if GPIO3 will generate vertical blank signal
- // in budget patch GPIO3 is connected to VSYNC_B
- count = 0;
-#if 0
- WRITE_RPS1(CMD_UPLOAD |
- MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 );
-#endif
- WRITE_RPS1(CMD_PAUSE | EVT_VBI_B);
- WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
- WRITE_RPS1(GPIO3_MSK);
- WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
-#if RPS_IRQ
- // issue RPS1 interrupt to increment counter
- WRITE_RPS1(CMD_INTERRUPT);
- // at least a NOP is neede between two interrupts
- WRITE_RPS1(CMD_NOP);
- // interrupt again
- WRITE_RPS1(CMD_INTERRUPT);
-#endif
- WRITE_RPS1(CMD_STOP);
-
-#if RPS_IRQ
- // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53)
- // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled
- // use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called
- saa7146_write(dev, EC1SSR, (0x03<<2) | 3 );
- // set event counter 1 threshold to maximum allowed value (rEC p55)
- saa7146_write(dev, ECT1R, 0x3fff );
-#endif
- // Fix VSYNC level
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
- // Set RPS1 Address register to point to RPS code (r108 p42)
- saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
- // Enable RPS1, (rFC p33)
- saa7146_write(dev, MC1, (MASK_13 | MASK_29 ));
-
-
- mdelay(50);
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);
- mdelay(150);
-
-
- if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0)
- detected = 1;
-
-#if RPS_IRQ
- printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff );
-#endif
- // Disable RPS1
- saa7146_write(dev, MC1, ( MASK_29 ));
-
- if(detected == 0)
- printk("budget-patch not detected or saa7146 in non-default state.\n"
- "try enabling resetting of 7146 with MASK_31 in MC1 register\n");
-
- else
- printk("BUDGET-PATCH DETECTED.\n");
-
-
-/* OLD (Original design by Roberto Deza):
-** This code will setup the SAA7146_RPS1 to generate a square
-** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of
-** TS_WIDTH packets) has been acquired on SAA7146_D1B video port;
-** then, this GPIO3 output which is connected to the D1B_VSYNC
-** input, will trigger the acquisition of the alternate field
-** and so on.
-** Currently, the TT_budget / WinTV_Nova cards have two ICs
-** (74HCT4040, LVC74) for the generation of this VSYNC signal,
-** which seems that can be done perfectly without this :-)).
-*/
-
-/* New design (By Emard)
-** this rps1 code will copy internal HS event to GPIO3 pin.
-** GPIO3 is in budget-patch hardware connected to port B VSYNC
-
-** HS is an internal event of 7146, accessible with RPS
-** and temporarily raised high every n lines
-** (n in defined in the RPS_THRESH1 counter threshold)
-** I think HS is raised high on the beginning of the n-th line
-** and remains high until this n-th line that triggered
-** it is completely received. When the reception of n-th line
-** ends, HS is lowered.
-
-** To transmit data over DMA, 7146 needs changing state at
-** port B VSYNC pin. Any changing of port B VSYNC will
-** cause some DMA data transfer, with more or less packets loss.
-** It depends on the phase and frequency of VSYNC and
-** the way of 7146 is instructed to trigger on port B (defined
-** in DD1_INIT register, 3rd nibble from the right valid
-** numbers are 0-7, see datasheet)
-**
-** The correct triggering can minimize packet loss,
-** dvbtraffic should give this stable bandwidths:
-** 22k transponder = 33814 kbit/s
-** 27.5k transponder = 38045 kbit/s
-** by experiment it is found that the best results
-** (stable bandwidths and almost no packet loss)
-** are obtained using DD1_INIT triggering number 2
-** (Va at rising edge of VS Fa = HS x VS-failing forced toggle)
-** and a VSYNC phase that occurs in the middle of DMA transfer
-** (about byte 188*512=96256 in the DMA window).
-**
-** Phase of HS is still not clear to me how to control,
-** It just happens to be so. It can be seen if one enables
-** RPS_IRQ and print Event Counter 1 in vpeirq(). Every
-** time RPS_INTERRUPT is called, the Event Counter 1 will
-** increment. That's how the 7146 is programmed to do event
-** counting in this budget-patch.c
-** I *think* HPS setting has something to do with the phase
-** of HS but I can't be 100% sure in that.
-
-** hardware debug note: a working budget card (including budget patch)
-** with vpeirq() interrupt setup in mode "0x90" (every 64K) will
-** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes
-** and that means 3*25=75 Hz of interrupt frequency, as seen by
-** watch cat /proc/interrupts
-**
-** If this frequency is 3x lower (and data received in the DMA
-** buffer don't start with 0x47, but in the middle of packets,
-** whose lengths appear to be like 188 292 188 104 etc.
-** this means VSYNC line is not connected in the hardware.
-** (check soldering pcb and pins)
-** The same behaviour of missing VSYNC can be duplicated on budget
-** cards, by setting DD1_INIT trigger mode 7 in 3rd nibble.
-*/
-
- // Setup RPS1 "program" (p35)
- count = 0;
-
-
- // Wait Source Line Counter Threshold (p36)
- WRITE_RPS1(CMD_PAUSE | EVT_HS);
- // Set GPIO3=1 (p42)
- WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
- WRITE_RPS1(GPIO3_MSK);
- WRITE_RPS1(SAA7146_GPIO_OUTHI<<24);
-#if RPS_IRQ
- // issue RPS1 interrupt
- WRITE_RPS1(CMD_INTERRUPT);
-#endif
- // Wait reset Source Line Counter Threshold (p36)
- WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS);
- // Set GPIO3=0 (p42)
- WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2));
- WRITE_RPS1(GPIO3_MSK);
- WRITE_RPS1(SAA7146_GPIO_OUTLO<<24);
-#if RPS_IRQ
- // issue RPS1 interrupt
- WRITE_RPS1(CMD_INTERRUPT);
-#endif
- // Jump to begin of RPS program (p37)
- WRITE_RPS1(CMD_JUMP);
- WRITE_RPS1(dev->d_rps1.dma_handle);
-
- // Fix VSYNC level
- saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);
- // Set RPS1 Address register to point to RPS code (r108 p42)
- saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle);
-
- if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL)))
- return -ENOMEM;
-
- dprintk(2, "budget: %p\n", budget);
-
- err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);
- if (err) {
- kfree(budget);
- return err;
- }
-
- // Set Source Line Counter Threshold, using BRS (rCC p43)
- // It generates HS event every TS_HEIGHT lines
- // this is related to TS_WIDTH set in register
- // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE
- // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188
- //,then RPS_THRESH1
- // should be set to trigger every TS_HEIGHT (512) lines.
- //
- saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 );
-
- // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 );
- // Enable RPS1 (rFC p33)
- saa7146_write(dev, MC1, (MASK_13 | MASK_29));
-
-
- dev->ext_priv = budget;
-
- budget->dvb_adapter.priv = budget;
- frontend_init(budget);
-
- ttpci_budget_init_hooks(budget);
-
- return 0;
-}
-
-static int budget_patch_detach (struct saa7146_dev* dev)
-{
- struct budget_patch *budget = (struct budget_patch*) dev->ext_priv;
- int err;
-
- if (budget->dvb_frontend) {
- dvb_unregister_frontend(budget->dvb_frontend);
- dvb_frontend_detach(budget->dvb_frontend);
- }
- err = ttpci_budget_deinit (budget);
-
- kfree (budget);
-
- return err;
-}
-
-static int __init budget_patch_init(void)
-{
- return saa7146_register_extension(&budget_extension);
-}
-
-static void __exit budget_patch_exit(void)
-{
- saa7146_unregister_extension(&budget_extension);
-}
-
-static struct saa7146_extension budget_extension = {
- .name = "budget_patch dvb",
- .flags = 0,
-
- .module = THIS_MODULE,
- .pci_tbl = pci_tbl,
- .attach = budget_patch_attach,
- .detach = budget_patch_detach,
-
- .irq_mask = MASK_10,
- .irq_func = ttpci_budget_irq10_handler,
-};
-
-module_init(budget_patch_init);
-module_exit(budget_patch_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others");
-MODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 based so-called Budget Patch cards");
diff --git a/drivers/staging/media/av7110/dvb_filter.c b/drivers/staging/media/av7110/dvb_filter.c
index 8c2eca5dcdc9..9eafbb82bf42 100644
--- a/drivers/staging/media/av7110/dvb_filter.c
+++ b/drivers/staging/media/av7110/dvb_filter.c
@@ -6,17 +6,19 @@
static u32 freq[4] = {480, 441, 320, 0};
-static unsigned int ac3_bitrates[32] =
- {32,40,48,56,64,80,96,112,128,160,192,224,256,320,384,448,512,576,640,
- 0,0,0,0,0,0,0,0,0,0,0,0,0};
-
-static u32 ac3_frames[3][32] =
- {{64,80,96,112,128,160,192,224,256,320,384,448,512,640,768,896,1024,
- 1152,1280,0,0,0,0,0,0,0,0,0,0,0,0,0},
- {69,87,104,121,139,174,208,243,278,348,417,487,557,696,835,975,1114,
- 1253,1393,0,0,0,0,0,0,0,0,0,0,0,0,0},
- {96,120,144,168,192,240,288,336,384,480,576,672,768,960,1152,1344,
- 1536,1728,1920,0,0,0,0,0,0,0,0,0,0,0,0,0}};
+static unsigned int ac3_bitrates[32] = {
+ 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 576, 640,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static u32 ac3_frames[3][32] = {
+ {64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 448, 512, 640, 768, 896, 1024,
+ 1152, 1280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {69, 87, 104, 121, 139, 174, 208, 243, 278, 348, 417, 487, 557, 696, 835, 975, 1114,
+ 1253, 1393, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
+ {96, 120, 144, 168, 192, 240, 288, 336, 384, 480, 576, 672, 768, 960, 1152, 1344,
+ 1536, 1728, 1920, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+};
int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr)
{
@@ -26,43 +28,40 @@ int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int p
u8 frame = 0;
int fr = 0;
- while ( !found && c < count){
- u8 *b = mbuf+c;
+ while (!found && c < count) {
+ u8 *b = mbuf + c;
- if ( b[0] == 0x0b && b[1] == 0x77 )
+ if (b[0] == 0x0b && b[1] == 0x77)
found = 1;
- else {
+ else
c++;
- }
}
- if (!found) return -1;
- if (pr)
- printk(KERN_DEBUG "Audiostream: AC3");
+ if (!found)
+ return -1;
ai->off = c;
- if (c+5 >= count) return -1;
+ if (c + 5 >= count)
+ return -1;
ai->layer = 0; // 0 for AC3
- headr = mbuf+c+2;
+ headr = mbuf + c + 2;
- frame = (headr[2]&0x3f);
- ai->bit_rate = ac3_bitrates[frame >> 1]*1000;
+ frame = (headr[2] & 0x3f);
+ ai->bit_rate = ac3_bitrates[frame >> 1] * 1000;
- if (pr)
- printk(KERN_CONT " BRate: %d kb/s", (int) ai->bit_rate/1000);
-
- ai->frequency = (headr[2] & 0xc0 ) >> 6;
- fr = (headr[2] & 0xc0 ) >> 6;
- ai->frequency = freq[fr]*100;
- if (pr)
- printk(KERN_CONT " Freq: %d Hz\n", (int) ai->frequency);
+ ai->frequency = (headr[2] & 0xc0) >> 6;
+ fr = (headr[2] & 0xc0) >> 6;
+ ai->frequency = freq[fr] * 100;
ai->framesize = ac3_frames[fr][frame >> 1];
- if ((frame & 1) && (fr == 1)) ai->framesize++;
+ if ((frame & 1) && (fr == 1))
+ ai->framesize++;
ai->framesize = ai->framesize << 1;
+
if (pr)
- printk(KERN_DEBUG " Framesize %d\n", (int) ai->framesize);
+ pr_info("Audiostream: AC3, BRate: %d kb/s, Freq: %d Hz, Framesize %d\n",
+ (int)ai->bit_rate / 1000, (int)ai->frequency, (int)ai->framesize);
return 0;
}
@@ -70,46 +69,47 @@ int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int p
void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
dvb_filter_pes2ts_cb_t *cb, void *priv)
{
- unsigned char *buf=p2ts->buf;
-
- buf[0]=0x47;
- buf[1]=(pid>>8);
- buf[2]=pid&0xff;
- p2ts->cc=0;
- p2ts->cb=cb;
- p2ts->priv=priv;
+ unsigned char *buf = p2ts->buf;
+
+ buf[0] = 0x47;
+ buf[1] = (pid >> 8);
+ buf[2] = pid & 0xff;
+ p2ts->cc = 0;
+ p2ts->cb = cb;
+ p2ts->priv = priv;
}
int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
int len, int payload_start)
{
- unsigned char *buf=p2ts->buf;
- int ret=0, rest;
+ unsigned char *buf = p2ts->buf;
+ int ret = 0, rest;
//len=6+((pes[4]<<8)|pes[5]);
if (payload_start)
- buf[1]|=0x40;
+ buf[1] |= 0x40;
else
- buf[1]&=~0x40;
- while (len>=184) {
- buf[3]=0x10|((p2ts->cc++)&0x0f);
- memcpy(buf+4, pes, 184);
- if ((ret=p2ts->cb(p2ts->priv, buf)))
+ buf[1] &= ~0x40;
+ while (len >= 184) {
+ buf[3] = 0x10 | ((p2ts->cc++) & 0x0f);
+ memcpy(buf + 4, pes, 184);
+ ret = p2ts->cb(p2ts->priv, buf);
+ if (ret)
return ret;
- len-=184; pes+=184;
- buf[1]&=~0x40;
+ len -= 184; pes += 184;
+ buf[1] &= ~0x40;
}
if (!len)
return 0;
- buf[3]=0x30|((p2ts->cc++)&0x0f);
- rest=183-len;
+ buf[3] = 0x30 | ((p2ts->cc++) & 0x0f);
+ rest = 183 - len;
if (rest) {
- buf[5]=0x00;
- if (rest-1)
- memset(buf+6, 0xff, rest-1);
+ buf[5] = 0x00;
+ if (rest - 1)
+ memset(buf + 6, 0xff, rest - 1);
}
- buf[4]=rest;
- memcpy(buf+5+rest, pes, len);
+ buf[4] = rest;
+ memcpy(buf + 5 + rest, pes, len);
return p2ts->cb(p2ts->priv, buf);
}
diff --git a/drivers/staging/media/av7110/dvb_filter.h b/drivers/staging/media/av7110/dvb_filter.h
index 67a3c6333bca..38b483508e07 100644
--- a/drivers/staging/media/av7110/dvb_filter.h
+++ b/drivers/staging/media/av7110/dvb_filter.h
@@ -1,6 +1,5 @@
+/* SPDX-License-Identifier: GPL-2.0 */
/*
- * dvb_filter.h
- *
* Copyright (C) 2003 Convergence GmbH
*
* This program is free software; you can redistribute it and/or
@@ -21,7 +20,7 @@
#include <media/demux.h>
-typedef int (dvb_filter_pes2ts_cb_t) (void *, unsigned char *);
+typedef int (dvb_filter_pes2ts_cb_t)(void *, unsigned char *);
struct dvb_filter_pes2ts {
unsigned char buf[188];
@@ -36,7 +35,6 @@ void dvb_filter_pes2ts_init(struct dvb_filter_pes2ts *p2ts, unsigned short pid,
int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
int len, int payload_start);
-
#define PROG_STREAM_MAP 0xBC
#define PRIVATE_STREAM1 0xBD
#define PADDING_STREAM 0xBE
@@ -78,7 +76,6 @@ int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
#define INIT_DISP_HORIZONTAL_SIZE 540
#define INIT_DISP_VERTICAL_SIZE 576
-
//flags2
#define PTS_DTS_FLAGS 0xC0
#define ESCR_FLAG 0x20
@@ -119,9 +116,8 @@ int dvb_filter_pes2ts(struct dvb_filter_pes2ts *p2ts, unsigned char *pes,
#define PIECE_RATE 0x40
#define SEAM_SPLICE 0x20
-
#define MAX_PLENGTH 0xFFFF
-#define MMAX_PLENGTH (256*MAX_PLENGTH)
+#define MMAX_PLENGTH (256 * MAX_PLENGTH)
#ifndef IPACKS
#define IPACKS 2048
@@ -187,10 +183,11 @@ struct mpg_picture {
s8 matrix_change_flag;
u8 picture_header_parameter;
- /* bit 0 - 2: bwd f code
- bit 3 : fpb vector
- bit 4 - 6: fwd f code
- bit 7 : fpf vector */
+ /* bit 0 - 2: bwd f code
+ * bit 3 : fpb vector
+ * bit 4 - 6: fwd f code
+ * bit 7 : fpf vector
+ */
int mpeg1_flag;
int progressive_sequence;
@@ -230,7 +227,7 @@ struct dvb_audio_info {
u32 bit_rate;
u32 frequency;
u32 mode;
- u32 mode_extension ;
+ u32 mode_extension;
u32 emphasis;
u32 framesize;
u32 off;
@@ -238,5 +235,4 @@ struct dvb_audio_info {
int dvb_filter_get_ac3info(u8 *mbuf, int count, struct dvb_audio_info *ai, int pr);
-
#endif
diff --git a/drivers/staging/media/av7110/sp8870.c b/drivers/staging/media/av7110/sp8870.c
index abf5c72607b6..0c813860f5b2 100644
--- a/drivers/staging/media/av7110/sp8870.c
+++ b/drivers/staging/media/av7110/sp8870.c
@@ -1,17 +1,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
- Driver for Spase SP8870 demodulator
-
- Copyright (C) 1999 Juergen Peitz
-
+ * Driver for Spase SP8870 demodulator
+.*
+ * Copyright (C) 1999 Juergen Peitz
+ */
-*/
/*
* This driver needs external firmware. Please use the command
* "<kerneldir>/scripts/get_dvb_firmware alps_tdlb7" to
* download/extract it, and then copy it to /usr/lib/hotplug/firmware
* or /lib/firmware (depending on configuration of firmware hotplug).
*/
+
+#ifdef pr_fmt
+#undef pr_fmt
+#endif
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#define SP8870_DEFAULT_FIRMWARE "dvb-fe-sp8870.fw"
#include <linux/init.h>
@@ -25,12 +30,10 @@
#include <media/dvb_frontend.h>
#include "sp8870.h"
-
struct sp8870_state {
+ struct i2c_adapter *i2c;
- struct i2c_adapter* i2c;
-
- const struct sp8870_config* config;
+ const struct sp8870_config *config;
struct dvb_frontend frontend;
@@ -39,9 +42,10 @@ struct sp8870_state {
};
static int debug;
-#define dprintk(args...) \
+#define dprintk(fmt, arg...) \
do { \
- if (debug) printk(KERN_DEBUG "sp8870: " args); \
+ if (debug) \
+ pr_info("%s(): " fmt, __func__, ##arg); \
} while (0)
/* firmware size for sp8870 */
@@ -50,39 +54,48 @@ static int debug;
/* starting point for firmware in file 'Sc_main.mc' */
#define SP8870_FIRMWARE_OFFSET 0x0A
-static int sp8870_writereg (struct sp8870_state* state, u16 reg, u16 data)
+static int sp8870_writereg(struct sp8870_state *state, u16 reg, u16 data)
{
- u8 buf [] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
- struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 4 };
+ u8 buf[] = { reg >> 8, reg & 0xff, data >> 8, data & 0xff };
+ struct i2c_msg msg = {
+ .addr = state->config->demod_address,
+ .flags = 0,
+ .buf = buf,
+ .len = 4
+ };
+
int err;
- if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
- dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1) {
+ dprintk("writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", err, reg, data);
return -EREMOTEIO;
}
return 0;
}
-static int sp8870_readreg (struct sp8870_state* state, u16 reg)
+static int sp8870_readreg(struct sp8870_state *state, u16 reg)
{
int ret;
- u8 b0 [] = { reg >> 8 , reg & 0xff };
- u8 b1 [] = { 0, 0 };
- struct i2c_msg msg [] = { { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
- { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 } };
+ u8 b0[] = { reg >> 8, reg & 0xff };
+ u8 b1[] = { 0, 0 };
+ struct i2c_msg msg[] = {
+ { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 2 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 2 }
+ };
- ret = i2c_transfer (state->i2c, msg, 2);
+ ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
- dprintk("%s: readreg error (ret == %i)\n", __func__, ret);
+ dprintk("readreg error (ret == %i)\n", ret);
return -1;
}
return (b1[0] << 8 | b1[1]);
}
-static int sp8870_firmware_upload (struct sp8870_state* state, const struct firmware *fw)
+static int sp8870_firmware_upload(struct sp8870_state *state, const struct firmware *fw)
{
struct i2c_msg msg;
const char *fw_buf = fw->data;
@@ -91,7 +104,7 @@ static int sp8870_firmware_upload (struct sp8870_state* state, const struct firm
int tx_len;
int err = 0;
- dprintk ("%s: ...\n", __func__);
+ dprintk("start firmware upload...\n");
if (fw->size < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET)
return -EINVAL;
@@ -107,8 +120,9 @@ static int sp8870_firmware_upload (struct sp8870_state* state, const struct firm
// do firmware upload
fw_pos = SP8870_FIRMWARE_OFFSET;
- while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET){
- tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 : SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
+ while (fw_pos < SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET) {
+ tx_len = (fw_pos <= SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - 252) ? 252 :
+ SP8870_FIRMWARE_SIZE + SP8870_FIRMWARE_OFFSET - fw_pos;
// write register 0xCF0A
tx_buf[0] = 0xCF;
tx_buf[1] = 0x0A;
@@ -117,19 +131,20 @@ static int sp8870_firmware_upload (struct sp8870_state* state, const struct firm
msg.flags = 0;
msg.buf = tx_buf;
msg.len = tx_len + 2;
- if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
- printk("%s: firmware upload failed!\n", __func__);
- printk ("%s: i2c error (err == %i)\n", __func__, err);
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1) {
+ pr_err("%s(): firmware upload failed!\n", __func__);
+ pr_err("%s(): i2c error (err == %i)\n", __func__, err);
return err;
}
fw_pos += tx_len;
}
- dprintk ("%s: done!\n", __func__);
+ dprintk("firmware upload successful!\n");
return 0;
};
-static void sp8870_microcontroller_stop (struct sp8870_state* state)
+static void sp8870_microcontroller_stop(struct sp8870_state *state)
{
sp8870_writereg(state, 0x0F08, 0x000);
sp8870_writereg(state, 0x0F09, 0x000);
@@ -138,7 +153,7 @@ static void sp8870_microcontroller_stop (struct sp8870_state* state)
sp8870_writereg(state, 0x0F00, 0x000);
}
-static void sp8870_microcontroller_start (struct sp8870_state* state)
+static void sp8870_microcontroller_start(struct sp8870_state *state)
{
sp8870_writereg(state, 0x0F08, 0x000);
sp8870_writereg(state, 0x0F09, 0x000);
@@ -150,12 +165,12 @@ static void sp8870_microcontroller_start (struct sp8870_state* state)
sp8870_readreg(state, 0x0D01);
}
-static int sp8870_read_data_valid_signal(struct sp8870_state* state)
+static int sp8870_read_data_valid_signal(struct sp8870_state *state)
{
return (sp8870_readreg(state, 0x0D02) > 0);
}
-static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05)
+static int configure_reg0xc05(struct dtv_frontend_properties *p, u16 *reg0xc05)
{
int known_parameters = 1;
@@ -226,7 +241,7 @@ static int configure_reg0xc05 (struct dtv_frontend_properties *p, u16 *reg0xc05)
return 0;
}
-static int sp8870_wake_up(struct sp8870_state* state)
+static int sp8870_wake_up(struct sp8870_state *state)
{
// enable TS output and interface pins
return sp8870_writereg(state, 0xC18, 0x00D);
@@ -235,11 +250,12 @@ static int sp8870_wake_up(struct sp8870_state* state)
static int sp8870_set_frontend_parameters(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct sp8870_state* state = fe->demodulator_priv;
+ struct sp8870_state *state = fe->demodulator_priv;
int err;
u16 reg0xc05;
- if ((err = configure_reg0xc05(p, &reg0xc05)))
+ err = configure_reg0xc05(p, &reg0xc05);
+ if (err)
return err;
// system controller stop
@@ -248,7 +264,8 @@ static int sp8870_set_frontend_parameters(struct dvb_frontend *fe)
// set tuner parameters
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe);
- if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
}
// sample rate correction bit [23..17]
@@ -290,32 +307,32 @@ static int sp8870_set_frontend_parameters(struct dvb_frontend *fe)
return 0;
}
-static int sp8870_init (struct dvb_frontend* fe)
+static int sp8870_init(struct dvb_frontend *fe)
{
- struct sp8870_state* state = fe->demodulator_priv;
+ struct sp8870_state *state = fe->demodulator_priv;
const struct firmware *fw = NULL;
sp8870_wake_up(state);
- if (state->initialised) return 0;
+ if (state->initialised)
+ return 0;
state->initialised = 1;
- dprintk ("%s\n", __func__);
-
+ dprintk("initialising frontend...\n");
/* request the firmware, this will block until someone uploads it */
- printk("sp8870: waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE);
+ pr_info("waiting for firmware upload (%s)...\n", SP8870_DEFAULT_FIRMWARE);
if (state->config->request_firmware(fe, &fw, SP8870_DEFAULT_FIRMWARE)) {
- printk("sp8870: no firmware upload (timeout or file not found?)\n");
+ pr_err("no firmware upload (timeout or file not found?)\n");
return -EIO;
}
if (sp8870_firmware_upload(state, fw)) {
- printk("sp8870: writing firmware to device failed\n");
+ pr_err("writing firmware to device failed\n");
release_firmware(fw);
return -EIO;
}
release_firmware(fw);
- printk("sp8870: firmware upload complete\n");
+ pr_info("firmware upload complete\n");
/* enable TS output and interface pins */
sp8870_writereg(state, 0xc18, 0x00d);
@@ -342,17 +359,17 @@ static int sp8870_init (struct dvb_frontend* fe)
static int sp8870_read_status(struct dvb_frontend *fe,
enum fe_status *fe_status)
{
- struct sp8870_state* state = fe->demodulator_priv;
+ struct sp8870_state *state = fe->demodulator_priv;
int status;
int signal;
*fe_status = 0;
- status = sp8870_readreg (state, 0x0200);
+ status = sp8870_readreg(state, 0x0200);
if (status < 0)
return -EIO;
- signal = sp8870_readreg (state, 0x0303);
+ signal = sp8870_readreg(state, 0x0303);
if (signal < 0)
return -EIO;
@@ -366,9 +383,9 @@ static int sp8870_read_status(struct dvb_frontend *fe,
return 0;
}
-static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
+static int sp8870_read_ber(struct dvb_frontend *fe, u32 *ber)
{
- struct sp8870_state* state = fe->demodulator_priv;
+ struct sp8870_state *state = fe->demodulator_priv;
int ret;
u32 tmp;
@@ -393,21 +410,21 @@ static int sp8870_read_ber (struct dvb_frontend* fe, u32 * ber)
return 0;
}
-static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
+static int sp8870_read_signal_strength(struct dvb_frontend *fe, u16 *signal)
{
- struct sp8870_state* state = fe->demodulator_priv;
+ struct sp8870_state *state = fe->demodulator_priv;
int ret;
u16 tmp;
*signal = 0;
- ret = sp8870_readreg (state, 0x306);
+ ret = sp8870_readreg(state, 0x306);
if (ret < 0)
return -EIO;
tmp = ret << 8;
- ret = sp8870_readreg (state, 0x303);
+ ret = sp8870_readreg(state, 0x303);
if (ret < 0)
return -EIO;
@@ -419,9 +436,9 @@ static int sp8870_read_signal_strength(struct dvb_frontend* fe, u16 * signal)
return 0;
}
-static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks)
+static int sp8870_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ublocks)
{
- struct sp8870_state* state = fe->demodulator_priv;
+ struct sp8870_state *state = fe->demodulator_priv;
int ret;
*ublocks = 0;
@@ -451,24 +468,23 @@ static int switches;
static int sp8870_set_frontend(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
- struct sp8870_state* state = fe->demodulator_priv;
+ struct sp8870_state *state = fe->demodulator_priv;
/*
- The firmware of the sp8870 sometimes locks up after setting frontend parameters.
- We try to detect this by checking the data valid signal.
- If it is not set after MAXCHECKS we try to recover the lockup by setting
- the frontend parameters again.
- */
+ * The firmware of the sp8870 sometimes locks up after setting frontend parameters.
+ * We try to detect this by checking the data valid signal.
+ * If it is not set after MAXCHECKS we try to recover the lockup by setting
+ * the frontend parameters again.
+ */
int err = 0;
int valid = 0;
int trials = 0;
int check_count = 0;
- dprintk("%s: frequency = %i\n", __func__, p->frequency);
+ dprintk("frequency = %i\n", p->frequency);
for (trials = 1; trials <= MAXTRIALS; trials++) {
-
err = sp8870_set_frontend_parameters(fe);
if (err)
return err;
@@ -477,8 +493,7 @@ static int sp8870_set_frontend(struct dvb_frontend *fe)
// valid = ((sp8870_readreg(i2c, 0x0200) & 4) == 0);
valid = sp8870_read_data_valid_signal(state);
if (valid) {
- dprintk("%s: delay = %i usec\n",
- __func__, check_count * 10);
+ dprintk("delay = %i usec\n", check_count * 10);
break;
}
udelay(10);
@@ -488,34 +503,34 @@ static int sp8870_set_frontend(struct dvb_frontend *fe)
}
if (!valid) {
- printk("%s: firmware crash!!!!!!\n", __func__);
+ pr_err("%s(): firmware crash!!!!!!\n", __func__);
return -EIO;
}
if (debug) {
if (valid) {
if (trials > 1) {
- printk("%s: firmware lockup!!!\n", __func__);
- printk("%s: recovered after %i trial(s))\n", __func__, trials - 1);
+ pr_info("%s(): firmware lockup!!!\n", __func__);
+ pr_info("%s(): recovered after %i trial(s))\n", __func__, trials - 1);
lockups++;
}
}
switches++;
- printk("%s: switches = %i lockups = %i\n", __func__, switches, lockups);
+ pr_info("%s(): switches = %i lockups = %i\n", __func__, switches, lockups);
}
return 0;
}
-static int sp8870_sleep(struct dvb_frontend* fe)
+static int sp8870_sleep(struct dvb_frontend *fe)
{
- struct sp8870_state* state = fe->demodulator_priv;
+ struct sp8870_state *state = fe->demodulator_priv;
// tristate TS output and disable interface pins
return sp8870_writereg(state, 0xC18, 0x000);
}
-static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings)
+static int sp8870_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *fesettings)
{
fesettings->min_delay_ms = 350;
fesettings->step_size = 0;
@@ -523,33 +538,34 @@ static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend
return 0;
}
-static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
+static int sp8870_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
- struct sp8870_state* state = fe->demodulator_priv;
+ struct sp8870_state *state = fe->demodulator_priv;
- if (enable) {
+ if (enable)
return sp8870_writereg(state, 0x206, 0x001);
- } else {
+ else
return sp8870_writereg(state, 0x206, 0x000);
- }
}
-static void sp8870_release(struct dvb_frontend* fe)
+static void sp8870_release(struct dvb_frontend *fe)
{
- struct sp8870_state* state = fe->demodulator_priv;
+ struct sp8870_state *state = fe->demodulator_priv;
+
kfree(state);
}
static const struct dvb_frontend_ops sp8870_ops;
-struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
- struct i2c_adapter* i2c)
+struct dvb_frontend *sp8870_attach(const struct sp8870_config *config,
+ struct i2c_adapter *i2c)
{
- struct sp8870_state* state = NULL;
+ struct sp8870_state *state = NULL;
/* allocate memory for the internal state */
- state = kzalloc(sizeof(struct sp8870_state), GFP_KERNEL);
- if (state == NULL) goto error;
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ goto error;
/* setup the state */
state->config = config;
@@ -557,10 +573,11 @@ struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
state->initialised = 0;
/* check if the demod is there */
- if (sp8870_readreg(state, 0x0200) < 0) goto error;
+ if (sp8870_readreg(state, 0x0200) < 0)
+ goto error;
/* create dvb_frontend */
- memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops));
+ memcpy(&state->frontend.ops, &sp8870_ops, sizeof(sp8870_ops));
state->frontend.demodulator_priv = state;
return &state->frontend;
@@ -568,6 +585,7 @@ error:
kfree(state);
return NULL;
}
+EXPORT_SYMBOL_GPL(sp8870_attach);
static const struct dvb_frontend_ops sp8870_ops = {
.delsys = { SYS_DVBT },
@@ -605,5 +623,3 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
MODULE_DESCRIPTION("Spase SP8870 DVB-T Demodulator driver");
MODULE_AUTHOR("Juergen Peitz");
MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL_GPL(sp8870_attach);
diff --git a/drivers/staging/media/av7110/sp8870.h b/drivers/staging/media/av7110/sp8870.h
index 5eacf39f425e..3323d1dfa568 100644
--- a/drivers/staging/media/av7110/sp8870.h
+++ b/drivers/staging/media/av7110/sp8870.h
@@ -1,11 +1,9 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
- Driver for Spase SP8870 demodulator
-
- Copyright (C) 1999 Juergen Peitz
-
-
-*/
+ * Driver for Spase SP8870 demodulator
+ *
+ * Copyright (C) 1999 Juergen Peitz
+ */
#ifndef SP8870_H
#define SP8870_H
@@ -13,23 +11,21 @@
#include <linux/dvb/frontend.h>
#include <linux/firmware.h>
-struct sp8870_config
-{
+struct sp8870_config {
/* the demodulator's i2c address */
u8 demod_address;
/* request firmware for device */
- int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name);
+ int (*request_firmware)(struct dvb_frontend *fe, const struct firmware **fw, char *name);
};
#if IS_REACHABLE(CONFIG_DVB_SP8870)
-extern struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
- struct i2c_adapter* i2c);
+struct dvb_frontend *sp8870_attach(const struct sp8870_config *config, struct i2c_adapter *i2c);
#else
-static inline struct dvb_frontend* sp8870_attach(const struct sp8870_config* config,
- struct i2c_adapter* i2c)
+static inline struct dvb_frontend *sp8870_attach(const struct sp8870_config *config,
+ struct i2c_adapter *i2c)
{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ pr_warn(KBUILD_MODNAME ": %s(): driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif // CONFIG_DVB_SP8870
diff --git a/drivers/staging/media/av7110/video-clear-buffer.rst b/drivers/staging/media/av7110/video-clear-buffer.rst
deleted file mode 100644
index a7730559bbb2..000000000000
--- a/drivers/staging/media/av7110/video-clear-buffer.rst
+++ /dev/null
@@ -1,54 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_CLEAR_BUFFER:
-
-==================
-VIDEO_CLEAR_BUFFER
-==================
-
-Name
-----
-
-VIDEO_CLEAR_BUFFER
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_CLEAR_BUFFER
-
-``int ioctl(fd, VIDEO_CLEAR_BUFFER)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_CLEAR_BUFFER for this command.
-
-Description
------------
-
-This ioctl call clears all video buffers in the driver and in the
-decoder hardware.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-command.rst b/drivers/staging/media/av7110/video-command.rst
deleted file mode 100644
index cae9445eb3af..000000000000
--- a/drivers/staging/media/av7110/video-command.rst
+++ /dev/null
@@ -1,96 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_COMMAND:
-
-=============
-VIDEO_COMMAND
-=============
-
-Name
-----
-
-VIDEO_COMMAND
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_COMMAND
-
-``int ioctl(int fd, VIDEO_COMMAND, struct video_command *cmd)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_COMMAND for this command.
-
- - .. row 3
-
- - struct video_command \*cmd
-
- - Commands the decoder.
-
-Description
------------
-
-This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders
-this ioctl has been replaced by the
-:ref:`VIDIOC_DECODER_CMD` ioctl.
-
-This ioctl commands the decoder. The ``video_command`` struct is a
-subset of the ``v4l2_decoder_cmd`` struct, so refer to the
-:ref:`VIDIOC_DECODER_CMD` documentation for
-more information.
-
-.. c:type:: video_command
-
-.. code-block:: c
-
- /* The structure must be zeroed before use by the application
- This ensures it can be extended safely in the future. */
- struct video_command {
- __u32 cmd;
- __u32 flags;
- union {
- struct {
- __u64 pts;
- } stop;
-
- struct {
- /* 0 or 1000 specifies normal speed,
- 1 specifies forward single stepping,
- -1 specifies backward single stepping,
- >1: playback at speed/1000 of the normal speed,
- <-1: reverse playback at (-speed/1000) of the normal speed. */
- __s32 speed;
- __u32 format;
- } play;
-
- struct {
- __u32 data[16];
- } raw;
- };
- };
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-continue.rst b/drivers/staging/media/av7110/video-continue.rst
deleted file mode 100644
index bc34bf3989e4..000000000000
--- a/drivers/staging/media/av7110/video-continue.rst
+++ /dev/null
@@ -1,57 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_CONTINUE:
-
-==============
-VIDEO_CONTINUE
-==============
-
-Name
-----
-
-VIDEO_CONTINUE
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_CONTINUE
-
-``int ioctl(fd, VIDEO_CONTINUE)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_CONTINUE for this command.
-
-Description
------------
-
-This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
-V4L2 :ref:`VIDIOC_DECODER_CMD` instead.
-
-This ioctl call restarts decoding and playing processes of the video
-stream which was played before a call to VIDEO_FREEZE was made.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-fast-forward.rst b/drivers/staging/media/av7110/video-fast-forward.rst
deleted file mode 100644
index e71fa8d6965b..000000000000
--- a/drivers/staging/media/av7110/video-fast-forward.rst
+++ /dev/null
@@ -1,72 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_FAST_FORWARD:
-
-==================
-VIDEO_FAST_FORWARD
-==================
-
-Name
-----
-
-VIDEO_FAST_FORWARD
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_FAST_FORWARD
-
-``int ioctl(fd, VIDEO_FAST_FORWARD, int nFrames)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_FAST_FORWARD for this command.
-
- - .. row 3
-
- - int nFrames
-
- - The number of frames to skip.
-
-Description
------------
-
-This ioctl call asks the Video Device to skip decoding of N number of
-I-frames. This call can only be used if VIDEO_SOURCE_MEMORY is
-selected.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
-
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``EPERM``
-
- - Mode VIDEO_SOURCE_MEMORY not selected.
diff --git a/drivers/staging/media/av7110/video-fclose.rst b/drivers/staging/media/av7110/video-fclose.rst
deleted file mode 100644
index 01d24d548439..000000000000
--- a/drivers/staging/media/av7110/video-fclose.rst
+++ /dev/null
@@ -1,51 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _video_fclose:
-
-=================
-dvb video close()
-=================
-
-Name
-----
-
-dvb video close()
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:function:: int close(int fd)
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
-Description
------------
-
-This system call closes a previously opened video device.
-
-Return Value
-------------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``EBADF``
-
- - fd is not a valid open file descriptor.
diff --git a/drivers/staging/media/av7110/video-fopen.rst b/drivers/staging/media/av7110/video-fopen.rst
deleted file mode 100644
index 1371b083e4e8..000000000000
--- a/drivers/staging/media/av7110/video-fopen.rst
+++ /dev/null
@@ -1,111 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _video_fopen:
-
-================
-dvb video open()
-================
-
-Name
-----
-
-dvb video open()
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:function:: int open(const char *deviceName, int flags)
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - const char \*deviceName
-
- - Name of specific video device.
-
- - .. row 2
-
- - int flags
-
- - A bit-wise OR of the following flags:
-
- - .. row 3
-
- -
- - O_RDONLY read-only access
-
- - .. row 4
-
- -
- - O_RDWR read/write access
-
- - .. row 5
-
- -
- - O_NONBLOCK open in non-blocking mode
-
- - .. row 6
-
- -
- - (blocking mode is the default)
-
-Description
------------
-
-This system call opens a named video device (e.g.
-/dev/dvb/adapter0/video0) for subsequent use.
-
-When an open() call has succeeded, the device will be ready for use. The
-significance of blocking or non-blocking mode is described in the
-documentation for functions where there is a difference. It does not
-affect the semantics of the open() call itself. A device opened in
-blocking mode can later be put into non-blocking mode (and vice versa)
-using the F_SETFL command of the fcntl system call. This is a standard
-system call, documented in the Linux manual page for fcntl. Only one
-user can open the Video Device in O_RDWR mode. All other attempts to
-open the device in this mode will fail, and an error-code will be
-returned. If the Video Device is opened in O_RDONLY mode, the only
-ioctl call that can be used is VIDEO_GET_STATUS. All other call will
-return an error code.
-
-Return Value
-------------
-
-.. tabularcolumns:: |p{2.5cm}|p{15.0cm}|
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``ENODEV``
-
- - Device driver not loaded/available.
-
- - .. row 2
-
- - ``EINTERNAL``
-
- - Internal error.
-
- - .. row 3
-
- - ``EBUSY``
-
- - Device or resource busy.
-
- - .. row 4
-
- - ``EINVAL``
-
- - Invalid argument.
diff --git a/drivers/staging/media/av7110/video-freeze.rst b/drivers/staging/media/av7110/video-freeze.rst
deleted file mode 100644
index 4321f257cb70..000000000000
--- a/drivers/staging/media/av7110/video-freeze.rst
+++ /dev/null
@@ -1,61 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_FREEZE:
-
-============
-VIDEO_FREEZE
-============
-
-Name
-----
-
-VIDEO_FREEZE
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_FREEZE
-
-``int ioctl(fd, VIDEO_FREEZE)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_FREEZE for this command.
-
-Description
------------
-
-This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
-V4L2 :ref:`VIDIOC_DECODER_CMD` instead.
-
-This ioctl call suspends the live video stream being played. Decoding
-and playing are frozen. It is then possible to restart the decoding and
-playing process of the video stream using the VIDEO_CONTINUE command.
-If VIDEO_SOURCE_MEMORY is selected in the ioctl call
-VIDEO_SELECT_SOURCE, the Digital TV subsystem will not decode any more data
-until the ioctl call VIDEO_CONTINUE or VIDEO_PLAY is performed.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-fwrite.rst b/drivers/staging/media/av7110/video-fwrite.rst
deleted file mode 100644
index a07fd7d7a40e..000000000000
--- a/drivers/staging/media/av7110/video-fwrite.rst
+++ /dev/null
@@ -1,79 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _video_fwrite:
-
-=================
-dvb video write()
-=================
-
-Name
-----
-
-dvb video write()
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:function:: size_t write(int fd, const void *buf, size_t count)
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - void \*buf
-
- - Pointer to the buffer containing the PES data.
-
- - .. row 3
-
- - size_t count
-
- - Size of buf.
-
-Description
------------
-
-This system call can only be used if VIDEO_SOURCE_MEMORY is selected
-in the ioctl call VIDEO_SELECT_SOURCE. The data provided shall be in
-PES format, unless the capability allows other formats. If O_NONBLOCK
-is not specified the function will block until buffer space is
-available. The amount of data to be transferred is implied by count.
-
-Return Value
-------------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``EPERM``
-
- - Mode VIDEO_SOURCE_MEMORY not selected.
-
- - .. row 2
-
- - ``ENOMEM``
-
- - Attempted to write more data than the internal buffer can hold.
-
- - .. row 3
-
- - ``EBADF``
-
- - fd is not a valid open file descriptor.
diff --git a/drivers/staging/media/av7110/video-get-capabilities.rst b/drivers/staging/media/av7110/video-get-capabilities.rst
deleted file mode 100644
index 01e09f56656c..000000000000
--- a/drivers/staging/media/av7110/video-get-capabilities.rst
+++ /dev/null
@@ -1,61 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_GET_CAPABILITIES:
-
-======================
-VIDEO_GET_CAPABILITIES
-======================
-
-Name
-----
-
-VIDEO_GET_CAPABILITIES
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_GET_CAPABILITIES
-
-``int ioctl(fd, VIDEO_GET_CAPABILITIES, unsigned int *cap)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_GET_CAPABILITIES for this command.
-
- - .. row 3
-
- - unsigned int \*cap
-
- - Pointer to a location where to store the capability information.
-
-Description
------------
-
-This ioctl call asks the video device about its decoding capabilities.
-On success it returns and integer which has bits set according to the
-defines in section ??.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-get-event.rst b/drivers/staging/media/av7110/video-get-event.rst
deleted file mode 100644
index 90382bc36cfe..000000000000
--- a/drivers/staging/media/av7110/video-get-event.rst
+++ /dev/null
@@ -1,105 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_GET_EVENT:
-
-===============
-VIDEO_GET_EVENT
-===============
-
-Name
-----
-
-VIDEO_GET_EVENT
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_GET_EVENT
-
-``int ioctl(fd, VIDEO_GET_EVENT, struct video_event *ev)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_GET_EVENT for this command.
-
- - .. row 3
-
- - struct video_event \*ev
-
- - Points to the location where the event, if any, is to be stored.
-
-Description
------------
-
-This ioctl is for Digital TV devices only. To get events from a V4L2 decoder
-use the V4L2 :ref:`VIDIOC_DQEVENT` ioctl instead.
-
-This ioctl call returns an event of type video_event if available. If
-an event is not available, the behavior depends on whether the device is
-in blocking or non-blocking mode. In the latter case, the call fails
-immediately with errno set to ``EWOULDBLOCK``. In the former case, the call
-blocks until an event becomes available. The standard Linux poll()
-and/or select() system calls can be used with the device file descriptor
-to watch for new events. For select(), the file descriptor should be
-included in the exceptfds argument, and for poll(), POLLPRI should be
-specified as the wake-up condition. Read-only permissions are sufficient
-for this ioctl call.
-
-.. c:type:: video_event
-
-.. code-block:: c
-
- struct video_event {
- __s32 type;
- #define VIDEO_EVENT_SIZE_CHANGED 1
- #define VIDEO_EVENT_FRAME_RATE_CHANGED 2
- #define VIDEO_EVENT_DECODER_STOPPED 3
- #define VIDEO_EVENT_VSYNC 4
- long timestamp;
- union {
- video_size_t size;
- unsigned int frame_rate; /* in frames per 1000sec */
- unsigned char vsync_field; /* unknown/odd/even/progressive */
- } u;
- };
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``EWOULDBLOCK``
-
- - There is no event pending, and the device is in non-blocking mode.
-
- - .. row 2
-
- - ``EOVERFLOW``
-
- - Overflow in event queue - one or more events were lost.
diff --git a/drivers/staging/media/av7110/video-get-frame-count.rst b/drivers/staging/media/av7110/video-get-frame-count.rst
deleted file mode 100644
index b48ac8c58a41..000000000000
--- a/drivers/staging/media/av7110/video-get-frame-count.rst
+++ /dev/null
@@ -1,65 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_GET_FRAME_COUNT:
-
-=====================
-VIDEO_GET_FRAME_COUNT
-=====================
-
-Name
-----
-
-VIDEO_GET_FRAME_COUNT
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_GET_FRAME_COUNT
-
-``int ioctl(int fd, VIDEO_GET_FRAME_COUNT, __u64 *pts)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_GET_FRAME_COUNT for this command.
-
- - .. row 3
-
- - __u64 \*pts
-
- - Returns the number of frames displayed since the decoder was
- started.
-
-Description
------------
-
-This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders
-this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_FRAME``
-control.
-
-This ioctl call asks the Video Device to return the number of displayed
-frames since the decoder was started.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-get-pts.rst b/drivers/staging/media/av7110/video-get-pts.rst
deleted file mode 100644
index fedaff41be0b..000000000000
--- a/drivers/staging/media/av7110/video-get-pts.rst
+++ /dev/null
@@ -1,69 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_GET_PTS:
-
-=============
-VIDEO_GET_PTS
-=============
-
-Name
-----
-
-VIDEO_GET_PTS
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_GET_PTS
-
-``int ioctl(int fd, VIDEO_GET_PTS, __u64 *pts)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_GET_PTS for this command.
-
- - .. row 3
-
- - __u64 \*pts
-
- - Returns the 33-bit timestamp as defined in ITU T-REC-H.222.0 /
- ISO/IEC 13818-1.
-
- The PTS should belong to the currently played frame if possible,
- but may also be a value close to it like the PTS of the last
- decoded frame or the last PTS extracted by the PES parser.
-
-Description
------------
-
-This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders
-this ioctl has been replaced by the ``V4L2_CID_MPEG_VIDEO_DEC_PTS``
-control.
-
-This ioctl call asks the Video Device to return the current PTS
-timestamp.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-get-size.rst b/drivers/staging/media/av7110/video-get-size.rst
deleted file mode 100644
index de34331c5bd1..000000000000
--- a/drivers/staging/media/av7110/video-get-size.rst
+++ /dev/null
@@ -1,69 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_GET_SIZE:
-
-==============
-VIDEO_GET_SIZE
-==============
-
-Name
-----
-
-VIDEO_GET_SIZE
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_GET_SIZE
-
-``int ioctl(int fd, VIDEO_GET_SIZE, video_size_t *size)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_GET_SIZE for this command.
-
- - .. row 3
-
- - video_size_t \*size
-
- - Returns the size and aspect ratio.
-
-Description
------------
-
-This ioctl returns the size and aspect ratio.
-
-.. c:type:: video_size_t
-
-.. code-block::c
-
- typedef struct {
- int w;
- int h;
- video_format_t aspect_ratio;
- } video_size_t;
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-get-status.rst b/drivers/staging/media/av7110/video-get-status.rst
deleted file mode 100644
index 9b86fbf411d4..000000000000
--- a/drivers/staging/media/av7110/video-get-status.rst
+++ /dev/null
@@ -1,72 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_GET_STATUS:
-
-================
-VIDEO_GET_STATUS
-================
-
-Name
-----
-
-VIDEO_GET_STATUS
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_GET_STATUS
-
-``int ioctl(fd, VIDEO_GET_STATUS, struct video_status *status)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_GET_STATUS for this command.
-
- - .. row 3
-
- - struct video_status \*status
-
- - Returns the current status of the Video Device.
-
-Description
------------
-
-This ioctl call asks the Video Device to return the current status of
-the device.
-
-.. c:type:: video_status
-
-.. code-block:: c
-
- struct video_status {
- int video_blank; /* blank video on freeze? */
- video_play_state_t play_state; /* current state of playback */
- video_stream_source_t stream_source; /* current source (demux/memory) */
- video_format_t video_format; /* current aspect ratio of stream*/
- video_displayformat_t display_format;/* selected cropping mode */
- };
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-play.rst b/drivers/staging/media/av7110/video-play.rst
deleted file mode 100644
index 35ac8b98fdbf..000000000000
--- a/drivers/staging/media/av7110/video-play.rst
+++ /dev/null
@@ -1,57 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_PLAY:
-
-==========
-VIDEO_PLAY
-==========
-
-Name
-----
-
-VIDEO_PLAY
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_PLAY
-
-``int ioctl(fd, VIDEO_PLAY)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_PLAY for this command.
-
-Description
------------
-
-This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
-V4L2 :ref:`VIDIOC_DECODER_CMD` instead.
-
-This ioctl call asks the Video Device to start playing a video stream
-from the selected source.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-select-source.rst b/drivers/staging/media/av7110/video-select-source.rst
deleted file mode 100644
index 929a20985d53..000000000000
--- a/drivers/staging/media/av7110/video-select-source.rst
+++ /dev/null
@@ -1,76 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_SELECT_SOURCE:
-
-===================
-VIDEO_SELECT_SOURCE
-===================
-
-Name
-----
-
-VIDEO_SELECT_SOURCE
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_SELECT_SOURCE
-
-``int ioctl(fd, VIDEO_SELECT_SOURCE, video_stream_source_t source)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_SELECT_SOURCE for this command.
-
- - .. row 3
-
- - video_stream_source_t source
-
- - Indicates which source shall be used for the Video stream.
-
-Description
------------
-
-This ioctl is for Digital TV devices only. This ioctl was also supported by the
-V4L2 ivtv driver, but that has been replaced by the ivtv-specific
-``IVTV_IOC_PASSTHROUGH_MODE`` ioctl.
-
-This ioctl call informs the video device which source shall be used for
-the input data. The possible sources are demux or memory. If memory is
-selected, the data is fed to the video device through the write command.
-
-.. c:type:: video_stream_source_t
-
-.. code-block:: c
-
- typedef enum {
- VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */
- VIDEO_SOURCE_MEMORY /* If this source is selected, the stream
- comes from the user through the write
- system call */
- } video_stream_source_t;
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-set-blank.rst b/drivers/staging/media/av7110/video-set-blank.rst
deleted file mode 100644
index 70249a6ba125..000000000000
--- a/drivers/staging/media/av7110/video-set-blank.rst
+++ /dev/null
@@ -1,64 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_SET_BLANK:
-
-===============
-VIDEO_SET_BLANK
-===============
-
-Name
-----
-
-VIDEO_SET_BLANK
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_SET_BLANK
-
-``int ioctl(fd, VIDEO_SET_BLANK, boolean mode)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_SET_BLANK for this command.
-
- - .. row 3
-
- - boolean mode
-
- - TRUE: Blank screen when stop.
-
- - .. row 4
-
- -
- - FALSE: Show last decoded frame.
-
-Description
------------
-
-This ioctl call asks the Video Device to blank out the picture.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-set-display-format.rst b/drivers/staging/media/av7110/video-set-display-format.rst
deleted file mode 100644
index 1de4f40ae732..000000000000
--- a/drivers/staging/media/av7110/video-set-display-format.rst
+++ /dev/null
@@ -1,60 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_SET_DISPLAY_FORMAT:
-
-========================
-VIDEO_SET_DISPLAY_FORMAT
-========================
-
-Name
-----
-
-VIDEO_SET_DISPLAY_FORMAT
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_SET_DISPLAY_FORMAT
-
-``int ioctl(fd, VIDEO_SET_DISPLAY_FORMAT)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_SET_DISPLAY_FORMAT for this command.
-
- - .. row 3
-
- - video_display_format_t format
-
- - Selects the video format to be used.
-
-Description
------------
-
-This ioctl call asks the Video Device to select the video format to be
-applied by the MPEG chip on the video.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-set-format.rst b/drivers/staging/media/av7110/video-set-format.rst
deleted file mode 100644
index bb64e37ae081..000000000000
--- a/drivers/staging/media/av7110/video-set-format.rst
+++ /dev/null
@@ -1,82 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_SET_FORMAT:
-
-================
-VIDEO_SET_FORMAT
-================
-
-Name
-----
-
-VIDEO_SET_FORMAT
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_SET_FORMAT
-
-``int ioctl(fd, VIDEO_SET_FORMAT, video_format_t format)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_SET_FORMAT for this command.
-
- - .. row 3
-
- - video_format_t format
-
- - video format of TV as defined in section ??.
-
-Description
------------
-
-This ioctl sets the screen format (aspect ratio) of the connected output
-device (TV) so that the output of the decoder can be adjusted
-accordingly.
-
-.. c:type:: video_format_t
-
-.. code-block:: c
-
- typedef enum {
- VIDEO_FORMAT_4_3, /* Select 4:3 format */
- VIDEO_FORMAT_16_9, /* Select 16:9 format. */
- VIDEO_FORMAT_221_1 /* 2.21:1 */
- } video_format_t;
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
-
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``EINVAL``
-
- - format is not a valid video format.
diff --git a/drivers/staging/media/av7110/video-set-streamtype.rst b/drivers/staging/media/av7110/video-set-streamtype.rst
deleted file mode 100644
index 1f31c048bdbc..000000000000
--- a/drivers/staging/media/av7110/video-set-streamtype.rst
+++ /dev/null
@@ -1,61 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_SET_STREAMTYPE:
-
-====================
-VIDEO_SET_STREAMTYPE
-====================
-
-Name
-----
-
-VIDEO_SET_STREAMTYPE
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_SET_STREAMTYPE
-
-``int ioctl(fd, VIDEO_SET_STREAMTYPE, int type)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_SET_STREAMTYPE for this command.
-
- - .. row 3
-
- - int type
-
- - stream type
-
-Description
------------
-
-This ioctl tells the driver which kind of stream to expect being written
-to it. If this call is not used the default of video PES is used. Some
-drivers might not support this call and always expect PES.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-slowmotion.rst b/drivers/staging/media/av7110/video-slowmotion.rst
deleted file mode 100644
index 1478fcc30cb8..000000000000
--- a/drivers/staging/media/av7110/video-slowmotion.rst
+++ /dev/null
@@ -1,72 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_SLOWMOTION:
-
-================
-VIDEO_SLOWMOTION
-================
-
-Name
-----
-
-VIDEO_SLOWMOTION
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_SLOWMOTION
-
-``int ioctl(fd, VIDEO_SLOWMOTION, int nFrames)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_SLOWMOTION for this command.
-
- - .. row 3
-
- - int nFrames
-
- - The number of times to repeat each frame.
-
-Description
------------
-
-This ioctl call asks the video device to repeat decoding frames N number
-of times. This call can only be used if VIDEO_SOURCE_MEMORY is
-selected.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
-
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - ``EPERM``
-
- - Mode VIDEO_SOURCE_MEMORY not selected.
diff --git a/drivers/staging/media/av7110/video-stillpicture.rst b/drivers/staging/media/av7110/video-stillpicture.rst
deleted file mode 100644
index d25384222a20..000000000000
--- a/drivers/staging/media/av7110/video-stillpicture.rst
+++ /dev/null
@@ -1,61 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_STILLPICTURE:
-
-==================
-VIDEO_STILLPICTURE
-==================
-
-Name
-----
-
-VIDEO_STILLPICTURE
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_STILLPICTURE
-
-``int ioctl(fd, VIDEO_STILLPICTURE, struct video_still_picture *sp)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_STILLPICTURE for this command.
-
- - .. row 3
-
- - struct video_still_picture \*sp
-
- - Pointer to a location where an I-frame and size is stored.
-
-Description
------------
-
-This ioctl call asks the Video Device to display a still picture
-(I-frame). The input data shall contain an I-frame. If the pointer is
-NULL, then the current displayed still picture is blanked.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-stop.rst b/drivers/staging/media/av7110/video-stop.rst
deleted file mode 100644
index 96f61c5b48a2..000000000000
--- a/drivers/staging/media/av7110/video-stop.rst
+++ /dev/null
@@ -1,74 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_STOP:
-
-==========
-VIDEO_STOP
-==========
-
-Name
-----
-
-VIDEO_STOP
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_STOP
-
-``int ioctl(fd, VIDEO_STOP, boolean mode)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_STOP for this command.
-
- - .. row 3
-
- - Boolean mode
-
- - Indicates how the screen shall be handled.
-
- - .. row 4
-
- -
- - TRUE: Blank screen when stop.
-
- - .. row 5
-
- -
- - FALSE: Show last decoded frame.
-
-Description
------------
-
-This ioctl is for Digital TV devices only. To control a V4L2 decoder use the
-V4L2 :ref:`VIDIOC_DECODER_CMD` instead.
-
-This ioctl call asks the Video Device to stop playing the current
-stream. Depending on the input parameter, the screen can be blanked out
-or displaying the last decoded frame.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video-try-command.rst b/drivers/staging/media/av7110/video-try-command.rst
deleted file mode 100644
index 79bf3dfb8a32..000000000000
--- a/drivers/staging/media/av7110/video-try-command.rst
+++ /dev/null
@@ -1,66 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-.. c:namespace:: DTV.video
-
-.. _VIDEO_TRY_COMMAND:
-
-=================
-VIDEO_TRY_COMMAND
-=================
-
-Name
-----
-
-VIDEO_TRY_COMMAND
-
-.. attention:: This ioctl is deprecated.
-
-Synopsis
---------
-
-.. c:macro:: VIDEO_TRY_COMMAND
-
-``int ioctl(int fd, VIDEO_TRY_COMMAND, struct video_command *cmd)``
-
-Arguments
----------
-
-.. flat-table::
- :header-rows: 0
- :stub-columns: 0
-
- - .. row 1
-
- - int fd
-
- - File descriptor returned by a previous call to open().
-
- - .. row 2
-
- - int request
-
- - Equals VIDEO_TRY_COMMAND for this command.
-
- - .. row 3
-
- - struct video_command \*cmd
-
- - Try a decoder command.
-
-Description
------------
-
-This ioctl is obsolete. Do not use in new drivers. For V4L2 decoders
-this ioctl has been replaced by the
-:ref:`VIDIOC_TRY_DECODER_CMD <VIDIOC_DECODER_CMD>` ioctl.
-
-This ioctl tries a decoder command. The ``video_command`` struct is a
-subset of the ``v4l2_decoder_cmd`` struct, so refer to the
-:ref:`VIDIOC_TRY_DECODER_CMD <VIDIOC_DECODER_CMD>` documentation
-for more information.
-
-Return Value
-------------
-
-On success 0 is returned, on error -1 and the ``errno`` variable is set
-appropriately. The generic error codes are described at the
-:ref:`Generic Error Codes <gen-errors>` chapter.
diff --git a/drivers/staging/media/av7110/video.rst b/drivers/staging/media/av7110/video.rst
deleted file mode 100644
index 808705b769a1..000000000000
--- a/drivers/staging/media/av7110/video.rst
+++ /dev/null
@@ -1,36 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-
-.. _dvb_video:
-
-#######################
-Digital TV Video Device
-#######################
-
-The Digital TV video device controls the MPEG2 video decoder of the Digital
-TV hardware. It can be accessed through **/dev/dvb/adapter0/video0**. Data
-types and ioctl definitions can be accessed by including
-**linux/dvb/video.h** in your application.
-
-Note that the Digital TV video device only controls decoding of the MPEG video
-stream, not its presentation on the TV or computer screen. On PCs this
-is typically handled by an associated video4linux device, e.g.
-**/dev/video**, which allows scaling and defining output windows.
-
-Some Digital TV cards don't have their own MPEG decoder, which results in the
-omission of the audio and video device as well as the video4linux
-device.
-
-The ioctls that deal with SPUs (sub picture units) and navigation
-packets are only supported on some MPEG decoders made for DVD playback.
-
-These ioctls were also used by V4L2 to control MPEG decoders implemented
-in V4L2. The use of these ioctls for that purpose has been made obsolete
-and proper V4L2 ioctls or controls have been created to replace that
-functionality.
-
-
-.. toctree::
- :maxdepth: 1
-
- video_types
- video_function_calls
diff --git a/drivers/staging/media/av7110/video_function_calls.rst b/drivers/staging/media/av7110/video_function_calls.rst
deleted file mode 100644
index 20a897be5dca..000000000000
--- a/drivers/staging/media/av7110/video_function_calls.rst
+++ /dev/null
@@ -1,35 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-
-.. _video_function_calls:
-
-********************
-Video Function Calls
-********************
-
-.. toctree::
- :maxdepth: 1
-
- video-fopen
- video-fclose
- video-fwrite
- video-stop
- video-play
- video-freeze
- video-continue
- video-select-source
- video-set-blank
- video-get-status
- video-get-frame-count
- video-get-pts
- video-get-event
- video-command
- video-try-command
- video-get-size
- video-set-display-format
- video-stillpicture
- video-fast-forward
- video-slowmotion
- video-get-capabilities
- video-clear-buffer
- video-set-streamtype
- video-set-format
diff --git a/drivers/staging/media/av7110/video_types.rst b/drivers/staging/media/av7110/video_types.rst
deleted file mode 100644
index c4557d328b7a..000000000000
--- a/drivers/staging/media/av7110/video_types.rst
+++ /dev/null
@@ -1,248 +0,0 @@
-.. SPDX-License-Identifier: GFDL-1.1-no-invariants-or-later
-
-.. _video_types:
-
-****************
-Video Data Types
-****************
-
-
-.. _video-format-t:
-
-video_format_t
-==============
-
-The ``video_format_t`` data type defined by
-
-
-.. code-block:: c
-
- typedef enum {
- VIDEO_FORMAT_4_3, /* Select 4:3 format */
- VIDEO_FORMAT_16_9, /* Select 16:9 format. */
- VIDEO_FORMAT_221_1 /* 2.21:1 */
- } video_format_t;
-
-is used in the VIDEO_SET_FORMAT function (??) to tell the driver which
-aspect ratio the output hardware (e.g. TV) has. It is also used in the
-data structures video_status (??) returned by VIDEO_GET_STATUS (??)
-and video_event (??) returned by VIDEO_GET_EVENT (??) which report
-about the display format of the current video stream.
-
-
-.. _video-displayformat-t:
-
-video_displayformat_t
-=====================
-
-In case the display format of the video stream and of the display
-hardware differ the application has to specify how to handle the
-cropping of the picture. This can be done using the
-VIDEO_SET_DISPLAY_FORMAT call (??) which accepts
-
-
-.. code-block:: c
-
- typedef enum {
- VIDEO_PAN_SCAN, /* use pan and scan format */
- VIDEO_LETTER_BOX, /* use letterbox format */
- VIDEO_CENTER_CUT_OUT /* use center cut out format */
- } video_displayformat_t;
-
-as argument.
-
-
-.. _video-stream-source-t:
-
-video_stream_source_t
-=====================
-
-The video stream source is set through the VIDEO_SELECT_SOURCE call
-and can take the following values, depending on whether we are replaying
-from an internal (demuxer) or external (user write) source.
-
-
-.. code-block:: c
-
- typedef enum {
- VIDEO_SOURCE_DEMUX, /* Select the demux as the main source */
- VIDEO_SOURCE_MEMORY /* If this source is selected, the stream
- comes from the user through the write
- system call */
- } video_stream_source_t;
-
-VIDEO_SOURCE_DEMUX selects the demultiplexer (fed either by the
-frontend or the DVR device) as the source of the video stream. If
-VIDEO_SOURCE_MEMORY is selected the stream comes from the application
-through the **write()** system call.
-
-
-.. _video-play-state-t:
-
-video_play_state_t
-==================
-
-The following values can be returned by the VIDEO_GET_STATUS call
-representing the state of video playback.
-
-
-.. code-block:: c
-
- typedef enum {
- VIDEO_STOPPED, /* Video is stopped */
- VIDEO_PLAYING, /* Video is currently playing */
- VIDEO_FREEZED /* Video is freezed */
- } video_play_state_t;
-
-
-.. c:type:: video_command
-
-struct video_command
-====================
-
-The structure must be zeroed before use by the application This ensures
-it can be extended safely in the future.
-
-
-.. code-block:: c
-
- struct video_command {
- __u32 cmd;
- __u32 flags;
- union {
- struct {
- __u64 pts;
- } stop;
-
- struct {
- /* 0 or 1000 specifies normal speed,
- 1 specifies forward single stepping,
- -1 specifies backward single stepping,
- >>1: playback at speed/1000 of the normal speed,
- <-1: reverse playback at (-speed/1000) of the normal speed. */
- __s32 speed;
- __u32 format;
- } play;
-
- struct {
- __u32 data[16];
- } raw;
- };
- };
-
-
-.. _video-size-t:
-
-video_size_t
-============
-
-
-.. code-block:: c
-
- typedef struct {
- int w;
- int h;
- video_format_t aspect_ratio;
- } video_size_t;
-
-
-.. c:type:: video_event
-
-struct video_event
-==================
-
-The following is the structure of a video event as it is returned by the
-VIDEO_GET_EVENT call.
-
-
-.. code-block:: c
-
- struct video_event {
- __s32 type;
- #define VIDEO_EVENT_SIZE_CHANGED 1
- #define VIDEO_EVENT_FRAME_RATE_CHANGED 2
- #define VIDEO_EVENT_DECODER_STOPPED 3
- #define VIDEO_EVENT_VSYNC 4
- long timestamp;
- union {
- video_size_t size;
- unsigned int frame_rate; /* in frames per 1000sec */
- unsigned char vsync_field; /* unknown/odd/even/progressive */
- } u;
- };
-
-
-.. c:type:: video_status
-
-struct video_status
-===================
-
-The VIDEO_GET_STATUS call returns the following structure informing
-about various states of the playback operation.
-
-
-.. code-block:: c
-
- struct video_status {
- int video_blank; /* blank video on freeze? */
- video_play_state_t play_state; /* current state of playback */
- video_stream_source_t stream_source; /* current source (demux/memory) */
- video_format_t video_format; /* current aspect ratio of stream */
- video_displayformat_t display_format;/* selected cropping mode */
- };
-
-If video_blank is set video will be blanked out if the channel is
-changed or if playback is stopped. Otherwise, the last picture will be
-displayed. play_state indicates if the video is currently frozen,
-stopped, or being played back. The stream_source corresponds to the
-selected source for the video stream. It can come either from the
-demultiplexer or from memory. The video_format indicates the aspect
-ratio (one of 4:3 or 16:9) of the currently played video stream.
-Finally, display_format corresponds to the selected cropping mode in
-case the source video format is not the same as the format of the output
-device.
-
-
-.. c:type:: video_still_picture
-
-struct video_still_picture
-==========================
-
-An I-frame displayed via the VIDEO_STILLPICTURE call is passed on
-within the following structure.
-
-
-.. code-block:: c
-
- /* pointer to and size of a single iframe in memory */
- struct video_still_picture {
- char *iFrame; /* pointer to a single iframe in memory */
- int32_t size;
- };
-
-
-.. _video_caps:
-
-video capabilities
-==================
-
-A call to VIDEO_GET_CAPABILITIES returns an unsigned integer with the
-following bits set according to the hardwares capabilities.
-
-
-.. code-block:: c
-
- /* bit definitions for capabilities: */
- /* can the hardware decode MPEG1 and/or MPEG2? */
- #define VIDEO_CAP_MPEG1 1
- #define VIDEO_CAP_MPEG2 2
- /* can you send a system and/or program stream to video device?
- (you still have to open the video and the audio device but only
- send the stream to the video device) */
- #define VIDEO_CAP_SYS 4
- #define VIDEO_CAP_PROG 8
- /* can the driver also handle SPU, NAVI and CSS encoded data?
- (CSS API is not present yet) */
- #define VIDEO_CAP_SPU 16
- #define VIDEO_CAP_NAVI 32
- #define VIDEO_CAP_CSS 64
diff --git a/drivers/staging/media/max96712/max96712.c b/drivers/staging/media/max96712/max96712.c
index ea67bcf69c9d..6bdbccbee05a 100644
--- a/drivers/staging/media/max96712/max96712.c
+++ b/drivers/staging/media/max96712/max96712.c
@@ -242,21 +242,34 @@ static const struct v4l2_subdev_video_ops max96712_video_ops = {
.s_stream = max96712_s_stream,
};
-static int max96712_get_pad_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
+static int max96712_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
{
- format->format.width = 1920;
- format->format.height = 1080;
- format->format.code = MEDIA_BUS_FMT_RGB888_1X24;
- format->format.field = V4L2_FIELD_NONE;
+ static const struct v4l2_mbus_framefmt default_fmt = {
+ .width = 1920,
+ .height = 1080,
+ .code = MEDIA_BUS_FMT_RGB888_1X24,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .field = V4L2_FIELD_NONE,
+ .ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT,
+ .quantization = V4L2_QUANTIZATION_DEFAULT,
+ .xfer_func = V4L2_XFER_FUNC_DEFAULT,
+ };
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_state_get_format(state, 0);
+ *fmt = default_fmt;
return 0;
}
+static const struct v4l2_subdev_internal_ops max96712_internal_ops = {
+ .init_state = max96712_init_state,
+};
+
static const struct v4l2_subdev_pad_ops max96712_pad_ops = {
- .get_fmt = max96712_get_pad_format,
- .set_fmt = max96712_get_pad_format,
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = v4l2_subdev_get_fmt,
};
static const struct v4l2_subdev_ops max96712_subdev_ops = {
@@ -293,6 +306,7 @@ static int max96712_v4l2_register(struct max96712_priv *priv)
long pixel_rate;
int ret;
+ priv->sd.internal_ops = &max96712_internal_ops;
v4l2_i2c_subdev_init(&priv->sd, priv->client, &max96712_subdev_ops);
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
@@ -324,6 +338,11 @@ static int max96712_v4l2_register(struct max96712_priv *priv)
v4l2_set_subdevdata(&priv->sd, priv);
+ priv->sd.state_lock = priv->ctrl_handler.lock;
+ ret = v4l2_subdev_init_finalize(&priv->sd);
+ if (ret)
+ goto error;
+
ret = v4l2_async_register_subdev(&priv->sd);
if (ret < 0) {
dev_err(&priv->client->dev, "Unable to register subdevice\n");
diff --git a/include/media/ipu-bridge.h b/include/media/ipu-bridge.h
index 783bda6d5cc3..16fac765456e 100644
--- a/include/media/ipu-bridge.h
+++ b/include/media/ipu-bridge.h
@@ -3,6 +3,7 @@
#ifndef __IPU_BRIDGE_H
#define __IPU_BRIDGE_H
+#include <linux/mod_devicetable.h>
#include <linux/property.h>
#include <linux/types.h>
#include <media/v4l2-fwnode.h>
diff --git a/include/media/rc-map.h b/include/media/rc-map.h
index 4676545ffd8f..4867eb2f931e 100644
--- a/include/media/rc-map.h
+++ b/include/media/rc-map.h
@@ -290,6 +290,7 @@ struct rc_map *rc_map_get(const char *name);
#define RC_MAP_MSI_DIGIVOX_III "rc-msi-digivox-iii"
#define RC_MAP_MSI_TVANYWHERE "rc-msi-tvanywhere"
#define RC_MAP_MSI_TVANYWHERE_PLUS "rc-msi-tvanywhere-plus"
+#define RC_MAP_MYGICA_UTV3 "rc-mygica-utv3"
#define RC_MAP_NEBULA "rc-nebula"
#define RC_MAP_NEC_TERRATEC_CINERGY_XS "rc-nec-terratec-cinergy-xs"
#define RC_MAP_NORWOOD "rc-norwood"
diff --git a/include/media/tuner.h b/include/media/tuner.h
index a7796e0a3659..c5fd6faabfd6 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -133,6 +133,7 @@
#define TUNER_SONY_BTF_PK467Z 90 /* NTSC_JP */
#define TUNER_SONY_BTF_PB463Z 91 /* NTSC */
#define TUNER_SI2157 92
+#define TUNER_TENA_TNF_931D_DFDR1 93
/* tv card specific */
#define TDA9887_PRESENT (1<<0)
diff --git a/include/media/v4l2-jpeg.h b/include/media/v4l2-jpeg.h
index 2dba843ce3bd..b65658a02e3c 100644
--- a/include/media/v4l2-jpeg.h
+++ b/include/media/v4l2-jpeg.h
@@ -14,6 +14,30 @@
#define V4L2_JPEG_MAX_COMPONENTS 4
#define V4L2_JPEG_MAX_TABLES 4
+/*
+ * Prefixes used to generate huffman table class and destination identifiers as
+ * described below:
+ *
+ * V4L2_JPEG_LUM_HT | V4L2_JPEG_DC_HT : Prefix for Luma DC coefficients
+ * huffman table
+ * V4L2_JPEG_LUM_HT | V4L2_JPEG_AC_HT : Prefix for Luma AC coefficients
+ * huffman table
+ * V4L2_JPEG_CHR_HT | V4L2_JPEG_DC_HT : Prefix for Chroma DC coefficients
+ * huffman table
+ * V4L2_JPEG_CHR_HT | V4L2_JPEG_AC_HT : Prefix for Chroma AC coefficients
+ * huffman table
+ */
+#define V4L2_JPEG_LUM_HT 0x00
+#define V4L2_JPEG_CHR_HT 0x01
+#define V4L2_JPEG_DC_HT 0x00
+#define V4L2_JPEG_AC_HT 0x10
+
+/* Length of reference huffman tables as provided in Table K.3 of ITU-T.81 */
+#define V4L2_JPEG_REF_HT_AC_LEN 178
+#define V4L2_JPEG_REF_HT_DC_LEN 28
+
+/* Array size for 8x8 block of samples or DCT coefficient */
+#define V4L2_JPEG_PIXELS_IN_BLOCK 64
/**
* struct v4l2_jpeg_reference - reference into the JPEG buffer
@@ -154,4 +178,12 @@ int v4l2_jpeg_parse_quantization_tables(void *buf, size_t len, u8 precision,
int v4l2_jpeg_parse_huffman_tables(void *buf, size_t len,
struct v4l2_jpeg_reference *huffman_tables);
+extern const u8 v4l2_jpeg_zigzag_scan_index[V4L2_JPEG_PIXELS_IN_BLOCK];
+extern const u8 v4l2_jpeg_ref_table_luma_qt[V4L2_JPEG_PIXELS_IN_BLOCK];
+extern const u8 v4l2_jpeg_ref_table_chroma_qt[V4L2_JPEG_PIXELS_IN_BLOCK];
+extern const u8 v4l2_jpeg_ref_table_luma_dc_ht[V4L2_JPEG_REF_HT_DC_LEN];
+extern const u8 v4l2_jpeg_ref_table_luma_ac_ht[V4L2_JPEG_REF_HT_AC_LEN];
+extern const u8 v4l2_jpeg_ref_table_chroma_dc_ht[V4L2_JPEG_REF_HT_DC_LEN];
+extern const u8 v4l2_jpeg_ref_table_chroma_ac_ht[V4L2_JPEG_REF_HT_AC_LEN];
+
#endif
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index e30c463d90e5..bd235d325ff9 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -450,6 +450,15 @@ enum v4l2_subdev_pre_streamon_flags {
* already started or stopped subdev. Also see call_s_stream wrapper in
* v4l2-subdev.c.
*
+ * New drivers should instead implement &v4l2_subdev_pad_ops.enable_streams
+ * and &v4l2_subdev_pad_ops.disable_streams operations, and use
+ * v4l2_subdev_s_stream_helper for the &v4l2_subdev_video_ops.s_stream
+ * operation to support legacy users.
+ *
+ * Drivers should also not call the .s_stream() subdev operation directly,
+ * but use the v4l2_subdev_enable_streams() and
+ * v4l2_subdev_disable_streams() helpers.
+ *
* @g_pixelaspect: callback to return the pixelaspect ratio.
*
* @s_rx_buffer: set a host allocated memory buffer for the subdev. The subdev
@@ -681,7 +690,7 @@ struct v4l2_subdev_pad_config {
*
* @pad: pad number
* @stream: stream number
- * @enabled: has the stream been enabled with v4l2_subdev_enable_stream()
+ * @enabled: has the stream been enabled with v4l2_subdev_enable_streams()
* @fmt: &struct v4l2_mbus_framefmt
* @crop: &struct v4l2_rect to be used for crop
* @compose: &struct v4l2_rect to be used for compose
@@ -1041,10 +1050,11 @@ struct v4l2_subdev_platform_data {
* @active_state: Active state for the subdev (NULL for subdevs tracking the
* state internally). Initialized by calling
* v4l2_subdev_init_finalize().
- * @enabled_streams: Bitmask of enabled streams used by
- * v4l2_subdev_enable_streams() and
- * v4l2_subdev_disable_streams() helper functions for fallback
- * cases.
+ * @enabled_pads: Bitmask of enabled pads used by v4l2_subdev_enable_streams()
+ * and v4l2_subdev_disable_streams() helper functions for
+ * fallback cases.
+ * @s_stream_enabled: Tracks whether streaming has been enabled with s_stream.
+ * This is only for call_s_stream() internal use.
*
* Each instance of a subdev driver should create this struct, either
* stand-alone or embedded in a larger struct.
@@ -1092,7 +1102,8 @@ struct v4l2_subdev {
* doesn't support it.
*/
struct v4l2_subdev_state *active_state;
- u64 enabled_streams;
+ u64 enabled_pads;
+ bool s_stream_enabled;
};
@@ -1326,6 +1337,16 @@ void v4l2_subdev_cleanup(struct v4l2_subdev *sd);
#define __v4l2_subdev_state_gen_call(NAME, _1, ARG, ...) \
__v4l2_subdev_state_get_ ## NAME ## ARG
+/*
+ * A macro to constify the return value of the state accessors when the state
+ * parameter is const.
+ */
+#define __v4l2_subdev_state_constify_ret(state, value) \
+ _Generic(state, \
+ const struct v4l2_subdev_state *: (const typeof(*(value)) *)(value), \
+ struct v4l2_subdev_state *: (value) \
+ )
+
/**
* v4l2_subdev_state_get_format() - Get pointer to a stream format
* @state: subdevice state
@@ -1340,16 +1361,21 @@ void v4l2_subdev_cleanup(struct v4l2_subdev *sd);
*/
/*
* Wrap v4l2_subdev_state_get_format(), allowing the function to be called with
- * two or three arguments. The purpose of the __v4l2_subdev_state_get_format()
- * macro below is to come up with the name of the function or macro to call,
- * using the last two arguments (_stream and _pad). The selected function or
- * macro is then called using the arguments specified by the caller. A similar
- * arrangement is used for v4l2_subdev_state_crop() and
- * v4l2_subdev_state_compose() below.
- */
-#define v4l2_subdev_state_get_format(state, pad, ...) \
- __v4l2_subdev_state_gen_call(format, ##__VA_ARGS__, , _pad) \
- (state, pad, ##__VA_ARGS__)
+ * two or three arguments. The purpose of the __v4l2_subdev_state_gen_call()
+ * macro is to come up with the name of the function or macro to call, using
+ * the last two arguments (_stream and _pad). The selected function or macro is
+ * then called using the arguments specified by the caller. The
+ * __v4l2_subdev_state_constify_ret() macro constifies the returned pointer
+ * when the state is const, allowing the state accessors to guarantee
+ * const-correctness in all cases.
+ *
+ * A similar arrangement is used for v4l2_subdev_state_crop(),
+ * v4l2_subdev_state_compose() and v4l2_subdev_state_get_interval() below.
+ */
+#define v4l2_subdev_state_get_format(state, pad, ...) \
+ __v4l2_subdev_state_constify_ret(state, \
+ __v4l2_subdev_state_gen_call(format, ##__VA_ARGS__, , _pad) \
+ ((struct v4l2_subdev_state *)state, pad, ##__VA_ARGS__))
#define __v4l2_subdev_state_get_format_pad(state, pad) \
__v4l2_subdev_state_get_format(state, pad, 0)
struct v4l2_mbus_framefmt *
@@ -1368,9 +1394,10 @@ __v4l2_subdev_state_get_format(struct v4l2_subdev_state *state,
* For stream-unaware drivers the crop rectangle for the corresponding pad is
* returned. If the pad does not exist, NULL is returned.
*/
-#define v4l2_subdev_state_get_crop(state, pad, ...) \
- __v4l2_subdev_state_gen_call(crop, ##__VA_ARGS__, , _pad) \
- (state, pad, ##__VA_ARGS__)
+#define v4l2_subdev_state_get_crop(state, pad, ...) \
+ __v4l2_subdev_state_constify_ret(state, \
+ __v4l2_subdev_state_gen_call(crop, ##__VA_ARGS__, , _pad) \
+ ((struct v4l2_subdev_state *)state, pad, ##__VA_ARGS__))
#define __v4l2_subdev_state_get_crop_pad(state, pad) \
__v4l2_subdev_state_get_crop(state, pad, 0)
struct v4l2_rect *
@@ -1389,9 +1416,10 @@ __v4l2_subdev_state_get_crop(struct v4l2_subdev_state *state, unsigned int pad,
* For stream-unaware drivers the compose rectangle for the corresponding pad is
* returned. If the pad does not exist, NULL is returned.
*/
-#define v4l2_subdev_state_get_compose(state, pad, ...) \
- __v4l2_subdev_state_gen_call(compose, ##__VA_ARGS__, , _pad) \
- (state, pad, ##__VA_ARGS__)
+#define v4l2_subdev_state_get_compose(state, pad, ...) \
+ __v4l2_subdev_state_constify_ret(state, \
+ __v4l2_subdev_state_gen_call(compose, ##__VA_ARGS__, , _pad) \
+ ((struct v4l2_subdev_state *)state, pad, ##__VA_ARGS__))
#define __v4l2_subdev_state_get_compose_pad(state, pad) \
__v4l2_subdev_state_get_compose(state, pad, 0)
struct v4l2_rect *
@@ -1410,9 +1438,10 @@ __v4l2_subdev_state_get_compose(struct v4l2_subdev_state *state,
* For stream-unaware drivers the frame interval for the corresponding pad is
* returned. If the pad does not exist, NULL is returned.
*/
-#define v4l2_subdev_state_get_interval(state, pad, ...) \
- __v4l2_subdev_state_gen_call(interval, ##__VA_ARGS__, , _pad) \
- (state, pad, ##__VA_ARGS__)
+#define v4l2_subdev_state_get_interval(state, pad, ...) \
+ __v4l2_subdev_state_constify_ret(state, \
+ __v4l2_subdev_state_gen_call(interval, ##__VA_ARGS__, , _pad) \
+ ((struct v4l2_subdev_state *)state, pad, ##__VA_ARGS__))
#define __v4l2_subdev_state_get_interval_pad(state, pad) \
__v4l2_subdev_state_get_interval(state, pad, 0)
struct v4l2_fract *
@@ -1954,4 +1983,17 @@ extern const struct v4l2_subdev_ops v4l2_subdev_call_wrappers;
void v4l2_subdev_notify_event(struct v4l2_subdev *sd,
const struct v4l2_event *ev);
+/**
+ * v4l2_subdev_is_streaming() - Returns if the subdevice is streaming
+ * @sd: The subdevice
+ *
+ * v4l2_subdev_is_streaming() tells if the subdevice is currently streaming.
+ * "Streaming" here means whether .s_stream() or .enable_streams() has been
+ * successfully called, and the streaming has not yet been disabled.
+ *
+ * If the subdevice implements .enable_streams() this function must be called
+ * while holding the active state lock.
+ */
+bool v4l2_subdev_is_streaming(struct v4l2_subdev *sd);
+
#endif /* _V4L2_SUBDEV_H */
diff --git a/include/uapi/linux/media/raspberrypi/pisp_be_config.h b/include/uapi/linux/media/raspberrypi/pisp_be_config.h
new file mode 100644
index 000000000000..cbeb714f4d61
--- /dev/null
+++ b/include/uapi/linux/media/raspberrypi/pisp_be_config.h
@@ -0,0 +1,968 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+/*
+ * PiSP Back End configuration definitions.
+ *
+ * Copyright (C) 2021 - Raspberry Pi Ltd
+ *
+ */
+#ifndef _UAPI_PISP_BE_CONFIG_H_
+#define _UAPI_PISP_BE_CONFIG_H_
+
+#include <linux/types.h>
+
+#include "pisp_common.h"
+
+/* byte alignment for inputs */
+#define PISP_BACK_END_INPUT_ALIGN 4u
+/* alignment for compressed inputs */
+#define PISP_BACK_END_COMPRESSED_ALIGN 8u
+/* minimum required byte alignment for outputs */
+#define PISP_BACK_END_OUTPUT_MIN_ALIGN 16u
+/* preferred byte alignment for outputs */
+#define PISP_BACK_END_OUTPUT_MAX_ALIGN 64u
+
+/* minimum allowed tile width anywhere in the pipeline */
+#define PISP_BACK_END_MIN_TILE_WIDTH 16u
+/* minimum allowed tile width anywhere in the pipeline */
+#define PISP_BACK_END_MIN_TILE_HEIGHT 16u
+
+#define PISP_BACK_END_NUM_OUTPUTS 2
+#define PISP_BACK_END_HOG_OUTPUT 1
+
+#define PISP_BACK_END_NUM_TILES 64
+
+enum pisp_be_bayer_enable {
+ PISP_BE_BAYER_ENABLE_INPUT = 0x000001,
+ PISP_BE_BAYER_ENABLE_DECOMPRESS = 0x000002,
+ PISP_BE_BAYER_ENABLE_DPC = 0x000004,
+ PISP_BE_BAYER_ENABLE_GEQ = 0x000008,
+ PISP_BE_BAYER_ENABLE_TDN_INPUT = 0x000010,
+ PISP_BE_BAYER_ENABLE_TDN_DECOMPRESS = 0x000020,
+ PISP_BE_BAYER_ENABLE_TDN = 0x000040,
+ PISP_BE_BAYER_ENABLE_TDN_COMPRESS = 0x000080,
+ PISP_BE_BAYER_ENABLE_TDN_OUTPUT = 0x000100,
+ PISP_BE_BAYER_ENABLE_SDN = 0x000200,
+ PISP_BE_BAYER_ENABLE_BLC = 0x000400,
+ PISP_BE_BAYER_ENABLE_STITCH_INPUT = 0x000800,
+ PISP_BE_BAYER_ENABLE_STITCH_DECOMPRESS = 0x001000,
+ PISP_BE_BAYER_ENABLE_STITCH = 0x002000,
+ PISP_BE_BAYER_ENABLE_STITCH_COMPRESS = 0x004000,
+ PISP_BE_BAYER_ENABLE_STITCH_OUTPUT = 0x008000,
+ PISP_BE_BAYER_ENABLE_WBG = 0x010000,
+ PISP_BE_BAYER_ENABLE_CDN = 0x020000,
+ PISP_BE_BAYER_ENABLE_LSC = 0x040000,
+ PISP_BE_BAYER_ENABLE_TONEMAP = 0x080000,
+ PISP_BE_BAYER_ENABLE_CAC = 0x100000,
+ PISP_BE_BAYER_ENABLE_DEBIN = 0x200000,
+ PISP_BE_BAYER_ENABLE_DEMOSAIC = 0x400000,
+};
+
+enum pisp_be_rgb_enable {
+ PISP_BE_RGB_ENABLE_INPUT = 0x000001,
+ PISP_BE_RGB_ENABLE_CCM = 0x000002,
+ PISP_BE_RGB_ENABLE_SAT_CONTROL = 0x000004,
+ PISP_BE_RGB_ENABLE_YCBCR = 0x000008,
+ PISP_BE_RGB_ENABLE_FALSE_COLOUR = 0x000010,
+ PISP_BE_RGB_ENABLE_SHARPEN = 0x000020,
+ /* Preferred colours would occupy 0x000040 */
+ PISP_BE_RGB_ENABLE_YCBCR_INVERSE = 0x000080,
+ PISP_BE_RGB_ENABLE_GAMMA = 0x000100,
+ PISP_BE_RGB_ENABLE_CSC0 = 0x000200,
+ PISP_BE_RGB_ENABLE_CSC1 = 0x000400,
+ PISP_BE_RGB_ENABLE_DOWNSCALE0 = 0x001000,
+ PISP_BE_RGB_ENABLE_DOWNSCALE1 = 0x002000,
+ PISP_BE_RGB_ENABLE_RESAMPLE0 = 0x008000,
+ PISP_BE_RGB_ENABLE_RESAMPLE1 = 0x010000,
+ PISP_BE_RGB_ENABLE_OUTPUT0 = 0x040000,
+ PISP_BE_RGB_ENABLE_OUTPUT1 = 0x080000,
+ PISP_BE_RGB_ENABLE_HOG = 0x200000
+};
+
+#define PISP_BE_RGB_ENABLE_CSC(i) (PISP_BE_RGB_ENABLE_CSC0 << (i))
+#define PISP_BE_RGB_ENABLE_DOWNSCALE(i) (PISP_BE_RGB_ENABLE_DOWNSCALE0 << (i))
+#define PISP_BE_RGB_ENABLE_RESAMPLE(i) (PISP_BE_RGB_ENABLE_RESAMPLE0 << (i))
+#define PISP_BE_RGB_ENABLE_OUTPUT(i) (PISP_BE_RGB_ENABLE_OUTPUT0 << (i))
+
+/*
+ * We use the enable flags to show when blocks are "dirty", but we need some
+ * extra ones too.
+ */
+enum pisp_be_dirty {
+ PISP_BE_DIRTY_GLOBAL = 0x0001,
+ PISP_BE_DIRTY_SH_FC_COMBINE = 0x0002,
+ PISP_BE_DIRTY_CROP = 0x0004
+};
+
+/**
+ * struct pisp_be_global_config - PiSP global enable bitmaps
+ * @bayer_enables: Bayer input enable flags
+ * @rgb_enables: RGB output enable flags
+ * @bayer_order: Bayer input format ordering
+ * @pad: Padding bytes
+ */
+struct pisp_be_global_config {
+ __u32 bayer_enables;
+ __u32 rgb_enables;
+ __u8 bayer_order;
+ __u8 pad[3];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_input_buffer_config - PiSP Back End input buffer
+ * @addr: Input buffer address
+ */
+struct pisp_be_input_buffer_config {
+ /* low 32 bits followed by high 32 bits (for each of up to 3 planes) */
+ __u32 addr[3][2];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_dpc_config - PiSP Back End DPC config
+ *
+ * Defective Pixel Correction configuration
+ *
+ * @coeff_level: Coefficient for the darkest neighbouring pixel value
+ * @coeff_range: Coefficient for the range of pixels for this Bayer channel
+ * @pad: Padding byte
+ * @flags: DPC configuration flags
+ */
+struct pisp_be_dpc_config {
+ __u8 coeff_level;
+ __u8 coeff_range;
+ __u8 pad;
+#define PISP_BE_DPC_FLAG_FOLDBACK 1
+ __u8 flags;
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_geq_config - PiSP Back End GEQ config
+ *
+ * Green Equalisation configuration
+ *
+ * @offset: Offset value for threshold calculation
+ * @slope_sharper: Slope/Sharper configuration
+ * @min: Minimum value the threshold may have
+ * @max: Maximum value the threshold may have
+ */
+struct pisp_be_geq_config {
+ __u16 offset;
+#define PISP_BE_GEQ_SHARPER (1U << 15)
+#define PISP_BE_GEQ_SLOPE ((1 << 10) - 1)
+ /* top bit is the "sharper" flag, slope value is bottom 10 bits */
+ __u16 slope_sharper;
+ __u16 min;
+ __u16 max;
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_tdn_input_buffer_config - PiSP Back End TDN input buffer
+ * @addr: TDN input buffer address
+ */
+struct pisp_be_tdn_input_buffer_config {
+ /* low 32 bits followed by high 32 bits */
+ __u32 addr[2];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_tdn_config - PiSP Back End TDN config
+ *
+ * Temporal Denoise configuration
+ *
+ * @black_level: Black level value subtracted from pixels
+ * @ratio: Multiplier for the LTA input frame
+ * @noise_constant: Constant offset value used in noise estimation
+ * @noise_slope: Noise estimation multiplier
+ * @threshold: Threshold for TDN operations
+ * @reset: Disable TDN operations
+ * @pad: Padding byte
+ */
+struct pisp_be_tdn_config {
+ __u16 black_level;
+ __u16 ratio;
+ __u16 noise_constant;
+ __u16 noise_slope;
+ __u16 threshold;
+ __u8 reset;
+ __u8 pad;
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_tdn_output_buffer_config - PiSP Back End TDN output buffer
+ * @addr: TDN output buffer address
+ */
+struct pisp_be_tdn_output_buffer_config {
+ /* low 32 bits followed by high 32 bits */
+ __u32 addr[2];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_sdn_config - PiSP Back End SDN config
+ *
+ * Spatial Denoise configuration
+ *
+ * @black_level: Black level subtracted from pixel for noise estimation
+ * @leakage: Proportion of the original undenoised value to mix in
+ * denoised output
+ * @pad: Padding byte
+ * @noise_constant: Noise constant used for noise estimation
+ * @noise_slope: Noise slope value used for noise estimation
+ * @noise_constant2: Second noise constant used for noise estimation
+ * @noise_slope2: Second slope value used for noise estimation
+ */
+struct pisp_be_sdn_config {
+ __u16 black_level;
+ __u8 leakage;
+ __u8 pad;
+ __u16 noise_constant;
+ __u16 noise_slope;
+ __u16 noise_constant2;
+ __u16 noise_slope2;
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_stitch_input_buffer_config - PiSP Back End Stitch input
+ * @addr: Stitch input buffer address
+ */
+struct pisp_be_stitch_input_buffer_config {
+ /* low 32 bits followed by high 32 bits */
+ __u32 addr[2];
+} __attribute__((packed));
+
+#define PISP_BE_STITCH_STREAMING_LONG 0x8000
+#define PISP_BE_STITCH_EXPOSURE_RATIO_MASK 0x7fff
+
+/**
+ * struct pisp_be_stitch_config - PiSP Back End Stitch config
+ *
+ * Stitch block configuration
+ *
+ * @threshold_lo: Low threshold value
+ * @threshold_diff_power: Low and high threshold difference
+ * @pad: Padding bytes
+ * @exposure_ratio: Multiplier to convert long exposure pixels into
+ * short exposure pixels
+ * @motion_threshold_256: Motion threshold above which short exposure
+ * pixels are used
+ * @motion_threshold_recip: Reciprocal of motion_threshold_256 value
+ */
+struct pisp_be_stitch_config {
+ __u16 threshold_lo;
+ __u8 threshold_diff_power;
+ __u8 pad;
+
+ /* top bit indicates whether streaming input is the long exposure */
+ __u16 exposure_ratio;
+
+ __u8 motion_threshold_256;
+ __u8 motion_threshold_recip;
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_stitch_output_buffer_config - PiSP Back End Stitch output
+ * @addr: Stitch input buffer address
+ */
+struct pisp_be_stitch_output_buffer_config {
+ /* low 32 bits followed by high 32 bits */
+ __u32 addr[2];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_cdn_config - PiSP Back End CDN config
+ *
+ * Colour Denoise configuration
+ *
+ * @thresh: Constant for noise estimation
+ * @iir_strength: Relative strength of the IIR part of the filter
+ * @g_adjust: Proportion of the change assigned to the G channel
+ */
+struct pisp_be_cdn_config {
+ __u16 thresh;
+ __u8 iir_strength;
+ __u8 g_adjust;
+} __attribute__((packed));
+
+#define PISP_BE_LSC_LOG_GRID_SIZE 5
+#define PISP_BE_LSC_GRID_SIZE (1 << PISP_BE_LSC_LOG_GRID_SIZE)
+#define PISP_BE_LSC_STEP_PRECISION 18
+
+/**
+ * struct pisp_be_lsc_config - PiSP Back End LSC config
+ *
+ * Lens Shading Correction configuration
+ *
+ * @grid_step_x: Reciprocal of cell size width
+ * @grid_step_y: Reciprocal of cell size height
+ * @lut_packed: Jointly-coded RGB gains for each LSC grid
+ */
+struct pisp_be_lsc_config {
+ /* (1<<18) / grid_cell_width */
+ __u16 grid_step_x;
+ /* (1<<18) / grid_cell_height */
+ __u16 grid_step_y;
+ /* RGB gains jointly encoded in 32 bits */
+#define PISP_BE_LSC_LUT_SIZE (PISP_BE_LSC_GRID_SIZE + 1)
+ __u32 lut_packed[PISP_BE_LSC_LUT_SIZE][PISP_BE_LSC_LUT_SIZE];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_lsc_extra - PiSP Back End LSC Extra config
+ * @offset_x: Horizontal offset into the LSC table of this tile
+ * @offset_y: Vertical offset into the LSC table of this tile
+ */
+struct pisp_be_lsc_extra {
+ __u16 offset_x;
+ __u16 offset_y;
+} __attribute__((packed));
+
+#define PISP_BE_CAC_LOG_GRID_SIZE 3
+#define PISP_BE_CAC_GRID_SIZE (1 << PISP_BE_CAC_LOG_GRID_SIZE)
+#define PISP_BE_CAC_STEP_PRECISION 20
+
+/**
+ * struct pisp_be_cac_config - PiSP Back End CAC config
+ *
+ * Chromatic Aberration Correction config
+ *
+ * @grid_step_x: Reciprocal of cell size width
+ * @grid_step_y: Reciprocal of cell size height
+ * @lut: Pixel shift for the CAC grid
+ */
+struct pisp_be_cac_config {
+ /* (1<<20) / grid_cell_width */
+ __u16 grid_step_x;
+ /* (1<<20) / grid_cell_height */
+ __u16 grid_step_y;
+ /* [gridy][gridx][rb][xy] */
+#define PISP_BE_CAC_LUT_SIZE (PISP_BE_CAC_GRID_SIZE + 1)
+ __s8 lut[PISP_BE_CAC_LUT_SIZE][PISP_BE_CAC_LUT_SIZE][2][2];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_cac_extra - PiSP Back End CAC extra config
+ * @offset_x: Horizontal offset into the CAC table of this tile
+ * @offset_y: Horizontal offset into the CAC table of this tile
+ */
+struct pisp_be_cac_extra {
+ __u16 offset_x;
+ __u16 offset_y;
+} __attribute__((packed));
+
+#define PISP_BE_DEBIN_NUM_COEFFS 4
+
+/**
+ * struct pisp_be_debin_config - PiSP Back End Debin config
+ *
+ * Debinning configuration
+ *
+ * @coeffs: Filter coefficients for debinning
+ * @h_enable: Horizontal debinning enable
+ * @v_enable: Vertical debinning enable
+ * @pad: Padding bytes
+ */
+struct pisp_be_debin_config {
+ __s8 coeffs[PISP_BE_DEBIN_NUM_COEFFS];
+ __s8 h_enable;
+ __s8 v_enable;
+ __s8 pad[2];
+} __attribute__((packed));
+
+#define PISP_BE_TONEMAP_LUT_SIZE 64
+
+/**
+ * struct pisp_be_tonemap_config - PiSP Back End Tonemap config
+ *
+ * Tonemapping configuration
+ *
+ * @detail_constant: Constant value for threshold calculation
+ * @detail_slope: Slope value for threshold calculation
+ * @iir_strength: Relative strength of the IIR fiter
+ * @strength: Strength factor
+ * @lut: Look-up table for tonemap curve
+ */
+struct pisp_be_tonemap_config {
+ __u16 detail_constant;
+ __u16 detail_slope;
+ __u16 iir_strength;
+ __u16 strength;
+ __u32 lut[PISP_BE_TONEMAP_LUT_SIZE];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_demosaic_config - PiSP Back End Demosaic config
+ *
+ * Demosaic configuration
+ *
+ * @sharper: Use other Bayer channels to increase sharpness
+ * @fc_mode: Built-in false colour suppression mode
+ * @pad: Padding bytes
+ */
+struct pisp_be_demosaic_config {
+ __u8 sharper;
+ __u8 fc_mode;
+ __u8 pad[2];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_ccm_config - PiSP Back End CCM config
+ *
+ * Colour Correction Matrix configuration
+ *
+ * @coeffs: Matrix coefficients
+ * @pad: Padding bytes
+ * @offsets: Offsets triplet
+ */
+struct pisp_be_ccm_config {
+ __s16 coeffs[9];
+ __u8 pad[2];
+ __s32 offsets[3];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_sat_control_config - PiSP Back End SAT config
+ *
+ * Saturation Control configuration
+ *
+ * @shift_r: Left shift for Red colour channel
+ * @shift_g: Left shift for Green colour channel
+ * @shift_b: Left shift for Blue colour channel
+ * @pad: Padding byte
+ */
+struct pisp_be_sat_control_config {
+ __u8 shift_r;
+ __u8 shift_g;
+ __u8 shift_b;
+ __u8 pad;
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_false_colour_config - PiSP Back End False Colour config
+ *
+ * False Colour configuration
+ *
+ * @distance: Distance of neighbouring pixels, either 1 or 2
+ * @pad: Padding bytes
+ */
+struct pisp_be_false_colour_config {
+ __u8 distance;
+ __u8 pad[3];
+} __attribute__((packed));
+
+#define PISP_BE_SHARPEN_SIZE 5
+#define PISP_BE_SHARPEN_FUNC_NUM_POINTS 9
+
+/**
+ * struct pisp_be_sharpen_config - PiSP Back End Sharpening config
+ *
+ * Sharpening configuration
+ *
+ * @kernel0: Coefficient for filter 0
+ * @pad0: Padding byte
+ * @kernel1: Coefficient for filter 1
+ * @pad1: Padding byte
+ * @kernel2: Coefficient for filter 2
+ * @pad2: Padding byte
+ * @kernel3: Coefficient for filter 3
+ * @pad3: Padding byte
+ * @kernel4: Coefficient for filter 4
+ * @pad4: Padding byte
+ * @threshold_offset0: Offset for filter 0 response calculation
+ * @threshold_slope0: Slope multiplier for the filter 0 response calculation
+ * @scale0: Scale factor for filter 0 response calculation
+ * @pad5: Padding byte
+ * @threshold_offset1: Offset for filter 0 response calculation
+ * @threshold_slope1: Slope multiplier for the filter 0 response calculation
+ * @scale1: Scale factor for filter 0 response calculation
+ * @pad6: Padding byte
+ * @threshold_offset2: Offset for filter 0 response calculation
+ * @threshold_slope2: Slope multiplier for the filter 0 response calculation
+ * @scale2: Scale factor for filter 0 response calculation
+ * @pad7: Padding byte
+ * @threshold_offset3: Offset for filter 0 response calculation
+ * @threshold_slope3: Slope multiplier for the filter 0 response calculation
+ * @scale3: Scale factor for filter 0 response calculation
+ * @pad8: Padding byte
+ * @threshold_offset4: Offset for filter 0 response calculation
+ * @threshold_slope4: Slope multiplier for the filter 0 response calculation
+ * @scale4: Scale factor for filter 0 response calculation
+ * @pad9: Padding byte
+ * @positive_strength: Factor to scale the positive sharpening strength
+ * @positive_pre_limit: Maximum allowed possible positive sharpening value
+ * @positive_func: Gain factor applied to positive sharpening response
+ * @positive_limit: Final gain factor applied to positive sharpening
+ * @negative_strength: Factor to scale the negative sharpening strength
+ * @negative_pre_limit: Maximum allowed possible negative sharpening value
+ * @negative_func: Gain factor applied to negative sharpening response
+ * @negative_limit: Final gain factor applied to negative sharpening
+ * @enables: Filter enable mask
+ * @white: White output pixel filter mask
+ * @black: Black output pixel filter mask
+ * @grey: Grey output pixel filter mask
+ */
+struct pisp_be_sharpen_config {
+ __s8 kernel0[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
+ __s8 pad0[3];
+ __s8 kernel1[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
+ __s8 pad1[3];
+ __s8 kernel2[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
+ __s8 pad2[3];
+ __s8 kernel3[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
+ __s8 pad3[3];
+ __s8 kernel4[PISP_BE_SHARPEN_SIZE * PISP_BE_SHARPEN_SIZE];
+ __s8 pad4[3];
+ __u16 threshold_offset0;
+ __u16 threshold_slope0;
+ __u16 scale0;
+ __u16 pad5;
+ __u16 threshold_offset1;
+ __u16 threshold_slope1;
+ __u16 scale1;
+ __u16 pad6;
+ __u16 threshold_offset2;
+ __u16 threshold_slope2;
+ __u16 scale2;
+ __u16 pad7;
+ __u16 threshold_offset3;
+ __u16 threshold_slope3;
+ __u16 scale3;
+ __u16 pad8;
+ __u16 threshold_offset4;
+ __u16 threshold_slope4;
+ __u16 scale4;
+ __u16 pad9;
+ __u16 positive_strength;
+ __u16 positive_pre_limit;
+ __u16 positive_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS];
+ __u16 positive_limit;
+ __u16 negative_strength;
+ __u16 negative_pre_limit;
+ __u16 negative_func[PISP_BE_SHARPEN_FUNC_NUM_POINTS];
+ __u16 negative_limit;
+ __u8 enables;
+ __u8 white;
+ __u8 black;
+ __u8 grey;
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_sh_fc_combine_config - PiSP Back End Sharpening and
+ * False Colour config
+ *
+ * Sharpening and False Colour configuration
+ *
+ * @y_factor: Control amount of desaturation of pixels being darkened
+ * @c1_factor: Control amount of brightening of a pixel for the Cb
+ * channel
+ * @c2_factor: Control amount of brightening of a pixel for the Cr
+ * channel
+ * @pad: Padding byte
+ */
+struct pisp_be_sh_fc_combine_config {
+ __u8 y_factor;
+ __u8 c1_factor;
+ __u8 c2_factor;
+ __u8 pad;
+} __attribute__((packed));
+
+#define PISP_BE_GAMMA_LUT_SIZE 64
+
+/**
+ * struct pisp_be_gamma_config - PiSP Back End Gamma configuration
+ * @lut: Gamma curve look-up table
+ */
+struct pisp_be_gamma_config {
+ __u32 lut[PISP_BE_GAMMA_LUT_SIZE];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_crop_config - PiSP Back End Crop config
+ *
+ * Crop configuration
+ *
+ * @offset_x: Number of pixels cropped from the left of the tile
+ * @offset_y: Number of pixels cropped from the top of the tile
+ * @width: Width of the cropped tile output
+ * @height: Height of the cropped tile output
+ */
+struct pisp_be_crop_config {
+ __u16 offset_x, offset_y;
+ __u16 width, height;
+} __attribute__((packed));
+
+#define PISP_BE_RESAMPLE_FILTER_SIZE 96
+
+/**
+ * struct pisp_be_resample_config - PiSP Back End Resampling config
+ *
+ * Resample configuration
+ *
+ * @scale_factor_h: Horizontal scale factor
+ * @scale_factor_v: Vertical scale factor
+ * @coef: Resample coefficients
+ */
+struct pisp_be_resample_config {
+ __u16 scale_factor_h, scale_factor_v;
+ __s16 coef[PISP_BE_RESAMPLE_FILTER_SIZE];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_resample_extra - PiSP Back End Resample config
+ *
+ * Resample configuration
+ *
+ * @scaled_width: Width in pixels of the scaled output
+ * @scaled_height: Height in pixels of the scaled output
+ * @initial_phase_h: Initial horizontal phase
+ * @initial_phase_v: Initial vertical phase
+ */
+struct pisp_be_resample_extra {
+ __u16 scaled_width;
+ __u16 scaled_height;
+ __s16 initial_phase_h[3];
+ __s16 initial_phase_v[3];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_downscale_config - PiSP Back End Downscale config
+ *
+ * Downscale configuration
+ *
+ * @scale_factor_h: Horizontal scale factor
+ * @scale_factor_v: Vertical scale factor
+ * @scale_recip_h: Horizontal reciprocal factor
+ * @scale_recip_v: Vertical reciprocal factor
+ */
+struct pisp_be_downscale_config {
+ __u16 scale_factor_h;
+ __u16 scale_factor_v;
+ __u16 scale_recip_h;
+ __u16 scale_recip_v;
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_downscale_extra - PiSP Back End Downscale Extra config
+ * @scaled_width: Scaled image width
+ * @scaled_height: Scaled image height
+ */
+struct pisp_be_downscale_extra {
+ __u16 scaled_width;
+ __u16 scaled_height;
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_hog_config - PiSP Back End HOG config
+ *
+ * Histogram of Oriented Gradients configuration
+ *
+ * @compute_signed: Set 0 for unsigned gradients, 1 for signed
+ * @channel_mix: Channels proportions to use
+ * @stride: Stride in bytes between blocks directly below
+ */
+struct pisp_be_hog_config {
+ __u8 compute_signed;
+ __u8 channel_mix[3];
+ __u32 stride;
+} __attribute__((packed));
+
+struct pisp_be_axi_config {
+ __u8 r_qos; /* Read QoS */
+ __u8 r_cache_prot; /* Read { prot[2:0], cache[3:0] } */
+ __u8 w_qos; /* Write QoS */
+ __u8 w_cache_prot; /* Write { prot[2:0], cache[3:0] } */
+} __attribute__((packed));
+
+/**
+ * enum pisp_be_transform - PiSP Back End Transform flags
+ * @PISP_BE_TRANSFORM_NONE: No transform
+ * @PISP_BE_TRANSFORM_HFLIP: Horizontal flip
+ * @PISP_BE_TRANSFORM_VFLIP: Vertical flip
+ * @PISP_BE_TRANSFORM_ROT180: 180 degress rotation
+ */
+enum pisp_be_transform {
+ PISP_BE_TRANSFORM_NONE = 0x0,
+ PISP_BE_TRANSFORM_HFLIP = 0x1,
+ PISP_BE_TRANSFORM_VFLIP = 0x2,
+ PISP_BE_TRANSFORM_ROT180 =
+ (PISP_BE_TRANSFORM_HFLIP | PISP_BE_TRANSFORM_VFLIP)
+};
+
+struct pisp_be_output_format_config {
+ struct pisp_image_format_config image;
+ __u8 transform;
+ __u8 pad[3];
+ __u16 lo;
+ __u16 hi;
+ __u16 lo2;
+ __u16 hi2;
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_output_buffer_config - PiSP Back End Output buffer
+ * @addr: Output buffer address
+ */
+struct pisp_be_output_buffer_config {
+ /* low 32 bits followed by high 32 bits (for each of 3 planes) */
+ __u32 addr[3][2];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_hog_buffer_config - PiSP Back End HOG buffer
+ * @addr: HOG buffer address
+ */
+struct pisp_be_hog_buffer_config {
+ /* low 32 bits followed by high 32 bits */
+ __u32 addr[2];
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_config - RaspberryPi PiSP Back End Processing configuration
+ *
+ * @input_buffer: Input buffer addresses
+ * @tdn_input_buffer: TDN input buffer addresses
+ * @stitch_input_buffer: Stitch input buffer addresses
+ * @tdn_output_buffer: TDN output buffer addresses
+ * @stitch_output_buffer: Stitch output buffer addresses
+ * @output_buffer: Output buffers addresses
+ * @hog_buffer: HOG buffer addresses
+ * @global: Global PiSP configuration
+ * @input_format: Input image format
+ * @decompress: Decompress configuration
+ * @dpc: Defective Pixel Correction configuration
+ * @geq: Green Equalisation configuration
+ * @tdn_input_format: Temporal Denoise input format
+ * @tdn_decompress: Temporal Denoise decompress configuration
+ * @tdn: Temporal Denoise configuration
+ * @tdn_compress: Temporal Denoise compress configuration
+ * @tdn_output_format: Temporal Denoise output format
+ * @sdn: Spatial Denoise configuration
+ * @blc: Black Level Correction configuration
+ * @stitch_compress: Stitch compress configuration
+ * @stitch_output_format: Stitch output format
+ * @stitch_input_format: Stitch input format
+ * @stitch_decompress: Stitch decompress configuration
+ * @stitch: Stitch configuration
+ * @lsc: Lens Shading Correction configuration
+ * @wbg: White Balance Gain configuration
+ * @cdn: Colour Denoise configuration
+ * @cac: Colour Aberration Correction configuration
+ * @debin: Debinning configuration
+ * @tonemap: Tonemapping configuration
+ * @demosaic: Demosaicing configuration
+ * @ccm: Colour Correction Matrix configuration
+ * @sat_control: Saturation Control configuration
+ * @ycbcr: YCbCr colour correction configuration
+ * @sharpen: Sharpening configuration
+ * @false_colour: False colour correction
+ * @sh_fc_combine: Sharpening and False Colour correction
+ * @ycbcr_inverse: Inverse YCbCr colour correction
+ * @gamma: Gamma curve configuration
+ * @csc: Color Space Conversion configuration
+ * @downscale: Downscale configuration
+ * @resample: Resampling configuration
+ * @output_format: Output format configuration
+ * @hog: HOG configuration
+ * @axi: AXI bus configuration
+ * @lsc_extra: LSC extra info
+ * @cac_extra: CAC extra info
+ * @downscale_extra: Downscaler extra info
+ * @resample_extra: Resample extra info
+ * @crop: Crop configuration
+ * @hog_format: HOG format info
+ * @dirty_flags_bayer: Bayer enable dirty flags
+ * (:c:type:`pisp_be_bayer_enable`)
+ * @dirty_flags_rgb: RGB enable dirty flags
+ * (:c:type:`pisp_be_rgb_enable`)
+ * @dirty_flags_extra: Extra dirty flags
+ */
+struct pisp_be_config {
+ /* I/O configuration: */
+ struct pisp_be_input_buffer_config input_buffer;
+ struct pisp_be_tdn_input_buffer_config tdn_input_buffer;
+ struct pisp_be_stitch_input_buffer_config stitch_input_buffer;
+ struct pisp_be_tdn_output_buffer_config tdn_output_buffer;
+ struct pisp_be_stitch_output_buffer_config stitch_output_buffer;
+ struct pisp_be_output_buffer_config
+ output_buffer[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_hog_buffer_config hog_buffer;
+ /* Processing configuration: */
+ struct pisp_be_global_config global;
+ struct pisp_image_format_config input_format;
+ struct pisp_decompress_config decompress;
+ struct pisp_be_dpc_config dpc;
+ struct pisp_be_geq_config geq;
+ struct pisp_image_format_config tdn_input_format;
+ struct pisp_decompress_config tdn_decompress;
+ struct pisp_be_tdn_config tdn;
+ struct pisp_compress_config tdn_compress;
+ struct pisp_image_format_config tdn_output_format;
+ struct pisp_be_sdn_config sdn;
+ struct pisp_bla_config blc;
+ struct pisp_compress_config stitch_compress;
+ struct pisp_image_format_config stitch_output_format;
+ struct pisp_image_format_config stitch_input_format;
+ struct pisp_decompress_config stitch_decompress;
+ struct pisp_be_stitch_config stitch;
+ struct pisp_be_lsc_config lsc;
+ struct pisp_wbg_config wbg;
+ struct pisp_be_cdn_config cdn;
+ struct pisp_be_cac_config cac;
+ struct pisp_be_debin_config debin;
+ struct pisp_be_tonemap_config tonemap;
+ struct pisp_be_demosaic_config demosaic;
+ struct pisp_be_ccm_config ccm;
+ struct pisp_be_sat_control_config sat_control;
+ struct pisp_be_ccm_config ycbcr;
+ struct pisp_be_sharpen_config sharpen;
+ struct pisp_be_false_colour_config false_colour;
+ struct pisp_be_sh_fc_combine_config sh_fc_combine;
+ struct pisp_be_ccm_config ycbcr_inverse;
+ struct pisp_be_gamma_config gamma;
+ struct pisp_be_ccm_config csc[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_downscale_config downscale[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_resample_config resample[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_output_format_config
+ output_format[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_hog_config hog;
+ struct pisp_be_axi_config axi;
+ /* Non-register fields: */
+ struct pisp_be_lsc_extra lsc_extra;
+ struct pisp_be_cac_extra cac_extra;
+ struct pisp_be_downscale_extra
+ downscale_extra[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_resample_extra resample_extra[PISP_BACK_END_NUM_OUTPUTS];
+ struct pisp_be_crop_config crop;
+ struct pisp_image_format_config hog_format;
+ __u32 dirty_flags_bayer; /* these use pisp_be_bayer_enable */
+ __u32 dirty_flags_rgb; /* use pisp_be_rgb_enable */
+ __u32 dirty_flags_extra; /* these use pisp_be_dirty_t */
+} __attribute__((packed));
+
+/**
+ * enum pisp_tile_edge - PiSP Back End Tile position
+ * @PISP_LEFT_EDGE: Left edge tile
+ * @PISP_RIGHT_EDGE: Right edge tile
+ * @PISP_TOP_EDGE: Top edge tile
+ * @PISP_BOTTOM_EDGE: Bottom edge tile
+ */
+enum pisp_tile_edge {
+ PISP_LEFT_EDGE = (1 << 0),
+ PISP_RIGHT_EDGE = (1 << 1),
+ PISP_TOP_EDGE = (1 << 2),
+ PISP_BOTTOM_EDGE = (1 << 3)
+};
+
+/**
+ * struct pisp_tile - Raspberry Pi PiSP Back End tile configuration
+ *
+ * Tile parameters: each set of tile parameters is a 160-bytes block of data
+ * which contains the tile processing parameters.
+ *
+ * @edge: Edge tile flag
+ * @pad0: Padding bytes
+ * @input_addr_offset: Top-left pixel offset, in bytes
+ * @input_addr_offset2: Top-left pixel offset, in bytes for the second/
+ * third image planes
+ * @input_offset_x: Horizontal offset in pixels of this tile in the
+ * input image
+ * @input_offset_y: Vertical offset in pixels of this tile in the
+ * input image
+ * @input_width: Width in pixels of this tile
+ * @input_height: Height in pixels of the this tile
+ * @tdn_input_addr_offset: TDN input image offset, in bytes
+ * @tdn_output_addr_offset: TDN output image offset, in bytes
+ * @stitch_input_addr_offset: Stitch input image offset, in bytes
+ * @stitch_output_addr_offset: Stitch output image offset, in bytes
+ * @lsc_grid_offset_x: Horizontal offset in the LSC table for this tile
+ * @lsc_grid_offset_y: Vertical offset in the LSC table for this tile
+ * @cac_grid_offset_x: Horizontal offset in the CAC table for this tile
+ * @cac_grid_offset_y: Horizontal offset in the CAC table for this tile
+ * @crop_x_start: Number of pixels cropped from the left of the
+ * tile
+ * @crop_x_end: Number of pixels cropped from the right of the
+ * tile
+ * @crop_y_start: Number of pixels cropped from the top of the
+ * tile
+ * @crop_y_end: Number of pixels cropped from the bottom of the
+ * tile
+ * @downscale_phase_x: Initial horizontal phase in pixels
+ * @downscale_phase_y: Initial vertical phase in pixels
+ * @resample_in_width: Width in pixels of the tile entering the
+ * Resample block
+ * @resample_in_height: Height in pixels of the tile entering the
+ * Resample block
+ * @resample_phase_x: Initial horizontal phase for the Resample block
+ * @resample_phase_y: Initial vertical phase for the Resample block
+ * @output_offset_x: Horizontal offset in pixels where the tile will
+ * be written into the output image
+ * @output_offset_y: Vertical offset in pixels where the tile will be
+ * written into the output image
+ * @output_width: Width in pixels in the output image of this tile
+ * @output_height: Height in pixels in the output image of this tile
+ * @output_addr_offset: Offset in bytes into the output buffer
+ * @output_addr_offset2: Offset in bytes into the output buffer for the
+ * second and third plane
+ * @output_hog_addr_offset: Offset in bytes into the HOG buffer where
+ * results of this tile are to be written
+ */
+struct pisp_tile {
+ __u8 edge; /* enum pisp_tile_edge */
+ __u8 pad0[3];
+ /* 4 bytes */
+ __u32 input_addr_offset;
+ __u32 input_addr_offset2;
+ __u16 input_offset_x;
+ __u16 input_offset_y;
+ __u16 input_width;
+ __u16 input_height;
+ /* 20 bytes */
+ __u32 tdn_input_addr_offset;
+ __u32 tdn_output_addr_offset;
+ __u32 stitch_input_addr_offset;
+ __u32 stitch_output_addr_offset;
+ /* 36 bytes */
+ __u32 lsc_grid_offset_x;
+ __u32 lsc_grid_offset_y;
+ /* 44 bytes */
+ __u32 cac_grid_offset_x;
+ __u32 cac_grid_offset_y;
+ /* 52 bytes */
+ __u16 crop_x_start[PISP_BACK_END_NUM_OUTPUTS];
+ __u16 crop_x_end[PISP_BACK_END_NUM_OUTPUTS];
+ __u16 crop_y_start[PISP_BACK_END_NUM_OUTPUTS];
+ __u16 crop_y_end[PISP_BACK_END_NUM_OUTPUTS];
+ /* 68 bytes */
+ /* Ordering is planes then branches */
+ __u16 downscale_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS];
+ __u16 downscale_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS];
+ /* 92 bytes */
+ __u16 resample_in_width[PISP_BACK_END_NUM_OUTPUTS];
+ __u16 resample_in_height[PISP_BACK_END_NUM_OUTPUTS];
+ /* 100 bytes */
+ /* Ordering is planes then branches */
+ __u16 resample_phase_x[3 * PISP_BACK_END_NUM_OUTPUTS];
+ __u16 resample_phase_y[3 * PISP_BACK_END_NUM_OUTPUTS];
+ /* 124 bytes */
+ __u16 output_offset_x[PISP_BACK_END_NUM_OUTPUTS];
+ __u16 output_offset_y[PISP_BACK_END_NUM_OUTPUTS];
+ __u16 output_width[PISP_BACK_END_NUM_OUTPUTS];
+ __u16 output_height[PISP_BACK_END_NUM_OUTPUTS];
+ /* 140 bytes */
+ __u32 output_addr_offset[PISP_BACK_END_NUM_OUTPUTS];
+ __u32 output_addr_offset2[PISP_BACK_END_NUM_OUTPUTS];
+ /* 156 bytes */
+ __u32 output_hog_addr_offset;
+ /* 160 bytes */
+} __attribute__((packed));
+
+/**
+ * struct pisp_be_tiles_config - Raspberry Pi PiSP Back End configuration
+ * @tiles: Tile descriptors
+ * @num_tiles: Number of tiles
+ * @config: PiSP Back End configuration
+ */
+struct pisp_be_tiles_config {
+ struct pisp_be_config config;
+ struct pisp_tile tiles[PISP_BACK_END_NUM_TILES];
+ __u32 num_tiles;
+} __attribute__((packed));
+
+#endif /* _UAPI_PISP_BE_CONFIG_H_ */
diff --git a/include/uapi/linux/media/raspberrypi/pisp_common.h b/include/uapi/linux/media/raspberrypi/pisp_common.h
new file mode 100644
index 000000000000..cbdccfed1261
--- /dev/null
+++ b/include/uapi/linux/media/raspberrypi/pisp_common.h
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
+/*
+ * RP1 PiSP common definitions.
+ *
+ * Copyright (C) 2021 - Raspberry Pi Ltd.
+ *
+ */
+#ifndef _UAPI_PISP_COMMON_H_
+#define _UAPI_PISP_COMMON_H_
+
+#include <linux/types.h>
+
+struct pisp_image_format_config {
+ /* size in pixels */
+ __u16 width;
+ __u16 height;
+ /* must match struct pisp_image_format below */
+ __u32 format;
+ __s32 stride;
+ /* some planar image formats will need a second stride */
+ __s32 stride2;
+} __attribute__((packed));
+
+enum pisp_bayer_order {
+ /*
+ * Note how bayer_order&1 tells you if G is on the even pixels of the
+ * checkerboard or not, and bayer_order&2 tells you if R is on the even
+ * rows or is swapped with B. Note that if the top (of the 8) bits is
+ * set, this denotes a monochrome or greyscale image, and the lower bits
+ * should all be ignored.
+ */
+ PISP_BAYER_ORDER_RGGB = 0,
+ PISP_BAYER_ORDER_GBRG = 1,
+ PISP_BAYER_ORDER_BGGR = 2,
+ PISP_BAYER_ORDER_GRBG = 3,
+ PISP_BAYER_ORDER_GREYSCALE = 128
+};
+
+enum pisp_image_format {
+ /*
+ * Precise values are mostly tbd. Generally these will be portmanteau
+ * values comprising bit fields and flags. This format must be shared
+ * throughout the PiSP.
+ */
+ PISP_IMAGE_FORMAT_BPS_8 = 0x00000000,
+ PISP_IMAGE_FORMAT_BPS_10 = 0x00000001,
+ PISP_IMAGE_FORMAT_BPS_12 = 0x00000002,
+ PISP_IMAGE_FORMAT_BPS_16 = 0x00000003,
+ PISP_IMAGE_FORMAT_BPS_MASK = 0x00000003,
+
+ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED = 0x00000000,
+ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR = 0x00000010,
+ PISP_IMAGE_FORMAT_PLANARITY_PLANAR = 0x00000020,
+ PISP_IMAGE_FORMAT_PLANARITY_MASK = 0x00000030,
+
+ PISP_IMAGE_FORMAT_SAMPLING_444 = 0x00000000,
+ PISP_IMAGE_FORMAT_SAMPLING_422 = 0x00000100,
+ PISP_IMAGE_FORMAT_SAMPLING_420 = 0x00000200,
+ PISP_IMAGE_FORMAT_SAMPLING_MASK = 0x00000300,
+
+ PISP_IMAGE_FORMAT_ORDER_NORMAL = 0x00000000,
+ PISP_IMAGE_FORMAT_ORDER_SWAPPED = 0x00001000,
+
+ PISP_IMAGE_FORMAT_SHIFT_0 = 0x00000000,
+ PISP_IMAGE_FORMAT_SHIFT_1 = 0x00010000,
+ PISP_IMAGE_FORMAT_SHIFT_2 = 0x00020000,
+ PISP_IMAGE_FORMAT_SHIFT_3 = 0x00030000,
+ PISP_IMAGE_FORMAT_SHIFT_4 = 0x00040000,
+ PISP_IMAGE_FORMAT_SHIFT_5 = 0x00050000,
+ PISP_IMAGE_FORMAT_SHIFT_6 = 0x00060000,
+ PISP_IMAGE_FORMAT_SHIFT_7 = 0x00070000,
+ PISP_IMAGE_FORMAT_SHIFT_8 = 0x00080000,
+ PISP_IMAGE_FORMAT_SHIFT_MASK = 0x000f0000,
+
+ PISP_IMAGE_FORMAT_BPP_32 = 0x00100000,
+
+ PISP_IMAGE_FORMAT_UNCOMPRESSED = 0x00000000,
+ PISP_IMAGE_FORMAT_COMPRESSION_MODE_1 = 0x01000000,
+ PISP_IMAGE_FORMAT_COMPRESSION_MODE_2 = 0x02000000,
+ PISP_IMAGE_FORMAT_COMPRESSION_MODE_3 = 0x03000000,
+ PISP_IMAGE_FORMAT_COMPRESSION_MASK = 0x03000000,
+
+ PISP_IMAGE_FORMAT_HOG_SIGNED = 0x04000000,
+ PISP_IMAGE_FORMAT_HOG_UNSIGNED = 0x08000000,
+ PISP_IMAGE_FORMAT_INTEGRAL_IMAGE = 0x10000000,
+ PISP_IMAGE_FORMAT_WALLPAPER_ROLL = 0x20000000,
+ PISP_IMAGE_FORMAT_THREE_CHANNEL = 0x40000000,
+
+ /* Lastly a few specific instantiations of the above. */
+ PISP_IMAGE_FORMAT_SINGLE_16 = PISP_IMAGE_FORMAT_BPS_16,
+ PISP_IMAGE_FORMAT_THREE_16 = PISP_IMAGE_FORMAT_BPS_16 |
+ PISP_IMAGE_FORMAT_THREE_CHANNEL
+};
+
+#define PISP_IMAGE_FORMAT_BPS_8(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_8)
+#define PISP_IMAGE_FORMAT_BPS_10(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_10)
+#define PISP_IMAGE_FORMAT_BPS_12(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_12)
+#define PISP_IMAGE_FORMAT_BPS_16(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) == PISP_IMAGE_FORMAT_BPS_16)
+#define PISP_IMAGE_FORMAT_BPS(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) ? \
+ 8 + (2 << (((fmt) & PISP_IMAGE_FORMAT_BPS_MASK) - 1)) : 8)
+#define PISP_IMAGE_FORMAT_SHIFT(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_SHIFT_MASK) / PISP_IMAGE_FORMAT_SHIFT_1)
+#define PISP_IMAGE_FORMAT_THREE_CHANNEL(fmt) \
+ ((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL)
+#define PISP_IMAGE_FORMAT_SINGLE_CHANNEL(fmt) \
+ (!((fmt) & PISP_IMAGE_FORMAT_THREE_CHANNEL))
+#define PISP_IMAGE_FORMAT_COMPRESSED(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_COMPRESSION_MASK) != \
+ PISP_IMAGE_FORMAT_UNCOMPRESSED)
+#define PISP_IMAGE_FORMAT_SAMPLING_444(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
+ PISP_IMAGE_FORMAT_SAMPLING_444)
+#define PISP_IMAGE_FORMAT_SAMPLING_422(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
+ PISP_IMAGE_FORMAT_SAMPLING_422)
+#define PISP_IMAGE_FORMAT_SAMPLING_420(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_SAMPLING_MASK) == \
+ PISP_IMAGE_FORMAT_SAMPLING_420)
+#define PISP_IMAGE_FORMAT_ORDER_NORMAL(fmt) \
+ (!((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED))
+#define PISP_IMAGE_FORMAT_ORDER_SWAPPED(fmt) \
+ ((fmt) & PISP_IMAGE_FORMAT_ORDER_SWAPPED)
+#define PISP_IMAGE_FORMAT_INTERLEAVED(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
+ PISP_IMAGE_FORMAT_PLANARITY_INTERLEAVED)
+#define PISP_IMAGE_FORMAT_SEMIPLANAR(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
+ PISP_IMAGE_FORMAT_PLANARITY_SEMI_PLANAR)
+#define PISP_IMAGE_FORMAT_PLANAR(fmt) \
+ (((fmt) & PISP_IMAGE_FORMAT_PLANARITY_MASK) == \
+ PISP_IMAGE_FORMAT_PLANARITY_PLANAR)
+#define PISP_IMAGE_FORMAT_WALLPAPER(fmt) \
+ ((fmt) & PISP_IMAGE_FORMAT_WALLPAPER_ROLL)
+#define PISP_IMAGE_FORMAT_BPP_32(fmt) ((fmt) & PISP_IMAGE_FORMAT_BPP_32)
+#define PISP_IMAGE_FORMAT_HOG(fmt) \
+ ((fmt) & \
+ (PISP_IMAGE_FORMAT_HOG_SIGNED | PISP_IMAGE_FORMAT_HOG_UNSIGNED))
+
+#define PISP_WALLPAPER_WIDTH 128 /* in bytes */
+
+struct pisp_bla_config {
+ __u16 black_level_r;
+ __u16 black_level_gr;
+ __u16 black_level_gb;
+ __u16 black_level_b;
+ __u16 output_black_level;
+ __u8 pad[2];
+} __attribute__((packed));
+
+struct pisp_wbg_config {
+ __u16 gain_r;
+ __u16 gain_g;
+ __u16 gain_b;
+ __u8 pad[2];
+} __attribute__((packed));
+
+struct pisp_compress_config {
+ /* value subtracted from incoming data */
+ __u16 offset;
+ __u8 pad;
+ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */
+ __u8 mode;
+} __attribute__((packed));
+
+struct pisp_decompress_config {
+ /* value added to reconstructed data */
+ __u16 offset;
+ __u8 pad;
+ /* 1 => Companding; 2 => Delta (recommended); 3 => Combined (for HDR) */
+ __u8 mode;
+} __attribute__((packed));
+
+enum pisp_axi_flags {
+ /*
+ * round down bursts to end at a 32-byte boundary, to align following
+ * bursts
+ */
+ PISP_AXI_FLAG_ALIGN = 128,
+ /* for FE writer: force WSTRB high, to pad output to 16-byte boundary */
+ PISP_AXI_FLAG_PAD = 64,
+ /* for FE writer: Use Output FIFO level to trigger "panic" */
+ PISP_AXI_FLAG_PANIC = 32,
+};
+
+struct pisp_axi_config {
+ /*
+ * burst length minus one, which must be in the range 0:15; OR'd with
+ * flags
+ */
+ __u8 maxlen_flags;
+ /* { prot[2:0], cache[3:0] } fields, echoed on AXI bus */
+ __u8 cache_prot;
+ /* QoS field(s) (4x4 bits for FE writer; 4 bits for other masters) */
+ __u16 qos;
+} __attribute__((packed));
+
+#endif /* _UAPI_PISP_COMMON_H_ */
diff --git a/include/uapi/linux/v4l2-controls.h b/include/uapi/linux/v4l2-controls.h
index 99c3f5e99da7..974fd254e573 100644
--- a/include/uapi/linux/v4l2-controls.h
+++ b/include/uapi/linux/v4l2-controls.h
@@ -898,6 +898,8 @@ enum v4l2_mpeg_video_av1_level {
V4L2_MPEG_VIDEO_AV1_LEVEL_7_3 = 23
};
+#define V4L2_CID_MPEG_VIDEO_AVERAGE_QP (V4L2_CID_CODEC_BASE + 657)
+
/* MPEG-class control IDs specific to the CX2341x driver as defined by V4L2 */
#define V4L2_CID_CODEC_CX2341X_BASE (V4L2_CTRL_CLASS_CODEC | 0x1000)
#define V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE (V4L2_CID_CODEC_CX2341X_BASE+0)
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index fe6b67e83751..4e91362da6da 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -582,6 +582,8 @@ struct v4l2_pix_format {
/* RGB formats (6 or 8 bytes per pixel) */
#define V4L2_PIX_FMT_BGR48_12 v4l2_fourcc('B', '3', '1', '2') /* 48 BGR 12-bit per component */
+#define V4L2_PIX_FMT_BGR48 v4l2_fourcc('B', 'G', 'R', '6') /* 48 BGR 16-bit per component */
+#define V4L2_PIX_FMT_RGB48 v4l2_fourcc('R', 'G', 'B', '6') /* 48 RGB 16-bit per component */
#define V4L2_PIX_FMT_ABGR64_12 v4l2_fourcc('B', '4', '1', '2') /* 64 BGRA 12-bit per component */
/* Grey formats */
@@ -814,6 +816,18 @@ struct v4l2_pix_format {
#define V4L2_PIX_FMT_IPU3_SGRBG10 v4l2_fourcc('i', 'p', '3', 'G') /* IPU3 packed 10-bit GRBG bayer */
#define V4L2_PIX_FMT_IPU3_SRGGB10 v4l2_fourcc('i', 'p', '3', 'r') /* IPU3 packed 10-bit RGGB bayer */
+/* Raspberry Pi PiSP compressed formats. */
+#define V4L2_PIX_FMT_PISP_COMP1_RGGB v4l2_fourcc('P', 'C', '1', 'R') /* PiSP 8-bit mode 1 compressed RGGB bayer */
+#define V4L2_PIX_FMT_PISP_COMP1_GRBG v4l2_fourcc('P', 'C', '1', 'G') /* PiSP 8-bit mode 1 compressed GRBG bayer */
+#define V4L2_PIX_FMT_PISP_COMP1_GBRG v4l2_fourcc('P', 'C', '1', 'g') /* PiSP 8-bit mode 1 compressed GBRG bayer */
+#define V4L2_PIX_FMT_PISP_COMP1_BGGR v4l2_fourcc('P', 'C', '1', 'B') /* PiSP 8-bit mode 1 compressed BGGR bayer */
+#define V4L2_PIX_FMT_PISP_COMP1_MONO v4l2_fourcc('P', 'C', '1', 'M') /* PiSP 8-bit mode 1 compressed monochrome */
+#define V4L2_PIX_FMT_PISP_COMP2_RGGB v4l2_fourcc('P', 'C', '2', 'R') /* PiSP 8-bit mode 2 compressed RGGB bayer */
+#define V4L2_PIX_FMT_PISP_COMP2_GRBG v4l2_fourcc('P', 'C', '2', 'G') /* PiSP 8-bit mode 2 compressed GRBG bayer */
+#define V4L2_PIX_FMT_PISP_COMP2_GBRG v4l2_fourcc('P', 'C', '2', 'g') /* PiSP 8-bit mode 2 compressed GBRG bayer */
+#define V4L2_PIX_FMT_PISP_COMP2_BGGR v4l2_fourcc('P', 'C', '2', 'B') /* PiSP 8-bit mode 2 compressed BGGR bayer */
+#define V4L2_PIX_FMT_PISP_COMP2_MONO v4l2_fourcc('P', 'C', '2', 'M') /* PiSP 8-bit mode 2 compressed monochrome */
+
/* SDR formats - used only for Software Defined Radio devices */
#define V4L2_SDR_FMT_CU8 v4l2_fourcc('C', 'U', '0', '8') /* IQ u8 */
#define V4L2_SDR_FMT_CU16LE v4l2_fourcc('C', 'U', '1', '6') /* IQ u16le */
@@ -841,6 +855,9 @@ struct v4l2_pix_format {
#define V4L2_META_FMT_RK_ISP1_PARAMS v4l2_fourcc('R', 'K', '1', 'P') /* Rockchip ISP1 3A Parameters */
#define V4L2_META_FMT_RK_ISP1_STAT_3A v4l2_fourcc('R', 'K', '1', 'S') /* Rockchip ISP1 3A Statistics */
+/* Vendor specific - used for RaspberryPi PiSP */
+#define V4L2_META_FMT_RPI_BE_CFG v4l2_fourcc('R', 'P', 'B', 'C') /* PiSP BE configuration */
+
#ifdef __KERNEL__
/*
* Line-based metadata formats. Remember to update v4l_fill_fmtdesc() when