summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/cec/core/cec-core.c2
-rw-r--r--drivers/media/cec/platform/Kconfig2
-rw-r--r--drivers/media/cec/platform/cec-gpio/cec-gpio.c4
-rw-r--r--drivers/media/cec/platform/cros-ec/cros-ec-cec.c2
-rw-r--r--drivers/media/cec/platform/meson/ao-cec-g12a.c2
-rw-r--r--drivers/media/cec/platform/meson/ao-cec.c2
-rw-r--r--drivers/media/cec/platform/s5p/s5p_cec.c2
-rw-r--r--drivers/media/cec/platform/seco/seco-cec.c2
-rw-r--r--drivers/media/cec/platform/sti/stih-cec.c2
-rw-r--r--drivers/media/cec/platform/stm32/stm32-cec.c2
-rw-r--r--drivers/media/cec/platform/tegra/tegra_cec.c2
-rw-r--r--drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c6
-rw-r--r--drivers/media/cec/usb/pulse8/pulse8-cec.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_vbi.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_video.c2
-rw-r--r--drivers/media/common/siano/smsdvb-debugfs.c9
-rw-r--r--drivers/media/common/uvc.c8
-rw-r--r--drivers/media/common/v4l2-tpg/v4l2-tpg-core.c3
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c77
-rw-r--r--drivers/media/common/videobuf2/videobuf2-v4l2.c2
-rw-r--r--drivers/media/dvb-core/dvb_frontend.c4
-rw-r--r--drivers/media/dvb-core/dvb_vb2.c8
-rw-r--r--drivers/media/dvb-core/dvbdev.c16
-rw-r--r--drivers/media/dvb-frontends/bcm3510.c2
-rw-r--r--drivers/media/dvb-frontends/cx24116.c7
-rw-r--r--drivers/media/dvb-frontends/dib0090.c4
-rw-r--r--drivers/media/dvb-frontends/dib3000mb.c2
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c4
-rw-r--r--drivers/media/dvb-frontends/stb0899_algo.c2
-rw-r--r--drivers/media/dvb-frontends/stv6111.c2
-rw-r--r--drivers/media/dvb-frontends/tda18271c2dd.c2
-rw-r--r--drivers/media/dvb-frontends/ts2020.c8
-rw-r--r--drivers/media/dvb-frontends/zd1301_demod.c2
-rw-r--r--drivers/media/dvb-frontends/zl10036.c2
-rw-r--r--drivers/media/i2c/adv7180.c3
-rw-r--r--drivers/media/i2c/adv7511-v4l2.c91
-rw-r--r--drivers/media/i2c/adv7604.c123
-rw-r--r--drivers/media/i2c/adv7842.c135
-rw-r--r--drivers/media/i2c/alvium-csi2.c5
-rw-r--r--drivers/media/i2c/ar0521.c4
-rw-r--r--drivers/media/i2c/ds90ub953.c5
-rw-r--r--drivers/media/i2c/ds90ub960.c7
-rw-r--r--drivers/media/i2c/dw9768.c15
-rw-r--r--drivers/media/i2c/gc0308.c4
-rw-r--r--drivers/media/i2c/gc05a2.c10
-rw-r--r--drivers/media/i2c/gc08a3.c10
-rw-r--r--drivers/media/i2c/gc2145.c41
-rw-r--r--drivers/media/i2c/hi556.c2
-rw-r--r--drivers/media/i2c/imx219.c10
-rw-r--r--drivers/media/i2c/imx283.c10
-rw-r--r--drivers/media/i2c/imx290.c40
-rw-r--r--drivers/media/i2c/imx415.c3
-rw-r--r--drivers/media/i2c/max96717.c6
-rw-r--r--drivers/media/i2c/mt9p031.c96
-rw-r--r--drivers/media/i2c/ov01a10.c6
-rw-r--r--drivers/media/i2c/ov08x40.c181
-rw-r--r--drivers/media/i2c/ov2740.c7
-rw-r--r--drivers/media/i2c/ov5640.c2
-rw-r--r--drivers/media/i2c/ov5645.c278
-rw-r--r--drivers/media/i2c/ov5670.c2
-rw-r--r--drivers/media/i2c/ov5675.c4
-rw-r--r--drivers/media/i2c/ov64a40.c10
-rw-r--r--drivers/media/i2c/ov772x.c2
-rw-r--r--drivers/media/i2c/ov7740.c2
-rw-r--r--drivers/media/i2c/ov8856.c2
-rw-r--r--drivers/media/i2c/ov8858.c9
-rw-r--r--drivers/media/i2c/ov9650.c2
-rw-r--r--drivers/media/i2c/ov9734.c2
-rw-r--r--drivers/media/i2c/st-mipid02.c117
-rw-r--r--drivers/media/i2c/tc358743.c40
-rw-r--r--drivers/media/i2c/thp7312.c5
-rw-r--r--drivers/media/i2c/ths7303.c2
-rw-r--r--drivers/media/i2c/vgxy61.c2
-rw-r--r--drivers/media/i2c/video-i2c.c4
-rw-r--r--drivers/media/mc/mc-entity.c14
-rw-r--r--drivers/media/mc/mc-request.c20
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c2
-rw-r--r--drivers/media/pci/bt8xx/bttv-vbi.c2
-rw-r--r--drivers/media/pci/cobalt/cobalt-driver.c2
-rw-r--r--drivers/media/pci/cobalt/cobalt-v4l2.c2
-rw-r--r--drivers/media/pci/cx18/cx18-streams.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-vbi.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c2
-rw-r--r--drivers/media/pci/cx25821/cx25821-video.c2
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c2
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c2
-rw-r--r--drivers/media/pci/cx88/cx88-vbi.c2
-rw-r--r--drivers/media/pci/cx88/cx88-video.c2
-rw-r--r--drivers/media/pci/dt3155/dt3155.c2
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2.c2
-rw-r--r--drivers/media/pci/intel/ipu6/Kconfig10
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-bus.c6
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-buttress.c65
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-buttress.h6
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-cpd.c24
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-dma.c208
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-dma.h34
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-fw-com.c22
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c4
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-queue.c66
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-queue.h1
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys-video.c6
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys.c25
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-isys.h2
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-mmu.c310
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-mmu.h4
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h2
-rw-r--r--drivers/media/pci/intel/ipu6/ipu6.c6
-rw-r--r--drivers/media/pci/mantis/mantis_core.h43
-rw-r--r--drivers/media/pci/mgb4/mgb4_cmt.c2
-rw-r--r--drivers/media/pci/mgb4/mgb4_core.c8
-rw-r--r--drivers/media/pci/mgb4/mgb4_core.h2
-rw-r--r--drivers/media/pci/mgb4/mgb4_vin.c57
-rw-r--r--drivers/media/pci/mgb4/mgb4_vin.h1
-rw-r--r--drivers/media/pci/mgb4/mgb4_vout.c27
-rw-r--r--drivers/media/pci/mgb4/mgb4_vout.h1
-rw-r--r--drivers/media/pci/netup_unidvb/netup_unidvb_spi.c6
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-ts.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c2
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-v4l2.c2
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c2
-rw-r--r--drivers/media/pci/tw5864/tw5864-video.c2
-rw-r--r--drivers/media/pci/tw68/tw68-video.c2
-rw-r--r--drivers/media/pci/tw686x/tw686x-video.c2
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c2
-rw-r--r--drivers/media/platform/allegro-dvt/allegro-core.c8
-rw-r--r--drivers/media/platform/amlogic/meson-ge2d/ge2d.c4
-rw-r--r--drivers/media/platform/amphion/venc.c12
-rw-r--r--drivers/media/platform/amphion/vpu_core.c2
-rw-r--r--drivers/media/platform/amphion/vpu_drv.c4
-rw-r--r--drivers/media/platform/amphion/vpu_v4l2.c4
-rw-r--r--drivers/media/platform/aspeed/aspeed-video.c4
-rw-r--r--drivers/media/platform/atmel/atmel-isi.c4
-rw-r--r--drivers/media/platform/broadcom/bcm2835-unicam.c4
-rw-r--r--drivers/media/platform/cadence/cdns-csi2rx.c2
-rw-r--r--drivers/media/platform/cadence/cdns-csi2tx.c2
-rw-r--r--drivers/media/platform/chips-media/coda/coda-common.c4
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-helper.c37
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-helper.h5
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-hw.c30
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c323
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c315
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu.c52
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpu.h5
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuapi.c33
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuapi.h1
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h27
-rw-r--r--drivers/media/platform/chips-media/wave5/wave5.h3
-rw-r--r--drivers/media/platform/imagination/e5010-jpeg-enc.c4
-rw-r--r--drivers/media/platform/intel/pxa_camera.c4
-rw-r--r--drivers/media/platform/m2m-deinterlace.c4
-rw-r--r--drivers/media/platform/marvell/mcam-core.c4
-rw-r--r--drivers/media/platform/marvell/mmp-driver.c2
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c16
-rw-r--r--drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c11
-rw-r--r--drivers/media/platform/mediatek/mdp/mtk_mdp_core.c2
-rw-r--r--drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c2
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c2
-rw-r--r--drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c2
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c2
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c2
-rw-r--r--drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c2
-rw-r--r--drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c2
-rw-r--r--drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c2
-rw-r--r--drivers/media/platform/mediatek/vpu/mtk_vpu.c2
-rw-r--r--drivers/media/platform/microchip/microchip-csi2dc.c2
-rw-r--r--drivers/media/platform/microchip/microchip-isc-base.c2
-rw-r--r--drivers/media/platform/microchip/microchip-sama5d2-isc.c2
-rw-r--r--drivers/media/platform/microchip/microchip-sama7g5-isc.c2
-rw-r--r--drivers/media/platform/nuvoton/npcm-video.c4
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/iommu.c7
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/v4l2.c14
-rw-r--r--drivers/media/platform/nvidia/tegra-vde/vde.c2
-rw-r--r--drivers/media/platform/nxp/dw100/dw100.c6
-rw-r--r--drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c19
-rw-r--r--drivers/media/platform/nxp/imx-mipi-csis.c2
-rw-r--r--drivers/media/platform/nxp/imx-pxp.c4
-rw-r--r--drivers/media/platform/nxp/imx7-media-csi.c4
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c2
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c2
-rw-r--r--drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c2
-rw-r--r--drivers/media/platform/nxp/imx8mq-mipi-csi2.c2
-rw-r--r--drivers/media/platform/nxp/mx2_emmaprp.c4
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy.c36
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy.h2
-rw-r--r--drivers/media/platform/qcom/camss/camss-ispif.c5
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe-4-1.c10
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.c1
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.c2
-rw-r--r--drivers/media/platform/qcom/camss/camss.c223
-rw-r--r--drivers/media/platform/qcom/camss/camss.h7
-rw-r--r--drivers/media/platform/qcom/venus/core.c37
-rw-r--r--drivers/media/platform/qcom/venus/core.h12
-rw-r--r--drivers/media/platform/qcom/venus/pm_helpers.c44
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c15
-rw-r--r--drivers/media/platform/qcom/venus/vdec.h1
-rw-r--r--drivers/media/platform/qcom/venus/vdec_ctrls.c5
-rw-r--r--drivers/media/platform/qcom/venus/venc.c87
-rw-r--r--drivers/media/platform/qcom/venus/venc.h1
-rw-r--r--drivers/media/platform/qcom/venus/venc_ctrls.c131
-rw-r--r--drivers/media/platform/raspberrypi/Kconfig1
-rw-r--r--drivers/media/platform/raspberrypi/Makefile1
-rw-r--r--drivers/media/platform/raspberrypi/pisp_be/pisp_be.c2
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/Kconfig15
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/Makefile6
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/cfe-fmts.h332
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace.h202
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/cfe.c2509
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/cfe.h43
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/csi2.c586
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/csi2.h89
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/dphy.c181
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/dphy.h27
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c605
-rw-r--r--drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.h53
-rw-r--r--drivers/media/platform/renesas/rcar-csi2.c520
-rw-r--r--drivers/media/platform/renesas/rcar-fcp.c2
-rw-r--r--drivers/media/platform/renesas/rcar-isp.c6
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-core.c3
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-dma.c32
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c43
-rw-r--r--drivers/media/platform/renesas/rcar-vin/rcar-vin.h4
-rw-r--r--drivers/media/platform/renesas/rcar_drif.c6
-rw-r--r--drivers/media/platform/renesas/rcar_fdp1.c4
-rw-r--r--drivers/media/platform/renesas/rcar_jpu.c4
-rw-r--r--drivers/media/platform/renesas/renesas-ceu.c4
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c18
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h80
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h34
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c41
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c85
-rw-r--r--drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c305
-rw-r--r--drivers/media/platform/renesas/sh_vou.c4
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_drv.c2
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_histo.c2
-rw-r--r--drivers/media/platform/renesas/vsp1/vsp1_video.c2
-rw-r--r--drivers/media/platform/rockchip/rga/rga-buf.c2
-rw-r--r--drivers/media/platform/rockchip/rga/rga.c4
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c2
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c2
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-params.c2
-rw-r--r--drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c2
-rw-r--r--drivers/media/platform/samsung/exynos-gsc/gsc-core.c2
-rw-r--r--drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-capture.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-core.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-is.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-lite.c4
-rw-r--r--drivers/media/platform/samsung/exynos4-is/fimc-m2m.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/media-dev.c2
-rw-r--r--drivers/media/platform/samsung/exynos4-is/media-dev.h5
-rw-r--r--drivers/media/platform/samsung/exynos4-is/mipi-csis.c2
-rw-r--r--drivers/media/platform/samsung/s3c-camif/camif-capture.c2
-rw-r--r--drivers/media/platform/samsung/s3c-camif/camif-core.c2
-rw-r--r--drivers/media/platform/samsung/s5p-g2d/g2d.c4
-rw-r--r--drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c21
-rw-r--r--drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c5
-rw-r--r--drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h1
-rw-r--r--drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c19
-rw-r--r--drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h4
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c2
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c2
-rw-r--r--drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c2
-rw-r--r--drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c4
-rw-r--r--drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c2
-rw-r--r--drivers/media/platform/st/sti/delta/delta-v4l2.c6
-rw-r--r--drivers/media/platform/st/sti/hva/hva-v4l2.c4
-rw-r--r--drivers/media/platform/st/stm32/dma2d/dma2d.c4
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmi.c4
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c6
-rw-r--r--drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c2
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c2
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c2
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c2
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c2
-rw-r--r--drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c2
-rw-r--r--drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c2
-rw-r--r--drivers/media/platform/sunxi/sun8i-di/sun8i-di.c4
-rw-r--r--drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c4
-rw-r--r--drivers/media/platform/ti/am437x/am437x-vpfe.c4
-rw-r--r--drivers/media/platform/ti/cal/cal-video.c2
-rw-r--r--drivers/media/platform/ti/cal/cal.c2
-rw-r--r--drivers/media/platform/ti/davinci/vpif.c2
-rw-r--r--drivers/media/platform/ti/davinci/vpif_capture.c4
-rw-r--r--drivers/media/platform/ti/davinci/vpif_display.c4
-rw-r--r--drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c10
-rw-r--r--drivers/media/platform/ti/omap/omap_vout.c4
-rw-r--r--drivers/media/platform/ti/omap/omap_voutdef.h2
-rw-r--r--drivers/media/platform/ti/omap3isp/isp.c2
-rw-r--r--drivers/media/platform/ti/omap3isp/ispvideo.c18
-rw-r--r--drivers/media/platform/ti/vpe/vpe.c4
-rw-r--r--drivers/media/platform/verisilicon/hantro_drv.c2
-rw-r--r--drivers/media/platform/verisilicon/hantro_v4l2.c20
-rw-r--r--drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c3
-rw-r--r--drivers/media/platform/via/via-camera.c4
-rw-r--r--drivers/media/platform/video-mux.c8
-rw-r--r--drivers/media/platform/xilinx/xilinx-csi2rxss.c2
-rw-r--r--drivers/media/platform/xilinx/xilinx-dma.c2
-rw-r--r--drivers/media/platform/xilinx/xilinx-tpg.c16
-rw-r--r--drivers/media/platform/xilinx/xilinx-vipp.c2
-rw-r--r--drivers/media/platform/xilinx/xilinx-vtc.c2
-rw-r--r--drivers/media/radio/radio-aimslab.c2
-rw-r--r--drivers/media/radio/radio-gemtek.c2
-rw-r--r--drivers/media/radio/radio-isa.c2
-rw-r--r--drivers/media/radio/radio-isa.h2
-rw-r--r--drivers/media/radio/radio-miropcm20.c2
-rw-r--r--drivers/media/radio/radio-rtrack2.c2
-rw-r--r--drivers/media/radio/radio-si476x.c2
-rw-r--r--drivers/media/radio/radio-terratec.c2
-rw-r--r--drivers/media/radio/radio-timb.c2
-rw-r--r--drivers/media/radio/radio-wl1273.c2
-rw-r--r--drivers/media/radio/radio-zoltrix.c2
-rw-r--r--drivers/media/radio/si4713/radio-platform-si4713.c2
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c3
-rw-r--r--drivers/media/rc/Kconfig1
-rw-r--r--drivers/media/rc/ati_remote.c6
-rw-r--r--drivers/media/rc/gpio-ir-recv.c2
-rw-r--r--drivers/media/rc/gpio-ir-tx.c4
-rw-r--r--drivers/media/rc/img-ir/img-ir-core.c2
-rw-r--r--drivers/media/rc/ir-hix5hd2.c2
-rw-r--r--drivers/media/rc/lirc_dev.c13
-rw-r--r--drivers/media/rc/meson-ir.c2
-rw-r--r--drivers/media/rc/mtk-cir.c2
-rw-r--r--drivers/media/rc/st_rc.c2
-rw-r--r--drivers/media/rc/sunxi-cir.c2
-rw-r--r--drivers/media/test-drivers/vicodec/vicodec-core.c29
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_bridge.c2
-rw-r--r--drivers/media/test-drivers/vim2m.c4
-rw-r--r--drivers/media/test-drivers/vimc/vimc-capture.c6
-rw-r--r--drivers/media/test-drivers/vimc/vimc-core.c2
-rw-r--r--drivers/media/test-drivers/visl/visl-core.c2
-rw-r--r--drivers/media/test-drivers/visl/visl-video.c22
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.c4
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.h4
-rw-r--r--drivers/media/test-drivers/vivid/vivid-ctrls.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-meta-cap.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-meta-out.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-sdr-cap.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-touch-cap.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vbi-cap.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vbi-out.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.c20
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-out.c2
-rw-r--r--drivers/media/tuners/it913x.c2
-rw-r--r--drivers/media/tuners/mt2063.c2
-rw-r--r--drivers/media/tuners/mxl301rf.c2
-rw-r--r--drivers/media/tuners/mxl5005s.c2
-rw-r--r--drivers/media/tuners/tda18271-fe.c4
-rw-r--r--drivers/media/tuners/tea5761.c4
-rw-r--r--drivers/media/tuners/tea5767.c4
-rw-r--r--drivers/media/usb/airspy/airspy.c4
-rw-r--r--drivers/media/usb/au0828/au0828-vbi.c2
-rw-r--r--drivers/media/usb/au0828/au0828-video.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-avcore.c59
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c6
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h5
-rw-r--r--drivers/media/usb/dvb-usb-v2/anysee.c17
-rw-r--r--drivers/media/usb/dvb-usb/cxusb-analog.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c2
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c2
-rw-r--r--drivers/media/usb/go7007/go7007-v4l2.c2
-rw-r--r--drivers/media/usb/gspca/gspca.c2
-rw-r--r--drivers/media/usb/gspca/ov534.c2
-rw-r--r--drivers/media/usb/hackrf/hackrf.c6
-rw-r--r--drivers/media/usb/msi2500/msi2500.c8
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-io.c4
-rw-r--r--drivers/media/usb/pwc/pwc-if.c4
-rw-r--r--drivers/media/usb/s2255/s2255drv.c2
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c2
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c2
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c148
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c4
-rw-r--r--drivers/media/usb/uvc/uvc_status.c63
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c22
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h10
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls-api.c17
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c16
-rw-r--r--drivers/media/v4l2-core/v4l2-dv-timings.c199
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c3
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c27
390 files changed, 8438 insertions, 2725 deletions
diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c
index 48282d272fe6..ca0db8d457b4 100644
--- a/drivers/media/cec/core/cec-core.c
+++ b/drivers/media/cec/core/cec-core.c
@@ -438,6 +438,6 @@ static void __exit cec_devnode_exit(void)
subsys_initcall(cec_devnode_init);
module_exit(cec_devnode_exit)
-MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
+MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>");
MODULE_DESCRIPTION("Device node registration for cec drivers");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/cec/platform/Kconfig b/drivers/media/cec/platform/Kconfig
index ede81fe331b0..e40413609f53 100644
--- a/drivers/media/cec/platform/Kconfig
+++ b/drivers/media/cec/platform/Kconfig
@@ -99,7 +99,7 @@ config CEC_TEGRA
config CEC_SECO
tristate "SECO Boards HDMI CEC driver"
- depends on X86 || COMPILE_TEST
+ depends on X86 || (COMPILE_TEST && HAS_IOPORT)
depends on PCI && DMI
select CEC_CORE
select CEC_NOTIFIER
diff --git a/drivers/media/cec/platform/cec-gpio/cec-gpio.c b/drivers/media/cec/platform/cec-gpio/cec-gpio.c
index 98dacb0919b6..cf64e8871fe5 100644
--- a/drivers/media/cec/platform/cec-gpio/cec-gpio.c
+++ b/drivers/media/cec/platform/cec-gpio/cec-gpio.c
@@ -279,7 +279,7 @@ MODULE_DEVICE_TABLE(of, cec_gpio_match);
static struct platform_driver cec_gpio_pdrv = {
.probe = cec_gpio_probe,
- .remove_new = cec_gpio_remove,
+ .remove = cec_gpio_remove,
.driver = {
.name = "cec-gpio",
.of_match_table = cec_gpio_match,
@@ -288,6 +288,6 @@ static struct platform_driver cec_gpio_pdrv = {
module_platform_driver(cec_gpio_pdrv);
-MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
+MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>");
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("CEC GPIO driver");
diff --git a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
index 8fbbb4091455..12b73ea0f31d 100644
--- a/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
+++ b/drivers/media/cec/platform/cros-ec/cros-ec-cec.c
@@ -582,7 +582,7 @@ MODULE_DEVICE_TABLE(platform, cros_ec_cec_id);
static struct platform_driver cros_ec_cec_driver = {
.probe = cros_ec_cec_probe,
- .remove_new = cros_ec_cec_remove,
+ .remove = cros_ec_cec_remove,
.driver = {
.name = DRV_NAME,
.pm = &cros_ec_cec_pm_ops,
diff --git a/drivers/media/cec/platform/meson/ao-cec-g12a.c b/drivers/media/cec/platform/meson/ao-cec-g12a.c
index 51294b9b6cd5..41f5b8669cb0 100644
--- a/drivers/media/cec/platform/meson/ao-cec-g12a.c
+++ b/drivers/media/cec/platform/meson/ao-cec-g12a.c
@@ -778,7 +778,7 @@ MODULE_DEVICE_TABLE(of, meson_ao_cec_g12a_of_match);
static struct platform_driver meson_ao_cec_g12a_driver = {
.probe = meson_ao_cec_g12a_probe,
- .remove_new = meson_ao_cec_g12a_remove,
+ .remove = meson_ao_cec_g12a_remove,
.driver = {
.name = "meson-ao-cec-g12a",
.of_match_table = of_match_ptr(meson_ao_cec_g12a_of_match),
diff --git a/drivers/media/cec/platform/meson/ao-cec.c b/drivers/media/cec/platform/meson/ao-cec.c
index 494738daf09a..145efd9af6ac 100644
--- a/drivers/media/cec/platform/meson/ao-cec.c
+++ b/drivers/media/cec/platform/meson/ao-cec.c
@@ -714,7 +714,7 @@ MODULE_DEVICE_TABLE(of, meson_ao_cec_of_match);
static struct platform_driver meson_ao_cec_driver = {
.probe = meson_ao_cec_probe,
- .remove_new = meson_ao_cec_remove,
+ .remove = meson_ao_cec_remove,
.driver = {
.name = "meson-ao-cec",
.of_match_table = meson_ao_cec_of_match,
diff --git a/drivers/media/cec/platform/s5p/s5p_cec.c b/drivers/media/cec/platform/s5p/s5p_cec.c
index 51ab4a80aafe..4a92d3230f66 100644
--- a/drivers/media/cec/platform/s5p/s5p_cec.c
+++ b/drivers/media/cec/platform/s5p/s5p_cec.c
@@ -294,7 +294,7 @@ MODULE_DEVICE_TABLE(of, s5p_cec_match);
static struct platform_driver s5p_cec_pdrv = {
.probe = s5p_cec_probe,
- .remove_new = s5p_cec_remove,
+ .remove = s5p_cec_remove,
.driver = {
.name = CEC_NAME,
.of_match_table = s5p_cec_match,
diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c
index 5d4c5a2cae09..b7bb49f02395 100644
--- a/drivers/media/cec/platform/seco/seco-cec.c
+++ b/drivers/media/cec/platform/seco/seco-cec.c
@@ -778,7 +778,7 @@ static struct platform_driver secocec_driver = {
.pm = SECOCEC_PM_OPS,
},
.probe = secocec_probe,
- .remove_new = secocec_remove,
+ .remove = secocec_remove,
};
module_platform_driver(secocec_driver);
diff --git a/drivers/media/cec/platform/sti/stih-cec.c b/drivers/media/cec/platform/sti/stih-cec.c
index 99978a7c8d9b..49843d576c7c 100644
--- a/drivers/media/cec/platform/sti/stih-cec.c
+++ b/drivers/media/cec/platform/sti/stih-cec.c
@@ -383,7 +383,7 @@ MODULE_DEVICE_TABLE(of, stih_cec_match);
static struct platform_driver stih_cec_pdrv = {
.probe = stih_cec_probe,
- .remove_new = stih_cec_remove,
+ .remove = stih_cec_remove,
.driver = {
.name = CEC_NAME,
.of_match_table = stih_cec_match,
diff --git a/drivers/media/cec/platform/stm32/stm32-cec.c b/drivers/media/cec/platform/stm32/stm32-cec.c
index bda9d254041a..fea2d65acffc 100644
--- a/drivers/media/cec/platform/stm32/stm32-cec.c
+++ b/drivers/media/cec/platform/stm32/stm32-cec.c
@@ -361,7 +361,7 @@ MODULE_DEVICE_TABLE(of, stm32_cec_of_match);
static struct platform_driver stm32_cec_driver = {
.probe = stm32_cec_probe,
- .remove_new = stm32_cec_remove,
+ .remove = stm32_cec_remove,
.driver = {
.name = CEC_NAME,
.of_match_table = stm32_cec_of_match,
diff --git a/drivers/media/cec/platform/tegra/tegra_cec.c b/drivers/media/cec/platform/tegra/tegra_cec.c
index 7c1022cee1e8..3ed50097262f 100644
--- a/drivers/media/cec/platform/tegra/tegra_cec.c
+++ b/drivers/media/cec/platform/tegra/tegra_cec.c
@@ -465,7 +465,7 @@ static struct platform_driver tegra_cec_driver = {
.of_match_table = tegra_cec_of_match,
},
.probe = tegra_cec_probe,
- .remove_new = tegra_cec_remove,
+ .remove = tegra_cec_remove,
#ifdef CONFIG_PM
.suspend = tegra_cec_suspend,
diff --git a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c
index 8526f613a40e..cfbfc4c1b2e6 100644
--- a/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c
+++ b/drivers/media/cec/usb/extron-da-hd-4k-plus/extron-da-hd-4k-plus.c
@@ -348,12 +348,12 @@ static int get_edid_tag_location(const u8 *edid, unsigned int size,
/* Return if not a CTA-861 extension block */
if (size < 256 || edid[0] != 0x02 || edid[1] != 0x03)
- return -1;
+ return -ENOENT;
/* search tag */
d = edid[0x02] & 0x7f;
if (d <= 4)
- return -1;
+ return -ENOENT;
i = 0x04;
end = 0x00 + d;
@@ -371,7 +371,7 @@ static int get_edid_tag_location(const u8 *edid, unsigned int size,
return offset + i;
i += len + 1;
} while (i < end);
- return -1;
+ return -ENOENT;
}
static void extron_edid_crc(u8 *edid)
diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c
index ba67587bd43e..171366fe3544 100644
--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c
+++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c
@@ -685,7 +685,7 @@ static int pulse8_setup(struct pulse8 *pulse8, struct serio *serio,
err = pulse8_send_and_wait(pulse8, cmd, 1, cmd[0], 4);
if (err)
return err;
- date = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
+ date = ((unsigned)data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
dev_info(pulse8->dev, "Firmware build date %ptT\n", &date);
dev_dbg(pulse8->dev, "Persistent config:\n");
diff --git a/drivers/media/common/saa7146/saa7146_vbi.c b/drivers/media/common/saa7146/saa7146_vbi.c
index bb7d81f7eba6..a1854b3dd004 100644
--- a/drivers/media/common/saa7146/saa7146_vbi.c
+++ b/drivers/media/common/saa7146/saa7146_vbi.c
@@ -407,8 +407,6 @@ const struct vb2_ops vbi_qops = {
.buf_cleanup = buf_cleanup,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* ------------------------------------------------------------------ */
diff --git a/drivers/media/common/saa7146/saa7146_video.c b/drivers/media/common/saa7146/saa7146_video.c
index 040489e15ea0..94e1cd4eaedb 100644
--- a/drivers/media/common/saa7146/saa7146_video.c
+++ b/drivers/media/common/saa7146/saa7146_video.c
@@ -681,8 +681,6 @@ const struct vb2_ops video_qops = {
.buf_cleanup = buf_cleanup,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/********************************************************************************/
diff --git a/drivers/media/common/siano/smsdvb-debugfs.c b/drivers/media/common/siano/smsdvb-debugfs.c
index 73990e469df9..d14ba271db50 100644
--- a/drivers/media/common/siano/smsdvb-debugfs.c
+++ b/drivers/media/common/siano/smsdvb-debugfs.c
@@ -398,8 +398,6 @@ void smsdvb_debugfs_release(struct smsdvb_client_t *client)
void smsdvb_debugfs_register(void)
{
- struct dentry *d;
-
/*
* FIXME: This was written to debug Siano USB devices. So, it creates
* the debugfs node under <debugfs>/usb.
@@ -410,12 +408,7 @@ void smsdvb_debugfs_register(void)
* node for sdio-based boards, but this may need some logic at sdio
* subsystem.
*/
- d = debugfs_create_dir("smsdvb", usb_debug_root);
- if (IS_ERR_OR_NULL(d)) {
- pr_err("Couldn't create sysfs node for smsdvb\n");
- return;
- }
- smsdvb_debugfs_usb_root = d;
+ smsdvb_debugfs_usb_root = debugfs_create_dir("smsdvb", usb_debug_root);
}
void smsdvb_debugfs_unregister(void)
diff --git a/drivers/media/common/uvc.c b/drivers/media/common/uvc.c
index c54c2268fee6..1ad4604474ac 100644
--- a/drivers/media/common/uvc.c
+++ b/drivers/media/common/uvc.c
@@ -97,6 +97,10 @@ static const struct uvc_format_desc uvc_fmts[] = {
.fcc = V4L2_PIX_FMT_RGB565,
},
{
+ .guid = UVC_GUID_FORMAT_D3DFMT_R5G6B5,
+ .fcc = V4L2_PIX_FMT_RGB565,
+ },
+ {
.guid = UVC_GUID_FORMAT_BGR3,
.fcc = V4L2_PIX_FMT_BGR24,
},
@@ -121,6 +125,10 @@ static const struct uvc_format_desc uvc_fmts[] = {
.fcc = V4L2_PIX_FMT_Y12I,
},
{
+ .guid = UVC_GUID_FORMAT_Y16I,
+ .fcc = V4L2_PIX_FMT_Y16I,
+ },
+ {
.guid = UVC_GUID_FORMAT_Z16,
.fcc = V4L2_PIX_FMT_Z16,
},
diff --git a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
index 642c48e8c1f5..ded11cd8dbf7 100644
--- a/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
+++ b/drivers/media/common/v4l2-tpg/v4l2-tpg-core.c
@@ -1795,6 +1795,9 @@ static void tpg_precalculate_line(struct tpg_data *tpg)
unsigned p;
unsigned x;
+ if (WARN_ON_ONCE(!tpg->src_width || !tpg->scaled_width))
+ return;
+
switch (tpg->pattern) {
case TPG_PAT_GREEN:
contrast = TPG_COLOR_100_RED;
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index 29a8d876e6c2..c0cc441b5164 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -1482,18 +1482,23 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
}
vb->planes[plane].dbuf_mapped = 1;
}
+ } else {
+ for (plane = 0; plane < vb->num_planes; ++plane)
+ dma_buf_put(planes[plane].dbuf);
+ }
- /*
- * Now that everything is in order, copy relevant information
- * provided by userspace.
- */
- for (plane = 0; plane < vb->num_planes; ++plane) {
- vb->planes[plane].bytesused = planes[plane].bytesused;
- vb->planes[plane].length = planes[plane].length;
- vb->planes[plane].m.fd = planes[plane].m.fd;
- vb->planes[plane].data_offset = planes[plane].data_offset;
- }
+ /*
+ * Now that everything is in order, copy relevant information
+ * provided by userspace.
+ */
+ for (plane = 0; plane < vb->num_planes; ++plane) {
+ vb->planes[plane].bytesused = planes[plane].bytesused;
+ vb->planes[plane].length = planes[plane].length;
+ vb->planes[plane].m.fd = planes[plane].m.fd;
+ vb->planes[plane].data_offset = planes[plane].data_offset;
+ }
+ if (reacquired) {
/*
* Call driver-specific initialization on the newly acquired buffer,
* if provided.
@@ -1503,9 +1508,6 @@ static int __prepare_dmabuf(struct vb2_buffer *vb)
dprintk(q, 1, "buffer initialization failed\n");
goto err_put_vb2_buf;
}
- } else {
- for (plane = 0; plane < vb->num_planes; ++plane)
- dma_buf_put(planes[plane].dbuf);
}
ret = call_vb_qop(vb, buf_prepare, vb);
@@ -2035,7 +2037,10 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
* become ready or for streamoff. Driver's lock is released to
* allow streamoff or qbuf to be called while waiting.
*/
- call_void_qop(q, wait_prepare, q);
+ if (q->ops->wait_prepare)
+ call_void_qop(q, wait_prepare, q);
+ else if (q->lock)
+ mutex_unlock(q->lock);
/*
* All locks have been released, it is safe to sleep now.
@@ -2045,12 +2050,16 @@ static int __vb2_wait_for_done_vb(struct vb2_queue *q, int nonblocking)
!list_empty(&q->done_list) || !q->streaming ||
q->error);
+ if (q->ops->wait_finish)
+ call_void_qop(q, wait_finish, q);
+ else if (q->lock)
+ mutex_lock(q->lock);
+
+ q->waiting_in_dqbuf = 0;
/*
* We need to reevaluate both conditions again after reacquiring
* the locks or return an error if one occurred.
*/
- call_void_qop(q, wait_finish, q);
- q->waiting_in_dqbuf = 0;
if (ret) {
dprintk(q, 1, "sleep was interrupted\n");
return ret;
@@ -2322,7 +2331,7 @@ int vb2_core_streamon(struct vb2_queue *q, unsigned int type)
}
if (q_num_bufs < q->min_queued_buffers) {
- dprintk(q, 1, "need at least %u queued buffers\n",
+ dprintk(q, 1, "need at least %u allocated buffers\n",
q->min_queued_buffers);
return -EINVAL;
}
@@ -2644,6 +2653,14 @@ int vb2_core_queue_init(struct vb2_queue *q)
if (WARN_ON(q->min_reqbufs_allocation > q->max_num_buffers))
return -EINVAL;
+ /* Either both or none are set */
+ if (WARN_ON(!q->ops->wait_prepare ^ !q->ops->wait_finish))
+ return -EINVAL;
+
+ /* Warn if q->lock is NULL and no custom wait_prepare is provided */
+ if (WARN_ON(!q->lock && !q->ops->wait_prepare))
+ return -EINVAL;
+
INIT_LIST_HEAD(&q->queued_list);
INIT_LIST_HEAD(&q->done_list);
spin_lock_init(&q->done_lock);
@@ -3203,10 +3220,17 @@ static int vb2_thread(void *data)
continue;
prequeue--;
} else {
- call_void_qop(q, wait_finish, q);
- if (!threadio->stop)
+ if (!threadio->stop) {
+ if (q->ops->wait_finish)
+ call_void_qop(q, wait_finish, q);
+ else if (q->lock)
+ mutex_lock(q->lock);
ret = vb2_core_dqbuf(q, &index, NULL, 0);
- call_void_qop(q, wait_prepare, q);
+ if (q->ops->wait_prepare)
+ call_void_qop(q, wait_prepare, q);
+ else if (q->lock)
+ mutex_unlock(q->lock);
+ }
dprintk(q, 5, "file io: vb2_dqbuf result: %d\n", ret);
if (!ret)
vb = vb2_get_buffer(q, index);
@@ -3218,12 +3242,19 @@ static int vb2_thread(void *data)
if (vb->state != VB2_BUF_STATE_ERROR)
if (threadio->fnc(vb, threadio->priv))
break;
- call_void_qop(q, wait_finish, q);
if (copy_timestamp)
vb->timestamp = ktime_get_ns();
- if (!threadio->stop)
+ if (!threadio->stop) {
+ if (q->ops->wait_finish)
+ call_void_qop(q, wait_finish, q);
+ else if (q->lock)
+ mutex_lock(q->lock);
ret = vb2_core_qbuf(q, vb, NULL, NULL);
- call_void_qop(q, wait_prepare, q);
+ if (q->ops->wait_prepare)
+ call_void_qop(q, wait_prepare, q);
+ else if (q->lock)
+ mutex_unlock(q->lock);
+ }
if (ret || threadio->stop)
break;
}
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index 293f3d5f1c4e..9201d854dbcc 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -231,7 +231,7 @@ static int vb2_fill_vb2_v4l2_buffer(struct vb2_buffer *vb, struct v4l2_buffer *b
break;
}
- /* Fill in driver-provided information for OUTPUT types */
+ /* Fill in user-provided information for OUTPUT types */
if (V4L2_TYPE_IS_OUTPUT(b->type)) {
/*
* Will have to go up to b->length when API starts
diff --git a/drivers/media/dvb-core/dvb_frontend.c b/drivers/media/dvb-core/dvb_frontend.c
index 4f78f30b3646..a05aa271a1ba 100644
--- a/drivers/media/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb-core/dvb_frontend.c
@@ -443,8 +443,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra
default:
fepriv->auto_step++;
- fepriv->auto_sub_step = -1; /* it'll be incremented to 0 in a moment */
- break;
+ fepriv->auto_sub_step = 0;
+ continue;
}
if (!ready) fepriv->auto_sub_step++;
diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c
index 192a8230c4aa..29edaaff7a5c 100644
--- a/drivers/media/dvb-core/dvb_vb2.c
+++ b/drivers/media/dvb-core/dvb_vb2.c
@@ -366,9 +366,15 @@ int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b)
int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp)
{
struct vb2_queue *q = &ctx->vb_q;
+ struct vb2_buffer *vb2 = vb2_get_buffer(q, exp->index);
int ret;
- ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, q->bufs[exp->index],
+ if (!vb2) {
+ dprintk(1, "[%s] invalid buffer index\n", ctx->name);
+ return -EINVAL;
+ }
+
+ ret = vb2_core_expbuf(&ctx->vb_q, &exp->fd, q->type, vb2,
0, exp->flags);
if (ret) {
dprintk(1, "[%s] index=%d errno=%d\n", ctx->name,
diff --git a/drivers/media/dvb-core/dvbdev.c b/drivers/media/dvb-core/dvbdev.c
index b43695bc51e7..9df7c213716a 100644
--- a/drivers/media/dvb-core/dvbdev.c
+++ b/drivers/media/dvb-core/dvbdev.c
@@ -86,10 +86,15 @@ static DECLARE_RWSEM(minor_rwsem);
static int dvb_device_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev;
+ unsigned int minor = iminor(inode);
+
+ if (minor >= MAX_DVB_MINORS)
+ return -ENODEV;
mutex_lock(&dvbdev_mutex);
down_read(&minor_rwsem);
- dvbdev = dvb_minors[iminor(inode)];
+
+ dvbdev = dvb_minors[minor];
if (dvbdev && dvbdev->fops) {
int err = 0;
@@ -525,7 +530,10 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
for (minor = 0; minor < MAX_DVB_MINORS; minor++)
if (!dvb_minors[minor])
break;
- if (minor == MAX_DVB_MINORS) {
+#else
+ minor = nums2minor(adap->num, type, id);
+#endif
+ if (minor >= MAX_DVB_MINORS) {
if (new_node) {
list_del(&new_node->list_head);
kfree(dvbdevfops);
@@ -538,9 +546,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
mutex_unlock(&dvbdev_register_lock);
return -EINVAL;
}
-#else
- minor = nums2minor(adap->num, type, id);
-#endif
+
dvbdev->minor = minor;
dvb_minors[minor] = dvb_device_get(dvbdev);
up_write(&minor_rwsem);
diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c
index 27f1de21f571..d935fb10e620 100644
--- a/drivers/media/dvb-frontends/bcm3510.c
+++ b/drivers/media/dvb-frontends/bcm3510.c
@@ -729,7 +729,7 @@ static int bcm3510_init_cold(struct bcm3510_state *st)
int ret;
bcm3510_register_value v;
- /* read Acquisation Processor status register and check it is not in RUN mode */
+ /* read Acquisition Processor status register and check it is not in RUN mode */
if ((ret = bcm3510_readB(st,0xa2,&v)) < 0)
return ret;
if (v.APSTAT1_a2.RUN) {
diff --git a/drivers/media/dvb-frontends/cx24116.c b/drivers/media/dvb-frontends/cx24116.c
index 8b978a9f74a4..f5dd3a81725a 100644
--- a/drivers/media/dvb-frontends/cx24116.c
+++ b/drivers/media/dvb-frontends/cx24116.c
@@ -741,6 +741,7 @@ static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
{
struct cx24116_state *state = fe->demodulator_priv;
u8 snr_reading;
+ int ret;
static const u32 snr_tab[] = { /* 10 x Table (rounded up) */
0x00000, 0x0199A, 0x03333, 0x04ccD, 0x06667,
0x08000, 0x0999A, 0x0b333, 0x0cccD, 0x0e667,
@@ -749,7 +750,11 @@ static int cx24116_read_snr_pct(struct dvb_frontend *fe, u16 *snr)
dprintk("%s()\n", __func__);
- snr_reading = cx24116_readreg(state, CX24116_REG_QUALITY0);
+ ret = cx24116_readreg(state, CX24116_REG_QUALITY0);
+ if (ret < 0)
+ return ret;
+
+ snr_reading = ret;
if (snr_reading >= 0xa0 /* 100% */)
*snr = 0xffff;
diff --git a/drivers/media/dvb-frontends/dib0090.c b/drivers/media/dvb-frontends/dib0090.c
index c958bcff026e..6cbbb351d545 100644
--- a/drivers/media/dvb-frontends/dib0090.c
+++ b/drivers/media/dvb-frontends/dib0090.c
@@ -78,7 +78,7 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
#define SOC_8090_P1G_11R1 0x86
#define SOC_8090_P1G_21R1 0x8e
-/* else use thos ones to check */
+/* else use those ones to check */
#define P1A_B 0x0
#define P1C 0x1
#define P1D_E_F 0x3
@@ -1574,7 +1574,7 @@ static int dib0090_reset(struct dvb_frontend *fe)
if (((state->identity.version & 0x1f) >= P1D_E_F) || (state->identity.in_soc))
dib0090_set_EFUSE(state);
- /* Congigure in function of the crystal */
+ /* Configure in function of the crystal */
if (state->config->force_crystal_mode != 0)
dib0090_write_reg(state, 0x14,
state->config->force_crystal_mode & 3);
diff --git a/drivers/media/dvb-frontends/dib3000mb.c b/drivers/media/dvb-frontends/dib3000mb.c
index c598b2a63325..822639f11c04 100644
--- a/drivers/media/dvb-frontends/dib3000mb.c
+++ b/drivers/media/dvb-frontends/dib3000mb.c
@@ -640,7 +640,7 @@ static int dib3000mb_read_ber(struct dvb_frontend* fe, u32 *ber)
return 0;
}
-/* see dib3000-watch dvb-apps for exact calcuations of signal_strength and snr */
+/* see dib3000-watch dvb-apps for exact calculations of signal_strength and snr */
static int dib3000mb_read_signal_strength(struct dvb_frontend* fe, u16 *strength)
{
struct dib3000_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index 023db6e793f8..05254d8717db 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -947,8 +947,6 @@ static const struct vb2_ops rtl2832_sdr_vb2_ops = {
.buf_queue = rtl2832_sdr_buf_queue,
.start_streaming = rtl2832_sdr_start_streaming,
.stop_streaming = rtl2832_sdr_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int rtl2832_sdr_g_tuner(struct file *file, void *priv,
@@ -1487,7 +1485,7 @@ static struct platform_driver rtl2832_sdr_driver = {
.name = "rtl2832_sdr",
},
.probe = rtl2832_sdr_probe,
- .remove_new = rtl2832_sdr_remove,
+ .remove = rtl2832_sdr_remove,
};
module_platform_driver(rtl2832_sdr_driver);
diff --git a/drivers/media/dvb-frontends/stb0899_algo.c b/drivers/media/dvb-frontends/stb0899_algo.c
index df89c33dac23..40537c4ccb0d 100644
--- a/drivers/media/dvb-frontends/stb0899_algo.c
+++ b/drivers/media/dvb-frontends/stb0899_algo.c
@@ -269,7 +269,7 @@ static enum stb0899_status stb0899_search_carrier(struct stb0899_state *state)
short int derot_freq = 0, last_derot_freq = 0, derot_limit, next_loop = 3;
int index = 0;
- u8 cfr[2];
+ u8 cfr[2] = {0};
u8 reg;
internal->status = NOCARRIER;
diff --git a/drivers/media/dvb-frontends/stv6111.c b/drivers/media/dvb-frontends/stv6111.c
index 2d0adb6fcb08..0ac15273922d 100644
--- a/drivers/media/dvb-frontends/stv6111.c
+++ b/drivers/media/dvb-frontends/stv6111.c
@@ -161,7 +161,7 @@ static const struct slookup gain_rfagc_lookup[] = {
};
/*
- * This table is 6 dB too low comapred to the others (probably created with
+ * This table is 6 dB too low compared to the others (probably created with
* a different BB_MAG setting)
*/
static const struct slookup gain_channel_agc_nf_lookup[] = {
diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c
index fd928787207e..c11563853c07 100644
--- a/drivers/media/dvb-frontends/tda18271c2dd.c
+++ b/drivers/media/dvb-frontends/tda18271c2dd.c
@@ -954,7 +954,7 @@ static int RFTrackingFiltersCorrection(struct tda_state *state,
Capprox = 255;
- /* TODO Temperature compensation. There is defenitely a scale factor */
+ /* TODO Temperature compensation. There is definitely a scale factor */
/* missing in the datasheet, so leave it out for now. */
state->m_Regs[EB14] = Capprox;
diff --git a/drivers/media/dvb-frontends/ts2020.c b/drivers/media/dvb-frontends/ts2020.c
index a5baca2449c7..e25add6cc38e 100644
--- a/drivers/media/dvb-frontends/ts2020.c
+++ b/drivers/media/dvb-frontends/ts2020.c
@@ -553,13 +553,19 @@ static void ts2020_regmap_unlock(void *__dev)
static int ts2020_probe(struct i2c_client *client)
{
struct ts2020_config *pdata = client->dev.platform_data;
- struct dvb_frontend *fe = pdata->fe;
+ struct dvb_frontend *fe;
struct ts2020_priv *dev;
int ret;
u8 u8tmp;
unsigned int utmp;
char *chip_str;
+ if (!pdata) {
+ dev_err(&client->dev, "platform data is mandatory\n");
+ return -EINVAL;
+ }
+
+ fe = pdata->fe;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev) {
ret = -ENOMEM;
diff --git a/drivers/media/dvb-frontends/zd1301_demod.c b/drivers/media/dvb-frontends/zd1301_demod.c
index 17f6e373c13d..e8b9e67a8717 100644
--- a/drivers/media/dvb-frontends/zd1301_demod.c
+++ b/drivers/media/dvb-frontends/zd1301_demod.c
@@ -531,7 +531,7 @@ static struct platform_driver zd1301_demod_driver = {
.suppress_bind_attrs = true,
},
.probe = zd1301_demod_probe,
- .remove_new = zd1301_demod_remove,
+ .remove = zd1301_demod_remove,
};
module_platform_driver(zd1301_demod_driver);
diff --git a/drivers/media/dvb-frontends/zl10036.c b/drivers/media/dvb-frontends/zl10036.c
index 3df055be66d6..5ad987c6861b 100644
--- a/drivers/media/dvb-frontends/zl10036.c
+++ b/drivers/media/dvb-frontends/zl10036.c
@@ -89,7 +89,7 @@ static int zl10036_write(struct zl10036_state *state, u8 buf[], u8 count)
int ret;
if (zl10036_debug & 0x02) {
- /* every 8bit-value satisifes this!
+ /* every 8bit-value satisfies this!
* so only check for debug log */
if ((buf[0] & 0x80) == 0x00)
reg = 2;
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 819ff9f7c90f..ff7dfa0278a7 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -1440,7 +1440,8 @@ static int adv7180_probe(struct i2c_client *client)
return ret;
}
- if (of_property_read_bool(np, "adv,force-bt656-4"))
+ if (of_property_read_bool(np, "adv,force-bt656-4") ||
+ of_property_read_bool(np, "adi,force-bt656-4"))
state->force_bt656_4 = true;
if (state->chip_info->flags & ADV7180_FLAG_MIPI_CSI2) {
diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c
index e9406d552699..4036972af3a6 100644
--- a/drivers/media/i2c/adv7511-v4l2.c
+++ b/drivers/media/i2c/adv7511-v4l2.c
@@ -116,6 +116,9 @@ struct adv7511_state {
unsigned edid_detect_counter;
struct workqueue_struct *work_queue;
struct delayed_work edid_handler; /* work entry */
+
+ struct dentry *debugfs_dir;
+ struct v4l2_debugfs_if *infoframes;
};
static void adv7511_check_monitor_present_status(struct v4l2_subdev *sd);
@@ -483,27 +486,25 @@ static u8 hdmi_infoframe_checksum(u8 *ptr, size_t size)
return 256 - csum;
}
-static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_infoframe *cri)
+static int read_infoframe(struct v4l2_subdev *sd,
+ const struct adv7511_cfg_read_infoframe *cri,
+ u8 *buffer)
{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct device *dev = &client->dev;
- union hdmi_infoframe frame;
- u8 buffer[32];
u8 len;
int i;
if (!(adv7511_rd(sd, cri->present_reg) & cri->present_mask)) {
v4l2_info(sd, "%s infoframe not transmitted\n", cri->desc);
- return;
+ return 0;
}
memcpy(buffer, cri->header, sizeof(cri->header));
len = buffer[2];
- if (len + 4 > sizeof(buffer)) {
+ if (len + 4 > V4L2_DEBUGFS_IF_MAX_LEN) {
v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len);
- return;
+ return 0;
}
if (cri->payload_addr >= 0x100) {
@@ -516,21 +517,38 @@ static void log_infoframe(struct v4l2_subdev *sd, const struct adv7511_cfg_read_
buffer[3] = 0;
buffer[3] = hdmi_infoframe_checksum(buffer, len + 4);
- if (hdmi_infoframe_unpack(&frame, buffer, len + 4) < 0) {
- v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
+ return len + 4;
+}
+
+static void log_infoframe(struct v4l2_subdev *sd,
+ const struct adv7511_cfg_read_infoframe *cri)
+{
+ union hdmi_infoframe frame;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device *dev = &client->dev;
+ u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+ int len = read_infoframe(sd, cri, buffer);
+
+ if (len <= 0)
+ return;
+
+ if (hdmi_infoframe_unpack(&frame, buffer, len) < 0) {
+ v4l2_err(sd, "%s: unpack of %s infoframe failed\n",
+ __func__, cri->desc);
return;
}
hdmi_infoframe_log(KERN_INFO, dev, &frame);
}
+static const struct adv7511_cfg_read_infoframe cri[] = {
+ { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 },
+ { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 },
+ { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 },
+};
+
static void adv7511_log_infoframes(struct v4l2_subdev *sd)
{
- static const struct adv7511_cfg_read_infoframe cri[] = {
- { "AVI", 0x44, 0x10, { 0x82, 2, 13 }, 0x55 },
- { "Audio", 0x44, 0x08, { 0x84, 1, 10 }, 0x73 },
- { "SDP", 0x40, 0x40, { 0x83, 1, 25 }, 0x103 },
- };
int i;
for (i = 0; i < ARRAY_SIZE(cri); i++)
@@ -1693,6 +1711,34 @@ static bool adv7511_check_edid_status(struct v4l2_subdev *sd)
return false;
}
+static ssize_t
+adv7511_debugfs_if_read(u32 type, void *priv,
+ struct file *filp, char __user *ubuf, size_t count, loff_t *ppos)
+{
+ u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+ struct v4l2_subdev *sd = priv;
+ int index;
+ int len;
+
+ switch (type) {
+ case V4L2_DEBUGFS_IF_AVI:
+ index = 0;
+ break;
+ case V4L2_DEBUGFS_IF_AUDIO:
+ index = 1;
+ break;
+ case V4L2_DEBUGFS_IF_SPD:
+ index = 2;
+ break;
+ default:
+ return 0;
+ }
+ len = read_infoframe(sd, &cri[index], buf);
+ if (len > 0)
+ len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
+ return len < 0 ? 0 : len;
+}
+
static int adv7511_registered(struct v4l2_subdev *sd)
{
struct adv7511_state *state = get_adv7511_state(sd);
@@ -1700,9 +1746,16 @@ static int adv7511_registered(struct v4l2_subdev *sd)
int err;
err = cec_register_adapter(state->cec_adap, &client->dev);
- if (err)
+ if (err) {
cec_delete_adapter(state->cec_adap);
- return err;
+ return err;
+ }
+
+ state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root());
+ state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir,
+ V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO |
+ V4L2_DEBUGFS_IF_SPD, sd, adv7511_debugfs_if_read);
+ return 0;
}
static void adv7511_unregistered(struct v4l2_subdev *sd)
@@ -1710,6 +1763,10 @@ static void adv7511_unregistered(struct v4l2_subdev *sd)
struct adv7511_state *state = get_adv7511_state(sd);
cec_unregister_adapter(state->cec_adap);
+ v4l2_debugfs_if_free(state->infoframes);
+ state->infoframes = NULL;
+ debugfs_remove_recursive(state->debugfs_dir);
+ state->debugfs_dir = NULL;
}
static const struct v4l2_subdev_internal_ops adv7511_int_ops = {
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 48230d5109f0..e271782b7b70 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -42,7 +42,7 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "debug level (0-2)");
MODULE_DESCRIPTION("Analog Devices ADV7604/10/11/12 video decoder driver");
-MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
+MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>");
MODULE_AUTHOR("Mats Randgaard <mats.randgaard@cisco.com>");
MODULE_LICENSE("GPL");
@@ -193,6 +193,9 @@ struct adv76xx_state {
struct delayed_work delayed_work_enable_hotplug;
bool restart_stdi_once;
+ struct dentry *debugfs_dir;
+ struct v4l2_debugfs_if *infoframes;
+
/* CEC */
struct cec_adapter *cec_adap;
u8 cec_addr[ADV76XX_MAX_ADDRS];
@@ -1405,12 +1408,13 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,
if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0,
(stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) |
(stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0),
- false, timings))
+ false, adv76xx_get_dv_timings_cap(sd, -1), timings))
return 0;
if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs,
(stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) |
(stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0),
- false, state->aspect_ratio, timings))
+ false, state->aspect_ratio,
+ adv76xx_get_dv_timings_cap(sd, -1), timings))
return 0;
v4l2_dbg(2, debug, sd,
@@ -2458,10 +2462,9 @@ static const struct adv76xx_cfg_read_infoframe adv76xx_cri[] = {
{ "Vendor", 0x10, 0xec, 0x54 }
};
-static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
- union hdmi_infoframe *frame)
+static int adv76xx_read_infoframe_buf(struct v4l2_subdev *sd, int index,
+ u8 buf[V4L2_DEBUGFS_IF_MAX_LEN])
{
- uint8_t buffer[32];
u8 len;
int i;
@@ -2472,27 +2475,20 @@ static int adv76xx_read_infoframe(struct v4l2_subdev *sd, int index,
}
for (i = 0; i < 3; i++)
- buffer[i] = infoframe_read(sd,
- adv76xx_cri[index].head_addr + i);
+ buf[i] = infoframe_read(sd, adv76xx_cri[index].head_addr + i);
- len = buffer[2] + 1;
+ len = buf[2] + 1;
- if (len + 3 > sizeof(buffer)) {
+ if (len + 3 > V4L2_DEBUGFS_IF_MAX_LEN) {
v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__,
adv76xx_cri[index].desc, len);
return -ENOENT;
}
for (i = 0; i < len; i++)
- buffer[i + 3] = infoframe_read(sd,
- adv76xx_cri[index].payload_addr + i);
-
- if (hdmi_infoframe_unpack(frame, buffer, len + 3) < 0) {
- v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__,
- adv76xx_cri[index].desc);
- return -ENOENT;
- }
- return 0;
+ buf[i + 3] = infoframe_read(sd,
+ adv76xx_cri[index].payload_addr + i);
+ return len + 3;
}
static void adv76xx_log_infoframes(struct v4l2_subdev *sd)
@@ -2505,10 +2501,19 @@ static void adv76xx_log_infoframes(struct v4l2_subdev *sd)
}
for (i = 0; i < ARRAY_SIZE(adv76xx_cri); i++) {
- union hdmi_infoframe frame;
struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+ union hdmi_infoframe frame;
+ int len;
+
+ len = adv76xx_read_infoframe_buf(sd, i, buffer);
+ if (len < 0)
+ continue;
- if (!adv76xx_read_infoframe(sd, i, &frame))
+ if (hdmi_infoframe_unpack(&frame, buffer, len) < 0)
+ v4l2_err(sd, "%s: unpack of %s infoframe failed\n",
+ __func__, adv76xx_cri[i].desc);
+ else
hdmi_infoframe_log(KERN_INFO, &client->dev, &frame);
}
}
@@ -2519,10 +2524,10 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)
const struct adv76xx_chip_info *info = state->info;
struct v4l2_dv_timings timings;
struct stdi_readback stdi;
- u8 reg_io_0x02 = io_read(sd, 0x02);
+ int ret;
+ u8 reg_io_0x02;
u8 edid_enabled;
u8 cable_det;
-
static const char * const csc_coeff_sel_rb[16] = {
"bypassed", "YPbPr601 -> RGB", "reserved", "YPbPr709 -> RGB",
"reserved", "RGB -> YPbPr601", "reserved", "RGB -> YPbPr709",
@@ -2621,13 +2626,21 @@ static int adv76xx_log_status(struct v4l2_subdev *sd)
v4l2_info(sd, "-----Color space-----\n");
v4l2_info(sd, "RGB quantization range ctrl: %s\n",
rgb_quantization_range_txt[state->rgb_quantization_range]);
- v4l2_info(sd, "Input color space: %s\n",
- input_color_space_txt[reg_io_0x02 >> 4]);
- v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n",
- (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr",
- (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ?
- "(16-235)" : "(0-255)",
- (reg_io_0x02 & 0x08) ? "enabled" : "disabled");
+
+ ret = io_read(sd, 0x02);
+ if (ret < 0) {
+ v4l2_info(sd, "Can't read Input/Output color space\n");
+ } else {
+ reg_io_0x02 = ret;
+
+ v4l2_info(sd, "Input color space: %s\n",
+ input_color_space_txt[reg_io_0x02 >> 4]);
+ v4l2_info(sd, "Output color space: %s %s, alt-gamma %s\n",
+ (reg_io_0x02 & 0x02) ? "RGB" : "YCbCr",
+ (((reg_io_0x02 >> 2) & 0x01) ^ (reg_io_0x02 & 0x01)) ?
+ "(16-235)" : "(0-255)",
+ (reg_io_0x02 & 0x08) ? "enabled" : "disabled");
+ }
v4l2_info(sd, "Color space conversion: %s\n",
csc_coeff_sel_rb[cp_read(sd, info->cp_csc) >> 4]);
@@ -2686,6 +2699,41 @@ static int adv76xx_subscribe_event(struct v4l2_subdev *sd,
}
}
+static ssize_t
+adv76xx_debugfs_if_read(u32 type, void *priv, struct file *filp,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+ struct v4l2_subdev *sd = priv;
+ int index;
+ int len;
+
+ if (!is_hdmi(sd))
+ return 0;
+
+ switch (type) {
+ case V4L2_DEBUGFS_IF_AVI:
+ index = 0;
+ break;
+ case V4L2_DEBUGFS_IF_AUDIO:
+ index = 1;
+ break;
+ case V4L2_DEBUGFS_IF_SPD:
+ index = 2;
+ break;
+ case V4L2_DEBUGFS_IF_HDMI:
+ index = 3;
+ break;
+ default:
+ return 0;
+ }
+
+ len = adv76xx_read_infoframe_buf(sd, index, buf);
+ if (len > 0)
+ len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
+ return len < 0 ? 0 : len;
+}
+
static int adv76xx_registered(struct v4l2_subdev *sd)
{
struct adv76xx_state *state = to_state(sd);
@@ -2693,9 +2741,16 @@ static int adv76xx_registered(struct v4l2_subdev *sd)
int err;
err = cec_register_adapter(state->cec_adap, &client->dev);
- if (err)
+ if (err) {
cec_delete_adapter(state->cec_adap);
- return err;
+ return err;
+ }
+ state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root());
+ state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir,
+ V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO |
+ V4L2_DEBUGFS_IF_SPD | V4L2_DEBUGFS_IF_HDMI, sd,
+ adv76xx_debugfs_if_read);
+ return 0;
}
static void adv76xx_unregistered(struct v4l2_subdev *sd)
@@ -2703,6 +2758,10 @@ static void adv76xx_unregistered(struct v4l2_subdev *sd)
struct adv76xx_state *state = to_state(sd);
cec_unregister_adapter(state->cec_adap);
+ v4l2_debugfs_if_free(state->infoframes);
+ state->infoframes = NULL;
+ debugfs_remove_recursive(state->debugfs_dir);
+ state->debugfs_dir = NULL;
}
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 014fc913225c..5545cd23e113 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -38,7 +38,7 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "debug level (0-2)");
MODULE_DESCRIPTION("Analog Devices ADV7842 video decoder driver");
-MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
+MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>");
MODULE_AUTHOR("Martin Bugge <marbugge@cisco.com>");
MODULE_LICENSE("GPL");
@@ -114,6 +114,9 @@ struct adv7842_state {
bool restart_stdi_once;
bool hdmi_port_a;
+ struct dentry *debugfs_dir;
+ struct v4l2_debugfs_if *infoframes;
+
/* i2c clients */
struct i2c_client *i2c_sdp_io;
struct i2c_client *i2c_sdp;
@@ -1431,14 +1434,15 @@ static int stdi2dv_timings(struct v4l2_subdev *sd,
}
if (v4l2_detect_cvt(stdi->lcf + 1, hfreq, stdi->lcvs, 0,
- (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) |
- (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0),
- false, timings))
+ (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) |
+ (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0),
+ false, adv7842_get_dv_timings_cap(sd), timings))
return 0;
if (v4l2_detect_gtf(stdi->lcf + 1, hfreq, stdi->lcvs,
- (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) |
- (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0),
- false, state->aspect_ratio, timings))
+ (stdi->hs_pol == '+' ? V4L2_DV_HSYNC_POS_POL : 0) |
+ (stdi->vs_pol == '+' ? V4L2_DV_VSYNC_POS_POL : 0),
+ false, state->aspect_ratio,
+ adv7842_get_dv_timings_cap(sd), timings))
return 0;
v4l2_dbg(2, debug, sd,
@@ -2565,58 +2569,65 @@ struct adv7842_cfg_read_infoframe {
u8 payload_addr;
};
-static void log_infoframe(struct v4l2_subdev *sd, const struct adv7842_cfg_read_infoframe *cri)
+static const struct adv7842_cfg_read_infoframe adv7842_cri[] = {
+ { "AVI", 0x01, 0xe0, 0x00 },
+ { "Audio", 0x02, 0xe3, 0x1c },
+ { "SDP", 0x04, 0xe6, 0x2a },
+ { "Vendor", 0x10, 0xec, 0x54 }
+};
+
+static int adv7842_read_infoframe_buf(struct v4l2_subdev *sd, int index,
+ u8 buf[V4L2_DEBUGFS_IF_MAX_LEN])
{
- int i;
- u8 buffer[32];
- union hdmi_infoframe frame;
- u8 len;
- struct i2c_client *client = v4l2_get_subdevdata(sd);
- struct device *dev = &client->dev;
+ const struct adv7842_cfg_read_infoframe *cri = &adv7842_cri[index];
+ int len, i;
if (!(io_read(sd, 0x60) & cri->present_mask)) {
- v4l2_info(sd, "%s infoframe not received\n", cri->desc);
- return;
+ v4l2_dbg(1, debug, sd,
+ "%s infoframe not received\n", cri->desc);
+ return -ENOENT;
}
for (i = 0; i < 3; i++)
- buffer[i] = infoframe_read(sd, cri->head_addr + i);
+ buf[i] = infoframe_read(sd, cri->head_addr + i);
- len = buffer[2] + 1;
+ len = buf[2] + 1;
- if (len + 3 > sizeof(buffer)) {
- v4l2_err(sd, "%s: invalid %s infoframe length %d\n", __func__, cri->desc, len);
- return;
+ if (len + 3 > V4L2_DEBUGFS_IF_MAX_LEN) {
+ v4l2_err(sd, "%s: invalid %s infoframe length %d\n",
+ __func__, cri->desc, len);
+ return -ENOENT;
}
for (i = 0; i < len; i++)
- buffer[i + 3] = infoframe_read(sd, cri->payload_addr + i);
-
- if (hdmi_infoframe_unpack(&frame, buffer, len + 3) < 0) {
- v4l2_err(sd, "%s: unpack of %s infoframe failed\n", __func__, cri->desc);
- return;
- }
-
- hdmi_infoframe_log(KERN_INFO, dev, &frame);
+ buf[i + 3] = infoframe_read(sd, cri->payload_addr + i);
+ return len + 3;
}
static void adv7842_log_infoframes(struct v4l2_subdev *sd)
{
- int i;
- static const struct adv7842_cfg_read_infoframe cri[] = {
- { "AVI", 0x01, 0xe0, 0x00 },
- { "Audio", 0x02, 0xe3, 0x1c },
- { "SDP", 0x04, 0xe6, 0x2a },
- { "Vendor", 0x10, 0xec, 0x54 }
- };
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct device *dev = &client->dev;
+ union hdmi_infoframe frame;
+ u8 buffer[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+ int len, i;
if (!(hdmi_read(sd, 0x05) & 0x80)) {
v4l2_info(sd, "receive DVI-D signal, no infoframes\n");
return;
}
- for (i = 0; i < ARRAY_SIZE(cri); i++)
- log_infoframe(sd, &cri[i]);
+ for (i = 0; i < ARRAY_SIZE(adv7842_cri); i++) {
+ len = adv7842_read_infoframe_buf(sd, i, buffer);
+ if (len < 0)
+ continue;
+
+ if (hdmi_infoframe_unpack(&frame, buffer, len) < 0)
+ v4l2_err(sd, "%s: unpack of %s infoframe failed\n",
+ __func__, adv7842_cri[i].desc);
+ else
+ hdmi_infoframe_log(KERN_INFO, dev, &frame);
+ }
}
#if 0
@@ -3263,6 +3274,41 @@ static int adv7842_subscribe_event(struct v4l2_subdev *sd,
}
}
+static ssize_t
+adv7842_debugfs_if_read(u32 type, void *priv, struct file *filp,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+ struct v4l2_subdev *sd = priv;
+ int index;
+ int len;
+
+ if (!is_hdmi(sd))
+ return 0;
+
+ switch (type) {
+ case V4L2_DEBUGFS_IF_AVI:
+ index = 0;
+ break;
+ case V4L2_DEBUGFS_IF_AUDIO:
+ index = 1;
+ break;
+ case V4L2_DEBUGFS_IF_SPD:
+ index = 2;
+ break;
+ case V4L2_DEBUGFS_IF_HDMI:
+ index = 3;
+ break;
+ default:
+ return 0;
+ }
+
+ len = adv7842_read_infoframe_buf(sd, index, buf);
+ if (len > 0)
+ len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
+ return len < 0 ? 0 : len;
+}
+
static int adv7842_registered(struct v4l2_subdev *sd)
{
struct adv7842_state *state = to_state(sd);
@@ -3270,8 +3316,15 @@ static int adv7842_registered(struct v4l2_subdev *sd)
int err;
err = cec_register_adapter(state->cec_adap, &client->dev);
- if (err)
+ if (err) {
cec_delete_adapter(state->cec_adap);
+ } else {
+ state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root());
+ state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir,
+ V4L2_DEBUGFS_IF_AVI | V4L2_DEBUGFS_IF_AUDIO |
+ V4L2_DEBUGFS_IF_SPD | V4L2_DEBUGFS_IF_HDMI, sd,
+ adv7842_debugfs_if_read);
+ }
return err;
}
@@ -3280,6 +3333,10 @@ static void adv7842_unregistered(struct v4l2_subdev *sd)
struct adv7842_state *state = to_state(sd);
cec_unregister_adapter(state->cec_adap);
+ v4l2_debugfs_if_free(state->infoframes);
+ state->infoframes = NULL;
+ debugfs_remove_recursive(state->debugfs_dir);
+ state->debugfs_dir = NULL;
}
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/i2c/alvium-csi2.c b/drivers/media/i2c/alvium-csi2.c
index 5ddfd3dcb188..05b708bd0a64 100644
--- a/drivers/media/i2c/alvium-csi2.c
+++ b/drivers/media/i2c/alvium-csi2.c
@@ -16,7 +16,6 @@
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
@@ -2240,8 +2239,6 @@ free_ctrls:
static const struct v4l2_subdev_core_ops alvium_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
static const struct v4l2_subdev_video_ops alvium_video_ops = {
@@ -2289,7 +2286,7 @@ static int alvium_subdev_init(struct alvium_dev *alvium)
v4l2_i2c_subdev_init(sd, client, &alvium_subdev_ops);
sd->internal_ops = &alvium_internal_ops;
- sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_HAS_DEVNODE;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
alvium->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
diff --git a/drivers/media/i2c/ar0521.c b/drivers/media/i2c/ar0521.c
index fc27238dd4d3..24873149096c 100644
--- a/drivers/media/i2c/ar0521.c
+++ b/drivers/media/i2c/ar0521.c
@@ -255,10 +255,10 @@ static u32 calc_pll(struct ar0521_dev *sensor, u32 freq, u16 *pre_ptr, u16 *mult
continue; /* Minimum value */
if (new_mult > 254)
break; /* Maximum, larger pre won't work either */
- if (sensor->extclk_freq * (u64)new_mult < AR0521_PLL_MIN *
+ if (sensor->extclk_freq * (u64)new_mult < (u64)AR0521_PLL_MIN *
new_pre)
continue;
- if (sensor->extclk_freq * (u64)new_mult > AR0521_PLL_MAX *
+ if (sensor->extclk_freq * (u64)new_mult > (u64)AR0521_PLL_MAX *
new_pre)
break; /* Larger pre won't work either */
new_pll = div64_round_up(sensor->extclk_freq * (u64)new_mult,
diff --git a/drivers/media/i2c/ds90ub953.c b/drivers/media/i2c/ds90ub953.c
index 16f88db14981..8b028a84f5bc 100644
--- a/drivers/media/i2c/ds90ub953.c
+++ b/drivers/media/i2c/ds90ub953.c
@@ -24,7 +24,6 @@
#include <media/i2c/ds90ub9xx.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-mediabus.h>
#include <media/v4l2-subdev.h>
@@ -717,8 +716,6 @@ static const struct v4l2_subdev_pad_ops ub953_pad_ops = {
static const struct v4l2_subdev_core_ops ub953_subdev_core_ops = {
.log_status = ub953_log_status,
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
static const struct v4l2_subdev_ops ub953_subdev_ops = {
@@ -1246,7 +1243,7 @@ static int ub953_subdev_init(struct ub953_data *priv)
priv->sd.internal_ops = &ub953_internal_ops;
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
- V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS;
+ V4L2_SUBDEV_FL_STREAMS;
priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
priv->sd.entity.ops = &ub953_entity_ops;
diff --git a/drivers/media/i2c/ds90ub960.c b/drivers/media/i2c/ds90ub960.c
index ffe5f25f8647..33f362a00875 100644
--- a/drivers/media/i2c/ds90ub960.c
+++ b/drivers/media/i2c/ds90ub960.c
@@ -48,7 +48,6 @@
#include <media/i2c/ds90ub9xx.h>
#include <media/mipi-csi2.h>
#include <media/v4l2-ctrls.h>
-#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#include <media/v4l2-subdev.h>
@@ -1286,7 +1285,7 @@ static int ub960_rxport_get_strobe_pos(struct ub960_data *priv,
clk_delay += v & UB960_IR_RX_ANA_STROBE_SET_CLK_DELAY_MASK;
- ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_1, &v);
+ ret = ub960_rxport_read(priv, nport, UB960_RR_SFILTER_STS_1, &v);
if (ret)
return ret;
@@ -3085,8 +3084,6 @@ static int ub960_log_status(struct v4l2_subdev *sd)
static const struct v4l2_subdev_core_ops ub960_subdev_core_ops = {
.log_status = ub960_log_status,
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
static const struct v4l2_subdev_internal_ops ub960_internal_ops = {
@@ -3667,7 +3664,7 @@ static int ub960_create_subdev(struct ub960_data *priv)
}
priv->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
- V4L2_SUBDEV_FL_HAS_EVENTS | V4L2_SUBDEV_FL_STREAMS;
+ V4L2_SUBDEV_FL_STREAMS;
priv->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
priv->sd.entity.ops = &ub960_entity_ops;
diff --git a/drivers/media/i2c/dw9768.c b/drivers/media/i2c/dw9768.c
index 18ef2b35c9aa..3a4d100b9199 100644
--- a/drivers/media/i2c/dw9768.c
+++ b/drivers/media/i2c/dw9768.c
@@ -374,7 +374,8 @@ static int dw9768_open(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
static int dw9768_close(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
{
- pm_runtime_put(sd->dev);
+ pm_runtime_mark_last_busy(sd->dev);
+ pm_runtime_put_autosuspend(sd->dev);
return 0;
}
@@ -471,10 +472,9 @@ static int dw9768_probe(struct i2c_client *client)
* to be powered on in an ACPI system. Similarly for power off in
* remove.
*/
- pm_runtime_enable(dev);
full_power = (is_acpi_node(dev_fwnode(dev)) &&
acpi_dev_state_d0(dev)) ||
- (is_of_node(dev_fwnode(dev)) && !pm_runtime_enabled(dev));
+ (is_of_node(dev_fwnode(dev)) && !IS_ENABLED(CONFIG_PM));
if (full_power) {
ret = dw9768_runtime_resume(dev);
if (ret < 0) {
@@ -484,23 +484,26 @@ static int dw9768_probe(struct i2c_client *client)
pm_runtime_set_active(dev);
}
+ pm_runtime_enable(dev);
ret = v4l2_async_register_subdev(&dw9768->sd);
if (ret < 0) {
dev_err(dev, "failed to register V4L2 subdev: %d", ret);
goto err_power_off;
}
+ pm_runtime_set_autosuspend_delay(dev, 1000);
+ pm_runtime_use_autosuspend(dev);
pm_runtime_idle(dev);
return 0;
err_power_off:
+ pm_runtime_disable(dev);
if (full_power) {
dw9768_runtime_suspend(dev);
pm_runtime_set_suspended(dev);
}
err_clean_entity:
- pm_runtime_disable(dev);
media_entity_cleanup(&dw9768->sd.entity);
err_free_handler:
v4l2_ctrl_handler_free(&dw9768->ctrls);
@@ -517,12 +520,12 @@ static void dw9768_remove(struct i2c_client *client)
v4l2_async_unregister_subdev(&dw9768->sd);
v4l2_ctrl_handler_free(&dw9768->ctrls);
media_entity_cleanup(&dw9768->sd.entity);
+ pm_runtime_disable(dev);
if ((is_acpi_node(dev_fwnode(dev)) && acpi_dev_state_d0(dev)) ||
- (is_of_node(dev_fwnode(dev)) && !pm_runtime_enabled(dev))) {
+ (is_of_node(dev_fwnode(dev)) && !IS_ENABLED(CONFIG_PM))) {
dw9768_runtime_suspend(dev);
pm_runtime_set_suspended(dev);
}
- pm_runtime_disable(dev);
}
static const struct of_device_id dw9768_of_table[] = {
diff --git a/drivers/media/i2c/gc0308.c b/drivers/media/i2c/gc0308.c
index fa754a8a39a6..069f42785b3c 100644
--- a/drivers/media/i2c/gc0308.c
+++ b/drivers/media/i2c/gc0308.c
@@ -18,7 +18,6 @@
#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-subdev.h>
@@ -987,8 +986,6 @@ static const struct v4l2_ctrl_ops gc0308_ctrl_ops = {
static const struct v4l2_subdev_core_ops gc0308_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = gc0308_g_register,
.s_register = gc0308_s_register,
@@ -1338,7 +1335,6 @@ static int gc0308_probe(struct i2c_client *client)
v4l2_i2c_subdev_init(&gc0308->sd, client, &gc0308_subdev_ops);
gc0308->sd.internal_ops = &gc0308_internal_ops;
gc0308->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
- gc0308->sd.flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
ret = gc0308_init_controls(gc0308);
if (ret)
diff --git a/drivers/media/i2c/gc05a2.c b/drivers/media/i2c/gc05a2.c
index 0413c557e594..3f7f3d5abeeb 100644
--- a/drivers/media/i2c/gc05a2.c
+++ b/drivers/media/i2c/gc05a2.c
@@ -24,7 +24,6 @@
#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>
@@ -1059,13 +1058,7 @@ static const struct v4l2_subdev_pad_ops gc05a2_subdev_pad_ops = {
.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,
};
@@ -1271,8 +1264,7 @@ static int gc05a2_probe(struct i2c_client *client)
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->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
gc05a2->pad.flags = MEDIA_PAD_FL_SOURCE;
gc05a2->sd.dev = &client->dev;
gc05a2->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
diff --git a/drivers/media/i2c/gc08a3.c b/drivers/media/i2c/gc08a3.c
index 84de5cff958d..938709a677b6 100644
--- a/drivers/media/i2c/gc08a3.c
+++ b/drivers/media/i2c/gc08a3.c
@@ -24,7 +24,6 @@
#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>
@@ -1001,13 +1000,7 @@ static const struct v4l2_subdev_pad_ops gc08a3_subdev_pad_ops = {
.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,
};
@@ -1247,8 +1240,7 @@ static int gc08a3_probe(struct i2c_client *client)
goto err_power_off;
}
- gc08a3->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
- V4L2_SUBDEV_FL_HAS_EVENTS;
+ gc08a3->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
gc08a3->pad.flags = MEDIA_PAD_FL_SOURCE;
gc08a3->sd.dev = &client->dev;
gc08a3->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
diff --git a/drivers/media/i2c/gc2145.c b/drivers/media/i2c/gc2145.c
index 667bb756d056..ba02161d46e7 100644
--- a/drivers/media/i2c/gc2145.c
+++ b/drivers/media/i2c/gc2145.c
@@ -21,7 +21,6 @@
#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>
@@ -899,9 +898,11 @@ static int gc2145_config_mipi_mode(struct gc2145 *gc2145,
return ret;
}
-static int gc2145_start_streaming(struct gc2145 *gc2145,
- struct v4l2_subdev_state *state)
+static int gc2145_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
{
+ struct gc2145 *gc2145 = to_gc2145(sd);
struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
const struct gc2145_format *gc2145_format;
struct v4l2_mbus_framefmt *fmt;
@@ -967,8 +968,11 @@ err_rpm_put:
return ret;
}
-static void gc2145_stop_streaming(struct gc2145 *gc2145)
+static int gc2145_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
{
+ struct gc2145 *gc2145 = to_gc2145(sd);
struct i2c_client *client = v4l2_get_subdevdata(&gc2145->sd);
int ret = 0;
@@ -983,22 +987,6 @@ static void gc2145_stop_streaming(struct gc2145 *gc2145)
pm_runtime_mark_last_busy(&client->dev);
pm_runtime_put_autosuspend(&client->dev);
-}
-
-static int gc2145_set_stream(struct v4l2_subdev *sd, int enable)
-{
- struct gc2145 *gc2145 = to_gc2145(sd);
- struct v4l2_subdev_state *state;
- int ret = 0;
-
- state = v4l2_subdev_lock_and_get_active_state(sd);
-
- if (enable)
- ret = gc2145_start_streaming(gc2145, state);
- else
- gc2145_stop_streaming(gc2145);
-
- v4l2_subdev_unlock_state(state);
return ret;
}
@@ -1123,13 +1111,8 @@ static const u8 test_pattern_val[] = {
GC2145_TEST_UNIFORM | GC2145_TEST_BLACK,
};
-static const struct v4l2_subdev_core_ops gc2145_core_ops = {
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-};
-
static const struct v4l2_subdev_video_ops gc2145_video_ops = {
- .s_stream = gc2145_set_stream,
+ .s_stream = v4l2_subdev_s_stream_helper,
};
static const struct v4l2_subdev_pad_ops gc2145_pad_ops = {
@@ -1138,10 +1121,11 @@ static const struct v4l2_subdev_pad_ops gc2145_pad_ops = {
.set_fmt = gc2145_set_pad_format,
.get_selection = gc2145_get_selection,
.enum_frame_size = gc2145_enum_frame_size,
+ .enable_streams = gc2145_enable_streams,
+ .disable_streams = gc2145_disable_streams,
};
static const struct v4l2_subdev_ops gc2145_subdev_ops = {
- .core = &gc2145_core_ops,
.video = &gc2145_video_ops,
.pad = &gc2145_pad_ops,
};
@@ -1407,8 +1391,7 @@ static int gc2145_probe(struct i2c_client *client)
goto error_power_off;
/* Initialize subdev */
- gc2145->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
- V4L2_SUBDEV_FL_HAS_EVENTS;
+ gc2145->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
gc2145->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
/* Initialize source pad */
diff --git a/drivers/media/i2c/hi556.c b/drivers/media/i2c/hi556.c
index f31f9886c924..3ac42d1ab8b4 100644
--- a/drivers/media/i2c/hi556.c
+++ b/drivers/media/i2c/hi556.c
@@ -644,7 +644,7 @@ struct hi556 {
/* Current mode */
const struct hi556_mode *cur_mode;
- /* To serialize asynchronus callbacks */
+ /* To serialize asynchronous callbacks */
struct mutex mutex;
/* True if the device has been identified */
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index e78a80b2bb2e..2d54cea113e1 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -26,7 +26,6 @@
#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>
@@ -922,11 +921,6 @@ static int imx219_init_state(struct v4l2_subdev *sd,
return 0;
}
-static const struct v4l2_subdev_core_ops imx219_core_ops = {
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-};
-
static const struct v4l2_subdev_video_ops imx219_video_ops = {
.s_stream = imx219_set_stream,
};
@@ -940,7 +934,6 @@ static const struct v4l2_subdev_pad_ops imx219_pad_ops = {
};
static const struct v4l2_subdev_ops imx219_subdev_ops = {
- .core = &imx219_core_ops,
.video = &imx219_video_ops,
.pad = &imx219_pad_ops,
};
@@ -1166,8 +1159,7 @@ static int imx219_probe(struct i2c_client *client)
goto error_power_off;
/* Initialize subdev */
- imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
- V4L2_SUBDEV_FL_HAS_EVENTS;
+ imx219->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
imx219->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
/* Initialize source pad */
diff --git a/drivers/media/i2c/imx283.c b/drivers/media/i2c/imx283.c
index 94276f4f2d83..f676faf4b301 100644
--- a/drivers/media/i2c/imx283.c
+++ b/drivers/media/i2c/imx283.c
@@ -32,7 +32,6 @@
#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>
@@ -1284,11 +1283,6 @@ static int imx283_get_selection(struct v4l2_subdev *sd,
}
}
-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,
};
@@ -1308,7 +1302,6 @@ static const struct v4l2_subdev_internal_ops imx283_internal_ops = {
};
static const struct v4l2_subdev_ops imx283_subdev_ops = {
- .core = &imx283_core_ops,
.video = &imx283_video_ops,
.pad = &imx283_pad_ops,
};
@@ -1548,8 +1541,7 @@ static int imx283_probe(struct i2c_client *client)
goto error_pm;
/* Initialize subdev */
- imx283->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
- V4L2_SUBDEV_FL_HAS_EVENTS;
+ imx283->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
imx283->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
imx283->sd.internal_ops = &imx283_internal_ops;
diff --git a/drivers/media/i2c/imx290.c b/drivers/media/i2c/imx290.c
index 458905dfb3e1..f5ee6bd3b52d 100644
--- a/drivers/media/i2c/imx290.c
+++ b/drivers/media/i2c/imx290.c
@@ -24,7 +24,6 @@
#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-subdev.h>
@@ -78,7 +77,6 @@
#define IMX290_ADBIT2 CCI_REG8(0x317c)
#define IMX290_ADBIT2_10BIT 0x12
#define IMX290_ADBIT2_12BIT 0x00
-#define IMX290_CHIP_ID CCI_REG16_LE(0x319a)
#define IMX290_ADBIT3 CCI_REG8(0x31ec)
#define IMX290_ADBIT3_10BIT 0x37
#define IMX290_ADBIT3_12BIT 0x0e
@@ -1211,11 +1209,6 @@ static int imx290_entity_init_state(struct v4l2_subdev *subdev,
return 0;
}
-static const struct v4l2_subdev_core_ops imx290_core_ops = {
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-};
-
static const struct v4l2_subdev_video_ops imx290_video_ops = {
.s_stream = imx290_set_stream,
};
@@ -1229,7 +1222,6 @@ static const struct v4l2_subdev_pad_ops imx290_pad_ops = {
};
static const struct v4l2_subdev_ops imx290_subdev_ops = {
- .core = &imx290_core_ops,
.video = &imx290_video_ops,
.pad = &imx290_pad_ops,
};
@@ -1250,11 +1242,20 @@ static int imx290_subdev_init(struct imx290 *imx290)
imx290->current_mode = &imx290_modes_ptr(imx290)[0];
+ /*
+ * After linking the subdev with the imx290 instance, we are allowed to
+ * use the pm_runtime functions. Decrease the PM usage count. The device
+ * will get suspended after the autosuspend delay, turning the power
+ * off. However, the communication happening in imx290_ctrl_update()
+ * will already be prevented even before the delay.
+ */
v4l2_i2c_subdev_init(&imx290->sd, client, &imx290_subdev_ops);
- imx290->sd.internal_ops = &imx290_internal_ops;
- imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
- V4L2_SUBDEV_FL_HAS_EVENTS;
imx290->sd.dev = imx290->dev;
+ pm_runtime_mark_last_busy(imx290->dev);
+ pm_runtime_put_autosuspend(imx290->dev);
+
+ imx290->sd.internal_ops = &imx290_internal_ops;
+ imx290->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
imx290->sd.entity.ops = &imx290_subdev_entity_ops;
imx290->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
@@ -1580,6 +1581,16 @@ static int imx290_probe(struct i2c_client *client)
pm_runtime_set_autosuspend_delay(dev, 1000);
pm_runtime_use_autosuspend(dev);
+ /*
+ * Make sure the sensor is available, in STANDBY and not streaming
+ * before the V4L2 subdev is initialized.
+ */
+ ret = imx290_stop_streaming(imx290);
+ if (ret) {
+ ret = dev_err_probe(dev, ret, "Could not initialize device\n");
+ goto err_pm;
+ }
+
/* Initialize the V4L2 subdev. */
ret = imx290_subdev_init(imx290);
if (ret)
@@ -1599,13 +1610,6 @@ static int imx290_probe(struct i2c_client *client)
goto err_subdev;
}
- /*
- * Decrease the PM usage count. The device will get suspended after the
- * autosuspend delay, turning the power off.
- */
- pm_runtime_mark_last_busy(dev);
- pm_runtime_put_autosuspend(dev);
-
return 0;
err_subdev:
diff --git a/drivers/media/i2c/imx415.c b/drivers/media/i2c/imx415.c
index a20b0db330d3..3f7924aa1bd3 100644
--- a/drivers/media/i2c/imx415.c
+++ b/drivers/media/i2c/imx415.c
@@ -1113,8 +1113,7 @@ static int imx415_subdev_init(struct imx415 *sensor)
if (ret)
return ret;
- sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
- V4L2_SUBDEV_FL_HAS_EVENTS;
+ sensor->subdev.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
sensor->pad.flags = MEDIA_PAD_FL_SOURCE;
sensor->subdev.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sensor->subdev.entity, 1, &sensor->pad);
diff --git a/drivers/media/i2c/max96717.c b/drivers/media/i2c/max96717.c
index 4e85b8eb1e77..9259d58ba734 100644
--- a/drivers/media/i2c/max96717.c
+++ b/drivers/media/i2c/max96717.c
@@ -697,8 +697,10 @@ static int max96717_subdev_init(struct max96717_priv *priv)
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");
+ if (ret) {
+ dev_err_probe(dev, ret, "Failed to init pads\n");
+ goto err_free_ctrl;
+ }
ret = v4l2_subdev_init_finalize(&priv->sd);
if (ret) {
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index d8735c246e52..4ef5fb06131d 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -17,14 +17,12 @@
#include <linux/log2.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_graph.h>
#include <linux/pm.h>
+#include <linux/property.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/videodev2.h>
-#include <media/i2c/mt9p031.h>
#include <media/v4l2-async.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
@@ -113,18 +111,25 @@
#define MT9P031_TEST_PATTERN_RED 0xa2
#define MT9P031_TEST_PATTERN_BLUE 0xa3
+struct mt9p031_model_info {
+ u32 code;
+};
+
struct mt9p031 {
struct v4l2_subdev subdev;
struct media_pad pad;
struct v4l2_rect crop; /* Sensor window */
struct v4l2_mbus_framefmt format;
- struct mt9p031_platform_data *pdata;
struct mutex power_lock; /* lock to protect power_count */
int power_count;
struct clk *clk;
struct regulator_bulk_data regulators[3];
+ unsigned int pixclk_pol:1;
+ int ext_freq;
+ int target_freq;
+
u32 code;
struct aptina_pll pll;
unsigned int clk_div;
@@ -225,7 +230,6 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
};
struct i2c_client *client = v4l2_get_subdevdata(&mt9p031->subdev);
- struct mt9p031_platform_data *pdata = mt9p031->pdata;
unsigned long ext_freq;
int ret;
@@ -233,7 +237,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
if (IS_ERR(mt9p031->clk))
return PTR_ERR(mt9p031->clk);
- ret = clk_set_rate(mt9p031->clk, pdata->ext_freq);
+ ret = clk_set_rate(mt9p031->clk, mt9p031->ext_freq);
if (ret < 0)
return ret;
@@ -245,7 +249,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
if (ext_freq > limits.ext_clock_max) {
unsigned int div;
- div = DIV_ROUND_UP(ext_freq, pdata->target_freq);
+ div = DIV_ROUND_UP(ext_freq, mt9p031->target_freq);
div = roundup_pow_of_two(div) / 2;
mt9p031->clk_div = min_t(unsigned int, div, 64);
@@ -255,7 +259,7 @@ static int mt9p031_clk_setup(struct mt9p031 *mt9p031)
}
mt9p031->pll.ext_clock = ext_freq;
- mt9p031->pll.pix_clock = pdata->target_freq;
+ mt9p031->pll.pix_clock = mt9p031->target_freq;
mt9p031->use_pll = true;
return aptina_pll_calculate(&client->dev, &limits, &mt9p031->pll);
@@ -376,7 +380,7 @@ static int __mt9p031_set_power(struct mt9p031 *mt9p031, bool on)
}
/* Configure the pixel clock polarity */
- if (mt9p031->pdata && mt9p031->pdata->pixclk_pol) {
+ if (mt9p031->pixclk_pol) {
ret = mt9p031_write(client, MT9P031_PIXEL_CLOCK_CONTROL,
MT9P031_PIXEL_CLOCK_INVERT);
if (ret < 0)
@@ -1057,53 +1061,41 @@ static const struct v4l2_subdev_internal_ops mt9p031_subdev_internal_ops = {
* Driver initialization and probing
*/
-static struct mt9p031_platform_data *
-mt9p031_get_pdata(struct i2c_client *client)
+static int mt9p031_parse_properties(struct mt9p031 *mt9p031, struct device *dev)
{
- struct mt9p031_platform_data *pdata = NULL;
- struct device_node *np;
struct v4l2_fwnode_endpoint endpoint = {
.bus_type = V4L2_MBUS_PARALLEL
};
+ struct fwnode_handle *np;
+ int ret;
- if (!IS_ENABLED(CONFIG_OF) || !client->dev.of_node)
- return client->dev.platform_data;
-
- np = of_graph_get_endpoint_by_regs(client->dev.of_node, 0, -1);
+ np = fwnode_graph_get_next_endpoint(dev_fwnode(dev), NULL);
if (!np)
- return NULL;
-
- if (v4l2_fwnode_endpoint_parse(of_fwnode_handle(np), &endpoint) < 0)
- goto done;
+ return dev_err_probe(dev, -EINVAL, "endpoint node not found\n");
- pdata = devm_kzalloc(&client->dev, sizeof(*pdata), GFP_KERNEL);
- if (!pdata)
- goto done;
+ ret = v4l2_fwnode_endpoint_parse(np, &endpoint);
+ fwnode_handle_put(np);
+ if (ret)
+ return dev_err_probe(dev, -EINVAL, "could not parse endpoint\n");
- of_property_read_u32(np, "input-clock-frequency", &pdata->ext_freq);
- of_property_read_u32(np, "pixel-clock-frequency", &pdata->target_freq);
+ fwnode_property_read_u32(np, "input-clock-frequency",
+ &mt9p031->ext_freq);
+ fwnode_property_read_u32(np, "pixel-clock-frequency",
+ &mt9p031->target_freq);
- pdata->pixclk_pol = !!(endpoint.bus.parallel.flags &
- V4L2_MBUS_PCLK_SAMPLE_RISING);
+ mt9p031->pixclk_pol = !!(endpoint.bus.parallel.flags &
+ V4L2_MBUS_PCLK_SAMPLE_RISING);
-done:
- of_node_put(np);
- return pdata;
+ return 0;
}
static int mt9p031_probe(struct i2c_client *client)
{
- struct mt9p031_platform_data *pdata = mt9p031_get_pdata(client);
struct i2c_adapter *adapter = client->adapter;
struct mt9p031 *mt9p031;
unsigned int i;
int ret;
- if (pdata == NULL) {
- dev_err(&client->dev, "No platform data\n");
- return -EINVAL;
- }
-
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
dev_warn(&client->dev,
"I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
@@ -1114,10 +1106,13 @@ static int mt9p031_probe(struct i2c_client *client)
if (mt9p031 == NULL)
return -ENOMEM;
- mt9p031->pdata = pdata;
+ ret = mt9p031_parse_properties(mt9p031, &client->dev);
+ if (ret)
+ return ret;
+
mt9p031->output_control = MT9P031_OUTPUT_CONTROL_DEF;
mt9p031->mode2 = MT9P031_READ_MODE_2_ROW_BLC;
- mt9p031->code = (uintptr_t)i2c_get_match_data(client);
+ mt9p031->code = (uintptr_t)device_get_match_data(&client->dev);
mt9p031->regulators[0].supply = "vdd";
mt9p031->regulators[1].supply = "vdd_io";
@@ -1145,8 +1140,8 @@ static int mt9p031_probe(struct i2c_client *client)
v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
V4L2_CID_VFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&mt9p031->ctrls, &mt9p031_ctrl_ops,
- V4L2_CID_PIXEL_RATE, pdata->target_freq,
- pdata->target_freq, 1, pdata->target_freq);
+ V4L2_CID_PIXEL_RATE, mt9p031->target_freq,
+ mt9p031->target_freq, 1, mt9p031->target_freq);
v4l2_ctrl_new_std_menu_items(&mt9p031->ctrls, &mt9p031_ctrl_ops,
V4L2_CID_TEST_PATTERN,
ARRAY_SIZE(mt9p031_test_pattern_menu) - 1, 0,
@@ -1213,18 +1208,18 @@ static void mt9p031_remove(struct i2c_client *client)
mutex_destroy(&mt9p031->power_lock);
}
-static const struct i2c_device_id mt9p031_id[] = {
- { "mt9p006", MEDIA_BUS_FMT_SGRBG12_1X12 },
- { "mt9p031", MEDIA_BUS_FMT_SGRBG12_1X12 },
- { "mt9p031m", MEDIA_BUS_FMT_Y12_1X12 },
- { /* sentinel */ }
+static const struct mt9p031_model_info mt9p031_models_bayer = {
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12
+};
+
+static const struct mt9p031_model_info mt9p031_models_mono = {
+ .code = MEDIA_BUS_FMT_Y12_1X12
};
-MODULE_DEVICE_TABLE(i2c, mt9p031_id);
static const struct of_device_id mt9p031_of_match[] = {
- { .compatible = "aptina,mt9p006", .data = (void *)MEDIA_BUS_FMT_SGRBG12_1X12 },
- { .compatible = "aptina,mt9p031", .data = (void *)MEDIA_BUS_FMT_SGRBG12_1X12 },
- { .compatible = "aptina,mt9p031m", .data = (void *)MEDIA_BUS_FMT_Y12_1X12 },
+ { .compatible = "aptina,mt9p006", .data = &mt9p031_models_bayer },
+ { .compatible = "aptina,mt9p031", .data = &mt9p031_models_bayer },
+ { .compatible = "aptina,mt9p031m", .data = &mt9p031_models_mono },
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, mt9p031_of_match);
@@ -1236,7 +1231,6 @@ static struct i2c_driver mt9p031_i2c_driver = {
},
.probe = mt9p031_probe,
.remove = mt9p031_remove,
- .id_table = mt9p031_id,
};
module_i2c_driver(mt9p031_i2c_driver);
diff --git a/drivers/media/i2c/ov01a10.c b/drivers/media/i2c/ov01a10.c
index 0b9fb1ddbe59..141cb6f75b55 100644
--- a/drivers/media/i2c/ov01a10.c
+++ b/drivers/media/i2c/ov01a10.c
@@ -13,7 +13,6 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-event.h>
#include <media/v4l2-fwnode.h>
#define OV01A10_LINK_FREQ_400MHZ 400000000ULL
@@ -804,8 +803,6 @@ static int ov01a10_get_selection(struct v4l2_subdev *sd,
static const struct v4l2_subdev_core_ops ov01a10_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
static const struct v4l2_subdev_video_ops ov01a10_video_ops = {
@@ -892,8 +889,7 @@ static int ov01a10_probe(struct i2c_client *client)
}
ov01a10->sd.state_lock = ov01a10->ctrl_handler.lock;
- ov01a10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE |
- V4L2_SUBDEV_FL_HAS_EVENTS;
+ ov01a10->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ov01a10->sd.entity.ops = &ov01a10_subdev_entity_ops;
ov01a10->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ov01a10->pad.flags = MEDIA_PAD_FL_SOURCE;
diff --git a/drivers/media/i2c/ov08x40.c b/drivers/media/i2c/ov08x40.c
index 7ead3c720e0e..b9682264e2f5 100644
--- a/drivers/media/i2c/ov08x40.c
+++ b/drivers/media/i2c/ov08x40.c
@@ -3,10 +3,13 @@
#include <linux/unaligned.h>
#include <linux/acpi.h>
+#include <linux/clk.h>
#include <linux/i2c.h>
+#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/pm_runtime.h>
+#include <linux/regulator/consumer.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fwnode.h>
@@ -1215,7 +1218,7 @@ static const char * const ov08x40_test_pattern_menu[] = {
/* Configurations for supported link frequencies */
#define OV08X40_LINK_FREQ_400MHZ 400000000ULL
#define OV08X40_SCLK_96MHZ 96000000ULL
-#define OV08X40_EXT_CLK 19200000
+#define OV08X40_XVCLK 19200000
#define OV08X40_DATA_LANES 4
/*
@@ -1279,6 +1282,12 @@ static const struct ov08x40_mode supported_modes[] = {
},
};
+static const char * const ov08x40_supply_names[] = {
+ "dovdd", /* Digital I/O power */
+ "avdd", /* Analog power */
+ "dvdd", /* Digital core power */
+};
+
struct ov08x40 {
struct v4l2_subdev sd;
struct media_pad pad;
@@ -1291,6 +1300,10 @@ struct ov08x40 {
struct v4l2_ctrl *hblank;
struct v4l2_ctrl *exposure;
+ struct clk *xvclk;
+ struct gpio_desc *reset_gpio;
+ struct regulator_bulk_data supplies[ARRAY_SIZE(ov08x40_supply_names)];
+
/* Current mode */
const struct ov08x40_mode *cur_mode;
@@ -1303,6 +1316,61 @@ struct ov08x40 {
#define to_ov08x40(_sd) container_of(_sd, struct ov08x40, sd)
+static int ov08x40_power_on(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov08x40 *ov08x = to_ov08x40(sd);
+ int ret;
+
+ if (is_acpi_node(dev_fwnode(dev)))
+ return 0;
+
+ ret = clk_prepare_enable(ov08x->xvclk);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable xvclk\n");
+ return ret;
+ }
+
+ if (ov08x->reset_gpio) {
+ gpiod_set_value_cansleep(ov08x->reset_gpio, 1);
+ usleep_range(1000, 2000);
+ }
+
+ ret = regulator_bulk_enable(ARRAY_SIZE(ov08x40_supply_names),
+ ov08x->supplies);
+ if (ret < 0) {
+ dev_err(dev, "failed to enable regulators\n");
+ goto disable_clk;
+ }
+
+ gpiod_set_value_cansleep(ov08x->reset_gpio, 0);
+ usleep_range(1500, 1800);
+
+ return 0;
+
+disable_clk:
+ gpiod_set_value_cansleep(ov08x->reset_gpio, 1);
+ clk_disable_unprepare(ov08x->xvclk);
+
+ return ret;
+}
+
+static int ov08x40_power_off(struct device *dev)
+{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct ov08x40 *ov08x = to_ov08x40(sd);
+
+ if (is_acpi_node(dev_fwnode(dev)))
+ return 0;
+
+ gpiod_set_value_cansleep(ov08x->reset_gpio, 1);
+ regulator_bulk_disable(ARRAY_SIZE(ov08x40_supply_names),
+ ov08x->supplies);
+ clk_disable_unprepare(ov08x->xvclk);
+
+ return 0;
+}
+
/* Read registers up to 4 at a time */
static int ov08x40_read_reg(struct ov08x40 *ov08x,
u16 reg, u32 len, u32 *val)
@@ -1339,15 +1407,13 @@ static int ov08x40_read_reg(struct ov08x40 *ov08x,
return 0;
}
-static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg,
- u16 last_reg, u8 val)
+static int __ov08x40_burst_fill_regs(struct i2c_client *client, u16 first_reg,
+ u16 last_reg, size_t num_regs, u8 val)
{
- struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd);
struct i2c_msg msgs;
- size_t i, num_regs;
+ size_t i;
int ret;
- num_regs = last_reg - first_reg + 1;
msgs.addr = client->addr;
msgs.flags = 0;
msgs.len = 2 + num_regs;
@@ -1373,6 +1439,31 @@ static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg,
return 0;
}
+static int ov08x40_burst_fill_regs(struct ov08x40 *ov08x, u16 first_reg,
+ u16 last_reg, u8 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(&ov08x->sd);
+ size_t num_regs, num_write_regs;
+ int ret;
+
+ num_regs = last_reg - first_reg + 1;
+ num_write_regs = num_regs;
+
+ if (client->adapter->quirks && client->adapter->quirks->max_write_len)
+ num_write_regs = client->adapter->quirks->max_write_len - 2;
+
+ while (first_reg < last_reg) {
+ ret = __ov08x40_burst_fill_regs(client, first_reg, last_reg,
+ num_write_regs, val);
+ if (ret)
+ return ret;
+
+ first_reg += num_write_regs;
+ }
+
+ return 0;
+}
+
/* Write registers up to 4 at a time */
static int ov08x40_write_reg(struct ov08x40 *ov08x,
u16 reg, u32 len, u32 __val)
@@ -2049,7 +2140,7 @@ static void ov08x40_free_controls(struct ov08x40 *ov08x)
mutex_destroy(&ov08x->mutex);
}
-static int ov08x40_check_hwcfg(struct device *dev)
+static int ov08x40_check_hwcfg(struct ov08x40 *ov08x, struct device *dev)
{
struct v4l2_fwnode_endpoint bus_cfg = {
.bus_type = V4L2_MBUS_CSI2_DPHY
@@ -2058,21 +2149,46 @@ static int ov08x40_check_hwcfg(struct device *dev)
struct fwnode_handle *fwnode = dev_fwnode(dev);
unsigned int i, j;
int ret;
- u32 ext_clk;
+ u32 xvclk_rate;
if (!fwnode)
return -ENXIO;
- ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
- &ext_clk);
- if (ret) {
- dev_err(dev, "can't get clock frequency");
- return ret;
+ if (!is_acpi_node(fwnode)) {
+ ov08x->xvclk = devm_clk_get(dev, NULL);
+ if (IS_ERR(ov08x->xvclk)) {
+ dev_err(dev, "could not get xvclk clock (%pe)\n",
+ ov08x->xvclk);
+ return PTR_ERR(ov08x->xvclk);
+ }
+
+ xvclk_rate = clk_get_rate(ov08x->xvclk);
+
+ ov08x->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+ GPIOD_OUT_LOW);
+ if (IS_ERR(ov08x->reset_gpio))
+ return PTR_ERR(ov08x->reset_gpio);
+
+ for (i = 0; i < ARRAY_SIZE(ov08x40_supply_names); i++)
+ ov08x->supplies[i].supply = ov08x40_supply_names[i];
+
+ ret = devm_regulator_bulk_get(dev,
+ ARRAY_SIZE(ov08x40_supply_names),
+ ov08x->supplies);
+ if (ret)
+ return ret;
+ } else {
+ ret = fwnode_property_read_u32(dev_fwnode(dev), "clock-frequency",
+ &xvclk_rate);
+ if (ret) {
+ dev_err(dev, "can't get clock frequency");
+ return ret;
+ }
}
- if (ext_clk != OV08X40_EXT_CLK) {
+ if (xvclk_rate != OV08X40_XVCLK) {
dev_err(dev, "external clock %d is not supported",
- ext_clk);
+ xvclk_rate);
return -EINVAL;
}
@@ -2120,32 +2236,37 @@ out_err:
}
static int ov08x40_probe(struct i2c_client *client)
-{
- struct ov08x40 *ov08x;
+{ struct ov08x40 *ov08x;
int ret;
bool full_power;
+ ov08x = devm_kzalloc(&client->dev, sizeof(*ov08x), GFP_KERNEL);
+ if (!ov08x)
+ return -ENOMEM;
+
/* Check HW config */
- ret = ov08x40_check_hwcfg(&client->dev);
+ ret = ov08x40_check_hwcfg(ov08x, &client->dev);
if (ret) {
dev_err(&client->dev, "failed to check hwcfg: %d", ret);
return ret;
}
- ov08x = devm_kzalloc(&client->dev, sizeof(*ov08x), GFP_KERNEL);
- if (!ov08x)
- return -ENOMEM;
-
/* Initialize subdev */
v4l2_i2c_subdev_init(&ov08x->sd, client, &ov08x40_subdev_ops);
full_power = acpi_dev_state_d0(&client->dev);
if (full_power) {
+ ret = ov08x40_power_on(&client->dev);
+ if (ret) {
+ dev_err(&client->dev, "failed to power on\n");
+ return ret;
+ }
+
/* Check module identity */
ret = ov08x40_identify_module(ov08x);
if (ret) {
dev_err(&client->dev, "failed to find sensor: %d\n", ret);
- return ret;
+ goto probe_power_off;
}
}
@@ -2154,7 +2275,7 @@ static int ov08x40_probe(struct i2c_client *client)
ret = ov08x40_init_controls(ov08x);
if (ret)
- return ret;
+ goto probe_power_off;
/* Initialize subdev */
ov08x->sd.internal_ops = &ov08x40_internal_ops;
@@ -2187,6 +2308,9 @@ error_media_entity:
error_handler_free:
ov08x40_free_controls(ov08x);
+probe_power_off:
+ ov08x40_power_off(&client->dev);
+
return ret;
}
@@ -2201,6 +2325,8 @@ static void ov08x40_remove(struct i2c_client *client)
pm_runtime_disable(&client->dev);
pm_runtime_set_suspended(&client->dev);
+
+ ov08x40_power_off(&client->dev);
}
#ifdef CONFIG_ACPI
@@ -2212,10 +2338,17 @@ static const struct acpi_device_id ov08x40_acpi_ids[] = {
MODULE_DEVICE_TABLE(acpi, ov08x40_acpi_ids);
#endif
+static const struct of_device_id ov08x40_of_match[] = {
+ { .compatible = "ovti,ov08x40" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, ov08x40_of_match);
+
static struct i2c_driver ov08x40_i2c_driver = {
.driver = {
.name = "ov08x40",
.acpi_match_table = ACPI_PTR(ov08x40_acpi_ids),
+ .of_match_table = ov08x40_of_match,
},
.probe = ov08x40_probe,
.remove = ov08x40_remove,
diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c
index bd0b2f0f0d45..c484b753a718 100644
--- a/drivers/media/i2c/ov2740.c
+++ b/drivers/media/i2c/ov2740.c
@@ -530,7 +530,7 @@ struct ov2740 {
/* Current mode */
const struct ov2740_mode *cur_mode;
- /* NVM data inforamtion */
+ /* NVM data information */
struct nvm_data *nvm;
/* Supported modes */
@@ -1132,7 +1132,8 @@ static int ov2740_check_hwcfg(struct device *dev)
*/
ep = fwnode_graph_get_next_endpoint(fwnode, NULL);
if (!ep)
- return -EPROBE_DEFER;
+ return dev_err_probe(dev, -EPROBE_DEFER,
+ "waiting for fwnode graph endpoint\n");
ret = fwnode_property_read_u32(fwnode, "clock-frequency", &mclk);
if (ret) {
@@ -1330,7 +1331,7 @@ static int ov2740_probe(struct i2c_client *client)
ret = ov2740_check_hwcfg(dev);
if (ret)
- return dev_err_probe(dev, ret, "failed to check HW configuration\n");
+ return ret;
ov2740->reset_gpio = devm_gpiod_get_optional(dev, "reset", GPIOD_OUT_HIGH);
if (IS_ERR(ov2740->reset_gpio)) {
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index c1d3fce4a7d3..da5cb5f45a4f 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -377,7 +377,7 @@ struct reg_value {
struct ov5640_timings {
/* Analog crop rectangle. */
struct v4l2_rect analog_crop;
- /* Visibile crop: from analog crop top-left corner. */
+ /* Visible crop: from analog crop top-left corner. */
struct v4l2_rect crop;
/* Total pixels per line: width + fixed hblank. */
u32 htot;
diff --git a/drivers/media/i2c/ov5645.c b/drivers/media/i2c/ov5645.c
index 0c32bd2940ec..004d0ee5c3f5 100644
--- a/drivers/media/i2c/ov5645.c
+++ b/drivers/media/i2c/ov5645.c
@@ -88,7 +88,6 @@ struct ov5645 {
struct v4l2_subdev sd;
struct media_pad pad;
struct v4l2_fwnode_endpoint ep;
- struct v4l2_mbus_framefmt fmt;
struct v4l2_rect crop;
struct clk *xclk;
@@ -105,8 +104,6 @@ struct ov5645 {
u8 timing_tc_reg20;
u8 timing_tc_reg21;
- struct mutex power_lock; /* lock to protect power state */
-
struct gpio_desc *enable_gpio;
struct gpio_desc *rst_gpio;
};
@@ -781,11 +778,8 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl)
struct ov5645, ctrls);
int ret;
- mutex_lock(&ov5645->power_lock);
- if (!pm_runtime_get_if_in_use(ov5645->dev)) {
- mutex_unlock(&ov5645->power_lock);
+ if (!pm_runtime_get_if_in_use(ov5645->dev))
return 0;
- }
switch (ctrl->id) {
case V4L2_CID_SATURATION:
@@ -816,7 +810,6 @@ static int ov5645_s_ctrl(struct v4l2_ctrl *ctrl)
pm_runtime_mark_last_busy(ov5645->dev);
pm_runtime_put_autosuspend(ov5645->dev);
- mutex_unlock(&ov5645->power_lock);
return ret;
}
@@ -855,49 +848,6 @@ static int ov5645_enum_frame_size(struct v4l2_subdev *subdev,
return 0;
}
-static struct v4l2_mbus_framefmt *
-__ov5645_get_pad_format(struct ov5645 *ov5645,
- 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_format(sd_state, pad);
- case V4L2_SUBDEV_FORMAT_ACTIVE:
- return &ov5645->fmt;
- default:
- return NULL;
- }
-}
-
-static int ov5645_get_format(struct v4l2_subdev *sd,
- struct v4l2_subdev_state *sd_state,
- struct v4l2_subdev_format *format)
-{
- struct ov5645 *ov5645 = to_ov5645(sd);
-
- format->format = *__ov5645_get_pad_format(ov5645, sd_state,
- format->pad,
- format->which);
- return 0;
-}
-
-static struct v4l2_rect *
-__ov5645_get_pad_crop(struct ov5645 *ov5645,
- 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 &ov5645->crop;
- default:
- return NULL;
- }
-}
-
static int ov5645_set_format(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_format *format)
@@ -908,33 +858,30 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
const struct ov5645_mode_info *new_mode;
int ret;
- __crop = __ov5645_get_pad_crop(ov5645, sd_state, format->pad,
- format->which);
-
+ __crop = v4l2_subdev_state_get_crop(sd_state, 0);
new_mode = v4l2_find_nearest_size(ov5645_mode_info_data,
- ARRAY_SIZE(ov5645_mode_info_data),
- width, height,
- format->format.width, format->format.height);
+ ARRAY_SIZE(ov5645_mode_info_data),
+ width, height, format->format.width,
+ format->format.height);
__crop->width = new_mode->width;
__crop->height = new_mode->height;
if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- ret = v4l2_ctrl_s_ctrl_int64(ov5645->pixel_clock,
- new_mode->pixel_clock);
+ ret = __v4l2_ctrl_s_ctrl_int64(ov5645->pixel_clock,
+ new_mode->pixel_clock);
if (ret < 0)
return ret;
- ret = v4l2_ctrl_s_ctrl(ov5645->link_freq,
- new_mode->link_freq);
+ ret = __v4l2_ctrl_s_ctrl(ov5645->link_freq,
+ new_mode->link_freq);
if (ret < 0)
return ret;
ov5645->current_mode = new_mode;
}
- __format = __ov5645_get_pad_format(ov5645, sd_state, format->pad,
- format->which);
+ __format = v4l2_subdev_state_get_format(sd_state, 0);
__format->width = __crop->width;
__format->height = __crop->height;
__format->code = MEDIA_BUS_FMT_UYVY8_1X16;
@@ -949,11 +896,15 @@ static int ov5645_set_format(struct v4l2_subdev *sd,
static int ov5645_init_state(struct v4l2_subdev *subdev,
struct v4l2_subdev_state *sd_state)
{
- struct v4l2_subdev_format fmt = { 0 };
-
- fmt.which = sd_state ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- fmt.format.width = 1920;
- fmt.format.height = 1080;
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_TRY,
+ .pad = 0,
+ .format = {
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .width = ov5645_mode_info_data[1].width,
+ .height = ov5645_mode_info_data[1].height,
+ },
+ };
ov5645_set_format(subdev, sd_state, &fmt);
@@ -964,82 +915,88 @@ static int ov5645_get_selection(struct v4l2_subdev *sd,
struct v4l2_subdev_state *sd_state,
struct v4l2_subdev_selection *sel)
{
- struct ov5645 *ov5645 = to_ov5645(sd);
-
if (sel->target != V4L2_SEL_TGT_CROP)
return -EINVAL;
- sel->r = *__ov5645_get_pad_crop(ov5645, sd_state, sel->pad,
- sel->which);
+ sel->r = *v4l2_subdev_state_get_crop(sd_state, 0);
return 0;
}
-static int ov5645_s_stream(struct v4l2_subdev *subdev, int enable)
+static int ov5645_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
{
- struct ov5645 *ov5645 = to_ov5645(subdev);
+ struct ov5645 *ov5645 = to_ov5645(sd);
int ret;
- if (enable) {
- ret = pm_runtime_resume_and_get(ov5645->dev);
- if (ret < 0)
- return ret;
+ ret = pm_runtime_resume_and_get(ov5645->dev);
+ if (ret < 0)
+ return ret;
- ret = ov5645_set_register_array(ov5645,
+ ret = ov5645_set_register_array(ov5645,
ov5645->current_mode->data,
ov5645->current_mode->data_size);
- if (ret < 0) {
- dev_err(ov5645->dev, "could not set mode %dx%d\n",
- ov5645->current_mode->width,
- ov5645->current_mode->height);
- goto err_rpm_put;
- }
- ret = v4l2_ctrl_handler_setup(&ov5645->ctrls);
- if (ret < 0) {
- dev_err(ov5645->dev, "could not sync v4l2 controls\n");
- goto err_rpm_put;
- }
-
- ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x45);
- if (ret < 0)
- goto err_rpm_put;
-
- ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0,
- OV5645_SYSTEM_CTRL0_START);
- if (ret < 0)
- goto err_rpm_put;
- } else {
- ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x40);
- if (ret < 0)
- goto stream_off_rpm_put;
+ if (ret < 0) {
+ dev_err(ov5645->dev, "could not set mode %dx%d\n",
+ ov5645->current_mode->width,
+ ov5645->current_mode->height);
+ goto err_rpm_put;
+ }
+ ret = __v4l2_ctrl_handler_setup(&ov5645->ctrls);
+ if (ret < 0) {
+ dev_err(ov5645->dev, "could not sync v4l2 controls\n");
+ goto err_rpm_put;
+ }
- ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0,
- OV5645_SYSTEM_CTRL0_STOP);
+ ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x45);
+ if (ret < 0)
+ goto err_rpm_put;
- goto stream_off_rpm_put;
- }
+ ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0,
+ OV5645_SYSTEM_CTRL0_START);
+ if (ret < 0)
+ goto err_rpm_put;
return 0;
err_rpm_put:
pm_runtime_put_sync(ov5645->dev);
return ret;
+}
+
+static int ov5645_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
+{
+ struct ov5645 *ov5645 = to_ov5645(sd);
+ int ret;
+
+ ret = ov5645_write_reg(ov5645, OV5645_IO_MIPI_CTRL00, 0x40);
+ if (ret < 0)
+ goto rpm_put;
-stream_off_rpm_put:
+ ret = ov5645_write_reg(ov5645, OV5645_SYSTEM_CTRL0,
+ OV5645_SYSTEM_CTRL0_STOP);
+
+rpm_put:
pm_runtime_mark_last_busy(ov5645->dev);
pm_runtime_put_autosuspend(ov5645->dev);
+
return ret;
}
static const struct v4l2_subdev_video_ops ov5645_video_ops = {
- .s_stream = ov5645_s_stream,
+ .s_stream = v4l2_subdev_s_stream_helper,
};
static const struct v4l2_subdev_pad_ops ov5645_subdev_pad_ops = {
.enum_mbus_code = ov5645_enum_mbus_code,
.enum_frame_size = ov5645_enum_frame_size,
- .get_fmt = ov5645_get_format,
+ .get_fmt = v4l2_subdev_get_fmt,
.set_fmt = ov5645_set_format,
.get_selection = ov5645_get_selection,
+ .enable_streams = ov5645_enable_streams,
+ .disable_streams = ov5645_disable_streams,
};
static const struct v4l2_subdev_ops ov5645_subdev_ops = {
@@ -1069,51 +1026,44 @@ static int ov5645_probe(struct i2c_client *client)
ov5645->dev = dev;
endpoint = of_graph_get_endpoint_by_regs(dev->of_node, 0, -1);
- if (!endpoint) {
- dev_err(dev, "endpoint node not found\n");
- return -EINVAL;
- }
+ if (!endpoint)
+ return dev_err_probe(dev, -EINVAL,
+ "endpoint node not found\n");
ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(endpoint),
&ov5645->ep);
of_node_put(endpoint);
- if (ret < 0) {
- dev_err(dev, "parsing endpoint node failed\n");
- return ret;
- }
+ if (ret < 0)
+ return dev_err_probe(dev, ret,
+ "parsing endpoint node failed\n");
- if (ov5645->ep.bus_type != V4L2_MBUS_CSI2_DPHY) {
- dev_err(dev, "invalid bus type, must be CSI2\n");
- return -EINVAL;
- }
+ if (ov5645->ep.bus_type != V4L2_MBUS_CSI2_DPHY)
+ return dev_err_probe(dev, -EINVAL,
+ "invalid bus type, must be CSI2\n");
/* get system clock (xclk) */
ov5645->xclk = devm_clk_get(dev, NULL);
- if (IS_ERR(ov5645->xclk)) {
- dev_err(dev, "could not get xclk");
- return PTR_ERR(ov5645->xclk);
- }
+ if (IS_ERR(ov5645->xclk))
+ return dev_err_probe(dev, PTR_ERR(ov5645->xclk),
+ "could not get xclk");
ret = of_property_read_u32(dev->of_node, "clock-frequency", &xclk_freq);
- if (ret) {
- dev_err(dev, "could not get xclk frequency\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "could not get xclk frequency\n");
/* external clock must be 24MHz, allow 1% tolerance */
- if (xclk_freq < 23760000 || xclk_freq > 24240000) {
- dev_err(dev, "external clock frequency %u is not supported\n",
- xclk_freq);
- return -EINVAL;
- }
+ if (xclk_freq < 23760000 || xclk_freq > 24240000)
+ return dev_err_probe(dev, -EINVAL,
+ "unsupported xclk frequency %u\n",
+ xclk_freq);
ret = clk_set_rate(ov5645->xclk, xclk_freq);
- if (ret) {
- dev_err(dev, "could not set xclk frequency\n");
- return ret;
- }
+ if (ret)
+ return dev_err_probe(dev, ret,
+ "could not set xclk frequency\n");
for (i = 0; i < OV5645_NUM_SUPPLIES; i++)
ov5645->supplies[i].supply = ov5645_supply_name[i];
@@ -1124,18 +1074,14 @@ static int ov5645_probe(struct i2c_client *client)
return ret;
ov5645->enable_gpio = devm_gpiod_get(dev, "enable", GPIOD_OUT_HIGH);
- if (IS_ERR(ov5645->enable_gpio)) {
- dev_err(dev, "cannot get enable gpio\n");
- return PTR_ERR(ov5645->enable_gpio);
- }
+ if (IS_ERR(ov5645->enable_gpio))
+ return dev_err_probe(dev, PTR_ERR(ov5645->enable_gpio),
+ "cannot get enable gpio\n");
ov5645->rst_gpio = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
- if (IS_ERR(ov5645->rst_gpio)) {
- dev_err(dev, "cannot get reset gpio\n");
- return PTR_ERR(ov5645->rst_gpio);
- }
-
- mutex_init(&ov5645->power_lock);
+ if (IS_ERR(ov5645->rst_gpio))
+ return dev_err_probe(dev, PTR_ERR(ov5645->rst_gpio),
+ "cannot get reset gpio\n");
v4l2_ctrl_handler_init(&ov5645->ctrls, 9);
v4l2_ctrl_new_std(&ov5645->ctrls, &ov5645_ctrl_ops,
@@ -1170,9 +1116,8 @@ static int ov5645_probe(struct i2c_client *client)
ov5645->sd.ctrl_handler = &ov5645->ctrls;
if (ov5645->ctrls.error) {
- dev_err(dev, "%s: control initialization error %d\n",
- __func__, ov5645->ctrls.error);
ret = ov5645->ctrls.error;
+ dev_err_probe(dev, ret, "failed to add controls\n");
goto free_ctrl;
}
@@ -1180,12 +1125,12 @@ static int ov5645_probe(struct i2c_client *client)
ov5645->sd.internal_ops = &ov5645_internal_ops;
ov5645->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ov5645->pad.flags = MEDIA_PAD_FL_SOURCE;
- ov5645->sd.dev = &client->dev;
+ ov5645->sd.dev = dev;
ov5645->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&ov5645->sd.entity, 1, &ov5645->pad);
if (ret < 0) {
- dev_err(dev, "could not register media entity\n");
+ dev_err_probe(dev, ret, "could not register media entity\n");
goto free_ctrl;
}
@@ -1195,14 +1140,14 @@ static int ov5645_probe(struct i2c_client *client)
ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_HIGH, &chip_id_high);
if (ret < 0 || chip_id_high != OV5645_CHIP_ID_HIGH_BYTE) {
- dev_err(dev, "could not read ID high\n");
ret = -ENODEV;
+ dev_err_probe(dev, ret, "could not read ID high\n");
goto power_down;
}
ret = ov5645_read_reg(ov5645, OV5645_CHIP_ID_LOW, &chip_id_low);
if (ret < 0 || chip_id_low != OV5645_CHIP_ID_LOW_BYTE) {
- dev_err(dev, "could not read ID low\n");
ret = -ENODEV;
+ dev_err_probe(dev, ret, "could not read ID low\n");
goto power_down;
}
@@ -1211,24 +1156,31 @@ static int ov5645_probe(struct i2c_client *client)
ret = ov5645_read_reg(ov5645, OV5645_AEC_PK_MANUAL,
&ov5645->aec_pk_manual);
if (ret < 0) {
- dev_err(dev, "could not read AEC/AGC mode\n");
ret = -ENODEV;
+ dev_err_probe(dev, ret, "could not read AEC/AGC mode\n");
goto power_down;
}
ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG20,
&ov5645->timing_tc_reg20);
if (ret < 0) {
- dev_err(dev, "could not read vflip value\n");
ret = -ENODEV;
+ dev_err_probe(dev, ret, "could not read vflip value\n");
goto power_down;
}
ret = ov5645_read_reg(ov5645, OV5645_TIMING_TC_REG21,
&ov5645->timing_tc_reg21);
if (ret < 0) {
- dev_err(dev, "could not read hflip value\n");
ret = -ENODEV;
+ dev_err_probe(dev, ret, "could not read hflip value\n");
+ goto power_down;
+ }
+
+ ov5645->sd.state_lock = ov5645->ctrls.lock;
+ ret = v4l2_subdev_init_finalize(&ov5645->sd);
+ if (ret < 0) {
+ dev_err_probe(dev, ret, "subdev init error\n");
goto power_down;
}
@@ -1236,11 +1188,9 @@ static int ov5645_probe(struct i2c_client *client)
pm_runtime_get_noresume(dev);
pm_runtime_enable(dev);
- ov5645_init_state(&ov5645->sd, NULL);
-
- ret = v4l2_async_register_subdev(&ov5645->sd);
+ ret = v4l2_async_register_subdev_sensor(&ov5645->sd);
if (ret < 0) {
- dev_err(dev, "could not register v4l2 device\n");
+ dev_err_probe(dev, ret, "could not register v4l2 device\n");
goto err_pm_runtime;
}
@@ -1254,13 +1204,13 @@ static int ov5645_probe(struct i2c_client *client)
err_pm_runtime:
pm_runtime_disable(dev);
pm_runtime_put_noidle(dev);
+ v4l2_subdev_cleanup(&ov5645->sd);
power_down:
ov5645_set_power_off(dev);
free_entity:
media_entity_cleanup(&ov5645->sd.entity);
free_ctrl:
v4l2_ctrl_handler_free(&ov5645->ctrls);
- mutex_destroy(&ov5645->power_lock);
return ret;
}
@@ -1271,13 +1221,13 @@ static void ov5645_remove(struct i2c_client *client)
struct ov5645 *ov5645 = to_ov5645(sd);
v4l2_async_unregister_subdev(&ov5645->sd);
+ v4l2_subdev_cleanup(sd);
media_entity_cleanup(&ov5645->sd.entity);
v4l2_ctrl_handler_free(&ov5645->ctrls);
pm_runtime_disable(ov5645->dev);
if (!pm_runtime_status_suspended(ov5645->dev))
ov5645_set_power_off(ov5645->dev);
pm_runtime_set_suspended(ov5645->dev);
- mutex_destroy(&ov5645->power_lock);
}
static const struct i2c_device_id ov5645_id[] = {
diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index f051045d340f..c54bbc207189 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -1879,7 +1879,7 @@ struct ov5670 {
struct gpio_desc *pwdn_gpio; /* PWDNB pin. */
struct gpio_desc *reset_gpio; /* XSHUTDOWN pin. */
- /* To serialize asynchronus callbacks */
+ /* To serialize asynchronous callbacks */
struct mutex mutex;
/* True if the device has been identified */
diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c
index 2833b14ee139..c1081deffc2f 100644
--- a/drivers/media/i2c/ov5675.c
+++ b/drivers/media/i2c/ov5675.c
@@ -510,7 +510,7 @@ struct ov5675 {
/* Current mode */
const struct ov5675_mode *cur_mode;
- /* To serialize asynchronus callbacks */
+ /* To serialize asynchronous callbacks */
struct mutex mutex;
/* True if the device has been identified */
@@ -732,7 +732,7 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_EXPOSURE:
/* 4 least significant bits of expsoure are fractional part
* val = val << 4
- * for ov5675, the unit of exposure is differnt from other
+ * for ov5675, the unit of exposure is different from other
* OmniVision sensors, its exposure value is twice of the
* register value, the exposure should be divided by 2 before
* set register, e.g. val << 3.
diff --git a/drivers/media/i2c/ov64a40.c b/drivers/media/i2c/ov64a40.c
index 541bf74581d2..a5da4fe47e0b 100644
--- a/drivers/media/i2c/ov64a40.c
+++ b/drivers/media/i2c/ov64a40.c
@@ -18,7 +18,6 @@
#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>
#include <media/v4l2-subdev.h>
@@ -3200,13 +3199,7 @@ static const struct v4l2_subdev_pad_ops ov64a40_pad_ops = {
.get_selection = ov64a40_get_selection,
};
-static const struct v4l2_subdev_core_ops ov64a40_core_ops = {
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-};
-
static const struct v4l2_subdev_ops ov64a40_subdev_ops = {
- .core = &ov64a40_core_ops,
.video = &ov64a40_video_ops,
.pad = &ov64a40_pad_ops,
};
@@ -3605,8 +3598,7 @@ static int ov64a40_probe(struct i2c_client *client)
/* Initialize subdev */
ov64a40->sd.internal_ops = &ov64a40_internal_ops;
- ov64a40->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE
- | V4L2_SUBDEV_FL_HAS_EVENTS;
+ ov64a40->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
ov64a40->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
ov64a40->pad.flags = MEDIA_PAD_FL_SOURCE;
diff --git a/drivers/media/i2c/ov772x.c b/drivers/media/i2c/ov772x.c
index 3b0fdb3c70c0..062e1023a411 100644
--- a/drivers/media/i2c/ov772x.c
+++ b/drivers/media/i2c/ov772x.c
@@ -269,7 +269,7 @@
#define AF_8x 0x08 /* Add frame when AGC reaches 8x gain */
#define AF_16x 0x0c /* Add frame when AGC reaches 16x gain */
/* AEC max step control */
-#define AEC_NO_LIMIT 0x01 /* 0 : AEC incease step has limit */
+#define AEC_NO_LIMIT 0x01 /* 0 : AEC increase step has limit */
/* 1 : No limit to AEC increase step */
/* CLKRC */
/* Input clock divider register */
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
index 0830676e5d5a..1f1c0de8e510 100644
--- a/drivers/media/i2c/ov7740.c
+++ b/drivers/media/i2c/ov7740.c
@@ -117,7 +117,7 @@ struct ov7740 {
struct v4l2_ctrl *brightness;
struct v4l2_ctrl *contrast;
- struct mutex mutex; /* To serialize asynchronus callbacks */
+ struct mutex mutex; /* To serialize asynchronous callbacks */
struct gpio_desc *resetb_gpio;
struct gpio_desc *pwdn_gpio;
diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c
index 3b94338f55ed..e6704d018248 100644
--- a/drivers/media/i2c/ov8856.c
+++ b/drivers/media/i2c/ov8856.c
@@ -1435,7 +1435,7 @@ struct ov8856 {
/* Application specified mbus format */
u32 cur_mbus_index;
- /* To serialize asynchronus callbacks */
+ /* To serialize asynchronous callbacks */
struct mutex mutex;
/* lanes index */
diff --git a/drivers/media/i2c/ov8858.c b/drivers/media/i2c/ov8858.c
index 326f50a5ab51..95f9ae794846 100644
--- a/drivers/media/i2c/ov8858.c
+++ b/drivers/media/i2c/ov8858.c
@@ -24,7 +24,6 @@
#include <media/v4l2-common.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>
#include <media/v4l2-subdev.h>
@@ -1500,13 +1499,7 @@ static const struct v4l2_subdev_pad_ops ov8858_pad_ops = {
.set_fmt = ov8858_set_fmt,
};
-static const struct v4l2_subdev_core_ops ov8858_core_ops = {
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
-};
-
static const struct v4l2_subdev_ops ov8858_subdev_ops = {
- .core = &ov8858_core_ops,
.video = &ov8858_video_ops,
.pad = &ov8858_pad_ops,
};
@@ -1917,7 +1910,7 @@ static int ov8858_probe(struct i2c_client *client)
return ret;
sd = &ov8858->subdev;
- sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+ sd->flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
ov8858->pad.flags = MEDIA_PAD_FL_SOURCE;
sd->entity.function = MEDIA_ENT_F_CAM_SENSOR;
ret = media_entity_pads_init(&sd->entity, 1, &ov8858->pad);
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 56df97c9886b..026ea34d6291 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -286,7 +286,7 @@ static const struct i2c_rv ov965x_init_regs[] = {
{ REG_COM5, 0x00 }, /* System clock options */
{ REG_COM2, 0x01 }, /* Output drive, soft sleep mode */
{ REG_COM10, 0x00 }, /* Slave mode, HREF vs HSYNC, signals negate */
- { REG_EDGE, 0xa6 }, /* Edge enhancement treshhold and factor */
+ { REG_EDGE, 0xa6 }, /* Edge enhancement threshold and factor */
{ REG_COM16, 0x02 }, /* Color matrix coeff double option */
{ REG_COM17, 0x08 }, /* Single frame out, banding filter */
{ 0x16, 0x06 },
diff --git a/drivers/media/i2c/ov9734.c b/drivers/media/i2c/ov9734.c
index bf9e2adbff34..cae3aeefb616 100644
--- a/drivers/media/i2c/ov9734.c
+++ b/drivers/media/i2c/ov9734.c
@@ -335,7 +335,7 @@ struct ov9734 {
/* Current mode */
const struct ov9734_mode *cur_mode;
- /* To serialize asynchronus callbacks */
+ /* To serialize asynchronous callbacks */
struct mutex mutex;
};
diff --git a/drivers/media/i2c/st-mipid02.c b/drivers/media/i2c/st-mipid02.c
index b947a55281f0..f08db3cfe076 100644
--- a/drivers/media/i2c/st-mipid02.c
+++ b/drivers/media/i2c/st-mipid02.c
@@ -14,6 +14,7 @@
#include <linux/gpio/consumer.h>
#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/pm_runtime.h>
#include <linux/of_graph.h>
#include <linux/regulator/consumer.h>
#include <media/mipi-csi2.h>
@@ -67,9 +68,6 @@ static const u32 mipid02_supported_fmt_codes[] = {
MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YVYU8_1X16,
MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_VYUY8_1X16,
MEDIA_BUS_FMT_RGB565_1X16, MEDIA_BUS_FMT_BGR888_1X24,
- MEDIA_BUS_FMT_RGB565_2X8_LE, MEDIA_BUS_FMT_RGB565_2X8_BE,
- MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YVYU8_2X8,
- MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_VYUY8_2X8,
MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_JPEG_1X8
};
@@ -100,6 +98,7 @@ struct mipid02_dev {
/* remote source */
struct v4l2_async_notifier notifier;
struct v4l2_subdev *s_subdev;
+ u16 s_subdev_pad_id;
/* registers */
struct {
u8 clk_lane_reg1;
@@ -138,12 +137,6 @@ static int bpp_from_code(__u32 code)
case MEDIA_BUS_FMT_UYVY8_1X16:
case MEDIA_BUS_FMT_VYUY8_1X16:
case MEDIA_BUS_FMT_RGB565_1X16:
- case MEDIA_BUS_FMT_YUYV8_2X8:
- case MEDIA_BUS_FMT_YVYU8_2X8:
- case MEDIA_BUS_FMT_UYVY8_2X8:
- case MEDIA_BUS_FMT_VYUY8_2X8:
- case MEDIA_BUS_FMT_RGB565_2X8_LE:
- case MEDIA_BUS_FMT_RGB565_2X8_BE:
return 16;
case MEDIA_BUS_FMT_BGR888_1X24:
return 24;
@@ -175,16 +168,10 @@ static u8 data_type_from_code(__u32 code)
case MEDIA_BUS_FMT_YVYU8_1X16:
case MEDIA_BUS_FMT_UYVY8_1X16:
case MEDIA_BUS_FMT_VYUY8_1X16:
- case MEDIA_BUS_FMT_YUYV8_2X8:
- case MEDIA_BUS_FMT_YVYU8_2X8:
- case MEDIA_BUS_FMT_UYVY8_2X8:
- case MEDIA_BUS_FMT_VYUY8_2X8:
return MIPI_CSI2_DT_YUV422_8B;
case MEDIA_BUS_FMT_BGR888_1X24:
return MIPI_CSI2_DT_RGB888;
case MEDIA_BUS_FMT_RGB565_1X16:
- case MEDIA_BUS_FMT_RGB565_2X8_LE:
- case MEDIA_BUS_FMT_RGB565_2X8_BE:
return MIPI_CSI2_DT_RGB565;
default:
return 0;
@@ -248,8 +235,10 @@ static void mipid02_apply_reset(struct mipid02_dev *bridge)
usleep_range(5000, 10000);
}
-static int mipid02_set_power_on(struct mipid02_dev *bridge)
+static int mipid02_set_power_on(struct device *dev)
{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct mipid02_dev *bridge = to_mipid02_dev(sd);
struct i2c_client *client = bridge->i2c_client;
int ret;
@@ -282,10 +271,15 @@ xclk_off:
return ret;
}
-static void mipid02_set_power_off(struct mipid02_dev *bridge)
+static int mipid02_set_power_off(struct device *dev)
{
+ struct v4l2_subdev *sd = dev_get_drvdata(dev);
+ struct mipid02_dev *bridge = to_mipid02_dev(sd);
+
regulator_bulk_disable(MIPID02_NUM_SUPPLIES, bridge->supplies);
clk_disable_unprepare(bridge->xclk);
+
+ return 0;
}
static int mipid02_detect(struct mipid02_dev *bridge)
@@ -447,15 +441,19 @@ static int mipid02_configure_from_code(struct mipid02_dev *bridge,
return 0;
}
-static int mipid02_stream_disable(struct mipid02_dev *bridge)
+static int mipid02_disable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
{
+ struct mipid02_dev *bridge = to_mipid02_dev(sd);
struct i2c_client *client = bridge->i2c_client;
int ret = -EINVAL;
if (!bridge->s_subdev)
goto error;
- ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 0);
+ ret = v4l2_subdev_disable_streams(bridge->s_subdev,
+ bridge->s_subdev_pad_id, BIT(0));
if (ret)
goto error;
@@ -465,6 +463,10 @@ static int mipid02_stream_disable(struct mipid02_dev *bridge)
cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, 0, &ret);
if (ret)
goto error;
+
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+
error:
if (ret)
dev_err(&client->dev, "failed to stream off %d", ret);
@@ -472,33 +474,36 @@ error:
return ret;
}
-static int mipid02_stream_enable(struct mipid02_dev *bridge)
+static int mipid02_enable_streams(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state, u32 pad,
+ u64 streams_mask)
{
+ struct mipid02_dev *bridge = to_mipid02_dev(sd);
struct i2c_client *client = bridge->i2c_client;
- struct v4l2_subdev_state *state;
struct v4l2_mbus_framefmt *fmt;
int ret = -EINVAL;
if (!bridge->s_subdev)
- goto error;
+ return ret;
memset(&bridge->r, 0, sizeof(bridge->r));
- state = v4l2_subdev_lock_and_get_active_state(&bridge->sd);
fmt = v4l2_subdev_state_get_format(state, MIPID02_SINK_0);
/* build registers content */
ret = mipid02_configure_from_rx(bridge, fmt);
if (ret)
- goto error;
+ return ret;
ret = mipid02_configure_from_tx(bridge);
if (ret)
- goto error;
+ return ret;
ret = mipid02_configure_from_code(bridge, fmt);
if (ret)
- goto error;
+ return ret;
- v4l2_subdev_unlock_state(state);
+ ret = pm_runtime_resume_and_get(&client->dev);
+ if (ret < 0)
+ return ret;
/* write mipi registers */
cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1,
@@ -524,33 +529,20 @@ static int mipid02_stream_enable(struct mipid02_dev *bridge)
if (ret)
goto error;
- ret = v4l2_subdev_call(bridge->s_subdev, video, s_stream, 1);
+ ret = v4l2_subdev_enable_streams(bridge->s_subdev,
+ bridge->s_subdev_pad_id, BIT(0));
if (ret)
goto error;
return 0;
error:
- dev_err(&client->dev, "failed to stream on %d", ret);
- mipid02_stream_disable(bridge);
-
- return ret;
-}
-
-static int mipid02_s_stream(struct v4l2_subdev *sd, int enable)
-{
- struct mipid02_dev *bridge = to_mipid02_dev(sd);
- struct i2c_client *client = bridge->i2c_client;
- int ret = 0;
-
- dev_dbg(&client->dev, "%s : requested %d\n", __func__, enable);
-
- ret = enable ? mipid02_stream_enable(bridge) :
- mipid02_stream_disable(bridge);
- if (ret)
- dev_err(&client->dev, "failed to stream %s (%d)\n",
- enable ? "enable" : "disable", ret);
+ cci_write(bridge->regmap, MIPID02_CLK_LANE_REG1, 0, &ret);
+ cci_write(bridge->regmap, MIPID02_DATA_LANE0_REG1, 0, &ret);
+ cci_write(bridge->regmap, MIPID02_DATA_LANE1_REG1, 0, &ret);
+ pm_runtime_mark_last_busy(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
return ret;
}
@@ -640,13 +632,15 @@ static int mipid02_set_fmt(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_video_ops mipid02_video_ops = {
- .s_stream = mipid02_s_stream,
+ .s_stream = v4l2_subdev_s_stream_helper,
};
static const struct v4l2_subdev_pad_ops mipid02_pad_ops = {
.enum_mbus_code = mipid02_enum_mbus_code,
.get_fmt = v4l2_subdev_get_fmt,
.set_fmt = mipid02_set_fmt,
+ .enable_streams = mipid02_enable_streams,
+ .disable_streams = mipid02_disable_streams,
};
static const struct v4l2_subdev_ops mipid02_subdev_ops = {
@@ -692,6 +686,7 @@ static int mipid02_async_bound(struct v4l2_async_notifier *notifier,
}
bridge->s_subdev = s_subdev;
+ bridge->s_subdev_pad_id = source_pad;
return 0;
}
@@ -875,7 +870,7 @@ static int mipid02_probe(struct i2c_client *client)
}
/* enable clock, power and reset device if available */
- ret = mipid02_set_power_on(bridge);
+ ret = mipid02_set_power_on(&client->dev);
if (ret)
goto entity_cleanup;
@@ -897,6 +892,15 @@ static int mipid02_probe(struct i2c_client *client)
goto power_off;
}
+ /* Enable runtime PM and turn off the device */
+ pm_runtime_set_active(dev);
+ pm_runtime_get_noresume(&client->dev);
+ pm_runtime_enable(dev);
+
+ pm_runtime_set_autosuspend_delay(&client->dev, 1000);
+ pm_runtime_use_autosuspend(&client->dev);
+ pm_runtime_put_autosuspend(&client->dev);
+
ret = v4l2_async_register_subdev(&bridge->sd);
if (ret < 0) {
dev_err(&client->dev, "v4l2_async_register_subdev failed %d",
@@ -911,8 +915,10 @@ static int mipid02_probe(struct i2c_client *client)
unregister_notifier:
v4l2_async_nf_unregister(&bridge->notifier);
v4l2_async_nf_cleanup(&bridge->notifier);
+ pm_runtime_disable(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
power_off:
- mipid02_set_power_off(bridge);
+ mipid02_set_power_off(&client->dev);
entity_cleanup:
media_entity_cleanup(&bridge->sd.entity);
@@ -927,7 +933,11 @@ static void mipid02_remove(struct i2c_client *client)
v4l2_async_nf_unregister(&bridge->notifier);
v4l2_async_nf_cleanup(&bridge->notifier);
v4l2_async_unregister_subdev(&bridge->sd);
- mipid02_set_power_off(bridge);
+
+ pm_runtime_disable(&client->dev);
+ if (!pm_runtime_status_suspended(&client->dev))
+ mipid02_set_power_off(&client->dev);
+ pm_runtime_set_suspended(&client->dev);
media_entity_cleanup(&bridge->sd.entity);
}
@@ -937,10 +947,15 @@ static const struct of_device_id mipid02_dt_ids[] = {
};
MODULE_DEVICE_TABLE(of, mipid02_dt_ids);
+static const struct dev_pm_ops mipid02_pm_ops = {
+ RUNTIME_PM_OPS(mipid02_set_power_off, mipid02_set_power_on, NULL)
+};
+
static struct i2c_driver mipid02_i2c_driver = {
.driver = {
.name = "st-mipid02",
.of_match_table = mipid02_dt_ids,
+ .pm = pm_ptr(&mipid02_pm_ops),
},
.probe = mipid02_probe,
.remove = mipid02_remove,
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index 65d58ddf0287..c50d4e85dfd1 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -87,6 +87,10 @@ struct tc358743_state {
struct timer_list timer;
struct work_struct work_i2c_poll;
+ /* debugfs */
+ struct dentry *debugfs_dir;
+ struct v4l2_debugfs_if *infoframes;
+
/* edid */
u8 edid_blocks_written;
@@ -430,12 +434,35 @@ static void tc358743_erase_bksv(struct v4l2_subdev *sd)
/* --------------- AVI infoframe --------------- */
+static ssize_t
+tc358743_debugfs_if_read(u32 type, void *priv, struct file *filp,
+ char __user *ubuf, size_t count, loff_t *ppos)
+{
+ u8 buf[V4L2_DEBUGFS_IF_MAX_LEN] = {};
+ struct v4l2_subdev *sd = priv;
+ int len;
+
+ if (!is_hdmi(sd))
+ return 0;
+
+ if (type != V4L2_DEBUGFS_IF_AVI)
+ return 0;
+
+ i2c_rd(sd, PK_AVI_0HEAD, buf, PK_AVI_16BYTE - PK_AVI_0HEAD + 1);
+ len = buf[2] + 4;
+ if (len > V4L2_DEBUGFS_IF_MAX_LEN)
+ len = -ENOENT;
+ if (len > 0)
+ len = simple_read_from_buffer(ubuf, count, ppos, buf, len);
+ return len < 0 ? 0 : len;
+}
+
static void print_avi_infoframe(struct v4l2_subdev *sd)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct device *dev = &client->dev;
union hdmi_infoframe frame;
- u8 buffer[HDMI_INFOFRAME_SIZE(AVI)];
+ u8 buffer[HDMI_INFOFRAME_SIZE(AVI)] = {};
if (!is_hdmi(sd)) {
v4l2_info(sd, "DVI-D signal - AVI infoframe not supported\n");
@@ -2161,6 +2188,11 @@ static int tc358743_probe(struct i2c_client *client)
if (err < 0)
goto err_work_queues;
+ state->debugfs_dir = debugfs_create_dir(sd->name, v4l2_debugfs_root());
+ state->infoframes = v4l2_debugfs_if_alloc(state->debugfs_dir,
+ V4L2_DEBUGFS_IF_AVI, sd,
+ tc358743_debugfs_if_read);
+
v4l2_info(sd, "%s found @ 0x%x (%s)\n", client->name,
client->addr << 1, client->adapter->name);
@@ -2168,8 +2200,10 @@ static int tc358743_probe(struct i2c_client *client)
err_work_queues:
cec_unregister_adapter(state->cec_adap);
- if (!state->i2c_client->irq)
+ if (!state->i2c_client->irq) {
+ del_timer(&state->timer);
flush_work(&state->work_i2c_poll);
+ }
cancel_delayed_work(&state->delayed_work_enable_hotplug);
mutex_destroy(&state->confctl_mutex);
err_hdl:
@@ -2188,6 +2222,8 @@ static void tc358743_remove(struct i2c_client *client)
flush_work(&state->work_i2c_poll);
}
cancel_delayed_work_sync(&state->delayed_work_enable_hotplug);
+ v4l2_debugfs_if_free(state->infoframes);
+ debugfs_remove_recursive(state->debugfs_dir);
cec_unregister_adapter(state->cec_adap);
v4l2_async_unregister_subdev(sd);
v4l2_device_unregister_subdev(sd);
diff --git a/drivers/media/i2c/thp7312.c b/drivers/media/i2c/thp7312.c
index c77440ff098c..8852c56431fe 100644
--- a/drivers/media/i2c/thp7312.c
+++ b/drivers/media/i2c/thp7312.c
@@ -27,7 +27,6 @@
#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-subdev.h>
@@ -879,8 +878,6 @@ static int thp7312_init_state(struct v4l2_subdev *sd,
static const struct v4l2_subdev_core_ops thp7312_core_ops = {
.log_status = v4l2_ctrl_subdev_log_status,
- .subscribe_event = v4l2_ctrl_subdev_subscribe_event,
- .unsubscribe_event = v4l2_event_subdev_unsubscribe,
};
static const struct v4l2_subdev_video_ops thp7312_video_ops = {
@@ -2127,7 +2124,7 @@ static int thp7312_probe(struct i2c_client *client)
v4l2_i2c_subdev_init(&thp7312->sd, client, &thp7312_subdev_ops);
thp7312->sd.internal_ops = &thp7312_internal_ops;
- thp7312->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_HAS_EVENTS;
+ thp7312->sd.flags |= V4L2_SUBDEV_FL_HAS_DEVNODE;
thp7312->pad.flags = MEDIA_PAD_FL_SOURCE;
thp7312->sd.entity.function = MEDIA_ENT_F_CAM_SENSOR;
diff --git a/drivers/media/i2c/ths7303.c b/drivers/media/i2c/ths7303.c
index 7526fabc7ee4..b7cedc5b3e8e 100644
--- a/drivers/media/i2c/ths7303.c
+++ b/drivers/media/i2c/ths7303.c
@@ -7,7 +7,7 @@
* Author: Chaithrika U S <chaithrika@ti.com>
*
* Contributors:
- * Hans Verkuil <hans.verkuil@cisco.com>
+ * Hans Verkuil <hansverk@cisco.com>
* Lad, Prabhakar <prabhakar.lad@ti.com>
* Martin Bugge <marbugge@cisco.com>
*
diff --git a/drivers/media/i2c/vgxy61.c b/drivers/media/i2c/vgxy61.c
index 409d2d4ffb4b..d77468c8587b 100644
--- a/drivers/media/i2c/vgxy61.c
+++ b/drivers/media/i2c/vgxy61.c
@@ -1617,7 +1617,7 @@ static int vgxy61_detect(struct vgxy61_dev *sensor)
ret = cci_read(sensor->regmap, VGXY61_REG_NVM, &st, NULL);
if (ret < 0)
- return st;
+ return ret;
if (st != VGXY61_NVM_OK)
dev_warn(&client->dev, "Bad nvm state got %u\n", (u8)st);
diff --git a/drivers/media/i2c/video-i2c.c b/drivers/media/i2c/video-i2c.c
index 56dbe07a1c99..036a6375627a 100644
--- a/drivers/media/i2c/video-i2c.c
+++ b/drivers/media/i2c/video-i2c.c
@@ -566,8 +566,6 @@ static const struct vb2_ops video_i2c_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int video_i2c_querycap(struct file *file, void *priv,
@@ -798,13 +796,13 @@ static int video_i2c_probe(struct i2c_client *client)
queue->min_queued_buffers = 1;
queue->ops = &video_i2c_video_qops;
queue->mem_ops = &vb2_vmalloc_memops;
+ queue->lock = &data->queue_lock;
ret = vb2_queue_init(queue);
if (ret < 0)
goto error_unregister_device;
data->vdev.queue = queue;
- data->vdev.queue->lock = &data->queue_lock;
snprintf(data->vdev.name, sizeof(data->vdev.name),
"I2C %d-%d Transport Video",
diff --git a/drivers/media/mc/mc-entity.c b/drivers/media/mc/mc-entity.c
index 96dd0f6ccd0d..045590905582 100644
--- a/drivers/media/mc/mc-entity.c
+++ b/drivers/media/mc/mc-entity.c
@@ -768,10 +768,10 @@ done:
return ret;
}
-__must_check int __media_pipeline_start(struct media_pad *pad,
+__must_check int __media_pipeline_start(struct media_pad *origin,
struct media_pipeline *pipe)
{
- struct media_device *mdev = pad->graph_obj.mdev;
+ struct media_device *mdev = origin->graph_obj.mdev;
struct media_pipeline_pad *err_ppad;
struct media_pipeline_pad *ppad;
int ret;
@@ -782,7 +782,7 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
* If the pad is already part of a pipeline, that pipeline must be the
* same as the pipe given to media_pipeline_start().
*/
- if (WARN_ON(pad->pipe && pad->pipe != pipe))
+ if (WARN_ON(origin->pipe && origin->pipe != pipe))
return -EINVAL;
/*
@@ -799,7 +799,7 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
* with media_pipeline_pad instances for each pad found during graph
* walk.
*/
- ret = media_pipeline_populate(pipe, pad);
+ ret = media_pipeline_populate(pipe, origin);
if (ret)
return ret;
@@ -914,14 +914,14 @@ error:
}
EXPORT_SYMBOL_GPL(__media_pipeline_start);
-__must_check int media_pipeline_start(struct media_pad *pad,
+__must_check int media_pipeline_start(struct media_pad *origin,
struct media_pipeline *pipe)
{
- struct media_device *mdev = pad->graph_obj.mdev;
+ struct media_device *mdev = origin->graph_obj.mdev;
int ret;
mutex_lock(&mdev->graph_mutex);
- ret = __media_pipeline_start(pad, pipe);
+ ret = __media_pipeline_start(origin, pipe);
mutex_unlock(&mdev->graph_mutex);
return ret;
}
diff --git a/drivers/media/mc/mc-request.c b/drivers/media/mc/mc-request.c
index e064914c476e..5edfc2791ce7 100644
--- a/drivers/media/mc/mc-request.c
+++ b/drivers/media/mc/mc-request.c
@@ -6,7 +6,7 @@
* Copyright (C) 2018 Intel Corporation
* Copyright (C) 2018 Google, Inc.
*
- * Author: Hans Verkuil <hans.verkuil@cisco.com>
+ * Author: Hans Verkuil <hansverk@cisco.com>
* Author: Sakari Ailus <sakari.ailus@linux.intel.com>
*/
@@ -246,22 +246,21 @@ static const struct file_operations request_fops = {
struct media_request *
media_request_get_by_fd(struct media_device *mdev, int request_fd)
{
- struct fd f;
struct media_request *req;
if (!mdev || !mdev->ops ||
!mdev->ops->req_validate || !mdev->ops->req_queue)
return ERR_PTR(-EBADR);
- f = fdget(request_fd);
- if (!fd_file(f))
- goto err_no_req_fd;
+ CLASS(fd, f)(request_fd);
+ if (fd_empty(f))
+ goto err;
if (fd_file(f)->f_op != &request_fops)
- goto err_fput;
+ goto err;
req = fd_file(f)->private_data;
if (req->mdev != mdev)
- goto err_fput;
+ goto err;
/*
* Note: as long as someone has an open filehandle of the request,
@@ -272,14 +271,9 @@ media_request_get_by_fd(struct media_device *mdev, int request_fd)
* before media_request_get() is called.
*/
media_request_get(req);
- fdput(f);
-
return req;
-err_fput:
- fdput(f);
-
-err_no_req_fd:
+err:
dev_dbg(mdev->dev, "cannot find request_fd %d\n", request_fd);
return ERR_PTR(-EINVAL);
}
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 511f013cc338..2782832f5eb8 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -1584,8 +1584,6 @@ static const struct vb2_ops bttv_video_qops = {
.buf_cleanup = buf_cleanup,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static void radio_enable(struct bttv *btv)
diff --git a/drivers/media/pci/bt8xx/bttv-vbi.c b/drivers/media/pci/bt8xx/bttv-vbi.c
index e489a3acb4b9..a71440611e46 100644
--- a/drivers/media/pci/bt8xx/bttv-vbi.c
+++ b/drivers/media/pci/bt8xx/bttv-vbi.c
@@ -170,8 +170,6 @@ const struct vb2_ops bttv_vbi_qops = {
.buf_cleanup = buf_cleanup_vbi,
.start_streaming = start_streaming_vbi,
.stop_streaming = stop_streaming_vbi,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* ----------------------------------------------------------------------- */
diff --git a/drivers/media/pci/cobalt/cobalt-driver.c b/drivers/media/pci/cobalt/cobalt-driver.c
index 6e1a0614e6d0..39e25cc53edb 100644
--- a/drivers/media/pci/cobalt/cobalt-driver.c
+++ b/drivers/media/pci/cobalt/cobalt-driver.c
@@ -44,7 +44,7 @@ module_param_named(ignore_err, cobalt_ignore_err, int, 0644);
MODULE_PARM_DESC(ignore_err,
"If set then ignore missing i2c adapters/receivers. Default: 0\n");
-MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com> & Morten Hestnes");
+MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com> & Morten Hestnes");
MODULE_DESCRIPTION("cobalt driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/cobalt/cobalt-v4l2.c b/drivers/media/pci/cobalt/cobalt-v4l2.c
index d4d7b264c965..ae82427e3479 100644
--- a/drivers/media/pci/cobalt/cobalt-v4l2.c
+++ b/drivers/media/pci/cobalt/cobalt-v4l2.c
@@ -424,8 +424,6 @@ static const struct vb2_ops cobalt_qops = {
.buf_queue = cobalt_buf_queue,
.start_streaming = cobalt_start_streaming,
.stop_streaming = cobalt_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* V4L2 ioctls */
diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c
index acc6418db425..42d6f7b90ede 100644
--- a/drivers/media/pci/cx18/cx18-streams.c
+++ b/drivers/media/pci/cx18/cx18-streams.c
@@ -229,8 +229,6 @@ static const struct vb2_ops cx18_vb2_qops = {
.buf_prepare = cx18_buf_prepare,
.start_streaming = cx18_start_streaming,
.stop_streaming = cx18_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int cx18_stream_init(struct cx18 *cx, int type)
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index fdb96f80c036..219937a153b3 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -1210,8 +1210,6 @@ static const struct vb2_ops cx23885_qops = {
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = cx23885_start_streaming,
.stop_streaming = cx23885_stop_streaming,
};
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 3d01cdc4c7f3..05a7859cbe57 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -170,8 +170,6 @@ static const struct vb2_ops dvb_qops = {
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = cx23885_start_streaming,
.stop_streaming = cx23885_stop_streaming,
};
diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c
index 4bdd2bea3713..40817cc52fc1 100644
--- a/drivers/media/pci/cx23885/cx23885-vbi.c
+++ b/drivers/media/pci/cx23885/cx23885-vbi.c
@@ -249,8 +249,6 @@ const struct vb2_ops cx23885_vbi_qops = {
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = cx23885_start_streaming,
.stop_streaming = cx23885_stop_streaming,
};
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 7d4a409c433e..35d58328db56 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -519,8 +519,6 @@ static const struct vb2_ops cx23885_video_qops = {
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = cx23885_start_streaming,
.stop_streaming = cx23885_stop_streaming,
};
diff --git a/drivers/media/pci/cx25821/cx25821-video.c b/drivers/media/pci/cx25821/cx25821-video.c
index 0bee4b728a60..84aa1209e717 100644
--- a/drivers/media/pci/cx25821/cx25821-video.c
+++ b/drivers/media/pci/cx25821/cx25821-video.c
@@ -295,8 +295,6 @@ static const struct vb2_ops cx25821_video_qops = {
.buf_prepare = cx25821_buffer_prepare,
.buf_finish = cx25821_buffer_finish,
.buf_queue = cx25821_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = cx25821_start_streaming,
.stop_streaming = cx25821_stop_streaming,
};
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index d55df8fdb3b6..13b8cc46835b 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -781,8 +781,6 @@ static const struct vb2_ops blackbird_qops = {
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
index b33b3a5e32ec..c9cfceed2f1b 100644
--- a/drivers/media/pci/cx88/cx88-dvb.c
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -152,8 +152,6 @@ static const struct vb2_ops dvb_qops = {
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c
index 469aeaa725ad..e3e379e6f620 100644
--- a/drivers/media/pci/cx88/cx88-vbi.c
+++ b/drivers/media/pci/cx88/cx88-vbi.c
@@ -228,8 +228,6 @@ const struct vb2_ops cx8800_vbi_qops = {
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index cefb6b25e921..0c87327689d3 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -562,8 +562,6 @@ static const struct vb2_ops cx8800_video_qops = {
.buf_prepare = buffer_prepare,
.buf_finish = buffer_finish,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c
index dff853e73fdc..7bddcbba4cf1 100644
--- a/drivers/media/pci/dt3155/dt3155.c
+++ b/drivers/media/pci/dt3155/dt3155.c
@@ -222,8 +222,6 @@ static void dt3155_buf_queue(struct vb2_buffer *vb)
static const struct vb2_ops q_ops = {
.queue_setup = dt3155_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_prepare = dt3155_buf_prepare,
.start_streaming = dt3155_start_streaming,
.stop_streaming = dt3155_stop_streaming,
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index 81ec8630453b..4e98f432ed55 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -1045,8 +1045,6 @@ static const struct vb2_ops cio2_vb2_ops = {
.queue_setup = cio2_vb2_queue_setup,
.start_streaming = cio2_vb2_start_streaming,
.stop_streaming = cio2_vb2_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/**************** V4L2 interface ****************/
diff --git a/drivers/media/pci/intel/ipu6/Kconfig b/drivers/media/pci/intel/ipu6/Kconfig
index 49e4fb696573..1129e2beb4be 100644
--- a/drivers/media/pci/intel/ipu6/Kconfig
+++ b/drivers/media/pci/intel/ipu6/Kconfig
@@ -2,19 +2,13 @@ config VIDEO_INTEL_IPU6
tristate "Intel IPU6 driver"
depends on ACPI || COMPILE_TEST
depends on VIDEO_DEV
- depends on X86 && X86_64 && HAS_DMA
+ depends on X86 && HAS_DMA
depends on IPU_BRIDGE || !IPU_BRIDGE
- #
- # This driver incorrectly tries to override the dma_ops. It should
- # never have done that, but for now keep it working on architectures
- # that use dma ops
- #
- depends on ARCH_HAS_DMA_OPS
select AUXILIARY_BUS
select IOMMU_IOVA
select VIDEO_V4L2_SUBDEV_API
select MEDIA_CONTROLLER
- select VIDEOBUF2_DMA_CONTIG
+ select VIDEOBUF2_DMA_SG
select V4L2_FWNODE
help
This is the 6th Gen Intel Image Processing Unit, found in Intel SoCs
diff --git a/drivers/media/pci/intel/ipu6/ipu6-bus.c b/drivers/media/pci/intel/ipu6/ipu6-bus.c
index 149ec098cdbf..37d88ddb6ee7 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-bus.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-bus.c
@@ -94,8 +94,6 @@ ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
if (!adev)
return ERR_PTR(-ENOMEM);
- adev->dma_mask = DMA_BIT_MASK(isp->secure_mode ? IPU6_MMU_ADDR_BITS :
- IPU6_MMU_ADDR_BITS_NON_SECURE);
adev->isp = isp;
adev->ctrl = ctrl;
adev->pdata = pdata;
@@ -106,10 +104,6 @@ ipu6_bus_initialize_device(struct pci_dev *pdev, struct device *parent,
auxdev->dev.parent = parent;
auxdev->dev.release = ipu6_bus_release;
- auxdev->dev.dma_ops = &ipu6_dma_ops;
- auxdev->dev.dma_mask = &adev->dma_mask;
- auxdev->dev.dma_parms = pdev->dev.dma_parms;
- auxdev->dev.coherent_dma_mask = adev->dma_mask;
ret = auxiliary_device_init(auxdev);
if (ret < 0) {
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.c b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
index e47f84c30e10..277e101da137 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.c
@@ -24,6 +24,7 @@
#include "ipu6.h"
#include "ipu6-bus.h"
+#include "ipu6-dma.h"
#include "ipu6-buttress.h"
#include "ipu6-platform-buttress-regs.h"
@@ -214,20 +215,17 @@ static void ipu6_buttress_ipc_recv(struct ipu6_device *isp,
}
static int ipu6_buttress_ipc_send_bulk(struct ipu6_device *isp,
- enum ipu6_buttress_ipc_domain ipc_domain,
struct ipu6_ipc_buttress_bulk_msg *msgs,
u32 size)
{
unsigned long tx_timeout_jiffies, rx_timeout_jiffies;
unsigned int i, retry = BUTTRESS_IPC_CMD_SEND_RETRY;
struct ipu6_buttress *b = &isp->buttress;
- struct ipu6_buttress_ipc *ipc;
+ struct ipu6_buttress_ipc *ipc = &b->cse;
u32 val;
int ret;
int tout;
- ipc = ipc_domain == IPU6_BUTTRESS_IPC_CSE ? &b->cse : &b->ish;
-
mutex_lock(&b->ipc_mutex);
ret = ipu6_buttress_ipc_validity_open(isp, ipc);
@@ -305,7 +303,6 @@ out:
static int
ipu6_buttress_ipc_send(struct ipu6_device *isp,
- enum ipu6_buttress_ipc_domain ipc_domain,
u32 ipc_msg, u32 size, bool require_resp,
u32 expected_resp)
{
@@ -316,7 +313,7 @@ ipu6_buttress_ipc_send(struct ipu6_device *isp,
.expected_resp = expected_resp,
};
- return ipu6_buttress_ipc_send_bulk(isp, ipc_domain, &msg, 1);
+ return ipu6_buttress_ipc_send_bulk(isp, &msg, 1);
}
static irqreturn_t ipu6_buttress_call_isr(struct ipu6_bus_device *adev)
@@ -345,12 +342,16 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
u32 disable_irqs = 0;
u32 irq_status;
u32 i, count = 0;
+ int active;
- pm_runtime_get_noresume(&isp->pdev->dev);
+ active = pm_runtime_get_if_active(&isp->pdev->dev);
+ if (!active)
+ return IRQ_NONE;
irq_status = readl(isp->base + reg_irq_sts);
- if (!irq_status) {
- pm_runtime_put_noidle(&isp->pdev->dev);
+ if (irq_status == 0 || WARN_ON_ONCE(irq_status == 0xffffffffu)) {
+ if (active > 0)
+ pm_runtime_put_noidle(&isp->pdev->dev);
return IRQ_NONE;
}
@@ -381,25 +382,12 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
complete(&b->cse.recv_complete);
}
- if (irq_status & BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING) {
- dev_dbg(&isp->pdev->dev,
- "BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING\n");
- ipu6_buttress_ipc_recv(isp, &b->ish, &b->ish.recv_data);
- complete(&b->ish.recv_complete);
- }
-
if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE) {
dev_dbg(&isp->pdev->dev,
"BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n");
complete(&b->cse.send_complete);
}
- if (irq_status & BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH) {
- dev_dbg(&isp->pdev->dev,
- "BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE\n");
- complete(&b->ish.send_complete);
- }
-
if (irq_status & BUTTRESS_ISR_SAI_VIOLATION &&
ipu6_buttress_get_secure_mode(isp))
dev_err(&isp->pdev->dev,
@@ -426,7 +414,8 @@ irqreturn_t ipu6_buttress_isr(int irq, void *isp_ptr)
writel(BUTTRESS_IRQS & ~disable_irqs,
isp->base + BUTTRESS_REG_ISR_ENABLE);
- pm_runtime_put(&isp->pdev->dev);
+ if (active > 0)
+ pm_runtime_put(&isp->pdev->dev);
return ret;
}
@@ -553,6 +542,7 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
const struct firmware *fw, struct sg_table *sgt)
{
bool is_vmalloc = is_vmalloc_addr(fw->data);
+ struct pci_dev *pdev = sys->isp->pdev;
struct page **pages;
const void *addr;
unsigned long n_pages;
@@ -562,7 +552,7 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
if (!is_vmalloc && !virt_addr_valid(fw->data))
return -EDOM;
- n_pages = PHYS_PFN(PAGE_ALIGN(fw->size));
+ n_pages = PFN_UP(fw->size);
pages = kmalloc_array(n_pages, sizeof(*pages), GFP_KERNEL);
if (!pages)
@@ -588,14 +578,20 @@ int ipu6_buttress_map_fw_image(struct ipu6_bus_device *sys,
goto out;
}
- ret = dma_map_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0);
- if (ret < 0) {
- ret = -ENOMEM;
+ ret = dma_map_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
+ if (ret) {
+ sg_free_table(sgt);
+ goto out;
+ }
+
+ ret = ipu6_dma_map_sgtable(sys, sgt, DMA_TO_DEVICE, 0);
+ if (ret) {
+ dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
sg_free_table(sgt);
goto out;
}
- dma_sync_sgtable_for_device(&sys->auxdev.dev, sgt, DMA_TO_DEVICE);
+ ipu6_dma_sync_sgtable(sys, sgt);
out:
kfree(pages);
@@ -607,7 +603,10 @@ EXPORT_SYMBOL_NS_GPL(ipu6_buttress_map_fw_image, INTEL_IPU6);
void ipu6_buttress_unmap_fw_image(struct ipu6_bus_device *sys,
struct sg_table *sgt)
{
- dma_unmap_sgtable(&sys->auxdev.dev, sgt, DMA_TO_DEVICE, 0);
+ struct pci_dev *pdev = sys->isp->pdev;
+
+ ipu6_dma_unmap_sgtable(sys, sgt, DMA_TO_DEVICE, 0);
+ dma_unmap_sgtable(&pdev->dev, sgt, DMA_TO_DEVICE, 0);
sg_free_table(sgt);
}
EXPORT_SYMBOL_NS_GPL(ipu6_buttress_unmap_fw_image, INTEL_IPU6);
@@ -650,7 +649,7 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
*/
dev_info(&isp->pdev->dev, "Sending BOOT_LOAD to CSE\n");
- ret = ipu6_buttress_ipc_send(isp, IPU6_BUTTRESS_IPC_CSE,
+ ret = ipu6_buttress_ipc_send(isp,
BUTTRESS_IU2CSEDATA0_IPC_BOOT_LOAD,
1, true,
BUTTRESS_CSE2IUDATA0_IPC_BOOT_LOAD_DONE);
@@ -692,7 +691,7 @@ int ipu6_buttress_authenticate(struct ipu6_device *isp)
* IU2CSEDB.IU2CSECMD and set IU2CSEDB.IU2CSEBUSY as
*/
dev_info(&isp->pdev->dev, "Sending AUTHENTICATE_RUN to CSE\n");
- ret = ipu6_buttress_ipc_send(isp, IPU6_BUTTRESS_IPC_CSE,
+ ret = ipu6_buttress_ipc_send(isp,
BUTTRESS_IU2CSEDATA0_IPC_AUTH_RUN,
1, true,
BUTTRESS_CSE2IUDATA0_IPC_AUTH_RUN_DONE);
@@ -833,9 +832,7 @@ int ipu6_buttress_init(struct ipu6_device *isp)
mutex_init(&b->auth_mutex);
mutex_init(&b->cons_mutex);
mutex_init(&b->ipc_mutex);
- init_completion(&b->ish.send_complete);
init_completion(&b->cse.send_complete);
- init_completion(&b->ish.recv_complete);
init_completion(&b->cse.recv_complete);
b->cse.nack = BUTTRESS_CSE2IUDATA0_IPC_NACK;
@@ -847,8 +844,6 @@ int ipu6_buttress_init(struct ipu6_device *isp)
b->cse.data0_in = BUTTRESS_REG_CSE2IUDATA0;
b->cse.data0_out = BUTTRESS_REG_IU2CSEDATA0;
- /* no ISH on IPU6 */
- memset(&b->ish, 0, sizeof(b->ish));
INIT_LIST_HEAD(&b->constraints);
isp->secure_mode = ipu6_buttress_get_secure_mode(isp);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-buttress.h b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
index 9b6f56958be7..482978c2a09d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-buttress.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-buttress.h
@@ -46,18 +46,12 @@ struct ipu6_buttress_ipc {
struct ipu6_buttress {
struct mutex power_mutex, auth_mutex, cons_mutex, ipc_mutex;
struct ipu6_buttress_ipc cse;
- struct ipu6_buttress_ipc ish;
struct list_head constraints;
u32 wdt_cached_value;
bool force_suspend;
u32 ref_clk;
};
-enum ipu6_buttress_ipc_domain {
- IPU6_BUTTRESS_IPC_CSE,
- IPU6_BUTTRESS_IPC_ISH,
-};
-
struct ipu6_ipc_buttress_bulk_msg {
u32 cmd;
u32 expected_resp;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-cpd.c b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
index 715b21ab4b8e..55ffd988ae4f 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-cpd.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-cpd.c
@@ -15,6 +15,7 @@
#include "ipu6.h"
#include "ipu6-bus.h"
#include "ipu6-cpd.h"
+#include "ipu6-dma.h"
/* 15 entries + header*/
#define MAX_PKG_DIR_ENT_CNT 16
@@ -43,9 +44,9 @@
* 63:56 55 54:48 47:32 31:24 23:0
* Rsvd Rsvd Type Version Rsvd Size
*/
-#define PKG_DIR_SIZE_MASK GENMASK(23, 0)
-#define PKG_DIR_VERSION_MASK GENMASK(47, 32)
-#define PKG_DIR_TYPE_MASK GENMASK(54, 48)
+#define PKG_DIR_SIZE_MASK GENMASK_ULL(23, 0)
+#define PKG_DIR_VERSION_MASK GENMASK_ULL(47, 32)
+#define PKG_DIR_TYPE_MASK GENMASK_ULL(54, 48)
static inline const struct ipu6_cpd_ent *ipu6_cpd_get_entry(const void *cpd,
u8 idx)
@@ -162,7 +163,6 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src)
{
dma_addr_t dma_addr_src = sg_dma_address(adev->fw_sgt.sgl);
const struct ipu6_cpd_ent *ent, *man_ent, *met_ent;
- struct device *dev = &adev->auxdev.dev;
struct ipu6_device *isp = adev->isp;
unsigned int man_sz, met_sz;
void *pkg_dir_pos;
@@ -175,8 +175,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src)
met_sz = met_ent->len;
adev->pkg_dir_size = PKG_DIR_SIZE + man_sz + met_sz;
- adev->pkg_dir = dma_alloc_attrs(dev, adev->pkg_dir_size,
- &adev->pkg_dir_dma_addr, GFP_KERNEL, 0);
+ adev->pkg_dir = ipu6_dma_alloc(adev, adev->pkg_dir_size,
+ &adev->pkg_dir_dma_addr, GFP_KERNEL, 0);
if (!adev->pkg_dir)
return -ENOMEM;
@@ -198,8 +198,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src)
met_ent->len);
if (ret) {
dev_err(&isp->pdev->dev, "Failed to parse module data\n");
- dma_free_attrs(dev, adev->pkg_dir_size,
- adev->pkg_dir, adev->pkg_dir_dma_addr, 0);
+ ipu6_dma_free(adev, adev->pkg_dir_size,
+ adev->pkg_dir, adev->pkg_dir_dma_addr, 0);
return ret;
}
@@ -211,8 +211,8 @@ int ipu6_cpd_create_pkg_dir(struct ipu6_bus_device *adev, const void *src)
pkg_dir_pos += man_sz;
memcpy(pkg_dir_pos, src + met_ent->offset, met_sz);
- dma_sync_single_range_for_device(dev, adev->pkg_dir_dma_addr,
- 0, adev->pkg_dir_size, DMA_TO_DEVICE);
+ ipu6_dma_sync_single(adev, adev->pkg_dir_dma_addr,
+ adev->pkg_dir_size);
return 0;
}
@@ -220,8 +220,8 @@ EXPORT_SYMBOL_NS_GPL(ipu6_cpd_create_pkg_dir, INTEL_IPU6);
void ipu6_cpd_free_pkg_dir(struct ipu6_bus_device *adev)
{
- dma_free_attrs(&adev->auxdev.dev, adev->pkg_dir_size, adev->pkg_dir,
- adev->pkg_dir_dma_addr, 0);
+ ipu6_dma_free(adev, adev->pkg_dir_size, adev->pkg_dir,
+ adev->pkg_dir_dma_addr, 0);
}
EXPORT_SYMBOL_NS_GPL(ipu6_cpd_free_pkg_dir, INTEL_IPU6);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.c b/drivers/media/pci/intel/ipu6/ipu6-dma.c
index 92530a1cc90f..287b77a6aeab 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-dma.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-dma.c
@@ -39,8 +39,7 @@ static struct vm_info *get_vm_info(struct ipu6_mmu *mmu, dma_addr_t iova)
return NULL;
}
-static void __dma_clear_buffer(struct page *page, size_t size,
- unsigned long attrs)
+static void __clear_buffer(struct page *page, size_t size, unsigned long attrs)
{
void *ptr;
@@ -56,8 +55,7 @@ static void __dma_clear_buffer(struct page *page, size_t size,
clflush_cache_range(ptr, size);
}
-static struct page **__dma_alloc_buffer(struct device *dev, size_t size,
- gfp_t gfp, unsigned long attrs)
+static struct page **__alloc_buffer(size_t size, gfp_t gfp, unsigned long attrs)
{
int count = PHYS_PFN(size);
int array_size = count * sizeof(struct page *);
@@ -86,7 +84,7 @@ static struct page **__dma_alloc_buffer(struct device *dev, size_t size,
pages[i + j] = pages[i] + j;
}
- __dma_clear_buffer(pages[i], PAGE_SIZE << order, attrs);
+ __clear_buffer(pages[i], PAGE_SIZE << order, attrs);
i += 1 << order;
count -= 1 << order;
}
@@ -100,29 +98,26 @@ error:
return NULL;
}
-static void __dma_free_buffer(struct device *dev, struct page **pages,
- size_t size, unsigned long attrs)
+static void __free_buffer(struct page **pages, size_t size, unsigned long attrs)
{
int count = PHYS_PFN(size);
unsigned int i;
for (i = 0; i < count && pages[i]; i++) {
- __dma_clear_buffer(pages[i], PAGE_SIZE, attrs);
+ __clear_buffer(pages[i], PAGE_SIZE, attrs);
__free_pages(pages[i], 0);
}
kvfree(pages);
}
-static void ipu6_dma_sync_single_for_cpu(struct device *dev,
- dma_addr_t dma_handle,
- size_t size,
- enum dma_data_direction dir)
+void ipu6_dma_sync_single(struct ipu6_bus_device *sys, dma_addr_t dma_handle,
+ size_t size)
{
void *vaddr;
u32 offset;
struct vm_info *info;
- struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
+ struct ipu6_mmu *mmu = sys->mmu;
info = get_vm_info(mmu, dma_handle);
if (WARN_ON(!info))
@@ -135,25 +130,33 @@ static void ipu6_dma_sync_single_for_cpu(struct device *dev,
vaddr = info->vaddr + offset;
clflush_cache_range(vaddr, size);
}
+EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_single, INTEL_IPU6);
-static void ipu6_dma_sync_sg_for_cpu(struct device *dev,
- struct scatterlist *sglist,
- int nents, enum dma_data_direction dir)
+void ipu6_dma_sync_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
+ int nents)
{
struct scatterlist *sg;
int i;
for_each_sg(sglist, sg, nents, i)
- clflush_cache_range(page_to_virt(sg_page(sg)), sg->length);
+ clflush_cache_range(sg_virt(sg), sg->length);
}
+EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_sg, INTEL_IPU6);
-static void *ipu6_dma_alloc(struct device *dev, size_t size,
- dma_addr_t *dma_handle, gfp_t gfp,
- unsigned long attrs)
+void ipu6_dma_sync_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt)
{
- struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
- struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
+ ipu6_dma_sync_sg(sys, sgt->sgl, sgt->orig_nents);
+}
+EXPORT_SYMBOL_NS_GPL(ipu6_dma_sync_sgtable, INTEL_IPU6);
+
+void *ipu6_dma_alloc(struct ipu6_bus_device *sys, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp,
+ unsigned long attrs)
+{
+ struct device *dev = &sys->auxdev.dev;
+ struct pci_dev *pdev = sys->isp->pdev;
dma_addr_t pci_dma_addr, ipu6_iova;
+ struct ipu6_mmu *mmu = sys->mmu;
struct vm_info *info;
unsigned long count;
struct page **pages;
@@ -173,7 +176,7 @@ static void *ipu6_dma_alloc(struct device *dev, size_t size,
if (!iova)
goto out_kfree;
- pages = __dma_alloc_buffer(dev, size, gfp, attrs);
+ pages = __alloc_buffer(size, gfp, attrs);
if (!pages)
goto out_free_iova;
@@ -227,7 +230,7 @@ out_unmap:
ipu6_mmu_unmap(mmu->dmap->mmu_info, ipu6_iova, PAGE_SIZE);
}
- __dma_free_buffer(dev, pages, size, attrs);
+ __free_buffer(pages, size, attrs);
out_free_iova:
__free_iova(&mmu->dmap->iovad, iova);
@@ -236,13 +239,13 @@ out_kfree:
return NULL;
}
+EXPORT_SYMBOL_NS_GPL(ipu6_dma_alloc, INTEL_IPU6);
-static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr,
- dma_addr_t dma_handle,
- unsigned long attrs)
+void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr,
+ dma_addr_t dma_handle, unsigned long attrs)
{
- struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
- struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
+ struct ipu6_mmu *mmu = sys->mmu;
+ struct pci_dev *pdev = sys->isp->pdev;
struct iova *iova = find_iova(&mmu->dmap->iovad, PHYS_PFN(dma_handle));
dma_addr_t pci_dma_addr, ipu6_iova;
struct vm_info *info;
@@ -281,7 +284,7 @@ static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr,
ipu6_mmu_unmap(mmu->dmap->mmu_info, PFN_PHYS(iova->pfn_lo),
PFN_PHYS(iova_size(iova)));
- __dma_free_buffer(dev, pages, size, attrs);
+ __free_buffer(pages, size, attrs);
mmu->tlb_invalidate(mmu);
@@ -289,13 +292,14 @@ static void ipu6_dma_free(struct device *dev, size_t size, void *vaddr,
kfree(info);
}
+EXPORT_SYMBOL_NS_GPL(ipu6_dma_free, INTEL_IPU6);
-static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma,
- void *addr, dma_addr_t iova, size_t size,
- unsigned long attrs)
+int ipu6_dma_mmap(struct ipu6_bus_device *sys, struct vm_area_struct *vma,
+ void *addr, dma_addr_t iova, size_t size,
+ unsigned long attrs)
{
- struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
- size_t count = PHYS_PFN(PAGE_ALIGN(size));
+ struct ipu6_mmu *mmu = sys->mmu;
+ size_t count = PFN_UP(size);
struct vm_info *info;
size_t i;
int ret;
@@ -323,18 +327,17 @@ static int ipu6_dma_mmap(struct device *dev, struct vm_area_struct *vma,
return 0;
}
-static void ipu6_dma_unmap_sg(struct device *dev,
- struct scatterlist *sglist,
- int nents, enum dma_data_direction dir,
- unsigned long attrs)
+void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
+ int nents, enum dma_data_direction dir,
+ unsigned long attrs)
{
- struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
- struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
+ struct device *dev = &sys->auxdev.dev;
+ struct ipu6_mmu *mmu = sys->mmu;
struct iova *iova = find_iova(&mmu->dmap->iovad,
PHYS_PFN(sg_dma_address(sglist)));
- int i, npages, count;
struct scatterlist *sg;
dma_addr_t pci_dma_addr;
+ unsigned int i;
if (!nents)
return;
@@ -342,31 +345,15 @@ static void ipu6_dma_unmap_sg(struct device *dev,
if (WARN_ON(!iova))
return;
- if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
- ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL);
-
- /* get the nents as orig_nents given by caller */
- count = 0;
- npages = iova_size(iova);
- for_each_sg(sglist, sg, nents, i) {
- if (sg_dma_len(sg) == 0 ||
- sg_dma_address(sg) == DMA_MAPPING_ERROR)
- break;
-
- npages -= PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
- count++;
- if (npages <= 0)
- break;
- }
-
/*
* Before IPU6 mmu unmap, return the pci dma address back to sg
* assume the nents is less than orig_nents as the least granule
* is 1 SZ_4K page
*/
- dev_dbg(dev, "trying to unmap concatenated %u ents\n", count);
- for_each_sg(sglist, sg, count, i) {
- dev_dbg(dev, "ipu unmap sg[%d] %pad\n", i, &sg_dma_address(sg));
+ dev_dbg(dev, "trying to unmap concatenated %u ents\n", nents);
+ for_each_sg(sglist, sg, nents, i) {
+ dev_dbg(dev, "unmap sg[%d] %pad size %u\n", i,
+ &sg_dma_address(sg), sg_dma_len(sg));
pci_dma_addr = ipu6_mmu_iova_to_phys(mmu->dmap->mmu_info,
sg_dma_address(sg));
dev_dbg(dev, "return pci_dma_addr %pad back to sg[%d]\n",
@@ -380,23 +367,21 @@ static void ipu6_dma_unmap_sg(struct device *dev,
PFN_PHYS(iova_size(iova)));
mmu->tlb_invalidate(mmu);
-
- dma_unmap_sg_attrs(&pdev->dev, sglist, nents, dir, attrs);
-
__free_iova(&mmu->dmap->iovad, iova);
}
+EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sg, INTEL_IPU6);
-static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist,
- int nents, enum dma_data_direction dir,
- unsigned long attrs)
+int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
+ int nents, enum dma_data_direction dir,
+ unsigned long attrs)
{
- struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
- struct pci_dev *pdev = to_ipu6_bus_device(dev)->isp->pdev;
+ struct device *dev = &sys->auxdev.dev;
+ struct ipu6_mmu *mmu = sys->mmu;
struct scatterlist *sg;
struct iova *iova;
size_t npages = 0;
unsigned long iova_addr;
- int i, count;
+ int i;
for_each_sg(sglist, sg, nents, i) {
if (sg->offset) {
@@ -406,17 +391,11 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist,
}
}
- dev_dbg(dev, "pci_dma_map_sg trying to map %d ents\n", nents);
- count = dma_map_sg_attrs(&pdev->dev, sglist, nents, dir, attrs);
- if (count <= 0) {
- dev_err(dev, "pci_dma_map_sg %d ents failed\n", nents);
- return 0;
- }
-
- dev_dbg(dev, "pci_dma_map_sg %d ents mapped\n", count);
+ for_each_sg(sglist, sg, nents, i)
+ npages += PFN_UP(sg_dma_len(sg));
- for_each_sg(sglist, sg, count, i)
- npages += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
+ dev_dbg(dev, "dmamap trying to map %d ents %zu pages\n",
+ nents, npages);
iova = alloc_iova(&mmu->dmap->iovad, npages,
PHYS_PFN(dma_get_mask(dev)), 0);
@@ -427,12 +406,13 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist,
iova->pfn_hi);
iova_addr = iova->pfn_lo;
- for_each_sg(sglist, sg, count, i) {
+ for_each_sg(sglist, sg, nents, i) {
+ phys_addr_t iova_pa;
int ret;
- dev_dbg(dev, "mapping entry %d: iova 0x%llx phy %pad size %d\n",
- i, PFN_PHYS(iova_addr), &sg_dma_address(sg),
- sg_dma_len(sg));
+ iova_pa = PFN_PHYS(iova_addr);
+ dev_dbg(dev, "mapping entry %d: iova %pap phy %pap size %d\n",
+ i, &iova_pa, &sg_dma_address(sg), sg_dma_len(sg));
ret = ipu6_mmu_map(mmu->dmap->mmu_info, PFN_PHYS(iova_addr),
sg_dma_address(sg),
@@ -442,28 +422,51 @@ static int ipu6_dma_map_sg(struct device *dev, struct scatterlist *sglist,
sg_dma_address(sg) = PFN_PHYS(iova_addr);
- iova_addr += PHYS_PFN(PAGE_ALIGN(sg_dma_len(sg)));
+ iova_addr += PFN_UP(sg_dma_len(sg));
}
- if ((attrs & DMA_ATTR_SKIP_CPU_SYNC) == 0)
- ipu6_dma_sync_sg_for_cpu(dev, sglist, nents, DMA_BIDIRECTIONAL);
+ dev_dbg(dev, "dmamap %d ents %zu pages mapped\n", nents, npages);
- return count;
+ return nents;
out_fail:
- ipu6_dma_unmap_sg(dev, sglist, i, dir, attrs);
+ ipu6_dma_unmap_sg(sys, sglist, i, dir, attrs);
+
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(ipu6_dma_map_sg, INTEL_IPU6);
+
+int ipu6_dma_map_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+ int nents;
+
+ nents = ipu6_dma_map_sg(sys, sgt->sgl, sgt->nents, dir, attrs);
+ if (nents < 0)
+ return nents;
+
+ sgt->nents = nents;
return 0;
}
+EXPORT_SYMBOL_NS_GPL(ipu6_dma_map_sgtable, INTEL_IPU6);
+
+void ipu6_dma_unmap_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
+ enum dma_data_direction dir, unsigned long attrs)
+{
+ ipu6_dma_unmap_sg(sys, sgt->sgl, sgt->nents, dir, attrs);
+}
+EXPORT_SYMBOL_NS_GPL(ipu6_dma_unmap_sgtable, INTEL_IPU6);
/*
* Create scatter-list for the already allocated DMA buffer
*/
-static int ipu6_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
- void *cpu_addr, dma_addr_t handle, size_t size,
- unsigned long attrs)
+int ipu6_dma_get_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
+ void *cpu_addr, dma_addr_t handle, size_t size,
+ unsigned long attrs)
{
- struct ipu6_mmu *mmu = to_ipu6_bus_device(dev)->mmu;
+ struct device *dev = &sys->auxdev.dev;
+ struct ipu6_mmu *mmu = sys->mmu;
struct vm_info *info;
int n_pages;
int ret = 0;
@@ -478,25 +481,12 @@ static int ipu6_dma_get_sgtable(struct device *dev, struct sg_table *sgt,
if (WARN_ON(!info->pages))
return -ENOMEM;
- n_pages = PHYS_PFN(PAGE_ALIGN(size));
+ n_pages = PFN_UP(size);
ret = sg_alloc_table_from_pages(sgt, info->pages, n_pages, 0, size,
GFP_KERNEL);
if (ret)
- dev_warn(dev, "IPU6 get sgt table failed\n");
+ dev_warn(dev, "get sgt table failed\n");
return ret;
}
-
-const struct dma_map_ops ipu6_dma_ops = {
- .alloc = ipu6_dma_alloc,
- .free = ipu6_dma_free,
- .mmap = ipu6_dma_mmap,
- .map_sg = ipu6_dma_map_sg,
- .unmap_sg = ipu6_dma_unmap_sg,
- .sync_single_for_cpu = ipu6_dma_sync_single_for_cpu,
- .sync_single_for_device = ipu6_dma_sync_single_for_cpu,
- .sync_sg_for_cpu = ipu6_dma_sync_sg_for_cpu,
- .sync_sg_for_device = ipu6_dma_sync_sg_for_cpu,
- .get_sgtable = ipu6_dma_get_sgtable,
-};
diff --git a/drivers/media/pci/intel/ipu6/ipu6-dma.h b/drivers/media/pci/intel/ipu6/ipu6-dma.h
index 847ea5b7c925..b51244add9e6 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-dma.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-dma.h
@@ -5,7 +5,13 @@
#define IPU6_DMA_H
#include <linux/dma-map-ops.h>
+#include <linux/dma-mapping.h>
#include <linux/iova.h>
+#include <linux/iova.h>
+#include <linux/scatterlist.h>
+#include <linux/types.h>
+
+#include "ipu6-bus.h"
struct ipu6_mmu_info;
@@ -14,6 +20,30 @@ struct ipu6_dma_mapping {
struct iova_domain iovad;
};
-extern const struct dma_map_ops ipu6_dma_ops;
-
+void ipu6_dma_sync_single(struct ipu6_bus_device *sys, dma_addr_t dma_handle,
+ size_t size);
+void ipu6_dma_sync_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
+ int nents);
+void ipu6_dma_sync_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt);
+void *ipu6_dma_alloc(struct ipu6_bus_device *sys, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp,
+ unsigned long attrs);
+void ipu6_dma_free(struct ipu6_bus_device *sys, size_t size, void *vaddr,
+ dma_addr_t dma_handle, unsigned long attrs);
+int ipu6_dma_mmap(struct ipu6_bus_device *sys, struct vm_area_struct *vma,
+ void *addr, dma_addr_t iova, size_t size,
+ unsigned long attrs);
+int ipu6_dma_map_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
+ int nents, enum dma_data_direction dir,
+ unsigned long attrs);
+void ipu6_dma_unmap_sg(struct ipu6_bus_device *sys, struct scatterlist *sglist,
+ int nents, enum dma_data_direction dir,
+ unsigned long attrs);
+int ipu6_dma_map_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
+ enum dma_data_direction dir, unsigned long attrs);
+void ipu6_dma_unmap_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
+ enum dma_data_direction dir, unsigned long attrs);
+int ipu6_dma_get_sgtable(struct ipu6_bus_device *sys, struct sg_table *sgt,
+ void *cpu_addr, dma_addr_t handle, size_t size,
+ unsigned long attrs);
#endif /* IPU6_DMA_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6-fw-com.c b/drivers/media/pci/intel/ipu6/ipu6-fw-com.c
index 0b33fe9e703d..53edb445d939 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-fw-com.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-fw-com.c
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include "ipu6-bus.h"
+#include "ipu6-dma.h"
#include "ipu6-fw-com.h"
/*
@@ -88,7 +89,6 @@ struct ipu6_fw_com_context {
void *dma_buffer;
dma_addr_t dma_addr;
unsigned int dma_size;
- unsigned long attrs;
struct ipu6_fw_sys_queue *input_queue; /* array of host to SP queues */
struct ipu6_fw_sys_queue *output_queue; /* array of SP to host */
@@ -164,7 +164,6 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
struct ipu6_fw_com_context *ctx;
struct device *dev = &adev->auxdev.dev;
size_t sizeall, offset;
- unsigned long attrs = 0;
void *specific_host_addr;
unsigned int i;
@@ -206,9 +205,8 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
sizeall += sizeinput + sizeoutput;
- ctx->dma_buffer = dma_alloc_attrs(dev, sizeall, &ctx->dma_addr,
- GFP_KERNEL, attrs);
- ctx->attrs = attrs;
+ ctx->dma_buffer = ipu6_dma_alloc(adev, sizeall, &ctx->dma_addr,
+ GFP_KERNEL, 0);
if (!ctx->dma_buffer) {
dev_err(dev, "failed to allocate dma memory\n");
kfree(ctx);
@@ -239,10 +237,12 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
memcpy(specific_host_addr, cfg->specific_addr,
cfg->specific_size);
+ ipu6_dma_sync_single(adev, ctx->config_vied_addr, sizeall);
+
/* initialize input queues */
offset += specific_size;
res.reg = SYSCOM_QPR_BASE_REG;
- res.host_address = (u64)(ctx->dma_buffer + offset);
+ res.host_address = (uintptr_t)(ctx->dma_buffer + offset);
res.vied_address = ctx->dma_addr + offset;
for (i = 0; i < cfg->num_input_queues; i++)
ipu6_sys_queue_init(ctx->input_queue + i,
@@ -251,7 +251,7 @@ void *ipu6_fw_com_prepare(struct ipu6_fw_com_cfg *cfg,
/* initialize output queues */
offset += sizeinput;
- res.host_address = (u64)(ctx->dma_buffer + offset);
+ res.host_address = (uintptr_t)(ctx->dma_buffer + offset);
res.vied_address = ctx->dma_addr + offset;
for (i = 0; i < cfg->num_output_queues; i++) {
ipu6_sys_queue_init(ctx->output_queue + i,
@@ -315,8 +315,8 @@ int ipu6_fw_com_release(struct ipu6_fw_com_context *ctx, unsigned int force)
if (!force && !ctx->cell_ready(ctx->adev))
return -EBUSY;
- dma_free_attrs(&ctx->adev->auxdev.dev, ctx->dma_size,
- ctx->dma_buffer, ctx->dma_addr, ctx->attrs);
+ ipu6_dma_free(ctx->adev, ctx->dma_size,
+ ctx->dma_buffer, ctx->dma_addr, 0);
kfree(ctx);
return 0;
}
@@ -358,7 +358,7 @@ void *ipu6_send_get_token(struct ipu6_fw_com_context *ctx, int q_nbr)
index = readl(q_dmem + FW_COM_WR_REG);
- return (void *)(q->host_address + index * q->token_size);
+ return (void *)((uintptr_t)q->host_address + index * q->token_size);
}
EXPORT_SYMBOL_NS_GPL(ipu6_send_get_token, INTEL_IPU6);
@@ -395,7 +395,7 @@ void *ipu6_recv_get_token(struct ipu6_fw_com_context *ctx, int q_nbr)
if (!packets)
return NULL;
- return (void *)(q->host_address + rd * q->token_size);
+ return (void *)((uintptr_t)q->host_address + rd * q->token_size);
}
EXPORT_SYMBOL_NS_GPL(ipu6_recv_get_token, INTEL_IPU6);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c b/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c
index 1715275e6776..db2874843453 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-dwc-phy.c
@@ -67,7 +67,7 @@ static void dwc_dphy_write(struct ipu6_isys *isys, u32 phy_id, u32 addr,
void __iomem *isys_base = isys->pdata->base;
void __iomem *base = isys_base + IPU6_DWC_DPHY_BASE(phy_id);
- dev_dbg(dev, "write: reg 0x%lx = data 0x%x", base + addr - isys_base,
+ dev_dbg(dev, "write: reg 0x%zx = data 0x%x", base + addr - isys_base,
data);
writel(data, base + addr);
}
@@ -80,7 +80,7 @@ static u32 dwc_dphy_read(struct ipu6_isys *isys, u32 phy_id, u32 addr)
u32 data;
data = readl(base + addr);
- dev_dbg(dev, "read: reg 0x%lx = data 0x%x", base + addr - isys_base,
+ dev_dbg(dev, "read: reg 0x%zx = data 0x%x", base + addr - isys_base,
data);
return data;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index 03dbb0e0ea79..bbb66b56ee88 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -13,17 +13,48 @@
#include <media/media-entity.h>
#include <media/v4l2-subdev.h>
-#include <media/videobuf2-dma-contig.h>
+#include <media/videobuf2-dma-sg.h>
#include <media/videobuf2-v4l2.h>
#include "ipu6-bus.h"
+#include "ipu6-dma.h"
#include "ipu6-fw-isys.h"
#include "ipu6-isys.h"
#include "ipu6-isys-video.h"
-static int queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
- unsigned int *num_planes, unsigned int sizes[],
- struct device *alloc_devs[])
+static int ipu6_isys_buf_init(struct vb2_buffer *vb)
+{
+ struct ipu6_isys *isys = vb2_get_drv_priv(vb->vb2_queue);
+ struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0);
+ struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+ struct ipu6_isys_video_buffer *ivb =
+ vb2_buffer_to_ipu6_isys_video_buffer(vvb);
+ int ret;
+
+ ret = ipu6_dma_map_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0);
+ if (ret)
+ return ret;
+
+ ivb->dma_addr = sg_dma_address(sg->sgl);
+
+ return 0;
+}
+
+static void ipu6_isys_buf_cleanup(struct vb2_buffer *vb)
+{
+ struct ipu6_isys *isys = vb2_get_drv_priv(vb->vb2_queue);
+ struct sg_table *sg = vb2_dma_sg_plane_desc(vb, 0);
+ struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+ struct ipu6_isys_video_buffer *ivb =
+ vb2_buffer_to_ipu6_isys_video_buffer(vvb);
+
+ ivb->dma_addr = 0;
+ ipu6_dma_unmap_sgtable(isys->adev, sg, DMA_TO_DEVICE, 0);
+}
+
+static int ipu6_isys_queue_setup(struct vb2_queue *q, unsigned int *num_buffers,
+ unsigned int *num_planes, unsigned int sizes[],
+ struct device *alloc_devs[])
{
struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(q);
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
@@ -207,9 +238,11 @@ ipu6_isys_buf_to_fw_frame_buf_pin(struct vb2_buffer *vb,
struct ipu6_fw_isys_frame_buff_set_abi *set)
{
struct ipu6_isys_queue *aq = vb2_queue_to_isys_queue(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vvb = to_vb2_v4l2_buffer(vb);
+ struct ipu6_isys_video_buffer *ivb =
+ vb2_buffer_to_ipu6_isys_video_buffer(vvb);
- set->output_pins[aq->fw_output].addr =
- vb2_dma_contig_plane_dma_addr(vb, 0);
+ set->output_pins[aq->fw_output].addr = ivb->dma_addr;
set->output_pins[aq->fw_output].out_buf_id = vb->index + 1;
}
@@ -332,7 +365,7 @@ static void buf_queue(struct vb2_buffer *vb)
dev_dbg(dev, "queue buffer %u for %s\n", vb->index, av->vdev.name);
- dma = vb2_dma_contig_plane_dma_addr(vb, 0);
+ dma = ivb->dma_addr;
dev_dbg(dev, "iova: iova %pad\n", &dma);
spin_lock_irqsave(&aq->lock, flags);
@@ -724,10 +757,14 @@ void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,
}
list_for_each_entry_reverse(ib, &aq->active, head) {
+ struct ipu6_isys_video_buffer *ivb;
+ struct vb2_v4l2_buffer *vvb;
dma_addr_t addr;
vb = ipu6_isys_buffer_to_vb2_buffer(ib);
- addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ vvb = to_vb2_v4l2_buffer(vb);
+ ivb = vb2_buffer_to_ipu6_isys_video_buffer(vvb);
+ addr = ivb->dma_addr;
if (info->pin.addr != addr) {
if (first)
@@ -766,10 +803,12 @@ void ipu6_isys_queue_buf_ready(struct ipu6_isys_stream *stream,
}
static const struct vb2_ops ipu6_isys_queue_ops = {
- .queue_setup = queue_setup,
+ .queue_setup = ipu6_isys_queue_setup,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
+ .buf_init = ipu6_isys_buf_init,
.buf_prepare = ipu6_isys_buf_prepare,
+ .buf_cleanup = ipu6_isys_buf_cleanup,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
.buf_queue = buf_queue,
@@ -779,16 +818,17 @@ int ipu6_isys_queue_init(struct ipu6_isys_queue *aq)
{
struct ipu6_isys *isys = ipu6_isys_queue_to_video(aq)->isys;
struct ipu6_isys_video *av = ipu6_isys_queue_to_video(aq);
+ struct ipu6_bus_device *adev = isys->adev;
int ret;
/* no support for userptr */
if (!aq->vbq.io_modes)
aq->vbq.io_modes = VB2_MMAP | VB2_DMABUF;
- aq->vbq.drv_priv = aq;
+ aq->vbq.drv_priv = isys;
aq->vbq.ops = &ipu6_isys_queue_ops;
aq->vbq.lock = &av->mutex;
- aq->vbq.mem_ops = &vb2_dma_contig_memops;
+ aq->vbq.mem_ops = &vb2_dma_sg_memops;
aq->vbq.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
aq->vbq.min_queued_buffers = 1;
aq->vbq.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
@@ -797,8 +837,8 @@ int ipu6_isys_queue_init(struct ipu6_isys_queue *aq)
if (ret)
return ret;
- aq->dev = &isys->adev->auxdev.dev;
- aq->vbq.dev = &isys->adev->auxdev.dev;
+ aq->dev = &adev->auxdev.dev;
+ aq->vbq.dev = &adev->isp->pdev->dev;
spin_lock_init(&aq->lock);
INIT_LIST_HEAD(&aq->active);
INIT_LIST_HEAD(&aq->incoming);
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
index 95cfd4869d93..fe8fc796a58f 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.h
@@ -38,6 +38,7 @@ struct ipu6_isys_buffer {
struct ipu6_isys_video_buffer {
struct vb2_v4l2_buffer vb_v4l2;
struct ipu6_isys_buffer ib;
+ dma_addr_t dma_addr;
};
#define IPU6_ISYS_BUFFER_LIST_FL_INCOMING BIT(0)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
index b37561352ead..387963529adb 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-video.c
@@ -543,7 +543,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
ret = ipu6_isys_fw_pin_cfg(__av, stream_cfg);
if (ret < 0) {
- ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg);
+ ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
return ret;
}
}
@@ -560,7 +560,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
IPU6_FW_ISYS_SEND_TYPE_STREAM_OPEN);
if (ret < 0) {
dev_err(dev, "can't open stream (%d)\n", ret);
- ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg);
+ ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
return ret;
}
@@ -569,7 +569,7 @@ static int start_stream_firmware(struct ipu6_isys_video *av,
tout = wait_for_completion_timeout(&stream->stream_open_completion,
IPU6_FW_CALL_TIMEOUT_JIFFIES);
- ipu6_put_fw_msg_buf(av->isys, (u64)stream_cfg);
+ ipu6_put_fw_msg_buf(av->isys, (uintptr_t)stream_cfg);
if (!tout) {
dev_err(dev, "stream open time out\n");
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.c b/drivers/media/pci/intel/ipu6/ipu6-isys.c
index c4aff2e2009b..7148f8fe23f5 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.c
@@ -34,6 +34,7 @@
#include "ipu6-bus.h"
#include "ipu6-cpd.h"
+#include "ipu6-dma.h"
#include "ipu6-isys.h"
#include "ipu6-isys-csi2.h"
#include "ipu6-mmu.h"
@@ -576,7 +577,7 @@ void update_watermark_setting(struct ipu6_isys *isys)
}
enable_iwake(isys, true);
- calc_fill_time_us = max_sram_size / isys_pb_datarate_mbs;
+ calc_fill_time_us = div64_u64(max_sram_size, isys_pb_datarate_mbs);
if (isys->pdata->ipdata->enhanced_iwake) {
ltr = isys->pdata->ipdata->ltr;
@@ -933,29 +934,27 @@ static const struct dev_pm_ops isys_pm_ops = {
static void free_fw_msg_bufs(struct ipu6_isys *isys)
{
- struct device *dev = &isys->adev->auxdev.dev;
struct isys_fw_msgs *fwmsg, *safe;
list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist, head)
- dma_free_attrs(dev, sizeof(struct isys_fw_msgs), fwmsg,
- fwmsg->dma_addr, 0);
+ ipu6_dma_free(isys->adev, sizeof(struct isys_fw_msgs), fwmsg,
+ fwmsg->dma_addr, 0);
list_for_each_entry_safe(fwmsg, safe, &isys->framebuflist_fw, head)
- dma_free_attrs(dev, sizeof(struct isys_fw_msgs), fwmsg,
- fwmsg->dma_addr, 0);
+ ipu6_dma_free(isys->adev, sizeof(struct isys_fw_msgs), fwmsg,
+ fwmsg->dma_addr, 0);
}
static int alloc_fw_msg_bufs(struct ipu6_isys *isys, int amount)
{
- struct device *dev = &isys->adev->auxdev.dev;
struct isys_fw_msgs *addr;
dma_addr_t dma_addr;
unsigned long flags;
unsigned int i;
for (i = 0; i < amount; i++) {
- addr = dma_alloc_attrs(dev, sizeof(struct isys_fw_msgs),
- &dma_addr, GFP_KERNEL, 0);
+ addr = ipu6_dma_alloc(isys->adev, sizeof(*addr),
+ &dma_addr, GFP_KERNEL, 0);
if (!addr)
break;
addr->dma_addr = dma_addr;
@@ -974,8 +973,8 @@ static int alloc_fw_msg_bufs(struct ipu6_isys *isys, int amount)
struct isys_fw_msgs, head);
list_del(&addr->head);
spin_unlock_irqrestore(&isys->listlock, flags);
- dma_free_attrs(dev, sizeof(struct isys_fw_msgs), addr,
- addr->dma_addr, 0);
+ ipu6_dma_free(isys->adev, sizeof(struct isys_fw_msgs), addr,
+ addr->dma_addr, 0);
spin_lock_irqsave(&isys->listlock, flags);
}
spin_unlock_irqrestore(&isys->listlock, flags);
@@ -1026,11 +1025,11 @@ void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys)
spin_unlock_irqrestore(&isys->listlock, flags);
}
-void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, u64 data)
+void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data)
{
struct isys_fw_msgs *msg;
unsigned long flags;
- u64 *ptr = (u64 *)data;
+ void *ptr = (void *)data;
if (!ptr)
return;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys.h b/drivers/media/pci/intel/ipu6/ipu6-isys.h
index 86dfc2eff5d0..610b60e69152 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys.h
@@ -180,7 +180,7 @@ struct isys_fw_msgs {
};
struct isys_fw_msgs *ipu6_get_fw_msg_buf(struct ipu6_isys_stream *stream);
-void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, u64 data);
+void ipu6_put_fw_msg_buf(struct ipu6_isys *isys, uintptr_t data);
void ipu6_cleanup_fw_msg_bufs(struct ipu6_isys *isys);
extern const struct v4l2_ioctl_ops ipu6_isys_ioctl_ops;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.c b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
index c3a20507d6db..a81e9b09a3c5 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.c
@@ -97,13 +97,15 @@ static void page_table_dump(struct ipu6_mmu_info *mmu_info)
for (l1_idx = 0; l1_idx < ISP_L1PT_PTES; l1_idx++) {
u32 l2_idx;
u32 iova = (phys_addr_t)l1_idx << ISP_L1PT_SHIFT;
+ phys_addr_t l2_phys;
if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval)
continue;
+
+ l2_phys = TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx];)
dev_dbg(mmu_info->dev,
- "l1 entry %u; iovas 0x%8.8x-0x%8.8x, at %pa\n",
- l1_idx, iova, iova + ISP_PAGE_SIZE,
- TBL_PHYS_ADDR(mmu_info->l1_pt[l1_idx]));
+ "l1 entry %u; iovas 0x%8.8x-0x%8.8x, at %pap\n",
+ l1_idx, iova, iova + ISP_PAGE_SIZE, &l2_phys);
for (l2_idx = 0; l2_idx < ISP_L2PT_PTES; l2_idx++) {
u32 *l2_pt = mmu_info->l2_pts[l1_idx];
@@ -227,7 +229,7 @@ static u32 *alloc_l1_pt(struct ipu6_mmu_info *mmu_info)
}
mmu_info->l1_pt_dma = dma >> ISP_PADDR_SHIFT;
- dev_dbg(mmu_info->dev, "l1 pt %p mapped at %llx\n", pt, dma);
+ dev_dbg(mmu_info->dev, "l1 pt %p mapped at %pad\n", pt, &dma);
return pt;
@@ -252,75 +254,142 @@ static u32 *alloc_l2_pt(struct ipu6_mmu_info *mmu_info)
return pt;
}
+static void l2_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
+ phys_addr_t dummy, size_t size)
+{
+ unsigned int l2_entries;
+ unsigned int l2_idx;
+ unsigned long flags;
+ u32 l1_idx;
+ u32 *l2_pt;
+
+ spin_lock_irqsave(&mmu_info->lock, flags);
+ for (l1_idx = iova >> ISP_L1PT_SHIFT;
+ size > 0 && l1_idx < ISP_L1PT_PTES; l1_idx++) {
+ dev_dbg(mmu_info->dev,
+ "unmapping l2 pgtable (l1 index %u (iova 0x%8.8lx))\n",
+ l1_idx, iova);
+
+ if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) {
+ dev_err(mmu_info->dev,
+ "unmap not mapped iova 0x%8.8lx l1 index %u\n",
+ iova, l1_idx);
+ continue;
+ }
+ l2_pt = mmu_info->l2_pts[l1_idx];
+
+ l2_entries = 0;
+ for (l2_idx = (iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT;
+ size > 0 && l2_idx < ISP_L2PT_PTES; l2_idx++) {
+ phys_addr_t pteval = TBL_PHYS_ADDR(l2_pt[l2_idx]);
+
+ dev_dbg(mmu_info->dev,
+ "unmap l2 index %u with pteval 0x%p\n",
+ l2_idx, &pteval);
+ l2_pt[l2_idx] = mmu_info->dummy_page_pteval;
+
+ iova += ISP_PAGE_SIZE;
+ size -= ISP_PAGE_SIZE;
+
+ l2_entries++;
+ }
+
+ WARN_ON_ONCE(!l2_entries);
+ clflush_cache_range(&l2_pt[l2_idx - l2_entries],
+ sizeof(l2_pt[0]) * l2_entries);
+ }
+
+ WARN_ON_ONCE(size);
+ spin_unlock_irqrestore(&mmu_info->lock, flags);
+}
+
static int l2_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
phys_addr_t paddr, size_t size)
{
- u32 l1_idx = iova >> ISP_L1PT_SHIFT;
- u32 iova_start = iova;
+ struct device *dev = mmu_info->dev;
+ unsigned int l2_entries;
u32 *l2_pt, *l2_virt;
unsigned int l2_idx;
unsigned long flags;
+ size_t mapped = 0;
dma_addr_t dma;
u32 l1_entry;
-
- dev_dbg(mmu_info->dev,
- "mapping l2 page table for l1 index %u (iova %8.8x)\n",
- l1_idx, (u32)iova);
+ u32 l1_idx;
+ int err = 0;
spin_lock_irqsave(&mmu_info->lock, flags);
- l1_entry = mmu_info->l1_pt[l1_idx];
- if (l1_entry == mmu_info->dummy_l2_pteval) {
- l2_virt = mmu_info->l2_pts[l1_idx];
- if (likely(!l2_virt)) {
- l2_virt = alloc_l2_pt(mmu_info);
- if (!l2_virt) {
- spin_unlock_irqrestore(&mmu_info->lock, flags);
- return -ENOMEM;
+
+ paddr = ALIGN(paddr, ISP_PAGE_SIZE);
+ for (l1_idx = iova >> ISP_L1PT_SHIFT;
+ size > 0 && l1_idx < ISP_L1PT_PTES; l1_idx++) {
+ dev_dbg(dev,
+ "mapping l2 page table for l1 index %u (iova %8.8x)\n",
+ l1_idx, (u32)iova);
+
+ l1_entry = mmu_info->l1_pt[l1_idx];
+ if (l1_entry == mmu_info->dummy_l2_pteval) {
+ l2_virt = mmu_info->l2_pts[l1_idx];
+ if (likely(!l2_virt)) {
+ l2_virt = alloc_l2_pt(mmu_info);
+ if (!l2_virt) {
+ err = -ENOMEM;
+ goto error;
+ }
}
- }
- dma = map_single(mmu_info, l2_virt);
- if (!dma) {
- dev_err(mmu_info->dev, "Failed to map l2pt page\n");
- free_page((unsigned long)l2_virt);
- spin_unlock_irqrestore(&mmu_info->lock, flags);
- return -EINVAL;
- }
+ dma = map_single(mmu_info, l2_virt);
+ if (!dma) {
+ dev_err(dev, "Failed to map l2pt page\n");
+ free_page((unsigned long)l2_virt);
+ err = -EINVAL;
+ goto error;
+ }
- l1_entry = dma >> ISP_PADDR_SHIFT;
+ l1_entry = dma >> ISP_PADDR_SHIFT;
- dev_dbg(mmu_info->dev, "page for l1_idx %u %p allocated\n",
- l1_idx, l2_virt);
- mmu_info->l1_pt[l1_idx] = l1_entry;
- mmu_info->l2_pts[l1_idx] = l2_virt;
- clflush_cache_range((void *)&mmu_info->l1_pt[l1_idx],
- sizeof(mmu_info->l1_pt[l1_idx]));
- }
+ dev_dbg(dev, "page for l1_idx %u %p allocated\n",
+ l1_idx, l2_virt);
+ mmu_info->l1_pt[l1_idx] = l1_entry;
+ mmu_info->l2_pts[l1_idx] = l2_virt;
- l2_pt = mmu_info->l2_pts[l1_idx];
+ clflush_cache_range(&mmu_info->l1_pt[l1_idx],
+ sizeof(mmu_info->l1_pt[l1_idx]));
+ }
- dev_dbg(mmu_info->dev, "l2_pt at %p with dma 0x%x\n", l2_pt, l1_entry);
+ l2_pt = mmu_info->l2_pts[l1_idx];
+ l2_entries = 0;
- paddr = ALIGN(paddr, ISP_PAGE_SIZE);
+ for (l2_idx = (iova & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT;
+ size > 0 && l2_idx < ISP_L2PT_PTES; l2_idx++) {
+ l2_pt[l2_idx] = paddr >> ISP_PADDR_SHIFT;
- l2_idx = (iova_start & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT;
+ dev_dbg(dev, "l2 index %u mapped as 0x%8.8x\n", l2_idx,
+ l2_pt[l2_idx]);
- dev_dbg(mmu_info->dev, "l2_idx %u, phys 0x%8.8x\n", l2_idx,
- l2_pt[l2_idx]);
- if (l2_pt[l2_idx] != mmu_info->dummy_page_pteval) {
- spin_unlock_irqrestore(&mmu_info->lock, flags);
- return -EINVAL;
- }
+ iova += ISP_PAGE_SIZE;
+ paddr += ISP_PAGE_SIZE;
+ mapped += ISP_PAGE_SIZE;
+ size -= ISP_PAGE_SIZE;
+
+ l2_entries++;
+ }
- l2_pt[l2_idx] = paddr >> ISP_PADDR_SHIFT;
+ WARN_ON_ONCE(!l2_entries);
+ clflush_cache_range(&l2_pt[l2_idx - l2_entries],
+ sizeof(l2_pt[0]) * l2_entries);
+ }
- clflush_cache_range((void *)&l2_pt[l2_idx], sizeof(l2_pt[l2_idx]));
spin_unlock_irqrestore(&mmu_info->lock, flags);
- dev_dbg(mmu_info->dev, "l2 index %u mapped as 0x%8.8x\n", l2_idx,
- l2_pt[l2_idx]);
-
return 0;
+
+error:
+ spin_unlock_irqrestore(&mmu_info->lock, flags);
+ /* unroll mapping in case something went wrong */
+ if (mapped)
+ l2_unmap(mmu_info, iova - mapped, paddr - mapped, mapped);
+
+ return err;
}
static int __ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
@@ -330,61 +399,21 @@ static int __ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
u32 iova_end = ALIGN(iova + size, ISP_PAGE_SIZE);
dev_dbg(mmu_info->dev,
- "mapping iova 0x%8.8x--0x%8.8x, size %zu at paddr 0x%10.10llx\n",
- iova_start, iova_end, size, paddr);
+ "mapping iova 0x%8.8x--0x%8.8x, size %zu at paddr %pap\n",
+ iova_start, iova_end, size, &paddr);
return l2_map(mmu_info, iova_start, paddr, size);
}
-static size_t l2_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
- phys_addr_t dummy, size_t size)
+static void __ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info,
+ unsigned long iova, size_t size)
{
- u32 l1_idx = iova >> ISP_L1PT_SHIFT;
- u32 iova_start = iova;
- unsigned int l2_idx;
- size_t unmapped = 0;
- unsigned long flags;
- u32 *l2_pt;
-
- dev_dbg(mmu_info->dev, "unmapping l2 page table for l1 index %u (iova 0x%8.8lx)\n",
- l1_idx, iova);
-
- spin_lock_irqsave(&mmu_info->lock, flags);
- if (mmu_info->l1_pt[l1_idx] == mmu_info->dummy_l2_pteval) {
- spin_unlock_irqrestore(&mmu_info->lock, flags);
- dev_err(mmu_info->dev,
- "unmap iova 0x%8.8lx l1 idx %u which was not mapped\n",
- iova, l1_idx);
- return 0;
- }
-
- for (l2_idx = (iova_start & ISP_L2PT_MASK) >> ISP_L2PT_SHIFT;
- (iova_start & ISP_L1PT_MASK) + (l2_idx << ISP_PAGE_SHIFT)
- < iova_start + size && l2_idx < ISP_L2PT_PTES; l2_idx++) {
- l2_pt = mmu_info->l2_pts[l1_idx];
- dev_dbg(mmu_info->dev,
- "unmap l2 index %u with pteval 0x%10.10llx\n",
- l2_idx, TBL_PHYS_ADDR(l2_pt[l2_idx]));
- l2_pt[l2_idx] = mmu_info->dummy_page_pteval;
-
- clflush_cache_range((void *)&l2_pt[l2_idx],
- sizeof(l2_pt[l2_idx]));
- unmapped++;
- }
- spin_unlock_irqrestore(&mmu_info->lock, flags);
-
- return unmapped << ISP_PAGE_SHIFT;
-}
-
-static size_t __ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info,
- unsigned long iova, size_t size)
-{
- return l2_unmap(mmu_info, iova, 0, size);
+ l2_unmap(mmu_info, iova, 0, size);
}
static int allocate_trash_buffer(struct ipu6_mmu *mmu)
{
- unsigned int n_pages = PHYS_PFN(PAGE_ALIGN(IPU6_MMUV2_TRASH_RANGE));
+ unsigned int n_pages = PFN_UP(IPU6_MMUV2_TRASH_RANGE);
struct iova *iova;
unsigned int i;
dma_addr_t dma;
@@ -525,9 +554,10 @@ static struct ipu6_mmu_info *ipu6_mmu_alloc(struct ipu6_device *isp)
return NULL;
mmu_info->aperture_start = 0;
- mmu_info->aperture_end = DMA_BIT_MASK(isp->secure_mode ?
- IPU6_MMU_ADDR_BITS :
- IPU6_MMU_ADDR_BITS_NON_SECURE);
+ mmu_info->aperture_end =
+ (dma_addr_t)DMA_BIT_MASK(isp->secure_mode ?
+ IPU6_MMU_ADDR_BITS :
+ IPU6_MMU_ADDR_BITS_NON_SECURE);
mmu_info->pgsize_bitmap = SZ_4K;
mmu_info->dev = &isp->pdev->dev;
@@ -619,40 +649,13 @@ phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info,
return phy_addr;
}
-static size_t ipu6_mmu_pgsize(unsigned long pgsize_bitmap,
- unsigned long addr_merge, size_t size)
-{
- unsigned int pgsize_idx;
- size_t pgsize;
-
- /* Max page size that still fits into 'size' */
- pgsize_idx = __fls(size);
-
- if (likely(addr_merge)) {
- /* Max page size allowed by address */
- unsigned int align_pgsize_idx = __ffs(addr_merge);
-
- pgsize_idx = min(pgsize_idx, align_pgsize_idx);
- }
-
- pgsize = (1UL << (pgsize_idx + 1)) - 1;
- pgsize &= pgsize_bitmap;
-
- WARN_ON(!pgsize);
-
- /* pick the biggest page */
- pgsize_idx = __fls(pgsize);
- pgsize = 1UL << pgsize_idx;
-
- return pgsize;
-}
-
-size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
- size_t size)
+void ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
+ size_t size)
{
- size_t unmapped_page, unmapped = 0;
unsigned int min_pagesz;
+ dev_dbg(mmu_info->dev, "unmapping iova 0x%lx size 0x%zx\n", iova, size);
+
/* find out the minimum page size supported */
min_pagesz = 1 << __ffs(mmu_info->pgsize_bitmap);
@@ -664,38 +667,16 @@ size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
if (!IS_ALIGNED(iova | size, min_pagesz)) {
dev_err(NULL, "unaligned: iova 0x%lx size 0x%zx min_pagesz 0x%x\n",
iova, size, min_pagesz);
- return -EINVAL;
- }
-
- /*
- * Keep iterating until we either unmap 'size' bytes (or more)
- * or we hit an area that isn't mapped.
- */
- while (unmapped < size) {
- size_t pgsize = ipu6_mmu_pgsize(mmu_info->pgsize_bitmap,
- iova, size - unmapped);
-
- unmapped_page = __ipu6_mmu_unmap(mmu_info, iova, pgsize);
- if (!unmapped_page)
- break;
-
- dev_dbg(mmu_info->dev, "unmapped: iova 0x%lx size 0x%zx\n",
- iova, unmapped_page);
-
- iova += unmapped_page;
- unmapped += unmapped_page;
+ return;
}
- return unmapped;
+ __ipu6_mmu_unmap(mmu_info, iova, size);
}
int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
phys_addr_t paddr, size_t size)
{
- unsigned long orig_iova = iova;
unsigned int min_pagesz;
- size_t orig_size = size;
- int ret = 0;
if (mmu_info->pgsize_bitmap == 0UL)
return -ENODEV;
@@ -718,28 +699,7 @@ int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
dev_dbg(mmu_info->dev, "map: iova 0x%lx pa %pa size 0x%zx\n",
iova, &paddr, size);
- while (size) {
- size_t pgsize = ipu6_mmu_pgsize(mmu_info->pgsize_bitmap,
- iova | paddr, size);
-
- dev_dbg(mmu_info->dev,
- "mapping: iova 0x%lx pa %pa pgsize 0x%zx\n",
- iova, &paddr, pgsize);
-
- ret = __ipu6_mmu_map(mmu_info, iova, paddr, pgsize);
- if (ret)
- break;
-
- iova += pgsize;
- paddr += pgsize;
- size -= pgsize;
- }
-
- /* unroll mapping in case something went wrong */
- if (ret)
- ipu6_mmu_unmap(mmu_info, orig_iova, orig_size - size);
-
- return ret;
+ return __ipu6_mmu_map(mmu_info, iova, paddr, size);
}
static void ipu6_mmu_destroy(struct ipu6_mmu *mmu)
diff --git a/drivers/media/pci/intel/ipu6/ipu6-mmu.h b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
index 21cdb0f146eb..8e40b4a66d7d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-mmu.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-mmu.h
@@ -66,8 +66,8 @@ int ipu6_mmu_hw_init(struct ipu6_mmu *mmu);
void ipu6_mmu_hw_cleanup(struct ipu6_mmu *mmu);
int ipu6_mmu_map(struct ipu6_mmu_info *mmu_info, unsigned long iova,
phys_addr_t paddr, size_t size);
-size_t ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
- size_t size);
+void ipu6_mmu_unmap(struct ipu6_mmu_info *mmu_info, unsigned long iova,
+ size_t size);
phys_addr_t ipu6_mmu_iova_to_phys(struct ipu6_mmu_info *mmu_info,
dma_addr_t iova);
#endif
diff --git a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
index 20f27011df43..efd65e494c16 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
+++ b/drivers/media/pci/intel/ipu6/ipu6-platform-buttress-regs.h
@@ -219,8 +219,6 @@ enum {
BUTTRESS_ISR_IS_IRQ | BUTTRESS_ISR_PS_IRQ)
#define BUTTRESS_EVENT (BUTTRESS_ISR_IPC_FROM_CSE_IS_WAITING | \
- BUTTRESS_ISR_IPC_FROM_ISH_IS_WAITING | \
BUTTRESS_ISR_IPC_EXEC_DONE_BY_CSE | \
- BUTTRESS_ISR_IPC_EXEC_DONE_BY_ISH | \
BUTTRESS_ISR_SAI_VIOLATION)
#endif /* IPU6_PLATFORM_BUTTRESS_REGS_H */
diff --git a/drivers/media/pci/intel/ipu6/ipu6.c b/drivers/media/pci/intel/ipu6/ipu6.c
index 7fb707d35309..a38292e8eaac 100644
--- a/drivers/media/pci/intel/ipu6/ipu6.c
+++ b/drivers/media/pci/intel/ipu6/ipu6.c
@@ -247,7 +247,8 @@ ipu6_pkg_dir_configure_spc(struct ipu6_device *isp,
dma_addr = sg_dma_address(isp->psys->fw_sgt.sgl);
pg_offset = server_fw_addr - dma_addr;
- prog = (struct ipu6_cell_program *)((u64)isp->cpd_fw->data + pg_offset);
+ prog = (struct ipu6_cell_program *)((uintptr_t)isp->cpd_fw->data +
+ pg_offset);
spc_base = base + prog->regs_addr;
if (spc_base != (base + hw_variant->spc_offset))
dev_warn(&isp->pdev->dev,
@@ -752,6 +753,9 @@ static void ipu6_pci_reset_done(struct pci_dev *pdev)
*/
static int ipu6_suspend(struct device *dev)
{
+ struct pci_dev *pdev = to_pci_dev(dev);
+
+ synchronize_irq(pdev->irq);
return 0;
}
diff --git a/drivers/media/pci/mantis/mantis_core.h b/drivers/media/pci/mantis/mantis_core.h
deleted file mode 100644
index 93c89a10a2c7..000000000000
--- a/drivers/media/pci/mantis/mantis_core.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/* SPDX-License-Identifier: GPL-2.0-or-later */
-/*
- Mantis PCI bridge driver
-
- Copyright (C) Manu Abraham (abraham.manu@gmail.com)
-
-*/
-
-#ifndef __MANTIS_CORE_H
-#define __MANTIS_CORE_H
-
-#include "mantis_common.h"
-
-
-#define FE_TYPE_SAT 0
-#define FE_TYPE_CAB 1
-#define FE_TYPE_TER 2
-
-#define FE_TYPE_TS204 0
-#define FE_TYPE_TS188 1
-
-
-struct vendorname {
- u8 *sub_vendor_name;
- u32 sub_vendor_id;
-};
-
-struct devicetype {
- u8 *sub_device_name;
- u32 sub_device_id;
- u8 device_type;
- u32 type_flags;
-};
-
-
-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 int mantis_i2c_init(struct mantis_pci *mantis);
-extern int mantis_i2c_exit(struct mantis_pci *mantis);
-
-#endif /* __MANTIS_CORE_H */
diff --git a/drivers/media/pci/mgb4/mgb4_cmt.c b/drivers/media/pci/mgb4/mgb4_cmt.c
index 70dc78ef193c..a25b68403bc6 100644
--- a/drivers/media/pci/mgb4/mgb4_cmt.c
+++ b/drivers/media/pci/mgb4/mgb4_cmt.c
@@ -227,6 +227,8 @@ void mgb4_cmt_set_vin_freq_range(struct mgb4_vin_dev *vindev,
u32 config;
size_t i;
+ freq_range = array_index_nospec(freq_range, ARRAY_SIZE(cmt_vals_in));
+
addr = cmt_addrs_in[vindev->config->id];
reg_set = cmt_vals_in[freq_range];
diff --git a/drivers/media/pci/mgb4/mgb4_core.c b/drivers/media/pci/mgb4/mgb4_core.c
index 2819bbdab484..bc63dc81bcae 100644
--- a/drivers/media/pci/mgb4/mgb4_core.c
+++ b/drivers/media/pci/mgb4/mgb4_core.c
@@ -582,9 +582,7 @@ static int mgb4_probe(struct pci_dev *pdev, const struct pci_device_id *id)
NULL);
#endif
-#ifdef CONFIG_DEBUG_FS
mgbdev->debugfs = debugfs_create_dir(dev_name(&pdev->dev), NULL);
-#endif
/* Get card serial number. On systems without MTD flash support we may
* get an error thus ignore the return value. An invalid serial number
@@ -646,6 +644,8 @@ static void mgb4_remove(struct pci_dev *pdev)
hwmon_device_unregister(mgbdev->hwmon_dev);
#endif
+ debugfs_remove_recursive(mgbdev->debugfs);
+
if (mgbdev->indio_dev)
mgb4_trigger_free(mgbdev->indio_dev);
@@ -656,10 +656,6 @@ static void mgb4_remove(struct pci_dev *pdev)
if (mgbdev->vin[i])
mgb4_vin_free(mgbdev->vin[i]);
-#ifdef CONFIG_DEBUG_FS
- debugfs_remove_recursive(mgbdev->debugfs);
-#endif
-
device_remove_groups(&mgbdev->pdev->dev, mgb4_pci_groups);
free_spi(mgbdev);
free_i2c(mgbdev);
diff --git a/drivers/media/pci/mgb4/mgb4_core.h b/drivers/media/pci/mgb4/mgb4_core.h
index b52cd67270b5..9aec62514c0b 100644
--- a/drivers/media/pci/mgb4/mgb4_core.h
+++ b/drivers/media/pci/mgb4/mgb4_core.h
@@ -68,9 +68,7 @@ struct mgb4_dev {
u8 module_version;
u32 serial_number;
-#ifdef CONFIG_DEBUG_FS
struct dentry *debugfs;
-#endif
};
#endif
diff --git a/drivers/media/pci/mgb4/mgb4_vin.c b/drivers/media/pci/mgb4/mgb4_vin.c
index e9332abb3172..3f171c624b40 100644
--- a/drivers/media/pci/mgb4/mgb4_vin.c
+++ b/drivers/media/pci/mgb4/mgb4_vin.c
@@ -260,6 +260,7 @@ static void buffer_queue(struct vb2_buffer *vb)
static void stop_streaming(struct vb2_queue *vq)
{
struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vq);
+ struct mgb4_regs *video = &vindev->mgbdev->video;
const struct mgb4_vin_config *config = vindev->config;
int irq = xdma_get_user_irq(vindev->mgbdev->xdev, config->vin_irq);
@@ -273,6 +274,9 @@ static void stop_streaming(struct vb2_queue *vq)
mgb4_mask_reg(&vindev->mgbdev->video, config->regs.config, 0x2,
0x0);
+ mgb4_write_reg(video, vindev->config->regs.padding, 0);
+ set_loopback_padding(vindev, 0);
+
cancel_work_sync(&vindev->dma_work);
return_all_buffers(vindev, VB2_BUF_STATE_ERROR);
}
@@ -280,6 +284,7 @@ static void stop_streaming(struct vb2_queue *vq)
static int start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct mgb4_vin_dev *vindev = vb2_get_drv_priv(vq);
+ struct mgb4_regs *video = &vindev->mgbdev->video;
const struct mgb4_vin_config *config = vindev->config;
int irq = xdma_get_user_irq(vindev->mgbdev->xdev, config->vin_irq);
@@ -292,6 +297,9 @@ static int start_streaming(struct vb2_queue *vq, unsigned int count)
mgb4_mask_reg(&vindev->mgbdev->video, config->regs.config, 0x2,
0x2);
+ mgb4_write_reg(video, vindev->config->regs.padding, vindev->padding);
+ set_loopback_padding(vindev, vindev->padding);
+
xdma_enable_user_irq(vindev->mgbdev->xdev, irq);
return 0;
@@ -304,8 +312,6 @@ static const struct vb2_ops queue_ops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish
};
static int fh_open(struct file *file)
@@ -324,34 +330,16 @@ static int fh_open(struct file *file)
if (get_timings(vindev, &vindev->timings) < 0)
vindev->timings = cea1080p60;
- set_loopback_padding(vindev, vindev->padding);
out:
mutex_unlock(&vindev->lock);
return rv;
}
-static int fh_release(struct file *file)
-{
- struct mgb4_vin_dev *vindev = video_drvdata(file);
- int rv;
-
- mutex_lock(&vindev->lock);
-
- if (v4l2_fh_is_singular_file(file))
- set_loopback_padding(vindev, 0);
-
- rv = _vb2_fop_release(file, NULL);
-
- mutex_unlock(&vindev->lock);
-
- return rv;
-}
-
static const struct v4l2_file_operations video_fops = {
.owner = THIS_MODULE,
.open = fh_open,
- .release = fh_release,
+ .release = vb2_fop_release,
.unlocked_ioctl = video_ioctl2,
.read = vb2_fop_read,
.mmap = vb2_fop_mmap,
@@ -507,8 +495,6 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
vindev->padding = (f->fmt.pix.bytesperline - (f->fmt.pix.width
* pixelsize)) / pixelsize;
- mgb4_write_reg(video, vindev->config->regs.padding, vindev->padding);
- set_loopback_padding(vindev, vindev->padding);
return 0;
}
@@ -853,14 +839,16 @@ static void fpga_init(struct mgb4_vin_dev *vindev)
mgb4_write_reg(video, regs->config, 1U << 9);
}
-#ifdef CONFIG_DEBUG_FS
-static void debugfs_init(struct mgb4_vin_dev *vindev)
+static void create_debugfs(struct mgb4_vin_dev *vindev)
{
+#ifdef CONFIG_DEBUG_FS
struct mgb4_regs *video = &vindev->mgbdev->video;
+ struct dentry *entry;
- vindev->debugfs = debugfs_create_dir(vindev->vdev.name,
- vindev->mgbdev->debugfs);
- if (!vindev->debugfs)
+ if (IS_ERR_OR_NULL(vindev->mgbdev->debugfs))
+ return;
+ entry = debugfs_create_dir(vindev->vdev.name, vindev->mgbdev->debugfs);
+ if (IS_ERR(entry))
return;
vindev->regs[0].name = "CONFIG";
@@ -892,10 +880,9 @@ static void debugfs_init(struct mgb4_vin_dev *vindev)
vindev->regset.base = video->membase;
vindev->regset.regs = vindev->regs;
- debugfs_create_regset32("registers", 0444, vindev->debugfs,
- &vindev->regset);
-}
+ debugfs_create_regset32("registers", 0444, entry, &vindev->regset);
#endif
+}
struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id)
{
@@ -1001,9 +988,7 @@ struct mgb4_vin_dev *mgb4_vin_create(struct mgb4_dev *mgbdev, int id)
goto err_video_dev;
}
-#ifdef CONFIG_DEBUG_FS
- debugfs_init(vindev);
-#endif
+ create_debugfs(vindev);
return vindev;
@@ -1034,10 +1019,6 @@ void mgb4_vin_free(struct mgb4_vin_dev *vindev)
free_irq(vin_irq, vindev);
free_irq(err_irq, vindev);
-#ifdef CONFIG_DEBUG_FS
- debugfs_remove_recursive(vindev->debugfs);
-#endif
-
groups = MGB4_IS_GMSL(vindev->mgbdev)
? mgb4_gmsl_in_groups : mgb4_fpdl3_in_groups;
device_remove_groups(&vindev->vdev.dev, groups);
diff --git a/drivers/media/pci/mgb4/mgb4_vin.h b/drivers/media/pci/mgb4/mgb4_vin.h
index 9693bd0ce180..8fd10c0a5554 100644
--- a/drivers/media/pci/mgb4/mgb4_vin.h
+++ b/drivers/media/pci/mgb4/mgb4_vin.h
@@ -58,7 +58,6 @@ struct mgb4_vin_dev {
const struct mgb4_vin_config *config;
#ifdef CONFIG_DEBUG_FS
- struct dentry *debugfs;
struct debugfs_regset32 regset;
struct debugfs_reg32 regs[sizeof(struct mgb4_vin_regs) / 4];
#endif
diff --git a/drivers/media/pci/mgb4/mgb4_vout.c b/drivers/media/pci/mgb4/mgb4_vout.c
index 998edcbd9723..6b2791e29de1 100644
--- a/drivers/media/pci/mgb4/mgb4_vout.c
+++ b/drivers/media/pci/mgb4/mgb4_vout.c
@@ -230,8 +230,6 @@ static const struct vb2_ops queue_ops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish
};
static int vidioc_querycap(struct file *file, void *priv,
@@ -676,14 +674,16 @@ static void fpga_init(struct mgb4_vout_dev *voutdev)
(voutdev->config->id + MGB4_VIN_DEVICES) << 2 | 1 << 4);
}
-#ifdef CONFIG_DEBUG_FS
-static void debugfs_init(struct mgb4_vout_dev *voutdev)
+static void create_debugfs(struct mgb4_vout_dev *voutdev)
{
+#ifdef CONFIG_DEBUG_FS
struct mgb4_regs *video = &voutdev->mgbdev->video;
+ struct dentry *entry;
- voutdev->debugfs = debugfs_create_dir(voutdev->vdev.name,
- voutdev->mgbdev->debugfs);
- if (!voutdev->debugfs)
+ if (IS_ERR_OR_NULL(voutdev->mgbdev->debugfs))
+ return;
+ entry = debugfs_create_dir(voutdev->vdev.name, voutdev->mgbdev->debugfs);
+ if (IS_ERR(entry))
return;
voutdev->regs[0].name = "CONFIG";
@@ -711,10 +711,9 @@ static void debugfs_init(struct mgb4_vout_dev *voutdev)
voutdev->regset.base = video->membase;
voutdev->regset.regs = voutdev->regs;
- debugfs_create_regset32("registers", 0444, voutdev->debugfs,
- &voutdev->regset);
-}
+ debugfs_create_regset32("registers", 0444, entry, &voutdev->regset);
#endif
+}
struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id)
{
@@ -808,9 +807,7 @@ struct mgb4_vout_dev *mgb4_vout_create(struct mgb4_dev *mgbdev, int id)
goto err_video_dev;
}
-#ifdef CONFIG_DEBUG_FS
- debugfs_init(voutdev);
-#endif
+ create_debugfs(voutdev);
return voutdev;
@@ -833,10 +830,6 @@ void mgb4_vout_free(struct mgb4_vout_dev *voutdev)
free_irq(irq, voutdev);
-#ifdef CONFIG_DEBUG_FS
- debugfs_remove_recursive(voutdev->debugfs);
-#endif
-
groups = MGB4_IS_GMSL(voutdev->mgbdev)
? mgb4_gmsl_out_groups : mgb4_fpdl3_out_groups;
device_remove_groups(&voutdev->vdev.dev, groups);
diff --git a/drivers/media/pci/mgb4/mgb4_vout.h b/drivers/media/pci/mgb4/mgb4_vout.h
index adc8fe1e7ae6..a07eeabdcf34 100644
--- a/drivers/media/pci/mgb4/mgb4_vout.h
+++ b/drivers/media/pci/mgb4/mgb4_vout.h
@@ -54,7 +54,6 @@ struct mgb4_vout_dev {
const struct mgb4_vout_config *config;
#ifdef CONFIG_DEBUG_FS
- struct dentry *debugfs;
struct debugfs_regset32 regset;
struct debugfs_reg32 regs[sizeof(struct mgb4_vout_regs) / 4];
#endif
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c b/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c
index e90aa1c1584c..34d6d52f1e4e 100644
--- a/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c
+++ b/drivers/media/pci/netup_unidvb/netup_unidvb_spi.c
@@ -175,11 +175,11 @@ int netup_spi_init(struct netup_unidvb_dev *ndev)
struct spi_controller *ctlr;
struct netup_spi *nspi;
- ctlr = devm_spi_alloc_master(&ndev->pci_dev->dev,
- sizeof(struct netup_spi));
+ ctlr = devm_spi_alloc_host(&ndev->pci_dev->dev,
+ sizeof(struct netup_spi));
if (!ctlr) {
dev_err(&ndev->pci_dev->dev,
- "%s(): unable to alloc SPI master\n", __func__);
+ "%s(): unable to alloc SPI host\n", __func__);
return -EINVAL;
}
nspi = spi_controller_get_devdata(ctlr);
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index bbf480ab31ca..8c4f70e4177d 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -78,8 +78,6 @@ static const struct vb2_ops saa7134_empress_qops = {
.buf_init = saa7134_ts_buffer_init,
.buf_prepare = saa7134_ts_buffer_prepare,
.buf_queue = saa7134_vb2_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c
index 437dbe5e75e2..ec699ea14799 100644
--- a/drivers/media/pci/saa7134/saa7134-ts.c
+++ b/drivers/media/pci/saa7134/saa7134-ts.c
@@ -166,8 +166,6 @@ struct vb2_ops saa7134_ts_qops = {
.buf_init = saa7134_ts_buffer_init,
.buf_prepare = saa7134_ts_buffer_prepare,
.buf_queue = saa7134_vb2_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = saa7134_ts_stop_streaming,
};
EXPORT_SYMBOL_GPL(saa7134_ts_qops);
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
index 3e773690468b..efa6e4fa423a 100644
--- a/drivers/media/pci/saa7134/saa7134-vbi.c
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -161,8 +161,6 @@ const struct vb2_ops saa7134_vbi_qops = {
.buf_init = buffer_init,
.buf_prepare = buffer_prepare,
.buf_queue = saa7134_vb2_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = saa7134_vb2_start_streaming,
.stop_streaming = saa7134_vb2_stop_streaming,
};
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index 56b4481a40e6..43e7b006eb59 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -844,8 +844,6 @@ static const struct vb2_ops vb2_qops = {
.buf_init = buffer_init,
.buf_prepare = buffer_prepare,
.buf_queue = saa7134_vb2_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = saa7134_vb2_start_streaming,
.stop_streaming = saa7134_vb2_stop_streaming,
};
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
index 0adf3d80f248..5ee59b3844cc 100644
--- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
@@ -756,8 +756,6 @@ static const struct vb2_ops solo_enc_video_qops = {
.buf_finish = solo_enc_buf_finish,
.start_streaming = solo_enc_start_streaming,
.stop_streaming = solo_enc_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int solo_enc_querycap(struct file *file, void *priv,
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2.c b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
index e18cc41fca83..35715b21dbdf 100644
--- a/drivers/media/pci/solo6x10/solo6x10-v4l2.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2.c
@@ -365,8 +365,6 @@ static const struct vb2_ops solo_video_qops = {
.buf_queue = solo_buf_queue,
.start_streaming = solo_start_streaming,
.stop_streaming = solo_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int solo_querycap(struct file *file, void *priv,
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 364ce9e57018..3049bad20f14 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -372,8 +372,6 @@ static const struct vb2_ops vip_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c
index 4f35c159efe5..0a08708e52b0 100644
--- a/drivers/media/pci/tw5864/tw5864-video.c
+++ b/drivers/media/pci/tw5864/tw5864-video.c
@@ -471,8 +471,6 @@ static const struct vb2_ops tw5864_video_qops = {
.buf_queue = tw5864_buf_queue,
.start_streaming = tw5864_start_streaming,
.stop_streaming = tw5864_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int tw5864_s_ctrl(struct v4l2_ctrl *ctrl)
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
index cdf5d733b863..77773dec48b8 100644
--- a/drivers/media/pci/tw68/tw68-video.c
+++ b/drivers/media/pci/tw68/tw68-video.c
@@ -524,8 +524,6 @@ static const struct vb2_ops tw68_video_qops = {
.buf_finish = tw68_buf_finish,
.start_streaming = tw68_start_streaming,
.stop_streaming = tw68_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* ------------------------------------------------------------------ */
diff --git a/drivers/media/pci/tw686x/tw686x-video.c b/drivers/media/pci/tw686x/tw686x-video.c
index 63be95fce83d..785dd797d921 100644
--- a/drivers/media/pci/tw686x/tw686x-video.c
+++ b/drivers/media/pci/tw686x/tw686x-video.c
@@ -579,8 +579,6 @@ static const struct vb2_ops tw686x_video_qops = {
.buf_prepare = tw686x_buf_prepare,
.start_streaming = tw686x_start_streaming,
.stop_streaming = tw686x_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int tw686x_s_ctrl(struct v4l2_ctrl *ctrl)
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
index 5c05e64c71a9..f42f596d3e62 100644
--- a/drivers/media/pci/zoran/zoran_driver.c
+++ b/drivers/media/pci/zoran/zoran_driver.c
@@ -950,8 +950,6 @@ static const struct vb2_ops zr_video_qops = {
.buf_prepare = zr_vb2_prepare,
.start_streaming = zr_vb2_start_streaming,
.stop_streaming = zr_vb2_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
int zoran_queue_init(struct zoran *zr, struct vb2_queue *vq, int dir)
diff --git a/drivers/media/platform/allegro-dvt/allegro-core.c b/drivers/media/platform/allegro-dvt/allegro-core.c
index 73606cee586e..e491399afcc9 100644
--- a/drivers/media/platform/allegro-dvt/allegro-core.c
+++ b/drivers/media/platform/allegro-dvt/allegro-core.c
@@ -1509,8 +1509,10 @@ static int allocate_buffers_internal(struct allegro_channel *channel,
INIT_LIST_HEAD(&buffer->head);
err = allegro_alloc_buffer(dev, buffer, size);
- if (err)
+ if (err) {
+ kfree(buffer);
goto err;
+ }
list_add(&buffer->head, list);
}
@@ -2895,8 +2897,6 @@ static const struct vb2_ops allegro_queue_ops = {
.buf_queue = allegro_buf_queue,
.start_streaming = allegro_start_streaming,
.stop_streaming = allegro_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int allegro_queue_init(void *priv,
@@ -4003,7 +4003,7 @@ static const struct dev_pm_ops allegro_pm_ops = {
static struct platform_driver allegro_driver = {
.probe = allegro_probe,
- .remove_new = allegro_remove,
+ .remove = allegro_remove,
.driver = {
.name = "allegro",
.of_match_table = allegro_dt_ids,
diff --git a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c
index 09409908ba5d..0c004bb8ba05 100644
--- a/drivers/media/platform/amlogic/meson-ge2d/ge2d.c
+++ b/drivers/media/platform/amlogic/meson-ge2d/ge2d.c
@@ -391,8 +391,6 @@ static const struct vb2_ops ge2d_qops = {
.buf_queue = ge2d_buf_queue,
.start_streaming = ge2d_start_streaming,
.stop_streaming = ge2d_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int
@@ -1045,7 +1043,7 @@ MODULE_DEVICE_TABLE(of, meson_ge2d_match);
static struct platform_driver ge2d_drv = {
.probe = ge2d_probe,
- .remove_new = ge2d_remove,
+ .remove = ge2d_remove,
.driver = {
.name = "meson-ge2d",
.of_match_table = meson_ge2d_match,
diff --git a/drivers/media/platform/amphion/venc.c b/drivers/media/platform/amphion/venc.c
index 351b4edc8742..c5c1f1fbaa80 100644
--- a/drivers/media/platform/amphion/venc.c
+++ b/drivers/media/platform/amphion/venc.c
@@ -52,6 +52,7 @@ struct venc_t {
u32 ready_count;
u32 enable;
u32 stopped;
+ u32 memory_resource_configured;
u32 skipped_count;
u32 skipped_bytes;
@@ -943,10 +944,19 @@ static int venc_start_session(struct vpu_inst *inst, u32 type)
ret = vpu_iface_set_encode_params(inst, &venc->params, 0);
if (ret)
goto error;
+
+ venc->memory_resource_configured = false;
ret = vpu_session_configure_codec(inst);
if (ret)
goto error;
+ if (!venc->memory_resource_configured) {
+ vb2_queue_error(v4l2_m2m_get_src_vq(inst->fh.m2m_ctx));
+ vb2_queue_error(v4l2_m2m_get_dst_vq(inst->fh.m2m_ctx));
+ ret = -ENOMEM;
+ goto error;
+ }
+
inst->state = VPU_CODEC_STATE_CONFIGURED;
/*vpu_iface_config_memory_resource*/
@@ -985,6 +995,7 @@ static void venc_cleanup_mem_resource(struct vpu_inst *inst)
u32 i;
venc = inst->priv;
+ venc->memory_resource_configured = false;
for (i = 0; i < ARRAY_SIZE(venc->enc); i++)
vpu_free_dma(&venc->enc[i]);
@@ -1048,6 +1059,7 @@ static void venc_request_mem_resource(struct vpu_inst *inst,
vpu_iface_config_memory_resource(inst, MEM_RES_REF, i, &venc->ref[i]);
for (i = 0; i < act_frame_num; i++)
vpu_iface_config_memory_resource(inst, MEM_RES_ACT, i, &venc->act[i]);
+ venc->memory_resource_configured = true;
}
static void venc_cleanup_frames(struct venc_t *venc)
diff --git a/drivers/media/platform/amphion/vpu_core.c b/drivers/media/platform/amphion/vpu_core.c
index 3a2030d02e45..8df85c14ab3f 100644
--- a/drivers/media/platform/amphion/vpu_core.c
+++ b/drivers/media/platform/amphion/vpu_core.c
@@ -864,7 +864,7 @@ MODULE_DEVICE_TABLE(of, vpu_core_dt_match);
static struct platform_driver amphion_vpu_core_driver = {
.probe = vpu_core_probe,
- .remove_new = vpu_core_remove,
+ .remove = vpu_core_remove,
.driver = {
.name = "amphion-vpu-core",
.of_match_table = vpu_core_dt_match,
diff --git a/drivers/media/platform/amphion/vpu_drv.c b/drivers/media/platform/amphion/vpu_drv.c
index 2bf70aafd2ba..efbfd2652721 100644
--- a/drivers/media/platform/amphion/vpu_drv.c
+++ b/drivers/media/platform/amphion/vpu_drv.c
@@ -151,8 +151,8 @@ err_add_decoder:
media_device_cleanup(&vpu->mdev);
v4l2_device_unregister(&vpu->v4l2_dev);
err_vpu_deinit:
- pm_runtime_set_suspended(dev);
pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
return ret;
}
@@ -227,7 +227,7 @@ MODULE_DEVICE_TABLE(of, vpu_dt_match);
static struct platform_driver amphion_vpu_driver = {
.probe = vpu_probe,
- .remove_new = vpu_remove,
+ .remove = vpu_remove,
.driver = {
.name = "amphion-vpu",
.of_match_table = vpu_dt_match,
diff --git a/drivers/media/platform/amphion/vpu_v4l2.c b/drivers/media/platform/amphion/vpu_v4l2.c
index 83db57bc80b7..45707931bc4f 100644
--- a/drivers/media/platform/amphion/vpu_v4l2.c
+++ b/drivers/media/platform/amphion/vpu_v4l2.c
@@ -646,8 +646,6 @@ static const struct vb2_ops vpu_vb2_ops = {
.start_streaming = vpu_vb2_start_streaming,
.stop_streaming = vpu_vb2_stop_streaming,
.buf_queue = vpu_vb2_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int vpu_m2m_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
@@ -841,6 +839,7 @@ int vpu_add_func(struct vpu_dev *vpu, struct vpu_func *func)
vfd->fops = vdec_get_fops();
vfd->ioctl_ops = vdec_get_ioctl_ops();
}
+ video_set_drvdata(vfd, vpu);
ret = video_register_device(vfd, VFL_TYPE_VIDEO, -1);
if (ret) {
@@ -848,7 +847,6 @@ int vpu_add_func(struct vpu_dev *vpu, struct vpu_func *func)
v4l2_m2m_release(func->m2m_dev);
return ret;
}
- video_set_drvdata(vfd, vpu);
func->vfd = vfd;
ret = v4l2_m2m_register_media_controller(func->m2m_dev, func->vfd, func->function);
diff --git a/drivers/media/platform/aspeed/aspeed-video.c b/drivers/media/platform/aspeed/aspeed-video.c
index fc6050e3be0d..54cae0da9aca 100644
--- a/drivers/media/platform/aspeed/aspeed-video.c
+++ b/drivers/media/platform/aspeed/aspeed-video.c
@@ -1891,8 +1891,6 @@ static void aspeed_video_buf_queue(struct vb2_buffer *vb)
static const struct vb2_ops aspeed_video_vb2_ops = {
.queue_setup = aspeed_video_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_prepare = aspeed_video_buf_prepare,
.start_streaming = aspeed_video_start_streaming,
.stop_streaming = aspeed_video_stop_streaming,
@@ -2226,7 +2224,7 @@ static struct platform_driver aspeed_video_driver = {
.of_match_table = aspeed_video_of_match,
},
.probe = aspeed_video_probe,
- .remove_new = aspeed_video_remove,
+ .remove = aspeed_video_remove,
};
module_platform_driver(aspeed_video_driver);
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index 5c823d3f9cc0..0d1c39347529 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -526,8 +526,6 @@ static const struct vb2_ops isi_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int isi_g_fmt_vid_cap(struct file *file, void *priv,
@@ -1367,7 +1365,7 @@ static struct platform_driver atmel_isi_driver = {
.pm = &atmel_isi_dev_pm_ops,
},
.probe = atmel_isi_probe,
- .remove_new = atmel_isi_remove,
+ .remove = atmel_isi_remove,
};
module_platform_driver(atmel_isi_driver);
diff --git a/drivers/media/platform/broadcom/bcm2835-unicam.c b/drivers/media/platform/broadcom/bcm2835-unicam.c
index a1d93c14553d..3aed0e493c81 100644
--- a/drivers/media/platform/broadcom/bcm2835-unicam.c
+++ b/drivers/media/platform/broadcom/bcm2835-unicam.c
@@ -1801,8 +1801,6 @@ static void unicam_buffer_queue(struct vb2_buffer *vb)
static const struct vb2_ops unicam_video_qops = {
.queue_setup = unicam_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_prepare = unicam_buffer_prepare,
.start_streaming = unicam_start_streaming,
.stop_streaming = unicam_stop_streaming,
@@ -2724,7 +2722,7 @@ MODULE_DEVICE_TABLE(of, unicam_of_match);
static struct platform_driver unicam_driver = {
.probe = unicam_probe,
- .remove_new = unicam_remove,
+ .remove = unicam_remove,
.driver = {
.name = UNICAM_MODULE_NAME,
.pm = pm_ptr(&unicam_pm_ops),
diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c
index 6f7d27a48eff..4d64df829e75 100644
--- a/drivers/media/platform/cadence/cdns-csi2rx.c
+++ b/drivers/media/platform/cadence/cdns-csi2rx.c
@@ -751,7 +751,7 @@ MODULE_DEVICE_TABLE(of, csi2rx_of_table);
static struct platform_driver csi2rx_driver = {
.probe = csi2rx_probe,
- .remove_new = csi2rx_remove,
+ .remove = csi2rx_remove,
.driver = {
.name = "cdns-csi2rx",
diff --git a/drivers/media/platform/cadence/cdns-csi2tx.c b/drivers/media/platform/cadence/cdns-csi2tx.c
index 3d98f91f1bee..e22b133f346d 100644
--- a/drivers/media/platform/cadence/cdns-csi2tx.c
+++ b/drivers/media/platform/cadence/cdns-csi2tx.c
@@ -644,7 +644,7 @@ static void csi2tx_remove(struct platform_device *pdev)
static struct platform_driver csi2tx_driver = {
.probe = csi2tx_probe,
- .remove_new = csi2tx_remove,
+ .remove = csi2tx_remove,
.driver = {
.name = "cdns-csi2tx",
diff --git a/drivers/media/platform/chips-media/coda/coda-common.c b/drivers/media/platform/chips-media/coda/coda-common.c
index 7da0194ec850..289a076c3bcc 100644
--- a/drivers/media/platform/chips-media/coda/coda-common.c
+++ b/drivers/media/platform/chips-media/coda/coda-common.c
@@ -2171,8 +2171,6 @@ static const struct vb2_ops coda_qops = {
.buf_queue = coda_buf_queue,
.start_streaming = coda_start_streaming,
.stop_streaming = coda_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
@@ -3346,7 +3344,7 @@ static const struct dev_pm_ops coda_pm_ops = {
static struct platform_driver coda_driver = {
.probe = coda_probe,
- .remove_new = coda_remove,
+ .remove = coda_remove,
.driver = {
.name = CODA_NAME,
.of_match_table = coda_dt_ids,
diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.c b/drivers/media/platform/chips-media/wave5/wave5-helper.c
index d60841c54a80..2c9d8cbca6e4 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-helper.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-helper.c
@@ -7,6 +7,8 @@
#include "wave5-helper.h"
+#define DEFAULT_BS_SIZE(width, height) ((width) * (height) / 8 * 3)
+
const char *state_to_str(enum vpu_instance_state state)
{
switch (state) {
@@ -58,7 +60,6 @@ int wave5_vpu_release_device(struct file *filp,
char *name)
{
struct vpu_instance *inst = wave5_to_vpu_inst(filp->private_data);
- struct vpu_device *dev = inst->dev;
int ret = 0;
v4l2_m2m_ctx_release(inst->v4l2_fh.m2m_ctx);
@@ -78,18 +79,6 @@ int wave5_vpu_release_device(struct file *filp,
}
wave5_cleanup_instance(inst);
- if (dev->irq < 0) {
- ret = mutex_lock_interruptible(&dev->dev_lock);
- if (ret)
- return ret;
-
- if (list_empty(&dev->instances)) {
- dev_dbg(dev->dev, "Disabling the hrtimer\n");
- hrtimer_cancel(&dev->hrtimer);
- }
-
- mutex_unlock(&dev->dev_lock);
- }
return ret;
}
@@ -230,3 +219,25 @@ void wave5_return_bufs(struct vb2_queue *q, u32 state)
v4l2_m2m_buf_done(vbuf, state);
}
}
+
+void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
+ int pix_fmt_type,
+ unsigned int width,
+ unsigned int height,
+ const struct v4l2_frmsize_stepwise *frmsize)
+{
+ v4l2_apply_frmsize_constraints(&width, &height, frmsize);
+
+ if (pix_fmt_type == VPU_FMT_TYPE_CODEC) {
+ pix_mp->width = width;
+ pix_mp->height = height;
+ pix_mp->num_planes = 1;
+ pix_mp->plane_fmt[0].bytesperline = 0;
+ pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_BS_SIZE(width, height),
+ pix_mp->plane_fmt[0].sizeimage);
+ } else {
+ v4l2_fill_pixfmt_mp(pix_mp, pix_mp->pixelformat, width, height);
+ }
+ pix_mp->flags = 0;
+ pix_mp->field = V4L2_FIELD_NONE;
+}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-helper.h b/drivers/media/platform/chips-media/wave5/wave5-helper.h
index 6cee1c14d3ce..9937fce553fc 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-helper.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-helper.h
@@ -28,4 +28,9 @@ const struct vpu_format *wave5_find_vpu_fmt_by_idx(unsigned int idx,
const struct vpu_format fmt_list[MAX_FMTS]);
enum wave_std wave5_to_vpu_std(unsigned int v4l2_pix_fmt, enum vpu_instance_type type);
void wave5_return_bufs(struct vb2_queue *q, u32 state);
+void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp,
+ int pix_fmt_type,
+ unsigned int width,
+ unsigned int height,
+ const struct v4l2_frmsize_stepwise *frmsize);
#endif
diff --git a/drivers/media/platform/chips-media/wave5/wave5-hw.c b/drivers/media/platform/chips-media/wave5/wave5-hw.c
index c89aafabc742..c8a905994109 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-hw.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c
@@ -23,6 +23,15 @@
#define W521_FEATURE_AVC_ENCODER BIT(1)
#define W521_FEATURE_HEVC_ENCODER BIT(0)
+#define ENC_AVC_INTRA_IDR_PARAM_MASK 0x7ff
+#define ENC_AVC_INTRA_PERIOD_SHIFT 6
+#define ENC_AVC_IDR_PERIOD_SHIFT 17
+#define ENC_AVC_FORCED_IDR_HEADER_SHIFT 28
+
+#define ENC_HEVC_INTRA_QP_SHIFT 3
+#define ENC_HEVC_FORCED_IDR_HEADER_SHIFT 9
+#define ENC_HEVC_INTRA_PERIOD_SHIFT 16
+
/* Decoder support fields */
#define W521_FEATURE_AVC_DECODER BIT(3)
#define W521_FEATURE_HEVC_DECODER BIT(2)
@@ -35,7 +44,7 @@
#define REMAP_CTRL_MAX_SIZE_BITS ((W5_REMAP_MAX_SIZE >> 12) & 0x1ff)
#define REMAP_CTRL_REGISTER_VALUE(index) ( \
- (BIT(31) | (index << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS) \
+ (BIT(31) | ((index) << 12) | BIT(11) | REMAP_CTRL_MAX_SIZE_BITS)\
)
#define FASTIO_ADDRESS_MASK GENMASK(15, 0)
@@ -1219,8 +1228,8 @@ int wave5_vpu_re_init(struct device *dev, u8 *fw, size_t size)
return setup_wave5_properties(dev);
}
-static int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code,
- size_t size)
+int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code,
+ size_t size)
{
u32 reg_val;
struct vpu_buf *common_vb;
@@ -1772,12 +1781,19 @@ int wave5_vpu_enc_init_seq(struct vpu_instance *inst)
if (inst->std == W_AVC_ENC)
vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM, p_param->intra_qp |
- ((p_param->intra_period & 0x7ff) << 6) |
- ((p_param->avc_idr_period & 0x7ff) << 17));
+ ((p_param->intra_period & ENC_AVC_INTRA_IDR_PARAM_MASK)
+ << ENC_AVC_INTRA_PERIOD_SHIFT) |
+ ((p_param->avc_idr_period & ENC_AVC_INTRA_IDR_PARAM_MASK)
+ << ENC_AVC_IDR_PERIOD_SHIFT) |
+ (p_param->forced_idr_header_enable
+ << ENC_AVC_FORCED_IDR_HEADER_SHIFT));
else if (inst->std == W_HEVC_ENC)
vpu_write_reg(inst->dev, W5_CMD_ENC_SEQ_INTRA_PARAM,
- p_param->decoding_refresh_type | (p_param->intra_qp << 3) |
- (p_param->intra_period << 16));
+ p_param->decoding_refresh_type |
+ (p_param->intra_qp << ENC_HEVC_INTRA_QP_SHIFT) |
+ (p_param->forced_idr_header_enable
+ << ENC_HEVC_FORCED_IDR_HEADER_SHIFT) |
+ (p_param->intra_period << ENC_HEVC_INTRA_PERIOD_SHIFT));
reg_val = (p_param->rdo_skip << 2) |
(p_param->lambda_scaling_enable << 3) |
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 0c5c9a8de91f..d3ff420c52ce 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-dec.c
@@ -5,116 +5,98 @@
* Copyright (C) 2021-2023 CHIPS&MEDIA INC
*/
+#include <linux/pm_runtime.h>
#include "wave5-helper.h"
#define VPU_DEC_DEV_NAME "C&M Wave5 VPU decoder"
#define VPU_DEC_DRV_NAME "wave5-dec"
-#define DEFAULT_SRC_SIZE(width, height) ({ \
- (width) * (height) / 8 * 3; \
-})
+static const struct v4l2_frmsize_stepwise dec_hevc_frmsize = {
+ .min_width = W5_MIN_DEC_PIC_8_WIDTH,
+ .max_width = W5_MAX_DEC_PIC_WIDTH,
+ .step_width = W5_DEC_CODEC_STEP_WIDTH,
+ .min_height = W5_MIN_DEC_PIC_8_HEIGHT,
+ .max_height = W5_MAX_DEC_PIC_HEIGHT,
+ .step_height = W5_DEC_CODEC_STEP_HEIGHT,
+};
+
+static const struct v4l2_frmsize_stepwise dec_h264_frmsize = {
+ .min_width = W5_MIN_DEC_PIC_32_WIDTH,
+ .max_width = W5_MAX_DEC_PIC_WIDTH,
+ .step_width = W5_DEC_CODEC_STEP_WIDTH,
+ .min_height = W5_MIN_DEC_PIC_32_HEIGHT,
+ .max_height = W5_MAX_DEC_PIC_HEIGHT,
+ .step_height = W5_DEC_CODEC_STEP_HEIGHT,
+};
+
+static const struct v4l2_frmsize_stepwise dec_raw_frmsize = {
+ .min_width = W5_MIN_DEC_PIC_8_WIDTH,
+ .max_width = W5_MAX_DEC_PIC_WIDTH,
+ .step_width = W5_DEC_RAW_STEP_WIDTH,
+ .min_height = W5_MIN_DEC_PIC_8_HEIGHT,
+ .max_height = W5_MAX_DEC_PIC_HEIGHT,
+ .step_height = W5_DEC_RAW_STEP_HEIGHT,
+};
static const struct vpu_format dec_fmt_list[FMT_TYPES][MAX_FMTS] = {
[VPU_FMT_TYPE_CODEC] = {
{
.v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_hevc_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_H264,
- .max_width = 8192,
- .min_width = 32,
- .max_height = 4320,
- .min_height = 32,
+ .v4l2_frmsize = &dec_h264_frmsize,
},
},
[VPU_FMT_TYPE_RAW] = {
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV16,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV61,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV16M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV61M,
- .max_width = 8192,
- .min_width = 8,
- .max_height = 4320,
- .min_height = 8,
+ .v4l2_frmsize = &dec_raw_frmsize,
},
}
};
@@ -233,74 +215,6 @@ static void wave5_handle_src_buffer(struct vpu_instance *inst, dma_addr_t rd_ptr
inst->remaining_consumed_bytes = consumed_bytes;
}
-static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width,
- unsigned int height)
-{
- switch (pix_mp->pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height * 3 / 2;
- break;
- case V4L2_PIX_FMT_YUV422P:
- case V4L2_PIX_FMT_NV16:
- case V4L2_PIX_FMT_NV61:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height * 2;
- break;
- case V4L2_PIX_FMT_YUV420M:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[1].sizeimage = width * height / 4;
- pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[2].sizeimage = width * height / 4;
- break;
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV21M:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[1].sizeimage = width * height / 2;
- break;
- case V4L2_PIX_FMT_YUV422M:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[1].sizeimage = width * height / 2;
- pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[2].sizeimage = width * height / 2;
- break;
- case V4L2_PIX_FMT_NV16M:
- case V4L2_PIX_FMT_NV61M:
- pix_mp->width = round_up(width, 32);
- pix_mp->height = round_up(height, 16);
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = width * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[1].sizeimage = width * height;
- break;
- default:
- pix_mp->width = width;
- pix_mp->height = height;
- pix_mp->plane_fmt[0].bytesperline = 0;
- pix_mp->plane_fmt[0].sizeimage = max(DEFAULT_SRC_SIZE(width, height),
- pix_mp->plane_fmt[0].sizeimage);
- break;
- }
-}
-
static int start_decode(struct vpu_instance *inst, u32 *fail_res)
{
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
@@ -388,6 +302,8 @@ static int handle_dynamic_resolution_change(struct vpu_instance *inst)
}
if (p_dec_info->initial_info_obtained) {
+ const struct vpu_format *vpu_fmt;
+
inst->conf_win.left = initial_info->pic_crop_rect.left;
inst->conf_win.top = initial_info->pic_crop_rect.top;
inst->conf_win.width = initial_info->pic_width -
@@ -395,10 +311,27 @@ static int handle_dynamic_resolution_change(struct vpu_instance *inst)
inst->conf_win.height = initial_info->pic_height -
initial_info->pic_crop_rect.top - initial_info->pic_crop_rect.bottom;
- wave5_update_pix_fmt(&inst->src_fmt, initial_info->pic_width,
- initial_info->pic_height);
- wave5_update_pix_fmt(&inst->dst_fmt, initial_info->pic_width,
- initial_info->pic_height);
+ vpu_fmt = wave5_find_vpu_fmt(inst->src_fmt.pixelformat,
+ dec_fmt_list[VPU_FMT_TYPE_CODEC]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ wave5_update_pix_fmt(&inst->src_fmt,
+ VPU_FMT_TYPE_CODEC,
+ initial_info->pic_width,
+ initial_info->pic_height,
+ vpu_fmt->v4l2_frmsize);
+
+ vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat,
+ dec_fmt_list[VPU_FMT_TYPE_RAW]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ wave5_update_pix_fmt(&inst->dst_fmt,
+ VPU_FMT_TYPE_RAW,
+ initial_info->pic_width,
+ initial_info->pic_height,
+ vpu_fmt->v4l2_frmsize);
}
v4l2_event_queue_fh(fh, &vpu_event_src_ch);
@@ -518,6 +451,8 @@ static void wave5_vpu_dec_finish_decode(struct vpu_instance *inst)
if (q_status.report_queue_count == 0 &&
(q_status.instance_queue_count == 0 || dec_info.sequence_changed)) {
dev_dbg(inst->dev->dev, "%s: finishing job.\n", __func__);
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
}
@@ -545,12 +480,12 @@ static int wave5_vpu_dec_enum_framesizes(struct file *f, void *fh, struct v4l2_f
}
fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
- fsize->stepwise.min_width = vpu_fmt->min_width;
- fsize->stepwise.max_width = vpu_fmt->max_width;
- fsize->stepwise.step_width = 1;
- fsize->stepwise.min_height = vpu_fmt->min_height;
- fsize->stepwise.max_height = vpu_fmt->max_height;
- fsize->stepwise.step_height = 1;
+ fsize->stepwise.min_width = vpu_fmt->v4l2_frmsize->min_width;
+ fsize->stepwise.max_width = vpu_fmt->v4l2_frmsize->max_width;
+ fsize->stepwise.step_width = W5_DEC_CODEC_STEP_WIDTH;
+ fsize->stepwise.min_height = vpu_fmt->v4l2_frmsize->min_height;
+ fsize->stepwise.max_height = vpu_fmt->v4l2_frmsize->max_height;
+ fsize->stepwise.step_height = W5_DEC_CODEC_STEP_HEIGHT;
return 0;
}
@@ -573,6 +508,7 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
struct dec_info *p_dec_info = &inst->codec_info->dec_info;
+ const struct v4l2_frmsize_stepwise *frmsize;
const struct vpu_format *vpu_fmt;
int width, height;
@@ -586,14 +522,12 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo
width = inst->dst_fmt.width;
height = inst->dst_fmt.height;
f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat;
- f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes;
+ frmsize = &dec_raw_frmsize;
} else {
- const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt);
-
- width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
- height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
+ width = f->fmt.pix_mp.width;
+ height = f->fmt.pix_mp.height;
f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
- f->fmt.pix_mp.num_planes = info->mem_planes;
+ frmsize = vpu_fmt->v4l2_frmsize;
}
if (p_dec_info->initial_info_obtained) {
@@ -601,9 +535,8 @@ static int wave5_vpu_dec_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo
height = inst->dst_fmt.height;
}
- wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
- f->fmt.pix_mp.flags = 0;
- f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_RAW,
+ width, height, frmsize);
f->fmt.pix_mp.colorspace = inst->colorspace;
f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
f->fmt.pix_mp.quantization = inst->quantization;
@@ -715,7 +648,9 @@ static int wave5_vpu_dec_enum_fmt_out(struct file *file, void *fh, struct v4l2_f
static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct v4l2_frmsize_stepwise *frmsize;
const struct vpu_format *vpu_fmt;
+ int width, height;
dev_dbg(inst->dev->dev,
"%s: fourcc: %u width: %u height: %u num_planes: %u colorspace: %u field: %u\n",
@@ -724,20 +659,19 @@ static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_fo
vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, dec_fmt_list[VPU_FMT_TYPE_CODEC]);
if (!vpu_fmt) {
+ width = inst->src_fmt.width;
+ height = inst->src_fmt.height;
f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
- f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes;
- wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height);
+ frmsize = &dec_hevc_frmsize;
} else {
- int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
- int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
-
+ width = f->fmt.pix_mp.width;
+ height = f->fmt.pix_mp.height;
f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
- f->fmt.pix_mp.num_planes = 1;
- wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
+ frmsize = vpu_fmt->v4l2_frmsize;
}
- f->fmt.pix_mp.flags = 0;
- f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_CODEC,
+ width, height, frmsize);
return 0;
}
@@ -745,6 +679,7 @@ static int wave5_vpu_dec_try_fmt_out(struct file *file, void *fh, struct v4l2_fo
static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
int i, ret;
dev_dbg(inst->dev->dev,
@@ -779,7 +714,13 @@ static int wave5_vpu_dec_s_fmt_out(struct file *file, void *fh, struct v4l2_form
inst->quantization = f->fmt.pix_mp.quantization;
inst->xfer_func = f->fmt.pix_mp.xfer_func;
- wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height);
+ vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, dec_fmt_list[VPU_FMT_TYPE_RAW]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ wave5_update_pix_fmt(&inst->dst_fmt, VPU_FMT_TYPE_RAW,
+ f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ vpu_fmt->v4l2_frmsize);
return 0;
}
@@ -1002,6 +943,7 @@ static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buff
struct vpu_instance *inst = vb2_get_drv_priv(q);
struct v4l2_pix_format_mplane inst_format =
(q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) ? inst->src_fmt : inst->dst_fmt;
+ unsigned int i;
dev_dbg(inst->dev->dev, "%s: num_buffers: %u | num_planes: %u | type: %u\n", __func__,
*num_buffers, *num_planes, q->type);
@@ -1015,31 +957,9 @@ static int wave5_vpu_dec_queue_setup(struct vb2_queue *q, unsigned int *num_buff
if (*num_buffers < inst->fbc_buf_count)
*num_buffers = inst->fbc_buf_count;
- if (*num_planes == 1) {
- if (inst->output_format == FORMAT_422)
- sizes[0] = inst_format.width * inst_format.height * 2;
- else
- sizes[0] = inst_format.width * inst_format.height * 3 / 2;
- dev_dbg(inst->dev->dev, "%s: size[0]: %u\n", __func__, sizes[0]);
- } else if (*num_planes == 2) {
- sizes[0] = inst_format.width * inst_format.height;
- if (inst->output_format == FORMAT_422)
- sizes[1] = inst_format.width * inst_format.height;
- else
- sizes[1] = inst_format.width * inst_format.height / 2;
- dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u\n",
- __func__, sizes[0], sizes[1]);
- } else if (*num_planes == 3) {
- sizes[0] = inst_format.width * inst_format.height;
- if (inst->output_format == FORMAT_422) {
- sizes[1] = inst_format.width * inst_format.height / 2;
- sizes[2] = inst_format.width * inst_format.height / 2;
- } else {
- sizes[1] = inst_format.width * inst_format.height / 4;
- sizes[2] = inst_format.width * inst_format.height / 4;
- }
- dev_dbg(inst->dev->dev, "%s: size[0]: %u | size[1]: %u | size[2]: %u\n",
- __func__, sizes[0], sizes[1], sizes[2]);
+ for (i = 0; i < *num_planes; i++) {
+ sizes[i] = inst_format.plane_fmt[i].sizeimage;
+ dev_dbg(inst->dev->dev, "%s: size[%u]: %u\n", __func__, i, sizes[i]);
}
}
@@ -1398,6 +1318,7 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count
int ret = 0;
dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
+ pm_runtime_resume_and_get(inst->dev->dev);
v4l2_m2m_update_start_streaming_state(m2m_ctx, q);
@@ -1429,13 +1350,15 @@ static int wave5_vpu_dec_start_streaming(struct vb2_queue *q, unsigned int count
if (ret)
goto return_buffers;
}
-
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
return ret;
free_bitstream_vbuf:
wave5_vdi_free_dma_memory(inst->dev, &inst->bitstream_vbuf);
return_buffers:
wave5_return_bufs(q, VB2_BUF_STATE_QUEUED);
+ pm_runtime_put_autosuspend(inst->dev->dev);
return ret;
}
@@ -1521,6 +1444,7 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q)
bool check_cmd = TRUE;
dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
+ pm_runtime_resume_and_get(inst->dev->dev);
while (check_cmd) {
struct queue_status_info q_status;
@@ -1544,12 +1468,13 @@ static void wave5_vpu_dec_stop_streaming(struct vb2_queue *q)
streamoff_output(q);
else
streamoff_capture(q);
+
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
}
static const struct vb2_ops wave5_vpu_dec_vb2_ops = {
.queue_setup = wave5_vpu_dec_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_queue = wave5_vpu_dec_buf_queue,
.start_streaming = wave5_vpu_dec_start_streaming,
.stop_streaming = wave5_vpu_dec_stop_streaming,
@@ -1558,20 +1483,15 @@ static const struct vb2_ops wave5_vpu_dec_vb2_ops = {
static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt,
struct v4l2_pix_format_mplane *dst_fmt)
{
- unsigned int dst_pix_fmt = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt;
- const struct v4l2_format_info *dst_fmt_info = v4l2_format_info(dst_pix_fmt);
-
src_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt;
- src_fmt->field = V4L2_FIELD_NONE;
- src_fmt->flags = 0;
- src_fmt->num_planes = 1;
- wave5_update_pix_fmt(src_fmt, 720, 480);
-
- dst_fmt->pixelformat = dst_pix_fmt;
- dst_fmt->field = V4L2_FIELD_NONE;
- dst_fmt->flags = 0;
- dst_fmt->num_planes = dst_fmt_info->mem_planes;
- wave5_update_pix_fmt(dst_fmt, 736, 480);
+ wave5_update_pix_fmt(src_fmt, VPU_FMT_TYPE_CODEC,
+ W5_DEF_DEC_PIC_WIDTH, W5_DEF_DEC_PIC_HEIGHT,
+ &dec_hevc_frmsize);
+
+ dst_fmt->pixelformat = dec_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt;
+ wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_RAW,
+ W5_DEF_DEC_PIC_WIDTH, W5_DEF_DEC_PIC_HEIGHT,
+ &dec_raw_frmsize);
}
static int wave5_vpu_dec_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
@@ -1630,7 +1550,7 @@ static void wave5_vpu_dec_device_run(void *priv)
int ret = 0;
dev_dbg(inst->dev->dev, "%s: Fill the ring buffer with new bitstream data", __func__);
-
+ pm_runtime_resume_and_get(inst->dev->dev);
ret = fill_ringbuffer(inst);
if (ret) {
dev_warn(inst->dev->dev, "Filling ring buffer failed\n");
@@ -1713,6 +1633,8 @@ static void wave5_vpu_dec_device_run(void *priv)
finish_job_and_return:
dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__);
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
@@ -1879,9 +1801,8 @@ static int wave5_vpu_open_dec(struct file *filp)
if (ret)
goto cleanup_inst;
- if (dev->irq < 0 && !hrtimer_active(&dev->hrtimer) && list_empty(&dev->instances))
- hrtimer_start(&dev->hrtimer, ns_to_ktime(dev->vpu_poll_interval * NSEC_PER_MSEC),
- HRTIMER_MODE_REL_PINNED);
+ if (list_empty(&dev->instances))
+ pm_runtime_use_autosuspend(inst->dev->dev);
list_add_tail(&inst->list, &dev->instances);
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 3e35a05c2d8d..1e5fc5f8b856 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c
@@ -5,70 +5,90 @@
* Copyright (C) 2021-2023 CHIPS&MEDIA INC
*/
+#include <linux/pm_runtime.h>
#include "wave5-helper.h"
#define VPU_ENC_DEV_NAME "C&M Wave5 VPU encoder"
#define VPU_ENC_DRV_NAME "wave5-enc"
+static const struct v4l2_frmsize_stepwise enc_frmsize[FMT_TYPES] = {
+ [VPU_FMT_TYPE_CODEC] = {
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .step_width = W5_ENC_CODEC_STEP_WIDTH,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .step_height = W5_ENC_CODEC_STEP_HEIGHT,
+ },
+ [VPU_FMT_TYPE_RAW] = {
+ .min_width = W5_MIN_ENC_PIC_WIDTH,
+ .max_width = W5_MAX_ENC_PIC_WIDTH,
+ .step_width = W5_ENC_RAW_STEP_WIDTH,
+ .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .max_height = W5_MAX_ENC_PIC_HEIGHT,
+ .step_height = W5_ENC_RAW_STEP_HEIGHT,
+ },
+};
+
static const struct vpu_format enc_fmt_list[FMT_TYPES][MAX_FMTS] = {
[VPU_FMT_TYPE_CODEC] = {
{
.v4l2_pix_fmt = V4L2_PIX_FMT_HEVC,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_H264,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC],
},
},
[VPU_FMT_TYPE_RAW] = {
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV420,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV12,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV21,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_YUV420M,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV12M,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
{
.v4l2_pix_fmt = V4L2_PIX_FMT_NV21M,
- .max_width = W5_MAX_ENC_PIC_WIDTH,
- .min_width = W5_MIN_ENC_PIC_WIDTH,
- .max_height = W5_MAX_ENC_PIC_HEIGHT,
- .min_height = W5_MIN_ENC_PIC_HEIGHT,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422P,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV16,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV61,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_YUV422M,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV16M,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
+ },
+ {
+ .v4l2_pix_fmt = V4L2_PIX_FMT_NV61M,
+ .v4l2_frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW],
},
}
};
@@ -105,46 +125,6 @@ invalid_state_switch:
return -EINVAL;
}
-static void wave5_update_pix_fmt(struct v4l2_pix_format_mplane *pix_mp, unsigned int width,
- unsigned int height)
-{
- switch (pix_mp->pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_NV12:
- case V4L2_PIX_FMT_NV21:
- pix_mp->width = width;
- pix_mp->height = height;
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height * 3 / 2;
- break;
- case V4L2_PIX_FMT_YUV420M:
- pix_mp->width = width;
- pix_mp->height = height;
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 4;
- pix_mp->plane_fmt[2].bytesperline = round_up(width, 32) / 2;
- pix_mp->plane_fmt[2].sizeimage = round_up(width, 32) * height / 4;
- break;
- case V4L2_PIX_FMT_NV12M:
- case V4L2_PIX_FMT_NV21M:
- pix_mp->width = width;
- pix_mp->height = height;
- pix_mp->plane_fmt[0].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[0].sizeimage = round_up(width, 32) * height;
- pix_mp->plane_fmt[1].bytesperline = round_up(width, 32);
- pix_mp->plane_fmt[1].sizeimage = round_up(width, 32) * height / 2;
- break;
- default:
- pix_mp->width = width;
- pix_mp->height = height;
- pix_mp->plane_fmt[0].bytesperline = 0;
- pix_mp->plane_fmt[0].sizeimage = width * height / 8 * 3;
- break;
- }
-}
-
static int start_encode(struct vpu_instance *inst, u32 *fail_res)
{
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
@@ -153,13 +133,26 @@ static int start_encode(struct vpu_instance *inst, u32 *fail_res)
struct vb2_v4l2_buffer *dst_buf;
struct frame_buffer frame_buf;
struct enc_param pic_param;
- u32 stride = ALIGN(inst->dst_fmt.width, 32);
- u32 luma_size = (stride * inst->dst_fmt.height);
- u32 chroma_size = ((stride / 2) * (inst->dst_fmt.height / 2));
+ const struct v4l2_format_info *info;
+ u32 stride = inst->src_fmt.plane_fmt[0].bytesperline;
+ u32 luma_size = 0;
+ u32 chroma_size = 0;
memset(&pic_param, 0, sizeof(struct enc_param));
memset(&frame_buf, 0, sizeof(struct frame_buffer));
+ info = v4l2_format_info(inst->src_fmt.pixelformat);
+ if (!info)
+ return -EINVAL;
+
+ if (info->mem_planes == 1) {
+ luma_size = stride * inst->dst_fmt.height;
+ chroma_size = luma_size / (info->hdiv * info->vdiv);
+ } else {
+ luma_size = inst->src_fmt.plane_fmt[0].sizeimage;
+ chroma_size = inst->src_fmt.plane_fmt[1].sizeimage;
+ }
+
dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx);
if (!dst_buf) {
dev_dbg(inst->dev->dev, "%s: No destination buffer found\n", __func__);
@@ -359,13 +352,8 @@ static int wave5_vpu_enc_enum_framesizes(struct file *f, void *fh, struct v4l2_f
return -EINVAL;
}
- fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
- fsize->stepwise.min_width = vpu_fmt->min_width;
- fsize->stepwise.max_width = vpu_fmt->max_width;
- fsize->stepwise.step_width = 1;
- fsize->stepwise.min_height = vpu_fmt->min_height;
- fsize->stepwise.max_height = vpu_fmt->max_height;
- fsize->stepwise.step_height = 1;
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise = enc_frmsize[VPU_FMT_TYPE_CODEC];
return 0;
}
@@ -390,7 +378,9 @@ static int wave5_vpu_enc_enum_fmt_cap(struct file *file, void *fh, struct v4l2_f
static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct v4l2_frmsize_stepwise *frmsize;
const struct vpu_format *vpu_fmt;
+ int width, height;
dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
__func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
@@ -398,20 +388,19 @@ static int wave5_vpu_enc_try_fmt_cap(struct file *file, void *fh, struct v4l2_fo
vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]);
if (!vpu_fmt) {
+ width = inst->dst_fmt.width;
+ height = inst->dst_fmt.height;
f->fmt.pix_mp.pixelformat = inst->dst_fmt.pixelformat;
- f->fmt.pix_mp.num_planes = inst->dst_fmt.num_planes;
- wave5_update_pix_fmt(&f->fmt.pix_mp, inst->dst_fmt.width, inst->dst_fmt.height);
+ frmsize = &enc_frmsize[VPU_FMT_TYPE_CODEC];
} else {
- int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
- int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
-
+ width = f->fmt.pix_mp.width;
+ height = f->fmt.pix_mp.height;
f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
- f->fmt.pix_mp.num_planes = 1;
- wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
+ frmsize = vpu_fmt->v4l2_frmsize;
}
- f->fmt.pix_mp.flags = 0;
- f->fmt.pix_mp.field = V4L2_FIELD_NONE;
+ wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_CODEC,
+ width, height, frmsize);
f->fmt.pix_mp.colorspace = inst->colorspace;
f->fmt.pix_mp.ycbcr_enc = inst->ycbcr_enc;
f->fmt.pix_mp.quantization = inst->quantization;
@@ -498,7 +487,9 @@ static int wave5_vpu_enc_enum_fmt_out(struct file *file, void *fh, struct v4l2_f
static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct v4l2_frmsize_stepwise *frmsize;
const struct vpu_format *vpu_fmt;
+ int width, height;
dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
__func__, f->fmt.pix_mp.pixelformat, f->fmt.pix_mp.width, f->fmt.pix_mp.height,
@@ -506,28 +497,27 @@ static int wave5_vpu_enc_try_fmt_out(struct file *file, void *fh, struct v4l2_fo
vpu_fmt = wave5_find_vpu_fmt(f->fmt.pix_mp.pixelformat, enc_fmt_list[VPU_FMT_TYPE_RAW]);
if (!vpu_fmt) {
+ width = inst->src_fmt.width;
+ height = inst->src_fmt.height;
f->fmt.pix_mp.pixelformat = inst->src_fmt.pixelformat;
- f->fmt.pix_mp.num_planes = inst->src_fmt.num_planes;
- wave5_update_pix_fmt(&f->fmt.pix_mp, inst->src_fmt.width, inst->src_fmt.height);
+ frmsize = &enc_frmsize[VPU_FMT_TYPE_RAW];
} else {
- int width = clamp(f->fmt.pix_mp.width, vpu_fmt->min_width, vpu_fmt->max_width);
- int height = clamp(f->fmt.pix_mp.height, vpu_fmt->min_height, vpu_fmt->max_height);
- const struct v4l2_format_info *info = v4l2_format_info(vpu_fmt->v4l2_pix_fmt);
-
+ width = f->fmt.pix_mp.width;
+ height = f->fmt.pix_mp.height;
f->fmt.pix_mp.pixelformat = vpu_fmt->v4l2_pix_fmt;
- f->fmt.pix_mp.num_planes = info->mem_planes;
- wave5_update_pix_fmt(&f->fmt.pix_mp, width, height);
+ frmsize = vpu_fmt->v4l2_frmsize;
}
- f->fmt.pix_mp.flags = 0;
- f->fmt.pix_mp.field = V4L2_FIELD_NONE;
-
+ wave5_update_pix_fmt(&f->fmt.pix_mp, VPU_FMT_TYPE_RAW,
+ width, height, frmsize);
return 0;
}
static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_format *f)
{
struct vpu_instance *inst = wave5_to_vpu_inst(fh);
+ const struct vpu_format *vpu_fmt;
+ const struct v4l2_format_info *info;
int i, ret;
dev_dbg(inst->dev->dev, "%s: fourcc: %u width: %u height: %u num_planes: %u field: %u\n",
@@ -549,16 +539,20 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form
inst->src_fmt.plane_fmt[i].sizeimage = f->fmt.pix_mp.plane_fmt[i].sizeimage;
}
- if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12 ||
- inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV12M) {
- inst->cbcr_interleave = true;
- inst->nv21 = false;
- } else if (inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21 ||
- inst->src_fmt.pixelformat == V4L2_PIX_FMT_NV21M) {
- inst->cbcr_interleave = true;
+ info = v4l2_format_info(inst->src_fmt.pixelformat);
+ if (!info)
+ return -EINVAL;
+
+ inst->cbcr_interleave = (info->comp_planes == 2) ? true : false;
+
+ switch (inst->src_fmt.pixelformat) {
+ case V4L2_PIX_FMT_NV21:
+ case V4L2_PIX_FMT_NV21M:
+ case V4L2_PIX_FMT_NV61:
+ case V4L2_PIX_FMT_NV61M:
inst->nv21 = true;
- } else {
- inst->cbcr_interleave = false;
+ break;
+ default:
inst->nv21 = false;
}
@@ -567,7 +561,15 @@ static int wave5_vpu_enc_s_fmt_out(struct file *file, void *fh, struct v4l2_form
inst->quantization = f->fmt.pix_mp.quantization;
inst->xfer_func = f->fmt.pix_mp.xfer_func;
- wave5_update_pix_fmt(&inst->dst_fmt, f->fmt.pix_mp.width, f->fmt.pix_mp.height);
+ vpu_fmt = wave5_find_vpu_fmt(inst->dst_fmt.pixelformat, enc_fmt_list[VPU_FMT_TYPE_CODEC]);
+ if (!vpu_fmt)
+ return -EINVAL;
+
+ wave5_update_pix_fmt(&inst->dst_fmt, VPU_FMT_TYPE_CODEC,
+ f->fmt.pix_mp.width, f->fmt.pix_mp.height,
+ vpu_fmt->v4l2_frmsize);
+ inst->conf_win.width = inst->dst_fmt.width;
+ inst->conf_win.height = inst->dst_fmt.height;
return 0;
}
@@ -583,12 +585,17 @@ static int wave5_vpu_enc_g_selection(struct file *file, void *fh, struct v4l2_se
switch (s->target) {
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
- case V4L2_SEL_TGT_CROP:
s->r.left = 0;
s->r.top = 0;
s->r.width = inst->dst_fmt.width;
s->r.height = inst->dst_fmt.height;
break;
+ case V4L2_SEL_TGT_CROP:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = inst->conf_win.width;
+ s->r.height = inst->conf_win.height;
+ break;
default:
return -EINVAL;
}
@@ -611,8 +618,10 @@ static int wave5_vpu_enc_s_selection(struct file *file, void *fh, struct v4l2_se
s->r.left = 0;
s->r.top = 0;
- s->r.width = inst->src_fmt.width;
- s->r.height = inst->src_fmt.height;
+ s->r.width = min(s->r.width, inst->dst_fmt.width);
+ s->r.height = min(s->r.height, inst->dst_fmt.height);
+
+ inst->conf_win = s->r;
return 0;
}
@@ -1061,6 +1070,9 @@ static int wave5_vpu_enc_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
inst->enc_param.entropy_coding_mode = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR:
+ inst->enc_param.forced_idr_header_enable = ctrl->val;
+ break;
case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
break;
default:
@@ -1125,13 +1137,23 @@ static void wave5_vpu_enc_buf_queue(struct vb2_buffer *vb)
v4l2_m2m_buf_queue(m2m_ctx, vbuf);
}
-static void wave5_set_enc_openparam(struct enc_open_param *open_param,
- struct vpu_instance *inst)
+static int wave5_set_enc_openparam(struct enc_open_param *open_param,
+ struct vpu_instance *inst)
{
struct enc_wave_param input = inst->enc_param;
+ const struct v4l2_format_info *info;
u32 num_ctu_row = ALIGN(inst->dst_fmt.height, 64) / 64;
u32 num_mb_row = ALIGN(inst->dst_fmt.height, 16) / 16;
+ info = v4l2_format_info(inst->src_fmt.pixelformat);
+ if (!info)
+ return -EINVAL;
+
+ if (info->hdiv == 2 && info->vdiv == 1)
+ open_param->src_format = FORMAT_422;
+ else
+ open_param->src_format = FORMAT_420;
+
open_param->wave_param.gop_preset_idx = PRESET_IDX_IPP_SINGLE;
open_param->wave_param.hvs_qp_scale = 2;
open_param->wave_param.hvs_max_delta_qp = 10;
@@ -1147,8 +1169,8 @@ static void wave5_set_enc_openparam(struct enc_open_param *open_param,
open_param->wave_param.lambda_scaling_enable = 1;
open_param->line_buf_int_en = true;
- open_param->pic_width = inst->dst_fmt.width;
- open_param->pic_height = inst->dst_fmt.height;
+ open_param->pic_width = inst->conf_win.width;
+ open_param->pic_height = inst->conf_win.height;
open_param->frame_rate_info = inst->frame_rate;
open_param->rc_enable = inst->rc_enable;
if (inst->rc_enable) {
@@ -1219,6 +1241,9 @@ static void wave5_set_enc_openparam(struct enc_open_param *open_param,
else
open_param->wave_param.intra_refresh_arg = num_ctu_row;
}
+ open_param->wave_param.forced_idr_header_enable = input.forced_idr_header_enable;
+
+ return 0;
}
static int initialize_sequence(struct vpu_instance *inst)
@@ -1306,6 +1331,7 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count
struct v4l2_m2m_ctx *m2m_ctx = inst->v4l2_fh.m2m_ctx;
int ret = 0;
+ pm_runtime_resume_and_get(inst->dev->dev);
v4l2_m2m_update_start_streaming_state(m2m_ctx, q);
if (inst->state == VPU_INST_STATE_NONE && q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
@@ -1313,7 +1339,12 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count
memset(&open_param, 0, sizeof(struct enc_open_param));
- wave5_set_enc_openparam(&open_param, inst);
+ ret = wave5_set_enc_openparam(&open_param, inst);
+ if (ret) {
+ dev_dbg(inst->dev->dev, "%s: wave5_set_enc_openparam, fail: %d\n",
+ __func__, ret);
+ goto return_buffers;
+ }
ret = wave5_vpu_enc_open(inst, &open_param);
if (ret) {
@@ -1360,9 +1391,13 @@ static int wave5_vpu_enc_start_streaming(struct vb2_queue *q, unsigned int count
if (ret)
goto return_buffers;
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
return 0;
return_buffers:
wave5_return_bufs(q, VB2_BUF_STATE_QUEUED);
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
return ret;
}
@@ -1404,6 +1439,7 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q)
*/
dev_dbg(inst->dev->dev, "%s: type: %u\n", __func__, q->type);
+ pm_runtime_resume_and_get(inst->dev->dev);
if (wave5_vpu_both_queues_are_streaming(inst))
switch_state(inst, VPU_INST_STATE_STOP);
@@ -1428,12 +1464,13 @@ static void wave5_vpu_enc_stop_streaming(struct vb2_queue *q)
streamoff_output(inst, q);
else
streamoff_capture(inst, q);
+
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
}
static const struct vb2_ops wave5_vpu_enc_vb2_ops = {
.queue_setup = wave5_vpu_enc_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_queue = wave5_vpu_enc_buf_queue,
.start_streaming = wave5_vpu_enc_start_streaming,
.stop_streaming = wave5_vpu_enc_stop_streaming,
@@ -1442,20 +1479,15 @@ static const struct vb2_ops wave5_vpu_enc_vb2_ops = {
static void wave5_set_default_format(struct v4l2_pix_format_mplane *src_fmt,
struct v4l2_pix_format_mplane *dst_fmt)
{
- unsigned int src_pix_fmt = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt;
- const struct v4l2_format_info *src_fmt_info = v4l2_format_info(src_pix_fmt);
-
- src_fmt->pixelformat = src_pix_fmt;
- src_fmt->field = V4L2_FIELD_NONE;
- src_fmt->flags = 0;
- src_fmt->num_planes = src_fmt_info->mem_planes;
- wave5_update_pix_fmt(src_fmt, 416, 240);
+ src_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_RAW][0].v4l2_pix_fmt;
+ wave5_update_pix_fmt(src_fmt, VPU_FMT_TYPE_RAW,
+ W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT,
+ &enc_frmsize[VPU_FMT_TYPE_RAW]);
dst_fmt->pixelformat = enc_fmt_list[VPU_FMT_TYPE_CODEC][0].v4l2_pix_fmt;
- dst_fmt->field = V4L2_FIELD_NONE;
- dst_fmt->flags = 0;
- dst_fmt->num_planes = 1;
- wave5_update_pix_fmt(dst_fmt, 416, 240);
+ wave5_update_pix_fmt(dst_fmt, VPU_FMT_TYPE_CODEC,
+ W5_DEF_ENC_PIC_WIDTH, W5_DEF_ENC_PIC_HEIGHT,
+ &enc_frmsize[VPU_FMT_TYPE_CODEC]);
}
static int wave5_vpu_enc_queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
@@ -1474,6 +1506,7 @@ static void wave5_vpu_enc_device_run(void *priv)
u32 fail_res = 0;
int ret = 0;
+ pm_runtime_resume_and_get(inst->dev->dev);
switch (inst->state) {
case VPU_INST_STATE_PIC_RUN:
ret = start_encode(inst, &fail_res);
@@ -1487,6 +1520,8 @@ static void wave5_vpu_enc_device_run(void *priv)
break;
}
dev_dbg(inst->dev->dev, "%s: leave with active job", __func__);
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
return;
default:
WARN(1, "Execution of a job in state %s is invalid.\n",
@@ -1494,6 +1529,8 @@ static void wave5_vpu_enc_device_run(void *priv)
break;
}
dev_dbg(inst->dev->dev, "%s: leave and finish job", __func__);
+ pm_runtime_mark_last_busy(inst->dev->dev);
+ pm_runtime_put_autosuspend(inst->dev->dev);
v4l2_m2m_job_finish(inst->v4l2_m2m_dev, m2m_ctx);
}
@@ -1701,6 +1738,9 @@ static int wave5_vpu_open_enc(struct file *filp)
0, 1, 1, 0);
v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 32, 1, 1);
+ v4l2_ctrl_new_std(v4l2_ctrl_hdl, &wave5_vpu_enc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_PREPEND_SPSPPS_TO_IDR,
+ 0, 1, 1, 0);
if (v4l2_ctrl_hdl->error) {
ret = -ENODEV;
@@ -1711,6 +1751,8 @@ static int wave5_vpu_open_enc(struct file *filp)
v4l2_ctrl_handler_setup(v4l2_ctrl_hdl);
wave5_set_default_format(&inst->src_fmt, &inst->dst_fmt);
+ inst->conf_win.width = inst->dst_fmt.width;
+ inst->conf_win.height = inst->dst_fmt.height;
inst->colorspace = V4L2_COLORSPACE_REC709;
inst->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
inst->quantization = V4L2_QUANTIZATION_DEFAULT;
@@ -1732,9 +1774,8 @@ static int wave5_vpu_open_enc(struct file *filp)
if (ret)
goto cleanup_inst;
- if (dev->irq < 0 && !hrtimer_active(&dev->hrtimer) && list_empty(&dev->instances))
- hrtimer_start(&dev->hrtimer, ns_to_ktime(dev->vpu_poll_interval * NSEC_PER_MSEC),
- HRTIMER_MODE_REL_PINNED);
+ if (list_empty(&dev->instances))
+ pm_runtime_use_autosuspend(inst->dev->dev);
list_add_tail(&inst->list, &dev->instances);
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c
index 7273254ecb03..6b294a2d6717 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/pm_runtime.h>
#include <linux/reset.h>
#include "wave5-vpu.h"
#include "wave5-regdefine.h"
@@ -153,6 +154,45 @@ static int wave5_vpu_load_firmware(struct device *dev, const char *fw_name,
return 0;
}
+static __maybe_unused int wave5_pm_suspend(struct device *dev)
+{
+ struct vpu_device *vpu = dev_get_drvdata(dev);
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ if (vpu->irq < 0)
+ hrtimer_cancel(&vpu->hrtimer);
+
+ wave5_vpu_sleep_wake(dev, true, NULL, 0);
+ clk_bulk_disable_unprepare(vpu->num_clks, vpu->clks);
+
+ return 0;
+}
+
+static __maybe_unused int wave5_pm_resume(struct device *dev)
+{
+ struct vpu_device *vpu = dev_get_drvdata(dev);
+ int ret = 0;
+
+ wave5_vpu_sleep_wake(dev, false, NULL, 0);
+ ret = clk_bulk_prepare_enable(vpu->num_clks, vpu->clks);
+ if (ret) {
+ dev_err(dev, "Enabling clocks, fail: %d\n", ret);
+ return ret;
+ }
+
+ if (vpu->irq < 0 && !hrtimer_active(&vpu->hrtimer))
+ hrtimer_start(&vpu->hrtimer, ns_to_ktime(vpu->vpu_poll_interval * NSEC_PER_MSEC),
+ HRTIMER_MODE_REL_PINNED);
+
+ return ret;
+}
+
+static const struct dev_pm_ops wave5_pm_ops = {
+ SET_RUNTIME_PM_OPS(wave5_pm_suspend, wave5_pm_resume, NULL)
+};
+
static int wave5_vpu_probe(struct platform_device *pdev)
{
int ret;
@@ -281,6 +321,12 @@ static int wave5_vpu_probe(struct platform_device *pdev)
(match_data->flags & WAVE5_IS_DEC) ? "'DECODE'" : "");
dev_info(&pdev->dev, "Product Code: 0x%x\n", dev->product_code);
dev_info(&pdev->dev, "Firmware Revision: %u\n", fw_revision);
+
+ pm_runtime_set_autosuspend_delay(&pdev->dev, 100);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+ wave5_vpu_sleep_wake(&pdev->dev, true, NULL, 0);
+
return 0;
err_enc_unreg:
@@ -310,6 +356,9 @@ static void wave5_vpu_remove(struct platform_device *pdev)
hrtimer_cancel(&dev->hrtimer);
}
+ pm_runtime_put_sync(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
mutex_destroy(&dev->dev_lock);
mutex_destroy(&dev->hw_lock);
reset_control_assert(dev->resets);
@@ -337,9 +386,10 @@ static struct platform_driver wave5_vpu_driver = {
.driver = {
.name = VPU_PLATFORM_DEVICE_NAME,
.of_match_table = of_match_ptr(wave5_dt_ids),
+ .pm = &wave5_pm_ops,
},
.probe = wave5_vpu_probe,
- .remove_new = wave5_vpu_remove,
+ .remove = wave5_vpu_remove,
};
module_platform_driver(wave5_vpu_driver);
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.h b/drivers/media/platform/chips-media/wave5/wave5-vpu.h
index 32b7fd3730b5..3847332551fc 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpu.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.h
@@ -38,10 +38,7 @@ enum vpu_fmt_type {
struct vpu_format {
unsigned int v4l2_pix_fmt;
- unsigned int max_width;
- unsigned int min_width;
- unsigned int max_height;
- unsigned int min_height;
+ const struct v4l2_frmsize_stepwise *v4l2_frmsize;
};
static inline struct vpu_instance *wave5_to_vpu_inst(struct v4l2_fh *vfh)
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
index 1a3efb638dde..e16b990041c2 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.c
@@ -6,6 +6,8 @@
*/
#include <linux/bug.h>
+#include <linux/pm_runtime.h>
+#include <linux/delay.h>
#include "wave5-vpuapi.h"
#include "wave5-regdefine.h"
#include "wave5.h"
@@ -195,14 +197,20 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res)
int retry = 0;
struct vpu_device *vpu_dev = inst->dev;
int i;
+ int inst_count = 0;
+ struct vpu_instance *inst_elm;
*fail_res = 0;
if (!inst->codec_info)
return -EINVAL;
+ pm_runtime_resume_and_get(inst->dev->dev);
+
ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
- if (ret)
+ if (ret) {
+ pm_runtime_put_sync(inst->dev->dev);
return ret;
+ }
do {
ret = wave5_vpu_dec_finish_seq(inst, fail_res);
@@ -232,9 +240,14 @@ int wave5_vpu_dec_close(struct vpu_instance *inst, u32 *fail_res)
wave5_vdi_free_dma_memory(vpu_dev, &p_dec_info->vb_task);
+ list_for_each_entry(inst_elm, &vpu_dev->instances, list)
+ inst_count++;
+ if (inst_count == 1)
+ pm_runtime_dont_use_autosuspend(vpu_dev->dev);
+
unlock_and_return:
mutex_unlock(&vpu_dev->hw_lock);
-
+ pm_runtime_put_sync(inst->dev->dev);
return ret;
}
@@ -697,25 +710,33 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res)
int ret;
int retry = 0;
struct vpu_device *vpu_dev = inst->dev;
+ int inst_count = 0;
+ struct vpu_instance *inst_elm;
*fail_res = 0;
if (!inst->codec_info)
return -EINVAL;
+ pm_runtime_resume_and_get(inst->dev->dev);
+
ret = mutex_lock_interruptible(&vpu_dev->hw_lock);
- if (ret)
+ if (ret) {
+ pm_runtime_resume_and_get(inst->dev->dev);
return ret;
+ }
do {
ret = wave5_vpu_enc_finish_seq(inst, fail_res);
if (ret < 0 && *fail_res != WAVE5_SYSERR_VPU_STILL_RUNNING) {
dev_warn(inst->dev->dev, "enc_finish_seq timed out\n");
+ pm_runtime_resume_and_get(inst->dev->dev);
mutex_unlock(&vpu_dev->hw_lock);
return ret;
}
if (*fail_res == WAVE5_SYSERR_VPU_STILL_RUNNING &&
retry++ >= MAX_FIRMWARE_CALL_RETRY) {
+ pm_runtime_resume_and_get(inst->dev->dev);
mutex_unlock(&vpu_dev->hw_lock);
return -ETIMEDOUT;
}
@@ -734,7 +755,13 @@ int wave5_vpu_enc_close(struct vpu_instance *inst, u32 *fail_res)
wave5_vdi_free_dma_memory(vpu_dev, &p_enc_info->vb_task);
+ list_for_each_entry(inst_elm, &vpu_dev->instances, list)
+ inst_count++;
+ if (inst_count == 1)
+ pm_runtime_dont_use_autosuspend(vpu_dev->dev);
+
mutex_unlock(&vpu_dev->hw_lock);
+ pm_runtime_put_sync(inst->dev->dev);
return 0;
}
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
index d2370511faf8..45615c15beca 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuapi.h
@@ -568,6 +568,7 @@ struct enc_wave_param {
u32 lambda_scaling_enable: 1; /* enable lambda scaling using custom GOP */
u32 transform8x8_enable: 1; /* enable 8x8 intra prediction and 8x8 transform */
u32 mb_level_rc_enable: 1; /* enable MB-level rate control */
+ u32 forced_idr_header_enable: 1; /* enable header encoding before IDR frame */
};
struct enc_open_param {
diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
index e4bc2e467cb5..1ea9f5f31499 100644
--- a/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
+++ b/drivers/media/platform/chips-media/wave5/wave5-vpuconfig.h
@@ -32,10 +32,29 @@
#define MAX_NUM_INSTANCE 32
-#define W5_MIN_ENC_PIC_WIDTH 256
-#define W5_MIN_ENC_PIC_HEIGHT 128
-#define W5_MAX_ENC_PIC_WIDTH 8192
-#define W5_MAX_ENC_PIC_HEIGHT 8192
+#define W5_DEF_DEC_PIC_WIDTH 720U
+#define W5_DEF_DEC_PIC_HEIGHT 480U
+#define W5_MIN_DEC_PIC_8_WIDTH 8U
+#define W5_MIN_DEC_PIC_8_HEIGHT 8U
+#define W5_MIN_DEC_PIC_32_WIDTH 32U
+#define W5_MIN_DEC_PIC_32_HEIGHT 32U
+#define W5_MAX_DEC_PIC_WIDTH 8192U
+#define W5_MAX_DEC_PIC_HEIGHT 4320U
+#define W5_DEC_CODEC_STEP_WIDTH 1U
+#define W5_DEC_CODEC_STEP_HEIGHT 1U
+#define W5_DEC_RAW_STEP_WIDTH 32U
+#define W5_DEC_RAW_STEP_HEIGHT 16U
+
+#define W5_DEF_ENC_PIC_WIDTH 416U
+#define W5_DEF_ENC_PIC_HEIGHT 240U
+#define W5_MIN_ENC_PIC_WIDTH 256U
+#define W5_MIN_ENC_PIC_HEIGHT 128U
+#define W5_MAX_ENC_PIC_WIDTH 8192U
+#define W5_MAX_ENC_PIC_HEIGHT 8192U
+#define W5_ENC_CODEC_STEP_WIDTH 8U
+#define W5_ENC_CODEC_STEP_HEIGHT 8U
+#define W5_ENC_RAW_STEP_WIDTH 32U
+#define W5_ENC_RAW_STEP_HEIGHT 16U
// application specific configuration
#define VPU_ENC_TIMEOUT 60000
diff --git a/drivers/media/platform/chips-media/wave5/wave5.h b/drivers/media/platform/chips-media/wave5/wave5.h
index 2a29b9164f97..2caab356f3e1 100644
--- a/drivers/media/platform/chips-media/wave5/wave5.h
+++ b/drivers/media/platform/chips-media/wave5/wave5.h
@@ -62,6 +62,9 @@ int wave5_vpu_get_version(struct vpu_device *vpu_dev, u32 *revision);
int wave5_vpu_init(struct device *dev, u8 *fw, size_t size);
+int wave5_vpu_sleep_wake(struct device *dev, bool i_sleep_wake, const uint16_t *code,
+ size_t size);
+
int wave5_vpu_reset(struct device *dev, enum sw_reset_mode reset_mode);
int wave5_vpu_build_up_dec_param(struct vpu_instance *inst, struct dec_open_param *param);
diff --git a/drivers/media/platform/imagination/e5010-jpeg-enc.c b/drivers/media/platform/imagination/e5010-jpeg-enc.c
index 187f2d8abfbb..c194f830577f 100644
--- a/drivers/media/platform/imagination/e5010-jpeg-enc.c
+++ b/drivers/media/platform/imagination/e5010-jpeg-enc.c
@@ -1593,8 +1593,6 @@ static const struct vb2_ops e5010_video_ops = {
.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,
};
@@ -1619,7 +1617,7 @@ MODULE_DEVICE_TABLE(of, e5010_of_match);
static struct platform_driver e5010_driver = {
.probe = e5010_probe,
- .remove_new = e5010_remove,
+ .remove = e5010_remove,
.driver = {
.name = E5010_MODULE_NAME,
.of_match_table = e5010_of_match,
diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c
index f118aaac0b38..bef1e7137f23 100644
--- a/drivers/media/platform/intel/pxa_camera.c
+++ b/drivers/media/platform/intel/pxa_camera.c
@@ -1504,8 +1504,6 @@ static const struct vb2_ops pxac_vb2_ops = {
.buf_cleanup = pxac_vb2_cleanup,
.start_streaming = pxac_vb2_start_streaming,
.stop_streaming = pxac_vb2_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev)
@@ -2460,7 +2458,7 @@ static struct platform_driver pxa_camera_driver = {
.of_match_table = pxa_camera_of_match,
},
.probe = pxa_camera_probe,
- .remove_new = pxa_camera_remove,
+ .remove = pxa_camera_remove,
};
module_platform_driver(pxa_camera_driver);
diff --git a/drivers/media/platform/m2m-deinterlace.c b/drivers/media/platform/m2m-deinterlace.c
index 5adcef80c698..5188f3189096 100644
--- a/drivers/media/platform/m2m-deinterlace.c
+++ b/drivers/media/platform/m2m-deinterlace.c
@@ -784,8 +784,6 @@ static const struct vb2_ops deinterlace_qops = {
.queue_setup = deinterlace_queue_setup,
.buf_prepare = deinterlace_buf_prepare,
.buf_queue = deinterlace_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq,
@@ -993,7 +991,7 @@ static void deinterlace_remove(struct platform_device *pdev)
static struct platform_driver deinterlace_pdrv = {
.probe = deinterlace_probe,
- .remove_new = deinterlace_remove,
+ .remove = deinterlace_remove,
.driver = {
.name = MEM2MEM_NAME,
},
diff --git a/drivers/media/platform/marvell/mcam-core.c b/drivers/media/platform/marvell/mcam-core.c
index c81593c969e0..9ec01228f907 100644
--- a/drivers/media/platform/marvell/mcam-core.c
+++ b/drivers/media/platform/marvell/mcam-core.c
@@ -1203,8 +1203,6 @@ static const struct vb2_ops mcam_vb2_ops = {
.buf_queue = mcam_vb_buf_queue,
.start_streaming = mcam_vb_start_streaming,
.stop_streaming = mcam_vb_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
@@ -1267,8 +1265,6 @@ static const struct vb2_ops mcam_vb2_sg_ops = {
.buf_cleanup = mcam_vb_sg_buf_cleanup,
.start_streaming = mcam_vb_start_streaming,
.stop_streaming = mcam_vb_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
#endif /* MCAM_MODE_DMA_SG */
diff --git a/drivers/media/platform/marvell/mmp-driver.c b/drivers/media/platform/marvell/mmp-driver.c
index ff9d151121d5..3fd4fc1b9c48 100644
--- a/drivers/media/platform/marvell/mmp-driver.c
+++ b/drivers/media/platform/marvell/mmp-driver.c
@@ -359,7 +359,7 @@ MODULE_DEVICE_TABLE(of, mmpcam_of_match);
static struct platform_driver mmpcam_driver = {
.probe = mmpcam_probe,
- .remove_new = mmpcam_remove,
+ .remove = mmpcam_remove,
.driver = {
.name = "mmp-camera",
.of_match_table = mmpcam_of_match,
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
index ac48658e2de4..834d2a354692 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.c
@@ -884,8 +884,6 @@ static const struct vb2_ops mtk_jpeg_dec_qops = {
.queue_setup = mtk_jpeg_queue_setup,
.buf_prepare = mtk_jpeg_buf_prepare,
.buf_queue = mtk_jpeg_dec_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = mtk_jpeg_dec_stop_streaming,
};
@@ -893,8 +891,6 @@ static const struct vb2_ops mtk_jpeg_enc_qops = {
.queue_setup = mtk_jpeg_queue_setup,
.buf_prepare = mtk_jpeg_buf_prepare,
.buf_queue = mtk_jpeg_enc_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = mtk_jpeg_enc_stop_streaming,
};
@@ -1293,6 +1289,11 @@ static int mtk_jpeg_single_core_init(struct platform_device *pdev,
return 0;
}
+static void mtk_jpeg_destroy_workqueue(void *data)
+{
+ destroy_workqueue(data);
+}
+
static int mtk_jpeg_probe(struct platform_device *pdev)
{
struct mtk_jpeg_dev *jpeg;
@@ -1337,6 +1338,11 @@ static int mtk_jpeg_probe(struct platform_device *pdev)
| WQ_FREEZABLE);
if (!jpeg->workqueue)
return -EINVAL;
+ ret = devm_add_action_or_reset(&pdev->dev,
+ mtk_jpeg_destroy_workqueue,
+ jpeg->workqueue);
+ if (ret)
+ return ret;
}
ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
@@ -1950,7 +1956,7 @@ MODULE_DEVICE_TABLE(of, mtk_jpeg_match);
static struct platform_driver mtk_jpeg_driver = {
.probe = mtk_jpeg_probe,
- .remove_new = mtk_jpeg_remove,
+ .remove = mtk_jpeg_remove,
.driver = {
.name = MTK_JPEG_NAME,
.of_match_table = mtk_jpeg_match,
diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
index 4a6ee211e18f..2c5d74939d0a 100644
--- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
+++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_dec_hw.c
@@ -578,11 +578,6 @@ static int mtk_jpegdec_hw_init_irq(struct mtk_jpegdec_comp_dev *dev)
return 0;
}
-static void mtk_jpegdec_destroy_workqueue(void *data)
-{
- destroy_workqueue(data);
-}
-
static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
{
struct mtk_jpegdec_clk *jpegdec_clk;
@@ -606,12 +601,6 @@ static int mtk_jpegdec_hw_probe(struct platform_device *pdev)
dev->plat_dev = pdev;
dev->dev = &pdev->dev;
- ret = devm_add_action_or_reset(&pdev->dev,
- mtk_jpegdec_destroy_workqueue,
- master_dev->workqueue);
- if (ret)
- return ret;
-
spin_lock_init(&dev->hw_lock);
dev->hw_state = MTK_JPEG_HW_IDLE;
diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c
index 917cdf38f230..80fdc6ff57e0 100644
--- a/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c
+++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_core.c
@@ -298,7 +298,7 @@ static const struct dev_pm_ops mtk_mdp_pm_ops = {
static struct platform_driver mtk_mdp_driver = {
.probe = mtk_mdp_probe,
- .remove_new = mtk_mdp_remove,
+ .remove = mtk_mdp_remove,
.driver = {
.name = MTK_MDP_MODULE_NAME,
.pm = &mtk_mdp_pm_ops,
diff --git a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c
index f14779e7596e..28c998bd3a81 100644
--- a/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c
+++ b/drivers/media/platform/mediatek/mdp/mtk_mdp_m2m.c
@@ -584,8 +584,6 @@ static const struct vb2_ops mtk_mdp_m2m_qops = {
.buf_queue = mtk_mdp_m2m_buf_queue,
.stop_streaming = mtk_mdp_m2m_stop_streaming,
.start_streaming = mtk_mdp_m2m_start_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int mtk_mdp_m2m_querycap(struct file *file, void *fh,
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
index 37e7b985d52c..5e94ff0d0756 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c
@@ -413,7 +413,7 @@ static const struct dev_pm_ops mdp_pm_ops = {
static struct platform_driver mdp_driver = {
.probe = mdp_probe,
- .remove_new = mdp_remove,
+ .remove = mdp_remove,
.driver = {
.name = MDP_MODULE_NAME,
.pm = &mdp_pm_ops,
diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c
index 0e69128a3772..59ce5cce0698 100644
--- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c
+++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c
@@ -266,8 +266,6 @@ static void mdp_m2m_buf_queue(struct vb2_buffer *vb)
static const struct vb2_ops mdp_m2m_qops = {
.queue_setup = mdp_m2m_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_prepare = mdp_m2m_buf_prepare,
.start_streaming = mdp_m2m_start_streaming,
.stop_streaming = mdp_m2m_stop_streaming,
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
index 2073781ccadb..9247d92d431d 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_drv.c
@@ -591,7 +591,7 @@ static void mtk_vcodec_dec_remove(struct platform_device *pdev)
static struct platform_driver mtk_vcodec_dec_driver = {
.probe = mtk_vcodec_probe,
- .remove_new = mtk_vcodec_dec_remove,
+ .remove = mtk_vcodec_dec_remove,
.driver = {
.name = MTK_VCODEC_DEC_NAME,
.of_match_table = mtk_vcodec_match,
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
index e62c1c18758b..aa9bdee7a96c 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateful.c
@@ -598,8 +598,6 @@ static void mtk_init_vdec_params(struct mtk_vcodec_dec_ctx *ctx)
static const struct vb2_ops mtk_vdec_frame_vb2_ops = {
.queue_setup = vb2ops_vdec_queue_setup,
.buf_prepare = vb2ops_vdec_buf_prepare,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = vb2ops_vdec_start_streaming,
.buf_queue = vb2ops_vdec_stateful_buf_queue,
diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
index 3307dc15fc1d..afa224da0f41 100644
--- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
+++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c
@@ -856,8 +856,6 @@ static int vb2ops_vdec_out_buf_validate(struct vb2_buffer *vb)
static const struct vb2_ops mtk_vdec_request_vb2_ops = {
.queue_setup = vb2ops_vdec_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = vb2ops_vdec_start_streaming,
.stop_streaming = vb2ops_vdec_stop_streaming,
diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
index 7eaf0e24c9fc..a01dc25a7699 100644
--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.c
@@ -1009,8 +1009,6 @@ static const struct vb2_ops mtk_venc_vb2_ops = {
.buf_out_validate = vb2ops_venc_buf_out_validate,
.buf_prepare = vb2ops_venc_buf_prepare,
.buf_queue = vb2ops_venc_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = vb2ops_venc_start_streaming,
.stop_streaming = vb2ops_venc_stop_streaming,
};
diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
index 3cb8a1622222..a1e4483abcdb 100644
--- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc_drv.c
@@ -473,7 +473,7 @@ static void mtk_vcodec_enc_remove(struct platform_device *pdev)
static struct platform_driver mtk_vcodec_enc_driver = {
.probe = mtk_vcodec_probe,
- .remove_new = mtk_vcodec_enc_remove,
+ .remove = mtk_vcodec_enc_remove,
.driver = {
.name = MTK_VCODEC_ENC_NAME,
.of_match_table = mtk_vcodec_enc_match,
diff --git a/drivers/media/platform/mediatek/vpu/mtk_vpu.c b/drivers/media/platform/mediatek/vpu/mtk_vpu.c
index 724ae7c2ab3b..8d8319f0cd22 100644
--- a/drivers/media/platform/mediatek/vpu/mtk_vpu.c
+++ b/drivers/media/platform/mediatek/vpu/mtk_vpu.c
@@ -1041,7 +1041,7 @@ static const struct dev_pm_ops mtk_vpu_pm = {
static struct platform_driver mtk_vpu_driver = {
.probe = mtk_vpu_probe,
- .remove_new = mtk_vpu_remove,
+ .remove = mtk_vpu_remove,
.driver = {
.name = "mtk_vpu",
.pm = &mtk_vpu_pm,
diff --git a/drivers/media/platform/microchip/microchip-csi2dc.c b/drivers/media/platform/microchip/microchip-csi2dc.c
index fee73260bb1e..70303a0b6919 100644
--- a/drivers/media/platform/microchip/microchip-csi2dc.c
+++ b/drivers/media/platform/microchip/microchip-csi2dc.c
@@ -782,7 +782,7 @@ MODULE_DEVICE_TABLE(of, csi2dc_of_match);
static struct platform_driver csi2dc_driver = {
.probe = csi2dc_probe,
- .remove_new = csi2dc_remove,
+ .remove = csi2dc_remove,
.driver = {
.name = "microchip-csi2dc",
.pm = &csi2dc_dev_pm_ops,
diff --git a/drivers/media/platform/microchip/microchip-isc-base.c b/drivers/media/platform/microchip/microchip-isc-base.c
index 28e56f6a695d..a7cdc743fda7 100644
--- a/drivers/media/platform/microchip/microchip-isc-base.c
+++ b/drivers/media/platform/microchip/microchip-isc-base.c
@@ -465,8 +465,6 @@ static void isc_buffer_queue(struct vb2_buffer *vb)
static const struct vb2_ops isc_vb2_ops = {
.queue_setup = isc_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_prepare = isc_buffer_prepare,
.start_streaming = isc_start_streaming,
.stop_streaming = isc_stop_streaming,
diff --git a/drivers/media/platform/microchip/microchip-sama5d2-isc.c b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
index 60b6d922d764..66d3d7891991 100644
--- a/drivers/media/platform/microchip/microchip-sama5d2-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama5d2-isc.c
@@ -658,7 +658,7 @@ MODULE_DEVICE_TABLE(of, microchip_isc_of_match);
static struct platform_driver microchip_isc_driver = {
.probe = microchip_isc_probe,
- .remove_new = microchip_isc_remove,
+ .remove = microchip_isc_remove,
.driver = {
.name = "microchip-sama5d2-isc",
.pm = &microchip_isc_dev_pm_ops,
diff --git a/drivers/media/platform/microchip/microchip-sama7g5-isc.c b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
index e97abe3e35af..b0302dfc3278 100644
--- a/drivers/media/platform/microchip/microchip-sama7g5-isc.c
+++ b/drivers/media/platform/microchip/microchip-sama7g5-isc.c
@@ -621,7 +621,7 @@ MODULE_DEVICE_TABLE(of, microchip_xisc_of_match);
static struct platform_driver microchip_xisc_driver = {
.probe = microchip_xisc_probe,
- .remove_new = microchip_xisc_remove,
+ .remove = microchip_xisc_remove,
.driver = {
.name = "microchip-sama7g5-xisc",
.pm = &microchip_xisc_dev_pm_ops,
diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c
index 60fbb9140035..4f5d75645b2b 100644
--- a/drivers/media/platform/nuvoton/npcm-video.c
+++ b/drivers/media/platform/nuvoton/npcm-video.c
@@ -1558,8 +1558,6 @@ static const struct regmap_config npcm_video_ece_regmap_cfg = {
static const struct vb2_ops npcm_video_vb2_ops = {
.queue_setup = npcm_video_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_prepare = npcm_video_buf_prepare,
.buf_finish = npcm_video_buf_finish,
.start_streaming = npcm_video_start_streaming,
@@ -1814,7 +1812,7 @@ static struct platform_driver npcm_video_driver = {
.of_match_table = npcm_video_match,
},
.probe = npcm_video_probe,
- .remove_new = npcm_video_remove,
+ .remove = npcm_video_remove,
};
module_platform_driver(npcm_video_driver);
diff --git a/drivers/media/platform/nvidia/tegra-vde/iommu.c b/drivers/media/platform/nvidia/tegra-vde/iommu.c
index 5521ed3e465f..b1d9d841d944 100644
--- a/drivers/media/platform/nvidia/tegra-vde/iommu.c
+++ b/drivers/media/platform/nvidia/tegra-vde/iommu.c
@@ -78,9 +78,10 @@ int tegra_vde_iommu_init(struct tegra_vde *vde)
arm_iommu_release_mapping(mapping);
}
#endif
- vde->domain = iommu_domain_alloc(&platform_bus_type);
- if (!vde->domain) {
- err = -ENOMEM;
+ vde->domain = iommu_paging_domain_alloc(dev);
+ if (IS_ERR(vde->domain)) {
+ err = PTR_ERR(vde->domain);
+ vde->domain = NULL;
goto put_group;
}
diff --git a/drivers/media/platform/nvidia/tegra-vde/v4l2.c b/drivers/media/platform/nvidia/tegra-vde/v4l2.c
index 0f48ce6f243e..e3726cab0c82 100644
--- a/drivers/media/platform/nvidia/tegra-vde/v4l2.c
+++ b/drivers/media/platform/nvidia/tegra-vde/v4l2.c
@@ -328,8 +328,6 @@ static const struct vb2_ops tegra_qops = {
.buf_request_complete = tegra_buf_request_complete,
.start_streaming = tegra_start_streaming,
.stop_streaming = tegra_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int tegra_queue_init(void *priv,
@@ -929,13 +927,13 @@ int tegra_vde_v4l2_init(struct tegra_vde *vde)
media_device_init(&vde->mdev);
video_set_drvdata(&vde->vdev, vde);
- vde->vdev.lock = &vde->v4l2_lock,
- vde->vdev.fops = &tegra_v4l2_fops,
- vde->vdev.vfl_dir = VFL_DIR_M2M,
- vde->vdev.release = video_device_release_empty,
+ vde->vdev.lock = &vde->v4l2_lock;
+ vde->vdev.fops = &tegra_v4l2_fops;
+ vde->vdev.vfl_dir = VFL_DIR_M2M;
+ vde->vdev.release = video_device_release_empty;
vde->vdev.v4l2_dev = &vde->v4l2_dev;
- vde->vdev.ioctl_ops = &tegra_v4l2_ioctl_ops,
- vde->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING,
+ vde->vdev.ioctl_ops = &tegra_v4l2_ioctl_ops;
+ vde->vdev.device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
vde->v4l2_dev.mdev = &vde->mdev;
vde->mdev.ops = &tegra_media_device_ops;
diff --git a/drivers/media/platform/nvidia/tegra-vde/vde.c b/drivers/media/platform/nvidia/tegra-vde/vde.c
index 81a0d3b76b88..3232392c60e2 100644
--- a/drivers/media/platform/nvidia/tegra-vde/vde.c
+++ b/drivers/media/platform/nvidia/tegra-vde/vde.c
@@ -535,7 +535,7 @@ MODULE_DEVICE_TABLE(of, tegra_vde_of_match);
static struct platform_driver tegra_vde_driver = {
.probe = tegra_vde_probe,
- .remove_new = tegra_vde_remove,
+ .remove = tegra_vde_remove,
.shutdown = tegra_vde_shutdown,
.driver = {
.name = "tegra-vde",
diff --git a/drivers/media/platform/nxp/dw100/dw100.c b/drivers/media/platform/nxp/dw100/dw100.c
index 0024d6175ad9..66582e7f92fc 100644
--- a/drivers/media/platform/nxp/dw100/dw100.c
+++ b/drivers/media/platform/nxp/dw100/dw100.c
@@ -558,8 +558,6 @@ static const struct vb2_ops dw100_qops = {
.buf_queue = dw100_buf_queue,
.start_streaming = dw100_start_streaming,
.stop_streaming = dw100_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int dw100_m2m_queue_init(void *priv, struct vb2_queue *src_vq,
@@ -1311,7 +1309,7 @@ static void dw100_hw_set_destination(struct dw100_device *dw_dev,
}
dev_dbg(&dw_dev->pdev->dev,
- "Set HW source registers for %ux%u - stride %u, pixfmt: %p4cc, dma:%pad\n",
+ "Set HW destination registers for %ux%u - stride %u, pixfmt: %p4cc, dma:%pad\n",
width, height, stride, &fourcc, &addr_y);
/* Pixel Format */
@@ -1688,7 +1686,7 @@ MODULE_DEVICE_TABLE(of, dw100_dt_ids);
static struct platform_driver dw100_driver = {
.probe = dw100_probe,
- .remove_new = dw100_remove,
+ .remove = dw100_remove,
.driver = {
.name = DRV_NAME,
.pm = &dw100_pm,
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
index 1d8913813037..7f5fe551179b 100644
--- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
+++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c
@@ -1965,8 +1965,6 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb)
static const struct vb2_ops mxc_jpeg_qops = {
.queue_setup = mxc_jpeg_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_out_validate = mxc_jpeg_buf_out_validate,
.buf_prepare = mxc_jpeg_buf_prepare,
.start_streaming = mxc_jpeg_start_streaming,
@@ -2679,6 +2677,8 @@ static void mxc_jpeg_detach_pm_domains(struct mxc_jpeg_dev *jpeg)
int i;
for (i = 0; i < jpeg->num_domains; i++) {
+ if (jpeg->pd_dev[i] && !pm_runtime_suspended(jpeg->pd_dev[i]))
+ pm_runtime_force_suspend(jpeg->pd_dev[i]);
if (jpeg->pd_link[i] && !IS_ERR(jpeg->pd_link[i]))
device_link_del(jpeg->pd_link[i]);
if (jpeg->pd_dev[i] && !IS_ERR(jpeg->pd_dev[i]))
@@ -2842,6 +2842,7 @@ static int mxc_jpeg_probe(struct platform_device *pdev)
jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M;
jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING |
V4L2_CAP_VIDEO_M2M_MPLANE;
+ video_set_drvdata(jpeg->dec_vdev, jpeg);
if (mode == MXC_JPEG_ENCODE) {
v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_DECODER_CMD);
v4l2_disable_ioctl(jpeg->dec_vdev, VIDIOC_TRY_DECODER_CMD);
@@ -2854,7 +2855,6 @@ static int mxc_jpeg_probe(struct platform_device *pdev)
dev_err(dev, "failed to register video device\n");
goto err_vdev_register;
}
- video_set_drvdata(jpeg->dec_vdev, jpeg);
if (mode == MXC_JPEG_ENCODE)
v4l2_info(&jpeg->v4l2_dev,
"encoder device registered as /dev/video%d (%d,%d)\n",
@@ -2888,7 +2888,6 @@ err_clk:
return ret;
}
-#ifdef CONFIG_PM
static int mxc_jpeg_runtime_resume(struct device *dev)
{
struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
@@ -2911,9 +2910,7 @@ static int mxc_jpeg_runtime_suspend(struct device *dev)
return 0;
}
-#endif
-#ifdef CONFIG_PM_SLEEP
static int mxc_jpeg_suspend(struct device *dev)
{
struct mxc_jpeg_dev *jpeg = dev_get_drvdata(dev);
@@ -2934,12 +2931,10 @@ static int mxc_jpeg_resume(struct device *dev)
v4l2_m2m_resume(jpeg->m2m_dev);
return ret;
}
-#endif
static const struct dev_pm_ops mxc_jpeg_pm_ops = {
- SET_RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend,
- mxc_jpeg_runtime_resume, NULL)
- SET_SYSTEM_SLEEP_PM_OPS(mxc_jpeg_suspend, mxc_jpeg_resume)
+ RUNTIME_PM_OPS(mxc_jpeg_runtime_suspend, mxc_jpeg_runtime_resume, NULL)
+ SYSTEM_SLEEP_PM_OPS(mxc_jpeg_suspend, mxc_jpeg_resume)
};
static void mxc_jpeg_remove(struct platform_device *pdev)
@@ -2959,11 +2954,11 @@ MODULE_DEVICE_TABLE(of, mxc_jpeg_match);
static struct platform_driver mxc_jpeg_driver = {
.probe = mxc_jpeg_probe,
- .remove_new = mxc_jpeg_remove,
+ .remove = mxc_jpeg_remove,
.driver = {
.name = "mxc-jpeg",
.of_match_table = mxc_jpeg_match,
- .pm = &mxc_jpeg_pm_ops,
+ .pm = pm_ptr(&mxc_jpeg_pm_ops),
},
};
module_platform_driver(mxc_jpeg_driver);
diff --git a/drivers/media/platform/nxp/imx-mipi-csis.c b/drivers/media/platform/nxp/imx-mipi-csis.c
index 44e1402e8be1..29523bb84d95 100644
--- a/drivers/media/platform/nxp/imx-mipi-csis.c
+++ b/drivers/media/platform/nxp/imx-mipi-csis.c
@@ -1570,7 +1570,7 @@ MODULE_DEVICE_TABLE(of, mipi_csis_of_match);
static struct platform_driver mipi_csis_driver = {
.probe = mipi_csis_probe,
- .remove_new = mipi_csis_remove,
+ .remove = mipi_csis_remove,
.driver = {
.of_match_table = mipi_csis_of_match,
.name = CSIS_DRIVER_NAME,
diff --git a/drivers/media/platform/nxp/imx-pxp.c b/drivers/media/platform/nxp/imx-pxp.c
index e4427e6487fb..7f8ffbac582f 100644
--- a/drivers/media/platform/nxp/imx-pxp.c
+++ b/drivers/media/platform/nxp/imx-pxp.c
@@ -1606,8 +1606,6 @@ static const struct vb2_ops pxp_qops = {
.buf_queue = pxp_buf_queue,
.start_streaming = pxp_start_streaming,
.stop_streaming = pxp_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq,
@@ -1943,7 +1941,7 @@ MODULE_DEVICE_TABLE(of, pxp_dt_ids);
static struct platform_driver pxp_driver = {
.probe = pxp_probe,
- .remove_new = pxp_remove,
+ .remove = pxp_remove,
.driver = {
.name = MEM2MEM_NAME,
.of_match_table = pxp_dt_ids,
diff --git a/drivers/media/platform/nxp/imx7-media-csi.c b/drivers/media/platform/nxp/imx7-media-csi.c
index 9566ff738818..34a92642bbfe 100644
--- a/drivers/media/platform/nxp/imx7-media-csi.c
+++ b/drivers/media/platform/nxp/imx7-media-csi.c
@@ -1507,8 +1507,6 @@ static const struct vb2_ops imx7_csi_video_qops = {
.buf_init = imx7_csi_video_buf_init,
.buf_prepare = imx7_csi_video_buf_prepare,
.buf_queue = imx7_csi_video_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = imx7_csi_video_start_streaming,
.stop_streaming = imx7_csi_video_stop_streaming,
};
@@ -2281,7 +2279,7 @@ MODULE_DEVICE_TABLE(of, imx7_csi_of_match);
static struct platform_driver imx7_csi_driver = {
.probe = imx7_csi_probe,
- .remove_new = imx7_csi_remove,
+ .remove = imx7_csi_remove,
.driver = {
.of_match_table = imx7_csi_of_match,
.name = "imx7-csi",
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
index c2013995049c..aaf58063677c 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c
@@ -535,7 +535,7 @@ MODULE_DEVICE_TABLE(of, mxc_isi_of_match);
static struct platform_driver mxc_isi_driver = {
.probe = mxc_isi_probe,
- .remove_new = mxc_isi_remove,
+ .remove = mxc_isi_remove,
.driver = {
.of_match_table = mxc_isi_of_match,
.name = MXC_ISI_DRIVER_NAME,
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
index 9745d6219a16..794050a6a919 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-m2m.c
@@ -269,8 +269,6 @@ static const struct vb2_ops mxc_isi_m2m_vb2_qops = {
.buf_init = mxc_isi_m2m_vb2_buffer_init,
.buf_prepare = mxc_isi_m2m_vb2_buffer_prepare,
.buf_queue = mxc_isi_m2m_vb2_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = mxc_isi_m2m_vb2_start_streaming,
.stop_streaming = mxc_isi_m2m_vb2_stop_streaming,
};
diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
index 4091f1c0e78b..c0ba34ea82fd 100644
--- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
+++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-video.c
@@ -987,8 +987,6 @@ static const struct vb2_ops mxc_isi_vb2_qops = {
.buf_init = mxc_isi_vb2_buffer_init,
.buf_prepare = mxc_isi_vb2_buffer_prepare,
.buf_queue = mxc_isi_vb2_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = mxc_isi_vb2_start_streaming,
.stop_streaming = mxc_isi_vb2_stop_streaming,
};
diff --git a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
index d4a6c5532969..1f2657cf6e82 100644
--- a/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
+++ b/drivers/media/platform/nxp/imx8mq-mipi-csi2.c
@@ -953,7 +953,7 @@ MODULE_DEVICE_TABLE(of, imx8mq_mipi_csi_of_match);
static struct platform_driver imx8mq_mipi_csi_driver = {
.probe = imx8mq_mipi_csi_probe,
- .remove_new = imx8mq_mipi_csi_remove,
+ .remove = imx8mq_mipi_csi_remove,
.driver = {
.of_match_table = imx8mq_mipi_csi_of_match,
.name = MIPI_CSI2_DRIVER_NAME,
diff --git a/drivers/media/platform/nxp/mx2_emmaprp.c b/drivers/media/platform/nxp/mx2_emmaprp.c
index 023ed40c6b08..0c6cc120fd2a 100644
--- a/drivers/media/platform/nxp/mx2_emmaprp.c
+++ b/drivers/media/platform/nxp/mx2_emmaprp.c
@@ -677,8 +677,6 @@ static const struct vb2_ops emmaprp_qops = {
.queue_setup = emmaprp_queue_setup,
.buf_prepare = emmaprp_buf_prepare,
.buf_queue = emmaprp_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq,
@@ -902,7 +900,7 @@ static void emmaprp_remove(struct platform_device *pdev)
static struct platform_driver emmaprp_pdrv = {
.probe = emmaprp_probe,
- .remove_new = emmaprp_remove,
+ .remove = emmaprp_remove,
.driver = {
.name = MEM2MEM_NAME,
},
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index 2f7361dfd461..5af2b382a843 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -212,14 +212,25 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on)
if (ret < 0)
return ret;
+ ret = regulator_bulk_enable(csiphy->num_supplies,
+ csiphy->supplies);
+ if (ret < 0) {
+ pm_runtime_put_sync(dev);
+ return ret;
+ }
+
ret = csiphy_set_clock_rates(csiphy);
if (ret < 0) {
+ regulator_bulk_disable(csiphy->num_supplies,
+ csiphy->supplies);
pm_runtime_put_sync(dev);
return ret;
}
ret = camss_enable_clocks(csiphy->nclocks, csiphy->clock, dev);
if (ret < 0) {
+ regulator_bulk_disable(csiphy->num_supplies,
+ csiphy->supplies);
pm_runtime_put_sync(dev);
return ret;
}
@@ -234,6 +245,8 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on)
camss_disable_clocks(csiphy->nclocks, csiphy->clock);
+ regulator_bulk_disable(csiphy->num_supplies, csiphy->supplies);
+
pm_runtime_put_sync(dev);
}
@@ -583,6 +596,7 @@ int msm_csiphy_subdev_init(struct camss *camss,
return PTR_ERR(csiphy->base);
if (camss->res->version == CAMSS_8x16 ||
+ camss->res->version == CAMSS_8x53 ||
camss->res->version == CAMSS_8x96) {
csiphy->base_clk_mux =
devm_platform_ioremap_resource_byname(pdev, res->reg[1]);
@@ -676,7 +690,27 @@ int msm_csiphy_subdev_init(struct camss *camss,
}
}
- return 0;
+ /* CSIPHY supplies */
+ for (i = 0; i < ARRAY_SIZE(res->regulators); i++) {
+ if (res->regulators[i])
+ csiphy->num_supplies++;
+ }
+
+ if (csiphy->num_supplies) {
+ csiphy->supplies = devm_kmalloc_array(camss->dev,
+ csiphy->num_supplies,
+ sizeof(*csiphy->supplies),
+ GFP_KERNEL);
+ if (!csiphy->supplies)
+ return -ENOMEM;
+ }
+
+ for (i = 0; i < csiphy->num_supplies; i++)
+ csiphy->supplies[i].supply = res->regulators[i];
+
+ ret = devm_regulator_bulk_get(camss->dev, csiphy->num_supplies,
+ csiphy->supplies);
+ return ret;
}
/*
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.h b/drivers/media/platform/qcom/camss/camss-csiphy.h
index 47f0b6b09eba..eebc1ff1cfab 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.h
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.h
@@ -91,6 +91,8 @@ struct csiphy_device {
bool *rate_set;
int nclocks;
u32 timer_clk_rate;
+ struct regulator_bulk_data *supplies;
+ int num_supplies;
struct csiphy_config cfg;
struct v4l2_mbus_framefmt fmt[MSM_CSIPHY_PADS_NUM];
const struct csiphy_subdev_resources *res;
diff --git a/drivers/media/platform/qcom/camss/camss-ispif.c b/drivers/media/platform/qcom/camss/camss-ispif.c
index a12dcc7ff438..2dc585c6123d 100644
--- a/drivers/media/platform/qcom/camss/camss-ispif.c
+++ b/drivers/media/platform/qcom/camss/camss-ispif.c
@@ -830,6 +830,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
ispif_select_cid(ispif, intf, cid, vfe, 1);
ispif_config_irq(ispif, intf, vfe, 1);
if (camss->res->version == CAMSS_8x96 ||
+ camss->res->version == CAMSS_8x53 ||
camss->res->version == CAMSS_660)
ispif_config_pack(ispif,
line->fmt[MSM_ISPIF_PAD_SINK].code,
@@ -848,6 +849,7 @@ static int ispif_set_stream(struct v4l2_subdev *sd, int enable)
mutex_lock(&ispif->config_lock);
if (camss->res->version == CAMSS_8x96 ||
+ camss->res->version == CAMSS_8x53 ||
camss->res->version == CAMSS_660)
ispif_config_pack(ispif,
line->fmt[MSM_ISPIF_PAD_SINK].code,
@@ -1111,6 +1113,7 @@ int msm_ispif_subdev_init(struct camss *camss,
if (camss->res->version == CAMSS_8x16)
ispif->line_num = 2;
else if (camss->res->version == CAMSS_8x96 ||
+ camss->res->version == CAMSS_8x53 ||
camss->res->version == CAMSS_660)
ispif->line_num = 4;
else
@@ -1130,6 +1133,7 @@ int msm_ispif_subdev_init(struct camss *camss,
ispif->line[i].nformats =
ARRAY_SIZE(ispif_formats_8x16);
} else if (camss->res->version == CAMSS_8x96 ||
+ camss->res->version == CAMSS_8x53 ||
camss->res->version == CAMSS_660) {
ispif->line[i].formats = ispif_formats_8x96;
ispif->line[i].nformats =
@@ -1162,6 +1166,7 @@ int msm_ispif_subdev_init(struct camss *camss,
ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x16,
IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
else if (camss->res->version == CAMSS_8x96 ||
+ camss->res->version == CAMSS_8x53 ||
camss->res->version == CAMSS_660)
ret = devm_request_irq(dev, ispif->irq, ispif_isr_8x96,
IRQF_TRIGGER_RISING, ispif->irq_name, ispif);
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 1bd3a6ef1d04..9a9007c3ff33 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe-4-1.c
@@ -938,7 +938,10 @@ static irqreturn_t vfe_isr(int irq, void *dev)
*/
static void vfe_4_1_pm_domain_off(struct vfe_device *vfe)
{
- /* nop */
+ if (!vfe->res->has_pd)
+ return;
+
+ vfe_pm_domain_off(vfe);
}
/*
@@ -947,7 +950,10 @@ static void vfe_4_1_pm_domain_off(struct vfe_device *vfe)
*/
static int vfe_4_1_pm_domain_on(struct vfe_device *vfe)
{
- return 0;
+ if (!vfe->res->has_pd)
+ return 0;
+
+ return vfe_pm_domain_on(vfe);
}
static const struct vfe_hw_ops_gen1 vfe_ops_gen1_4_1 = {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index 83c5a36d071f..80a62ba11295 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -285,6 +285,7 @@ static u32 vfe_src_pad_code(struct vfe_line *line, u32 sink_code,
switch (vfe->camss->res->version) {
case CAMSS_8x16:
+ case CAMSS_8x53:
switch (sink_code) {
case MEDIA_BUS_FMT_YUYV8_1X16:
{
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index 3b8fc31d957c..aa021fd5e123 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -310,8 +310,6 @@ static void video_stop_streaming(struct vb2_queue *q)
static const struct vb2_ops msm_video_vb2_q_ops = {
.queue_setup = video_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_init = video_buf_init,
.buf_prepare = video_buf_prepare,
.buf_queue = video_buf_queue,
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index d64985ca6e88..9fb31f4c18ad 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -152,6 +152,160 @@ static const struct camss_subdev_resources vfe_res_8x16[] = {
}
};
+static const struct camss_subdev_resources csid_res_8x53[] = {
+ /* CSID0 */
+ {
+ .regulators = { "vdda" },
+ .clock = { "top_ahb", "ispif_ahb", "csi0_ahb", "ahb",
+ "csi0", "csi0_phy", "csi0_pix", "csi0_rdi" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 100000000, 200000000, 310000000,
+ 400000000, 465000000 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "csid0" },
+ .interrupt = { "csid0" },
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
+ },
+
+ /* CSID1 */
+ {
+ .regulators = { "vdda" },
+ .clock = { "top_ahb", "ispif_ahb", "csi1_ahb", "ahb",
+ "csi1", "csi1_phy", "csi1_pix", "csi1_rdi" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 100000000, 200000000, 310000000,
+ 400000000, 465000000 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "csid1" },
+ .interrupt = { "csid1" },
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
+ },
+
+ /* CSID2 */
+ {
+ .regulators = { "vdda" },
+ .clock = { "top_ahb", "ispif_ahb", "csi2_ahb", "ahb",
+ "csi2", "csi2_phy", "csi2_pix", "csi2_rdi" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 0 },
+ { 100000000, 200000000, 310000000,
+ 400000000, 465000000 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "csid2" },
+ .interrupt = { "csid2" },
+ .csid = {
+ .hw_ops = &csid_ops_4_7,
+ .parent_dev_ops = &vfe_parent_dev_ops,
+ .formats = &csid_formats_4_7
+ }
+ },
+};
+
+static const struct camss_subdev_resources ispif_res_8x53 = {
+ /* ISPIF */
+ .clock = { "top_ahb", "ahb", "ispif_ahb",
+ "csi0", "csi0_pix", "csi0_rdi",
+ "csi1", "csi1_pix", "csi1_rdi",
+ "csi2", "csi2_pix", "csi2_rdi" },
+ .clock_for_reset = { "vfe0", "csi_vfe0", "vfe1", "csi_vfe1" },
+ .reg = { "ispif", "csi_clk_mux" },
+ .interrupt = { "ispif" },
+};
+
+static const struct camss_subdev_resources vfe_res_8x53[] = {
+ /* VFE0 */
+ {
+ .regulators = {},
+ .clock = { "top_ahb", "ahb", "ispif_ahb",
+ "vfe0", "csi_vfe0", "vfe0_ahb", "vfe0_axi" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 50000000, 100000000, 133330000,
+ 160000000, 200000000, 266670000,
+ 310000000, 400000000, 465000000 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe0" },
+ .interrupt = { "vfe0" },
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .pd_name = "vfe0",
+ .hw_ops = &vfe_ops_4_1,
+ .formats_rdi = &vfe_formats_rdi_8x16,
+ .formats_pix = &vfe_formats_pix_8x16
+ }
+ },
+
+ /* VFE1 */
+ {
+ .regulators = {},
+ .clock = { "top_ahb", "ahb", "ispif_ahb",
+ "vfe1", "csi_vfe1", "vfe1_ahb", "vfe1_axi" },
+ .clock_rate = { { 0 },
+ { 0 },
+ { 0 },
+ { 50000000, 100000000, 133330000,
+ 160000000, 200000000, 266670000,
+ 310000000, 400000000, 465000000 },
+ { 0 },
+ { 0 },
+ { 0 } },
+ .reg = { "vfe1" },
+ .interrupt = { "vfe1" },
+ .vfe = {
+ .line_num = 3,
+ .has_pd = true,
+ .pd_name = "vfe1",
+ .hw_ops = &vfe_ops_4_1,
+ .formats_rdi = &vfe_formats_rdi_8x16,
+ .formats_pix = &vfe_formats_pix_8x16
+ }
+ }
+};
+
+static const struct resources_icc icc_res_8x53[] = {
+ {
+ .name = "cam_ahb",
+ .icc_bw_tbl.avg = 38400,
+ .icc_bw_tbl.peak = 76800,
+ },
+ {
+ .name = "cam_vfe0_mem",
+ .icc_bw_tbl.avg = 939524,
+ .icc_bw_tbl.peak = 1342177,
+ },
+ {
+ .name = "cam_vfe1_mem",
+ .icc_bw_tbl.avg = 939524,
+ .icc_bw_tbl.peak = 1342177,
+ },
+};
+
static const struct camss_subdev_resources csiphy_res_8x96[] = {
/* CSIPHY0 */
{
@@ -837,7 +991,7 @@ static const struct camss_subdev_resources vfe_res_845[] = {
static const struct camss_subdev_resources csiphy_res_8250[] = {
/* CSIPHY0 */
{
- .regulators = {},
+ .regulators = { "vdda-phy", "vdda-pll" },
.clock = { "csiphy0", "csiphy0_timer" },
.clock_rate = { { 400000000 },
{ 300000000 } },
@@ -850,7 +1004,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
},
/* CSIPHY1 */
{
- .regulators = {},
+ .regulators = { "vdda-phy", "vdda-pll" },
.clock = { "csiphy1", "csiphy1_timer" },
.clock_rate = { { 400000000 },
{ 300000000 } },
@@ -863,7 +1017,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
},
/* CSIPHY2 */
{
- .regulators = {},
+ .regulators = { "vdda-phy", "vdda-pll" },
.clock = { "csiphy2", "csiphy2_timer" },
.clock_rate = { { 400000000 },
{ 300000000 } },
@@ -876,7 +1030,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
},
/* CSIPHY3 */
{
- .regulators = {},
+ .regulators = { "vdda-phy", "vdda-pll" },
.clock = { "csiphy3", "csiphy3_timer" },
.clock_rate = { { 400000000 },
{ 300000000 } },
@@ -889,7 +1043,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
},
/* CSIPHY4 */
{
- .regulators = {},
+ .regulators = { "vdda-phy", "vdda-pll" },
.clock = { "csiphy4", "csiphy4_timer" },
.clock_rate = { { 400000000 },
{ 300000000 } },
@@ -902,7 +1056,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
},
/* CSIPHY5 */
{
- .regulators = {},
+ .regulators = { "vdda-phy", "vdda-pll" },
.clock = { "csiphy5", "csiphy5_timer" },
.clock_rate = { { 400000000 },
{ 300000000 } },
@@ -918,7 +1072,7 @@ static const struct camss_subdev_resources csiphy_res_8250[] = {
static const struct camss_subdev_resources csid_res_8250[] = {
/* CSID0 */
{
- .regulators = { "vdda-phy", "vdda-pll" },
+ .regulators = {},
.clock = { "vfe0_csid", "vfe0_cphy_rx", "vfe0", "vfe0_areg", "vfe0_ahb" },
.clock_rate = { { 400000000 },
{ 400000000 },
@@ -935,7 +1089,7 @@ static const struct camss_subdev_resources csid_res_8250[] = {
},
/* CSID1 */
{
- .regulators = { "vdda-phy", "vdda-pll" },
+ .regulators = {},
.clock = { "vfe1_csid", "vfe1_cphy_rx", "vfe1", "vfe1_areg", "vfe1_ahb" },
.clock_rate = { { 400000000 },
{ 400000000 },
@@ -952,7 +1106,7 @@ static const struct camss_subdev_resources csid_res_8250[] = {
},
/* CSID2 */
{
- .regulators = { "vdda-phy", "vdda-pll" },
+ .regulators = {},
.clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "vfe_lite_ahb" },
.clock_rate = { { 400000000 },
{ 400000000 },
@@ -969,7 +1123,7 @@ static const struct camss_subdev_resources csid_res_8250[] = {
},
/* CSID3 */
{
- .regulators = { "vdda-phy", "vdda-pll" },
+ .regulators = {},
.clock = { "vfe_lite_csid", "vfe_lite_cphy_rx", "vfe_lite", "vfe_lite_ahb" },
.clock_rate = { { 400000000 },
{ 400000000 },
@@ -1780,6 +1934,7 @@ err_cleanup:
*/
static int camss_init_subdevices(struct camss *camss)
{
+ struct platform_device *pdev = to_platform_device(camss->dev);
const struct camss_resources *res = camss->res;
unsigned int i;
int ret;
@@ -1806,6 +1961,17 @@ static int camss_init_subdevices(struct camss *camss)
}
}
+ /* Get optional CSID wrapper regs shared between CSID devices */
+ if (res->csid_wrapper_res) {
+ char *reg = res->csid_wrapper_res->reg;
+ void __iomem *base;
+
+ base = devm_platform_ioremap_resource_byname(pdev, reg);
+ if (IS_ERR(base))
+ return PTR_ERR(base);
+ camss->csid_wrapper_base = base;
+ }
+
for (i = 0; i < camss->res->csid_num; i++) {
ret = msm_csid_subdev_init(camss, &camss->csid[i],
&res->csid_res[i], i);
@@ -2130,10 +2296,8 @@ static int camss_configure_pd(struct camss *camss)
if (camss->res->pd_name) {
camss->genpd = dev_pm_domain_attach_by_name(camss->dev,
camss->res->pd_name);
- if (IS_ERR(camss->genpd)) {
- ret = PTR_ERR(camss->genpd);
- goto fail_pm;
- }
+ if (IS_ERR(camss->genpd))
+ return PTR_ERR(camss->genpd);
}
if (!camss->genpd) {
@@ -2143,14 +2307,13 @@ static int camss_configure_pd(struct camss *camss)
*/
camss->genpd = dev_pm_domain_attach_by_id(camss->dev,
camss->genpd_num - 1);
+ if (IS_ERR(camss->genpd))
+ return PTR_ERR(camss->genpd);
}
- if (IS_ERR_OR_NULL(camss->genpd)) {
- if (!camss->genpd)
- ret = -ENODEV;
- else
- ret = PTR_ERR(camss->genpd);
- goto fail_pm;
- }
+
+ if (!camss->genpd)
+ return -ENODEV;
+
camss->genpd_link = device_link_add(camss->dev, camss->genpd,
DL_FLAG_STATELESS | DL_FLAG_PM_RUNTIME |
DL_FLAG_RPM_ACTIVE);
@@ -2239,6 +2402,7 @@ static int camss_probe(struct platform_device *pdev)
return -ENOMEM;
if (camss->res->version == CAMSS_8x16 ||
+ camss->res->version == CAMSS_8x53 ||
camss->res->version == CAMSS_8x96) {
camss->ispif = devm_kcalloc(dev, 1, sizeof(*camss->ispif), GFP_KERNEL);
if (!camss->ispif)
@@ -2380,6 +2544,20 @@ static const struct camss_resources msm8916_resources = {
.link_entities = camss_link_entities
};
+static const struct camss_resources msm8953_resources = {
+ .version = CAMSS_8x53,
+ .icc_res = icc_res_8x53,
+ .icc_path_num = ARRAY_SIZE(icc_res_8x53),
+ .csiphy_res = csiphy_res_8x96,
+ .csid_res = csid_res_8x53,
+ .ispif_res = &ispif_res_8x53,
+ .vfe_res = vfe_res_8x53,
+ .csiphy_num = ARRAY_SIZE(csiphy_res_8x96),
+ .csid_num = ARRAY_SIZE(csid_res_8x53),
+ .vfe_num = ARRAY_SIZE(vfe_res_8x53),
+ .link_entities = camss_link_entities
+};
+
static const struct camss_resources msm8996_resources = {
.version = CAMSS_8x96,
.csiphy_res = csiphy_res_8x96,
@@ -2446,6 +2624,7 @@ static const struct camss_resources sc8280xp_resources = {
static const struct of_device_id camss_dt_match[] = {
{ .compatible = "qcom,msm8916-camss", .data = &msm8916_resources },
+ { .compatible = "qcom,msm8953-camss", .data = &msm8953_resources },
{ .compatible = "qcom,msm8996-camss", .data = &msm8996_resources },
{ .compatible = "qcom,sdm660-camss", .data = &sdm660_resources },
{ .compatible = "qcom,sdm845-camss", .data = &sdm845_resources },
@@ -2497,7 +2676,7 @@ static const struct dev_pm_ops camss_pm_ops = {
static struct platform_driver qcom_camss_driver = {
.probe = camss_probe,
- .remove_new = camss_remove,
+ .remove = camss_remove,
.driver = {
.name = "qcom-camss",
.of_match_table = camss_dt_match,
diff --git a/drivers/media/platform/qcom/camss/camss.h b/drivers/media/platform/qcom/camss/camss.h
index 73c47c07fc30..9da7f48f5dd7 100644
--- a/drivers/media/platform/qcom/camss/camss.h
+++ b/drivers/media/platform/qcom/camss/camss.h
@@ -66,6 +66,10 @@ struct resources_icc {
struct icc_bw_tbl icc_bw_tbl;
};
+struct resources_wrapper {
+ char *reg;
+};
+
enum pm_domain {
PM_DOMAIN_VFE0 = 0,
PM_DOMAIN_VFE1 = 1,
@@ -74,6 +78,7 @@ enum pm_domain {
enum camss_version {
CAMSS_8x16,
+ CAMSS_8x53,
CAMSS_8x96,
CAMSS_660,
CAMSS_845,
@@ -93,6 +98,7 @@ struct camss_resources {
const struct camss_subdev_resources *csid_res;
const struct camss_subdev_resources *ispif_res;
const struct camss_subdev_resources *vfe_res;
+ const struct resources_wrapper *csid_wrapper_res;
const struct resources_icc *icc_res;
const unsigned int icc_path_num;
const unsigned int csiphy_num;
@@ -110,6 +116,7 @@ struct camss {
struct csid_device *csid;
struct ispif_device *ispif;
struct vfe_device *vfe;
+ void __iomem *csid_wrapper_base;
atomic_t ref_count;
int genpd_num;
struct device *genpd;
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 84e95a46dfc9..2d27c5167246 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -19,6 +19,7 @@
#include <linux/pm_domain.h>
#include <linux/pm_runtime.h>
#include <media/videobuf2-v4l2.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-mem2mem.h>
#include <media/v4l2-ioctl.h>
@@ -412,8 +413,8 @@ err_of_depopulate:
of_platform_depopulate(dev);
err_runtime_disable:
pm_runtime_put_noidle(dev);
- pm_runtime_set_suspended(dev);
pm_runtime_disable(dev);
+ pm_runtime_set_suspended(dev);
hfi_destroy(core);
err_core_deinit:
hfi_core_deinit(core, false);
@@ -502,6 +503,30 @@ err_cpucfg_path:
return ret;
}
+void venus_close_common(struct venus_inst *inst)
+{
+ /*
+ * First, remove the inst from the ->instances list, so that
+ * to_instance() will return NULL.
+ */
+ hfi_session_destroy(inst);
+ /*
+ * Second, make sure we don't have IRQ/IRQ-thread currently running
+ * or pending execution, which would race with the inst destruction.
+ */
+ synchronize_irq(inst->core->irq);
+
+ v4l2_m2m_ctx_release(inst->m2m_ctx);
+ v4l2_m2m_release(inst->m2m_dev);
+ v4l2_fh_del(&inst->fh);
+ v4l2_fh_exit(&inst->fh);
+ v4l2_ctrl_handler_free(&inst->ctrl_handler);
+
+ mutex_destroy(&inst->lock);
+ mutex_destroy(&inst->ctx_q_lock);
+}
+EXPORT_SYMBOL_GPL(venus_close_common);
+
static __maybe_unused int venus_runtime_resume(struct device *dev)
{
struct venus_core *core = dev_get_drvdata(dev);
@@ -752,7 +777,7 @@ static const struct venus_resources sdm845_res_v2 = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" },
.vcodec_pmdomains_num = 3,
- .opp_pmdomain = (const char *[]) { "cx", NULL },
+ .opp_pmdomain = (const char *[]) { "cx" },
.vcodec_num = 2,
.max_load = 3110400, /* 4096x2160@90 */
.hfi_version = HFI_VERSION_4XX,
@@ -801,7 +826,7 @@ static const struct venus_resources sc7180_res = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2,
- .opp_pmdomain = (const char *[]) { "cx", NULL },
+ .opp_pmdomain = (const char *[]) { "cx" },
.vcodec_num = 1,
.hfi_version = HFI_VERSION_4XX,
.vpu_version = VPU_VERSION_AR50,
@@ -858,7 +883,7 @@ static const struct venus_resources sm8250_res = {
.vcodec_clks_num = 1,
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2,
- .opp_pmdomain = (const char *[]) { "mx", NULL },
+ .opp_pmdomain = (const char *[]) { "mx" },
.vcodec_num = 1,
.max_load = 7833600,
.hfi_version = HFI_VERSION_6XX,
@@ -917,7 +942,7 @@ static const struct venus_resources sc7280_res = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2,
- .opp_pmdomain = (const char *[]) { "cx", NULL },
+ .opp_pmdomain = (const char *[]) { "cx" },
.vcodec_num = 1,
.hfi_version = HFI_VERSION_6XX,
.vpu_version = VPU_VERSION_IRIS2_1,
@@ -949,7 +974,7 @@ MODULE_DEVICE_TABLE(of, venus_dt_match);
static struct platform_driver qcom_venus_driver = {
.probe = venus_probe,
- .remove_new = venus_remove,
+ .remove = venus_remove,
.driver = {
.name = "qcom-venus",
.of_match_table = venus_dt_match,
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index 55202b89e1b9..44f1c3bc4186 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -26,6 +26,7 @@
#define VIDC_CLKS_NUM_MAX 4
#define VIDC_VCODEC_CLKS_NUM_MAX 2
#define VIDC_RESETS_NUM_MAX 2
+#define VIDC_MAX_HIER_CODING_LAYER 6
extern int venus_fw_debug;
@@ -132,9 +133,7 @@ struct venus_format {
* @vcodec1_clks: an array of vcodec1 struct clk pointers
* @video_path: an interconnect handle to video to/from memory path
* @cpucfg_path: an interconnect handle to cpu configuration path
- * @has_opp_table: does OPP table exist
* @pmdomains: a pointer to a list of pmdomains
- * @opp_dl_venus: an device-link for device OPP
* @opp_pmdomain: an OPP power-domain
* @resets: an array of reset signals
* @vdev_dec: a reference to video device structure for decoder instances
@@ -186,10 +185,8 @@ struct venus_core {
struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
struct icc_path *video_path;
struct icc_path *cpucfg_path;
- bool has_opp_table;
struct dev_pm_domain_list *pmdomains;
- struct device_link *opp_dl_venus;
- struct device *opp_pmdomain;
+ struct dev_pm_domain_list *opp_pmdomain;
struct reset_control *resets[VIDC_RESETS_NUM_MAX];
struct video_device *vdev_dec;
struct video_device *vdev_enc;
@@ -255,6 +252,7 @@ struct venc_controls {
u32 rc_enable;
u32 const_quality;
u32 frame_skip_mode;
+ u32 layer_bitrate;
u32 h264_i_period;
u32 h264_entropy_mode;
@@ -273,6 +271,8 @@ struct venc_controls {
s32 h264_loop_filter_alpha;
s32 h264_loop_filter_beta;
u32 h264_8x8_transform;
+ u32 h264_hier_layers;
+ u32 h264_hier_layer_bitrate[VIDC_MAX_HIER_CODING_LAYER];
u32 hevc_i_qp;
u32 hevc_p_qp;
@@ -564,4 +564,6 @@ is_fw_rev_or_older(struct venus_core *core, u32 vmajor, u32 vminor, u32 vrev)
(core)->venus_ver.minor == vminor &&
(core)->venus_ver.rev <= vrev);
}
+
+void venus_close_common(struct venus_inst *inst);
#endif
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
index ea8a2bd9419e..33a5a659c0ad 100644
--- a/drivers/media/platform/qcom/venus/pm_helpers.c
+++ b/drivers/media/platform/qcom/venus/pm_helpers.c
@@ -864,7 +864,6 @@ static int venc_power_v4(struct device *dev, int on)
static int vcodec_domains_get(struct venus_core *core)
{
int ret;
- struct device **opp_virt_dev;
struct device *dev = core->dev;
const struct venus_resources *res = core->res;
struct dev_pm_domain_attach_data vcodec_data = {
@@ -872,6 +871,11 @@ static int vcodec_domains_get(struct venus_core *core)
.num_pd_names = res->vcodec_pmdomains_num,
.pd_flags = PD_FLAG_NO_DEV_LINK,
};
+ struct dev_pm_domain_attach_data opp_pd_data = {
+ .pd_names = res->opp_pmdomain,
+ .num_pd_names = 1,
+ .pd_flags = PD_FLAG_DEV_LINK_ON | PD_FLAG_REQUIRED_OPP,
+ };
if (!res->vcodec_pmdomains_num)
goto skip_pmdomains;
@@ -881,37 +885,15 @@ static int vcodec_domains_get(struct venus_core *core)
return ret;
skip_pmdomains:
- if (!core->res->opp_pmdomain)
+ if (!res->opp_pmdomain)
return 0;
/* Attach the power domain for setting performance state */
- ret = devm_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
- if (ret)
- goto opp_attach_err;
-
- core->opp_pmdomain = *opp_virt_dev;
- core->opp_dl_venus = device_link_add(dev, core->opp_pmdomain,
- DL_FLAG_RPM_ACTIVE |
- DL_FLAG_PM_RUNTIME |
- DL_FLAG_STATELESS);
- if (!core->opp_dl_venus) {
- ret = -ENODEV;
- goto opp_attach_err;
- }
+ ret = devm_pm_domain_attach_list(dev, &opp_pd_data, &core->opp_pmdomain);
+ if (ret < 0)
+ return ret;
return 0;
-
-opp_attach_err:
- return ret;
-}
-
-static void vcodec_domains_put(struct venus_core *core)
-{
- if (!core->has_opp_table)
- return;
-
- if (core->opp_dl_venus)
- device_link_del(core->opp_dl_venus);
}
static int core_resets_reset(struct venus_core *core)
@@ -1000,9 +982,7 @@ static int core_get_v4(struct venus_core *core)
if (core->res->opp_pmdomain) {
ret = devm_pm_opp_of_add_table(dev);
- if (!ret) {
- core->has_opp_table = true;
- } else if (ret != -ENODEV) {
+ if (ret && ret != -ENODEV) {
dev_err(dev, "invalid OPP table in device tree\n");
return ret;
}
@@ -1013,10 +993,6 @@ static int core_get_v4(struct venus_core *core)
static void core_put_v4(struct venus_core *core)
{
- if (legacy_binding)
- return;
-
- vcodec_domains_put(core);
}
static int core_power_v4(struct venus_core *core, int on)
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index d12089370d91..98c22b9f9372 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -1735,7 +1735,7 @@ err_m2m_release:
err_session_destroy:
hfi_session_destroy(inst);
err_ctrl_deinit:
- vdec_ctrl_deinit(inst);
+ v4l2_ctrl_handler_free(&inst->ctrl_handler);
err_free:
kfree(inst);
return ret;
@@ -1746,18 +1746,9 @@ static int vdec_close(struct file *file)
struct venus_inst *inst = to_inst(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);
+ venus_close_common(inst);
ida_destroy(&inst->dpb_ids);
- hfi_session_destroy(inst);
- mutex_destroy(&inst->lock);
- mutex_destroy(&inst->ctx_q_lock);
- v4l2_fh_del(&inst->fh);
- v4l2_fh_exit(&inst->fh);
-
vdec_pm_put(inst, false);
kfree(inst);
@@ -1875,7 +1866,7 @@ MODULE_DEVICE_TABLE(of, vdec_dt_match);
static struct platform_driver qcom_venus_dec_driver = {
.probe = vdec_probe,
- .remove_new = vdec_remove,
+ .remove = vdec_remove,
.driver = {
.name = "qcom-venus-decoder",
.of_match_table = vdec_dt_match,
diff --git a/drivers/media/platform/qcom/venus/vdec.h b/drivers/media/platform/qcom/venus/vdec.h
index 6b262d0bf561..0cf981108ff0 100644
--- a/drivers/media/platform/qcom/venus/vdec.h
+++ b/drivers/media/platform/qcom/venus/vdec.h
@@ -9,6 +9,5 @@
struct venus_inst;
int vdec_ctrl_init(struct venus_inst *inst);
-void vdec_ctrl_deinit(struct venus_inst *inst);
#endif
diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c
index 7e0f29bf7fae..36ed955b0419 100644
--- a/drivers/media/platform/qcom/venus/vdec_ctrls.c
+++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c
@@ -187,8 +187,3 @@ int vdec_ctrl_init(struct venus_inst *inst)
return 0;
}
-
-void vdec_ctrl_deinit(struct venus_inst *inst)
-{
- v4l2_ctrl_handler_free(&inst->ctrl_handler);
-}
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index 3ec2fb8d9fab..c1c543535aaf 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -734,6 +734,29 @@ static int venc_set_properties(struct venus_inst *inst)
if (ret)
return ret;
+ if (ctr->layer_bitrate) {
+ unsigned int i;
+
+ ptype = HFI_PROPERTY_PARAM_VENC_HIER_P_MAX_NUM_ENH_LAYER;
+ ret = hfi_session_set_property(inst, ptype, &ctr->h264_hier_layers);
+ if (ret)
+ return ret;
+
+ ptype = HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER;
+ ret = hfi_session_set_property(inst, ptype, &ctr->layer_bitrate);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < ctr->h264_hier_layers; ++i) {
+ ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
+ brate.bitrate = ctr->h264_hier_layer_bitrate[i];
+ brate.layer_id = i;
+
+ ret = hfi_session_set_property(inst, ptype, &brate);
+ if (ret)
+ return ret;
+ }
+ }
}
if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 ||
@@ -823,18 +846,33 @@ static int venc_set_properties(struct venus_inst *inst)
return ret;
}
- if (!ctr->bitrate)
- bitrate = 64000;
- else
- bitrate = ctr->bitrate;
+ if (!ctr->layer_bitrate) {
+ if (!ctr->bitrate)
+ bitrate = 64000;
+ else
+ bitrate = ctr->bitrate;
- ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
- brate.bitrate = bitrate;
- brate.layer_id = 0;
+ ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
+ brate.bitrate = bitrate;
+ brate.layer_id = 0;
- ret = hfi_session_set_property(inst, ptype, &brate);
- if (ret)
- return ret;
+ ret = hfi_session_set_property(inst, ptype, &brate);
+ if (ret)
+ return ret;
+
+ if (!ctr->bitrate_peak)
+ bitrate *= 2;
+ else
+ bitrate = ctr->bitrate_peak;
+
+ ptype = HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE;
+ brate.bitrate = bitrate;
+ brate.layer_id = 0;
+
+ ret = hfi_session_set_property(inst, ptype, &brate);
+ if (ret)
+ return ret;
+ }
if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264 ||
inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) {
@@ -849,19 +887,6 @@ static int venc_set_properties(struct venus_inst *inst)
return ret;
}
- if (!ctr->bitrate_peak)
- bitrate *= 2;
- else
- bitrate = ctr->bitrate_peak;
-
- ptype = HFI_PROPERTY_CONFIG_VENC_MAX_BITRATE;
- brate.bitrate = bitrate;
- brate.layer_id = 0;
-
- ret = hfi_session_set_property(inst, ptype, &brate);
- if (ret)
- return ret;
-
ptype = HFI_PROPERTY_PARAM_VENC_SESSION_QP;
if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) {
quant.qp_i = ctr->hevc_i_qp;
@@ -1503,7 +1528,7 @@ err_m2m_release:
err_session_destroy:
hfi_session_destroy(inst);
err_ctrl_deinit:
- venc_ctrl_deinit(inst);
+ v4l2_ctrl_handler_free(&inst->ctrl_handler);
err_free:
kfree(inst);
return ret;
@@ -1514,18 +1539,8 @@ static int venc_close(struct file *file)
struct venus_inst *inst = to_inst(file);
venc_pm_get(inst);
-
- v4l2_m2m_ctx_release(inst->m2m_ctx);
- v4l2_m2m_release(inst->m2m_dev);
- venc_ctrl_deinit(inst);
- hfi_session_destroy(inst);
- mutex_destroy(&inst->lock);
- mutex_destroy(&inst->ctx_q_lock);
- v4l2_fh_del(&inst->fh);
- v4l2_fh_exit(&inst->fh);
-
+ venus_close_common(inst);
inst->enc_state = VENUS_ENC_STATE_DEINIT;
-
venc_pm_put(inst, false);
kfree(inst);
@@ -1643,7 +1658,7 @@ MODULE_DEVICE_TABLE(of, venc_dt_match);
static struct platform_driver qcom_venus_enc_driver = {
.probe = venc_probe,
- .remove_new = venc_remove,
+ .remove = venc_remove,
.driver = {
.name = "qcom-venus-encoder",
.of_match_table = venc_dt_match,
diff --git a/drivers/media/platform/qcom/venus/venc.h b/drivers/media/platform/qcom/venus/venc.h
index 4ea37fdcd9b8..719d0f73b14b 100644
--- a/drivers/media/platform/qcom/venus/venc.h
+++ b/drivers/media/platform/qcom/venus/venc.h
@@ -9,6 +9,5 @@
struct venus_inst;
int venc_ctrl_init(struct venus_inst *inst);
-void venc_ctrl_deinit(struct venus_inst *inst);
#endif
diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c
index d9d2a293f3ef..51801a962ed2 100644
--- a/drivers/media/platform/qcom/venus/venc_ctrls.c
+++ b/drivers/media/platform/qcom/venus/venc_ctrls.c
@@ -67,12 +67,28 @@ static int venc_calc_bpframes(u32 gop_size, u32 conseq_b, u32 *bf, u32 *pf)
return 0;
}
+static int dynamic_bitrate_update(struct venus_inst *inst, u32 bitrate,
+ u32 layer_id)
+{
+ int ret = 0;
+
+ mutex_lock(&inst->lock);
+ if (inst->streamon_out && inst->streamon_cap) {
+ u32 ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
+ struct hfi_bitrate brate = { .bitrate = bitrate, .layer_id = layer_id };
+
+ ret = hfi_session_set_property(inst, ptype, &brate);
+ }
+ mutex_unlock(&inst->lock);
+
+ return ret;
+}
+
static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
{
struct venus_inst *inst = ctrl_to_inst(ctrl);
struct venc_controls *ctr = &inst->controls.enc;
struct hfi_enable en = { .enable = 1 };
- struct hfi_bitrate brate;
struct hfi_ltr_use ltr_use;
struct hfi_ltr_mark ltr_mark;
u32 bframes;
@@ -85,19 +101,9 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_MPEG_VIDEO_BITRATE:
ctr->bitrate = ctrl->val;
- mutex_lock(&inst->lock);
- if (inst->streamon_out && inst->streamon_cap) {
- ptype = HFI_PROPERTY_CONFIG_VENC_TARGET_BITRATE;
- brate.bitrate = ctr->bitrate;
- brate.layer_id = 0;
-
- ret = hfi_session_set_property(inst, ptype, &brate);
- if (ret) {
- mutex_unlock(&inst->lock);
- return ret;
- }
- }
- mutex_unlock(&inst->lock);
+ ret = dynamic_bitrate_update(inst, ctr->bitrate, 0);
+ if (ret)
+ return ret;
break;
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
ctr->bitrate_peak = ctrl->val;
@@ -340,6 +346,55 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
ctr->h264_8x8_transform = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE:
+ if (ctrl->val != V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P)
+ return -EINVAL;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING:
+ ctr->layer_bitrate = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER:
+ if (ctrl->val > VIDC_MAX_HIER_CODING_LAYER)
+ return -EINVAL;
+ ctr->h264_hier_layers = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR:
+ ctr->h264_hier_layer_bitrate[0] = ctrl->val;
+ ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[0], 0);
+ if (ret)
+ return ret;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR:
+ ctr->h264_hier_layer_bitrate[1] = ctrl->val;
+ ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[1], 1);
+ if (ret)
+ return ret;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR:
+ ctr->h264_hier_layer_bitrate[2] = ctrl->val;
+ ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[2], 2);
+ if (ret)
+ return ret;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR:
+ ctr->h264_hier_layer_bitrate[3] = ctrl->val;
+ ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[3], 3);
+ if (ret)
+ return ret;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR:
+ ctr->h264_hier_layer_bitrate[4] = ctrl->val;
+ ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[4], 4);
+ if (ret)
+ return ret;
+ break;
+ case V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR:
+ ctr->h264_hier_layer_bitrate[5] = ctrl->val;
+ ret = dynamic_bitrate_update(inst, ctr->h264_hier_layer_bitrate[5], 5);
+ if (ret)
+ return ret;
+ break;
+
default:
return -EINVAL;
}
@@ -622,6 +677,49 @@ int venc_ctrl_init(struct venus_inst *inst)
V4L2_CID_MPEG_VIDEO_INTRA_REFRESH_PERIOD, 0,
((4096 * 2304) >> 8), 1, 0);
+ if (IS_V4(inst->core) || IS_V6(inst->core)) {
+ v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_TYPE,
+ V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P,
+ 1, V4L2_MPEG_VIDEO_H264_HIERARCHICAL_CODING_P);
+
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING, 0, 1, 1, 0);
+
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_HIERARCHICAL_CODING_LAYER, 0,
+ VIDC_MAX_HIER_CODING_LAYER, 1, 0);
+
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L0_BR,
+ BITRATE_MIN, BITRATE_MAX, BITRATE_STEP, BITRATE_DEFAULT);
+
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L1_BR,
+ BITRATE_MIN, BITRATE_MAX,
+ BITRATE_STEP, BITRATE_DEFAULT);
+
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L2_BR,
+ BITRATE_MIN, BITRATE_MAX,
+ BITRATE_STEP, BITRATE_DEFAULT);
+
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L3_BR,
+ BITRATE_MIN, BITRATE_MAX,
+ BITRATE_STEP, BITRATE_DEFAULT);
+
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L4_BR,
+ BITRATE_MIN, BITRATE_MAX,
+ BITRATE_STEP, BITRATE_DEFAULT);
+
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_H264_HIER_CODING_L5_BR,
+ BITRATE_MIN, BITRATE_MAX,
+ BITRATE_STEP, BITRATE_DEFAULT);
+ }
+
ret = inst->ctrl_handler.error;
if (ret)
goto err;
@@ -635,8 +733,3 @@ err:
v4l2_ctrl_handler_free(&inst->ctrl_handler);
return ret;
}
-
-void venc_ctrl_deinit(struct venus_inst *inst)
-{
- v4l2_ctrl_handler_free(&inst->ctrl_handler);
-}
diff --git a/drivers/media/platform/raspberrypi/Kconfig b/drivers/media/platform/raspberrypi/Kconfig
index e928f979019e..bd5101ffefb5 100644
--- a/drivers/media/platform/raspberrypi/Kconfig
+++ b/drivers/media/platform/raspberrypi/Kconfig
@@ -3,3 +3,4 @@
comment "Raspberry Pi media platform drivers"
source "drivers/media/platform/raspberrypi/pisp_be/Kconfig"
+source "drivers/media/platform/raspberrypi/rp1-cfe/Kconfig"
diff --git a/drivers/media/platform/raspberrypi/Makefile b/drivers/media/platform/raspberrypi/Makefile
index c0d1a2dab486..af7fde84eefe 100644
--- a/drivers/media/platform/raspberrypi/Makefile
+++ b/drivers/media/platform/raspberrypi/Makefile
@@ -1,3 +1,4 @@
# SPDX-License-Identifier: GPL-2.0
obj-y += pisp_be/
+obj-y += rp1-cfe/
diff --git a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
index 65ff2382cffe..7596ae1f7de6 100644
--- a/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
+++ b/drivers/media/platform/raspberrypi/pisp_be/pisp_be.c
@@ -1781,7 +1781,7 @@ MODULE_DEVICE_TABLE(of, pispbe_of_match);
static struct platform_driver pispbe_pdrv = {
.probe = pispbe_probe,
- .remove_new = pispbe_remove,
+ .remove = pispbe_remove,
.driver = {
.name = PISPBE_NAME,
.of_match_table = pispbe_of_match,
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/Kconfig b/drivers/media/platform/raspberrypi/rp1-cfe/Kconfig
new file mode 100644
index 000000000000..327b61f1134b
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/Kconfig
@@ -0,0 +1,15 @@
+# RP1 V4L2 camera support
+
+config VIDEO_RP1_CFE
+ tristate "Raspberry Pi RP1 Camera Front End (CFE) video capture driver"
+ depends on VIDEO_DEV
+ depends on PM
+ select VIDEO_V4L2_SUBDEV_API
+ select MEDIA_CONTROLLER
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_FWNODE
+ help
+ Say Y here to enable support for the Raspberry Pi RP1 Camera Front End.
+
+ To compile this driver as a module, choose M here. The module will be
+ called rp1-cfe.
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/Makefile b/drivers/media/platform/raspberrypi/rp1-cfe/Makefile
new file mode 100644
index 000000000000..3f0d0fc8570e
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/Makefile
@@ -0,0 +1,6 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Makefile for RP1 Camera Front End driver
+#
+rp1-cfe-objs := cfe.o csi2.o pisp-fe.o dphy.o
+obj-$(CONFIG_VIDEO_RP1_CFE) += rp1-cfe.o
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe-fmts.h b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-fmts.h
new file mode 100644
index 000000000000..7aecf7f83733
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-fmts.h
@@ -0,0 +1,332 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * RP1 Camera Front End formats definition
+ *
+ * Copyright (C) 2021-2024 - Raspberry Pi Ltd.
+ */
+#ifndef _CFE_FMTS_H_
+#define _CFE_FMTS_H_
+
+#include "cfe.h"
+#include <media/mipi-csi2.h>
+
+static const struct cfe_fmt formats[] = {
+ /* YUV Formats */
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .code = MEDIA_BUS_FMT_YUYV8_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_YUV422_8B,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_YUV422_8B,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .code = MEDIA_BUS_FMT_YVYU8_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_YUV422_8B,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .code = MEDIA_BUS_FMT_VYUY8_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_YUV422_8B,
+ },
+ {
+ /* RGB Formats */
+ .fourcc = V4L2_PIX_FMT_RGB565, /* gggbbbbb rrrrrggg */
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RGB565,
+ },
+ { .fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RGB565,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB555, /* gggbbbbb arrrrrgg */
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RGB555,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB555X, /* arrrrrgg gggbbbbb */
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RGB555,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB24, /* rgb */
+ .code = MEDIA_BUS_FMT_RGB888_1X24,
+ .depth = 24,
+ .csi_dt = MIPI_CSI2_DT_RGB888,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_BGR24, /* bgr */
+ .code = MEDIA_BUS_FMT_BGR888_1X24,
+ .depth = 24,
+ .csi_dt = MIPI_CSI2_DT_RGB888,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB32, /* argb */
+ .code = MEDIA_BUS_FMT_ARGB8888_1X32,
+ .depth = 32,
+ .csi_dt = 0x0,
+ },
+
+ /* Bayer Formats */
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .depth = 8,
+ .csi_dt = MIPI_CSI2_DT_RAW8,
+ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .depth = 8,
+ .csi_dt = MIPI_CSI2_DT_RAW8,
+ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .depth = 8,
+ .csi_dt = MIPI_CSI2_DT_RAW8,
+ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB8,
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .depth = 8,
+ .csi_dt = MIPI_CSI2_DT_RAW8,
+ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR10P,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
+ .depth = 10,
+ .csi_dt = MIPI_CSI2_DT_RAW10,
+ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG10P,
+ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
+ .depth = 10,
+ .csi_dt = MIPI_CSI2_DT_RAW10,
+ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG10P,
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
+ .depth = 10,
+ .csi_dt = MIPI_CSI2_DT_RAW10,
+ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB10P,
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .depth = 10,
+ .csi_dt = MIPI_CSI2_DT_RAW10,
+ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR12P,
+ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
+ .depth = 12,
+ .csi_dt = MIPI_CSI2_DT_RAW12,
+ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG12P,
+ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
+ .depth = 12,
+ .csi_dt = MIPI_CSI2_DT_RAW12,
+ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG12P,
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
+ .depth = 12,
+ .csi_dt = MIPI_CSI2_DT_RAW12,
+ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB12P,
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
+ .depth = 12,
+ .csi_dt = MIPI_CSI2_DT_RAW12,
+ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR14P,
+ .code = MEDIA_BUS_FMT_SBGGR14_1X14,
+ .depth = 14,
+ .csi_dt = MIPI_CSI2_DT_RAW14,
+ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG14P,
+ .code = MEDIA_BUS_FMT_SGBRG14_1X14,
+ .depth = 14,
+ .csi_dt = MIPI_CSI2_DT_RAW14,
+ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG14P,
+ .code = MEDIA_BUS_FMT_SGRBG14_1X14,
+ .depth = 14,
+ .csi_dt = MIPI_CSI2_DT_RAW14,
+ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB14P,
+ .code = MEDIA_BUS_FMT_SRGGB14_1X14,
+ .depth = 14,
+ .csi_dt = MIPI_CSI2_DT_RAW14,
+ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR16,
+ .code = MEDIA_BUS_FMT_SBGGR16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ .flags = CFE_FORMAT_FLAG_FE_OUT,
+ .remap = { V4L2_PIX_FMT_SBGGR16, V4L2_PIX_FMT_PISP_COMP1_BGGR },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG16,
+ .code = MEDIA_BUS_FMT_SGBRG16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ .flags = CFE_FORMAT_FLAG_FE_OUT,
+ .remap = { V4L2_PIX_FMT_SGBRG16, V4L2_PIX_FMT_PISP_COMP1_GBRG },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG16,
+ .code = MEDIA_BUS_FMT_SGRBG16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ .flags = CFE_FORMAT_FLAG_FE_OUT,
+ .remap = { V4L2_PIX_FMT_SGRBG16, V4L2_PIX_FMT_PISP_COMP1_GRBG },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB16,
+ .code = MEDIA_BUS_FMT_SRGGB16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ .flags = CFE_FORMAT_FLAG_FE_OUT,
+ .remap = { V4L2_PIX_FMT_SRGGB16, V4L2_PIX_FMT_PISP_COMP1_RGGB },
+ },
+ /* PiSP Compressed Mode 1 */
+ {
+ .fourcc = V4L2_PIX_FMT_PISP_COMP1_RGGB,
+ .code = MEDIA_BUS_FMT_SRGGB16_1X16,
+ .depth = 8,
+ .flags = CFE_FORMAT_FLAG_FE_OUT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_PISP_COMP1_BGGR,
+ .code = MEDIA_BUS_FMT_SBGGR16_1X16,
+ .depth = 8,
+ .flags = CFE_FORMAT_FLAG_FE_OUT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GBRG,
+ .code = MEDIA_BUS_FMT_SGBRG16_1X16,
+ .depth = 8,
+ .flags = CFE_FORMAT_FLAG_FE_OUT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_PISP_COMP1_GRBG,
+ .code = MEDIA_BUS_FMT_SGRBG16_1X16,
+ .depth = 8,
+ .flags = CFE_FORMAT_FLAG_FE_OUT,
+ },
+ /* Greyscale format */
+ {
+ .fourcc = V4L2_PIX_FMT_GREY,
+ .code = MEDIA_BUS_FMT_Y8_1X8,
+ .depth = 8,
+ .csi_dt = MIPI_CSI2_DT_RAW8,
+ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y10P,
+ .code = MEDIA_BUS_FMT_Y10_1X10,
+ .depth = 10,
+ .csi_dt = MIPI_CSI2_DT_RAW10,
+ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y12P,
+ .code = MEDIA_BUS_FMT_Y12_1X12,
+ .depth = 12,
+ .csi_dt = MIPI_CSI2_DT_RAW12,
+ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y14P,
+ .code = MEDIA_BUS_FMT_Y14_1X14,
+ .depth = 14,
+ .csi_dt = MIPI_CSI2_DT_RAW14,
+ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_Y16,
+ .code = MEDIA_BUS_FMT_Y16_1X16,
+ .depth = 16,
+ .csi_dt = MIPI_CSI2_DT_RAW16,
+ .flags = CFE_FORMAT_FLAG_FE_OUT,
+ .remap = { V4L2_PIX_FMT_Y16, V4L2_PIX_FMT_PISP_COMP1_MONO },
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_PISP_COMP1_MONO,
+ .code = MEDIA_BUS_FMT_Y16_1X16,
+ .depth = 8,
+ .flags = CFE_FORMAT_FLAG_FE_OUT,
+ },
+
+ /* Embedded data formats */
+ {
+ .fourcc = V4L2_META_FMT_GENERIC_8,
+ .code = MEDIA_BUS_FMT_META_8,
+ .depth = 8,
+ .csi_dt = MIPI_CSI2_DT_EMBEDDED_8B,
+ .flags = CFE_FORMAT_FLAG_META_CAP,
+ },
+ {
+ .fourcc = V4L2_META_FMT_GENERIC_CSI2_10,
+ .code = MEDIA_BUS_FMT_META_10,
+ .depth = 10,
+ .csi_dt = MIPI_CSI2_DT_EMBEDDED_8B,
+ .flags = CFE_FORMAT_FLAG_META_CAP,
+ },
+ {
+ .fourcc = V4L2_META_FMT_GENERIC_CSI2_12,
+ .code = MEDIA_BUS_FMT_META_12,
+ .depth = 12,
+ .csi_dt = MIPI_CSI2_DT_EMBEDDED_8B,
+ .flags = CFE_FORMAT_FLAG_META_CAP,
+ },
+
+ /* Frontend formats */
+ {
+ .fourcc = V4L2_META_FMT_RPI_FE_CFG,
+ .code = MEDIA_BUS_FMT_FIXED,
+ .flags = CFE_FORMAT_FLAG_META_OUT,
+ },
+ {
+ .fourcc = V4L2_META_FMT_RPI_FE_STATS,
+ .code = MEDIA_BUS_FMT_FIXED,
+ .flags = CFE_FORMAT_FLAG_META_CAP,
+ },
+};
+
+#endif /* _CFE_FMTS_H_ */
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace.h b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace.h
new file mode 100644
index 000000000000..1a36259f51b7
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace.h
@@ -0,0 +1,202 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2024 Raspberry Pi Ltd.
+ * Copyright (c) 2024 Ideas on Board Oy
+ */
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM cfe
+
+#if !defined(_CFE_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _CFE_TRACE_H
+
+#include <linux/tracepoint.h>
+#include <media/videobuf2-v4l2.h>
+
+TRACE_EVENT(cfe_return_buffer,
+ TP_PROTO(u32 node_id, u32 buf_idx, u32 queue_id),
+ TP_ARGS(node_id, buf_idx, queue_id),
+ TP_STRUCT__entry(
+ __field(u32, node_id)
+ __field(u32, buf_idx)
+ __field(u32, queue_id)
+ ),
+ TP_fast_assign(
+ __entry->node_id = node_id;
+ __entry->buf_idx = buf_idx;
+ __entry->queue_id = queue_id;
+ ),
+ TP_printk("node=%u buf=%u, queue=%u", __entry->node_id,
+ __entry->buf_idx, __entry->queue_id)
+);
+
+DECLARE_EVENT_CLASS(cfe_buffer_template,
+ TP_PROTO(u32 node_id, struct vb2_buffer *buf),
+ TP_ARGS(node_id, buf),
+ TP_STRUCT__entry(
+ __field(u32, node_id)
+ __field(u32, buf_idx)
+ ),
+ TP_fast_assign(
+ __entry->node_id = node_id;
+ __entry->buf_idx = buf->index;
+ ),
+ TP_printk("node=%u buf=%u", __entry->node_id, __entry->buf_idx)
+);
+
+DEFINE_EVENT(cfe_buffer_template, cfe_buffer_prepare,
+ TP_PROTO(u32 node_id, struct vb2_buffer *buf),
+ TP_ARGS(node_id, buf));
+
+TRACE_EVENT(cfe_buffer_queue,
+ TP_PROTO(u32 node_id, struct vb2_buffer *buf, bool schedule_now),
+ TP_ARGS(node_id, buf, schedule_now),
+ TP_STRUCT__entry(
+ __field(u32, node_id)
+ __field(u32, buf_idx)
+ __field(bool, schedule_now)
+ ),
+ TP_fast_assign(
+ __entry->node_id = node_id;
+ __entry->buf_idx = buf->index;
+ __entry->schedule_now = schedule_now;
+ ),
+ TP_printk("node=%u buf=%u%s", __entry->node_id, __entry->buf_idx,
+ __entry->schedule_now ? " schedule immediately" : "")
+);
+
+DEFINE_EVENT(cfe_buffer_template, cfe_csi2_schedule,
+ TP_PROTO(u32 node_id, struct vb2_buffer *buf),
+ TP_ARGS(node_id, buf));
+
+DEFINE_EVENT(cfe_buffer_template, cfe_fe_schedule,
+ TP_PROTO(u32 node_id, struct vb2_buffer *buf),
+ TP_ARGS(node_id, buf));
+
+TRACE_EVENT(cfe_buffer_complete,
+ TP_PROTO(u32 node_id, struct vb2_v4l2_buffer *buf),
+ TP_ARGS(node_id, buf),
+ TP_STRUCT__entry(
+ __field(u32, node_id)
+ __field(u32, buf_idx)
+ __field(u32, seq)
+ __field(u64, ts)
+ ),
+ TP_fast_assign(
+ __entry->node_id = node_id;
+ __entry->buf_idx = buf->vb2_buf.index;
+ __entry->seq = buf->sequence;
+ __entry->ts = buf->vb2_buf.timestamp;
+ ),
+ TP_printk("node=%u buf=%u seq=%u ts=%llu", __entry->node_id,
+ __entry->buf_idx, __entry->seq, __entry->ts)
+);
+
+TRACE_EVENT(cfe_frame_start,
+ TP_PROTO(u32 node_id, u32 fs_count),
+ TP_ARGS(node_id, fs_count),
+ TP_STRUCT__entry(
+ __field(u32, node_id)
+ __field(u32, fs_count)
+ ),
+ TP_fast_assign(
+ __entry->node_id = node_id;
+ __entry->fs_count = fs_count;
+ ),
+ TP_printk("node=%u fs_count=%u", __entry->node_id, __entry->fs_count)
+);
+
+TRACE_EVENT(cfe_frame_end,
+ TP_PROTO(u32 node_id, u32 fs_count),
+ TP_ARGS(node_id, fs_count),
+ TP_STRUCT__entry(
+ __field(u32, node_id)
+ __field(u32, fs_count)
+ ),
+ TP_fast_assign(
+ __entry->node_id = node_id;
+ __entry->fs_count = fs_count;
+ ),
+ TP_printk("node=%u fs_count=%u", __entry->node_id, __entry->fs_count)
+);
+
+TRACE_EVENT(cfe_prepare_next_job,
+ TP_PROTO(bool fe_enabled),
+ TP_ARGS(fe_enabled),
+ TP_STRUCT__entry(
+ __field(bool, fe_enabled)
+ ),
+ TP_fast_assign(
+ __entry->fe_enabled = fe_enabled;
+ ),
+ TP_printk("fe_enabled=%u", __entry->fe_enabled)
+);
+
+/* These are copied from csi2.c */
+#define CSI2_STATUS_IRQ_FS(x) (BIT(0) << (x))
+#define CSI2_STATUS_IRQ_FE(x) (BIT(4) << (x))
+#define CSI2_STATUS_IRQ_FE_ACK(x) (BIT(8) << (x))
+#define CSI2_STATUS_IRQ_LE(x) (BIT(12) << (x))
+#define CSI2_STATUS_IRQ_LE_ACK(x) (BIT(16) << (x))
+
+TRACE_EVENT(csi2_irq,
+ TP_PROTO(u32 channel, u32 status, u32 dbg),
+ TP_ARGS(channel, status, dbg),
+ TP_STRUCT__entry(
+ __field(u32, channel)
+ __field(u32, status)
+ __field(u32, dbg)
+ ),
+ TP_fast_assign(
+ __entry->channel = channel;
+ __entry->status = status;
+ __entry->dbg = dbg;
+ ),
+ TP_printk("ch=%u flags=[ %s%s%s%s%s] frame=%u line=%u\n",
+ __entry->channel,
+ (__entry->status & CSI2_STATUS_IRQ_FS(__entry->channel)) ?
+ "FS " : "",
+ (__entry->status & CSI2_STATUS_IRQ_FE(__entry->channel)) ?
+ "FE " : "",
+ (__entry->status & CSI2_STATUS_IRQ_FE_ACK(__entry->channel)) ?
+ "FE_ACK " : "",
+ (__entry->status & CSI2_STATUS_IRQ_LE(__entry->channel)) ?
+ "LE " : "",
+ (__entry->status & CSI2_STATUS_IRQ_LE_ACK(__entry->channel)) ?
+ "LE_ACK " : "",
+ __entry->dbg >> 16, __entry->dbg & 0xffff)
+);
+
+TRACE_EVENT(fe_irq,
+ TP_PROTO(u32 status, u32 output_status, u32 frame_status,
+ u32 error_status, u32 int_status),
+ TP_ARGS(status, output_status, frame_status, error_status, int_status),
+ TP_STRUCT__entry(
+ __field(u32, status)
+ __field(u32, output_status)
+ __field(u32, frame_status)
+ __field(u32, error_status)
+ __field(u32, int_status)
+ ),
+ TP_fast_assign(
+ __entry->status = status;
+ __entry->output_status = output_status;
+ __entry->frame_status = frame_status;
+ __entry->error_status = error_status;
+ __entry->int_status = int_status;
+ ),
+ TP_printk("status 0x%x out_status 0x%x frame_status 0x%x error_status 0x%x int_status 0x%x",
+ __entry->status,
+ __entry->output_status,
+ __entry->frame_status,
+ __entry->error_status,
+ __entry->int_status)
+);
+
+#endif /* _CFE_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#define TRACE_INCLUDE_FILE ../../drivers/media/platform/raspberrypi/rp1-cfe/cfe-trace
+#include <trace/define_trace.h>
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c
new file mode 100644
index 000000000000..12660087b12f
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.c
@@ -0,0 +1,2509 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * RP1 Camera Front End Driver
+ *
+ * Copyright (c) 2021-2024 Raspberry Pi Ltd.
+ * Copyright (c) 2023-2024 Ideas on Board Oy
+ */
+
+#include <linux/clk.h>
+#include <linux/debugfs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/dma-mapping.h>
+#include <linux/err.h>
+#include <linux/fwnode.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/lcm.h>
+#include <linux/math.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/property.h>
+#include <linux/seq_file.h>
+#include <linux/slab.h>
+#include <linux/uaccess.h>
+#include <linux/videodev2.h>
+
+#include <media/v4l2-async.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-fwnode.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mc.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include <linux/media/raspberrypi/pisp_fe_config.h>
+#include <linux/media/raspberrypi/pisp_fe_statistics.h>
+
+#include "cfe-fmts.h"
+#include "cfe.h"
+#include "csi2.h"
+#include "pisp-fe.h"
+
+#define CREATE_TRACE_POINTS
+#include "cfe-trace.h"
+
+#define CFE_MODULE_NAME "rp1-cfe"
+#define CFE_VERSION "1.0"
+
+#define cfe_dbg(cfe, fmt, arg...) dev_dbg(&(cfe)->pdev->dev, fmt, ##arg)
+#define cfe_info(cfe, fmt, arg...) dev_info(&(cfe)->pdev->dev, fmt, ##arg)
+#define cfe_err(cfe, fmt, arg...) dev_err(&(cfe)->pdev->dev, fmt, ##arg)
+
+/* MIPICFG registers */
+#define MIPICFG_CFG 0x004
+#define MIPICFG_INTR 0x028
+#define MIPICFG_INTE 0x02c
+#define MIPICFG_INTF 0x030
+#define MIPICFG_INTS 0x034
+
+#define MIPICFG_CFG_SEL_CSI BIT(0)
+
+#define MIPICFG_INT_CSI_DMA BIT(0)
+#define MIPICFG_INT_CSI_HOST BIT(2)
+#define MIPICFG_INT_PISP_FE BIT(4)
+
+#define BPL_ALIGNMENT 16
+#define MAX_BYTESPERLINE 0xffffff00
+#define MAX_BUFFER_SIZE 0xffffff00
+/*
+ * Max width is therefore determined by the max stride divided by the number of
+ * bits per pixel.
+ *
+ * However, to avoid overflow issues let's use a 16k maximum. This lets us
+ * calculate 16k * 16k * 4 with 32bits. If we need higher maximums, a careful
+ * review and adjustment of the code is needed so that it will deal with
+ * overflows correctly.
+ */
+#define MAX_WIDTH 16384
+#define MAX_HEIGHT MAX_WIDTH
+/* Define a nominal minimum image size */
+#define MIN_WIDTH 16
+#define MIN_HEIGHT 16
+
+#define MIN_META_WIDTH 4
+#define MIN_META_HEIGHT 1
+
+const struct v4l2_mbus_framefmt cfe_default_format = {
+ .width = 640,
+ .height = 480,
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
+ .field = V4L2_FIELD_NONE,
+ .colorspace = V4L2_COLORSPACE_RAW,
+ .ycbcr_enc = V4L2_YCBCR_ENC_601,
+ .quantization = V4L2_QUANTIZATION_FULL_RANGE,
+ .xfer_func = V4L2_XFER_FUNC_NONE,
+};
+
+enum node_ids {
+ /* CSI2 HW output nodes first. */
+ CSI2_CH0,
+ CSI2_CH1,
+ CSI2_CH2,
+ CSI2_CH3,
+ /* FE only nodes from here on. */
+ FE_OUT0,
+ FE_OUT1,
+ FE_STATS,
+ FE_CONFIG,
+ NUM_NODES
+};
+
+struct node_description {
+ enum node_ids id;
+ const char *name;
+ unsigned int caps;
+ unsigned int pad_flags;
+ unsigned int link_pad;
+};
+
+/* Must match the ordering of enum ids */
+static const struct node_description node_desc[NUM_NODES] = {
+ [CSI2_CH0] = {
+ .name = "csi2-ch0",
+ .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE,
+ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT,
+ .link_pad = CSI2_PAD_FIRST_SOURCE + 0
+ },
+ /*
+ * At the moment the main userspace component (libcamera) doesn't
+ * support metadata with video nodes that support both video and
+ * metadata. So for the time being this node is set to only support
+ * V4L2_CAP_META_CAPTURE.
+ */
+ [CSI2_CH1] = {
+ .name = "csi2-ch1",
+ .caps = V4L2_CAP_META_CAPTURE,
+ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT,
+ .link_pad = CSI2_PAD_FIRST_SOURCE + 1
+ },
+ [CSI2_CH2] = {
+ .name = "csi2-ch2",
+ .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE,
+ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT,
+ .link_pad = CSI2_PAD_FIRST_SOURCE + 2
+ },
+ [CSI2_CH3] = {
+ .name = "csi2-ch3",
+ .caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE,
+ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT,
+ .link_pad = CSI2_PAD_FIRST_SOURCE + 3
+ },
+ [FE_OUT0] = {
+ .name = "fe-image0",
+ .caps = V4L2_CAP_VIDEO_CAPTURE,
+ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT,
+ .link_pad = FE_OUTPUT0_PAD
+ },
+ [FE_OUT1] = {
+ .name = "fe-image1",
+ .caps = V4L2_CAP_VIDEO_CAPTURE,
+ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT,
+ .link_pad = FE_OUTPUT1_PAD
+ },
+ [FE_STATS] = {
+ .name = "fe-stats",
+ .caps = V4L2_CAP_META_CAPTURE,
+ .pad_flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT,
+ .link_pad = FE_STATS_PAD
+ },
+ [FE_CONFIG] = {
+ .name = "fe-config",
+ .caps = V4L2_CAP_META_OUTPUT,
+ .pad_flags = MEDIA_PAD_FL_SOURCE | MEDIA_PAD_FL_MUST_CONNECT,
+ .link_pad = FE_CONFIG_PAD
+ },
+};
+
+#define is_fe_node(node) (((node)->id) >= FE_OUT0)
+#define is_csi2_node(node) (!is_fe_node(node))
+
+#define node_supports_image_output(node) \
+ (node_desc[(node)->id].caps & V4L2_CAP_VIDEO_CAPTURE)
+#define node_supports_meta_output(node) \
+ (node_desc[(node)->id].caps & V4L2_CAP_META_CAPTURE)
+#define node_supports_image_input(node) \
+ (node_desc[(node)->id].caps & V4L2_CAP_VIDEO_OUTPUT)
+#define node_supports_meta_input(node) \
+ (node_desc[(node)->id].caps & V4L2_CAP_META_OUTPUT)
+#define node_supports_image(node) \
+ (node_supports_image_output(node) || node_supports_image_input(node))
+#define node_supports_meta(node) \
+ (node_supports_meta_output(node) || node_supports_meta_input(node))
+
+#define is_image_output_node(node) \
+ ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+#define is_image_input_node(node) \
+ ((node)->buffer_queue.type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+#define is_image_node(node) \
+ (is_image_output_node(node) || is_image_input_node(node))
+#define is_meta_output_node(node) \
+ ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_CAPTURE)
+#define is_meta_input_node(node) \
+ ((node)->buffer_queue.type == V4L2_BUF_TYPE_META_OUTPUT)
+#define is_meta_node(node) \
+ (is_meta_output_node(node) || is_meta_input_node(node))
+
+/* To track state across all nodes. */
+#define NODE_REGISTERED BIT(0)
+#define NODE_ENABLED BIT(1)
+#define NODE_STREAMING BIT(2)
+#define FS_INT BIT(3)
+#define FE_INT BIT(4)
+#define NUM_STATES 5
+
+struct cfe_buffer {
+ struct vb2_v4l2_buffer vb;
+ struct list_head list;
+};
+
+struct cfe_config_buffer {
+ struct cfe_buffer buf;
+ struct pisp_fe_config config;
+};
+
+static inline struct cfe_buffer *to_cfe_buffer(struct vb2_buffer *vb)
+{
+ return container_of(vb, struct cfe_buffer, vb.vb2_buf);
+}
+
+static inline
+struct cfe_config_buffer *to_cfe_config_buffer(struct cfe_buffer *buf)
+{
+ return container_of(buf, struct cfe_config_buffer, buf);
+}
+
+struct cfe_node {
+ /* Node id */
+ enum node_ids id;
+ /* Pointer pointing to current v4l2_buffer */
+ struct cfe_buffer *cur_frm;
+ /* Pointer pointing to next v4l2_buffer */
+ struct cfe_buffer *next_frm;
+ /* Used to store current pixel format */
+ struct v4l2_format vid_fmt;
+ /* Used to store current meta format */
+ struct v4l2_format meta_fmt;
+ /* Buffer queue used in video-buf */
+ struct vb2_queue buffer_queue;
+ /* Queue of filled frames */
+ struct list_head dma_queue;
+ /* lock used to access this structure */
+ struct mutex lock;
+ /* Identifies video device for this channel */
+ struct video_device video_dev;
+ /* Pointer to the parent handle */
+ struct cfe_device *cfe;
+ /* Media pad for this node */
+ struct media_pad pad;
+ /* Frame-start counter */
+ unsigned int fs_count;
+ /* Timestamp of the current buffer */
+ u64 ts;
+};
+
+struct cfe_device {
+ struct dentry *debugfs;
+ struct kref kref;
+
+ /* peripheral base address */
+ void __iomem *mipi_cfg_base;
+
+ struct clk *clk;
+
+ /* V4l2 device */
+ struct v4l2_device v4l2_dev;
+ struct media_device mdev;
+ struct media_pipeline pipe;
+
+ /* IRQ lock for node state and DMA queues */
+ spinlock_t state_lock;
+ bool job_ready;
+ bool job_queued;
+
+ /* parent device */
+ struct platform_device *pdev;
+ /* subdevice async Notifier */
+ struct v4l2_async_notifier notifier;
+
+ /* Source sub device */
+ struct v4l2_subdev *source_sd;
+ /* Source subdev's pad */
+ u32 source_pad;
+
+ struct cfe_node node[NUM_NODES];
+ DECLARE_BITMAP(node_flags, NUM_STATES * NUM_NODES);
+
+ struct csi2_device csi2;
+ struct pisp_fe_device fe;
+
+ int fe_csi2_channel;
+
+ /* Mask of enabled streams */
+ u64 streams_mask;
+};
+
+static inline bool is_fe_enabled(struct cfe_device *cfe)
+{
+ return cfe->fe_csi2_channel != -1;
+}
+
+static inline struct cfe_device *to_cfe_device(struct v4l2_device *v4l2_dev)
+{
+ return container_of(v4l2_dev, struct cfe_device, v4l2_dev);
+}
+
+static inline u32 cfg_reg_read(struct cfe_device *cfe, u32 offset)
+{
+ return readl(cfe->mipi_cfg_base + offset);
+}
+
+static inline void cfg_reg_write(struct cfe_device *cfe, u32 offset, u32 val)
+{
+ writel(val, cfe->mipi_cfg_base + offset);
+}
+
+static bool check_state(struct cfe_device *cfe, unsigned long state,
+ unsigned int node_id)
+{
+ unsigned long bit;
+
+ for_each_set_bit(bit, &state, sizeof(state)) {
+ if (!test_bit(bit + (node_id * NUM_STATES), cfe->node_flags))
+ return false;
+ }
+
+ return true;
+}
+
+static void set_state(struct cfe_device *cfe, unsigned long state,
+ unsigned int node_id)
+{
+ unsigned long bit;
+
+ for_each_set_bit(bit, &state, sizeof(state))
+ set_bit(bit + (node_id * NUM_STATES), cfe->node_flags);
+}
+
+static void clear_state(struct cfe_device *cfe, unsigned long state,
+ unsigned int node_id)
+{
+ unsigned long bit;
+
+ for_each_set_bit(bit, &state, sizeof(state))
+ clear_bit(bit + (node_id * NUM_STATES), cfe->node_flags);
+}
+
+static bool test_any_node(struct cfe_device *cfe, unsigned long cond)
+{
+ for (unsigned int i = 0; i < NUM_NODES; i++) {
+ if (check_state(cfe, cond, i))
+ return true;
+ }
+
+ return false;
+}
+
+static bool test_all_nodes(struct cfe_device *cfe, unsigned long precond,
+ unsigned long cond)
+{
+ for (unsigned int i = 0; i < NUM_NODES; i++) {
+ if (check_state(cfe, precond, i)) {
+ if (!check_state(cfe, cond, i))
+ return false;
+ }
+ }
+
+ return true;
+}
+
+static int mipi_cfg_regs_show(struct seq_file *s, void *data)
+{
+ struct cfe_device *cfe = s->private;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(&cfe->pdev->dev);
+ if (ret)
+ return ret;
+
+#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", cfg_reg_read(cfe, reg))
+ DUMP(MIPICFG_CFG);
+ DUMP(MIPICFG_INTR);
+ DUMP(MIPICFG_INTE);
+ DUMP(MIPICFG_INTF);
+ DUMP(MIPICFG_INTS);
+#undef DUMP
+
+ pm_runtime_put(&cfe->pdev->dev);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(mipi_cfg_regs);
+
+/* Format setup functions */
+const struct cfe_fmt *find_format_by_code(u32 code)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (formats[i].code == code)
+ return &formats[i];
+ }
+
+ return NULL;
+}
+
+const struct cfe_fmt *find_format_by_pix(u32 pixelformat)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (formats[i].fourcc == pixelformat)
+ return &formats[i];
+ }
+
+ return NULL;
+}
+
+static const struct cfe_fmt *find_format_by_code_and_fourcc(u32 code,
+ u32 fourcc)
+{
+ for (unsigned int i = 0; i < ARRAY_SIZE(formats); i++) {
+ if (formats[i].code == code && formats[i].fourcc == fourcc)
+ return &formats[i];
+ }
+
+ return NULL;
+}
+
+/*
+ * Given the mbus code, find the 16 bit remapped code. Returns 0 if no remap
+ * possible.
+ */
+u32 cfe_find_16bit_code(u32 code)
+{
+ const struct cfe_fmt *cfe_fmt;
+
+ cfe_fmt = find_format_by_code(code);
+
+ if (!cfe_fmt || !cfe_fmt->remap[CFE_REMAP_16BIT])
+ return 0;
+
+ cfe_fmt = find_format_by_pix(cfe_fmt->remap[CFE_REMAP_16BIT]);
+ if (!cfe_fmt)
+ return 0;
+
+ return cfe_fmt->code;
+}
+
+/*
+ * Given the mbus code, find the 8 bit compressed code. Returns 0 if no remap
+ * possible.
+ */
+u32 cfe_find_compressed_code(u32 code)
+{
+ const struct cfe_fmt *cfe_fmt;
+
+ cfe_fmt = find_format_by_code(code);
+
+ if (!cfe_fmt || !cfe_fmt->remap[CFE_REMAP_COMPRESSED])
+ return 0;
+
+ cfe_fmt = find_format_by_pix(cfe_fmt->remap[CFE_REMAP_COMPRESSED]);
+ if (!cfe_fmt)
+ return 0;
+
+ return cfe_fmt->code;
+}
+
+static void cfe_calc_vid_format_size_bpl(struct cfe_device *cfe,
+ const struct cfe_fmt *fmt,
+ struct v4l2_format *f)
+{
+ unsigned int min_bytesperline;
+
+ v4l_bound_align_image(&f->fmt.pix.width, MIN_WIDTH, MAX_WIDTH, 2,
+ &f->fmt.pix.height, MIN_HEIGHT, MAX_HEIGHT, 0, 0);
+
+ min_bytesperline =
+ ALIGN((f->fmt.pix.width * fmt->depth) >> 3, BPL_ALIGNMENT);
+
+ if (f->fmt.pix.bytesperline > min_bytesperline &&
+ f->fmt.pix.bytesperline <= MAX_BYTESPERLINE)
+ f->fmt.pix.bytesperline =
+ ALIGN(f->fmt.pix.bytesperline, BPL_ALIGNMENT);
+ else
+ f->fmt.pix.bytesperline = min_bytesperline;
+
+ f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ cfe_dbg(cfe, "%s: %p4cc size: %ux%u bpl:%u img_size:%u\n", __func__,
+ &f->fmt.pix.pixelformat, f->fmt.pix.width, f->fmt.pix.height,
+ f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
+}
+
+static void cfe_calc_meta_format_size_bpl(struct cfe_device *cfe,
+ const struct cfe_fmt *fmt,
+ struct v4l2_format *f)
+{
+ v4l_bound_align_image(&f->fmt.meta.width, MIN_META_WIDTH, MAX_WIDTH, 2,
+ &f->fmt.meta.height, MIN_META_HEIGHT, MAX_HEIGHT,
+ 0, 0);
+
+ f->fmt.meta.bytesperline = (f->fmt.meta.width * fmt->depth) >> 3;
+ f->fmt.meta.buffersize = f->fmt.meta.height * f->fmt.pix.bytesperline;
+
+ cfe_dbg(cfe, "%s: %p4cc size: %ux%u bpl:%u buf_size:%u\n", __func__,
+ &f->fmt.meta.dataformat, f->fmt.meta.width, f->fmt.meta.height,
+ f->fmt.meta.bytesperline, f->fmt.meta.buffersize);
+}
+
+static void cfe_schedule_next_csi2_job(struct cfe_device *cfe)
+{
+ struct cfe_buffer *buf;
+ dma_addr_t addr;
+
+ for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) {
+ struct cfe_node *node = &cfe->node[i];
+ unsigned int stride, size;
+
+ if (!check_state(cfe, NODE_STREAMING, i))
+ continue;
+
+ buf = list_first_entry(&node->dma_queue, struct cfe_buffer,
+ list);
+ node->next_frm = buf;
+ list_del(&buf->list);
+
+ trace_cfe_csi2_schedule(node->id, &buf->vb.vb2_buf);
+
+ if (is_meta_node(node)) {
+ size = node->meta_fmt.fmt.meta.buffersize;
+ /* We use CSI2_CH_CTRL_PACK_BYTES, so stride == 0 */
+ stride = 0;
+ } else {
+ size = node->vid_fmt.fmt.pix.sizeimage;
+ stride = node->vid_fmt.fmt.pix.bytesperline;
+ }
+
+ addr = vb2_dma_contig_plane_dma_addr(&buf->vb.vb2_buf, 0);
+ csi2_set_buffer(&cfe->csi2, node->id, addr, stride, size);
+ }
+}
+
+static void cfe_schedule_next_pisp_job(struct cfe_device *cfe)
+{
+ struct vb2_buffer *vb2_bufs[FE_NUM_PADS] = { 0 };
+ struct cfe_config_buffer *config_buf;
+ struct cfe_buffer *buf;
+
+ for (unsigned int i = CSI2_NUM_CHANNELS; i < NUM_NODES; i++) {
+ struct cfe_node *node = &cfe->node[i];
+
+ if (!check_state(cfe, NODE_STREAMING, i))
+ continue;
+
+ buf = list_first_entry(&node->dma_queue, struct cfe_buffer,
+ list);
+
+ trace_cfe_fe_schedule(node->id, &buf->vb.vb2_buf);
+
+ node->next_frm = buf;
+ vb2_bufs[node_desc[i].link_pad] = &buf->vb.vb2_buf;
+ list_del(&buf->list);
+ }
+
+ config_buf = to_cfe_config_buffer(cfe->node[FE_CONFIG].next_frm);
+ pisp_fe_submit_job(&cfe->fe, vb2_bufs, &config_buf->config);
+}
+
+static bool cfe_check_job_ready(struct cfe_device *cfe)
+{
+ for (unsigned int i = 0; i < NUM_NODES; i++) {
+ struct cfe_node *node = &cfe->node[i];
+
+ if (!check_state(cfe, NODE_ENABLED, i))
+ continue;
+
+ if (list_empty(&node->dma_queue))
+ return false;
+ }
+
+ return true;
+}
+
+static void cfe_prepare_next_job(struct cfe_device *cfe)
+{
+ trace_cfe_prepare_next_job(is_fe_enabled(cfe));
+
+ cfe->job_queued = true;
+ cfe_schedule_next_csi2_job(cfe);
+ if (is_fe_enabled(cfe))
+ cfe_schedule_next_pisp_job(cfe);
+
+ /* Flag if another job is ready after this. */
+ cfe->job_ready = cfe_check_job_ready(cfe);
+}
+
+static void cfe_process_buffer_complete(struct cfe_node *node,
+ enum vb2_buffer_state state)
+{
+ trace_cfe_buffer_complete(node->id, &node->cur_frm->vb);
+
+ node->cur_frm->vb.sequence = node->fs_count - 1;
+ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state);
+}
+
+static void cfe_queue_event_sof(struct cfe_node *node)
+{
+ struct v4l2_event event = {
+ .type = V4L2_EVENT_FRAME_SYNC,
+ .u.frame_sync.frame_sequence = node->fs_count - 1,
+ };
+
+ v4l2_event_queue(&node->video_dev, &event);
+}
+
+static void cfe_sof_isr(struct cfe_node *node)
+{
+ struct cfe_device *cfe = node->cfe;
+ bool matching_fs = true;
+
+ trace_cfe_frame_start(node->id, node->fs_count);
+
+ /*
+ * If the sensor is producing unexpected frame event ordering over a
+ * sustained period of time, guard against the possibility of coming
+ * here and orphaning the cur_frm if it's not been dequeued already.
+ * Unfortunately, there is not enough hardware state to tell if this
+ * may have occurred.
+ */
+ if (WARN(node->cur_frm, "%s: [%s] Orphaned frame at seq %u\n",
+ __func__, node_desc[node->id].name, node->fs_count))
+ cfe_process_buffer_complete(node, VB2_BUF_STATE_ERROR);
+
+ node->cur_frm = node->next_frm;
+ node->next_frm = NULL;
+ node->fs_count++;
+
+ node->ts = ktime_get_ns();
+ for (unsigned int i = 0; i < NUM_NODES; i++) {
+ if (!check_state(cfe, NODE_STREAMING, i) || i == node->id)
+ continue;
+ /*
+ * This checks if any other node has seen a FS. If yes, use the
+ * same timestamp, eventually across all node buffers.
+ */
+ if (cfe->node[i].fs_count >= node->fs_count)
+ node->ts = cfe->node[i].ts;
+ /*
+ * This checks if all other node have seen a matching FS. If
+ * yes, we can flag another job to be queued.
+ */
+ if (matching_fs && cfe->node[i].fs_count != node->fs_count)
+ matching_fs = false;
+ }
+
+ if (matching_fs)
+ cfe->job_queued = false;
+
+ if (node->cur_frm)
+ node->cur_frm->vb.vb2_buf.timestamp = node->ts;
+
+ set_state(cfe, FS_INT, node->id);
+ clear_state(cfe, FE_INT, node->id);
+
+ if (is_image_output_node(node))
+ cfe_queue_event_sof(node);
+}
+
+static void cfe_eof_isr(struct cfe_node *node)
+{
+ struct cfe_device *cfe = node->cfe;
+
+ trace_cfe_frame_end(node->id, node->fs_count - 1);
+
+ if (node->cur_frm)
+ cfe_process_buffer_complete(node, VB2_BUF_STATE_DONE);
+
+ node->cur_frm = NULL;
+ set_state(cfe, FE_INT, node->id);
+ clear_state(cfe, FS_INT, node->id);
+}
+
+static irqreturn_t cfe_isr(int irq, void *dev)
+{
+ struct cfe_device *cfe = dev;
+ bool sof[NUM_NODES] = { 0 }, eof[NUM_NODES] = { 0 };
+ u32 sts;
+
+ sts = cfg_reg_read(cfe, MIPICFG_INTS);
+
+ if (sts & MIPICFG_INT_CSI_DMA)
+ csi2_isr(&cfe->csi2, sof, eof);
+
+ if (sts & MIPICFG_INT_PISP_FE)
+ pisp_fe_isr(&cfe->fe, sof + CSI2_NUM_CHANNELS,
+ eof + CSI2_NUM_CHANNELS);
+
+ spin_lock(&cfe->state_lock);
+
+ for (unsigned int i = 0; i < NUM_NODES; i++) {
+ struct cfe_node *node = &cfe->node[i];
+
+ /*
+ * The check_state(NODE_STREAMING) is to ensure we do not loop
+ * over the CSI2_CHx nodes when the FE is active since they
+ * generate interrupts even though the node is not streaming.
+ */
+ if (!check_state(cfe, NODE_STREAMING, i) || !(sof[i] || eof[i]))
+ continue;
+
+ /*
+ * There are 3 cases where we could get FS + FE_ACK at
+ * the same time:
+ * 1) FE of the current frame, and FS of the next frame.
+ * 2) FS + FE of the same frame.
+ * 3) FE of the current frame, and FS + FE of the next
+ * frame. To handle this, see the sof handler below.
+ *
+ * (1) is handled implicitly by the ordering of the FE and FS
+ * handlers below.
+ */
+ if (eof[i]) {
+ /*
+ * The condition below tests for (2). Run the FS handler
+ * first before the FE handler, both for the current
+ * frame.
+ */
+ if (sof[i] && !check_state(cfe, FS_INT, i)) {
+ cfe_sof_isr(node);
+ sof[i] = false;
+ }
+
+ cfe_eof_isr(node);
+ }
+
+ if (sof[i]) {
+ /*
+ * The condition below tests for (3). In such cases, we
+ * come in here with FS flag set in the node state from
+ * the previous frame since it only gets cleared in
+ * cfe_eof_isr(). Handle the FE for the previous
+ * frame first before the FS handler for the current
+ * frame.
+ */
+ if (check_state(cfe, FS_INT, node->id) &&
+ !check_state(cfe, FE_INT, node->id)) {
+ cfe_dbg(cfe, "%s: [%s] Handling missing previous FE interrupt\n",
+ __func__, node_desc[node->id].name);
+ cfe_eof_isr(node);
+ }
+
+ cfe_sof_isr(node);
+ }
+
+ if (!cfe->job_queued && cfe->job_ready)
+ cfe_prepare_next_job(cfe);
+ }
+
+ spin_unlock(&cfe->state_lock);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Stream helpers
+ */
+
+static int cfe_get_vc_dt_fallback(struct cfe_device *cfe, u8 *vc, u8 *dt)
+{
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *fmt;
+ const struct cfe_fmt *cfe_fmt;
+
+ state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd);
+
+ fmt = v4l2_subdev_state_get_format(state, CSI2_PAD_SINK, 0);
+ if (!fmt)
+ return -EINVAL;
+
+ cfe_fmt = find_format_by_code(fmt->code);
+ if (!cfe_fmt)
+ return -EINVAL;
+
+ *vc = 0;
+ *dt = cfe_fmt->csi_dt;
+
+ return 0;
+}
+
+static int cfe_get_vc_dt(struct cfe_device *cfe, unsigned int channel, u8 *vc,
+ u8 *dt)
+{
+ struct v4l2_mbus_frame_desc remote_desc;
+ struct v4l2_subdev_state *state;
+ u32 sink_stream;
+ unsigned int i;
+ int ret;
+
+ state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd);
+
+ ret = v4l2_subdev_routing_find_opposite_end(&state->routing,
+ CSI2_PAD_FIRST_SOURCE + channel, 0, NULL, &sink_stream);
+ if (ret)
+ return ret;
+
+ ret = v4l2_subdev_call(cfe->source_sd, pad, get_frame_desc,
+ cfe->source_pad, &remote_desc);
+ if (ret == -ENOIOCTLCMD) {
+ cfe_dbg(cfe, "source does not support get_frame_desc, use fallback\n");
+ return cfe_get_vc_dt_fallback(cfe, vc, dt);
+ } else if (ret) {
+ cfe_err(cfe, "Failed to get frame descriptor\n");
+ return ret;
+ }
+
+ if (remote_desc.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+ cfe_err(cfe, "Frame descriptor does not describe CSI-2 link");
+ return -EINVAL;
+ }
+
+ for (i = 0; i < remote_desc.num_entries; i++) {
+ if (remote_desc.entry[i].stream == sink_stream)
+ break;
+ }
+
+ if (i == remote_desc.num_entries) {
+ cfe_err(cfe, "Stream %u not found in remote frame desc\n",
+ sink_stream);
+ return -EINVAL;
+ }
+
+ *vc = remote_desc.entry[i].bus.csi2.vc;
+ *dt = remote_desc.entry[i].bus.csi2.dt;
+
+ return 0;
+}
+
+static int cfe_start_channel(struct cfe_node *node)
+{
+ struct cfe_device *cfe = node->cfe;
+ struct v4l2_subdev_state *state;
+ struct v4l2_mbus_framefmt *source_fmt;
+ const struct cfe_fmt *fmt;
+ unsigned long flags;
+ bool start_fe;
+ int ret;
+
+ cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
+
+ start_fe = is_fe_enabled(cfe) &&
+ test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING);
+
+ state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd);
+
+ if (start_fe) {
+ unsigned int width, height;
+ u8 vc, dt;
+
+ cfe_dbg(cfe, "%s: %s using csi2 channel %d\n", __func__,
+ node_desc[FE_OUT0].name, cfe->fe_csi2_channel);
+
+ ret = cfe_get_vc_dt(cfe, cfe->fe_csi2_channel, &vc, &dt);
+ if (ret)
+ return ret;
+
+ source_fmt = v4l2_subdev_state_get_format(state,
+ node_desc[cfe->fe_csi2_channel].link_pad);
+ fmt = find_format_by_code(source_fmt->code);
+
+ width = source_fmt->width;
+ height = source_fmt->height;
+
+ /* Must have a valid CSI2 datatype. */
+ WARN_ON(!fmt->csi_dt);
+
+ /*
+ * Start the associated CSI2 Channel as well.
+ *
+ * Must write to the ADDR register to latch the ctrl values
+ * even if we are connected to the front end. Once running,
+ * this is handled by the CSI2 AUTO_ARM mode.
+ */
+ csi2_start_channel(&cfe->csi2, cfe->fe_csi2_channel,
+ CSI2_MODE_FE_STREAMING,
+ true, false, width, height, vc, dt);
+ csi2_set_buffer(&cfe->csi2, cfe->fe_csi2_channel, 0, 0, -1);
+ pisp_fe_start(&cfe->fe);
+ }
+
+ if (is_csi2_node(node)) {
+ unsigned int width = 0, height = 0;
+ u8 vc, dt;
+
+ ret = cfe_get_vc_dt(cfe, node->id, &vc, &dt);
+ if (ret) {
+ if (start_fe) {
+ csi2_stop_channel(&cfe->csi2,
+ cfe->fe_csi2_channel);
+ pisp_fe_stop(&cfe->fe);
+ }
+
+ return ret;
+ }
+
+ u32 mode = CSI2_MODE_NORMAL;
+
+ source_fmt = v4l2_subdev_state_get_format(state,
+ node_desc[node->id].link_pad);
+ fmt = find_format_by_code(source_fmt->code);
+
+ /* Must have a valid CSI2 datatype. */
+ WARN_ON(!fmt->csi_dt);
+
+ if (is_image_output_node(node)) {
+ u32 pixfmt;
+
+ width = source_fmt->width;
+ height = source_fmt->height;
+
+ pixfmt = node->vid_fmt.fmt.pix.pixelformat;
+
+ if (pixfmt == fmt->remap[CFE_REMAP_16BIT]) {
+ mode = CSI2_MODE_REMAP;
+ } else if (pixfmt == fmt->remap[CFE_REMAP_COMPRESSED]) {
+ mode = CSI2_MODE_COMPRESSED;
+ csi2_set_compression(&cfe->csi2, node->id,
+ CSI2_COMPRESSION_DELTA, 0,
+ 0);
+ }
+ }
+ /* Unconditionally start this CSI2 channel. */
+ csi2_start_channel(&cfe->csi2, node->id,
+ mode,
+ /* Auto arm */
+ false,
+ /* Pack bytes */
+ is_meta_node(node) ? true : false,
+ width, height, vc, dt);
+ }
+
+ spin_lock_irqsave(&cfe->state_lock, flags);
+ if (cfe->job_ready && test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING))
+ cfe_prepare_next_job(cfe);
+ spin_unlock_irqrestore(&cfe->state_lock, flags);
+
+ return 0;
+}
+
+static void cfe_stop_channel(struct cfe_node *node, bool fe_stop)
+{
+ struct cfe_device *cfe = node->cfe;
+
+ cfe_dbg(cfe, "%s: [%s] fe_stop %u\n", __func__,
+ node_desc[node->id].name, fe_stop);
+
+ if (fe_stop) {
+ csi2_stop_channel(&cfe->csi2, cfe->fe_csi2_channel);
+ pisp_fe_stop(&cfe->fe);
+ }
+
+ if (is_csi2_node(node))
+ csi2_stop_channel(&cfe->csi2, node->id);
+}
+
+static void cfe_return_buffers(struct cfe_node *node,
+ enum vb2_buffer_state state)
+{
+ struct cfe_device *cfe = node->cfe;
+ struct cfe_buffer *buf, *tmp;
+ unsigned long flags;
+
+ cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
+
+ spin_lock_irqsave(&cfe->state_lock, flags);
+ list_for_each_entry_safe(buf, tmp, &node->dma_queue, list) {
+ list_del(&buf->list);
+ trace_cfe_return_buffer(node->id, buf->vb.vb2_buf.index, 2);
+ vb2_buffer_done(&buf->vb.vb2_buf, state);
+ }
+
+ if (node->cur_frm) {
+ trace_cfe_return_buffer(node->id,
+ node->cur_frm->vb.vb2_buf.index, 0);
+ vb2_buffer_done(&node->cur_frm->vb.vb2_buf, state);
+ }
+ if (node->next_frm && node->cur_frm != node->next_frm) {
+ trace_cfe_return_buffer(node->id,
+ node->next_frm->vb.vb2_buf.index, 1);
+ vb2_buffer_done(&node->next_frm->vb.vb2_buf, state);
+ }
+
+ node->cur_frm = NULL;
+ node->next_frm = NULL;
+ spin_unlock_irqrestore(&cfe->state_lock, flags);
+}
+
+/*
+ * vb2 ops
+ */
+
+static int cfe_queue_setup(struct vb2_queue *vq, unsigned int *nbuffers,
+ unsigned int *nplanes, unsigned int sizes[],
+ struct device *alloc_devs[])
+{
+ struct cfe_node *node = vb2_get_drv_priv(vq);
+ struct cfe_device *cfe = node->cfe;
+ unsigned int size = is_image_node(node) ?
+ node->vid_fmt.fmt.pix.sizeimage :
+ node->meta_fmt.fmt.meta.buffersize;
+
+ cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name,
+ node->buffer_queue.type);
+
+ if (vq->max_num_buffers + *nbuffers < 3)
+ *nbuffers = 3 - vq->max_num_buffers;
+
+ if (*nplanes) {
+ if (sizes[0] < size) {
+ cfe_err(cfe, "sizes[0] %i < size %u\n", sizes[0], size);
+ return -EINVAL;
+ }
+ size = sizes[0];
+ }
+
+ *nplanes = 1;
+ sizes[0] = size;
+
+ return 0;
+}
+
+static int cfe_buffer_prepare(struct vb2_buffer *vb)
+{
+ struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue);
+ struct cfe_device *cfe = node->cfe;
+ struct cfe_buffer *buf = to_cfe_buffer(vb);
+ unsigned long size;
+
+ trace_cfe_buffer_prepare(node->id, vb);
+
+ size = is_image_node(node) ? node->vid_fmt.fmt.pix.sizeimage :
+ node->meta_fmt.fmt.meta.buffersize;
+ if (vb2_plane_size(vb, 0) < size) {
+ cfe_err(cfe, "data will not fit into plane (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
+ return -EINVAL;
+ }
+
+ vb2_set_plane_payload(&buf->vb.vb2_buf, 0, size);
+
+ if (node->id == FE_CONFIG) {
+ struct cfe_config_buffer *b = to_cfe_config_buffer(buf);
+ void *addr = vb2_plane_vaddr(vb, 0);
+
+ memcpy(&b->config, addr, sizeof(struct pisp_fe_config));
+ return pisp_fe_validate_config(&cfe->fe, &b->config,
+ &cfe->node[FE_OUT0].vid_fmt,
+ &cfe->node[FE_OUT1].vid_fmt);
+ }
+
+ return 0;
+}
+
+static void cfe_buffer_queue(struct vb2_buffer *vb)
+{
+ struct cfe_node *node = vb2_get_drv_priv(vb->vb2_queue);
+ struct cfe_device *cfe = node->cfe;
+ struct cfe_buffer *buf = to_cfe_buffer(vb);
+ unsigned long flags;
+ bool schedule_now;
+
+ spin_lock_irqsave(&cfe->state_lock, flags);
+
+ list_add_tail(&buf->list, &node->dma_queue);
+
+ if (!cfe->job_ready)
+ cfe->job_ready = cfe_check_job_ready(cfe);
+
+ schedule_now = !cfe->job_queued && cfe->job_ready &&
+ test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING);
+
+ trace_cfe_buffer_queue(node->id, vb, schedule_now);
+
+ if (schedule_now)
+ cfe_prepare_next_job(cfe);
+
+ spin_unlock_irqrestore(&cfe->state_lock, flags);
+}
+
+static s64 cfe_get_source_link_freq(struct cfe_device *cfe)
+{
+ struct v4l2_subdev_state *state;
+ s64 link_freq;
+ u32 bpp;
+
+ state = v4l2_subdev_get_locked_active_state(&cfe->csi2.sd);
+
+ /*
+ * v4l2_get_link_freq() uses V4L2_CID_LINK_FREQ first, and falls back
+ * to V4L2_CID_PIXEL_RATE if V4L2_CID_LINK_FREQ is not available.
+ *
+ * With multistream input there is no single pixel rate, and thus we
+ * cannot use V4L2_CID_PIXEL_RATE, so we pass 0 as the bpp which
+ * causes v4l2_get_link_freq() to return an error if it falls back to
+ * V4L2_CID_PIXEL_RATE.
+ */
+
+ if (state->routing.num_routes == 1) {
+ struct v4l2_subdev_route *route = &state->routing.routes[0];
+ struct v4l2_mbus_framefmt *source_fmt;
+ const struct cfe_fmt *fmt;
+
+ source_fmt = v4l2_subdev_state_get_format(state,
+ route->sink_pad,
+ route->sink_stream);
+
+ fmt = find_format_by_code(source_fmt->code);
+ if (!fmt)
+ return -EINVAL;
+
+ bpp = fmt->depth;
+ } else {
+ bpp = 0;
+ }
+
+ link_freq = v4l2_get_link_freq(cfe->source_sd->ctrl_handler, bpp,
+ 2 * cfe->csi2.dphy.active_lanes);
+ if (link_freq < 0)
+ cfe_err(cfe, "failed to get link freq for subdev '%s'\n",
+ cfe->source_sd->name);
+
+ return link_freq;
+}
+
+static int cfe_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct v4l2_mbus_config mbus_config = { 0 };
+ struct cfe_node *node = vb2_get_drv_priv(vq);
+ struct cfe_device *cfe = node->cfe;
+ struct v4l2_subdev_state *state;
+ struct v4l2_subdev_route *route;
+ s64 link_freq;
+ int ret;
+
+ cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
+
+ if (!check_state(cfe, NODE_ENABLED, node->id)) {
+ cfe_err(cfe, "%s node link is not enabled.\n",
+ node_desc[node->id].name);
+ ret = -EINVAL;
+ goto err_streaming;
+ }
+
+ ret = pm_runtime_resume_and_get(&cfe->pdev->dev);
+ if (ret < 0) {
+ cfe_err(cfe, "pm_runtime_resume_and_get failed\n");
+ goto err_streaming;
+ }
+
+ /* When using the Frontend, we must enable the FE_CONFIG node. */
+ if (is_fe_enabled(cfe) &&
+ !check_state(cfe, NODE_ENABLED, cfe->node[FE_CONFIG].id)) {
+ cfe_err(cfe, "FE enabled, but FE_CONFIG node is not\n");
+ ret = -EINVAL;
+ goto err_pm_put;
+ }
+
+ ret = media_pipeline_start(&node->pad, &cfe->pipe);
+ if (ret < 0) {
+ cfe_err(cfe, "Failed to start media pipeline: %d\n", ret);
+ goto err_pm_put;
+ }
+
+ state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd);
+
+ clear_state(cfe, FS_INT | FE_INT, node->id);
+ set_state(cfe, NODE_STREAMING, node->id);
+ node->fs_count = 0;
+
+ ret = cfe_start_channel(node);
+ if (ret)
+ goto err_unlock_state;
+
+ if (!test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING)) {
+ cfe_dbg(cfe, "Streaming on hold, as all nodes are not set to streaming yet\n");
+ v4l2_subdev_unlock_state(state);
+ return 0;
+ }
+
+ cfg_reg_write(cfe, MIPICFG_CFG, MIPICFG_CFG_SEL_CSI);
+ cfg_reg_write(cfe, MIPICFG_INTE,
+ MIPICFG_INT_CSI_DMA | MIPICFG_INT_PISP_FE);
+
+ ret = v4l2_subdev_call(cfe->source_sd, pad, get_mbus_config, 0,
+ &mbus_config);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ cfe_err(cfe, "g_mbus_config failed\n");
+ goto err_clear_inte;
+ }
+
+ cfe->csi2.dphy.active_lanes = mbus_config.bus.mipi_csi2.num_data_lanes;
+ if (!cfe->csi2.dphy.active_lanes)
+ cfe->csi2.dphy.active_lanes = cfe->csi2.dphy.max_lanes;
+ if (cfe->csi2.dphy.active_lanes > cfe->csi2.dphy.max_lanes) {
+ cfe_err(cfe, "Device has requested %u data lanes, which is >%u configured in DT\n",
+ cfe->csi2.dphy.active_lanes, cfe->csi2.dphy.max_lanes);
+ ret = -EINVAL;
+ goto err_clear_inte;
+ }
+
+ link_freq = cfe_get_source_link_freq(cfe);
+ if (link_freq < 0)
+ goto err_clear_inte;
+
+ cfe->csi2.dphy.dphy_rate = div_s64(link_freq * 2, 1000000);
+ csi2_open_rx(&cfe->csi2);
+
+ cfe->streams_mask = 0;
+
+ for_each_active_route(&state->routing, route)
+ cfe->streams_mask |= BIT_ULL(route->sink_stream);
+
+ ret = v4l2_subdev_enable_streams(cfe->source_sd, cfe->source_pad,
+ cfe->streams_mask);
+ if (ret) {
+ cfe_err(cfe, "stream on failed in subdev\n");
+ goto err_disable_cfe;
+ }
+
+ cfe_dbg(cfe, "Streaming enabled\n");
+
+ v4l2_subdev_unlock_state(state);
+
+ return 0;
+
+err_disable_cfe:
+ csi2_close_rx(&cfe->csi2);
+err_clear_inte:
+ cfg_reg_write(cfe, MIPICFG_INTE, 0);
+
+ cfe_stop_channel(node,
+ is_fe_enabled(cfe) && test_all_nodes(cfe, NODE_ENABLED,
+ NODE_STREAMING));
+err_unlock_state:
+ v4l2_subdev_unlock_state(state);
+ media_pipeline_stop(&node->pad);
+err_pm_put:
+ pm_runtime_put(&cfe->pdev->dev);
+err_streaming:
+ cfe_return_buffers(node, VB2_BUF_STATE_QUEUED);
+ clear_state(cfe, NODE_STREAMING, node->id);
+
+ return ret;
+}
+
+static void cfe_stop_streaming(struct vb2_queue *vq)
+{
+ struct cfe_node *node = vb2_get_drv_priv(vq);
+ struct cfe_device *cfe = node->cfe;
+ unsigned long flags;
+ bool fe_stop;
+
+ cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
+
+ spin_lock_irqsave(&cfe->state_lock, flags);
+ fe_stop = is_fe_enabled(cfe) &&
+ test_all_nodes(cfe, NODE_ENABLED, NODE_STREAMING);
+
+ cfe->job_ready = false;
+ clear_state(cfe, NODE_STREAMING, node->id);
+ spin_unlock_irqrestore(&cfe->state_lock, flags);
+
+ cfe_stop_channel(node, fe_stop);
+
+ if (!test_any_node(cfe, NODE_STREAMING)) {
+ struct v4l2_subdev_state *state;
+ int ret;
+
+ state = v4l2_subdev_lock_and_get_active_state(&cfe->csi2.sd);
+
+ ret = v4l2_subdev_disable_streams(cfe->source_sd,
+ cfe->source_pad,
+ cfe->streams_mask);
+ if (ret)
+ cfe_err(cfe, "stream disable failed in subdev\n");
+
+ v4l2_subdev_unlock_state(state);
+
+ csi2_close_rx(&cfe->csi2);
+
+ cfg_reg_write(cfe, MIPICFG_INTE, 0);
+
+ cfe_dbg(cfe, "%s: Streaming disabled\n", __func__);
+ }
+
+ media_pipeline_stop(&node->pad);
+
+ /* Clear all queued buffers for the node */
+ cfe_return_buffers(node, VB2_BUF_STATE_ERROR);
+
+ pm_runtime_put(&cfe->pdev->dev);
+}
+
+static const struct vb2_ops cfe_video_qops = {
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .queue_setup = cfe_queue_setup,
+ .buf_prepare = cfe_buffer_prepare,
+ .buf_queue = cfe_buffer_queue,
+ .start_streaming = cfe_start_streaming,
+ .stop_streaming = cfe_stop_streaming,
+};
+
+/*
+ * v4l2 ioctl ops
+ */
+
+static int cfe_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strscpy(cap->driver, CFE_MODULE_NAME, sizeof(cap->driver));
+ strscpy(cap->card, CFE_MODULE_NAME, sizeof(cap->card));
+
+ cap->capabilities |= V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_META_CAPTURE |
+ V4L2_CAP_META_OUTPUT;
+
+ return 0;
+}
+
+static int cfe_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct cfe_node *node = video_drvdata(file);
+ struct cfe_device *cfe = node->cfe;
+ unsigned int i, j;
+
+ if (!node_supports_image_output(node))
+ return -EINVAL;
+
+ cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
+
+ for (i = 0, j = 0; i < ARRAY_SIZE(formats); i++) {
+ if (f->mbus_code && formats[i].code != f->mbus_code)
+ continue;
+
+ if (formats[i].flags & CFE_FORMAT_FLAG_META_OUT ||
+ formats[i].flags & CFE_FORMAT_FLAG_META_CAP)
+ continue;
+
+ if (is_fe_node(node) &&
+ !(formats[i].flags & CFE_FORMAT_FLAG_FE_OUT))
+ continue;
+
+ if (j == f->index) {
+ f->pixelformat = formats[i].fourcc;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ return 0;
+ }
+ j++;
+ }
+
+ return -EINVAL;
+}
+
+static int cfe_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct cfe_node *node = video_drvdata(file);
+
+ if (!node_supports_image(node))
+ return -EINVAL;
+
+ *f = node->vid_fmt;
+
+ return 0;
+}
+
+static int cfe_validate_fmt_vid_cap(struct cfe_node *node,
+ struct v4l2_format *f)
+{
+ struct cfe_device *cfe = node->cfe;
+ const struct cfe_fmt *fmt;
+
+ cfe_dbg(cfe, "%s: [%s] %ux%u, V4L2 pix %p4cc\n", __func__,
+ node_desc[node->id].name, f->fmt.pix.width, f->fmt.pix.height,
+ &f->fmt.pix.pixelformat);
+
+ if (!node_supports_image_output(node))
+ return -EINVAL;
+
+ /*
+ * Default to a format that works for both CSI2 and FE.
+ */
+ fmt = find_format_by_pix(f->fmt.pix.pixelformat);
+ if (!fmt)
+ fmt = find_format_by_code(MEDIA_BUS_FMT_SBGGR10_1X10);
+
+ f->fmt.pix.pixelformat = fmt->fourcc;
+
+ if (is_fe_node(node) && fmt->remap[CFE_REMAP_16BIT]) {
+ f->fmt.pix.pixelformat = fmt->remap[CFE_REMAP_16BIT];
+ fmt = find_format_by_pix(f->fmt.pix.pixelformat);
+ }
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+
+ cfe_calc_vid_format_size_bpl(cfe, fmt, f);
+
+ return 0;
+}
+
+static int cfe_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cfe_node *node = video_drvdata(file);
+ struct cfe_device *cfe = node->cfe;
+ struct vb2_queue *q = &node->buffer_queue;
+ int ret;
+
+ if (vb2_is_busy(q))
+ return -EBUSY;
+
+ ret = cfe_validate_fmt_vid_cap(node, f);
+ if (ret)
+ return ret;
+
+ node->vid_fmt = *f;
+
+ cfe_dbg(cfe, "%s: Set %ux%u, V4L2 pix %p4cc\n", __func__,
+ node->vid_fmt.fmt.pix.width, node->vid_fmt.fmt.pix.height,
+ &node->vid_fmt.fmt.pix.pixelformat);
+
+ return 0;
+}
+
+static int cfe_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cfe_node *node = video_drvdata(file);
+ struct cfe_device *cfe = node->cfe;
+
+ cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
+
+ return cfe_validate_fmt_vid_cap(node, f);
+}
+
+static int cfe_enum_fmt_meta(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct cfe_node *node = video_drvdata(file);
+ struct cfe_device *cfe = node->cfe;
+
+ cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
+
+ if (!node_supports_meta(node))
+ return -EINVAL;
+
+ switch (node->id) {
+ case CSI2_CH0...CSI2_CH3:
+ f->flags = V4L2_FMT_FLAG_META_LINE_BASED;
+
+ switch (f->index) {
+ case 0:
+ f->pixelformat = V4L2_META_FMT_GENERIC_8;
+ return 0;
+ case 1:
+ f->pixelformat = V4L2_META_FMT_GENERIC_CSI2_10;
+ return 0;
+ case 2:
+ f->pixelformat = V4L2_META_FMT_GENERIC_CSI2_12;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+ default:
+ break;
+ }
+
+ if (f->index != 0)
+ return -EINVAL;
+
+ switch (node->id) {
+ case FE_STATS:
+ f->pixelformat = V4L2_META_FMT_RPI_FE_STATS;
+ return 0;
+ case FE_CONFIG:
+ f->pixelformat = V4L2_META_FMT_RPI_FE_CFG;
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cfe_validate_fmt_meta(struct cfe_node *node, struct v4l2_format *f)
+{
+ struct cfe_device *cfe = node->cfe;
+ const struct cfe_fmt *fmt;
+
+ switch (node->id) {
+ case CSI2_CH0...CSI2_CH3:
+ cfe_dbg(cfe, "%s: [%s] %ux%u, V4L2 meta %p4cc\n", __func__,
+ node_desc[node->id].name, f->fmt.meta.width,
+ f->fmt.meta.height, &f->fmt.meta.dataformat);
+ break;
+ case FE_STATS:
+ case FE_CONFIG:
+ cfe_dbg(cfe, "%s: [%s] %u bytes, V4L2 meta %p4cc\n", __func__,
+ node_desc[node->id].name, f->fmt.meta.buffersize,
+ &f->fmt.meta.dataformat);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (!node_supports_meta(node))
+ return -EINVAL;
+
+ switch (node->id) {
+ case CSI2_CH0...CSI2_CH3:
+ fmt = find_format_by_pix(f->fmt.meta.dataformat);
+ if (!fmt || !(fmt->flags & CFE_FORMAT_FLAG_META_CAP))
+ fmt = find_format_by_pix(V4L2_META_FMT_GENERIC_CSI2_10);
+
+ f->fmt.meta.dataformat = fmt->fourcc;
+
+ cfe_calc_meta_format_size_bpl(cfe, fmt, f);
+
+ return 0;
+ case FE_STATS:
+ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_STATS;
+ f->fmt.meta.buffersize = sizeof(struct pisp_statistics);
+ return 0;
+ case FE_CONFIG:
+ f->fmt.meta.dataformat = V4L2_META_FMT_RPI_FE_CFG;
+ f->fmt.meta.buffersize = sizeof(struct pisp_fe_config);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static int cfe_g_fmt_meta(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct cfe_node *node = video_drvdata(file);
+ struct cfe_device *cfe = node->cfe;
+
+ cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
+
+ if (!node_supports_meta(node))
+ return -EINVAL;
+
+ *f = node->meta_fmt;
+
+ return 0;
+}
+
+static int cfe_s_fmt_meta(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct cfe_node *node = video_drvdata(file);
+ struct cfe_device *cfe = node->cfe;
+ struct vb2_queue *q = &node->buffer_queue;
+ int ret;
+
+ cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
+
+ if (vb2_is_busy(q))
+ return -EBUSY;
+
+ if (!node_supports_meta(node))
+ return -EINVAL;
+
+ ret = cfe_validate_fmt_meta(node, f);
+ if (ret)
+ return ret;
+
+ node->meta_fmt = *f;
+
+ cfe_dbg(cfe, "%s: Set %p4cc\n", __func__,
+ &node->meta_fmt.fmt.meta.dataformat);
+
+ return 0;
+}
+
+static int cfe_try_fmt_meta(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cfe_node *node = video_drvdata(file);
+ struct cfe_device *cfe = node->cfe;
+
+ cfe_dbg(cfe, "%s: [%s]\n", __func__, node_desc[node->id].name);
+ return cfe_validate_fmt_meta(node, f);
+}
+
+static int cfe_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct cfe_node *node = video_drvdata(file);
+ struct cfe_device *cfe = node->cfe;
+ const struct cfe_fmt *fmt;
+
+ cfe_dbg(cfe, "%s [%s]\n", __func__, node_desc[node->id].name);
+
+ if (fsize->index > 0)
+ return -EINVAL;
+
+ /* check for valid format */
+ fmt = find_format_by_pix(fsize->pixel_format);
+ if (!fmt) {
+ cfe_dbg(cfe, "Invalid pixel code: %x\n", fsize->pixel_format);
+ return -EINVAL;
+ }
+
+ /* TODO: Do we have limits on the step_width? */
+
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise.min_width = MIN_WIDTH;
+ fsize->stepwise.max_width = MAX_WIDTH;
+ fsize->stepwise.step_width = 2;
+ fsize->stepwise.min_height = MIN_HEIGHT;
+ fsize->stepwise.max_height = MAX_HEIGHT;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
+static int cfe_vb2_ioctl_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct cfe_node *node = video_get_drvdata(vdev);
+ struct cfe_device *cfe = node->cfe;
+ int ret;
+
+ cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name,
+ p->type);
+
+ if (p->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ p->type != V4L2_BUF_TYPE_META_CAPTURE &&
+ p->type != V4L2_BUF_TYPE_META_OUTPUT)
+ return -EINVAL;
+
+ ret = vb2_queue_change_type(vdev->queue, p->type);
+ if (ret)
+ return ret;
+
+ return vb2_ioctl_reqbufs(file, priv, p);
+}
+
+static int cfe_vb2_ioctl_create_bufs(struct file *file, void *priv,
+ struct v4l2_create_buffers *p)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct cfe_node *node = video_get_drvdata(vdev);
+ struct cfe_device *cfe = node->cfe;
+ int ret;
+
+ cfe_dbg(cfe, "%s: [%s] type:%u\n", __func__, node_desc[node->id].name,
+ p->format.type);
+
+ if (p->format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ p->format.type != V4L2_BUF_TYPE_META_CAPTURE &&
+ p->format.type != V4L2_BUF_TYPE_META_OUTPUT)
+ return -EINVAL;
+
+ ret = vb2_queue_change_type(vdev->queue, p->format.type);
+ if (ret)
+ return ret;
+
+ return vb2_ioctl_create_bufs(file, priv, p);
+}
+
+static int cfe_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ struct cfe_node *node = video_get_drvdata(fh->vdev);
+
+ switch (sub->type) {
+ case V4L2_EVENT_FRAME_SYNC:
+ if (!node_supports_image_output(node))
+ break;
+
+ return v4l2_event_subscribe(fh, sub, 2, NULL);
+ case V4L2_EVENT_SOURCE_CHANGE:
+ if (!node_supports_image_output(node) &&
+ !node_supports_meta_output(node))
+ break;
+
+ return v4l2_event_subscribe(fh, sub, 4, NULL);
+ }
+
+ return v4l2_ctrl_subscribe_event(fh, sub);
+}
+
+static const struct v4l2_ioctl_ops cfe_ioctl_ops = {
+ .vidioc_querycap = cfe_querycap,
+ .vidioc_enum_fmt_vid_cap = cfe_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = cfe_g_fmt,
+ .vidioc_s_fmt_vid_cap = cfe_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = cfe_try_fmt_vid_cap,
+
+ .vidioc_enum_fmt_meta_cap = cfe_enum_fmt_meta,
+ .vidioc_g_fmt_meta_cap = cfe_g_fmt_meta,
+ .vidioc_s_fmt_meta_cap = cfe_s_fmt_meta,
+ .vidioc_try_fmt_meta_cap = cfe_try_fmt_meta,
+
+ .vidioc_enum_fmt_meta_out = cfe_enum_fmt_meta,
+ .vidioc_g_fmt_meta_out = cfe_g_fmt_meta,
+ .vidioc_s_fmt_meta_out = cfe_s_fmt_meta,
+ .vidioc_try_fmt_meta_out = cfe_try_fmt_meta,
+
+ .vidioc_enum_framesizes = cfe_enum_framesizes,
+
+ .vidioc_reqbufs = cfe_vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = cfe_vb2_ioctl_create_bufs,
+ .vidioc_prepare_buf = vb2_ioctl_prepare_buf,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+
+ .vidioc_subscribe_event = cfe_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static void cfe_notify(struct v4l2_subdev *sd, unsigned int notification,
+ void *arg)
+{
+ struct cfe_device *cfe = to_cfe_device(sd->v4l2_dev);
+
+ switch (notification) {
+ case V4L2_DEVICE_NOTIFY_EVENT:
+ for (unsigned int i = 0; i < NUM_NODES; i++) {
+ struct cfe_node *node = &cfe->node[i];
+
+ if (check_state(cfe, NODE_REGISTERED, i))
+ continue;
+
+ v4l2_event_queue(&node->video_dev, arg);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+/* cfe capture driver file operations */
+static const struct v4l2_file_operations cfe_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 cfe_video_link_validate(struct media_link *link)
+{
+ struct video_device *vd = container_of(link->sink->entity,
+ struct video_device, entity);
+ struct cfe_node *node = container_of(vd, struct cfe_node, video_dev);
+ struct cfe_device *cfe = node->cfe;
+ struct v4l2_mbus_framefmt *source_fmt;
+ struct v4l2_subdev_state *state;
+ struct v4l2_subdev *source_sd;
+ int ret = 0;
+
+ cfe_dbg(cfe, "%s: [%s] link \"%s\":%u -> \"%s\":%u\n", __func__,
+ node_desc[node->id].name,
+ link->source->entity->name, link->source->index,
+ link->sink->entity->name, link->sink->index);
+
+ if (!media_entity_remote_source_pad_unique(link->sink->entity)) {
+ cfe_err(cfe, "video node %s pad not connected\n", vd->name);
+ return -ENOTCONN;
+ }
+
+ source_sd = media_entity_to_v4l2_subdev(link->source->entity);
+
+ state = v4l2_subdev_lock_and_get_active_state(source_sd);
+
+ source_fmt = v4l2_subdev_state_get_format(state, link->source->index);
+ if (!source_fmt) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (is_image_output_node(node)) {
+ struct v4l2_pix_format *pix_fmt = &node->vid_fmt.fmt.pix;
+ const struct cfe_fmt *fmt;
+
+ if (source_fmt->width != pix_fmt->width ||
+ source_fmt->height != pix_fmt->height) {
+ cfe_err(cfe, "Wrong width or height %ux%u (remote pad set to %ux%u)\n",
+ pix_fmt->width, pix_fmt->height,
+ source_fmt->width, source_fmt->height);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ fmt = find_format_by_code_and_fourcc(source_fmt->code,
+ pix_fmt->pixelformat);
+ if (!fmt) {
+ cfe_err(cfe, "Format mismatch!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ } else if (is_csi2_node(node) && is_meta_output_node(node)) {
+ struct v4l2_meta_format *meta_fmt = &node->meta_fmt.fmt.meta;
+ const struct cfe_fmt *fmt;
+
+ if (source_fmt->width != meta_fmt->width ||
+ source_fmt->height != meta_fmt->height) {
+ cfe_err(cfe, "Wrong width or height %ux%u (remote pad set to %ux%u)\n",
+ meta_fmt->width, meta_fmt->height,
+ source_fmt->width, source_fmt->height);
+ ret = -EINVAL;
+ goto out;
+ }
+
+ fmt = find_format_by_code_and_fourcc(source_fmt->code,
+ meta_fmt->dataformat);
+ if (!fmt) {
+ cfe_err(cfe, "Format mismatch!\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+out:
+ v4l2_subdev_unlock_state(state);
+
+ return ret;
+}
+
+static const struct media_entity_operations cfe_media_entity_ops = {
+ .link_validate = cfe_video_link_validate,
+};
+
+static int cfe_video_link_notify(struct media_link *link, u32 flags,
+ unsigned int notification)
+{
+ struct media_device *mdev = link->graph_obj.mdev;
+ struct cfe_device *cfe = container_of(mdev, struct cfe_device, mdev);
+ struct media_entity *fe = &cfe->fe.sd.entity;
+ struct media_entity *csi2 = &cfe->csi2.sd.entity;
+ unsigned long lock_flags;
+
+ if (notification != MEDIA_DEV_NOTIFY_POST_LINK_CH)
+ return 0;
+
+ cfe_dbg(cfe, "%s: %s[%u] -> %s[%u] 0x%x", __func__,
+ link->source->entity->name, link->source->index,
+ link->sink->entity->name, link->sink->index, flags);
+
+ spin_lock_irqsave(&cfe->state_lock, lock_flags);
+
+ for (unsigned int i = 0; i < NUM_NODES; i++) {
+ if (link->sink->entity != &cfe->node[i].video_dev.entity &&
+ link->source->entity != &cfe->node[i].video_dev.entity)
+ continue;
+
+ if (link->flags & MEDIA_LNK_FL_ENABLED)
+ set_state(cfe, NODE_ENABLED, i);
+ else
+ clear_state(cfe, NODE_ENABLED, i);
+
+ break;
+ }
+
+ spin_unlock_irqrestore(&cfe->state_lock, lock_flags);
+
+ if (link->source->entity != csi2)
+ return 0;
+ if (link->sink->entity != fe)
+ return 0;
+ if (link->sink->index != 0)
+ return 0;
+
+ cfe->fe_csi2_channel = -1;
+ if (link->flags & MEDIA_LNK_FL_ENABLED) {
+ if (link->source->index == node_desc[CSI2_CH0].link_pad)
+ cfe->fe_csi2_channel = CSI2_CH0;
+ else if (link->source->index == node_desc[CSI2_CH1].link_pad)
+ cfe->fe_csi2_channel = CSI2_CH1;
+ else if (link->source->index == node_desc[CSI2_CH2].link_pad)
+ cfe->fe_csi2_channel = CSI2_CH2;
+ else if (link->source->index == node_desc[CSI2_CH3].link_pad)
+ cfe->fe_csi2_channel = CSI2_CH3;
+ }
+
+ if (is_fe_enabled(cfe))
+ cfe_dbg(cfe, "%s: Found CSI2:%d -> FE:0 link\n", __func__,
+ cfe->fe_csi2_channel);
+ else
+ cfe_dbg(cfe, "%s: Unable to find CSI2:x -> FE:0 link\n",
+ __func__);
+
+ return 0;
+}
+
+static const struct media_device_ops cfe_media_device_ops = {
+ .link_notify = cfe_video_link_notify,
+};
+
+static void cfe_release(struct kref *kref)
+{
+ struct cfe_device *cfe = container_of(kref, struct cfe_device, kref);
+
+ media_device_cleanup(&cfe->mdev);
+
+ kfree(cfe);
+}
+
+static void cfe_put(struct cfe_device *cfe)
+{
+ kref_put(&cfe->kref, cfe_release);
+}
+
+static void cfe_get(struct cfe_device *cfe)
+{
+ kref_get(&cfe->kref);
+}
+
+static void cfe_node_release(struct video_device *vdev)
+{
+ struct cfe_node *node = video_get_drvdata(vdev);
+
+ cfe_put(node->cfe);
+}
+
+static int cfe_register_node(struct cfe_device *cfe, int id)
+{
+ struct video_device *vdev;
+ const struct cfe_fmt *fmt;
+ struct vb2_queue *q;
+ struct cfe_node *node = &cfe->node[id];
+ int ret;
+
+ node->cfe = cfe;
+ node->id = id;
+
+ if (node_supports_image(node)) {
+ if (node_supports_image_output(node))
+ node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ else
+ node->vid_fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+
+ fmt = find_format_by_code(cfe_default_format.code);
+ if (!fmt) {
+ cfe_err(cfe, "Failed to find format code\n");
+ return -EINVAL;
+ }
+
+ node->vid_fmt.fmt.pix.pixelformat = fmt->fourcc;
+ v4l2_fill_pix_format(&node->vid_fmt.fmt.pix,
+ &cfe_default_format);
+
+ ret = cfe_validate_fmt_vid_cap(node, &node->vid_fmt);
+ if (ret)
+ return ret;
+ }
+
+ if (node_supports_meta(node)) {
+ if (node_supports_meta_output(node))
+ node->meta_fmt.type = V4L2_BUF_TYPE_META_CAPTURE;
+ else
+ node->meta_fmt.type = V4L2_BUF_TYPE_META_OUTPUT;
+
+ ret = cfe_validate_fmt_meta(node, &node->meta_fmt);
+ if (ret)
+ return ret;
+ }
+
+ mutex_init(&node->lock);
+
+ q = &node->buffer_queue;
+ q->type = node_supports_image(node) ? node->vid_fmt.type :
+ node->meta_fmt.type;
+ q->io_modes = VB2_MMAP | VB2_DMABUF;
+ q->drv_priv = node;
+ q->ops = &cfe_video_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = id == FE_CONFIG ? sizeof(struct cfe_config_buffer)
+ : sizeof(struct cfe_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &node->lock;
+ q->min_queued_buffers = 1;
+ q->dev = &cfe->pdev->dev;
+
+ ret = vb2_queue_init(q);
+ if (ret) {
+ cfe_err(cfe, "vb2_queue_init() failed\n");
+ return ret;
+ }
+
+ INIT_LIST_HEAD(&node->dma_queue);
+
+ vdev = &node->video_dev;
+ vdev->release = cfe_node_release;
+ vdev->fops = &cfe_fops;
+ vdev->ioctl_ops = &cfe_ioctl_ops;
+ vdev->entity.ops = &cfe_media_entity_ops;
+ vdev->v4l2_dev = &cfe->v4l2_dev;
+ vdev->vfl_dir = (node_supports_image_output(node) ||
+ node_supports_meta_output(node)) ?
+ VFL_DIR_RX :
+ VFL_DIR_TX;
+ vdev->queue = q;
+ vdev->lock = &node->lock;
+ vdev->device_caps = node_desc[id].caps;
+ vdev->device_caps |= V4L2_CAP_STREAMING | V4L2_CAP_IO_MC;
+
+ /* Define the device names */
+ snprintf(vdev->name, sizeof(vdev->name), "%s-%s", CFE_MODULE_NAME,
+ node_desc[id].name);
+
+ video_set_drvdata(vdev, node);
+ node->pad.flags = node_desc[id].pad_flags;
+ media_entity_pads_init(&vdev->entity, 1, &node->pad);
+
+ if (!node_supports_image(node)) {
+ v4l2_disable_ioctl(&node->video_dev,
+ VIDIOC_ENUM_FRAMEINTERVALS);
+ v4l2_disable_ioctl(&node->video_dev, VIDIOC_ENUM_FRAMESIZES);
+ }
+
+ ret = video_register_device(vdev, VFL_TYPE_VIDEO, -1);
+ if (ret) {
+ cfe_err(cfe, "Unable to register video device %s\n",
+ vdev->name);
+ return ret;
+ }
+
+ cfe_info(cfe, "Registered [%s] node id %d as /dev/video%u\n",
+ vdev->name, id, vdev->num);
+
+ /*
+ * Acquire a reference to cfe, which will be released when the video
+ * device will be unregistered and userspace will have closed all open
+ * file handles.
+ */
+ cfe_get(cfe);
+ set_state(cfe, NODE_REGISTERED, id);
+
+ return 0;
+}
+
+static void cfe_unregister_nodes(struct cfe_device *cfe)
+{
+ for (unsigned int i = 0; i < NUM_NODES; i++) {
+ struct cfe_node *node = &cfe->node[i];
+
+ if (check_state(cfe, NODE_REGISTERED, i)) {
+ clear_state(cfe, NODE_REGISTERED, i);
+ video_unregister_device(&node->video_dev);
+ }
+ }
+}
+
+static int cfe_link_node_pads(struct cfe_device *cfe)
+{
+ struct media_pad *remote_pad;
+ int ret;
+
+ /* Source -> CSI2 */
+
+ ret = v4l2_create_fwnode_links_to_pad(cfe->source_sd,
+ &cfe->csi2.pad[CSI2_PAD_SINK],
+ MEDIA_LNK_FL_IMMUTABLE | MEDIA_LNK_FL_ENABLED);
+
+ if (ret) {
+ cfe_err(cfe, "Failed to create links to the source: %d\n", ret);
+ return ret;
+ }
+
+ remote_pad = media_pad_remote_pad_unique(&cfe->csi2.pad[CSI2_PAD_SINK]);
+ if (IS_ERR(remote_pad)) {
+ ret = PTR_ERR(remote_pad);
+ cfe_err(cfe, "Failed to get unique remote source pad: %d\n",
+ ret);
+ return ret;
+ }
+
+ cfe->source_pad = remote_pad->index;
+
+ for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) {
+ struct cfe_node *node = &cfe->node[i];
+
+ if (!check_state(cfe, NODE_REGISTERED, i))
+ continue;
+
+ /* CSI2 channel # -> /dev/video# */
+ ret = media_create_pad_link(&cfe->csi2.sd.entity,
+ node_desc[i].link_pad,
+ &node->video_dev.entity, 0, 0);
+ if (ret)
+ return ret;
+
+ if (node_supports_image(node)) {
+ /* CSI2 channel # -> FE Input */
+ ret = media_create_pad_link(&cfe->csi2.sd.entity,
+ node_desc[i].link_pad,
+ &cfe->fe.sd.entity,
+ FE_STREAM_PAD, 0);
+ if (ret)
+ return ret;
+ }
+ }
+
+ for (unsigned int i = CSI2_NUM_CHANNELS; i < NUM_NODES; i++) {
+ struct cfe_node *node = &cfe->node[i];
+ struct media_entity *src, *dst;
+ unsigned int src_pad, dst_pad;
+
+ if (node_desc[i].pad_flags & MEDIA_PAD_FL_SINK) {
+ /* FE -> /dev/video# */
+ src = &cfe->fe.sd.entity;
+ src_pad = node_desc[i].link_pad;
+ dst = &node->video_dev.entity;
+ dst_pad = 0;
+ } else {
+ /* /dev/video# -> FE */
+ dst = &cfe->fe.sd.entity;
+ dst_pad = node_desc[i].link_pad;
+ src = &node->video_dev.entity;
+ src_pad = 0;
+ }
+
+ ret = media_create_pad_link(src, src_pad, dst, dst_pad, 0);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cfe_probe_complete(struct cfe_device *cfe)
+{
+ int ret;
+
+ cfe->v4l2_dev.notify = cfe_notify;
+
+ for (unsigned int i = 0; i < NUM_NODES; i++) {
+ ret = cfe_register_node(cfe, i);
+ if (ret) {
+ cfe_err(cfe, "Unable to register video node %u.\n", i);
+ goto unregister;
+ }
+ }
+
+ ret = cfe_link_node_pads(cfe);
+ if (ret) {
+ cfe_err(cfe, "Unable to link node pads.\n");
+ goto unregister;
+ }
+
+ ret = v4l2_device_register_subdev_nodes(&cfe->v4l2_dev);
+ if (ret) {
+ cfe_err(cfe, "Unable to register subdev nodes.\n");
+ goto unregister;
+ }
+
+ return 0;
+
+unregister:
+ cfe_unregister_nodes(cfe);
+ return ret;
+}
+
+static int cfe_async_bound(struct v4l2_async_notifier *notifier,
+ struct v4l2_subdev *subdev,
+ struct v4l2_async_connection *asd)
+{
+ struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev);
+
+ if (cfe->source_sd) {
+ cfe_err(cfe, "Rejecting subdev %s (Already set!!)",
+ subdev->name);
+ return 0;
+ }
+
+ cfe->source_sd = subdev;
+
+ cfe_dbg(cfe, "Using source %s for capture\n", subdev->name);
+
+ return 0;
+}
+
+static int cfe_async_complete(struct v4l2_async_notifier *notifier)
+{
+ struct cfe_device *cfe = to_cfe_device(notifier->v4l2_dev);
+
+ return cfe_probe_complete(cfe);
+}
+
+static const struct v4l2_async_notifier_operations cfe_async_ops = {
+ .bound = cfe_async_bound,
+ .complete = cfe_async_complete,
+};
+
+static int cfe_register_async_nf(struct cfe_device *cfe)
+{
+ struct platform_device *pdev = cfe->pdev;
+ struct v4l2_fwnode_endpoint ep = { .bus_type = V4L2_MBUS_CSI2_DPHY };
+ struct fwnode_handle *local_ep_fwnode;
+ struct v4l2_async_connection *asd;
+ int ret;
+
+ local_ep_fwnode = fwnode_graph_get_endpoint_by_id(pdev->dev.fwnode, 0,
+ 0, 0);
+ if (!local_ep_fwnode) {
+ cfe_err(cfe, "Failed to find local endpoint fwnode\n");
+ return -ENODEV;
+ }
+
+ /* Parse the local endpoint and validate its configuration. */
+ ret = v4l2_fwnode_endpoint_parse(local_ep_fwnode, &ep);
+ if (ret) {
+ cfe_err(cfe, "Failed to find remote endpoint fwnode\n");
+ goto err_put_local_fwnode;
+ }
+
+ for (unsigned int lane = 0; lane < ep.bus.mipi_csi2.num_data_lanes;
+ lane++) {
+ if (ep.bus.mipi_csi2.data_lanes[lane] != lane + 1) {
+ cfe_err(cfe, "Data lanes reordering not supported\n");
+ ret = -EINVAL;
+ goto err_put_local_fwnode;
+ }
+ }
+
+ cfe->csi2.dphy.max_lanes = ep.bus.mipi_csi2.num_data_lanes;
+ cfe->csi2.bus_flags = ep.bus.mipi_csi2.flags;
+
+ /* Initialize and register the async notifier. */
+ v4l2_async_nf_init(&cfe->notifier, &cfe->v4l2_dev);
+ cfe->notifier.ops = &cfe_async_ops;
+
+ asd = v4l2_async_nf_add_fwnode_remote(&cfe->notifier, local_ep_fwnode,
+ struct v4l2_async_connection);
+ if (IS_ERR(asd)) {
+ ret = PTR_ERR(asd);
+ cfe_err(cfe, "Error adding subdevice: %d\n", ret);
+ goto err_put_local_fwnode;
+ }
+
+ ret = v4l2_async_nf_register(&cfe->notifier);
+ if (ret) {
+ cfe_err(cfe, "Error registering async notifier: %d\n", ret);
+ goto err_nf_cleanup;
+ }
+
+ fwnode_handle_put(local_ep_fwnode);
+
+ return 0;
+
+err_nf_cleanup:
+ v4l2_async_nf_cleanup(&cfe->notifier);
+err_put_local_fwnode:
+ fwnode_handle_put(local_ep_fwnode);
+
+ return ret;
+}
+
+static int cfe_probe(struct platform_device *pdev)
+{
+ struct cfe_device *cfe;
+ char debugfs_name[32];
+ int ret;
+
+ cfe = kzalloc(sizeof(*cfe), GFP_KERNEL);
+ if (!cfe)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, cfe);
+
+ kref_init(&cfe->kref);
+ cfe->pdev = pdev;
+ cfe->fe_csi2_channel = -1;
+ spin_lock_init(&cfe->state_lock);
+
+ cfe->csi2.base = devm_platform_ioremap_resource(pdev, 0);
+ if (IS_ERR(cfe->csi2.base)) {
+ dev_err(&pdev->dev, "Failed to get dma io block\n");
+ ret = PTR_ERR(cfe->csi2.base);
+ goto err_cfe_put;
+ }
+
+ cfe->csi2.dphy.base = devm_platform_ioremap_resource(pdev, 1);
+ if (IS_ERR(cfe->csi2.dphy.base)) {
+ dev_err(&pdev->dev, "Failed to get host io block\n");
+ ret = PTR_ERR(cfe->csi2.dphy.base);
+ goto err_cfe_put;
+ }
+
+ cfe->mipi_cfg_base = devm_platform_ioremap_resource(pdev, 2);
+ if (IS_ERR(cfe->mipi_cfg_base)) {
+ dev_err(&pdev->dev, "Failed to get mipi cfg io block\n");
+ ret = PTR_ERR(cfe->mipi_cfg_base);
+ goto err_cfe_put;
+ }
+
+ cfe->fe.base = devm_platform_ioremap_resource(pdev, 3);
+ if (IS_ERR(cfe->fe.base)) {
+ dev_err(&pdev->dev, "Failed to get pisp fe io block\n");
+ ret = PTR_ERR(cfe->fe.base);
+ goto err_cfe_put;
+ }
+
+ ret = platform_get_irq(pdev, 0);
+ if (ret <= 0) {
+ ret = -EINVAL;
+ goto err_cfe_put;
+ }
+
+ ret = devm_request_irq(&pdev->dev, ret, cfe_isr, 0, "rp1-cfe", cfe);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to request interrupt\n");
+ ret = -EINVAL;
+ goto err_cfe_put;
+ }
+
+ ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
+ if (ret) {
+ dev_err(&pdev->dev, "DMA enable failed\n");
+ goto err_cfe_put;
+ }
+
+ ret = vb2_dma_contig_set_max_seg_size(&pdev->dev, UINT_MAX);
+ if (ret)
+ goto err_cfe_put;
+
+ /* TODO: Enable clock only when running. */
+ cfe->clk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(cfe->clk)) {
+ ret = dev_err_probe(&pdev->dev, PTR_ERR(cfe->clk),
+ "clock not found\n");
+ goto err_cfe_put;
+ }
+
+ cfe->mdev.dev = &pdev->dev;
+ cfe->mdev.ops = &cfe_media_device_ops;
+ strscpy(cfe->mdev.model, CFE_MODULE_NAME, sizeof(cfe->mdev.model));
+ strscpy(cfe->mdev.serial, "", sizeof(cfe->mdev.serial));
+ snprintf(cfe->mdev.bus_info, sizeof(cfe->mdev.bus_info), "platform:%s",
+ dev_name(&pdev->dev));
+
+ media_device_init(&cfe->mdev);
+
+ cfe->v4l2_dev.mdev = &cfe->mdev;
+
+ ret = v4l2_device_register(&pdev->dev, &cfe->v4l2_dev);
+ if (ret) {
+ cfe_err(cfe, "Unable to register v4l2 device.\n");
+ goto err_cfe_put;
+ }
+
+ snprintf(debugfs_name, sizeof(debugfs_name), "rp1-cfe:%s",
+ dev_name(&pdev->dev));
+ cfe->debugfs = debugfs_create_dir(debugfs_name, NULL);
+ debugfs_create_file("regs", 0440, cfe->debugfs, cfe,
+ &mipi_cfg_regs_fops);
+
+ /* Enable the block power domain */
+ pm_runtime_enable(&pdev->dev);
+
+ ret = pm_runtime_resume_and_get(&cfe->pdev->dev);
+ if (ret)
+ goto err_runtime_disable;
+
+ cfe->csi2.v4l2_dev = &cfe->v4l2_dev;
+ ret = csi2_init(&cfe->csi2, cfe->debugfs);
+ if (ret) {
+ cfe_err(cfe, "Failed to init csi2 (%d)\n", ret);
+ goto err_runtime_put;
+ }
+
+ cfe->fe.v4l2_dev = &cfe->v4l2_dev;
+ ret = pisp_fe_init(&cfe->fe, cfe->debugfs);
+ if (ret) {
+ cfe_err(cfe, "Failed to init pisp fe (%d)\n", ret);
+ goto err_csi2_uninit;
+ }
+
+ cfe->mdev.hw_revision = cfe->fe.hw_revision;
+ ret = media_device_register(&cfe->mdev);
+ if (ret < 0) {
+ cfe_err(cfe, "Unable to register media-controller device.\n");
+ goto err_pisp_fe_uninit;
+ }
+
+ ret = cfe_register_async_nf(cfe);
+ if (ret) {
+ cfe_err(cfe, "Failed to connect subdevs\n");
+ goto err_media_unregister;
+ }
+
+ pm_runtime_put(&cfe->pdev->dev);
+
+ return 0;
+
+err_media_unregister:
+ media_device_unregister(&cfe->mdev);
+err_pisp_fe_uninit:
+ pisp_fe_uninit(&cfe->fe);
+err_csi2_uninit:
+ csi2_uninit(&cfe->csi2);
+err_runtime_put:
+ pm_runtime_put(&cfe->pdev->dev);
+err_runtime_disable:
+ pm_runtime_disable(&pdev->dev);
+ debugfs_remove(cfe->debugfs);
+ v4l2_device_unregister(&cfe->v4l2_dev);
+err_cfe_put:
+ cfe_put(cfe);
+
+ return ret;
+}
+
+static void cfe_remove(struct platform_device *pdev)
+{
+ struct cfe_device *cfe = platform_get_drvdata(pdev);
+
+ debugfs_remove(cfe->debugfs);
+
+ v4l2_async_nf_unregister(&cfe->notifier);
+ v4l2_async_nf_cleanup(&cfe->notifier);
+
+ media_device_unregister(&cfe->mdev);
+ cfe_unregister_nodes(cfe);
+
+ pisp_fe_uninit(&cfe->fe);
+ csi2_uninit(&cfe->csi2);
+
+ pm_runtime_disable(&pdev->dev);
+
+ v4l2_device_unregister(&cfe->v4l2_dev);
+
+ cfe_put(cfe);
+}
+
+static int cfe_runtime_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct cfe_device *cfe = platform_get_drvdata(pdev);
+
+ clk_disable_unprepare(cfe->clk);
+
+ return 0;
+}
+
+static int cfe_runtime_resume(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct cfe_device *cfe = platform_get_drvdata(pdev);
+ int ret;
+
+ ret = clk_prepare_enable(cfe->clk);
+ if (ret) {
+ dev_err(dev, "Unable to enable clock\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct dev_pm_ops cfe_pm_ops = {
+ SET_RUNTIME_PM_OPS(cfe_runtime_suspend, cfe_runtime_resume, NULL)
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+};
+
+static const struct of_device_id cfe_of_match[] = {
+ { .compatible = "raspberrypi,rp1-cfe" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, cfe_of_match);
+
+static struct platform_driver cfe_driver = {
+ .probe = cfe_probe,
+ .remove = cfe_remove,
+ .driver = {
+ .name = CFE_MODULE_NAME,
+ .of_match_table = cfe_of_match,
+ .pm = &cfe_pm_ops,
+ },
+};
+
+module_platform_driver(cfe_driver);
+
+MODULE_AUTHOR("Naushir Patuck <naush@raspberrypi.com>");
+MODULE_AUTHOR("Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>");
+MODULE_DESCRIPTION("Raspberry Pi RP1 Camera Front End driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(CFE_VERSION);
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/cfe.h b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.h
new file mode 100644
index 000000000000..c63cc314be3c
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/cfe.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * RP1 CFE Driver
+ *
+ * Copyright (c) 2021-2024 Raspberry Pi Ltd.
+ * Copyright (c) 2023-2024 Ideas on Board Oy
+ */
+#ifndef _RP1_CFE_
+#define _RP1_CFE_
+
+#include <linux/media-bus-format.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+extern bool cfe_debug_verbose;
+
+enum cfe_remap_types {
+ CFE_REMAP_16BIT,
+ CFE_REMAP_COMPRESSED,
+ CFE_NUM_REMAP,
+};
+
+#define CFE_FORMAT_FLAG_META_OUT BIT(0)
+#define CFE_FORMAT_FLAG_META_CAP BIT(1)
+#define CFE_FORMAT_FLAG_FE_OUT BIT(2)
+
+struct cfe_fmt {
+ u32 fourcc;
+ u32 code;
+ u8 depth;
+ u8 csi_dt;
+ u32 remap[CFE_NUM_REMAP];
+ u32 flags;
+};
+
+extern const struct v4l2_mbus_framefmt cfe_default_format;
+
+const struct cfe_fmt *find_format_by_code(u32 code);
+const struct cfe_fmt *find_format_by_pix(u32 pixelformat);
+u32 cfe_find_16bit_code(u32 code);
+u32 cfe_find_compressed_code(u32 code);
+
+#endif
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c
new file mode 100644
index 000000000000..35c2ab1e2cd4
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.c
@@ -0,0 +1,586 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * RP1 CSI-2 Driver
+ *
+ * Copyright (c) 2021-2024 Raspberry Pi Ltd.
+ * Copyright (c) 2023-2024 Ideas on Board Oy
+ */
+
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/pm_runtime.h>
+#include <linux/seq_file.h>
+
+#include <media/videobuf2-dma-contig.h>
+
+#include "cfe.h"
+#include "csi2.h"
+
+#include "cfe-trace.h"
+
+static bool csi2_track_errors;
+module_param_named(track_csi2_errors, csi2_track_errors, bool, 0);
+MODULE_PARM_DESC(track_csi2_errors, "track csi-2 errors");
+
+#define csi2_dbg(csi2, fmt, arg...) dev_dbg((csi2)->v4l2_dev->dev, fmt, ##arg)
+#define csi2_err(csi2, fmt, arg...) dev_err((csi2)->v4l2_dev->dev, fmt, ##arg)
+
+/* CSI2-DMA registers */
+#define CSI2_STATUS 0x000
+#define CSI2_QOS 0x004
+#define CSI2_DISCARDS_OVERFLOW 0x008
+#define CSI2_DISCARDS_INACTIVE 0x00c
+#define CSI2_DISCARDS_UNMATCHED 0x010
+#define CSI2_DISCARDS_LEN_LIMIT 0x014
+
+#define CSI2_DISCARDS_AMOUNT_SHIFT 0
+#define CSI2_DISCARDS_AMOUNT_MASK GENMASK(23, 0)
+#define CSI2_DISCARDS_DT_SHIFT 24
+#define CSI2_DISCARDS_DT_MASK GENMASK(29, 24)
+#define CSI2_DISCARDS_VC_SHIFT 30
+#define CSI2_DISCARDS_VC_MASK GENMASK(31, 30)
+
+#define CSI2_LLEV_PANICS 0x018
+#define CSI2_ULEV_PANICS 0x01c
+#define CSI2_IRQ_MASK 0x020
+#define CSI2_IRQ_MASK_IRQ_OVERFLOW BIT(0)
+#define CSI2_IRQ_MASK_IRQ_DISCARD_OVERFLOW BIT(1)
+#define CSI2_IRQ_MASK_IRQ_DISCARD_LENGTH_LIMIT BIT(2)
+#define CSI2_IRQ_MASK_IRQ_DISCARD_UNMATCHED BIT(3)
+#define CSI2_IRQ_MASK_IRQ_DISCARD_INACTIVE BIT(4)
+#define CSI2_IRQ_MASK_IRQ_ALL \
+ (CSI2_IRQ_MASK_IRQ_OVERFLOW | CSI2_IRQ_MASK_IRQ_DISCARD_OVERFLOW | \
+ CSI2_IRQ_MASK_IRQ_DISCARD_LENGTH_LIMIT | \
+ CSI2_IRQ_MASK_IRQ_DISCARD_UNMATCHED | \
+ CSI2_IRQ_MASK_IRQ_DISCARD_INACTIVE)
+
+#define CSI2_CTRL 0x024
+#define CSI2_CH_CTRL(x) ((x) * 0x40 + 0x28)
+#define CSI2_CH_ADDR0(x) ((x) * 0x40 + 0x2c)
+#define CSI2_CH_ADDR1(x) ((x) * 0x40 + 0x3c)
+#define CSI2_CH_STRIDE(x) ((x) * 0x40 + 0x30)
+#define CSI2_CH_LENGTH(x) ((x) * 0x40 + 0x34)
+#define CSI2_CH_DEBUG(x) ((x) * 0x40 + 0x38)
+#define CSI2_CH_FRAME_SIZE(x) ((x) * 0x40 + 0x40)
+#define CSI2_CH_COMP_CTRL(x) ((x) * 0x40 + 0x44)
+#define CSI2_CH_FE_FRAME_ID(x) ((x) * 0x40 + 0x48)
+
+/* CSI2_STATUS */
+#define CSI2_STATUS_IRQ_FS(x) (BIT(0) << (x))
+#define CSI2_STATUS_IRQ_FE(x) (BIT(4) << (x))
+#define CSI2_STATUS_IRQ_FE_ACK(x) (BIT(8) << (x))
+#define CSI2_STATUS_IRQ_LE(x) (BIT(12) << (x))
+#define CSI2_STATUS_IRQ_LE_ACK(x) (BIT(16) << (x))
+#define CSI2_STATUS_IRQ_CH_MASK(x) \
+ (CSI2_STATUS_IRQ_FS(x) | CSI2_STATUS_IRQ_FE(x) | \
+ CSI2_STATUS_IRQ_FE_ACK(x) | CSI2_STATUS_IRQ_LE(x) | \
+ CSI2_STATUS_IRQ_LE_ACK(x))
+#define CSI2_STATUS_IRQ_OVERFLOW BIT(20)
+#define CSI2_STATUS_IRQ_DISCARD_OVERFLOW BIT(21)
+#define CSI2_STATUS_IRQ_DISCARD_LEN_LIMIT BIT(22)
+#define CSI2_STATUS_IRQ_DISCARD_UNMATCHED BIT(23)
+#define CSI2_STATUS_IRQ_DISCARD_INACTIVE BIT(24)
+
+/* CSI2_CTRL */
+#define CSI2_CTRL_EOP_IS_EOL BIT(0)
+
+/* CSI2_CH_CTRL */
+#define CSI2_CH_CTRL_DMA_EN BIT(0)
+#define CSI2_CH_CTRL_FORCE BIT(3)
+#define CSI2_CH_CTRL_AUTO_ARM BIT(4)
+#define CSI2_CH_CTRL_IRQ_EN_FS BIT(13)
+#define CSI2_CH_CTRL_IRQ_EN_FE BIT(14)
+#define CSI2_CH_CTRL_IRQ_EN_FE_ACK BIT(15)
+#define CSI2_CH_CTRL_IRQ_EN_LE BIT(16)
+#define CSI2_CH_CTRL_IRQ_EN_LE_ACK BIT(17)
+#define CSI2_CH_CTRL_FLUSH_FE BIT(28)
+#define CSI2_CH_CTRL_PACK_LINE BIT(29)
+#define CSI2_CH_CTRL_PACK_BYTES BIT(30)
+#define CSI2_CH_CTRL_CH_MODE_MASK GENMASK(2, 1)
+#define CSI2_CH_CTRL_VC_MASK GENMASK(6, 5)
+#define CSI2_CH_CTRL_DT_MASK GENMASK(12, 7)
+#define CSI2_CH_CTRL_LC_MASK GENMASK(27, 18)
+
+/* CHx_COMPRESSION_CONTROL */
+#define CSI2_CH_COMP_CTRL_OFFSET_MASK GENMASK(15, 0)
+#define CSI2_CH_COMP_CTRL_SHIFT_MASK GENMASK(19, 16)
+#define CSI2_CH_COMP_CTRL_MODE_MASK GENMASK(25, 24)
+
+static inline u32 csi2_reg_read(struct csi2_device *csi2, u32 offset)
+{
+ return readl(csi2->base + offset);
+}
+
+static inline void csi2_reg_write(struct csi2_device *csi2, u32 offset, u32 val)
+{
+ writel(val, csi2->base + offset);
+}
+
+static inline void set_field(u32 *valp, u32 field, u32 mask)
+{
+ u32 val = *valp;
+
+ val &= ~mask;
+ val |= (field << __ffs(mask)) & mask;
+ *valp = val;
+}
+
+static int csi2_regs_show(struct seq_file *s, void *data)
+{
+ struct csi2_device *csi2 = s->private;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(csi2->v4l2_dev->dev);
+ if (ret)
+ return ret;
+
+#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", csi2_reg_read(csi2, reg))
+#define DUMP_CH(idx, reg) seq_printf(s, #reg "(%u) \t0x%08x\n", idx, \
+ csi2_reg_read(csi2, reg(idx)))
+
+ DUMP(CSI2_STATUS);
+ DUMP(CSI2_DISCARDS_OVERFLOW);
+ DUMP(CSI2_DISCARDS_INACTIVE);
+ DUMP(CSI2_DISCARDS_UNMATCHED);
+ DUMP(CSI2_DISCARDS_LEN_LIMIT);
+ DUMP(CSI2_LLEV_PANICS);
+ DUMP(CSI2_ULEV_PANICS);
+ DUMP(CSI2_IRQ_MASK);
+ DUMP(CSI2_CTRL);
+
+ for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; ++i) {
+ DUMP_CH(i, CSI2_CH_CTRL);
+ DUMP_CH(i, CSI2_CH_ADDR0);
+ DUMP_CH(i, CSI2_CH_ADDR1);
+ DUMP_CH(i, CSI2_CH_STRIDE);
+ DUMP_CH(i, CSI2_CH_LENGTH);
+ DUMP_CH(i, CSI2_CH_DEBUG);
+ DUMP_CH(i, CSI2_CH_FRAME_SIZE);
+ DUMP_CH(i, CSI2_CH_COMP_CTRL);
+ DUMP_CH(i, CSI2_CH_FE_FRAME_ID);
+ }
+
+#undef DUMP
+#undef DUMP_CH
+
+ pm_runtime_put(csi2->v4l2_dev->dev);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(csi2_regs);
+
+static int csi2_errors_show(struct seq_file *s, void *data)
+{
+ struct csi2_device *csi2 = s->private;
+ unsigned long flags;
+ u32 discards_table[DISCARDS_TABLE_NUM_VCS][DISCARDS_TABLE_NUM_ENTRIES];
+ u32 discards_dt_table[DISCARDS_TABLE_NUM_ENTRIES];
+ u32 overflows;
+
+ spin_lock_irqsave(&csi2->errors_lock, flags);
+
+ memcpy(discards_table, csi2->discards_table, sizeof(discards_table));
+ memcpy(discards_dt_table, csi2->discards_dt_table,
+ sizeof(discards_dt_table));
+ overflows = csi2->overflows;
+
+ csi2->overflows = 0;
+ memset(csi2->discards_table, 0, sizeof(discards_table));
+ memset(csi2->discards_dt_table, 0, sizeof(discards_dt_table));
+
+ spin_unlock_irqrestore(&csi2->errors_lock, flags);
+
+ seq_printf(s, "Overflows %u\n", overflows);
+ seq_puts(s, "Discards:\n");
+ seq_puts(s, "VC OVLF LEN UNMATCHED INACTIVE\n");
+
+ for (unsigned int vc = 0; vc < DISCARDS_TABLE_NUM_VCS; ++vc) {
+ seq_printf(s, "%u %10u %10u %10u %10u\n", vc,
+ discards_table[vc][DISCARDS_TABLE_OVERFLOW],
+ discards_table[vc][DISCARDS_TABLE_LENGTH_LIMIT],
+ discards_table[vc][DISCARDS_TABLE_UNMATCHED],
+ discards_table[vc][DISCARDS_TABLE_INACTIVE]);
+ }
+
+ seq_printf(s, "Last DT %10u %10u %10u %10u\n",
+ discards_dt_table[DISCARDS_TABLE_OVERFLOW],
+ discards_dt_table[DISCARDS_TABLE_LENGTH_LIMIT],
+ discards_dt_table[DISCARDS_TABLE_UNMATCHED],
+ discards_dt_table[DISCARDS_TABLE_INACTIVE]);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(csi2_errors);
+
+static void csi2_isr_handle_errors(struct csi2_device *csi2, u32 status)
+{
+ spin_lock(&csi2->errors_lock);
+
+ if (status & CSI2_STATUS_IRQ_OVERFLOW)
+ csi2->overflows++;
+
+ for (unsigned int i = 0; i < DISCARDS_TABLE_NUM_ENTRIES; ++i) {
+ static const u32 discard_bits[] = {
+ CSI2_STATUS_IRQ_DISCARD_OVERFLOW,
+ CSI2_STATUS_IRQ_DISCARD_LEN_LIMIT,
+ CSI2_STATUS_IRQ_DISCARD_UNMATCHED,
+ CSI2_STATUS_IRQ_DISCARD_INACTIVE,
+ };
+ static const u8 discard_regs[] = {
+ CSI2_DISCARDS_OVERFLOW,
+ CSI2_DISCARDS_LEN_LIMIT,
+ CSI2_DISCARDS_UNMATCHED,
+ CSI2_DISCARDS_INACTIVE,
+ };
+ u32 amount;
+ u8 dt, vc;
+ u32 v;
+
+ if (!(status & discard_bits[i]))
+ continue;
+
+ v = csi2_reg_read(csi2, discard_regs[i]);
+ csi2_reg_write(csi2, discard_regs[i], 0);
+
+ amount = (v & CSI2_DISCARDS_AMOUNT_MASK) >>
+ CSI2_DISCARDS_AMOUNT_SHIFT;
+ dt = (v & CSI2_DISCARDS_DT_MASK) >> CSI2_DISCARDS_DT_SHIFT;
+ vc = (v & CSI2_DISCARDS_VC_MASK) >> CSI2_DISCARDS_VC_SHIFT;
+
+ csi2->discards_table[vc][i] += amount;
+ csi2->discards_dt_table[i] = dt;
+ }
+
+ spin_unlock(&csi2->errors_lock);
+}
+
+void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof)
+{
+ u32 status;
+
+ status = csi2_reg_read(csi2, CSI2_STATUS);
+
+ /* Write value back to clear the interrupts */
+ csi2_reg_write(csi2, CSI2_STATUS, status);
+
+ for (unsigned int i = 0; i < CSI2_NUM_CHANNELS; i++) {
+ u32 dbg;
+
+ if ((status & CSI2_STATUS_IRQ_CH_MASK(i)) == 0)
+ continue;
+
+ dbg = csi2_reg_read(csi2, CSI2_CH_DEBUG(i));
+
+ trace_csi2_irq(i, status, dbg);
+
+ sof[i] = !!(status & CSI2_STATUS_IRQ_FS(i));
+ eof[i] = !!(status & CSI2_STATUS_IRQ_FE_ACK(i));
+ }
+
+ if (csi2_track_errors)
+ csi2_isr_handle_errors(csi2, status);
+}
+
+void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel,
+ dma_addr_t dmaaddr, unsigned int stride, unsigned int size)
+{
+ u64 addr = dmaaddr;
+ /*
+ * ADDRESS0 must be written last as it triggers the double buffering
+ * mechanism for all buffer registers within the hardware.
+ */
+ addr >>= 4;
+ csi2_reg_write(csi2, CSI2_CH_LENGTH(channel), size >> 4);
+ csi2_reg_write(csi2, CSI2_CH_STRIDE(channel), stride >> 4);
+ csi2_reg_write(csi2, CSI2_CH_ADDR1(channel), addr >> 32);
+ csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), addr & 0xffffffff);
+}
+
+void csi2_set_compression(struct csi2_device *csi2, unsigned int channel,
+ enum csi2_compression_mode mode, unsigned int shift,
+ unsigned int offset)
+{
+ u32 compression = 0;
+
+ set_field(&compression, CSI2_CH_COMP_CTRL_OFFSET_MASK, offset);
+ set_field(&compression, CSI2_CH_COMP_CTRL_SHIFT_MASK, shift);
+ set_field(&compression, CSI2_CH_COMP_CTRL_MODE_MASK, mode);
+ csi2_reg_write(csi2, CSI2_CH_COMP_CTRL(channel), compression);
+}
+
+void csi2_start_channel(struct csi2_device *csi2, unsigned int channel,
+ enum csi2_mode mode, bool auto_arm, bool pack_bytes,
+ unsigned int width, unsigned int height,
+ u8 vc, u8 dt)
+{
+ u32 ctrl;
+
+ csi2_dbg(csi2, "%s [%u]\n", __func__, channel);
+
+ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), 0);
+ csi2_reg_write(csi2, CSI2_CH_DEBUG(channel), 0);
+ csi2_reg_write(csi2, CSI2_STATUS, CSI2_STATUS_IRQ_CH_MASK(channel));
+
+ /* Enable channel and FS/FE interrupts. */
+ ctrl = CSI2_CH_CTRL_DMA_EN | CSI2_CH_CTRL_IRQ_EN_FS |
+ CSI2_CH_CTRL_IRQ_EN_FE_ACK | CSI2_CH_CTRL_PACK_LINE;
+ /* PACK_BYTES ensures no striding for embedded data. */
+ if (pack_bytes)
+ ctrl |= CSI2_CH_CTRL_PACK_BYTES;
+
+ if (auto_arm)
+ ctrl |= CSI2_CH_CTRL_AUTO_ARM;
+
+ if (width && height) {
+ set_field(&ctrl, mode, CSI2_CH_CTRL_CH_MODE_MASK);
+ csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel),
+ (height << 16) | width);
+ } else {
+ set_field(&ctrl, 0x0, CSI2_CH_CTRL_CH_MODE_MASK);
+ csi2_reg_write(csi2, CSI2_CH_FRAME_SIZE(channel), 0);
+ }
+
+ set_field(&ctrl, vc, CSI2_CH_CTRL_VC_MASK);
+ set_field(&ctrl, dt, CSI2_CH_CTRL_DT_MASK);
+ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), ctrl);
+ csi2->num_lines[channel] = height;
+}
+
+void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel)
+{
+ csi2_dbg(csi2, "%s [%u]\n", __func__, channel);
+
+ /* Channel disable. Use FORCE to allow stopping mid-frame. */
+ csi2_reg_write(csi2, CSI2_CH_CTRL(channel), CSI2_CH_CTRL_FORCE);
+ /* Latch the above change by writing to the ADDR0 register. */
+ csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0);
+ /* Write this again, the HW needs it! */
+ csi2_reg_write(csi2, CSI2_CH_ADDR0(channel), 0);
+}
+
+void csi2_open_rx(struct csi2_device *csi2)
+{
+ csi2_reg_write(csi2, CSI2_IRQ_MASK,
+ csi2_track_errors ? CSI2_IRQ_MASK_IRQ_ALL : 0);
+
+ dphy_start(&csi2->dphy);
+
+ csi2_reg_write(csi2, CSI2_CTRL, CSI2_CTRL_EOP_IS_EOL);
+}
+
+void csi2_close_rx(struct csi2_device *csi2)
+{
+ dphy_stop(&csi2->dphy);
+
+ csi2_reg_write(csi2, CSI2_IRQ_MASK, 0);
+}
+
+static int csi2_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_subdev_route routes[] = { {
+ .sink_pad = CSI2_PAD_SINK,
+ .sink_stream = 0,
+ .source_pad = CSI2_PAD_FIRST_SOURCE,
+ .source_stream = 0,
+ .flags = V4L2_SUBDEV_ROUTE_FL_ACTIVE,
+ } };
+
+ struct v4l2_subdev_krouting routing = {
+ .num_routes = ARRAY_SIZE(routes),
+ .routes = routes,
+ };
+
+ int ret;
+
+ ret = v4l2_subdev_set_routing_with_fmt(sd, state, &routing,
+ &cfe_default_format);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int csi2_pad_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ if (format->pad == CSI2_PAD_SINK) {
+ /* Store the sink format and propagate it to the source. */
+
+ const struct cfe_fmt *cfe_fmt;
+
+ cfe_fmt = find_format_by_code(format->format.code);
+ if (!cfe_fmt) {
+ cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB10_1X10);
+ format->format.code = cfe_fmt->code;
+ }
+
+ struct v4l2_mbus_framefmt *fmt;
+
+ 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;
+
+ format->format.field = V4L2_FIELD_NONE;
+
+ *fmt = format->format;
+ } else {
+ /* Only allow changing the source pad mbus code. */
+
+ struct v4l2_mbus_framefmt *sink_fmt, *source_fmt;
+ u32 sink_code;
+ u32 code;
+
+ sink_fmt = v4l2_subdev_state_get_opposite_stream_format(state,
+ format->pad,
+ format->stream);
+ if (!sink_fmt)
+ return -EINVAL;
+
+ source_fmt = v4l2_subdev_state_get_format(state, format->pad,
+ format->stream);
+ if (!source_fmt)
+ return -EINVAL;
+
+ sink_code = sink_fmt->code;
+ code = format->format.code;
+
+ /*
+ * Only allow changing the mbus code to:
+ * - The sink's mbus code
+ * - The 16-bit version of the sink's mbus code
+ * - The compressed version of the sink's mbus code
+ */
+ if (code == sink_code ||
+ code == cfe_find_16bit_code(sink_code) ||
+ code == cfe_find_compressed_code(sink_code))
+ source_fmt->code = code;
+
+ format->format.code = source_fmt->code;
+ }
+
+ return 0;
+}
+
+static int csi2_set_routing(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ enum v4l2_subdev_format_whence which,
+ struct v4l2_subdev_krouting *routing)
+{
+ int ret;
+
+ ret = v4l2_subdev_routing_validate(sd, routing,
+ V4L2_SUBDEV_ROUTING_ONLY_1_TO_1 |
+ V4L2_SUBDEV_ROUTING_NO_SOURCE_MULTIPLEXING);
+ if (ret)
+ return ret;
+
+ /* Only stream ID 0 allowed on source pads */
+ for (unsigned int i = 0; i < routing->num_routes; ++i) {
+ const struct v4l2_subdev_route *route = &routing->routes[i];
+
+ if (route->source_stream != 0)
+ return -EINVAL;
+ }
+
+ ret = v4l2_subdev_set_routing_with_fmt(sd, state, routing,
+ &cfe_default_format);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static const struct v4l2_subdev_pad_ops csi2_subdev_pad_ops = {
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = csi2_pad_set_fmt,
+ .set_routing = csi2_set_routing,
+ .link_validate = v4l2_subdev_link_validate_default,
+};
+
+static const struct media_entity_operations csi2_entity_ops = {
+ .link_validate = v4l2_subdev_link_validate,
+ .has_pad_interdep = v4l2_subdev_has_pad_interdep,
+};
+
+static const struct v4l2_subdev_ops csi2_subdev_ops = {
+ .pad = &csi2_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops csi2_internal_ops = {
+ .init_state = csi2_init_state,
+};
+
+int csi2_init(struct csi2_device *csi2, struct dentry *debugfs)
+{
+ unsigned int ret;
+
+ spin_lock_init(&csi2->errors_lock);
+
+ csi2->dphy.dev = csi2->v4l2_dev->dev;
+ dphy_probe(&csi2->dphy);
+
+ debugfs_create_file("csi2_regs", 0440, debugfs, csi2, &csi2_regs_fops);
+
+ if (csi2_track_errors)
+ debugfs_create_file("csi2_errors", 0440, debugfs, csi2,
+ &csi2_errors_fops);
+
+ csi2->pad[CSI2_PAD_SINK].flags = MEDIA_PAD_FL_SINK;
+
+ for (unsigned int i = CSI2_PAD_FIRST_SOURCE;
+ i < CSI2_PAD_FIRST_SOURCE + CSI2_PAD_NUM_SOURCES; i++)
+ csi2->pad[i].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&csi2->sd.entity, ARRAY_SIZE(csi2->pad),
+ csi2->pad);
+ if (ret)
+ return ret;
+
+ /* Initialize subdev */
+ v4l2_subdev_init(&csi2->sd, &csi2_subdev_ops);
+ csi2->sd.internal_ops = &csi2_internal_ops;
+ csi2->sd.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
+ csi2->sd.entity.ops = &csi2_entity_ops;
+ csi2->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE | V4L2_SUBDEV_FL_STREAMS;
+ csi2->sd.owner = THIS_MODULE;
+ snprintf(csi2->sd.name, sizeof(csi2->sd.name), "csi2");
+
+ ret = v4l2_subdev_init_finalize(&csi2->sd);
+ if (ret)
+ goto err_entity_cleanup;
+
+ ret = v4l2_device_register_subdev(csi2->v4l2_dev, &csi2->sd);
+ if (ret) {
+ csi2_err(csi2, "Failed register csi2 subdev (%d)\n", ret);
+ goto err_subdev_cleanup;
+ }
+
+ return 0;
+
+err_subdev_cleanup:
+ v4l2_subdev_cleanup(&csi2->sd);
+err_entity_cleanup:
+ media_entity_cleanup(&csi2->sd.entity);
+
+ return ret;
+}
+
+void csi2_uninit(struct csi2_device *csi2)
+{
+ v4l2_device_unregister_subdev(&csi2->sd);
+ v4l2_subdev_cleanup(&csi2->sd);
+ media_entity_cleanup(&csi2->sd.entity);
+}
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/csi2.h b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.h
new file mode 100644
index 000000000000..a8ee5de565fb
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/csi2.h
@@ -0,0 +1,89 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * RP1 CSI-2 Driver
+ *
+ * Copyright (c) 2021-2024 Raspberry Pi Ltd.
+ * Copyright (c) 2023-2024 Ideas on Board Oy
+ */
+
+#ifndef _RP1_CSI2_
+#define _RP1_CSI2_
+
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include "dphy.h"
+
+#define CSI2_NUM_CHANNELS 4
+
+#define CSI2_PAD_SINK 0
+#define CSI2_PAD_FIRST_SOURCE 1
+#define CSI2_PAD_NUM_SOURCES 4
+#define CSI2_NUM_PADS 5
+
+#define DISCARDS_TABLE_NUM_VCS 4
+
+enum csi2_mode {
+ CSI2_MODE_NORMAL = 0,
+ CSI2_MODE_REMAP = 1,
+ CSI2_MODE_COMPRESSED = 2,
+ CSI2_MODE_FE_STREAMING = 3,
+};
+
+enum csi2_compression_mode {
+ CSI2_COMPRESSION_DELTA = 1,
+ CSI2_COMPRESSION_SIMPLE = 2,
+ CSI2_COMPRESSION_COMBINED = 3,
+};
+
+enum discards_table_index {
+ DISCARDS_TABLE_OVERFLOW = 0,
+ DISCARDS_TABLE_LENGTH_LIMIT,
+ DISCARDS_TABLE_UNMATCHED,
+ DISCARDS_TABLE_INACTIVE,
+ DISCARDS_TABLE_NUM_ENTRIES,
+};
+
+struct csi2_device {
+ /* Parent V4l2 device */
+ struct v4l2_device *v4l2_dev;
+
+ void __iomem *base;
+
+ struct dphy_data dphy;
+
+ enum v4l2_mbus_type bus_type;
+ unsigned int bus_flags;
+ unsigned int num_lines[CSI2_NUM_CHANNELS];
+
+ struct media_pad pad[CSI2_NUM_PADS];
+ struct v4l2_subdev sd;
+
+ /* lock for csi2 errors counters */
+ spinlock_t errors_lock;
+ u32 overflows;
+ u32 discards_table[DISCARDS_TABLE_NUM_VCS][DISCARDS_TABLE_NUM_ENTRIES];
+ u32 discards_dt_table[DISCARDS_TABLE_NUM_ENTRIES];
+};
+
+void csi2_isr(struct csi2_device *csi2, bool *sof, bool *eof);
+void csi2_set_buffer(struct csi2_device *csi2, unsigned int channel,
+ dma_addr_t dmaaddr, unsigned int stride,
+ unsigned int size);
+void csi2_set_compression(struct csi2_device *csi2, unsigned int channel,
+ enum csi2_compression_mode mode, unsigned int shift,
+ unsigned int offset);
+void csi2_start_channel(struct csi2_device *csi2, unsigned int channel,
+ enum csi2_mode mode, bool auto_arm,
+ bool pack_bytes, unsigned int width,
+ unsigned int height, u8 vc, u8 dt);
+void csi2_stop_channel(struct csi2_device *csi2, unsigned int channel);
+void csi2_open_rx(struct csi2_device *csi2);
+void csi2_close_rx(struct csi2_device *csi2);
+int csi2_init(struct csi2_device *csi2, struct dentry *debugfs);
+void csi2_uninit(struct csi2_device *csi2);
+
+#endif
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c
new file mode 100644
index 000000000000..b443f0f56ddc
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.c
@@ -0,0 +1,181 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * RP1 CSI-2 Driver
+ *
+ * Copyright (c) 2021-2024 Raspberry Pi Ltd.
+ * Copyright (c) 2023-2024 Ideas on Board Oy
+ */
+
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+
+#include "dphy.h"
+
+#define dphy_dbg(dphy, fmt, arg...) dev_dbg((dphy)->dev, fmt, ##arg)
+#define dphy_err(dphy, fmt, arg...) dev_err((dphy)->dev, fmt, ##arg)
+
+/* DW dphy Host registers */
+#define DPHY_VERSION 0x000
+#define DPHY_N_LANES 0x004
+#define DPHY_RESETN 0x008
+#define DPHY_PHY_SHUTDOWNZ 0x040
+#define DPHY_PHY_RSTZ 0x044
+#define DPHY_PHY_RX 0x048
+#define DPHY_PHY_STOPSTATE 0x04c
+#define DPHY_PHY_TST_CTRL0 0x050
+#define DPHY_PHY_TST_CTRL1 0x054
+#define DPHY_PHY2_TST_CTRL0 0x058
+#define DPHY_PHY2_TST_CTRL1 0x05c
+
+/* DW dphy Host Transactions */
+#define DPHY_HS_RX_CTRL_LANE0_OFFSET 0x44
+#define DPHY_PLL_INPUT_DIV_OFFSET 0x17
+#define DPHY_PLL_LOOP_DIV_OFFSET 0x18
+#define DPHY_PLL_DIV_CTRL_OFFSET 0x19
+
+static u32 dw_csi2_host_read(struct dphy_data *dphy, u32 offset)
+{
+ return readl(dphy->base + offset);
+}
+
+static void dw_csi2_host_write(struct dphy_data *dphy, u32 offset, u32 data)
+{
+ writel(data, dphy->base + offset);
+}
+
+static void set_tstclr(struct dphy_data *dphy, u32 val)
+{
+ u32 ctrl0 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL0);
+
+ dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL0, (ctrl0 & ~1) | val);
+}
+
+static void set_tstclk(struct dphy_data *dphy, u32 val)
+{
+ u32 ctrl0 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL0);
+
+ dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL0, (ctrl0 & ~2) | (val << 1));
+}
+
+static uint8_t get_tstdout(struct dphy_data *dphy)
+{
+ u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1);
+
+ return ((ctrl1 >> 8) & 0xff);
+}
+
+static void set_testen(struct dphy_data *dphy, u32 val)
+{
+ u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1);
+
+ dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL1,
+ (ctrl1 & ~(1 << 16)) | (val << 16));
+}
+
+static void set_testdin(struct dphy_data *dphy, u32 val)
+{
+ u32 ctrl1 = dw_csi2_host_read(dphy, DPHY_PHY_TST_CTRL1);
+
+ dw_csi2_host_write(dphy, DPHY_PHY_TST_CTRL1, (ctrl1 & ~0xff) | val);
+}
+
+static uint8_t dphy_transaction(struct dphy_data *dphy, u8 test_code,
+ uint8_t test_data)
+{
+ /* See page 101 of the MIPI DPHY databook. */
+ set_tstclk(dphy, 1);
+ set_testen(dphy, 0);
+ set_testdin(dphy, test_code);
+ set_testen(dphy, 1);
+ set_tstclk(dphy, 0);
+ set_testen(dphy, 0);
+ set_testdin(dphy, test_data);
+ set_tstclk(dphy, 1);
+ return get_tstdout(dphy);
+}
+
+static void dphy_set_hsfreqrange(struct dphy_data *dphy, uint32_t mbps)
+{
+ /* See Table 5-1 on page 65 of dphy databook */
+ static const u16 hsfreqrange_table[][2] = {
+ { 89, 0b000000 }, { 99, 0b010000 }, { 109, 0b100000 },
+ { 129, 0b000001 }, { 139, 0b010001 }, { 149, 0b100001 },
+ { 169, 0b000010 }, { 179, 0b010010 }, { 199, 0b100010 },
+ { 219, 0b000011 }, { 239, 0b010011 }, { 249, 0b100011 },
+ { 269, 0b000100 }, { 299, 0b010100 }, { 329, 0b000101 },
+ { 359, 0b010101 }, { 399, 0b100101 }, { 449, 0b000110 },
+ { 499, 0b010110 }, { 549, 0b000111 }, { 599, 0b010111 },
+ { 649, 0b001000 }, { 699, 0b011000 }, { 749, 0b001001 },
+ { 799, 0b011001 }, { 849, 0b101001 }, { 899, 0b111001 },
+ { 949, 0b001010 }, { 999, 0b011010 }, { 1049, 0b101010 },
+ { 1099, 0b111010 }, { 1149, 0b001011 }, { 1199, 0b011011 },
+ { 1249, 0b101011 }, { 1299, 0b111011 }, { 1349, 0b001100 },
+ { 1399, 0b011100 }, { 1449, 0b101100 }, { 1500, 0b111100 },
+ };
+ unsigned int i;
+
+ if (mbps < 80 || mbps > 1500)
+ dphy_err(dphy, "DPHY: Datarate %u Mbps out of range\n", mbps);
+
+ for (i = 0; i < ARRAY_SIZE(hsfreqrange_table) - 1; i++) {
+ if (mbps <= hsfreqrange_table[i][0])
+ break;
+ }
+
+ dphy_transaction(dphy, DPHY_HS_RX_CTRL_LANE0_OFFSET,
+ hsfreqrange_table[i][1] << 1);
+}
+
+static void dphy_init(struct dphy_data *dphy)
+{
+ dw_csi2_host_write(dphy, DPHY_PHY_RSTZ, 0);
+ dw_csi2_host_write(dphy, DPHY_PHY_SHUTDOWNZ, 0);
+ set_tstclk(dphy, 1);
+ set_testen(dphy, 0);
+ set_tstclr(dphy, 1);
+ usleep_range(15, 20);
+ set_tstclr(dphy, 0);
+ usleep_range(15, 20);
+
+ dphy_set_hsfreqrange(dphy, dphy->dphy_rate);
+
+ usleep_range(5, 10);
+ dw_csi2_host_write(dphy, DPHY_PHY_SHUTDOWNZ, 1);
+ usleep_range(5, 10);
+ dw_csi2_host_write(dphy, DPHY_PHY_RSTZ, 1);
+}
+
+void dphy_start(struct dphy_data *dphy)
+{
+ dphy_dbg(dphy, "%s: Link rate %u Mbps, %u data lanes\n", __func__,
+ dphy->dphy_rate, dphy->active_lanes);
+
+ dw_csi2_host_write(dphy, DPHY_N_LANES, (dphy->active_lanes - 1));
+ dphy_init(dphy);
+ dw_csi2_host_write(dphy, DPHY_RESETN, 0xffffffff);
+ usleep_range(10, 50);
+}
+
+void dphy_stop(struct dphy_data *dphy)
+{
+ dphy_dbg(dphy, "%s\n", __func__);
+
+ /* Set only one lane (lane 0) as active (ON) */
+ dw_csi2_host_write(dphy, DPHY_N_LANES, 0);
+ dw_csi2_host_write(dphy, DPHY_RESETN, 0);
+}
+
+void dphy_probe(struct dphy_data *dphy)
+{
+ u32 host_ver;
+ u8 host_ver_major, host_ver_minor;
+
+ host_ver = dw_csi2_host_read(dphy, DPHY_VERSION);
+ host_ver_major = (u8)((host_ver >> 24) - '0');
+ host_ver_minor = (u8)((host_ver >> 16) - '0');
+ host_ver_minor = host_ver_minor * 10;
+ host_ver_minor += (u8)((host_ver >> 8) - '0');
+
+ dphy_dbg(dphy, "DW dphy Host HW v%u.%u\n", host_ver_major,
+ host_ver_minor);
+}
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/dphy.h b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.h
new file mode 100644
index 000000000000..84fa370957cc
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/dphy.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Copyright (c) 2021-2024 Raspberry Pi Ltd.
+ * Copyright (c) 2023-2024 Ideas on Board Oy
+ */
+
+#ifndef _RP1_DPHY_
+#define _RP1_DPHY_
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+struct dphy_data {
+ struct device *dev;
+
+ void __iomem *base;
+
+ u32 dphy_rate;
+ u32 max_lanes;
+ u32 active_lanes;
+};
+
+void dphy_probe(struct dphy_data *dphy);
+void dphy_start(struct dphy_data *dphy);
+void dphy_stop(struct dphy_data *dphy);
+
+#endif
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c
new file mode 100644
index 000000000000..05762b1be2bc
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.c
@@ -0,0 +1,605 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * PiSP Front End Driver
+ *
+ * Copyright (c) 2021-2024 Raspberry Pi Ltd.
+ */
+
+#include <linux/bitops.h>
+#include <linux/delay.h>
+#include <linux/moduleparam.h>
+#include <linux/pm_runtime.h>
+#include <linux/seq_file.h>
+
+#include <media/videobuf2-dma-contig.h>
+
+#include "cfe.h"
+#include "pisp-fe.h"
+
+#include "cfe-trace.h"
+
+#define FE_VERSION 0x000
+#define FE_CONTROL 0x004
+#define FE_STATUS 0x008
+#define FE_FRAME_STATUS 0x00c
+#define FE_ERROR_STATUS 0x010
+#define FE_OUTPUT_STATUS 0x014
+#define FE_INT_EN 0x018
+#define FE_INT_STATUS 0x01c
+
+/* CONTROL */
+#define FE_CONTROL_QUEUE BIT(0)
+#define FE_CONTROL_ABORT BIT(1)
+#define FE_CONTROL_RESET BIT(2)
+#define FE_CONTROL_LATCH_REGS BIT(3)
+
+/* INT_EN / INT_STATUS */
+#define FE_INT_EOF BIT(0)
+#define FE_INT_SOF BIT(1)
+#define FE_INT_LINES0 BIT(8)
+#define FE_INT_LINES1 BIT(9)
+#define FE_INT_STATS BIT(16)
+#define FE_INT_QREADY BIT(24)
+
+/* STATUS */
+#define FE_STATUS_QUEUED BIT(0)
+#define FE_STATUS_WAITING BIT(1)
+#define FE_STATUS_ACTIVE BIT(2)
+
+#define PISP_FE_CONFIG_BASE_OFFSET 0x0040
+
+#define PISP_FE_ENABLE_STATS_CLUSTER \
+ (PISP_FE_ENABLE_STATS_CROP | PISP_FE_ENABLE_DECIMATE | \
+ PISP_FE_ENABLE_BLC | PISP_FE_ENABLE_CDAF_STATS | \
+ PISP_FE_ENABLE_AWB_STATS | PISP_FE_ENABLE_RGBY | \
+ PISP_FE_ENABLE_LSC | PISP_FE_ENABLE_AGC_STATS)
+
+#define PISP_FE_ENABLE_OUTPUT_CLUSTER(i) \
+ ((PISP_FE_ENABLE_CROP0 | PISP_FE_ENABLE_DOWNSCALE0 | \
+ PISP_FE_ENABLE_COMPRESS0 | PISP_FE_ENABLE_OUTPUT0) << (4 * (i)))
+
+struct pisp_fe_config_param {
+ u32 dirty_flags;
+ u32 dirty_flags_extra;
+ size_t offset;
+ size_t size;
+};
+
+static const struct pisp_fe_config_param pisp_fe_config_map[] = {
+ /* *_dirty_flag_extra types */
+ { 0, PISP_FE_DIRTY_GLOBAL,
+ offsetof(struct pisp_fe_config, global),
+ sizeof(struct pisp_fe_global_config) },
+ { 0, PISP_FE_DIRTY_FLOATING,
+ offsetof(struct pisp_fe_config, floating_stats),
+ sizeof(struct pisp_fe_floating_stats_config) },
+ { 0, PISP_FE_DIRTY_OUTPUT_AXI,
+ offsetof(struct pisp_fe_config, output_axi),
+ sizeof(struct pisp_fe_output_axi_config) },
+ /* *_dirty_flag types */
+ { PISP_FE_ENABLE_INPUT, 0,
+ offsetof(struct pisp_fe_config, input),
+ sizeof(struct pisp_fe_input_config) },
+ { PISP_FE_ENABLE_DECOMPRESS, 0,
+ offsetof(struct pisp_fe_config, decompress),
+ sizeof(struct pisp_decompress_config) },
+ { PISP_FE_ENABLE_DECOMPAND, 0,
+ offsetof(struct pisp_fe_config, decompand),
+ sizeof(struct pisp_fe_decompand_config) },
+ { PISP_FE_ENABLE_BLA, 0,
+ offsetof(struct pisp_fe_config, bla),
+ sizeof(struct pisp_bla_config) },
+ { PISP_FE_ENABLE_DPC, 0,
+ offsetof(struct pisp_fe_config, dpc),
+ sizeof(struct pisp_fe_dpc_config) },
+ { PISP_FE_ENABLE_STATS_CROP, 0,
+ offsetof(struct pisp_fe_config, stats_crop),
+ sizeof(struct pisp_fe_crop_config) },
+ { PISP_FE_ENABLE_BLC, 0,
+ offsetof(struct pisp_fe_config, blc),
+ sizeof(struct pisp_bla_config) },
+ { PISP_FE_ENABLE_CDAF_STATS, 0,
+ offsetof(struct pisp_fe_config, cdaf_stats),
+ sizeof(struct pisp_fe_cdaf_stats_config) },
+ { PISP_FE_ENABLE_AWB_STATS, 0,
+ offsetof(struct pisp_fe_config, awb_stats),
+ sizeof(struct pisp_fe_awb_stats_config) },
+ { PISP_FE_ENABLE_RGBY, 0,
+ offsetof(struct pisp_fe_config, rgby),
+ sizeof(struct pisp_fe_rgby_config) },
+ { PISP_FE_ENABLE_LSC, 0,
+ offsetof(struct pisp_fe_config, lsc),
+ sizeof(struct pisp_fe_lsc_config) },
+ { PISP_FE_ENABLE_AGC_STATS, 0,
+ offsetof(struct pisp_fe_config, agc_stats),
+ sizeof(struct pisp_agc_statistics) },
+ { PISP_FE_ENABLE_CROP0, 0,
+ offsetof(struct pisp_fe_config, ch[0].crop),
+ sizeof(struct pisp_fe_crop_config) },
+ { PISP_FE_ENABLE_DOWNSCALE0, 0,
+ offsetof(struct pisp_fe_config, ch[0].downscale),
+ sizeof(struct pisp_fe_downscale_config) },
+ { PISP_FE_ENABLE_COMPRESS0, 0,
+ offsetof(struct pisp_fe_config, ch[0].compress),
+ sizeof(struct pisp_compress_config) },
+ { PISP_FE_ENABLE_OUTPUT0, 0,
+ offsetof(struct pisp_fe_config, ch[0].output),
+ sizeof(struct pisp_fe_output_config) },
+ { PISP_FE_ENABLE_CROP1, 0,
+ offsetof(struct pisp_fe_config, ch[1].crop),
+ sizeof(struct pisp_fe_crop_config) },
+ { PISP_FE_ENABLE_DOWNSCALE1, 0,
+ offsetof(struct pisp_fe_config, ch[1].downscale),
+ sizeof(struct pisp_fe_downscale_config) },
+ { PISP_FE_ENABLE_COMPRESS1, 0,
+ offsetof(struct pisp_fe_config, ch[1].compress),
+ sizeof(struct pisp_compress_config) },
+ { PISP_FE_ENABLE_OUTPUT1, 0,
+ offsetof(struct pisp_fe_config, ch[1].output),
+ sizeof(struct pisp_fe_output_config) },
+};
+
+#define pisp_fe_dbg(fe, fmt, arg...) dev_dbg((fe)->v4l2_dev->dev, fmt, ##arg)
+#define pisp_fe_info(fe, fmt, arg...) dev_info((fe)->v4l2_dev->dev, fmt, ##arg)
+#define pisp_fe_err(fe, fmt, arg...) dev_err((fe)->v4l2_dev->dev, fmt, ##arg)
+
+static inline u32 pisp_fe_reg_read(struct pisp_fe_device *fe, u32 offset)
+{
+ return readl(fe->base + offset);
+}
+
+static inline void pisp_fe_reg_write(struct pisp_fe_device *fe, u32 offset,
+ u32 val)
+{
+ writel(val, fe->base + offset);
+}
+
+static inline void pisp_fe_reg_write_relaxed(struct pisp_fe_device *fe,
+ u32 offset, u32 val)
+{
+ writel_relaxed(val, fe->base + offset);
+}
+
+static int pisp_fe_regs_show(struct seq_file *s, void *data)
+{
+ struct pisp_fe_device *fe = s->private;
+ int ret;
+
+ ret = pm_runtime_resume_and_get(fe->v4l2_dev->dev);
+ if (ret)
+ return ret;
+
+ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS);
+
+#define DUMP(reg) seq_printf(s, #reg " \t0x%08x\n", pisp_fe_reg_read(fe, reg))
+ DUMP(FE_VERSION);
+ DUMP(FE_CONTROL);
+ DUMP(FE_STATUS);
+ DUMP(FE_FRAME_STATUS);
+ DUMP(FE_ERROR_STATUS);
+ DUMP(FE_OUTPUT_STATUS);
+ DUMP(FE_INT_EN);
+ DUMP(FE_INT_STATUS);
+#undef DUMP
+
+ pm_runtime_put(fe->v4l2_dev->dev);
+
+ return 0;
+}
+
+DEFINE_SHOW_ATTRIBUTE(pisp_fe_regs);
+
+static void pisp_fe_config_write(struct pisp_fe_device *fe,
+ struct pisp_fe_config *config,
+ unsigned int start_offset, unsigned int size)
+{
+ const unsigned int max_offset =
+ offsetof(struct pisp_fe_config, ch[PISP_FE_NUM_OUTPUTS]);
+ unsigned int end_offset;
+ u32 *cfg = (u32 *)config;
+
+ start_offset = min(start_offset, max_offset);
+ end_offset = min(start_offset + size, max_offset);
+
+ cfg += start_offset >> 2;
+ for (unsigned int i = start_offset; i < end_offset; i += 4, cfg++)
+ pisp_fe_reg_write_relaxed(fe, PISP_FE_CONFIG_BASE_OFFSET + i,
+ *cfg);
+}
+
+void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof)
+{
+ u32 status, int_status, out_status, frame_status, error_status;
+
+ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_LATCH_REGS);
+ status = pisp_fe_reg_read(fe, FE_STATUS);
+ out_status = pisp_fe_reg_read(fe, FE_OUTPUT_STATUS);
+ frame_status = pisp_fe_reg_read(fe, FE_FRAME_STATUS);
+ error_status = pisp_fe_reg_read(fe, FE_ERROR_STATUS);
+
+ int_status = pisp_fe_reg_read(fe, FE_INT_STATUS);
+ pisp_fe_reg_write(fe, FE_INT_STATUS, int_status);
+
+ trace_fe_irq(status, out_status, frame_status, error_status,
+ int_status);
+
+ /* We do not report interrupts for the input/stream pad. */
+ for (unsigned int i = 0; i < FE_NUM_PADS - 1; i++) {
+ sof[i] = !!(int_status & FE_INT_SOF);
+ eof[i] = !!(int_status & FE_INT_EOF);
+ }
+}
+
+static bool pisp_fe_validate_output(struct pisp_fe_config const *cfg,
+ unsigned int c, struct v4l2_format const *f)
+{
+ unsigned int wbytes;
+
+ wbytes = cfg->ch[c].output.format.width;
+ if (cfg->ch[c].output.format.format & PISP_IMAGE_FORMAT_BPS_MASK)
+ wbytes *= 2;
+
+ /* Check output image dimensions are nonzero and not too big */
+ if (cfg->ch[c].output.format.width < 2 ||
+ cfg->ch[c].output.format.height < 2 ||
+ cfg->ch[c].output.format.height > f->fmt.pix.height ||
+ cfg->ch[c].output.format.stride > f->fmt.pix.bytesperline ||
+ wbytes > f->fmt.pix.bytesperline)
+ return false;
+
+ /* Check for zero-sized crops, which could cause lockup */
+ if ((cfg->global.enables & PISP_FE_ENABLE_CROP(c)) &&
+ ((cfg->ch[c].crop.offset_x >= (cfg->input.format.width & ~1) ||
+ cfg->ch[c].crop.offset_y >= cfg->input.format.height ||
+ cfg->ch[c].crop.width < 2 || cfg->ch[c].crop.height < 2)))
+ return false;
+
+ if ((cfg->global.enables & PISP_FE_ENABLE_DOWNSCALE(c)) &&
+ (cfg->ch[c].downscale.output_width < 2 ||
+ cfg->ch[c].downscale.output_height < 2))
+ return false;
+
+ return true;
+}
+
+static bool pisp_fe_validate_stats(struct pisp_fe_config const *cfg)
+{
+ /* Check for zero-sized crop, which could cause lockup */
+ return (!(cfg->global.enables & PISP_FE_ENABLE_STATS_CROP) ||
+ (cfg->stats_crop.offset_x < (cfg->input.format.width & ~1) &&
+ cfg->stats_crop.offset_y < cfg->input.format.height &&
+ cfg->stats_crop.width >= 2 && cfg->stats_crop.height >= 2));
+}
+
+int pisp_fe_validate_config(struct pisp_fe_device *fe,
+ struct pisp_fe_config *cfg,
+ struct v4l2_format const *f0,
+ struct v4l2_format const *f1)
+{
+ /*
+ * Check the input is enabled, streaming and has nonzero size;
+ * to avoid cases where the hardware might lock up or try to
+ * read inputs from memory (which this driver doesn't support).
+ */
+ if (!(cfg->global.enables & PISP_FE_ENABLE_INPUT) ||
+ cfg->input.streaming != 1 || cfg->input.format.width < 2 ||
+ cfg->input.format.height < 2) {
+ pisp_fe_err(fe, "%s: Input config not valid", __func__);
+ return -EINVAL;
+ }
+
+ for (unsigned int i = 0; i < PISP_FE_NUM_OUTPUTS; i++) {
+ if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i))) {
+ if (cfg->global.enables &
+ PISP_FE_ENABLE_OUTPUT_CLUSTER(i)) {
+ pisp_fe_err(fe, "%s: Output %u not valid",
+ __func__, i);
+ return -EINVAL;
+ }
+ continue;
+ }
+
+ if (!pisp_fe_validate_output(cfg, i, i ? f1 : f0))
+ return -EINVAL;
+ }
+
+ if ((cfg->global.enables & PISP_FE_ENABLE_STATS_CLUSTER) &&
+ !pisp_fe_validate_stats(cfg)) {
+ pisp_fe_err(fe, "%s: Stats config not valid", __func__);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs,
+ struct pisp_fe_config *cfg)
+{
+ u64 addr;
+ u32 status;
+
+ /*
+ * Check output buffers exist and outputs are correctly configured.
+ * If valid, set the buffer's DMA address; otherwise disable.
+ */
+ for (unsigned int i = 0; i < PISP_FE_NUM_OUTPUTS; i++) {
+ struct vb2_buffer *buf = vb2_bufs[FE_OUTPUT0_PAD + i];
+
+ if (!(cfg->global.enables & PISP_FE_ENABLE_OUTPUT(i)))
+ continue;
+
+ addr = vb2_dma_contig_plane_dma_addr(buf, 0);
+ cfg->output_buffer[i].addr_lo = addr & 0xffffffff;
+ cfg->output_buffer[i].addr_hi = addr >> 32;
+ }
+
+ if (vb2_bufs[FE_STATS_PAD]) {
+ addr = vb2_dma_contig_plane_dma_addr(vb2_bufs[FE_STATS_PAD], 0);
+ cfg->stats_buffer.addr_lo = addr & 0xffffffff;
+ cfg->stats_buffer.addr_hi = addr >> 32;
+ }
+
+ /* Set up ILINES interrupts 3/4 of the way down each output */
+ cfg->ch[0].output.ilines =
+ max(0x80u, (3u * cfg->ch[0].output.format.height) >> 2);
+ cfg->ch[1].output.ilines =
+ max(0x80u, (3u * cfg->ch[1].output.format.height) >> 2);
+
+ /*
+ * The hardware must have consumed the previous config by now.
+ * This read of status also serves as a memory barrier before the
+ * sequence of relaxed writes which follow.
+ */
+ status = pisp_fe_reg_read(fe, FE_STATUS);
+ if (WARN_ON(status & FE_STATUS_QUEUED))
+ return;
+
+ /*
+ * Unconditionally write buffers, global and input parameters.
+ * Write cropping and output parameters whenever they are enabled.
+ * Selectively write other parameters that have been marked as
+ * changed through the dirty flags.
+ */
+ pisp_fe_config_write(fe, cfg, 0,
+ offsetof(struct pisp_fe_config, decompress));
+ cfg->dirty_flags_extra &= ~PISP_FE_DIRTY_GLOBAL;
+ cfg->dirty_flags &= ~PISP_FE_ENABLE_INPUT;
+ cfg->dirty_flags |= (cfg->global.enables &
+ (PISP_FE_ENABLE_STATS_CROP |
+ PISP_FE_ENABLE_OUTPUT_CLUSTER(0) |
+ PISP_FE_ENABLE_OUTPUT_CLUSTER(1)));
+ for (unsigned int i = 0; i < ARRAY_SIZE(pisp_fe_config_map); i++) {
+ const struct pisp_fe_config_param *p = &pisp_fe_config_map[i];
+
+ if (cfg->dirty_flags & p->dirty_flags ||
+ cfg->dirty_flags_extra & p->dirty_flags_extra)
+ pisp_fe_config_write(fe, cfg, p->offset, p->size);
+ }
+
+ /* This final non-relaxed write serves as a memory barrier */
+ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_QUEUE);
+}
+
+void pisp_fe_start(struct pisp_fe_device *fe)
+{
+ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_RESET);
+ pisp_fe_reg_write(fe, FE_INT_STATUS, ~0);
+ pisp_fe_reg_write(fe, FE_INT_EN, FE_INT_EOF | FE_INT_SOF |
+ FE_INT_LINES0 | FE_INT_LINES1);
+ fe->inframe_count = 0;
+}
+
+void pisp_fe_stop(struct pisp_fe_device *fe)
+{
+ pisp_fe_reg_write(fe, FE_INT_EN, 0);
+ pisp_fe_reg_write(fe, FE_CONTROL, FE_CONTROL_ABORT);
+ usleep_range(1000, 2000);
+ WARN_ON(pisp_fe_reg_read(fe, FE_STATUS));
+ pisp_fe_reg_write(fe, FE_INT_STATUS, ~0);
+}
+
+static int pisp_fe_init_state(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state)
+{
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD);
+ *fmt = cfe_default_format;
+ fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16;
+
+ fmt = v4l2_subdev_state_get_format(state, FE_CONFIG_PAD);
+ fmt->code = MEDIA_BUS_FMT_FIXED;
+ fmt->width = sizeof(struct pisp_fe_config);
+ fmt->height = 1;
+
+ fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT0_PAD);
+ *fmt = cfe_default_format;
+ fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16;
+
+ fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT1_PAD);
+ *fmt = cfe_default_format;
+ fmt->code = MEDIA_BUS_FMT_SRGGB16_1X16;
+
+ fmt = v4l2_subdev_state_get_format(state, FE_STATS_PAD);
+ fmt->code = MEDIA_BUS_FMT_FIXED;
+ fmt->width = sizeof(struct pisp_statistics);
+ fmt->height = 1;
+
+ return 0;
+}
+
+static int pisp_fe_pad_set_fmt(struct v4l2_subdev *sd,
+ struct v4l2_subdev_state *state,
+ struct v4l2_subdev_format *format)
+{
+ struct v4l2_mbus_framefmt *fmt;
+ const struct cfe_fmt *cfe_fmt;
+
+ /* TODO: format propagation to source pads */
+ /* TODO: format validation */
+
+ switch (format->pad) {
+ case FE_STREAM_PAD:
+ cfe_fmt = find_format_by_code(format->format.code);
+ if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT))
+ cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16);
+
+ format->format.code = cfe_fmt->code;
+ format->format.field = V4L2_FIELD_NONE;
+
+ fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD);
+ *fmt = format->format;
+
+ fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT0_PAD);
+ *fmt = format->format;
+
+ fmt = v4l2_subdev_state_get_format(state, FE_OUTPUT1_PAD);
+ *fmt = format->format;
+
+ return 0;
+
+ case FE_OUTPUT0_PAD:
+ case FE_OUTPUT1_PAD: {
+ /*
+ * TODO: we should allow scaling and cropping by allowing the
+ * user to set the size here.
+ */
+ struct v4l2_mbus_framefmt *sink_fmt, *source_fmt;
+ u32 sink_code;
+ u32 code;
+
+ cfe_fmt = find_format_by_code(format->format.code);
+ if (!cfe_fmt || !(cfe_fmt->flags & CFE_FORMAT_FLAG_FE_OUT))
+ cfe_fmt = find_format_by_code(MEDIA_BUS_FMT_SRGGB16_1X16);
+
+ format->format.code = cfe_fmt->code;
+
+ sink_fmt = v4l2_subdev_state_get_format(state, FE_STREAM_PAD);
+ if (!sink_fmt)
+ return -EINVAL;
+
+ source_fmt = v4l2_subdev_state_get_format(state, format->pad);
+ if (!source_fmt)
+ return -EINVAL;
+
+ sink_code = sink_fmt->code;
+ code = format->format.code;
+
+ /*
+ * If the source code from the user does not match the code in
+ * the sink pad, check that the source code matches the
+ * compressed version of the sink code.
+ */
+
+ if (code != sink_code &&
+ code == cfe_find_compressed_code(sink_code))
+ source_fmt->code = code;
+
+ return 0;
+ }
+
+ case FE_CONFIG_PAD:
+ case FE_STATS_PAD:
+ default:
+ return v4l2_subdev_get_fmt(sd, state, format);
+ }
+}
+
+static const struct v4l2_subdev_pad_ops pisp_fe_subdev_pad_ops = {
+ .get_fmt = v4l2_subdev_get_fmt,
+ .set_fmt = pisp_fe_pad_set_fmt,
+ .link_validate = v4l2_subdev_link_validate_default,
+};
+
+static int pisp_fe_link_validate(struct media_link *link)
+{
+ struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(link->sink->entity);
+ struct pisp_fe_device *fe = container_of(sd, struct pisp_fe_device, sd);
+
+ pisp_fe_dbg(fe, "%s: link \"%s\":%u -> \"%s\":%u\n", __func__,
+ link->source->entity->name, link->source->index,
+ link->sink->entity->name, link->sink->index);
+
+ if (link->sink->index == FE_STREAM_PAD)
+ return v4l2_subdev_link_validate(link);
+
+ if (link->sink->index == FE_CONFIG_PAD)
+ return 0;
+
+ return -EINVAL;
+}
+
+static const struct media_entity_operations pisp_fe_entity_ops = {
+ .link_validate = pisp_fe_link_validate,
+};
+
+static const struct v4l2_subdev_ops pisp_fe_subdev_ops = {
+ .pad = &pisp_fe_subdev_pad_ops,
+};
+
+static const struct v4l2_subdev_internal_ops pisp_fe_internal_ops = {
+ .init_state = pisp_fe_init_state,
+};
+
+int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs)
+{
+ int ret;
+
+ debugfs_create_file("fe_regs", 0440, debugfs, fe, &pisp_fe_regs_fops);
+
+ fe->hw_revision = pisp_fe_reg_read(fe, FE_VERSION);
+ pisp_fe_info(fe, "PiSP FE HW v%u.%u\n",
+ (fe->hw_revision >> 24) & 0xff,
+ (fe->hw_revision >> 20) & 0x0f);
+
+ fe->pad[FE_STREAM_PAD].flags =
+ MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
+ fe->pad[FE_CONFIG_PAD].flags = MEDIA_PAD_FL_SINK;
+ fe->pad[FE_OUTPUT0_PAD].flags = MEDIA_PAD_FL_SOURCE;
+ fe->pad[FE_OUTPUT1_PAD].flags = MEDIA_PAD_FL_SOURCE;
+ fe->pad[FE_STATS_PAD].flags = MEDIA_PAD_FL_SOURCE;
+
+ ret = media_entity_pads_init(&fe->sd.entity, ARRAY_SIZE(fe->pad),
+ fe->pad);
+ if (ret)
+ return ret;
+
+ /* Initialize subdev */
+ v4l2_subdev_init(&fe->sd, &pisp_fe_subdev_ops);
+ fe->sd.internal_ops = &pisp_fe_internal_ops;
+ fe->sd.entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
+ fe->sd.entity.ops = &pisp_fe_entity_ops;
+ fe->sd.entity.name = "pisp-fe";
+ fe->sd.flags = V4L2_SUBDEV_FL_HAS_DEVNODE;
+ fe->sd.owner = THIS_MODULE;
+ snprintf(fe->sd.name, sizeof(fe->sd.name), "pisp-fe");
+
+ ret = v4l2_subdev_init_finalize(&fe->sd);
+ if (ret)
+ goto err_entity_cleanup;
+
+ ret = v4l2_device_register_subdev(fe->v4l2_dev, &fe->sd);
+ if (ret) {
+ pisp_fe_err(fe, "Failed register pisp fe subdev (%d)\n", ret);
+ goto err_subdev_cleanup;
+ }
+
+ /* Must be in IDLE state (STATUS == 0) here. */
+ WARN_ON(pisp_fe_reg_read(fe, FE_STATUS));
+
+ return 0;
+
+err_subdev_cleanup:
+ v4l2_subdev_cleanup(&fe->sd);
+err_entity_cleanup:
+ media_entity_cleanup(&fe->sd.entity);
+
+ return ret;
+}
+
+void pisp_fe_uninit(struct pisp_fe_device *fe)
+{
+ v4l2_device_unregister_subdev(&fe->sd);
+ v4l2_subdev_cleanup(&fe->sd);
+ media_entity_cleanup(&fe->sd.entity);
+}
diff --git a/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.h b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.h
new file mode 100644
index 000000000000..54d506e19cf2
--- /dev/null
+++ b/drivers/media/platform/raspberrypi/rp1-cfe/pisp-fe.h
@@ -0,0 +1,53 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * PiSP Front End Driver
+ *
+ * Copyright (c) 2021-2024 Raspberry Pi Ltd.
+ */
+#ifndef _PISP_FE_H_
+#define _PISP_FE_H_
+
+#include <linux/debugfs.h>
+#include <linux/io.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+
+#include <media/media-device.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+
+#include <linux/media/raspberrypi/pisp_fe_config.h>
+
+enum pisp_fe_pads {
+ FE_STREAM_PAD,
+ FE_CONFIG_PAD,
+ FE_OUTPUT0_PAD,
+ FE_OUTPUT1_PAD,
+ FE_STATS_PAD,
+ FE_NUM_PADS
+};
+
+struct pisp_fe_device {
+ /* Parent V4l2 device */
+ struct v4l2_device *v4l2_dev;
+ void __iomem *base;
+ u32 hw_revision;
+
+ u16 inframe_count;
+ struct media_pad pad[FE_NUM_PADS];
+ struct v4l2_subdev sd;
+};
+
+void pisp_fe_isr(struct pisp_fe_device *fe, bool *sof, bool *eof);
+int pisp_fe_validate_config(struct pisp_fe_device *fe,
+ struct pisp_fe_config *cfg,
+ struct v4l2_format const *f0,
+ struct v4l2_format const *f1);
+void pisp_fe_submit_job(struct pisp_fe_device *fe, struct vb2_buffer **vb2_bufs,
+ struct pisp_fe_config *cfg);
+void pisp_fe_start(struct pisp_fe_device *fe);
+void pisp_fe_stop(struct pisp_fe_device *fe);
+int pisp_fe_init(struct pisp_fe_device *fe, struct dentry *debugfs);
+void pisp_fe_uninit(struct pisp_fe_device *fe);
+
+#endif
diff --git a/drivers/media/platform/renesas/rcar-csi2.c b/drivers/media/platform/renesas/rcar-csi2.c
index c419ddb4c5a2..27ffdd28cbf7 100644
--- a/drivers/media/platform/renesas/rcar-csi2.c
+++ b/drivers/media/platform/renesas/rcar-csi2.c
@@ -135,13 +135,23 @@ struct rcar_csi2;
/* V4H BASE registers */
#define V4H_N_LANES_REG 0x0004
#define V4H_CSI2_RESETN_REG 0x0008
+
#define V4H_PHY_MODE_REG 0x001c
+#define V4H_PHY_MODE_DPHY 0
+#define V4H_PHY_MODE_CPHY 1
+
#define V4H_PHY_SHUTDOWNZ_REG 0x0040
#define V4H_DPHY_RSTZ_REG 0x0044
#define V4H_FLDC_REG 0x0804
#define V4H_FLDD_REG 0x0808
#define V4H_IDIC_REG 0x0810
+
#define V4H_PHY_EN_REG 0x2000
+#define V4H_PHY_EN_ENABLE_3 BIT(7)
+#define V4H_PHY_EN_ENABLE_2 BIT(6)
+#define V4H_PHY_EN_ENABLE_1 BIT(5)
+#define V4H_PHY_EN_ENABLE_0 BIT(4)
+#define V4H_PHY_EN_ENABLE_CLK BIT(0)
#define V4H_ST_PHYST_REG 0x2814
#define V4H_ST_PHYST_ST_PHY_READY BIT(31)
@@ -237,17 +247,37 @@ static const struct rcsi2_cphy_setting cphy_setting_table_r8a779g0[] = {
{ /* sentinel */ },
};
+/* V4M registers */
+#define V4M_OVR1_REG 0x0848
+#define V4M_OVR1_FORCERXMODE_3 BIT(12)
+#define V4M_OVR1_FORCERXMODE_2 BIT(11)
+#define V4M_OVR1_FORCERXMODE_1 BIT(10)
+#define V4M_OVR1_FORCERXMODE_0 BIT(9)
+
+#define V4M_FRXM_REG 0x2004
+#define V4M_FRXM_FORCERXMODE_3 BIT(3)
+#define V4M_FRXM_FORCERXMODE_2 BIT(2)
+#define V4M_FRXM_FORCERXMODE_1 BIT(1)
+#define V4M_FRXM_FORCERXMODE_0 BIT(0)
+
+#define V4M_PHYPLL_REG 0x02050
+#define V4M_CSI0CLKFCPR_REG 0x02054
+#define V4M_PHTW_REG 0x02060
+#define V4M_PHTR_REG 0x02064
+#define V4M_PHTC_REG 0x02068
+
struct phtw_value {
- u16 data;
- u16 code;
+ u8 data;
+ u8 code;
};
-struct rcsi2_mbps_reg {
+struct rcsi2_mbps_info {
u16 mbps;
- u16 reg;
+ u8 reg;
+ u16 osc_freq; /* V4M */
};
-static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = {
+static const struct rcsi2_mbps_info phtw_mbps_v3u[] = {
{ .mbps = 1500, .reg = 0xcc },
{ .mbps = 1550, .reg = 0x1d },
{ .mbps = 1600, .reg = 0x27 },
@@ -272,7 +302,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = {
{ /* sentinel */ },
};
-static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = {
+static const struct rcsi2_mbps_info phtw_mbps_h3_v3h_m3n[] = {
{ .mbps = 80, .reg = 0x86 },
{ .mbps = 90, .reg = 0x86 },
{ .mbps = 100, .reg = 0x87 },
@@ -292,7 +322,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = {
{ /* sentinel */ },
};
-static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = {
+static const struct rcsi2_mbps_info phtw_mbps_v3m_e3[] = {
{ .mbps = 80, .reg = 0x00 },
{ .mbps = 90, .reg = 0x20 },
{ .mbps = 100, .reg = 0x40 },
@@ -336,7 +366,7 @@ static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = {
#define PHYPLL_REG 0x68
#define PHYPLL_HSFREQRANGE(n) ((n) << 16)
-static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = {
+static const struct rcsi2_mbps_info hsfreqrange_v3u[] = {
{ .mbps = 80, .reg = 0x00 },
{ .mbps = 90, .reg = 0x10 },
{ .mbps = 100, .reg = 0x20 },
@@ -402,7 +432,7 @@ static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = {
{ /* sentinel */ },
};
-static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = {
+static const struct rcsi2_mbps_info hsfreqrange_h3_v3h_m3n[] = {
{ .mbps = 80, .reg = 0x00 },
{ .mbps = 90, .reg = 0x10 },
{ .mbps = 100, .reg = 0x20 },
@@ -449,7 +479,7 @@ static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = {
{ /* sentinel */ },
};
-static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = {
+static const struct rcsi2_mbps_info hsfreqrange_m3w[] = {
{ .mbps = 80, .reg = 0x00 },
{ .mbps = 90, .reg = 0x10 },
{ .mbps = 100, .reg = 0x20 },
@@ -496,6 +526,73 @@ static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = {
{ /* sentinel */ },
};
+static const struct rcsi2_mbps_info hsfreqrange_v4m[] = {
+ { .mbps = 80, .reg = 0x00, .osc_freq = 0x01a9 },
+ { .mbps = 90, .reg = 0x10, .osc_freq = 0x01a9 },
+ { .mbps = 100, .reg = 0x20, .osc_freq = 0x01a9 },
+ { .mbps = 110, .reg = 0x30, .osc_freq = 0x01a9 },
+ { .mbps = 120, .reg = 0x01, .osc_freq = 0x01a9 },
+ { .mbps = 130, .reg = 0x11, .osc_freq = 0x01a9 },
+ { .mbps = 140, .reg = 0x21, .osc_freq = 0x01a9 },
+ { .mbps = 150, .reg = 0x31, .osc_freq = 0x01a9 },
+ { .mbps = 160, .reg = 0x02, .osc_freq = 0x01a9 },
+ { .mbps = 170, .reg = 0x12, .osc_freq = 0x01a9 },
+ { .mbps = 180, .reg = 0x22, .osc_freq = 0x01a9 },
+ { .mbps = 190, .reg = 0x32, .osc_freq = 0x01a9 },
+ { .mbps = 205, .reg = 0x03, .osc_freq = 0x01a9 },
+ { .mbps = 220, .reg = 0x13, .osc_freq = 0x01a9 },
+ { .mbps = 235, .reg = 0x23, .osc_freq = 0x01a9 },
+ { .mbps = 250, .reg = 0x33, .osc_freq = 0x01a9 },
+ { .mbps = 275, .reg = 0x04, .osc_freq = 0x01a9 },
+ { .mbps = 300, .reg = 0x14, .osc_freq = 0x01a9 },
+ { .mbps = 325, .reg = 0x25, .osc_freq = 0x01a9 },
+ { .mbps = 350, .reg = 0x35, .osc_freq = 0x01a9 },
+ { .mbps = 400, .reg = 0x05, .osc_freq = 0x01a9 },
+ { .mbps = 450, .reg = 0x16, .osc_freq = 0x01a9 },
+ { .mbps = 500, .reg = 0x26, .osc_freq = 0x01a9 },
+ { .mbps = 550, .reg = 0x37, .osc_freq = 0x01a9 },
+ { .mbps = 600, .reg = 0x07, .osc_freq = 0x01a9 },
+ { .mbps = 650, .reg = 0x18, .osc_freq = 0x01a9 },
+ { .mbps = 700, .reg = 0x28, .osc_freq = 0x01a9 },
+ { .mbps = 750, .reg = 0x39, .osc_freq = 0x01a9 },
+ { .mbps = 800, .reg = 0x09, .osc_freq = 0x01a9 },
+ { .mbps = 850, .reg = 0x19, .osc_freq = 0x01a9 },
+ { .mbps = 900, .reg = 0x29, .osc_freq = 0x01a9 },
+ { .mbps = 950, .reg = 0x3a, .osc_freq = 0x01a9 },
+ { .mbps = 1000, .reg = 0x0a, .osc_freq = 0x01a9 },
+ { .mbps = 1050, .reg = 0x1a, .osc_freq = 0x01a9 },
+ { .mbps = 1100, .reg = 0x2a, .osc_freq = 0x01a9 },
+ { .mbps = 1150, .reg = 0x3b, .osc_freq = 0x01a9 },
+ { .mbps = 1200, .reg = 0x0b, .osc_freq = 0x01a9 },
+ { .mbps = 1250, .reg = 0x1b, .osc_freq = 0x01a9 },
+ { .mbps = 1300, .reg = 0x2b, .osc_freq = 0x01a9 },
+ { .mbps = 1350, .reg = 0x3c, .osc_freq = 0x01a9 },
+ { .mbps = 1400, .reg = 0x0c, .osc_freq = 0x01a9 },
+ { .mbps = 1450, .reg = 0x1c, .osc_freq = 0x01a9 },
+ { .mbps = 1500, .reg = 0x2c, .osc_freq = 0x01a9 },
+ { .mbps = 1550, .reg = 0x3d, .osc_freq = 0x0108 },
+ { .mbps = 1600, .reg = 0x0d, .osc_freq = 0x0110 },
+ { .mbps = 1650, .reg = 0x1d, .osc_freq = 0x0119 },
+ { .mbps = 1700, .reg = 0x2e, .osc_freq = 0x0121 },
+ { .mbps = 1750, .reg = 0x3e, .osc_freq = 0x012a },
+ { .mbps = 1800, .reg = 0x0e, .osc_freq = 0x0132 },
+ { .mbps = 1850, .reg = 0x1e, .osc_freq = 0x013b },
+ { .mbps = 1900, .reg = 0x2f, .osc_freq = 0x0143 },
+ { .mbps = 1950, .reg = 0x3f, .osc_freq = 0x014c },
+ { .mbps = 2000, .reg = 0x0f, .osc_freq = 0x0154 },
+ { .mbps = 2050, .reg = 0x40, .osc_freq = 0x015d },
+ { .mbps = 2100, .reg = 0x41, .osc_freq = 0x0165 },
+ { .mbps = 2150, .reg = 0x42, .osc_freq = 0x016e },
+ { .mbps = 2200, .reg = 0x43, .osc_freq = 0x0176 },
+ { .mbps = 2250, .reg = 0x44, .osc_freq = 0x017f },
+ { .mbps = 2300, .reg = 0x45, .osc_freq = 0x0187 },
+ { .mbps = 2350, .reg = 0x46, .osc_freq = 0x0190 },
+ { .mbps = 2400, .reg = 0x47, .osc_freq = 0x0198 },
+ { .mbps = 2450, .reg = 0x48, .osc_freq = 0x01a1 },
+ { .mbps = 2500, .reg = 0x49, .osc_freq = 0x01a9 },
+ { /* sentinel */ },
+};
+
/* PHY ESC Error Monitor */
#define PHEERM_REG 0x74
@@ -584,13 +681,19 @@ enum rcar_csi2_pads {
NR_OF_RCAR_CSI2_PAD,
};
+struct rcsi2_register_layout {
+ unsigned int phtw;
+ unsigned int phypll;
+};
+
struct rcar_csi2_info {
+ const struct rcsi2_register_layout *regs;
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,
struct v4l2_subdev_state *state);
void (*enter_standby)(struct rcar_csi2 *priv);
- const struct rcsi2_mbps_reg *hsfreqrange;
+ const struct rcsi2_mbps_info *hsfreqrange;
unsigned int csi0clkfreqrange;
unsigned int num_channels;
bool clear_ulps;
@@ -656,6 +759,70 @@ static void rcsi2_write16(struct rcar_csi2 *priv, unsigned int reg, u16 data)
iowrite16(data, priv->base + reg);
}
+static int rcsi2_phtw_write(struct rcar_csi2 *priv, u8 data, u8 code)
+{
+ unsigned int timeout;
+
+ rcsi2_write(priv, priv->info->regs->phtw,
+ PHTW_DWEN | PHTW_TESTDIN_DATA(data) |
+ PHTW_CWEN | PHTW_TESTDIN_CODE(code));
+
+ /* Wait for DWEN and CWEN to be cleared by hardware. */
+ for (timeout = 0; timeout <= 20; timeout++) {
+ if (!(rcsi2_read(priv, priv->info->regs->phtw) & (PHTW_DWEN | PHTW_CWEN)))
+ return 0;
+
+ usleep_range(1000, 2000);
+ }
+
+ dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n");
+
+ return -ETIMEDOUT;
+}
+
+static int rcsi2_phtw_write_array(struct rcar_csi2 *priv,
+ const struct phtw_value *values,
+ unsigned int size)
+{
+ int ret;
+
+ for (unsigned int i = 0; i < size; i++) {
+ ret = rcsi2_phtw_write(priv, values[i].data, values[i].code);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct rcsi2_mbps_info *
+rcsi2_mbps_to_info(struct rcar_csi2 *priv,
+ const struct rcsi2_mbps_info *infotable, unsigned int mbps)
+{
+ const struct rcsi2_mbps_info *info;
+ const struct rcsi2_mbps_info *prev = NULL;
+
+ if (mbps < infotable->mbps)
+ dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps",
+ mbps, infotable->mbps);
+
+ for (info = infotable; info->mbps != 0; info++) {
+ if (info->mbps >= mbps)
+ break;
+ prev = info;
+ }
+
+ if (!info->mbps) {
+ dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps);
+ return NULL;
+ }
+
+ if (prev && ((mbps - prev->mbps) <= (info->mbps - mbps)))
+ info = prev;
+
+ return info;
+}
+
static void rcsi2_enter_standby_gen3(struct rcar_csi2 *priv)
{
rcsi2_write(priv, PHYCNT_REG, 0);
@@ -708,29 +875,13 @@ static int rcsi2_wait_phy_start(struct rcar_csi2 *priv,
static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps)
{
- const struct rcsi2_mbps_reg *hsfreq;
- const struct rcsi2_mbps_reg *hsfreq_prev = NULL;
-
- if (mbps < priv->info->hsfreqrange->mbps)
- dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps",
- mbps, priv->info->hsfreqrange->mbps);
-
- for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) {
- if (hsfreq->mbps >= mbps)
- break;
- hsfreq_prev = hsfreq;
- }
+ const struct rcsi2_mbps_info *info;
- if (!hsfreq->mbps) {
- dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps);
+ info = rcsi2_mbps_to_info(priv, priv->info->hsfreqrange, mbps);
+ if (!info)
return -ERANGE;
- }
- if (hsfreq_prev &&
- ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps)))
- hsfreq = hsfreq_prev;
-
- rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg));
+ rcsi2_write(priv, priv->info->regs->phypll, PHYPLL_HSFREQRANGE(info->reg));
return 0;
}
@@ -1092,11 +1243,11 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv,
rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0);
/* PHY static setting */
- rcsi2_write(priv, V4H_PHY_EN_REG, BIT(0));
+ rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK);
rcsi2_write(priv, V4H_FLDC_REG, 0);
rcsi2_write(priv, V4H_FLDD_REG, 0);
rcsi2_write(priv, V4H_IDIC_REG, 0);
- rcsi2_write(priv, V4H_PHY_MODE_REG, BIT(0));
+ rcsi2_write(priv, V4H_PHY_MODE_REG, V4H_PHY_MODE_CPHY);
rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1);
/* Reset CSI2 */
@@ -1131,6 +1282,195 @@ static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv,
return 0;
}
+static int rcsi2_d_phy_setting_v4m(struct rcar_csi2 *priv, int data_rate)
+{
+ unsigned int timeout;
+ int ret;
+
+ static const struct phtw_value step1[] = {
+ { .data = 0x00, .code = 0x00 },
+ { .data = 0x00, .code = 0x1e },
+ };
+
+ /* Shutdown and reset PHY. */
+ rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0));
+ rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0));
+
+ /* Start internal calibration (POR). */
+ ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1));
+ if (ret)
+ return ret;
+
+ /* Wait for POR to complete. */
+ for (timeout = 10; timeout > 0; timeout--) {
+ if ((rcsi2_read(priv, V4M_PHTR_REG) & 0xf0000) == 0x70000)
+ break;
+ usleep_range(1000, 2000);
+ }
+
+ if (!timeout) {
+ dev_err(priv->dev, "D-PHY calibration failed\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
+
+static int rcsi2_set_osc_freq(struct rcar_csi2 *priv, unsigned int mbps)
+{
+ const struct rcsi2_mbps_info *info;
+ struct phtw_value steps[] = {
+ { .data = 0x00, .code = 0x00 },
+ { .code = 0xe2 }, /* Data filled in below. */
+ { .code = 0xe3 }, /* Data filled in below. */
+ { .data = 0x01, .code = 0xe4 },
+ };
+
+ info = rcsi2_mbps_to_info(priv, priv->info->hsfreqrange, mbps);
+ if (!info)
+ return -ERANGE;
+
+ /* Fill in data for command. */
+ steps[1].data = (info->osc_freq & 0x00ff) >> 0;
+ steps[2].data = (info->osc_freq & 0x0f00) >> 8;
+
+ return rcsi2_phtw_write_array(priv, steps, ARRAY_SIZE(steps));
+}
+
+static int rcsi2_init_common_v4m(struct rcar_csi2 *priv, unsigned int mbps)
+{
+ int ret;
+
+ static const struct phtw_value step1[] = {
+ { .data = 0x00, .code = 0x00 },
+ { .data = 0x3c, .code = 0x08 },
+ };
+
+ static const struct phtw_value step2[] = {
+ { .data = 0x00, .code = 0x00 },
+ { .data = 0x80, .code = 0xe0 },
+ { .data = 0x01, .code = 0xe1 },
+ { .data = 0x06, .code = 0x00 },
+ { .data = 0x0f, .code = 0x11 },
+ { .data = 0x08, .code = 0x00 },
+ { .data = 0x0f, .code = 0x11 },
+ { .data = 0x0a, .code = 0x00 },
+ { .data = 0x0f, .code = 0x11 },
+ { .data = 0x0c, .code = 0x00 },
+ { .data = 0x0f, .code = 0x11 },
+ { .data = 0x01, .code = 0x00 },
+ { .data = 0x31, .code = 0xaa },
+ { .data = 0x05, .code = 0x00 },
+ { .data = 0x05, .code = 0x09 },
+ { .data = 0x07, .code = 0x00 },
+ { .data = 0x05, .code = 0x09 },
+ { .data = 0x09, .code = 0x00 },
+ { .data = 0x05, .code = 0x09 },
+ { .data = 0x0b, .code = 0x00 },
+ { .data = 0x05, .code = 0x09 },
+ };
+
+ if (priv->info->hsfreqrange) {
+ ret = rcsi2_set_phypll(priv, mbps);
+ if (ret)
+ return ret;
+
+ ret = rcsi2_set_osc_freq(priv, mbps);
+ if (ret)
+ return ret;
+ }
+
+ if (mbps <= 1500) {
+ ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1));
+ if (ret)
+ return ret;
+ }
+
+ if (priv->info->csi0clkfreqrange)
+ rcsi2_write(priv, V4M_CSI0CLKFCPR_REG,
+ CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange));
+
+ rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK |
+ V4H_PHY_EN_ENABLE_0 | V4H_PHY_EN_ENABLE_1 |
+ V4H_PHY_EN_ENABLE_2 | V4H_PHY_EN_ENABLE_3);
+
+ if (mbps > 1500) {
+ ret = rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2));
+ if (ret)
+ return ret;
+ }
+
+ return ret;
+}
+
+static int rcsi2_start_receiver_v4m(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 mbps;
+ int ret;
+
+ /* Calculate parameters */
+ fmt = v4l2_subdev_state_get_format(state, RCAR_CSI2_SINK);
+ format = rcsi2_code_to_fmt(fmt->code);
+ if (!format)
+ return -EINVAL;
+
+ ret = rcsi2_get_active_lanes(priv, &lanes);
+ if (ret)
+ return ret;
+
+ mbps = rcsi2_calc_mbps(priv, format->bpp, lanes);
+ if (mbps < 0)
+ return mbps;
+
+ /* Reset LINK and PHY */
+ rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0);
+ rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0);
+ rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0);
+ rcsi2_write(priv, V4M_PHTC_REG, PHTC_TESTCLR);
+
+ /* PHY static setting */
+ rcsi2_write(priv, V4H_PHY_EN_REG, V4H_PHY_EN_ENABLE_CLK);
+ rcsi2_write(priv, V4H_FLDC_REG, 0);
+ rcsi2_write(priv, V4H_FLDD_REG, 0);
+ rcsi2_write(priv, V4H_IDIC_REG, 0);
+ rcsi2_write(priv, V4H_PHY_MODE_REG, V4H_PHY_MODE_DPHY);
+ rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1);
+
+ rcsi2_write(priv, V4M_FRXM_REG,
+ V4M_FRXM_FORCERXMODE_0 | V4M_FRXM_FORCERXMODE_1 |
+ V4M_FRXM_FORCERXMODE_2 | V4M_FRXM_FORCERXMODE_3);
+ rcsi2_write(priv, V4M_OVR1_REG,
+ V4M_OVR1_FORCERXMODE_0 | V4M_OVR1_FORCERXMODE_1 |
+ V4M_OVR1_FORCERXMODE_2 | V4M_OVR1_FORCERXMODE_3);
+
+ /* Reset CSI2 */
+ rcsi2_write(priv, V4M_PHTC_REG, 0);
+ rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0));
+
+ /* Common settings */
+ ret = rcsi2_init_common_v4m(priv, mbps);
+ if (ret)
+ return ret;
+
+ /* D-PHY settings */
+ ret = rcsi2_d_phy_setting_v4m(priv, mbps);
+ if (ret)
+ return ret;
+
+ rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 |
+ V4H_ST_PHYST_ST_STOPSTATE_1 |
+ V4H_ST_PHYST_ST_STOPSTATE_2 |
+ V4H_ST_PHYST_ST_STOPSTATE_3);
+
+ rcsi2_write(priv, V4M_FRXM_REG, 0);
+
+ return 0;
+}
+
static int rcsi2_start(struct rcar_csi2 *priv, struct v4l2_subdev_state *state)
{
int ret;
@@ -1451,64 +1791,16 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv)
* NOTE: Magic values are from the datasheet and lack documentation.
*/
-static int rcsi2_phtw_write(struct rcar_csi2 *priv, u16 data, u16 code)
-{
- unsigned int timeout;
-
- rcsi2_write(priv, PHTW_REG,
- PHTW_DWEN | PHTW_TESTDIN_DATA(data) |
- PHTW_CWEN | PHTW_TESTDIN_CODE(code));
-
- /* Wait for DWEN and CWEN to be cleared by hardware. */
- for (timeout = 0; timeout <= 20; timeout++) {
- if (!(rcsi2_read(priv, PHTW_REG) & (PHTW_DWEN | PHTW_CWEN)))
- return 0;
-
- usleep_range(1000, 2000);
- }
-
- dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n");
-
- return -ETIMEDOUT;
-}
-
-static int rcsi2_phtw_write_array(struct rcar_csi2 *priv,
- const struct phtw_value *values)
-{
- const struct phtw_value *value;
- int ret;
-
- for (value = values; value->data || value->code; value++) {
- ret = rcsi2_phtw_write(priv, value->data, value->code);
- if (ret)
- return ret;
- }
-
- return 0;
-}
-
static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps,
- const struct rcsi2_mbps_reg *values, u16 code)
+ const struct rcsi2_mbps_info *values, u8 code)
{
- const struct rcsi2_mbps_reg *value;
- const struct rcsi2_mbps_reg *prev_value = NULL;
-
- for (value = values; value->mbps; value++) {
- if (value->mbps >= mbps)
- break;
- prev_value = value;
- }
+ const struct rcsi2_mbps_info *info;
- if (prev_value &&
- ((mbps - prev_value->mbps) <= (value->mbps - mbps)))
- value = prev_value;
-
- if (!value->mbps) {
- dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps);
+ info = rcsi2_mbps_to_info(priv, values, mbps);
+ if (!info)
return -ERANGE;
- }
- return rcsi2_phtw_write(priv, value->reg, code);
+ return rcsi2_phtw_write(priv, info->reg, code);
}
static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv,
@@ -1520,7 +1812,6 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv,
{ .data = 0x11, .code = 0xe4 },
{ .data = 0x01, .code = 0xe5 },
{ .data = 0x10, .code = 0x04 },
- { /* sentinel */ },
};
static const struct phtw_value step2[] = {
@@ -1529,12 +1820,11 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv,
{ .data = 0x4b, .code = 0xac },
{ .data = 0x03, .code = 0x00 },
{ .data = 0x80, .code = 0x07 },
- { /* sentinel */ },
};
int ret;
- ret = rcsi2_phtw_write_array(priv, step1);
+ ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1));
if (ret)
return ret;
@@ -1549,7 +1839,7 @@ static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv,
return ret;
}
- return rcsi2_phtw_write_array(priv, step2);
+ return rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2));
}
static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps)
@@ -1575,10 +1865,9 @@ static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv)
{ .data = 0xee, .code = 0x54 },
{ .data = 0xee, .code = 0x84 },
{ .data = 0xee, .code = 0x94 },
- { /* sentinel */ },
};
- return rcsi2_phtw_write_array(priv, step1);
+ return rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1));
}
static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
@@ -1587,20 +1876,17 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
/* In case of 1500Mbps or less */
static const struct phtw_value step1[] = {
{ .data = 0xcc, .code = 0xe2 },
- { /* sentinel */ },
};
static const struct phtw_value step2[] = {
{ .data = 0x01, .code = 0xe3 },
{ .data = 0x11, .code = 0xe4 },
{ .data = 0x01, .code = 0xe5 },
- { /* sentinel */ },
};
/* In case of 1500Mbps or less */
static const struct phtw_value step3[] = {
{ .data = 0x38, .code = 0x08 },
- { /* sentinel */ },
};
static const struct phtw_value step4[] = {
@@ -1608,29 +1894,28 @@ static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv,
{ .data = 0x4b, .code = 0xac },
{ .data = 0x03, .code = 0x00 },
{ .data = 0x80, .code = 0x07 },
- { /* sentinel */ },
};
int ret;
if (mbps != 0 && mbps <= 1500)
- ret = rcsi2_phtw_write_array(priv, step1);
+ ret = rcsi2_phtw_write_array(priv, step1, ARRAY_SIZE(step1));
else
ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3u, 0xe2);
if (ret)
return ret;
- ret = rcsi2_phtw_write_array(priv, step2);
+ ret = rcsi2_phtw_write_array(priv, step2, ARRAY_SIZE(step2));
if (ret)
return ret;
if (mbps != 0 && mbps <= 1500) {
- ret = rcsi2_phtw_write_array(priv, step3);
+ ret = rcsi2_phtw_write_array(priv, step3, ARRAY_SIZE(step3));
if (ret)
return ret;
}
- ret = rcsi2_phtw_write_array(priv, step4);
+ ret = rcsi2_phtw_write_array(priv, step4, ARRAY_SIZE(step4));
if (ret)
return ret;
@@ -1714,7 +1999,13 @@ static int rcsi2_probe_resources(struct rcar_csi2 *priv,
return PTR_ERR_OR_ZERO(priv->rstc);
}
+static const struct rcsi2_register_layout rcsi2_registers_gen3 = {
+ .phtw = PHTW_REG,
+ .phypll = PHYPLL_REG,
+};
+
static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
@@ -1726,6 +2017,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_h3es2,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
@@ -1737,6 +2029,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
+ .regs = &rcsi2_registers_gen3,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
.hsfreqrange = hsfreqrange_m3w,
@@ -1745,6 +2038,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = {
+ .regs = &rcsi2_registers_gen3,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
.hsfreqrange = hsfreqrange_m3w,
@@ -1753,6 +2047,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
@@ -1764,6 +2059,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_v3m_e3,
.phy_post_init = rcsi2_phy_post_init_v3m_e3,
.start_receiver = rcsi2_start_receiver_gen3,
@@ -1773,6 +2069,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_h3_v3h_m3n,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
@@ -1783,6 +2080,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_v3m_e3,
.phy_post_init = rcsi2_phy_post_init_v3m_e3,
.start_receiver = rcsi2_start_receiver_gen3,
@@ -1792,6 +2090,7 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = {
+ .regs = &rcsi2_registers_gen3,
.init_phtw = rcsi2_init_phtw_v3u,
.start_receiver = rcsi2_start_receiver_gen3,
.enter_standby = rcsi2_enter_standby_gen3,
@@ -1803,11 +2102,26 @@ static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = {
};
static const struct rcar_csi2_info rcar_csi2_info_r8a779g0 = {
+ .regs = &rcsi2_registers_gen3,
.start_receiver = rcsi2_start_receiver_v4h,
.use_isp = true,
.support_cphy = true,
};
+static const struct rcsi2_register_layout rcsi2_registers_v4m = {
+ .phtw = V4M_PHTW_REG,
+ .phypll = V4M_PHYPLL_REG,
+};
+
+static const struct rcar_csi2_info rcar_csi2_info_r8a779h0 = {
+ .regs = &rcsi2_registers_v4m,
+ .start_receiver = rcsi2_start_receiver_v4m,
+ .hsfreqrange = hsfreqrange_v4m,
+ .csi0clkfreqrange = 0x0c,
+ .use_isp = true,
+ .support_dphy = true,
+};
+
static const struct of_device_id rcar_csi2_of_table[] = {
{
.compatible = "renesas,r8a774a1-csi2",
@@ -1861,6 +2175,10 @@ static const struct of_device_id rcar_csi2_of_table[] = {
.compatible = "renesas,r8a779g0-csi2",
.data = &rcar_csi2_info_r8a779g0,
},
+ {
+ .compatible = "renesas,r8a779h0-csi2",
+ .data = &rcar_csi2_info_r8a779h0,
+ },
{ /* sentinel */ },
};
MODULE_DEVICE_TABLE(of, rcar_csi2_of_table);
@@ -1974,7 +2292,7 @@ static void rcsi2_remove(struct platform_device *pdev)
}
static struct platform_driver rcar_csi2_pdrv = {
- .remove_new = rcsi2_remove,
+ .remove = rcsi2_remove,
.probe = rcsi2_probe,
.driver = {
.name = "rcar-csi2",
diff --git a/drivers/media/platform/renesas/rcar-fcp.c b/drivers/media/platform/renesas/rcar-fcp.c
index bcef7b87da7c..cee9bbce4e3a 100644
--- a/drivers/media/platform/renesas/rcar-fcp.c
+++ b/drivers/media/platform/renesas/rcar-fcp.c
@@ -164,7 +164,7 @@ MODULE_DEVICE_TABLE(of, rcar_fcp_of_match);
static struct platform_driver rcar_fcp_platform_driver = {
.probe = rcar_fcp_probe,
- .remove_new = rcar_fcp_remove,
+ .remove = rcar_fcp_remove,
.driver = {
.name = "rcar-fcp",
.of_match_table = rcar_fcp_of_match,
diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c
index 4512ac338ca5..c515278e3be5 100644
--- a/drivers/media/platform/renesas/rcar-isp.c
+++ b/drivers/media/platform/renesas/rcar-isp.c
@@ -431,7 +431,9 @@ static int risp_probe_resources(struct rcar_isp *isp,
static const struct of_device_id risp_of_id_table[] = {
{ .compatible = "renesas,r8a779a0-isp" },
{ .compatible = "renesas,r8a779g0-isp" },
- { /* sentinel */ },
+ /* Keep above for compatibility with old DTB files. */
+ { .compatible = "renesas,rcar-gen4-isp" },
+ { /* sentinel */ }
};
MODULE_DEVICE_TABLE(of, risp_of_id_table);
@@ -522,7 +524,7 @@ static struct platform_driver rcar_isp_driver = {
.of_match_table = risp_of_id_table,
},
.probe = risp_probe,
- .remove_new = risp_remove,
+ .remove = risp_remove,
};
module_platform_driver(rcar_isp_driver);
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-core.c b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
index 695d884a22d1..ddfb18e6e7a4 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-core.c
@@ -1279,6 +1279,7 @@ static const struct rvin_info rcar_info_gen4 = {
.use_mc = true,
.use_isp = true,
.nv12 = true,
+ .raw10 = true,
.max_width = 4096,
.max_height = 4096,
};
@@ -1443,7 +1444,7 @@ static struct platform_driver rcar_vin_driver = {
.of_match_table = rvin_of_id_table,
},
.probe = rcar_vin_probe,
- .remove_new = rcar_vin_remove,
+ .remove = rcar_vin_remove,
};
module_platform_driver(rcar_vin_driver);
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
index 21d5b2815e86..8773998101ff 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-dma.c
@@ -123,7 +123,9 @@
/* Video n Data Mode Register bits */
#define VNDMR_A8BIT(n) (((n) & 0xff) << 24)
#define VNDMR_A8BIT_MASK (0xff << 24)
+#define VNDMR_RMODE_RAW10 (2 << 19)
#define VNDMR_YMODE_Y8 (1 << 12)
+#define VNDMR_YC_THR (1 << 11)
#define VNDMR_EXRGB (1 << 8)
#define VNDMR_BPSM (1 << 4)
#define VNDMR_ABIT (1 << 2)
@@ -790,6 +792,12 @@ static int rvin_setup(struct rvin_dev *vin)
case MEDIA_BUS_FMT_Y8_1X8:
vnmc |= VNMC_INF_RAW8;
break;
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ vnmc |= VNMC_INF_RGB666;
+ break;
default:
break;
}
@@ -898,6 +906,12 @@ static int rvin_setup(struct rvin_dev *vin)
dmr = 0;
}
break;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ dmr = VNDMR_RMODE_RAW10 | VNDMR_YC_THR;
+ break;
default:
vin_err(vin, "Invalid pixelformat (0x%x)\n",
vin->format.pixelformat);
@@ -1280,6 +1294,22 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd,
if (vin->format.pixelformat != V4L2_PIX_FMT_GREY)
return -EPIPE;
break;
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR10)
+ return -EPIPE;
+ break;
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG10)
+ return -EPIPE;
+ break;
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG10)
+ return -EPIPE;
+ break;
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB10)
+ return -EPIPE;
+ break;
default:
return -EPIPE;
}
@@ -1529,8 +1559,6 @@ static const struct vb2_ops rvin_qops = {
.buf_queue = rvin_buffer_queue,
.start_streaming = rvin_start_streaming_vq,
.stop_streaming = rvin_stop_streaming_vq,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
void rvin_dma_unregister(struct rvin_dev *vin)
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
index bb4b07bed28d..756fdfdbce61 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-v4l2.c
@@ -86,6 +86,22 @@ static const struct rvin_video_format rvin_formats[] = {
.fourcc = V4L2_PIX_FMT_GREY,
.bpp = 1,
},
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .bpp = 4,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG10,
+ .bpp = 4,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG10,
+ .bpp = 4,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SRGGB10,
+ .bpp = 4,
+ },
};
const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
@@ -106,6 +122,13 @@ const struct rvin_video_format *rvin_format_from_pixel(struct rvin_dev *vin,
if (!vin->info->nv12 || !(BIT(vin->id) & 0x3333))
return NULL;
break;
+ case V4L2_PIX_FMT_SBGGR10:
+ case V4L2_PIX_FMT_SGBRG10:
+ case V4L2_PIX_FMT_SGRBG10:
+ case V4L2_PIX_FMT_SRGGB10:
+ if (!vin->info->raw10)
+ return NULL;
+ break;
default:
break;
}
@@ -407,6 +430,26 @@ static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
f->pixelformat = V4L2_PIX_FMT_SRGGB8;
return 0;
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SBGGR10;
+ return 0;
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SGBRG10;
+ return 0;
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SGRBG10;
+ return 0;
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SRGGB10;
+ return 0;
default:
return -EINVAL;
}
diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
index 997a66318a29..f87d4bc9e53e 100644
--- a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h
@@ -151,7 +151,8 @@ struct rvin_group_route {
* @model: VIN model
* @use_mc: use media controller instead of controlling subdevice
* @use_isp: the VIN is connected to the ISP and not to the CSI-2
- * @nv12: support outputing NV12 pixel format
+ * @nv12: support outputting NV12 pixel format
+ * @raw10: support outputting RAW10 pixel format
* @max_width: max input width the VIN supports
* @max_height: max input height the VIN supports
* @routes: list of possible routes from the CSI-2 recivers to
@@ -163,6 +164,7 @@ struct rvin_info {
bool use_mc;
bool use_isp;
bool nv12;
+ bool raw10;
unsigned int max_width;
unsigned int max_height;
diff --git a/drivers/media/platform/renesas/rcar_drif.c b/drivers/media/platform/renesas/rcar_drif.c
index f21d05054341..fc8b6bbef793 100644
--- a/drivers/media/platform/renesas/rcar_drif.c
+++ b/drivers/media/platform/renesas/rcar_drif.c
@@ -861,8 +861,6 @@ static const struct vb2_ops rcar_drif_vb2_ops = {
.buf_queue = rcar_drif_buf_queue,
.start_streaming = rcar_drif_start_streaming,
.stop_streaming = rcar_drif_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int rcar_drif_querycap(struct file *file, void *fh,
@@ -1071,7 +1069,6 @@ static int rcar_drif_sdr_register(struct rcar_drif_sdr *sdr)
sdr->vdev->release = video_device_release;
sdr->vdev->lock = &sdr->v4l2_mutex;
sdr->vdev->queue = &sdr->vb_queue;
- sdr->vdev->queue->lock = &sdr->vb_queue_mutex;
sdr->vdev->ctrl_handler = &sdr->ctrl_hdl;
sdr->vdev->v4l2_dev = &sdr->v4l2_dev;
sdr->vdev->device_caps = V4L2_CAP_SDR_CAPTURE | V4L2_CAP_TUNER |
@@ -1316,6 +1313,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr)
sdr->vb_queue.ops = &rcar_drif_vb2_ops;
sdr->vb_queue.mem_ops = &vb2_vmalloc_memops;
sdr->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ sdr->vb_queue.lock = &sdr->vb_queue_mutex;
/* Init videobuf2 queue */
ret = vb2_queue_init(&sdr->vb_queue);
@@ -1475,7 +1473,7 @@ static struct platform_driver rcar_drif_driver = {
.pm = &rcar_drif_pm_ops,
},
.probe = rcar_drif_probe,
- .remove_new = rcar_drif_remove,
+ .remove = rcar_drif_remove,
};
module_platform_driver(rcar_drif_driver);
diff --git a/drivers/media/platform/renesas/rcar_fdp1.c b/drivers/media/platform/renesas/rcar_fdp1.c
index a2565b269f3b..5d453a7a8988 100644
--- a/drivers/media/platform/renesas/rcar_fdp1.c
+++ b/drivers/media/platform/renesas/rcar_fdp1.c
@@ -2032,8 +2032,6 @@ static const struct vb2_ops fdp1_qops = {
.buf_queue = fdp1_buf_queue,
.start_streaming = fdp1_start_streaming,
.stop_streaming = fdp1_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq,
@@ -2444,7 +2442,7 @@ MODULE_DEVICE_TABLE(of, fdp1_dt_ids);
static struct platform_driver fdp1_pdrv = {
.probe = fdp1_probe,
- .remove_new = fdp1_remove,
+ .remove = fdp1_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = fdp1_dt_ids,
diff --git a/drivers/media/platform/renesas/rcar_jpu.c b/drivers/media/platform/renesas/rcar_jpu.c
index e50fe7525a73..81038df71bb5 100644
--- a/drivers/media/platform/renesas/rcar_jpu.c
+++ b/drivers/media/platform/renesas/rcar_jpu.c
@@ -1171,8 +1171,6 @@ static const struct vb2_ops jpu_qops = {
.buf_finish = jpu_buf_finish,
.start_streaming = jpu_start_streaming,
.stop_streaming = jpu_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int jpu_queue_init(void *priv, struct vb2_queue *src_vq,
@@ -1736,7 +1734,7 @@ static const struct dev_pm_ops jpu_pm_ops = {
static struct platform_driver jpu_driver = {
.probe = jpu_probe,
- .remove_new = jpu_remove,
+ .remove = jpu_remove,
.driver = {
.of_match_table = jpu_dt_ids,
.name = DRV_NAME,
diff --git a/drivers/media/platform/renesas/renesas-ceu.c b/drivers/media/platform/renesas/renesas-ceu.c
index 167760276796..8cceafe491b1 100644
--- a/drivers/media/platform/renesas/renesas-ceu.c
+++ b/drivers/media/platform/renesas/renesas-ceu.c
@@ -761,8 +761,6 @@ static const struct vb2_ops ceu_vb2_ops = {
.queue_setup = ceu_vb2_setup,
.buf_queue = ceu_vb2_queue,
.buf_prepare = ceu_vb2_prepare,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = ceu_start_streaming,
.stop_streaming = ceu_stop_streaming,
};
@@ -1723,7 +1721,7 @@ static struct platform_driver ceu_driver = {
.of_match_table = of_match_ptr(ceu_of_match),
},
.probe = ceu_probe,
- .remove_new = ceu_remove,
+ .remove = ceu_remove,
};
module_platform_driver(ceu_driver);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
index 280efd2a8185..89be584a4988 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-core.c
@@ -72,7 +72,6 @@ static int rzg2l_cru_group_notify_complete(struct v4l2_async_notifier *notifier)
source->name, sink->name);
return ret;
}
- cru->csi.channel = 0;
cru->ip.remote = cru->csi.subdev;
/* Create media device link between CRU IP <-> CRU OUTPUT */
@@ -209,7 +208,7 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru)
const struct of_device_id *match;
int ret;
- cru->pad.flags = MEDIA_PAD_FL_SINK;
+ cru->pad.flags = MEDIA_PAD_FL_SINK | MEDIA_PAD_FL_MUST_CONNECT;
ret = media_entity_pads_init(&cru->vdev.entity, 1, &cru->pad);
if (ret)
return ret;
@@ -242,7 +241,7 @@ static int rzg2l_cru_media_init(struct rzg2l_cru_dev *cru)
static int rzg2l_cru_probe(struct platform_device *pdev)
{
struct rzg2l_cru_dev *cru;
- int ret;
+ int irq, ret;
cru = devm_kzalloc(&pdev->dev, sizeof(*cru), GFP_KERNEL);
if (!cru)
@@ -270,9 +269,14 @@ static int rzg2l_cru_probe(struct platform_device *pdev)
cru->dev = &pdev->dev;
cru->info = of_device_get_match_data(&pdev->dev);
- cru->image_conv_irq = platform_get_irq(pdev, 0);
- if (cru->image_conv_irq < 0)
- return cru->image_conv_irq;
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0)
+ return irq;
+
+ ret = devm_request_irq(&pdev->dev, irq, rzg2l_cru_irq, 0,
+ KBUILD_MODNAME, cru);
+ if (ret)
+ return dev_err_probe(&pdev->dev, ret, "failed to request irq\n");
platform_set_drvdata(pdev, cru);
@@ -325,7 +329,7 @@ static struct platform_driver rzg2l_cru_driver = {
.of_match_table = rzg2l_cru_of_id_table,
},
.probe = rzg2l_cru_probe,
- .remove_new = rzg2l_cru_remove,
+ .remove = rzg2l_cru_remove,
};
module_platform_driver(rzg2l_cru_driver);
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
new file mode 100644
index 000000000000..1c9f22118a5d
--- /dev/null
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru-regs.h
@@ -0,0 +1,80 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * rzg2l-cru-regs.h--RZ/G2L (and alike SoCs) CRU Registers Definitions
+ *
+ * Copyright (C) 2024 Renesas Electronics Corp.
+ */
+
+#ifndef __RZG2L_CRU_REGS_H__
+#define __RZG2L_CRU_REGS_H__
+
+/* HW CRU Registers Definition */
+
+/* CRU Control Register */
+#define CRUnCTRL 0x0
+#define CRUnCTRL_VINSEL(x) ((x) << 0)
+
+/* CRU Interrupt Enable Register */
+#define CRUnIE 0x4
+#define CRUnIE_EFE BIT(17)
+
+/* CRU Interrupt Status Register */
+#define CRUnINTS 0x8
+#define CRUnINTS_SFS BIT(16)
+
+/* CRU Reset Register */
+#define CRUnRST 0xc
+#define CRUnRST_VRESETN BIT(0)
+
+/* Memory Bank Base Address (Lower) Register for CRU Image Data */
+#define AMnMBxADDRL(x) (0x100 + ((x) * 8))
+
+/* Memory Bank Base Address (Higher) Register for CRU Image Data */
+#define AMnMBxADDRH(x) (0x104 + ((x) * 8))
+
+/* Memory Bank Enable Register for CRU Image Data */
+#define AMnMBVALID 0x148
+#define AMnMBVALID_MBVALID(x) GENMASK(x, 0)
+
+/* Memory Bank Status Register for CRU Image Data */
+#define AMnMBS 0x14c
+#define AMnMBS_MBSTS 0x7
+
+/* AXI Master Transfer Setting Register for CRU Image Data */
+#define AMnAXIATTR 0x158
+#define AMnAXIATTR_AXILEN_MASK GENMASK(3, 0)
+#define AMnAXIATTR_AXILEN (0xf)
+
+/* AXI Master FIFO Pointer Register for CRU Image Data */
+#define AMnFIFOPNTR 0x168
+#define AMnFIFOPNTR_FIFOWPNTR GENMASK(7, 0)
+#define AMnFIFOPNTR_FIFORPNTR_Y GENMASK(23, 16)
+
+/* AXI Master Transfer Stop Register for CRU Image Data */
+#define AMnAXISTP 0x174
+#define AMnAXISTP_AXI_STOP BIT(0)
+
+/* AXI Master Transfer Stop Status Register for CRU Image Data */
+#define AMnAXISTPACK 0x178
+#define AMnAXISTPACK_AXI_STOP_ACK BIT(0)
+
+/* CRU Image Processing Enable Register */
+#define ICnEN 0x200
+#define ICnEN_ICEN BIT(0)
+
+/* CRU Image Processing Main Control Register */
+#define ICnMC 0x208
+#define ICnMC_CSCTHR BIT(5)
+#define ICnMC_INF(x) ((x) << 16)
+#define ICnMC_VCSEL(x) ((x) << 22)
+#define ICnMC_INF_MASK GENMASK(21, 16)
+
+/* CRU Module Status Register */
+#define ICnMS 0x254
+#define ICnMS_IA BIT(2)
+
+/* CRU Data Output Mode Register */
+#define ICnDMR 0x26c
+#define ICnDMR_YCMODE_UYVY (1 << 4)
+
+#endif /* __RZG2L_CRU_REGS_H__ */
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
index a5a99b004322..8b898ce05b84 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h
@@ -8,6 +8,7 @@
#ifndef __RZG2L_CRU__
#define __RZG2L_CRU__
+#include <linux/irqreturn.h>
#include <linux/reset.h>
#include <media/v4l2-async.h>
@@ -30,6 +31,11 @@
#define RZG2L_CRU_MIN_INPUT_HEIGHT 240
#define RZG2L_CRU_MAX_INPUT_HEIGHT 4095
+enum rzg2l_csi2_pads {
+ RZG2L_CRU_IP_SINK = 0,
+ RZG2L_CRU_IP_SOURCE,
+};
+
/**
* enum rzg2l_cru_dma_state - DMA states
* @RZG2L_CRU_DMA_STOPPED: No operation in progress
@@ -47,7 +53,6 @@ enum rzg2l_cru_dma_state {
struct rzg2l_cru_csi {
struct v4l2_async_connection *asd;
struct v4l2_subdev *subdev;
- u32 channel;
};
struct rzg2l_cru_ip {
@@ -58,6 +63,24 @@ struct rzg2l_cru_ip {
};
/**
+ * struct rzg2l_cru_ip_format - CRU IP format
+ * @code: Media bus code
+ * @datatype: MIPI CSI2 data type
+ * @format: 4CC format identifier (V4L2_PIX_FMT_*)
+ * @icndmr: ICnDMR register value
+ * @bpp: bytes per pixel
+ * @yuv: Flag to indicate whether the format is YUV-based.
+ */
+struct rzg2l_cru_ip_format {
+ u32 code;
+ u32 datatype;
+ u32 format;
+ u32 icndmr;
+ u8 bpp;
+ bool yuv;
+};
+
+/**
* struct rzg2l_cru_dev - Renesas CRU device structure
* @dev: (OF) device
* @base: device I/O register space remapped to virtual memory
@@ -68,8 +91,6 @@ struct rzg2l_cru_ip {
*
* @vclk: CRU Main clock
*
- * @image_conv_irq: Holds image conversion interrupt number
- *
* @vdev: V4L2 video device associated with CRU
* @v4l2_dev: V4L2 device
* @num_buf: Holds the current number of buffers enabled
@@ -105,8 +126,6 @@ struct rzg2l_cru_dev {
struct clk *vclk;
- int image_conv_irq;
-
struct video_device vdev;
struct v4l2_device v4l2_dev;
u8 num_buf;
@@ -141,6 +160,7 @@ void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru);
int rzg2l_cru_video_register(struct rzg2l_cru_dev *cru);
void rzg2l_cru_video_unregister(struct rzg2l_cru_dev *cru);
+irqreturn_t rzg2l_cru_irq(int irq, void *data);
const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format);
@@ -148,4 +168,8 @@ int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru);
void rzg2l_cru_ip_subdev_unregister(struct rzg2l_cru_dev *cru);
struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru);
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code);
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format);
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index);
+
#endif
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
index c7fdee347ac8..881e910dce02 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c
@@ -183,12 +183,15 @@ static const struct rzg2l_csi2_timings rzg2l_csi2_global_timings[] = {
struct rzg2l_csi2_format {
u32 code;
- unsigned int datatype;
unsigned int bpp;
};
static const struct rzg2l_csi2_format rzg2l_csi2_formats[] = {
- { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 },
+ { .code = MEDIA_BUS_FMT_UYVY8_1X16, .bpp = 16 },
+ { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .bpp = 8, },
+ { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, },
+ { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, },
+ { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, },
};
static inline struct rzg2l_csi2 *sd_to_csi2(struct v4l2_subdev *sd)
@@ -574,6 +577,9 @@ static int rzg2l_csi2_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index != 0)
return -EINVAL;
+ if (!rzg2l_csi2_code_to_fmt(fse->code))
+ return -EINVAL;
+
fse->min_width = RZG2L_CSI2_MIN_WIDTH;
fse->min_height = RZG2L_CSI2_MIN_HEIGHT;
fse->max_width = RZG2L_CSI2_MAX_WIDTH;
@@ -582,6 +588,25 @@ static int rzg2l_csi2_enum_frame_size(struct v4l2_subdev *sd,
return 0;
}
+static int rzg2l_csi2_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_frame_desc *fd)
+{
+ struct rzg2l_csi2 *csi2 = sd_to_csi2(sd);
+ struct media_pad *remote_pad;
+
+ if (!csi2->remote_source)
+ return -ENODEV;
+
+ remote_pad = media_pad_remote_pad_unique(&csi2->pads[RZG2L_CSI2_SINK]);
+ if (IS_ERR(remote_pad)) {
+ dev_err(csi2->dev, "can't get source pad of %s (%ld)\n",
+ csi2->remote_source->name, PTR_ERR(remote_pad));
+ return PTR_ERR(remote_pad);
+ }
+ return v4l2_subdev_call(csi2->remote_source, pad, get_frame_desc,
+ remote_pad->index, fd);
+}
+
static const struct v4l2_subdev_video_ops rzg2l_csi2_video_ops = {
.s_stream = rzg2l_csi2_s_stream,
.pre_streamon = rzg2l_csi2_pre_streamon,
@@ -593,6 +618,7 @@ static const struct v4l2_subdev_pad_ops rzg2l_csi2_pad_ops = {
.enum_frame_size = rzg2l_csi2_enum_frame_size,
.set_fmt = rzg2l_csi2_set_format,
.get_fmt = v4l2_subdev_get_fmt,
+ .get_frame_desc = rzg2l_csi2_get_frame_desc,
};
static const struct v4l2_subdev_ops rzg2l_csi2_subdev_ops = {
@@ -795,14 +821,17 @@ static int rzg2l_csi2_probe(struct platform_device *pdev)
csi2->subdev.entity.function = MEDIA_ENT_F_VID_IF_BRIDGE;
csi2->subdev.entity.ops = &rzg2l_csi2_entity_ops;
- csi2->pads[RZG2L_CSI2_SINK].flags = MEDIA_PAD_FL_SINK;
+ csi2->pads[RZG2L_CSI2_SINK].flags = MEDIA_PAD_FL_SINK |
+ MEDIA_PAD_FL_MUST_CONNECT;
/*
* TODO: RZ/G2L CSI2 supports 4 virtual channels, as virtual
* channels should be implemented by streams API which is under
* development lets hardcode to VC0 for now.
*/
- csi2->pads[RZG2L_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE;
- ret = media_entity_pads_init(&csi2->subdev.entity, 2, csi2->pads);
+ csi2->pads[RZG2L_CSI2_SOURCE].flags = MEDIA_PAD_FL_SOURCE |
+ MEDIA_PAD_FL_MUST_CONNECT;
+ ret = media_entity_pads_init(&csi2->subdev.entity, ARRAY_SIZE(csi2->pads),
+ csi2->pads);
if (ret)
goto error_pm;
@@ -868,7 +897,7 @@ static const struct of_device_id rzg2l_csi2_of_table[] = {
MODULE_DEVICE_TABLE(of, rzg2l_csi2_of_table);
static struct platform_driver rzg2l_csi2_pdrv = {
- .remove_new = rzg2l_csi2_remove,
+ .remove = rzg2l_csi2_remove,
.probe = rzg2l_csi2_probe,
.driver = {
.name = "rzg2l-csi2",
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
index ac8ebae4ed07..76a2b451f1da 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c
@@ -6,24 +6,55 @@
*/
#include <linux/delay.h>
-#include "rzg2l-cru.h"
+#include <media/mipi-csi2.h>
-struct rzg2l_cru_ip_format {
- u32 code;
- unsigned int datatype;
- unsigned int bpp;
-};
+#include "rzg2l-cru.h"
+#include "rzg2l-cru-regs.h"
static const struct rzg2l_cru_ip_format rzg2l_cru_ip_formats[] = {
- { .code = MEDIA_BUS_FMT_UYVY8_1X16, .datatype = 0x1e, .bpp = 16 },
-};
-
-enum rzg2l_csi2_pads {
- RZG2L_CRU_IP_SINK = 0,
- RZG2L_CRU_IP_SOURCE,
+ {
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
+ .datatype = MIPI_CSI2_DT_YUV422_8B,
+ .format = V4L2_PIX_FMT_UYVY,
+ .bpp = 2,
+ .icndmr = ICnDMR_YCMODE_UYVY,
+ .yuv = true,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
+ .format = V4L2_PIX_FMT_SBGGR8,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .bpp = 1,
+ .icndmr = 0,
+ .yuv = false,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGBRG8_1X8,
+ .format = V4L2_PIX_FMT_SGBRG8,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .bpp = 1,
+ .icndmr = 0,
+ .yuv = false,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
+ .format = V4L2_PIX_FMT_SGRBG8,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .bpp = 1,
+ .icndmr = 0,
+ .yuv = false,
+ },
+ {
+ .code = MEDIA_BUS_FMT_SRGGB8_1X8,
+ .format = V4L2_PIX_FMT_SRGGB8,
+ .datatype = MIPI_CSI2_DT_RAW8,
+ .bpp = 1,
+ .icndmr = 0,
+ .yuv = false,
+ },
};
-static const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code)
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int code)
{
unsigned int i;
@@ -34,6 +65,26 @@ static const struct rzg2l_cru_ip_format *rzg2l_cru_ip_code_to_fmt(unsigned int c
return NULL;
}
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_format_to_fmt(u32 format)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(rzg2l_cru_ip_formats); i++) {
+ if (rzg2l_cru_ip_formats[i].format == format)
+ return &rzg2l_cru_ip_formats[i];
+ }
+
+ return NULL;
+}
+
+const struct rzg2l_cru_ip_format *rzg2l_cru_ip_index_to_fmt(u32 index)
+{
+ if (index >= ARRAY_SIZE(rzg2l_cru_ip_formats))
+ return NULL;
+
+ return &rzg2l_cru_ip_formats[index];
+}
+
struct v4l2_mbus_framefmt *rzg2l_cru_ip_get_src_fmt(struct rzg2l_cru_dev *cru)
{
struct v4l2_subdev_state *state;
@@ -149,7 +200,7 @@ static int rzg2l_cru_ip_enum_frame_size(struct v4l2_subdev *sd,
if (fse->index != 0)
return -EINVAL;
- if (fse->code != MEDIA_BUS_FMT_UYVY8_1X16)
+ if (!rzg2l_cru_ip_code_to_fmt(fse->code))
return -EINVAL;
fse->min_width = RZG2L_CRU_MIN_INPUT_WIDTH;
@@ -217,8 +268,10 @@ int rzg2l_cru_ip_subdev_register(struct rzg2l_cru_dev *cru)
ip->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
ip->subdev.entity.ops = &rzg2l_cru_ip_entity_ops;
- ip->pads[0].flags = MEDIA_PAD_FL_SINK;
- ip->pads[1].flags = MEDIA_PAD_FL_SOURCE;
+ ip->pads[RZG2L_CRU_IP_SINK].flags = MEDIA_PAD_FL_SINK |
+ MEDIA_PAD_FL_MUST_CONNECT;
+ ip->pads[RZG2L_CRU_IP_SOURCE].flags = MEDIA_PAD_FL_SOURCE |
+ MEDIA_PAD_FL_MUST_CONNECT;
ret = media_entity_pads_init(&ip->subdev.entity, 2, ip->pads);
if (ret)
diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
index b16b8af6e8f8..17a1af507a27 100644
--- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
+++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c
@@ -15,75 +15,12 @@
#include <linux/delay.h>
#include <linux/pm_runtime.h>
+#include <media/mipi-csi2.h>
#include <media/v4l2-ioctl.h>
#include <media/videobuf2-dma-contig.h>
#include "rzg2l-cru.h"
-
-/* HW CRU Registers Definition */
-
-/* CRU Control Register */
-#define CRUnCTRL 0x0
-#define CRUnCTRL_VINSEL(x) ((x) << 0)
-
-/* CRU Interrupt Enable Register */
-#define CRUnIE 0x4
-#define CRUnIE_EFE BIT(17)
-
-/* CRU Interrupt Status Register */
-#define CRUnINTS 0x8
-#define CRUnINTS_SFS BIT(16)
-
-/* CRU Reset Register */
-#define CRUnRST 0xc
-#define CRUnRST_VRESETN BIT(0)
-
-/* Memory Bank Base Address (Lower) Register for CRU Image Data */
-#define AMnMBxADDRL(x) (0x100 + ((x) * 8))
-
-/* Memory Bank Base Address (Higher) Register for CRU Image Data */
-#define AMnMBxADDRH(x) (0x104 + ((x) * 8))
-
-/* Memory Bank Enable Register for CRU Image Data */
-#define AMnMBVALID 0x148
-#define AMnMBVALID_MBVALID(x) GENMASK(x, 0)
-
-/* Memory Bank Status Register for CRU Image Data */
-#define AMnMBS 0x14c
-#define AMnMBS_MBSTS 0x7
-
-/* AXI Master FIFO Pointer Register for CRU Image Data */
-#define AMnFIFOPNTR 0x168
-#define AMnFIFOPNTR_FIFOWPNTR GENMASK(7, 0)
-#define AMnFIFOPNTR_FIFORPNTR_Y GENMASK(23, 16)
-
-/* AXI Master Transfer Stop Register for CRU Image Data */
-#define AMnAXISTP 0x174
-#define AMnAXISTP_AXI_STOP BIT(0)
-
-/* AXI Master Transfer Stop Status Register for CRU Image Data */
-#define AMnAXISTPACK 0x178
-#define AMnAXISTPACK_AXI_STOP_ACK BIT(0)
-
-/* CRU Image Processing Enable Register */
-#define ICnEN 0x200
-#define ICnEN_ICEN BIT(0)
-
-/* CRU Image Processing Main Control Register */
-#define ICnMC 0x208
-#define ICnMC_CSCTHR BIT(5)
-#define ICnMC_INF_YUV8_422 (0x1e << 16)
-#define ICnMC_INF_USER (0x30 << 16)
-#define ICnMC_VCSEL(x) ((x) << 22)
-#define ICnMC_INF_MASK GENMASK(21, 16)
-
-/* CRU Module Status Register */
-#define ICnMS 0x254
-#define ICnMS_IA BIT(2)
-
-/* CRU Data Output Mode Register */
-#define ICnDMR 0x26c
-#define ICnDMR_YCMODE_UYVY (1 << 4)
+#include "rzg2l-cru-regs.h"
#define RZG2L_TIMEOUT_MS 100
#define RZG2L_RETRIES 10
@@ -184,46 +121,6 @@ static void rzg2l_cru_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&cru->qlock, flags);
}
-static int rzg2l_cru_mc_validate_format(struct rzg2l_cru_dev *cru,
- struct v4l2_subdev *sd,
- struct media_pad *pad)
-{
- struct v4l2_subdev_format fmt = {
- .which = V4L2_SUBDEV_FORMAT_ACTIVE,
- };
-
- fmt.pad = pad->index;
- if (v4l2_subdev_call_state_active(sd, pad, get_fmt, &fmt))
- return -EPIPE;
-
- switch (fmt.format.code) {
- case MEDIA_BUS_FMT_UYVY8_1X16:
- break;
- default:
- return -EPIPE;
- }
-
- switch (fmt.format.field) {
- case V4L2_FIELD_TOP:
- case V4L2_FIELD_BOTTOM:
- case V4L2_FIELD_NONE:
- case V4L2_FIELD_INTERLACED_TB:
- case V4L2_FIELD_INTERLACED_BT:
- case V4L2_FIELD_INTERLACED:
- case V4L2_FIELD_SEQ_TB:
- case V4L2_FIELD_SEQ_BT:
- break;
- default:
- return -EPIPE;
- }
-
- if (fmt.format.width != cru->format.width ||
- fmt.format.height != cru->format.height)
- return -EPIPE;
-
- return 0;
-}
-
static void rzg2l_cru_set_slot_addr(struct rzg2l_cru_dev *cru,
int slot, dma_addr_t addr)
{
@@ -278,6 +175,7 @@ static void rzg2l_cru_fill_hw_slot(struct rzg2l_cru_dev *cru, int slot)
static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
{
unsigned int slot;
+ u32 amnaxiattr;
/*
* Set image data memory banks.
@@ -287,55 +185,47 @@ static void rzg2l_cru_initialize_axi(struct rzg2l_cru_dev *cru)
for (slot = 0; slot < cru->num_buf; slot++)
rzg2l_cru_fill_hw_slot(cru, slot);
+
+ /* Set AXI burst max length to recommended setting */
+ amnaxiattr = rzg2l_cru_read(cru, AMnAXIATTR) & ~AMnAXIATTR_AXILEN_MASK;
+ amnaxiattr |= AMnAXIATTR_AXILEN;
+ rzg2l_cru_write(cru, AMnAXIATTR, amnaxiattr);
}
-static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru, bool *input_is_yuv,
- struct v4l2_mbus_framefmt *ip_sd_fmt)
+static void rzg2l_cru_csi2_setup(struct rzg2l_cru_dev *cru,
+ const struct rzg2l_cru_ip_format *ip_fmt,
+ u8 csi_vc)
{
- u32 icnmc;
-
- switch (ip_sd_fmt->code) {
- case MEDIA_BUS_FMT_UYVY8_1X16:
- icnmc = ICnMC_INF_YUV8_422;
- *input_is_yuv = true;
- break;
- default:
- *input_is_yuv = false;
- icnmc = ICnMC_INF_USER;
- break;
- }
+ u32 icnmc = ICnMC_INF(ip_fmt->datatype);
icnmc |= (rzg2l_cru_read(cru, ICnMC) & ~ICnMC_INF_MASK);
/* Set virtual channel CSI2 */
- icnmc |= ICnMC_VCSEL(cru->csi.channel);
+ icnmc |= ICnMC_VCSEL(csi_vc);
rzg2l_cru_write(cru, ICnMC, icnmc);
}
static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
- struct v4l2_mbus_framefmt *ip_sd_fmt)
+ struct v4l2_mbus_framefmt *ip_sd_fmt,
+ u8 csi_vc)
{
- bool output_is_yuv = false;
- bool input_is_yuv = false;
- u32 icndmr;
+ const struct rzg2l_cru_ip_format *cru_video_fmt;
+ const struct rzg2l_cru_ip_format *cru_ip_fmt;
- rzg2l_cru_csi2_setup(cru, &input_is_yuv, ip_sd_fmt);
+ cru_ip_fmt = rzg2l_cru_ip_code_to_fmt(ip_sd_fmt->code);
+ rzg2l_cru_csi2_setup(cru, cru_ip_fmt, csi_vc);
/* Output format */
- switch (cru->format.pixelformat) {
- case V4L2_PIX_FMT_UYVY:
- icndmr = ICnDMR_YCMODE_UYVY;
- output_is_yuv = true;
- break;
- default:
+ cru_video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat);
+ if (!cru_video_fmt) {
dev_err(cru->dev, "Invalid pixelformat (0x%x)\n",
cru->format.pixelformat);
return -EINVAL;
}
/* If input and output use same colorspace, do bypass mode */
- if (output_is_yuv == input_is_yuv)
+ if (cru_ip_fmt->yuv == cru_video_fmt->yuv)
rzg2l_cru_write(cru, ICnMC,
rzg2l_cru_read(cru, ICnMC) | ICnMC_CSCTHR);
else
@@ -343,7 +233,7 @@ static int rzg2l_cru_initialize_image_conv(struct rzg2l_cru_dev *cru,
rzg2l_cru_read(cru, ICnMC) & (~ICnMC_CSCTHR));
/* Set output data format */
- rzg2l_cru_write(cru, ICnDMR, icndmr);
+ rzg2l_cru_write(cru, ICnDMR, cru_video_fmt->icndmr);
return 0;
}
@@ -422,12 +312,47 @@ void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru)
spin_unlock_irqrestore(&cru->qlock, flags);
}
+static int rzg2l_cru_get_virtual_channel(struct rzg2l_cru_dev *cru)
+{
+ struct v4l2_mbus_frame_desc fd = { };
+ struct media_pad *remote_pad;
+ int ret;
+
+ remote_pad = media_pad_remote_pad_unique(&cru->ip.pads[RZG2L_CRU_IP_SINK]);
+ ret = v4l2_subdev_call(cru->ip.remote, pad, get_frame_desc, remote_pad->index, &fd);
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_err(cru->dev, "get_frame_desc failed on IP remote subdev\n");
+ return ret;
+ }
+ /* If remote subdev does not implement .get_frame_desc default to VC0. */
+ if (ret == -ENOIOCTLCMD)
+ return 0;
+
+ if (fd.type != V4L2_MBUS_FRAME_DESC_TYPE_CSI2) {
+ dev_err(cru->dev, "get_frame_desc returned invalid bus type %d\n", fd.type);
+ return -EINVAL;
+ }
+
+ if (!fd.num_entries) {
+ dev_err(cru->dev, "get_frame_desc returned zero entries\n");
+ return -EINVAL;
+ }
+
+ return fd.entry[0].bus.csi2.vc;
+}
+
int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
{
struct v4l2_mbus_framefmt *fmt = rzg2l_cru_ip_get_src_fmt(cru);
unsigned long flags;
+ u8 csi_vc;
int ret;
+ ret = rzg2l_cru_get_virtual_channel(cru);
+ if (ret < 0)
+ return ret;
+ csi_vc = ret;
+
spin_lock_irqsave(&cru->qlock, flags);
/* Select a video input */
@@ -444,7 +369,7 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru)
rzg2l_cru_initialize_axi(cru);
/* Initialize image convert */
- ret = rzg2l_cru_initialize_image_conv(cru, fmt);
+ ret = rzg2l_cru_initialize_image_conv(cru, fmt, csi_vc);
if (ret) {
spin_unlock_irqrestore(&cru->qlock, flags);
return ret;
@@ -492,10 +417,6 @@ static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on)
return stream_off_ret;
}
- ret = rzg2l_cru_mc_validate_format(cru, sd, pad);
- if (ret)
- return ret;
-
pipe = media_entity_pipeline(&sd->entity) ? : &cru->vdev.pipe;
ret = video_device_pipeline_start(&cru->vdev, pipe);
if (ret)
@@ -527,7 +448,7 @@ static void rzg2l_cru_stop_streaming(struct rzg2l_cru_dev *cru)
rzg2l_cru_set_stream(cru, 0);
}
-static irqreturn_t rzg2l_cru_irq(int irq, void *data)
+irqreturn_t rzg2l_cru_irq(int irq, void *data)
{
struct rzg2l_cru_dev *cru = data;
unsigned int handled = 0;
@@ -637,13 +558,6 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
goto assert_aresetn;
}
- ret = request_irq(cru->image_conv_irq, rzg2l_cru_irq,
- IRQF_SHARED, KBUILD_MODNAME, cru);
- if (ret) {
- dev_err(cru->dev, "failed to request irq\n");
- goto assert_presetn;
- }
-
/* Allocate scratch buffer. */
cru->scratch = dma_alloc_coherent(cru->dev, cru->format.sizeimage,
&cru->scratch_phys, GFP_KERNEL);
@@ -651,7 +565,7 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count
return_unused_buffers(cru, VB2_BUF_STATE_QUEUED);
dev_err(cru->dev, "Failed to allocate scratch buffer\n");
ret = -ENOMEM;
- goto free_image_conv_irq;
+ goto assert_presetn;
}
cru->sequence = 0;
@@ -670,9 +584,6 @@ out:
if (ret)
dma_free_coherent(cru->dev, cru->format.sizeimage, cru->scratch,
cru->scratch_phys);
-free_image_conv_irq:
- free_irq(cru->image_conv_irq, cru);
-
assert_presetn:
reset_control_assert(cru->presetn);
@@ -698,7 +609,6 @@ static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq)
dma_free_coherent(cru->dev, cru->format.sizeimage,
cru->scratch, cru->scratch_phys);
- free_irq(cru->image_conv_irq, cru);
return_unused_buffers(cru, VB2_BUF_STATE_ERROR);
reset_control_assert(cru->presetn);
@@ -712,8 +622,6 @@ static const struct vb2_ops rzg2l_cru_qops = {
.buf_queue = rzg2l_cru_buffer_queue,
.start_streaming = rzg2l_cru_start_streaming_vq,
.stop_streaming = rzg2l_cru_stop_streaming_vq,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
void rzg2l_cru_dma_unregister(struct rzg2l_cru_dev *cru)
@@ -775,46 +683,16 @@ error:
* V4L2 stuff
*/
-static const struct v4l2_format_info rzg2l_cru_formats[] = {
- {
- .format = V4L2_PIX_FMT_UYVY,
- .bpp[0] = 2,
- },
-};
-
-const struct v4l2_format_info *rzg2l_cru_format_from_pixel(u32 format)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(rzg2l_cru_formats); i++)
- if (rzg2l_cru_formats[i].format == format)
- return rzg2l_cru_formats + i;
-
- return NULL;
-}
-
-static u32 rzg2l_cru_format_bytesperline(struct v4l2_pix_format *pix)
-{
- const struct v4l2_format_info *fmt;
-
- fmt = rzg2l_cru_format_from_pixel(pix->pixelformat);
-
- if (WARN_ON(!fmt))
- return -EINVAL;
-
- return pix->width * fmt->bpp[0];
-}
-
-static u32 rzg2l_cru_format_sizeimage(struct v4l2_pix_format *pix)
-{
- return pix->bytesperline * pix->height;
-}
-
static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru,
struct v4l2_pix_format *pix)
{
- if (!rzg2l_cru_format_from_pixel(pix->pixelformat))
+ const struct rzg2l_cru_ip_format *fmt;
+
+ fmt = rzg2l_cru_ip_format_to_fmt(pix->pixelformat);
+ if (!fmt) {
pix->pixelformat = RZG2L_CRU_DEFAULT_FORMAT;
+ fmt = rzg2l_cru_ip_format_to_fmt(pix->pixelformat);
+ }
switch (pix->field) {
case V4L2_FIELD_TOP:
@@ -833,8 +711,8 @@ static void rzg2l_cru_format_align(struct rzg2l_cru_dev *cru,
v4l_bound_align_image(&pix->width, 320, RZG2L_CRU_MAX_INPUT_WIDTH, 1,
&pix->height, 240, RZG2L_CRU_MAX_INPUT_HEIGHT, 2, 0);
- pix->bytesperline = rzg2l_cru_format_bytesperline(pix);
- pix->sizeimage = rzg2l_cru_format_sizeimage(pix);
+ pix->bytesperline = pix->width * fmt->bpp;
+ pix->sizeimage = pix->bytesperline * pix->height;
dev_dbg(cru->dev, "Format %ux%u bpl: %u size: %u\n",
pix->width, pix->height, pix->bytesperline, pix->sizeimage);
@@ -905,10 +783,13 @@ static int rzg2l_cru_g_fmt_vid_cap(struct file *file, void *priv,
static int rzg2l_cru_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- if (f->index >= ARRAY_SIZE(rzg2l_cru_formats))
+ const struct rzg2l_cru_ip_format *fmt;
+
+ fmt = rzg2l_cru_ip_index_to_fmt(f->index);
+ if (!fmt)
return -EINVAL;
- f->pixelformat = rzg2l_cru_formats[f->index].format;
+ f->pixelformat = fmt->format;
return 0;
}
@@ -984,6 +865,43 @@ static const struct v4l2_file_operations rzg2l_cru_fops = {
.read = vb2_fop_read,
};
+/* -----------------------------------------------------------------------------
+ * Media entity operations
+ */
+
+static int rzg2l_cru_video_link_validate(struct media_link *link)
+{
+ struct v4l2_subdev_format fmt = {
+ .which = V4L2_SUBDEV_FORMAT_ACTIVE,
+ };
+ const struct rzg2l_cru_ip_format *video_fmt;
+ struct v4l2_subdev *subdev;
+ struct rzg2l_cru_dev *cru;
+ int ret;
+
+ subdev = media_entity_to_v4l2_subdev(link->source->entity);
+ fmt.pad = link->source->index;
+ ret = v4l2_subdev_call(subdev, pad, get_fmt, NULL, &fmt);
+ if (ret < 0)
+ return ret == -ENOIOCTLCMD ? -EINVAL : ret;
+
+ cru = container_of(media_entity_to_video_device(link->sink->entity),
+ struct rzg2l_cru_dev, vdev);
+ video_fmt = rzg2l_cru_ip_format_to_fmt(cru->format.pixelformat);
+
+ if (fmt.format.width != cru->format.width ||
+ fmt.format.height != cru->format.height ||
+ fmt.format.field != cru->format.field ||
+ video_fmt->code != fmt.format.code)
+ return -EPIPE;
+
+ return 0;
+}
+
+static const struct media_entity_operations rzg2l_cru_video_media_ops = {
+ .link_validate = rzg2l_cru_video_link_validate,
+};
+
static void rzg2l_cru_v4l2_init(struct rzg2l_cru_dev *cru)
{
struct video_device *vdev = &cru->vdev;
@@ -995,6 +913,7 @@ static void rzg2l_cru_v4l2_init(struct rzg2l_cru_dev *cru)
vdev->lock = &cru->lock;
vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
vdev->device_caps |= V4L2_CAP_IO_MC;
+ vdev->entity.ops = &rzg2l_cru_video_media_ops;
vdev->fops = &rzg2l_cru_fops;
vdev->ioctl_ops = &rzg2l_cru_ioctl_ops;
diff --git a/drivers/media/platform/renesas/sh_vou.c b/drivers/media/platform/renesas/sh_vou.c
index 1e74dd601c2b..4ad7ae188d5b 100644
--- a/drivers/media/platform/renesas/sh_vou.c
+++ b/drivers/media/platform/renesas/sh_vou.c
@@ -360,8 +360,6 @@ static const struct vb2_ops sh_vou_qops = {
.buf_queue = sh_vou_buf_queue,
.start_streaming = sh_vou_start_streaming,
.stop_streaming = sh_vou_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* Video IOCTLs */
@@ -1359,7 +1357,7 @@ static void sh_vou_remove(struct platform_device *pdev)
}
static struct platform_driver sh_vou = {
- .remove_new = sh_vou_remove,
+ .remove = sh_vou_remove,
.driver = {
.name = "sh-vou",
},
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_drv.c b/drivers/media/platform/renesas/vsp1/vsp1_drv.c
index 1aac44d68731..9fc6bf624a52 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_drv.c
@@ -1005,7 +1005,7 @@ MODULE_DEVICE_TABLE(of, vsp1_of_match);
static struct platform_driver vsp1_platform_driver = {
.probe = vsp1_probe,
- .remove_new = vsp1_remove,
+ .remove = vsp1_remove,
.driver = {
.name = "vsp1",
.pm = &vsp1_pm_ops,
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_histo.c b/drivers/media/platform/renesas/vsp1/vsp1_histo.c
index 9c2d4c91bfad..c762202877ba 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_histo.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_histo.c
@@ -155,8 +155,6 @@ static const struct vb2_ops histo_video_queue_qops = {
.queue_setup = histo_queue_setup,
.buf_prepare = histo_buffer_prepare,
.buf_queue = histo_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = histo_start_streaming,
.stop_streaming = histo_stop_streaming,
};
diff --git a/drivers/media/platform/renesas/vsp1/vsp1_video.c b/drivers/media/platform/renesas/vsp1/vsp1_video.c
index e728f9f5160e..03f4efd6b82b 100644
--- a/drivers/media/platform/renesas/vsp1/vsp1_video.c
+++ b/drivers/media/platform/renesas/vsp1/vsp1_video.c
@@ -873,8 +873,6 @@ static const struct vb2_ops vsp1_video_queue_qops = {
.queue_setup = vsp1_video_queue_setup,
.buf_prepare = vsp1_video_buffer_prepare,
.buf_queue = vsp1_video_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = vsp1_video_start_streaming,
.stop_streaming = vsp1_video_stop_streaming,
};
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 70808049d2e8..8a48e9d91f96 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -218,8 +218,6 @@ const struct vb2_ops rga_qops = {
.buf_prepare = rga_buf_prepare,
.buf_queue = rga_buf_queue,
.buf_cleanup = rga_buf_cleanup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = rga_buf_start_streaming,
.stop_streaming = rga_buf_stop_streaming,
};
diff --git a/drivers/media/platform/rockchip/rga/rga.c b/drivers/media/platform/rockchip/rga/rga.c
index 0e768f3e9eda..1739ac0c8e92 100644
--- a/drivers/media/platform/rockchip/rga/rga.c
+++ b/drivers/media/platform/rockchip/rga/rga.c
@@ -102,7 +102,7 @@ queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
src_vq->drv_priv = ctx;
src_vq->ops = &rga_qops;
src_vq->mem_ops = &vb2_dma_sg_memops;
- dst_vq->gfp_flags = __GFP_DMA32;
+ src_vq->gfp_flags = __GFP_DMA32;
src_vq->buf_struct_size = sizeof(struct rga_vb_buffer);
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->rga->mutex;
@@ -972,7 +972,7 @@ MODULE_DEVICE_TABLE(of, rockchip_rga_match);
static struct platform_driver rga_pdrv = {
.probe = rga_probe,
- .remove_new = rga_remove,
+ .remove = rga_remove,
.driver = {
.name = RGA_NAME,
.pm = &rga_pm,
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
index 2bddb4fa8a5c..02339cd94486 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c
@@ -1203,8 +1203,6 @@ static const struct vb2_ops rkisp1_vb2_ops = {
.buf_init = rkisp1_vb2_buf_init,
.buf_queue = rkisp1_vb2_buf_queue,
.buf_prepare = rkisp1_vb2_buf_prepare,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = rkisp1_vb2_stop_streaming,
.start_streaming = rkisp1_vb2_start_streaming,
};
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
index dd114ab77800..0100b9c3edbe 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c
@@ -752,7 +752,7 @@ static struct platform_driver rkisp1_drv = {
.pm = &rkisp1_pm_ops,
},
.probe = rkisp1_probe,
- .remove_new = rkisp1_remove,
+ .remove = rkisp1_remove,
};
module_platform_driver(rkisp1_drv);
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
index 320581a9f866..b28f4140c8a3 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-params.c
@@ -2704,8 +2704,6 @@ static const struct vb2_ops rkisp1_params_vb2_ops = {
.queue_setup = rkisp1_params_vb2_queue_setup,
.buf_init = rkisp1_params_vb2_buf_init,
.buf_cleanup = rkisp1_params_vb2_buf_cleanup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_queue = rkisp1_params_vb2_buf_queue,
.buf_prepare = rkisp1_params_vb2_buf_prepare,
.stop_streaming = rkisp1_params_vb2_stop_streaming,
diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
index a502719e916a..d5fdb8f82dc7 100644
--- a/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
+++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-stats.c
@@ -150,8 +150,6 @@ static const struct vb2_ops rkisp1_stats_vb2_ops = {
.queue_setup = rkisp1_stats_vb2_queue_setup,
.buf_queue = rkisp1_stats_vb2_buf_queue,
.buf_prepare = rkisp1_stats_vb2_buf_prepare,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = rkisp1_stats_vb2_stop_streaming,
};
diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c
index f45f5c8612a6..a06d7cace92f 100644
--- a/drivers/media/platform/samsung/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/samsung/exynos-gsc/gsc-core.c
@@ -1309,7 +1309,7 @@ static const struct dev_pm_ops gsc_pm_ops = {
static struct platform_driver gsc_driver = {
.probe = gsc_probe,
- .remove_new = gsc_remove,
+ .remove = gsc_remove,
.driver = {
.name = GSC_MODULE_NAME,
.pm = &gsc_pm_ops,
diff --git a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c
index b7854ce5fb8e..4bda1c369c44 100644
--- a/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c
+++ b/drivers/media/platform/samsung/exynos-gsc/gsc-m2m.c
@@ -276,8 +276,6 @@ static const struct vb2_ops gsc_m2m_qops = {
.queue_setup = gsc_m2m_queue_setup,
.buf_prepare = gsc_m2m_buf_prepare,
.buf_queue = gsc_m2m_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = gsc_m2m_stop_streaming,
.start_streaming = gsc_m2m_start_streaming,
};
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
index ffa4ea21387d..c3c2e474a18a 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c
@@ -455,8 +455,6 @@ static const struct vb2_ops fimc_capture_qops = {
.queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.c b/drivers/media/platform/samsung/exynos4-is/fimc-core.c
index adfc2d73d04b..2c9edd0a559b 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.c
@@ -1157,7 +1157,7 @@ static const struct dev_pm_ops fimc_pm_ops = {
static struct platform_driver fimc_driver = {
.probe = fimc_probe,
- .remove_new = fimc_remove,
+ .remove = fimc_remove,
.driver = {
.of_match_table = fimc_of_match,
.name = FIMC_DRIVER_NAME,
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c
index 44363c4241d5..b243cbb1d010 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is-i2c.c
@@ -137,7 +137,7 @@ static const struct of_device_id fimc_is_i2c_of_match[] = {
static struct platform_driver fimc_is_i2c_driver = {
.probe = fimc_is_i2c_probe,
- .remove_new = fimc_is_i2c_remove,
+ .remove = fimc_is_i2c_remove,
.driver = {
.of_match_table = fimc_is_i2c_of_match,
.name = "fimc-isp-i2c",
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c
index 0a4b58daf924..2e8fe9e49735 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c
@@ -963,7 +963,7 @@ static const struct dev_pm_ops fimc_is_pm_ops = {
static struct platform_driver fimc_is_driver = {
.probe = fimc_is_probe,
- .remove_new = fimc_is_remove,
+ .remove = fimc_is_remove,
.driver = {
.of_match_table = fimc_is_of_match,
.name = FIMC_IS_DRV_NAME,
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c
index 06c4352562b3..ad219ac1b951 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c
@@ -255,8 +255,6 @@ static const struct vb2_ops isp_video_capture_qops = {
.queue_setup = isp_video_capture_queue_setup,
.buf_prepare = isp_video_capture_buffer_prepare,
.buf_queue = isp_video_capture_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = isp_video_capture_start_streaming,
.stop_streaming = isp_video_capture_stop_streaming,
};
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
index 1a4d75443215..f23e51e3da2f 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c
@@ -441,8 +441,6 @@ static const struct vb2_ops fimc_lite_qops = {
.queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
@@ -1654,7 +1652,7 @@ MODULE_DEVICE_TABLE(of, flite_of_match);
static struct platform_driver fimc_lite_driver = {
.probe = fimc_lite_probe,
- .remove_new = fimc_lite_remove,
+ .remove = fimc_lite_remove,
.driver = {
.of_match_table = flite_of_match,
.name = FIMC_LITE_DRV_NAME,
diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c
index 199997eec1cc..951433c8e92a 100644
--- a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c
+++ b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c
@@ -216,8 +216,6 @@ static const struct vb2_ops fimc_qops = {
.queue_setup = fimc_queue_setup,
.buf_prepare = fimc_buf_prepare,
.buf_queue = fimc_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = stop_streaming,
.start_streaming = start_streaming,
};
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.c b/drivers/media/platform/samsung/exynos4-is/media-dev.c
index 5f10bb4eb4f7..b5ee3c547789 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.c
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.c
@@ -1564,7 +1564,7 @@ MODULE_DEVICE_TABLE(of, fimc_md_of_match);
static struct platform_driver fimc_md_driver = {
.probe = fimc_md_probe,
- .remove_new = fimc_md_remove,
+ .remove = fimc_md_remove,
.driver = {
.of_match_table = of_match_ptr(fimc_md_of_match),
.name = "s5p-fimc-md",
diff --git a/drivers/media/platform/samsung/exynos4-is/media-dev.h b/drivers/media/platform/samsung/exynos4-is/media-dev.h
index 786264cf79dc..a50e58ab7ef7 100644
--- a/drivers/media/platform/samsung/exynos4-is/media-dev.h
+++ b/drivers/media/platform/samsung/exynos4-is/media-dev.h
@@ -178,8 +178,9 @@ int fimc_md_set_camclk(struct v4l2_subdev *sd, bool on);
#ifdef CONFIG_OF
static inline bool fimc_md_is_isp_available(struct device_node *node)
{
- node = of_get_child_by_name(node, FIMC_IS_OF_NODE_NAME);
- return node ? of_device_is_available(node) : false;
+ struct device_node *child __free(device_node) =
+ of_get_child_by_name(node, FIMC_IS_OF_NODE_NAME);
+ return child ? of_device_is_available(child) : false;
}
#else
#define fimc_md_is_isp_available(node) (false)
diff --git a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
index 4b9b20ba3504..63f3eecdd7e6 100644
--- a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c
@@ -1020,7 +1020,7 @@ MODULE_DEVICE_TABLE(of, s5pcsis_of_match);
static struct platform_driver s5pcsis_driver = {
.probe = s5pcsis_probe,
- .remove_new = s5pcsis_remove,
+ .remove = s5pcsis_remove,
.driver = {
.of_match_table = s5pcsis_of_match,
.name = CSIS_DRIVER_NAME,
diff --git a/drivers/media/platform/samsung/s3c-camif/camif-capture.c b/drivers/media/platform/samsung/s3c-camif/camif-capture.c
index be58260ea67e..bd1149e8abc2 100644
--- a/drivers/media/platform/samsung/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/samsung/s3c-camif/camif-capture.c
@@ -525,8 +525,6 @@ static const struct vb2_ops s3c_camif_qops = {
.queue_setup = queue_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
};
diff --git a/drivers/media/platform/samsung/s3c-camif/camif-core.c b/drivers/media/platform/samsung/s3c-camif/camif-core.c
index e4529f666e20..de6e8f151849 100644
--- a/drivers/media/platform/samsung/s3c-camif/camif-core.c
+++ b/drivers/media/platform/samsung/s3c-camif/camif-core.c
@@ -622,7 +622,7 @@ static const struct dev_pm_ops s3c_camif_pm_ops = {
static struct platform_driver s3c_camif_driver = {
.probe = s3c_camif_probe,
- .remove_new = s3c_camif_remove,
+ .remove = s3c_camif_remove,
.id_table = s3c_camif_driver_ids,
.driver = {
.name = S3C_CAMIF_DRIVER_NAME,
diff --git a/drivers/media/platform/samsung/s5p-g2d/g2d.c b/drivers/media/platform/samsung/s5p-g2d/g2d.c
index 89aeba47ed07..ffed16a34493 100644
--- a/drivers/media/platform/samsung/s5p-g2d/g2d.c
+++ b/drivers/media/platform/samsung/s5p-g2d/g2d.c
@@ -133,8 +133,6 @@ static const struct vb2_ops g2d_qops = {
.queue_setup = g2d_queue_setup,
.buf_prepare = g2d_buf_prepare,
.buf_queue = g2d_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq,
@@ -777,7 +775,7 @@ MODULE_DEVICE_TABLE(of, exynos_g2d_match);
static struct platform_driver g2d_pdrv = {
.probe = g2d_probe,
- .remove_new = g2d_remove,
+ .remove = g2d_remove,
.driver = {
.name = G2D_NAME,
.of_match_table = exynos_g2d_match,
diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
index d2c4a0178b3c..ac4cf269456a 100644
--- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-core.c
@@ -775,11 +775,14 @@ static void exynos4_jpeg_parse_decode_h_tbl(struct s5p_jpeg_ctx *ctx)
(unsigned long)vb2_plane_vaddr(&vb->vb2_buf, 0) + ctx->out_q.sos + 2;
jpeg_buffer.curr = 0;
- word = 0;
-
if (get_word_be(&jpeg_buffer, &word))
return;
- jpeg_buffer.size = (long)word - 2;
+
+ if (word < 2)
+ jpeg_buffer.size = 0;
+ else
+ jpeg_buffer.size = (long)word - 2;
+
jpeg_buffer.data += 2;
jpeg_buffer.curr = 0;
@@ -1058,6 +1061,7 @@ static int get_word_be(struct s5p_jpeg_buffer *buf, unsigned int *word)
if (byte == -1)
return -1;
*word = (unsigned int)byte | temp;
+
return 0;
}
@@ -1145,7 +1149,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word))
break;
length = (long)word - 2;
- if (!length)
+ if (length <= 0)
return false;
sof = jpeg_buffer.curr; /* after 0xffc0 */
sof_len = length;
@@ -1176,7 +1180,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word))
break;
length = (long)word - 2;
- if (!length)
+ if (length <= 0)
return false;
if (n_dqt >= S5P_JPEG_MAX_MARKER)
return false;
@@ -1189,7 +1193,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word))
break;
length = (long)word - 2;
- if (!length)
+ if (length <= 0)
return false;
if (n_dht >= S5P_JPEG_MAX_MARKER)
return false;
@@ -1214,6 +1218,7 @@ static bool s5p_jpeg_parse_hdr(struct s5p_jpeg_q_data *result,
if (get_word_be(&jpeg_buffer, &word))
break;
length = (long)word - 2;
+ /* No need to check underflows as skip() does it */
skip(&jpeg_buffer, length);
break;
}
@@ -2590,8 +2595,6 @@ static const struct vb2_ops s5p_jpeg_qops = {
.queue_setup = s5p_jpeg_queue_setup,
.buf_prepare = s5p_jpeg_buf_prepare,
.buf_queue = s5p_jpeg_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = s5p_jpeg_start_streaming,
.stop_streaming = s5p_jpeg_stop_streaming,
};
@@ -3160,7 +3163,7 @@ static void *jpeg_get_drv_data(struct device *dev)
static struct platform_driver s5p_jpeg_driver = {
.probe = s5p_jpeg_probe,
- .remove_new = s5p_jpeg_remove,
+ .remove = s5p_jpeg_remove,
.driver = {
.of_match_table = samsung_jpeg_match,
.name = S5P_JPEG_M2M_NAME,
diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c
index 637a5104d948..6657d294c10a 100644
--- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c
+++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.c
@@ -427,11 +427,6 @@ void exynos3250_jpeg_clear_int_status(void __iomem *regs,
writel(value, regs + EXYNOS3250_JPGINTST);
}
-unsigned int exynos3250_jpeg_operating(void __iomem *regs)
-{
- return readl(regs + S5P_JPGOPR) & EXYNOS3250_JPGOPR_MASK;
-}
-
unsigned int exynos3250_jpeg_compressed_size(void __iomem *regs)
{
return readl(regs + EXYNOS3250_JPGCNT) & EXYNOS3250_JPGCNT_MASK;
diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h
index 15af928fad76..709c61ae322c 100644
--- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h
+++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos3250.h
@@ -45,7 +45,6 @@ void exynos3250_jpeg_rstart(void __iomem *regs);
unsigned int exynos3250_jpeg_get_int_status(void __iomem *regs);
void exynos3250_jpeg_clear_int_status(void __iomem *regs,
unsigned int value);
-unsigned int exynos3250_jpeg_operating(void __iomem *regs);
unsigned int exynos3250_jpeg_compressed_size(void __iomem *regs);
void exynos3250_jpeg_dec_stream_size(void __iomem *regs, unsigned int size);
void exynos3250_jpeg_dec_scaling_ratio(void __iomem *regs, unsigned int sratio);
diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c
index 0828cfa783fe..479288fc8c77 100644
--- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c
+++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.c
@@ -185,11 +185,6 @@ unsigned int exynos4_jpeg_get_int_status(void __iomem *base)
return readl(base + EXYNOS4_INT_STATUS_REG);
}
-unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base)
-{
- return readl(base + EXYNOS4_FIFO_STATUS_REG);
-}
-
void exynos4_jpeg_set_huf_table_enable(void __iomem *base, int value)
{
unsigned int reg;
@@ -300,22 +295,8 @@ void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size)
writel(size, base + EXYNOS4_BITSTREAM_SIZE_REG);
}
-void exynos4_jpeg_get_frame_size(void __iomem *base,
- unsigned int *width, unsigned int *height)
-{
- *width = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) &
- EXYNOS4_DECODED_SIZE_MASK);
- *height = (readl(base + EXYNOS4_DECODE_XY_SIZE_REG) >> 16) &
- EXYNOS4_DECODED_SIZE_MASK;
-}
-
unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base)
{
return readl(base + EXYNOS4_DECODE_IMG_FMT_REG) &
EXYNOS4_JPEG_DECODED_IMG_FMT_MASK;
}
-
-void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size)
-{
- writel(size, base + EXYNOS4_INT_TIMER_COUNT_REG);
-}
diff --git a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h
index 3e2887526960..b941cc89e4ba 100644
--- a/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h
+++ b/drivers/media/platform/samsung/s5p-jpeg/jpeg-hw-exynos4.h
@@ -35,10 +35,6 @@ void exynos4_jpeg_select_dec_h_tbl(void __iomem *base, char c, char x);
void exynos4_jpeg_set_encode_hoff_cnt(void __iomem *base, unsigned int fmt);
void exynos4_jpeg_set_dec_bitstream_size(void __iomem *base, unsigned int size);
unsigned int exynos4_jpeg_get_stream_size(void __iomem *base);
-void exynos4_jpeg_get_frame_size(void __iomem *base,
- unsigned int *width, unsigned int *height);
unsigned int exynos4_jpeg_get_frame_fmt(void __iomem *base);
-unsigned int exynos4_jpeg_get_fifo_status(void __iomem *base);
-void exynos4_jpeg_set_timer_count(void __iomem *base, unsigned int size);
#endif /* JPEG_HW_EXYNOS4_H_ */
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
index 50451984d59f..2fe3c9228ac5 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c
@@ -1721,7 +1721,7 @@ MODULE_DEVICE_TABLE(of, exynos_mfc_match);
static struct platform_driver s5p_mfc_driver = {
.probe = s5p_mfc_probe,
- .remove_new = s5p_mfc_remove,
+ .remove = s5p_mfc_remove,
.driver = {
.name = S5P_MFC_NAME,
.pm = &s5p_mfc_pm_ops,
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
index 91e102d4ec4e..3efbc3367906 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c
@@ -1161,8 +1161,6 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
static const struct vb2_ops s5p_mfc_dec_qops = {
.queue_setup = s5p_mfc_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_init = s5p_mfc_buf_init,
.start_streaming = s5p_mfc_start_streaming,
.stop_streaming = s5p_mfc_stop_streaming,
diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
index 81cbb36fb382..6c603dcd5664 100644
--- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c
@@ -2652,8 +2652,6 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb)
static const struct vb2_ops s5p_mfc_enc_qops = {
.queue_setup = s5p_mfc_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_init = s5p_mfc_buf_init,
.buf_prepare = s5p_mfc_buf_prepare,
.start_streaming = s5p_mfc_start_streaming,
diff --git a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c
index c7ee6e1a4451..73ad66ed20f2 100644
--- a/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c
+++ b/drivers/media/platform/st/sti/bdisp/bdisp-v4l2.c
@@ -531,8 +531,6 @@ static const struct vb2_ops bdisp_qops = {
.queue_setup = bdisp_queue_setup,
.buf_prepare = bdisp_buf_prepare,
.buf_queue = bdisp_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = bdisp_stop_streaming,
.start_streaming = bdisp_start_streaming,
};
@@ -1411,7 +1409,7 @@ MODULE_DEVICE_TABLE(of, bdisp_match_types);
static struct platform_driver bdisp_driver = {
.probe = bdisp_probe,
- .remove_new = bdisp_remove,
+ .remove = bdisp_remove,
.driver = {
.name = BDISP_NAME,
.of_match_table = bdisp_match_types,
diff --git a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
index 67d3d6e50d2e..7b3a37957e3a 100644
--- a/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
+++ b/drivers/media/platform/st/sti/c8sectpfe/c8sectpfe-core.c
@@ -1158,7 +1158,7 @@ static struct platform_driver c8sectpfe_driver = {
.of_match_table = c8sectpfe_match,
},
.probe = c8sectpfe_probe,
- .remove_new = c8sectpfe_remove,
+ .remove = c8sectpfe_remove,
};
module_platform_driver(c8sectpfe_driver);
diff --git a/drivers/media/platform/st/sti/delta/delta-v4l2.c b/drivers/media/platform/st/sti/delta/delta-v4l2.c
index da402d1e9171..196e6a40335d 100644
--- a/drivers/media/platform/st/sti/delta/delta-v4l2.c
+++ b/drivers/media/platform/st/sti/delta/delta-v4l2.c
@@ -1559,8 +1559,6 @@ static const struct vb2_ops delta_vb2_au_ops = {
.queue_setup = delta_vb2_au_queue_setup,
.buf_prepare = delta_vb2_au_prepare,
.buf_queue = delta_vb2_au_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = delta_vb2_au_start_streaming,
.stop_streaming = delta_vb2_au_stop_streaming,
};
@@ -1570,8 +1568,6 @@ static const struct vb2_ops delta_vb2_frame_ops = {
.buf_prepare = delta_vb2_frame_prepare,
.buf_finish = delta_vb2_frame_finish,
.buf_queue = delta_vb2_frame_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = delta_vb2_frame_stop_streaming,
};
@@ -1954,7 +1950,7 @@ MODULE_DEVICE_TABLE(of, delta_match_types);
static struct platform_driver delta_driver = {
.probe = delta_probe,
- .remove_new = delta_remove,
+ .remove = delta_remove,
.driver = {
.name = DELTA_NAME,
.of_match_table = delta_match_types,
diff --git a/drivers/media/platform/st/sti/hva/hva-v4l2.c b/drivers/media/platform/st/sti/hva/hva-v4l2.c
index 161a5c0fbc4e..5366c0f92549 100644
--- a/drivers/media/platform/st/sti/hva/hva-v4l2.c
+++ b/drivers/media/platform/st/sti/hva/hva-v4l2.c
@@ -1114,8 +1114,6 @@ static const struct vb2_ops hva_qops = {
.buf_queue = hva_buf_queue,
.start_streaming = hva_start_streaming,
.stop_streaming = hva_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/*
@@ -1456,7 +1454,7 @@ MODULE_DEVICE_TABLE(of, hva_match_types);
static struct platform_driver hva_driver = {
.probe = hva_probe,
- .remove_new = hva_remove,
+ .remove = hva_remove,
.driver = {
.name = HVA_NAME,
.of_match_table = hva_match_types,
diff --git a/drivers/media/platform/st/stm32/dma2d/dma2d.c b/drivers/media/platform/st/stm32/dma2d/dma2d.c
index 92f1edee58f8..b6c8400fb92d 100644
--- a/drivers/media/platform/st/stm32/dma2d/dma2d.c
+++ b/drivers/media/platform/st/stm32/dma2d/dma2d.c
@@ -186,8 +186,6 @@ static const struct vb2_ops dma2d_qops = {
.buf_queue = dma2d_buf_queue,
.start_streaming = dma2d_start_streaming,
.stop_streaming = dma2d_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq,
@@ -717,7 +715,7 @@ MODULE_DEVICE_TABLE(of, stm32_dma2d_match);
static struct platform_driver dma2d_pdrv = {
.probe = dma2d_probe,
- .remove_new = dma2d_remove,
+ .remove = dma2d_remove,
.driver = {
.name = DMA2D_NAME,
.of_match_table = stm32_dma2d_match,
diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c
index ff3331af9406..9b699ee2b1e0 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmi.c
@@ -898,8 +898,6 @@ static const struct vb2_ops dcmi_video_qops = {
.buf_queue = dcmi_buf_queue,
.start_streaming = dcmi_start_streaming,
.stop_streaming = dcmi_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int dcmi_g_fmt_vid_cap(struct file *file, void *priv,
@@ -2149,7 +2147,7 @@ static const struct dev_pm_ops dcmi_pm_ops = {
static struct platform_driver stm32_dcmi_driver = {
.probe = dcmi_probe,
- .remove_new = dcmi_remove,
+ .remove = dcmi_remove,
.driver = {
.name = DRV_NAME,
.of_match_table = of_match_ptr(stm32_dcmi_of_match),
diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
index 9f768f011fa2..7edd49bfe7e5 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-bytecap.c
@@ -625,12 +625,6 @@ static const struct vb2_ops dcmipp_bytecap_qops = {
.buf_prepare = dcmipp_bytecap_buf_prepare,
.buf_queue = dcmipp_bytecap_buf_queue,
.queue_setup = dcmipp_bytecap_queue_setup,
- /*
- * Since q->lock is set we can use the standard
- * vb2_ops_wait_prepare/finish helper functions.
- */
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static void dcmipp_bytecap_release(struct video_device *vdev)
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 7f771ea49b78..3806f7c6e2fe 100644
--- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
+++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c
@@ -583,7 +583,7 @@ static const struct dev_pm_ops dcmipp_pm_ops = {
static struct platform_driver dcmipp_pdrv = {
.probe = dcmipp_probe,
- .remove_new = dcmipp_remove,
+ .remove = dcmipp_remove,
.driver = {
.name = DCMIPP_PDEV_NAME,
.of_match_table = dcmipp_of_match,
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
index d07e980aba61..e53a07b770b7 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -340,7 +340,7 @@ static const struct dev_pm_ops sun4i_csi_pm_ops = {
static struct platform_driver sun4i_csi_driver = {
.probe = sun4i_csi_probe,
- .remove_new = sun4i_csi_remove,
+ .remove = sun4i_csi_remove,
.driver = {
.name = "sun4i-csi",
.of_match_table = sun4i_csi_of_match,
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
index d1371e130113..e911c7f7acc5 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
@@ -371,8 +371,6 @@ static const struct vb2_ops sun4i_csi_qops = {
.buf_queue = sun4i_csi_buffer_queue,
.start_streaming = sun4i_csi_start_streaming,
.stop_streaming = sun4i_csi_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static irqreturn_t sun4i_csi_irq(int irq, void *data)
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
index c6ba385c0c86..af2a32c226a5 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi.c
@@ -423,7 +423,7 @@ MODULE_DEVICE_TABLE(of, sun6i_csi_of_match);
static struct platform_driver sun6i_csi_platform_driver = {
.probe = sun6i_csi_probe,
- .remove_new = sun6i_csi_remove,
+ .remove = sun6i_csi_remove,
.driver = {
.name = SUN6I_CSI_NAME,
.of_match_table = sun6i_csi_of_match,
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
index 14c0dc827c52..76356bc7f10e 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_csi_capture.c
@@ -657,8 +657,6 @@ static const struct vb2_ops sun6i_csi_capture_queue_ops = {
.buf_queue = sun6i_csi_capture_buffer_queue,
.start_streaming = sun6i_csi_capture_start_streaming,
.stop_streaming = sun6i_csi_capture_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* V4L2 Device */
diff --git a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
index f9d4dc45b490..b06cb73015cd 100644
--- a/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun6i-mipi-csi2/sun6i_mipi_csi2.c
@@ -757,7 +757,7 @@ MODULE_DEVICE_TABLE(of, sun6i_mipi_csi2_of_match);
static struct platform_driver sun6i_mipi_csi2_platform_driver = {
.probe = sun6i_mipi_csi2_probe,
- .remove_new = sun6i_mipi_csi2_remove,
+ .remove = sun6i_mipi_csi2_remove,
.driver = {
.name = SUN6I_MIPI_CSI2_NAME,
.of_match_table = sun6i_mipi_csi2_of_match,
diff --git a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
index 4a5698eb12b7..dbc51daa4fe3 100644
--- a/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
+++ b/drivers/media/platform/sunxi/sun8i-a83t-mipi-csi2/sun8i_a83t_mipi_csi2.c
@@ -824,7 +824,7 @@ MODULE_DEVICE_TABLE(of, sun8i_a83t_mipi_csi2_of_match);
static struct platform_driver sun8i_a83t_mipi_csi2_platform_driver = {
.probe = sun8i_a83t_mipi_csi2_probe,
- .remove_new = sun8i_a83t_mipi_csi2_remove,
+ .remove = sun8i_a83t_mipi_csi2_remove,
.driver = {
.name = SUN8I_A83T_MIPI_CSI2_NAME,
.of_match_table = sun8i_a83t_mipi_csi2_of_match,
diff --git a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
index a1c35a2b68ed..3e7f2df70408 100644
--- a/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
+++ b/drivers/media/platform/sunxi/sun8i-di/sun8i-di.c
@@ -659,8 +659,6 @@ static const struct vb2_ops deinterlace_qops = {
.buf_queue = deinterlace_buf_queue,
.start_streaming = deinterlace_start_streaming,
.stop_streaming = deinterlace_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int deinterlace_queue_init(void *priv, struct vb2_queue *src_vq,
@@ -1001,7 +999,7 @@ static const struct dev_pm_ops deinterlace_pm_ops = {
static struct platform_driver deinterlace_driver = {
.probe = deinterlace_probe,
- .remove_new = deinterlace_remove,
+ .remove = deinterlace_remove,
.driver = {
.name = DEINTERLACE_NAME,
.of_match_table = deinterlace_dt_match,
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
index a12323ca89fa..abd10b218aa1 100644
--- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
+++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
@@ -522,8 +522,6 @@ static const struct vb2_ops rotate_qops = {
.buf_queue = rotate_buf_queue,
.start_streaming = rotate_start_streaming,
.stop_streaming = rotate_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int rotate_queue_init(void *priv, struct vb2_queue *src_vq,
@@ -905,7 +903,7 @@ static const struct dev_pm_ops rotate_pm_ops = {
static struct platform_driver rotate_driver = {
.probe = rotate_probe,
- .remove_new = rotate_remove,
+ .remove = rotate_remove,
.driver = {
.name = ROTATE_NAME,
.of_match_table = rotate_dt_match,
diff --git a/drivers/media/platform/ti/am437x/am437x-vpfe.c b/drivers/media/platform/ti/am437x/am437x-vpfe.c
index 009ff68a2b43..44cdccb89377 100644
--- a/drivers/media/platform/ti/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/ti/am437x/am437x-vpfe.c
@@ -2079,8 +2079,6 @@ static long vpfe_ioctl_default(struct file *file, void *priv,
}
static const struct vb2_ops vpfe_video_qops = {
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.queue_setup = vpfe_queue_setup,
.buf_prepare = vpfe_buffer_prepare,
.buf_queue = vpfe_buffer_queue,
@@ -2617,7 +2615,7 @@ MODULE_DEVICE_TABLE(of, vpfe_of_match);
static struct platform_driver vpfe_driver = {
.probe = vpfe_probe,
- .remove_new = vpfe_remove,
+ .remove = vpfe_remove,
.driver = {
.name = VPFE_MODULE_NAME,
.pm = &vpfe_pm_ops,
diff --git a/drivers/media/platform/ti/cal/cal-video.c b/drivers/media/platform/ti/cal/cal-video.c
index e1ba5dfc217e..e29743ae61e2 100644
--- a/drivers/media/platform/ti/cal/cal-video.c
+++ b/drivers/media/platform/ti/cal/cal-video.c
@@ -808,8 +808,6 @@ static const struct vb2_ops cal_video_qops = {
.buf_queue = cal_buffer_queue,
.start_streaming = cal_start_streaming,
.stop_streaming = cal_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* ------------------------------------------------------------------
diff --git a/drivers/media/platform/ti/cal/cal.c b/drivers/media/platform/ti/cal/cal.c
index 5c2c04142aee..4bd2092e0255 100644
--- a/drivers/media/platform/ti/cal/cal.c
+++ b/drivers/media/platform/ti/cal/cal.c
@@ -1332,7 +1332,7 @@ static const struct dev_pm_ops cal_pm_ops = {
static struct platform_driver cal_pdrv = {
.probe = cal_probe,
- .remove_new = cal_remove,
+ .remove = cal_remove,
.driver = {
.name = CAL_MODULE_NAME,
.pm = &cal_pm_ops,
diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c
index f4e1fa76bf37..a81719702a22 100644
--- a/drivers/media/platform/ti/davinci/vpif.c
+++ b/drivers/media/platform/ti/davinci/vpif.c
@@ -589,7 +589,7 @@ static struct platform_driver vpif_driver = {
.name = VPIF_DRIVER_NAME,
.pm = vpif_pm_ops,
},
- .remove_new = vpif_remove,
+ .remove = vpif_remove,
.probe = vpif_probe,
};
diff --git a/drivers/media/platform/ti/davinci/vpif_capture.c b/drivers/media/platform/ti/davinci/vpif_capture.c
index 16326437767f..d053972888d1 100644
--- a/drivers/media/platform/ti/davinci/vpif_capture.c
+++ b/drivers/media/platform/ti/davinci/vpif_capture.c
@@ -310,8 +310,6 @@ static const struct vb2_ops video_qops = {
.start_streaming = vpif_start_streaming,
.stop_streaming = vpif_stop_streaming,
.buf_queue = vpif_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/**
@@ -1815,7 +1813,7 @@ static __refdata struct platform_driver vpif_driver = {
.pm = &vpif_pm_ops,
},
.probe = vpif_probe,
- .remove_new = vpif_remove,
+ .remove = vpif_remove,
};
module_platform_driver(vpif_driver);
diff --git a/drivers/media/platform/ti/davinci/vpif_display.c b/drivers/media/platform/ti/davinci/vpif_display.c
index 76d8fa8ad088..70c89549f4b6 100644
--- a/drivers/media/platform/ti/davinci/vpif_display.c
+++ b/drivers/media/platform/ti/davinci/vpif_display.c
@@ -293,8 +293,6 @@ static void vpif_stop_streaming(struct vb2_queue *vq)
static const struct vb2_ops video_qops = {
.queue_setup = vpif_buffer_queue_setup,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_prepare = vpif_buffer_prepare,
.start_streaming = vpif_start_streaming,
.stop_streaming = vpif_stop_streaming,
@@ -1398,7 +1396,7 @@ static __refdata struct platform_driver vpif_driver = {
.pm = &vpif_pm_ops,
},
.probe = vpif_probe,
- .remove_new = vpif_remove,
+ .remove = vpif_remove,
};
module_platform_driver(vpif_driver);
diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
index 22442fce7607..6412a00be8ea 100644
--- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
+++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c
@@ -878,8 +878,6 @@ static const struct vb2_ops csi_vb2_qops = {
.buf_queue = ti_csi2rx_buffer_queue,
.start_streaming = ti_csi2rx_start_streaming,
.stop_streaming = ti_csi2rx_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int ti_csi2rx_init_vb2q(struct ti_csi2rx_dev *csi)
@@ -1014,9 +1012,9 @@ static int ti_csi2rx_v4l2_init(struct ti_csi2rx_dev *csi)
pix_fmt->height = 480;
pix_fmt->field = V4L2_FIELD_NONE;
pix_fmt->colorspace = V4L2_COLORSPACE_SRGB;
- pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601,
- pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE,
- pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB,
+ pix_fmt->ycbcr_enc = V4L2_YCBCR_ENC_601;
+ pix_fmt->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+ pix_fmt->xfer_func = V4L2_XFER_FUNC_SRGB;
ti_csi2rx_fill_fmt(fmt, &csi->v_fmt);
@@ -1163,7 +1161,7 @@ MODULE_DEVICE_TABLE(of, ti_csi2rx_of_match);
static struct platform_driver ti_csi2rx_pdrv = {
.probe = ti_csi2rx_probe,
- .remove_new = ti_csi2rx_remove,
+ .remove = ti_csi2rx_remove,
.driver = {
.name = TI_CSI2RX_MODULE_NAME,
.of_match_table = ti_csi2rx_of_match,
diff --git a/drivers/media/platform/ti/omap/omap_vout.c b/drivers/media/platform/ti/omap/omap_vout.c
index 1c56b6a87ced..a87d5030ac35 100644
--- a/drivers/media/platform/ti/omap/omap_vout.c
+++ b/drivers/media/platform/ti/omap/omap_vout.c
@@ -1300,8 +1300,6 @@ static const struct vb2_ops omap_vout_vb2_ops = {
.buf_prepare = omap_vout_vb2_prepare,
.start_streaming = omap_vout_vb2_start_streaming,
.stop_streaming = omap_vout_vb2_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* Init functions used during driver initialization */
@@ -1721,7 +1719,7 @@ static struct platform_driver omap_vout_driver = {
.driver = {
.name = VOUT_NAME,
},
- .remove_new = omap_vout_remove,
+ .remove = omap_vout_remove,
};
static int __init omap_vout_init(void)
diff --git a/drivers/media/platform/ti/omap/omap_voutdef.h b/drivers/media/platform/ti/omap/omap_voutdef.h
index b586193341d2..159e5e670d91 100644
--- a/drivers/media/platform/ti/omap/omap_voutdef.h
+++ b/drivers/media/platform/ti/omap/omap_voutdef.h
@@ -48,7 +48,7 @@
#define VRFB_TX_TIMEOUT 1000
#define VRFB_NUM_BUFS 4
-/* Max buffer size tobe allocated during init */
+/* Max buffer size to be allocated during init */
#define OMAP_VOUT_MAX_BUF_SIZE (VID_MAX_WIDTH*VID_MAX_HEIGHT*4)
enum dma_channel_state {
diff --git a/drivers/media/platform/ti/omap3isp/isp.c b/drivers/media/platform/ti/omap3isp/isp.c
index 91101ba88ef0..405ca215179d 100644
--- a/drivers/media/platform/ti/omap3isp/isp.c
+++ b/drivers/media/platform/ti/omap3isp/isp.c
@@ -2472,7 +2472,7 @@ MODULE_DEVICE_TABLE(of, omap3isp_of_table);
static struct platform_driver omap3isp_driver = {
.probe = isp_probe,
- .remove_new = isp_remove,
+ .remove = isp_remove,
.id_table = omap3isp_id_table,
.driver = {
.name = "omap3isp",
diff --git a/drivers/media/platform/ti/omap3isp/ispvideo.c b/drivers/media/platform/ti/omap3isp/ispvideo.c
index daca689dc082..5c9aa80023fd 100644
--- a/drivers/media/platform/ti/omap3isp/ispvideo.c
+++ b/drivers/media/platform/ti/omap3isp/ispvideo.c
@@ -480,11 +480,29 @@ static int isp_video_start_streaming(struct vb2_queue *queue,
return 0;
}
+static void omap3isp_wait_prepare(struct vb2_queue *vq)
+{
+ struct isp_video_fh *vfh = vb2_get_drv_priv(vq);
+ struct isp_video *video = vfh->video;
+
+ mutex_unlock(&video->queue_lock);
+}
+
+static void omap3isp_wait_finish(struct vb2_queue *vq)
+{
+ struct isp_video_fh *vfh = vb2_get_drv_priv(vq);
+ struct isp_video *video = vfh->video;
+
+ mutex_lock(&video->queue_lock);
+}
+
static const struct vb2_ops isp_video_queue_ops = {
.queue_setup = isp_video_queue_setup,
.buf_prepare = isp_video_buffer_prepare,
.buf_queue = isp_video_buffer_queue,
.start_streaming = isp_video_start_streaming,
+ .wait_prepare = omap3isp_wait_prepare,
+ .wait_finish = omap3isp_wait_finish,
};
/*
diff --git a/drivers/media/platform/ti/vpe/vpe.c b/drivers/media/platform/ti/vpe/vpe.c
index 6848cbc82f52..636d76ecebcd 100644
--- a/drivers/media/platform/ti/vpe/vpe.c
+++ b/drivers/media/platform/ti/vpe/vpe.c
@@ -2210,8 +2210,6 @@ static const struct vb2_ops vpe_qops = {
.queue_setup = vpe_queue_setup,
.buf_prepare = vpe_buf_prepare,
.buf_queue = vpe_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = vpe_start_streaming,
.stop_streaming = vpe_stop_streaming,
};
@@ -2649,7 +2647,7 @@ MODULE_DEVICE_TABLE(of, vpe_of_match);
static struct platform_driver vpe_pdrv = {
.probe = vpe_probe,
- .remove_new = vpe_remove,
+ .remove = vpe_remove,
.driver = {
.name = VPE_MODULE_NAME,
.of_match_table = of_match_ptr(vpe_of_match),
diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
index 05bbac853c4f..8542238e0fb1 100644
--- a/drivers/media/platform/verisilicon/hantro_drv.c
+++ b/drivers/media/platform/verisilicon/hantro_drv.c
@@ -1277,7 +1277,7 @@ static const struct dev_pm_ops hantro_pm_ops = {
static struct platform_driver hantro_driver = {
.probe = hantro_probe,
- .remove_new = hantro_remove,
+ .remove = hantro_remove,
.driver = {
.name = DRIVER_NAME,
.of_match_table = of_hantro_match,
diff --git a/drivers/media/platform/verisilicon/hantro_v4l2.c b/drivers/media/platform/verisilicon/hantro_v4l2.c
index 62d3962c18d9..2513adfbd825 100644
--- a/drivers/media/platform/verisilicon/hantro_v4l2.c
+++ b/drivers/media/platform/verisilicon/hantro_v4l2.c
@@ -201,7 +201,15 @@ static int vidioc_enum_fmt(struct file *file, void *priv,
struct hantro_ctx *ctx = fh_to_ctx(priv);
const struct hantro_fmt *fmt, *formats;
unsigned int num_fmts, i, j = 0;
- bool skip_mode_none;
+ bool skip_mode_none, enum_all_formats;
+ u32 index = f->index & ~V4L2_FMTDESC_FLAG_ENUM_ALL;
+
+ /*
+ * If the V4L2_FMTDESC_FLAG_ENUM_ALL flag is set, we want to enumerate all
+ * hardware supported pixel formats
+ */
+ enum_all_formats = !!(f->index & V4L2_FMTDESC_FLAG_ENUM_ALL);
+ f->index = index;
/*
* When dealing with an encoder:
@@ -222,9 +230,9 @@ static int vidioc_enum_fmt(struct file *file, void *priv,
if (skip_mode_none == mode_none)
continue;
- if (!hantro_check_depth_match(fmt, ctx->bit_depth))
+ if (!hantro_check_depth_match(fmt, ctx->bit_depth) && !enum_all_formats)
continue;
- if (j == f->index) {
+ if (j == index) {
f->pixelformat = fmt->fourcc;
return 0;
}
@@ -242,9 +250,9 @@ static int vidioc_enum_fmt(struct file *file, void *priv,
for (i = 0; i < num_fmts; i++) {
fmt = &formats[i];
- if (!hantro_check_depth_match(fmt, ctx->bit_depth))
+ if (!hantro_check_depth_match(fmt, ctx->bit_depth) && !enum_all_formats)
continue;
- if (j == f->index) {
+ if (j == index) {
f->pixelformat = fmt->fourcc;
return 0;
}
@@ -996,6 +1004,4 @@ const struct vb2_ops hantro_queue_ops = {
.buf_request_complete = hantro_buf_request_complete,
.start_streaming = hantro_start_streaming,
.stop_streaming = hantro_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
index 65e8f2d07400..e54f5fac325b 100644
--- a/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
+++ b/drivers/media/platform/verisilicon/rockchip_vpu981_hw_av1_dec.c
@@ -161,8 +161,7 @@ static int rockchip_vpu981_av1_dec_frame_ref(struct hantro_ctx *ctx,
av1_dec->frame_refs[i].timestamp = timestamp;
av1_dec->frame_refs[i].frame_type = frame->frame_type;
av1_dec->frame_refs[i].order_hint = frame->order_hint;
- if (!av1_dec->frame_refs[i].vb2_ref)
- av1_dec->frame_refs[i].vb2_ref = hantro_get_dst_buf(ctx);
+ av1_dec->frame_refs[i].vb2_ref = hantro_get_dst_buf(ctx);
for (j = 0; j < V4L2_AV1_TOTAL_REFS_PER_FRAME; j++)
av1_dec->frame_refs[i].order_hints[j] = frame->order_hints[j];
diff --git a/drivers/media/platform/via/via-camera.c b/drivers/media/platform/via/via-camera.c
index 4cb8f29e2f14..5702eff664d4 100644
--- a/drivers/media/platform/via/via-camera.c
+++ b/drivers/media/platform/via/via-camera.c
@@ -666,8 +666,6 @@ static const struct vb2_ops viacam_vb2_ops = {
.buf_prepare = viacam_vb2_prepare,
.start_streaming = viacam_vb2_start_streaming,
.stop_streaming = viacam_vb2_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* --------------------------------------------------------------------------*/
@@ -1307,7 +1305,7 @@ static struct platform_driver viacam_driver = {
.name = "viafb-camera",
},
.probe = viacam_probe,
- .remove_new = viacam_remove,
+ .remove = viacam_remove,
};
module_platform_driver(viacam_driver);
diff --git a/drivers/media/platform/video-mux.c b/drivers/media/platform/video-mux.c
index 31e9e92e723e..cba34893258a 100644
--- a/drivers/media/platform/video-mux.c
+++ b/drivers/media/platform/video-mux.c
@@ -52,6 +52,7 @@ static int video_mux_link_setup(struct media_entity *entity,
const struct media_pad *remote, u32 flags)
{
struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity);
+ struct v4l2_subdev_state *sd_state;
struct video_mux *vmux = v4l2_subdev_to_video_mux(sd);
u16 source_pad = entity->num_pads - 1;
int ret = 0;
@@ -67,10 +68,10 @@ static int video_mux_link_setup(struct media_entity *entity,
remote->entity->name, remote->index, local->entity->name,
local->index, flags & MEDIA_LNK_FL_ENABLED);
+ sd_state = v4l2_subdev_lock_and_get_active_state(sd);
mutex_lock(&vmux->lock);
if (flags & MEDIA_LNK_FL_ENABLED) {
- struct v4l2_subdev_state *sd_state;
struct v4l2_mbus_framefmt *source_mbusformat;
if (vmux->active == local->index)
@@ -88,12 +89,10 @@ static int video_mux_link_setup(struct media_entity *entity,
vmux->active = local->index;
/* Propagate the active format to the source */
- sd_state = v4l2_subdev_lock_and_get_active_state(sd);
source_mbusformat = v4l2_subdev_state_get_format(sd_state,
source_pad);
*source_mbusformat = *v4l2_subdev_state_get_format(sd_state,
vmux->active);
- v4l2_subdev_unlock_state(sd_state);
} else {
if (vmux->active != local->index)
goto out;
@@ -105,6 +104,7 @@ static int video_mux_link_setup(struct media_entity *entity,
out:
mutex_unlock(&vmux->lock);
+ v4l2_subdev_unlock_state(sd_state);
return ret;
}
@@ -486,7 +486,7 @@ MODULE_DEVICE_TABLE(of, video_mux_dt_ids);
static struct platform_driver video_mux_driver = {
.probe = video_mux_probe,
- .remove_new = video_mux_remove,
+ .remove = video_mux_remove,
.driver = {
.of_match_table = video_mux_dt_ids,
.name = "video-mux",
diff --git a/drivers/media/platform/xilinx/xilinx-csi2rxss.c b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
index f953d5474ae0..146131b8f37e 100644
--- a/drivers/media/platform/xilinx/xilinx-csi2rxss.c
+++ b/drivers/media/platform/xilinx/xilinx-csi2rxss.c
@@ -1028,7 +1028,7 @@ static struct platform_driver xcsi2rxss_driver = {
.of_match_table = xcsi2rxss_of_id_table,
},
.probe = xcsi2rxss_probe,
- .remove_new = xcsi2rxss_remove,
+ .remove = xcsi2rxss_remove,
};
module_platform_driver(xcsi2rxss_driver);
diff --git a/drivers/media/platform/xilinx/xilinx-dma.c b/drivers/media/platform/xilinx/xilinx-dma.c
index a1687b868a44..18bfa6001909 100644
--- a/drivers/media/platform/xilinx/xilinx-dma.c
+++ b/drivers/media/platform/xilinx/xilinx-dma.c
@@ -458,8 +458,6 @@ static const struct vb2_ops xvip_dma_queue_qops = {
.queue_setup = xvip_dma_queue_setup,
.buf_prepare = xvip_dma_buffer_prepare,
.buf_queue = xvip_dma_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = xvip_dma_start_streaming,
.stop_streaming = xvip_dma_stop_streaming,
};
diff --git a/drivers/media/platform/xilinx/xilinx-tpg.c b/drivers/media/platform/xilinx/xilinx-tpg.c
index e05e528ffc6f..cb93711ea3e3 100644
--- a/drivers/media/platform/xilinx/xilinx-tpg.c
+++ b/drivers/media/platform/xilinx/xilinx-tpg.c
@@ -13,6 +13,7 @@
#include <linux/gpio/consumer.h>
#include <linux/module.h>
#include <linux/of.h>
+#include <linux/of_graph.h>
#include <linux/platform_device.h>
#include <linux/xilinx-v4l2-controls.h>
@@ -711,22 +712,13 @@ static int xtpg_parse_of(struct xtpg_device *xtpg)
{
struct device *dev = xtpg->xvip.dev;
struct device_node *node = xtpg->xvip.dev->of_node;
- struct device_node *ports;
- struct device_node *port;
unsigned int nports = 0;
bool has_endpoint = false;
- ports = of_get_child_by_name(node, "ports");
- if (ports == NULL)
- ports = node;
-
- for_each_child_of_node(ports, port) {
+ for_each_of_graph_port(node, port) {
const struct xvip_video_format *format;
struct device_node *endpoint;
- if (!of_node_name_eq(port, "port"))
- continue;
-
format = xvip_of_get_format(port);
if (IS_ERR(format)) {
dev_err(dev, "invalid format in DT");
@@ -744,7 +736,7 @@ static int xtpg_parse_of(struct xtpg_device *xtpg)
}
if (nports == 0) {
- endpoint = of_get_next_child(port, NULL);
+ endpoint = of_graph_get_next_port_endpoint(port, NULL);
if (endpoint)
has_endpoint = true;
of_node_put(endpoint);
@@ -920,7 +912,7 @@ static struct platform_driver xtpg_driver = {
.of_match_table = xtpg_of_id_table,
},
.probe = xtpg_probe,
- .remove_new = xtpg_remove,
+ .remove = xtpg_remove,
};
module_platform_driver(xtpg_driver);
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index bfe48cc0ab52..024b439feec9 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -618,7 +618,7 @@ static struct platform_driver xvip_composite_driver = {
.of_match_table = xvip_composite_of_id_table,
},
.probe = xvip_composite_probe,
- .remove_new = xvip_composite_remove,
+ .remove = xvip_composite_remove,
};
module_platform_driver(xvip_composite_driver);
diff --git a/drivers/media/platform/xilinx/xilinx-vtc.c b/drivers/media/platform/xilinx/xilinx-vtc.c
index dda70719f004..92fec7bb47da 100644
--- a/drivers/media/platform/xilinx/xilinx-vtc.c
+++ b/drivers/media/platform/xilinx/xilinx-vtc.c
@@ -365,7 +365,7 @@ static struct platform_driver xvtc_driver = {
.of_match_table = xvtc_of_id_table,
},
.probe = xvtc_probe,
- .remove_new = xvtc_remove,
+ .remove = xvtc_remove,
};
module_platform_driver(xvtc_driver);
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 0e9a3787724c..3c8c17d64821 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -4,7 +4,7 @@
*
* Copyright 1997 M. Kirkwood
*
- * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
+ * Converted to the radio-isa framework by Hans Verkuil <hansverk@cisco.com>
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org>
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index a532f63aa9d9..5ca6274c45bd 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -15,7 +15,7 @@
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
*
- * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
+ * Converted to the radio-isa framework by Hans Verkuil <hansverk@cisco.com>
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org>
*
* Note: this card seems to swap the left and right audio channels!
diff --git a/drivers/media/radio/radio-isa.c b/drivers/media/radio/radio-isa.c
index ad49151f5ff0..4f87c76a2a96 100644
--- a/drivers/media/radio/radio-isa.c
+++ b/drivers/media/radio/radio-isa.c
@@ -4,7 +4,7 @@
* This takes care of all the V4L2 scaffolding, allowing the ISA drivers
* to concentrate on the actual hardware operation.
*
- * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com>
+ * Copyright (C) 2012 Hans Verkuil <hansverk@cisco.com>
*/
#include <linux/module.h>
diff --git a/drivers/media/radio/radio-isa.h b/drivers/media/radio/radio-isa.h
index c9159958203e..0f3db473da5e 100644
--- a/drivers/media/radio/radio-isa.h
+++ b/drivers/media/radio/radio-isa.h
@@ -4,7 +4,7 @@
* This takes care of all the V4L2 scaffolding, allowing the ISA drivers
* to concentrate on the actual hardware operation.
*
- * Copyright (C) 2012 Hans Verkuil <hans.verkuil@cisco.com>
+ * Copyright (C) 2012 Hans Verkuil <hansverk@cisco.com>
*/
#ifndef _RADIO_ISA_H_
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index 08be77b8f3b7..27f058c5e677 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -23,7 +23,7 @@
* This code has been reintroduced and converted to use
* the new V4L2 RDS API by:
*
- * Hans Verkuil <hans.verkuil@cisco.com>
+ * Hans Verkuil <hansverk@cisco.com>
*/
#include <linux/module.h>
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 73d2c187f122..16b13a63bfed 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -7,7 +7,7 @@
* Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
* Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
*
- * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
+ * Converted to the radio-isa framework by Hans Verkuil <hansverk@cisco.com>
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org>
*
* Fully tested with actual hardware and the v4l2-compliance tool.
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
index b2c5809a8bc7..9980346cb5ea 100644
--- a/drivers/media/radio/radio-si476x.c
+++ b/drivers/media/radio/radio-si476x.c
@@ -1513,7 +1513,7 @@ static struct platform_driver si476x_radio_driver = {
.name = DRIVER_NAME,
},
.probe = si476x_radio_probe,
- .remove_new = si476x_radio_remove,
+ .remove = si476x_radio_remove,
};
module_platform_driver(si476x_radio_driver);
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index 621bb8523271..720080634454 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -17,7 +17,7 @@
* Frequency control is done digitally -- ie out(port,encodefreq(95.8));
* Volume Control is done digitally
*
- * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
+ * Converted to the radio-isa framework by Hans Verkuil <hansverk@cisco.com>
* Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@kernel.org>
*/
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index 04daa9c358c2..a6069b106fd3 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -164,7 +164,7 @@ static struct platform_driver timbradio_platform_driver = {
.name = DRIVER_NAME,
},
.probe = timbradio_probe,
- .remove_new = timbradio_remove,
+ .remove = timbradio_remove,
};
module_platform_driver(timbradio_platform_driver);
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index f6b98c304b72..511a8ede05ec 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -2145,7 +2145,7 @@ pdata_err:
static struct platform_driver wl1273_fm_radio_driver = {
.probe = wl1273_fm_radio_probe,
- .remove_new = wl1273_fm_radio_remove,
+ .remove = wl1273_fm_radio_remove,
.driver = {
.name = "wl1273_fm_radio",
},
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index f3dc57c75131..099b7af6a410 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -30,7 +30,7 @@
* 2006-07-24 - Converted to V4L2 API
* by Mauro Carvalho Chehab <mchehab@kernel.org>
*
- * Converted to the radio-isa framework by Hans Verkuil <hans.verkuil@cisco.com>
+ * Converted to the radio-isa framework by Hans Verkuil <hansverk@cisco.com>
*
* Note that this is the driver for the Zoltrix Radio Plus.
* This driver does not work for the Zoltrix Radio Plus 108 or the
diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c
index 9fdaed68a962..67b4afadc95a 100644
--- a/drivers/media/radio/si4713/radio-platform-si4713.c
+++ b/drivers/media/radio/si4713/radio-platform-si4713.c
@@ -205,7 +205,7 @@ static struct platform_driver radio_si4713_pdriver = {
.name = "radio-si4713",
},
.probe = radio_si4713_pdriver_probe,
- .remove_new = radio_si4713_pdriver_remove,
+ .remove = radio_si4713_pdriver_remove,
};
module_platform_driver(radio_si4713_pdriver);
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index 3d36f323a8f8..4d032436691c 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -466,11 +466,12 @@ int fmc_send_cmd(struct fmdev *fmdev, u8 fm_op, u16 type, void *payload,
jiffies_to_msecs(FM_DRV_TX_TIMEOUT) / 1000);
return -ETIMEDOUT;
}
+ spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
if (!fmdev->resp_skb) {
+ spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
fmerr("Response SKB is missing\n");
return -EFAULT;
}
- spin_lock_irqsave(&fmdev->resp_skb_lock, flags);
skb = fmdev->resp_skb;
fmdev->resp_skb = NULL;
spin_unlock_irqrestore(&fmdev->resp_skb_lock, flags);
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 74d69ce22a33..0a8aeafdb7e0 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -184,6 +184,7 @@ config IR_GPIO_TX
tristate "GPIO IR Bit Banging Transmitter"
depends on LIRC
depends on (OF && GPIOLIB) || COMPILE_TEST
+ depends on !PREEMPT_RT
help
Say Y if you want to a GPIO based IR transmitter. This is a
bit banging driver.
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index d7721e60776e..a733914a2574 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -311,9 +311,9 @@ static void ati_remote_dump(struct device *dev, unsigned char *data,
if (data[0] != (unsigned char)0xff && data[0] != 0x00)
dev_warn(dev, "Weird byte 0x%02x\n", data[0]);
} else if (len == 4)
- dev_warn(dev, "Weird key %*ph\n", 4, data);
+ dev_warn(dev, "Weird key %4ph\n", data);
else
- dev_warn(dev, "Weird data, len=%d %*ph ...\n", len, 6, data);
+ dev_warn(dev, "Weird data, len=%d %6ph ...\n", len, data);
}
/*
@@ -502,7 +502,7 @@ static void ati_remote_input_report(struct urb *urb)
if (data[1] != ((data[2] + data[3] + 0xd5) & 0xff)) {
dbginfo(&ati_remote->interface->dev,
- "wrong checksum in input: %*ph\n", 4, data);
+ "wrong checksum in input: %4ph\n", data);
return;
}
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index b29a1a9f381d..bf6d8fa983bf 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -201,7 +201,7 @@ MODULE_DEVICE_TABLE(of, gpio_ir_recv_of_match);
static struct platform_driver gpio_ir_recv_driver = {
.probe = gpio_ir_recv_probe,
- .remove_new = gpio_ir_recv_remove,
+ .remove = gpio_ir_recv_remove,
.driver = {
.name = KBUILD_MODNAME,
.of_match_table = gpio_ir_recv_of_match,
diff --git a/drivers/media/rc/gpio-ir-tx.c b/drivers/media/rc/gpio-ir-tx.c
index 1a8fea357f14..e185ead40464 100644
--- a/drivers/media/rc/gpio-ir-tx.c
+++ b/drivers/media/rc/gpio-ir-tx.c
@@ -78,8 +78,6 @@ static void gpio_ir_tx_unmodulated(struct gpio_ir *gpio_ir, uint *txbuf,
ktime_t edge;
int i;
- local_irq_disable();
-
edge = ktime_get();
for (i = 0; i < count; i++) {
@@ -110,8 +108,6 @@ static void gpio_ir_tx_modulated(struct gpio_ir *gpio_ir, uint *txbuf,
space = DIV_ROUND_CLOSEST((100 - gpio_ir->duty_cycle) *
(NSEC_PER_SEC / 100), gpio_ir->carrier);
- local_irq_disable();
-
edge = ktime_get();
for (i = 0; i < count; i++) {
diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c
index d87d8e14c556..067f4bc7fcc3 100644
--- a/drivers/media/rc/img-ir/img-ir-core.c
+++ b/drivers/media/rc/img-ir/img-ir-core.c
@@ -181,7 +181,7 @@ static struct platform_driver img_ir_driver = {
.pm = &img_ir_pmops,
},
.probe = img_ir_probe,
- .remove_new = img_ir_remove,
+ .remove = img_ir_remove,
};
module_platform_driver(img_ir_driver);
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
index de5bb9a08ea4..afd80d2350c6 100644
--- a/drivers/media/rc/ir-hix5hd2.c
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -394,7 +394,7 @@ static struct platform_driver hix5hd2_ir_driver = {
.pm = &hix5hd2_ir_pm_ops,
},
.probe = hix5hd2_ir_probe,
- .remove_new = hix5hd2_ir_remove,
+ .remove = hix5hd2_ir_remove,
};
module_platform_driver(hix5hd2_ir_driver);
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index f042f3f14afa..a2257dc2f25d 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -815,28 +815,23 @@ void __exit lirc_dev_exit(void)
struct rc_dev *rc_dev_get_from_fd(int fd, bool write)
{
- struct fd f = fdget(fd);
+ CLASS(fd, f)(fd);
struct lirc_fh *fh;
struct rc_dev *dev;
- if (!fd_file(f))
+ if (fd_empty(f))
return ERR_PTR(-EBADF);
- if (fd_file(f)->f_op != &lirc_fops) {
- fdput(f);
+ if (fd_file(f)->f_op != &lirc_fops)
return ERR_PTR(-EINVAL);
- }
- if (write && !(fd_file(f)->f_mode & FMODE_WRITE)) {
- fdput(f);
+ if (write && !(fd_file(f)->f_mode & FMODE_WRITE))
return ERR_PTR(-EPERM);
- }
fh = fd_file(f)->private_data;
dev = fh->rc;
get_device(&dev->dev);
- fdput(f);
return dev;
}
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
index 9cdb45821ecc..272ebb0d97c8 100644
--- a/drivers/media/rc/meson-ir.c
+++ b/drivers/media/rc/meson-ir.c
@@ -628,7 +628,7 @@ MODULE_DEVICE_TABLE(of, meson_ir_match);
static struct platform_driver meson_ir_driver = {
.probe = meson_ir_probe,
- .remove_new = meson_ir_remove,
+ .remove = meson_ir_remove,
.shutdown = meson_ir_shutdown,
.driver = {
.name = DRIVER_NAME,
diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c
index b2f82b2d1c8d..85c9436b0a20 100644
--- a/drivers/media/rc/mtk-cir.c
+++ b/drivers/media/rc/mtk-cir.c
@@ -440,7 +440,7 @@ static void mtk_ir_remove(struct platform_device *pdev)
static struct platform_driver mtk_ir_driver = {
.probe = mtk_ir_probe,
- .remove_new = mtk_ir_remove,
+ .remove = mtk_ir_remove,
.driver = {
.name = MTK_IR_DEV,
.of_match_table = mtk_ir_match,
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 988b09191c4c..6539fa0a6e79 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -408,7 +408,7 @@ static struct platform_driver st_rc_driver = {
.pm = &st_rc_pm_ops,
},
.probe = st_rc_probe,
- .remove_new = st_rc_remove,
+ .remove = st_rc_remove,
};
module_platform_driver(st_rc_driver);
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index b49df8355e6b..92ef4e7c6f69 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -413,7 +413,7 @@ MODULE_DEVICE_TABLE(of, sunxi_ir_match);
static struct platform_driver sunxi_ir_driver = {
.probe = sunxi_ir_probe,
- .remove_new = sunxi_ir_remove,
+ .remove = sunxi_ir_remove,
.shutdown = sunxi_ir_shutdown,
.driver = {
.name = SUNXI_IR_DEV,
diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c
index 846e90c06291..c45f5cf12ded 100644
--- a/drivers/media/test-drivers/vicodec/vicodec-core.c
+++ b/drivers/media/test-drivers/vicodec/vicodec-core.c
@@ -26,7 +26,7 @@
#include "codec-v4l2-fwht.h"
MODULE_DESCRIPTION("Virtual codec device");
-MODULE_AUTHOR("Hans Verkuil <hans.verkuil@cisco.com>");
+MODULE_AUTHOR("Hans Verkuil <hansverk@cisco.com>");
MODULE_LICENSE("GPL v2");
static bool multiplanar;
@@ -43,6 +43,8 @@ MODULE_PARM_DESC(debug, " activates debug info");
#define MIN_WIDTH 640U
#define MAX_HEIGHT 2160U
#define MIN_HEIGHT 360U
+/* Recommended number of buffers for the stateful codecs */
+#define VICODEC_REC_BUFS 2
#define dprintk(dev, fmt, arg...) \
v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
@@ -1688,8 +1690,6 @@ static const struct vb2_ops vicodec_qops = {
.buf_request_complete = vicodec_buf_request_complete,
.start_streaming = vicodec_start_streaming,
.stop_streaming = vicodec_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq,
@@ -1707,12 +1707,14 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
src_vq->ops = &vicodec_qops;
src_vq->mem_ops = &vb2_vmalloc_memops;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
- if (ctx->is_enc)
+ if (ctx->is_enc) {
src_vq->lock = &ctx->dev->stateful_enc.mutex;
- else if (ctx->is_stateless)
+ src_vq->min_reqbufs_allocation = VICODEC_REC_BUFS;
+ } else if (ctx->is_stateless) {
src_vq->lock = &ctx->dev->stateless_dec.mutex;
- else
+ } else {
src_vq->lock = &ctx->dev->stateful_dec.mutex;
+ }
src_vq->supports_requests = ctx->is_stateless;
src_vq->requires_requests = ctx->is_stateless;
ret = vb2_queue_init(src_vq);
@@ -1730,6 +1732,8 @@ static int queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->mem_ops = &vb2_vmalloc_memops;
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = src_vq->lock;
+ if (!ctx->is_stateless && !ctx->is_enc)
+ dst_vq->min_reqbufs_allocation = VICODEC_REC_BUFS;
return vb2_queue_init(dst_vq);
}
@@ -1854,11 +1858,16 @@ static int vicodec_open(struct file *file)
1, 31, 1, 20);
v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, V4L2_CID_FWHT_P_FRAME_QP,
1, 31, 1, 20);
- if (ctx->is_enc)
- v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops,
- V4L2_CID_MIN_BUFFERS_FOR_OUTPUT, 1, 1, 1, 1);
+
if (ctx->is_stateless)
v4l2_ctrl_new_custom(hdl, &vicodec_ctrl_stateless_state, NULL);
+ else
+ v4l2_ctrl_new_std(hdl, &vicodec_ctrl_ops, ctx->is_enc ?
+ V4L2_CID_MIN_BUFFERS_FOR_OUTPUT :
+ V4L2_CID_MIN_BUFFERS_FOR_CAPTURE,
+ VICODEC_REC_BUFS, VICODEC_REC_BUFS, 1,
+ VICODEC_REC_BUFS);
+
if (hdl->error) {
rc = hdl->error;
v4l2_ctrl_handler_free(hdl);
@@ -2207,7 +2216,7 @@ static void vicodec_remove(struct platform_device *pdev)
static struct platform_driver vicodec_pdrv = {
.probe = vicodec_probe,
- .remove_new = vicodec_remove,
+ .remove = vicodec_remove,
.driver = {
.name = VICODEC_NAME,
},
diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
index 613949df897d..e1dd8adeba46 100644
--- a/drivers/media/test-drivers/vidtv/vidtv_bridge.c
+++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
@@ -572,7 +572,7 @@ static struct platform_driver vidtv_bridge_driver = {
.name = VIDTV_PDEV_NAME,
},
.probe = vidtv_bridge_probe,
- .remove_new = vidtv_bridge_remove,
+ .remove = vidtv_bridge_remove,
};
static void __exit vidtv_bridge_exit(void)
diff --git a/drivers/media/test-drivers/vim2m.c b/drivers/media/test-drivers/vim2m.c
index 3e3b424b4860..6c24dcf27eb0 100644
--- a/drivers/media/test-drivers/vim2m.c
+++ b/drivers/media/test-drivers/vim2m.c
@@ -1100,8 +1100,6 @@ static const struct vb2_ops vim2m_qops = {
.buf_queue = vim2m_buf_queue,
.start_streaming = vim2m_start_streaming,
.stop_streaming = vim2m_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_request_complete = vim2m_buf_request_complete,
};
@@ -1394,7 +1392,7 @@ static void vim2m_remove(struct platform_device *pdev)
static struct platform_driver vim2m_pdrv = {
.probe = vim2m_probe,
- .remove_new = vim2m_remove,
+ .remove = vim2m_remove,
.driver = {
.name = MEM2MEM_NAME,
},
diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c
index 89506ae00901..10df039278e7 100644
--- a/drivers/media/test-drivers/vimc/vimc-capture.c
+++ b/drivers/media/test-drivers/vimc/vimc-capture.c
@@ -326,12 +326,6 @@ static const struct vb2_ops vimc_capture_qops = {
.buf_queue = vimc_capture_buf_queue,
.queue_setup = vimc_capture_queue_setup,
.buf_prepare = vimc_capture_buffer_prepare,
- /*
- * Since q->lock is set we can use the standard
- * vb2_ops_wait_prepare/finish helper functions.
- */
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct media_entity_operations vimc_capture_mops = {
diff --git a/drivers/media/test-drivers/vimc/vimc-core.c b/drivers/media/test-drivers/vimc/vimc-core.c
index 2083c60e34d6..c812fa9f0650 100644
--- a/drivers/media/test-drivers/vimc/vimc-core.c
+++ b/drivers/media/test-drivers/vimc/vimc-core.c
@@ -410,7 +410,7 @@ static struct platform_device vimc_pdev = {
static struct platform_driver vimc_pdrv = {
.probe = vimc_probe,
- .remove_new = vimc_remove,
+ .remove = vimc_remove,
.driver = {
.name = VIMC_PDEV_NAME,
},
diff --git a/drivers/media/test-drivers/visl/visl-core.c b/drivers/media/test-drivers/visl/visl-core.c
index c46464bcaf2e..01c964ea6f76 100644
--- a/drivers/media/test-drivers/visl/visl-core.c
+++ b/drivers/media/test-drivers/visl/visl-core.c
@@ -523,7 +523,7 @@ static void visl_remove(struct platform_device *pdev)
static struct platform_driver visl_pdrv = {
.probe = visl_probe,
- .remove_new = visl_remove,
+ .remove = visl_remove,
.driver = {
.name = VISL_NAME,
},
diff --git a/drivers/media/test-drivers/visl/visl-video.c b/drivers/media/test-drivers/visl/visl-video.c
index f8d970319764..8be505d8908c 100644
--- a/drivers/media/test-drivers/visl/visl-video.c
+++ b/drivers/media/test-drivers/visl/visl-video.c
@@ -136,6 +136,12 @@ static const u32 visl_decoded_fmts[] = {
V4L2_PIX_FMT_YUV420,
};
+static const u32 visl_extended_decoded_fmts[] = {
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_P010,
+};
+
const struct visl_coded_format_desc visl_coded_fmts[] = {
{
.pixelformat = V4L2_PIX_FMT_FWHT_STATELESS,
@@ -341,11 +347,21 @@ static int visl_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
struct visl_ctx *ctx = visl_file_to_ctx(file);
+ u32 index = f->index & ~V4L2_FMTDESC_FLAG_ENUM_ALL;
+ int max_fmts = ctx->coded_format_desc->num_decoded_fmts;
+ const u32 *decoded_fmts = ctx->coded_format_desc->decoded_fmts;
+
+ if (f->index & V4L2_FMTDESC_FLAG_ENUM_ALL) {
+ max_fmts = ARRAY_SIZE(visl_extended_decoded_fmts);
+ decoded_fmts = visl_extended_decoded_fmts;
+ }
+
+ f->index = index;
- if (f->index >= ctx->coded_format_desc->num_decoded_fmts)
+ if (index >= max_fmts)
return -EINVAL;
- f->pixelformat = ctx->coded_format_desc->decoded_fmts[f->index];
+ f->pixelformat = decoded_fmts[index];
return 0;
}
@@ -716,8 +732,6 @@ static const struct vb2_ops visl_qops = {
.buf_queue = visl_buf_queue,
.start_streaming = visl_start_streaming,
.stop_streaming = visl_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.buf_request_complete = visl_buf_request_complete,
};
diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c
index 00e0d08af357..7477ac8cb955 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.c
+++ b/drivers/media/test-drivers/vivid/vivid-core.c
@@ -910,7 +910,7 @@ static int vivid_create_queue(struct vivid_dev *dev,
* videobuf2-core.c to MAX_BUFFER_INDEX.
*/
if (buf_type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- q->max_num_buffers = 64;
+ q->max_num_buffers = MAX_VID_CAP_BUFFERS;
if (buf_type == V4L2_BUF_TYPE_SDR_CAPTURE)
q->max_num_buffers = 1024;
if (buf_type == V4L2_BUF_TYPE_VBI_CAPTURE)
@@ -2239,7 +2239,7 @@ static struct platform_device vivid_pdev = {
static struct platform_driver vivid_pdrv = {
.probe = vivid_probe,
- .remove_new = vivid_remove,
+ .remove = vivid_remove,
.driver = {
.name = "vivid",
},
diff --git a/drivers/media/test-drivers/vivid/vivid-core.h b/drivers/media/test-drivers/vivid/vivid-core.h
index cc18a3bc6dc0..d2d52763b119 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.h
+++ b/drivers/media/test-drivers/vivid/vivid-core.h
@@ -26,6 +26,8 @@
#define MAX_INPUTS 16
/* The maximum number of outputs */
#define MAX_OUTPUTS 16
+/* The maximum number of video capture buffers */
+#define MAX_VID_CAP_BUFFERS 64
/* The maximum up or down scaling factor is 4 */
#define MAX_ZOOM 4
/* The maximum image width/height are set to 4K DMT */
@@ -481,7 +483,7 @@ struct vivid_dev {
/* video capture */
struct tpg_data tpg;
unsigned ms_vid_cap;
- bool must_blank[VIDEO_MAX_FRAME];
+ bool must_blank[MAX_VID_CAP_BUFFERS];
const struct vivid_fmt *fmt_cap;
struct v4l2_fract timeperframe_vid_cap;
diff --git a/drivers/media/test-drivers/vivid/vivid-ctrls.c b/drivers/media/test-drivers/vivid/vivid-ctrls.c
index 8bb38bc7b8cc..2b5c8fbcd0a2 100644
--- a/drivers/media/test-drivers/vivid/vivid-ctrls.c
+++ b/drivers/media/test-drivers/vivid/vivid-ctrls.c
@@ -553,7 +553,7 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
break;
case VIVID_CID_PERCENTAGE_FILL:
tpg_s_perc_fill(&dev->tpg, ctrl->val);
- for (i = 0; i < VIDEO_MAX_FRAME; i++)
+ for (i = 0; i < MAX_VID_CAP_BUFFERS; i++)
dev->must_blank[i] = ctrl->val < 100;
break;
case VIVID_CID_INSERT_SAV:
diff --git a/drivers/media/test-drivers/vivid/vivid-meta-cap.c b/drivers/media/test-drivers/vivid/vivid-meta-cap.c
index 0a718d037e59..c7aaecc0b5a2 100644
--- a/drivers/media/test-drivers/vivid/vivid-meta-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-meta-cap.c
@@ -122,8 +122,6 @@ const struct vb2_ops vivid_meta_cap_qops = {
.start_streaming = meta_cap_start_streaming,
.stop_streaming = meta_cap_stop_streaming,
.buf_request_complete = meta_cap_buf_request_complete,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
int vidioc_enum_fmt_meta_cap(struct file *file, void *priv,
diff --git a/drivers/media/test-drivers/vivid/vivid-meta-out.c b/drivers/media/test-drivers/vivid/vivid-meta-out.c
index 82ab3b26914e..55e5e5dec2f2 100644
--- a/drivers/media/test-drivers/vivid/vivid-meta-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-meta-out.c
@@ -122,8 +122,6 @@ const struct vb2_ops vivid_meta_out_qops = {
.start_streaming = meta_out_start_streaming,
.stop_streaming = meta_out_stop_streaming,
.buf_request_complete = meta_out_buf_request_complete,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
int vidioc_enum_fmt_meta_out(struct file *file, void *priv,
diff --git a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
index 38cda33dffb2..74a91d28c8be 100644
--- a/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-sdr-cap.c
@@ -337,8 +337,6 @@ const struct vb2_ops vivid_sdr_cap_qops = {
.start_streaming = sdr_cap_start_streaming,
.stop_streaming = sdr_cap_stop_streaming,
.buf_request_complete = sdr_cap_buf_request_complete,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
int vivid_sdr_enum_freq_bands(struct file *file, void *fh,
diff --git a/drivers/media/test-drivers/vivid/vivid-touch-cap.c b/drivers/media/test-drivers/vivid/vivid-touch-cap.c
index 3600b084bca5..36a781fa17bc 100644
--- a/drivers/media/test-drivers/vivid/vivid-touch-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-touch-cap.c
@@ -110,8 +110,6 @@ const struct vb2_ops vivid_touch_cap_qops = {
.start_streaming = touch_cap_start_streaming,
.stop_streaming = touch_cap_stop_streaming,
.buf_request_complete = touch_cap_buf_request_complete,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
int vivid_enum_fmt_tch(struct file *file, void *priv, struct v4l2_fmtdesc *f)
diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
index 99138f63585c..a09f62c66c33 100644
--- a/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vbi-cap.c
@@ -230,8 +230,6 @@ const struct vb2_ops vivid_vbi_cap_qops = {
.start_streaming = vbi_cap_start_streaming,
.stop_streaming = vbi_cap_stop_streaming,
.buf_request_complete = vbi_cap_buf_request_complete,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-out.c b/drivers/media/test-drivers/vivid/vivid-vbi-out.c
index 871a56d93425..b7a09d2f394e 100644
--- a/drivers/media/test-drivers/vivid/vivid-vbi-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-vbi-out.c
@@ -128,8 +128,6 @@ const struct vb2_ops vivid_vbi_out_qops = {
.start_streaming = vbi_out_start_streaming,
.stop_streaming = vbi_out_stop_streaming,
.buf_request_complete = vbi_out_buf_request_complete,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
int vidioc_g_fmt_vbi_out(struct file *file, void *priv,
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
index 69620e0a35a0..b166d90177c6 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
@@ -10,6 +10,7 @@
#include <linux/sched.h>
#include <linux/vmalloc.h>
#include <linux/videodev2.h>
+#include <linux/prandom.h>
#include <linux/v4l2-dv-timings.h>
#include <media/v4l2-common.h>
#include <media/v4l2-event.h>
@@ -213,7 +214,7 @@ static int vid_cap_start_streaming(struct vb2_queue *vq, unsigned count)
dev->vid_cap_seq_count = 0;
dprintk(dev, 1, "%s\n", __func__);
- for (i = 0; i < VIDEO_MAX_FRAME; i++)
+ for (i = 0; i < MAX_VID_CAP_BUFFERS; i++)
dev->must_blank[i] = tpg_g_perc_fill(&dev->tpg) < 100;
if (dev->start_streaming_error) {
dev->start_streaming_error = false;
@@ -257,8 +258,6 @@ const struct vb2_ops vivid_vid_cap_qops = {
.start_streaming = vid_cap_start_streaming,
.stop_streaming = vid_cap_stop_streaming,
.buf_request_complete = vid_cap_buf_request_complete,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/*
@@ -1459,12 +1458,19 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings)
h_freq = (u32)bt->pixelclock / total_h_pixel;
if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_CVT)) {
+ struct v4l2_dv_timings cvt = {};
+
if (v4l2_detect_cvt(total_v_lines, h_freq, bt->vsync, bt->width,
- bt->polarities, bt->interlaced, timings))
+ bt->polarities, bt->interlaced,
+ &vivid_dv_timings_cap, &cvt) &&
+ cvt.bt.width == bt->width && cvt.bt.height == bt->height) {
+ *timings = cvt;
return true;
+ }
}
if (bt->standards == 0 || (bt->standards & V4L2_DV_BT_STD_GTF)) {
+ struct v4l2_dv_timings gtf = {};
struct v4l2_fract aspect_ratio;
find_aspect_ratio(bt->width, bt->height,
@@ -1472,8 +1478,12 @@ static bool valid_cvt_gtf_timings(struct v4l2_dv_timings *timings)
&aspect_ratio.denominator);
if (v4l2_detect_gtf(total_v_lines, h_freq, bt->vsync,
bt->polarities, bt->interlaced,
- aspect_ratio, timings))
+ aspect_ratio, &vivid_dv_timings_cap,
+ &gtf) &&
+ gtf.bt.width == bt->width && gtf.bt.height == bt->height) {
+ *timings = gtf;
return true;
+ }
}
return false;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-out.c b/drivers/media/test-drivers/vivid/vivid-vid-out.c
index 60327f3612af..5ec84db934d6 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-out.c
@@ -201,8 +201,6 @@ const struct vb2_ops vivid_vid_out_qops = {
.start_streaming = vid_out_start_streaming,
.stop_streaming = vid_out_stop_streaming,
.buf_request_complete = vid_out_buf_request_complete,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/*
diff --git a/drivers/media/tuners/it913x.c b/drivers/media/tuners/it913x.c
index 4d5b1c878028..9186174a46fd 100644
--- a/drivers/media/tuners/it913x.c
+++ b/drivers/media/tuners/it913x.c
@@ -444,7 +444,7 @@ static struct platform_driver it913x_driver = {
.suppress_bind_attrs = true,
},
.probe = it913x_probe,
- .remove_new = it913x_remove,
+ .remove = it913x_remove,
.id_table = it913x_id_table,
};
diff --git a/drivers/media/tuners/mt2063.c b/drivers/media/tuners/mt2063.c
index 6afef11a49cb..2c8ce74ddca4 100644
--- a/drivers/media/tuners/mt2063.c
+++ b/drivers/media/tuners/mt2063.c
@@ -1476,7 +1476,7 @@ static u32 MT2063_CalcLO2Mult(u32 *Div,
}
/*
- * FindClearTuneFilter() - Calculate the corrrect ClearTune filter to be
+ * FindClearTuneFilter() - Calculate the correct ClearTune filter to be
* used for a given input frequency.
*
* @state: ptr to tuner data structure
diff --git a/drivers/media/tuners/mxl301rf.c b/drivers/media/tuners/mxl301rf.c
index 7c03d4132763..3b61c3afed18 100644
--- a/drivers/media/tuners/mxl301rf.c
+++ b/drivers/media/tuners/mxl301rf.c
@@ -64,7 +64,7 @@ static int reg_read(struct mxl301rf_state *state, u8 reg, u8 *val)
/* tuner_ops */
-/* get RSSI and update propery cache, set to *out in % */
+/* get RSSI and update property cache, set to *out in % */
static int mxl301rf_get_rf_strength(struct dvb_frontend *fe, u16 *out)
{
struct mxl301rf_state *state;
diff --git a/drivers/media/tuners/mxl5005s.c b/drivers/media/tuners/mxl5005s.c
index d9bfa257a005..0e811c5eae6c 100644
--- a/drivers/media/tuners/mxl5005s.c
+++ b/drivers/media/tuners/mxl5005s.c
@@ -2639,7 +2639,7 @@ static u16 MXL_TuneRF(struct dvb_frontend *fe, u32 RF_Freq)
E5A = (((Fmax - state->RF_LO)/1000)*4/((Fmax-Fmin)/1000)) + 1 ;
status += MXL_ControlWrite(fe, RFSYN_LPF_R, E5A);
- /* Euqation E5B CHCAL_EN_INIT_RF */
+ /* Equation E5B CHCAL_EN_INIT_RF */
status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, ((E5 == 0) ? 1 : 0));
/*if (E5 == 0)
* status += MXL_ControlWrite(fe, CHCAL_EN_INT_RF, 1);
diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c
index a7e721baaa99..3a3309bc0151 100644
--- a/drivers/media/tuners/tda18271-fe.c
+++ b/drivers/media/tuners/tda18271-fe.c
@@ -279,7 +279,9 @@ static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
if (approx > 255)
approx = 255;
- tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
+ ret = tda18271_lookup_map(fe, RF_CAL_DC_OVER_DT, &freq, &dc_over_dt);
+ if (tda_fail(ret))
+ goto fail;
/* calculate temperature compensation */
rfcal_comp = dc_over_dt * (s32)(tm_current - priv->tm_rfcal) / 1000;
diff --git a/drivers/media/tuners/tea5761.c b/drivers/media/tuners/tea5761.c
index d78a2bdb3e36..425e9fd3f3d4 100644
--- a/drivers/media/tuners/tea5761.c
+++ b/drivers/media/tuners/tea5761.c
@@ -46,7 +46,7 @@ struct tea5761_priv {
/* FRQSET - Read: bytes 2 and 3 / Write: byte 1 and 2 */
/* First byte */
-#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from botton to up */
+#define TEA5761_FRQSET_SEARCH_UP 0x80 /* 1=Station search from bottom to up */
#define TEA5761_FRQSET_SEARCH_MODE 0x40 /* 1=Search mode */
/* Bits 0-5 for divider MSB */
@@ -132,7 +132,7 @@ static void tea5761_status_dump(unsigned char *buffer)
frq / 1000, frq % 1000, div);
}
-/* Freq should be specifyed at 62.5 Hz */
+/* Freq should be specified at 62.5 Hz */
static int __set_radio_freq(struct dvb_frontend *fe,
unsigned int freq,
bool mono)
diff --git a/drivers/media/tuners/tea5767.c b/drivers/media/tuners/tea5767.c
index 016d0d5ec50b..ef4acb1f1bfa 100644
--- a/drivers/media/tuners/tea5767.c
+++ b/drivers/media/tuners/tea5767.c
@@ -44,7 +44,7 @@ struct tea5767_priv {
/* Third register */
-/* Station search from botton to up */
+/* Station search from bottom to up */
#define TEA5767_SEARCH_UP 0x80
/* Searches with ADC output = 10 */
@@ -183,7 +183,7 @@ static void tea5767_status_dump(struct tea5767_priv *priv,
(buffer[4] & TEA5767_RESERVED_MASK));
}
-/* Freq should be specifyed at 62.5 Hz */
+/* Freq should be specified at 62.5 Hz */
static int set_radio_freq(struct dvb_frontend *fe,
struct analog_parameters *params)
{
diff --git a/drivers/media/usb/airspy/airspy.c b/drivers/media/usb/airspy/airspy.c
index e24e655fb1db..08f0920cf6ca 100644
--- a/drivers/media/usb/airspy/airspy.c
+++ b/drivers/media/usb/airspy/airspy.c
@@ -603,8 +603,6 @@ static const struct vb2_ops airspy_vb2_ops = {
.buf_queue = airspy_buf_queue,
.start_streaming = airspy_start_streaming,
.stop_streaming = airspy_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int airspy_querycap(struct file *file, void *fh,
@@ -1017,6 +1015,7 @@ static int airspy_probe(struct usb_interface *intf,
s->vb_queue.ops = &airspy_vb2_ops;
s->vb_queue.mem_ops = &vb2_vmalloc_memops;
s->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ s->vb_queue.lock = &s->vb_queue_lock;
ret = vb2_queue_init(&s->vb_queue);
if (ret) {
dev_err(s->dev, "Could not initialize vb2 queue\n");
@@ -1026,7 +1025,6 @@ static int airspy_probe(struct usb_interface *intf,
/* Init video_device structure */
s->vdev = airspy_template;
s->vdev.queue = &s->vb_queue;
- s->vdev.queue->lock = &s->vb_queue_lock;
video_set_drvdata(&s->vdev, s);
/* Register the v4l2_device structure */
diff --git a/drivers/media/usb/au0828/au0828-vbi.c b/drivers/media/usb/au0828/au0828-vbi.c
index b0333637b747..11203adf47ea 100644
--- a/drivers/media/usb/au0828/au0828-vbi.c
+++ b/drivers/media/usb/au0828/au0828-vbi.c
@@ -74,6 +74,4 @@ const struct vb2_ops au0828_vbi_qops = {
.prepare_streaming = v4l_vb2q_enable_media_source,
.start_streaming = au0828_start_analog_streaming,
.stop_streaming = au0828_stop_vbi_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 2ec49ea479d5..e9cd2a335f7f 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -915,8 +915,6 @@ static const struct vb2_ops au0828_video_qops = {
.prepare_streaming = v4l_vb2q_enable_media_source,
.start_streaming = au0828_start_analog_streaming,
.stop_streaming = au0828_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* ------------------------------------------------------------------
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index abb967c8bd35..a4a9781328c5 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -1458,8 +1458,6 @@ static const struct vb2_ops cx231xx_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* ------------------------------------------------------------------ */
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
index 3d3c881c8e58..6139ef5d891d 100644
--- a/drivers/media/usb/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -623,7 +623,7 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
}
int cx231xx_set_decoder_video_input(struct cx231xx *dev,
- u8 pin_type, u8 input)
+ u8 pin_type, u32 input)
{
int status = 0;
u32 value = 0;
@@ -1338,39 +1338,6 @@ void update_HH_register_after_set_DIF(struct cx231xx *dev)
*/
}
-void cx231xx_dump_HH_reg(struct cx231xx *dev)
-{
- u32 value = 0;
- u16 i = 0;
-
- value = 0x45005390;
- vid_blk_write_word(dev, 0x104, value);
-
- for (i = 0x100; i < 0x140; i++) {
- vid_blk_read_word(dev, i, &value);
- dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value);
- i = i+3;
- }
-
- for (i = 0x300; i < 0x400; i++) {
- vid_blk_read_word(dev, i, &value);
- dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value);
- i = i+3;
- }
-
- for (i = 0x400; i < 0x440; i++) {
- vid_blk_read_word(dev, i, &value);
- dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value);
- i = i+3;
- }
-
- vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
- dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
- vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
- vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
- dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
-}
-
#if 0
static void cx231xx_dump_SC_reg(struct cx231xx *dev)
{
@@ -2460,30 +2427,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
return status;
}
-int cx231xx_power_suspend(struct cx231xx *dev)
-{
- u8 value[4] = { 0, 0, 0, 0 };
- u32 tmp = 0;
- int status = 0;
-
- status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
- value, 4);
- if (status > 0)
- return status;
-
- tmp = le32_to_cpu(*((__le32 *) value));
- tmp &= (~PWR_MODE_MASK);
-
- value[0] = (u8) tmp;
- value[1] = (u8) (tmp >> 8);
- value[2] = (u8) (tmp >> 16);
- value[3] = (u8) (tmp >> 24);
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER, PWR_CTL_EN,
- value, 4);
-
- return status;
-}
-
/******************************************************************************
* S T R E A M C O N T R O L functions *
******************************************************************************/
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 92efe6c1f47b..691f073892b3 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -679,8 +679,7 @@ struct cx231xx_board cx231xx_boards[] = {
}, {
.type = CX231XX_VMUX_SVIDEO,
.vmux = CX231XX_VIN_1_1 |
- (CX231XX_VIN_1_2 << 8) |
- CX25840_SVIDEO_ON,
+ (CX231XX_VIN_3_2 << 8),
.amux = CX231XX_AMUX_LINE_IN,
.gpio = NULL,
}
@@ -990,10 +989,11 @@ struct cx231xx_board cx231xx_boards[] = {
} },
},
};
-const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
/* table of devices that work with this driver */
struct usb_device_id cx231xx_id_table[] = {
+ {USB_DEVICE(0x1D19, 0x6108),
+ .driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
{USB_DEVICE(0x1D19, 0x6109),
.driver_info = CX231XX_BOARD_PV_XCAPTURE_USB},
{USB_DEVICE(0x0572, 0x5A3C),
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index 33431d9f54c2..338e10148465 100644
--- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -243,8 +243,6 @@ struct vb2_ops cx231xx_vbi_qops = {
.buf_queue = vbi_buf_queue,
.start_streaming = vbi_start_streaming,
.stop_streaming = vbi_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/* ------------------------------------------------------------------
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 435eb0b32cb1..2cd4e333bc4b 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -800,8 +800,6 @@ static const struct vb2_ops cx231xx_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/********************* v4l2 interface **************************************/
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index 74339a6a2f71..19f5036a78d7 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -790,7 +790,6 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
u8 spectral_invert, u32 mode);
void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev);
void reset_s5h1432_demod(struct cx231xx *dev);
-void cx231xx_dump_HH_reg(struct cx231xx *dev);
void update_HH_register_after_set_DIF(struct cx231xx *dev);
@@ -905,7 +904,6 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type);
/* Power control functions */
int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode);
-int cx231xx_power_suspend(struct cx231xx *dev);
/* chip specific control functions */
int cx231xx_init_ctrl_pin_status(struct cx231xx *dev);
@@ -916,7 +914,7 @@ int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3);
/* video audio decoder related functions */
void video_mux(struct cx231xx *dev, int index);
int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input);
-int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u8 input);
+int cx231xx_set_decoder_video_input(struct cx231xx *dev, u8 pin_type, u32 input);
int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev);
int cx231xx_set_audio_input(struct cx231xx *dev, u8 input);
@@ -949,7 +947,6 @@ extern void cx231xx_pre_card_setup(struct cx231xx *dev);
extern void cx231xx_card_setup(struct cx231xx *dev);
extern struct cx231xx_board cx231xx_boards[];
extern struct usb_device_id cx231xx_id_table[];
-extern const unsigned int cx231xx_bcount;
int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
/* cx23885-417.c */
diff --git a/drivers/media/usb/dvb-usb-v2/anysee.c b/drivers/media/usb/dvb-usb-v2/anysee.c
index 8699846eb416..bea12cdc85e8 100644
--- a/drivers/media/usb/dvb-usb-v2/anysee.c
+++ b/drivers/media/usb/dvb-usb-v2/anysee.c
@@ -46,24 +46,15 @@ static int anysee_ctrl_msg(struct dvb_usb_device *d,
dev_dbg(&d->udev->dev, "%s: >>> %*ph\n", __func__, slen, state->buf);
- /* We need receive one message more after dvb_usb_generic_rw due
- to weird transaction flow, which is 1 x send + 2 x receive. */
+ /*
+ * We need receive one message more after dvb_usbv2_generic_rw_locked()
+ * due to weird transaction flow, which is 1 x send + 2 x receive.
+ */
ret = dvb_usbv2_generic_rw_locked(d, state->buf, sizeof(state->buf),
state->buf, sizeof(state->buf));
if (ret)
goto error_unlock;
- /* TODO FIXME: dvb_usb_generic_rw() fails rarely with error code -32
- * (EPIPE, Broken pipe). Function supports currently msleep() as a
- * parameter but I would not like to use it, since according to
- * Documentation/timers/timers-howto.rst it should not be used such
- * short, under < 20ms, sleeps. Repeating failed message would be
- * better choice as not to add unwanted delays...
- * Fixing that correctly is one of those or both;
- * 1) use repeat if possible
- * 2) add suitable delay
- */
-
/* get answer, retry few times if error returned */
for (i = 0; i < 3; i++) {
/* receive 2nd answer */
diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c
index b5d8c6b75ae1..8253046cd6e6 100644
--- a/drivers/media/usb/dvb-usb/cxusb-analog.c
+++ b/drivers/media/usb/dvb-usb/cxusb-analog.c
@@ -956,8 +956,6 @@ static const struct vb2_ops cxdev_video_qops = {
.start_streaming = cxusb_medion_v_start_streaming,
.stop_streaming = cxusb_medion_v_stop_streaming,
.buf_queue = cxusub_medion_v_buf_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish
};
static const __u32 videocaps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER |
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index b253c44c9724..8c5d95181223 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -84,6 +84,4 @@ const struct vb2_ops em28xx_vbi_qops = {
.buf_queue = vbi_buffer_queue,
.start_streaming = em28xx_start_analog_streaming,
.stop_streaming = em28xx_stop_vbi_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 4aef584e21da..66c09bc6d59e 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -1229,8 +1229,6 @@ static const struct vb2_ops em28xx_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = em28xx_start_analog_streaming,
.stop_streaming = em28xx_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int em28xx_vb2_setup(struct em28xx *dev)
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c
index 13256565b034..2087ffcb85a5 100644
--- a/drivers/media/usb/go7007/go7007-v4l2.c
+++ b/drivers/media/usb/go7007/go7007-v4l2.c
@@ -452,8 +452,6 @@ static const struct vb2_ops go7007_video_qops = {
.buf_finish = go7007_buf_finish,
.start_streaming = go7007_start_streaming,
.stop_streaming = go7007_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int vidioc_g_parm(struct file *filp, void *priv,
diff --git a/drivers/media/usb/gspca/gspca.c b/drivers/media/usb/gspca/gspca.c
index e8c8bdb9c40b..25edd2189654 100644
--- a/drivers/media/usb/gspca/gspca.c
+++ b/drivers/media/usb/gspca/gspca.c
@@ -1380,8 +1380,6 @@ static const struct vb2_ops gspca_qops = {
.buf_queue = gspca_buffer_queue,
.start_streaming = gspca_start_streaming,
.stop_streaming = gspca_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct v4l2_file_operations dev_fops = {
diff --git a/drivers/media/usb/gspca/ov534.c b/drivers/media/usb/gspca/ov534.c
index 8b6a57f170d0..bdff64a29a33 100644
--- a/drivers/media/usb/gspca/ov534.c
+++ b/drivers/media/usb/gspca/ov534.c
@@ -847,7 +847,7 @@ static void set_frame_rate(struct gspca_dev *gspca_dev)
r = rate_1;
i = ARRAY_SIZE(rate_1);
}
- while (--i > 0) {
+ while (--i >= 0) {
if (sd->frame_rate >= r->fps)
break;
r++;
diff --git a/drivers/media/usb/hackrf/hackrf.c b/drivers/media/usb/hackrf/hackrf.c
index 9c0ecd5f056c..0b50de8775a3 100644
--- a/drivers/media/usb/hackrf/hackrf.c
+++ b/drivers/media/usb/hackrf/hackrf.c
@@ -888,8 +888,6 @@ static const struct vb2_ops hackrf_vb2_ops = {
.buf_queue = hackrf_buf_queue,
.start_streaming = hackrf_start_streaming,
.stop_streaming = hackrf_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int hackrf_querycap(struct file *file, void *fh,
@@ -1398,6 +1396,7 @@ static int hackrf_probe(struct usb_interface *intf,
dev->rx_vb2_queue.drv_priv = dev;
dev->rx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer);
dev->rx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ dev->rx_vb2_queue.lock = &dev->vb_queue_lock;
ret = vb2_queue_init(&dev->rx_vb2_queue);
if (ret) {
dev_err(dev->dev, "Could not initialize rx vb2 queue\n");
@@ -1413,6 +1412,7 @@ static int hackrf_probe(struct usb_interface *intf,
dev->tx_vb2_queue.drv_priv = dev;
dev->tx_vb2_queue.buf_struct_size = sizeof(struct hackrf_buffer);
dev->tx_vb2_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ dev->tx_vb2_queue.lock = &dev->vb_queue_lock;
ret = vb2_queue_init(&dev->tx_vb2_queue);
if (ret) {
dev_err(dev->dev, "Could not initialize tx vb2 queue\n");
@@ -1474,7 +1474,6 @@ static int hackrf_probe(struct usb_interface *intf,
/* Init video_device structure for receiver */
dev->rx_vdev = hackrf_template;
dev->rx_vdev.queue = &dev->rx_vb2_queue;
- dev->rx_vdev.queue->lock = &dev->vb_queue_lock;
dev->rx_vdev.v4l2_dev = &dev->v4l2_dev;
dev->rx_vdev.ctrl_handler = &dev->rx_ctrl_handler;
dev->rx_vdev.lock = &dev->v4l2_lock;
@@ -1494,7 +1493,6 @@ static int hackrf_probe(struct usb_interface *intf,
/* Init video_device structure for transmitter */
dev->tx_vdev = hackrf_template;
dev->tx_vdev.queue = &dev->tx_vb2_queue;
- dev->tx_vdev.queue->lock = &dev->vb_queue_lock;
dev->tx_vdev.v4l2_dev = &dev->v4l2_dev;
dev->tx_vdev.ctrl_handler = &dev->tx_ctrl_handler;
dev->tx_vdev.lock = &dev->v4l2_lock;
diff --git a/drivers/media/usb/msi2500/msi2500.c b/drivers/media/usb/msi2500/msi2500.c
index 5138486abfa0..33099f39146a 100644
--- a/drivers/media/usb/msi2500/msi2500.c
+++ b/drivers/media/usb/msi2500/msi2500.c
@@ -883,8 +883,6 @@ static const struct vb2_ops msi2500_vb2_ops = {
.buf_queue = msi2500_buf_queue,
.start_streaming = msi2500_start_streaming,
.stop_streaming = msi2500_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int msi2500_enum_fmt_sdr_cap(struct file *file, void *priv,
@@ -1199,6 +1197,7 @@ static int msi2500_probe(struct usb_interface *intf,
dev->vb_queue.ops = &msi2500_vb2_ops;
dev->vb_queue.mem_ops = &vb2_vmalloc_memops;
dev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ dev->vb_queue.lock = &dev->vb_queue_lock;
ret = vb2_queue_init(&dev->vb_queue);
if (ret) {
dev_err(dev->dev, "Could not initialize vb2 queue\n");
@@ -1208,7 +1207,6 @@ static int msi2500_probe(struct usb_interface *intf,
/* Init video_device structure */
dev->vdev = msi2500_template;
dev->vdev.queue = &dev->vb_queue;
- dev->vdev.queue->lock = &dev->vb_queue_lock;
video_set_drvdata(&dev->vdev, dev);
/* Register the v4l2_device structure */
@@ -1219,8 +1217,8 @@ static int msi2500_probe(struct usb_interface *intf,
goto err_free_mem;
}
- /* SPI master adapter */
- ctlr = spi_alloc_master(dev->dev, 0);
+ /* SPI host adapter */
+ ctlr = spi_alloc_host(dev->dev, 0);
if (ctlr == NULL) {
ret = -ENOMEM;
goto err_unregister_v4l2_dev;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-io.c b/drivers/media/usb/pvrusb2/pvrusb2-io.c
index 675dc7153e2b..28ffe7981f8c 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-io.c
@@ -335,8 +335,8 @@ static int pvr2_stream_buffer_count(struct pvr2_stream *sp, unsigned int cnt)
if (scnt < sp->buffer_slot_count) {
struct pvr2_buffer **nb = NULL;
if (scnt) {
- nb = kmemdup(sp->buffers, scnt * sizeof(*nb),
- GFP_KERNEL);
+ nb = kmemdup_array(sp->buffers, scnt, sizeof(*nb),
+ GFP_KERNEL);
if (!nb) return -ENOMEM;
}
kfree(sp->buffers);
diff --git a/drivers/media/usb/pwc/pwc-if.c b/drivers/media/usb/pwc/pwc-if.c
index e342199711d3..3ec9eb5956ed 100644
--- a/drivers/media/usb/pwc/pwc-if.c
+++ b/drivers/media/usb/pwc/pwc-if.c
@@ -760,8 +760,6 @@ static const struct vb2_ops pwc_vb_queue_ops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
/***************************************************************************/
@@ -1054,6 +1052,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vb_queue.ops = &pwc_vb_queue_ops;
pdev->vb_queue.mem_ops = &vb2_vmalloc_memops;
pdev->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ pdev->vb_queue.lock = &pdev->vb_queue_lock;
rc = vb2_queue_init(&pdev->vb_queue);
if (rc < 0) {
PWC_ERROR("Oops, could not initialize vb2 queue.\n");
@@ -1064,7 +1063,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
pdev->vdev = pwc_template;
strscpy(pdev->vdev.name, name, sizeof(pdev->vdev.name));
pdev->vdev.queue = &pdev->vb_queue;
- pdev->vdev.queue->lock = &pdev->vb_queue_lock;
video_set_drvdata(&pdev->vdev, pdev);
pdev->release = le16_to_cpu(udev->descriptor.bcdDevice);
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index a6e450181fd0..899a7a67e2ba 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -704,8 +704,6 @@ static const struct vb2_ops s2255_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int vidioc_querycap(struct file *file, void *priv,
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index a1f785a5ffd8..5ba3d9c4b3fb 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -734,8 +734,6 @@ static const struct vb2_ops stk1160_video_qops = {
.buf_queue = buffer_queue,
.start_streaming = start_streaming,
.stop_streaming = stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static const struct video_device v4l_template = {
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index 702f1c8bd2ab..be22a9697197 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -780,8 +780,6 @@ static const struct vb2_ops usbtv_vb2_ops = {
.buf_queue = usbtv_buf_queue,
.start_streaming = usbtv_start_streaming,
.stop_streaming = usbtv_stop_streaming,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
};
static int usbtv_s_ctrl(struct v4l2_ctrl *ctrl)
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 0fac689c6350..b3c8411dc05c 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -371,7 +371,7 @@ static int uvc_parse_format(struct uvc_device *dev,
* Parse the frame descriptors. Only uncompressed, MJPEG and frame
* based formats have frame descriptors.
*/
- while (buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
+ while (ftype && buflen > 2 && buffer[1] == USB_DT_CS_INTERFACE &&
buffer[2] == ftype) {
unsigned int maxIntervalIndex;
@@ -775,14 +775,27 @@ static const u8 uvc_media_transport_input_guid[16] =
UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
static const u8 uvc_processing_guid[16] = UVC_GUID_UVC_PROCESSING;
-static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id,
- unsigned int num_pads, unsigned int extra_size)
+static struct uvc_entity *uvc_alloc_new_entity(struct uvc_device *dev, u16 type,
+ u16 id, unsigned int num_pads,
+ unsigned int extra_size)
{
struct uvc_entity *entity;
unsigned int num_inputs;
unsigned int size;
unsigned int i;
+ /* Per UVC 1.1+ spec 3.7.2, the ID should be non-zero. */
+ if (id == 0) {
+ dev_err(&dev->udev->dev, "Found Unit with invalid ID 0.\n");
+ return ERR_PTR(-EINVAL);
+ }
+
+ /* Per UVC 1.1+ spec 3.7.2, the ID is unique. */
+ if (uvc_entity_by_id(dev, id)) {
+ dev_err(&dev->udev->dev, "Found multiple Units with ID %u\n", id);
+ return ERR_PTR(-EINVAL);
+ }
+
extra_size = roundup(extra_size, sizeof(*entity->pads));
if (num_pads)
num_inputs = type & UVC_TERM_OUTPUT ? num_pads : num_pads - 1;
@@ -792,7 +805,7 @@ static struct uvc_entity *uvc_alloc_entity(u16 type, u16 id,
+ num_inputs;
entity = kzalloc(size, GFP_KERNEL);
if (entity == NULL)
- return NULL;
+ return ERR_PTR(-ENOMEM);
entity->id = id;
entity->type = type;
@@ -904,10 +917,10 @@ static int uvc_parse_vendor_control(struct uvc_device *dev,
break;
}
- unit = uvc_alloc_entity(UVC_VC_EXTENSION_UNIT, buffer[3],
- p + 1, 2*n);
- if (unit == NULL)
- return -ENOMEM;
+ unit = uvc_alloc_new_entity(dev, UVC_VC_EXTENSION_UNIT,
+ buffer[3], p + 1, 2 * n);
+ if (IS_ERR(unit))
+ return PTR_ERR(unit);
memcpy(unit->guid, &buffer[4], 16);
unit->extension.bNumControls = buffer[20];
@@ -1016,10 +1029,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
return -EINVAL;
}
- term = uvc_alloc_entity(type | UVC_TERM_INPUT, buffer[3],
- 1, n + p);
- if (term == NULL)
- return -ENOMEM;
+ term = uvc_alloc_new_entity(dev, type | UVC_TERM_INPUT,
+ buffer[3], 1, n + p);
+ if (IS_ERR(term))
+ return PTR_ERR(term);
if (UVC_ENTITY_TYPE(term) == UVC_ITT_CAMERA) {
term->camera.bControlSize = n;
@@ -1075,10 +1088,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
return 0;
}
- term = uvc_alloc_entity(type | UVC_TERM_OUTPUT, buffer[3],
- 1, 0);
- if (term == NULL)
- return -ENOMEM;
+ term = uvc_alloc_new_entity(dev, type | UVC_TERM_OUTPUT,
+ buffer[3], 1, 0);
+ if (IS_ERR(term))
+ return PTR_ERR(term);
memcpy(term->baSourceID, &buffer[7], 1);
@@ -1097,9 +1110,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
return -EINVAL;
}
- unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, 0);
- if (unit == NULL)
- return -ENOMEM;
+ unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3],
+ p + 1, 0);
+ if (IS_ERR(unit))
+ return PTR_ERR(unit);
memcpy(unit->baSourceID, &buffer[5], p);
@@ -1119,9 +1133,9 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
return -EINVAL;
}
- unit = uvc_alloc_entity(buffer[2], buffer[3], 2, n);
- if (unit == NULL)
- return -ENOMEM;
+ unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3], 2, n);
+ if (IS_ERR(unit))
+ return PTR_ERR(unit);
memcpy(unit->baSourceID, &buffer[4], 1);
unit->processing.wMaxMultiplier =
@@ -1148,9 +1162,10 @@ static int uvc_parse_standard_control(struct uvc_device *dev,
return -EINVAL;
}
- unit = uvc_alloc_entity(buffer[2], buffer[3], p + 1, n);
- if (unit == NULL)
- return -ENOMEM;
+ unit = uvc_alloc_new_entity(dev, buffer[2], buffer[3],
+ p + 1, n);
+ if (IS_ERR(unit))
+ return PTR_ERR(unit);
memcpy(unit->guid, &buffer[4], 16);
unit->extension.bNumControls = buffer[20];
@@ -1290,9 +1305,10 @@ static int uvc_gpio_parse(struct uvc_device *dev)
return dev_err_probe(&dev->udev->dev, irq,
"No IRQ for privacy GPIO\n");
- unit = uvc_alloc_entity(UVC_EXT_GPIO_UNIT, UVC_EXT_GPIO_UNIT_ID, 0, 1);
- if (!unit)
- return -ENOMEM;
+ unit = uvc_alloc_new_entity(dev, UVC_EXT_GPIO_UNIT,
+ UVC_EXT_GPIO_UNIT_ID, 0, 1);
+ if (IS_ERR(unit))
+ return PTR_ERR(unit);
unit->gpio.gpio_privacy = gpio_privacy;
unit->gpio.irq = irq;
@@ -1919,11 +1935,41 @@ static void uvc_unregister_video(struct uvc_device *dev)
struct uvc_streaming *stream;
list_for_each_entry(stream, &dev->streams, list) {
+ /* Nothing to do here, continue. */
if (!video_is_registered(&stream->vdev))
continue;
+ /*
+ * For stream->vdev we follow the same logic as:
+ * vb2_video_unregister_device().
+ */
+
+ /* 1. Take a reference to vdev */
+ get_device(&stream->vdev.dev);
+
+ /* 2. Ensure that no new ioctls can be called. */
video_unregister_device(&stream->vdev);
- video_unregister_device(&stream->meta.vdev);
+
+ /* 3. Wait for old ioctls to finish. */
+ mutex_lock(&stream->mutex);
+
+ /* 4. Stop streaming. */
+ uvc_queue_release(&stream->queue);
+
+ mutex_unlock(&stream->mutex);
+
+ put_device(&stream->vdev.dev);
+
+ /*
+ * For stream->meta.vdev we can directly call:
+ * vb2_video_unregister_device().
+ */
+ vb2_video_unregister_device(&stream->meta.vdev);
+
+ /*
+ * Now both vdevs are not streaming and all the ioctls will
+ * return -ENODEV.
+ */
uvc_debugfs_cleanup_stream(stream);
}
@@ -2116,7 +2162,6 @@ static int uvc_probe(struct usb_interface *intf,
INIT_LIST_HEAD(&dev->streams);
kref_init(&dev->ref);
atomic_set(&dev->nmappings, 0);
- mutex_init(&dev->lock);
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
@@ -2288,10 +2333,7 @@ static int uvc_suspend(struct usb_interface *intf, pm_message_t message)
/* Controls are cached on the fly so they don't need to be saved. */
if (intf->cur_altsetting->desc.bInterfaceSubClass ==
UVC_SC_VIDEOCONTROL) {
- mutex_lock(&dev->lock);
- if (dev->users)
- uvc_status_stop(dev);
- mutex_unlock(&dev->lock);
+ uvc_status_suspend(dev);
return 0;
}
@@ -2322,12 +2364,7 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
return ret;
}
- mutex_lock(&dev->lock);
- if (dev->users)
- ret = uvc_status_start(dev, GFP_NOIO);
- mutex_unlock(&dev->lock);
-
- return ret;
+ return uvc_status_resume(dev);
}
list_for_each_entry(stream, &dev->streams, list) {
@@ -2428,12 +2465,25 @@ static const struct uvc_device_info uvc_quirk_force_y8 = {
* The Logitech cameras listed below have their interface class set to
* VENDOR_SPEC because they don't announce themselves as UVC devices, even
* though they are compliant.
+ *
+ * Sort these by vendor/product ID.
*/
static const struct usb_device_id uvc_ids[] = {
/* Quanta ACER HD User Facing */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = 0x0408,
+ .idProduct = 0x4033,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = UVC_PC_PROTOCOL_15,
+ .driver_info = (kernel_ulong_t)&(const struct uvc_device_info){
+ .uvc_version = 0x010a,
+ } },
+ /* Quanta ACER HD User Facing */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x0408,
.idProduct = 0x4035,
.bInterfaceClass = USB_CLASS_VIDEO,
.bInterfaceSubClass = 1,
@@ -2964,6 +3014,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceProtocol = 0,
.driver_info = UVC_INFO_QUIRK(UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_IGNORE_SELECTOR_UNIT) },
+ /* NXP Semiconductors IR VIDEO */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x1fc9,
+ .idProduct = 0x009b,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = (kernel_ulong_t)&uvc_quirk_probe_minmax },
/* Oculus VR Positional Tracker DK2 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -3072,6 +3131,15 @@ static const struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) },
+ /* Intel D421 Depth Module */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x8086,
+ .idProduct = 0x1155,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_INFO_META(V4L2_META_FMT_D4XX) },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_UNDEFINED) },
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, UVC_PC_PROTOCOL_15) },
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 16fa17bbd15e..26ee85657fc8 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -197,8 +197,6 @@ static const struct vb2_ops uvc_queue_qops = {
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
.buf_finish = uvc_buffer_finish,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.start_streaming = uvc_start_streaming,
.stop_streaming = uvc_stop_streaming,
};
@@ -207,8 +205,6 @@ static const struct vb2_ops uvc_meta_queue_qops = {
.queue_setup = uvc_queue_setup,
.buf_prepare = uvc_buffer_prepare,
.buf_queue = uvc_buffer_queue,
- .wait_prepare = vb2_ops_wait_prepare,
- .wait_finish = vb2_ops_wait_finish,
.stop_streaming = uvc_stop_streaming,
};
diff --git a/drivers/media/usb/uvc/uvc_status.c b/drivers/media/usb/uvc/uvc_status.c
index a78a88c710e2..06c867510c8f 100644
--- a/drivers/media/usb/uvc/uvc_status.c
+++ b/drivers/media/usb/uvc/uvc_status.c
@@ -257,6 +257,8 @@ int uvc_status_init(struct uvc_device *dev)
unsigned int pipe;
int interval;
+ mutex_init(&dev->status_lock);
+
if (ep == NULL)
return 0;
@@ -292,7 +294,7 @@ int uvc_status_init(struct uvc_device *dev)
void uvc_status_unregister(struct uvc_device *dev)
{
- usb_kill_urb(dev->int_urb);
+ uvc_status_suspend(dev);
uvc_input_unregister(dev);
}
@@ -302,18 +304,25 @@ void uvc_status_cleanup(struct uvc_device *dev)
kfree(dev->status);
}
-int uvc_status_start(struct uvc_device *dev, gfp_t flags)
+static int uvc_status_start(struct uvc_device *dev, gfp_t flags)
{
- if (dev->int_urb == NULL)
+ lockdep_assert_held(&dev->status_lock);
+
+ if (!dev->int_urb)
return 0;
return usb_submit_urb(dev->int_urb, flags);
}
-void uvc_status_stop(struct uvc_device *dev)
+static void uvc_status_stop(struct uvc_device *dev)
{
struct uvc_ctrl_work *w = &dev->async_ctrl;
+ lockdep_assert_held(&dev->status_lock);
+
+ if (!dev->int_urb)
+ return;
+
/*
* Prevent the asynchronous control handler from requeing the URB. The
* barrier is needed so the flush_status change is visible to other
@@ -350,3 +359,49 @@ void uvc_status_stop(struct uvc_device *dev)
*/
smp_store_release(&dev->flush_status, false);
}
+
+int uvc_status_resume(struct uvc_device *dev)
+{
+ guard(mutex)(&dev->status_lock);
+
+ if (dev->status_users)
+ return uvc_status_start(dev, GFP_NOIO);
+
+ return 0;
+}
+
+void uvc_status_suspend(struct uvc_device *dev)
+{
+ guard(mutex)(&dev->status_lock);
+
+ if (dev->status_users)
+ uvc_status_stop(dev);
+}
+
+int uvc_status_get(struct uvc_device *dev)
+{
+ int ret;
+
+ guard(mutex)(&dev->status_lock);
+
+ if (!dev->status_users) {
+ ret = uvc_status_start(dev, GFP_KERNEL);
+ if (ret)
+ return ret;
+ }
+
+ dev->status_users++;
+
+ return 0;
+}
+
+void uvc_status_put(struct uvc_device *dev)
+{
+ guard(mutex)(&dev->status_lock);
+
+ if (dev->status_users == 1)
+ uvc_status_stop(dev);
+ WARN_ON(!dev->status_users);
+ if (dev->status_users)
+ dev->status_users--;
+}
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index f4988f03640a..97c5407f6603 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -628,20 +628,13 @@ static int uvc_v4l2_open(struct file *file)
return -ENOMEM;
}
- mutex_lock(&stream->dev->lock);
- if (stream->dev->users == 0) {
- ret = uvc_status_start(stream->dev, GFP_KERNEL);
- if (ret < 0) {
- mutex_unlock(&stream->dev->lock);
- usb_autopm_put_interface(stream->dev->intf);
- kfree(handle);
- return ret;
- }
+ ret = uvc_status_get(stream->dev);
+ if (ret) {
+ usb_autopm_put_interface(stream->dev->intf);
+ kfree(handle);
+ return ret;
}
- stream->dev->users++;
- mutex_unlock(&stream->dev->lock);
-
v4l2_fh_init(&handle->vfh, &stream->vdev);
v4l2_fh_add(&handle->vfh);
handle->chain = stream->chain;
@@ -670,10 +663,7 @@ static int uvc_v4l2_release(struct file *file)
kfree(handle);
file->private_data = NULL;
- mutex_lock(&stream->dev->lock);
- if (--stream->dev->users == 0)
- uvc_status_stop(stream->dev);
- mutex_unlock(&stream->dev->lock);
+ uvc_status_put(stream->dev);
usb_autopm_put_interface(stream->dev->intf);
return 0;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index b7d24a853ce4..07f9921d83f2 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -563,8 +563,6 @@ struct uvc_device {
const struct uvc_device_info *info;
- struct mutex lock; /* Protects users */
- unsigned int users;
atomic_t nmappings;
/* Video control interface */
@@ -586,6 +584,8 @@ struct uvc_device {
struct usb_host_endpoint *int_ep;
struct urb *int_urb;
struct uvc_status *status;
+ struct mutex status_lock; /* Protects status_users */
+ unsigned int status_users;
bool flush_status;
struct input_dev *input;
@@ -752,8 +752,10 @@ int uvc_register_video_device(struct uvc_device *dev,
int uvc_status_init(struct uvc_device *dev);
void uvc_status_unregister(struct uvc_device *dev);
void uvc_status_cleanup(struct uvc_device *dev);
-int uvc_status_start(struct uvc_device *dev, gfp_t flags);
-void uvc_status_stop(struct uvc_device *dev);
+int uvc_status_resume(struct uvc_device *dev);
+void uvc_status_suspend(struct uvc_device *dev);
+int uvc_status_get(struct uvc_device *dev);
+void uvc_status_put(struct uvc_device *dev);
/* Controls */
extern const struct v4l2_subscribed_event_ops uvc_ctrl_sub_ev_ops;
diff --git a/drivers/media/v4l2-core/v4l2-ctrls-api.c b/drivers/media/v4l2-core/v4l2-ctrls-api.c
index e5a364efd5e6..95a2202879d8 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls-api.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls-api.c
@@ -753,9 +753,10 @@ static int get_ctrl(struct v4l2_ctrl *ctrl, struct v4l2_ext_control *c)
for (i = 0; i < master->ncontrols; i++)
cur_to_new(master->cluster[i]);
ret = call_op(master, g_volatile_ctrl);
- new_to_user(c, ctrl);
+ if (!ret)
+ ret = new_to_user(c, ctrl);
} else {
- cur_to_user(c, ctrl);
+ ret = cur_to_user(c, ctrl);
}
v4l2_ctrl_unlock(master);
return ret;
@@ -770,7 +771,10 @@ int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
if (!ctrl || !ctrl->is_int)
return -EINVAL;
ret = get_ctrl(ctrl, &c);
- control->value = c.value;
+
+ if (!ret)
+ control->value = c.value;
+
return ret;
}
EXPORT_SYMBOL(v4l2_g_ctrl);
@@ -811,10 +815,11 @@ static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
int ret;
v4l2_ctrl_lock(ctrl);
- user_to_new(c, ctrl);
- ret = set_ctrl(fh, ctrl, 0);
+ ret = user_to_new(c, ctrl);
+ if (!ret)
+ ret = set_ctrl(fh, ctrl, 0);
if (!ret)
- cur_to_user(c, ctrl);
+ ret = cur_to_user(c, ctrl);
v4l2_ctrl_unlock(ctrl);
return ret;
}
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 3d7711cc42bc..5bcaeeba4d09 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -93,6 +93,8 @@ static struct attribute *video_device_attrs[] = {
};
ATTRIBUTE_GROUPS(video_device);
+static struct dentry *v4l2_debugfs_root_dir;
+
/*
* Active devices
*/
@@ -227,7 +229,7 @@ static void v4l2_device_release(struct device *cd)
v4l2_device_put(v4l2_dev);
}
-static struct class video_class = {
+static const struct class video_class = {
.name = VIDEO_NAME,
.dev_groups = video_device_groups,
};
@@ -1118,6 +1120,16 @@ void video_unregister_device(struct video_device *vdev)
}
EXPORT_SYMBOL(video_unregister_device);
+#ifdef CONFIG_DEBUG_FS
+struct dentry *v4l2_debugfs_root(void)
+{
+ if (!v4l2_debugfs_root_dir)
+ v4l2_debugfs_root_dir = debugfs_create_dir("v4l2", NULL);
+ return v4l2_debugfs_root_dir;
+}
+EXPORT_SYMBOL_GPL(v4l2_debugfs_root);
+#endif
+
#if defined(CONFIG_MEDIA_CONTROLLER)
__must_check int video_device_pipeline_start(struct video_device *vdev,
@@ -1222,6 +1234,8 @@ static void __exit videodev_exit(void)
class_unregister(&video_class);
unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
+ debugfs_remove_recursive(v4l2_debugfs_root_dir);
+ v4l2_debugfs_root_dir = NULL;
}
subsys_initcall(videodev_init);
diff --git a/drivers/media/v4l2-core/v4l2-dv-timings.c b/drivers/media/v4l2-core/v4l2-dv-timings.c
index 942d0005c55e..d26edf157e64 100644
--- a/drivers/media/v4l2-core/v4l2-dv-timings.c
+++ b/drivers/media/v4l2-core/v4l2-dv-timings.c
@@ -481,25 +481,28 @@ EXPORT_SYMBOL_GPL(v4l2_calc_timeperframe);
* @polarities - the horizontal and vertical polarities (same as struct
* v4l2_bt_timings polarities).
* @interlaced - if this flag is true, it indicates interlaced format
- * @fmt - the resulting timings.
+ * @cap - the v4l2_dv_timings_cap capabilities.
+ * @timings - the resulting timings.
*
* This function will attempt to detect if the given values correspond to a
* valid CVT format. If so, then it will return true, and fmt will be filled
* in with the found CVT timings.
*/
-bool v4l2_detect_cvt(unsigned frame_height,
- unsigned hfreq,
- unsigned vsync,
- unsigned active_width,
+bool v4l2_detect_cvt(unsigned int frame_height,
+ unsigned int hfreq,
+ unsigned int vsync,
+ unsigned int active_width,
u32 polarities,
bool interlaced,
- struct v4l2_dv_timings *fmt)
+ const struct v4l2_dv_timings_cap *cap,
+ struct v4l2_dv_timings *timings)
{
- int v_fp, v_bp, h_fp, h_bp, hsync;
- int frame_width, image_height, image_width;
+ struct v4l2_dv_timings t = {};
+ int v_fp, v_bp, h_fp, h_bp, hsync;
+ int frame_width, image_height, image_width;
bool reduced_blanking;
bool rb_v2 = false;
- unsigned pix_clk;
+ unsigned int pix_clk;
if (vsync < 4 || vsync > 8)
return false;
@@ -625,36 +628,39 @@ bool v4l2_detect_cvt(unsigned frame_height,
h_fp = h_blank - hsync - h_bp;
}
- fmt->type = V4L2_DV_BT_656_1120;
- fmt->bt.polarities = polarities;
- fmt->bt.width = image_width;
- fmt->bt.height = image_height;
- fmt->bt.hfrontporch = h_fp;
- fmt->bt.vfrontporch = v_fp;
- fmt->bt.hsync = hsync;
- fmt->bt.vsync = vsync;
- fmt->bt.hbackporch = frame_width - image_width - h_fp - hsync;
+ t.type = V4L2_DV_BT_656_1120;
+ t.bt.polarities = polarities;
+ t.bt.width = image_width;
+ t.bt.height = image_height;
+ t.bt.hfrontporch = h_fp;
+ t.bt.vfrontporch = v_fp;
+ t.bt.hsync = hsync;
+ t.bt.vsync = vsync;
+ t.bt.hbackporch = frame_width - image_width - h_fp - hsync;
if (!interlaced) {
- fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync;
- fmt->bt.interlaced = V4L2_DV_PROGRESSIVE;
+ t.bt.vbackporch = frame_height - image_height - v_fp - vsync;
+ t.bt.interlaced = V4L2_DV_PROGRESSIVE;
} else {
- fmt->bt.vbackporch = (frame_height - image_height - 2 * v_fp -
+ t.bt.vbackporch = (frame_height - image_height - 2 * v_fp -
2 * vsync) / 2;
- fmt->bt.il_vbackporch = frame_height - image_height - 2 * v_fp -
- 2 * vsync - fmt->bt.vbackporch;
- fmt->bt.il_vfrontporch = v_fp;
- fmt->bt.il_vsync = vsync;
- fmt->bt.flags |= V4L2_DV_FL_HALF_LINE;
- fmt->bt.interlaced = V4L2_DV_INTERLACED;
+ t.bt.il_vbackporch = frame_height - image_height - 2 * v_fp -
+ 2 * vsync - t.bt.vbackporch;
+ t.bt.il_vfrontporch = v_fp;
+ t.bt.il_vsync = vsync;
+ t.bt.flags |= V4L2_DV_FL_HALF_LINE;
+ t.bt.interlaced = V4L2_DV_INTERLACED;
}
- fmt->bt.pixelclock = pix_clk;
- fmt->bt.standards = V4L2_DV_BT_STD_CVT;
+ t.bt.pixelclock = pix_clk;
+ t.bt.standards = V4L2_DV_BT_STD_CVT;
if (reduced_blanking)
- fmt->bt.flags |= V4L2_DV_FL_REDUCED_BLANKING;
+ t.bt.flags |= V4L2_DV_FL_REDUCED_BLANKING;
+ if (!v4l2_valid_dv_timings(&t, cap, NULL, NULL))
+ return false;
+ *timings = t;
return true;
}
EXPORT_SYMBOL_GPL(v4l2_detect_cvt);
@@ -699,22 +705,25 @@ EXPORT_SYMBOL_GPL(v4l2_detect_cvt);
* image height, so it has to be passed explicitly. Usually
* the native screen aspect ratio is used for this. If it
* is not filled in correctly, then 16:9 will be assumed.
- * @fmt - the resulting timings.
+ * @cap - the v4l2_dv_timings_cap capabilities.
+ * @timings - the resulting timings.
*
* This function will attempt to detect if the given values correspond to a
* valid GTF format. If so, then it will return true, and fmt will be filled
* in with the found GTF timings.
*/
-bool v4l2_detect_gtf(unsigned frame_height,
- unsigned hfreq,
- unsigned vsync,
- u32 polarities,
- bool interlaced,
- struct v4l2_fract aspect,
- struct v4l2_dv_timings *fmt)
+bool v4l2_detect_gtf(unsigned int frame_height,
+ unsigned int hfreq,
+ unsigned int vsync,
+ u32 polarities,
+ bool interlaced,
+ struct v4l2_fract aspect,
+ const struct v4l2_dv_timings_cap *cap,
+ struct v4l2_dv_timings *timings)
{
+ struct v4l2_dv_timings t = {};
int pix_clk;
- int v_fp, v_bp, h_fp, hsync;
+ int v_fp, v_bp, h_fp, hsync;
int frame_width, image_height, image_width;
bool default_gtf;
int h_blank;
@@ -783,36 +792,39 @@ bool v4l2_detect_gtf(unsigned frame_height,
h_fp = h_blank / 2 - hsync;
- fmt->type = V4L2_DV_BT_656_1120;
- fmt->bt.polarities = polarities;
- fmt->bt.width = image_width;
- fmt->bt.height = image_height;
- fmt->bt.hfrontporch = h_fp;
- fmt->bt.vfrontporch = v_fp;
- fmt->bt.hsync = hsync;
- fmt->bt.vsync = vsync;
- fmt->bt.hbackporch = frame_width - image_width - h_fp - hsync;
+ t.type = V4L2_DV_BT_656_1120;
+ t.bt.polarities = polarities;
+ t.bt.width = image_width;
+ t.bt.height = image_height;
+ t.bt.hfrontporch = h_fp;
+ t.bt.vfrontporch = v_fp;
+ t.bt.hsync = hsync;
+ t.bt.vsync = vsync;
+ t.bt.hbackporch = frame_width - image_width - h_fp - hsync;
if (!interlaced) {
- fmt->bt.vbackporch = frame_height - image_height - v_fp - vsync;
- fmt->bt.interlaced = V4L2_DV_PROGRESSIVE;
+ t.bt.vbackporch = frame_height - image_height - v_fp - vsync;
+ t.bt.interlaced = V4L2_DV_PROGRESSIVE;
} else {
- fmt->bt.vbackporch = (frame_height - image_height - 2 * v_fp -
+ t.bt.vbackporch = (frame_height - image_height - 2 * v_fp -
2 * vsync) / 2;
- fmt->bt.il_vbackporch = frame_height - image_height - 2 * v_fp -
- 2 * vsync - fmt->bt.vbackporch;
- fmt->bt.il_vfrontporch = v_fp;
- fmt->bt.il_vsync = vsync;
- fmt->bt.flags |= V4L2_DV_FL_HALF_LINE;
- fmt->bt.interlaced = V4L2_DV_INTERLACED;
+ t.bt.il_vbackporch = frame_height - image_height - 2 * v_fp -
+ 2 * vsync - t.bt.vbackporch;
+ t.bt.il_vfrontporch = v_fp;
+ t.bt.il_vsync = vsync;
+ t.bt.flags |= V4L2_DV_FL_HALF_LINE;
+ t.bt.interlaced = V4L2_DV_INTERLACED;
}
- fmt->bt.pixelclock = pix_clk;
- fmt->bt.standards = V4L2_DV_BT_STD_GTF;
+ t.bt.pixelclock = pix_clk;
+ t.bt.standards = V4L2_DV_BT_STD_GTF;
if (!default_gtf)
- fmt->bt.flags |= V4L2_DV_FL_REDUCED_BLANKING;
+ t.bt.flags |= V4L2_DV_FL_REDUCED_BLANKING;
+ if (!v4l2_valid_dv_timings(&t, cap, NULL, NULL))
+ return false;
+ *timings = t;
return true;
}
EXPORT_SYMBOL_GPL(v4l2_detect_gtf);
@@ -1154,3 +1166,70 @@ int v4l2_phys_addr_validate(u16 phys_addr, u16 *parent, u16 *port)
return 0;
}
EXPORT_SYMBOL_GPL(v4l2_phys_addr_validate);
+
+#ifdef CONFIG_DEBUG_FS
+
+#define DEBUGFS_FOPS(type, flag) \
+static ssize_t \
+infoframe_read_##type(struct file *filp, \
+ char __user *ubuf, size_t count, loff_t *ppos) \
+{ \
+ struct v4l2_debugfs_if *infoframes = filp->private_data; \
+ \
+ return infoframes->if_read((flag), infoframes->priv, filp, \
+ ubuf, count, ppos); \
+} \
+ \
+static const struct file_operations infoframe_##type##_fops = { \
+ .owner = THIS_MODULE, \
+ .open = simple_open, \
+ .read = infoframe_read_##type, \
+}
+
+DEBUGFS_FOPS(avi, V4L2_DEBUGFS_IF_AVI);
+DEBUGFS_FOPS(audio, V4L2_DEBUGFS_IF_AUDIO);
+DEBUGFS_FOPS(spd, V4L2_DEBUGFS_IF_SPD);
+DEBUGFS_FOPS(hdmi, V4L2_DEBUGFS_IF_HDMI);
+
+struct v4l2_debugfs_if *v4l2_debugfs_if_alloc(struct dentry *root, u32 if_types,
+ void *priv,
+ v4l2_debugfs_if_read_t if_read)
+{
+ struct v4l2_debugfs_if *infoframes;
+
+ if (IS_ERR_OR_NULL(root) || !if_types || !if_read)
+ return NULL;
+
+ infoframes = kzalloc(sizeof(*infoframes), GFP_KERNEL);
+ if (!infoframes)
+ return NULL;
+
+ infoframes->if_dir = debugfs_create_dir("infoframes", root);
+ infoframes->priv = priv;
+ infoframes->if_read = if_read;
+ if (if_types & V4L2_DEBUGFS_IF_AVI)
+ debugfs_create_file("avi", 0400, infoframes->if_dir,
+ infoframes, &infoframe_avi_fops);
+ if (if_types & V4L2_DEBUGFS_IF_AUDIO)
+ debugfs_create_file("audio", 0400, infoframes->if_dir,
+ infoframes, &infoframe_audio_fops);
+ if (if_types & V4L2_DEBUGFS_IF_SPD)
+ debugfs_create_file("spd", 0400, infoframes->if_dir,
+ infoframes, &infoframe_spd_fops);
+ if (if_types & V4L2_DEBUGFS_IF_HDMI)
+ debugfs_create_file("hdmi", 0400, infoframes->if_dir,
+ infoframes, &infoframe_hdmi_fops);
+ return infoframes;
+}
+EXPORT_SYMBOL_GPL(v4l2_debugfs_if_alloc);
+
+void v4l2_debugfs_if_free(struct v4l2_debugfs_if *infoframes)
+{
+ if (infoframes) {
+ debugfs_remove_recursive(infoframes->if_dir);
+ kfree(infoframes);
+ }
+}
+EXPORT_SYMBOL_GPL(v4l2_debugfs_if_free);
+
+#endif
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index e14db67be97c..0304daa8471d 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -1327,6 +1327,7 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
case V4L2_PIX_FMT_Y14P: descr = "14-bit Greyscale (MIPI Packed)"; break;
case V4L2_PIX_FMT_Y8I: descr = "Interleaved 8-bit Greyscale"; break;
case V4L2_PIX_FMT_Y12I: descr = "Interleaved 12-bit Greyscale"; break;
+ case V4L2_PIX_FMT_Y16I: descr = "Interleaved 16-bit Greyscale"; break;
case V4L2_PIX_FMT_Z16: descr = "16-bit Depth"; break;
case V4L2_PIX_FMT_INZI: descr = "Planar 10:16 Greyscale Depth"; break;
case V4L2_PIX_FMT_CNF4: descr = "4-bit Depth Confidence (Packed)"; break;
@@ -1467,6 +1468,8 @@ static void v4l_fill_fmtdesc(struct v4l2_fmtdesc *fmt)
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_RPI_FE_CFG: descr = "RPi PiSP FE Config format"; break;
+ case V4L2_META_FMT_RPI_FE_STATS: descr = "RPi PiSP FE Statistics 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;
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 3a4ba08810d2..cde1774c9098 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -334,6 +334,11 @@ static int call_get_frame_desc(struct v4l2_subdev *sd, unsigned int pad,
unsigned int i;
int ret;
+#if defined(CONFIG_MEDIA_CONTROLLER)
+ if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
+ return -EOPNOTSUPP;
+#endif
+
memset(fd, 0, sizeof(*fd));
ret = sd->ops->pad->get_frame_desc(sd, pad, fd);
@@ -691,10 +696,25 @@ static long subdev_do_ioctl(struct file *file, unsigned int cmd, void *arg,
return v4l2_event_dequeue(vfh, arg, file->f_flags & O_NONBLOCK);
case VIDIOC_SUBSCRIBE_EVENT:
- return v4l2_subdev_call(sd, core, subscribe_event, vfh, arg);
+ if (v4l2_subdev_has_op(sd, core, subscribe_event))
+ return v4l2_subdev_call(sd, core, subscribe_event,
+ vfh, arg);
+
+ if ((sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS) &&
+ vfh->ctrl_handler)
+ return v4l2_ctrl_subdev_subscribe_event(sd, vfh, arg);
+
+ return -ENOIOCTLCMD;
case VIDIOC_UNSUBSCRIBE_EVENT:
- return v4l2_subdev_call(sd, core, unsubscribe_event, vfh, arg);
+ if (v4l2_subdev_has_op(sd, core, unsubscribe_event))
+ return v4l2_subdev_call(sd, core, unsubscribe_event,
+ vfh, arg);
+
+ if (sd->flags & V4L2_SUBDEV_FL_HAS_EVENTS)
+ return v4l2_event_subdev_unsubscribe(sd, vfh, arg);
+
+ return -ENOIOCTLCMD;
#ifdef CONFIG_VIDEO_ADV_DEBUG
case VIDIOC_DBG_G_REGISTER:
@@ -1641,6 +1661,9 @@ int __v4l2_subdev_init_finalize(struct v4l2_subdev *sd, const char *name,
}
}
+ if (sd->ctrl_handler)
+ sd->flags |= V4L2_SUBDEV_FL_HAS_EVENTS;
+
state = __v4l2_subdev_state_alloc(sd, name, key);
if (IS_ERR(state))
return PTR_ERR(state);