summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/cec/core/cec-adap.c10
-rw-r--r--drivers/media/cec/core/cec-core.c31
-rw-r--r--drivers/media/cec/core/cec-pin.c6
-rw-r--r--drivers/media/cec/platform/seco/seco-cec.c2
-rw-r--r--drivers/media/cec/usb/pulse8/pulse8-cec.c2
-rw-r--r--drivers/media/common/saa7146/saa7146_core.c2
-rw-r--r--drivers/media/common/siano/sms-cards.c2
-rw-r--r--drivers/media/common/siano/smsir.c4
-rw-r--r--drivers/media/common/videobuf2/videobuf2-core.c46
-rw-r--r--drivers/media/common/videobuf2/videobuf2-dma-contig.c53
-rw-r--r--drivers/media/common/videobuf2/videobuf2-dma-sg.c35
-rw-r--r--drivers/media/common/videobuf2/videobuf2-v4l2.c71
-rw-r--r--drivers/media/common/videobuf2/videobuf2-vmalloc.c12
-rw-r--r--drivers/media/dvb-core/dvb_vb2.c2
-rw-r--r--drivers/media/dvb-frontends/af9013.c2
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c3
-rw-r--r--drivers/media/dvb-frontends/lg2160.c2
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.c2
-rw-r--r--drivers/media/dvb-frontends/mb86a16.c7
-rw-r--r--drivers/media/dvb-frontends/mxl5xx.c1
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c1
-rw-r--r--drivers/media/dvb-frontends/tda10021.c40
-rw-r--r--drivers/media/dvb-frontends/tda10086.c22
-rw-r--r--drivers/media/dvb-frontends/tda18271c2dd.c41
-rw-r--r--drivers/media/dvb-frontends/tda18271c2dd_maps.h22
-rw-r--r--drivers/media/dvb-frontends/zd1301_demod.h6
-rw-r--r--drivers/media/firewire/firedtv-fw.c6
-rw-r--r--drivers/media/i2c/Kconfig2
-rw-r--r--drivers/media/i2c/adv7180.c9
-rw-r--r--drivers/media/i2c/adv748x/adv748x-core.c31
-rw-r--r--drivers/media/i2c/adv748x/adv748x-csi2.c31
-rw-r--r--drivers/media/i2c/adv748x/adv748x.h1
-rw-r--r--drivers/media/i2c/adv7511-v4l2.c4
-rw-r--r--drivers/media/i2c/cx25840/cx25840-ir.c2
-rw-r--r--drivers/media/i2c/dw9807-vcm.c2
-rw-r--r--drivers/media/i2c/imx219.c2
-rw-r--r--drivers/media/i2c/imx258.c2
-rw-r--r--drivers/media/i2c/imx274.c8
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c3
-rw-r--r--drivers/media/i2c/max9286.c43
-rw-r--r--drivers/media/i2c/ml86v7667.c7
-rw-r--r--drivers/media/i2c/msp3400-kthreads.c2
-rw-r--r--drivers/media/i2c/mt9m001.c7
-rw-r--r--drivers/media/i2c/mt9m111.c7
-rw-r--r--drivers/media/i2c/ov2740.c24
-rw-r--r--drivers/media/i2c/ov5640.c340
-rw-r--r--drivers/media/i2c/ov5675.c15
-rw-r--r--drivers/media/i2c/ov6650.c57
-rw-r--r--drivers/media/i2c/ov7740.c10
-rw-r--r--drivers/media/i2c/ov8856.c430
-rw-r--r--drivers/media/i2c/ov9640.c9
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c2
-rw-r--r--drivers/media/i2c/s5k5baf.c5
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c6
-rw-r--r--drivers/media/i2c/tc358743.c21
-rw-r--r--drivers/media/i2c/tda1997x.c16
-rw-r--r--drivers/media/i2c/tvp5150.c9
-rw-r--r--drivers/media/i2c/tvp7002.c4
-rw-r--r--drivers/media/mc/mc-device.c7
-rw-r--r--drivers/media/pci/bt8xx/bttv-driver.c15
-rw-r--r--drivers/media/pci/bt8xx/dvb-bt8xx.c7
-rw-r--r--drivers/media/pci/cobalt/cobalt-i2c.c8
-rw-r--r--drivers/media/pci/cobalt/cobalt-omnitek.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885-alsa.c11
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c2
-rw-r--r--drivers/media/pci/cx23885/cx23885.h4
-rw-r--r--drivers/media/pci/cx23885/cx23888-ir.c2
-rw-r--r--drivers/media/pci/cx25821/cx25821-alsa.c15
-rw-r--r--drivers/media/pci/cx88/cx88-alsa.c19
-rw-r--r--drivers/media/pci/cx88/cx88-cards.c2
-rw-r--r--drivers/media/pci/cx88/cx88-input.c4
-rw-r--r--drivers/media/pci/cx88/cx88-video.c2
-rw-r--r--drivers/media/pci/dt3155/dt3155.c3
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2.c159
-rw-r--r--drivers/media/pci/intel/ipu3/ipu3-cio2.h4
-rw-r--r--drivers/media/pci/mantis/mantis_dma.c4
-rw-r--r--drivers/media/pci/mantis/mantis_dma.h2
-rw-r--r--drivers/media/pci/mantis/mantis_dvb.c2
-rw-r--r--drivers/media/pci/netup_unidvb/netup_unidvb_core.c2
-rw-r--r--drivers/media/pci/ngene/ngene-core.c12
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c11
-rw-r--r--drivers/media/pci/saa7134/saa7134-cards.c4
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c47
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c3
-rw-r--r--drivers/media/pci/saa7134/saa7134-go7007.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134-tvaudio.c3
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c2
-rw-r--r--drivers/media/pci/saa7134/saa7134.h2
-rw-r--r--drivers/media/pci/saa7164/saa7164-buffer.c8
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c12
-rw-r--r--drivers/media/pci/saa7164/saa7164-dvb.c7
-rw-r--r--drivers/media/pci/saa7164/saa7164-vbi.c6
-rw-r--r--drivers/media/pci/smipcie/smipcie-ir.c7
-rw-r--r--drivers/media/pci/smipcie/smipcie-main.c6
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-core.c2
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-i2c.c2
-rw-r--r--drivers/media/pci/sta2x11/sta2x11_vip.c6
-rw-r--r--drivers/media/pci/ttpci/av7110.c20
-rw-r--r--drivers/media/pci/ttpci/av7110_v4l.c4
-rw-r--r--drivers/media/pci/ttpci/budget-ci.c15
-rw-r--r--drivers/media/pci/ttpci/budget-core.c6
-rw-r--r--drivers/media/pci/tw5864/tw5864-video.c19
-rw-r--r--drivers/media/platform/Kconfig9
-rw-r--r--drivers/media/platform/aspeed-video.c5
-rw-r--r--drivers/media/platform/coda/coda-bit.c4
-rw-r--r--drivers/media/platform/coda/coda-common.c17
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c27
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.c67
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.h5
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c17
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.c4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.c9
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.c89
-rw-r--r--drivers/media/platform/exynos4-is/media-dev.h11
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c4
-rw-r--r--drivers/media/platform/fsl-viu.c2
-rw-r--r--drivers/media/platform/marvell-ccic/cafe-driver.c10
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c40
-rw-r--r--drivers/media/platform/marvell-ccic/mmp-driver.c133
-rw-r--r--drivers/media/platform/mtk-jpeg/Makefile5
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c930
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h106
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_hw.c (renamed from drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c)10
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_hw.h (renamed from drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h)12
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_parse.c (renamed from drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c)2
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_parse.h (renamed from drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h)2
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_reg.h (renamed from drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h)19
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.c154
-rw-r--r--drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.h91
-rw-r--r--drivers/media/platform/mtk-mdp/mtk_mdp_core.c2
-rw-r--r--drivers/media/platform/mtk-vcodec/Makefile6
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c11
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c62
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c1
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h40
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c211
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c180
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c2
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c231
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h38
-rw-r--r--drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c1
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c1
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c1
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c3
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_drv_base.h2
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_drv_if.c1
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_vpu_if.c12
-rw-r--r--drivers/media/platform/mtk-vcodec/vdec_vpu_if.h11
-rw-r--r--drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c68
-rw-r--r--drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c11
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_drv_if.c1
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_drv_if.h13
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_ipi_msg.h27
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_vpu_if.c141
-rw-r--r--drivers/media/platform/mtk-vcodec/venc_vpu_if.h8
-rw-r--r--drivers/media/platform/mtk-vpu/mtk_vpu.c5
-rw-r--r--drivers/media/platform/mx2_emmaprp.c7
-rw-r--r--drivers/media/platform/omap3isp/isp.c8
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c2
-rw-r--r--drivers/media/platform/pxa_camera.c195
-rw-r--r--drivers/media/platform/qcom/camss/camss-csiphy.c4
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.c8
-rw-r--r--drivers/media/platform/qcom/camss/camss-vfe.h2
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.c124
-rw-r--r--drivers/media/platform/qcom/camss/camss-video.h2
-rw-r--r--drivers/media/platform/qcom/camss/camss.c5
-rw-r--r--drivers/media/platform/qcom/venus/Makefile2
-rw-r--r--drivers/media/platform/qcom/venus/core.c56
-rw-r--r--drivers/media/platform/qcom/venus/core.h34
-rw-r--r--drivers/media/platform/qcom/venus/dbgfs.c19
-rw-r--r--drivers/media/platform/qcom/venus/dbgfs.h12
-rw-r--r--drivers/media/platform/qcom/venus/firmware.c19
-rw-r--r--drivers/media/platform/qcom/venus/helpers.c241
-rw-r--r--drivers/media/platform/qcom/venus/helpers.h2
-rw-r--r--drivers/media/platform/qcom/venus/hfi.c5
-rw-r--r--drivers/media/platform/qcom/venus/hfi.h1
-rw-r--r--drivers/media/platform/qcom/venus/hfi_cmds.c37
-rw-r--r--drivers/media/platform/qcom/venus/hfi_helper.h28
-rw-r--r--drivers/media/platform/qcom/venus/hfi_msgs.c18
-rw-r--r--drivers/media/platform/qcom/venus/hfi_parser.c3
-rw-r--r--drivers/media/platform/qcom/venus/hfi_venus.c72
-rw-r--r--drivers/media/platform/qcom/venus/hfi_venus.h1
-rw-r--r--drivers/media/platform/qcom/venus/pm_helpers.c94
-rw-r--r--drivers/media/platform/qcom/venus/vdec.c26
-rw-r--r--drivers/media/platform/qcom/venus/vdec_ctrls.c31
-rw-r--r--drivers/media/platform/qcom/venus/venc.c199
-rw-r--r--drivers/media/platform/qcom/venus/venc_ctrls.c35
-rw-r--r--drivers/media/platform/rcar-fcp.c8
-rw-r--r--drivers/media/platform/rcar-vin/Kconfig4
-rw-r--r--drivers/media/platform/rcar-vin/rcar-core.c71
-rw-r--r--drivers/media/platform/rcar-vin/rcar-csi2.c106
-rw-r--r--drivers/media/platform/rcar-vin/rcar-dma.c49
-rw-r--r--drivers/media/platform/rcar-vin/rcar-v4l2.c31
-rw-r--r--drivers/media/platform/rcar-vin/rcar-vin.h5
-rw-r--r--drivers/media/platform/rcar_drif.c30
-rw-r--r--drivers/media/platform/renesas-ceu.c4
-rw-r--r--drivers/media/platform/rockchip/rga/rga-buf.c1
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.c5
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c7
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_pm.c4
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-debug.c29
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp-v4l2.c10
-rw-r--r--drivers/media/platform/sti/bdisp/bdisp.h2
-rw-r--r--drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c10
-rw-r--r--drivers/media/platform/sti/delta/delta-v4l2.c4
-rw-r--r--drivers/media/platform/sti/hva/hva-debugfs.c22
-rw-r--r--drivers/media/platform/sti/hva/hva-hw.c4
-rw-r--r--drivers/media/platform/stm32/stm32-dcmi.c4
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c1
-rw-r--r--drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c6
-rw-r--r--drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c7
-rw-r--r--drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c5
-rw-r--r--drivers/media/platform/ti-vpe/vpe.c2
-rw-r--r--drivers/media/platform/vsp1/vsp1_drm.c8
-rw-r--r--drivers/media/platform/vsp1/vsp1_drv.c11
-rw-r--r--drivers/media/radio/radio-si476x.c66
-rw-r--r--drivers/media/radio/si4713/si4713.c2
-rw-r--r--drivers/media/radio/wl128x/fmdrv_common.c28
-rw-r--r--drivers/media/rc/ati_remote.c4
-rw-r--r--drivers/media/rc/ene_ir.c18
-rw-r--r--drivers/media/rc/fintek-cir.c8
-rw-r--r--drivers/media/rc/gpio-ir-recv.c53
-rw-r--r--drivers/media/rc/igorplugusb.c6
-rw-r--r--drivers/media/rc/iguanair.c6
-rw-r--r--drivers/media/rc/imon_raw.c2
-rw-r--r--drivers/media/rc/ir-hix5hd2.c8
-rw-r--r--drivers/media/rc/ir-imon-decoder.c10
-rw-r--r--drivers/media/rc/ir-jvc-decoder.c6
-rw-r--r--drivers/media/rc/ir-mce_kbd-decoder.c8
-rw-r--r--drivers/media/rc/ir-nec-decoder.c6
-rw-r--r--drivers/media/rc/ir-rc5-decoder.c6
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c6
-rw-r--r--drivers/media/rc/ir-rcmm-decoder.c18
-rw-r--r--drivers/media/rc/ir-sanyo-decoder.c6
-rw-r--r--drivers/media/rc/ir-sharp-decoder.c6
-rw-r--r--drivers/media/rc/ir-sony-decoder.c6
-rw-r--r--drivers/media/rc/ir-xmp-decoder.c15
-rw-r--r--drivers/media/rc/ir_toy.c14
-rw-r--r--drivers/media/rc/ite-cir.c10
-rw-r--r--drivers/media/rc/ite-cir.h4
-rw-r--r--drivers/media/rc/lirc_dev.c95
-rw-r--r--drivers/media/rc/mceusb.c12
-rw-r--r--drivers/media/rc/meson-ir.c4
-rw-r--r--drivers/media/rc/mtk-cir.c4
-rw-r--r--drivers/media/rc/nuvoton-cir.c10
-rw-r--r--drivers/media/rc/nuvoton-cir.h2
-rw-r--r--drivers/media/rc/rc-core-priv.h21
-rw-r--r--drivers/media/rc/rc-ir-raw.c16
-rw-r--r--drivers/media/rc/rc-loopback.c8
-rw-r--r--drivers/media/rc/rc-main.c10
-rw-r--r--drivers/media/rc/redrat3.c17
-rw-r--r--drivers/media/rc/serial_ir.c12
-rw-r--r--drivers/media/rc/sir_ir.c2
-rw-r--r--drivers/media/rc/st_rc.c6
-rw-r--r--drivers/media/rc/streamzap.c10
-rw-r--r--drivers/media/rc/sunxi-cir.c4
-rw-r--r--drivers/media/rc/ttusbir.c18
-rw-r--r--drivers/media/rc/winbond-cir.c10
-rw-r--r--drivers/media/rc/xbox_remote.c2
-rw-r--r--drivers/media/test-drivers/Kconfig16
-rw-r--r--drivers/media/test-drivers/Makefile1
-rw-r--r--drivers/media/test-drivers/vicodec/vicodec-core.c6
-rw-r--r--drivers/media/test-drivers/vidtv/Kconfig11
-rw-r--r--drivers/media/test-drivers/vidtv/Makefile9
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_bridge.c566
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_bridge.h63
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_channel.c310
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_channel.h76
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_common.c89
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_common.h33
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_demod.c464
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_demod.h69
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_encoder.h166
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_mux.c474
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_mux.h167
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_pes.c438
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_pes.h191
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_psi.c1322
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_psi.h577
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_s302m.c502
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_s302m.h92
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_ts.c137
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_ts.h108
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_tuner.c438
-rw-r--r--drivers/media/test-drivers/vidtv/vidtv_tuner.h43
-rw-r--r--drivers/media/test-drivers/vimc/vimc-capture.c7
-rw-r--r--drivers/media/test-drivers/vivid/vivid-core.c674
-rw-r--r--drivers/media/test-drivers/vivid/vivid-meta-out.c9
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vbi-gen.c2
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-cap.c38
-rw-r--r--drivers/media/test-drivers/vivid/vivid-vid-common.c25
-rw-r--r--drivers/media/tuners/fc0011.c2
-rw-r--r--drivers/media/tuners/qt1010.c25
-rw-r--r--drivers/media/tuners/tda18271-fe.c2
-rw-r--r--drivers/media/tuners/tuner-simple.c5
-rw-r--r--drivers/media/usb/au0828/au0828-input.c8
-rw-r--r--drivers/media/usb/au0828/au0828-video.c12
-rw-r--r--drivers/media/usb/b2c2/flexcop-usb.c9
-rw-r--r--drivers/media/usb/b2c2/flexcop-usb.h2
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-core.c16
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9015.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/gl861.c2
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c8
-rw-r--r--drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c4
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c4
-rw-r--r--drivers/media/usb/dvb-usb/Kconfig1
-rw-r--r--drivers/media/usb/dvb-usb/cxusb-analog.c13
-rw-r--r--drivers/media/usb/dvb-usb/dib0700_devices.c11
-rw-r--r--drivers/media/usb/dvb-usb/pctv452e.c26
-rw-r--r--drivers/media/usb/dvb-usb/technisat-usb2.c4
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c8
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c22
-rw-r--r--drivers/media/usb/em28xx/em28xx.h1
-rw-r--r--drivers/media/usb/go7007/go7007-driver.c2
-rw-r--r--drivers/media/usb/gspca/mr97310a.c10
-rw-r--r--drivers/media/usb/gspca/nw80x.c2
-rw-r--r--drivers/media/usb/gspca/ov519.c6
-rw-r--r--drivers/media/usb/gspca/sn9c20x.c2
-rw-r--r--drivers/media/usb/gspca/sunplus.c4
-rw-r--r--drivers/media/usb/gspca/xirlink_cit.c4
-rw-r--r--drivers/media/usb/gspca/zc3xx.c4
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c5
-rw-r--r--drivers/media/usb/pwc/pwc-v4l.c2
-rw-r--r--drivers/media/usb/siano/smsusb.c2
-rw-r--r--drivers/media/usb/tm6000/tm6000-alsa.c8
-rw-r--r--drivers/media/usb/tm6000/tm6000-core.c24
-rw-r--r--drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c197
-rw-r--r--drivers/media/usb/ttusb-dec/ttusb_dec.c7
-rw-r--r--drivers/media/usb/usbtv/usbtv-core.c3
-rw-r--r--drivers/media/usb/usbtv/usbtv-video.c4
-rw-r--r--drivers/media/usb/uvc/uvc_ctrl.c46
-rw-r--r--drivers/media/usb/uvc/uvc_debugfs.c20
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c71
-rw-r--r--drivers/media/usb/uvc/uvc_entity.c35
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c34
-rw-r--r--drivers/media/usb/uvc/uvc_video.c6
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h8
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c10
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c61
-rw-r--r--drivers/media/v4l2-core/v4l2-fwnode.c4
-rw-r--r--drivers/media/v4l2-core/v4l2-h264.c12
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c5
-rw-r--r--drivers/media/v4l2-core/v4l2-mem2mem.c68
-rw-r--r--drivers/media/v4l2-core/v4l2-subdev.c16
-rw-r--r--drivers/media/v4l2-core/videobuf-dma-sg.c22
346 files changed, 11902 insertions, 3341 deletions
diff --git a/drivers/media/cec/core/cec-adap.c b/drivers/media/cec/core/cec-adap.c
index 4efe8014445e..d5d5d28d0b36 100644
--- a/drivers/media/cec/core/cec-adap.c
+++ b/drivers/media/cec/core/cec-adap.c
@@ -751,6 +751,9 @@ int cec_transmit_msg_fh(struct cec_adapter *adap, struct cec_msg *msg,
struct cec_data *data;
bool is_raw = msg_is_raw(msg);
+ if (adap->devnode.unregistered)
+ return -ENODEV;
+
msg->rx_ts = 0;
msg->tx_ts = 0;
msg->rx_status = 0;
@@ -1049,6 +1052,9 @@ void cec_received_msg_ts(struct cec_adapter *adap,
if (WARN_ON(!msg->len || msg->len > CEC_MAX_MSG_SIZE))
return;
+ if (adap->devnode.unregistered)
+ return;
+
/*
* Some CEC adapters will receive the messages that they transmitted.
* This test filters out those messages by checking if we are the
@@ -1199,7 +1205,7 @@ void cec_received_msg_ts(struct cec_adapter *adap,
/* Cancel the pending timeout work */
if (!cancel_delayed_work(&data->work)) {
mutex_unlock(&adap->lock);
- flush_scheduled_work();
+ cancel_delayed_work_sync(&data->work);
mutex_lock(&adap->lock);
}
/*
@@ -1928,7 +1934,7 @@ static int cec_receive_notify(struct cec_adapter *adap, struct cec_msg *msg,
*/
if (!adap->passthrough && from_unregistered)
return 0;
- /* Fall through */
+ fallthrough;
case CEC_MSG_GIVE_DEVICE_VENDOR_ID:
case CEC_MSG_GIVE_FEATURES:
case CEC_MSG_GIVE_PHYSICAL_ADDR:
diff --git a/drivers/media/cec/core/cec-core.c b/drivers/media/cec/core/cec-core.c
index c599cd94dd62..ece236291f35 100644
--- a/drivers/media/cec/core/cec-core.c
+++ b/drivers/media/cec/core/cec-core.c
@@ -309,7 +309,7 @@ struct cec_adapter *cec_allocate_adapter(const struct cec_adap_ops *ops,
adap->rc->allowed_protocols = RC_PROTO_BIT_CEC;
adap->rc->priv = adap;
adap->rc->map_name = RC_MAP_CEC;
- adap->rc->timeout = MS_TO_NS(550);
+ adap->rc->timeout = MS_TO_US(550);
#endif
return adap;
}
@@ -359,27 +359,16 @@ int cec_register_adapter(struct cec_adapter *adap,
if (!top_cec_dir)
return 0;
- adap->cec_dir = debugfs_create_dir(dev_name(&adap->devnode.dev), top_cec_dir);
- if (IS_ERR_OR_NULL(adap->cec_dir)) {
- pr_warn("cec-%s: Failed to create debugfs dir\n", adap->name);
- return 0;
- }
- adap->status_file = debugfs_create_devm_seqfile(&adap->devnode.dev,
- "status", adap->cec_dir, cec_adap_status);
- if (IS_ERR_OR_NULL(adap->status_file)) {
- pr_warn("cec-%s: Failed to create status file\n", adap->name);
- debugfs_remove_recursive(adap->cec_dir);
- adap->cec_dir = NULL;
- return 0;
- }
+ adap->cec_dir = debugfs_create_dir(dev_name(&adap->devnode.dev),
+ top_cec_dir);
+
+ debugfs_create_devm_seqfile(&adap->devnode.dev, "status", adap->cec_dir,
+ cec_adap_status);
+
if (!adap->ops->error_inj_show || !adap->ops->error_inj_parse_line)
return 0;
- adap->error_inj_file = debugfs_create_file("error-inj", 0644,
- adap->cec_dir, adap,
- &cec_error_inj_fops);
- if (IS_ERR_OR_NULL(adap->error_inj_file))
- pr_warn("cec-%s: Failed to create error-inj file\n",
- adap->name);
+ debugfs_create_file("error-inj", 0644, adap->cec_dir, adap,
+ &cec_error_inj_fops);
#endif
return 0;
}
@@ -407,9 +396,9 @@ void cec_delete_adapter(struct cec_adapter *adap)
{
if (IS_ERR_OR_NULL(adap))
return;
- kthread_stop(adap->kthread);
if (adap->kthread_config)
kthread_stop(adap->kthread_config);
+ kthread_stop(adap->kthread);
if (adap->ops->adap_free)
adap->ops->adap_free(adap);
#ifdef CONFIG_MEDIA_CEC_RC
diff --git a/drivers/media/cec/core/cec-pin.c b/drivers/media/cec/core/cec-pin.c
index 660fe111f540..f006bd8eec63 100644
--- a/drivers/media/cec/core/cec-pin.c
+++ b/drivers/media/cec/core/cec-pin.c
@@ -417,7 +417,7 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts)
wake_up_interruptible(&pin->kthread_waitq);
break;
}
- /* fall through */
+ fallthrough;
case CEC_ST_TX_DATA_BIT_0_HIGH:
case CEC_ST_TX_DATA_BIT_0_HIGH_SHORT:
case CEC_ST_TX_DATA_BIT_0_HIGH_LONG:
@@ -445,7 +445,7 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts)
wake_up_interruptible(&pin->kthread_waitq);
break;
}
- /* fall through */
+ fallthrough;
case CEC_ST_TX_DATA_BIT_HIGH_CUSTOM:
if (tx_last_bit(pin)) {
/* Error Injection: just stop sending after this bit */
@@ -459,7 +459,7 @@ static void cec_pin_tx_states(struct cec_pin *pin, ktime_t ts)
break;
}
pin->tx_bit++;
- /* fall through */
+ fallthrough;
case CEC_ST_TX_START_BIT_HIGH:
case CEC_ST_TX_START_BIT_HIGH_SHORT:
case CEC_ST_TX_START_BIT_HIGH_LONG:
diff --git a/drivers/media/cec/platform/seco/seco-cec.c b/drivers/media/cec/platform/seco/seco-cec.c
index 075dd79beb6f..ae138cc253fd 100644
--- a/drivers/media/cec/platform/seco/seco-cec.c
+++ b/drivers/media/cec/platform/seco/seco-cec.c
@@ -369,7 +369,7 @@ static int secocec_ir_probe(void *priv)
cec->ir->allowed_protocols = RC_PROTO_BIT_RC5;
cec->ir->priv = cec;
cec->ir->map_name = RC_MAP_HAUPPAUGE;
- cec->ir->timeout = MS_TO_NS(100);
+ cec->ir->timeout = MS_TO_US(100);
/* Clear the status register */
status = smb_rd16(SECOCEC_STATUS_REG_1, &val);
diff --git a/drivers/media/cec/usb/pulse8/pulse8-cec.c b/drivers/media/cec/usb/pulse8/pulse8-cec.c
index beae6aa12638..e4d8446b87da 100644
--- a/drivers/media/cec/usb/pulse8/pulse8-cec.c
+++ b/drivers/media/cec/usb/pulse8/pulse8-cec.c
@@ -389,7 +389,7 @@ static irqreturn_t pulse8_interrupt(struct serio *serio, unsigned char data,
pulse8->new_rx_msg[0] = pulse8->buf[1];
break;
}
- /* fall through */
+ fallthrough;
case MSGCODE_FRAME_DATA:
if (pulse8->new_rx_msg_len < CEC_MAX_MSG_SIZE)
pulse8->new_rx_msg[pulse8->new_rx_msg_len++] =
diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c
index 6b06ea590074..21fb16cc5ca1 100644
--- a/drivers/media/common/saa7146/saa7146_core.c
+++ b/drivers/media/common/saa7146/saa7146_core.c
@@ -140,7 +140,7 @@ static struct scatterlist* vmalloc_to_sg(unsigned char *virt, int nr_pages)
struct page *pg;
int i;
- sglist = kcalloc(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
+ sglist = kmalloc_array(nr_pages, sizeof(struct scatterlist), GFP_KERNEL);
if (NULL == sglist)
return NULL;
sg_init_table(sglist, nr_pages);
diff --git a/drivers/media/common/siano/sms-cards.c b/drivers/media/common/siano/sms-cards.c
index e67ee3d55488..d4a116ab6c88 100644
--- a/drivers/media/common/siano/sms-cards.c
+++ b/drivers/media/common/siano/sms-cards.c
@@ -79,7 +79,7 @@ static struct sms_board sms_boards[] = {
.board_cfg.rf_switch_uhf = 17,
},
[SMS1XXX_BOARD_HAUPPAUGE_TIGER_MINICARD_R2] = {
- .name = "Hauppauge WinTV MiniCard",
+ .name = "Hauppauge WinTV MiniCard Rev 2",
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_DVBT_BDA] = SMS_FW_DVBT_HCW_55XXX,
.default_mode = DEVICE_MODE_DVBT_BDA,
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index 79bd627f84b8..d85c78c104b9 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -27,7 +27,7 @@ void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
for (i = 0; i < len >> 2; i++) {
struct ir_raw_event ev = {
- .duration = abs(samples[i]) * 1000, /* Convert to ns */
+ .duration = abs(samples[i]),
.pulse = (samples[i] > 0) ? false : true
};
@@ -48,7 +48,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
return -ENOMEM;
coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
- coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
+ coredev->ir.timeout = US_TO_NS(IR_DEFAULT_TIMEOUT);
pr_debug("IR port %d, timeout %d ms\n",
coredev->ir.controller, coredev->ir.timeout);
diff --git a/drivers/media/common/videobuf2/videobuf2-core.c b/drivers/media/common/videobuf2/videobuf2-core.c
index f544d3393e9d..4eab6d81cce1 100644
--- a/drivers/media/common/videobuf2/videobuf2-core.c
+++ b/drivers/media/common/videobuf2/videobuf2-core.c
@@ -721,39 +721,14 @@ int vb2_verify_memory_type(struct vb2_queue *q,
}
EXPORT_SYMBOL(vb2_verify_memory_type);
-static void set_queue_consistency(struct vb2_queue *q, bool consistent_mem)
-{
- q->dma_attrs &= ~DMA_ATTR_NON_CONSISTENT;
-
- if (!vb2_queue_allows_cache_hints(q))
- return;
- if (!consistent_mem)
- q->dma_attrs |= DMA_ATTR_NON_CONSISTENT;
-}
-
-static bool verify_consistency_attr(struct vb2_queue *q, bool consistent_mem)
-{
- bool queue_is_consistent = !(q->dma_attrs & DMA_ATTR_NON_CONSISTENT);
-
- if (consistent_mem != queue_is_consistent) {
- dprintk(q, 1, "memory consistency model mismatch\n");
- return false;
- }
- return true;
-}
-
int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
- unsigned int flags, unsigned int *count)
+ unsigned int *count)
{
unsigned int num_buffers, allocated_buffers, num_planes = 0;
unsigned plane_sizes[VB2_MAX_PLANES] = { };
- bool consistent_mem = true;
unsigned int i;
int ret;
- if (flags & V4L2_FLAG_MEMORY_NON_CONSISTENT)
- consistent_mem = false;
-
if (q->streaming) {
dprintk(q, 1, "streaming active\n");
return -EBUSY;
@@ -765,8 +740,7 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
}
if (*count == 0 || q->num_buffers != 0 ||
- (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory) ||
- !verify_consistency_attr(q, consistent_mem)) {
+ (q->memory != VB2_MEMORY_UNKNOWN && q->memory != memory)) {
/*
* We already have buffers allocated, so first check if they
* are not in use and can be freed.
@@ -803,7 +777,6 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
num_buffers = min_t(unsigned int, num_buffers, VB2_MAX_FRAME);
memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
q->memory = memory;
- set_queue_consistency(q, consistent_mem);
/*
* Ask the driver how many buffers and planes per buffer it requires.
@@ -888,18 +861,14 @@ int vb2_core_reqbufs(struct vb2_queue *q, enum vb2_memory memory,
EXPORT_SYMBOL_GPL(vb2_core_reqbufs);
int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
- unsigned int flags, unsigned int *count,
+ unsigned int *count,
unsigned int requested_planes,
const unsigned int requested_sizes[])
{
unsigned int num_planes = 0, num_buffers, allocated_buffers;
unsigned plane_sizes[VB2_MAX_PLANES] = { };
- bool consistent_mem = true;
int ret;
- if (flags & V4L2_FLAG_MEMORY_NON_CONSISTENT)
- consistent_mem = false;
-
if (q->num_buffers == VB2_MAX_FRAME) {
dprintk(q, 1, "maximum number of buffers already allocated\n");
return -ENOBUFS;
@@ -912,15 +881,12 @@ int vb2_core_create_bufs(struct vb2_queue *q, enum vb2_memory memory,
}
memset(q->alloc_devs, 0, sizeof(q->alloc_devs));
q->memory = memory;
- set_queue_consistency(q, consistent_mem);
q->waiting_for_buffers = !q->is_output;
} else {
if (q->memory != memory) {
dprintk(q, 1, "memory model mismatch\n");
return -EINVAL;
}
- if (!verify_consistency_attr(q, consistent_mem))
- return -EINVAL;
}
num_buffers = min(*count, VB2_MAX_FRAME - q->num_buffers);
@@ -2581,7 +2547,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
fileio->memory = VB2_MEMORY_MMAP;
fileio->type = q->type;
q->fileio = fileio;
- ret = vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count);
+ ret = vb2_core_reqbufs(q, fileio->memory, &fileio->count);
if (ret)
goto err_kfree;
@@ -2638,7 +2604,7 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
err_reqbufs:
fileio->count = 0;
- vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count);
+ vb2_core_reqbufs(q, fileio->memory, &fileio->count);
err_kfree:
q->fileio = NULL;
@@ -2658,7 +2624,7 @@ static int __vb2_cleanup_fileio(struct vb2_queue *q)
vb2_core_streamoff(q, q->type);
q->fileio = NULL;
fileio->count = 0;
- vb2_core_reqbufs(q, fileio->memory, 0, &fileio->count);
+ vb2_core_reqbufs(q, fileio->memory, &fileio->count);
kfree(fileio);
dprintk(q, 3, "file io emulator closed\n");
}
diff --git a/drivers/media/common/videobuf2/videobuf2-dma-contig.c b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
index ec3446cc45b8..2f3a5996d3fc 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-contig.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-contig.c
@@ -42,11 +42,6 @@ struct vb2_dc_buf {
struct dma_buf_attachment *db_attach;
};
-static inline bool vb2_dc_buffer_consistent(unsigned long attr)
-{
- return !(attr & DMA_ATTR_NON_CONSISTENT);
-}
-
/*********************************************/
/* scatterlist table functions */
/*********************************************/
@@ -58,10 +53,10 @@ static unsigned long vb2_dc_get_contiguous_size(struct sg_table *sgt)
unsigned int i;
unsigned long size = 0;
- for_each_sg(sgt->sgl, s, sgt->nents, i) {
+ for_each_sgtable_dma_sg(sgt, s, i) {
if (sg_dma_address(s) != expected)
break;
- expected = sg_dma_address(s) + sg_dma_len(s);
+ expected += sg_dma_len(s);
size += sg_dma_len(s);
}
return size;
@@ -103,8 +98,7 @@ static void vb2_dc_prepare(void *buf_priv)
if (!sgt)
return;
- dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir);
+ dma_sync_sgtable_for_device(buf->dev, sgt, buf->dma_dir);
}
static void vb2_dc_finish(void *buf_priv)
@@ -115,7 +109,7 @@ static void vb2_dc_finish(void *buf_priv)
if (!sgt)
return;
- dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
+ dma_sync_sgtable_for_cpu(buf->dev, sgt, buf->dma_dir);
}
/*********************************************/
@@ -275,8 +269,8 @@ static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf,
* memory locations do not require any explicit cache
* maintenance prior or after being used by the device.
*/
- dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents,
- attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+ dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
sg_free_table(sgt);
kfree(attach);
db_attach->priv = NULL;
@@ -301,8 +295,8 @@ static struct sg_table *vb2_dc_dmabuf_ops_map(
/* release any previous cache */
if (attach->dma_dir != DMA_NONE) {
- dma_unmap_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents,
- attach->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+ dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
attach->dma_dir = DMA_NONE;
}
@@ -310,9 +304,8 @@ static struct sg_table *vb2_dc_dmabuf_ops_map(
* mapping to the client with new direction, no cache sync
* required see comment in vb2_dc_dmabuf_ops_detach()
*/
- sgt->nents = dma_map_sg_attrs(db_attach->dev, sgt->sgl, sgt->orig_nents,
- dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
- if (!sgt->nents) {
+ if (dma_map_sgtable(db_attach->dev, sgt, dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC)) {
pr_err("failed to map scatterlist\n");
mutex_unlock(lock);
return ERR_PTR(-EIO);
@@ -341,13 +334,6 @@ static int
vb2_dc_dmabuf_ops_begin_cpu_access(struct dma_buf *dbuf,
enum dma_data_direction direction)
{
- struct vb2_dc_buf *buf = dbuf->priv;
- struct sg_table *sgt = buf->dma_sgt;
-
- if (vb2_dc_buffer_consistent(buf->attrs))
- return 0;
-
- dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
return 0;
}
@@ -355,13 +341,6 @@ static int
vb2_dc_dmabuf_ops_end_cpu_access(struct dma_buf *dbuf,
enum dma_data_direction direction)
{
- struct vb2_dc_buf *buf = dbuf->priv;
- struct sg_table *sgt = buf->dma_sgt;
-
- if (vb2_dc_buffer_consistent(buf->attrs))
- return 0;
-
- dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
return 0;
}
@@ -455,8 +434,8 @@ static void vb2_dc_put_userptr(void *buf_priv)
* No need to sync to CPU, it's already synced to the CPU
* since the finish() memop will have been called before this.
*/
- dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+ dma_unmap_sgtable(buf->dev, sgt, buf->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
pages = frame_vector_pages(buf->vec);
/* sgt should exist only if vector contains pages... */
BUG_ON(IS_ERR(pages));
@@ -553,9 +532,8 @@ static void *vb2_dc_get_userptr(struct device *dev, unsigned long vaddr,
* No need to sync to the device, this will happen later when the
* prepare() memop is called.
*/
- sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
- if (sgt->nents <= 0) {
+ if (dma_map_sgtable(buf->dev, sgt, buf->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC)) {
pr_err("failed to map scatterlist\n");
ret = -EIO;
goto fail_sgt_init;
@@ -577,8 +555,7 @@ out:
return buf;
fail_map_sg:
- dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+ dma_unmap_sgtable(buf->dev, sgt, buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
fail_sgt_init:
sg_free_table(sgt);
diff --git a/drivers/media/common/videobuf2/videobuf2-dma-sg.c b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
index 0a40e00f0d7e..748131151c49 100644
--- a/drivers/media/common/videobuf2/videobuf2-dma-sg.c
+++ b/drivers/media/common/videobuf2/videobuf2-dma-sg.c
@@ -123,8 +123,7 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs,
/*
* NOTE: dma-sg allocates memory using the page allocator directly, so
* there is no memory consistency guarantee, hence dma-sg ignores DMA
- * attributes passed from the upper layer. That means that
- * V4L2_FLAG_MEMORY_NON_CONSISTENT has no effect on dma-sg buffers.
+ * attributes passed from the upper layer.
*/
buf->pages = kvmalloc_array(buf->num_pages, sizeof(struct page *),
GFP_KERNEL | __GFP_ZERO);
@@ -148,9 +147,8 @@ static void *vb2_dma_sg_alloc(struct device *dev, unsigned long dma_attrs,
* No need to sync to the device, this will happen later when the
* prepare() memop is called.
*/
- sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
- if (!sgt->nents)
+ if (dma_map_sgtable(buf->dev, sgt, buf->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC))
goto fail_map;
buf->handler.refcount = &buf->refcount;
@@ -186,8 +184,8 @@ static void vb2_dma_sg_put(void *buf_priv)
if (refcount_dec_and_test(&buf->refcount)) {
dprintk(1, "%s: Freeing buffer of %d pages\n", __func__,
buf->num_pages);
- dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
+ dma_unmap_sgtable(buf->dev, sgt, buf->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC);
if (buf->vaddr)
vm_unmap_ram(buf->vaddr, buf->num_pages);
sg_free_table(buf->dma_sgt);
@@ -204,8 +202,7 @@ static void vb2_dma_sg_prepare(void *buf_priv)
struct vb2_dma_sg_buf *buf = buf_priv;
struct sg_table *sgt = buf->dma_sgt;
- dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir);
+ dma_sync_sgtable_for_device(buf->dev, sgt, buf->dma_dir);
}
static void vb2_dma_sg_finish(void *buf_priv)
@@ -213,7 +210,7 @@ static void vb2_dma_sg_finish(void *buf_priv)
struct vb2_dma_sg_buf *buf = buf_priv;
struct sg_table *sgt = buf->dma_sgt;
- dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
+ dma_sync_sgtable_for_cpu(buf->dev, sgt, buf->dma_dir);
}
static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr,
@@ -256,9 +253,8 @@ static void *vb2_dma_sg_get_userptr(struct device *dev, unsigned long vaddr,
* No need to sync to the device, this will happen later when the
* prepare() memop is called.
*/
- sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
- if (!sgt->nents)
+ if (dma_map_sgtable(buf->dev, sgt, buf->dma_dir,
+ DMA_ATTR_SKIP_CPU_SYNC))
goto userptr_fail_map;
return buf;
@@ -284,8 +280,7 @@ static void vb2_dma_sg_put_userptr(void *buf_priv)
dprintk(1, "%s: Releasing userspace buffer of %d pages\n",
__func__, buf->num_pages);
- dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir,
- DMA_ATTR_SKIP_CPU_SYNC);
+ dma_unmap_sgtable(buf->dev, sgt, buf->dma_dir, DMA_ATTR_SKIP_CPU_SYNC);
if (buf->vaddr)
vm_unmap_ram(buf->vaddr, buf->num_pages);
sg_free_table(buf->dma_sgt);
@@ -408,8 +403,7 @@ static void vb2_dma_sg_dmabuf_ops_detach(struct dma_buf *dbuf,
/* release the scatterlist cache */
if (attach->dma_dir != DMA_NONE)
- dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
- attach->dma_dir);
+ dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir, 0);
sg_free_table(sgt);
kfree(attach);
db_attach->priv = NULL;
@@ -434,15 +428,12 @@ static struct sg_table *vb2_dma_sg_dmabuf_ops_map(
/* release any previous cache */
if (attach->dma_dir != DMA_NONE) {
- dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
- attach->dma_dir);
+ dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir, 0);
attach->dma_dir = DMA_NONE;
}
/* mapping to the client with new direction */
- sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
- dma_dir);
- if (!sgt->nents) {
+ if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) {
pr_err("failed to map scatterlist\n");
mutex_unlock(lock);
return ERR_PTR(-EIO);
diff --git a/drivers/media/common/videobuf2/videobuf2-v4l2.c b/drivers/media/common/videobuf2/videobuf2-v4l2.c
index 30caad27281e..96d3b2b2aa31 100644
--- a/drivers/media/common/videobuf2/videobuf2-v4l2.c
+++ b/drivers/media/common/videobuf2/videobuf2-v4l2.c
@@ -14,21 +14,22 @@
* the Free Software Foundation.
*/
+#include <linux/device.h>
#include <linux/err.h>
+#include <linux/freezer.h>
#include <linux/kernel.h>
-#include <linux/module.h>
+#include <linux/kthread.h>
#include <linux/mm.h>
+#include <linux/module.h>
#include <linux/poll.h>
-#include <linux/slab.h>
#include <linux/sched.h>
-#include <linux/freezer.h>
-#include <linux/kthread.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
-#include <media/v4l2-common.h>
+#include <media/v4l2-fh.h>
#include <media/videobuf2-v4l2.h>
@@ -600,7 +601,7 @@ static void __fill_v4l2_buffer(struct vb2_buffer *vb, void *pb)
break;
case VB2_BUF_STATE_ERROR:
b->flags |= V4L2_BUF_FLAG_ERROR;
- /* fall through */
+ fallthrough;
case VB2_BUF_STATE_DONE:
b->flags |= V4L2_BUF_FLAG_DONE;
break;
@@ -722,22 +723,12 @@ static void fill_buf_caps(struct vb2_queue *q, u32 *caps)
#endif
}
-static void clear_consistency_attr(struct vb2_queue *q,
- int memory,
- unsigned int *flags)
-{
- if (!q->allow_cache_hints || memory != V4L2_MEMORY_MMAP)
- *flags &= ~V4L2_FLAG_MEMORY_NON_CONSISTENT;
-}
-
int vb2_reqbufs(struct vb2_queue *q, struct v4l2_requestbuffers *req)
{
int ret = vb2_verify_memory_type(q, req->memory, req->type);
fill_buf_caps(q, &req->capabilities);
- clear_consistency_attr(q, req->memory, &req->flags);
- return ret ? ret : vb2_core_reqbufs(q, req->memory,
- req->flags, &req->count);
+ return ret ? ret : vb2_core_reqbufs(q, req->memory, &req->count);
}
EXPORT_SYMBOL_GPL(vb2_reqbufs);
@@ -769,7 +760,6 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
unsigned i;
fill_buf_caps(q, &create->capabilities);
- clear_consistency_attr(q, create->memory, &create->flags);
create->index = q->num_buffers;
if (create->count == 0)
return ret != -EBUSY ? ret : 0;
@@ -813,7 +803,6 @@ int vb2_create_bufs(struct vb2_queue *q, struct v4l2_create_buffers *create)
if (requested_sizes[i] == 0)
return -EINVAL;
return ret ? ret : vb2_core_create_bufs(q, create->memory,
- create->flags,
&create->count,
requested_planes,
requested_sizes);
@@ -998,12 +987,11 @@ int vb2_ioctl_reqbufs(struct file *file, void *priv,
int res = vb2_verify_memory_type(vdev->queue, p->memory, p->type);
fill_buf_caps(vdev->queue, &p->capabilities);
- clear_consistency_attr(vdev->queue, p->memory, &p->flags);
if (res)
return res;
if (vb2_queue_is_busy(vdev, file))
return -EBUSY;
- res = vb2_core_reqbufs(vdev->queue, p->memory, p->flags, &p->count);
+ res = vb2_core_reqbufs(vdev->queue, p->memory, &p->count);
/* If count == 0, then the owner has released all buffers and he
is no longer owner of the queue. Otherwise we have a new owner. */
if (res == 0)
@@ -1021,7 +1009,6 @@ int vb2_ioctl_create_bufs(struct file *file, void *priv,
p->index = vdev->queue->num_buffers;
fill_buf_caps(vdev->queue, &p->capabilities);
- clear_consistency_attr(vdev->queue, p->memory, &p->flags);
/*
* If count == 0, then just check if memory and type are valid.
* Any -EBUSY result from vb2_verify_memory_type can be mapped to 0.
@@ -1234,6 +1221,44 @@ unsigned long vb2_fop_get_unmapped_area(struct file *file, unsigned long addr,
EXPORT_SYMBOL_GPL(vb2_fop_get_unmapped_area);
#endif
+void vb2_video_unregister_device(struct video_device *vdev)
+{
+ /* Check if vdev was ever registered at all */
+ if (!vdev || !video_is_registered(vdev))
+ return;
+
+ /*
+ * Calling this function only makes sense if vdev->queue is set.
+ * If it is NULL, then just call video_unregister_device() instead.
+ */
+ WARN_ON(!vdev->queue);
+
+ /*
+ * Take a reference to the device since video_unregister_device()
+ * calls device_unregister(), but we don't want that to release
+ * the device since we want to clean up the queue first.
+ */
+ get_device(&vdev->dev);
+ video_unregister_device(vdev);
+ if (vdev->queue && vdev->queue->owner) {
+ struct mutex *lock = vdev->queue->lock ?
+ vdev->queue->lock : vdev->lock;
+
+ if (lock)
+ mutex_lock(lock);
+ vb2_queue_release(vdev->queue);
+ vdev->queue->owner = NULL;
+ if (lock)
+ mutex_unlock(lock);
+ }
+ /*
+ * Now we put the device, and in most cases this will release
+ * everything.
+ */
+ put_device(&vdev->dev);
+}
+EXPORT_SYMBOL_GPL(vb2_video_unregister_device);
+
/* vb2_ops helpers. Only use if vq->lock is non-NULL. */
void vb2_ops_wait_prepare(struct vb2_queue *vq)
diff --git a/drivers/media/common/videobuf2/videobuf2-vmalloc.c b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
index c66fda4a65e4..bf5ac63a5742 100644
--- a/drivers/media/common/videobuf2/videobuf2-vmalloc.c
+++ b/drivers/media/common/videobuf2/videobuf2-vmalloc.c
@@ -229,7 +229,7 @@ static int vb2_vmalloc_dmabuf_ops_attach(struct dma_buf *dbuf,
kfree(attach);
return ret;
}
- for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ for_each_sgtable_sg(sgt, sg, i) {
struct page *page = vmalloc_to_page(vaddr);
if (!page) {
@@ -259,8 +259,7 @@ static void vb2_vmalloc_dmabuf_ops_detach(struct dma_buf *dbuf,
/* release the scatterlist cache */
if (attach->dma_dir != DMA_NONE)
- dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
- attach->dma_dir);
+ dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir, 0);
sg_free_table(sgt);
kfree(attach);
db_attach->priv = NULL;
@@ -285,15 +284,12 @@ static struct sg_table *vb2_vmalloc_dmabuf_ops_map(
/* release any previous cache */
if (attach->dma_dir != DMA_NONE) {
- dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
- attach->dma_dir);
+ dma_unmap_sgtable(db_attach->dev, sgt, attach->dma_dir, 0);
attach->dma_dir = DMA_NONE;
}
/* mapping to the client with new direction */
- sgt->nents = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
- dma_dir);
- if (!sgt->nents) {
+ if (dma_map_sgtable(db_attach->dev, sgt, dma_dir, 0)) {
pr_err("failed to map scatterlist\n");
mutex_unlock(lock);
return ERR_PTR(-EIO);
diff --git a/drivers/media/dvb-core/dvb_vb2.c b/drivers/media/dvb-core/dvb_vb2.c
index 959d110407a4..6974f1731529 100644
--- a/drivers/media/dvb-core/dvb_vb2.c
+++ b/drivers/media/dvb-core/dvb_vb2.c
@@ -342,7 +342,7 @@ int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req)
ctx->buf_siz = req->size;
ctx->buf_cnt = req->count;
- ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, 0, &req->count);
+ ret = vb2_core_reqbufs(&ctx->vb_q, VB2_MEMORY_MMAP, &req->count);
if (ret) {
ctx->state = DVB_VB2_STATE_NONE;
dprintk(1, "[%s] count=%d size=%d errno=%d\n", ctx->name,
diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c
index 7281899bd7ae..7d7c341b2bd8 100644
--- a/drivers/media/dvb-frontends/af9013.c
+++ b/drivers/media/dvb-frontends/af9013.c
@@ -597,7 +597,7 @@ static int af9013_read_status(struct dvb_frontend *fe, enum fe_status *status)
state->strength_en = 2;
break;
}
- /* Fall through */
+ fallthrough;
case 1:
if (time_is_after_jiffies(state->strength_jiffies + msecs_to_jiffies(2000)))
break;
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index 32f9346deb3e..a57470bf71bf 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -1011,8 +1011,7 @@ static int hi_command(struct drxk_state *state, u16 cmd, u16 *p_result)
retry_count += 1;
status = read16(state, SIO_HI_RA_RAM_CMD__A,
&wait_cmd);
- } while ((status < 0) && (retry_count < DRXK_MAX_RETRIES)
- && (wait_cmd != 0));
+ } while ((status < 0 || wait_cmd) && (retry_count < DRXK_MAX_RETRIES));
if (status < 0)
goto error;
status = read16(state, SIO_HI_RA_RAM_RES__A, p_result);
diff --git a/drivers/media/dvb-frontends/lg2160.c b/drivers/media/dvb-frontends/lg2160.c
index 10c152f461dd..f343066c297e 100644
--- a/drivers/media/dvb-frontends/lg2160.c
+++ b/drivers/media/dvb-frontends/lg2160.c
@@ -1408,7 +1408,7 @@ struct dvb_frontend *lg2160_attach(const struct lg2160_config *config,
switch (config->lg_chip) {
default:
lg_warn("invalid chip requested, defaulting to LG2160");
- /* fall-thru */
+ fallthrough;
case LG2160:
memcpy(&state->frontend.ops, &lg2160_ops,
sizeof(struct dvb_frontend_ops));
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index f204e715bc59..ad6d9d564a87 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -906,7 +906,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
if (ret)
goto err;
}
- /* fall through */
+ fallthrough;
default:
u16tmp = DIV_ROUND_UP(target_mclk, dev->cfg->ts_clk);
u8tmp1 = u16tmp / 2 - 1;
diff --git a/drivers/media/dvb-frontends/mb86a16.c b/drivers/media/dvb-frontends/mb86a16.c
index 3843181bba16..2505f1e5794e 100644
--- a/drivers/media/dvb-frontends/mb86a16.c
+++ b/drivers/media/dvb-frontends/mb86a16.c
@@ -1452,11 +1452,8 @@ static int mb86a16_set_fe(struct mb86a16_state *state)
wait_t = (786432 + state->srate / 2) / state->srate;
else
wait_t = (1572864 + state->srate / 2) / state->srate;
- if (state->srate < 5000)
- /* FIXME ! , should be a long wait ! */
- msleep_interruptible(wait_t);
- else
- msleep_interruptible(wait_t);
+
+ msleep_interruptible(wait_t);
if (sync_chk(state, &junk) == 0) {
iq_vt_set(state, 1);
diff --git a/drivers/media/dvb-frontends/mxl5xx.c b/drivers/media/dvb-frontends/mxl5xx.c
index 4404ace82981..0b00a23436ed 100644
--- a/drivers/media/dvb-frontends/mxl5xx.c
+++ b/drivers/media/dvb-frontends/mxl5xx.c
@@ -27,7 +27,6 @@
#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/i2c.h>
-#include <linux/version.h>
#include <linux/mutex.h>
#include <linux/vmalloc.h>
#include <asm/div64.h>
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index 720756728f2d..ef6feb299d46 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -1411,6 +1411,7 @@ static int rtl2832_sdr_probe(struct platform_device *pdev)
default:
v4l2_ctrl_handler_init(&dev->hdl, 0);
dev_err(&pdev->dev, "Unsupported tuner\n");
+ ret = -ENODEV;
goto err_v4l2_ctrl_handler_free;
}
if (dev->hdl.error) {
diff --git a/drivers/media/dvb-frontends/tda10021.c b/drivers/media/dvb-frontends/tda10021.c
index 9fb207b41576..faa6e54b3372 100644
--- a/drivers/media/dvb-frontends/tda10021.c
+++ b/drivers/media/dvb-frontends/tda10021.c
@@ -137,26 +137,36 @@ static int tda10021_set_symbolrate (struct tda10021_state* state, u32 symbolrate
{
s32 BDR;
s32 BDRI;
- s16 SFIL=0;
+ s16 SFIL = 0;
u16 NDEC = 0;
u32 tmp, ratio;
- if (symbolrate > XIN/2)
- symbolrate = XIN/2;
- if (symbolrate < 500000)
+ if (symbolrate > XIN / 2)
+ symbolrate = XIN / 2;
+ else if (symbolrate < 500000)
symbolrate = 500000;
- if (symbolrate < XIN/16) NDEC = 1;
- if (symbolrate < XIN/32) NDEC = 2;
- if (symbolrate < XIN/64) NDEC = 3;
-
- if (symbolrate < (u32)(XIN/12.3)) SFIL = 1;
- if (symbolrate < (u32)(XIN/16)) SFIL = 0;
- if (symbolrate < (u32)(XIN/24.6)) SFIL = 1;
- if (symbolrate < (u32)(XIN/32)) SFIL = 0;
- if (symbolrate < (u32)(XIN/49.2)) SFIL = 1;
- if (symbolrate < (u32)(XIN/64)) SFIL = 0;
- if (symbolrate < (u32)(XIN/98.4)) SFIL = 1;
+ if (symbolrate < XIN / 16)
+ NDEC = 1;
+ if (symbolrate < XIN / 32)
+ NDEC = 2;
+ if (symbolrate < XIN / 64)
+ NDEC = 3;
+
+ if (symbolrate < XIN * 10 / 123)
+ SFIL = 1;
+ if (symbolrate < XIN * 10 / 160)
+ SFIL = 0;
+ if (symbolrate < XIN * 10 / 246)
+ SFIL = 1;
+ if (symbolrate < XIN * 10 / 320)
+ SFIL = 0;
+ if (symbolrate < XIN * 10 / 492)
+ SFIL = 1;
+ if (symbolrate < XIN * 10 / 640)
+ SFIL = 0;
+ if (symbolrate < XIN * 10 / 984)
+ SFIL = 1;
symbolrate <<= NDEC;
ratio = (symbolrate << 4) / FIN;
diff --git a/drivers/media/dvb-frontends/tda10086.c b/drivers/media/dvb-frontends/tda10086.c
index be6b40138f6e..cdcf97664bba 100644
--- a/drivers/media/dvb-frontends/tda10086.c
+++ b/drivers/media/dvb-frontends/tda10086.c
@@ -17,7 +17,7 @@
#include <media/dvb_frontend.h>
#include "tda10086.h"
-#define SACLK 96000000
+#define SACLK 96000000U
struct tda10086_state {
struct i2c_adapter* i2c;
@@ -297,34 +297,34 @@ static int tda10086_set_symbol_rate(struct tda10086_state *state,
dprintk ("%s %i\n", __func__, symbol_rate);
/* setup the decimation and anti-aliasing filters.. */
- if (symbol_rate < (u32) (SACLK * 0.0137)) {
+ if (symbol_rate < SACLK / 10000 * 137) {
dfn=4;
afs=1;
- } else if (symbol_rate < (u32) (SACLK * 0.0208)) {
+ } else if (symbol_rate < SACLK / 10000 * 208) {
dfn=4;
afs=0;
- } else if (symbol_rate < (u32) (SACLK * 0.0270)) {
+ } else if (symbol_rate < SACLK / 10000 * 270) {
dfn=3;
afs=1;
- } else if (symbol_rate < (u32) (SACLK * 0.0416)) {
+ } else if (symbol_rate < SACLK / 10000 * 416) {
dfn=3;
afs=0;
- } else if (symbol_rate < (u32) (SACLK * 0.0550)) {
+ } else if (symbol_rate < SACLK / 10000 * 550) {
dfn=2;
afs=1;
- } else if (symbol_rate < (u32) (SACLK * 0.0833)) {
+ } else if (symbol_rate < SACLK / 10000 * 833) {
dfn=2;
afs=0;
- } else if (symbol_rate < (u32) (SACLK * 0.1100)) {
+ } else if (symbol_rate < SACLK / 10000 * 1100) {
dfn=1;
afs=1;
- } else if (symbol_rate < (u32) (SACLK * 0.1666)) {
+ } else if (symbol_rate < SACLK / 10000 * 1666) {
dfn=1;
afs=0;
- } else if (symbol_rate < (u32) (SACLK * 0.2200)) {
+ } else if (symbol_rate < SACLK / 10000 * 2200) {
dfn=0;
afs=1;
- } else if (symbol_rate < (u32) (SACLK * 0.3333)) {
+ } else if (symbol_rate < SACLK / 10000 * 3333) {
dfn=0;
afs=0;
} else {
diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c
index 43312bba1aec..a34834487943 100644
--- a/drivers/media/dvb-frontends/tda18271c2dd.c
+++ b/drivers/media/dvb-frontends/tda18271c2dd.c
@@ -198,58 +198,55 @@ static void reset(struct tda_state *state)
state->m_bFMInput = (ulFMInput == 2);
}
-static bool SearchMap1(struct SMap Map[],
- u32 Frequency, u8 *pParam)
+static bool SearchMap1(const struct SMap map[], u32 frequency, u8 *param)
{
int i = 0;
- while ((Map[i].m_Frequency != 0) && (Frequency > Map[i].m_Frequency))
+ while ((map[i].m_Frequency != 0) && (frequency > map[i].m_Frequency))
i += 1;
- if (Map[i].m_Frequency == 0)
+ if (map[i].m_Frequency == 0)
return false;
- *pParam = Map[i].m_Param;
+ *param = map[i].m_Param;
return true;
}
-static bool SearchMap2(struct SMapI Map[],
- u32 Frequency, s32 *pParam)
+static bool SearchMap2(const struct SMapI map[], u32 frequency, s32 *param)
{
int i = 0;
- while ((Map[i].m_Frequency != 0) &&
- (Frequency > Map[i].m_Frequency))
+ while ((map[i].m_Frequency != 0) &&
+ (frequency > map[i].m_Frequency))
i += 1;
- if (Map[i].m_Frequency == 0)
+ if (map[i].m_Frequency == 0)
return false;
- *pParam = Map[i].m_Param;
+ *param = map[i].m_Param;
return true;
}
-static bool SearchMap3(struct SMap2 Map[], u32 Frequency,
- u8 *pParam1, u8 *pParam2)
+static bool SearchMap3(const struct SMap2 map[], u32 frequency, u8 *param1,
+ u8 *param2)
{
int i = 0;
- while ((Map[i].m_Frequency != 0) &&
- (Frequency > Map[i].m_Frequency))
+ while ((map[i].m_Frequency != 0) &&
+ (frequency > map[i].m_Frequency))
i += 1;
- if (Map[i].m_Frequency == 0)
+ if (map[i].m_Frequency == 0)
return false;
- *pParam1 = Map[i].m_Param1;
- *pParam2 = Map[i].m_Param2;
+ *param1 = map[i].m_Param1;
+ *param2 = map[i].m_Param2;
return true;
}
-static bool SearchMap4(struct SRFBandMap Map[],
- u32 Frequency, u8 *pRFBand)
+static bool SearchMap4(const struct SRFBandMap map[], u32 frequency, u8 *rfband)
{
int i = 0;
- while (i < 7 && (Frequency > Map[i].m_RF_max))
+ while (i < 7 && (frequency > map[i].m_RF_max))
i += 1;
if (i == 7)
return false;
- *pRFBand = i;
+ *rfband = i;
return true;
}
diff --git a/drivers/media/dvb-frontends/tda18271c2dd_maps.h b/drivers/media/dvb-frontends/tda18271c2dd_maps.h
index 5f75516bc0cb..82218e02d77d 100644
--- a/drivers/media/dvb-frontends/tda18271c2dd_maps.h
+++ b/drivers/media/dvb-frontends/tda18271c2dd_maps.h
@@ -6,7 +6,7 @@ enum HF_S {
HF_DVBC_8MHZ, HF_DVBC
};
-static struct SStandardParam m_StandardTable[] = {
+static const struct SStandardParam m_StandardTable[] = {
{ 0, 0, 0x00, 0x00 }, /* HF_None */
{ 6000000, 7000000, 0x1D, 0x2C }, /* HF_B, */
{ 6900000, 8000000, 0x1E, 0x2C }, /* HF_DK, */
@@ -28,7 +28,7 @@ static struct SStandardParam m_StandardTable[] = {
{ 0, 0, 0x00, 0x00 }, /* HF_DVBC (Unused) */
};
-static struct SMap m_BP_Filter_Map[] = {
+static const struct SMap m_BP_Filter_Map[] = {
{ 62000000, 0x00 },
{ 84000000, 0x01 },
{ 100000000, 0x02 },
@@ -39,7 +39,7 @@ static struct SMap m_BP_Filter_Map[] = {
{ 0, 0x00 }, /* Table End */
};
-static struct SMapI m_RF_Cal_Map[] = {
+static const struct SMapI m_RF_Cal_Map[] = {
{ 41000000, 0x0F },
{ 43000000, 0x1C },
{ 45000000, 0x2F },
@@ -481,7 +481,7 @@ static struct SMapI m_RF_Cal_Map[] = {
};
-static struct SMap2 m_KM_Map[] = {
+static const struct SMap2 m_KM_Map[] = {
{ 47900000, 3, 2 },
{ 61100000, 3, 1 },
{ 350000000, 3, 0 },
@@ -490,7 +490,7 @@ static struct SMap2 m_KM_Map[] = {
{ 0, 0x00 }, /* Table End */
};
-static struct SMap2 m_Main_PLL_Map[] = {
+static const struct SMap2 m_Main_PLL_Map[] = {
{ 33125000, 0x57, 0xF0 },
{ 35500000, 0x56, 0xE0 },
{ 38188000, 0x55, 0xD0 },
@@ -534,7 +534,7 @@ static struct SMap2 m_Main_PLL_Map[] = {
{ 0, 0x00, 0x00 }, /* Table End */
};
-static struct SMap2 m_Cal_PLL_Map[] = {
+static const struct SMap2 m_Cal_PLL_Map[] = {
{ 33813000, 0xDD, 0xD0 },
{ 36625000, 0xDC, 0xC0 },
{ 39938000, 0xDB, 0xB0 },
@@ -572,7 +572,7 @@ static struct SMap2 m_Cal_PLL_Map[] = {
{ 0, 0x00, 0x00 }, /* Table End */
};
-static struct SMap m_GainTaper_Map[] = {
+static const struct SMap m_GainTaper_Map[] = {
{ 45400000, 0x1F },
{ 45800000, 0x1E },
{ 46200000, 0x1D },
@@ -661,7 +661,7 @@ static struct SMap m_GainTaper_Map[] = {
{ 0, 0x00 }, /* Table End */
};
-static struct SMap m_RF_Cal_DC_Over_DT_Map[] = {
+static const struct SMap m_RF_Cal_DC_Over_DT_Map[] = {
{ 47900000, 0x00 },
{ 55000000, 0x00 },
{ 61100000, 0x0A },
@@ -767,14 +767,14 @@ static struct SMap m_RF_Cal_DC_Over_DT_Map[] = {
};
-static struct SMap m_IR_Meas_Map[] = {
+static const struct SMap m_IR_Meas_Map[] = {
{ 200000000, 0x05 },
{ 400000000, 0x06 },
{ 865000000, 0x07 },
{ 0, 0x00 }, /* Table End */
};
-static struct SMap2 m_CID_Target_Map[] = {
+static const struct SMap2 m_CID_Target_Map[] = {
{ 46000000, 0x04, 18 },
{ 52200000, 0x0A, 15 },
{ 70100000, 0x01, 40 },
@@ -790,7 +790,7 @@ static struct SMap2 m_CID_Target_Map[] = {
{ 0, 0x00, 0 }, /* Table End */
};
-static struct SRFBandMap m_RF_Band_Map[7] = {
+static const struct SRFBandMap m_RF_Band_Map[7] = {
{ 47900000, 46000000, 0, 0},
{ 61100000, 52200000, 0, 0},
{ 152600000, 70100000, 136800000, 0},
diff --git a/drivers/media/dvb-frontends/zd1301_demod.h b/drivers/media/dvb-frontends/zd1301_demod.h
index d56196f5c801..01eaacf76a13 100644
--- a/drivers/media/dvb-frontends/zd1301_demod.h
+++ b/drivers/media/dvb-frontends/zd1301_demod.h
@@ -43,12 +43,6 @@ struct i2c_adapter *zd1301_demod_get_i2c_adapter(struct platform_device *pdev);
#else
-/**
- * zd1301_demod_get_dvb_frontend() - Attach a zd1301 frontend
- * @dev: Pointer to platform device
- *
- * Return: Pointer to %struct dvb_frontend or NULL if attach fails.
- */
static inline struct dvb_frontend *zd1301_demod_get_dvb_frontend(struct platform_device *dev)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
diff --git a/drivers/media/firewire/firedtv-fw.c b/drivers/media/firewire/firedtv-fw.c
index 3f1ca40b9b98..8a8585261bb8 100644
--- a/drivers/media/firewire/firedtv-fw.c
+++ b/drivers/media/firewire/firedtv-fw.c
@@ -272,8 +272,10 @@ static int node_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
name_len = fw_csr_string(unit->directory, CSR_MODEL,
name, sizeof(name));
- if (name_len < 0)
- return name_len;
+ if (name_len < 0) {
+ err = name_len;
+ goto fail_free;
+ }
for (i = ARRAY_SIZE(model_names); --i; )
if (strlen(model_names[i]) <= name_len &&
strncmp(name, model_names[i], name_len) == 0)
diff --git a/drivers/media/i2c/Kconfig b/drivers/media/i2c/Kconfig
index c7ba76fee599..878f66ef2719 100644
--- a/drivers/media/i2c/Kconfig
+++ b/drivers/media/i2c/Kconfig
@@ -1015,7 +1015,7 @@ config VIDEO_OV7670
config VIDEO_OV7740
tristate "OmniVision OV7740 sensor support"
depends on I2C && VIDEO_V4L2
- select REGMAP_I2C
+ select REGMAP_SCCB
help
This is a Video4Linux2 sensor driver for the OmniVision
OV7740 VGA camera sensor.
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 00159daa6fcd..4498d14d3429 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -726,7 +726,7 @@ static int adv7180_set_pad_format(struct v4l2_subdev *sd,
case V4L2_FIELD_NONE:
if (state->chip_info->flags & ADV7180_FLAG_I2P)
break;
- /* fall through */
+ fallthrough;
default:
format->format.field = V4L2_FIELD_ALTERNATE;
break;
@@ -760,8 +760,9 @@ static int adv7180_init_cfg(struct v4l2_subdev *sd,
return adv7180_set_pad_format(sd, cfg, &fmt);
}
-static int adv7180_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int adv7180_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
struct adv7180_state *state = to_state(sd);
@@ -852,7 +853,6 @@ static const struct v4l2_subdev_video_ops adv7180_video_ops = {
.querystd = adv7180_querystd,
.g_input_status = adv7180_g_input_status,
.s_routing = adv7180_s_routing,
- .g_mbus_config = adv7180_g_mbus_config,
.g_pixelaspect = adv7180_g_pixelaspect,
.g_tvnorms = adv7180_g_tvnorms,
.s_stream = adv7180_s_stream,
@@ -869,6 +869,7 @@ static const struct v4l2_subdev_pad_ops adv7180_pad_ops = {
.enum_mbus_code = adv7180_enum_mbus_code,
.set_fmt = adv7180_set_pad_format,
.get_fmt = adv7180_get_pad_format,
+ .get_mbus_config = adv7180_get_mbus_config,
};
static const struct v4l2_subdev_sensor_ops adv7180_sensor_ops = {
diff --git a/drivers/media/i2c/adv748x/adv748x-core.c b/drivers/media/i2c/adv748x/adv748x-core.c
index 23e02ff27b17..1fe7f97c6d52 100644
--- a/drivers/media/i2c/adv748x/adv748x-core.c
+++ b/drivers/media/i2c/adv748x/adv748x-core.c
@@ -241,10 +241,10 @@ static int adv748x_power_up_tx(struct adv748x_csi2 *tx)
int ret = 0;
/* Enable n-lane MIPI */
- adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret);
+ adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret);
/* Set Auto DPHY Timing */
- adv748x_write_check(state, page, 0x00, 0xa0 | tx->num_lanes, &ret);
+ adv748x_write_check(state, page, 0x00, 0xa0 | tx->active_lanes, &ret);
/* ADI Required Write */
if (tx->src == &state->hdmi.sd) {
@@ -270,7 +270,7 @@ static int adv748x_power_up_tx(struct adv748x_csi2 *tx)
usleep_range(2000, 2500);
/* Power-up CSI-TX */
- adv748x_write_check(state, page, 0x00, 0x20 | tx->num_lanes, &ret);
+ adv748x_write_check(state, page, 0x00, 0x20 | tx->active_lanes, &ret);
usleep_range(1000, 1500);
/* ADI Required Writes */
@@ -292,7 +292,7 @@ static int adv748x_power_down_tx(struct adv748x_csi2 *tx)
adv748x_write_check(state, page, 0x1e, 0x00, &ret);
/* Enable n-lane MIPI */
- adv748x_write_check(state, page, 0x00, 0x80 | tx->num_lanes, &ret);
+ adv748x_write_check(state, page, 0x00, 0x80 | tx->active_lanes, &ret);
/* i2c_mipi_pll_en - 1'b1 */
adv748x_write_check(state, page, 0xda, 0x01, &ret);
@@ -357,14 +357,29 @@ static int adv748x_link_setup(struct media_entity *entity,
if (state->afe.tx) {
/* AFE Requires TXA enabled, even when output to TXB */
io10 |= ADV748X_IO_10_CSI4_EN;
- if (is_txa(tx))
+ if (is_txa(tx)) {
+ /*
+ * Output from the SD-core (480i and 576i) from the TXA
+ * interface requires reducing the number of enabled
+ * data lanes in order to guarantee a valid link
+ * frequency.
+ */
+ tx->active_lanes = min(tx->num_lanes, 2U);
io10 |= ADV748X_IO_10_CSI4_IN_SEL_AFE;
- else
+ } else {
+ /* TXB has a single data lane, no need to adjust. */
io10 |= ADV748X_IO_10_CSI1_EN;
+ }
}
- if (state->hdmi.tx)
+ if (state->hdmi.tx) {
+ /*
+ * Restore the number of active lanes, in case we have gone
+ * through an AFE->TXA streaming sessions.
+ */
+ tx->active_lanes = tx->num_lanes;
io10 |= ADV748X_IO_10_CSI4_EN;
+ }
return io_clrset(state, ADV748X_IO_10, io10_mask, io10);
}
@@ -596,6 +611,7 @@ static int adv748x_parse_csi2_lanes(struct adv748x_state *state,
}
state->txa.num_lanes = num_lanes;
+ state->txa.active_lanes = num_lanes;
adv_dbg(state, "TXA: using %u lanes\n", state->txa.num_lanes);
}
@@ -607,6 +623,7 @@ static int adv748x_parse_csi2_lanes(struct adv748x_state *state,
}
state->txb.num_lanes = num_lanes;
+ state->txb.active_lanes = num_lanes;
adv_dbg(state, "TXB: using %u lanes\n", state->txb.num_lanes);
}
diff --git a/drivers/media/i2c/adv748x/adv748x-csi2.c b/drivers/media/i2c/adv748x/adv748x-csi2.c
index 2091cda50935..99bb63d05eef 100644
--- a/drivers/media/i2c/adv748x/adv748x-csi2.c
+++ b/drivers/media/i2c/adv748x/adv748x-csi2.c
@@ -214,9 +214,40 @@ unlock:
return ret;
}
+static int adv748x_csi2_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_config *config)
+{
+ struct adv748x_csi2 *tx = adv748x_sd_to_csi2(sd);
+
+ if (pad != ADV748X_CSI2_SOURCE)
+ return -EINVAL;
+
+ config->type = V4L2_MBUS_CSI2_DPHY;
+ switch (tx->active_lanes) {
+ case 1:
+ config->flags = V4L2_MBUS_CSI2_1_LANE;
+ break;
+
+ case 2:
+ config->flags = V4L2_MBUS_CSI2_2_LANE;
+ break;
+
+ case 3:
+ config->flags = V4L2_MBUS_CSI2_3_LANE;
+ break;
+
+ case 4:
+ config->flags = V4L2_MBUS_CSI2_4_LANE;
+ break;
+ }
+
+ return 0;
+}
+
static const struct v4l2_subdev_pad_ops adv748x_csi2_pad_ops = {
.get_fmt = adv748x_csi2_get_format,
.set_fmt = adv748x_csi2_set_format,
+ .get_mbus_config = adv748x_csi2_get_mbus_config,
};
/* -----------------------------------------------------------------------------
diff --git a/drivers/media/i2c/adv748x/adv748x.h b/drivers/media/i2c/adv748x/adv748x.h
index fccb388ce179..1061f425ece5 100644
--- a/drivers/media/i2c/adv748x/adv748x.h
+++ b/drivers/media/i2c/adv748x/adv748x.h
@@ -79,6 +79,7 @@ struct adv748x_csi2 {
unsigned int page;
unsigned int port;
unsigned int num_lanes;
+ unsigned int active_lanes;
struct media_pad pads[ADV748X_CSI2_NR_PADS];
struct v4l2_ctrl_handler ctrl_hdl;
diff --git a/drivers/media/i2c/adv7511-v4l2.c b/drivers/media/i2c/adv7511-v4l2.c
index 62763ec4cd07..a3161d709015 100644
--- a/drivers/media/i2c/adv7511-v4l2.c
+++ b/drivers/media/i2c/adv7511-v4l2.c
@@ -470,7 +470,7 @@ static int adv7511_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
reg->val = adv7511_cec_read(sd, reg->reg & 0xff);
break;
}
- /* fall through */
+ fallthrough;
default:
v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
adv7511_inv_register(sd);
@@ -492,7 +492,7 @@ static int adv7511_s_register(struct v4l2_subdev *sd, const struct v4l2_dbg_regi
adv7511_cec_write(sd, reg->reg & 0xff, reg->val & 0xff);
break;
}
- /* fall through */
+ fallthrough;
default:
v4l2_info(sd, "Register %03llx not supported\n", reg->reg);
adv7511_inv_register(sd);
diff --git a/drivers/media/i2c/cx25840/cx25840-ir.c b/drivers/media/i2c/cx25840/cx25840-ir.c
index 2181c8a347fc..2cf3e6a1f9e1 100644
--- a/drivers/media/i2c/cx25840/cx25840-ir.c
+++ b/drivers/media/i2c/cx25840/cx25840-ir.c
@@ -688,7 +688,7 @@ static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
}
v = (unsigned) pulse_width_count_to_ns(
- (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
+ (u16)(p->hw_fifo_data & FIFO_RXTX), divider) / 1000;
if (v > IR_MAX_DURATION)
v = IR_MAX_DURATION;
diff --git a/drivers/media/i2c/dw9807-vcm.c b/drivers/media/i2c/dw9807-vcm.c
index b38a4e6d270d..438a44b76da8 100644
--- a/drivers/media/i2c/dw9807-vcm.c
+++ b/drivers/media/i2c/dw9807-vcm.c
@@ -324,6 +324,6 @@ static struct i2c_driver dw9807_i2c_driver = {
module_i2c_driver(dw9807_i2c_driver);
-MODULE_AUTHOR("Chiang, Alan <alanx.chiang@intel.com>");
+MODULE_AUTHOR("Chiang, Alan");
MODULE_DESCRIPTION("DW9807 VCM driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/imx219.c b/drivers/media/i2c/imx219.c
index f64c0ef7a897..1cee45e35355 100644
--- a/drivers/media/i2c/imx219.c
+++ b/drivers/media/i2c/imx219.c
@@ -1188,7 +1188,7 @@ static int __maybe_unused imx219_resume(struct device *dev)
error:
imx219_stop_streaming(imx219);
- imx219->streaming = 0;
+ imx219->streaming = false;
return ret;
}
diff --git a/drivers/media/i2c/imx258.c b/drivers/media/i2c/imx258.c
index f86ae18bc104..ccb55fd1d506 100644
--- a/drivers/media/i2c/imx258.c
+++ b/drivers/media/i2c/imx258.c
@@ -1304,7 +1304,7 @@ static struct i2c_driver imx258_i2c_driver = {
module_i2c_driver(imx258_i2c_driver);
MODULE_AUTHOR("Yeh, Andy <andy.yeh@intel.com>");
-MODULE_AUTHOR("Chiang, Alan <alanx.chiang@intel.com>");
+MODULE_AUTHOR("Chiang, Alan");
MODULE_AUTHOR("Chen, Jason <jasonx.z.chen@intel.com>");
MODULE_DESCRIPTION("Sony IMX258 sensor driver");
MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/i2c/imx274.c b/drivers/media/i2c/imx274.c
index 6011cec5e351..e6aa9f32b6a8 100644
--- a/drivers/media/i2c/imx274.c
+++ b/drivers/media/i2c/imx274.c
@@ -1235,6 +1235,8 @@ static int imx274_s_frame_interval(struct v4l2_subdev *sd,
ret = imx274_set_frame_interval(imx274, fi->interval);
if (!ret) {
+ fi->interval = imx274->frame_interval;
+
/*
* exposure time range is decided by frame interval
* need to update it after frame interval changes
@@ -1730,9 +1732,9 @@ static int imx274_set_frame_interval(struct stimx274 *priv,
__func__, frame_interval.numerator,
frame_interval.denominator);
- if (frame_interval.numerator == 0) {
- err = -EINVAL;
- goto fail;
+ if (frame_interval.numerator == 0 || frame_interval.denominator == 0) {
+ frame_interval.denominator = IMX274_DEF_FRAME_RATE;
+ frame_interval.numerator = 1;
}
req_frame_rate = (u32)(frame_interval.denominator
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index de295114ca48..21666d705e37 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -764,7 +764,8 @@ static int m5mols_sensor_power(struct m5mols_info *info, bool enable)
ret = regulator_bulk_enable(ARRAY_SIZE(supplies), supplies);
if (ret) {
- info->set_power(&client->dev, 0);
+ if (info->set_power)
+ info->set_power(&client->dev, 0);
return ret;
}
diff --git a/drivers/media/i2c/max9286.c b/drivers/media/i2c/max9286.c
index 47f280518fdb..c82c1493e099 100644
--- a/drivers/media/i2c/max9286.c
+++ b/drivers/media/i2c/max9286.c
@@ -135,13 +135,19 @@
#define MAX9286_SRC_PAD 4
struct max9286_source {
- struct v4l2_async_subdev asd;
struct v4l2_subdev *sd;
struct fwnode_handle *fwnode;
};
-#define asd_to_max9286_source(_asd) \
- container_of(_asd, struct max9286_source, asd)
+struct max9286_asd {
+ struct v4l2_async_subdev base;
+ struct max9286_source *source;
+};
+
+static inline struct max9286_asd *to_max9286_asd(struct v4l2_async_subdev *asd)
+{
+ return container_of(asd, struct max9286_asd, base);
+}
struct max9286_priv {
struct i2c_client *client;
@@ -405,10 +411,11 @@ static int max9286_check_config_link(struct max9286_priv *priv,
* to 5 milliseconds.
*/
for (i = 0; i < 10; i++) {
- ret = max9286_read(priv, 0x49) & 0xf0;
+ ret = max9286_read(priv, 0x49);
if (ret < 0)
return -EIO;
+ ret &= 0xf0;
if (ret == conflink_mask)
break;
@@ -480,7 +487,7 @@ static int max9286_notify_bound(struct v4l2_async_notifier *notifier,
struct v4l2_async_subdev *asd)
{
struct max9286_priv *priv = sd_to_max9286(notifier->sd);
- struct max9286_source *source = asd_to_max9286_source(asd);
+ struct max9286_source *source = to_max9286_asd(asd)->source;
unsigned int index = to_index(priv, source);
unsigned int src_pad;
int ret;
@@ -544,7 +551,7 @@ static void max9286_notify_unbind(struct v4l2_async_notifier *notifier,
struct v4l2_async_subdev *asd)
{
struct max9286_priv *priv = sd_to_max9286(notifier->sd);
- struct max9286_source *source = asd_to_max9286_source(asd);
+ struct max9286_source *source = to_max9286_asd(asd)->source;
unsigned int index = to_index(priv, source);
source->sd = NULL;
@@ -569,23 +576,19 @@ static int max9286_v4l2_notifier_register(struct max9286_priv *priv)
for_each_source(priv, source) {
unsigned int i = to_index(priv, source);
-
- source->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
- source->asd.match.fwnode = source->fwnode;
-
- ret = v4l2_async_notifier_add_subdev(&priv->notifier,
- &source->asd);
- if (ret) {
- dev_err(dev, "Failed to add subdev for source %d", i);
+ struct v4l2_async_subdev *asd;
+
+ asd = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier,
+ source->fwnode,
+ sizeof(*asd));
+ if (IS_ERR(asd)) {
+ dev_err(dev, "Failed to add subdev for source %u: %ld",
+ i, PTR_ERR(asd));
v4l2_async_notifier_cleanup(&priv->notifier);
- return ret;
+ return PTR_ERR(asd);
}
- /*
- * Balance the reference counting handled through
- * v4l2_async_notifier_cleanup()
- */
- fwnode_handle_get(source->fwnode);
+ to_max9286_asd(asd)->source = source;
}
priv->notifier.ops = &max9286_notify_ops;
diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c
index c444bd6a0658..ff212335326a 100644
--- a/drivers/media/i2c/ml86v7667.c
+++ b/drivers/media/i2c/ml86v7667.c
@@ -219,8 +219,9 @@ static int ml86v7667_fill_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int ml86v7667_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int ml86v7667_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_PCLK_SAMPLE_RISING |
V4L2_MBUS_DATA_ACTIVE_HIGH;
@@ -291,13 +292,13 @@ static const struct v4l2_subdev_video_ops ml86v7667_subdev_video_ops = {
.s_std = ml86v7667_s_std,
.querystd = ml86v7667_querystd,
.g_input_status = ml86v7667_g_input_status,
- .g_mbus_config = ml86v7667_g_mbus_config,
};
static const struct v4l2_subdev_pad_ops ml86v7667_subdev_pad_ops = {
.enum_mbus_code = ml86v7667_enum_mbus_code,
.get_fmt = ml86v7667_fill_fmt,
.set_fmt = ml86v7667_fill_fmt,
+ .get_mbus_config = ml86v7667_get_mbus_config,
};
static const struct v4l2_subdev_core_ops ml86v7667_subdev_core_ops = {
diff --git a/drivers/media/i2c/msp3400-kthreads.c b/drivers/media/i2c/msp3400-kthreads.c
index d3b0d1c18efd..52e506f86de5 100644
--- a/drivers/media/i2c/msp3400-kthreads.c
+++ b/drivers/media/i2c/msp3400-kthreads.c
@@ -646,7 +646,7 @@ restart:
break;
case 0: /* 4.5 */
state->detected_std = V4L2_STD_MN;
- /* fall-through */
+ fallthrough;
default:
no_second:
state->second = msp3400c_carrier_detect_main[max1].cdo;
diff --git a/drivers/media/i2c/mt9m001.c b/drivers/media/i2c/mt9m001.c
index 210ea76adb53..3b0ba8ed5233 100644
--- a/drivers/media/i2c/mt9m001.c
+++ b/drivers/media/i2c/mt9m001.c
@@ -689,8 +689,9 @@ static int mt9m001_enum_mbus_code(struct v4l2_subdev *sd,
return 0;
}
-static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int mt9m001_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
/* MT9M001 has all capture_format parameters fixed */
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_FALLING |
@@ -703,7 +704,6 @@ static int mt9m001_g_mbus_config(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops mt9m001_subdev_video_ops = {
.s_stream = mt9m001_s_stream,
- .g_mbus_config = mt9m001_g_mbus_config,
};
static const struct v4l2_subdev_sensor_ops mt9m001_subdev_sensor_ops = {
@@ -717,6 +717,7 @@ static const struct v4l2_subdev_pad_ops mt9m001_subdev_pad_ops = {
.set_selection = mt9m001_set_selection,
.get_fmt = mt9m001_get_fmt,
.set_fmt = mt9m001_set_fmt,
+ .get_mbus_config = mt9m001_get_mbus_config,
};
static const struct v4l2_subdev_ops mt9m001_subdev_ops = {
diff --git a/drivers/media/i2c/mt9m111.c b/drivers/media/i2c/mt9m111.c
index 17e8253f5748..69697386ffcd 100644
--- a/drivers/media/i2c/mt9m111.c
+++ b/drivers/media/i2c/mt9m111.c
@@ -1137,8 +1137,9 @@ static int mt9m111_init_cfg(struct v4l2_subdev *sd,
return 0;
}
-static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int mt9m111_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
struct mt9m111 *mt9m111 = container_of(sd, struct mt9m111, subdev);
@@ -1155,7 +1156,6 @@ static int mt9m111_g_mbus_config(struct v4l2_subdev *sd,
}
static const struct v4l2_subdev_video_ops mt9m111_subdev_video_ops = {
- .g_mbus_config = mt9m111_g_mbus_config,
.s_stream = mt9m111_s_stream,
.g_frame_interval = mt9m111_g_frame_interval,
.s_frame_interval = mt9m111_s_frame_interval,
@@ -1168,6 +1168,7 @@ static const struct v4l2_subdev_pad_ops mt9m111_subdev_pad_ops = {
.set_selection = mt9m111_set_selection,
.get_fmt = mt9m111_get_fmt,
.set_fmt = mt9m111_set_fmt,
+ .get_mbus_config = mt9m111_get_mbus_config,
};
static const struct v4l2_subdev_ops mt9m111_subdev_ops = {
diff --git a/drivers/media/i2c/ov2740.c b/drivers/media/i2c/ov2740.c
index fd0b6a903ec1..bd0d45b0d43f 100644
--- a/drivers/media/i2c/ov2740.c
+++ b/drivers/media/i2c/ov2740.c
@@ -1018,6 +1018,10 @@ static int ov2740_register_nvmem(struct i2c_client *client)
if (!nvm)
return -ENOMEM;
+ nvm->nvm_buffer = devm_kzalloc(dev, CUSTOMER_USE_OTP_SIZE, GFP_KERNEL);
+ if (!nvm->nvm_buffer)
+ return -ENOMEM;
+
regmap_config.val_bits = 8;
regmap_config.reg_bits = 16;
regmap_config.disable_locking = true;
@@ -1027,6 +1031,12 @@ static int ov2740_register_nvmem(struct i2c_client *client)
nvm->regmap = regmap;
+ ret = ov2740_load_otp_data(client, nvm);
+ if (ret) {
+ dev_err(dev, "failed to load OTP data, ret %d\n", ret);
+ return ret;
+ }
+
nvmem_config.name = dev_name(dev);
nvmem_config.dev = dev;
nvmem_config.read_only = true;
@@ -1042,18 +1052,8 @@ static int ov2740_register_nvmem(struct i2c_client *client)
nvmem_config.size = CUSTOMER_USE_OTP_SIZE;
nvm->nvmem = devm_nvmem_register(dev, &nvmem_config);
- if (IS_ERR(nvm->nvmem))
- return PTR_ERR(nvm->nvmem);
- nvm->nvm_buffer = devm_kzalloc(dev, CUSTOMER_USE_OTP_SIZE, GFP_KERNEL);
- if (!nvm->nvm_buffer)
- return -ENOMEM;
-
- ret = ov2740_load_otp_data(client, nvm);
- if (ret)
- dev_err(dev, "failed to load OTP data, ret %d\n", ret);
-
- return ret;
+ return PTR_ERR_OR_ZERO(nvm->nvmem);
}
static int ov2740_probe(struct i2c_client *client)
@@ -1107,7 +1107,7 @@ static int ov2740_probe(struct i2c_client *client)
ret = ov2740_register_nvmem(client);
if (ret)
- dev_err(&client->dev, "register nvmem failed, ret %d\n", ret);
+ dev_warn(&client->dev, "register nvmem failed, ret %d\n", ret);
/*
* Device is already turned on by i2c-core with ACPI domain PM.
diff --git a/drivers/media/i2c/ov5640.c b/drivers/media/i2c/ov5640.c
index 2fe4a7ac0592..8d0254d0e5ea 100644
--- a/drivers/media/i2c/ov5640.c
+++ b/drivers/media/i2c/ov5640.c
@@ -34,6 +34,8 @@
#define OV5640_REG_SYS_RESET02 0x3002
#define OV5640_REG_SYS_CLOCK_ENABLE02 0x3006
#define OV5640_REG_SYS_CTRL0 0x3008
+#define OV5640_REG_SYS_CTRL0_SW_PWDN 0x42
+#define OV5640_REG_SYS_CTRL0_SW_PWUP 0x02
#define OV5640_REG_CHIP_ID 0x300a
#define OV5640_REG_IO_MIPI_CTRL00 0x300e
#define OV5640_REG_PAD_OUTPUT_ENABLE01 0x3017
@@ -82,6 +84,7 @@
#define OV5640_REG_VFIFO_HSIZE 0x4602
#define OV5640_REG_VFIFO_VSIZE 0x4604
#define OV5640_REG_JPG_MODE_SELECT 0x4713
+#define OV5640_REG_CCIR656_CTRL00 0x4730
#define OV5640_REG_POLARITY_CTRL00 0x4740
#define OV5640_REG_MIPI_CTRL00 0x4800
#define OV5640_REG_DEBUG_MODE 0x4814
@@ -274,8 +277,7 @@ static inline struct v4l2_subdev *ctrl_to_sd(struct v4l2_ctrl *ctrl)
/* YUV422 UYVY VGA@30fps */
static const struct reg_value ov5640_init_setting_30fps_VGA[] = {
{0x3103, 0x11, 0, 0}, {0x3008, 0x82, 0, 5}, {0x3008, 0x42, 0, 0},
- {0x3103, 0x03, 0, 0}, {0x3017, 0x00, 0, 0}, {0x3018, 0x00, 0, 0},
- {0x3630, 0x36, 0, 0},
+ {0x3103, 0x03, 0, 0}, {0x3630, 0x36, 0, 0},
{0x3631, 0x0e, 0, 0}, {0x3632, 0xe2, 0, 0}, {0x3633, 0x12, 0, 0},
{0x3621, 0xe0, 0, 0}, {0x3704, 0xa0, 0, 0}, {0x3703, 0x5a, 0, 0},
{0x3715, 0x78, 0, 0}, {0x3717, 0x01, 0, 0}, {0x370b, 0x60, 0, 0},
@@ -751,7 +753,7 @@ static int ov5640_mod_reg(struct ov5640_dev *sensor, u16 reg,
* +->| PLL Root Div | - reg 0x3037, bit 4
* +-+------------+
* | +---------+
- * +->| Bit Div | - reg 0x3035, bits 0-3
+ * +->| Bit Div | - reg 0x3034, bits 0-3
* +-+-------+
* | +-------------+
* +->| SCLK Div | - reg 0x3108, bits 0-1
@@ -1120,6 +1122,12 @@ static int ov5640_load_regs(struct ov5640_dev *sensor,
val = regs->val;
mask = regs->mask;
+ /* remain in power down mode for DVP */
+ if (regs->reg_addr == OV5640_REG_SYS_CTRL0 &&
+ val == OV5640_REG_SYS_CTRL0_SW_PWUP &&
+ sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY)
+ continue;
+
if (mask)
ret = ov5640_mod_reg(sensor, reg_addr, mask, val);
else
@@ -1208,98 +1216,25 @@ static int ov5640_set_autogain(struct ov5640_dev *sensor, bool on)
BIT(1), on ? 0 : BIT(1));
}
-static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
+static int ov5640_set_stream_bt656(struct ov5640_dev *sensor, bool on)
{
int ret;
- unsigned int flags = sensor->ep.bus.parallel.flags;
- u8 pclk_pol = 0;
- u8 hsync_pol = 0;
- u8 vsync_pol = 0;
-
- /*
- * Note about parallel port configuration.
- *
- * When configured in parallel mode, the OV5640 will
- * output 10 bits data on DVP data lines [9:0].
- * If only 8 bits data are wanted, the 8 bits data lines
- * of the camera interface must be physically connected
- * on the DVP data lines [9:2].
- *
- * Control lines polarity can be configured through
- * devicetree endpoint control lines properties.
- * If no endpoint control lines properties are set,
- * polarity will be as below:
- * - VSYNC: active high
- * - HREF: active low
- * - PCLK: active low
- */
- if (on) {
- /*
- * configure parallel port control lines polarity
- *
- * POLARITY CTRL0
- * - [5]: PCLK polarity (0: active low, 1: active high)
- * - [1]: HREF polarity (0: active low, 1: active high)
- * - [0]: VSYNC polarity (mismatch here between
- * datasheet and hardware, 0 is active high
- * and 1 is active low...)
- */
- if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
- pclk_pol = 1;
- if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
- hsync_pol = 1;
- if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
- vsync_pol = 1;
-
- ret = ov5640_write_reg(sensor,
- OV5640_REG_POLARITY_CTRL00,
- (pclk_pol << 5) |
- (hsync_pol << 1) |
- vsync_pol);
-
- if (ret)
- return ret;
- }
-
- /*
- * powerdown MIPI TX/RX PHY & disable MIPI
- *
- * MIPI CONTROL 00
- * 4: PWDN PHY TX
- * 3: PWDN PHY RX
- * 2: MIPI enable
- */
- ret = ov5640_write_reg(sensor,
- OV5640_REG_IO_MIPI_CTRL00, on ? 0x18 : 0);
+ ret = ov5640_write_reg(sensor, OV5640_REG_CCIR656_CTRL00,
+ on ? 0x1 : 0x00);
if (ret)
return ret;
- /*
- * enable VSYNC/HREF/PCLK DVP control lines
- * & D[9:6] DVP data lines
- *
- * PAD OUTPUT ENABLE 01
- * - 6: VSYNC output enable
- * - 5: HREF output enable
- * - 4: PCLK output enable
- * - [3:0]: D[9:6] output enable
- */
- ret = ov5640_write_reg(sensor,
- OV5640_REG_PAD_OUTPUT_ENABLE01,
- on ? 0x7f : 0);
- if (ret)
- return ret;
+ return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
+ OV5640_REG_SYS_CTRL0_SW_PWUP :
+ OV5640_REG_SYS_CTRL0_SW_PWDN);
+}
- /*
- * enable D[5:0] DVP data lines
- *
- * PAD OUTPUT ENABLE 02
- * - [7:2]: D[5:0] output enable
- */
- return ov5640_write_reg(sensor,
- OV5640_REG_PAD_OUTPUT_ENABLE02,
- on ? 0xfc : 0);
+static int ov5640_set_stream_dvp(struct ov5640_dev *sensor, bool on)
+{
+ return ov5640_write_reg(sensor, OV5640_REG_SYS_CTRL0, on ?
+ OV5640_REG_SYS_CTRL0_SW_PWUP :
+ OV5640_REG_SYS_CTRL0_SW_PWDN);
}
static int ov5640_set_stream_mipi(struct ov5640_dev *sensor, bool on)
@@ -2001,79 +1936,181 @@ static void ov5640_set_power_off(struct ov5640_dev *sensor)
clk_disable_unprepare(sensor->xclk);
}
-static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
+static int ov5640_set_power_mipi(struct ov5640_dev *sensor, bool on)
{
- int ret = 0;
+ int ret;
+
+ if (!on) {
+ /* Reset MIPI bus settings to their default values. */
+ ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
+ ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x04);
+ ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x00);
+ return 0;
+ }
+
+ /*
+ * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
+ *
+ * 0x300e = 0x40
+ * [7:5] = 010 : 2 data lanes mode (see FIXME note in
+ * "ov5640_set_stream_mipi()")
+ * [4] = 0 : Power up MIPI HS Tx
+ * [3] = 0 : Power up MIPI LS Rx
+ * [2] = 0 : MIPI interface disabled
+ */
+ ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x40);
+ if (ret)
+ return ret;
+
+ /*
+ * Gate clock and set LP11 in 'no packets mode' (idle)
+ *
+ * 0x4800 = 0x24
+ * [5] = 1 : Gate clock when 'no packets'
+ * [2] = 1 : MIPI bus in LP11 when 'no packets'
+ */
+ ret = ov5640_write_reg(sensor, OV5640_REG_MIPI_CTRL00, 0x24);
+ if (ret)
+ return ret;
+
+ /*
+ * Set data lanes and clock in LP11 when 'sleeping'
+ *
+ * 0x3019 = 0x70
+ * [6] = 1 : MIPI data lane 2 in LP11 when 'sleeping'
+ * [5] = 1 : MIPI data lane 1 in LP11 when 'sleeping'
+ * [4] = 1 : MIPI clock lane in LP11 when 'sleeping'
+ */
+ ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT00, 0x70);
+ if (ret)
+ return ret;
+
+ /* Give lanes some time to coax into LP11 state. */
+ usleep_range(500, 1000);
+
+ return 0;
+}
+
+static int ov5640_set_power_dvp(struct ov5640_dev *sensor, bool on)
+{
+ unsigned int flags = sensor->ep.bus.parallel.flags;
+ u8 pclk_pol = 0;
+ u8 hsync_pol = 0;
+ u8 vsync_pol = 0;
+ int ret;
+
+ if (!on) {
+ /* Reset settings to their default values. */
+ ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x58);
+ ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00, 0x20);
+ ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01, 0x00);
+ ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0x00);
+ return 0;
+ }
+
+ /*
+ * Note about parallel port configuration.
+ *
+ * When configured in parallel mode, the OV5640 will
+ * output 10 bits data on DVP data lines [9:0].
+ * If only 8 bits data are wanted, the 8 bits data lines
+ * of the camera interface must be physically connected
+ * on the DVP data lines [9:2].
+ *
+ * Control lines polarity can be configured through
+ * devicetree endpoint control lines properties.
+ * If no endpoint control lines properties are set,
+ * polarity will be as below:
+ * - VSYNC: active high
+ * - HREF: active low
+ * - PCLK: active low
+ */
+ /*
+ * configure parallel port control lines polarity
+ *
+ * POLARITY CTRL0
+ * - [5]: PCLK polarity (0: active low, 1: active high)
+ * - [1]: HREF polarity (0: active low, 1: active high)
+ * - [0]: VSYNC polarity (mismatch here between
+ * datasheet and hardware, 0 is active high
+ * and 1 is active low...)
+ */
+ if (sensor->ep.bus_type == V4L2_MBUS_PARALLEL) {
+ if (flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
+ pclk_pol = 1;
+ if (flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ hsync_pol = 1;
+ if (flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ vsync_pol = 1;
+
+ ret = ov5640_write_reg(sensor, OV5640_REG_POLARITY_CTRL00,
+ (pclk_pol << 5) | (hsync_pol << 1) |
+ vsync_pol);
- if (on) {
- ret = ov5640_set_power_on(sensor);
if (ret)
return ret;
+ }
- ret = ov5640_restore_mode(sensor);
- if (ret)
- goto power_off;
+ /*
+ * powerdown MIPI TX/RX PHY & disable MIPI
+ *
+ * MIPI CONTROL 00
+ * 4: PWDN PHY TX
+ * 3: PWDN PHY RX
+ * 2: MIPI enable
+ */
+ ret = ov5640_write_reg(sensor, OV5640_REG_IO_MIPI_CTRL00, 0x18);
+ if (ret)
+ return ret;
- /* We're done here for DVP bus, while CSI-2 needs setup. */
- if (sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY)
- return 0;
+ /*
+ * enable VSYNC/HREF/PCLK DVP control lines
+ * & D[9:6] DVP data lines
+ *
+ * PAD OUTPUT ENABLE 01
+ * - 6: VSYNC output enable
+ * - 5: HREF output enable
+ * - 4: PCLK output enable
+ * - [3:0]: D[9:6] output enable
+ */
+ ret = ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE01,
+ sensor->ep.bus_type == V4L2_MBUS_PARALLEL ?
+ 0x7f : 0x1f);
+ if (ret)
+ return ret;
- /*
- * Power up MIPI HS Tx and LS Rx; 2 data lanes mode
- *
- * 0x300e = 0x40
- * [7:5] = 010 : 2 data lanes mode (see FIXME note in
- * "ov5640_set_stream_mipi()")
- * [4] = 0 : Power up MIPI HS Tx
- * [3] = 0 : Power up MIPI LS Rx
- * [2] = 0 : MIPI interface disabled
- */
- ret = ov5640_write_reg(sensor,
- OV5640_REG_IO_MIPI_CTRL00, 0x40);
- if (ret)
- goto power_off;
+ /*
+ * enable D[5:0] DVP data lines
+ *
+ * PAD OUTPUT ENABLE 02
+ * - [7:2]: D[5:0] output enable
+ */
+ return ov5640_write_reg(sensor, OV5640_REG_PAD_OUTPUT_ENABLE02, 0xfc);
+}
- /*
- * Gate clock and set LP11 in 'no packets mode' (idle)
- *
- * 0x4800 = 0x24
- * [5] = 1 : Gate clock when 'no packets'
- * [2] = 1 : MIPI bus in LP11 when 'no packets'
- */
- ret = ov5640_write_reg(sensor,
- OV5640_REG_MIPI_CTRL00, 0x24);
+static int ov5640_set_power(struct ov5640_dev *sensor, bool on)
+{
+ int ret = 0;
+
+ if (on) {
+ ret = ov5640_set_power_on(sensor);
if (ret)
- goto power_off;
+ return ret;
- /*
- * Set data lanes and clock in LP11 when 'sleeping'
- *
- * 0x3019 = 0x70
- * [6] = 1 : MIPI data lane 2 in LP11 when 'sleeping'
- * [5] = 1 : MIPI data lane 1 in LP11 when 'sleeping'
- * [4] = 1 : MIPI clock lane in LP11 when 'sleeping'
- */
- ret = ov5640_write_reg(sensor,
- OV5640_REG_PAD_OUTPUT00, 0x70);
+ ret = ov5640_restore_mode(sensor);
if (ret)
goto power_off;
+ }
- /* Give lanes some time to coax into LP11 state. */
- usleep_range(500, 1000);
-
- } else {
- if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY) {
- /* Reset MIPI bus settings to their default values. */
- ov5640_write_reg(sensor,
- OV5640_REG_IO_MIPI_CTRL00, 0x58);
- ov5640_write_reg(sensor,
- OV5640_REG_MIPI_CTRL00, 0x04);
- ov5640_write_reg(sensor,
- OV5640_REG_PAD_OUTPUT00, 0x00);
- }
+ if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
+ ret = ov5640_set_power_mipi(sensor, on);
+ else
+ ret = ov5640_set_power_dvp(sensor, on);
+ if (ret)
+ goto power_off;
+ if (!on)
ov5640_set_power_off(sensor);
- }
return 0;
@@ -2888,6 +2925,8 @@ static int ov5640_s_stream(struct v4l2_subdev *sd, int enable)
if (sensor->ep.bus_type == V4L2_MBUS_CSI2_DPHY)
ret = ov5640_set_stream_mipi(sensor, enable);
+ else if (sensor->ep.bus_type == V4L2_MBUS_BT656)
+ ret = ov5640_set_stream_bt656(sensor, enable);
else
ret = ov5640_set_stream_dvp(sensor, enable);
@@ -3010,7 +3049,7 @@ static int ov5640_probe(struct i2c_client *client)
switch (rotation) {
case 180:
sensor->upside_down = true;
- /* fall through */
+ fallthrough;
case 0:
break;
default:
@@ -3033,6 +3072,13 @@ static int ov5640_probe(struct i2c_client *client)
return ret;
}
+ if (sensor->ep.bus_type != V4L2_MBUS_PARALLEL &&
+ sensor->ep.bus_type != V4L2_MBUS_CSI2_DPHY &&
+ sensor->ep.bus_type != V4L2_MBUS_BT656) {
+ dev_err(dev, "Unsupported bus type %d\n", sensor->ep.bus_type);
+ return -EINVAL;
+ }
+
/* get system clock (xclk) */
sensor->xclk = devm_clk_get(dev, "xclk");
if (IS_ERR(sensor->xclk)) {
diff --git a/drivers/media/i2c/ov5675.c b/drivers/media/i2c/ov5675.c
index 8537cc4ca108..9540ce8918f0 100644
--- a/drivers/media/i2c/ov5675.c
+++ b/drivers/media/i2c/ov5675.c
@@ -666,8 +666,8 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl)
/* Propagate change of current control to all related controls */
if (ctrl->id == V4L2_CID_VBLANK) {
/* Update max exposure while meeting expected vblanking */
- exposure_max = (ov5675->cur_mode->height + ctrl->val -
- OV5675_EXPOSURE_MAX_MARGIN) / 2;
+ exposure_max = ov5675->cur_mode->height + ctrl->val -
+ OV5675_EXPOSURE_MAX_MARGIN;
__v4l2_ctrl_modify_range(ov5675->exposure,
ov5675->exposure->minimum,
exposure_max, ov5675->exposure->step,
@@ -689,7 +689,13 @@ static int ov5675_set_ctrl(struct v4l2_ctrl *ctrl)
break;
case V4L2_CID_EXPOSURE:
- /* 3 least significant bits of expsoure are fractional part */
+ /* 4 least significant bits of expsoure are fractional part
+ * val = val << 4
+ * for ov5675, the unit of exposure is differnt 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.
+ */
ret = ov5675_write_reg(ov5675, OV5675_REG_EXPOSURE,
OV5675_REG_VALUE_24BIT, ctrl->val << 3);
break;
@@ -770,8 +776,7 @@ static int ov5675_init_controls(struct ov5675 *ov5675)
v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops, V4L2_CID_DIGITAL_GAIN,
OV5675_DGTL_GAIN_MIN, OV5675_DGTL_GAIN_MAX,
OV5675_DGTL_GAIN_STEP, OV5675_DGTL_GAIN_DEFAULT);
- exposure_max = (ov5675->cur_mode->vts_def -
- OV5675_EXPOSURE_MAX_MARGIN) / 2;
+ exposure_max = (ov5675->cur_mode->vts_def - OV5675_EXPOSURE_MAX_MARGIN);
ov5675->exposure = v4l2_ctrl_new_std(ctrl_hdlr, &ov5675_ctrl_ops,
V4L2_CID_EXPOSURE,
OV5675_EXPOSURE_MIN, exposure_max,
diff --git a/drivers/media/i2c/ov6650.c b/drivers/media/i2c/ov6650.c
index 91906b94f978..d73f9f540932 100644
--- a/drivers/media/i2c/ov6650.c
+++ b/drivers/media/i2c/ov6650.c
@@ -685,7 +685,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
switch (mf->code) {
case MEDIA_BUS_FMT_Y10_1X10:
mf->code = MEDIA_BUS_FMT_Y8_1X8;
- /* fall through */
+ fallthrough;
case MEDIA_BUS_FMT_Y8_1X8:
case MEDIA_BUS_FMT_YVYU8_2X8:
case MEDIA_BUS_FMT_YUYV8_2X8:
@@ -694,7 +694,7 @@ static int ov6650_set_fmt(struct v4l2_subdev *sd,
break;
default:
mf->code = MEDIA_BUS_FMT_SBGGR8_1X8;
- /* fall through */
+ fallthrough;
case MEDIA_BUS_FMT_SBGGR8_1X8:
break;
}
@@ -921,55 +921,74 @@ static const struct v4l2_subdev_core_ops ov6650_core_ops = {
};
/* Request bus settings on camera side */
-static int ov6650_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int ov6650_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ u8 comj, comf;
+ int ret;
+
+ ret = ov6650_reg_read(client, REG_COMJ, &comj);
+ if (ret)
+ return ret;
- cfg->flags = V4L2_MBUS_MASTER |
- V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_PCLK_SAMPLE_FALLING |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_LOW |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_VSYNC_ACTIVE_LOW |
- V4L2_MBUS_DATA_ACTIVE_HIGH;
+ ret = ov6650_reg_read(client, REG_COMF, &comf);
+ if (ret)
+ return ret;
+
+ cfg->flags = V4L2_MBUS_MASTER | V4L2_MBUS_DATA_ACTIVE_HIGH
+ | ((comj & COMJ_VSYNC_HIGH) ? V4L2_MBUS_VSYNC_ACTIVE_HIGH
+ : V4L2_MBUS_VSYNC_ACTIVE_LOW)
+ | ((comf & COMF_HREF_LOW) ? V4L2_MBUS_HSYNC_ACTIVE_LOW
+ : V4L2_MBUS_HSYNC_ACTIVE_HIGH)
+ | ((comj & COMJ_PCLK_RISING) ? V4L2_MBUS_PCLK_SAMPLE_RISING
+ : V4L2_MBUS_PCLK_SAMPLE_FALLING);
cfg->type = V4L2_MBUS_PARALLEL;
return 0;
}
/* Alter bus settings on camera side */
-static int ov6650_s_mbus_config(struct v4l2_subdev *sd,
- const struct v4l2_mbus_config *cfg)
+static int ov6650_set_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
- int ret;
+ int ret = 0;
if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_RISING)
ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0);
- else
+ else if (cfg->flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)
ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING);
if (ret)
return ret;
if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)
ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0);
- else
+ else if (cfg->flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH)
ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW);
if (ret)
return ret;
if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH)
ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0);
- else
+ else if (cfg->flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)
ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH);
+ if (ret)
+ return ret;
- return ret;
+ /*
+ * Update the configuration to report what is actually applied to
+ * the hardware.
+ */
+ return ov6650_get_mbus_config(sd, pad, cfg);
}
static const struct v4l2_subdev_video_ops ov6650_video_ops = {
.s_stream = ov6650_s_stream,
.g_frame_interval = ov6650_g_frame_interval,
.s_frame_interval = ov6650_s_frame_interval,
- .g_mbus_config = ov6650_g_mbus_config,
- .s_mbus_config = ov6650_s_mbus_config,
};
static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
@@ -978,6 +997,8 @@ static const struct v4l2_subdev_pad_ops ov6650_pad_ops = {
.set_selection = ov6650_set_selection,
.get_fmt = ov6650_get_fmt,
.set_fmt = ov6650_set_fmt,
+ .get_mbus_config = ov6650_get_mbus_config,
+ .set_mbus_config = ov6650_set_mbus_config,
};
static const struct v4l2_subdev_ops ov6650_subdev_ops = {
diff --git a/drivers/media/i2c/ov7740.c b/drivers/media/i2c/ov7740.c
index 732655fe4ba3..5832461c032d 100644
--- a/drivers/media/i2c/ov7740.c
+++ b/drivers/media/i2c/ov7740.c
@@ -1068,13 +1068,6 @@ static int ov7740_probe(struct i2c_client *client)
struct v4l2_subdev *sd;
int ret;
- if (!i2c_check_functionality(client->adapter,
- I2C_FUNC_SMBUS_BYTE_DATA)) {
- dev_err(&client->dev,
- "OV7740: I2C-Adapter doesn't support SMBUS\n");
- return -EIO;
- }
-
ov7740 = devm_kzalloc(&client->dev, sizeof(*ov7740), GFP_KERNEL);
if (!ov7740)
return -ENOMEM;
@@ -1091,7 +1084,7 @@ static int ov7740_probe(struct i2c_client *client)
if (ret)
return ret;
- ov7740->regmap = devm_regmap_init_i2c(client, &ov7740_regmap_config);
+ ov7740->regmap = devm_regmap_init_sccb(client, &ov7740_regmap_config);
if (IS_ERR(ov7740->regmap)) {
ret = PTR_ERR(ov7740->regmap);
dev_err(&client->dev, "Failed to allocate register map: %d\n",
@@ -1100,7 +1093,6 @@ static int ov7740_probe(struct i2c_client *client)
}
sd = &ov7740->subdev;
- client->flags |= I2C_CLIENT_SCCB;
v4l2_i2c_subdev_init(sd, client, &ov7740_subdev_ops);
#ifdef CONFIG_VIDEO_V4L2_SUBDEV_API
diff --git a/drivers/media/i2c/ov8856.c b/drivers/media/i2c/ov8856.c
index 4ca27675cc5a..2f4ceaa80593 100644
--- a/drivers/media/i2c/ov8856.c
+++ b/drivers/media/i2c/ov8856.c
@@ -338,6 +338,209 @@ static const struct ov8856_reg mode_3280x2464_regs[] = {
{0x5e00, 0x00}
};
+static const struct ov8856_reg mode_3264x2448_regs[] = {
+ {0x0103, 0x01},
+ {0x0302, 0x3c},
+ {0x0303, 0x01},
+ {0x031e, 0x0c},
+ {0x3000, 0x20},
+ {0x3003, 0x08},
+ {0x300e, 0x20},
+ {0x3010, 0x00},
+ {0x3015, 0x84},
+ {0x3018, 0x72},
+ {0x3021, 0x23},
+ {0x3033, 0x24},
+ {0x3500, 0x00},
+ {0x3501, 0x9a},
+ {0x3502, 0x20},
+ {0x3503, 0x08},
+ {0x3505, 0x83},
+ {0x3508, 0x01},
+ {0x3509, 0x80},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x350e, 0x04},
+ {0x350f, 0x00},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3600, 0x72},
+ {0x3601, 0x40},
+ {0x3602, 0x30},
+ {0x3610, 0xc5},
+ {0x3611, 0x58},
+ {0x3612, 0x5c},
+ {0x3613, 0xca},
+ {0x3614, 0x60},
+ {0x3628, 0xff},
+ {0x3629, 0xff},
+ {0x362a, 0xff},
+ {0x3633, 0x10},
+ {0x3634, 0x10},
+ {0x3635, 0x10},
+ {0x3636, 0x10},
+ {0x3663, 0x08},
+ {0x3669, 0x34},
+ {0x366d, 0x00},
+ {0x366e, 0x10},
+ {0x3706, 0x86},
+ {0x370b, 0x7e},
+ {0x3714, 0x23},
+ {0x3730, 0x12},
+ {0x3733, 0x10},
+ {0x3764, 0x00},
+ {0x3765, 0x00},
+ {0x3769, 0x62},
+ {0x376a, 0x2a},
+ {0x376b, 0x30},
+ {0x3780, 0x00},
+ {0x3781, 0x24},
+ {0x3782, 0x00},
+ {0x3783, 0x23},
+ {0x3798, 0x2f},
+ {0x37a1, 0x60},
+ {0x37a8, 0x6a},
+ {0x37ab, 0x3f},
+ {0x37c2, 0x04},
+ {0x37c3, 0xf1},
+ {0x37c9, 0x80},
+ {0x37cb, 0x16},
+ {0x37cc, 0x16},
+ {0x37cd, 0x16},
+ {0x37ce, 0x16},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x0c},
+ {0x3804, 0x0c},
+ {0x3805, 0xdf},
+ {0x3806, 0x09},
+ {0x3807, 0xa3},
+ {0x3808, 0x0c},
+ {0x3809, 0xc0},
+ {0x380a, 0x09},
+ {0x380b, 0x90},
+ {0x380c, 0x07},
+ {0x380d, 0x8c},
+ {0x380e, 0x09},
+ {0x380f, 0xb2},
+ {0x3810, 0x00},
+ {0x3811, 0x04},
+ {0x3812, 0x00},
+ {0x3813, 0x02},
+ {0x3814, 0x01},
+ {0x3815, 0x01},
+ {0x3816, 0x00},
+ {0x3817, 0x00},
+ {0x3818, 0x00},
+ {0x3819, 0x10},
+ {0x3820, 0x80},
+ {0x3821, 0x46},
+ {0x382a, 0x01},
+ {0x382b, 0x01},
+ {0x3830, 0x06},
+ {0x3836, 0x02},
+ {0x3862, 0x04},
+ {0x3863, 0x08},
+ {0x3cc0, 0x33},
+ {0x3d85, 0x17},
+ {0x3d8c, 0x73},
+ {0x3d8d, 0xde},
+ {0x4001, 0xe0},
+ {0x4003, 0x40},
+ {0x4008, 0x00},
+ {0x4009, 0x0b},
+ {0x400a, 0x00},
+ {0x400b, 0x84},
+ {0x400f, 0x80},
+ {0x4010, 0xf0},
+ {0x4011, 0xff},
+ {0x4012, 0x02},
+ {0x4013, 0x01},
+ {0x4014, 0x01},
+ {0x4015, 0x01},
+ {0x4042, 0x00},
+ {0x4043, 0x80},
+ {0x4044, 0x00},
+ {0x4045, 0x80},
+ {0x4046, 0x00},
+ {0x4047, 0x80},
+ {0x4048, 0x00},
+ {0x4049, 0x80},
+ {0x4041, 0x03},
+ {0x404c, 0x20},
+ {0x404d, 0x00},
+ {0x404e, 0x20},
+ {0x4203, 0x80},
+ {0x4307, 0x30},
+ {0x4317, 0x00},
+ {0x4502, 0x50},
+ {0x4503, 0x08},
+ {0x4601, 0x80},
+ {0x4800, 0x44},
+ {0x4816, 0x53},
+ {0x481b, 0x50},
+ {0x481f, 0x27},
+ {0x4823, 0x3c},
+ {0x482b, 0x00},
+ {0x4831, 0x66},
+ {0x4837, 0x16},
+ {0x483c, 0x0f},
+ {0x484b, 0x05},
+ {0x5000, 0x77},
+ {0x5001, 0x0a},
+ {0x5003, 0xc8},
+ {0x5004, 0x04},
+ {0x5006, 0x00},
+ {0x5007, 0x00},
+ {0x502e, 0x03},
+ {0x5030, 0x41},
+ {0x5780, 0x14},
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x01},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3},
+ {0x5795, 0x02},
+ {0x5796, 0x20},
+ {0x5797, 0x20},
+ {0x5798, 0xd5},
+ {0x5799, 0xd5},
+ {0x579a, 0x00},
+ {0x579b, 0x50},
+ {0x579c, 0x00},
+ {0x579d, 0x2c},
+ {0x579e, 0x0c},
+ {0x579f, 0x40},
+ {0x57a0, 0x09},
+ {0x57a1, 0x40},
+ {0x59f8, 0x3d},
+ {0x5a08, 0x02},
+ {0x5b00, 0x02},
+ {0x5b01, 0x10},
+ {0x5b02, 0x03},
+ {0x5b03, 0xcf},
+ {0x5b05, 0x6c},
+ {0x5e00, 0x00},
+ {0x5e10, 0xfc}
+};
+
static const struct ov8856_reg mode_1640x1232_regs[] = {
{0x3000, 0x20},
{0x3003, 0x08},
@@ -528,6 +731,209 @@ static const struct ov8856_reg mode_1640x1232_regs[] = {
{0x5e00, 0x00}
};
+static const struct ov8856_reg mode_1632x1224_regs[] = {
+ {0x0103, 0x01},
+ {0x0302, 0x3c},
+ {0x0303, 0x01},
+ {0x031e, 0x0c},
+ {0x3000, 0x20},
+ {0x3003, 0x08},
+ {0x300e, 0x20},
+ {0x3010, 0x00},
+ {0x3015, 0x84},
+ {0x3018, 0x72},
+ {0x3021, 0x23},
+ {0x3033, 0x24},
+ {0x3500, 0x00},
+ {0x3501, 0x4c},
+ {0x3502, 0xe0},
+ {0x3503, 0x08},
+ {0x3505, 0x83},
+ {0x3508, 0x01},
+ {0x3509, 0x80},
+ {0x350c, 0x00},
+ {0x350d, 0x80},
+ {0x350e, 0x04},
+ {0x350f, 0x00},
+ {0x3510, 0x00},
+ {0x3511, 0x02},
+ {0x3512, 0x00},
+ {0x3600, 0x72},
+ {0x3601, 0x40},
+ {0x3602, 0x30},
+ {0x3610, 0xc5},
+ {0x3611, 0x58},
+ {0x3612, 0x5c},
+ {0x3613, 0xca},
+ {0x3614, 0x60},
+ {0x3628, 0xff},
+ {0x3629, 0xff},
+ {0x362a, 0xff},
+ {0x3633, 0x10},
+ {0x3634, 0x10},
+ {0x3635, 0x10},
+ {0x3636, 0x10},
+ {0x3663, 0x08},
+ {0x3669, 0x34},
+ {0x366d, 0x00},
+ {0x366e, 0x08},
+ {0x3706, 0x86},
+ {0x370b, 0x7e},
+ {0x3714, 0x27},
+ {0x3730, 0x12},
+ {0x3733, 0x10},
+ {0x3764, 0x00},
+ {0x3765, 0x00},
+ {0x3769, 0x62},
+ {0x376a, 0x2a},
+ {0x376b, 0x30},
+ {0x3780, 0x00},
+ {0x3781, 0x24},
+ {0x3782, 0x00},
+ {0x3783, 0x23},
+ {0x3798, 0x2f},
+ {0x37a1, 0x60},
+ {0x37a8, 0x6a},
+ {0x37ab, 0x3f},
+ {0x37c2, 0x14},
+ {0x37c3, 0xf1},
+ {0x37c9, 0x80},
+ {0x37cb, 0x16},
+ {0x37cc, 0x16},
+ {0x37cd, 0x16},
+ {0x37ce, 0x16},
+ {0x3800, 0x00},
+ {0x3801, 0x00},
+ {0x3802, 0x00},
+ {0x3803, 0x0c},
+ {0x3804, 0x0c},
+ {0x3805, 0xdf},
+ {0x3806, 0x09},
+ {0x3807, 0xa3},
+ {0x3808, 0x06},
+ {0x3809, 0x60},
+ {0x380a, 0x04},
+ {0x380b, 0xc8},
+ {0x380c, 0x07},
+ {0x380d, 0x8c},
+ {0x380e, 0x09},
+ {0x380f, 0xb2},
+ {0x3810, 0x00},
+ {0x3811, 0x02},
+ {0x3812, 0x00},
+ {0x3813, 0x02},
+ {0x3814, 0x03},
+ {0x3815, 0x01},
+ {0x3816, 0x00},
+ {0x3817, 0x00},
+ {0x3818, 0x00},
+ {0x3819, 0x10},
+ {0x3820, 0x80},
+ {0x3821, 0x47},
+ {0x382a, 0x03},
+ {0x382b, 0x01},
+ {0x3830, 0x06},
+ {0x3836, 0x02},
+ {0x3862, 0x04},
+ {0x3863, 0x08},
+ {0x3cc0, 0x33},
+ {0x3d85, 0x17},
+ {0x3d8c, 0x73},
+ {0x3d8d, 0xde},
+ {0x4001, 0xe0},
+ {0x4003, 0x40},
+ {0x4008, 0x00},
+ {0x4009, 0x05},
+ {0x400a, 0x00},
+ {0x400b, 0x84},
+ {0x400f, 0x80},
+ {0x4010, 0xf0},
+ {0x4011, 0xff},
+ {0x4012, 0x02},
+ {0x4013, 0x01},
+ {0x4014, 0x01},
+ {0x4015, 0x01},
+ {0x4042, 0x00},
+ {0x4043, 0x80},
+ {0x4044, 0x00},
+ {0x4045, 0x80},
+ {0x4046, 0x00},
+ {0x4047, 0x80},
+ {0x4048, 0x00},
+ {0x4049, 0x80},
+ {0x4041, 0x03},
+ {0x404c, 0x20},
+ {0x404d, 0x00},
+ {0x404e, 0x20},
+ {0x4203, 0x80},
+ {0x4307, 0x30},
+ {0x4317, 0x00},
+ {0x4502, 0x50},
+ {0x4503, 0x08},
+ {0x4601, 0x80},
+ {0x4800, 0x44},
+ {0x4816, 0x53},
+ {0x481b, 0x50},
+ {0x481f, 0x27},
+ {0x4823, 0x3c},
+ {0x482b, 0x00},
+ {0x4831, 0x66},
+ {0x4837, 0x16},
+ {0x483c, 0x0f},
+ {0x484b, 0x05},
+ {0x5000, 0x77},
+ {0x5001, 0x0a},
+ {0x5003, 0xc8},
+ {0x5004, 0x04},
+ {0x5006, 0x00},
+ {0x5007, 0x00},
+ {0x502e, 0x03},
+ {0x5030, 0x41},
+ {0x5795, 0x00},
+ {0x5796, 0x10},
+ {0x5797, 0x10},
+ {0x5798, 0x73},
+ {0x5799, 0x73},
+ {0x579a, 0x00},
+ {0x579b, 0x28},
+ {0x579c, 0x00},
+ {0x579d, 0x16},
+ {0x579e, 0x06},
+ {0x579f, 0x20},
+ {0x57a0, 0x04},
+ {0x57a1, 0xa0},
+ {0x5780, 0x14},
+ {0x5781, 0x0f},
+ {0x5782, 0x44},
+ {0x5783, 0x02},
+ {0x5784, 0x01},
+ {0x5785, 0x01},
+ {0x5786, 0x00},
+ {0x5787, 0x04},
+ {0x5788, 0x02},
+ {0x5789, 0x0f},
+ {0x578a, 0xfd},
+ {0x578b, 0xf5},
+ {0x578c, 0xf5},
+ {0x578d, 0x03},
+ {0x578e, 0x08},
+ {0x578f, 0x0c},
+ {0x5790, 0x08},
+ {0x5791, 0x04},
+ {0x5792, 0x00},
+ {0x5793, 0x52},
+ {0x5794, 0xa3},
+ {0x59f8, 0x3d},
+ {0x5a08, 0x02},
+ {0x5b00, 0x02},
+ {0x5b01, 0x10},
+ {0x5b02, 0x03},
+ {0x5b03, 0xcf},
+ {0x5b05, 0x6c},
+ {0x5e00, 0x00},
+ {0x5e10, 0xfc}
+};
+
static const char * const ov8856_test_pattern_menu[] = {
"Disabled",
"Standard Color Bar",
@@ -570,6 +976,18 @@ static const struct ov8856_mode supported_modes[] = {
.link_freq_index = OV8856_LINK_FREQ_720MBPS,
},
{
+ .width = 3264,
+ .height = 2448,
+ .hts = 1932,
+ .vts_def = 2482,
+ .vts_min = 2482,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_3264x2448_regs),
+ .regs = mode_3264x2448_regs,
+ },
+ .link_freq_index = OV8856_LINK_FREQ_720MBPS,
+ },
+ {
.width = 1640,
.height = 1232,
.hts = 3820,
@@ -580,6 +998,18 @@ static const struct ov8856_mode supported_modes[] = {
.regs = mode_1640x1232_regs,
},
.link_freq_index = OV8856_LINK_FREQ_360MBPS,
+ },
+ {
+ .width = 1632,
+ .height = 1224,
+ .hts = 1932,
+ .vts_def = 2482,
+ .vts_min = 2482,
+ .reg_list = {
+ .num_of_regs = ARRAY_SIZE(mode_1632x1224_regs),
+ .regs = mode_1632x1224_regs,
+ },
+ .link_freq_index = OV8856_LINK_FREQ_360MBPS,
}
};
diff --git a/drivers/media/i2c/ov9640.c b/drivers/media/i2c/ov9640.c
index 3a21f51d9325..e2a25240fc85 100644
--- a/drivers/media/i2c/ov9640.c
+++ b/drivers/media/i2c/ov9640.c
@@ -538,7 +538,7 @@ static int ov9640_set_fmt(struct v4l2_subdev *sd,
break;
default:
mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
- /* fall through */
+ fallthrough;
case MEDIA_BUS_FMT_UYVY8_2X8:
mf->colorspace = V4L2_COLORSPACE_JPEG;
break;
@@ -648,8 +648,9 @@ static const struct v4l2_subdev_core_ops ov9640_core_ops = {
};
/* Request bus settings on camera side */
-static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int ov9640_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
cfg->flags = V4L2_MBUS_PCLK_SAMPLE_RISING | V4L2_MBUS_MASTER |
V4L2_MBUS_VSYNC_ACTIVE_HIGH | V4L2_MBUS_HSYNC_ACTIVE_HIGH |
@@ -661,13 +662,13 @@ static int ov9640_g_mbus_config(struct v4l2_subdev *sd,
static const struct v4l2_subdev_video_ops ov9640_video_ops = {
.s_stream = ov9640_s_stream,
- .g_mbus_config = ov9640_g_mbus_config,
};
static const struct v4l2_subdev_pad_ops ov9640_pad_ops = {
.enum_mbus_code = ov9640_enum_mbus_code,
.get_selection = ov9640_get_selection,
.set_fmt = ov9640_set_fmt,
+ .get_mbus_config = ov9640_get_mbus_config,
};
static const struct v4l2_subdev_ops ov9640_subdev_ops = {
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
index 71cf68a95bb2..141ad0ba7f5a 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
+++ b/drivers/media/i2c/s5c73m3/s5c73m3-ctrls.c
@@ -46,7 +46,7 @@ static int s5c73m3_get_af_status(struct s5c73m3 *state, struct v4l2_ctrl *ctrl)
break;
default:
v4l2_info(&state->sensor_sd, "Unknown AF status %#x\n", reg);
- /* Fall through */
+ fallthrough;
case REG_CAF_STATUS_UNFOCUSED:
case REG_AF_STATUS_UNFOCUSED:
case REG_AF_STATUS_INVALID:
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 42584a088273..ec6f22efe19a 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -280,8 +280,7 @@ struct s5k5baf_fw {
struct {
u16 id;
u16 offset;
- } seq[0];
- u16 data[];
+ } seq[];
};
struct s5k5baf {
@@ -563,7 +562,7 @@ static u16 *s5k5baf_fw_get_seq(struct s5k5baf *state, u16 seq_id)
if (fw == NULL)
return NULL;
- data = fw->data + 2 * fw->count;
+ data = &fw->seq[0].id + 2 * fw->count;
for (i = 0; i < fw->count; ++i) {
if (fw->seq[i].id == seq_id)
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 8a9c7de0c056..6fc0680a93d0 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -1721,7 +1721,7 @@ static void smiapp_propagate(struct v4l2_subdev *subdev,
sensor->binning_vertical = 1;
}
}
- /* Fall through */
+ fallthrough;
case V4L2_SEL_TGT_COMPOSE:
*crops[SMIAPP_PAD_SRC] = *comp;
break;
@@ -2120,7 +2120,7 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
&& SMIA_LIM(sensor, SCALING_CAPABILITY)
!= SMIAPP_SCALING_CAPABILITY_NONE)
return 0;
- /* Fall through */
+ fallthrough;
default:
return -EINVAL;
}
@@ -2795,7 +2795,7 @@ static struct smiapp_hwconfig *smiapp_get_hwconfig(struct device *dev)
case 180:
hwcfg->module_board_orient =
SMIAPP_MODULE_BOARD_ORIENT_180;
- /* Fall through */
+ fallthrough;
case 0:
break;
default:
diff --git a/drivers/media/i2c/tc358743.c b/drivers/media/i2c/tc358743.c
index dbbab75f135e..831b5b54fd78 100644
--- a/drivers/media/i2c/tc358743.c
+++ b/drivers/media/i2c/tc358743.c
@@ -919,8 +919,8 @@ static const struct cec_adap_ops tc358743_cec_adap_ops = {
.adap_monitor_all_enable = tc358743_cec_adap_monitor_all_enable,
};
-static void tc358743_cec_isr(struct v4l2_subdev *sd, u16 intstatus,
- bool *handled)
+static void tc358743_cec_handler(struct v4l2_subdev *sd, u16 intstatus,
+ bool *handled)
{
struct tc358743_state *state = to_state(sd);
unsigned int cec_rxint, cec_txint;
@@ -953,7 +953,8 @@ static void tc358743_cec_isr(struct v4l2_subdev *sd, u16 intstatus,
cec_transmit_attempt_done(state->cec_adap,
CEC_TX_STATUS_ERROR);
}
- *handled = true;
+ if (handled)
+ *handled = true;
}
if ((intstatus & MASK_CEC_RINT) &&
(cec_rxint & MASK_CECRIEND)) {
@@ -968,7 +969,8 @@ static void tc358743_cec_isr(struct v4l2_subdev *sd, u16 intstatus,
msg.msg[i] = v & 0xff;
}
cec_received_msg(state->cec_adap, &msg);
- *handled = true;
+ if (handled)
+ *handled = true;
}
i2c_wr16(sd, INTSTATUS,
intstatus & (MASK_CEC_RINT | MASK_CEC_TINT));
@@ -1432,7 +1434,7 @@ static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
#ifdef CONFIG_VIDEO_TC358743_CEC
if (intstatus & (MASK_CEC_RINT | MASK_CEC_TINT)) {
- tc358743_cec_isr(sd, intstatus, handled);
+ tc358743_cec_handler(sd, intstatus, handled);
i2c_wr16(sd, INTSTATUS,
intstatus & (MASK_CEC_RINT | MASK_CEC_TINT));
intstatus &= ~(MASK_CEC_RINT | MASK_CEC_TINT);
@@ -1461,7 +1463,7 @@ static int tc358743_isr(struct v4l2_subdev *sd, u32 status, bool *handled)
static irqreturn_t tc358743_irq_handler(int irq, void *dev_id)
{
struct tc358743_state *state = dev_id;
- bool handled;
+ bool handled = false;
tc358743_isr(&state->sd, 0, &handled);
@@ -1602,8 +1604,9 @@ static int tc358743_dv_timings_cap(struct v4l2_subdev *sd,
return 0;
}
-static int tc358743_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int tc358743_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
struct tc358743_state *state = to_state(sd);
@@ -1836,7 +1839,6 @@ static const struct v4l2_subdev_video_ops tc358743_video_ops = {
.s_dv_timings = tc358743_s_dv_timings,
.g_dv_timings = tc358743_g_dv_timings,
.query_dv_timings = tc358743_query_dv_timings,
- .g_mbus_config = tc358743_g_mbus_config,
.s_stream = tc358743_s_stream,
};
@@ -1848,6 +1850,7 @@ static const struct v4l2_subdev_pad_ops tc358743_pad_ops = {
.set_edid = tc358743_s_edid,
.enum_dv_timings = tc358743_enum_dv_timings,
.dv_timings_cap = tc358743_dv_timings_cap,
+ .get_mbus_config = tc358743_get_mbus_config,
};
static const struct v4l2_subdev_ops tc358743_ops = {
diff --git a/drivers/media/i2c/tda1997x.c b/drivers/media/i2c/tda1997x.c
index 5e68182001ec..a09bf0a39d05 100644
--- a/drivers/media/i2c/tda1997x.c
+++ b/drivers/media/i2c/tda1997x.c
@@ -908,7 +908,7 @@ tda1997x_configure_audout(struct v4l2_subdev *sd, u8 channel_assignment)
{
struct tda1997x_state *state = to_state(sd);
struct tda1997x_platform_data *pdata = &state->pdata;
- bool sp_used_by_fifo = 1;
+ bool sp_used_by_fifo = true;
u8 reg;
if (!pdata->audout_format)
@@ -936,7 +936,7 @@ tda1997x_configure_audout(struct v4l2_subdev *sd, u8 channel_assignment)
break;
case AUDCFG_TYPE_DST:
reg |= AUDCFG_TYPE_DST << AUDCFG_TYPE_SHIFT;
- sp_used_by_fifo = 0;
+ sp_used_by_fifo = false;
break;
case AUDCFG_TYPE_HBR:
reg |= AUDCFG_TYPE_HBR << AUDCFG_TYPE_SHIFT;
@@ -944,7 +944,7 @@ tda1997x_configure_audout(struct v4l2_subdev *sd, u8 channel_assignment)
/* demuxed via AP0:AP3 */
reg |= AUDCFG_HBR_DEMUX << AUDCFG_HBR_SHIFT;
if (pdata->audout_format == AUDFMT_TYPE_SPDIF)
- sp_used_by_fifo = 0;
+ sp_used_by_fifo = false;
} else {
/* straight via AP0 */
reg |= AUDCFG_HBR_STRAIGHT << AUDCFG_HBR_SHIFT;
@@ -2588,7 +2588,7 @@ static int tda1997x_probe(struct i2c_client *client,
case 36:
mbus_codes[i++] = MEDIA_BUS_FMT_RGB121212_1X36;
mbus_codes[i++] = MEDIA_BUS_FMT_YUV12_1X36;
- /* fall-through */
+ fallthrough;
case 24:
mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
break;
@@ -2617,10 +2617,10 @@ static int tda1997x_probe(struct i2c_client *client,
mbus_codes[i++] = MEDIA_BUS_FMT_RGB888_1X24;
mbus_codes[i++] = MEDIA_BUS_FMT_YUV8_1X24;
mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_1X24;
- /* fall through */
+ fallthrough;
case 20:
mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_1X20;
- /* fall through */
+ fallthrough;
case 16:
mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_1X16;
break;
@@ -2633,10 +2633,10 @@ static int tda1997x_probe(struct i2c_client *client,
case 16:
case 12:
mbus_codes[i++] = MEDIA_BUS_FMT_UYVY12_2X12;
- /* fall through */
+ fallthrough;
case 10:
mbus_codes[i++] = MEDIA_BUS_FMT_UYVY10_2X10;
- /* fall through */
+ fallthrough;
case 8:
mbus_codes[i++] = MEDIA_BUS_FMT_UYVY8_2X8;
break;
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 9df575238952..7d9401219a3a 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -293,7 +293,7 @@ static void tvp5150_selmux(struct v4l2_subdev *sd)
switch (decoder->input) {
case TVP5150_COMPOSITE1:
input |= 2;
- /* fall through */
+ fallthrough;
case TVP5150_COMPOSITE0:
break;
case TVP5150_SVIDEO:
@@ -1191,8 +1191,9 @@ static int tvp5150_get_selection(struct v4l2_subdev *sd,
}
}
-static int tvp5150_g_mbus_config(struct v4l2_subdev *sd,
- struct v4l2_mbus_config *cfg)
+static int tvp5150_get_mbus_config(struct v4l2_subdev *sd,
+ unsigned int pad,
+ struct v4l2_mbus_config *cfg)
{
struct tvp5150 *decoder = to_tvp5150(sd);
@@ -1721,7 +1722,6 @@ static const struct v4l2_subdev_video_ops tvp5150_video_ops = {
.querystd = tvp5150_querystd,
.s_stream = tvp5150_s_stream,
.s_routing = tvp5150_s_routing,
- .g_mbus_config = tvp5150_g_mbus_config,
};
static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
@@ -1739,6 +1739,7 @@ static const struct v4l2_subdev_pad_ops tvp5150_pad_ops = {
.get_fmt = tvp5150_fill_fmt,
.get_selection = tvp5150_get_selection,
.set_selection = tvp5150_set_selection,
+ .get_mbus_config = tvp5150_get_mbus_config,
};
static const struct v4l2_subdev_ops tvp5150_ops = {
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index de313b1306da..ada4ec5ef782 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -688,9 +688,11 @@ static int tvp7002_g_register(struct v4l2_subdev *sd,
int ret;
ret = tvp7002_read(sd, reg->reg & 0xff, &val);
+ if (ret < 0)
+ return ret;
reg->val = val;
reg->size = 1;
- return ret;
+ return 0;
}
/*
diff --git a/drivers/media/mc/mc-device.c b/drivers/media/mc/mc-device.c
index da8088351135..9e56d2ad6b94 100644
--- a/drivers/media/mc/mc-device.c
+++ b/drivers/media/mc/mc-device.c
@@ -370,10 +370,11 @@ static long media_device_get_topology(struct media_device *mdev, void *arg)
return ret;
}
-static long media_device_request_alloc(struct media_device *mdev,
- int *alloc_fd)
+static long media_device_request_alloc(struct media_device *mdev, void *arg)
{
#ifdef CONFIG_MEDIA_CONTROLLER_REQUEST_API
+ int *alloc_fd = arg;
+
if (!mdev->ops || !mdev->ops->req_validate || !mdev->ops->req_queue)
return -ENOTTY;
@@ -407,7 +408,7 @@ static long copy_arg_to_user(void __user *uarg, void *karg, unsigned int cmd)
#define MEDIA_IOC_ARG(__cmd, func, fl, from_user, to_user) \
[_IOC_NR(MEDIA_IOC_##__cmd)] = { \
.cmd = MEDIA_IOC_##__cmd, \
- .fn = (long (*)(struct media_device *, void *))func, \
+ .fn = func, \
.flags = fl, \
.arg_from_user = from_user, \
.arg_to_user = to_user, \
diff --git a/drivers/media/pci/bt8xx/bttv-driver.c b/drivers/media/pci/bt8xx/bttv-driver.c
index 9144f795fb93..8824dd0fb331 100644
--- a/drivers/media/pci/bt8xx/bttv-driver.c
+++ b/drivers/media/pci/bt8xx/bttv-driver.c
@@ -2332,7 +2332,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
field = V4L2_FIELD_SEQ_TB;
break;
}
- /* fall through */
+ fallthrough;
default: /* FIELD_ANY case */
height2 = btv->crop[!!fh->do_crop].rect.height >> 1;
field = (f->fmt.pix.height > height2)
@@ -4013,11 +4013,13 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
btv->id = dev->device;
if (pci_enable_device(dev)) {
pr_warn("%d: Can't enable device\n", btv->c.nr);
- return -EIO;
+ result = -EIO;
+ goto free_mem;
}
if (pci_set_dma_mask(dev, DMA_BIT_MASK(32))) {
pr_warn("%d: No suitable DMA available\n", btv->c.nr);
- return -EIO;
+ result = -EIO;
+ goto free_mem;
}
if (!request_mem_region(pci_resource_start(dev,0),
pci_resource_len(dev,0),
@@ -4025,7 +4027,8 @@ static int bttv_probe(struct pci_dev *dev, const struct pci_device_id *pci_id)
pr_warn("%d: can't request iomem (0x%llx)\n",
btv->c.nr,
(unsigned long long)pci_resource_start(dev, 0));
- return -EBUSY;
+ result = -EBUSY;
+ goto free_mem;
}
pci_set_master(dev);
pci_set_command(dev);
@@ -4211,6 +4214,10 @@ fail0:
release_mem_region(pci_resource_start(btv->c.pci,0),
pci_resource_len(btv->c.pci,0));
pci_disable_device(btv->c.pci);
+
+free_mem:
+ bttvs[btv->c.nr] = NULL;
+ kfree(btv);
return result;
}
diff --git a/drivers/media/pci/bt8xx/dvb-bt8xx.c b/drivers/media/pci/bt8xx/dvb-bt8xx.c
index 02ebd43e672e..4cb890b949c3 100644
--- a/drivers/media/pci/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/pci/bt8xx/dvb-bt8xx.c
@@ -39,9 +39,10 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
-static void dvb_bt8xx_task(unsigned long data)
+static void dvb_bt8xx_task(struct tasklet_struct *t)
{
- struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *)data;
+ struct bt878 *bt = from_tasklet(bt, t, tasklet);
+ struct dvb_bt8xx_card *card = dev_get_drvdata(&bt->adapter->dev);
dprintk("%d\n", card->bt->finished_block);
@@ -777,7 +778,7 @@ static int dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type)
goto err_disconnect_frontend;
}
- tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card);
+ tasklet_setup(&card->bt->tasklet, dvb_bt8xx_task);
frontend_init(card, type);
diff --git a/drivers/media/pci/cobalt/cobalt-i2c.c b/drivers/media/pci/cobalt/cobalt-i2c.c
index c374dae78bf7..10c9ee33f73e 100644
--- a/drivers/media/pci/cobalt/cobalt-i2c.c
+++ b/drivers/media/pci/cobalt/cobalt-i2c.c
@@ -118,11 +118,11 @@ static int cobalt_tx_bytes(struct cobalt_i2c_regs __iomem *regs,
iowrite8(data[i], &regs->txr_rxr);
/* Setup command */
- if (i == 0 && start != 0) {
+ if (i == 0 && start) {
/* Write + Start */
cmd = M00018_CR_BITMAP_WR_MSK |
M00018_CR_BITMAP_STA_MSK;
- } else if (i == len - 1 && stop != 0) {
+ } else if (i == len - 1 && stop) {
/* Write + Stop */
cmd = M00018_CR_BITMAP_WR_MSK |
M00018_CR_BITMAP_STO_MSK;
@@ -173,11 +173,11 @@ static int cobalt_rx_bytes(struct cobalt_i2c_regs __iomem *regs,
for (i = 0; i < len; i++) {
/* Setup command */
- if (i == 0 && start != 0) {
+ if (i == 0 && start) {
/* Read + Start */
cmd = M00018_CR_BITMAP_RD_MSK |
M00018_CR_BITMAP_STA_MSK;
- } else if (i == len - 1 && stop != 0) {
+ } else if (i == len - 1 && stop) {
/* Read + Stop */
cmd = M00018_CR_BITMAP_RD_MSK |
M00018_CR_BITMAP_STO_MSK;
diff --git a/drivers/media/pci/cobalt/cobalt-omnitek.c b/drivers/media/pci/cobalt/cobalt-omnitek.c
index 4c137453e679..01b82a2e8d33 100644
--- a/drivers/media/pci/cobalt/cobalt-omnitek.c
+++ b/drivers/media/pci/cobalt/cobalt-omnitek.c
@@ -116,7 +116,7 @@ void omni_sg_dma_abort_channel(struct cobalt_stream *s)
{
struct cobalt *cobalt = s->cobalt;
- if (is_dma_done(s) == false)
+ if (!is_dma_done(s))
iowrite32(ABORT, CS_REG(s->dma_channel));
}
diff --git a/drivers/media/pci/cx23885/cx23885-alsa.c b/drivers/media/pci/cx23885/cx23885-alsa.c
index df44ed7393a0..13689c5dd47f 100644
--- a/drivers/media/pci/cx23885/cx23885-alsa.c
+++ b/drivers/media/pci/cx23885/cx23885-alsa.c
@@ -68,7 +68,8 @@ MODULE_PARM_DESC(audio_debug, "enable debug messages [analog audio]");
#define AUD_INT_MCHG_IRQ (1 << 21)
#define GP_COUNT_CONTROL_RESET 0x3
-static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages)
+static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip,
+ unsigned long nr_pages)
{
struct cx23885_audio_buffer *buf = chip->buf;
struct page *pg;
@@ -76,11 +77,11 @@ static int cx23885_alsa_dma_init(struct cx23885_audio_dev *chip, int nr_pages)
buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
if (NULL == buf->vaddr) {
- dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
+ dprintk(1, "vmalloc_32(%lu pages) failed\n", nr_pages);
return -ENOMEM;
}
- dprintk(1, "vmalloc is at addr %p, size=%d\n",
+ dprintk(1, "vmalloc is at addr %p, size=%lu\n",
buf->vaddr, nr_pages << PAGE_SHIFT);
memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
@@ -113,7 +114,7 @@ static int cx23885_alsa_dma_map(struct cx23885_audio_dev *dev)
struct cx23885_audio_buffer *buf = dev->buf;
buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,
- buf->nr_pages, PCI_DMA_FROMDEVICE);
+ buf->nr_pages, DMA_FROM_DEVICE);
if (0 == buf->sglen) {
pr_warn("%s: cx23885_alsa_map_sg failed\n", __func__);
@@ -129,7 +130,7 @@ static int cx23885_alsa_dma_unmap(struct cx23885_audio_dev *dev)
if (!buf->sglen)
return 0;
- dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE);
+ dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->nr_pages, DMA_FROM_DEVICE);
buf->sglen = 0;
return 0;
}
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 440d108b7ddd..a380e0920a21 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -637,7 +637,7 @@ static int vidioc_querycap(struct file *file, void *priv,
sprintf(cap->bus_info, "PCIe:%s", pci_name(dev->pci));
cap->capabilities = V4L2_CAP_READWRITE | V4L2_CAP_STREAMING |
V4L2_CAP_AUDIO | V4L2_CAP_VBI_CAPTURE |
- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_DEVICE_CAPS;
switch (dev->board) { /* i2c device tuners */
case CX23885_BOARD_HAUPPAUGE_HVR1265_K4:
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index c472498e57c4..349462ee2c48 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -325,8 +325,8 @@ struct cx23885_audio_buffer {
struct cx23885_riscmem risc;
void *vaddr;
struct scatterlist *sglist;
- int sglen;
- int nr_pages;
+ int sglen;
+ unsigned long nr_pages;
};
struct cx23885_audio_dev {
diff --git a/drivers/media/pci/cx23885/cx23888-ir.c b/drivers/media/pci/cx23885/cx23888-ir.c
index ad7f8ccad526..ddfd2eb37484 100644
--- a/drivers/media/pci/cx23885/cx23888-ir.c
+++ b/drivers/media/pci/cx23885/cx23888-ir.c
@@ -663,7 +663,7 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
}
v = (unsigned) pulse_width_count_to_ns(
- (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
+ (u16)(p->hw_fifo_data & FIFO_RXTX), divider) / 1000;
if (v > IR_MAX_DURATION)
v = IR_MAX_DURATION;
diff --git a/drivers/media/pci/cx25821/cx25821-alsa.c b/drivers/media/pci/cx25821/cx25821-alsa.c
index 301616426d8a..608fbaf0f659 100644
--- a/drivers/media/pci/cx25821/cx25821-alsa.c
+++ b/drivers/media/pci/cx25821/cx25821-alsa.c
@@ -53,8 +53,8 @@ struct cx25821_audio_buffer {
struct cx25821_riscmem risc;
void *vaddr;
struct scatterlist *sglist;
- int sglen;
- int nr_pages;
+ int sglen;
+ unsigned long nr_pages;
};
struct cx25821_audio_dev {
@@ -131,7 +131,8 @@ MODULE_PARM_DESC(debug, "enable debug messages");
#define PCI_MSK_AUD_EXT (1 << 4)
#define PCI_MSK_AUD_INT (1 << 3)
-static int cx25821_alsa_dma_init(struct cx25821_audio_dev *chip, int nr_pages)
+static int cx25821_alsa_dma_init(struct cx25821_audio_dev *chip,
+ unsigned long nr_pages)
{
struct cx25821_audio_buffer *buf = chip->buf;
struct page *pg;
@@ -139,11 +140,11 @@ static int cx25821_alsa_dma_init(struct cx25821_audio_dev *chip, int nr_pages)
buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
if (NULL == buf->vaddr) {
- dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
+ dprintk(1, "vmalloc_32(%lu pages) failed\n", nr_pages);
return -ENOMEM;
}
- dprintk(1, "vmalloc is at addr 0x%p, size=%d\n",
+ dprintk(1, "vmalloc is at addr 0x%p, size=%lu\n",
buf->vaddr,
nr_pages << PAGE_SHIFT);
@@ -177,7 +178,7 @@ static int cx25821_alsa_dma_map(struct cx25821_audio_dev *dev)
struct cx25821_audio_buffer *buf = dev->buf;
buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,
- buf->nr_pages, PCI_DMA_FROMDEVICE);
+ buf->nr_pages, DMA_FROM_DEVICE);
if (0 == buf->sglen) {
pr_warn("%s: cx25821_alsa_map_sg failed\n", __func__);
@@ -193,7 +194,7 @@ static int cx25821_alsa_dma_unmap(struct cx25821_audio_dev *dev)
if (!buf->sglen)
return 0;
- dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE);
+ dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->nr_pages, DMA_FROM_DEVICE);
buf->sglen = 0;
return 0;
}
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
index 7d7aceecc985..95e0cbb1277d 100644
--- a/drivers/media/pci/cx88/cx88-alsa.c
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -42,12 +42,12 @@
*/
struct cx88_audio_buffer {
- unsigned int bpl;
- struct cx88_riscmem risc;
+ unsigned int bpl;
+ struct cx88_riscmem risc;
void *vaddr;
struct scatterlist *sglist;
int sglen;
- int nr_pages;
+ unsigned long nr_pages;
};
struct cx88_audio_dev {
@@ -271,7 +271,8 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
-static int cx88_alsa_dma_init(struct cx88_audio_dev *chip, int nr_pages)
+static int cx88_alsa_dma_init(struct cx88_audio_dev *chip,
+ unsigned long nr_pages)
{
struct cx88_audio_buffer *buf = chip->buf;
struct page *pg;
@@ -279,11 +280,11 @@ static int cx88_alsa_dma_init(struct cx88_audio_dev *chip, int nr_pages)
buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
if (!buf->vaddr) {
- dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
+ dprintk(1, "vmalloc_32(%lu pages) failed\n", nr_pages);
return -ENOMEM;
}
- dprintk(1, "vmalloc is at addr %p, size=%d\n",
+ dprintk(1, "vmalloc is at addr %p, size=%lu\n",
buf->vaddr, nr_pages << PAGE_SHIFT);
memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
@@ -316,7 +317,7 @@ static int cx88_alsa_dma_map(struct cx88_audio_dev *dev)
struct cx88_audio_buffer *buf = dev->buf;
buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,
- buf->nr_pages, PCI_DMA_FROMDEVICE);
+ buf->nr_pages, DMA_FROM_DEVICE);
if (buf->sglen == 0) {
pr_warn("%s: cx88_alsa_map_sg failed\n", __func__);
@@ -332,8 +333,8 @@ static int cx88_alsa_dma_unmap(struct cx88_audio_dev *dev)
if (!buf->sglen)
return 0;
- dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen,
- PCI_DMA_FROMDEVICE);
+ dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->nr_pages,
+ DMA_FROM_DEVICE);
buf->sglen = 0;
return 0;
}
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index 9fa388626bae..8e224fc0474d 100644
--- a/drivers/media/pci/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -3499,7 +3499,7 @@ static void cx88_card_setup(struct cx88_core *core)
cx_clear(MO_GP0_IO, 0x00000040);
msleep(1000);
cx_set(MO_GP0_IO, 0x00004040);
- /* FALLTHROUGH */
+ fallthrough;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1:
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_HYBRID:
diff --git a/drivers/media/pci/cx88/cx88-input.c b/drivers/media/pci/cx88/cx88-input.c
index 7e0fed9cd200..ce0ef0b8186f 100644
--- a/drivers/media/pci/cx88/cx88-input.c
+++ b/drivers/media/pci/cx88/cx88-input.c
@@ -479,7 +479,7 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
dev->scancode_mask = hardware_mask;
if (ir->sampling) {
- dev->timeout = 10 * 1000 * 1000; /* 10 ms */
+ dev->timeout = MS_TO_US(10); /* 10 ms */
} else {
dev->driver_type = RC_DRIVER_SCANCODE;
dev->allowed_protocols = rc_proto;
@@ -544,7 +544,7 @@ void cx88_ir_irq(struct cx88_core *core)
for (todo = 32; todo > 0; todo -= bits) {
ev.pulse = samples & 0x80000000 ? false : true;
bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
- ev.duration = (bits * (NSEC_PER_SEC / 1000)) / ir_samplerate;
+ ev.duration = (bits * (USEC_PER_SEC / 1000)) / ir_samplerate;
ir_raw_event_store_with_filter(ir->dev, &ev);
samples <<= bits;
}
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index e7fd7516787c..8cffdacf6007 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -1385,7 +1385,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
request_module("rtc-isl1208");
core->i2c_rtc = i2c_new_client_device(&core->i2c_adap, &rtc_info);
}
- /* fall-through */
+ fallthrough;
case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
request_module("ir-kbd-i2c");
}
diff --git a/drivers/media/pci/dt3155/dt3155.c b/drivers/media/pci/dt3155/dt3155.c
index ef8d5c9cfffe..961f844de99c 100644
--- a/drivers/media/pci/dt3155/dt3155.c
+++ b/drivers/media/pci/dt3155/dt3155.c
@@ -575,9 +575,8 @@ static void dt3155_remove(struct pci_dev *pdev)
struct dt3155_priv *pd = container_of(v4l2_dev, struct dt3155_priv,
v4l2_dev);
- video_unregister_device(&pd->vdev);
+ vb2_video_unregister_device(&pd->vdev);
free_irq(pd->pdev->irq, pd);
- vb2_queue_release(&pd->vidq);
v4l2_device_unregister(&pd->v4l2_dev);
pci_iounmap(pdev, pd->regs);
pci_release_region(pdev, 0);
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.c b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
index 92f5eadf2c99..4e598e937dfe 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.c
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.c
@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/*
- * Copyright (C) 2017 Intel Corporation
+ * Copyright (C) 2017,2020 Intel Corporation
*
* Based partially on Intel IPU4 driver written by
* Sakari Ailus <sakari.ailus@linux.intel.com>
@@ -9,13 +9,14 @@
* Jouni Ukkonen <jouni.ukkonen@intel.com>
* Antti Laakso <antti.laakso@intel.com>
* et al.
- *
*/
#include <linux/delay.h>
#include <linux/interrupt.h>
+#include <linux/iopoll.h>
#include <linux/module.h>
#include <linux/pci.h>
+#include <linux/pfn.h>
#include <linux/pm_runtime.h>
#include <linux/property.h>
#include <linux/vmalloc.h>
@@ -96,12 +97,12 @@ static inline u32 cio2_bytesperline(const unsigned int width)
static void cio2_fbpt_exit_dummy(struct cio2_device *cio2)
{
if (cio2->dummy_lop) {
- dma_free_coherent(&cio2->pci_dev->dev, CIO2_PAGE_SIZE,
+ dma_free_coherent(&cio2->pci_dev->dev, PAGE_SIZE,
cio2->dummy_lop, cio2->dummy_lop_bus_addr);
cio2->dummy_lop = NULL;
}
if (cio2->dummy_page) {
- dma_free_coherent(&cio2->pci_dev->dev, CIO2_PAGE_SIZE,
+ dma_free_coherent(&cio2->pci_dev->dev, PAGE_SIZE,
cio2->dummy_page, cio2->dummy_page_bus_addr);
cio2->dummy_page = NULL;
}
@@ -111,12 +112,10 @@ static int cio2_fbpt_init_dummy(struct cio2_device *cio2)
{
unsigned int i;
- cio2->dummy_page = dma_alloc_coherent(&cio2->pci_dev->dev,
- CIO2_PAGE_SIZE,
+ cio2->dummy_page = dma_alloc_coherent(&cio2->pci_dev->dev, PAGE_SIZE,
&cio2->dummy_page_bus_addr,
GFP_KERNEL);
- cio2->dummy_lop = dma_alloc_coherent(&cio2->pci_dev->dev,
- CIO2_PAGE_SIZE,
+ cio2->dummy_lop = dma_alloc_coherent(&cio2->pci_dev->dev, PAGE_SIZE,
&cio2->dummy_lop_bus_addr,
GFP_KERNEL);
if (!cio2->dummy_page || !cio2->dummy_lop) {
@@ -127,8 +126,8 @@ static int cio2_fbpt_init_dummy(struct cio2_device *cio2)
* List of Pointers(LOP) contains 1024x32b pointers to 4KB page each
* Initialize each entry to dummy_page bus base address.
*/
- for (i = 0; i < CIO2_PAGE_SIZE / sizeof(*cio2->dummy_lop); i++)
- cio2->dummy_lop[i] = cio2->dummy_page_bus_addr >> PAGE_SHIFT;
+ for (i = 0; i < CIO2_LOP_ENTRIES; i++)
+ cio2->dummy_lop[i] = PFN_DOWN(cio2->dummy_page_bus_addr);
return 0;
}
@@ -160,12 +159,11 @@ static void cio2_fbpt_entry_init_dummy(struct cio2_device *cio2,
unsigned int i;
entry[0].first_entry.first_page_offset = 0;
- entry[1].second_entry.num_of_pages =
- CIO2_PAGE_SIZE / sizeof(u32) * CIO2_MAX_LOPS;
- entry[1].second_entry.last_page_available_bytes = CIO2_PAGE_SIZE - 1;
+ entry[1].second_entry.num_of_pages = CIO2_LOP_ENTRIES * CIO2_MAX_LOPS;
+ entry[1].second_entry.last_page_available_bytes = PAGE_SIZE - 1;
for (i = 0; i < CIO2_MAX_LOPS; i++)
- entry[i].lop_page_addr = cio2->dummy_lop_bus_addr >> PAGE_SHIFT;
+ entry[i].lop_page_addr = PFN_DOWN(cio2->dummy_lop_bus_addr);
cio2_fbpt_entry_enable(cio2, entry);
}
@@ -182,26 +180,24 @@ static void cio2_fbpt_entry_init_buf(struct cio2_device *cio2,
entry[0].first_entry.first_page_offset = b->offset;
remaining = length + entry[0].first_entry.first_page_offset;
- entry[1].second_entry.num_of_pages =
- DIV_ROUND_UP(remaining, CIO2_PAGE_SIZE);
+ entry[1].second_entry.num_of_pages = PFN_UP(remaining);
/*
* last_page_available_bytes has the offset of the last byte in the
* last page which is still accessible by DMA. DMA cannot access
* beyond this point. Valid range for this is from 0 to 4095.
* 0 indicates 1st byte in the page is DMA accessible.
- * 4095 (CIO2_PAGE_SIZE - 1) means every single byte in the last page
+ * 4095 (PAGE_SIZE - 1) means every single byte in the last page
* is available for DMA transfer.
*/
entry[1].second_entry.last_page_available_bytes =
(remaining & ~PAGE_MASK) ?
- (remaining & ~PAGE_MASK) - 1 :
- CIO2_PAGE_SIZE - 1;
+ (remaining & ~PAGE_MASK) - 1 : PAGE_SIZE - 1;
/* Fill FBPT */
remaining = length;
i = 0;
while (remaining > 0) {
- entry->lop_page_addr = b->lop_bus_addr[i] >> PAGE_SHIFT;
- remaining -= CIO2_PAGE_SIZE / sizeof(u32) * CIO2_PAGE_SIZE;
+ entry->lop_page_addr = PFN_DOWN(b->lop_bus_addr[i]);
+ remaining -= CIO2_LOP_ENTRIES * PAGE_SIZE;
entry++;
i++;
}
@@ -209,7 +205,7 @@ static void cio2_fbpt_entry_init_buf(struct cio2_device *cio2,
/*
* The first not meaningful FBPT entry should point to a valid LOP
*/
- entry->lop_page_addr = cio2->dummy_lop_bus_addr >> PAGE_SHIFT;
+ entry->lop_page_addr = PFN_DOWN(cio2->dummy_lop_bus_addr);
cio2_fbpt_entry_enable(cio2, entry);
}
@@ -295,7 +291,7 @@ static int cio2_csi2_calc_timing(struct cio2_device *cio2, struct cio2_queue *q,
struct cio2_csi2_timing *timing)
{
struct device *dev = &cio2->pci_dev->dev;
- struct v4l2_querymenu qm = {.id = V4L2_CID_LINK_FREQ, };
+ struct v4l2_querymenu qm = { .id = V4L2_CID_LINK_FREQ };
struct v4l2_ctrl *link_freq;
s64 freq;
int r;
@@ -475,8 +471,7 @@ static int cio2_hw_init(struct cio2_device *cio2, struct cio2_queue *q)
}
/* Enable DMA */
- writel(q->fbpt_bus_addr >> PAGE_SHIFT,
- base + CIO2_REG_CDMABA(CIO2_DMA_CHAN));
+ writel(PFN_DOWN(q->fbpt_bus_addr), base + CIO2_REG_CDMABA(CIO2_DMA_CHAN));
writel(num_buffers1 << CIO2_CDMAC0_FBPT_LEN_SHIFT |
FBPT_WIDTH << CIO2_CDMAC0_FBPT_WIDTH_SHIFT |
@@ -512,8 +507,10 @@ static int cio2_hw_init(struct cio2_device *cio2, struct cio2_queue *q)
static void cio2_hw_exit(struct cio2_device *cio2, struct cio2_queue *q)
{
- void __iomem *base = cio2->base;
- unsigned int i, maxloops = 1000;
+ void __iomem *const base = cio2->base;
+ unsigned int i;
+ u32 value;
+ int ret;
/* Disable CSI receiver and MIPI backend devices */
writel(0, q->csi_rx_base + CIO2_REG_IRQCTRL_MASK);
@@ -523,13 +520,10 @@ static void cio2_hw_exit(struct cio2_device *cio2, struct cio2_queue *q)
/* Halt DMA */
writel(0, base + CIO2_REG_CDMAC0(CIO2_DMA_CHAN));
- do {
- if (readl(base + CIO2_REG_CDMAC0(CIO2_DMA_CHAN)) &
- CIO2_CDMAC0_DMA_HALTED)
- break;
- usleep_range(1000, 2000);
- } while (--maxloops);
- if (!maxloops)
+ ret = readl_poll_timeout(base + CIO2_REG_CDMAC0(CIO2_DMA_CHAN),
+ value, value & CIO2_CDMAC0_DMA_HALTED,
+ 4000, 2000000);
+ if (ret)
dev_err(&cio2->pci_dev->dev,
"DMA %i can not be halted\n", CIO2_DMA_CHAN);
@@ -545,7 +539,7 @@ static void cio2_buffer_done(struct cio2_device *cio2, unsigned int dma_chan)
{
struct device *dev = &cio2->pci_dev->dev;
struct cio2_queue *q = cio2->cur_queue;
- int buffers_found = 0;
+ struct cio2_fbpt_entry *entry;
u64 ns = ktime_get_ns();
if (dma_chan >= CIO2_QUEUES) {
@@ -553,15 +547,18 @@ static void cio2_buffer_done(struct cio2_device *cio2, unsigned int dma_chan)
return;
}
+ entry = &q->fbpt[q->bufs_first * CIO2_MAX_LOPS];
+ if (entry->first_entry.ctrl & CIO2_FBPT_CTRL_VALID) {
+ dev_warn(&cio2->pci_dev->dev,
+ "no ready buffers found on DMA channel %u\n",
+ dma_chan);
+ return;
+ }
+
/* Find out which buffer(s) are ready */
do {
- struct cio2_fbpt_entry *const entry =
- &q->fbpt[q->bufs_first * CIO2_MAX_LOPS];
struct cio2_buffer *b;
- if (entry->first_entry.ctrl & CIO2_FBPT_CTRL_VALID)
- break;
-
b = q->bufs[q->bufs_first];
if (b) {
unsigned int bytes = entry[1].second_entry.num_of_bytes;
@@ -583,13 +580,8 @@ static void cio2_buffer_done(struct cio2_device *cio2, unsigned int dma_chan)
atomic_inc(&q->frame_sequence);
cio2_fbpt_entry_init_dummy(cio2, entry);
q->bufs_first = (q->bufs_first + 1) % CIO2_MAX_BUFFERS;
- buffers_found++;
- } while (1);
-
- if (buffers_found == 0)
- dev_warn(&cio2->pci_dev->dev,
- "no ready buffers found on DMA channel %u\n",
- dma_chan);
+ entry = &q->fbpt[q->bufs_first * CIO2_MAX_LOPS];
+ } while (!(entry->first_entry.ctrl & CIO2_FBPT_CTRL_VALID));
}
static void cio2_queue_event_sof(struct cio2_device *cio2, struct cio2_queue *q)
@@ -841,13 +833,11 @@ static int cio2_vb2_buf_init(struct vb2_buffer *vb)
struct device *dev = &cio2->pci_dev->dev;
struct cio2_buffer *b =
container_of(vb, struct cio2_buffer, vbb.vb2_buf);
- static const unsigned int entries_per_page =
- CIO2_PAGE_SIZE / sizeof(u32);
- unsigned int pages = DIV_ROUND_UP(vb->planes[0].length, CIO2_PAGE_SIZE);
- unsigned int lops = DIV_ROUND_UP(pages + 1, entries_per_page);
+ unsigned int pages = PFN_UP(vb->planes[0].length);
+ unsigned int lops = DIV_ROUND_UP(pages + 1, CIO2_LOP_ENTRIES);
struct sg_table *sg;
struct sg_dma_page_iter sg_iter;
- int i, j;
+ unsigned int i, j;
if (lops <= 0 || lops > CIO2_MAX_LOPS) {
dev_err(dev, "%s: bad buffer size (%i)\n", __func__,
@@ -858,7 +848,7 @@ static int cio2_vb2_buf_init(struct vb2_buffer *vb)
memset(b->lop, 0, sizeof(b->lop));
/* Allocate LOP table */
for (i = 0; i < lops; i++) {
- b->lop[i] = dma_alloc_coherent(dev, CIO2_PAGE_SIZE,
+ b->lop[i] = dma_alloc_coherent(dev, PAGE_SIZE,
&b->lop_bus_addr[i], GFP_KERNEL);
if (!b->lop[i])
goto fail;
@@ -873,23 +863,22 @@ static int cio2_vb2_buf_init(struct vb2_buffer *vb)
b->offset = sg->sgl->offset;
i = j = 0;
- for_each_sg_dma_page (sg->sgl, &sg_iter, sg->nents, 0) {
+ for_each_sg_dma_page(sg->sgl, &sg_iter, sg->nents, 0) {
if (!pages--)
break;
- b->lop[i][j] = sg_page_iter_dma_address(&sg_iter) >> PAGE_SHIFT;
+ b->lop[i][j] = PFN_DOWN(sg_page_iter_dma_address(&sg_iter));
j++;
- if (j == entries_per_page) {
+ if (j == CIO2_LOP_ENTRIES) {
i++;
j = 0;
}
}
- b->lop[i][j] = cio2->dummy_page_bus_addr >> PAGE_SHIFT;
+ b->lop[i][j] = PFN_DOWN(cio2->dummy_page_bus_addr);
return 0;
fail:
- for (i--; i >= 0; i--)
- dma_free_coherent(dev, CIO2_PAGE_SIZE,
- b->lop[i], b->lop_bus_addr[i]);
+ while (i--)
+ dma_free_coherent(dev, PAGE_SIZE, b->lop[i], b->lop_bus_addr[i]);
return -ENOMEM;
}
@@ -979,7 +968,7 @@ static void cio2_vb2_buf_cleanup(struct vb2_buffer *vb)
/* Free LOP table */
for (i = 0; i < CIO2_MAX_LOPS; i++) {
if (b->lop[i])
- dma_free_coherent(&cio2->pci_dev->dev, CIO2_PAGE_SIZE,
+ dma_free_coherent(&cio2->pci_dev->dev, PAGE_SIZE,
b->lop[i], b->lop_bus_addr[i]);
}
}
@@ -1633,7 +1622,7 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q)
if (r) {
dev_err(&cio2->pci_dev->dev,
"failed to initialize videobuf2 queue (%d)\n", r);
- goto fail_vbq;
+ goto fail_subdev;
}
/* Initialize vdev */
@@ -1664,10 +1653,8 @@ static int cio2_queue_init(struct cio2_device *cio2, struct cio2_queue *q)
return 0;
fail_link:
- video_unregister_device(&q->vdev);
+ vb2_video_unregister_device(&q->vdev);
fail_vdev:
- vb2_queue_release(vbq);
-fail_vbq:
v4l2_device_unregister_subdev(subdev);
fail_subdev:
media_entity_cleanup(&vdev->entity);
@@ -1683,9 +1670,8 @@ fail_fbpt:
static void cio2_queue_exit(struct cio2_device *cio2, struct cio2_queue *q)
{
- video_unregister_device(&q->vdev);
+ vb2_video_unregister_device(&q->vdev);
media_entity_cleanup(&q->vdev.entity);
- vb2_queue_release(&q->vbq);
v4l2_device_unregister_subdev(&q->subdev);
media_entity_cleanup(&q->subdev.entity);
cio2_fbpt_exit(q, &cio2->pci_dev->dev);
@@ -1721,29 +1707,10 @@ static void cio2_queues_exit(struct cio2_device *cio2)
/**************** PCI interface ****************/
-static int cio2_pci_config_setup(struct pci_dev *dev)
-{
- u16 pci_command;
- int r = pci_enable_msi(dev);
-
- if (r) {
- dev_err(&dev->dev, "failed to enable MSI (%d)\n", r);
- return r;
- }
-
- pci_read_config_word(dev, PCI_COMMAND, &pci_command);
- pci_command |= PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
- PCI_COMMAND_INTX_DISABLE;
- pci_write_config_word(dev, PCI_COMMAND, pci_command);
-
- return 0;
-}
-
static int cio2_pci_probe(struct pci_dev *pci_dev,
const struct pci_device_id *id)
{
struct cio2_device *cio2;
- void __iomem *const *iomap;
int r;
cio2 = devm_kzalloc(&pci_dev->dev, sizeof(*cio2), GFP_KERNEL);
@@ -1766,13 +1733,7 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,
return -ENODEV;
}
- iomap = pcim_iomap_table(pci_dev);
- if (!iomap) {
- dev_err(&pci_dev->dev, "failed to iomap table\n");
- return -ENODEV;
- }
-
- cio2->base = iomap[CIO2_PCI_BAR];
+ cio2->base = pcim_iomap_table(pci_dev)[CIO2_PCI_BAR];
pci_set_drvdata(pci_dev, cio2);
@@ -1784,9 +1745,11 @@ static int cio2_pci_probe(struct pci_dev *pci_dev,
return -ENODEV;
}
- r = cio2_pci_config_setup(pci_dev);
- if (r)
- return -ENODEV;
+ r = pci_enable_msi(pci_dev);
+ if (r) {
+ dev_err(&pci_dev->dev, "failed to enable MSI (%d)\n", r);
+ return r;
+ }
r = cio2_fbpt_init_dummy(cio2);
if (r)
@@ -2012,8 +1975,8 @@ static int __maybe_unused cio2_suspend(struct device *dev)
static int __maybe_unused cio2_resume(struct device *dev)
{
struct cio2_device *cio2 = dev_get_drvdata(dev);
- int r = 0;
struct cio2_queue *q = cio2->cur_queue;
+ int r;
dev_dbg(dev, "cio2 resume\n");
if (!cio2->streaming)
@@ -2040,7 +2003,7 @@ static const struct dev_pm_ops cio2_pm_ops = {
static const struct pci_device_id cio2_pci_id_table[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, CIO2_PCI_ID) },
- { 0 }
+ { }
};
MODULE_DEVICE_TABLE(pci, cio2_pci_id_table);
diff --git a/drivers/media/pci/intel/ipu3/ipu3-cio2.h b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
index 7caab9b8c2b9..549b08f88f0c 100644
--- a/drivers/media/pci/intel/ipu3/ipu3-cio2.h
+++ b/drivers/media/pci/intel/ipu3/ipu3-cio2.h
@@ -4,6 +4,8 @@
#ifndef __IPU3_CIO2_H
#define __IPU3_CIO2_H
+#include <linux/types.h>
+
#define CIO2_NAME "ipu3-cio2"
#define CIO2_DEVICE_NAME "Intel IPU3 CIO2"
#define CIO2_ENTITY_NAME "ipu3-csi2"
@@ -17,6 +19,7 @@
/* 32MB = 8xFBPT_entry */
#define CIO2_MAX_LOPS 8
#define CIO2_MAX_BUFFERS (PAGE_SIZE / 16 / CIO2_MAX_LOPS)
+#define CIO2_LOP_ENTRIES (PAGE_SIZE / sizeof(u32))
#define CIO2_PAD_SINK 0
#define CIO2_PAD_SOURCE 1
@@ -389,7 +392,6 @@ struct cio2_device {
sizeof(struct cio2_fbpt_entry))
#define CIO2_FBPT_SUBENTRY_UNIT 4
-#define CIO2_PAGE_SIZE 4096
/* cio2 fbpt first_entry ctrl status */
#define CIO2_FBPT_CTRL_VALID BIT(0)
diff --git a/drivers/media/pci/mantis/mantis_dma.c b/drivers/media/pci/mantis/mantis_dma.c
index affc5977387f..4df571ff272b 100644
--- a/drivers/media/pci/mantis/mantis_dma.c
+++ b/drivers/media/pci/mantis/mantis_dma.c
@@ -200,9 +200,9 @@ void mantis_dma_stop(struct mantis_pci *mantis)
}
-void mantis_dma_xfer(unsigned long data)
+void mantis_dma_xfer(struct tasklet_struct *t)
{
- struct mantis_pci *mantis = (struct mantis_pci *) data;
+ struct mantis_pci *mantis = from_tasklet(mantis, t, tasklet);
struct mantis_hwconfig *config = mantis->hwconfig;
while (mantis->last_block != mantis->busy_block) {
diff --git a/drivers/media/pci/mantis/mantis_dma.h b/drivers/media/pci/mantis/mantis_dma.h
index 421663443d62..37da982c9c29 100644
--- a/drivers/media/pci/mantis/mantis_dma.h
+++ b/drivers/media/pci/mantis/mantis_dma.h
@@ -13,6 +13,6 @@ extern int mantis_dma_init(struct mantis_pci *mantis);
extern int mantis_dma_exit(struct mantis_pci *mantis);
extern void mantis_dma_start(struct mantis_pci *mantis);
extern void mantis_dma_stop(struct mantis_pci *mantis);
-extern void mantis_dma_xfer(unsigned long data);
+extern void mantis_dma_xfer(struct tasklet_struct *t);
#endif /* __MANTIS_DMA_H */
diff --git a/drivers/media/pci/mantis/mantis_dvb.c b/drivers/media/pci/mantis/mantis_dvb.c
index 2da94be5b373..c7ba4a76e608 100644
--- a/drivers/media/pci/mantis/mantis_dvb.c
+++ b/drivers/media/pci/mantis/mantis_dvb.c
@@ -205,7 +205,7 @@ int mantis_dvb_init(struct mantis_pci *mantis)
}
dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
- tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
+ tasklet_setup(&mantis->tasklet, mantis_dma_xfer);
tasklet_disable(&mantis->tasklet);
if (mantis->hwconfig) {
result = config->frontend_init(mantis, mantis->fe);
diff --git a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
index 80a7c41baa90..6f3125c2d097 100644
--- a/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
+++ b/drivers/media/pci/netup_unidvb/netup_unidvb_core.c
@@ -1016,8 +1016,6 @@ static struct pci_driver netup_unidvb_pci_driver = {
.id_table = netup_unidvb_pci_tbl,
.probe = netup_unidvb_initdev,
.remove = netup_unidvb_finidev,
- .suspend = NULL,
- .resume = NULL,
};
module_pci_driver(netup_unidvb_pci_driver);
diff --git a/drivers/media/pci/ngene/ngene-core.c b/drivers/media/pci/ngene/ngene-core.c
index af15ca1c501b..f9f94f47d76b 100644
--- a/drivers/media/pci/ngene/ngene-core.c
+++ b/drivers/media/pci/ngene/ngene-core.c
@@ -50,9 +50,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* nGene interrupt handler **************************************************/
/****************************************************************************/
-static void event_tasklet(unsigned long data)
+static void event_tasklet(struct tasklet_struct *t)
{
- struct ngene *dev = (struct ngene *)data;
+ struct ngene *dev = from_tasklet(dev, t, event_tasklet);
while (dev->EventQueueReadIndex != dev->EventQueueWriteIndex) {
struct EVENT_BUFFER Event =
@@ -68,9 +68,9 @@ static void event_tasklet(unsigned long data)
}
}
-static void demux_tasklet(unsigned long data)
+static void demux_tasklet(struct tasklet_struct *t)
{
- struct ngene_channel *chan = (struct ngene_channel *)data;
+ struct ngene_channel *chan = from_tasklet(chan, t, demux_tasklet);
struct device *pdev = &chan->dev->pci_dev->dev;
struct SBufferHeader *Cur = chan->nextBuffer;
@@ -1181,7 +1181,7 @@ static void ngene_init(struct ngene *dev)
struct device *pdev = &dev->pci_dev->dev;
int i;
- tasklet_init(&dev->event_tasklet, event_tasklet, (unsigned long)dev);
+ tasklet_setup(&dev->event_tasklet, event_tasklet);
memset_io(dev->iomem + 0xc000, 0x00, 0x220);
memset_io(dev->iomem + 0xc400, 0x00, 0x100);
@@ -1445,7 +1445,7 @@ static int init_channel(struct ngene_channel *chan)
struct ngene_info *ni = dev->card_info;
int io = ni->io_type[nr];
- tasklet_init(&chan->demux_tasklet, demux_tasklet, (unsigned long)chan);
+ tasklet_setup(&chan->demux_tasklet, demux_tasklet);
chan->users = 0;
chan->type = io;
chan->mode = chan->type; /* for now only one mode */
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
index 544ca57eee75..7a1fb067b0e0 100644
--- a/drivers/media/pci/saa7134/saa7134-alsa.c
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -252,7 +252,8 @@ static int snd_card_saa7134_capture_trigger(struct snd_pcm_substream * substream
return err;
}
-static int saa7134_alsa_dma_init(struct saa7134_dev *dev, int nr_pages)
+static int saa7134_alsa_dma_init(struct saa7134_dev *dev,
+ unsigned long nr_pages)
{
struct saa7134_dmasound *dma = &dev->dmasound;
struct page *pg;
@@ -260,11 +261,11 @@ static int saa7134_alsa_dma_init(struct saa7134_dev *dev, int nr_pages)
dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
if (NULL == dma->vaddr) {
- pr_debug("vmalloc_32(%d pages) failed\n", nr_pages);
+ pr_debug("vmalloc_32(%lu pages) failed\n", nr_pages);
return -ENOMEM;
}
- pr_debug("vmalloc is at addr %p, size=%d\n",
+ pr_debug("vmalloc is at addr %p, size=%lu\n",
dma->vaddr, nr_pages << PAGE_SHIFT);
memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
@@ -297,7 +298,7 @@ static int saa7134_alsa_dma_map(struct saa7134_dev *dev)
struct saa7134_dmasound *dma = &dev->dmasound;
dma->sglen = dma_map_sg(&dev->pci->dev, dma->sglist,
- dma->nr_pages, PCI_DMA_FROMDEVICE);
+ dma->nr_pages, DMA_FROM_DEVICE);
if (0 == dma->sglen) {
pr_warn("%s: saa7134_alsa_map_sg failed\n", __func__);
@@ -313,7 +314,7 @@ static int saa7134_alsa_dma_unmap(struct saa7134_dev *dev)
if (!dma->sglen)
return 0;
- dma_unmap_sg(&dev->pci->dev, dma->sglist, dma->sglen, PCI_DMA_FROMDEVICE);
+ dma_unmap_sg(&dev->pci->dev, dma->sglist, dma->nr_pages, DMA_FROM_DEVICE);
dma->sglen = 0;
return 0;
}
diff --git a/drivers/media/pci/saa7134/saa7134-cards.c b/drivers/media/pci/saa7134/saa7134-cards.c
index c1937c33c33d..ce449c941171 100644
--- a/drivers/media/pci/saa7134/saa7134-cards.c
+++ b/drivers/media/pci/saa7134/saa7134-cards.c
@@ -7812,7 +7812,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
dev->name, saa7134_boards[dev->board].name);
break;
}
- /* fall-through */
+ fallthrough;
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
@@ -7870,7 +7870,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
hauppauge_eeprom(dev, dev->eedata+0x80);
- /* fall-through */
+ fallthrough;
case SAA7134_BOARD_PINNACLE_PCTV_310i:
case SAA7134_BOARD_KWORLD_DVBT_210:
case SAA7134_BOARD_TEVION_DVBT_220RF:
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index e4623ed2f831..391572a6ec76 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -359,14 +359,12 @@ void saa7134_stop_streaming(struct saa7134_dev *dev, struct saa7134_dmaqueue *q)
struct saa7134_buf *tmp;
spin_lock_irqsave(&dev->slock, flags);
- if (!list_empty(&q->queue)) {
- list_for_each_safe(pos, n, &q->queue) {
- tmp = list_entry(pos, struct saa7134_buf, entry);
- vb2_buffer_done(&tmp->vb2.vb2_buf,
- VB2_BUF_STATE_ERROR);
- list_del(pos);
- tmp = NULL;
- }
+ list_for_each_safe(pos, n, &q->queue) {
+ tmp = list_entry(pos, struct saa7134_buf, entry);
+ vb2_buffer_done(&tmp->vb2.vb2_buf,
+ VB2_BUF_STATE_ERROR);
+ list_del(pos);
+ tmp = NULL;
}
spin_unlock_irqrestore(&dev->slock, flags);
saa7134_buffer_timeout(&q->timeout); /* also calls del_timer(&q->timeout) */
@@ -965,21 +963,21 @@ static void saa7134_unregister_video(struct saa7134_dev *dev)
if (dev->video_dev) {
if (video_is_registered(dev->video_dev))
- video_unregister_device(dev->video_dev);
+ vb2_video_unregister_device(dev->video_dev);
else
video_device_release(dev->video_dev);
dev->video_dev = NULL;
}
if (dev->vbi_dev) {
if (video_is_registered(dev->vbi_dev))
- video_unregister_device(dev->vbi_dev);
+ vb2_video_unregister_device(dev->vbi_dev);
else
video_device_release(dev->vbi_dev);
dev->vbi_dev = NULL;
}
if (dev->radio_dev) {
if (video_is_registered(dev->radio_dev))
- video_unregister_device(dev->radio_dev);
+ vb2_video_unregister_device(dev->radio_dev);
else
video_device_release(dev->radio_dev);
dev->radio_dev = NULL;
@@ -1370,11 +1368,9 @@ static void saa7134_finidev(struct pci_dev *pci_dev)
kfree(dev);
}
-#ifdef CONFIG_PM
-
/* resends a current buffer in queue after resume */
-static int saa7134_buffer_requeue(struct saa7134_dev *dev,
- struct saa7134_dmaqueue *q)
+static int __maybe_unused saa7134_buffer_requeue(struct saa7134_dev *dev,
+ struct saa7134_dmaqueue *q)
{
struct saa7134_buf *buf, *next;
@@ -1397,8 +1393,9 @@ static int saa7134_buffer_requeue(struct saa7134_dev *dev,
return 0;
}
-static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
+static int __maybe_unused saa7134_suspend(struct device *dev_d)
{
+ struct pci_dev *pci_dev = to_pci_dev(dev_d);
struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
@@ -1428,21 +1425,15 @@ static int saa7134_suspend(struct pci_dev *pci_dev , pm_message_t state)
if (dev->remote && dev->remote->dev->users)
saa7134_ir_close(dev->remote->dev);
- pci_save_state(pci_dev);
- pci_set_power_state(pci_dev, pci_choose_state(pci_dev, state));
-
return 0;
}
-static int saa7134_resume(struct pci_dev *pci_dev)
+static int __maybe_unused saa7134_resume(struct device *dev_d)
{
- struct v4l2_device *v4l2_dev = pci_get_drvdata(pci_dev);
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev_d);
struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
unsigned long flags;
- pci_set_power_state(pci_dev, PCI_D0);
- pci_restore_state(pci_dev);
-
/* Do things that are done in saa7134_initdev ,
except of initializing memory structures.*/
@@ -1490,7 +1481,6 @@ static int saa7134_resume(struct pci_dev *pci_dev)
return 0;
}
-#endif
/* ----------------------------------------------------------- */
@@ -1522,15 +1512,14 @@ EXPORT_SYMBOL(saa7134_ts_unregister);
/* ----------------------------------------------------------- */
+static SIMPLE_DEV_PM_OPS(saa7134_pm_ops, saa7134_suspend, saa7134_resume);
+
static struct pci_driver saa7134_pci_driver = {
.name = "saa7134",
.id_table = saa7134_pci_tbl,
.probe = saa7134_initdev,
.remove = saa7134_finidev,
-#ifdef CONFIG_PM
- .suspend = saa7134_suspend,
- .resume = saa7134_resume
-#endif
+ .driver.pm = &saa7134_pm_ops,
};
static int __init saa7134_init(void)
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index 8ad7879bd840..39e3c7f8c5b4 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -314,8 +314,7 @@ static int empress_fini(struct saa7134_dev *dev)
if (NULL == dev->empress_dev)
return 0;
flush_work(&dev->empress_workqueue);
- video_unregister_device(dev->empress_dev);
- vb2_queue_release(&dev->empress_vbq);
+ vb2_video_unregister_device(dev->empress_dev);
v4l2_ctrl_handler_free(&dev->empress_ctrl_handler);
dev->empress_dev = NULL;
return 0;
diff --git a/drivers/media/pci/saa7134/saa7134-go7007.c b/drivers/media/pci/saa7134/saa7134-go7007.c
index e1b034663958..f319edb39c0e 100644
--- a/drivers/media/pci/saa7134/saa7134-go7007.c
+++ b/drivers/media/pci/saa7134/saa7134-go7007.c
@@ -493,7 +493,7 @@ static int saa7134_go7007_fini(struct saa7134_dev *dev)
free_page((unsigned long)saa->bottom);
v4l2_device_unregister_subdev(&saa->sd);
kfree(saa);
- video_unregister_device(&go->vdev);
+ vb2_video_unregister_device(&go->vdev);
v4l2_device_put(&go->v4l2_dev);
dev->empress_dev = NULL;
diff --git a/drivers/media/pci/saa7134/saa7134-tvaudio.c b/drivers/media/pci/saa7134/saa7134-tvaudio.c
index 79e1afb71075..5cc4ef21f9d3 100644
--- a/drivers/media/pci/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/pci/saa7134/saa7134-tvaudio.c
@@ -683,7 +683,8 @@ int saa_dsp_writel(struct saa7134_dev *dev, int reg, u32 value)
{
int err;
- audio_dbg(2, "dsp write reg 0x%x = 0x%06x\n", reg << 2, value);
+ audio_dbg(2, "dsp write reg 0x%x = 0x%06x\n",
+ (reg << 2) & 0xffffffff, value);
err = saa_dsp_wait_bit(dev,SAA7135_DSP_RWSTATE_WRR);
if (err < 0)
return err;
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index a8ac94fadc14..9a6a6b68f8e3 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -2154,9 +2154,7 @@ int saa7134_video_init1(struct saa7134_dev *dev)
void saa7134_video_fini(struct saa7134_dev *dev)
{
/* free stuff */
- vb2_queue_release(&dev->video_vbq);
saa7134_pgtable_free(dev->pci, &dev->video_q.pt);
- vb2_queue_release(&dev->vbi_vbq);
saa7134_pgtable_free(dev->pci, &dev->vbi_q.pt);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
if (card_has_radio(dev))
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 77c325e64a97..d29499cd7370 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -509,7 +509,7 @@ struct saa7134_dmasound {
void *vaddr;
struct scatterlist *sglist;
int sglen;
- int nr_pages;
+ unsigned long nr_pages;
unsigned int dma_blk;
unsigned int read_offset;
unsigned int read_count;
diff --git a/drivers/media/pci/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c
index 289cb901985b..245d9db280aa 100644
--- a/drivers/media/pci/saa7164/saa7164-buffer.c
+++ b/drivers/media/pci/saa7164/saa7164-buffer.c
@@ -250,15 +250,14 @@ int saa7164_buffer_cfg_port(struct saa7164_port *port)
list_for_each_safe(c, n, &port->dmaqueue.list) {
buf = list_entry(c, struct saa7164_buffer, list);
- if (buf->flags != SAA7164_BUFFER_FREE)
- BUG();
+ BUG_ON(buf->flags != SAA7164_BUFFER_FREE);
/* Place the buffer in the h/w queue */
saa7164_buffer_activate(buf, i);
/* Don't exceed the device maximum # bufs */
- if (i++ > port->hwcfg.buffercount)
- BUG();
+ BUG_ON(i > port->hwcfg.buffercount);
+ i++;
}
mutex_unlock(&port->dmaqueue_lock);
@@ -302,4 +301,3 @@ void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf)
kfree(buf);
}
-
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index 4b637891b79a..6c08b77bfd47 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -575,8 +575,8 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_port *port)
/* Find the current write point from the hardware */
wp = saa7164_readl(port->bufcounter);
- if (wp > (port->hwcfg.buffercount - 1))
- BUG();
+
+ BUG_ON(wp > (port->hwcfg.buffercount - 1));
/* Find the previous buffer to the current write point */
if (wp == 0)
@@ -588,8 +588,8 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_port *port)
/* TODO: turn this into a worker thread */
list_for_each_safe(c, n, &port->dmaqueue.list) {
buf = list_entry(c, struct saa7164_buffer, list);
- if (i++ > port->hwcfg.buffercount)
- BUG();
+ BUG_ON(i > port->hwcfg.buffercount);
+ i++;
if (buf->idx == rp) {
/* Found the buffer, deal with it */
@@ -894,8 +894,7 @@ static int saa7164_port_init(struct saa7164_dev *dev, int portnr)
{
struct saa7164_port *port = NULL;
- if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS))
- BUG();
+ BUG_ON((portnr < 0) || (portnr >= SAA7164_MAX_PORTS));
port = &dev->ports[portnr];
@@ -1563,4 +1562,3 @@ static void __exit saa7164_fini(void)
module_init(saa7164_init);
module_exit(saa7164_fini);
-
diff --git a/drivers/media/pci/saa7164/saa7164-dvb.c b/drivers/media/pci/saa7164/saa7164-dvb.c
index bf8c2bb8852e..24421c116b0b 100644
--- a/drivers/media/pci/saa7164/saa7164-dvb.c
+++ b/drivers/media/pci/saa7164/saa7164-dvb.c
@@ -337,8 +337,7 @@ static int dvb_register(struct saa7164_port *port)
dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
- if (port->type != SAA7164_MPEG_DVB)
- BUG();
+ BUG_ON(port->type != SAA7164_MPEG_DVB);
/* Sanity check that the PCI configuration space is active */
if (port->hwcfg.BARLocation == 0) {
@@ -479,8 +478,7 @@ int saa7164_dvb_unregister(struct saa7164_port *port)
dprintk(DBGLVL_DVB, "%s()\n", __func__);
- if (port->type != SAA7164_MPEG_DVB)
- BUG();
+ BUG_ON(port->type != SAA7164_MPEG_DVB);
/* Remove any allocated buffers */
mutex_lock(&port->dmaqueue_lock);
@@ -740,4 +738,3 @@ frontend_detach:
printk(KERN_ERR "%s() Frontend/I2C initialization failed\n", __func__);
return -1;
}
-
diff --git a/drivers/media/pci/saa7164/saa7164-vbi.c b/drivers/media/pci/saa7164/saa7164-vbi.c
index 49d61a64c8cb..cb2e09f0841d 100644
--- a/drivers/media/pci/saa7164/saa7164-vbi.c
+++ b/drivers/media/pci/saa7164/saa7164-vbi.c
@@ -703,8 +703,7 @@ int saa7164_vbi_register(struct saa7164_port *port)
dprintk(DBGLVL_VBI, "%s()\n", __func__);
- if (port->type != SAA7164_MPEG_VBI)
- BUG();
+ BUG_ON(port->type != SAA7164_MPEG_VBI);
/* Sanity check that the PCI configuration space is active */
if (port->hwcfg.BARLocation == 0) {
@@ -756,8 +755,7 @@ void saa7164_vbi_unregister(struct saa7164_port *port)
dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
- if (port->type != SAA7164_MPEG_VBI)
- BUG();
+ BUG_ON(port->type != SAA7164_MPEG_VBI);
if (port->v4l_device) {
if (port->v4l_device->minor != -1)
diff --git a/drivers/media/pci/smipcie/smipcie-ir.c b/drivers/media/pci/smipcie/smipcie-ir.c
index 9445d792bfc9..e6b74e161a05 100644
--- a/drivers/media/pci/smipcie/smipcie-ir.c
+++ b/drivers/media/pci/smipcie/smipcie-ir.c
@@ -87,8 +87,7 @@ static void smi_ir_decode(struct smi_rc *ir)
struct ir_raw_event rawir = {};
rawir.pulse = 0;
- rawir.duration = US_TO_NS(SMI_SAMPLE_PERIOD *
- SMI_SAMPLE_IDLEMIN);
+ rawir.duration = SMI_SAMPLE_PERIOD * SMI_SAMPLE_IDLEMIN;
ir_raw_event_store_with_filter(rc_dev, &rawir);
smi_set(IR_Init_Reg, rbIRhighidle);
}
@@ -151,8 +150,8 @@ int smi_ir_init(struct smi_dev *dev)
rc_dev->dev.parent = &dev->pci_dev->dev;
rc_dev->map_name = dev->info->rc_map;
- rc_dev->timeout = MS_TO_NS(100);
- rc_dev->rx_resolution = US_TO_NS(SMI_SAMPLE_PERIOD);
+ rc_dev->timeout = MS_TO_US(100);
+ rc_dev->rx_resolution = SMI_SAMPLE_PERIOD;
ir->rc_dev = rc_dev;
ir->dev = dev;
diff --git a/drivers/media/pci/smipcie/smipcie-main.c b/drivers/media/pci/smipcie/smipcie-main.c
index 9ca0fc3e6f80..e7604b7ecc8d 100644
--- a/drivers/media/pci/smipcie/smipcie-main.c
+++ b/drivers/media/pci/smipcie/smipcie-main.c
@@ -280,9 +280,9 @@ static void smi_port_clearInterrupt(struct smi_port *port)
}
/* tasklet handler: DMA data to dmx.*/
-static void smi_dma_xfer(unsigned long data)
+static void smi_dma_xfer(struct tasklet_struct *t)
{
- struct smi_port *port = (struct smi_port *) data;
+ struct smi_port *port = from_tasklet(port, t, tasklet);
struct smi_dev *dev = port->dev;
u32 intr_status, finishedData, dmaManagement;
u8 dmaChan0State, dmaChan1State;
@@ -422,7 +422,7 @@ static int smi_port_init(struct smi_port *port, int dmaChanUsed)
}
smi_port_disableInterrupt(port);
- tasklet_init(&port->tasklet, smi_dma_xfer, (unsigned long)port);
+ tasklet_setup(&port->tasklet, smi_dma_xfer);
tasklet_disable(&port->tasklet);
port->enable = 1;
return 0;
diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c
index c6e0090f27e8..d497afc7e7b7 100644
--- a/drivers/media/pci/solo6x10/solo6x10-core.c
+++ b/drivers/media/pci/solo6x10/solo6x10-core.c
@@ -503,7 +503,7 @@ static int solo_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
default:
dev_warn(&pdev->dev, "Invalid chip_id 0x%02x, assuming 4 ch\n",
chip_id);
- /* fall through */
+ fallthrough;
case 5:
solo_dev->nr_chans = 4;
solo_dev->nr_ext = 1;
diff --git a/drivers/media/pci/solo6x10/solo6x10-i2c.c b/drivers/media/pci/solo6x10/solo6x10-i2c.c
index f86f12fa6350..7db785e9c997 100644
--- a/drivers/media/pci/solo6x10/solo6x10-i2c.c
+++ b/drivers/media/pci/solo6x10/solo6x10-i2c.c
@@ -183,7 +183,7 @@ int solo_i2c_isr(struct solo_dev *solo_dev)
}
solo_dev->i2c_state = IIC_STATE_WRITE;
- /* fall through */
+ fallthrough;
case IIC_STATE_WRITE:
ret = solo_i2c_handle_write(solo_dev);
break;
diff --git a/drivers/media/pci/sta2x11/sta2x11_vip.c b/drivers/media/pci/sta2x11/sta2x11_vip.c
index 0fdb0fd6e764..336df65c8af1 100644
--- a/drivers/media/pci/sta2x11/sta2x11_vip.c
+++ b/drivers/media/pci/sta2x11/sta2x11_vip.c
@@ -1101,12 +1101,11 @@ static int sta2x11_vip_init_one(struct pci_dev *pdev,
vunreg:
video_set_drvdata(&vip->video_dev, NULL);
vrelease:
- video_unregister_device(&vip->video_dev);
+ vb2_video_unregister_device(&vip->video_dev);
free_irq(pdev->irq, vip);
release_buf:
pci_disable_msi(pdev);
unmap:
- vb2_queue_release(&vip->vb_vidq);
pci_iounmap(pdev, vip->iomem);
release:
pci_release_regions(pdev);
@@ -1146,10 +1145,9 @@ static void sta2x11_vip_remove_one(struct pci_dev *pdev)
sta2x11_vip_clear_register(vip);
video_set_drvdata(&vip->video_dev, NULL);
- video_unregister_device(&vip->video_dev);
+ vb2_video_unregister_device(&vip->video_dev);
free_irq(pdev->irq, vip);
pci_disable_msi(pdev);
- vb2_queue_release(&vip->vb_vidq);
pci_iounmap(pdev, vip->iomem);
pci_release_regions(pdev);
diff --git a/drivers/media/pci/ttpci/av7110.c b/drivers/media/pci/ttpci/av7110.c
index 45228f4f6fc6..2f7069e19b78 100644
--- a/drivers/media/pci/ttpci/av7110.c
+++ b/drivers/media/pci/ttpci/av7110.c
@@ -357,9 +357,9 @@ static inline void start_debi_dma(struct av7110 *av7110, int dir,
irdebi(av7110, DEBISWAB, addr, 0, len);
}
-static void debiirq(unsigned long cookie)
+static void debiirq(struct tasklet_struct *t)
{
- struct av7110 *av7110 = (struct av7110 *)cookie;
+ struct av7110 *av7110 = from_tasklet(av7110, t, debi_tasklet);
int type = av7110->debitype;
int handle = (type >> 8) & 0x1f;
unsigned int xfer = 0;
@@ -458,9 +458,9 @@ debi_done:
}
/* irq from av7110 firmware writing the mailbox register in the DPRAM */
-static void gpioirq(unsigned long cookie)
+static void gpioirq(struct tasklet_struct *t)
{
- struct av7110 *av7110 = (struct av7110 *)cookie;
+ struct av7110 *av7110 = from_tasklet(av7110, t, gpio_tasklet);
u32 rxbuf, txbuf;
int len;
@@ -1230,9 +1230,9 @@ static int budget_stop_feed(struct dvb_demux_feed *feed)
return status;
}
-static void vpeirq(unsigned long cookie)
+static void vpeirq(struct tasklet_struct *t)
{
- struct av7110 *budget = (struct av7110 *)cookie;
+ struct av7110 *budget = from_tasklet(budget, t, vpe_tasklet);
u8 *mem = (u8 *) (budget->grabbing);
u32 olddma = budget->ttbp;
u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
@@ -2518,7 +2518,7 @@ static int av7110_attach(struct saa7146_dev* dev,
saa7146_write(dev, NUM_LINE_BYTE3, (TS_HEIGHT << 16) | TS_WIDTH);
saa7146_write(dev, MC2, MASK_04 | MASK_20);
- tasklet_init(&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
+ tasklet_setup(&av7110->vpe_tasklet, vpeirq);
} else if (budgetpatch) {
spin_lock_init(&av7110->feedlock1);
@@ -2599,7 +2599,7 @@ static int av7110_attach(struct saa7146_dev* dev,
saa7146_write(dev, MC1, (MASK_13 | MASK_29));
/* end of budgetpatch register initialization */
- tasklet_init (&av7110->vpe_tasklet, vpeirq, (unsigned long) av7110);
+ tasklet_setup(&av7110->vpe_tasklet, vpeirq);
} else {
saa7146_write(dev, PCI_BT_V1, 0x1c00101f);
saa7146_write(dev, BCS_CTRL, 0x80400040);
@@ -2614,8 +2614,8 @@ static int av7110_attach(struct saa7146_dev* dev,
saa7146_write(dev, GPIO_CTRL, 0x000000);
}
- tasklet_init (&av7110->debi_tasklet, debiirq, (unsigned long) av7110);
- tasklet_init (&av7110->gpio_tasklet, gpioirq, (unsigned long) av7110);
+ tasklet_setup(&av7110->debi_tasklet, debiirq);
+ tasklet_setup(&av7110->gpio_tasklet, gpioirq);
mutex_init(&av7110->pid_mutex);
diff --git a/drivers/media/pci/ttpci/av7110_v4l.c b/drivers/media/pci/ttpci/av7110_v4l.c
index cabe006658dd..c89f536f699c 100644
--- a/drivers/media/pci/ttpci/av7110_v4l.c
+++ b/drivers/media/pci/ttpci/av7110_v4l.c
@@ -160,9 +160,9 @@ static int ves1820_set_tv_freq(struct saa7146_dev *dev, u32 freq)
buf[1] = div & 0xff;
buf[2] = 0x8e;
- if (freq < (u32) (16 * 168.25))
+ if (freq < 16U * 16825 / 100)
config = 0xa0;
- else if (freq < (u32) (16 * 447.25))
+ else if (freq < 16U * 44725 / 100)
config = 0x90;
else
config = 0x30;
diff --git a/drivers/media/pci/ttpci/budget-ci.c b/drivers/media/pci/ttpci/budget-ci.c
index 77b102b8a013..d59d18647371 100644
--- a/drivers/media/pci/ttpci/budget-ci.c
+++ b/drivers/media/pci/ttpci/budget-ci.c
@@ -99,9 +99,10 @@ struct budget_ci {
u8 tuner_pll_address; /* used for philips_tdm1316l configs */
};
-static void msp430_ir_interrupt(unsigned long data)
+static void msp430_ir_interrupt(struct tasklet_struct *t)
{
- struct budget_ci *budget_ci = (struct budget_ci *) data;
+ struct budget_ci_ir *ir = from_tasklet(ir, t, msp430_irq_tasklet);
+ struct budget_ci *budget_ci = container_of(ir, typeof(*budget_ci), ir);
struct rc_dev *dev = budget_ci->ir.dev;
u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
@@ -229,8 +230,7 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
budget_ci->ir.dev = dev;
- tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
- (unsigned long) budget_ci);
+ tasklet_setup(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt);
SAA7146_IER_ENABLE(saa, MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_IRQHI);
@@ -348,9 +348,10 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot)
return 0;
}
-static void ciintf_interrupt(unsigned long data)
+static void ciintf_interrupt(struct tasklet_struct *t)
{
- struct budget_ci *budget_ci = (struct budget_ci *) data;
+ struct budget_ci *budget_ci = from_tasklet(budget_ci, t,
+ ciintf_irq_tasklet);
struct saa7146_dev *saa = budget_ci->budget.dev;
unsigned int flags;
@@ -491,7 +492,7 @@ static int ciintf_init(struct budget_ci *budget_ci)
// Setup CI slot IRQ
if (budget_ci->ci_irq) {
- tasklet_init(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt, (unsigned long) budget_ci);
+ tasklet_setup(&budget_ci->ciintf_irq_tasklet, ciintf_interrupt);
if (budget_ci->slot_status != SLOTSTATUS_NONE) {
saa7146_setgpio(saa, 0, SAA7146_GPIO_IRQLO);
} else {
diff --git a/drivers/media/pci/ttpci/budget-core.c b/drivers/media/pci/ttpci/budget-core.c
index 293867b9e796..d405eea5c37f 100644
--- a/drivers/media/pci/ttpci/budget-core.c
+++ b/drivers/media/pci/ttpci/budget-core.c
@@ -171,9 +171,9 @@ static int budget_read_fe_status(struct dvb_frontend *fe,
return ret;
}
-static void vpeirq(unsigned long data)
+static void vpeirq(struct tasklet_struct *t)
{
- struct budget *budget = (struct budget *) data;
+ struct budget *budget = from_tasklet(budget, t, vpe_tasklet);
u8 *mem = (u8 *) (budget->grabbing);
u32 olddma = budget->ttbp;
u32 newdma = saa7146_read(budget->dev, PCI_VDP3);
@@ -519,7 +519,7 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
/* upload all */
saa7146_write(dev, GPIO_CTRL, 0x000000);
- tasklet_init(&budget->vpe_tasklet, vpeirq, (unsigned long) budget);
+ tasklet_setup(&budget->vpe_tasklet, vpeirq);
/* frontend power on */
if (bi->type != BUDGET_FS_ACTIVY)
diff --git a/drivers/media/pci/tw5864/tw5864-video.c b/drivers/media/pci/tw5864/tw5864-video.c
index ec1e06da7e4f..9131265c2b87 100644
--- a/drivers/media/pci/tw5864/tw5864-video.c
+++ b/drivers/media/pci/tw5864/tw5864-video.c
@@ -175,7 +175,7 @@ static const unsigned int intra4x4_lambda3[] = {
static v4l2_std_id tw5864_get_v4l2_std(enum tw5864_vid_std std);
static enum tw5864_vid_std tw5864_from_v4l2_std(v4l2_std_id v4l2_std);
-static void tw5864_handle_frame_task(unsigned long data);
+static void tw5864_handle_frame_task(struct tasklet_struct *t);
static void tw5864_handle_frame(struct tw5864_h264_frame *frame);
static void tw5864_frame_interval_set(struct tw5864_input *input);
@@ -767,6 +767,9 @@ static int tw5864_enum_frameintervals(struct file *file, void *priv,
fintv->type = V4L2_FRMIVAL_TYPE_STEPWISE;
ret = tw5864_frameinterval_get(input, &frameinterval);
+ if (ret)
+ return ret;
+
fintv->stepwise.step = frameinterval;
fintv->stepwise.min = frameinterval;
fintv->stepwise.max = frameinterval;
@@ -785,6 +788,9 @@ static int tw5864_g_parm(struct file *file, void *priv,
cp->capability = V4L2_CAP_TIMEPERFRAME;
ret = tw5864_frameinterval_get(input, &cp->timeperframe);
+ if (ret)
+ return ret;
+
cp->timeperframe.numerator *= input->frame_interval;
cp->capturemode = 0;
cp->readbuffers = 2;
@@ -1057,8 +1063,7 @@ int tw5864_video_init(struct tw5864_dev *dev, int *video_nr)
dev->irqmask |= TW5864_INTR_VLC_DONE | TW5864_INTR_TIMER;
tw5864_irqmask_apply(dev);
- tasklet_init(&dev->tasklet, tw5864_handle_frame_task,
- (unsigned long)dev);
+ tasklet_setup(&dev->tasklet, tw5864_handle_frame_task);
for (i = 0; i < TW5864_INPUTS; i++) {
dev->inputs[i].root = dev;
@@ -1178,7 +1183,6 @@ static int tw5864_video_input_init(struct tw5864_input *input, int video_nr)
free_v4l2_hdl:
v4l2_ctrl_handler_free(hdl);
- vb2_queue_release(&input->vidq);
free_mutex:
mutex_destroy(&input->lock);
@@ -1187,9 +1191,8 @@ free_mutex:
static void tw5864_video_input_fini(struct tw5864_input *dev)
{
- video_unregister_device(&dev->vdev);
+ vb2_video_unregister_device(&dev->vdev);
v4l2_ctrl_handler_free(&dev->hdl);
- vb2_queue_release(&dev->vidq);
}
void tw5864_video_fini(struct tw5864_dev *dev)
@@ -1313,9 +1316,9 @@ static int tw5864_is_motion_triggered(struct tw5864_h264_frame *frame)
return detected;
}
-static void tw5864_handle_frame_task(unsigned long data)
+static void tw5864_handle_frame_task(struct tasklet_struct *t)
{
- struct tw5864_dev *dev = (struct tw5864_dev *)data;
+ struct tw5864_dev *dev = from_tasklet(dev, t, tasklet);
unsigned long flags;
int batch_size = H264_BUF_CNT;
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index c57ee78fa99d..a3cb104956d5 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -256,13 +256,14 @@ config VIDEO_MEDIATEK_VCODEC
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
select VIDEO_MEDIATEK_VPU
+ select MTK_SCP
help
Mediatek video codec driver provides HW capability to
encode and decode in a range of video formats
This driver rely on VPU driver to communicate with VPU.
- To compile this driver as a module, choose M here: the
- module will be called mtk-vcodec
+ To compile this driver as modules, choose M here: the
+ modules will be called mtk-vcodec-dec and mtk-vcodec-enc.
config VIDEO_MEM2MEM_DEINTERLACE
tristate "Deinterlace support"
@@ -426,8 +427,8 @@ config VIDEO_RENESAS_FCP
help
This is a driver for the Renesas Frame Compression Processor (FCP).
The FCP is a companion module of video processing modules in the
- Renesas R-Car Gen3 SoCs. It handles memory access for the codec,
- VSP and FDP modules.
+ Renesas R-Car Gen3 and RZ/G2 SoCs. It handles memory access for
+ the codec, VSP and FDP modules.
To compile this driver as a module, choose M here: the module
will be called rcar-fcp.
diff --git a/drivers/media/platform/aspeed-video.c b/drivers/media/platform/aspeed-video.c
index 7d98db1d9b52..c46a79eace98 100644
--- a/drivers/media/platform/aspeed-video.c
+++ b/drivers/media/platform/aspeed-video.c
@@ -1597,7 +1597,6 @@ static int aspeed_video_setup_video(struct aspeed_video *video)
video_set_drvdata(vdev, video);
rc = video_register_device(vdev, VFL_TYPE_VIDEO, 0);
if (rc) {
- vb2_queue_release(vbq);
v4l2_ctrl_handler_free(&video->ctrl_handler);
v4l2_device_unregister(v4l2_dev);
@@ -1737,9 +1736,7 @@ static int aspeed_video_remove(struct platform_device *pdev)
clk_unprepare(video->vclk);
clk_unprepare(video->eclk);
- video_unregister_device(&video->vdev);
-
- vb2_queue_release(&video->queue);
+ vb2_video_unregister_device(&video->vdev);
v4l2_ctrl_handler_free(&video->ctrl_handler);
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index b021604eceaa..bf75927bac4e 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -1101,7 +1101,7 @@ static int coda_start_encoding(struct coda_ctx *ctx)
break;
case CODA_960:
coda_write(dev, 0, CODA9_GDI_WPROT_RGN_EN);
- /* fallthrough */
+ fallthrough;
case CODA_HX4:
case CODA_7541:
coda_write(dev, CODA7_STREAM_BUF_DYNALLOC_EN |
@@ -1141,7 +1141,7 @@ static int coda_start_encoding(struct coda_ctx *ctx)
CODA7_PICHEIGHT_MASK) << CODA_PICHEIGHT_OFFSET;
break;
}
- /* fallthrough */
+ fallthrough;
case CODA_960:
value = (q_data_src->rect.width & CODA7_PICWIDTH_MASK)
<< CODA7_PICWIDTH_OFFSET;
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index 3ab3d976d8ca..87a2c706f747 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -808,7 +808,7 @@ static int coda_s_fmt(struct coda_ctx *ctx, struct v4l2_format *f,
ctx->tiled_map_type = GDI_TILED_FRAME_MB_RASTER_MAP;
break;
}
- /* else fall through */
+ fallthrough;
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
case V4L2_PIX_FMT_YUV422P:
@@ -1015,7 +1015,7 @@ static int coda_g_selection(struct file *file, void *fh,
case V4L2_SEL_TGT_CROP_DEFAULT:
case V4L2_SEL_TGT_CROP_BOUNDS:
rsel = &r;
- /* fallthrough */
+ fallthrough;
case V4L2_SEL_TGT_CROP:
if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT ||
ctx->inst_type == CODA_INST_DECODER)
@@ -1024,7 +1024,7 @@ static int coda_g_selection(struct file *file, void *fh,
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
case V4L2_SEL_TGT_COMPOSE_PADDED:
rsel = &r;
- /* fallthrough */
+ fallthrough;
case V4L2_SEL_TGT_COMPOSE:
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
@@ -1074,7 +1074,7 @@ static int coda_s_selection(struct file *file, void *fh,
return 0;
}
- /* else fall through */
+ fallthrough;
case V4L2_SEL_TGT_NATIVE_SIZE:
case V4L2_SEL_TGT_COMPOSE:
return coda_g_selection(file, fh, s);
@@ -1937,9 +1937,6 @@ int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
buf->blob.size = size;
buf->dentry = debugfs_create_blob(name, 0644, parent,
&buf->blob);
- if (!buf->dentry)
- dev_warn(dev->dev,
- "failed to create debugfs entry %s\n", name);
}
return 0;
@@ -2628,7 +2625,7 @@ static int coda_open(struct file *file)
*/
if (enable_bwb || ctx->inst_type == CODA_INST_ENCODER)
ctx->frame_mem_ctrl = CODA9_FRAME_ENABLE_BWB;
- /* fallthrough */
+ fallthrough;
case CODA_HX4:
case CODA_7541:
ctx->reg_idx = 0;
@@ -3211,8 +3208,6 @@ static int coda_probe(struct platform_device *pdev)
ida_init(&dev->ida);
dev->debugfs_root = debugfs_create_dir("coda", NULL);
- if (!dev->debugfs_root)
- dev_warn(&pdev->dev, "failed to create debugfs root\n");
/* allocate auxiliary per-device buffers for the BIT processor */
if (dev->devtype->product == CODA_DX6) {
@@ -3269,6 +3264,8 @@ static int coda_probe(struct platform_device *pdev)
return 0;
err_alloc_workqueue:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
destroy_workqueue(dev->workqueue);
err_v4l2_register:
v4l2_device_unregister(&dev->v4l2_dev);
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index e7a4b06e6dfe..6000a4e789ad 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -495,17 +495,6 @@ static int fimc_capture_open(struct file *file)
ret = fimc_pipeline_call(ve, open, &ve->vdev.entity, true);
- if (ret == 0 && vc->user_subdev_api && vc->inh_sensor_ctrls) {
- /*
- * Recreate controls of the the video node to drop
- * any controls inherited from the sensor subdev.
- */
- fimc_ctrls_delete(vc->ctx);
-
- ret = fimc_ctrls_create(vc->ctx);
- if (ret == 0)
- vc->inh_sensor_ctrls = false;
- }
if (ret == 0)
ve->vdev.entity.use_count++;
@@ -1246,8 +1235,11 @@ static int fimc_cap_streamoff(struct file *file, void *priv,
if (ret < 0)
return ret;
- media_pipeline_stop(&vc->ve.vdev.entity);
- vc->streaming = false;
+ if (vc->streaming) {
+ media_pipeline_stop(&vc->ve.vdev.entity);
+ vc->streaming = false;
+ }
+
return 0;
}
@@ -1279,7 +1271,7 @@ static int fimc_cap_g_selection(struct file *file, void *fh,
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
f = &ctx->d_frame;
- /* fall through */
+ fallthrough;
case V4L2_SEL_TGT_CROP_BOUNDS:
case V4L2_SEL_TGT_CROP_DEFAULT:
s->r.left = 0;
@@ -1290,7 +1282,7 @@ static int fimc_cap_g_selection(struct file *file, void *fh,
case V4L2_SEL_TGT_COMPOSE:
f = &ctx->d_frame;
- /* fall through */
+ fallthrough;
case V4L2_SEL_TGT_CROP:
s->r.left = f->offs_h;
s->r.top = f->offs_v;
@@ -1398,7 +1390,7 @@ static int fimc_link_setup(struct media_entity *entity,
vc->input = sd->grp_id;
- if (vc->user_subdev_api || vc->inh_sensor_ctrls)
+ if (vc->user_subdev_api)
return 0;
/* Inherit V4L2 controls from the image sensor subdev. */
@@ -1601,7 +1593,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd,
switch (sel->target) {
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
f = &ctx->d_frame;
- /* fall through */
+ fallthrough;
case V4L2_SEL_TGT_CROP_BOUNDS:
r->width = f->o_width;
r->height = f->o_height;
@@ -1888,6 +1880,7 @@ int fimc_initialize_capture_subdev(struct fimc_dev *fimc)
return ret;
sd->entity.ops = &fimc_sd_media_ops;
+ sd->entity.function = MEDIA_ENT_F_PROC_VIDEO_SCALER;
sd->internal_ops = &fimc_capture_sd_internal_ops;
v4l2_set_subdevdata(sd, fimc);
return 0;
diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c
index cde60fbb23a8..08d1f39a914c 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/exynos4-is/fimc-core.c
@@ -954,9 +954,11 @@ static int fimc_probe(struct platform_device *pdev)
spin_lock_init(&fimc->slock);
mutex_init(&fimc->lock);
- fimc->sysreg = fimc_get_sysreg_regmap(dev->of_node);
- if (IS_ERR(fimc->sysreg))
- return PTR_ERR(fimc->sysreg);
+ if (fimc->variant->has_isp_wb) {
+ fimc->sysreg = fimc_get_sysreg_regmap(dev->of_node);
+ if (IS_ERR(fimc->sysreg))
+ return PTR_ERR(fimc->sysreg);
+ }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
fimc->regs = devm_ioremap_resource(dev, res);
@@ -1110,67 +1112,8 @@ static int fimc_remove(struct platform_device *pdev)
return 0;
}
-/* Image pixel limits, similar across several FIMC HW revisions. */
-static const struct fimc_pix_limit s5p_pix_limit[4] = {
- [0] = {
- .scaler_en_w = 3264,
- .scaler_dis_w = 8192,
- .out_rot_en_w = 1920,
- .out_rot_dis_w = 4224,
- },
- [1] = {
- .scaler_en_w = 4224,
- .scaler_dis_w = 8192,
- .out_rot_en_w = 1920,
- .out_rot_dis_w = 4224,
- },
- [2] = {
- .scaler_en_w = 1920,
- .scaler_dis_w = 8192,
- .out_rot_en_w = 1280,
- .out_rot_dis_w = 1920,
- },
-};
-
-static const struct fimc_variant fimc0_variant_s5pv210 = {
- .has_inp_rot = 1,
- .has_out_rot = 1,
- .has_cam_if = 1,
- .min_inp_pixsize = 16,
- .min_out_pixsize = 16,
- .hor_offs_align = 8,
- .min_vsize_align = 16,
- .pix_limit = &s5p_pix_limit[1],
-};
-
-static const struct fimc_variant fimc1_variant_s5pv210 = {
- .has_inp_rot = 1,
- .has_out_rot = 1,
- .has_cam_if = 1,
- .has_mainscaler_ext = 1,
- .min_inp_pixsize = 16,
- .min_out_pixsize = 16,
- .hor_offs_align = 1,
- .min_vsize_align = 1,
- .pix_limit = &s5p_pix_limit[2],
-};
-
-static const struct fimc_variant fimc2_variant_s5pv210 = {
- .has_cam_if = 1,
- .min_inp_pixsize = 16,
- .min_out_pixsize = 16,
- .hor_offs_align = 8,
- .min_vsize_align = 16,
- .pix_limit = &s5p_pix_limit[2],
-};
-
/* S5PV210, S5PC110 */
static const struct fimc_drvdata fimc_drvdata_s5pv210 = {
- .variant = {
- [0] = &fimc0_variant_s5pv210,
- [1] = &fimc1_variant_s5pv210,
- [2] = &fimc2_variant_s5pv210,
- },
.num_entities = 3,
.lclk_frequency = 166000000UL,
.out_buf_count = 4,
diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h
index d130f664a60b..e4a56232907a 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.h
+++ b/drivers/media/platform/exynos4-is/fimc-core.h
@@ -296,11 +296,8 @@ struct fimc_m2m_device {
* @buf_index: index for managing the output DMA buffers
* @frame_count: the frame counter for statistics
* @reqbufs_count: the number of buffers requested in REQBUFS ioctl
- * @input_index: input (camera sensor) index
* @input: capture input type, grp_id of the attached subdev
* @user_subdev_api: true if subdevs are not configured by the host driver
- * @inh_sensor_ctrls: a flag indicating v4l2 controls are inherited from
- * an image sensor subdev
*/
struct fimc_vid_cap {
struct fimc_ctx *ctx;
@@ -319,10 +316,8 @@ struct fimc_vid_cap {
unsigned int frame_count;
unsigned int reqbufs_count;
bool streaming;
- int input_index;
u32 input;
bool user_subdev_api;
- bool inh_sensor_ctrls;
};
/**
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index a474014f0a0f..019bb47df915 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -756,18 +756,12 @@ static void fimc_is_debugfs_remove(struct fimc_is *is)
is->debugfs_entry = NULL;
}
-static int fimc_is_debugfs_create(struct fimc_is *is)
+static void fimc_is_debugfs_create(struct fimc_is *is)
{
- struct dentry *dentry;
-
is->debugfs_entry = debugfs_create_dir("fimc_is", NULL);
- dentry = debugfs_create_file("fw_log", S_IRUGO, is->debugfs_entry,
- is, &fimc_is_fops);
- if (!dentry)
- fimc_is_debugfs_remove(is);
-
- return is->debugfs_entry == NULL ? -EIO : 0;
+ debugfs_create_file("fw_log", S_IRUGO, is->debugfs_entry, is,
+ &fimc_is_fops);
}
static int fimc_is_runtime_resume(struct device *dev);
@@ -853,9 +847,7 @@ static int fimc_is_probe(struct platform_device *pdev)
if (ret < 0)
goto err_pm;
- ret = fimc_is_debugfs_create(is);
- if (ret < 0)
- goto err_sd;
+ fimc_is_debugfs_create(is);
ret = fimc_is_request_firmware(is, FIMC_IS_FW_FILENAME);
if (ret < 0)
@@ -868,7 +860,6 @@ static int fimc_is_probe(struct platform_device *pdev)
err_dfs:
fimc_is_debugfs_remove(is);
-err_sd:
fimc_is_unregister_subdevs(is);
err_pm:
pm_runtime_put_noidle(dev);
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index cde0d254ec1c..a77c49b18511 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -305,8 +305,10 @@ static int fimc_isp_subdev_s_power(struct v4l2_subdev *sd, int on)
if (on) {
ret = pm_runtime_get_sync(&is->pdev->dev);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put(&is->pdev->dev);
return ret;
+ }
set_bit(IS_ST_PWR_ON, &is->state);
ret = fimc_is_start_firmware(is);
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index 9c666f663ab4..fdd0d369b192 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -471,7 +471,7 @@ static int fimc_lite_open(struct file *file)
set_bit(ST_FLITE_IN_USE, &fimc->state);
ret = pm_runtime_get_sync(&fimc->pdev->dev);
if (ret < 0)
- goto unlock;
+ goto err_pm;
ret = v4l2_fh_open(file);
if (ret < 0)
diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c
index 5ce2bdebd424..8764999a5fd7 100644
--- a/drivers/media/platform/exynos4-is/fimc-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-reg.c
@@ -606,6 +606,11 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc,
switch (source->fimc_bus_type) {
case FIMC_BUS_TYPE_ITU_601:
case FIMC_BUS_TYPE_ITU_656:
+ if (fimc_fmt_is_user_defined(f->fmt->color)) {
+ cfg |= FIMC_REG_CISRCFMT_ITU601_8BIT;
+ break;
+ }
+
for (i = 0; i < ARRAY_SIZE(pix_desc); i++) {
if (vc->ci_fmt.code == pix_desc[i].pixelcode) {
cfg = pix_desc[i].cisrcfmt;
@@ -707,10 +712,12 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
case FIMC_BUS_TYPE_ITU_601...FIMC_BUS_TYPE_ITU_656:
if (source->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
cfg |= FIMC_REG_CIGCTRL_SELCAM_ITU_A;
+ if (vid_cap->ci_fmt.code == MEDIA_BUS_FMT_JPEG_1X8)
+ cfg |= FIMC_REG_CIGCTRL_CAM_JPEG;
break;
case FIMC_BUS_TYPE_LCD_WRITEBACK_A:
cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
- /* fall through */
+ fallthrough;
case FIMC_BUS_TYPE_ISP_WRITEBACK:
if (fimc->variant->has_isp_wb)
cfg |= FIMC_REG_CIGCTRL_CAMIF_SELWB;
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index 16dd660137a8..e636c33e847b 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -19,6 +19,7 @@
#include <linux/of_platform.h>
#include <linux/of_device.h>
#include <linux/of_graph.h>
+#include <linux/pinctrl/consumer.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
@@ -92,7 +93,7 @@ static void fimc_pipeline_prepare(struct fimc_pipeline *p,
switch (sd->grp_id) {
case GRP_ID_SENSOR:
sensor = sd;
- /* fall through */
+ fallthrough;
case GRP_ID_FIMC_IS_SENSOR:
p->subdevs[IDX_SENSOR] = sd;
break;
@@ -289,11 +290,26 @@ static int __fimc_pipeline_s_stream(struct exynos_media_pipeline *ep, bool on)
{ IDX_CSIS, IDX_FLITE, IDX_FIMC, IDX_SENSOR, IDX_IS_ISP },
};
struct fimc_pipeline *p = to_fimc_pipeline(ep);
- struct fimc_md *fmd = entity_to_fimc_mdev(&p->subdevs[IDX_CSIS]->entity);
enum fimc_subdev_index sd_id;
int i, ret = 0;
if (p->subdevs[IDX_SENSOR] == NULL) {
+ struct fimc_md *fmd;
+ struct v4l2_subdev *sd = p->subdevs[IDX_CSIS];
+
+ if (!sd)
+ sd = p->subdevs[IDX_FIMC];
+
+ if (!sd) {
+ /*
+ * If neither CSIS nor FIMC was set up,
+ * it's impossible to have any sensors
+ */
+ return -ENODEV;
+ }
+
+ fmd = entity_to_fimc_mdev(&sd->entity);
+
if (!fmd->user_subdev_api) {
/*
* Sensor must be already discovered if we
@@ -379,21 +395,15 @@ static void fimc_md_pipelines_free(struct fimc_md *fmd)
}
}
-/* Parse port node and register as a sub-device any sensor specified there. */
-static int fimc_md_parse_port_node(struct fimc_md *fmd,
- struct device_node *port,
- unsigned int index)
+static int fimc_md_parse_one_endpoint(struct fimc_md *fmd,
+ struct device_node *ep)
{
+ int index = fmd->num_sensors;
struct fimc_source_info *pd = &fmd->sensor[index].pdata;
- struct device_node *rem, *ep, *np;
+ struct device_node *rem, *np;
struct v4l2_fwnode_endpoint endpoint = { .bus_type = 0 };
int ret;
- /* Assume here a port node can have only one endpoint node. */
- ep = of_get_next_child(port, NULL);
- if (!ep)
- return 0;
-
ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &endpoint);
if (ret) {
of_node_put(ep);
@@ -467,13 +477,28 @@ static int fimc_md_parse_port_node(struct fimc_md *fmd,
return 0;
}
+/* Parse port node and register as a sub-device any sensor specified there. */
+static int fimc_md_parse_port_node(struct fimc_md *fmd,
+ struct device_node *port)
+{
+ struct device_node *ep;
+ int ret;
+
+ for_each_child_of_node(port, ep) {
+ ret = fimc_md_parse_one_endpoint(fmd, ep);
+ if (ret < 0)
+ return ret;
+ }
+
+ return 0;
+}
+
/* Register all SoC external sub-devices */
static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
{
struct device_node *parent = fmd->pdev->dev.of_node;
struct device_node *ports = NULL;
struct device_node *node;
- int index = 0;
int ret;
/*
@@ -484,8 +509,10 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
return -ENXIO;
ret = pm_runtime_get_sync(fmd->pmf);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put(fmd->pmf);
return ret;
+ }
fmd->num_sensors = 0;
@@ -500,13 +527,12 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
if (!port)
continue;
- ret = fimc_md_parse_port_node(fmd, port, index);
+ ret = fimc_md_parse_port_node(fmd, port);
of_node_put(port);
if (ret < 0) {
of_node_put(node);
goto cleanup;
}
- index++;
}
/* Attach sensors listed in the parallel-ports node */
@@ -515,12 +541,11 @@ static int fimc_md_register_sensor_entities(struct fimc_md *fmd)
goto rpm_put;
for_each_child_of_node(ports, node) {
- ret = fimc_md_parse_port_node(fmd, node, index);
+ ret = fimc_md_parse_port_node(fmd, node);
if (ret < 0) {
of_node_put(node);
goto cleanup;
}
- index++;
}
of_node_put(ports);
@@ -1254,28 +1279,6 @@ static ssize_t fimc_md_sysfs_store(struct device *dev,
static DEVICE_ATTR(subdev_conf_mode, S_IWUSR | S_IRUGO,
fimc_md_sysfs_show, fimc_md_sysfs_store);
-static int fimc_md_get_pinctrl(struct fimc_md *fmd)
-{
- struct device *dev = &fmd->pdev->dev;
- struct fimc_pinctrl *pctl = &fmd->pinctl;
-
- pctl->pinctrl = devm_pinctrl_get(dev);
- if (IS_ERR(pctl->pinctrl))
- return PTR_ERR(pctl->pinctrl);
-
- pctl->state_default = pinctrl_lookup_state(pctl->pinctrl,
- PINCTRL_STATE_DEFAULT);
- if (IS_ERR(pctl->state_default))
- return PTR_ERR(pctl->state_default);
-
- pctl->state_idle = pinctrl_lookup_state(pctl->pinctrl,
- PINCTRL_STATE_IDLE);
- if (IS_ERR(pctl->state_idle))
- return PTR_ERR(pctl->state_idle);
-
- return 0;
-}
-
static int cam_clk_prepare(struct clk_hw *hw)
{
struct cam_clk *camclk = to_cam_clk(hw);
@@ -1431,6 +1434,7 @@ static int fimc_md_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct v4l2_device *v4l2_dev;
+ struct pinctrl *pinctrl;
struct fimc_md *fmd;
int ret;
@@ -1467,8 +1471,9 @@ static int fimc_md_probe(struct platform_device *pdev)
if (ret)
goto err_v4l2dev;
- ret = fimc_md_get_pinctrl(fmd);
- if (ret < 0) {
+ pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(pinctrl)) {
+ ret = PTR_ERR(pinctrl);
if (ret != EPROBE_DEFER)
dev_err(dev, "Failed to get pinctrl: %d\n", ret);
goto err_clk;
diff --git a/drivers/media/platform/exynos4-is/media-dev.h b/drivers/media/platform/exynos4-is/media-dev.h
index 4b8f9ac52ebc..9447fafe23c6 100644
--- a/drivers/media/platform/exynos4-is/media-dev.h
+++ b/drivers/media/platform/exynos4-is/media-dev.h
@@ -27,8 +27,6 @@
#define FIMC_IS_OF_NODE_NAME "fimc-is"
#define CSIS_OF_NODE_NAME "csis"
-#define PINCTRL_STATE_IDLE "idle"
-
#define FIMC_MAX_SENSORS 4
#define FIMC_MAX_CAMCLKS 2
#define DEFAULT_SENSOR_CLK_FREQ 24000000U
@@ -109,9 +107,6 @@ struct cam_clk {
* @media_dev: top level media device
* @v4l2_dev: top level v4l2_device holding up the subdevs
* @pdev: platform device this media device is hooked up into
- * @pinctrl: camera port pinctrl handle
- * @state_default: pinctrl default state handle
- * @state_idle: pinctrl idle state handle
* @cam_clk_provider: CAMCLK clock provider structure
* @user_subdev_api: true if subdevs are not configured by the host driver
* @slock: spinlock protecting @sensor array
@@ -131,12 +126,6 @@ struct fimc_md {
struct v4l2_device v4l2_dev;
struct platform_device *pdev;
- struct fimc_pinctrl {
- struct pinctrl *pinctrl;
- struct pinctrl_state *state_default;
- struct pinctrl_state *state_idle;
- } pinctl;
-
struct cam_clk_provider {
struct clk *clks[FIMC_MAX_CAMCLKS];
struct clk_onecell_data clk_data;
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index 540151bbf58f..1aac167abb17 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -510,8 +510,10 @@ static int s5pcsis_s_stream(struct v4l2_subdev *sd, int enable)
if (enable) {
s5pcsis_clear_counters(state);
ret = pm_runtime_get_sync(&state->pdev->dev);
- if (ret && ret != 1)
+ if (ret && ret != 1) {
+ pm_runtime_put_noidle(&state->pdev->dev);
return ret;
+ }
}
mutex_lock(&state->lock);
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index 84633a3b8475..4f2a0f992905 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -32,7 +32,7 @@
#define VIU_VERSION "0.5.1"
/* Allow building this driver with COMPILE_TEST */
-#if !defined(CONFIG_PPC) && !defined(CONFIG_MICROBLAZE)
+#if !defined(CONFIG_PPC) && !defined(CONFIG_MICROBLAZE) && !defined(CONFIG_M68K)
#define out_be32(v, a) iowrite32be(a, (void __iomem *)v)
#define in_be32(a) ioread32be((void __iomem *)a)
#endif
diff --git a/drivers/media/platform/marvell-ccic/cafe-driver.c b/drivers/media/platform/marvell-ccic/cafe-driver.c
index 58b9915ac7a4..00f623d62c96 100644
--- a/drivers/media/platform/marvell-ccic/cafe-driver.c
+++ b/drivers/media/platform/marvell-ccic/cafe-driver.c
@@ -497,6 +497,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
cam = kzalloc(sizeof(struct cafe_camera), GFP_KERNEL);
if (cam == NULL)
goto out;
+ pci_set_drvdata(pdev, cam);
cam->pdev = pdev;
mcam = &cam->mcam;
mcam->chip_id = MCAM_CAFE;
@@ -592,8 +593,7 @@ static void cafe_shutdown(struct cafe_camera *cam)
static void cafe_pci_remove(struct pci_dev *pdev)
{
- struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
- struct cafe_camera *cam = to_cam(v4l2_dev);
+ struct cafe_camera *cam = pci_get_drvdata(pdev);
if (cam == NULL) {
printk(KERN_WARNING "pci_remove on unknown pdev %p\n", pdev);
@@ -609,8 +609,7 @@ static void cafe_pci_remove(struct pci_dev *pdev)
*/
static int __maybe_unused cafe_pci_suspend(struct device *dev)
{
- struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
- struct cafe_camera *cam = to_cam(v4l2_dev);
+ struct cafe_camera *cam = dev_get_drvdata(dev);
mccic_suspend(&cam->mcam);
return 0;
@@ -619,8 +618,7 @@ static int __maybe_unused cafe_pci_suspend(struct device *dev)
static int __maybe_unused cafe_pci_resume(struct device *dev)
{
- struct v4l2_device *v4l2_dev = dev_get_drvdata(dev);
- struct cafe_camera *cam = to_cam(v4l2_dev);
+ struct cafe_camera *cam = dev_get_drvdata(dev);
cafe_ctlr_init(&cam->mcam);
return mccic_resume(&cam->mcam);
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index 3d4242b8182b..c012fd2e1d29 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -24,6 +24,7 @@
#include <linux/clk.h>
#include <linux/clk-provider.h>
#include <linux/videodev2.h>
+#include <linux/pm_runtime.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-ctrls.h>
@@ -388,7 +389,7 @@ static int mcam_alloc_dma_bufs(struct mcam_camera *cam, int loadtime)
dma_free_coherent(cam->dev, cam->dma_buf_size,
cam->dma_bufs[0], cam->dma_handles[0]);
cam->nbufs = 0;
- /* fall-through */
+ fallthrough;
case 0:
cam_err(cam, "Insufficient DMA buffers, cannot operate\n");
return -ENOMEM;
@@ -438,9 +439,9 @@ static void mcam_ctlr_dma_vmalloc(struct mcam_camera *cam)
/*
* Copy data out to user space in the vmalloc case
*/
-static void mcam_frame_tasklet(unsigned long data)
+static void mcam_frame_tasklet(struct tasklet_struct *t)
{
- struct mcam_camera *cam = (struct mcam_camera *) data;
+ struct mcam_camera *cam = from_tasklet(cam, t, s_tasklet);
int i;
unsigned long flags;
struct mcam_vb_buffer *buf;
@@ -895,30 +896,6 @@ static void mcam_ctlr_power_down(struct mcam_camera *cam)
/* ---------------------------------------------------------------------- */
/*
- * Controller clocks.
- */
-static void mcam_clk_enable(struct mcam_camera *mcam)
-{
- unsigned int i;
-
- for (i = 0; i < NR_MCAM_CLK; i++) {
- if (!IS_ERR(mcam->clk[i]))
- clk_prepare_enable(mcam->clk[i]);
- }
-}
-
-static void mcam_clk_disable(struct mcam_camera *mcam)
-{
- int i;
-
- for (i = NR_MCAM_CLK - 1; i >= 0; i--) {
- if (!IS_ERR(mcam->clk[i]))
- clk_disable_unprepare(mcam->clk[i]);
- }
-}
-
-/* ---------------------------------------------------------------------- */
-/*
* Master sensor clock.
*/
static int mclk_prepare(struct clk_hw *hw)
@@ -1323,8 +1300,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam)
break;
case B_vmalloc:
#ifdef MCAM_MODE_VMALLOC
- tasklet_init(&cam->s_tasklet, mcam_frame_tasklet,
- (unsigned long) cam);
+ tasklet_setup(&cam->s_tasklet, mcam_frame_tasklet);
vq->ops = &mcam_vb2_ops;
vq->mem_ops = &vb2_vmalloc_memops;
cam->dma_setup = mcam_ctlr_dma_vmalloc;
@@ -1633,7 +1609,7 @@ static int mcam_v4l_open(struct file *filp)
ret = sensor_call(cam, core, s_power, 1);
if (ret)
goto out;
- mcam_clk_enable(cam);
+ pm_runtime_get_sync(cam->dev);
__mcam_cam_reset(cam);
mcam_set_config_needed(cam, 1);
}
@@ -1656,7 +1632,7 @@ static int mcam_v4l_release(struct file *filp)
if (last_open) {
mcam_disable_mipi(cam);
sensor_call(cam, core, s_power, 0);
- mcam_clk_disable(cam);
+ pm_runtime_put(cam->dev);
if (cam->buffer_mode == B_vmalloc && alloc_bufs_at_read)
mcam_free_dma_bufs(cam);
}
@@ -1977,7 +1953,6 @@ void mccic_suspend(struct mcam_camera *cam)
mcam_ctlr_stop_dma(cam);
sensor_call(cam, core, s_power, 0);
- mcam_clk_disable(cam);
cam->state = cstate;
}
mutex_unlock(&cam->s_mutex);
@@ -1990,7 +1965,6 @@ int mccic_resume(struct mcam_camera *cam)
mutex_lock(&cam->s_mutex);
if (!list_empty(&cam->vdev.fh_list)) {
- mcam_clk_enable(cam);
ret = sensor_call(cam, core, s_power, 1);
if (ret) {
mutex_unlock(&cam->s_mutex);
diff --git a/drivers/media/platform/marvell-ccic/mmp-driver.c b/drivers/media/platform/marvell-ccic/mmp-driver.c
index 92b92255dac6..cd902b180669 100644
--- a/drivers/media/platform/marvell-ccic/mmp-driver.c
+++ b/drivers/media/platform/marvell-ccic/mmp-driver.c
@@ -20,6 +20,7 @@
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
#include <linux/io.h>
#include <linux/list.h>
#include <linux/pm.h>
@@ -47,49 +48,6 @@ static inline struct mmp_camera *mcam_to_cam(struct mcam_camera *mcam)
}
/*
- * A silly little infrastructure so we can keep track of our devices.
- * Chances are that we will never have more than one of them, but
- * the Armada 610 *does* have two controllers...
- */
-
-static LIST_HEAD(mmpcam_devices);
-static struct mutex mmpcam_devices_lock;
-
-static void mmpcam_add_device(struct mmp_camera *cam)
-{
- mutex_lock(&mmpcam_devices_lock);
- list_add(&cam->devlist, &mmpcam_devices);
- mutex_unlock(&mmpcam_devices_lock);
-}
-
-static void mmpcam_remove_device(struct mmp_camera *cam)
-{
- mutex_lock(&mmpcam_devices_lock);
- list_del(&cam->devlist);
- mutex_unlock(&mmpcam_devices_lock);
-}
-
-/*
- * Platform dev remove passes us a platform_device, and there's
- * no handy unused drvdata to stash a backpointer in. So just
- * dig it out of our list.
- */
-static struct mmp_camera *mmpcam_find_device(struct platform_device *pdev)
-{
- struct mmp_camera *cam;
-
- mutex_lock(&mmpcam_devices_lock);
- list_for_each_entry(cam, &mmpcam_devices, devlist) {
- if (cam->pdev == pdev) {
- mutex_unlock(&mmpcam_devices_lock);
- return cam;
- }
- }
- mutex_unlock(&mmpcam_devices_lock);
- return NULL;
-}
-
-/*
* calc the dphy register values
* There are three dphy registers being used.
* dphy[0] - CSI2_DPHY3
@@ -227,6 +185,7 @@ static int mmpcam_probe(struct platform_device *pdev)
cam = devm_kzalloc(&pdev->dev, sizeof(*cam), GFP_KERNEL);
if (cam == NULL)
return -ENOMEM;
+ platform_set_drvdata(pdev, cam);
cam->pdev = pdev;
INIT_LIST_HEAD(&cam->devlist);
@@ -313,11 +272,11 @@ static int mmpcam_probe(struct platform_device *pdev)
cam->irq = res->start;
ret = devm_request_irq(&pdev->dev, cam->irq, mmpcam_irq, IRQF_SHARED,
"mmp-camera", mcam);
- if (ret == 0) {
- mmpcam_add_device(cam);
- return 0;
- }
+ if (ret)
+ goto out;
+ pm_runtime_enable(&pdev->dev);
+ return 0;
out:
fwnode_handle_put(mcam->asd.match.fwnode);
mccic_shutdown(mcam);
@@ -330,14 +289,14 @@ static int mmpcam_remove(struct mmp_camera *cam)
{
struct mcam_camera *mcam = &cam->mcam;
- mmpcam_remove_device(cam);
mccic_shutdown(mcam);
+ pm_runtime_force_suspend(mcam->dev);
return 0;
}
static int mmpcam_platform_remove(struct platform_device *pdev)
{
- struct mmp_camera *cam = mmpcam_find_device(pdev);
+ struct mmp_camera *cam = platform_get_drvdata(pdev);
if (cam == NULL)
return -ENODEV;
@@ -347,26 +306,57 @@ static int mmpcam_platform_remove(struct platform_device *pdev)
/*
* Suspend/resume support.
*/
-#ifdef CONFIG_PM
-static int mmpcam_suspend(struct platform_device *pdev, pm_message_t state)
+static int mmpcam_runtime_resume(struct device *dev)
+{
+ struct mmp_camera *cam = dev_get_drvdata(dev);
+ struct mcam_camera *mcam = &cam->mcam;
+ unsigned int i;
+
+ for (i = 0; i < NR_MCAM_CLK; i++) {
+ if (!IS_ERR(mcam->clk[i]))
+ clk_prepare_enable(mcam->clk[i]);
+ }
+
+ return 0;
+}
+
+static int mmpcam_runtime_suspend(struct device *dev)
+{
+ struct mmp_camera *cam = dev_get_drvdata(dev);
+ struct mcam_camera *mcam = &cam->mcam;
+ int i;
+
+ for (i = NR_MCAM_CLK - 1; i >= 0; i--) {
+ if (!IS_ERR(mcam->clk[i]))
+ clk_disable_unprepare(mcam->clk[i]);
+ }
+
+ return 0;
+}
+
+static int __maybe_unused mmpcam_suspend(struct device *dev)
{
- struct mmp_camera *cam = mmpcam_find_device(pdev);
+ struct mmp_camera *cam = dev_get_drvdata(dev);
- if (state.event != PM_EVENT_SUSPEND)
- return 0;
- mccic_suspend(&cam->mcam);
+ if (!pm_runtime_suspended(dev))
+ mccic_suspend(&cam->mcam);
return 0;
}
-static int mmpcam_resume(struct platform_device *pdev)
+static int __maybe_unused mmpcam_resume(struct device *dev)
{
- struct mmp_camera *cam = mmpcam_find_device(pdev);
+ struct mmp_camera *cam = dev_get_drvdata(dev);
- return mccic_resume(&cam->mcam);
+ if (!pm_runtime_suspended(dev))
+ return mccic_resume(&cam->mcam);
+ return 0;
}
-#endif
+static const struct dev_pm_ops mmpcam_pm_ops = {
+ SET_RUNTIME_PM_OPS(mmpcam_runtime_suspend, mmpcam_runtime_resume, NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(mmpcam_suspend, mmpcam_resume)
+};
static const struct of_device_id mmpcam_of_match[] = {
{ .compatible = "marvell,mmp2-ccic", },
@@ -377,32 +367,11 @@ MODULE_DEVICE_TABLE(of, mmpcam_of_match);
static struct platform_driver mmpcam_driver = {
.probe = mmpcam_probe,
.remove = mmpcam_platform_remove,
-#ifdef CONFIG_PM
- .suspend = mmpcam_suspend,
- .resume = mmpcam_resume,
-#endif
.driver = {
.name = "mmp-camera",
.of_match_table = of_match_ptr(mmpcam_of_match),
+ .pm = &mmpcam_pm_ops,
}
};
-
-static int __init mmpcam_init_module(void)
-{
- mutex_init(&mmpcam_devices_lock);
- return platform_driver_register(&mmpcam_driver);
-}
-
-static void __exit mmpcam_exit_module(void)
-{
- platform_driver_unregister(&mmpcam_driver);
- /*
- * platform_driver_unregister() should have emptied the list
- */
- if (!list_empty(&mmpcam_devices))
- printk(KERN_ERR "mmp_camera leaving devices behind\n");
-}
-
-module_init(mmpcam_init_module);
-module_exit(mmpcam_exit_module);
+module_platform_driver(mmpcam_driver);
diff --git a/drivers/media/platform/mtk-jpeg/Makefile b/drivers/media/platform/mtk-jpeg/Makefile
index 92a4fc046bfe..76c33aad0f3f 100644
--- a/drivers/media/platform/mtk-jpeg/Makefile
+++ b/drivers/media/platform/mtk-jpeg/Makefile
@@ -1,3 +1,6 @@
# SPDX-License-Identifier: GPL-2.0-only
-mtk_jpeg-objs := mtk_jpeg_core.o mtk_jpeg_hw.o mtk_jpeg_parse.o
+mtk_jpeg-objs := mtk_jpeg_core.o \
+ mtk_jpeg_dec_hw.o \
+ mtk_jpeg_dec_parse.o \
+ mtk_jpeg_enc_hw.o
obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
index 61fed1e35a00..227245ccaedc 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
@@ -3,6 +3,7 @@
* Copyright (c) 2016 MediaTek Inc.
* Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
* Rick Chang <rick.chang@mediatek.com>
+ * Xia Jiang <xia.jiang@mediatek.com>
*/
#include <linux/clk.h>
@@ -23,15 +24,64 @@
#include <media/videobuf2-dma-contig.h>
#include <soc/mediatek/smi.h>
-#include "mtk_jpeg_hw.h"
+#include "mtk_jpeg_enc_hw.h"
+#include "mtk_jpeg_dec_hw.h"
#include "mtk_jpeg_core.h"
-#include "mtk_jpeg_parse.h"
+#include "mtk_jpeg_dec_parse.h"
-static struct mtk_jpeg_fmt mtk_jpeg_formats[] = {
+static struct mtk_jpeg_fmt mtk_jpeg_enc_formats[] = {
{
.fourcc = V4L2_PIX_FMT_JPEG,
.colplanes = 1,
- .flags = MTK_JPEG_FMT_FLAG_DEC_OUTPUT,
+ .flags = MTK_JPEG_FMT_FLAG_CAPTURE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .hw_format = JPEG_ENC_YUV_FORMAT_NV12,
+ .h_sample = {4, 4},
+ .v_sample = {4, 2},
+ .colplanes = 2,
+ .h_align = 4,
+ .v_align = 4,
+ .flags = MTK_JPEG_FMT_FLAG_OUTPUT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .hw_format = JEPG_ENC_YUV_FORMAT_NV21,
+ .h_sample = {4, 4},
+ .v_sample = {4, 2},
+ .colplanes = 2,
+ .h_align = 4,
+ .v_align = 4,
+ .flags = MTK_JPEG_FMT_FLAG_OUTPUT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .hw_format = JPEG_ENC_YUV_FORMAT_YUYV,
+ .h_sample = {8},
+ .v_sample = {4},
+ .colplanes = 1,
+ .h_align = 5,
+ .v_align = 3,
+ .flags = MTK_JPEG_FMT_FLAG_OUTPUT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .hw_format = JPEG_ENC_YUV_FORMAT_YVYU,
+ .h_sample = {8},
+ .v_sample = {4},
+ .colplanes = 1,
+ .h_align = 5,
+ .v_align = 3,
+ .flags = MTK_JPEG_FMT_FLAG_OUTPUT,
+ },
+};
+
+static struct mtk_jpeg_fmt mtk_jpeg_dec_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .colplanes = 1,
+ .flags = MTK_JPEG_FMT_FLAG_OUTPUT,
},
{
.fourcc = V4L2_PIX_FMT_YUV420M,
@@ -40,7 +90,7 @@ static struct mtk_jpeg_fmt mtk_jpeg_formats[] = {
.colplanes = 3,
.h_align = 5,
.v_align = 4,
- .flags = MTK_JPEG_FMT_FLAG_DEC_CAPTURE,
+ .flags = MTK_JPEG_FMT_FLAG_CAPTURE,
},
{
.fourcc = V4L2_PIX_FMT_YUV422M,
@@ -49,27 +99,27 @@ static struct mtk_jpeg_fmt mtk_jpeg_formats[] = {
.colplanes = 3,
.h_align = 5,
.v_align = 3,
- .flags = MTK_JPEG_FMT_FLAG_DEC_CAPTURE,
+ .flags = MTK_JPEG_FMT_FLAG_CAPTURE,
},
};
-#define MTK_JPEG_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_formats)
-
-enum {
- MTK_JPEG_BUF_FLAGS_INIT = 0,
- MTK_JPEG_BUF_FLAGS_LAST_FRAME = 1,
-};
+#define MTK_JPEG_ENC_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_enc_formats)
+#define MTK_JPEG_DEC_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_dec_formats)
struct mtk_jpeg_src_buf {
struct vb2_v4l2_buffer b;
struct list_head list;
- int flags;
struct mtk_jpeg_dec_param dec_param;
};
static int debug;
module_param(debug, int, 0644);
+static inline struct mtk_jpeg_ctx *ctrl_to_ctx(struct v4l2_ctrl *ctrl)
+{
+ return container_of(ctrl->handler, struct mtk_jpeg_ctx, ctrl_hdl);
+}
+
static inline struct mtk_jpeg_ctx *mtk_jpeg_fh_to_ctx(struct v4l2_fh *fh)
{
return container_of(fh, struct mtk_jpeg_ctx, fh);
@@ -86,14 +136,61 @@ static int mtk_jpeg_querycap(struct file *file, void *priv,
{
struct mtk_jpeg_dev *jpeg = video_drvdata(file);
- strscpy(cap->driver, MTK_JPEG_NAME " decoder", sizeof(cap->driver));
- strscpy(cap->card, MTK_JPEG_NAME " decoder", sizeof(cap->card));
+ strscpy(cap->driver, jpeg->variant->dev_name, sizeof(cap->driver));
+ strscpy(cap->card, jpeg->variant->dev_name, sizeof(cap->card));
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
dev_name(jpeg->dev));
return 0;
}
+static int vidioc_jpeg_enc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct mtk_jpeg_ctx *ctx = ctrl_to_ctx(ctrl);
+
+ switch (ctrl->id) {
+ case V4L2_CID_JPEG_RESTART_INTERVAL:
+ ctx->restart_interval = ctrl->val;
+ break;
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ ctx->enc_quality = ctrl->val;
+ break;
+ case V4L2_CID_JPEG_ACTIVE_MARKER:
+ ctx->enable_exif = ctrl->val & V4L2_JPEG_ACTIVE_MARKER_APP1;
+ break;
+ }
+
+ return 0;
+}
+
+static const struct v4l2_ctrl_ops mtk_jpeg_enc_ctrl_ops = {
+ .s_ctrl = vidioc_jpeg_enc_s_ctrl,
+};
+
+static int mtk_jpeg_enc_ctrls_setup(struct mtk_jpeg_ctx *ctx)
+{
+ const struct v4l2_ctrl_ops *ops = &mtk_jpeg_enc_ctrl_ops;
+ struct v4l2_ctrl_handler *handler = &ctx->ctrl_hdl;
+
+ v4l2_ctrl_handler_init(handler, 3);
+
+ v4l2_ctrl_new_std(handler, ops, V4L2_CID_JPEG_RESTART_INTERVAL, 0, 100,
+ 1, 0);
+ v4l2_ctrl_new_std(handler, ops, V4L2_CID_JPEG_COMPRESSION_QUALITY, 48,
+ 100, 1, 90);
+ v4l2_ctrl_new_std(handler, ops, V4L2_CID_JPEG_ACTIVE_MARKER, 0,
+ V4L2_JPEG_ACTIVE_MARKER_APP1, 0, 0);
+
+ if (handler->error) {
+ v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
+ return handler->error;
+ }
+
+ v4l2_ctrl_handler_setup(&ctx->ctrl_hdl);
+
+ return 0;
+}
+
static int mtk_jpeg_enum_fmt(struct mtk_jpeg_fmt *mtk_jpeg_formats, int n,
struct v4l2_fmtdesc *f, u32 type)
{
@@ -118,15 +215,23 @@ static int mtk_jpeg_enum_fmt(struct mtk_jpeg_fmt *mtk_jpeg_formats, int n,
static int mtk_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f,
- MTK_JPEG_FMT_FLAG_DEC_CAPTURE);
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+
+ return mtk_jpeg_enum_fmt(jpeg->variant->formats,
+ jpeg->variant->num_formats, f,
+ MTK_JPEG_FMT_FLAG_CAPTURE);
}
static int mtk_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f,
- MTK_JPEG_FMT_FLAG_DEC_OUTPUT);
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+
+ return mtk_jpeg_enum_fmt(jpeg->variant->formats,
+ jpeg->variant->num_formats, f,
+ MTK_JPEG_FMT_FLAG_OUTPUT);
}
static struct mtk_jpeg_q_data *mtk_jpeg_get_q_data(struct mtk_jpeg_ctx *ctx,
@@ -137,126 +242,63 @@ static struct mtk_jpeg_q_data *mtk_jpeg_get_q_data(struct mtk_jpeg_ctx *ctx,
return &ctx->cap_q;
}
-static struct mtk_jpeg_fmt *mtk_jpeg_find_format(struct mtk_jpeg_ctx *ctx,
- u32 pixelformat,
- unsigned int fmt_type)
+static struct mtk_jpeg_fmt *
+mtk_jpeg_find_format(struct mtk_jpeg_fmt *mtk_jpeg_formats, int num_formats,
+ u32 pixelformat, unsigned int fmt_type)
{
- unsigned int k, fmt_flag;
-
- fmt_flag = (fmt_type == MTK_JPEG_FMT_TYPE_OUTPUT) ?
- MTK_JPEG_FMT_FLAG_DEC_OUTPUT :
- MTK_JPEG_FMT_FLAG_DEC_CAPTURE;
+ unsigned int k;
+ struct mtk_jpeg_fmt *fmt;
- for (k = 0; k < MTK_JPEG_NUM_FORMATS; k++) {
- struct mtk_jpeg_fmt *fmt = &mtk_jpeg_formats[k];
+ for (k = 0; k < num_formats; k++) {
+ fmt = &mtk_jpeg_formats[k];
- if (fmt->fourcc == pixelformat && fmt->flags & fmt_flag)
+ if (fmt->fourcc == pixelformat && fmt->flags & fmt_type)
return fmt;
}
return NULL;
}
-static void mtk_jpeg_bound_align_image(u32 *w, unsigned int wmin,
- unsigned int wmax, unsigned int walign,
- u32 *h, unsigned int hmin,
- unsigned int hmax, unsigned int halign)
+static int mtk_jpeg_try_fmt_mplane(struct v4l2_pix_format_mplane *pix_mp,
+ struct mtk_jpeg_fmt *fmt)
{
- int width, height, w_step, h_step;
-
- width = *w;
- height = *h;
- w_step = 1 << walign;
- h_step = 1 << halign;
-
- v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
- if (*w < width && (*w + w_step) <= wmax)
- *w += w_step;
- if (*h < height && (*h + h_step) <= hmax)
- *h += h_step;
-}
-
-static void mtk_jpeg_adjust_fmt_mplane(struct mtk_jpeg_ctx *ctx,
- struct v4l2_format *f)
-{
- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
- struct mtk_jpeg_q_data *q_data;
- int i;
-
- q_data = mtk_jpeg_get_q_data(ctx, f->type);
-
- pix_mp->width = q_data->w;
- pix_mp->height = q_data->h;
- pix_mp->pixelformat = q_data->fmt->fourcc;
- pix_mp->num_planes = q_data->fmt->colplanes;
-
- for (i = 0; i < pix_mp->num_planes; i++) {
- pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i];
- pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
- }
-}
-
-static int mtk_jpeg_try_fmt_mplane(struct v4l2_format *f,
- struct mtk_jpeg_fmt *fmt,
- struct mtk_jpeg_ctx *ctx, int q_type)
-{
- struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
- struct mtk_jpeg_dev *jpeg = ctx->jpeg;
int i;
- memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
pix_mp->field = V4L2_FIELD_NONE;
- if (ctx->state != MTK_JPEG_INIT) {
- mtk_jpeg_adjust_fmt_mplane(ctx, f);
- goto end;
- }
-
pix_mp->num_planes = fmt->colplanes;
pix_mp->pixelformat = fmt->fourcc;
- if (q_type == MTK_JPEG_FMT_TYPE_OUTPUT) {
+ if (fmt->fourcc == V4L2_PIX_FMT_JPEG) {
struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
- mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH,
- MTK_JPEG_MAX_WIDTH, 0,
- &pix_mp->height, MTK_JPEG_MIN_HEIGHT,
- MTK_JPEG_MAX_HEIGHT, 0);
+ pix_mp->height = clamp(pix_mp->height, MTK_JPEG_MIN_HEIGHT,
+ MTK_JPEG_MAX_HEIGHT);
+ pix_mp->width = clamp(pix_mp->width, MTK_JPEG_MIN_WIDTH,
+ MTK_JPEG_MAX_WIDTH);
- memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
pfmt->bytesperline = 0;
/* Source size must be aligned to 128 */
- pfmt->sizeimage = mtk_jpeg_align(pfmt->sizeimage, 128);
+ pfmt->sizeimage = round_up(pfmt->sizeimage, 128);
if (pfmt->sizeimage == 0)
pfmt->sizeimage = MTK_JPEG_DEFAULT_SIZEIMAGE;
- goto end;
+ return 0;
}
- /* type is MTK_JPEG_FMT_TYPE_CAPTURE */
- mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH,
- MTK_JPEG_MAX_WIDTH, fmt->h_align,
- &pix_mp->height, MTK_JPEG_MIN_HEIGHT,
- MTK_JPEG_MAX_HEIGHT, fmt->v_align);
+ /* other fourcc */
+ pix_mp->height = clamp(round_up(pix_mp->height, fmt->v_align),
+ MTK_JPEG_MIN_HEIGHT, MTK_JPEG_MAX_HEIGHT);
+ pix_mp->width = clamp(round_up(pix_mp->width, fmt->h_align),
+ MTK_JPEG_MIN_WIDTH, MTK_JPEG_MAX_WIDTH);
for (i = 0; i < fmt->colplanes; i++) {
struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i];
u32 stride = pix_mp->width * fmt->h_sample[i] / 4;
u32 h = pix_mp->height * fmt->v_sample[i] / 4;
- memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
pfmt->bytesperline = stride;
pfmt->sizeimage = stride * h;
}
-end:
- v4l2_dbg(2, debug, &jpeg->v4l2_dev, "wxh:%ux%u\n",
- pix_mp->width, pix_mp->height);
- for (i = 0; i < pix_mp->num_planes; i++) {
- v4l2_dbg(2, debug, &jpeg->v4l2_dev,
- "plane[%d] bpl=%u, size=%u\n",
- i,
- pix_mp->plane_fmt[i].bytesperline,
- pix_mp->plane_fmt[i].sizeimage);
- }
return 0;
}
@@ -276,16 +318,15 @@ static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv,
q_data = mtk_jpeg_get_q_data(ctx, f->type);
- memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
- pix_mp->width = q_data->w;
- pix_mp->height = q_data->h;
+ pix_mp->width = q_data->pix_mp.width;
+ pix_mp->height = q_data->pix_mp.height;
pix_mp->field = V4L2_FIELD_NONE;
pix_mp->pixelformat = q_data->fmt->fourcc;
pix_mp->num_planes = q_data->fmt->colplanes;
- pix_mp->colorspace = ctx->colorspace;
- pix_mp->ycbcr_enc = ctx->ycbcr_enc;
- pix_mp->xfer_func = ctx->xfer_func;
- pix_mp->quantization = ctx->quantization;
+ pix_mp->colorspace = q_data->pix_mp.colorspace;
+ pix_mp->ycbcr_enc = q_data->pix_mp.ycbcr_enc;
+ pix_mp->xfer_func = q_data->pix_mp.xfer_func;
+ pix_mp->quantization = q_data->pix_mp.quantization;
v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) g_fmt:%c%c%c%c wxh:%ux%u\n",
f->type,
@@ -298,9 +339,8 @@ static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv,
for (i = 0; i < pix_mp->num_planes; i++) {
struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i];
- pfmt->bytesperline = q_data->bytesperline[i];
- pfmt->sizeimage = q_data->sizeimage[i];
- memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+ pfmt->bytesperline = q_data->pix_mp.plane_fmt[i].bytesperline;
+ pfmt->sizeimage = q_data->pix_mp.plane_fmt[i].sizeimage;
v4l2_dbg(1, debug, &jpeg->v4l2_dev,
"plane[%d] bpl=%u, size=%u\n",
@@ -315,10 +355,13 @@ static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv,
struct v4l2_format *f)
{
struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
struct mtk_jpeg_fmt *fmt;
- fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
- MTK_JPEG_FMT_TYPE_CAPTURE);
+ fmt = mtk_jpeg_find_format(jpeg->variant->formats,
+ jpeg->variant->num_formats,
+ f->fmt.pix_mp.pixelformat,
+ MTK_JPEG_FMT_FLAG_CAPTURE);
if (!fmt)
fmt = ctx->cap_q.fmt;
@@ -329,17 +372,25 @@ static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv,
(fmt->fourcc >> 16 & 0xff),
(fmt->fourcc >> 24 & 0xff));
- return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_CAPTURE);
+ if (ctx->state != MTK_JPEG_INIT) {
+ mtk_jpeg_g_fmt_vid_mplane(file, priv, f);
+ return 0;
+ }
+
+ return mtk_jpeg_try_fmt_mplane(&f->fmt.pix_mp, fmt);
}
static int mtk_jpeg_try_fmt_vid_out_mplane(struct file *file, void *priv,
struct v4l2_format *f)
{
struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
struct mtk_jpeg_fmt *fmt;
- fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
- MTK_JPEG_FMT_TYPE_OUTPUT);
+ fmt = mtk_jpeg_find_format(jpeg->variant->formats,
+ jpeg->variant->num_formats,
+ f->fmt.pix_mp.pixelformat,
+ MTK_JPEG_FMT_FLAG_OUTPUT);
if (!fmt)
fmt = ctx->out_q.fmt;
@@ -350,17 +401,21 @@ static int mtk_jpeg_try_fmt_vid_out_mplane(struct file *file, void *priv,
(fmt->fourcc >> 16 & 0xff),
(fmt->fourcc >> 24 & 0xff));
- return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_OUTPUT);
+ if (ctx->state != MTK_JPEG_INIT) {
+ mtk_jpeg_g_fmt_vid_mplane(file, priv, f);
+ return 0;
+ }
+
+ return mtk_jpeg_try_fmt_mplane(&f->fmt.pix_mp, fmt);
}
static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx,
- struct v4l2_format *f)
+ struct v4l2_format *f, unsigned int fmt_type)
{
struct vb2_queue *vq;
struct mtk_jpeg_q_data *q_data = NULL;
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
struct mtk_jpeg_dev *jpeg = ctx->jpeg;
- unsigned int f_type;
int i;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
@@ -374,16 +429,17 @@ static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx,
return -EBUSY;
}
- f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
- MTK_JPEG_FMT_TYPE_OUTPUT : MTK_JPEG_FMT_TYPE_CAPTURE;
-
- q_data->fmt = mtk_jpeg_find_format(ctx, pix_mp->pixelformat, f_type);
- q_data->w = pix_mp->width;
- q_data->h = pix_mp->height;
- ctx->colorspace = pix_mp->colorspace;
- ctx->ycbcr_enc = pix_mp->ycbcr_enc;
- ctx->xfer_func = pix_mp->xfer_func;
- ctx->quantization = pix_mp->quantization;
+ q_data->fmt = mtk_jpeg_find_format(jpeg->variant->formats,
+ jpeg->variant->num_formats,
+ pix_mp->pixelformat, fmt_type);
+ q_data->pix_mp.width = pix_mp->width;
+ q_data->pix_mp.height = pix_mp->height;
+ q_data->enc_crop_rect.width = pix_mp->width;
+ q_data->enc_crop_rect.height = pix_mp->height;
+ q_data->pix_mp.colorspace = V4L2_COLORSPACE_SRGB;
+ q_data->pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ q_data->pix_mp.xfer_func = V4L2_XFER_FUNC_SRGB;
+ q_data->pix_mp.quantization = V4L2_QUANTIZATION_FULL_RANGE;
v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) s_fmt:%c%c%c%c wxh:%ux%u\n",
f->type,
@@ -391,15 +447,18 @@ static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx,
(q_data->fmt->fourcc >> 8 & 0xff),
(q_data->fmt->fourcc >> 16 & 0xff),
(q_data->fmt->fourcc >> 24 & 0xff),
- q_data->w, q_data->h);
+ q_data->pix_mp.width, q_data->pix_mp.height);
for (i = 0; i < q_data->fmt->colplanes; i++) {
- q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline;
- q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
+ q_data->pix_mp.plane_fmt[i].bytesperline =
+ pix_mp->plane_fmt[i].bytesperline;
+ q_data->pix_mp.plane_fmt[i].sizeimage =
+ pix_mp->plane_fmt[i].sizeimage;
v4l2_dbg(1, debug, &jpeg->v4l2_dev,
"plane[%d] bpl=%u, size=%u\n",
- i, q_data->bytesperline[i], q_data->sizeimage[i]);
+ i, q_data->pix_mp.plane_fmt[i].bytesperline,
+ q_data->pix_mp.plane_fmt[i].sizeimage);
}
return 0;
@@ -414,7 +473,8 @@ static int mtk_jpeg_s_fmt_vid_out_mplane(struct file *file, void *priv,
if (ret)
return ret;
- return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f);
+ return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f,
+ MTK_JPEG_FMT_FLAG_OUTPUT);
}
static int mtk_jpeg_s_fmt_vid_cap_mplane(struct file *file, void *priv,
@@ -426,7 +486,8 @@ static int mtk_jpeg_s_fmt_vid_cap_mplane(struct file *file, void *priv,
if (ret)
return ret;
- return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f);
+ return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f,
+ MTK_JPEG_FMT_FLAG_CAPTURE);
}
static void mtk_jpeg_queue_src_chg_event(struct mtk_jpeg_ctx *ctx)
@@ -446,13 +507,38 @@ static int mtk_jpeg_subscribe_event(struct v4l2_fh *fh,
switch (sub->type) {
case V4L2_EVENT_SOURCE_CHANGE:
return v4l2_src_change_event_subscribe(fh, sub);
+ }
+
+ return v4l2_ctrl_subscribe_event(fh, sub);
+}
+
+static int mtk_jpeg_enc_g_selection(struct file *file, void *priv,
+ struct v4l2_selection *s)
+{
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_CROP:
+ s->r = ctx->out_q.enc_crop_rect;
+ break;
+ case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_CROP_DEFAULT:
+ s->r.width = ctx->out_q.pix_mp.width;
+ s->r.height = ctx->out_q.pix_mp.height;
+ s->r.left = 0;
+ s->r.top = 0;
+ break;
default:
return -EINVAL;
}
+ return 0;
}
-static int mtk_jpeg_g_selection(struct file *file, void *priv,
- struct v4l2_selection *s)
+static int mtk_jpeg_dec_g_selection(struct file *file, void *priv,
+ struct v4l2_selection *s)
{
struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
@@ -462,15 +548,15 @@ static int mtk_jpeg_g_selection(struct file *file, void *priv,
switch (s->target) {
case V4L2_SEL_TGT_COMPOSE:
case V4L2_SEL_TGT_COMPOSE_DEFAULT:
- s->r.width = ctx->out_q.w;
- s->r.height = ctx->out_q.h;
+ s->r.width = ctx->out_q.pix_mp.width;
+ s->r.height = ctx->out_q.pix_mp.height;
s->r.left = 0;
s->r.top = 0;
break;
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
case V4L2_SEL_TGT_COMPOSE_PADDED:
- s->r.width = ctx->cap_q.w;
- s->r.height = ctx->cap_q.h;
+ s->r.width = ctx->cap_q.pix_mp.width;
+ s->r.height = ctx->cap_q.pix_mp.height;
s->r.left = 0;
s->r.top = 0;
break;
@@ -480,53 +566,57 @@ static int mtk_jpeg_g_selection(struct file *file, void *priv,
return 0;
}
-static int mtk_jpeg_s_selection(struct file *file, void *priv,
- struct v4l2_selection *s)
+static int mtk_jpeg_enc_s_selection(struct file *file, void *priv,
+ struct v4l2_selection *s)
{
struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
- if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (s->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
switch (s->target) {
- case V4L2_SEL_TGT_COMPOSE:
+ case V4L2_SEL_TGT_CROP:
s->r.left = 0;
s->r.top = 0;
- s->r.width = ctx->out_q.w;
- s->r.height = ctx->out_q.h;
+ s->r.width = min(s->r.width, ctx->out_q.pix_mp.width);
+ s->r.height = min(s->r.height, ctx->out_q.pix_mp.height);
+ ctx->out_q.enc_crop_rect = s->r;
break;
default:
return -EINVAL;
}
+
return 0;
}
-static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
-{
- struct v4l2_fh *fh = file->private_data;
- struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
- struct vb2_queue *vq;
- struct vb2_buffer *vb;
- struct mtk_jpeg_src_buf *jpeg_src_buf;
-
- if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
- goto end;
+static const struct v4l2_ioctl_ops mtk_jpeg_enc_ioctl_ops = {
+ .vidioc_querycap = mtk_jpeg_querycap,
+ .vidioc_enum_fmt_vid_cap = mtk_jpeg_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = mtk_jpeg_enum_fmt_vid_out,
+ .vidioc_try_fmt_vid_cap_mplane = mtk_jpeg_try_fmt_vid_cap_mplane,
+ .vidioc_try_fmt_vid_out_mplane = mtk_jpeg_try_fmt_vid_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = mtk_jpeg_g_fmt_vid_mplane,
+ .vidioc_g_fmt_vid_out_mplane = mtk_jpeg_g_fmt_vid_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = mtk_jpeg_s_fmt_vid_cap_mplane,
+ .vidioc_s_fmt_vid_out_mplane = mtk_jpeg_s_fmt_vid_out_mplane,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
+ .vidioc_subscribe_event = mtk_jpeg_subscribe_event,
+ .vidioc_g_selection = mtk_jpeg_enc_g_selection,
+ .vidioc_s_selection = mtk_jpeg_enc_s_selection,
- vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type);
- if (buf->index >= vq->num_buffers) {
- dev_err(ctx->jpeg->dev, "buffer index out of range\n");
- return -EINVAL;
- }
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
- vb = vb2_get_buffer(vq, buf->index);
- jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
- jpeg_src_buf->flags = (buf->m.planes[0].bytesused == 0) ?
- MTK_JPEG_BUF_FLAGS_LAST_FRAME : MTK_JPEG_BUF_FLAGS_INIT;
-end:
- return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf);
-}
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
-static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = {
+static const struct v4l2_ioctl_ops mtk_jpeg_dec_ioctl_ops = {
.vidioc_querycap = mtk_jpeg_querycap,
.vidioc_enum_fmt_vid_cap = mtk_jpeg_enum_fmt_vid_cap,
.vidioc_enum_fmt_vid_out = mtk_jpeg_enum_fmt_vid_out,
@@ -536,10 +626,9 @@ static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = {
.vidioc_g_fmt_vid_out_mplane = mtk_jpeg_g_fmt_vid_mplane,
.vidioc_s_fmt_vid_cap_mplane = mtk_jpeg_s_fmt_vid_cap_mplane,
.vidioc_s_fmt_vid_out_mplane = mtk_jpeg_s_fmt_vid_out_mplane,
- .vidioc_qbuf = mtk_jpeg_qbuf,
+ .vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
.vidioc_subscribe_event = mtk_jpeg_subscribe_event,
- .vidioc_g_selection = mtk_jpeg_g_selection,
- .vidioc_s_selection = mtk_jpeg_s_selection,
+ .vidioc_g_selection = mtk_jpeg_dec_g_selection,
.vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
.vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
@@ -571,9 +660,16 @@ static int mtk_jpeg_queue_setup(struct vb2_queue *q,
if (!q_data)
return -EINVAL;
+ if (*num_planes) {
+ for (i = 0; i < *num_planes; i++)
+ if (sizes[i] < q_data->pix_mp.plane_fmt[i].sizeimage)
+ return -EINVAL;
+ return 0;
+ }
+
*num_planes = q_data->fmt->colplanes;
for (i = 0; i < q_data->fmt->colplanes; i++) {
- sizes[i] = q_data->sizeimage[i];
+ sizes[i] = q_data->pix_mp.plane_fmt[i].sizeimage;
v4l2_dbg(1, debug, &jpeg->v4l2_dev, "sizeimage[%d]=%u\n",
i, sizes[i]);
}
@@ -585,14 +681,22 @@ static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb)
{
struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct mtk_jpeg_q_data *q_data = NULL;
+ struct v4l2_plane_pix_format plane_fmt = {};
int i;
q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type);
if (!q_data)
return -EINVAL;
- for (i = 0; i < q_data->fmt->colplanes; i++)
- vb2_set_plane_payload(vb, i, q_data->sizeimage[i]);
+ for (i = 0; i < q_data->fmt->colplanes; i++) {
+ plane_fmt = q_data->pix_mp.plane_fmt[i];
+ if (ctx->enable_exif &&
+ q_data->fmt->fourcc == V4L2_PIX_FMT_JPEG)
+ vb2_set_plane_payload(vb, i, plane_fmt.sizeimage +
+ MTK_JPEG_MAX_EXIF_SIZE);
+ else
+ vb2_set_plane_payload(vb, i, plane_fmt.sizeimage);
+ }
return 0;
}
@@ -604,14 +708,17 @@ static bool mtk_jpeg_check_resolution_change(struct mtk_jpeg_ctx *ctx,
struct mtk_jpeg_q_data *q_data;
q_data = &ctx->out_q;
- if (q_data->w != param->pic_w || q_data->h != param->pic_h) {
+ if (q_data->pix_mp.width != param->pic_w ||
+ q_data->pix_mp.height != param->pic_h) {
v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Picture size change\n");
return true;
}
q_data = &ctx->cap_q;
- if (q_data->fmt != mtk_jpeg_find_format(ctx, param->dst_fourcc,
- MTK_JPEG_FMT_TYPE_CAPTURE)) {
+ if (q_data->fmt !=
+ mtk_jpeg_find_format(jpeg->variant->formats,
+ jpeg->variant->num_formats, param->dst_fourcc,
+ MTK_JPEG_FMT_FLAG_CAPTURE)) {
v4l2_dbg(1, debug, &jpeg->v4l2_dev, "format change\n");
return true;
}
@@ -626,19 +733,20 @@ static void mtk_jpeg_set_queue_data(struct mtk_jpeg_ctx *ctx,
int i;
q_data = &ctx->out_q;
- q_data->w = param->pic_w;
- q_data->h = param->pic_h;
+ q_data->pix_mp.width = param->pic_w;
+ q_data->pix_mp.height = param->pic_h;
q_data = &ctx->cap_q;
- q_data->w = param->dec_w;
- q_data->h = param->dec_h;
- q_data->fmt = mtk_jpeg_find_format(ctx,
+ q_data->pix_mp.width = param->dec_w;
+ q_data->pix_mp.height = param->dec_h;
+ q_data->fmt = mtk_jpeg_find_format(jpeg->variant->formats,
+ jpeg->variant->num_formats,
param->dst_fourcc,
- MTK_JPEG_FMT_TYPE_CAPTURE);
+ MTK_JPEG_FMT_FLAG_CAPTURE);
for (i = 0; i < q_data->fmt->colplanes; i++) {
- q_data->bytesperline[i] = param->mem_stride[i];
- q_data->sizeimage[i] = param->comp_size[i];
+ q_data->pix_mp.plane_fmt[i].bytesperline = param->mem_stride[i];
+ q_data->pix_mp.plane_fmt[i].sizeimage = param->comp_size[i];
}
v4l2_dbg(1, debug, &jpeg->v4l2_dev,
@@ -651,7 +759,18 @@ static void mtk_jpeg_set_queue_data(struct mtk_jpeg_ctx *ctx,
param->dec_w, param->dec_h);
}
-static void mtk_jpeg_buf_queue(struct vb2_buffer *vb)
+static void mtk_jpeg_enc_buf_queue(struct vb2_buffer *vb)
+{
+ struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+
+ v4l2_dbg(2, debug, &jpeg->v4l2_dev, "(%d) buf_q id=%d, vb=%p\n",
+ vb->vb2_queue->type, vb->index, vb);
+
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, to_vb2_v4l2_buffer(vb));
+}
+
+static void mtk_jpeg_dec_buf_queue(struct vb2_buffer *vb)
{
struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
struct mtk_jpeg_dec_param *param;
@@ -669,10 +788,6 @@ static void mtk_jpeg_buf_queue(struct vb2_buffer *vb)
param = &jpeg_src_buf->dec_param;
memset(param, 0, sizeof(*param));
- if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) {
- v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Got eos\n");
- goto end;
- }
header_valid = mtk_jpeg_parse(param, (u8 *)vb2_plane_vaddr(vb, 0),
vb2_get_plane_payload(vb, 0));
if (!header_valid) {
@@ -703,24 +818,16 @@ static struct vb2_v4l2_buffer *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx,
return v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
}
-static int mtk_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
+static void mtk_jpeg_enc_stop_streaming(struct vb2_queue *q)
{
struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
struct vb2_v4l2_buffer *vb;
- int ret = 0;
- ret = pm_runtime_get_sync(ctx->jpeg->dev);
- if (ret < 0)
- goto err;
-
- return 0;
-err:
while ((vb = mtk_jpeg_buf_remove(ctx, q->type)))
- v4l2_m2m_buf_done(vb, VB2_BUF_STATE_QUEUED);
- return ret;
+ v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
}
-static void mtk_jpeg_stop_streaming(struct vb2_queue *q)
+static void mtk_jpeg_dec_stop_streaming(struct vb2_queue *q)
{
struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
struct vb2_v4l2_buffer *vb;
@@ -744,18 +851,24 @@ static void mtk_jpeg_stop_streaming(struct vb2_queue *q)
while ((vb = mtk_jpeg_buf_remove(ctx, q->type)))
v4l2_m2m_buf_done(vb, VB2_BUF_STATE_ERROR);
-
- pm_runtime_put_sync(ctx->jpeg->dev);
}
-static const struct vb2_ops mtk_jpeg_qops = {
+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,
+};
+
+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_buf_queue,
+ .buf_queue = mtk_jpeg_enc_buf_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
- .start_streaming = mtk_jpeg_start_streaming,
- .stop_streaming = mtk_jpeg_stop_streaming,
+ .stop_streaming = mtk_jpeg_enc_stop_streaming,
};
static void mtk_jpeg_set_dec_src(struct mtk_jpeg_ctx *ctx,
@@ -764,8 +877,8 @@ static void mtk_jpeg_set_dec_src(struct mtk_jpeg_ctx *ctx,
{
bs->str_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
bs->end_addr = bs->str_addr +
- mtk_jpeg_align(vb2_get_plane_payload(src_buf, 0), 16);
- bs->size = mtk_jpeg_align(vb2_plane_size(src_buf, 0), 128);
+ round_up(vb2_get_plane_payload(src_buf, 0), 16);
+ bs->size = round_up(vb2_plane_size(src_buf, 0), 128);
}
static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx,
@@ -795,7 +908,49 @@ static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx,
return 0;
}
-static void mtk_jpeg_device_run(void *priv)
+static void mtk_jpeg_enc_device_run(void *priv)
+{
+ struct mtk_jpeg_ctx *ctx = priv;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+ unsigned long flags;
+ int ret;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+
+ ret = pm_runtime_get_sync(jpeg->dev);
+ if (ret < 0)
+ goto enc_end;
+
+ schedule_delayed_work(&jpeg->job_timeout_work,
+ msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
+
+ spin_lock_irqsave(&jpeg->hw_lock, flags);
+
+ /*
+ * Resetting the hardware every frame is to ensure that all the
+ * registers are cleared. This is a hardware requirement.
+ */
+ mtk_jpeg_enc_reset(jpeg->reg_base);
+
+ mtk_jpeg_set_enc_src(ctx, jpeg->reg_base, &src_buf->vb2_buf);
+ mtk_jpeg_set_enc_dst(ctx, jpeg->reg_base, &dst_buf->vb2_buf);
+ mtk_jpeg_set_enc_params(ctx, jpeg->reg_base);
+ mtk_jpeg_enc_start(jpeg->reg_base);
+ spin_unlock_irqrestore(&jpeg->hw_lock, flags);
+ return;
+
+enc_end:
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_buf_done(src_buf, buf_state);
+ v4l2_m2m_buf_done(dst_buf, buf_state);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static void mtk_jpeg_dec_device_run(void *priv)
{
struct mtk_jpeg_ctx *ctx = priv;
struct mtk_jpeg_dev *jpeg = ctx->jpeg;
@@ -805,19 +960,12 @@ static void mtk_jpeg_device_run(void *priv)
struct mtk_jpeg_src_buf *jpeg_src_buf;
struct mtk_jpeg_bs bs;
struct mtk_jpeg_fb fb;
- int i;
+ int ret;
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf);
- if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) {
- for (i = 0; i < dst_buf->vb2_buf.num_planes; i++)
- vb2_set_plane_payload(&dst_buf->vb2_buf, i, 0);
- buf_state = VB2_BUF_STATE_DONE;
- goto dec_end;
- }
-
if (mtk_jpeg_check_resolution_change(ctx, &jpeg_src_buf->dec_param)) {
mtk_jpeg_queue_src_chg_event(ctx);
ctx->state = MTK_JPEG_SOURCE_CHANGE;
@@ -825,16 +973,23 @@ static void mtk_jpeg_device_run(void *priv)
return;
}
+ ret = pm_runtime_get_sync(jpeg->dev);
+ if (ret < 0)
+ goto dec_end;
+
+ schedule_delayed_work(&jpeg->job_timeout_work,
+ msecs_to_jiffies(MTK_JPEG_HW_TIMEOUT_MSEC));
+
mtk_jpeg_set_dec_src(ctx, &src_buf->vb2_buf, &bs);
if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, &dst_buf->vb2_buf, &fb))
goto dec_end;
spin_lock_irqsave(&jpeg->hw_lock, flags);
- mtk_jpeg_dec_reset(jpeg->dec_reg_base);
- mtk_jpeg_dec_set_config(jpeg->dec_reg_base,
+ mtk_jpeg_dec_reset(jpeg->reg_base);
+ mtk_jpeg_dec_set_config(jpeg->reg_base,
&jpeg_src_buf->dec_param, &bs, &fb);
- mtk_jpeg_dec_start(jpeg->dec_reg_base);
+ mtk_jpeg_dec_start(jpeg->reg_base);
spin_unlock_irqrestore(&jpeg->hw_lock, flags);
return;
@@ -846,29 +1001,34 @@ dec_end:
v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
}
-static int mtk_jpeg_job_ready(void *priv)
+static int mtk_jpeg_dec_job_ready(void *priv)
{
struct mtk_jpeg_ctx *ctx = priv;
return (ctx->state == MTK_JPEG_RUNNING) ? 1 : 0;
}
-static const struct v4l2_m2m_ops mtk_jpeg_m2m_ops = {
- .device_run = mtk_jpeg_device_run,
- .job_ready = mtk_jpeg_job_ready,
+static const struct v4l2_m2m_ops mtk_jpeg_enc_m2m_ops = {
+ .device_run = mtk_jpeg_enc_device_run,
+};
+
+static const struct v4l2_m2m_ops mtk_jpeg_dec_m2m_ops = {
+ .device_run = mtk_jpeg_dec_device_run,
+ .job_ready = mtk_jpeg_dec_job_ready,
};
static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
struct vb2_queue *dst_vq)
{
struct mtk_jpeg_ctx *ctx = priv;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct mtk_jpeg_src_buf);
- src_vq->ops = &mtk_jpeg_qops;
+ src_vq->ops = jpeg->variant->qops;
src_vq->mem_ops = &vb2_dma_contig_memops;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->jpeg->lock;
@@ -881,7 +1041,7 @@ static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- dst_vq->ops = &mtk_jpeg_qops;
+ dst_vq->ops = jpeg->variant->qops;
dst_vq->mem_ops = &vb2_dma_contig_memops;
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->jpeg->lock;
@@ -898,17 +1058,68 @@ static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg)
ret = mtk_smi_larb_get(jpeg->larb);
if (ret)
dev_err(jpeg->dev, "mtk_smi_larb_get larbvdec fail %d\n", ret);
- clk_prepare_enable(jpeg->clk_jdec_smi);
- clk_prepare_enable(jpeg->clk_jdec);
+
+ ret = clk_bulk_prepare_enable(jpeg->variant->num_clks,
+ jpeg->variant->clks);
+ if (ret)
+ dev_err(jpeg->dev, "Failed to open jpeg clk: %d\n", ret);
}
static void mtk_jpeg_clk_off(struct mtk_jpeg_dev *jpeg)
{
- clk_disable_unprepare(jpeg->clk_jdec);
- clk_disable_unprepare(jpeg->clk_jdec_smi);
+ clk_bulk_disable_unprepare(jpeg->variant->num_clks,
+ jpeg->variant->clks);
mtk_smi_larb_put(jpeg->larb);
}
+static irqreturn_t mtk_jpeg_enc_done(struct mtk_jpeg_dev *jpeg)
+{
+ struct mtk_jpeg_ctx *ctx;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+ enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+ u32 result_size;
+
+ ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+ if (!ctx) {
+ v4l2_err(&jpeg->v4l2_dev, "Context is NULL\n");
+ return IRQ_HANDLED;
+ }
+
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ result_size = mtk_jpeg_enc_get_file_size(jpeg->reg_base);
+ vb2_set_plane_payload(&dst_buf->vb2_buf, 0, result_size);
+
+ buf_state = VB2_BUF_STATE_DONE;
+
+ v4l2_m2m_buf_done(src_buf, buf_state);
+ v4l2_m2m_buf_done(dst_buf, buf_state);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+ pm_runtime_put(ctx->jpeg->dev);
+ return IRQ_HANDLED;
+}
+
+static irqreturn_t mtk_jpeg_enc_irq(int irq, void *priv)
+{
+ struct mtk_jpeg_dev *jpeg = priv;
+ u32 irq_status;
+ irqreturn_t ret = IRQ_NONE;
+
+ cancel_delayed_work(&jpeg->job_timeout_work);
+
+ irq_status = readl(jpeg->reg_base + JPEG_ENC_INT_STS) &
+ JPEG_ENC_INT_STATUS_MASK_ALLIRQ;
+ if (irq_status)
+ writel(0, jpeg->reg_base + JPEG_ENC_INT_STS);
+
+ if (!(irq_status & JPEG_ENC_INT_STATUS_DONE))
+ return ret;
+
+ ret = mtk_jpeg_enc_done(jpeg);
+ return ret;
+}
+
static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv)
{
struct mtk_jpeg_dev *jpeg = priv;
@@ -920,7 +1131,9 @@ static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv)
u32 dec_ret;
int i;
- dec_ret = mtk_jpeg_dec_get_int_status(jpeg->dec_reg_base);
+ cancel_delayed_work(&jpeg->job_timeout_work);
+
+ dec_ret = mtk_jpeg_dec_get_int_status(jpeg->reg_base);
dec_irq_ret = mtk_jpeg_dec_enum_result(dec_ret);
ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
if (!ctx) {
@@ -933,7 +1146,7 @@ static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv)
jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(&src_buf->vb2_buf);
if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW)
- mtk_jpeg_dec_reset(jpeg->dec_reg_base);
+ mtk_jpeg_dec_reset(jpeg->reg_base);
if (dec_irq_ret != MTK_JPEG_DEC_RESULT_EOF_DONE) {
dev_err(jpeg->dev, "decode failed\n");
@@ -950,39 +1163,42 @@ dec_end:
v4l2_m2m_buf_done(src_buf, buf_state);
v4l2_m2m_buf_done(dst_buf, buf_state);
v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+ pm_runtime_put(ctx->jpeg->dev);
return IRQ_HANDLED;
}
static void mtk_jpeg_set_default_params(struct mtk_jpeg_ctx *ctx)
{
struct mtk_jpeg_q_data *q = &ctx->out_q;
- int i;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
- ctx->colorspace = V4L2_COLORSPACE_JPEG,
- ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
- ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
- ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ ctx->fh.ctrl_handler = &ctx->ctrl_hdl;
+ q->pix_mp.colorspace = V4L2_COLORSPACE_SRGB;
+ q->pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ q->pix_mp.quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ q->pix_mp.xfer_func = V4L2_XFER_FUNC_SRGB;
- q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
- MTK_JPEG_FMT_TYPE_OUTPUT);
- q->w = MTK_JPEG_MIN_WIDTH;
- q->h = MTK_JPEG_MIN_HEIGHT;
- q->bytesperline[0] = 0;
- q->sizeimage[0] = MTK_JPEG_DEFAULT_SIZEIMAGE;
+ q->fmt = mtk_jpeg_find_format(jpeg->variant->formats,
+ jpeg->variant->num_formats,
+ jpeg->variant->out_q_default_fourcc,
+ MTK_JPEG_FMT_FLAG_OUTPUT);
+ q->pix_mp.width = MTK_JPEG_MIN_WIDTH;
+ q->pix_mp.height = MTK_JPEG_MIN_HEIGHT;
+ mtk_jpeg_try_fmt_mplane(&q->pix_mp, q->fmt);
q = &ctx->cap_q;
- q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_YUV420M,
- MTK_JPEG_FMT_TYPE_CAPTURE);
- q->w = MTK_JPEG_MIN_WIDTH;
- q->h = MTK_JPEG_MIN_HEIGHT;
-
- for (i = 0; i < q->fmt->colplanes; i++) {
- u32 stride = q->w * q->fmt->h_sample[i] / 4;
- u32 h = q->h * q->fmt->v_sample[i] / 4;
-
- q->bytesperline[i] = stride;
- q->sizeimage[i] = stride * h;
- }
+ q->fmt = mtk_jpeg_find_format(jpeg->variant->formats,
+ jpeg->variant->num_formats,
+ jpeg->variant->cap_q_default_fourcc,
+ MTK_JPEG_FMT_FLAG_CAPTURE);
+ q->pix_mp.colorspace = V4L2_COLORSPACE_SRGB;
+ q->pix_mp.ycbcr_enc = V4L2_YCBCR_ENC_601;
+ q->pix_mp.quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ q->pix_mp.xfer_func = V4L2_XFER_FUNC_SRGB;
+ q->pix_mp.width = MTK_JPEG_MIN_WIDTH;
+ q->pix_mp.height = MTK_JPEG_MIN_HEIGHT;
+
+ mtk_jpeg_try_fmt_mplane(&q->pix_mp, q->fmt);
}
static int mtk_jpeg_open(struct file *file)
@@ -1013,6 +1229,15 @@ static int mtk_jpeg_open(struct file *file)
goto error;
}
+ if (jpeg->variant->cap_q_default_fourcc == V4L2_PIX_FMT_JPEG) {
+ ret = mtk_jpeg_enc_ctrls_setup(ctx);
+ if (ret) {
+ v4l2_err(&jpeg->v4l2_dev, "Failed to setup jpeg enc controls\n");
+ goto error;
+ }
+ } else {
+ v4l2_ctrl_handler_init(&ctx->ctrl_hdl, 0);
+ }
mtk_jpeg_set_default_params(ctx);
mutex_unlock(&jpeg->lock);
return 0;
@@ -1033,6 +1258,7 @@ static int mtk_jpeg_release(struct file *file)
mutex_lock(&jpeg->lock);
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ v4l2_ctrl_handler_free(&ctx->ctrl_hdl);
v4l2_fh_del(&ctx->fh);
v4l2_fh_exit(&ctx->fh);
kfree(ctx);
@@ -1049,10 +1275,20 @@ static const struct v4l2_file_operations mtk_jpeg_fops = {
.mmap = v4l2_m2m_fop_mmap,
};
+static struct clk_bulk_data mt8173_jpeg_dec_clocks[] = {
+ { .id = "jpgdec-smi" },
+ { .id = "jpgdec" },
+};
+
+static struct clk_bulk_data mtk_jpeg_clocks[] = {
+ { .id = "jpgenc" },
+};
+
static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg)
{
struct device_node *node;
struct platform_device *pdev;
+ int ret;
node = of_parse_phandle(jpeg->dev->of_node, "mediatek,larb", 0);
if (!node)
@@ -1066,19 +1302,40 @@ static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg)
jpeg->larb = &pdev->dev;
- jpeg->clk_jdec = devm_clk_get(jpeg->dev, "jpgdec");
- if (IS_ERR(jpeg->clk_jdec))
- return PTR_ERR(jpeg->clk_jdec);
+ ret = devm_clk_bulk_get(jpeg->dev, jpeg->variant->num_clks,
+ jpeg->variant->clks);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to get jpeg clock:%d\n", ret);
+ return ret;
+ }
- jpeg->clk_jdec_smi = devm_clk_get(jpeg->dev, "jpgdec-smi");
- return PTR_ERR_OR_ZERO(jpeg->clk_jdec_smi);
+ return 0;
}
+static void mtk_jpeg_job_timeout_work(struct work_struct *work)
+{
+ struct mtk_jpeg_dev *jpeg = container_of(work, struct mtk_jpeg_dev,
+ job_timeout_work.work);
+ struct mtk_jpeg_ctx *ctx;
+ struct vb2_v4l2_buffer *src_buf, *dst_buf;
+
+ ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+
+ jpeg->variant->hw_reset(jpeg->reg_base);
+
+ pm_runtime_put(jpeg->dev);
+
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+}
static int mtk_jpeg_probe(struct platform_device *pdev)
{
struct mtk_jpeg_dev *jpeg;
struct resource *res;
- int dec_irq;
+ int jpeg_irq;
int ret;
jpeg = devm_kzalloc(&pdev->dev, sizeof(*jpeg), GFP_KERNEL);
@@ -1088,28 +1345,27 @@ static int mtk_jpeg_probe(struct platform_device *pdev)
mutex_init(&jpeg->lock);
spin_lock_init(&jpeg->hw_lock);
jpeg->dev = &pdev->dev;
+ jpeg->variant = of_device_get_match_data(jpeg->dev);
+ INIT_DELAYED_WORK(&jpeg->job_timeout_work, mtk_jpeg_job_timeout_work);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- jpeg->dec_reg_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(jpeg->dec_reg_base)) {
- ret = PTR_ERR(jpeg->dec_reg_base);
+ jpeg->reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(jpeg->reg_base)) {
+ ret = PTR_ERR(jpeg->reg_base);
return ret;
}
- res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- dec_irq = platform_get_irq(pdev, 0);
- if (!res || dec_irq < 0) {
- dev_err(&pdev->dev, "Failed to get dec_irq %d.\n", dec_irq);
- ret = -EINVAL;
- return ret;
+ jpeg_irq = platform_get_irq(pdev, 0);
+ if (jpeg_irq < 0) {
+ dev_err(&pdev->dev, "Failed to get jpeg_irq %d.\n", jpeg_irq);
+ return jpeg_irq;
}
- ret = devm_request_irq(&pdev->dev, dec_irq, mtk_jpeg_dec_irq, 0,
- pdev->name, jpeg);
+ ret = devm_request_irq(&pdev->dev, jpeg_irq,
+ jpeg->variant->irq_handler, 0, pdev->name, jpeg);
if (ret) {
- dev_err(&pdev->dev, "Failed to request dec_irq %d (%d)\n",
- dec_irq, ret);
- ret = -EINVAL;
+ dev_err(&pdev->dev, "Failed to request jpeg_irq %d (%d)\n",
+ jpeg_irq, ret);
goto err_req_irq;
}
@@ -1126,40 +1382,42 @@ static int mtk_jpeg_probe(struct platform_device *pdev)
goto err_dev_register;
}
- jpeg->m2m_dev = v4l2_m2m_init(&mtk_jpeg_m2m_ops);
+ jpeg->m2m_dev = v4l2_m2m_init(jpeg->variant->m2m_ops);
+
if (IS_ERR(jpeg->m2m_dev)) {
v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
ret = PTR_ERR(jpeg->m2m_dev);
goto err_m2m_init;
}
- jpeg->dec_vdev = video_device_alloc();
- if (!jpeg->dec_vdev) {
+ jpeg->vdev = video_device_alloc();
+ if (!jpeg->vdev) {
ret = -ENOMEM;
- goto err_dec_vdev_alloc;
+ goto err_vfd_jpeg_alloc;
}
- snprintf(jpeg->dec_vdev->name, sizeof(jpeg->dec_vdev->name),
- "%s-dec", MTK_JPEG_NAME);
- jpeg->dec_vdev->fops = &mtk_jpeg_fops;
- jpeg->dec_vdev->ioctl_ops = &mtk_jpeg_ioctl_ops;
- jpeg->dec_vdev->minor = -1;
- jpeg->dec_vdev->release = video_device_release;
- jpeg->dec_vdev->lock = &jpeg->lock;
- jpeg->dec_vdev->v4l2_dev = &jpeg->v4l2_dev;
- jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M;
- jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_M2M_MPLANE;
-
- ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_VIDEO, 3);
+ snprintf(jpeg->vdev->name, sizeof(jpeg->vdev->name),
+ "%s", jpeg->variant->dev_name);
+ jpeg->vdev->fops = &mtk_jpeg_fops;
+ jpeg->vdev->ioctl_ops = jpeg->variant->ioctl_ops;
+ jpeg->vdev->minor = -1;
+ jpeg->vdev->release = video_device_release;
+ jpeg->vdev->lock = &jpeg->lock;
+ jpeg->vdev->v4l2_dev = &jpeg->v4l2_dev;
+ jpeg->vdev->vfl_dir = VFL_DIR_M2M;
+ jpeg->vdev->device_caps = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_M2M_MPLANE;
+
+ ret = video_register_device(jpeg->vdev, VFL_TYPE_VIDEO, -1);
if (ret) {
v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
- goto err_dec_vdev_register;
+ goto err_vfd_jpeg_register;
}
- video_set_drvdata(jpeg->dec_vdev, jpeg);
+ video_set_drvdata(jpeg->vdev, jpeg);
v4l2_info(&jpeg->v4l2_dev,
- "decoder device registered as /dev/video%d (%d,%d)\n",
- jpeg->dec_vdev->num, VIDEO_MAJOR, jpeg->dec_vdev->minor);
+ "%s device registered as /dev/video%d (%d,%d)\n",
+ jpeg->variant->dev_name, jpeg->vdev->num,
+ VIDEO_MAJOR, jpeg->vdev->minor);
platform_set_drvdata(pdev, jpeg);
@@ -1167,10 +1425,10 @@ static int mtk_jpeg_probe(struct platform_device *pdev)
return 0;
-err_dec_vdev_register:
- video_device_release(jpeg->dec_vdev);
+err_vfd_jpeg_register:
+ video_device_release(jpeg->vdev);
-err_dec_vdev_alloc:
+err_vfd_jpeg_alloc:
v4l2_m2m_release(jpeg->m2m_dev);
err_m2m_init:
@@ -1190,8 +1448,8 @@ static int mtk_jpeg_remove(struct platform_device *pdev)
struct mtk_jpeg_dev *jpeg = platform_get_drvdata(pdev);
pm_runtime_disable(&pdev->dev);
- video_unregister_device(jpeg->dec_vdev);
- video_device_release(jpeg->dec_vdev);
+ video_unregister_device(jpeg->vdev);
+ video_device_release(jpeg->vdev);
v4l2_m2m_release(jpeg->m2m_dev);
v4l2_device_unregister(&jpeg->v4l2_dev);
@@ -1202,7 +1460,6 @@ static __maybe_unused int mtk_jpeg_pm_suspend(struct device *dev)
{
struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev);
- mtk_jpeg_dec_reset(jpeg->dec_reg_base);
mtk_jpeg_clk_off(jpeg);
return 0;
@@ -1213,31 +1470,28 @@ static __maybe_unused int mtk_jpeg_pm_resume(struct device *dev)
struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev);
mtk_jpeg_clk_on(jpeg);
- mtk_jpeg_dec_reset(jpeg->dec_reg_base);
return 0;
}
static __maybe_unused int mtk_jpeg_suspend(struct device *dev)
{
- int ret;
-
- if (pm_runtime_suspended(dev))
- return 0;
+ struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev);
- ret = mtk_jpeg_pm_suspend(dev);
- return ret;
+ v4l2_m2m_suspend(jpeg->m2m_dev);
+ return pm_runtime_force_suspend(dev);
}
static __maybe_unused int mtk_jpeg_resume(struct device *dev)
{
+ struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev);
int ret;
- if (pm_runtime_suspended(dev))
- return 0;
-
- ret = mtk_jpeg_pm_resume(dev);
+ ret = pm_runtime_force_resume(dev);
+ if (ret < 0)
+ return ret;
+ v4l2_m2m_resume(jpeg->m2m_dev);
return ret;
}
@@ -1246,14 +1500,48 @@ static const struct dev_pm_ops mtk_jpeg_pm_ops = {
SET_RUNTIME_PM_OPS(mtk_jpeg_pm_suspend, mtk_jpeg_pm_resume, NULL)
};
+static const struct mtk_jpeg_variant mt8173_jpeg_drvdata = {
+ .clks = mt8173_jpeg_dec_clocks,
+ .num_clks = ARRAY_SIZE(mt8173_jpeg_dec_clocks),
+ .formats = mtk_jpeg_dec_formats,
+ .num_formats = MTK_JPEG_DEC_NUM_FORMATS,
+ .qops = &mtk_jpeg_dec_qops,
+ .irq_handler = mtk_jpeg_dec_irq,
+ .hw_reset = mtk_jpeg_dec_reset,
+ .m2m_ops = &mtk_jpeg_dec_m2m_ops,
+ .dev_name = "mtk-jpeg-dec",
+ .ioctl_ops = &mtk_jpeg_dec_ioctl_ops,
+ .out_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+ .cap_q_default_fourcc = V4L2_PIX_FMT_YUV420M,
+};
+
+static const struct mtk_jpeg_variant mtk_jpeg_drvdata = {
+ .clks = mtk_jpeg_clocks,
+ .num_clks = ARRAY_SIZE(mtk_jpeg_clocks),
+ .formats = mtk_jpeg_enc_formats,
+ .num_formats = MTK_JPEG_ENC_NUM_FORMATS,
+ .qops = &mtk_jpeg_enc_qops,
+ .irq_handler = mtk_jpeg_enc_irq,
+ .hw_reset = mtk_jpeg_enc_reset,
+ .m2m_ops = &mtk_jpeg_enc_m2m_ops,
+ .dev_name = "mtk-jpeg-enc",
+ .ioctl_ops = &mtk_jpeg_enc_ioctl_ops,
+ .out_q_default_fourcc = V4L2_PIX_FMT_YUYV,
+ .cap_q_default_fourcc = V4L2_PIX_FMT_JPEG,
+};
+
static const struct of_device_id mtk_jpeg_match[] = {
{
.compatible = "mediatek,mt8173-jpgdec",
- .data = NULL,
+ .data = &mt8173_jpeg_drvdata,
},
{
.compatible = "mediatek,mt2701-jpgdec",
- .data = NULL,
+ .data = &mt8173_jpeg_drvdata,
+ },
+ {
+ .compatible = "mediatek,mtk-jpgenc",
+ .data = &mtk_jpeg_drvdata,
},
{},
};
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
index 999bd1427809..68e634f02e00 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
@@ -3,6 +3,7 @@
* Copyright (c) 2016 MediaTek Inc.
* Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
* Rick Chang <rick.chang@mediatek.com>
+ * Xia Jiang <xia.jiang@mediatek.com>
*/
#ifndef _MTK_JPEG_CORE_H
@@ -15,19 +16,28 @@
#define MTK_JPEG_NAME "mtk-jpeg"
-#define MTK_JPEG_FMT_FLAG_DEC_OUTPUT BIT(0)
-#define MTK_JPEG_FMT_FLAG_DEC_CAPTURE BIT(1)
+#define MTK_JPEG_COMP_MAX 3
-#define MTK_JPEG_FMT_TYPE_OUTPUT 1
-#define MTK_JPEG_FMT_TYPE_CAPTURE 2
+#define MTK_JPEG_FMT_FLAG_OUTPUT BIT(0)
+#define MTK_JPEG_FMT_FLAG_CAPTURE BIT(1)
-#define MTK_JPEG_MIN_WIDTH 32
-#define MTK_JPEG_MIN_HEIGHT 32
-#define MTK_JPEG_MAX_WIDTH 8192
-#define MTK_JPEG_MAX_HEIGHT 8192
+#define MTK_JPEG_MIN_WIDTH 32U
+#define MTK_JPEG_MIN_HEIGHT 32U
+#define MTK_JPEG_MAX_WIDTH 65535U
+#define MTK_JPEG_MAX_HEIGHT 65535U
#define MTK_JPEG_DEFAULT_SIZEIMAGE (1 * 1024 * 1024)
+#define MTK_JPEG_HW_TIMEOUT_MSEC 1000
+
+#define MTK_JPEG_MAX_EXIF_SIZE (64 * 1024)
+
+/**
+ * enum mtk_jpeg_ctx_state - states of the context state machine
+ * @MTK_JPEG_INIT: current state is initialized
+ * @MTK_JPEG_RUNNING: current state is running
+ * @MTK_JPEG_SOURCE_CHANGE: current state is source resolution change
+ */
enum mtk_jpeg_ctx_state {
MTK_JPEG_INIT = 0,
MTK_JPEG_RUNNING,
@@ -35,6 +45,36 @@ enum mtk_jpeg_ctx_state {
};
/**
+ * mtk_jpeg_variant - mtk jpeg driver variant
+ * @clks: clock names
+ * @num_clks: numbers of clock
+ * @format: jpeg driver's internal color format
+ * @num_format: number of format
+ * @qops: the callback of jpeg vb2_ops
+ * @irq_handler: jpeg irq handler callback
+ * @hw_reset: jpeg hardware reset callback
+ * @m2m_ops: the callback of jpeg v4l2_m2m_ops
+ * @dev_name: jpeg device name
+ * @ioctl_ops: the callback of jpeg v4l2_ioctl_ops
+ * @out_q_default_fourcc: output queue default fourcc
+ * @cap_q_default_fourcc: capture queue default fourcc
+ */
+struct mtk_jpeg_variant {
+ struct clk_bulk_data *clks;
+ int num_clks;
+ struct mtk_jpeg_fmt *formats;
+ int num_formats;
+ const struct vb2_ops *qops;
+ irqreturn_t (*irq_handler)(int irq, void *priv);
+ void (*hw_reset)(void __iomem *base);
+ const struct v4l2_m2m_ops *m2m_ops;
+ const char *dev_name;
+ const struct v4l2_ioctl_ops *ioctl_ops;
+ u32 out_q_default_fourcc;
+ u32 cap_q_default_fourcc;
+};
+
+/**
* struct mt_jpeg - JPEG IP abstraction
* @lock: the mutex protecting this structure
* @hw_lock: spinlock protecting the hw device resource
@@ -43,11 +83,11 @@ enum mtk_jpeg_ctx_state {
* @v4l2_dev: v4l2 device for mem2mem mode
* @m2m_dev: v4l2 mem2mem device data
* @alloc_ctx: videobuf2 memory allocator's context
- * @dec_vdev: video device node for decoder mem2mem mode
- * @dec_reg_base: JPEG registers mapping
- * @clk_jdec: JPEG hw working clock
- * @clk_jdec_smi: JPEG SMI bus clock
+ * @vdev: video device node for jpeg mem2mem mode
+ * @reg_base: JPEG registers mapping
* @larb: SMI device
+ * @job_timeout_work: IRQ timeout structure
+ * @variant: driver variant to be used
*/
struct mtk_jpeg_dev {
struct mutex lock;
@@ -57,16 +97,17 @@ struct mtk_jpeg_dev {
struct v4l2_device v4l2_dev;
struct v4l2_m2m_dev *m2m_dev;
void *alloc_ctx;
- struct video_device *dec_vdev;
- void __iomem *dec_reg_base;
- struct clk *clk_jdec;
- struct clk *clk_jdec_smi;
+ struct video_device *vdev;
+ void __iomem *reg_base;
struct device *larb;
+ struct delayed_work job_timeout_work;
+ const struct mtk_jpeg_variant *variant;
};
/**
* struct jpeg_fmt - driver's internal color format data
* @fourcc: the fourcc code, 0 if not applicable
+ * @hw_format: hardware format value
* @h_sample: horizontal sample count of plane in 4 * 4 pixel image
* @v_sample: vertical sample count of plane in 4 * 4 pixel image
* @colplanes: number of color planes (1 for packed formats)
@@ -76,6 +117,7 @@ struct mtk_jpeg_dev {
*/
struct mtk_jpeg_fmt {
u32 fourcc;
+ u32 hw_format;
int h_sample[VIDEO_MAX_PLANES];
int v_sample[VIDEO_MAX_PLANES];
int colplanes;
@@ -87,18 +129,13 @@ struct mtk_jpeg_fmt {
/**
* mtk_jpeg_q_data - parameters of one queue
* @fmt: driver-specific format of this queue
- * @w: image width
- * @h: image height
- * @bytesperline: distance in bytes between the leftmost pixels in two adjacent
- * lines
- * @sizeimage: image buffer size in bytes
+ * @pix_mp: multiplanar format
+ * @enc_crop_rect: jpeg encoder crop information
*/
struct mtk_jpeg_q_data {
struct mtk_jpeg_fmt *fmt;
- u32 w;
- u32 h;
- u32 bytesperline[VIDEO_MAX_PLANES];
- u32 sizeimage[VIDEO_MAX_PLANES];
+ struct v4l2_pix_format_mplane pix_mp;
+ struct v4l2_rect enc_crop_rect;
};
/**
@@ -107,13 +144,11 @@ struct mtk_jpeg_q_data {
* @out_q: source (output) queue information
* @cap_q: destination (capture) queue queue information
* @fh: V4L2 file handle
- * @dec_param parameters for HW decoding
* @state: state of the context
- * @header_valid: set if header has been parsed and valid
- * @colorspace: enum v4l2_colorspace; supplemental to pixelformat
- * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
- * @quantization: enum v4l2_quantization, colorspace quantization
- * @xfer_func: enum v4l2_xfer_func, colorspace transfer function
+ * @enable_exif: enable exif mode of jpeg encoder
+ * @enc_quality: jpeg encoder quality
+ * @restart_interval: jpeg encoder restart interval
+ * @ctrl_hdl: controls handler
*/
struct mtk_jpeg_ctx {
struct mtk_jpeg_dev *jpeg;
@@ -121,11 +156,10 @@ struct mtk_jpeg_ctx {
struct mtk_jpeg_q_data cap_q;
struct v4l2_fh fh;
enum mtk_jpeg_ctx_state state;
-
- enum v4l2_colorspace colorspace;
- enum v4l2_ycbcr_encoding ycbcr_enc;
- enum v4l2_quantization quantization;
- enum v4l2_xfer_func xfer_func;
+ bool enable_exif;
+ u8 enc_quality;
+ u8 restart_interval;
+ struct v4l2_ctrl_handler ctrl_hdl;
};
#endif /* _MTK_JPEG_CORE_H */
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_hw.c
index ddf0dfa78e20..afbbfd5d02bc 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_hw.c
@@ -9,7 +9,7 @@
#include <linux/kernel.h>
#include <media/videobuf2-core.h>
-#include "mtk_jpeg_hw.h"
+#include "mtk_jpeg_dec_hw.h"
#define MTK_JPEG_DUNUM_MASK(val) (((val) - 1) & 0x3)
@@ -153,10 +153,10 @@ static int mtk_jpeg_calc_dst_size(struct mtk_jpeg_dec_param *param)
param->sampling_w[i];
/* output format is 420/422 */
param->comp_w[i] = padding_w >> brz_w[i];
- param->comp_w[i] = mtk_jpeg_align(param->comp_w[i],
- MTK_JPEG_DCTSIZE);
- param->img_stride[i] = i ? mtk_jpeg_align(param->comp_w[i], 16)
- : mtk_jpeg_align(param->comp_w[i], 32);
+ param->comp_w[i] = round_up(param->comp_w[i],
+ MTK_JPEG_DCTSIZE);
+ param->img_stride[i] = i ? round_up(param->comp_w[i], 16)
+ : round_up(param->comp_w[i], 32);
ds_row_h[i] = (MTK_JPEG_DCTSIZE * param->sampling_h[i]);
}
param->dec_w = param->img_stride[0];
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_hw.h
index 9c6584eaad99..fa0d45fd7c34 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_hw.h
@@ -3,15 +3,16 @@
* Copyright (c) 2016 MediaTek Inc.
* Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
* Rick Chang <rick.chang@mediatek.com>
+ * Xia Jiang <xia.jiang@mediatek.com>
*/
-#ifndef _MTK_JPEG_HW_H
-#define _MTK_JPEG_HW_H
+#ifndef _MTK_JPEG_DEC_HW_H
+#define _MTK_JPEG_DEC_HW_H
#include <media/videobuf2-core.h>
#include "mtk_jpeg_core.h"
-#include "mtk_jpeg_reg.h"
+#include "mtk_jpeg_dec_reg.h"
enum {
MTK_JPEG_DEC_RESULT_EOF_DONE = 0,
@@ -54,11 +55,6 @@ struct mtk_jpeg_dec_param {
u8 uv_brz_w;
};
-static inline u32 mtk_jpeg_align(u32 val, u32 align)
-{
- return (val + align - 1) & ~(align - 1);
-}
-
struct mtk_jpeg_bs {
dma_addr_t str_addr;
dma_addr_t end_addr;
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_parse.c
index f862d38f3af7..b95c45791c29 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_parse.c
@@ -8,7 +8,7 @@
#include <linux/kernel.h>
#include <linux/videodev2.h>
-#include "mtk_jpeg_parse.h"
+#include "mtk_jpeg_dec_parse.h"
#define TEM 0x01
#define SOF0 0xc0
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_parse.h
index 0a48eeabaff2..2918f15811f8 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_parse.h
@@ -8,7 +8,7 @@
#ifndef _MTK_JPEG_PARSE_H
#define _MTK_JPEG_PARSE_H
-#include "mtk_jpeg_hw.h"
+#include "mtk_jpeg_dec_hw.h"
bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
u32 src_size);
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_reg.h
index 94db04e9cdb6..21ec8f96797f 100644
--- a/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_dec_reg.h
@@ -8,7 +8,6 @@
#ifndef _MTK_JPEG_REG_H
#define _MTK_JPEG_REG_H
-#define MTK_JPEG_COMP_MAX 3
#define MTK_JPEG_BLOCK_MAX 10
#define MTK_JPEG_DCTSIZE 8
@@ -20,29 +19,29 @@
#define BIT_INQST_MASK_ALLIRQ 0x37
#define JPGDEC_REG_RESET 0x0090
-#define JPGDEC_REG_BRZ_FACTOR 0x00F8
-#define JPGDEC_REG_DU_NUM 0x00FC
+#define JPGDEC_REG_BRZ_FACTOR 0x00f8
+#define JPGDEC_REG_DU_NUM 0x00fc
#define JPGDEC_REG_DEST_ADDR0_Y 0x0140
#define JPGDEC_REG_DEST_ADDR0_U 0x0144
#define JPGDEC_REG_DEST_ADDR0_V 0x0148
-#define JPGDEC_REG_DEST_ADDR1_Y 0x014C
+#define JPGDEC_REG_DEST_ADDR1_Y 0x014c
#define JPGDEC_REG_DEST_ADDR1_U 0x0150
#define JPGDEC_REG_DEST_ADDR1_V 0x0154
#define JPGDEC_REG_STRIDE_Y 0x0158
-#define JPGDEC_REG_STRIDE_UV 0x015C
+#define JPGDEC_REG_STRIDE_UV 0x015c
#define JPGDEC_REG_IMG_STRIDE_Y 0x0160
#define JPGDEC_REG_IMG_STRIDE_UV 0x0164
-#define JPGDEC_REG_WDMA_CTRL 0x016C
+#define JPGDEC_REG_WDMA_CTRL 0x016c
#define JPGDEC_REG_PAUSE_MCU_NUM 0x0170
-#define JPGDEC_REG_OPERATION_MODE 0x017C
+#define JPGDEC_REG_OPERATION_MODE 0x017c
#define JPGDEC_REG_FILE_ADDR 0x0200
-#define JPGDEC_REG_COMP_ID 0x020C
+#define JPGDEC_REG_COMP_ID 0x020c
#define JPGDEC_REG_TOTAL_MCU_NUM 0x0210
#define JPGDEC_REG_COMP0_DATA_UNIT_NUM 0x0224
-#define JPGDEC_REG_DU_CTRL 0x023C
+#define JPGDEC_REG_DU_CTRL 0x023c
#define JPGDEC_REG_TRIG 0x0240
#define JPGDEC_REG_FILE_BRP 0x0248
-#define JPGDEC_REG_FILE_TOTAL_SIZE 0x024C
+#define JPGDEC_REG_FILE_TOTAL_SIZE 0x024c
#define JPGDEC_REG_QT_ID 0x0270
#define JPGDEC_REG_INTERRUPT_STATUS 0x0274
#define JPGDEC_REG_STATUS 0x0278
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.c
new file mode 100644
index 000000000000..1cf037bf72dd
--- /dev/null
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.c
@@ -0,0 +1,154 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Xia Jiang <xia.jiang@mediatek.com>
+ *
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+
+#include "mtk_jpeg_enc_hw.h"
+
+static const struct mtk_jpeg_enc_qlt mtk_jpeg_enc_quality[] = {
+ {.quality_param = 34, .hardware_value = JPEG_ENC_QUALITY_Q34},
+ {.quality_param = 39, .hardware_value = JPEG_ENC_QUALITY_Q39},
+ {.quality_param = 48, .hardware_value = JPEG_ENC_QUALITY_Q48},
+ {.quality_param = 60, .hardware_value = JPEG_ENC_QUALITY_Q60},
+ {.quality_param = 64, .hardware_value = JPEG_ENC_QUALITY_Q64},
+ {.quality_param = 68, .hardware_value = JPEG_ENC_QUALITY_Q68},
+ {.quality_param = 74, .hardware_value = JPEG_ENC_QUALITY_Q74},
+ {.quality_param = 80, .hardware_value = JPEG_ENC_QUALITY_Q80},
+ {.quality_param = 82, .hardware_value = JPEG_ENC_QUALITY_Q82},
+ {.quality_param = 84, .hardware_value = JPEG_ENC_QUALITY_Q84},
+ {.quality_param = 87, .hardware_value = JPEG_ENC_QUALITY_Q87},
+ {.quality_param = 90, .hardware_value = JPEG_ENC_QUALITY_Q90},
+ {.quality_param = 92, .hardware_value = JPEG_ENC_QUALITY_Q92},
+ {.quality_param = 95, .hardware_value = JPEG_ENC_QUALITY_Q95},
+ {.quality_param = 97, .hardware_value = JPEG_ENC_QUALITY_Q97},
+};
+
+void mtk_jpeg_enc_reset(void __iomem *base)
+{
+ writel(0, base + JPEG_ENC_RSTB);
+ writel(JPEG_ENC_RESET_BIT, base + JPEG_ENC_RSTB);
+ writel(0, base + JPEG_ENC_CODEC_SEL);
+}
+
+u32 mtk_jpeg_enc_get_file_size(void __iomem *base)
+{
+ return readl(base + JPEG_ENC_DMA_ADDR0) -
+ readl(base + JPEG_ENC_DST_ADDR0);
+}
+
+void mtk_jpeg_enc_start(void __iomem *base)
+{
+ u32 value;
+
+ value = readl(base + JPEG_ENC_CTRL);
+ value |= JPEG_ENC_CTRL_INT_EN_BIT | JPEG_ENC_CTRL_ENABLE_BIT;
+ writel(value, base + JPEG_ENC_CTRL);
+}
+
+void mtk_jpeg_set_enc_src(struct mtk_jpeg_ctx *ctx, void __iomem *base,
+ struct vb2_buffer *src_buf)
+{
+ int i;
+ dma_addr_t dma_addr;
+
+ for (i = 0; i < src_buf->num_planes; i++) {
+ dma_addr = vb2_dma_contig_plane_dma_addr(src_buf, i) +
+ src_buf->planes[i].data_offset;
+ if (!i)
+ writel(dma_addr, base + JPEG_ENC_SRC_LUMA_ADDR);
+ else
+ writel(dma_addr, base + JPEG_ENC_SRC_CHROMA_ADDR);
+ }
+}
+
+void mtk_jpeg_set_enc_dst(struct mtk_jpeg_ctx *ctx, void __iomem *base,
+ struct vb2_buffer *dst_buf)
+{
+ dma_addr_t dma_addr;
+ size_t size;
+ u32 dma_addr_offset;
+ u32 dma_addr_offsetmask;
+
+ dma_addr = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+ dma_addr_offset = ctx->enable_exif ? MTK_JPEG_MAX_EXIF_SIZE : 0;
+ dma_addr_offsetmask = dma_addr & JPEG_ENC_DST_ADDR_OFFSET_MASK;
+ size = vb2_plane_size(dst_buf, 0);
+
+ writel(dma_addr_offset & ~0xf, base + JPEG_ENC_OFFSET_ADDR);
+ writel(dma_addr_offsetmask & 0xf, base + JPEG_ENC_BYTE_OFFSET_MASK);
+ writel(dma_addr & ~0xf, base + JPEG_ENC_DST_ADDR0);
+ writel((dma_addr + size) & ~0xf, base + JPEG_ENC_STALL_ADDR0);
+}
+
+void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base)
+{
+ u32 value;
+ u32 width = ctx->out_q.enc_crop_rect.width;
+ u32 height = ctx->out_q.enc_crop_rect.height;
+ u32 enc_format = ctx->out_q.fmt->fourcc;
+ u32 bytesperline = ctx->out_q.pix_mp.plane_fmt[0].bytesperline;
+ u32 blk_num;
+ u32 img_stride;
+ u32 mem_stride;
+ u32 i, enc_quality;
+
+ value = width << 16 | height;
+ writel(value, base + JPEG_ENC_IMG_SIZE);
+
+ if (enc_format == V4L2_PIX_FMT_NV12M ||
+ enc_format == V4L2_PIX_FMT_NV21M)
+ /*
+ * Total 8 x 8 block number of luma and chroma.
+ * The number of blocks is counted from 0.
+ */
+ blk_num = DIV_ROUND_UP(width, 16) *
+ DIV_ROUND_UP(height, 16) * 6 - 1;
+ else
+ blk_num = DIV_ROUND_UP(width, 16) *
+ DIV_ROUND_UP(height, 8) * 4 - 1;
+ writel(blk_num, base + JPEG_ENC_BLK_NUM);
+
+ if (enc_format == V4L2_PIX_FMT_NV12M ||
+ enc_format == V4L2_PIX_FMT_NV21M) {
+ /* 4:2:0 */
+ img_stride = round_up(width, 16);
+ mem_stride = bytesperline;
+ } else {
+ /* 4:2:2 */
+ img_stride = round_up(width * 2, 32);
+ mem_stride = img_stride;
+ }
+ writel(img_stride, base + JPEG_ENC_IMG_STRIDE);
+ writel(mem_stride, base + JPEG_ENC_STRIDE);
+
+ enc_quality = mtk_jpeg_enc_quality[0].hardware_value;
+ for (i = 0; i < ARRAY_SIZE(mtk_jpeg_enc_quality); i++) {
+ if (ctx->enc_quality <= mtk_jpeg_enc_quality[i].quality_param) {
+ enc_quality = mtk_jpeg_enc_quality[i].hardware_value;
+ break;
+ }
+ }
+ writel(enc_quality, base + JPEG_ENC_QUALITY);
+
+ value = readl(base + JPEG_ENC_CTRL);
+ value &= ~JPEG_ENC_CTRL_YUV_FORMAT_MASK;
+ value |= (ctx->out_q.fmt->hw_format & 3) << 3;
+ if (ctx->enable_exif)
+ value |= JPEG_ENC_CTRL_FILE_FORMAT_BIT;
+ else
+ value &= ~JPEG_ENC_CTRL_FILE_FORMAT_BIT;
+ if (ctx->restart_interval)
+ value |= JPEG_ENC_CTRL_RESTART_EN_BIT;
+ else
+ value &= ~JPEG_ENC_CTRL_RESTART_EN_BIT;
+ writel(value, base + JPEG_ENC_CTRL);
+
+ writel(ctx->restart_interval, base + JPEG_ENC_RST_MCU_NUM);
+}
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.h
new file mode 100644
index 000000000000..61c60e4e58ea
--- /dev/null
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_enc_hw.h
@@ -0,0 +1,91 @@
+/* SPDX-License-Identifier: GPL-2.0-only */
+/*
+ * Copyright (c) 2019 MediaTek Inc.
+ * Author: Xia Jiang <xia.jiang@mediatek.com>
+ *
+ */
+
+#ifndef _MTK_JPEG_ENC_HW_H
+#define _MTK_JPEG_ENC_HW_H
+
+#include <media/videobuf2-core.h>
+
+#include "mtk_jpeg_core.h"
+
+#define JPEG_ENC_INT_STATUS_DONE BIT(0)
+#define JPEG_ENC_INT_STATUS_MASK_ALLIRQ 0x13
+
+#define JPEG_ENC_DST_ADDR_OFFSET_MASK GENMASK(3, 0)
+
+#define JPEG_ENC_CTRL_YUV_FORMAT_MASK 0x18
+#define JPEG_ENC_CTRL_RESTART_EN_BIT BIT(10)
+#define JPEG_ENC_CTRL_FILE_FORMAT_BIT BIT(5)
+#define JPEG_ENC_CTRL_INT_EN_BIT BIT(2)
+#define JPEG_ENC_CTRL_ENABLE_BIT BIT(0)
+#define JPEG_ENC_RESET_BIT BIT(0)
+
+#define JPEG_ENC_YUV_FORMAT_YUYV 0
+#define JPEG_ENC_YUV_FORMAT_YVYU 1
+#define JPEG_ENC_YUV_FORMAT_NV12 2
+#define JEPG_ENC_YUV_FORMAT_NV21 3
+
+#define JPEG_ENC_QUALITY_Q60 0x0
+#define JPEG_ENC_QUALITY_Q80 0x1
+#define JPEG_ENC_QUALITY_Q90 0x2
+#define JPEG_ENC_QUALITY_Q95 0x3
+#define JPEG_ENC_QUALITY_Q39 0x4
+#define JPEG_ENC_QUALITY_Q68 0x5
+#define JPEG_ENC_QUALITY_Q84 0x6
+#define JPEG_ENC_QUALITY_Q92 0x7
+#define JPEG_ENC_QUALITY_Q48 0x8
+#define JPEG_ENC_QUALITY_Q74 0xa
+#define JPEG_ENC_QUALITY_Q87 0xb
+#define JPEG_ENC_QUALITY_Q34 0xc
+#define JPEG_ENC_QUALITY_Q64 0xe
+#define JPEG_ENC_QUALITY_Q82 0xf
+#define JPEG_ENC_QUALITY_Q97 0x10
+
+#define JPEG_ENC_RSTB 0x100
+#define JPEG_ENC_CTRL 0x104
+#define JPEG_ENC_QUALITY 0x108
+#define JPEG_ENC_BLK_NUM 0x10C
+#define JPEG_ENC_BLK_CNT 0x110
+#define JPEG_ENC_INT_STS 0x11c
+#define JPEG_ENC_DST_ADDR0 0x120
+#define JPEG_ENC_DMA_ADDR0 0x124
+#define JPEG_ENC_STALL_ADDR0 0x128
+#define JPEG_ENC_OFFSET_ADDR 0x138
+#define JPEG_ENC_RST_MCU_NUM 0x150
+#define JPEG_ENC_IMG_SIZE 0x154
+#define JPEG_ENC_DEBUG_INFO0 0x160
+#define JPEG_ENC_DEBUG_INFO1 0x164
+#define JPEG_ENC_TOTAL_CYCLE 0x168
+#define JPEG_ENC_BYTE_OFFSET_MASK 0x16c
+#define JPEG_ENC_SRC_LUMA_ADDR 0x170
+#define JPEG_ENC_SRC_CHROMA_ADDR 0x174
+#define JPEG_ENC_STRIDE 0x178
+#define JPEG_ENC_IMG_STRIDE 0x17c
+#define JPEG_ENC_DCM_CTRL 0x300
+#define JPEG_ENC_CODEC_SEL 0x314
+#define JPEG_ENC_ULTRA_THRES 0x318
+
+/**
+ * struct mtk_jpeg_enc_qlt - JPEG encoder quality data
+ * @quality_param: quality value
+ * @hardware_value: hardware value of quality
+ */
+struct mtk_jpeg_enc_qlt {
+ u8 quality_param;
+ u8 hardware_value;
+};
+
+void mtk_jpeg_enc_reset(void __iomem *base);
+u32 mtk_jpeg_enc_get_file_size(void __iomem *base);
+void mtk_jpeg_enc_start(void __iomem *enc_reg_base);
+void mtk_jpeg_set_enc_src(struct mtk_jpeg_ctx *ctx, void __iomem *base,
+ struct vb2_buffer *src_buf);
+void mtk_jpeg_set_enc_dst(struct mtk_jpeg_ctx *ctx, void __iomem *base,
+ struct vb2_buffer *dst_buf);
+void mtk_jpeg_set_enc_params(struct mtk_jpeg_ctx *ctx, void __iomem *base);
+
+#endif /* _MTK_JPEG_ENC_HW_H */
diff --git a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
index f96c8b3bf861..976aa1f4829b 100644
--- a/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
+++ b/drivers/media/platform/mtk-mdp/mtk_mdp_core.c
@@ -94,7 +94,7 @@ static void mtk_mdp_reset_handler(void *priv)
void mtk_mdp_register_component(struct mtk_mdp_dev *mdp,
struct mtk_mdp_comp *comp)
{
- list_add(&mdp->comp_list, &comp->node);
+ list_add(&comp->node, &mdp->comp_list);
}
void mtk_mdp_unregister_component(struct mtk_mdp_dev *mdp,
diff --git a/drivers/media/platform/mtk-vcodec/Makefile b/drivers/media/platform/mtk-vcodec/Makefile
index 37b94b555fa1..f679c6e1a3e9 100644
--- a/drivers/media/platform/mtk-vcodec/Makefile
+++ b/drivers/media/platform/mtk-vcodec/Makefile
@@ -13,7 +13,6 @@ mtk-vcodec-dec-y := vdec/vdec_h264_if.o \
mtk_vcodec_dec.o \
mtk_vcodec_dec_pm.o \
-
mtk-vcodec-enc-y := venc/venc_vp8_if.o \
venc/venc_h264_if.o \
mtk_vcodec_enc.o \
@@ -24,6 +23,5 @@ mtk-vcodec-enc-y := venc/venc_vp8_if.o \
mtk-vcodec-common-y := mtk_vcodec_intr.o \
- mtk_vcodec_util.o\
-
-ccflags-y += -I$(srctree)/drivers/media/platform/mtk-vpu
+ mtk_vcodec_util.o \
+ mtk_vcodec_fw.o
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
index 0f3e710aed4e..c768a587a944 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec.c
@@ -194,8 +194,7 @@ static struct vb2_buffer *get_free_buffer(struct mtk_vcodec_ctx *ctx)
vb->vb2_buf.index,
dstbuf->queued_in_vb2);
v4l2_m2m_buf_queue(ctx->m2m_ctx, vb);
- } else if ((dstbuf->queued_in_vb2 == false) &&
- (dstbuf->queued_in_v4l2 == true)) {
+ } else if (!dstbuf->queued_in_vb2 && dstbuf->queued_in_v4l2) {
/*
* If buffer in v4l2 driver but not in vb2 queue yet,
* and we get this buffer from free_list, it means
@@ -448,7 +447,7 @@ static void mtk_vdec_worker(struct work_struct *work)
mutex_unlock(&ctx->lock);
}
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
- } else if (res_chg == false) {
+ } else if (!res_chg) {
/*
* we only return src buffer with VB2_BUF_STATE_DONE
* when decode success without resolution change
@@ -1156,7 +1155,7 @@ static void vb2ops_vdec_buf_queue(struct vb2_buffer *vb)
buf = container_of(vb2_v4l2, struct mtk_video_dec_buf,
m2m_buf.vb);
mutex_lock(&ctx->lock);
- if (buf->used == false) {
+ if (!buf->used) {
v4l2_m2m_buf_queue(ctx->m2m_ctx, vb2_v4l2);
buf->queued_in_vb2 = true;
buf->queued_in_v4l2 = true;
@@ -1525,10 +1524,8 @@ int mtk_vcodec_dec_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->dev = &ctx->dev->plat_dev->dev;
ret = vb2_queue_init(dst_vq);
- if (ret) {
- vb2_queue_release(src_vq);
+ if (ret)
mtk_v4l2_err("Failed to initialize videobuf2 queue(capture)");
- }
return ret;
}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
index 97a1b6664c20..d14bc208ea5e 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_drv.c
@@ -20,7 +20,7 @@
#include "mtk_vcodec_dec_pm.h"
#include "mtk_vcodec_intr.h"
#include "mtk_vcodec_util.h"
-#include "mtk_vpu.h"
+#include "mtk_vcodec_fw.h"
#define VDEC_HW_ACTIVE 0x10
#define VDEC_IRQ_CFG 0x11
@@ -77,22 +77,6 @@ static irqreturn_t mtk_vcodec_dec_irq_handler(int irq, void *priv)
return IRQ_HANDLED;
}
-static void mtk_vcodec_dec_reset_handler(void *priv)
-{
- struct mtk_vcodec_dev *dev = priv;
- struct mtk_vcodec_ctx *ctx;
-
- mtk_v4l2_err("Watchdog timeout!!");
-
- mutex_lock(&dev->dev_mutex);
- list_for_each_entry(ctx, &dev->ctx_list, list) {
- ctx->state = MTK_STATE_ABORT;
- mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ERROR",
- ctx->id);
- }
- mutex_unlock(&dev->dev_mutex);
-}
-
static int fops_vcodec_open(struct file *file)
{
struct mtk_vcodec_dev *dev = video_drvdata(file);
@@ -144,21 +128,20 @@ static int fops_vcodec_open(struct file *file)
if (v4l2_fh_is_singular(&ctx->fh)) {
mtk_vcodec_dec_pw_on(&dev->pm);
/*
- * vpu_load_firmware checks if it was loaded already and
- * does nothing in that case
+ * Does nothing if firmware was already loaded.
*/
- ret = vpu_load_firmware(dev->vpu_plat_dev);
+ ret = mtk_vcodec_fw_load_firmware(dev->fw_handler);
if (ret < 0) {
/*
* Return 0 if downloading firmware successfully,
* otherwise it is failed
*/
- mtk_v4l2_err("vpu_load_firmware failed!");
+ mtk_v4l2_err("failed to load firmware!");
goto err_load_fw;
}
dev->dec_capability =
- vpu_get_vdec_hw_capa(dev->vpu_plat_dev);
+ mtk_vcodec_fw_get_vdec_capa(dev->fw_handler);
mtk_v4l2_debug(0, "decoder capability %x", dev->dec_capability);
}
@@ -228,6 +211,8 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
struct mtk_vcodec_dev *dev;
struct video_device *vfd_dec;
struct resource *res;
+ phandle rproc_phandle;
+ enum mtk_vcodec_fw_type fw_type;
int i, ret;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
@@ -237,19 +222,33 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&dev->ctx_list);
dev->plat_dev = pdev;
- dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev);
- if (dev->vpu_plat_dev == NULL) {
- mtk_v4l2_err("[VPU] vpu device in not ready");
- return -EPROBE_DEFER;
+ if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
+ &rproc_phandle)) {
+ fw_type = VPU;
+ } else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp",
+ &rproc_phandle)) {
+ fw_type = SCP;
+ } else {
+ mtk_v4l2_err("Could not get vdec IPI device");
+ return -ENODEV;
+ }
+ if (!pdev->dev.dma_parms) {
+ pdev->dev.dma_parms = devm_kzalloc(&pdev->dev,
+ sizeof(*pdev->dev.dma_parms),
+ GFP_KERNEL);
+ if (!pdev->dev.dma_parms)
+ return -ENOMEM;
}
+ dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
- vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_dec_reset_handler,
- dev, VPU_RST_DEC);
+ dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, VPU_RST_DEC);
+ if (IS_ERR(dev->fw_handler))
+ return PTR_ERR(dev->fw_handler);
ret = mtk_vcodec_init_dec_pm(dev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to get mt vcodec clock source");
- return ret;
+ goto err_dec_pm;
}
for (i = 0; i < NUM_MAX_VDEC_REG_BASE; i++) {
@@ -269,6 +268,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
}
dev->dec_irq = platform_get_irq(pdev, 0);
+ irq_set_status_flags(dev->dec_irq, IRQ_NOAUTOEN);
ret = devm_request_irq(&pdev->dev, dev->dec_irq,
mtk_vcodec_dec_irq_handler, 0, pdev->name, dev);
if (ret) {
@@ -278,7 +278,6 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
goto err_res;
}
- disable_irq(dev->dec_irq);
mutex_init(&dev->dec_mutex);
mutex_init(&dev->dev_mutex);
spin_lock_init(&dev->irqlock);
@@ -352,6 +351,8 @@ err_dec_alloc:
v4l2_device_unregister(&dev->v4l2_dev);
err_res:
mtk_vcodec_release_dec_pm(dev);
+err_dec_pm:
+ mtk_vcodec_fw_release(dev->fw_handler);
return ret;
}
@@ -376,6 +377,7 @@ static int mtk_vcodec_dec_remove(struct platform_device *pdev)
v4l2_device_unregister(&dev->v4l2_dev);
mtk_vcodec_release_dec_pm(dev);
+ mtk_vcodec_fw_release(dev->fw_handler);
return 0;
}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
index 5a6ec8fb52da..36dfe3fc056a 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_dec_pm.c
@@ -12,7 +12,6 @@
#include "mtk_vcodec_dec_pm.h"
#include "mtk_vcodec_util.h"
-#include "mtk_vpu.h"
int mtk_vcodec_init_dec_pm(struct mtk_vcodec_dev *mtkdev)
{
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
index 9fd56dee7fd1..3dd010cba23e 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_drv.h
@@ -300,6 +300,40 @@ struct mtk_vcodec_ctx {
};
+enum mtk_chip {
+ MTK_MT8173,
+ MTK_MT8183,
+};
+
+/**
+ * struct mtk_vcodec_enc_pdata - compatible data for each IC
+ *
+ * @chip: chip this encoder is compatible with
+ *
+ * @uses_ext: whether the encoder uses the extended firmware messaging format
+ * @has_lt_irq: whether the encoder uses the LT irq
+ * @min_birate: minimum supported encoding bitrate
+ * @max_bitrate: maximum supported encoding bitrate
+ * @capture_formats: array of supported capture formats
+ * @num_capture_formats: number of entries in capture_formats
+ * @output_formats: array of supported output formats
+ * @num_output_formats: number of entries in output_formats
+ */
+struct mtk_vcodec_enc_pdata {
+ enum mtk_chip chip;
+
+ bool uses_ext;
+ bool has_lt_irq;
+ unsigned long min_bitrate;
+ unsigned long max_bitrate;
+ const struct mtk_video_fmt *capture_formats;
+ size_t num_capture_formats;
+ const struct mtk_video_fmt *output_formats;
+ size_t num_output_formats;
+};
+
+#define MTK_ENC_CTX_IS_EXT(ctx) ((ctx)->dev->venc_pdata->uses_ext)
+
/**
* struct mtk_vcodec_dev - driver data
* @v4l2_dev: V4L2 device to register video devices for.
@@ -309,13 +343,13 @@ struct mtk_vcodec_ctx {
* @m2m_dev_dec: m2m device for decoder
* @m2m_dev_enc: m2m device for encoder.
* @plat_dev: platform device
- * @vpu_plat_dev: mtk vpu platform device
* @ctx_list: list of struct mtk_vcodec_ctx
* @irqlock: protect data access by irq handler and work thread
* @curr_ctx: The context that is waiting for codec hardware
*
* @reg_base: Mapped address of MTK Vcodec registers.
*
+ * @fw_handler: used to communicate with the firmware.
* @id_counter: used to identify current opened instance
*
* @encode_workqueue: encode work queue
@@ -344,11 +378,13 @@ struct mtk_vcodec_dev {
struct v4l2_m2m_dev *m2m_dev_dec;
struct v4l2_m2m_dev *m2m_dev_enc;
struct platform_device *plat_dev;
- struct platform_device *vpu_plat_dev;
struct list_head ctx_list;
spinlock_t irqlock;
struct mtk_vcodec_ctx *curr_ctx;
void __iomem *reg_base[NUM_MAX_VCODEC_REG_BASE];
+ const struct mtk_vcodec_enc_pdata *venc_pdata;
+
+ struct mtk_vcodec_fw *fw_handler;
unsigned long id_counter;
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
index d469ff6464b2..21de1431cfcb 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc.c
@@ -23,58 +23,15 @@
#define DFT_CFG_WIDTH MTK_VENC_MIN_W
#define DFT_CFG_HEIGHT MTK_VENC_MIN_H
#define MTK_MAX_CTRLS_HINT 20
-#define OUT_FMT_IDX 0
-#define CAP_FMT_IDX 4
+#define MTK_DEFAULT_FRAMERATE_NUM 1001
+#define MTK_DEFAULT_FRAMERATE_DENOM 30000
static void mtk_venc_worker(struct work_struct *work);
-static const struct mtk_video_fmt mtk_video_formats[] = {
- {
- .fourcc = V4L2_PIX_FMT_NV12M,
- .type = MTK_FMT_FRAME,
- .num_planes = 2,
- },
- {
- .fourcc = V4L2_PIX_FMT_NV21M,
- .type = MTK_FMT_FRAME,
- .num_planes = 2,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUV420M,
- .type = MTK_FMT_FRAME,
- .num_planes = 3,
- },
- {
- .fourcc = V4L2_PIX_FMT_YVU420M,
- .type = MTK_FMT_FRAME,
- .num_planes = 3,
- },
- {
- .fourcc = V4L2_PIX_FMT_H264,
- .type = MTK_FMT_ENC,
- .num_planes = 1,
- },
- {
- .fourcc = V4L2_PIX_FMT_VP8,
- .type = MTK_FMT_ENC,
- .num_planes = 1,
- },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(mtk_video_formats)
-
-static const struct mtk_codec_framesizes mtk_venc_framesizes[] = {
- {
- .fourcc = V4L2_PIX_FMT_H264,
- .stepwise = { MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16,
- MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16 },
- },
- {
- .fourcc = V4L2_PIX_FMT_VP8,
- .stepwise = { MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16,
- MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16 },
- },
+static const struct v4l2_frmsize_stepwise mtk_venc_framesizes = {
+ MTK_VENC_MIN_W, MTK_VENC_MAX_W, 16,
+ MTK_VENC_MIN_H, MTK_VENC_MAX_H, 16,
};
#define NUM_SUPPORTED_FRAMESIZE ARRAY_SIZE(mtk_venc_framesizes)
@@ -156,59 +113,77 @@ static const struct v4l2_ctrl_ops mtk_vcodec_enc_ctrl_ops = {
.s_ctrl = vidioc_venc_s_ctrl,
};
-static int vidioc_enum_fmt(struct v4l2_fmtdesc *f, bool output_queue)
+static int vidioc_enum_fmt(struct v4l2_fmtdesc *f,
+ const struct mtk_video_fmt *formats,
+ size_t num_formats)
+{
+ if (f->index >= num_formats)
+ return -EINVAL;
+
+ f->pixelformat = formats[f->index].fourcc;
+ memset(f->reserved, 0, sizeof(f->reserved));
+
+ return 0;
+}
+
+static const struct mtk_video_fmt *
+mtk_venc_find_format(u32 fourcc, const struct mtk_vcodec_enc_pdata *pdata)
{
const struct mtk_video_fmt *fmt;
- int i, j = 0;
-
- for (i = 0; i < NUM_FORMATS; ++i) {
- if (output_queue && mtk_video_formats[i].type != MTK_FMT_FRAME)
- continue;
- if (!output_queue && mtk_video_formats[i].type != MTK_FMT_ENC)
- continue;
-
- if (j == f->index) {
- fmt = &mtk_video_formats[i];
- f->pixelformat = fmt->fourcc;
- memset(f->reserved, 0, sizeof(f->reserved));
- return 0;
- }
- ++j;
+ unsigned int k;
+
+ for (k = 0; k < pdata->num_capture_formats; k++) {
+ fmt = &pdata->capture_formats[k];
+ if (fmt->fourcc == fourcc)
+ return fmt;
+ }
+
+ for (k = 0; k < pdata->num_output_formats; k++) {
+ fmt = &pdata->output_formats[k];
+ if (fmt->fourcc == fourcc)
+ return fmt;
}
- return -EINVAL;
+ return NULL;
}
static int vidioc_enum_framesizes(struct file *file, void *fh,
struct v4l2_frmsizeenum *fsize)
{
- int i = 0;
+ const struct mtk_video_fmt *fmt;
if (fsize->index != 0)
return -EINVAL;
- for (i = 0; i < NUM_SUPPORTED_FRAMESIZE; ++i) {
- if (fsize->pixel_format != mtk_venc_framesizes[i].fourcc)
- continue;
+ fmt = mtk_venc_find_format(fsize->pixel_format,
+ fh_to_ctx(fh)->dev->venc_pdata);
+ if (!fmt)
+ return -EINVAL;
- fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
- fsize->stepwise = mtk_venc_framesizes[i].stepwise;
- return 0;
- }
+ fsize->type = V4L2_FRMSIZE_TYPE_STEPWISE;
+ fsize->stepwise = mtk_venc_framesizes;
- return -EINVAL;
+ return 0;
}
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- return vidioc_enum_fmt(f, false);
+ const struct mtk_vcodec_enc_pdata *pdata =
+ fh_to_ctx(priv)->dev->venc_pdata;
+
+ return vidioc_enum_fmt(f, pdata->capture_formats,
+ pdata->num_capture_formats);
}
static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- return vidioc_enum_fmt(f, true);
+ const struct mtk_vcodec_enc_pdata *pdata =
+ fh_to_ctx(priv)->dev->venc_pdata;
+
+ return vidioc_enum_fmt(f, pdata->output_formats,
+ pdata->num_output_formats);
}
static int vidioc_venc_querycap(struct file *file, void *priv,
@@ -225,14 +200,18 @@ static int vidioc_venc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *a)
{
struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+ struct v4l2_fract *timeperframe = &a->parm.output.timeperframe;
if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
return -EINVAL;
- ctx->enc_params.framerate_num =
- a->parm.output.timeperframe.denominator;
- ctx->enc_params.framerate_denom =
- a->parm.output.timeperframe.numerator;
+ if (timeperframe->numerator == 0 || timeperframe->denominator == 0) {
+ timeperframe->numerator = MTK_DEFAULT_FRAMERATE_NUM;
+ timeperframe->denominator = MTK_DEFAULT_FRAMERATE_DENOM;
+ }
+
+ ctx->enc_params.framerate_num = timeperframe->denominator;
+ ctx->enc_params.framerate_denom = timeperframe->numerator;
ctx->param_change |= MTK_ENCODE_PARAM_FRAMERATE;
a->parm.output.capability = V4L2_CAP_TIMEPERFRAME;
@@ -266,20 +245,6 @@ static struct mtk_q_data *mtk_venc_get_q_data(struct mtk_vcodec_ctx *ctx,
return &ctx->q_data[MTK_Q_DATA_DST];
}
-static const struct mtk_video_fmt *mtk_venc_find_format(struct v4l2_format *f)
-{
- const struct mtk_video_fmt *fmt;
- unsigned int k;
-
- for (k = 0; k < NUM_FORMATS; k++) {
- fmt = &mtk_video_formats[k];
- if (fmt->fourcc == f->fmt.pix.pixelformat)
- return fmt;
- }
-
- return NULL;
-}
-
/* V4L2 specification suggests the driver corrects the format struct if any of
* the dimensions is unsupported
*/
@@ -332,12 +297,14 @@ static int vidioc_try_fmt(struct v4l2_format *f,
pix_fmt_mp->num_planes = fmt->num_planes;
pix_fmt_mp->plane_fmt[0].sizeimage =
- pix_fmt_mp->width * pix_fmt_mp->height;
+ pix_fmt_mp->width * pix_fmt_mp->height +
+ ((ALIGN(pix_fmt_mp->width, 16) * 2) * 16);
pix_fmt_mp->plane_fmt[0].bytesperline = pix_fmt_mp->width;
if (pix_fmt_mp->num_planes == 2) {
pix_fmt_mp->plane_fmt[1].sizeimage =
- (pix_fmt_mp->width * pix_fmt_mp->height) / 2;
+ (pix_fmt_mp->width * pix_fmt_mp->height) / 2 +
+ (ALIGN(pix_fmt_mp->width, 16) * 16);
pix_fmt_mp->plane_fmt[2].sizeimage = 0;
pix_fmt_mp->plane_fmt[1].bytesperline =
pix_fmt_mp->width;
@@ -345,7 +312,8 @@ static int vidioc_try_fmt(struct v4l2_format *f,
} else if (pix_fmt_mp->num_planes == 3) {
pix_fmt_mp->plane_fmt[1].sizeimage =
pix_fmt_mp->plane_fmt[2].sizeimage =
- (pix_fmt_mp->width * pix_fmt_mp->height) / 4;
+ (pix_fmt_mp->width * pix_fmt_mp->height) / 4 +
+ ((ALIGN(pix_fmt_mp->width, 16) / 2) * 16);
pix_fmt_mp->plane_fmt[1].bytesperline =
pix_fmt_mp->plane_fmt[2].bytesperline =
pix_fmt_mp->width / 2;
@@ -414,6 +382,7 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+ const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
struct vb2_queue *vq;
struct mtk_q_data *q_data;
int i, ret;
@@ -436,10 +405,10 @@ static int vidioc_venc_s_fmt_cap(struct file *file, void *priv,
return -EINVAL;
}
- fmt = mtk_venc_find_format(f);
+ fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
if (!fmt) {
- f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc;
- fmt = mtk_venc_find_format(f);
+ fmt = &ctx->dev->venc_pdata->capture_formats[0];
+ f->fmt.pix.pixelformat = fmt->fourcc;
}
q_data->fmt = fmt;
@@ -476,6 +445,7 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
struct v4l2_format *f)
{
struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+ const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
struct vb2_queue *vq;
struct mtk_q_data *q_data;
int ret, i;
@@ -499,10 +469,10 @@ static int vidioc_venc_s_fmt_out(struct file *file, void *priv,
return -EINVAL;
}
- fmt = mtk_venc_find_format(f);
+ fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
if (!fmt) {
- f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc;
- fmt = mtk_venc_find_format(f);
+ fmt = &ctx->dev->venc_pdata->output_formats[0];
+ f->fmt.pix.pixelformat = fmt->fourcc;
}
pix_fmt_mp->height = clamp(pix_fmt_mp->height,
@@ -580,11 +550,12 @@ static int vidioc_try_fmt_vid_cap_mplane(struct file *file, void *priv,
{
const struct mtk_video_fmt *fmt;
struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+ const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
- fmt = mtk_venc_find_format(f);
+ fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
if (!fmt) {
- f->fmt.pix.pixelformat = mtk_video_formats[CAP_FMT_IDX].fourcc;
- fmt = mtk_venc_find_format(f);
+ fmt = &ctx->dev->venc_pdata->capture_formats[0];
+ f->fmt.pix.pixelformat = fmt->fourcc;
}
f->fmt.pix_mp.colorspace = ctx->colorspace;
f->fmt.pix_mp.ycbcr_enc = ctx->ycbcr_enc;
@@ -598,11 +569,13 @@ static int vidioc_try_fmt_vid_out_mplane(struct file *file, void *priv,
struct v4l2_format *f)
{
const struct mtk_video_fmt *fmt;
+ struct mtk_vcodec_ctx *ctx = fh_to_ctx(priv);
+ const struct mtk_vcodec_enc_pdata *pdata = ctx->dev->venc_pdata;
- fmt = mtk_venc_find_format(f);
+ fmt = mtk_venc_find_format(f->fmt.pix.pixelformat, pdata);
if (!fmt) {
- f->fmt.pix.pixelformat = mtk_video_formats[OUT_FMT_IDX].fourcc;
- fmt = mtk_venc_find_format(f);
+ fmt = &ctx->dev->venc_pdata->output_formats[0];
+ f->fmt.pix.pixelformat = fmt->fourcc;
}
if (!f->fmt.pix_mp.colorspace) {
f->fmt.pix_mp.colorspace = V4L2_COLORSPACE_REC709;
@@ -918,8 +891,17 @@ static void vb2ops_venc_stop_streaming(struct vb2_queue *q)
ctx->state = MTK_STATE_FREE;
}
+static int vb2ops_venc_buf_out_validate(struct vb2_buffer *vb)
+{
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+
+ vbuf->field = V4L2_FIELD_NONE;
+ return 0;
+}
+
static const struct vb2_ops mtk_venc_vb2_ops = {
.queue_setup = vb2ops_venc_queue_setup,
+ .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,
@@ -1187,7 +1169,7 @@ void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx)
q_data->coded_height = DFT_CFG_HEIGHT;
q_data->field = V4L2_FIELD_NONE;
- q_data->fmt = &mtk_video_formats[OUT_FMT_IDX];
+ q_data->fmt = &ctx->dev->venc_pdata->output_formats[0];
v4l_bound_align_image(&q_data->coded_width,
MTK_VENC_MIN_W,
@@ -1216,12 +1198,14 @@ void mtk_vcodec_enc_set_default_params(struct mtk_vcodec_ctx *ctx)
memset(q_data, 0, sizeof(struct mtk_q_data));
q_data->coded_width = DFT_CFG_WIDTH;
q_data->coded_height = DFT_CFG_HEIGHT;
- q_data->fmt = &mtk_video_formats[CAP_FMT_IDX];
+ q_data->fmt = &ctx->dev->venc_pdata->capture_formats[0];
q_data->field = V4L2_FIELD_NONE;
ctx->q_data[MTK_Q_DATA_DST].sizeimage[0] =
DFT_CFG_WIDTH * DFT_CFG_HEIGHT;
ctx->q_data[MTK_Q_DATA_DST].bytesperline[0] = 0;
+ ctx->enc_params.framerate_num = MTK_DEFAULT_FRAMERATE_NUM;
+ ctx->enc_params.framerate_denom = MTK_DEFAULT_FRAMERATE_DENOM;
}
int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
@@ -1231,8 +1215,11 @@ int mtk_vcodec_enc_ctrls_setup(struct mtk_vcodec_ctx *ctx)
v4l2_ctrl_handler_init(handler, MTK_MAX_CTRLS_HINT);
+ v4l2_ctrl_new_std(handler, ops, V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
+ 1, 1, 1, 1);
v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_BITRATE,
- 1, 4000000, 1, 4000000);
+ ctx->dev->venc_pdata->min_bitrate,
+ ctx->dev->venc_pdata->max_bitrate, 1, 4000000);
v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_B_FRAMES,
0, 2, 1, 0);
v4l2_ctrl_new_std(handler, ops, V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE,
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
index 4d31f1ed113f..dcfa2c2d4def 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_drv.c
@@ -21,11 +21,55 @@
#include "mtk_vcodec_enc_pm.h"
#include "mtk_vcodec_intr.h"
#include "mtk_vcodec_util.h"
-#include "mtk_vpu.h"
+#include "mtk_vcodec_fw.h"
module_param(mtk_v4l2_dbg_level, int, S_IRUGO | S_IWUSR);
module_param(mtk_vcodec_dbg, bool, S_IRUGO | S_IWUSR);
+static const struct mtk_video_fmt mtk_video_formats_output_mt8173[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_NV12M,
+ .type = MTK_FMT_FRAME,
+ .num_planes = 2,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_NV21M,
+ .type = MTK_FMT_FRAME,
+ .num_planes = 2,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .type = MTK_FMT_FRAME,
+ .num_planes = 3,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU420M,
+ .type = MTK_FMT_FRAME,
+ .num_planes = 3,
+ },
+};
+
+static const struct mtk_video_fmt mtk_video_formats_capture_mt8173[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_H264,
+ .type = MTK_FMT_ENC,
+ .num_planes = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VP8,
+ .type = MTK_FMT_ENC,
+ .num_planes = 1,
+ },
+};
+
+static const struct mtk_video_fmt mtk_video_formats_capture_mt8183[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_H264,
+ .type = MTK_FMT_ENC,
+ .num_planes = 1,
+ },
+};
+
/* Wake up context wait_queue */
static void wake_up_ctx(struct mtk_vcodec_ctx *ctx, unsigned int reason)
{
@@ -101,22 +145,6 @@ static irqreturn_t mtk_vcodec_enc_lt_irq_handler(int irq, void *priv)
return IRQ_HANDLED;
}
-static void mtk_vcodec_enc_reset_handler(void *priv)
-{
- struct mtk_vcodec_dev *dev = priv;
- struct mtk_vcodec_ctx *ctx;
-
- mtk_v4l2_debug(0, "Watchdog timeout!!");
-
- mutex_lock(&dev->dev_mutex);
- list_for_each_entry(ctx, &dev->ctx_list, list) {
- ctx->state = MTK_STATE_ABORT;
- mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT",
- ctx->id);
- }
- mutex_unlock(&dev->dev_mutex);
-}
-
static int fops_vcodec_open(struct file *file)
{
struct mtk_vcodec_dev *dev = video_drvdata(file);
@@ -159,10 +187,10 @@ static int fops_vcodec_open(struct file *file)
if (v4l2_fh_is_singular(&ctx->fh)) {
/*
- * vpu_load_firmware checks if it was loaded already and
+ * load fireware to checks if it was loaded already and
* does nothing in that case
*/
- ret = vpu_load_firmware(dev->vpu_plat_dev);
+ ret = mtk_vcodec_fw_load_firmware(dev->fw_handler);
if (ret < 0) {
/*
* Return 0 if downloading firmware successfully,
@@ -173,7 +201,7 @@ static int fops_vcodec_open(struct file *file)
}
dev->enc_capability =
- vpu_get_venc_hw_capa(dev->vpu_plat_dev);
+ mtk_vcodec_fw_get_venc_capa(dev->fw_handler);
mtk_v4l2_debug(0, "encoder capability %x", dev->enc_capability);
}
@@ -235,7 +263,9 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
struct mtk_vcodec_dev *dev;
struct video_device *vfd_enc;
struct resource *res;
- int i, j, ret;
+ phandle rproc_phandle;
+ enum mtk_vcodec_fw_type fw_type;
+ int ret;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev)
@@ -244,30 +274,43 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&dev->ctx_list);
dev->plat_dev = pdev;
- dev->vpu_plat_dev = vpu_get_plat_device(dev->plat_dev);
- if (dev->vpu_plat_dev == NULL) {
- mtk_v4l2_err("[VPU] vpu device in not ready");
- return -EPROBE_DEFER;
+ if (!of_property_read_u32(pdev->dev.of_node, "mediatek,vpu",
+ &rproc_phandle)) {
+ fw_type = VPU;
+ } else if (!of_property_read_u32(pdev->dev.of_node, "mediatek,scp",
+ &rproc_phandle)) {
+ fw_type = SCP;
+ } else {
+ mtk_v4l2_err("Could not get venc IPI device");
+ return -ENODEV;
}
+ if (!pdev->dev.dma_parms) {
+ pdev->dev.dma_parms = devm_kzalloc(&pdev->dev,
+ sizeof(*pdev->dev.dma_parms),
+ GFP_KERNEL);
+ if (!pdev->dev.dma_parms)
+ return -ENOMEM;
+ }
+ dma_set_max_seg_size(&pdev->dev, DMA_BIT_MASK(32));
- vpu_wdt_reg_handler(dev->vpu_plat_dev, mtk_vcodec_enc_reset_handler,
- dev, VPU_RST_ENC);
+ dev->fw_handler = mtk_vcodec_fw_select(dev, fw_type, VPU_RST_ENC);
+ if (IS_ERR(dev->fw_handler))
+ return PTR_ERR(dev->fw_handler);
+ dev->venc_pdata = of_device_get_match_data(&pdev->dev);
ret = mtk_vcodec_init_enc_pm(dev);
if (ret < 0) {
dev_err(&pdev->dev, "Failed to get mt vcodec clock source!");
- return ret;
+ goto err_enc_pm;
}
- for (i = VENC_SYS, j = 0; i < NUM_MAX_VCODEC_REG_BASE; i++, j++) {
- res = platform_get_resource(pdev, IORESOURCE_MEM, j);
- dev->reg_base[i] = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR((__force void *)dev->reg_base[i])) {
- ret = PTR_ERR((__force void *)dev->reg_base[i]);
- goto err_res;
- }
- mtk_v4l2_debug(2, "reg[%d] base=0x%p", i, dev->reg_base[i]);
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ dev->reg_base[VENC_SYS] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR((__force void *)dev->reg_base[VENC_SYS])) {
+ ret = PTR_ERR((__force void *)dev->reg_base[VENC_SYS]);
+ goto err_res;
}
+ mtk_v4l2_debug(2, "reg[%d] base=0x%p", i, dev->reg_base[VENC_SYS]);
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (res == NULL) {
@@ -277,6 +320,7 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
}
dev->enc_irq = platform_get_irq(pdev, 0);
+ irq_set_status_flags(dev->enc_irq, IRQ_NOAUTOEN);
ret = devm_request_irq(&pdev->dev, dev->enc_irq,
mtk_vcodec_enc_irq_handler,
0, pdev->name, dev);
@@ -288,20 +332,30 @@ static int mtk_vcodec_probe(struct platform_device *pdev)
goto err_res;
}
- dev->enc_lt_irq = platform_get_irq(pdev, 1);
- ret = devm_request_irq(&pdev->dev,
- dev->enc_lt_irq, mtk_vcodec_enc_lt_irq_handler,
- 0, pdev->name, dev);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to install dev->enc_lt_irq %d (%d)",
- dev->enc_lt_irq, ret);
- ret = -EINVAL;
- goto err_res;
+ if (dev->venc_pdata->has_lt_irq) {
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ dev->reg_base[VENC_LT_SYS] = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR((__force void *)dev->reg_base[VENC_LT_SYS])) {
+ ret = PTR_ERR((__force void *)dev->reg_base[VENC_LT_SYS]);
+ goto err_res;
+ }
+ mtk_v4l2_debug(2, "reg[%d] base=0x%p", i, dev->reg_base[VENC_LT_SYS]);
+
+ dev->enc_lt_irq = platform_get_irq(pdev, 1);
+ irq_set_status_flags(dev->enc_lt_irq, IRQ_NOAUTOEN);
+ ret = devm_request_irq(&pdev->dev,
+ dev->enc_lt_irq,
+ mtk_vcodec_enc_lt_irq_handler,
+ 0, pdev->name, dev);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to install dev->enc_lt_irq %d (%d)",
+ dev->enc_lt_irq, ret);
+ ret = -EINVAL;
+ goto err_res;
+ }
}
- disable_irq(dev->enc_irq);
- disable_irq(dev->enc_lt_irq); /* VENC_LT */
mutex_init(&dev->enc_mutex);
mutex_init(&dev->dev_mutex);
spin_lock_init(&dev->irqlock);
@@ -377,11 +431,38 @@ err_enc_alloc:
v4l2_device_unregister(&dev->v4l2_dev);
err_res:
mtk_vcodec_release_enc_pm(dev);
+err_enc_pm:
+ mtk_vcodec_fw_release(dev->fw_handler);
return ret;
}
+static const struct mtk_vcodec_enc_pdata mt8173_pdata = {
+ .chip = MTK_MT8173,
+ .has_lt_irq = true,
+ .capture_formats = mtk_video_formats_capture_mt8173,
+ .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8173),
+ .output_formats = mtk_video_formats_output_mt8173,
+ .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173),
+ .min_bitrate = 1,
+ .max_bitrate = 4000000,
+};
+
+static const struct mtk_vcodec_enc_pdata mt8183_pdata = {
+ .chip = MTK_MT8183,
+ .has_lt_irq = false,
+ .uses_ext = true,
+ .capture_formats = mtk_video_formats_capture_mt8183,
+ .num_capture_formats = ARRAY_SIZE(mtk_video_formats_capture_mt8183),
+ /* MT8183 supports the same output formats as MT8173 */
+ .output_formats = mtk_video_formats_output_mt8173,
+ .num_output_formats = ARRAY_SIZE(mtk_video_formats_output_mt8173),
+ .min_bitrate = 64,
+ .max_bitrate = 40000000,
+};
+
static const struct of_device_id mtk_vcodec_enc_match[] = {
- {.compatible = "mediatek,mt8173-vcodec-enc",},
+ {.compatible = "mediatek,mt8173-vcodec-enc", .data = &mt8173_pdata},
+ {.compatible = "mediatek,mt8183-vcodec-enc", .data = &mt8183_pdata},
{},
};
MODULE_DEVICE_TABLE(of, mtk_vcodec_enc_match);
@@ -401,6 +482,7 @@ static int mtk_vcodec_enc_remove(struct platform_device *pdev)
v4l2_device_unregister(&dev->v4l2_dev);
mtk_vcodec_release_enc_pm(dev);
+ mtk_vcodec_fw_release(dev->fw_handler);
return 0;
}
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
index 3e2bfded79a6..ee22902aaa71 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_enc_pm.c
@@ -12,8 +12,6 @@
#include "mtk_vcodec_enc_pm.h"
#include "mtk_vcodec_util.h"
-#include "mtk_vpu.h"
-
int mtk_vcodec_init_enc_pm(struct mtk_vcodec_dev *mtkdev)
{
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c
new file mode 100644
index 000000000000..6c2a2568d844
--- /dev/null
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.c
@@ -0,0 +1,231 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include "mtk_vcodec_fw.h"
+#include "mtk_vcodec_util.h"
+#include "mtk_vcodec_drv.h"
+
+struct mtk_vcodec_fw_ops {
+ int (*load_firmware)(struct mtk_vcodec_fw *fw);
+ unsigned int (*get_vdec_capa)(struct mtk_vcodec_fw *fw);
+ unsigned int (*get_venc_capa)(struct mtk_vcodec_fw *fw);
+ void * (*map_dm_addr)(struct mtk_vcodec_fw *fw, u32 dtcm_dmem_addr);
+ int (*ipi_register)(struct mtk_vcodec_fw *fw, int id,
+ mtk_vcodec_ipi_handler handler, const char *name, void *priv);
+ int (*ipi_send)(struct mtk_vcodec_fw *fw, int id, void *buf,
+ unsigned int len, unsigned int wait);
+};
+
+struct mtk_vcodec_fw {
+ enum mtk_vcodec_fw_type type;
+ const struct mtk_vcodec_fw_ops *ops;
+ struct platform_device *pdev;
+ struct mtk_scp *scp;
+};
+
+static int mtk_vcodec_vpu_load_firmware(struct mtk_vcodec_fw *fw)
+{
+ return vpu_load_firmware(fw->pdev);
+}
+
+static unsigned int mtk_vcodec_vpu_get_vdec_capa(struct mtk_vcodec_fw *fw)
+{
+ return vpu_get_vdec_hw_capa(fw->pdev);
+}
+
+static unsigned int mtk_vcodec_vpu_get_venc_capa(struct mtk_vcodec_fw *fw)
+{
+ return vpu_get_venc_hw_capa(fw->pdev);
+}
+
+static void *mtk_vcodec_vpu_map_dm_addr(struct mtk_vcodec_fw *fw,
+ u32 dtcm_dmem_addr)
+{
+ return vpu_mapping_dm_addr(fw->pdev, dtcm_dmem_addr);
+}
+
+static int mtk_vcodec_vpu_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
+ mtk_vcodec_ipi_handler handler,
+ const char *name, void *priv)
+{
+ /*
+ * The handler we receive takes a void * as its first argument. We
+ * cannot change this because it needs to be passed down to the rproc
+ * subsystem when SCP is used. VPU takes a const argument, which is
+ * more constrained, so the conversion below is safe.
+ */
+ ipi_handler_t handler_const = (ipi_handler_t)handler;
+
+ return vpu_ipi_register(fw->pdev, id, handler_const, name, priv);
+}
+
+static int mtk_vcodec_vpu_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
+ unsigned int len, unsigned int wait)
+{
+ return vpu_ipi_send(fw->pdev, id, buf, len);
+}
+
+static const struct mtk_vcodec_fw_ops mtk_vcodec_vpu_msg = {
+ .load_firmware = mtk_vcodec_vpu_load_firmware,
+ .get_vdec_capa = mtk_vcodec_vpu_get_vdec_capa,
+ .get_venc_capa = mtk_vcodec_vpu_get_venc_capa,
+ .map_dm_addr = mtk_vcodec_vpu_map_dm_addr,
+ .ipi_register = mtk_vcodec_vpu_set_ipi_register,
+ .ipi_send = mtk_vcodec_vpu_ipi_send,
+};
+
+static int mtk_vcodec_scp_load_firmware(struct mtk_vcodec_fw *fw)
+{
+ return rproc_boot(scp_get_rproc(fw->scp));
+}
+
+static unsigned int mtk_vcodec_scp_get_vdec_capa(struct mtk_vcodec_fw *fw)
+{
+ return scp_get_vdec_hw_capa(fw->scp);
+}
+
+static unsigned int mtk_vcodec_scp_get_venc_capa(struct mtk_vcodec_fw *fw)
+{
+ return scp_get_venc_hw_capa(fw->scp);
+}
+
+static void *mtk_vcodec_vpu_scp_dm_addr(struct mtk_vcodec_fw *fw,
+ u32 dtcm_dmem_addr)
+{
+ return scp_mapping_dm_addr(fw->scp, dtcm_dmem_addr);
+}
+
+static int mtk_vcodec_scp_set_ipi_register(struct mtk_vcodec_fw *fw, int id,
+ mtk_vcodec_ipi_handler handler,
+ const char *name, void *priv)
+{
+ return scp_ipi_register(fw->scp, id, handler, priv);
+}
+
+static int mtk_vcodec_scp_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
+ unsigned int len, unsigned int wait)
+{
+ return scp_ipi_send(fw->scp, id, buf, len, wait);
+}
+
+static const struct mtk_vcodec_fw_ops mtk_vcodec_rproc_msg = {
+ .load_firmware = mtk_vcodec_scp_load_firmware,
+ .get_vdec_capa = mtk_vcodec_scp_get_vdec_capa,
+ .get_venc_capa = mtk_vcodec_scp_get_venc_capa,
+ .map_dm_addr = mtk_vcodec_vpu_scp_dm_addr,
+ .ipi_register = mtk_vcodec_scp_set_ipi_register,
+ .ipi_send = mtk_vcodec_scp_ipi_send,
+};
+
+static void mtk_vcodec_reset_handler(void *priv)
+{
+ struct mtk_vcodec_dev *dev = priv;
+ struct mtk_vcodec_ctx *ctx;
+
+ mtk_v4l2_err("Watchdog timeout!!");
+
+ mutex_lock(&dev->dev_mutex);
+ list_for_each_entry(ctx, &dev->ctx_list, list) {
+ ctx->state = MTK_STATE_ABORT;
+ mtk_v4l2_debug(0, "[%d] Change to state MTK_STATE_ABORT",
+ ctx->id);
+ }
+ mutex_unlock(&dev->dev_mutex);
+}
+
+struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev,
+ enum mtk_vcodec_fw_type type,
+ enum rst_id rst_id)
+{
+ const struct mtk_vcodec_fw_ops *ops;
+ struct mtk_vcodec_fw *fw;
+ struct platform_device *fw_pdev = NULL;
+ struct mtk_scp *scp = NULL;
+
+ switch (type) {
+ case VPU:
+ ops = &mtk_vcodec_vpu_msg;
+ fw_pdev = vpu_get_plat_device(dev->plat_dev);
+ if (!fw_pdev) {
+ mtk_v4l2_err("firmware device is not ready");
+ return ERR_PTR(-EINVAL);
+ }
+ vpu_wdt_reg_handler(fw_pdev, mtk_vcodec_reset_handler,
+ dev, rst_id);
+ break;
+ case SCP:
+ ops = &mtk_vcodec_rproc_msg;
+ scp = scp_get(dev->plat_dev);
+ if (!scp) {
+ mtk_v4l2_err("could not get vdec scp handle");
+ return ERR_PTR(-EPROBE_DEFER);
+ }
+ break;
+ default:
+ mtk_v4l2_err("invalid vcodec fw type");
+ return ERR_PTR(-EINVAL);
+ }
+
+ fw = devm_kzalloc(&dev->plat_dev->dev, sizeof(*fw), GFP_KERNEL);
+ if (!fw)
+ return ERR_PTR(-EINVAL);
+
+ fw->type = type;
+ fw->ops = ops;
+ fw->pdev = fw_pdev;
+ fw->scp = scp;
+
+ return fw;
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_select);
+
+void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw)
+{
+ switch (fw->type) {
+ case VPU:
+ put_device(&fw->pdev->dev);
+ break;
+ case SCP:
+ scp_put(fw->scp);
+ break;
+ }
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_release);
+
+int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw)
+{
+ return fw->ops->load_firmware(fw);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_load_firmware);
+
+unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw)
+{
+ return fw->ops->get_vdec_capa(fw);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_vdec_capa);
+
+unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw)
+{
+ return fw->ops->get_venc_capa(fw);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_get_venc_capa);
+
+void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr)
+{
+ return fw->ops->map_dm_addr(fw, mem_addr);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_map_dm_addr);
+
+int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id,
+ mtk_vcodec_ipi_handler handler,
+ const char *name, void *priv)
+{
+ return fw->ops->ipi_register(fw, id, handler, name, priv);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_register);
+
+int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id, void *buf,
+ unsigned int len, unsigned int wait)
+{
+ return fw->ops->ipi_send(fw, id, buf, len, wait);
+}
+EXPORT_SYMBOL_GPL(mtk_vcodec_fw_ipi_send);
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h
new file mode 100644
index 000000000000..fadbbe6ba6cd
--- /dev/null
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_fw.h
@@ -0,0 +1,38 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#ifndef _MTK_VCODEC_FW_H_
+#define _MTK_VCODEC_FW_H_
+
+#include <linux/remoteproc.h>
+#include <linux/remoteproc/mtk_scp.h>
+
+#include "../mtk-vpu/mtk_vpu.h"
+
+struct mtk_vcodec_dev;
+
+enum mtk_vcodec_fw_type {
+ VPU,
+ SCP,
+};
+
+struct mtk_vcodec_fw;
+
+typedef void (*mtk_vcodec_ipi_handler) (void *data,
+ unsigned int len, void *priv);
+
+struct mtk_vcodec_fw *mtk_vcodec_fw_select(struct mtk_vcodec_dev *dev,
+ enum mtk_vcodec_fw_type type,
+ enum rst_id rst_id);
+void mtk_vcodec_fw_release(struct mtk_vcodec_fw *fw);
+
+int mtk_vcodec_fw_load_firmware(struct mtk_vcodec_fw *fw);
+unsigned int mtk_vcodec_fw_get_vdec_capa(struct mtk_vcodec_fw *fw);
+unsigned int mtk_vcodec_fw_get_venc_capa(struct mtk_vcodec_fw *fw);
+void *mtk_vcodec_fw_map_dm_addr(struct mtk_vcodec_fw *fw, u32 mem_addr);
+int mtk_vcodec_fw_ipi_register(struct mtk_vcodec_fw *fw, int id,
+ mtk_vcodec_ipi_handler handler,
+ const char *name, void *priv);
+int mtk_vcodec_fw_ipi_send(struct mtk_vcodec_fw *fw, int id,
+ void *buf, unsigned int len, unsigned int wait);
+
+#endif /* _MTK_VCODEC_FW_H_ */
diff --git a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
index d48f542db1a9..ac5973b6735f 100644
--- a/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
+++ b/drivers/media/platform/mtk-vcodec/mtk_vcodec_util.c
@@ -9,7 +9,6 @@
#include "mtk_vcodec_drv.h"
#include "mtk_vcodec_util.h"
-#include "mtk_vpu.h"
/* For encoder, this will enable logs in venc/*/
bool mtk_vcodec_dbg;
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
index 50048c170b99..40d6e6c5ac7a 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_h264_if.c
@@ -281,7 +281,6 @@ static int vdec_h264_init(struct mtk_vcodec_ctx *ctx)
inst->ctx = ctx;
inst->vpu.id = IPI_VDEC_H264;
- inst->vpu.dev = ctx->dev->vpu_plat_dev;
inst->vpu.ctx = ctx;
err = vpu_dec_init(&inst->vpu);
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
index 6011fdd60a22..e5393f841080 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp8_if.c
@@ -400,7 +400,6 @@ static int vdec_vp8_init(struct mtk_vcodec_ctx *ctx)
inst->ctx = ctx;
inst->vpu.id = IPI_VDEC_VP8;
- inst->vpu.dev = ctx->dev->vpu_plat_dev;
inst->vpu.ctx = ctx;
err = vpu_dec_init(&inst->vpu);
diff --git a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
index 257a5b5ad212..5ea153a68522 100644
--- a/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec/vdec_vp9_if.c
@@ -795,7 +795,6 @@ static int vdec_vp9_init(struct mtk_vcodec_ctx *ctx)
inst->ctx = ctx;
inst->vpu.id = IPI_VDEC_VP9;
- inst->vpu.dev = ctx->dev->vpu_plat_dev;
inst->vpu.ctx = ctx;
if (vpu_dec_init(&inst->vpu)) {
@@ -960,7 +959,7 @@ static int vdec_vp9_decode(void *h_vdec, struct mtk_vcodec_mem *bs,
goto DECODE_ERROR;
}
- if (vp9_decode_end_proc(inst) != true) {
+ if (!vp9_decode_end_proc(inst)) {
mtk_vcodec_err(inst, "vp9_decode_end_proc");
ret = -EINVAL;
goto DECODE_ERROR;
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
index ceb4db4cb3be..e913f963b7db 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_drv_base.h
@@ -7,8 +7,6 @@
#ifndef _VDEC_DRV_BASE_
#define _VDEC_DRV_BASE_
-#include "mtk_vcodec_drv.h"
-
#include "vdec_drv_if.h"
struct vdec_common_if {
diff --git a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
index 2e43dd4486e0..b18743b906ea 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_drv_if.c
@@ -13,7 +13,6 @@
#include "mtk_vcodec_dec.h"
#include "vdec_drv_base.h"
#include "mtk_vcodec_dec_pm.h"
-#include "mtk_vpu.h"
int vdec_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
{
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
index 948a12fd9d46..58b0e6fa8fd2 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.c
@@ -8,6 +8,7 @@
#include "mtk_vcodec_util.h"
#include "vdec_ipi_msg.h"
#include "vdec_vpu_if.h"
+#include "mtk_vcodec_fw.h"
static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg)
{
@@ -18,7 +19,8 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg)
/* mapping VPU address to kernel virtual address */
/* the content in vsi is initialized to 0 in VPU */
- vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr);
+ vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler,
+ msg->vpu_inst_addr);
vpu->inst_addr = msg->vpu_inst_addr;
mtk_vcodec_debug(vpu, "- vpu_inst_addr = 0x%x", vpu->inst_addr);
@@ -34,7 +36,7 @@ static void handle_init_ack_msg(const struct vdec_vpu_ipi_init_ack *msg)
* This function runs in interrupt context and it means there's an IPI MSG
* from VPU.
*/
-static void vpu_dec_ipi_handler(const void *data, unsigned int len, void *priv)
+static void vpu_dec_ipi_handler(void *data, unsigned int len, void *priv)
{
const struct vdec_vpu_ipi_ack *msg = data;
struct vdec_vpu_inst *vpu = (struct vdec_vpu_inst *)
@@ -74,7 +76,8 @@ static int vcodec_vpu_send_msg(struct vdec_vpu_inst *vpu, void *msg, int len)
vpu->failure = 0;
vpu->signaled = 0;
- err = vpu_ipi_send(vpu->dev, vpu->id, msg, len);
+ err = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, vpu->id, msg,
+ len, 2000);
if (err) {
mtk_vcodec_err(vpu, "send fail vpu_id=%d msg_id=%X status=%d",
vpu->id, *(uint32_t *)msg, err);
@@ -110,7 +113,8 @@ int vpu_dec_init(struct vdec_vpu_inst *vpu)
init_waitqueue_head(&vpu->wq);
vpu->handler = vpu_dec_ipi_handler;
- err = vpu_ipi_register(vpu->dev, vpu->id, vpu->handler, "vdec", NULL);
+ err = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id,
+ vpu->handler, "vdec", NULL);
if (err != 0) {
mtk_vcodec_err(vpu, "vpu_ipi_register fail status=%d", err);
return err;
diff --git a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
index f779b0676fbd..85224eb7e34b 100644
--- a/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
+++ b/drivers/media/platform/mtk-vcodec/vdec_vpu_if.h
@@ -7,11 +7,13 @@
#ifndef _VDEC_VPU_IF_H_
#define _VDEC_VPU_IF_H_
-#include "mtk_vpu.h"
+#include "mtk_vcodec_fw.h"
+
+struct mtk_vcodec_ctx;
/**
* struct vdec_vpu_inst - VPU instance for video codec
- * @ipi_id : ipi id for each decoder
+ * @id : ipi msg id for each decoder
* @vsi : driver structure allocated by VPU side and shared to AP side
* for control and info share
* @failure : VPU execution result status, 0: success, others: fail
@@ -23,15 +25,14 @@
* @handler : ipi handler for each decoder
*/
struct vdec_vpu_inst {
- enum ipi_id id;
+ int id;
void *vsi;
int32_t failure;
uint32_t inst_addr;
unsigned int signaled;
struct mtk_vcodec_ctx *ctx;
- struct platform_device *dev;
wait_queue_head_t wq;
- ipi_handler_t handler;
+ mtk_vcodec_ipi_handler handler;
};
/**
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
index b9624f8df0e9..d0123dfc5f93 100644
--- a/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc/venc_h264_if.c
@@ -18,7 +18,6 @@
#include "../venc_drv_base.h"
#include "../venc_ipi_msg.h"
#include "../venc_vpu_if.h"
-#include "mtk_vpu.h"
static const char h264_filler_marker[] = {0x0, 0x0, 0x0, 0x1, 0xc};
@@ -26,6 +25,16 @@ static const char h264_filler_marker[] = {0x0, 0x0, 0x0, 0x1, 0xc};
#define VENC_PIC_BITSTREAM_BYTE_CNT 0x0098
/*
+ * enum venc_h264_frame_type - h264 encoder output bitstream frame type
+ */
+enum venc_h264_frame_type {
+ VENC_H264_IDR_FRM,
+ VENC_H264_I_FRM,
+ VENC_H264_P_FRM,
+ VENC_H264_B_FRM,
+};
+
+/*
* enum venc_h264_vpu_work_buf - h264 encoder buffer index
*/
enum venc_h264_vpu_work_buf {
@@ -139,6 +148,7 @@ struct venc_h264_inst {
struct mtk_vcodec_mem pps_buf;
bool work_buf_allocated;
unsigned int frm_cnt;
+ unsigned int skip_frm_cnt;
unsigned int prepend_hdr;
struct venc_vpu_inst vpu_inst;
struct venc_h264_vsi *vsi;
@@ -257,8 +267,11 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
*/
inst->work_bufs[i].size = wb[i].size;
if (i == VENC_H264_VPU_WORK_BUF_SKIP_FRAME) {
- inst->work_bufs[i].va = vpu_mapping_dm_addr(
- inst->vpu_inst.dev, wb[i].vpua);
+ struct mtk_vcodec_fw *handler;
+
+ handler = inst->vpu_inst.ctx->dev->fw_handler;
+ inst->work_bufs[i].va =
+ mtk_vcodec_fw_map_dm_addr(handler, wb[i].vpua);
inst->work_bufs[i].dma_addr = 0;
} else {
ret = mtk_vcodec_mem_alloc(inst->ctx,
@@ -275,10 +288,12 @@ static int h264_enc_alloc_work_buf(struct venc_h264_inst *inst)
* setting in VPU side.
*/
if (i == VENC_H264_VPU_WORK_BUF_RC_CODE) {
+ struct mtk_vcodec_fw *handler;
void *tmp_va;
- tmp_va = vpu_mapping_dm_addr(inst->vpu_inst.dev,
- wb[i].vpua);
+ handler = inst->vpu_inst.ctx->dev->fw_handler;
+ tmp_va = mtk_vcodec_fw_map_dm_addr(handler,
+ wb[i].vpua);
memcpy(inst->work_bufs[i].va, tmp_va,
wb[i].size);
}
@@ -323,6 +338,22 @@ static unsigned int h264_enc_wait_venc_done(struct venc_h264_inst *inst)
return irq_status;
}
+static int h264_frame_type(struct venc_h264_inst *inst)
+{
+ if ((inst->vsi->config.gop_size != 0 &&
+ (inst->frm_cnt % inst->vsi->config.gop_size) == 0) ||
+ (inst->frm_cnt == 0 && inst->vsi->config.gop_size == 0)) {
+ /* IDR frame */
+ return VENC_H264_IDR_FRM;
+ } else if ((inst->vsi->config.intra_period != 0 &&
+ (inst->frm_cnt % inst->vsi->config.intra_period) == 0) ||
+ (inst->frm_cnt == 0 && inst->vsi->config.intra_period == 0)) {
+ /* I frame */
+ return VENC_H264_I_FRM;
+ } else {
+ return VENC_H264_P_FRM; /* Note: B frames are not supported */
+ }
+}
static int h264_encode_sps(struct venc_h264_inst *inst,
struct mtk_vcodec_mem *bs_buf,
unsigned int *bs_size)
@@ -333,7 +364,7 @@ static int h264_encode_sps(struct venc_h264_inst *inst,
mtk_vcodec_debug_enter(inst);
ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_SPS, NULL,
- bs_buf, bs_size);
+ bs_buf, bs_size, NULL);
if (ret)
return ret;
@@ -360,7 +391,7 @@ static int h264_encode_pps(struct venc_h264_inst *inst,
mtk_vcodec_debug_enter(inst);
ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_PPS, NULL,
- bs_buf, bs_size);
+ bs_buf, bs_size, NULL);
if (ret)
return ret;
@@ -406,11 +437,18 @@ static int h264_encode_frame(struct venc_h264_inst *inst,
{
int ret = 0;
unsigned int irq_status;
+ struct venc_frame_info frame_info;
mtk_vcodec_debug_enter(inst);
-
+ mtk_vcodec_debug(inst, "frm_cnt = %d\n ", inst->frm_cnt);
+ frame_info.frm_count = inst->frm_cnt;
+ frame_info.skip_frm_count = inst->skip_frm_cnt;
+ frame_info.frm_type = h264_frame_type(inst);
+ mtk_vcodec_debug(inst, "frm_count = %d,skip_frm_count =%d,frm_type=%d.\n",
+ frame_info.frm_count, frame_info.skip_frm_count,
+ frame_info.frm_type);
ret = vpu_enc_encode(&inst->vpu_inst, H264_BS_MODE_FRAME, frm_buf,
- bs_buf, bs_size);
+ bs_buf, bs_size, &frame_info);
if (ret)
return ret;
@@ -424,6 +462,7 @@ static int h264_encode_frame(struct venc_h264_inst *inst,
inst->work_bufs[VENC_H264_VPU_WORK_BUF_SKIP_FRAME].va,
*bs_size);
++inst->frm_cnt;
+ ++inst->skip_frm_cnt;
return ret;
}
@@ -460,6 +499,7 @@ static void h264_encode_filler(struct venc_h264_inst *inst, void *buf,
static int h264_enc_init(struct mtk_vcodec_ctx *ctx)
{
+ const bool is_ext = MTK_ENC_CTX_IS_EXT(ctx);
int ret = 0;
struct venc_h264_inst *inst;
@@ -469,8 +509,7 @@ static int h264_enc_init(struct mtk_vcodec_ctx *ctx)
inst->ctx = ctx;
inst->vpu_inst.ctx = ctx;
- inst->vpu_inst.dev = ctx->dev->vpu_plat_dev;
- inst->vpu_inst.id = IPI_VENC_H264;
+ inst->vpu_inst.id = is_ext ? SCP_IPI_VENC_H264 : IPI_VENC_H264;
inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_SYS);
mtk_vcodec_debug_enter(inst);
@@ -626,7 +665,12 @@ static int h264_enc_set_param(void *handle,
inst->prepend_hdr = 1;
mtk_vcodec_debug(inst, "set prepend header mode");
break;
-
+ case VENC_SET_PARAM_FORCE_INTRA:
+ case VENC_SET_PARAM_GOP_SIZE:
+ case VENC_SET_PARAM_INTRA_PERIOD:
+ inst->frm_cnt = 0;
+ inst->skip_frm_cnt = 0;
+ fallthrough;
default:
ret = vpu_enc_set_param(&inst->vpu_inst, type, enc_prm);
break;
diff --git a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
index 8d36f0362efe..11abb191ada5 100644
--- a/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc/venc_vp8_if.c
@@ -17,7 +17,6 @@
#include "../venc_drv_base.h"
#include "../venc_ipi_msg.h"
#include "../venc_vpu_if.h"
-#include "mtk_vpu.h"
#define VENC_BITSTREAM_FRAME_SIZE 0x0098
#define VENC_BITSTREAM_HEADER_LEN 0x00e8
@@ -190,10 +189,12 @@ static int vp8_enc_alloc_work_buf(struct venc_vp8_inst *inst)
if (i == VENC_VP8_VPU_WORK_BUF_RC_CODE ||
i == VENC_VP8_VPU_WORK_BUF_RC_CODE2 ||
i == VENC_VP8_VPU_WORK_BUF_RC_CODE3) {
+ struct mtk_vcodec_fw *handler;
void *tmp_va;
- tmp_va = vpu_mapping_dm_addr(inst->vpu_inst.dev,
- wb[i].vpua);
+ handler = inst->vpu_inst.ctx->dev->fw_handler;
+ tmp_va = mtk_vcodec_fw_map_dm_addr(handler,
+ wb[i].vpua);
memcpy(inst->work_bufs[i].va, tmp_va, wb[i].size);
}
wb[i].iova = inst->work_bufs[i].dma_addr;
@@ -301,7 +302,8 @@ static int vp8_enc_encode_frame(struct venc_vp8_inst *inst,
mtk_vcodec_debug(inst, "->frm_cnt=%d", inst->frm_cnt);
- ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, bs_size);
+ ret = vpu_enc_encode(&inst->vpu_inst, 0, frm_buf, bs_buf, bs_size,
+ NULL);
if (ret)
return ret;
@@ -334,7 +336,6 @@ static int vp8_enc_init(struct mtk_vcodec_ctx *ctx)
inst->ctx = ctx;
inst->vpu_inst.ctx = ctx;
- inst->vpu_inst.dev = ctx->dev->vpu_plat_dev;
inst->vpu_inst.id = IPI_VENC_VP8;
inst->hw_base = mtk_vcodec_get_reg_addr(inst->ctx, VENC_LT_SYS);
diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.c b/drivers/media/platform/mtk-vcodec/venc_drv_if.c
index c6bb82ac2dcd..ce0bce811615 100644
--- a/drivers/media/platform/mtk-vcodec/venc_drv_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.c
@@ -15,7 +15,6 @@
#include "mtk_vcodec_enc.h"
#include "mtk_vcodec_enc_pm.h"
-#include "mtk_vpu.h"
int venc_if_init(struct mtk_vcodec_ctx *ctx, unsigned int fourcc)
{
diff --git a/drivers/media/platform/mtk-vcodec/venc_drv_if.h b/drivers/media/platform/mtk-vcodec/venc_drv_if.h
index 52fc9cc812fc..0b04a1020873 100644
--- a/drivers/media/platform/mtk-vcodec/venc_drv_if.h
+++ b/drivers/media/platform/mtk-vcodec/venc_drv_if.h
@@ -92,6 +92,19 @@ struct venc_enc_param {
unsigned int gop_size;
};
+/**
+ * struct venc_frame_info - per-frame information to pass to the firmware.
+ *
+ * @frm_count: sequential number for this frame
+ * @skip_frm_count: number of frames skipped so far while decoding
+ * @frm_type: type of the frame, from enum venc_h264_frame_type
+ */
+struct venc_frame_info {
+ unsigned int frm_count; /* per frame update */
+ unsigned int skip_frm_count; /* per frame update */
+ unsigned int frm_type; /* per frame update */
+};
+
/*
* struct venc_frm_buf - frame buffer information used in venc_if_encode()
* @fb_addr: plane frame buffer addresses
diff --git a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
index 28ee04ca6241..2feb0365179f 100644
--- a/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
+++ b/drivers/media/platform/mtk-vcodec/venc_ipi_msg.h
@@ -62,6 +62,11 @@ struct venc_ap_ipi_msg_set_param {
uint32_t data[8];
};
+struct venc_ap_ipi_msg_set_param_ext {
+ struct venc_ap_ipi_msg_set_param base;
+ uint32_t data_ext[24];
+};
+
/**
* struct venc_ap_ipi_msg_enc - AP to VPU enc cmd structure
* @msg_id: message id (AP_IPIMSG_XXX_ENC_ENCODE)
@@ -83,6 +88,19 @@ struct venc_ap_ipi_msg_enc {
};
/**
+ * struct venc_ap_ipi_msg_enc_ext - AP to SCP extended enc cmd structure
+ *
+ * @base: base msg structure
+ * @data_item: number of items in the data array
+ * @data[8]: data array to store the set parameters
+ */
+struct venc_ap_ipi_msg_enc_ext {
+ struct venc_ap_ipi_msg_enc base;
+ uint32_t data_item;
+ uint32_t data[32];
+};
+
+/**
* struct venc_ap_ipi_msg_deinit - AP to VPU deinit cmd structure
* @msg_id: message id (AP_IPIMSG_XXX_ENC_DEINIT)
* @vpu_inst_addr: VPU encoder instance addr
@@ -120,16 +138,17 @@ struct venc_vpu_ipi_msg_common {
* @venc_inst: AP encoder instance (struct venc_vp8_inst/venc_h264_inst *)
* @vpu_inst_addr: VPU encoder instance addr
* (struct venc_vp8_vsi/venc_h264_vsi *)
- * @reserved: reserved for future use. vpu is running in 32bit. Without
- * this reserved field, if kernel run in 64bit. this struct size
- * will be different between kernel and vpu
+ * @venc_abi_version: ABI version of the firmware. Kernel can use it to
+ * ensure that it is compatible with the firmware.
+ * For MT8173 the value of this field is undefined and
+ * should not be used.
*/
struct venc_vpu_ipi_msg_init {
uint32_t msg_id;
uint32_t status;
uint64_t venc_inst;
uint32_t vpu_inst_addr;
- uint32_t reserved;
+ uint32_t venc_abi_version;
};
/**
diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
index 9540709c1905..be6d8790a41e 100644
--- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
+++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.c
@@ -4,7 +4,8 @@
* Author: PoChun Lin <pochun.lin@mediatek.com>
*/
-#include "mtk_vpu.h"
+#include "mtk_vcodec_drv.h"
+#include "mtk_vcodec_fw.h"
#include "venc_ipi_msg.h"
#include "venc_vpu_if.h"
@@ -13,7 +14,25 @@ static void handle_enc_init_msg(struct venc_vpu_inst *vpu, const void *data)
const struct venc_vpu_ipi_msg_init *msg = data;
vpu->inst_addr = msg->vpu_inst_addr;
- vpu->vsi = vpu_mapping_dm_addr(vpu->dev, msg->vpu_inst_addr);
+ vpu->vsi = mtk_vcodec_fw_map_dm_addr(vpu->ctx->dev->fw_handler,
+ msg->vpu_inst_addr);
+
+ /* Firmware version field value is unspecified on MT8173. */
+ if (vpu->ctx->dev->venc_pdata->chip == MTK_MT8173)
+ return;
+
+ /* Check firmware version. */
+ mtk_vcodec_debug(vpu, "firmware version: 0x%x\n",
+ msg->venc_abi_version);
+ switch (msg->venc_abi_version) {
+ case 1:
+ break;
+ default:
+ mtk_vcodec_err(vpu, "unhandled firmware version 0x%x\n",
+ msg->venc_abi_version);
+ vpu->failure = 1;
+ break;
+ }
}
static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data)
@@ -25,7 +44,7 @@ static void handle_enc_encode_msg(struct venc_vpu_inst *vpu, const void *data)
vpu->is_key_frm = msg->is_key_frm;
}
-static void vpu_enc_ipi_handler(const void *data, unsigned int len, void *priv)
+static void vpu_enc_ipi_handler(void *data, unsigned int len, void *priv)
{
const struct venc_vpu_ipi_msg_common *msg = data;
struct venc_vpu_inst *vpu =
@@ -34,6 +53,11 @@ static void vpu_enc_ipi_handler(const void *data, unsigned int len, void *priv)
mtk_vcodec_debug(vpu, "msg_id %x inst %p status %d",
msg->msg_id, vpu, msg->status);
+ vpu->signaled = 1;
+ vpu->failure = (msg->status != VENC_IPI_MSG_STATUS_OK);
+ if (vpu->failure)
+ goto failure;
+
switch (msg->msg_id) {
case VPU_IPIMSG_ENC_INIT_DONE:
handle_enc_init_msg(vpu, data);
@@ -50,9 +74,7 @@ static void vpu_enc_ipi_handler(const void *data, unsigned int len, void *priv)
break;
}
- vpu->signaled = 1;
- vpu->failure = (msg->status != VENC_IPI_MSG_STATUS_OK);
-
+failure:
mtk_vcodec_debug_leave(vpu);
}
@@ -63,12 +85,13 @@ static int vpu_enc_send_msg(struct venc_vpu_inst *vpu, void *msg,
mtk_vcodec_debug_enter(vpu);
- if (!vpu->dev) {
+ if (!vpu->ctx->dev->fw_handler) {
mtk_vcodec_err(vpu, "inst dev is NULL");
return -EINVAL;
}
- status = vpu_ipi_send(vpu->dev, vpu->id, msg, len);
+ status = mtk_vcodec_fw_ipi_send(vpu->ctx->dev->fw_handler, vpu->id, msg,
+ len, 2000);
if (status) {
mtk_vcodec_err(vpu, "vpu_ipi_send msg_id %x len %d fail %d",
*(uint32_t *)msg, len, status);
@@ -93,8 +116,9 @@ int vpu_enc_init(struct venc_vpu_inst *vpu)
vpu->signaled = 0;
vpu->failure = 0;
- status = vpu_ipi_register(vpu->dev, vpu->id, vpu_enc_ipi_handler,
- NULL, NULL);
+ status = mtk_vcodec_fw_ipi_register(vpu->ctx->dev->fw_handler, vpu->id,
+ vpu_enc_ipi_handler, "venc", NULL);
+
if (status) {
mtk_vcodec_err(vpu, "vpu_ipi_register fail %d", status);
return -EINVAL;
@@ -113,49 +137,81 @@ int vpu_enc_init(struct venc_vpu_inst *vpu)
return 0;
}
+static unsigned int venc_enc_param_crop_right(struct venc_vpu_inst *vpu,
+ struct venc_enc_param *enc_prm)
+{
+ unsigned int img_crop_right = enc_prm->buf_width - enc_prm->width;
+
+ return img_crop_right % 16;
+}
+
+static unsigned int venc_enc_param_crop_bottom(struct venc_enc_param *enc_prm)
+{
+ return round_up(enc_prm->height, 16) - enc_prm->height;
+}
+
+static unsigned int venc_enc_param_num_mb(struct venc_enc_param *enc_prm)
+{
+ return DIV_ROUND_UP(enc_prm->width, 16) *
+ DIV_ROUND_UP(enc_prm->height, 16);
+}
+
int vpu_enc_set_param(struct venc_vpu_inst *vpu,
enum venc_set_param_type id,
struct venc_enc_param *enc_param)
{
- struct venc_ap_ipi_msg_set_param out;
+ const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx);
+ size_t msg_size = is_ext ?
+ sizeof(struct venc_ap_ipi_msg_set_param_ext) :
+ sizeof(struct venc_ap_ipi_msg_set_param);
+ struct venc_ap_ipi_msg_set_param_ext out;
mtk_vcodec_debug(vpu, "id %d ->", id);
memset(&out, 0, sizeof(out));
- out.msg_id = AP_IPIMSG_ENC_SET_PARAM;
- out.vpu_inst_addr = vpu->inst_addr;
- out.param_id = id;
+ out.base.msg_id = AP_IPIMSG_ENC_SET_PARAM;
+ out.base.vpu_inst_addr = vpu->inst_addr;
+ out.base.param_id = id;
switch (id) {
case VENC_SET_PARAM_ENC:
- out.data_item = 0;
+ if (is_ext) {
+ out.base.data_item = 3;
+ out.base.data[0] =
+ venc_enc_param_crop_right(vpu, enc_param);
+ out.base.data[1] =
+ venc_enc_param_crop_bottom(enc_param);
+ out.base.data[2] = venc_enc_param_num_mb(enc_param);
+ } else {
+ out.base.data_item = 0;
+ }
break;
case VENC_SET_PARAM_FORCE_INTRA:
- out.data_item = 0;
+ out.base.data_item = 0;
break;
case VENC_SET_PARAM_ADJUST_BITRATE:
- out.data_item = 1;
- out.data[0] = enc_param->bitrate;
+ out.base.data_item = 1;
+ out.base.data[0] = enc_param->bitrate;
break;
case VENC_SET_PARAM_ADJUST_FRAMERATE:
- out.data_item = 1;
- out.data[0] = enc_param->frm_rate;
+ out.base.data_item = 1;
+ out.base.data[0] = enc_param->frm_rate;
break;
case VENC_SET_PARAM_GOP_SIZE:
- out.data_item = 1;
- out.data[0] = enc_param->gop_size;
+ out.base.data_item = 1;
+ out.base.data[0] = enc_param->gop_size;
break;
case VENC_SET_PARAM_INTRA_PERIOD:
- out.data_item = 1;
- out.data[0] = enc_param->intra_period;
+ out.base.data_item = 1;
+ out.base.data[0] = enc_param->intra_period;
break;
case VENC_SET_PARAM_SKIP_FRAME:
- out.data_item = 0;
+ out.base.data_item = 0;
break;
default:
mtk_vcodec_err(vpu, "id %d not supported", id);
return -EINVAL;
}
- if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
+ if (vpu_enc_send_msg(vpu, &out, msg_size)) {
mtk_vcodec_err(vpu,
"AP_IPIMSG_ENC_SET_PARAM %d fail", id);
return -EINVAL;
@@ -169,33 +225,44 @@ int vpu_enc_set_param(struct venc_vpu_inst *vpu,
int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode,
struct venc_frm_buf *frm_buf,
struct mtk_vcodec_mem *bs_buf,
- unsigned int *bs_size)
+ unsigned int *bs_size,
+ struct venc_frame_info *frame_info)
{
- struct venc_ap_ipi_msg_enc out;
+ const bool is_ext = MTK_ENC_CTX_IS_EXT(vpu->ctx);
+ size_t msg_size = is_ext ?
+ sizeof(struct venc_ap_ipi_msg_enc_ext) :
+ sizeof(struct venc_ap_ipi_msg_enc);
+ struct venc_ap_ipi_msg_enc_ext out;
mtk_vcodec_debug(vpu, "bs_mode %d ->", bs_mode);
memset(&out, 0, sizeof(out));
- out.msg_id = AP_IPIMSG_ENC_ENCODE;
- out.vpu_inst_addr = vpu->inst_addr;
- out.bs_mode = bs_mode;
+ out.base.msg_id = AP_IPIMSG_ENC_ENCODE;
+ out.base.vpu_inst_addr = vpu->inst_addr;
+ out.base.bs_mode = bs_mode;
if (frm_buf) {
if ((frm_buf->fb_addr[0].dma_addr % 16 == 0) &&
(frm_buf->fb_addr[1].dma_addr % 16 == 0) &&
(frm_buf->fb_addr[2].dma_addr % 16 == 0)) {
- out.input_addr[0] = frm_buf->fb_addr[0].dma_addr;
- out.input_addr[1] = frm_buf->fb_addr[1].dma_addr;
- out.input_addr[2] = frm_buf->fb_addr[2].dma_addr;
+ out.base.input_addr[0] = frm_buf->fb_addr[0].dma_addr;
+ out.base.input_addr[1] = frm_buf->fb_addr[1].dma_addr;
+ out.base.input_addr[2] = frm_buf->fb_addr[2].dma_addr;
} else {
mtk_vcodec_err(vpu, "dma_addr not align to 16");
return -EINVAL;
}
}
if (bs_buf) {
- out.bs_addr = bs_buf->dma_addr;
- out.bs_size = bs_buf->size;
+ out.base.bs_addr = bs_buf->dma_addr;
+ out.base.bs_size = bs_buf->size;
}
- if (vpu_enc_send_msg(vpu, &out, sizeof(out))) {
+ if (is_ext && frame_info) {
+ out.data_item = 3;
+ out.data[0] = frame_info->frm_count;
+ out.data[1] = frame_info->skip_frm_count;
+ out.data[2] = frame_info->frm_type;
+ }
+ if (vpu_enc_send_msg(vpu, &out, msg_size)) {
mtk_vcodec_err(vpu, "AP_IPIMSG_ENC_ENCODE %d fail",
bs_mode);
return -EINVAL;
diff --git a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h
index ba301a138a5a..f9be9cab7ff7 100644
--- a/drivers/media/platform/mtk-vcodec/venc_vpu_if.h
+++ b/drivers/media/platform/mtk-vcodec/venc_vpu_if.h
@@ -7,7 +7,7 @@
#ifndef _VENC_VPU_IF_H_
#define _VENC_VPU_IF_H_
-#include "mtk_vpu.h"
+#include "mtk_vcodec_fw.h"
#include "venc_drv_if.h"
/*
@@ -34,9 +34,8 @@ struct venc_vpu_inst {
int is_key_frm;
unsigned int inst_addr;
void *vsi;
- enum ipi_id id;
+ int id;
struct mtk_vcodec_ctx *ctx;
- struct platform_device *dev;
};
int vpu_enc_init(struct venc_vpu_inst *vpu);
@@ -46,7 +45,8 @@ int vpu_enc_set_param(struct venc_vpu_inst *vpu,
int vpu_enc_encode(struct venc_vpu_inst *vpu, unsigned int bs_mode,
struct venc_frm_buf *frm_buf,
struct mtk_vcodec_mem *bs_buf,
- unsigned int *bs_size);
+ unsigned int *bs_size,
+ struct venc_frame_info *frame_info);
int vpu_enc_deinit(struct venc_vpu_inst *vpu);
#endif
diff --git a/drivers/media/platform/mtk-vpu/mtk_vpu.c b/drivers/media/platform/mtk-vpu/mtk_vpu.c
index d30c08983f56..36cb9b6131f7 100644
--- a/drivers/media/platform/mtk-vpu/mtk_vpu.c
+++ b/drivers/media/platform/mtk-vpu/mtk_vpu.c
@@ -849,10 +849,6 @@ static int mtk_vpu_probe(struct platform_device *pdev)
#ifdef CONFIG_DEBUG_FS
vpu_debugfs = debugfs_create_file("mtk_vpu", S_IRUGO, NULL, (void *)dev,
&vpu_debug_fops);
- if (!vpu_debugfs) {
- ret = -ENOMEM;
- goto cleanup_ipi;
- }
#endif
/* Set PTCM to 96K and DTCM to 32K */
@@ -910,7 +906,6 @@ remove_debugfs:
of_reserved_mem_device_release(dev);
#ifdef CONFIG_DEBUG_FS
debugfs_remove(vpu_debugfs);
-cleanup_ipi:
#endif
memset(vpu->ipi_desc, 0, sizeof(struct vpu_ipi_desc) * IPI_MAX);
vpu_mutex_destroy:
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index df78df59da45..08a5473b5610 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -852,8 +852,11 @@ static int emmaprp_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, pcdev);
irq = platform_get_irq(pdev, 0);
- if (irq < 0)
- return irq;
+ if (irq < 0) {
+ ret = irq;
+ goto rel_vdev;
+ }
+
ret = devm_request_irq(&pdev->dev, irq, emmaprp_irq, 0,
dev_name(&pdev->dev), pcdev);
if (ret)
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index b91e472ee764..b1fc4518e275 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -142,7 +142,7 @@ static struct isp_reg isp_reg_list[] = {
* readback the same register, in this case the revision register.
*
* See this link for reference:
- * http://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
+ * https://www.mail-archive.com/linux-omap@vger.kernel.org/msg08149.html
*/
void omap3isp_flush(struct isp_device *isp)
{
@@ -2328,8 +2328,10 @@ static int isp_probe(struct platform_device *pdev)
mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
isp->mmio_base[map_idx] =
devm_ioremap_resource(isp->dev, mem);
- if (IS_ERR(isp->mmio_base[map_idx]))
- return PTR_ERR(isp->mmio_base[map_idx]);
+ if (IS_ERR(isp->mmio_base[map_idx])) {
+ ret = PTR_ERR(isp->mmio_base[map_idx]);
+ goto error;
+ }
}
ret = isp_get_clocks(isp);
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index 1ac9aef70dff..8811d6dd4ee7 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -703,7 +703,7 @@ isp_video_set_format(struct file *file, void *fh, struct v4l2_format *format)
* requested.
*/
format->fmt.pix.field = V4L2_FIELD_INTERLACED_TB;
- /* Fall-through */
+ fallthrough;
case V4L2_FIELD_INTERLACED_TB:
case V4L2_FIELD_INTERLACED_BT:
/* Interlaced orders are only supported at the CCDC output. */
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index 6dce33f35041..e47520fcb93c 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -605,42 +605,6 @@ static const struct pxa_mbus_pixelfmt *pxa_mbus_get_fmtdesc(
return pxa_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
}
-static unsigned int pxa_mbus_config_compatible(const struct v4l2_mbus_config *cfg,
- unsigned int flags)
-{
- unsigned long common_flags;
- bool hsync = true, vsync = true, pclk, data, mode;
- bool mipi_lanes, mipi_clock;
-
- common_flags = cfg->flags & flags;
-
- switch (cfg->type) {
- case V4L2_MBUS_PARALLEL:
- hsync = common_flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH |
- V4L2_MBUS_HSYNC_ACTIVE_LOW);
- vsync = common_flags & (V4L2_MBUS_VSYNC_ACTIVE_HIGH |
- V4L2_MBUS_VSYNC_ACTIVE_LOW);
- /* fall through */
- case V4L2_MBUS_BT656:
- pclk = common_flags & (V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_PCLK_SAMPLE_FALLING);
- data = common_flags & (V4L2_MBUS_DATA_ACTIVE_HIGH |
- V4L2_MBUS_DATA_ACTIVE_LOW);
- mode = common_flags & (V4L2_MBUS_MASTER | V4L2_MBUS_SLAVE);
- return (!hsync || !vsync || !pclk || !data || !mode) ?
- 0 : common_flags;
- case V4L2_MBUS_CSI2_DPHY:
- mipi_lanes = common_flags & V4L2_MBUS_CSI2_LANES;
- mipi_clock = common_flags & (V4L2_MBUS_CSI2_NONCONTINUOUS_CLOCK |
- V4L2_MBUS_CSI2_CONTINUOUS_CLOCK);
- return (!mipi_lanes || !mipi_clock) ? 0 : common_flags;
- default:
- WARN_ON(1);
- return -EINVAL;
- }
- return 0;
-}
-
/**
* struct pxa_camera_format_xlate - match between host and sensor formats
* @code: code of a sensor provided format
@@ -1186,9 +1150,9 @@ static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
clk_disable_unprepare(pcdev->clk);
}
-static void pxa_camera_eof(unsigned long arg)
+static void pxa_camera_eof(struct tasklet_struct *t)
{
- struct pxa_camera_dev *pcdev = (struct pxa_camera_dev *)arg;
+ struct pxa_camera_dev *pcdev = from_tasklet(pcdev, t, task_eof);
unsigned long cifr;
struct pxa_buffer *buf;
@@ -1231,31 +1195,6 @@ static irqreturn_t pxa_camera_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int test_platform_param(struct pxa_camera_dev *pcdev,
- unsigned char buswidth, unsigned long *flags)
-{
- /*
- * Platform specified synchronization and pixel clock polarities are
- * only a recommendation and are only used during probing. The PXA270
- * quick capture interface supports both.
- */
- *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
- V4L2_MBUS_MASTER : V4L2_MBUS_SLAVE) |
- V4L2_MBUS_HSYNC_ACTIVE_HIGH |
- V4L2_MBUS_HSYNC_ACTIVE_LOW |
- V4L2_MBUS_VSYNC_ACTIVE_HIGH |
- V4L2_MBUS_VSYNC_ACTIVE_LOW |
- V4L2_MBUS_DATA_ACTIVE_HIGH |
- V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_PCLK_SAMPLE_FALLING;
-
- /* If requested data width is supported by the platform, use it */
- if ((1 << (buswidth - 1)) & pcdev->width_flags)
- return 0;
-
- return -EINVAL;
-}
-
static void pxa_camera_setup_cicr(struct pxa_camera_dev *pcdev,
unsigned long flags, __u32 pixfmt)
{
@@ -1598,99 +1537,78 @@ static int pxa_camera_init_videobuf2(struct pxa_camera_dev *pcdev)
*/
static int pxa_camera_set_bus_param(struct pxa_camera_dev *pcdev)
{
+ unsigned int bus_width = pcdev->current_fmt->host_fmt->bits_per_sample;
struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
u32 pixfmt = pcdev->current_fmt->host_fmt->fourcc;
- unsigned long bus_flags, common_flags;
+ int mbus_config;
int ret;
- ret = test_platform_param(pcdev,
- pcdev->current_fmt->host_fmt->bits_per_sample,
- &bus_flags);
- if (ret < 0)
- return ret;
-
- ret = sensor_call(pcdev, video, g_mbus_config, &cfg);
- if (!ret) {
- common_flags = pxa_mbus_config_compatible(&cfg,
- bus_flags);
- if (!common_flags) {
- dev_warn(pcdev_to_dev(pcdev),
- "Flags incompatible: camera 0x%x, host 0x%lx\n",
- cfg.flags, bus_flags);
- return -EINVAL;
- }
- } else if (ret != -ENOIOCTLCMD) {
- return ret;
- } else {
- common_flags = bus_flags;
+ if (!((1 << (bus_width - 1)) & pcdev->width_flags)) {
+ dev_err(pcdev_to_dev(pcdev), "Unsupported bus width %u",
+ bus_width);
+ return -EINVAL;
}
pcdev->channels = 1;
/* Make choices, based on platform preferences */
- if ((common_flags & V4L2_MBUS_HSYNC_ACTIVE_HIGH) &&
- (common_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW)) {
- if (pcdev->platform_flags & PXA_CAMERA_HSP)
- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_HIGH;
- else
- common_flags &= ~V4L2_MBUS_HSYNC_ACTIVE_LOW;
- }
+ mbus_config = 0;
+ if (pcdev->platform_flags & PXA_CAMERA_MASTER)
+ mbus_config |= V4L2_MBUS_MASTER;
+ else
+ mbus_config |= V4L2_MBUS_SLAVE;
- if ((common_flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH) &&
- (common_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW)) {
- if (pcdev->platform_flags & PXA_CAMERA_VSP)
- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_HIGH;
- else
- common_flags &= ~V4L2_MBUS_VSYNC_ACTIVE_LOW;
- }
+ if (pcdev->platform_flags & PXA_CAMERA_HSP)
+ mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_HIGH;
+ else
+ mbus_config |= V4L2_MBUS_HSYNC_ACTIVE_LOW;
- if ((common_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) &&
- (common_flags & V4L2_MBUS_PCLK_SAMPLE_FALLING)) {
- if (pcdev->platform_flags & PXA_CAMERA_PCP)
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_RISING;
- else
- common_flags &= ~V4L2_MBUS_PCLK_SAMPLE_FALLING;
- }
+ if (pcdev->platform_flags & PXA_CAMERA_VSP)
+ mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_HIGH;
+ else
+ mbus_config |= V4L2_MBUS_VSYNC_ACTIVE_LOW;
- cfg.flags = common_flags;
- ret = sensor_call(pcdev, video, s_mbus_config, &cfg);
+ if (pcdev->platform_flags & PXA_CAMERA_PCP)
+ mbus_config |= V4L2_MBUS_PCLK_SAMPLE_RISING;
+ else
+ mbus_config |= V4L2_MBUS_PCLK_SAMPLE_FALLING;
+ mbus_config |= V4L2_MBUS_DATA_ACTIVE_HIGH;
+
+ cfg.flags = mbus_config;
+ ret = sensor_call(pcdev, pad, set_mbus_config, 0, &cfg);
if (ret < 0 && ret != -ENOIOCTLCMD) {
- dev_dbg(pcdev_to_dev(pcdev),
- "camera s_mbus_config(0x%lx) returned %d\n",
- common_flags, ret);
+ dev_err(pcdev_to_dev(pcdev),
+ "Failed to call set_mbus_config: %d\n", ret);
return ret;
}
- pxa_camera_setup_cicr(pcdev, common_flags, pixfmt);
-
- return 0;
-}
-
-static int pxa_camera_try_bus_param(struct pxa_camera_dev *pcdev,
- unsigned char buswidth)
-{
- struct v4l2_mbus_config cfg = {.type = V4L2_MBUS_PARALLEL,};
- unsigned long bus_flags, common_flags;
- int ret = test_platform_param(pcdev, buswidth, &bus_flags);
-
- if (ret < 0)
- return ret;
+ /*
+ * If the requested media bus configuration has not been fully applied
+ * make sure it is supported by the platform.
+ *
+ * PXA does not support V4L2_MBUS_DATA_ACTIVE_LOW and the bus mastering
+ * roles should match.
+ */
+ if (cfg.flags != mbus_config) {
+ unsigned int pxa_mbus_role = mbus_config & (V4L2_MBUS_MASTER |
+ V4L2_MBUS_SLAVE);
+ if (pxa_mbus_role != (cfg.flags & (V4L2_MBUS_MASTER |
+ V4L2_MBUS_SLAVE))) {
+ dev_err(pcdev_to_dev(pcdev),
+ "Unsupported mbus configuration: bus mastering\n");
+ return -EINVAL;
+ }
- ret = sensor_call(pcdev, video, g_mbus_config, &cfg);
- if (!ret) {
- common_flags = pxa_mbus_config_compatible(&cfg,
- bus_flags);
- if (!common_flags) {
- dev_warn(pcdev_to_dev(pcdev),
- "Flags incompatible: camera 0x%x, host 0x%lx\n",
- cfg.flags, bus_flags);
+ if (cfg.flags & V4L2_MBUS_DATA_ACTIVE_LOW) {
+ dev_err(pcdev_to_dev(pcdev),
+ "Unsupported mbus configuration: DATA_ACTIVE_LOW\n");
return -EINVAL;
}
- } else if (ret == -ENOIOCTLCMD) {
- ret = 0;
}
- return ret;
+ pxa_camera_setup_cicr(pcdev, cfg.flags, pixfmt);
+
+ return 0;
}
static const struct pxa_mbus_pixelfmt pxa_camera_formats[] = {
@@ -1738,11 +1656,6 @@ static int pxa_camera_get_formats(struct v4l2_device *v4l2_dev,
return 0;
}
- /* This also checks support for the requested bits-per-sample */
- ret = pxa_camera_try_bus_param(pcdev, fmt->bits_per_sample);
- if (ret < 0)
- return 0;
-
switch (code.code) {
case MEDIA_BUS_FMT_UYVY8_2X8:
formats++;
@@ -2478,7 +2391,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
goto exit_free_dma;
}
- tasklet_init(&pcdev->task_eof, pxa_camera_eof, (unsigned long)pcdev);
+ tasklet_setup(&pcdev->task_eof, pxa_camera_eof);
pxa_camera_activate(pcdev);
diff --git a/drivers/media/platform/qcom/camss/camss-csiphy.c b/drivers/media/platform/qcom/camss/camss-csiphy.c
index 03ef9c5f4774..85b24054f35e 100644
--- a/drivers/media/platform/qcom/camss/camss-csiphy.c
+++ b/drivers/media/platform/qcom/camss/camss-csiphy.c
@@ -176,8 +176,10 @@ static int csiphy_set_power(struct v4l2_subdev *sd, int on)
int ret;
ret = pm_runtime_get_sync(dev);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put_sync(dev);
return ret;
+ }
ret = csiphy_set_clock_rates(csiphy);
if (ret < 0) {
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.c b/drivers/media/platform/qcom/camss/camss-vfe.c
index fc31c2c169cd..b7d2293a5004 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.c
+++ b/drivers/media/platform/qcom/camss/camss-vfe.c
@@ -2205,14 +2205,6 @@ static const struct camss_video_ops camss_vfe_video_ops = {
.flush_buffers = vfe_flush_buffers,
};
-void msm_vfe_stop_streaming(struct vfe_device *vfe)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(vfe->line); i++)
- msm_video_stop_streaming(&vfe->line[i].video_out);
-}
-
/*
* msm_vfe_register_entities - Register subdev node for VFE module
* @vfe: VFE device
diff --git a/drivers/media/platform/qcom/camss/camss-vfe.h b/drivers/media/platform/qcom/camss/camss-vfe.h
index 0d10071ae881..a90b0d2cc6de 100644
--- a/drivers/media/platform/qcom/camss/camss-vfe.h
+++ b/drivers/media/platform/qcom/camss/camss-vfe.h
@@ -178,8 +178,6 @@ void msm_vfe_unregister_entities(struct vfe_device *vfe);
void msm_vfe_get_vfe_id(struct media_entity *entity, u8 *id);
void msm_vfe_get_vfe_line_id(struct media_entity *entity, enum vfe_line_id *id);
-void msm_vfe_stop_streaming(struct vfe_device *vfe);
-
extern const struct vfe_hw_ops vfe_ops_4_1;
extern const struct vfe_hw_ops vfe_ops_4_7;
diff --git a/drivers/media/platform/qcom/camss/camss-video.c b/drivers/media/platform/qcom/camss/camss-video.c
index cdbd6dba1122..114c3ae4a4ab 100644
--- a/drivers/media/platform/qcom/camss/camss-video.c
+++ b/drivers/media/platform/qcom/camss/camss-video.c
@@ -18,6 +18,12 @@
#include "camss-video.h"
#include "camss.h"
+#define CAMSS_FRAME_MIN_WIDTH 1
+#define CAMSS_FRAME_MAX_WIDTH 8191
+#define CAMSS_FRAME_MIN_HEIGHT 1
+#define CAMSS_FRAME_MAX_HEIGHT_RDI 8191
+#define CAMSS_FRAME_MAX_HEIGHT_PIX 4096
+
struct fract {
u8 numerator;
u8 denominator;
@@ -529,17 +535,16 @@ static int video_querycap(struct file *file, void *fh,
return 0;
}
-static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+/*
+ * Returns the index in the video->formats[] array of the element which
+ * has the "ndx"th unique value of pixelformat field.
+ * If not found (no more unique pixelformat's) returns -EINVAL.
+ */
+static int video_get_unique_pixelformat_by_index(struct camss_video *video,
+ int ndx)
{
- struct camss_video *video = video_drvdata(file);
int i, j, k;
- if (f->type != video->type)
- return -EINVAL;
-
- if (f->index >= video->nformats)
- return -EINVAL;
-
/* find index "i" of "k"th unique pixelformat in formats array */
k = -1;
for (i = 0; i < video->nformats; i++) {
@@ -552,11 +557,53 @@ static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
if (j == i)
k++;
- if (k == f->index)
- break;
+ if (k == ndx)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * Returns the index in the video->formats[] array of the element which
+ * has code equal to mcode.
+ * If not found returns -EINVAL.
+ */
+static int video_get_pixelformat_by_mbus_code(struct camss_video *video,
+ u32 mcode)
+{
+ int i;
+
+ for (i = 0; i < video->nformats; i++) {
+ if (video->formats[i].code == mcode)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
+{
+ struct camss_video *video = video_drvdata(file);
+ int i;
+
+ if (f->type != video->type)
+ return -EINVAL;
+
+ if (f->index >= video->nformats)
+ return -EINVAL;
+
+ if (f->mbus_code) {
+ /* Each entry in formats[] table has unique mbus_code */
+ if (f->index > 0)
+ return -EINVAL;
+
+ i = video_get_pixelformat_by_mbus_code(video, f->mbus_code);
+ } else {
+ i = video_get_unique_pixelformat_by_index(video, f->index);
}
- if (k < f->index)
+ if (i < 0)
return -EINVAL;
f->pixelformat = video->formats[i].pixelformat;
@@ -564,6 +611,36 @@ static int video_enum_fmt(struct file *file, void *fh, struct v4l2_fmtdesc *f)
return 0;
}
+static int video_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct camss_video *video = video_drvdata(file);
+ int i;
+
+ if (fsize->index)
+ return -EINVAL;
+
+ /* Only accept pixel format present in the formats[] table */
+ for (i = 0; i < video->nformats; i++) {
+ if (video->formats[i].pixelformat == fsize->pixel_format)
+ break;
+ }
+
+ if (i == video->nformats)
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ fsize->stepwise.min_width = CAMSS_FRAME_MIN_WIDTH;
+ fsize->stepwise.max_width = CAMSS_FRAME_MAX_WIDTH;
+ fsize->stepwise.min_height = CAMSS_FRAME_MIN_HEIGHT;
+ fsize->stepwise.max_height = (video->line_based) ?
+ CAMSS_FRAME_MAX_HEIGHT_PIX : CAMSS_FRAME_MAX_HEIGHT_RDI;
+ fsize->stepwise.step_width = 1;
+ fsize->stepwise.step_height = 1;
+
+ return 0;
+}
+
static int video_g_fmt(struct file *file, void *fh, struct v4l2_format *f)
{
struct camss_video *video = video_drvdata(file);
@@ -593,7 +670,7 @@ static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f)
1, 65528);
sizeimage[i] = clamp_t(u32, p->sizeimage,
bytesperline[i],
- bytesperline[i] * 4096);
+ bytesperline[i] * CAMSS_FRAME_MAX_HEIGHT_PIX);
}
for (j = 0; j < video->nformats; j++)
@@ -610,8 +687,8 @@ static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f)
memset(pix_mp, 0, sizeof(*pix_mp));
pix_mp->pixelformat = fi->pixelformat;
- pix_mp->width = clamp_t(u32, width, 1, 8191);
- pix_mp->height = clamp_t(u32, height, 1, 8191);
+ pix_mp->width = clamp_t(u32, width, 1, CAMSS_FRAME_MAX_WIDTH);
+ pix_mp->height = clamp_t(u32, height, 1, CAMSS_FRAME_MAX_HEIGHT_RDI);
pix_mp->num_planes = fi->planes;
for (i = 0; i < pix_mp->num_planes; i++) {
bpl = pix_mp->width / fi->hsub[i].numerator *
@@ -637,7 +714,7 @@ static int __video_try_fmt(struct camss_video *video, struct v4l2_format *f)
1, 65528);
p->sizeimage = clamp_t(u32, p->sizeimage,
p->bytesperline,
- p->bytesperline * 4096);
+ p->bytesperline * CAMSS_FRAME_MAX_HEIGHT_PIX);
lines = p->sizeimage / p->bytesperline;
if (p->bytesperline < bytesperline[i])
@@ -704,6 +781,7 @@ static int video_s_input(struct file *file, void *fh, unsigned int input)
static const struct v4l2_ioctl_ops msm_vid_ioctl_ops = {
.vidioc_querycap = video_querycap,
.vidioc_enum_fmt_vid_cap = video_enum_fmt,
+ .vidioc_enum_framesizes = video_enum_framesizes,
.vidioc_g_fmt_vid_cap_mplane = video_g_fmt,
.vidioc_s_fmt_vid_cap_mplane = video_s_fmt,
.vidioc_try_fmt_vid_cap_mplane = video_try_fmt,
@@ -879,7 +957,7 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
if (ret < 0) {
dev_err(v4l2_dev->dev, "Failed to init video entity: %d\n",
ret);
- goto error_media_init;
+ goto error_vb2_init;
}
mutex_init(&video->lock);
@@ -911,8 +989,8 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
}
vdev->fops = &msm_vid_fops;
- vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING |
- V4L2_CAP_READWRITE;
+ vdev->device_caps = V4L2_CAP_VIDEO_CAPTURE_MPLANE | V4L2_CAP_STREAMING
+ | V4L2_CAP_READWRITE | V4L2_CAP_IO_MC;
vdev->ioctl_ops = &msm_vid_ioctl_ops;
vdev->release = msm_video_release;
vdev->v4l2_dev = v4l2_dev;
@@ -936,23 +1014,15 @@ int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
error_video_register:
media_entity_cleanup(&vdev->entity);
mutex_destroy(&video->lock);
-error_media_init:
- vb2_queue_release(&video->vb2_q);
error_vb2_init:
mutex_destroy(&video->q_lock);
return ret;
}
-void msm_video_stop_streaming(struct camss_video *video)
-{
- if (vb2_is_streaming(&video->vb2_q))
- vb2_queue_release(&video->vb2_q);
-}
-
void msm_video_unregister(struct camss_video *video)
{
atomic_inc(&video->camss->ref_count);
- video_unregister_device(&video->vdev);
+ vb2_video_unregister_device(&video->vdev);
atomic_dec(&video->camss->ref_count);
}
diff --git a/drivers/media/platform/qcom/camss/camss-video.h b/drivers/media/platform/qcom/camss/camss-video.h
index aa35e8cc6fd5..bdbae8424140 100644
--- a/drivers/media/platform/qcom/camss/camss-video.h
+++ b/drivers/media/platform/qcom/camss/camss-video.h
@@ -52,8 +52,6 @@ struct camss_video {
unsigned int nformats;
};
-void msm_video_stop_streaming(struct camss_video *video);
-
int msm_video_register(struct camss_video *video, struct v4l2_device *v4l2_dev,
const char *name, int is_pix);
diff --git a/drivers/media/platform/qcom/camss/camss.c b/drivers/media/platform/qcom/camss/camss.c
index 2483641799df..9186881afc98 100644
--- a/drivers/media/platform/qcom/camss/camss.c
+++ b/drivers/media/platform/qcom/camss/camss.c
@@ -974,13 +974,8 @@ void camss_delete(struct camss *camss)
*/
static int camss_remove(struct platform_device *pdev)
{
- unsigned int i;
-
struct camss *camss = platform_get_drvdata(pdev);
- for (i = 0; i < camss->vfe_num; i++)
- msm_vfe_stop_streaming(&camss->vfe[i]);
-
v4l2_async_notifier_unregister(&camss->notifier);
v4l2_async_notifier_cleanup(&camss->notifier);
camss_unregister_entities(camss);
diff --git a/drivers/media/platform/qcom/venus/Makefile b/drivers/media/platform/qcom/venus/Makefile
index 64af0bc1edae..dfc636865709 100644
--- a/drivers/media/platform/qcom/venus/Makefile
+++ b/drivers/media/platform/qcom/venus/Makefile
@@ -3,7 +3,7 @@
venus-core-objs += core.o helpers.o firmware.o \
hfi_venus.o hfi_msgs.o hfi_cmds.o hfi.o \
- hfi_parser.o pm_helpers.o
+ hfi_parser.o pm_helpers.o dbgfs.o
venus-dec-objs += vdec.o vdec_ctrls.o
venus-enc-objs += venc.o venc_ctrls.o
diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c
index 203c6538044f..6103aaf43987 100644
--- a/drivers/media/platform/qcom/venus/core.c
+++ b/drivers/media/platform/qcom/venus/core.c
@@ -6,6 +6,7 @@
#include <linux/init.h>
#include <linux/interconnect.h>
#include <linux/ioctl.h>
+#include <linux/delay.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/of_device.h>
@@ -40,13 +41,7 @@ static void venus_event_notify(struct venus_core *core, u32 event)
mutex_unlock(&core->lock);
disable_irq_nosync(core->irq);
-
- /*
- * Delay recovery to ensure venus has completed any pending cache
- * operations. Without this sleep, we see device reset when firmware is
- * unloaded after a system error.
- */
- schedule_delayed_work(&core->work, msecs_to_jiffies(100));
+ schedule_delayed_work(&core->work, msecs_to_jiffies(10));
}
static const struct hfi_core_ops venus_core_ops = {
@@ -59,23 +54,29 @@ static void venus_sys_error_handler(struct work_struct *work)
container_of(work, struct venus_core, work.work);
int ret = 0;
- dev_warn(core->dev, "system error has occurred, starting recovery!\n");
-
pm_runtime_get_sync(core->dev);
hfi_core_deinit(core, true);
- hfi_destroy(core);
+
+ dev_warn(core->dev, "system error has occurred, starting recovery!\n");
+
mutex_lock(&core->lock);
+
+ while (pm_runtime_active(core->dev_dec) || pm_runtime_active(core->dev_enc))
+ msleep(10);
+
venus_shutdown(core);
pm_runtime_put_sync(core->dev);
- ret |= hfi_create(core, &venus_core_ops);
+ while (core->pmdomains[0] && pm_runtime_active(core->pmdomains[0]))
+ usleep_range(1000, 1500);
+
+ hfi_reinit(core);
pm_runtime_get_sync(core->dev);
ret |= venus_boot(core);
-
ret |= hfi_core_resume(core, true);
enable_irq(core->irq);
@@ -224,15 +225,9 @@ static int venus_probe(struct platform_device *pdev)
ret = dma_set_mask_and_coherent(dev, core->res->dma_mask);
if (ret)
- return ret;
+ goto err_core_put;
- if (!dev->dma_parms) {
- dev->dma_parms = devm_kzalloc(dev, sizeof(*dev->dma_parms),
- GFP_KERNEL);
- if (!dev->dma_parms)
- return -ENOMEM;
- }
- dma_set_max_seg_size(dev, DMA_BIT_MASK(32));
+ dma_set_max_seg_size(dev, UINT_MAX);
INIT_LIST_HEAD(&core->instances);
mutex_init(&core->lock);
@@ -242,11 +237,11 @@ static int venus_probe(struct platform_device *pdev)
IRQF_TRIGGER_HIGH | IRQF_ONESHOT,
"venus", core);
if (ret)
- return ret;
+ goto err_core_put;
ret = hfi_create(core, &venus_core_ops);
if (ret)
- return ret;
+ goto err_core_put;
pm_runtime_enable(dev);
@@ -287,8 +282,12 @@ static int venus_probe(struct platform_device *pdev)
goto err_core_deinit;
ret = pm_runtime_put_sync(dev);
- if (ret)
+ if (ret) {
+ pm_runtime_get_noresume(dev);
goto err_dev_unregister;
+ }
+
+ venus_dbgfs_init(core);
return 0;
@@ -299,9 +298,13 @@ err_core_deinit:
err_venus_shutdown:
venus_shutdown(core);
err_runtime_disable:
+ pm_runtime_put_noidle(dev);
pm_runtime_set_suspended(dev);
pm_runtime_disable(dev);
hfi_destroy(core);
+err_core_put:
+ if (core->pm_ops->core_put)
+ core->pm_ops->core_put(dev);
return ret;
}
@@ -337,6 +340,7 @@ static int venus_remove(struct platform_device *pdev)
v4l2_device_unregister(&core->v4l2_dev);
mutex_destroy(&core->pm_lock);
mutex_destroy(&core->lock);
+ venus_dbgfs_deinit(core);
return ret;
}
@@ -520,6 +524,7 @@ static const struct venus_resources sdm845_res_v2 = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" },
.vcodec_pmdomains_num = 3,
+ .opp_pmdomain = (const char *[]) { "cx", NULL },
.vcodec_num = 2,
.max_load = 3110400, /* 4096x2160@90 */
.hfi_version = HFI_VERSION_4XX,
@@ -527,6 +532,10 @@ static const struct venus_resources sdm845_res_v2 = {
.vmem_size = 0,
.vmem_addr = 0,
.dma_mask = 0xe0000000 - 1,
+ .cp_start = 0,
+ .cp_size = 0x70800000,
+ .cp_nonpixel_start = 0x1000000,
+ .cp_nonpixel_size = 0x24800000,
.fwname = "qcom/venus-5.2/venus.mdt",
};
@@ -565,6 +574,7 @@ static const struct venus_resources sc7180_res = {
.vcodec_clks_num = 2,
.vcodec_pmdomains = { "venus", "vcodec0" },
.vcodec_pmdomains_num = 2,
+ .opp_pmdomain = (const char *[]) { "cx", NULL },
.vcodec_num = 1,
.hfi_version = HFI_VERSION_4XX,
.vmem_id = VIDC_RESOURCE_NONE,
diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h
index 7118612673c9..7b79a33dc9d6 100644
--- a/drivers/media/platform/qcom/venus/core.h
+++ b/drivers/media/platform/qcom/venus/core.h
@@ -12,12 +12,20 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
+#include "dbgfs.h"
#include "hfi.h"
+#define VDBGL "VenusLow : "
+#define VDBGM "VenusMed : "
+#define VDBGH "VenusHigh: "
+#define VDBGFW "VenusFW : "
+
#define VIDC_CLKS_NUM_MAX 4
#define VIDC_VCODEC_CLKS_NUM_MAX 2
#define VIDC_PMDOMAINS_NUM_MAX 3
+extern int venus_fw_debug;
+
struct freq_tbl {
unsigned int load;
unsigned long freq;
@@ -62,12 +70,17 @@ struct venus_resources {
unsigned int vcodec_clks_num;
const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX];
unsigned int vcodec_pmdomains_num;
+ const char **opp_pmdomain;
unsigned int vcodec_num;
enum hfi_version hfi_version;
u32 max_load;
unsigned int vmem_id;
u32 vmem_size;
u32 vmem_addr;
+ u32 cp_start;
+ u32 cp_size;
+ u32 cp_nonpixel_start;
+ u32 cp_nonpixel_size;
const char *fwname;
};
@@ -136,6 +149,7 @@ struct venus_caps {
* @priv: a private filed for HFI operations
* @ops: the core HFI operations
* @work: a delayed work for handling system fatal error
+ * @root: debugfs root directory
*/
struct venus_core {
void __iomem *base;
@@ -145,8 +159,12 @@ struct venus_core {
struct clk *vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX];
struct icc_path *video_path;
struct icc_path *cpucfg_path;
+ struct opp_table *opp_table;
+ bool has_opp_table;
struct device_link *pd_dl_venus;
struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX];
+ struct device_link *opp_dl_venus;
+ struct device *opp_pmdomain;
struct video_device *vdev_dec;
struct video_device *vdev_enc;
struct v4l2_device v4l2_dev;
@@ -185,6 +203,7 @@ struct venus_core {
unsigned int codecs_count;
unsigned int core0_usage_count;
unsigned int core1_usage_count;
+ struct dentry *root;
};
struct vdec_controls {
@@ -201,6 +220,8 @@ struct venc_controls {
u32 bitrate;
u32 bitrate_peak;
u32 rc_enable;
+ u32 const_quality;
+ u32 frame_skip_mode;
u32 h264_i_period;
u32 h264_entropy_mode;
@@ -222,17 +243,8 @@ struct venc_controls {
u32 header_mode;
- struct {
- u32 mpeg4;
- u32 h264;
- u32 vpx;
- u32 hevc;
- } profile;
- struct {
- u32 mpeg4;
- u32 h264;
- u32 hevc;
- } level;
+ u32 profile;
+ u32 level;
};
struct venus_buffer {
diff --git a/drivers/media/platform/qcom/venus/dbgfs.c b/drivers/media/platform/qcom/venus/dbgfs.c
new file mode 100644
index 000000000000..52de47f2ca88
--- /dev/null
+++ b/drivers/media/platform/qcom/venus/dbgfs.c
@@ -0,0 +1,19 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (C) 2020 Linaro Ltd.
+ */
+
+#include <linux/debugfs.h>
+
+#include "core.h"
+
+void venus_dbgfs_init(struct venus_core *core)
+{
+ core->root = debugfs_create_dir("venus", NULL);
+ debugfs_create_x32("fw_level", 0644, core->root, &venus_fw_debug);
+}
+
+void venus_dbgfs_deinit(struct venus_core *core)
+{
+ debugfs_remove_recursive(core->root);
+}
diff --git a/drivers/media/platform/qcom/venus/dbgfs.h b/drivers/media/platform/qcom/venus/dbgfs.h
new file mode 100644
index 000000000000..b7b621a8472f
--- /dev/null
+++ b/drivers/media/platform/qcom/venus/dbgfs.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2020 Linaro Ltd. */
+
+#ifndef __VENUS_DBGFS_H__
+#define __VENUS_DBGFS_H__
+
+struct venus_core;
+
+void venus_dbgfs_init(struct venus_core *core);
+void venus_dbgfs_deinit(struct venus_core *core);
+
+#endif
diff --git a/drivers/media/platform/qcom/venus/firmware.c b/drivers/media/platform/qcom/venus/firmware.c
index 8801a6a7543d..1db64a854b88 100644
--- a/drivers/media/platform/qcom/venus/firmware.c
+++ b/drivers/media/platform/qcom/venus/firmware.c
@@ -181,6 +181,7 @@ static int venus_shutdown_no_tz(struct venus_core *core)
int venus_boot(struct venus_core *core)
{
struct device *dev = core->dev;
+ const struct venus_resources *res = core->res;
phys_addr_t mem_phys;
size_t mem_size;
int ret;
@@ -200,7 +201,23 @@ int venus_boot(struct venus_core *core)
else
ret = venus_boot_no_tz(core, mem_phys, mem_size);
- return ret;
+ if (ret)
+ return ret;
+
+ if (core->use_tz && res->cp_size) {
+ ret = qcom_scm_mem_protect_video_var(res->cp_start,
+ res->cp_size,
+ res->cp_nonpixel_start,
+ res->cp_nonpixel_size);
+ if (ret) {
+ qcom_scm_pas_shutdown(VENUS_PAS_ID);
+ dev_err(dev, "set virtual address ranges fail (%d)\n",
+ ret);
+ return ret;
+ }
+ }
+
+ return 0;
}
int venus_shutdown(struct venus_core *core)
diff --git a/drivers/media/platform/qcom/venus/helpers.c b/drivers/media/platform/qcom/venus/helpers.c
index 0143af7822b2..50439eb1ffea 100644
--- a/drivers/media/platform/qcom/venus/helpers.c
+++ b/drivers/media/platform/qcom/venus/helpers.c
@@ -6,6 +6,7 @@
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/slab.h>
+#include <linux/kernel.h>
#include <media/videobuf2-dma-sg.h>
#include <media/v4l2-mem2mem.h>
#include <asm/div64.h>
@@ -396,7 +397,7 @@ put_ts_metadata(struct venus_inst *inst, struct vb2_v4l2_buffer *vbuf)
}
if (slot == -1) {
- dev_dbg(inst->core->dev, "%s: no free slot\n", __func__);
+ dev_dbg(inst->core->dev, VDBGL "no free slot\n");
return;
}
@@ -582,6 +583,244 @@ int venus_helper_get_bufreq(struct venus_inst *inst, u32 type,
}
EXPORT_SYMBOL_GPL(venus_helper_get_bufreq);
+struct id_mapping {
+ u32 hfi_id;
+ u32 v4l2_id;
+};
+
+static const struct id_mapping mpeg4_profiles[] = {
+ { HFI_MPEG4_PROFILE_SIMPLE, V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE },
+ { HFI_MPEG4_PROFILE_ADVANCEDSIMPLE, V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE },
+};
+
+static const struct id_mapping mpeg4_levels[] = {
+ { HFI_MPEG4_LEVEL_0, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0 },
+ { HFI_MPEG4_LEVEL_0b, V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B },
+ { HFI_MPEG4_LEVEL_1, V4L2_MPEG_VIDEO_MPEG4_LEVEL_1 },
+ { HFI_MPEG4_LEVEL_2, V4L2_MPEG_VIDEO_MPEG4_LEVEL_2 },
+ { HFI_MPEG4_LEVEL_3, V4L2_MPEG_VIDEO_MPEG4_LEVEL_3 },
+ { HFI_MPEG4_LEVEL_4, V4L2_MPEG_VIDEO_MPEG4_LEVEL_4 },
+ { HFI_MPEG4_LEVEL_5, V4L2_MPEG_VIDEO_MPEG4_LEVEL_5 },
+};
+
+static const struct id_mapping mpeg2_profiles[] = {
+ { HFI_MPEG2_PROFILE_SIMPLE, V4L2_MPEG_VIDEO_MPEG2_PROFILE_SIMPLE },
+ { HFI_MPEG2_PROFILE_MAIN, V4L2_MPEG_VIDEO_MPEG2_PROFILE_MAIN },
+ { HFI_MPEG2_PROFILE_SNR, V4L2_MPEG_VIDEO_MPEG2_PROFILE_SNR_SCALABLE },
+ { HFI_MPEG2_PROFILE_SPATIAL, V4L2_MPEG_VIDEO_MPEG2_PROFILE_SPATIALLY_SCALABLE },
+ { HFI_MPEG2_PROFILE_HIGH, V4L2_MPEG_VIDEO_MPEG2_PROFILE_HIGH },
+};
+
+static const struct id_mapping mpeg2_levels[] = {
+ { HFI_MPEG2_LEVEL_LL, V4L2_MPEG_VIDEO_MPEG2_LEVEL_LOW },
+ { HFI_MPEG2_LEVEL_ML, V4L2_MPEG_VIDEO_MPEG2_LEVEL_MAIN },
+ { HFI_MPEG2_LEVEL_H14, V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH_1440 },
+ { HFI_MPEG2_LEVEL_HL, V4L2_MPEG_VIDEO_MPEG2_LEVEL_HIGH },
+};
+
+static const struct id_mapping h264_profiles[] = {
+ { HFI_H264_PROFILE_BASELINE, V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE },
+ { HFI_H264_PROFILE_MAIN, V4L2_MPEG_VIDEO_H264_PROFILE_MAIN },
+ { HFI_H264_PROFILE_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_HIGH },
+ { HFI_H264_PROFILE_STEREO_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_STEREO_HIGH },
+ { HFI_H264_PROFILE_MULTIVIEW_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_MULTIVIEW_HIGH },
+ { HFI_H264_PROFILE_CONSTRAINED_BASE, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE },
+ { HFI_H264_PROFILE_CONSTRAINED_HIGH, V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_HIGH },
+};
+
+static const struct id_mapping h264_levels[] = {
+ { HFI_H264_LEVEL_1, V4L2_MPEG_VIDEO_H264_LEVEL_1_0 },
+ { HFI_H264_LEVEL_1b, V4L2_MPEG_VIDEO_H264_LEVEL_1B },
+ { HFI_H264_LEVEL_11, V4L2_MPEG_VIDEO_H264_LEVEL_1_1 },
+ { HFI_H264_LEVEL_12, V4L2_MPEG_VIDEO_H264_LEVEL_1_2 },
+ { HFI_H264_LEVEL_13, V4L2_MPEG_VIDEO_H264_LEVEL_1_3 },
+ { HFI_H264_LEVEL_2, V4L2_MPEG_VIDEO_H264_LEVEL_2_0 },
+ { HFI_H264_LEVEL_21, V4L2_MPEG_VIDEO_H264_LEVEL_2_1 },
+ { HFI_H264_LEVEL_22, V4L2_MPEG_VIDEO_H264_LEVEL_2_2 },
+ { HFI_H264_LEVEL_3, V4L2_MPEG_VIDEO_H264_LEVEL_3_0 },
+ { HFI_H264_LEVEL_31, V4L2_MPEG_VIDEO_H264_LEVEL_3_1 },
+ { HFI_H264_LEVEL_32, V4L2_MPEG_VIDEO_H264_LEVEL_3_2 },
+ { HFI_H264_LEVEL_4, V4L2_MPEG_VIDEO_H264_LEVEL_4_0 },
+ { HFI_H264_LEVEL_41, V4L2_MPEG_VIDEO_H264_LEVEL_4_1 },
+ { HFI_H264_LEVEL_42, V4L2_MPEG_VIDEO_H264_LEVEL_4_2 },
+ { HFI_H264_LEVEL_5, V4L2_MPEG_VIDEO_H264_LEVEL_5_0 },
+ { HFI_H264_LEVEL_51, V4L2_MPEG_VIDEO_H264_LEVEL_5_1 },
+ { HFI_H264_LEVEL_52, V4L2_MPEG_VIDEO_H264_LEVEL_5_1 },
+};
+
+static const struct id_mapping hevc_profiles[] = {
+ { HFI_HEVC_PROFILE_MAIN, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN },
+ { HFI_HEVC_PROFILE_MAIN_STILL_PIC, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE },
+ { HFI_HEVC_PROFILE_MAIN10, V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10 },
+};
+
+static const struct id_mapping hevc_levels[] = {
+ { HFI_HEVC_LEVEL_1, V4L2_MPEG_VIDEO_HEVC_LEVEL_1 },
+ { HFI_HEVC_LEVEL_2, V4L2_MPEG_VIDEO_HEVC_LEVEL_2 },
+ { HFI_HEVC_LEVEL_21, V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1 },
+ { HFI_HEVC_LEVEL_3, V4L2_MPEG_VIDEO_HEVC_LEVEL_3 },
+ { HFI_HEVC_LEVEL_31, V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1 },
+ { HFI_HEVC_LEVEL_4, V4L2_MPEG_VIDEO_HEVC_LEVEL_4 },
+ { HFI_HEVC_LEVEL_41, V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1 },
+ { HFI_HEVC_LEVEL_5, V4L2_MPEG_VIDEO_HEVC_LEVEL_5 },
+ { HFI_HEVC_LEVEL_51, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1 },
+ { HFI_HEVC_LEVEL_52, V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2 },
+ { HFI_HEVC_LEVEL_6, V4L2_MPEG_VIDEO_HEVC_LEVEL_6 },
+ { HFI_HEVC_LEVEL_61, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1 },
+ { HFI_HEVC_LEVEL_62, V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2 },
+};
+
+static const struct id_mapping vp8_profiles[] = {
+ { HFI_VPX_PROFILE_VERSION_0, V4L2_MPEG_VIDEO_VP8_PROFILE_0 },
+ { HFI_VPX_PROFILE_VERSION_1, V4L2_MPEG_VIDEO_VP8_PROFILE_1 },
+ { HFI_VPX_PROFILE_VERSION_2, V4L2_MPEG_VIDEO_VP8_PROFILE_2 },
+ { HFI_VPX_PROFILE_VERSION_3, V4L2_MPEG_VIDEO_VP8_PROFILE_3 },
+};
+
+static const struct id_mapping vp9_profiles[] = {
+ { HFI_VP9_PROFILE_P0, V4L2_MPEG_VIDEO_VP9_PROFILE_0 },
+ { HFI_VP9_PROFILE_P2_10B, V4L2_MPEG_VIDEO_VP9_PROFILE_2 },
+};
+
+static const struct id_mapping vp9_levels[] = {
+ { HFI_VP9_LEVEL_1, V4L2_MPEG_VIDEO_VP9_LEVEL_1_0 },
+ { HFI_VP9_LEVEL_11, V4L2_MPEG_VIDEO_VP9_LEVEL_1_1 },
+ { HFI_VP9_LEVEL_2, V4L2_MPEG_VIDEO_VP9_LEVEL_2_0},
+ { HFI_VP9_LEVEL_21, V4L2_MPEG_VIDEO_VP9_LEVEL_2_1 },
+ { HFI_VP9_LEVEL_3, V4L2_MPEG_VIDEO_VP9_LEVEL_3_0},
+ { HFI_VP9_LEVEL_31, V4L2_MPEG_VIDEO_VP9_LEVEL_3_1 },
+ { HFI_VP9_LEVEL_4, V4L2_MPEG_VIDEO_VP9_LEVEL_4_0 },
+ { HFI_VP9_LEVEL_41, V4L2_MPEG_VIDEO_VP9_LEVEL_4_1 },
+ { HFI_VP9_LEVEL_5, V4L2_MPEG_VIDEO_VP9_LEVEL_5_0 },
+ { HFI_VP9_LEVEL_51, V4L2_MPEG_VIDEO_VP9_LEVEL_5_1 },
+ { HFI_VP9_LEVEL_6, V4L2_MPEG_VIDEO_VP9_LEVEL_6_0 },
+ { HFI_VP9_LEVEL_61, V4L2_MPEG_VIDEO_VP9_LEVEL_6_1 },
+};
+
+static u32 find_v4l2_id(u32 hfi_id, const struct id_mapping *array, unsigned int array_sz)
+{
+ unsigned int i;
+
+ if (!array || !array_sz)
+ return 0;
+
+ for (i = 0; i < array_sz; i++)
+ if (hfi_id == array[i].hfi_id)
+ return array[i].v4l2_id;
+
+ return 0;
+}
+
+static u32 find_hfi_id(u32 v4l2_id, const struct id_mapping *array, unsigned int array_sz)
+{
+ unsigned int i;
+
+ if (!array || !array_sz)
+ return 0;
+
+ for (i = 0; i < array_sz; i++)
+ if (v4l2_id == array[i].v4l2_id)
+ return array[i].hfi_id;
+
+ return 0;
+}
+
+static void
+v4l2_id_profile_level(u32 hfi_codec, struct hfi_profile_level *pl, u32 *profile, u32 *level)
+{
+ u32 hfi_pf = pl->profile;
+ u32 hfi_lvl = pl->level;
+
+ switch (hfi_codec) {
+ case HFI_VIDEO_CODEC_H264:
+ *profile = find_v4l2_id(hfi_pf, h264_profiles, ARRAY_SIZE(h264_profiles));
+ *level = find_v4l2_id(hfi_lvl, h264_levels, ARRAY_SIZE(h264_levels));
+ break;
+ case HFI_VIDEO_CODEC_MPEG2:
+ *profile = find_v4l2_id(hfi_pf, mpeg2_profiles, ARRAY_SIZE(mpeg2_profiles));
+ *level = find_v4l2_id(hfi_lvl, mpeg2_levels, ARRAY_SIZE(mpeg2_levels));
+ break;
+ case HFI_VIDEO_CODEC_MPEG4:
+ *profile = find_v4l2_id(hfi_pf, mpeg4_profiles, ARRAY_SIZE(mpeg4_profiles));
+ *level = find_v4l2_id(hfi_lvl, mpeg4_levels, ARRAY_SIZE(mpeg4_levels));
+ break;
+ case HFI_VIDEO_CODEC_VP8:
+ *profile = find_v4l2_id(hfi_pf, vp8_profiles, ARRAY_SIZE(vp8_profiles));
+ *level = 0;
+ break;
+ case HFI_VIDEO_CODEC_VP9:
+ *profile = find_v4l2_id(hfi_pf, vp9_profiles, ARRAY_SIZE(vp9_profiles));
+ *level = find_v4l2_id(hfi_lvl, vp9_levels, ARRAY_SIZE(vp9_levels));
+ break;
+ case HFI_VIDEO_CODEC_HEVC:
+ *profile = find_v4l2_id(hfi_pf, hevc_profiles, ARRAY_SIZE(hevc_profiles));
+ *level = find_v4l2_id(hfi_lvl, hevc_levels, ARRAY_SIZE(hevc_levels));
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+hfi_id_profile_level(u32 hfi_codec, u32 v4l2_pf, u32 v4l2_lvl, struct hfi_profile_level *pl)
+{
+ switch (hfi_codec) {
+ case HFI_VIDEO_CODEC_H264:
+ pl->profile = find_hfi_id(v4l2_pf, h264_profiles, ARRAY_SIZE(h264_profiles));
+ pl->level = find_hfi_id(v4l2_lvl, h264_levels, ARRAY_SIZE(h264_levels));
+ break;
+ case HFI_VIDEO_CODEC_MPEG2:
+ pl->profile = find_hfi_id(v4l2_pf, mpeg2_profiles, ARRAY_SIZE(mpeg2_profiles));
+ pl->level = find_hfi_id(v4l2_lvl, mpeg2_levels, ARRAY_SIZE(mpeg2_levels));
+ break;
+ case HFI_VIDEO_CODEC_MPEG4:
+ pl->profile = find_hfi_id(v4l2_pf, mpeg4_profiles, ARRAY_SIZE(mpeg4_profiles));
+ pl->level = find_hfi_id(v4l2_lvl, mpeg4_levels, ARRAY_SIZE(mpeg4_levels));
+ break;
+ case HFI_VIDEO_CODEC_VP8:
+ pl->profile = find_hfi_id(v4l2_pf, vp8_profiles, ARRAY_SIZE(vp8_profiles));
+ pl->level = 0;
+ break;
+ case HFI_VIDEO_CODEC_VP9:
+ pl->profile = find_hfi_id(v4l2_pf, vp9_profiles, ARRAY_SIZE(vp9_profiles));
+ pl->level = find_hfi_id(v4l2_lvl, vp9_levels, ARRAY_SIZE(vp9_levels));
+ break;
+ case HFI_VIDEO_CODEC_HEVC:
+ pl->profile = find_hfi_id(v4l2_pf, hevc_profiles, ARRAY_SIZE(hevc_profiles));
+ pl->level = find_hfi_id(v4l2_lvl, hevc_levels, ARRAY_SIZE(hevc_levels));
+ break;
+ default:
+ break;
+ }
+}
+
+int venus_helper_get_profile_level(struct venus_inst *inst, u32 *profile, u32 *level)
+{
+ const u32 ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
+ union hfi_get_property hprop;
+ int ret;
+
+ ret = hfi_session_get_property(inst, ptype, &hprop);
+ if (ret)
+ return ret;
+
+ v4l2_id_profile_level(inst->hfi_codec, &hprop.profile_level, profile, level);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(venus_helper_get_profile_level);
+
+int venus_helper_set_profile_level(struct venus_inst *inst, u32 profile, u32 level)
+{
+ const u32 ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
+ struct hfi_profile_level pl;
+
+ hfi_id_profile_level(inst->hfi_codec, profile, level, &pl);
+
+ return hfi_session_set_property(inst, ptype, &pl);
+}
+EXPORT_SYMBOL_GPL(venus_helper_set_profile_level);
+
static u32 get_framesize_raw_nv12(u32 width, u32 height)
{
u32 y_stride, uv_stride, y_plane;
diff --git a/drivers/media/platform/qcom/venus/helpers.h b/drivers/media/platform/qcom/venus/helpers.h
index 8fbbda12a4fe..a4a0562bc83f 100644
--- a/drivers/media/platform/qcom/venus/helpers.h
+++ b/drivers/media/platform/qcom/venus/helpers.h
@@ -61,4 +61,6 @@ int venus_helper_process_initial_cap_bufs(struct venus_inst *inst);
int venus_helper_process_initial_out_bufs(struct venus_inst *inst);
void venus_helper_get_ts_metadata(struct venus_inst *inst, u64 timestamp_us,
struct vb2_v4l2_buffer *vbuf);
+int venus_helper_get_profile_level(struct venus_inst *inst, u32 *profile, u32 *level);
+int venus_helper_set_profile_level(struct venus_inst *inst, u32 profile, u32 level);
#endif
diff --git a/drivers/media/platform/qcom/venus/hfi.c b/drivers/media/platform/qcom/venus/hfi.c
index a211eb93e0f9..a59022adb14c 100644
--- a/drivers/media/platform/qcom/venus/hfi.c
+++ b/drivers/media/platform/qcom/venus/hfi.c
@@ -517,3 +517,8 @@ void hfi_destroy(struct venus_core *core)
{
venus_hfi_destroy(core);
}
+
+void hfi_reinit(struct venus_core *core)
+{
+ venus_hfi_queues_reinit(core);
+}
diff --git a/drivers/media/platform/qcom/venus/hfi.h b/drivers/media/platform/qcom/venus/hfi.h
index 62c315291484..f25d412d6553 100644
--- a/drivers/media/platform/qcom/venus/hfi.h
+++ b/drivers/media/platform/qcom/venus/hfi.h
@@ -145,6 +145,7 @@ struct hfi_ops {
int hfi_create(struct venus_core *core, const struct hfi_core_ops *ops);
void hfi_destroy(struct venus_core *core);
+void hfi_reinit(struct venus_core *core);
int hfi_core_init(struct venus_core *core);
int hfi_core_deinit(struct venus_core *core, bool blocking);
diff --git a/drivers/media/platform/qcom/venus/hfi_cmds.c b/drivers/media/platform/qcom/venus/hfi_cmds.c
index c67e412f8201..7022368c1e63 100644
--- a/drivers/media/platform/qcom/venus/hfi_cmds.c
+++ b/drivers/media/platform/qcom/venus/hfi_cmds.c
@@ -640,6 +640,7 @@ static int pkt_session_set_property_1x(struct hfi_session_set_property_pkt *pkt,
case HFI_RATE_CONTROL_CBR_VFR:
case HFI_RATE_CONTROL_VBR_CFR:
case HFI_RATE_CONTROL_VBR_VFR:
+ case HFI_RATE_CONTROL_CQ:
break;
default:
ret = -EINVAL;
@@ -1218,6 +1219,37 @@ pkt_session_set_property_4xx(struct hfi_session_set_property_pkt *pkt,
return 0;
}
+static int
+pkt_session_set_property_6xx(struct hfi_session_set_property_pkt *pkt,
+ void *cookie, u32 ptype, void *pdata)
+{
+ void *prop_data;
+
+ if (!pkt || !cookie || !pdata)
+ return -EINVAL;
+
+ prop_data = &pkt->data[1];
+
+ pkt->shdr.hdr.size = sizeof(*pkt);
+ pkt->shdr.hdr.pkt_type = HFI_CMD_SESSION_SET_PROPERTY;
+ pkt->shdr.session_id = hash32_ptr(cookie);
+ pkt->num_properties = 1;
+ pkt->data[0] = ptype;
+
+ switch (ptype) {
+ case HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY: {
+ struct hfi_heic_frame_quality *in = pdata, *cq = prop_data;
+
+ cq->frame_quality = in->frame_quality;
+ pkt->shdr.hdr.size += sizeof(u32) + sizeof(*cq);
+ break;
+ } default:
+ return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata);
+ }
+
+ return 0;
+}
+
int pkt_session_get_property(struct hfi_session_get_property_pkt *pkt,
void *cookie, u32 ptype)
{
@@ -1236,7 +1268,10 @@ int pkt_session_set_property(struct hfi_session_set_property_pkt *pkt,
if (hfi_ver == HFI_VERSION_3XX)
return pkt_session_set_property_3xx(pkt, cookie, ptype, pdata);
- return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata);
+ if (hfi_ver == HFI_VERSION_4XX)
+ return pkt_session_set_property_4xx(pkt, cookie, ptype, pdata);
+
+ return pkt_session_set_property_6xx(pkt, cookie, ptype, pdata);
}
void pkt_set_version(enum hfi_version version)
diff --git a/drivers/media/platform/qcom/venus/hfi_helper.h b/drivers/media/platform/qcom/venus/hfi_helper.h
index f6613df1d16b..60ee2479f7a6 100644
--- a/drivers/media/platform/qcom/venus/hfi_helper.h
+++ b/drivers/media/platform/qcom/venus/hfi_helper.h
@@ -231,6 +231,7 @@
#define HFI_RATE_CONTROL_VBR_CFR 0x1000003
#define HFI_RATE_CONTROL_CBR_VFR 0x1000004
#define HFI_RATE_CONTROL_CBR_CFR 0x1000005
+#define HFI_RATE_CONTROL_CQ 0x1000008
#define HFI_VIDEO_CODEC_H264 0x00000002
#define HFI_VIDEO_CODEC_H263 0x00000004
@@ -363,6 +364,24 @@
#define HFI_HEVC_TIER_MAIN 0x1
#define HFI_HEVC_TIER_HIGH0 0x2
+/* VP9 Profile 0, 8-bit */
+#define HFI_VP9_PROFILE_P0 0x00000001
+/* VP9 Profile 2, 10-bit */
+#define HFI_VP9_PROFILE_P2_10B 0x00000004
+
+#define HFI_VP9_LEVEL_1 0x00000001
+#define HFI_VP9_LEVEL_11 0x00000002
+#define HFI_VP9_LEVEL_2 0x00000004
+#define HFI_VP9_LEVEL_21 0x00000008
+#define HFI_VP9_LEVEL_3 0x00000010
+#define HFI_VP9_LEVEL_31 0x00000020
+#define HFI_VP9_LEVEL_4 0x00000040
+#define HFI_VP9_LEVEL_41 0x00000080
+#define HFI_VP9_LEVEL_5 0x00000100
+#define HFI_VP9_LEVEL_51 0x00000200
+#define HFI_VP9_LEVEL_6 0x00000400
+#define HFI_VP9_LEVEL_61 0x00000800
+
#define HFI_BUFFER_INPUT 0x1
#define HFI_BUFFER_OUTPUT 0x2
#define HFI_BUFFER_OUTPUT2 0x3
@@ -504,6 +523,7 @@
#define HFI_PROPERTY_CONFIG_VENC_HIER_P_ENH_LAYER 0x200600b
#define HFI_PROPERTY_CONFIG_VENC_LTRPERIOD 0x200600c
#define HFI_PROPERTY_CONFIG_VENC_PERF_MODE 0x200600e
+#define HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY 0x2006014
/*
* HFI_PROPERTY_PARAM_VPE_COMMON_START
@@ -520,7 +540,8 @@
enum hfi_version {
HFI_VERSION_1XX,
HFI_VERSION_3XX,
- HFI_VERSION_4XX
+ HFI_VERSION_4XX,
+ HFI_VERSION_6XX,
};
struct hfi_buffer_info {
@@ -725,6 +746,11 @@ struct hfi_quality_vs_speed {
u32 quality_vs_speed;
};
+struct hfi_heic_frame_quality {
+ u32 frame_quality;
+ u32 reserved[3];
+};
+
struct hfi_quantization {
u32 qp_i;
u32 qp_p;
diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c
index 279a9d6fe737..06a1908ca225 100644
--- a/drivers/media/platform/qcom/venus/hfi_msgs.c
+++ b/drivers/media/platform/qcom/venus/hfi_msgs.c
@@ -138,7 +138,7 @@ static void event_sys_error(struct venus_core *core, u32 event,
struct hfi_msg_event_notify_pkt *pkt)
{
if (pkt)
- dev_dbg(core->dev,
+ dev_dbg(core->dev, VDBGH
"sys error (session id:%x, data1:%x, data2:%x)\n",
pkt->shdr.session_id, pkt->event_data1,
pkt->event_data2);
@@ -152,7 +152,7 @@ event_session_error(struct venus_core *core, struct venus_inst *inst,
{
struct device *dev = core->dev;
- dev_dbg(dev, "session error: event id:%x, session id:%x\n",
+ dev_dbg(dev, VDBGH "session error: event id:%x, session id:%x\n",
pkt->event_data1, pkt->shdr.session_id);
if (!inst)
@@ -247,7 +247,7 @@ sys_get_prop_image_version(struct device *dev,
/* bad packet */
return;
- dev_dbg(dev, "F/W version: %s\n", (u8 *)&pkt->data[1]);
+ dev_dbg(dev, VDBGL "F/W version: %s\n", (u8 *)&pkt->data[1]);
}
static void hfi_sys_property_info(struct venus_core *core,
@@ -257,7 +257,7 @@ static void hfi_sys_property_info(struct venus_core *core,
struct device *dev = core->dev;
if (!pkt->num_properties) {
- dev_dbg(dev, "%s: no properties\n", __func__);
+ dev_dbg(dev, VDBGL "no properties\n");
return;
}
@@ -266,7 +266,7 @@ static void hfi_sys_property_info(struct venus_core *core,
sys_get_prop_image_version(dev, pkt);
break;
default:
- dev_dbg(dev, "%s: unknown property data\n", __func__);
+ dev_dbg(dev, VDBGL "unknown property data\n");
break;
}
}
@@ -297,7 +297,7 @@ static void hfi_sys_ping_done(struct venus_core *core, struct venus_inst *inst,
static void hfi_sys_idle_done(struct venus_core *core, struct venus_inst *inst,
void *packet)
{
- dev_dbg(core->dev, "sys idle\n");
+ dev_dbg(core->dev, VDBGL "sys idle\n");
}
static void hfi_sys_pc_prepare_done(struct venus_core *core,
@@ -305,7 +305,8 @@ static void hfi_sys_pc_prepare_done(struct venus_core *core,
{
struct hfi_msg_sys_pc_prep_done_pkt *pkt = packet;
- dev_dbg(core->dev, "pc prepare done (error %x)\n", pkt->error_type);
+ dev_dbg(core->dev, VDBGL "pc prepare done (error %x)\n",
+ pkt->error_type);
}
static unsigned int
@@ -387,8 +388,7 @@ static void hfi_session_prop_info(struct venus_core *core,
case HFI_PROPERTY_CONFIG_VDEC_ENTROPY:
break;
default:
- dev_dbg(dev, "%s: unknown property id:%x\n", __func__,
- pkt->data[0]);
+ dev_dbg(dev, VDBGM "unknown property id:%x\n", pkt->data[0]);
return;
}
diff --git a/drivers/media/platform/qcom/venus/hfi_parser.c b/drivers/media/platform/qcom/venus/hfi_parser.c
index 7f515a4b9bd1..363ee2a65453 100644
--- a/drivers/media/platform/qcom/venus/hfi_parser.c
+++ b/drivers/media/platform/qcom/venus/hfi_parser.c
@@ -239,6 +239,9 @@ u32 hfi_parser(struct venus_core *core, struct venus_inst *inst, void *buf,
parser_init(inst, &codecs, &domain);
+ core->codecs_count = 0;
+ memset(core->caps, 0, sizeof(core->caps));
+
while (words_count) {
data = word + 1;
diff --git a/drivers/media/platform/qcom/venus/hfi_venus.c b/drivers/media/platform/qcom/venus/hfi_venus.c
index 0d8855014ab3..4be4a75ddcb6 100644
--- a/drivers/media/platform/qcom/venus/hfi_venus.c
+++ b/drivers/media/platform/qcom/venus/hfi_venus.c
@@ -130,7 +130,7 @@ struct venus_hfi_device {
};
static bool venus_pkt_debug;
-static int venus_fw_debug = HFI_DEBUG_MSG_ERROR | HFI_DEBUG_MSG_FATAL;
+int venus_fw_debug = HFI_DEBUG_MSG_ERROR | HFI_DEBUG_MSG_FATAL;
static bool venus_sys_idle_indicator;
static bool venus_fw_low_power_mode = true;
static int venus_hw_rsp_timeout = 1000;
@@ -477,7 +477,7 @@ static u32 venus_hwversion(struct venus_hfi_device *hdev)
minor = minor >> WRAPPER_HW_VERSION_MINOR_VERSION_SHIFT;
step = ver & WRAPPER_HW_VERSION_STEP_VERSION_MASK;
- dev_dbg(dev, "venus hw version %x.%x.%x\n", major, minor, step);
+ dev_dbg(dev, VDBGL "venus hw version %x.%x.%x\n", major, minor, step);
return major;
}
@@ -906,7 +906,7 @@ static void venus_flush_debug_queue(struct venus_hfi_device *hdev)
if (pkt->hdr.pkt_type != HFI_MSG_SYS_COV) {
struct hfi_msg_sys_debug_pkt *pkt = packet;
- dev_dbg(dev, "%s", pkt->msg_data);
+ dev_dbg(dev, VDBGFW "%s", pkt->msg_data);
}
}
}
@@ -986,13 +986,6 @@ static void venus_process_msg_sys_error(struct venus_hfi_device *hdev,
venus_set_state(hdev, VENUS_STATE_DEINIT);
- /*
- * Once SYS_ERROR received from HW, it is safe to halt the AXI.
- * With SYS_ERROR, Venus FW may have crashed and HW might be
- * active and causing unnecessary transactions. Hence it is
- * safe to stop all AXI transactions from venus subsystem.
- */
- venus_halt_axi(hdev);
venus_sfr_print(hdev);
}
@@ -1009,10 +1002,6 @@ static irqreturn_t venus_isr_thread(struct venus_core *core)
res = hdev->core->res;
pkt = hdev->pkt_buf;
- if (hdev->irq_status & WRAPPER_INTR_STATUS_A2HWD_MASK) {
- venus_sfr_print(hdev);
- hfi_process_watchdog_timeout(core);
- }
while (!venus_iface_msgq_read(hdev, pkt)) {
msg_ret = hfi_process_msg_packet(core, pkt);
@@ -1133,6 +1122,10 @@ static int venus_session_init(struct venus_inst *inst, u32 session_type,
struct hfi_session_init_pkt pkt;
int ret;
+ ret = venus_sys_set_debug(hdev, venus_fw_debug);
+ if (ret)
+ goto err;
+
ret = pkt_session_init(&pkt, inst, session_type, codec);
if (ret)
goto err;
@@ -1614,3 +1607,54 @@ err_kfree:
core->ops = NULL;
return ret;
}
+
+void venus_hfi_queues_reinit(struct venus_core *core)
+{
+ struct venus_hfi_device *hdev = to_hfi_priv(core);
+ struct hfi_queue_table_header *tbl_hdr;
+ struct iface_queue *queue;
+ struct hfi_sfr *sfr;
+ unsigned int i;
+
+ mutex_lock(&hdev->lock);
+
+ for (i = 0; i < IFACEQ_NUM; i++) {
+ queue = &hdev->queues[i];
+ queue->qhdr =
+ IFACEQ_GET_QHDR_START_ADDR(hdev->ifaceq_table.kva, i);
+
+ venus_set_qhdr_defaults(queue->qhdr);
+
+ queue->qhdr->start_addr = queue->qmem.da;
+
+ if (i == IFACEQ_CMD_IDX)
+ queue->qhdr->type |= HFI_HOST_TO_CTRL_CMD_Q;
+ else if (i == IFACEQ_MSG_IDX)
+ queue->qhdr->type |= HFI_CTRL_TO_HOST_MSG_Q;
+ else if (i == IFACEQ_DBG_IDX)
+ queue->qhdr->type |= HFI_CTRL_TO_HOST_DBG_Q;
+ }
+
+ tbl_hdr = hdev->ifaceq_table.kva;
+ tbl_hdr->version = 0;
+ tbl_hdr->size = IFACEQ_TABLE_SIZE;
+ tbl_hdr->qhdr0_offset = sizeof(struct hfi_queue_table_header);
+ tbl_hdr->qhdr_size = sizeof(struct hfi_queue_header);
+ tbl_hdr->num_q = IFACEQ_NUM;
+ tbl_hdr->num_active_q = IFACEQ_NUM;
+
+ /*
+ * Set receive request to zero on debug queue as there is no
+ * need of interrupt from video hardware for debug messages
+ */
+ queue = &hdev->queues[IFACEQ_DBG_IDX];
+ queue->qhdr->rx_req = 0;
+
+ sfr = hdev->sfr.kva;
+ sfr->buf_size = ALIGNED_SFR_SIZE;
+
+ /* ensure table and queue header structs are settled in memory */
+ wmb();
+
+ mutex_unlock(&hdev->lock);
+}
diff --git a/drivers/media/platform/qcom/venus/hfi_venus.h b/drivers/media/platform/qcom/venus/hfi_venus.h
index 57154832090e..1b656ef2bf07 100644
--- a/drivers/media/platform/qcom/venus/hfi_venus.h
+++ b/drivers/media/platform/qcom/venus/hfi_venus.h
@@ -10,5 +10,6 @@ struct venus_core;
void venus_hfi_destroy(struct venus_core *core);
int venus_hfi_create(struct venus_core *core);
+void venus_hfi_queues_reinit(struct venus_core *core);
#endif
diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c
index 531e7a41658f..57877eacecf0 100644
--- a/drivers/media/platform/qcom/venus/pm_helpers.c
+++ b/drivers/media/platform/qcom/venus/pm_helpers.c
@@ -9,6 +9,7 @@
#include <linux/iopoll.h>
#include <linux/kernel.h>
#include <linux/pm_domain.h>
+#include <linux/pm_opp.h>
#include <linux/pm_runtime.h>
#include <linux/types.h>
#include <media/v4l2-mem2mem.h>
@@ -66,10 +67,9 @@ static void core_clks_disable(struct venus_core *core)
static int core_clks_set_rate(struct venus_core *core, unsigned long freq)
{
- struct clk *clk = core->clks[0];
int ret;
- ret = clk_set_rate(clk, freq);
+ ret = dev_pm_opp_set_rate(core->dev, freq);
if (ret)
return ret;
@@ -212,7 +212,7 @@ static int load_scale_bw(struct venus_core *core)
}
mutex_unlock(&core->lock);
- dev_dbg(core->dev, "total: avg_bw: %u, peak_bw: %u\n",
+ dev_dbg(core->dev, VDBGL "total: avg_bw: %u, peak_bw: %u\n",
total_avg, total_peak);
return icc_set_bw(core->video_path, total_avg, total_peak);
@@ -744,13 +744,16 @@ static int venc_power_v4(struct device *dev, int on)
static int vcodec_domains_get(struct device *dev)
{
+ int ret;
+ struct opp_table *opp_table;
+ struct device **opp_virt_dev;
struct venus_core *core = dev_get_drvdata(dev);
const struct venus_resources *res = core->res;
struct device *pd;
unsigned int i;
if (!res->vcodec_pmdomains_num)
- return -ENODEV;
+ goto skip_pmdomains;
for (i = 0; i < res->vcodec_pmdomains_num; i++) {
pd = dev_pm_domain_attach_by_name(dev,
@@ -767,7 +770,41 @@ static int vcodec_domains_get(struct device *dev)
if (!core->pd_dl_venus)
return -ENODEV;
+skip_pmdomains:
+ if (!core->has_opp_table)
+ return 0;
+
+ /* Attach the power domain for setting performance state */
+ opp_table = dev_pm_opp_attach_genpd(dev, res->opp_pmdomain, &opp_virt_dev);
+ if (IS_ERR(opp_table)) {
+ ret = PTR_ERR(opp_table);
+ 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_dl_add_err;
+ }
+
return 0;
+
+opp_dl_add_err:
+ dev_pm_domain_detach(core->opp_pmdomain, true);
+opp_attach_err:
+ if (core->pd_dl_venus) {
+ device_link_del(core->pd_dl_venus);
+ for (i = 0; i < res->vcodec_pmdomains_num; i++) {
+ if (IS_ERR_OR_NULL(core->pmdomains[i]))
+ continue;
+ dev_pm_domain_detach(core->pmdomains[i], true);
+ }
+ }
+ return ret;
}
static void vcodec_domains_put(struct device *dev)
@@ -777,7 +814,7 @@ static void vcodec_domains_put(struct device *dev)
unsigned int i;
if (!res->vcodec_pmdomains_num)
- return;
+ goto skip_pmdomains;
if (core->pd_dl_venus)
device_link_del(core->pd_dl_venus);
@@ -787,6 +824,15 @@ static void vcodec_domains_put(struct device *dev)
continue;
dev_pm_domain_detach(core->pmdomains[i], true);
}
+
+skip_pmdomains:
+ if (!core->has_opp_table)
+ return;
+
+ if (core->opp_dl_venus)
+ device_link_del(core->opp_dl_venus);
+
+ dev_pm_domain_detach(core->opp_pmdomain, true);
}
static int core_get_v4(struct device *dev)
@@ -815,19 +861,46 @@ static int core_get_v4(struct device *dev)
if (legacy_binding)
return 0;
+ core->opp_table = dev_pm_opp_set_clkname(dev, "core");
+ if (IS_ERR(core->opp_table))
+ return PTR_ERR(core->opp_table);
+
+ if (core->res->opp_pmdomain) {
+ ret = dev_pm_opp_of_add_table(dev);
+ if (!ret) {
+ core->has_opp_table = true;
+ } else if (ret != -ENODEV) {
+ dev_err(dev, "invalid OPP table in device tree\n");
+ dev_pm_opp_put_clkname(core->opp_table);
+ return ret;
+ }
+ }
+
ret = vcodec_domains_get(dev);
- if (ret)
+ if (ret) {
+ if (core->has_opp_table)
+ dev_pm_opp_of_remove_table(dev);
+ dev_pm_opp_put_clkname(core->opp_table);
return ret;
+ }
return 0;
}
static void core_put_v4(struct device *dev)
{
+ struct venus_core *core = dev_get_drvdata(dev);
+
if (legacy_binding)
return;
vcodec_domains_put(dev);
+
+ if (core->has_opp_table)
+ dev_pm_opp_of_remove_table(dev);
+ if (core->opp_table)
+ dev_pm_opp_put_clkname(core->opp_table);
+
}
static int core_power_v4(struct device *dev, int on)
@@ -835,10 +908,15 @@ static int core_power_v4(struct device *dev, int on)
struct venus_core *core = dev_get_drvdata(dev);
int ret = 0;
- if (on == POWER_ON)
+ if (on == POWER_ON) {
ret = core_clks_enable(core);
- else
+ } else {
+ /* Drop the performance state vote */
+ if (core->opp_pmdomain)
+ dev_pm_opp_set_rate(dev, 0);
+
core_clks_disable(core);
+ }
return ret;
}
diff --git a/drivers/media/platform/qcom/venus/vdec.c b/drivers/media/platform/qcom/venus/vdec.c
index 7c4c483d5438..ea13170a6a2c 100644
--- a/drivers/media/platform/qcom/venus/vdec.c
+++ b/drivers/media/platform/qcom/venus/vdec.c
@@ -225,7 +225,7 @@ static int vdec_check_src_change(struct venus_inst *inst)
if (!(inst->codec_state == VENUS_DEC_STATE_CAPTURE_SETUP) ||
!inst->reconfig)
- dev_dbg(inst->core->dev, "%s: wrong state\n", __func__);
+ dev_dbg(inst->core->dev, VDBGH "wrong state\n");
done:
return 0;
@@ -1072,7 +1072,7 @@ static int vdec_stop_capture(struct venus_inst *inst)
switch (inst->codec_state) {
case VENUS_DEC_STATE_DECODING:
ret = hfi_session_flush(inst, HFI_FLUSH_ALL, true);
- /* fallthrough */
+ fallthrough;
case VENUS_DEC_STATE_DRAIN:
vdec_cancel_dst_buffers(inst);
inst->codec_state = VENUS_DEC_STATE_STOPPED;
@@ -1088,8 +1088,6 @@ static int vdec_stop_capture(struct venus_inst *inst)
break;
}
- INIT_LIST_HEAD(&inst->registeredbufs);
-
return ret;
}
@@ -1189,6 +1187,14 @@ static int vdec_buf_init(struct vb2_buffer *vb)
static void vdec_buf_cleanup(struct vb2_buffer *vb)
{
struct venus_inst *inst = vb2_get_drv_priv(vb->vb2_queue);
+ struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
+ struct venus_buffer *buf = to_venus_buffer(vbuf);
+
+ mutex_lock(&inst->lock);
+ if (vb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ if (!list_empty(&inst->registeredbufs))
+ list_del_init(&buf->reg_list);
+ mutex_unlock(&inst->lock);
inst->buf_count--;
if (!inst->buf_count)
@@ -1310,7 +1316,7 @@ static void vdec_event_change(struct venus_inst *inst,
if (inst->bit_depth != ev_data->bit_depth)
inst->bit_depth = ev_data->bit_depth;
- dev_dbg(dev, "event %s sufficient resources (%ux%u)\n",
+ dev_dbg(dev, VDBGM "event %s sufficient resources (%ux%u)\n",
sufficient ? "" : "not", ev_data->width, ev_data->height);
if (sufficient) {
@@ -1344,7 +1350,7 @@ static void vdec_event_change(struct venus_inst *inst,
ret = hfi_session_flush(inst, HFI_FLUSH_OUTPUT, false);
if (ret)
- dev_dbg(dev, "flush output error %d\n", ret);
+ dev_dbg(dev, VDBGH "flush output error %d\n", ret);
}
inst->reconfig = true;
@@ -1453,13 +1459,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->allow_zero_bytesused = 1;
dst_vq->min_buffers_needed = 0;
dst_vq->dev = inst->core->dev;
- ret = vb2_queue_init(dst_vq);
- if (ret) {
- vb2_queue_release(src_vq);
- return ret;
- }
-
- return 0;
+ return vb2_queue_init(dst_vq);
}
static int vdec_open(struct file *file)
diff --git a/drivers/media/platform/qcom/venus/vdec_ctrls.c b/drivers/media/platform/qcom/venus/vdec_ctrls.c
index 3a963cbd342a..974110b75b93 100644
--- a/drivers/media/platform/qcom/venus/vdec_ctrls.c
+++ b/drivers/media/platform/qcom/venus/vdec_ctrls.c
@@ -22,10 +22,12 @@ static int vdec_op_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
ctr->profile = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
+ case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
ctr->level = ctrl->val;
break;
default:
@@ -40,25 +42,26 @@ static int vdec_op_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
struct venus_inst *inst = ctrl_to_inst(ctrl);
struct vdec_controls *ctr = &inst->controls.dec;
struct hfi_buffer_requirements bufreq;
- union hfi_get_property hprop;
enum hfi_version ver = inst->core->res->hfi_version;
- u32 ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
+ u32 profile, level;
int ret;
switch (ctrl->id) {
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
- ret = hfi_session_get_property(inst, ptype, &hprop);
+ case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
+ ret = venus_helper_get_profile_level(inst, &profile, &level);
if (!ret)
- ctr->profile = hprop.profile_level.profile;
+ ctr->profile = profile;
ctrl->val = ctr->profile;
break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
- ret = hfi_session_get_property(inst, ptype, &hprop);
+ case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
+ ret = venus_helper_get_profile_level(inst, &profile, &level);
if (!ret)
- ctr->level = hprop.profile_level.level;
+ ctr->level = level;
ctrl->val = ctr->level;
break;
case V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER:
@@ -86,7 +89,7 @@ int vdec_ctrl_init(struct venus_inst *inst)
struct v4l2_ctrl *ctrl;
int ret;
- ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 7);
+ ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 9);
if (ret)
return ret;
@@ -133,6 +136,20 @@ int vdec_ctrl_init(struct venus_inst *inst)
if (ctrl)
ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+ ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_VP9_PROFILE,
+ V4L2_MPEG_VIDEO_VP9_PROFILE_3,
+ 0, V4L2_MPEG_VIDEO_VP9_PROFILE_0);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
+ ctrl = v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &vdec_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_VP9_LEVEL,
+ V4L2_MPEG_VIDEO_VP9_LEVEL_6_2,
+ 0, V4L2_MPEG_VIDEO_VP9_LEVEL_1_0);
+ if (ctrl)
+ ctrl->flags |= V4L2_CTRL_FLAG_VOLATILE;
+
v4l2_ctrl_new_std(&inst->ctrl_handler, &vdec_ctrl_ops,
V4L2_CID_MPEG_VIDEO_DECODER_MPEG4_DEBLOCK_FILTER, 0, 1, 1, 0);
diff --git a/drivers/media/platform/qcom/venus/venc.c b/drivers/media/platform/qcom/venus/venc.c
index 513bbc07f7bc..f8b1484e7dcd 100644
--- a/drivers/media/platform/qcom/venus/venc.c
+++ b/drivers/media/platform/qcom/venus/venc.c
@@ -113,80 +113,6 @@ find_format_by_index(struct venus_inst *inst, unsigned int index, u32 type)
static int venc_v4l2_to_hfi(int id, int value)
{
switch (id) {
- case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
- switch (value) {
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0:
- default:
- return HFI_MPEG4_LEVEL_0;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_0B:
- return HFI_MPEG4_LEVEL_0b;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_1:
- return HFI_MPEG4_LEVEL_1;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_2:
- return HFI_MPEG4_LEVEL_2;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_3:
- return HFI_MPEG4_LEVEL_3;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_4:
- return HFI_MPEG4_LEVEL_4;
- case V4L2_MPEG_VIDEO_MPEG4_LEVEL_5:
- return HFI_MPEG4_LEVEL_5;
- }
- case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
- switch (value) {
- case V4L2_MPEG_VIDEO_MPEG4_PROFILE_SIMPLE:
- default:
- return HFI_MPEG4_PROFILE_SIMPLE;
- case V4L2_MPEG_VIDEO_MPEG4_PROFILE_ADVANCED_SIMPLE:
- return HFI_MPEG4_PROFILE_ADVANCEDSIMPLE;
- }
- case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- switch (value) {
- case V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE:
- return HFI_H264_PROFILE_BASELINE;
- case V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE:
- return HFI_H264_PROFILE_CONSTRAINED_BASE;
- case V4L2_MPEG_VIDEO_H264_PROFILE_MAIN:
- return HFI_H264_PROFILE_MAIN;
- case V4L2_MPEG_VIDEO_H264_PROFILE_HIGH:
- default:
- return HFI_H264_PROFILE_HIGH;
- }
- case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
- switch (value) {
- case V4L2_MPEG_VIDEO_H264_LEVEL_1_0:
- return HFI_H264_LEVEL_1;
- case V4L2_MPEG_VIDEO_H264_LEVEL_1B:
- return HFI_H264_LEVEL_1b;
- case V4L2_MPEG_VIDEO_H264_LEVEL_1_1:
- return HFI_H264_LEVEL_11;
- case V4L2_MPEG_VIDEO_H264_LEVEL_1_2:
- return HFI_H264_LEVEL_12;
- case V4L2_MPEG_VIDEO_H264_LEVEL_1_3:
- return HFI_H264_LEVEL_13;
- case V4L2_MPEG_VIDEO_H264_LEVEL_2_0:
- return HFI_H264_LEVEL_2;
- case V4L2_MPEG_VIDEO_H264_LEVEL_2_1:
- return HFI_H264_LEVEL_21;
- case V4L2_MPEG_VIDEO_H264_LEVEL_2_2:
- return HFI_H264_LEVEL_22;
- case V4L2_MPEG_VIDEO_H264_LEVEL_3_0:
- return HFI_H264_LEVEL_3;
- case V4L2_MPEG_VIDEO_H264_LEVEL_3_1:
- return HFI_H264_LEVEL_31;
- case V4L2_MPEG_VIDEO_H264_LEVEL_3_2:
- return HFI_H264_LEVEL_32;
- case V4L2_MPEG_VIDEO_H264_LEVEL_4_0:
- return HFI_H264_LEVEL_4;
- case V4L2_MPEG_VIDEO_H264_LEVEL_4_1:
- return HFI_H264_LEVEL_41;
- case V4L2_MPEG_VIDEO_H264_LEVEL_4_2:
- return HFI_H264_LEVEL_42;
- case V4L2_MPEG_VIDEO_H264_LEVEL_5_0:
- default:
- return HFI_H264_LEVEL_5;
- case V4L2_MPEG_VIDEO_H264_LEVEL_5_1:
- return HFI_H264_LEVEL_51;
- }
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
switch (value) {
case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CAVLC:
@@ -195,18 +121,6 @@ static int venc_v4l2_to_hfi(int id, int value)
case V4L2_MPEG_VIDEO_H264_ENTROPY_MODE_CABAC:
return HFI_H264_ENTROPY_CABAC;
}
- case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
- switch (value) {
- case 0:
- default:
- return HFI_VPX_PROFILE_VERSION_0;
- case 1:
- return HFI_VPX_PROFILE_VERSION_1;
- case 2:
- return HFI_VPX_PROFILE_VERSION_2;
- case 3:
- return HFI_VPX_PROFILE_VERSION_3;
- }
case V4L2_CID_MPEG_VIDEO_H264_LOOP_FILTER_MODE:
switch (value) {
case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_ENABLED:
@@ -217,46 +131,6 @@ static int venc_v4l2_to_hfi(int id, int value)
case V4L2_MPEG_VIDEO_H264_LOOP_FILTER_MODE_DISABLED_AT_SLICE_BOUNDARY:
return HFI_H264_DB_MODE_SKIP_SLICE_BOUNDARY;
}
- case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
- switch (value) {
- case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN:
- default:
- return HFI_HEVC_PROFILE_MAIN;
- case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE:
- return HFI_HEVC_PROFILE_MAIN_STILL_PIC;
- case V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_10:
- return HFI_HEVC_PROFILE_MAIN10;
- }
- case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
- switch (value) {
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_1:
- default:
- return HFI_HEVC_LEVEL_1;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_2:
- return HFI_HEVC_LEVEL_2;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_2_1:
- return HFI_HEVC_LEVEL_21;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_3:
- return HFI_HEVC_LEVEL_3;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_3_1:
- return HFI_HEVC_LEVEL_31;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_4:
- return HFI_HEVC_LEVEL_4;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_4_1:
- return HFI_HEVC_LEVEL_41;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_5:
- return HFI_HEVC_LEVEL_5;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_1:
- return HFI_HEVC_LEVEL_51;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_5_2:
- return HFI_HEVC_LEVEL_52;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_6:
- return HFI_HEVC_LEVEL_6;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_1:
- return HFI_HEVC_LEVEL_61;
- case V4L2_MPEG_VIDEO_HEVC_LEVEL_6_2:
- return HFI_HEVC_LEVEL_62;
- }
}
return 0;
@@ -584,6 +458,7 @@ static int venc_enum_frameintervals(struct file *file, void *fh,
{
struct venus_inst *inst = to_inst(file);
const struct venus_format *fmt;
+ unsigned int framerate_factor = 1;
fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
@@ -608,12 +483,17 @@ static int venc_enum_frameintervals(struct file *file, void *fh,
fival->height < frame_height_min(inst))
return -EINVAL;
+ if (IS_V1(inst->core)) {
+ /* framerate is reported in 1/65535 fps unit */
+ framerate_factor = (1 << 16);
+ }
+
fival->stepwise.min.numerator = 1;
- fival->stepwise.min.denominator = frate_max(inst);
+ fival->stepwise.min.denominator = frate_max(inst) / framerate_factor;
fival->stepwise.max.numerator = 1;
- fival->stepwise.max.denominator = frate_min(inst);
+ fival->stepwise.max.denominator = frate_min(inst) / framerate_factor;
fival->stepwise.step.numerator = 1;
- fival->stepwise.step.denominator = frate_max(inst);
+ fival->stepwise.step.denominator = frate_max(inst) / framerate_factor;
return 0;
}
@@ -651,13 +531,12 @@ static int venc_set_properties(struct venus_inst *inst)
{
struct venc_controls *ctr = &inst->controls.enc;
struct hfi_intra_period intra_period;
- struct hfi_profile_level pl;
struct hfi_framerate frate;
struct hfi_bitrate brate;
struct hfi_idr_period idrp;
struct hfi_quantization quant;
struct hfi_quantization_range quant_range;
- u32 ptype, rate_control, bitrate, profile = 0, level = 0;
+ u32 ptype, rate_control, bitrate;
int ret;
ret = venus_helper_set_work_mode(inst, VIDC_WORK_MODE_2);
@@ -739,15 +618,29 @@ static int venc_set_properties(struct venus_inst *inst)
if (!ctr->rc_enable)
rate_control = HFI_RATE_CONTROL_OFF;
else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR)
- rate_control = HFI_RATE_CONTROL_VBR_CFR;
- else
- rate_control = HFI_RATE_CONTROL_CBR_CFR;
+ rate_control = ctr->frame_skip_mode ? HFI_RATE_CONTROL_VBR_VFR :
+ HFI_RATE_CONTROL_VBR_CFR;
+ else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ rate_control = ctr->frame_skip_mode ? HFI_RATE_CONTROL_CBR_VFR :
+ HFI_RATE_CONTROL_CBR_CFR;
+ else if (ctr->bitrate_mode == V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)
+ rate_control = HFI_RATE_CONTROL_CQ;
ptype = HFI_PROPERTY_PARAM_VENC_RATE_CONTROL;
ret = hfi_session_set_property(inst, ptype, &rate_control);
if (ret)
return ret;
+ if (rate_control == HFI_RATE_CONTROL_CQ && ctr->const_quality) {
+ struct hfi_heic_frame_quality quality = {};
+
+ ptype = HFI_PROPERTY_CONFIG_HEIC_FRAME_QUALITY;
+ quality.frame_quality = ctr->const_quality;
+ ret = hfi_session_set_property(inst, ptype, &quality);
+ if (ret)
+ return ret;
+ }
+
if (!ctr->bitrate)
bitrate = 64000;
else
@@ -791,35 +684,7 @@ static int venc_set_properties(struct venus_inst *inst)
if (ret)
return ret;
- if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H264) {
- profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_H264_PROFILE,
- ctr->profile.h264);
- level = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_H264_LEVEL,
- ctr->level.h264);
- } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_VP8) {
- profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_VP8_PROFILE,
- ctr->profile.vpx);
- level = 0;
- } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_MPEG4) {
- profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE,
- ctr->profile.mpeg4);
- level = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL,
- ctr->level.mpeg4);
- } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_H263) {
- profile = 0;
- level = 0;
- } else if (inst->fmt_cap->pixfmt == V4L2_PIX_FMT_HEVC) {
- profile = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_HEVC_PROFILE,
- ctr->profile.hevc);
- level = venc_v4l2_to_hfi(V4L2_CID_MPEG_VIDEO_HEVC_LEVEL,
- ctr->level.hevc);
- }
-
- ptype = HFI_PROPERTY_PARAM_PROFILE_LEVEL_CURRENT;
- pl.profile = profile;
- pl.level = level;
-
- ret = hfi_session_set_property(inst, ptype, &pl);
+ ret = venus_helper_set_profile_level(inst, ctr->profile, ctr->level);
if (ret)
return ret;
@@ -1129,13 +994,7 @@ static int m2m_queue_init(void *priv, struct vb2_queue *src_vq,
dst_vq->allow_zero_bytesused = 1;
dst_vq->min_buffers_needed = 1;
dst_vq->dev = inst->core->dev;
- ret = vb2_queue_init(dst_vq);
- if (ret) {
- vb2_queue_release(src_vq);
- return ret;
- }
-
- return 0;
+ return vb2_queue_init(dst_vq);
}
static void venc_inst_init(struct venus_inst *inst)
diff --git a/drivers/media/platform/qcom/venus/venc_ctrls.c b/drivers/media/platform/qcom/venus/venc_ctrls.c
index 8362dde7949e..0708b3b89d0c 100644
--- a/drivers/media/platform/qcom/venus/venc_ctrls.c
+++ b/drivers/media/platform/qcom/venus/venc_ctrls.c
@@ -103,25 +103,15 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
ctr->h264_entropy_mode = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_PROFILE:
- ctr->profile.mpeg4 = ctrl->val;
- break;
case V4L2_CID_MPEG_VIDEO_H264_PROFILE:
- ctr->profile.h264 = ctrl->val;
- break;
case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
- ctr->profile.hevc = ctrl->val;
- break;
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
- ctr->profile.vpx = ctrl->val;
+ ctr->profile = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_MPEG4_LEVEL:
- ctr->level.mpeg4 = ctrl->val;
- break;
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
- ctr->level.h264 = ctrl->val;
- break;
case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
- ctr->level.hevc = ctrl->val;
+ ctr->level = ctrl->val;
break;
case V4L2_CID_MPEG_VIDEO_H264_I_FRAME_QP:
ctr->h264_i_qp = ctrl->val;
@@ -202,6 +192,12 @@ static int venc_op_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE:
ctr->rc_enable = ctrl->val;
break;
+ case V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY:
+ ctr->const_quality = ctrl->val;
+ break;
+ case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
+ ctr->frame_skip_mode = ctrl->val;
+ break;
default:
return -EINVAL;
}
@@ -217,7 +213,7 @@ int venc_ctrl_init(struct venus_inst *inst)
{
int ret;
- ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 31);
+ ret = v4l2_ctrl_handler_init(&inst->ctrl_handler, 33);
if (ret)
return ret;
@@ -225,7 +221,8 @@ int venc_ctrl_init(struct venus_inst *inst)
V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
~((1 << V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) |
- (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)),
+ (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CBR) |
+ (1 << V4L2_MPEG_VIDEO_BITRATE_MODE_CQ)),
V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
@@ -357,6 +354,16 @@ int venc_ctrl_init(struct venus_inst *inst)
v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
V4L2_CID_MPEG_VIDEO_FRAME_RC_ENABLE, 0, 1, 1, 1);
+ v4l2_ctrl_new_std(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY, 0, 100, 1, 0);
+
+ v4l2_ctrl_new_std_menu(&inst->ctrl_handler, &venc_ctrl_ops,
+ V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE,
+ V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+ ~((1 << V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED) |
+ (1 << V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT)),
+ V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED);
+
ret = inst->ctrl_handler.error;
if (ret)
goto err;
diff --git a/drivers/media/platform/rcar-fcp.c b/drivers/media/platform/rcar-fcp.c
index 5c6b00737fe7..5c03318ae07b 100644
--- a/drivers/media/platform/rcar-fcp.c
+++ b/drivers/media/platform/rcar-fcp.c
@@ -22,7 +22,6 @@
struct rcar_fcp_device {
struct list_head list;
struct device *dev;
- struct device_dma_parameters dma_parms;
};
static LIST_HEAD(fcp_devices);
@@ -103,8 +102,10 @@ int rcar_fcp_enable(struct rcar_fcp_device *fcp)
return 0;
ret = pm_runtime_get_sync(fcp->dev);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put_noidle(fcp->dev);
return ret;
+ }
return 0;
}
@@ -138,8 +139,7 @@ static int rcar_fcp_probe(struct platform_device *pdev)
fcp->dev = &pdev->dev;
- fcp->dev->dma_parms = &fcp->dma_parms;
- dma_set_max_seg_size(fcp->dev, DMA_BIT_MASK(32));
+ dma_set_max_seg_size(fcp->dev, UINT_MAX);
pm_runtime_enable(&pdev->dev);
diff --git a/drivers/media/platform/rcar-vin/Kconfig b/drivers/media/platform/rcar-vin/Kconfig
index ca0d906dce2f..030312d862e7 100644
--- a/drivers/media/platform/rcar-vin/Kconfig
+++ b/drivers/media/platform/rcar-vin/Kconfig
@@ -9,7 +9,7 @@ config VIDEO_RCAR_CSI2
select V4L2_FWNODE
help
Support for Renesas R-Car MIPI CSI-2 receiver.
- Supports R-Car Gen3 SoCs.
+ Supports R-Car Gen3 and RZ/G2 SoCs.
To compile this driver as a module, choose M here: the
module will be called rcar-csi2.
@@ -24,7 +24,7 @@ config VIDEO_RCAR_VIN
select V4L2_FWNODE
help
Support for Renesas R-Car Video Input (VIN) driver.
- Supports R-Car Gen2 and Gen3 SoCs.
+ Supports R-Car Gen{2,3} and RZ/G{1,2} SoCs.
To compile this driver as a module, choose M here: the
module will be called rcar-vin.
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 7440c8965d27..34d003e0e9b9 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -243,7 +243,6 @@ static struct rvin_group *rvin_group_data;
static void rvin_group_cleanup(struct rvin_group *group)
{
- media_device_unregister(&group->mdev);
media_device_cleanup(&group->mdev);
mutex_destroy(&group->lock);
}
@@ -253,7 +252,6 @@ static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin)
struct media_device *mdev = &group->mdev;
const struct of_device_id *match;
struct device_node *np;
- int ret;
mutex_init(&group->lock);
@@ -278,11 +276,7 @@ static int rvin_group_init(struct rvin_group *group, struct rvin_dev *vin)
media_device_init(mdev);
- ret = media_device_register(&group->mdev);
- if (ret)
- rvin_group_cleanup(group);
-
- return ret;
+ return 0;
}
static void rvin_group_release(struct kref *kref)
@@ -626,12 +620,11 @@ static int rvin_parallel_parse_v4l2(struct device *dev,
switch (vin->parallel->mbus_type) {
case V4L2_MBUS_PARALLEL:
- vin_dbg(vin, "Found PARALLEL media bus\n");
- vin->parallel->mbus_flags = vep->bus.parallel.flags;
- break;
case V4L2_MBUS_BT656:
- vin_dbg(vin, "Found BT656 media bus\n");
- vin->parallel->mbus_flags = 0;
+ vin_dbg(vin, "Found %s media bus\n",
+ vin->parallel->mbus_type == V4L2_MBUS_PARALLEL ?
+ "PARALLEL" : "BT656");
+ vin->parallel->bus = vep->bus.parallel;
break;
default:
vin_err(vin, "Unknown media bus type\n");
@@ -682,6 +675,10 @@ static int rvin_group_notify_complete(struct v4l2_async_notifier *notifier)
unsigned int i;
int ret;
+ ret = media_device_register(&vin->group->mdev);
+ if (ret)
+ return ret;
+
ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
if (ret) {
vin_err(vin, "Failed to register subdev nodes\n");
@@ -762,6 +759,8 @@ static void rvin_group_notify_unbind(struct v4l2_async_notifier *notifier,
}
mutex_unlock(&vin->group->lock);
+
+ media_device_unregister(&vin->group->mdev);
}
static int rvin_group_notify_bound(struct v4l2_async_notifier *notifier,
@@ -944,6 +943,42 @@ static const struct rvin_info rcar_info_gen2 = {
.max_height = 2048,
};
+static const struct rvin_group_route rcar_info_r8a774e1_routes[] = {
+ { .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
+ { .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
+ { .csi = RVIN_CSI40, .channel = 1, .vin = 0, .mask = BIT(2) },
+ { .csi = RVIN_CSI20, .channel = 0, .vin = 1, .mask = BIT(0) },
+ { .csi = RVIN_CSI40, .channel = 1, .vin = 1, .mask = BIT(1) | BIT(3) },
+ { .csi = RVIN_CSI40, .channel = 0, .vin = 1, .mask = BIT(2) },
+ { .csi = RVIN_CSI20, .channel = 1, .vin = 1, .mask = BIT(4) },
+ { .csi = RVIN_CSI20, .channel = 1, .vin = 2, .mask = BIT(0) },
+ { .csi = RVIN_CSI40, .channel = 0, .vin = 2, .mask = BIT(1) },
+ { .csi = RVIN_CSI20, .channel = 0, .vin = 2, .mask = BIT(2) },
+ { .csi = RVIN_CSI40, .channel = 2, .vin = 2, .mask = BIT(3) },
+ { .csi = RVIN_CSI20, .channel = 2, .vin = 2, .mask = BIT(4) },
+ { .csi = RVIN_CSI40, .channel = 1, .vin = 3, .mask = BIT(0) },
+ { .csi = RVIN_CSI20, .channel = 1, .vin = 3, .mask = BIT(1) | BIT(2) },
+ { .csi = RVIN_CSI40, .channel = 3, .vin = 3, .mask = BIT(3) },
+ { .csi = RVIN_CSI20, .channel = 3, .vin = 3, .mask = BIT(4) },
+ { .csi = RVIN_CSI20, .channel = 0, .vin = 4, .mask = BIT(1) | BIT(4) },
+ { .csi = RVIN_CSI20, .channel = 0, .vin = 5, .mask = BIT(0) },
+ { .csi = RVIN_CSI20, .channel = 1, .vin = 5, .mask = BIT(4) },
+ { .csi = RVIN_CSI20, .channel = 1, .vin = 6, .mask = BIT(0) },
+ { .csi = RVIN_CSI20, .channel = 0, .vin = 6, .mask = BIT(2) },
+ { .csi = RVIN_CSI20, .channel = 2, .vin = 6, .mask = BIT(4) },
+ { .csi = RVIN_CSI20, .channel = 1, .vin = 7, .mask = BIT(1) | BIT(2) },
+ { .csi = RVIN_CSI20, .channel = 3, .vin = 7, .mask = BIT(4) },
+ { /* Sentinel */ }
+};
+
+static const struct rvin_info rcar_info_r8a774e1 = {
+ .model = RCAR_GEN3,
+ .use_mc = true,
+ .max_width = 4096,
+ .max_height = 4096,
+ .routes = rcar_info_r8a774e1_routes,
+};
+
static const struct rvin_group_route rcar_info_r8a7795_routes[] = {
{ .csi = RVIN_CSI40, .channel = 0, .vin = 0, .mask = BIT(0) | BIT(3) },
{ .csi = RVIN_CSI20, .channel = 0, .vin = 0, .mask = BIT(1) | BIT(4) },
@@ -1221,6 +1256,10 @@ static const struct of_device_id rvin_of_id_table[] = {
.data = &rcar_info_r8a77990,
},
{
+ .compatible = "renesas,vin-r8a774e1",
+ .data = &rcar_info_r8a774e1,
+ },
+ {
.compatible = "renesas,vin-r8a7778",
.data = &rcar_info_m1,
},
@@ -1370,12 +1409,8 @@ static int rcar_vin_remove(struct platform_device *pdev)
v4l2_async_notifier_cleanup(&vin->notifier);
if (vin->info->use_mc) {
- mutex_lock(&vin->group->lock);
- if (&vin->v4l2_dev == vin->group->notifier.v4l2_dev) {
- v4l2_async_notifier_unregister(&vin->group->notifier);
- v4l2_async_notifier_cleanup(&vin->group->notifier);
- }
- mutex_unlock(&vin->group->lock);
+ v4l2_async_notifier_unregister(&vin->group->notifier);
+ v4l2_async_notifier_cleanup(&vin->group->notifier);
rvin_group_put(vin);
}
diff --git a/drivers/media/platform/rcar-vin/rcar-csi2.c b/drivers/media/platform/rcar-vin/rcar-csi2.c
index c6cc4f473a07..79f229756805 100644
--- a/drivers/media/platform/rcar-vin/rcar-csi2.c
+++ b/drivers/media/platform/rcar-vin/rcar-csi2.c
@@ -320,6 +320,9 @@ static const struct rcar_csi2_format rcar_csi2_formats[] = {
{ .code = MEDIA_BUS_FMT_YUYV8_1X16, .datatype = 0x1e, .bpp = 16 },
{ .code = MEDIA_BUS_FMT_UYVY8_2X8, .datatype = 0x1e, .bpp = 16 },
{ .code = MEDIA_BUS_FMT_YUYV10_2X10, .datatype = 0x1e, .bpp = 20 },
+ { .code = MEDIA_BUS_FMT_SBGGR8_1X8, .datatype = 0x2a, .bpp = 8 },
+ { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .datatype = 0x2a, .bpp = 8 },
+ { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .datatype = 0x2a, .bpp = 8 },
{ .code = MEDIA_BUS_FMT_SRGGB8_1X8, .datatype = 0x2a, .bpp = 8 },
};
@@ -362,8 +365,8 @@ struct rcar_csi2 {
struct media_pad pads[NR_OF_RCAR_CSI2_PAD];
struct v4l2_async_notifier notifier;
- struct v4l2_async_subdev asd;
struct v4l2_subdev *remote;
+ unsigned int remote_pad;
struct v4l2_mbus_framefmt mf;
@@ -409,13 +412,14 @@ static void rcsi2_exit_standby(struct rcar_csi2 *priv)
reset_control_deassert(priv->rstc);
}
-static int rcsi2_wait_phy_start(struct rcar_csi2 *priv)
+static int rcsi2_wait_phy_start(struct rcar_csi2 *priv,
+ unsigned int lanes)
{
unsigned int timeout;
/* Wait for the clock and data lanes to enter LP-11 state. */
for (timeout = 0; timeout <= 20; timeout++) {
- const u32 lane_mask = (1 << priv->lanes) - 1;
+ const u32 lane_mask = (1 << lanes) - 1;
if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) &&
(rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask)
@@ -447,7 +451,8 @@ static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps)
return 0;
}
-static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp)
+static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp,
+ unsigned int lanes)
{
struct v4l2_subdev *source;
struct v4l2_ctrl *ctrl;
@@ -472,15 +477,64 @@ static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp)
* bps = link_freq * 2
*/
mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp;
- do_div(mbps, priv->lanes * 1000000);
+ do_div(mbps, lanes * 1000000);
return mbps;
}
+static int rcsi2_get_active_lanes(struct rcar_csi2 *priv,
+ unsigned int *lanes)
+{
+ struct v4l2_mbus_config mbus_config = { 0 };
+ unsigned int num_lanes = UINT_MAX;
+ int ret;
+
+ *lanes = priv->lanes;
+
+ ret = v4l2_subdev_call(priv->remote, pad, get_mbus_config,
+ priv->remote_pad, &mbus_config);
+ if (ret == -ENOIOCTLCMD) {
+ dev_dbg(priv->dev, "No remote mbus configuration available\n");
+ return 0;
+ }
+
+ if (ret) {
+ dev_err(priv->dev, "Failed to get remote mbus configuration\n");
+ return ret;
+ }
+
+ if (mbus_config.type != V4L2_MBUS_CSI2_DPHY) {
+ dev_err(priv->dev, "Unsupported media bus type %u\n",
+ mbus_config.type);
+ return -EINVAL;
+ }
+
+ if (mbus_config.flags & V4L2_MBUS_CSI2_1_LANE)
+ num_lanes = 1;
+ else if (mbus_config.flags & V4L2_MBUS_CSI2_2_LANE)
+ num_lanes = 2;
+ else if (mbus_config.flags & V4L2_MBUS_CSI2_3_LANE)
+ num_lanes = 3;
+ else if (mbus_config.flags & V4L2_MBUS_CSI2_4_LANE)
+ num_lanes = 4;
+
+ if (num_lanes > priv->lanes) {
+ dev_err(priv->dev,
+ "Unsupported mbus config: too many data lanes %u\n",
+ num_lanes);
+ return -EINVAL;
+ }
+
+ *lanes = num_lanes;
+
+ return 0;
+}
+
static int rcsi2_start_receiver(struct rcar_csi2 *priv)
{
const struct rcar_csi2_format *format;
u32 phycnt, vcdt = 0, vcdt2 = 0, fld = 0;
+ unsigned int lanes;
unsigned int i;
int mbps, ret;
@@ -522,10 +576,18 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
fld |= FLD_FLD_NUM(1);
}
+ /*
+ * Get the number of active data lanes inspecting the remote mbus
+ * configuration.
+ */
+ ret = rcsi2_get_active_lanes(priv, &lanes);
+ if (ret)
+ return ret;
+
phycnt = PHYCNT_ENABLECLK;
- phycnt |= (1 << priv->lanes) - 1;
+ phycnt |= (1 << lanes) - 1;
- mbps = rcsi2_calc_mbps(priv, format->bpp);
+ mbps = rcsi2_calc_mbps(priv, format->bpp, lanes);
if (mbps < 0)
return mbps;
@@ -572,7 +634,7 @@ static int rcsi2_start_receiver(struct rcar_csi2 *priv)
rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ);
rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ);
- ret = rcsi2_wait_phy_start(priv);
+ ret = rcsi2_wait_phy_start(priv, lanes);
if (ret)
return ret;
@@ -749,6 +811,7 @@ static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier,
}
priv->remote = subdev;
+ priv->remote_pad = pad;
dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad);
@@ -811,6 +874,8 @@ static int rcsi2_parse_v4l2(struct rcar_csi2 *priv,
static int rcsi2_parse_dt(struct rcar_csi2 *priv)
{
+ struct v4l2_async_subdev *asd;
+ struct fwnode_handle *fwnode;
struct device_node *ep;
struct v4l2_fwnode_endpoint v4l2_ep = { .bus_type = 0 };
int ret;
@@ -834,24 +899,19 @@ static int rcsi2_parse_dt(struct rcar_csi2 *priv)
return ret;
}
- priv->asd.match.fwnode =
- fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep));
- priv->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
-
+ fwnode = fwnode_graph_get_remote_endpoint(of_fwnode_handle(ep));
of_node_put(ep);
- v4l2_async_notifier_init(&priv->notifier);
-
- ret = v4l2_async_notifier_add_subdev(&priv->notifier, &priv->asd);
- if (ret) {
- fwnode_handle_put(priv->asd.match.fwnode);
- return ret;
- }
+ dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode));
+ v4l2_async_notifier_init(&priv->notifier);
priv->notifier.ops = &rcar_csi2_notify_ops;
- dev_dbg(priv->dev, "Found '%pOF'\n",
- to_of_node(priv->asd.match.fwnode));
+ asd = v4l2_async_notifier_add_fwnode_subdev(&priv->notifier, fwnode,
+ sizeof(*asd));
+ fwnode_handle_put(fwnode);
+ if (IS_ERR(asd))
+ return PTR_ERR(asd);
ret = v4l2_async_subdev_notifier_register(&priv->subdev,
&priv->notifier);
@@ -1091,6 +1151,10 @@ static const struct of_device_id rcar_csi2_of_table[] = {
.data = &rcar_csi2_info_r8a77990,
},
{
+ .compatible = "renesas,r8a774e1-csi2",
+ .data = &rcar_csi2_info_r8a7795,
+ },
+ {
.compatible = "renesas,r8a7795-csi2",
.data = &rcar_csi2_info_r8a7795,
},
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index a5dbb90c5210..692dea300b0d 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -125,6 +125,7 @@
#define VNDMR2_VPS (1 << 30)
#define VNDMR2_HPS (1 << 29)
#define VNDMR2_CES (1 << 28)
+#define VNDMR2_YDS (1 << 22)
#define VNDMR2_FTEV (1 << 17)
#define VNDMR2_VLV(n) ((n & 0xf) << 12)
@@ -598,8 +599,16 @@ void rvin_crop_scale_comp(struct rvin_dev *vin)
/* For RAW8 format bpp is 1, but the hardware process RAW8
* format in 2 pixel unit hence configure VNIS_REG as stride / 2.
*/
- if (vin->format.pixelformat == V4L2_PIX_FMT_SRGGB8)
+ switch (vin->format.pixelformat) {
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
+ case V4L2_PIX_FMT_SRGGB8:
stride /= 2;
+ break;
+ default:
+ break;
+ }
rvin_write(vin, stride, VNIS_REG);
}
@@ -683,6 +692,9 @@ static int rvin_setup(struct rvin_dev *vin)
input_is_yuv = true;
break;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
case MEDIA_BUS_FMT_SRGGB8_1X8:
vnmc |= VNMC_INF_RAW8;
break;
@@ -698,16 +710,26 @@ static int rvin_setup(struct rvin_dev *vin)
if (!vin->is_csi) {
/* Hsync Signal Polarity Select */
- if (!(vin->parallel->mbus_flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
+ if (!(vin->parallel->bus.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
dmr2 |= VNDMR2_HPS;
/* Vsync Signal Polarity Select */
- if (!(vin->parallel->mbus_flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
+ if (!(vin->parallel->bus.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
dmr2 |= VNDMR2_VPS;
/* Data Enable Polarity Select */
- if (vin->parallel->mbus_flags & V4L2_MBUS_DATA_ENABLE_LOW)
+ if (vin->parallel->bus.flags & V4L2_MBUS_DATA_ENABLE_LOW)
dmr2 |= VNDMR2_CES;
+
+ switch (vin->mbus_code) {
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ if (vin->parallel->bus.bus_width == 8 &&
+ vin->parallel->bus.data_shift == 8)
+ dmr2 |= VNDMR2_YDS;
+ break;
+ default:
+ break;
+ }
}
/*
@@ -747,6 +769,9 @@ static int rvin_setup(struct rvin_dev *vin)
case V4L2_PIX_FMT_ABGR32:
dmr = VNDMR_A8BIT(vin->alpha) | VNDMR_EXRGB | VNDMR_DTMD_ARGB;
break;
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SGRBG8:
case V4L2_PIX_FMT_SRGGB8:
dmr = 0;
break;
@@ -1124,6 +1149,18 @@ static int rvin_mc_validate_format(struct rvin_dev *vin, struct v4l2_subdev *sd,
case MEDIA_BUS_FMT_UYVY10_2X10:
case MEDIA_BUS_FMT_RGB888_1X24:
break;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SBGGR8)
+ return -EPIPE;
+ break;
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SGBRG8)
+ return -EPIPE;
+ break;
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ if (vin->format.pixelformat != V4L2_PIX_FMT_SGRBG8)
+ return -EPIPE;
+ break;
case MEDIA_BUS_FMT_SRGGB8_1X8:
if (vin->format.pixelformat != V4L2_PIX_FMT_SRGGB8)
return -EPIPE;
@@ -1409,8 +1446,10 @@ int rvin_set_channel_routing(struct rvin_dev *vin, u8 chsel)
int ret;
ret = pm_runtime_get_sync(vin->dev);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put_noidle(vin->dev);
return ret;
+ }
/* Make register writes take effect immediately. */
vnmc = rvin_read(vin, VNMC_REG);
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index 0e066bba747e..3e7a3ae2a6b9 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -67,6 +67,18 @@ static const struct rvin_video_format rvin_formats[] = {
.bpp = 4,
},
{
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .bpp = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .bpp = 1,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGRBG8,
+ .bpp = 1,
+ },
+ {
.fourcc = V4L2_PIX_FMT_SRGGB8,
.bpp = 1,
},
@@ -366,6 +378,21 @@ static int rvin_enum_fmt_vid_cap(struct file *file, void *priv,
case MEDIA_BUS_FMT_UYVY10_2X10:
case MEDIA_BUS_FMT_RGB888_1X24:
break;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SBGGR8;
+ return 0;
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SGBRG8;
+ return 0;
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ if (f->index)
+ return -EINVAL;
+ f->pixelformat = V4L2_PIX_FMT_SGRBG8;
+ return 0;
case MEDIA_BUS_FMT_SRGGB8_1X8:
if (f->index)
return -EINVAL;
@@ -844,8 +871,10 @@ static int rvin_open(struct file *file)
int ret;
ret = pm_runtime_get_sync(vin->dev);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put_noidle(vin->dev);
return ret;
+ }
ret = mutex_lock_interruptible(&vin->lock);
if (ret)
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h
index c19d077ce1cb..8396e0e45478 100644
--- a/drivers/media/platform/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/rcar-vin/rcar-vin.h
@@ -19,6 +19,7 @@
#include <media/v4l2-ctrls.h>
#include <media/v4l2-dev.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
#include <media/videobuf2-v4l2.h>
/* Number of HW buffers */
@@ -92,7 +93,7 @@ struct rvin_video_format {
* @asd: sub-device descriptor for async framework
* @subdev: subdevice matched using async framework
* @mbus_type: media bus type
- * @mbus_flags: media bus configuration flags
+ * @bus: media bus parallel configuration
* @source_pad: source pad of remote subdevice
* @sink_pad: sink pad of remote subdevice
*
@@ -102,7 +103,7 @@ struct rvin_parallel_entity {
struct v4l2_subdev *subdev;
enum v4l2_mbus_type mbus_type;
- unsigned int mbus_flags;
+ struct v4l2_fwnode_bus_parallel bus;
unsigned int source_pad;
unsigned int sink_pad;
diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
index 3d2451ac347d..f318cd4b8086 100644
--- a/drivers/media/platform/rcar_drif.c
+++ b/drivers/media/platform/rcar_drif.c
@@ -185,7 +185,6 @@ struct rcar_drif_frame_buf {
/* OF graph endpoint's V4L2 async data */
struct rcar_drif_graph_ep {
struct v4l2_subdev *subdev; /* Async matched subdev */
- struct v4l2_async_subdev asd; /* Async sub-device descriptor */
};
/* DMA buffer */
@@ -1109,12 +1108,6 @@ static int rcar_drif_notify_bound(struct v4l2_async_notifier *notifier,
struct rcar_drif_sdr *sdr =
container_of(notifier, struct rcar_drif_sdr, notifier);
- if (sdr->ep.asd.match.fwnode !=
- of_fwnode_handle(subdev->dev->of_node)) {
- rdrif_err(sdr, "subdev %s cannot bind\n", subdev->name);
- return -EINVAL;
- }
-
v4l2_set_subdev_hostdata(subdev, sdr);
sdr->ep.subdev = subdev;
rdrif_dbg(sdr, "bound asd %s\n", subdev->name);
@@ -1218,7 +1211,7 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr)
{
struct v4l2_async_notifier *notifier = &sdr->notifier;
struct fwnode_handle *fwnode, *ep;
- int ret;
+ struct v4l2_async_subdev *asd;
v4l2_async_notifier_init(notifier);
@@ -1227,26 +1220,21 @@ static int rcar_drif_parse_subdevs(struct rcar_drif_sdr *sdr)
if (!ep)
return 0;
+ /* Get the endpoint properties */
+ rcar_drif_get_ep_properties(sdr, ep);
+
fwnode = fwnode_graph_get_remote_port_parent(ep);
+ fwnode_handle_put(ep);
if (!fwnode) {
dev_warn(sdr->dev, "bad remote port parent\n");
- fwnode_handle_put(ep);
return -EINVAL;
}
- sdr->ep.asd.match.fwnode = fwnode;
- sdr->ep.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
- ret = v4l2_async_notifier_add_subdev(notifier, &sdr->ep.asd);
- if (ret) {
- fwnode_handle_put(fwnode);
- return ret;
- }
-
- /* Get the endpoint properties */
- rcar_drif_get_ep_properties(sdr, ep);
-
+ asd = v4l2_async_notifier_add_fwnode_subdev(notifier, fwnode,
+ sizeof(*asd));
fwnode_handle_put(fwnode);
- fwnode_handle_put(ep);
+ if (IS_ERR(asd))
+ return PTR_ERR(asd);
return 0;
}
diff --git a/drivers/media/platform/renesas-ceu.c b/drivers/media/platform/renesas-ceu.c
index f7d71a6a7970..4a633ad0e8fa 100644
--- a/drivers/media/platform/renesas-ceu.c
+++ b/drivers/media/platform/renesas-ceu.c
@@ -405,7 +405,7 @@ static int ceu_hw_config(struct ceu_device *ceudev)
/* Non-swapped planar image capture mode. */
case V4L2_PIX_FMT_NV16:
cdocr |= CEU_CDOCR_NO_DOWSAMPLE;
- /* fall-through */
+ fallthrough;
case V4L2_PIX_FMT_NV12:
if (mbus_fmt->swapped)
camcr = mbus_fmt->fmt_order_swap;
@@ -419,7 +419,7 @@ static int ceu_hw_config(struct ceu_device *ceudev)
/* Swapped planar image capture mode. */
case V4L2_PIX_FMT_NV61:
cdocr |= CEU_CDOCR_NO_DOWSAMPLE;
- /* fall-through */
+ fallthrough;
case V4L2_PIX_FMT_NV21:
if (mbus_fmt->swapped)
camcr = mbus_fmt->fmt_order;
diff --git a/drivers/media/platform/rockchip/rga/rga-buf.c b/drivers/media/platform/rockchip/rga/rga-buf.c
index 36b821ccc1db..bf9a75b75083 100644
--- a/drivers/media/platform/rockchip/rga/rga-buf.c
+++ b/drivers/media/platform/rockchip/rga/rga-buf.c
@@ -81,6 +81,7 @@ static int rga_buf_start_streaming(struct vb2_queue *q, unsigned int count)
ret = pm_runtime_get_sync(rga->dev);
if (ret < 0) {
+ pm_runtime_put_noidle(rga->dev);
rga_buf_return_buffers(q, VB2_BUF_STATE_QUEUED);
return ret;
}
diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c
index 92f43c0cbc0c..422fd549e9c8 100644
--- a/drivers/media/platform/s3c-camif/camif-core.c
+++ b/drivers/media/platform/s3c-camif/camif-core.c
@@ -464,7 +464,7 @@ static int s3c_camif_probe(struct platform_device *pdev)
ret = camif_media_dev_init(camif);
if (ret < 0)
- goto err_alloc;
+ goto err_pm;
ret = camif_register_sensor(camif);
if (ret < 0)
@@ -498,10 +498,9 @@ err_sens:
media_device_unregister(&camif->media_dev);
media_device_cleanup(&camif->media_dev);
camif_unregister_media_entities(camif);
-err_alloc:
+err_pm:
pm_runtime_put(dev);
pm_runtime_disable(dev);
-err_pm:
camif_clk_put(camif);
err_clk:
s3c_camif_unregister_subdev(camif);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index 912fe0c5ab18..acc2217dd7e9 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -262,6 +262,12 @@ static struct mfc_control controls[] = {
.default_value = V4L2_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE_DISABLED,
},
{
+ .id = V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE,
+ .type = V4L2_CTRL_TYPE_MENU,
+ .maximum = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_BUF_LIMIT,
+ .default_value = V4L2_MPEG_VIDEO_FRAME_SKIP_MODE_DISABLED,
+ },
+ {
.id = V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Fixed Target Bit Enable",
@@ -1849,6 +1855,7 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
p->seq_hdr_mode = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_FRAME_SKIP_MODE:
+ case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
p->frame_skip_mode = ctrl->val;
break;
case V4L2_CID_MPEG_MFC51_VIDEO_RC_FIXED_TARGET_BIT:
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
index 7d52431c2c83..62d2320a7218 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -79,8 +79,10 @@ int s5p_mfc_power_on(void)
int i, ret = 0;
ret = pm_runtime_get_sync(pm->device);
- if (ret < 0)
+ if (ret < 0) {
+ pm_runtime_put_noidle(pm->device);
return ret;
+ }
/* clock control */
for (i = 0; i < pm->num_clocks; i++) {
diff --git a/drivers/media/platform/sti/bdisp/bdisp-debug.c b/drivers/media/platform/sti/bdisp/bdisp-debug.c
index 77ca7517fa3e..2b270093009c 100644
--- a/drivers/media/platform/sti/bdisp/bdisp-debug.c
+++ b/drivers/media/platform/sti/bdisp/bdisp-debug.c
@@ -637,35 +637,18 @@ DEFINE_SHOW_ATTRIBUTE(last_nodes_raw);
DEFINE_SHOW_ATTRIBUTE(last_request);
DEFINE_SHOW_ATTRIBUTE(perf);
-int bdisp_debugfs_create(struct bdisp_dev *bdisp)
+void bdisp_debugfs_create(struct bdisp_dev *bdisp)
{
char dirname[16];
snprintf(dirname, sizeof(dirname), "%s%d", BDISP_NAME, bdisp->id);
bdisp->dbg.debugfs_entry = debugfs_create_dir(dirname, NULL);
- if (!bdisp->dbg.debugfs_entry)
- goto err;
- if (!bdisp_dbg_create_entry(regs))
- goto err;
-
- if (!bdisp_dbg_create_entry(last_nodes))
- goto err;
-
- if (!bdisp_dbg_create_entry(last_nodes_raw))
- goto err;
-
- if (!bdisp_dbg_create_entry(last_request))
- goto err;
-
- if (!bdisp_dbg_create_entry(perf))
- goto err;
-
- return 0;
-
-err:
- bdisp_debugfs_remove(bdisp);
- return -ENOMEM;
+ bdisp_dbg_create_entry(regs);
+ bdisp_dbg_create_entry(last_nodes);
+ bdisp_dbg_create_entry(last_nodes_raw);
+ bdisp_dbg_create_entry(last_request);
+ bdisp_dbg_create_entry(perf);
}
void bdisp_debugfs_remove(struct bdisp_dev *bdisp)
diff --git a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
index af2d5eb782ce..060ca85f64d5 100644
--- a/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
+++ b/drivers/media/platform/sti/bdisp/bdisp-v4l2.c
@@ -1360,18 +1360,14 @@ static int bdisp_probe(struct platform_device *pdev)
}
/* Debug */
- ret = bdisp_debugfs_create(bdisp);
- if (ret) {
- dev_err(dev, "failed to create debugfs\n");
- goto err_v4l2;
- }
+ bdisp_debugfs_create(bdisp);
/* Power management */
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "failed to set PM\n");
- goto err_dbg;
+ goto err_pm;
}
/* Filters */
@@ -1399,9 +1395,7 @@ err_filter:
bdisp_hw_free_filters(bdisp->dev);
err_pm:
pm_runtime_put(dev);
-err_dbg:
bdisp_debugfs_remove(bdisp);
-err_v4l2:
v4l2_device_unregister(&bdisp->v4l2_dev);
err_clk:
if (!IS_ERR(bdisp->clock))
diff --git a/drivers/media/platform/sti/bdisp/bdisp.h b/drivers/media/platform/sti/bdisp/bdisp.h
index e309cde379ca..3fb009d24791 100644
--- a/drivers/media/platform/sti/bdisp/bdisp.h
+++ b/drivers/media/platform/sti/bdisp/bdisp.h
@@ -209,6 +209,6 @@ int bdisp_hw_get_and_clear_irq(struct bdisp_dev *bdisp);
int bdisp_hw_update(struct bdisp_ctx *ctx);
void bdisp_debugfs_remove(struct bdisp_dev *bdisp);
-int bdisp_debugfs_create(struct bdisp_dev *bdisp);
+void bdisp_debugfs_create(struct bdisp_dev *bdisp);
void bdisp_dbg_perf_begin(struct bdisp_dev *bdisp);
void bdisp_dbg_perf_end(struct bdisp_dev *bdisp);
diff --git a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
index 5baada4f65e5..dbe7788083a4 100644
--- a/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
+++ b/drivers/media/platform/sti/c8sectpfe/c8sectpfe-core.c
@@ -77,9 +77,9 @@ static void c8sectpfe_timer_interrupt(struct timer_list *t)
add_timer(&fei->timer);
}
-static void channel_swdemux_tsklet(unsigned long data)
+static void channel_swdemux_tsklet(struct tasklet_struct *t)
{
- struct channel_info *channel = (struct channel_info *)data;
+ struct channel_info *channel = from_tasklet(channel, t, tsklet);
struct c8sectpfei *fei;
unsigned long wp, rp;
int pos, num_packets, n, size;
@@ -208,8 +208,7 @@ static int c8sectpfe_start_feed(struct dvb_demux_feed *dvbdmxfeed)
dev_dbg(fei->dev, "Starting channel=%p\n", channel);
- tasklet_init(&channel->tsklet, channel_swdemux_tsklet,
- (unsigned long) channel);
+ tasklet_setup(&channel->tsklet, channel_swdemux_tsklet);
/* Reset the internal inputblock sram pointers */
writel(channel->fifo,
@@ -638,8 +637,7 @@ static int configure_memdma_and_inputblock(struct c8sectpfei *fei,
writel(tsin->back_buffer_busaddr, tsin->irec + DMA_PRDS_BUSRP_TP(0));
/* initialize tasklet */
- tasklet_init(&tsin->tsklet, channel_swdemux_tsklet,
- (unsigned long) tsin);
+ tasklet_setup(&tsin->tsklet, channel_swdemux_tsklet);
return 0;
diff --git a/drivers/media/platform/sti/delta/delta-v4l2.c b/drivers/media/platform/sti/delta/delta-v4l2.c
index 2503224eeee5..c691b3d81549 100644
--- a/drivers/media/platform/sti/delta/delta-v4l2.c
+++ b/drivers/media/platform/sti/delta/delta-v4l2.c
@@ -954,8 +954,10 @@ static void delta_run_work(struct work_struct *work)
/* enable the hardware */
if (!dec->pm) {
ret = delta_get_sync(ctx);
- if (ret)
+ if (ret) {
+ delta_put_autosuspend(ctx);
goto err;
+ }
}
/* decode this access unit */
diff --git a/drivers/media/platform/sti/hva/hva-debugfs.c b/drivers/media/platform/sti/hva/hva-debugfs.c
index 7d12a5b5d914..a86a07b6fbc7 100644
--- a/drivers/media/platform/sti/hva/hva-debugfs.c
+++ b/drivers/media/platform/sti/hva/hva-debugfs.c
@@ -337,25 +337,11 @@ DEFINE_SHOW_ATTRIBUTE(regs);
void hva_debugfs_create(struct hva_dev *hva)
{
hva->dbg.debugfs_entry = debugfs_create_dir(HVA_NAME, NULL);
- if (!hva->dbg.debugfs_entry)
- goto err;
- if (!hva_dbg_create_entry(device))
- goto err;
-
- if (!hva_dbg_create_entry(encoders))
- goto err;
-
- if (!hva_dbg_create_entry(last))
- goto err;
-
- if (!hva_dbg_create_entry(regs))
- goto err;
-
- return;
-
-err:
- hva_debugfs_remove(hva);
+ hva_dbg_create_entry(device);
+ hva_dbg_create_entry(encoders);
+ hva_dbg_create_entry(last);
+ hva_dbg_create_entry(regs);
}
void hva_debugfs_remove(struct hva_dev *hva)
diff --git a/drivers/media/platform/sti/hva/hva-hw.c b/drivers/media/platform/sti/hva/hva-hw.c
index 401aaafa1710..43f279e2a6a3 100644
--- a/drivers/media/platform/sti/hva/hva-hw.c
+++ b/drivers/media/platform/sti/hva/hva-hw.c
@@ -272,6 +272,7 @@ static unsigned long int hva_hw_get_ip_version(struct hva_dev *hva)
if (pm_runtime_get_sync(dev) < 0) {
dev_err(dev, "%s failed to get pm_runtime\n", HVA_PREFIX);
+ pm_runtime_put_noidle(dev);
mutex_unlock(&hva->protect_mutex);
return -EFAULT;
}
@@ -388,7 +389,7 @@ int hva_hw_probe(struct platform_device *pdev, struct hva_dev *hva)
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "%s failed to set PM\n", HVA_PREFIX);
- goto err_clk;
+ goto err_pm;
}
/* check IP hardware version */
@@ -553,6 +554,7 @@ void hva_hw_dump_regs(struct hva_dev *hva, struct seq_file *s)
if (pm_runtime_get_sync(dev) < 0) {
seq_puts(s, "Cannot wake up IP\n");
+ pm_runtime_put_noidle(dev);
mutex_unlock(&hva->protect_mutex);
return;
}
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index b8931490b83b..fd1c41cba52f 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -733,7 +733,7 @@ static int dcmi_start_streaming(struct vb2_queue *vq, unsigned int count)
if (ret < 0) {
dev_err(dcmi->dev, "%s: Failed to start streaming, cannot get sync (%d)\n",
__func__, ret);
- goto err_release_buffers;
+ goto err_pm_put;
}
ret = media_pipeline_start(&dcmi->vdev->entity, &dcmi->pipeline);
@@ -837,8 +837,6 @@ err_media_pipeline_stop:
err_pm_put:
pm_runtime_put(dcmi->dev);
-
-err_release_buffers:
spin_lock_irq(&dcmi->irqlock);
/*
* Return all buffers to vb2 in QUEUED state.
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
index 5319eb1ab309..d226ecadff8e 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_csi.c
@@ -287,6 +287,7 @@ static int sun4i_csi_remove(struct platform_device *pdev)
v4l2_async_notifier_unregister(&csi->notifier);
v4l2_async_notifier_cleanup(&csi->notifier);
+ vb2_video_unregister_device(&csi->vdev);
media_device_unregister(&csi->mdev);
sun4i_csi_dma_unregister(csi);
media_device_cleanup(&csi->mdev);
diff --git a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
index 3278746246aa..2c39cd7f2862 100644
--- a/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
+++ b/drivers/media/platform/sunxi/sun4i-csi/sun4i_dma.c
@@ -431,7 +431,7 @@ int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq)
ret = v4l2_device_register(csi->dev, &csi->v4l);
if (ret) {
dev_err(csi->dev, "Couldn't register the v4l2 device\n");
- goto err_free_queue;
+ goto err_free_mutex;
}
ret = devm_request_irq(csi->dev, irq, sun4i_csi_irq, 0,
@@ -446,9 +446,6 @@ int sun4i_csi_dma_register(struct sun4i_csi *csi, int irq)
err_unregister_device:
v4l2_device_unregister(&csi->v4l);
-err_free_queue:
- vb2_queue_release(q);
-
err_free_mutex:
mutex_destroy(&csi->lock);
return ret;
@@ -457,6 +454,5 @@ err_free_mutex:
void sun4i_csi_dma_unregister(struct sun4i_csi *csi)
{
v4l2_device_unregister(&csi->v4l);
- vb2_queue_release(&csi->queue);
mutex_destroy(&csi->lock);
}
diff --git a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
index d9648b2810b9..b55de9ab64d8 100644
--- a/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
+++ b/drivers/media/platform/sunxi/sun6i-csi/sun6i_video.c
@@ -660,13 +660,11 @@ int sun6i_video_init(struct sun6i_video *video, struct sun6i_csi *csi,
if (ret < 0) {
v4l2_err(&csi->v4l2_dev,
"video_register_device failed: %d\n", ret);
- goto release_vb2;
+ goto clean_entity;
}
return 0;
-release_vb2:
- vb2_queue_release(&video->vb2_vidq);
clean_entity:
media_entity_cleanup(&video->vdev.entity);
mutex_destroy(&video->lock);
@@ -675,8 +673,7 @@ clean_entity:
void sun6i_video_cleanup(struct sun6i_video *video)
{
- video_unregister_device(&video->vdev);
+ vb2_video_unregister_device(&video->vdev);
media_entity_cleanup(&video->vdev.entity);
- vb2_queue_release(&video->vb2_vidq);
mutex_destroy(&video->lock);
}
diff --git a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
index 94f505d3cbad..3f81dd17755c 100644
--- a/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
+++ b/drivers/media/platform/sunxi/sun8i-rotate/sun8i_rotate.c
@@ -747,11 +747,8 @@ static int rotate_probe(struct platform_device *pdev)
dev->dev = &pdev->dev;
irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_err(dev->dev, "Failed to get IRQ\n");
-
+ if (irq <= 0)
return irq;
- }
ret = devm_request_irq(dev->dev, irq, rotate_irq,
0, dev_name(dev->dev), dev);
diff --git a/drivers/media/platform/ti-vpe/vpe.c b/drivers/media/platform/ti-vpe/vpe.c
index 346f8212791c..779dd74b82d0 100644
--- a/drivers/media/platform/ti-vpe/vpe.c
+++ b/drivers/media/platform/ti-vpe/vpe.c
@@ -2475,6 +2475,8 @@ static int vpe_runtime_get(struct platform_device *pdev)
r = pm_runtime_get_sync(&pdev->dev);
WARN_ON(r < 0);
+ if (r)
+ pm_runtime_put_noidle(&pdev->dev);
return r < 0 ? r : 0;
}
diff --git a/drivers/media/platform/vsp1/vsp1_drm.c b/drivers/media/platform/vsp1/vsp1_drm.c
index a4a45d68a6ef..86d5e3f4b1ff 100644
--- a/drivers/media/platform/vsp1/vsp1_drm.c
+++ b/drivers/media/platform/vsp1/vsp1_drm.c
@@ -912,8 +912,8 @@ int vsp1_du_map_sg(struct device *dev, struct sg_table *sgt)
* skip cache sync. This will need to be revisited when support for
* non-coherent buffers will be added to the DU driver.
*/
- return dma_map_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
+ return dma_map_sgtable(vsp1->bus_master, sgt, DMA_TO_DEVICE,
+ DMA_ATTR_SKIP_CPU_SYNC);
}
EXPORT_SYMBOL_GPL(vsp1_du_map_sg);
@@ -921,8 +921,8 @@ void vsp1_du_unmap_sg(struct device *dev, struct sg_table *sgt)
{
struct vsp1_device *vsp1 = dev_get_drvdata(dev);
- dma_unmap_sg_attrs(vsp1->bus_master, sgt->sgl, sgt->nents,
- DMA_TO_DEVICE, DMA_ATTR_SKIP_CPU_SYNC);
+ dma_unmap_sgtable(vsp1->bus_master, sgt, DMA_TO_DEVICE,
+ DMA_ATTR_SKIP_CPU_SYNC);
}
EXPORT_SYMBOL_GPL(vsp1_du_unmap_sg);
diff --git a/drivers/media/platform/vsp1/vsp1_drv.c b/drivers/media/platform/vsp1/vsp1_drv.c
index c650e45bb0ad..dc62533cf32c 100644
--- a/drivers/media/platform/vsp1/vsp1_drv.c
+++ b/drivers/media/platform/vsp1/vsp1_drv.c
@@ -562,7 +562,12 @@ int vsp1_device_get(struct vsp1_device *vsp1)
int ret;
ret = pm_runtime_get_sync(vsp1->dev);
- return ret < 0 ? ret : 0;
+ if (ret < 0) {
+ pm_runtime_put_noidle(vsp1->dev);
+ return ret;
+ }
+
+ return 0;
}
/*
@@ -845,12 +850,12 @@ static int vsp1_probe(struct platform_device *pdev)
/* Configure device parameters based on the version register. */
pm_runtime_enable(&pdev->dev);
- ret = pm_runtime_get_sync(&pdev->dev);
+ ret = vsp1_device_get(vsp1);
if (ret < 0)
goto done;
vsp1->version = vsp1_read(vsp1, VI6_IP_VERSION);
- pm_runtime_put_sync(&pdev->dev);
+ vsp1_device_put(vsp1);
for (i = 0; i < ARRAY_SIZE(vsp1_device_infos); ++i) {
if ((vsp1->version & VI6_IP_VERSION_MODEL_MASK) ==
diff --git a/drivers/media/radio/radio-si476x.c b/drivers/media/radio/radio-si476x.c
index 7e2460263882..23997425bdb5 100644
--- a/drivers/media/radio/radio-si476x.c
+++ b/drivers/media/radio/radio-si476x.c
@@ -1345,60 +1345,24 @@ static const struct file_operations radio_rsq_primary_fops = {
};
-static int si476x_radio_init_debugfs(struct si476x_radio *radio)
+static void si476x_radio_init_debugfs(struct si476x_radio *radio)
{
- struct dentry *dentry;
- int ret;
+ radio->debugfs = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL);
- dentry = debugfs_create_dir(dev_name(radio->v4l2dev.dev), NULL);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto exit;
- }
- radio->debugfs = dentry;
-
- dentry = debugfs_create_file("acf", S_IRUGO,
- radio->debugfs, radio, &radio_acf_fops);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto cleanup;
- }
+ debugfs_create_file("acf", S_IRUGO, radio->debugfs, radio,
+ &radio_acf_fops);
- dentry = debugfs_create_file("rds_blckcnt", S_IRUGO,
- radio->debugfs, radio,
- &radio_rds_blckcnt_fops);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto cleanup;
- }
+ debugfs_create_file("rds_blckcnt", S_IRUGO, radio->debugfs, radio,
+ &radio_rds_blckcnt_fops);
- dentry = debugfs_create_file("agc", S_IRUGO,
- radio->debugfs, radio, &radio_agc_fops);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto cleanup;
- }
+ debugfs_create_file("agc", S_IRUGO, radio->debugfs, radio,
+ &radio_agc_fops);
- dentry = debugfs_create_file("rsq", S_IRUGO,
- radio->debugfs, radio, &radio_rsq_fops);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto cleanup;
- }
+ debugfs_create_file("rsq", S_IRUGO, radio->debugfs, radio,
+ &radio_rsq_fops);
- dentry = debugfs_create_file("rsq_primary", S_IRUGO,
- radio->debugfs, radio,
- &radio_rsq_primary_fops);
- if (IS_ERR(dentry)) {
- ret = PTR_ERR(dentry);
- goto cleanup;
- }
-
- return 0;
-cleanup:
- debugfs_remove_recursive(radio->debugfs);
-exit:
- return ret;
+ debugfs_create_file("rsq_primary", S_IRUGO, radio->debugfs, radio,
+ &radio_rsq_primary_fops);
}
@@ -1535,11 +1499,7 @@ static int si476x_radio_probe(struct platform_device *pdev)
goto exit;
}
- rval = si476x_radio_init_debugfs(radio);
- if (rval < 0) {
- dev_err(&pdev->dev, "Could not create debugfs interface\n");
- goto exit;
- }
+ si476x_radio_init_debugfs(radio);
return 0;
exit:
diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
index 7f3aee495ed3..6afa7c3464ab 100644
--- a/drivers/media/radio/si4713/si4713.c
+++ b/drivers/media/radio/si4713/si4713.c
@@ -1157,7 +1157,7 @@ static int si4713_s_ctrl(struct v4l2_ctrl *ctrl)
* V4L2_CID_TUNE_POWER_LEVEL. */
if (force)
break;
- /* fall through */
+ fallthrough;
case V4L2_CID_TUNE_POWER_LEVEL:
ret = si4713_tx_tune_power(sdev,
sdev->tune_pwr_level->val, sdev->tune_ant_cap->val);
diff --git a/drivers/media/radio/wl128x/fmdrv_common.c b/drivers/media/radio/wl128x/fmdrv_common.c
index cce97c9d5409..6142484d5cb4 100644
--- a/drivers/media/radio/wl128x/fmdrv_common.c
+++ b/drivers/media/radio/wl128x/fmdrv_common.c
@@ -19,9 +19,11 @@
* Author: Manjunatha Halli <manjunatha_halli@ti.com>
*/
-#include <linux/module.h>
-#include <linux/firmware.h>
#include <linux/delay.h>
+#include <linux/firmware.h>
+#include <linux/module.h>
+#include <linux/nospec.h>
+
#include "fmdrv.h"
#include "fmdrv_v4l2.h"
#include "fmdrv_common.h"
@@ -244,7 +246,7 @@ void fmc_update_region_info(struct fmdev *fmdev, u8 region_to_set)
* FM common sub-module will schedule this tasklet whenever it receives
* FM packet from ST driver.
*/
-static void recv_tasklet(unsigned long arg)
+static void recv_tasklet(struct tasklet_struct *t)
{
struct fmdev *fmdev;
struct fm_irq *irq_info;
@@ -253,7 +255,7 @@ static void recv_tasklet(unsigned long arg)
u8 num_fm_hci_cmds;
unsigned long flags;
- fmdev = (struct fmdev *)arg;
+ fmdev = from_tasklet(fmdev, t, tx_task);
irq_info = &fmdev->irq_info;
/* Process all packets in the RX queue */
while ((skb = skb_dequeue(&fmdev->rx_q))) {
@@ -328,13 +330,13 @@ static void recv_tasklet(unsigned long arg)
}
/* FM send tasklet: is scheduled when FM packet has to be sent to chip */
-static void send_tasklet(unsigned long arg)
+static void send_tasklet(struct tasklet_struct *t)
{
struct fmdev *fmdev;
struct sk_buff *skb;
int len;
- fmdev = (struct fmdev *)arg;
+ fmdev = from_tasklet(fmdev, t, tx_task);
if (!atomic_read(&fmdev->tx_cnt))
return;
@@ -700,7 +702,7 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev)
struct fm_rds *rds = &fmdev->rx.rds;
unsigned long group_idx, flags;
u8 *rds_data, meta_data, tmpbuf[FM_RDS_BLK_SIZE];
- u8 type, blk_idx;
+ u8 type, blk_idx, idx;
u16 cur_picode;
u32 rds_len;
@@ -733,9 +735,11 @@ static void fm_irq_handle_rdsdata_getcmd_resp(struct fmdev *fmdev)
}
/* Skip checkword (control) byte and copy only data byte */
- memcpy(&rds_fmt.data.groupdatabuff.
- buff[blk_idx * (FM_RDS_BLK_SIZE - 1)],
- rds_data, (FM_RDS_BLK_SIZE - 1));
+ idx = array_index_nospec(blk_idx * (FM_RDS_BLK_SIZE - 1),
+ FM_RX_RDS_INFO_FIELD_MAX - (FM_RDS_BLK_SIZE - 1));
+
+ memcpy(&rds_fmt.data.groupdatabuff.buff[idx], rds_data,
+ FM_RDS_BLK_SIZE - 1);
rds->last_blk_idx = blk_idx;
@@ -1535,11 +1539,11 @@ int fmc_prepare(struct fmdev *fmdev)
/* Initialize TX queue and TX tasklet */
skb_queue_head_init(&fmdev->tx_q);
- tasklet_init(&fmdev->tx_task, send_tasklet, (unsigned long)fmdev);
+ tasklet_setup(&fmdev->tx_task, send_tasklet);
/* Initialize RX Queue and RX tasklet */
skb_queue_head_init(&fmdev->rx_q);
- tasklet_init(&fmdev->rx_task, recv_tasklet, (unsigned long)fmdev);
+ tasklet_setup(&fmdev->rx_task, recv_tasklet);
fmdev->irq_info.stage = 0;
atomic_set(&fmdev->tx_cnt, 1);
diff --git a/drivers/media/rc/ati_remote.c b/drivers/media/rc/ati_remote.c
index 9cdef17b4793..c12dda73cdd5 100644
--- a/drivers/media/rc/ati_remote.c
+++ b/drivers/media/rc/ati_remote.c
@@ -835,6 +835,10 @@ static int ati_remote_probe(struct usb_interface *interface,
err("%s: endpoint_in message size==0? \n", __func__);
return -ENODEV;
}
+ if (!usb_endpoint_is_int_out(endpoint_out)) {
+ err("%s: Unexpected endpoint_out\n", __func__);
+ return -ENODEV;
+ }
ati_remote = kzalloc(sizeof (struct ati_remote), GFP_KERNEL);
rc_dev = rc_allocate_device(RC_DRIVER_SCANCODE);
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
index 82867a2a60b0..6049e5c95394 100644
--- a/drivers/media/rc/ene_ir.c
+++ b/drivers/media/rc/ene_ir.c
@@ -432,27 +432,27 @@ static void ene_rx_setup(struct ene_device *dev)
select_timeout:
if (dev->rx_fan_input_inuse) {
- dev->rdev->rx_resolution = US_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
+ dev->rdev->rx_resolution = ENE_FW_SAMPLE_PERIOD_FAN;
/* Fan input doesn't support timeouts, it just ends the
input with a maximum sample */
dev->rdev->min_timeout = dev->rdev->max_timeout =
- US_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
- ENE_FW_SAMPLE_PERIOD_FAN);
+ ENE_FW_SMPL_BUF_FAN_MSK *
+ ENE_FW_SAMPLE_PERIOD_FAN;
} else {
- dev->rdev->rx_resolution = US_TO_NS(sample_period);
+ dev->rdev->rx_resolution = sample_period;
/* Theoreticly timeout is unlimited, but we cap it
* because it was seen that on one device, it
* would stop sending spaces after around 250 msec.
* Besides, this is close to 2^32 anyway and timeout is u32.
*/
- dev->rdev->min_timeout = US_TO_NS(127 * sample_period);
- dev->rdev->max_timeout = US_TO_NS(200000);
+ dev->rdev->min_timeout = 127 * sample_period;
+ dev->rdev->max_timeout = 200000;
}
if (dev->hw_learning_and_tx_capable)
- dev->rdev->tx_resolution = US_TO_NS(sample_period);
+ dev->rdev->tx_resolution = sample_period;
if (dev->rdev->timeout > dev->rdev->max_timeout)
dev->rdev->timeout = dev->rdev->max_timeout;
@@ -798,7 +798,7 @@ static irqreturn_t ene_isr(int irq, void *data)
dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
- ev.duration = US_TO_NS(hw_sample);
+ ev.duration = hw_sample;
ev.pulse = pulse;
ir_raw_event_store_with_filter(dev->rdev, &ev);
}
@@ -818,7 +818,7 @@ static void ene_setup_default_settings(struct ene_device *dev)
dev->learning_mode_enabled = learning_mode_force;
/* Set reasonable default timeout */
- dev->rdev->timeout = US_TO_NS(150000);
+ dev->rdev->timeout = MS_TO_US(150);
}
/* Upload all hardware settings at once. Used at load and resume time */
diff --git a/drivers/media/rc/fintek-cir.c b/drivers/media/rc/fintek-cir.c
index 8e3177c5b586..b0d580566e4e 100644
--- a/drivers/media/rc/fintek-cir.c
+++ b/drivers/media/rc/fintek-cir.c
@@ -299,8 +299,8 @@ static void fintek_process_rx_ir_data(struct fintek_dev *fintek)
case PARSE_IRDATA:
fintek->rem--;
rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
- rawir.duration = US_TO_NS((sample & BUF_SAMPLE_MASK)
- * CIR_SAMPLE_PERIOD);
+ rawir.duration = (sample & BUF_SAMPLE_MASK)
+ * CIR_SAMPLE_PERIOD;
fit_dbg("Storing %s with duration %d",
rawir.pulse ? "pulse" : "space",
@@ -524,9 +524,9 @@ static int fintek_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id
rdev->dev.parent = &pdev->dev;
rdev->driver_name = FINTEK_DRIVER_NAME;
rdev->map_name = RC_MAP_RC6_MCE;
- rdev->timeout = US_TO_NS(1000);
+ rdev->timeout = 1000;
/* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
- rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD);
+ rdev->rx_resolution = CIR_SAMPLE_PERIOD;
fintek->rdev = rdev;
diff --git a/drivers/media/rc/gpio-ir-recv.c b/drivers/media/rc/gpio-ir-recv.c
index a20413008c3c..22e524b69806 100644
--- a/drivers/media/rc/gpio-ir-recv.c
+++ b/drivers/media/rc/gpio-ir-recv.c
@@ -11,6 +11,8 @@
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
#include <linux/irq.h>
#include <media/rc-core.h>
@@ -20,17 +22,38 @@ struct gpio_rc_dev {
struct rc_dev *rcdev;
struct gpio_desc *gpiod;
int irq;
+ struct device *pmdev;
+ struct pm_qos_request qos;
};
static irqreturn_t gpio_ir_recv_irq(int irq, void *dev_id)
{
int val;
struct gpio_rc_dev *gpio_dev = dev_id;
+ struct device *pmdev = gpio_dev->pmdev;
+
+ /*
+ * For some cpuidle systems, not all:
+ * Respond to interrupt taking more latency when cpu in idle.
+ * Invoke asynchronous pm runtime get from interrupt context,
+ * this may introduce a millisecond delay to call resume callback,
+ * where to disable cpuilde.
+ *
+ * Two issues lead to fail to decode first frame, one is latency to
+ * respond to interrupt, another is delay introduced by async api.
+ */
+ if (pmdev)
+ pm_runtime_get(pmdev);
val = gpiod_get_value(gpio_dev->gpiod);
if (val >= 0)
ir_raw_event_store_edge(gpio_dev->rcdev, val == 1);
+ if (pmdev) {
+ pm_runtime_mark_last_busy(pmdev);
+ pm_runtime_put_autosuspend(pmdev);
+ }
+
return IRQ_HANDLED;
}
@@ -40,6 +63,7 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
struct device_node *np = dev->of_node;
struct gpio_rc_dev *gpio_dev;
struct rc_dev *rcdev;
+ u32 period = 0;
int rc;
if (!np)
@@ -90,6 +114,15 @@ static int gpio_ir_recv_probe(struct platform_device *pdev)
return rc;
}
+ of_property_read_u32(np, "linux,autosuspend-period", &period);
+ if (period) {
+ gpio_dev->pmdev = dev;
+ pm_runtime_set_autosuspend_delay(dev, period);
+ pm_runtime_use_autosuspend(dev);
+ pm_runtime_set_suspended(dev);
+ pm_runtime_enable(dev);
+ }
+
platform_set_drvdata(pdev, gpio_dev);
return devm_request_irq(dev, gpio_dev->irq, gpio_ir_recv_irq,
@@ -122,9 +155,29 @@ static int gpio_ir_recv_resume(struct device *dev)
return 0;
}
+static int gpio_ir_recv_runtime_suspend(struct device *dev)
+{
+ struct gpio_rc_dev *gpio_dev = dev_get_drvdata(dev);
+
+ cpu_latency_qos_remove_request(&gpio_dev->qos);
+
+ return 0;
+}
+
+static int gpio_ir_recv_runtime_resume(struct device *dev)
+{
+ struct gpio_rc_dev *gpio_dev = dev_get_drvdata(dev);
+
+ cpu_latency_qos_add_request(&gpio_dev->qos, 0);
+
+ return 0;
+}
+
static const struct dev_pm_ops gpio_ir_recv_pm_ops = {
.suspend = gpio_ir_recv_suspend,
.resume = gpio_ir_recv_resume,
+ .runtime_suspend = gpio_ir_recv_runtime_suspend,
+ .runtime_resume = gpio_ir_recv_runtime_resume,
};
#endif
diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c
index b981f7290c1b..effaa5751d6c 100644
--- a/drivers/media/rc/igorplugusb.c
+++ b/drivers/media/rc/igorplugusb.c
@@ -69,7 +69,7 @@ static void igorplugusb_irdata(struct igorplugusb *ir, unsigned len)
overflow);
do {
- rawir.duration = ir->buf_in[i] * 85333;
+ rawir.duration = ir->buf_in[i] * 85;
rawir.pulse = i & 1;
ir_raw_event_store_with_filter(ir->rc, &rawir);
@@ -202,8 +202,8 @@ static int igorplugusb_probe(struct usb_interface *intf,
rc->priv = ir;
rc->driver_name = DRIVER_NAME;
rc->map_name = RC_MAP_HAUPPAUGE;
- rc->timeout = MS_TO_NS(100);
- rc->rx_resolution = 85333;
+ rc->timeout = MS_TO_US(100);
+ rc->rx_resolution = 85;
ir->rc = rc;
ret = rc_register_device(rc);
diff --git a/drivers/media/rc/iguanair.c b/drivers/media/rc/iguanair.c
index 566c2816d5be..84949baf9f6b 100644
--- a/drivers/media/rc/iguanair.c
+++ b/drivers/media/rc/iguanair.c
@@ -59,7 +59,7 @@ struct iguanair {
#define MAX_IN_PACKET 8u
#define MAX_OUT_PACKET (sizeof(struct send_packet) + BUF_SIZE)
#define TIMEOUT 1000
-#define RX_RESOLUTION 21333
+#define RX_RESOLUTION 21
struct packet {
uint16_t start;
@@ -101,7 +101,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
break;
case CMD_TX_OVERFLOW:
ir->tx_overflow = true;
- /* fall through */
+ fallthrough;
case CMD_RECEIVER_OFF:
case CMD_RECEIVER_ON:
case CMD_SEND:
@@ -124,7 +124,7 @@ static void process_ir_data(struct iguanair *ir, unsigned len)
for (i = 0; i < 7; i++) {
if (ir->buf_in[i] == 0x80) {
rawir.pulse = false;
- rawir.duration = US_TO_NS(21845);
+ rawir.duration = 21845;
} else {
rawir.pulse = (ir->buf_in[i] & 0x80) == 0;
rawir.duration = ((ir->buf_in[i] & 0x7f) + 1) *
diff --git a/drivers/media/rc/imon_raw.c b/drivers/media/rc/imon_raw.c
index aae0a3cc9479..d41580f6e4c7 100644
--- a/drivers/media/rc/imon_raw.c
+++ b/drivers/media/rc/imon_raw.c
@@ -8,7 +8,7 @@
#include <media/rc-core.h>
/* Each bit is 250us */
-#define BIT_DURATION 250000
+#define BIT_DURATION 250
struct imon {
struct device *dev;
diff --git a/drivers/media/rc/ir-hix5hd2.c b/drivers/media/rc/ir-hix5hd2.c
index d80cfa455c73..0ffc27514fab 100644
--- a/drivers/media/rc/ir-hix5hd2.c
+++ b/drivers/media/rc/ir-hix5hd2.c
@@ -214,12 +214,12 @@ static irqreturn_t hix5hd2_ir_rx_interrupt(int irq, void *data)
data_h = ((symb_val >> 16) & 0xffff) * 10;
symb_time = (data_l + data_h) / 10;
- ev.duration = US_TO_NS(data_l);
+ ev.duration = data_l;
ev.pulse = true;
ir_raw_event_store(priv->rdev, &ev);
if (symb_time < IR_CFG_SYMBOL_MAXWIDTH) {
- ev.duration = US_TO_NS(data_h);
+ ev.duration = data_h;
ev.pulse = false;
ir_raw_event_store(priv->rdev, &ev);
} else {
@@ -311,8 +311,8 @@ static int hix5hd2_ir_probe(struct platform_device *pdev)
rdev->input_id.vendor = 0x0001;
rdev->input_id.product = 0x0001;
rdev->input_id.version = 0x0100;
- rdev->rx_resolution = US_TO_NS(10);
- rdev->timeout = US_TO_NS(IR_CFG_SYMBOL_MAXWIDTH * 10);
+ rdev->rx_resolution = 10;
+ rdev->timeout = IR_CFG_SYMBOL_MAXWIDTH * 10;
ret = rc_register_device(rdev);
if (ret < 0)
diff --git a/drivers/media/rc/ir-imon-decoder.c b/drivers/media/rc/ir-imon-decoder.c
index a0efe2605393..41dbbef27fa6 100644
--- a/drivers/media/rc/ir-imon-decoder.c
+++ b/drivers/media/rc/ir-imon-decoder.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include "rc-core-priv.h"
-#define IMON_UNIT 415662 /* ns */
+#define IMON_UNIT 416 /* us */
#define IMON_BITS 30
#define IMON_CHKBITS (BIT(30) | BIT(25) | BIT(24) | BIT(22) | \
BIT(21) | BIT(20) | BIT(19) | BIT(18) | \
@@ -102,8 +102,7 @@ static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev)
dev_dbg(&dev->dev,
"iMON decode started at state %d bitno %d (%uus %s)\n",
- data->state, data->count, TO_US(ev.duration),
- TO_STR(ev.pulse));
+ data->state, data->count, ev.duration, TO_STR(ev.pulse));
/*
* Since iMON protocol is a series of bits, if at any point
@@ -116,7 +115,7 @@ static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev)
* we're at a new scancode.
*/
if (data->state == STATE_ERROR) {
- if (!ev.pulse && ev.duration > MS_TO_NS(10))
+ if (!ev.pulse && ev.duration > MS_TO_US(10))
data->state = STATE_INACTIVE;
return 0;
}
@@ -169,8 +168,7 @@ static int ir_imon_decode(struct rc_dev *dev, struct ir_raw_event ev)
err_out:
dev_dbg(&dev->dev,
"iMON decode failed at state %d bitno %d (%uus %s)\n",
- data->state, data->count, TO_US(ev.duration),
- TO_STR(ev.pulse));
+ data->state, data->count, ev.duration, TO_STR(ev.pulse));
data->state = STATE_ERROR;
diff --git a/drivers/media/rc/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 864d9e316c33..470f2e1fd507 100644
--- a/drivers/media/rc/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -9,7 +9,7 @@
#include "rc-core-priv.h"
#define JVC_NBITS 16 /* dev(8) + func(8) */
-#define JVC_UNIT 525000 /* ns */
+#define JVC_UNIT 525 /* us */
#define JVC_HEADER_PULSE (16 * JVC_UNIT) /* lack of header -> repeat */
#define JVC_HEADER_SPACE (8 * JVC_UNIT)
#define JVC_BIT_PULSE (1 * JVC_UNIT)
@@ -49,7 +49,7 @@ static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
goto out;
dev_dbg(&dev->dev, "JVC decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
again:
switch (data->state) {
@@ -157,7 +157,7 @@ again:
out:
dev_dbg(&dev->dev, "JVC decode failed at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-mce_kbd-decoder.c b/drivers/media/rc/ir-mce_kbd-decoder.c
index cfe837f773c1..be8f2756a444 100644
--- a/drivers/media/rc/ir-mce_kbd-decoder.c
+++ b/drivers/media/rc/ir-mce_kbd-decoder.c
@@ -21,7 +21,7 @@
* input device for the remote, rather than the keyboard/mouse one.
*/
-#define MCIR2_UNIT 333333 /* ns */
+#define MCIR2_UNIT 333 /* us */
#define MCIR2_HEADER_NBITS 5
#define MCIR2_MOUSE_NBITS 29
#define MCIR2_KEYBOARD_NBITS 32
@@ -231,7 +231,7 @@ static int ir_mce_kbd_decode(struct rc_dev *dev, struct ir_raw_event ev)
again:
dev_dbg(&dev->dev, "started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
if (!geq_margin(ev.duration, MCIR2_UNIT, MCIR2_UNIT / 2))
return 0;
@@ -344,7 +344,7 @@ again:
}
lsc.scancode = scancode;
- ir_lirc_scancode_event(dev, &lsc);
+ lirc_scancode_event(dev, &lsc);
data->state = STATE_INACTIVE;
input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
input_sync(dev->input_dev);
@@ -353,7 +353,7 @@ again:
out:
dev_dbg(&dev->dev, "failed at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index 6a8973ae3684..b4c3e4baf34d 100644
--- a/drivers/media/rc/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -8,7 +8,7 @@
#include "rc-core-priv.h"
#define NEC_NBITS 32
-#define NEC_UNIT 562500 /* ns */
+#define NEC_UNIT 563 /* us */
#define NEC_HEADER_PULSE (16 * NEC_UNIT)
#define NECX_HEADER_PULSE (8 * NEC_UNIT) /* Less common NEC variant */
#define NEC_HEADER_SPACE (8 * NEC_UNIT)
@@ -50,7 +50,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
dev_dbg(&dev->dev, "NEC decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
switch (data->state) {
@@ -163,7 +163,7 @@ static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
dev_dbg(&dev->dev, "NEC decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->count, data->state, ev.duration, TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 63624654a71e..d58b6226afeb 100644
--- a/drivers/media/rc/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -16,7 +16,7 @@
#define RC5_SZ_NBITS 15
#define RC5X_NBITS 20
#define CHECK_RC5X_NBITS 8
-#define RC5_UNIT 888888 /* ns */
+#define RC5_UNIT 889 /* us */
#define RC5_BIT_START (1 * RC5_UNIT)
#define RC5_BIT_END (1 * RC5_UNIT)
#define RC5X_SPACE (4 * RC5_UNIT)
@@ -55,7 +55,7 @@ static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
again:
dev_dbg(&dev->dev, "RC5(x/sz) decode started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
return 0;
@@ -164,7 +164,7 @@ again:
out:
dev_dbg(&dev->dev, "RC5(x/sz) decode failed at state %i count %d (%uus %s)\n",
- data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, data->count, ev.duration, TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 0cda78f72fd8..0657ad5eef48 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -15,7 +15,7 @@
* RC6-6A-32 (MCE version with toggle bit in body)
*/
-#define RC6_UNIT 444444 /* nanosecs */
+#define RC6_UNIT 444 /* microseconds */
#define RC6_HEADER_NBITS 4 /* not including toggle bit */
#define RC6_0_NBITS 16
#define RC6_6A_32_NBITS 32
@@ -95,7 +95,7 @@ static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
again:
dev_dbg(&dev->dev, "RC6 decode started at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
if (!geq_margin(ev.duration, RC6_UNIT, RC6_UNIT / 2))
return 0;
@@ -270,7 +270,7 @@ again:
out:
dev_dbg(&dev->dev, "RC6 decode failed at state %i (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-rcmm-decoder.c b/drivers/media/rc/ir-rcmm-decoder.c
index 028df5cb1828..fd9ec69a3718 100644
--- a/drivers/media/rc/ir-rcmm-decoder.c
+++ b/drivers/media/rc/ir-rcmm-decoder.c
@@ -6,12 +6,12 @@
#include "rc-core-priv.h"
#include <linux/module.h>
-#define RCMM_UNIT 166667 /* nanosecs */
-#define RCMM_PREFIX_PULSE 416666 /* 166666.666666666*2.5 */
-#define RCMM_PULSE_0 277777 /* 166666.666666666*(1+2/3) */
-#define RCMM_PULSE_1 444444 /* 166666.666666666*(2+2/3) */
-#define RCMM_PULSE_2 611111 /* 166666.666666666*(3+2/3) */
-#define RCMM_PULSE_3 777778 /* 166666.666666666*(4+2/3) */
+#define RCMM_UNIT 166 /* microseconds */
+#define RCMM_PREFIX_PULSE 417 /* 166.666666666666*2.5 */
+#define RCMM_PULSE_0 278 /* 166.666666666666*(1+2/3) */
+#define RCMM_PULSE_1 444 /* 166.666666666666*(2+2/3) */
+#define RCMM_PULSE_2 611 /* 166.666666666666*(3+2/3) */
+#define RCMM_PULSE_3 778 /* 166.666666666666*(4+2/3) */
enum rcmm_state {
STATE_INACTIVE,
@@ -64,8 +64,8 @@ static int ir_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev)
int value;
if (!(dev->enabled_protocols & (RC_PROTO_BIT_RCMM32 |
- RC_PROTO_BIT_RCMM24 |
- RC_PROTO_BIT_RCMM12)))
+ RC_PROTO_BIT_RCMM24 |
+ RC_PROTO_BIT_RCMM12)))
return 0;
if (!is_timing_event(ev)) {
@@ -165,7 +165,7 @@ static int ir_rcmm_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
dev_dbg(&dev->dev, "RC-MM decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->count, data->state, ev.duration, TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-sanyo-decoder.c b/drivers/media/rc/ir-sanyo-decoder.c
index dd6ee1e339d6..bfc181be1044 100644
--- a/drivers/media/rc/ir-sanyo-decoder.c
+++ b/drivers/media/rc/ir-sanyo-decoder.c
@@ -17,7 +17,7 @@
#include "rc-core-priv.h"
#define SANYO_NBITS (13+13+8+8)
-#define SANYO_UNIT 562500 /* ns */
+#define SANYO_UNIT 563 /* us */
#define SANYO_HEADER_PULSE (16 * SANYO_UNIT)
#define SANYO_HEADER_SPACE (8 * SANYO_UNIT)
#define SANYO_BIT_PULSE (1 * SANYO_UNIT)
@@ -59,7 +59,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
dev_dbg(&dev->dev, "SANYO decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
switch (data->state) {
@@ -158,7 +158,7 @@ static int ir_sanyo_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
dev_dbg(&dev->dev, "SANYO decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->count, data->state, ev.duration, TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-sharp-decoder.c b/drivers/media/rc/ir-sharp-decoder.c
index 37fab0919131..d09c38c07dbd 100644
--- a/drivers/media/rc/ir-sharp-decoder.c
+++ b/drivers/media/rc/ir-sharp-decoder.c
@@ -12,7 +12,7 @@
#include "rc-core-priv.h"
#define SHARP_NBITS 15
-#define SHARP_UNIT 40000 /* ns */
+#define SHARP_UNIT 40 /* us */
#define SHARP_BIT_PULSE (8 * SHARP_UNIT) /* 320us */
#define SHARP_BIT_0_PERIOD (25 * SHARP_UNIT) /* 1ms (680us space) */
#define SHARP_BIT_1_PERIOD (50 * SHARP_UNIT) /* 2ms (1680ms space) */
@@ -47,7 +47,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
dev_dbg(&dev->dev, "Sharp decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
switch (data->state) {
@@ -159,7 +159,7 @@ static int ir_sharp_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
dev_dbg(&dev->dev, "Sharp decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->count, data->state, ev.duration, TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index 7d9a7c000c75..d760d52abaa2 100644
--- a/drivers/media/rc/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -8,7 +8,7 @@
#include <linux/module.h>
#include "rc-core-priv.h"
-#define SONY_UNIT 600000 /* ns */
+#define SONY_UNIT 600 /* us */
#define SONY_HEADER_PULSE (4 * SONY_UNIT)
#define SONY_HEADER_SPACE (1 * SONY_UNIT)
#define SONY_BIT_0_PULSE (1 * SONY_UNIT)
@@ -48,7 +48,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
goto out;
dev_dbg(&dev->dev, "Sony decode started at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
switch (data->state) {
@@ -154,7 +154,7 @@ static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
out:
dev_dbg(&dev->dev, "Sony decode failed at state %d (%uus %s)\n",
- data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, ev.duration, TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
diff --git a/drivers/media/rc/ir-xmp-decoder.c b/drivers/media/rc/ir-xmp-decoder.c
index 4c3d03876200..ff94f48bda32 100644
--- a/drivers/media/rc/ir-xmp-decoder.c
+++ b/drivers/media/rc/ir-xmp-decoder.c
@@ -12,11 +12,12 @@
#include <linux/module.h>
#include "rc-core-priv.h"
-#define XMP_UNIT 136000 /* ns */
-#define XMP_LEADER 210000 /* ns */
-#define XMP_NIBBLE_PREFIX 760000 /* ns */
-#define XMP_HALFFRAME_SPACE 13800000 /* ns */
-#define XMP_TRAILER_SPACE 20000000 /* should be 80ms but not all dureation supliers can go that high */
+#define XMP_UNIT 136 /* us */
+#define XMP_LEADER 210 /* us */
+#define XMP_NIBBLE_PREFIX 760 /* us */
+#define XMP_HALFFRAME_SPACE 13800 /* us */
+/* should be 80ms but not all duration supliers can go that high */
+#define XMP_TRAILER_SPACE 20000
enum xmp_state {
STATE_INACTIVE,
@@ -42,7 +43,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
dev_dbg(&dev->dev, "XMP decode started at state %d %d (%uus %s)\n",
- data->state, data->count, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state, data->count, ev.duration, TO_STR(ev.pulse));
switch (data->state) {
@@ -183,7 +184,7 @@ static int ir_xmp_decode(struct rc_dev *dev, struct ir_raw_event ev)
}
dev_dbg(&dev->dev, "XMP decode failed at count %d state %d (%uus %s)\n",
- data->count, data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->count, data->state, ev.duration, TO_STR(ev.pulse));
data->state = STATE_INACTIVE;
return -EINVAL;
}
diff --git a/drivers/media/rc/ir_toy.c b/drivers/media/rc/ir_toy.c
index 5c7a7500a925..e0242c9b6aeb 100644
--- a/drivers/media/rc/ir_toy.c
+++ b/drivers/media/rc/ir_toy.c
@@ -38,8 +38,8 @@ static const u8 COMMAND_TXSTART[] = { 0x26, 0x24, 0x25, 0x03 };
#define LEN_SAMPLEMODEPROTO 3
#define MIN_FW_VERSION 20
-#define UNIT_NS 21333
-#define MAX_TIMEOUT_NS (UNIT_NS * U16_MAX)
+#define UNIT_US 21
+#define MAX_TIMEOUT_US (UNIT_US * U16_MAX)
#define MAX_PACKET 64
@@ -131,7 +131,7 @@ static void irtoy_response(struct irtoy *irtoy, u32 len)
if (v == 0xffff) {
rawir.pulse = false;
} else {
- rawir.duration = v * UNIT_NS;
+ rawir.duration = v * UNIT_US;
ir_raw_event_store_with_timeout(irtoy->rc,
&rawir);
}
@@ -302,7 +302,7 @@ static int irtoy_tx(struct rc_dev *rc, uint *txbuf, uint count)
return -ENOMEM;
for (i = 0; i < count; i++) {
- u16 v = DIV_ROUND_CLOSEST(US_TO_NS(txbuf[i]), UNIT_NS);
+ u16 v = DIV_ROUND_CLOSEST(txbuf[i], UNIT_US);
if (!v)
v = 1;
@@ -438,7 +438,7 @@ static int irtoy_probe(struct usb_interface *intf,
rc->tx_ir = irtoy_tx;
rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
rc->map_name = RC_MAP_RC6_MCE;
- rc->rx_resolution = UNIT_NS;
+ rc->rx_resolution = UNIT_US;
rc->timeout = IR_DEFAULT_TIMEOUT;
/*
@@ -450,8 +450,8 @@ static int irtoy_probe(struct usb_interface *intf,
*
* So, make timeout a largish minimum which works with most protocols.
*/
- rc->min_timeout = MS_TO_NS(40);
- rc->max_timeout = MAX_TIMEOUT_NS;
+ rc->min_timeout = MS_TO_US(40);
+ rc->max_timeout = MAX_TIMEOUT_US;
err = rc_register_device(rc);
if (err)
diff --git a/drivers/media/rc/ite-cir.c b/drivers/media/rc/ite-cir.c
index 07667c04c1d2..a905113fef6e 100644
--- a/drivers/media/rc/ite-cir.c
+++ b/drivers/media/rc/ite-cir.c
@@ -176,14 +176,14 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int
if (next_one > 0) {
ev.pulse = true;
ev.duration =
- ITE_BITS_TO_NS(next_one, sample_period);
+ ITE_BITS_TO_US(next_one, sample_period);
ir_raw_event_store_with_filter(dev->rdev, &ev);
}
while (next_one < size) {
next_zero = find_next_zero_bit_le(ldata, size, next_one + 1);
ev.pulse = false;
- ev.duration = ITE_BITS_TO_NS(next_zero - next_one, sample_period);
+ ev.duration = ITE_BITS_TO_US(next_zero - next_one, sample_period);
ir_raw_event_store_with_filter(dev->rdev, &ev);
if (next_zero < size) {
@@ -193,7 +193,7 @@ static void ite_decode_bytes(struct ite_dev *dev, const u8 * data, int
next_zero + 1);
ev.pulse = true;
ev.duration =
- ITE_BITS_TO_NS(next_one - next_zero,
+ ITE_BITS_TO_US(next_one - next_zero,
sample_period);
ir_raw_event_store_with_filter
(dev->rdev, &ev);
@@ -1555,9 +1555,9 @@ static int ite_probe(struct pnp_dev *pdev, const struct pnp_device_id
rdev->timeout = IR_DEFAULT_TIMEOUT;
rdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
rdev->rx_resolution = ITE_BAUDRATE_DIVISOR *
- itdev->params.sample_period;
+ itdev->params.sample_period / 1000;
rdev->tx_resolution = ITE_BAUDRATE_DIVISOR *
- itdev->params.sample_period;
+ itdev->params.sample_period / 1000;
/* set up transmitter related values if needed */
if (itdev->params.hw_tx_capable) {
diff --git a/drivers/media/rc/ite-cir.h b/drivers/media/rc/ite-cir.h
index f04c4b34ff0c..4954470448a7 100644
--- a/drivers/media/rc/ite-cir.h
+++ b/drivers/media/rc/ite-cir.h
@@ -146,8 +146,8 @@ struct ite_dev {
#define ITE_DEFAULT_CARRIER_FREQ 38000
/* convert bits to us */
-#define ITE_BITS_TO_NS(bits, sample_period) \
-((u32) ((bits) * ITE_BAUDRATE_DIVISOR * sample_period))
+#define ITE_BITS_TO_US(bits, sample_period) \
+((u32)((bits) * ITE_BAUDRATE_DIVISOR * (sample_period) / 1000))
/*
* n in RDCR produces a tolerance of +/- n * 6.25% around the center
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 583e4f32a0da..220363b9a868 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -30,12 +30,12 @@ static DEFINE_IDA(lirc_ida);
static struct class *lirc_class;
/**
- * ir_lirc_raw_event() - Send raw IR data to lirc to be relayed to userspace
+ * lirc_raw_event() - Send raw IR data to lirc to be relayed to userspace
*
* @dev: the struct rc_dev descriptor of the device
* @ev: the struct ir_raw_event descriptor of the pulse/space
*/
-void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
+void lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
{
unsigned long flags;
struct lirc_fh *fh;
@@ -67,17 +67,16 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
dev->gap = true;
dev->gap_duration = ev.duration;
- sample = LIRC_TIMEOUT(ev.duration / 1000);
+ sample = LIRC_TIMEOUT(ev.duration);
dev_dbg(&dev->dev, "timeout report (duration: %d)\n", sample);
/* Normal sample */
} else {
if (dev->gap) {
- dev->gap_duration += ktime_to_ns(ktime_sub(ktime_get(),
+ dev->gap_duration += ktime_to_us(ktime_sub(ktime_get(),
dev->gap_start));
- /* Convert to ms and cap by LIRC_VALUE_MASK */
- do_div(dev->gap_duration, 1000);
+ /* Cap by LIRC_VALUE_MASK */
dev->gap_duration = min_t(u64, dev->gap_duration,
LIRC_VALUE_MASK);
@@ -89,10 +88,10 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
dev->gap = false;
}
- sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
- LIRC_SPACE(ev.duration / 1000);
+ sample = ev.pulse ? LIRC_PULSE(ev.duration) :
+ LIRC_SPACE(ev.duration);
dev_dbg(&dev->dev, "delivering %uus %s to lirc_dev\n",
- TO_US(ev.duration), TO_STR(ev.pulse));
+ ev.duration, TO_STR(ev.pulse));
}
/*
@@ -112,12 +111,12 @@ void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev)
}
/**
- * ir_lirc_scancode_event() - Send scancode data to lirc to be relayed to
+ * lirc_scancode_event() - Send scancode data to lirc to be relayed to
* userspace. This can be called in atomic context.
* @dev: the struct rc_dev descriptor of the device
* @lsc: the struct lirc_scancode describing the decoded scancode
*/
-void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc)
+void lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc)
{
unsigned long flags;
struct lirc_fh *fh;
@@ -131,9 +130,9 @@ void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc)
}
spin_unlock_irqrestore(&dev->lirc_fh_lock, flags);
}
-EXPORT_SYMBOL_GPL(ir_lirc_scancode_event);
+EXPORT_SYMBOL_GPL(lirc_scancode_event);
-static int ir_lirc_open(struct inode *inode, struct file *file)
+static int lirc_open(struct inode *inode, struct file *file)
{
struct rc_dev *dev = container_of(inode->i_cdev, struct rc_dev,
lirc_cdev);
@@ -201,7 +200,7 @@ out_fh:
return retval;
}
-static int ir_lirc_close(struct inode *inode, struct file *file)
+static int lirc_close(struct inode *inode, struct file *file)
{
struct lirc_fh *fh = file->private_data;
struct rc_dev *dev = fh->rc;
@@ -223,8 +222,8 @@ static int ir_lirc_close(struct inode *inode, struct file *file)
return 0;
}
-static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
- size_t n, loff_t *ppos)
+static ssize_t lirc_transmit(struct file *file, const char __user *buf,
+ size_t n, loff_t *ppos)
{
struct lirc_fh *fh = file->private_data;
struct rc_dev *dev = fh->rc;
@@ -296,8 +295,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
}
for (i = 0; i < count; i++)
- /* Convert from NS to US */
- txbuf[i] = DIV_ROUND_UP(raw[i].duration, 1000);
+ txbuf[i] = raw[i].duration;
if (dev->s_tx_carrier) {
int carrier = ir_raw_encode_carrier(scan.rc_proto);
@@ -325,7 +323,7 @@ static ssize_t ir_lirc_transmit_ir(struct file *file, const char __user *buf,
}
for (i = 0; i < count; i++) {
- if (txbuf[i] > IR_MAX_DURATION / 1000 - duration || !txbuf[i]) {
+ if (txbuf[i] > IR_MAX_DURATION - duration || !txbuf[i]) {
ret = -EINVAL;
goto out_kfree;
}
@@ -365,8 +363,7 @@ out_unlock:
return ret;
}
-static long ir_lirc_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
+static long lirc_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct lirc_fh *fh = file->private_data;
struct rc_dev *dev = fh->rc;
@@ -517,7 +514,7 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd,
if (!dev->rx_resolution)
ret = -ENOTTY;
else
- val = dev->rx_resolution / 1000;
+ val = dev->rx_resolution;
break;
case LIRC_SET_WIDEBAND_RECEIVER:
@@ -539,31 +536,26 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd,
if (!dev->max_timeout)
ret = -ENOTTY;
else
- val = DIV_ROUND_UP(dev->min_timeout, 1000);
+ val = dev->min_timeout;
break;
case LIRC_GET_MAX_TIMEOUT:
if (!dev->max_timeout)
ret = -ENOTTY;
else
- val = dev->max_timeout / 1000;
+ val = dev->max_timeout;
break;
case LIRC_SET_REC_TIMEOUT:
if (!dev->max_timeout) {
ret = -ENOTTY;
- } else if (val > U32_MAX / 1000) {
- /* Check for multiply overflow */
- ret = -EINVAL;
} else {
- u32 tmp = val * 1000;
-
- if (tmp < dev->min_timeout || tmp > dev->max_timeout)
+ if (val < dev->min_timeout || val > dev->max_timeout)
ret = -EINVAL;
else if (dev->s_timeout)
- ret = dev->s_timeout(dev, tmp);
+ ret = dev->s_timeout(dev, val);
else
- dev->timeout = tmp;
+ dev->timeout = val;
}
break;
@@ -571,7 +563,7 @@ static long ir_lirc_ioctl(struct file *file, unsigned int cmd,
if (!dev->timeout)
ret = -ENOTTY;
else
- val = DIV_ROUND_UP(dev->timeout, 1000);
+ val = dev->timeout;
break;
case LIRC_SET_REC_TIMEOUT_REPORTS:
@@ -593,7 +585,7 @@ out:
return ret;
}
-static __poll_t ir_lirc_poll(struct file *file, struct poll_table_struct *wait)
+static __poll_t lirc_poll(struct file *file, struct poll_table_struct *wait)
{
struct lirc_fh *fh = file->private_data;
struct rc_dev *rcdev = fh->rc;
@@ -616,8 +608,8 @@ static __poll_t ir_lirc_poll(struct file *file, struct poll_table_struct *wait)
return events;
}
-static ssize_t ir_lirc_read_mode2(struct file *file, char __user *buffer,
- size_t length)
+static ssize_t lirc_read_mode2(struct file *file, char __user *buffer,
+ size_t length)
{
struct lirc_fh *fh = file->private_data;
struct rc_dev *rcdev = fh->rc;
@@ -654,8 +646,8 @@ static ssize_t ir_lirc_read_mode2(struct file *file, char __user *buffer,
return copied;
}
-static ssize_t ir_lirc_read_scancode(struct file *file, char __user *buffer,
- size_t length)
+static ssize_t lirc_read_scancode(struct file *file, char __user *buffer,
+ size_t length)
{
struct lirc_fh *fh = file->private_data;
struct rc_dev *rcdev = fh->rc;
@@ -693,8 +685,8 @@ static ssize_t ir_lirc_read_scancode(struct file *file, char __user *buffer,
return copied;
}
-static ssize_t ir_lirc_read(struct file *file, char __user *buffer,
- size_t length, loff_t *ppos)
+static ssize_t lirc_read(struct file *file, char __user *buffer, size_t length,
+ loff_t *ppos)
{
struct lirc_fh *fh = file->private_data;
struct rc_dev *rcdev = fh->rc;
@@ -706,20 +698,20 @@ static ssize_t ir_lirc_read(struct file *file, char __user *buffer,
return -ENODEV;
if (fh->rec_mode == LIRC_MODE_MODE2)
- return ir_lirc_read_mode2(file, buffer, length);
+ return lirc_read_mode2(file, buffer, length);
else /* LIRC_MODE_SCANCODE */
- return ir_lirc_read_scancode(file, buffer, length);
+ return lirc_read_scancode(file, buffer, length);
}
static const struct file_operations lirc_fops = {
.owner = THIS_MODULE,
- .write = ir_lirc_transmit_ir,
- .unlocked_ioctl = ir_lirc_ioctl,
+ .write = lirc_transmit,
+ .unlocked_ioctl = lirc_ioctl,
.compat_ioctl = compat_ptr_ioctl,
- .read = ir_lirc_read,
- .poll = ir_lirc_poll,
- .open = ir_lirc_open,
- .release = ir_lirc_close,
+ .read = lirc_read,
+ .poll = lirc_poll,
+ .open = lirc_open,
+ .release = lirc_close,
.llseek = no_llseek,
};
@@ -730,7 +722,7 @@ static void lirc_release_device(struct device *ld)
put_device(&rcdev->dev);
}
-int ir_lirc_register(struct rc_dev *dev)
+int lirc_register(struct rc_dev *dev)
{
const char *rx_type, *tx_type;
int err, minor;
@@ -784,7 +776,7 @@ out_ida:
return err;
}
-void ir_lirc_unregister(struct rc_dev *dev)
+void lirc_unregister(struct rc_dev *dev)
{
unsigned long flags;
struct lirc_fh *fh;
@@ -811,8 +803,7 @@ int __init lirc_dev_init(void)
return PTR_ERR(lirc_class);
}
- retval = alloc_chrdev_region(&lirc_base_dev, 0, RC_DEV_MAX,
- "BaseRemoteCtl");
+ retval = alloc_chrdev_region(&lirc_base_dev, 0, RC_DEV_MAX, "lirc");
if (retval) {
class_destroy(lirc_class);
pr_err("alloc_chrdev_region failed\n");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
index 98681ba10428..f1dbd059ed08 100644
--- a/drivers/media/rc/mceusb.c
+++ b/drivers/media/rc/mceusb.c
@@ -1070,7 +1070,7 @@ static int mceusb_set_timeout(struct rc_dev *dev, unsigned int timeout)
struct mceusb_dev *ir = dev->priv;
unsigned int units;
- units = DIV_ROUND_CLOSEST(timeout, US_TO_NS(MCE_TIME_UNIT));
+ units = DIV_ROUND_CLOSEST(timeout, MCE_TIME_UNIT);
cmdbuf[2] = units >> 8;
cmdbuf[3] = units;
@@ -1196,7 +1196,7 @@ static void mceusb_handle_command(struct mceusb_dev *ir, u8 *buf_in)
switch (subcmd) {
/* 2-byte return value commands */
case MCE_RSP_EQIRTIMEOUT:
- ir->rc->timeout = US_TO_NS((*hi << 8 | *lo) * MCE_TIME_UNIT);
+ ir->rc->timeout = (*hi << 8 | *lo) * MCE_TIME_UNIT;
break;
case MCE_RSP_EQIRNUMPORTS:
ir->num_txports = *hi;
@@ -1291,9 +1291,9 @@ static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
ir->pulse_tunit += rawir.duration;
ir->pulse_count++;
}
- rawir.duration *= US_TO_NS(MCE_TIME_UNIT);
+ rawir.duration *= MCE_TIME_UNIT;
- dev_dbg(ir->dev, "Storing %s %u ns (%02x)",
+ dev_dbg(ir->dev, "Storing %s %u us (%02x)",
rawir.pulse ? "pulse" : "space",
rawir.duration, ir->buf_in[i]);
@@ -1605,8 +1605,8 @@ static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
rc->dev.parent = dev;
rc->priv = ir;
rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
- rc->min_timeout = US_TO_NS(MCE_TIME_UNIT);
- rc->timeout = MS_TO_NS(100);
+ rc->min_timeout = MCE_TIME_UNIT;
+ rc->timeout = MS_TO_US(100);
if (!mceusb_model[ir->model].broken_irtimeout) {
rc->s_timeout = mceusb_set_timeout;
rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
index 51c6dd3406a0..dad55950dfc6 100644
--- a/drivers/media/rc/meson-ir.c
+++ b/drivers/media/rc/meson-ir.c
@@ -86,7 +86,7 @@ static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
duration = readl_relaxed(ir->reg + IR_DEC_REG1);
duration = FIELD_GET(REG1_TIME_IV_MASK, duration);
- rawir.duration = US_TO_NS(duration * MESON_TRATE);
+ rawir.duration = duration * MESON_TRATE;
status = readl_relaxed(ir->reg + IR_DEC_STATUS);
rawir.pulse = !!(status & STATUS_IR_DEC_IN);
@@ -133,7 +133,7 @@ static int meson_ir_probe(struct platform_device *pdev)
map_name = of_get_property(node, "linux,rc-map-name", NULL);
ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY;
ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
- ir->rc->rx_resolution = US_TO_NS(MESON_TRATE);
+ ir->rc->rx_resolution = MESON_TRATE;
ir->rc->min_timeout = 1;
ir->rc->timeout = IR_DEFAULT_TIMEOUT;
ir->rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
diff --git a/drivers/media/rc/mtk-cir.c b/drivers/media/rc/mtk-cir.c
index a0c94ab322c7..5051a5e5244b 100644
--- a/drivers/media/rc/mtk-cir.c
+++ b/drivers/media/rc/mtk-cir.c
@@ -52,8 +52,8 @@
#define MTK_IR_END(v, p) ((v) == MTK_MAX_SAMPLES && (p) == 0)
/* Number of registers to record the pulse width */
#define MTK_CHKDATA_SZ 17
-/* Sample period in ns */
-#define MTK_IR_SAMPLE 46000
+/* Sample period in us */
+#define MTK_IR_SAMPLE 46
enum mtk_fields {
/* Register to setting software sampling period */
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
index 52d246dc5b3d..8a37f083fe3d 100644
--- a/drivers/media/rc/nuvoton-cir.c
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -653,8 +653,7 @@ static int nvt_ir_raw_set_wakeup_filter(struct rc_dev *dev,
/* Inspect the ir samples */
for (i = 0, count = 0; i < ret && count < WAKEUP_MAX_SIZE; ++i) {
- /* NS to US */
- val = DIV_ROUND_UP(raw[i].duration, 1000L) / SAMPLE_PERIOD;
+ val = raw[i].duration / SAMPLE_PERIOD;
/* Split too large values into several smaller ones */
while (val > 0 && count < WAKEUP_MAX_SIZE) {
@@ -721,8 +720,7 @@ static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
sample = nvt->buf[i];
rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
- rawir.duration = US_TO_NS((sample & BUF_LEN_MASK)
- * SAMPLE_PERIOD);
+ rawir.duration = (sample & BUF_LEN_MASK) * SAMPLE_PERIOD;
nvt_dbg("Storing %s with duration %d",
rawir.pulse ? "pulse" : "space", rawir.duration);
@@ -1000,9 +998,9 @@ static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
rdev->input_id.version = nvt->chip_minor;
rdev->driver_name = NVT_DRIVER_NAME;
rdev->map_name = RC_MAP_RC6_MCE;
- rdev->timeout = MS_TO_NS(100);
+ rdev->timeout = MS_TO_US(100);
/* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
- rdev->rx_resolution = US_TO_NS(CIR_SAMPLE_PERIOD);
+ rdev->rx_resolution = CIR_SAMPLE_PERIOD;
#if 0
rdev->min_timeout = XYZ;
rdev->max_timeout = XYZ;
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
index 0cf301d1e163..ed7d93beaa28 100644
--- a/drivers/media/rc/nuvoton-cir.h
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -94,7 +94,7 @@ struct nvt_dev {
#define CIR_IOREG_LENGTH 0x0f
/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL */
-#define CIR_RX_LIMIT_COUNT (IR_DEFAULT_TIMEOUT / US_TO_NS(SAMPLE_PERIOD))
+#define CIR_RX_LIMIT_COUNT (IR_DEFAULT_TIMEOUT / SAMPLE_PERIOD)
/* CIR Regs */
#define CIR_IRCON 0x00
diff --git a/drivers/media/rc/rc-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 1eeab277a08e..62f032dffd33 100644
--- a/drivers/media/rc/rc-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -193,7 +193,6 @@ static inline bool is_timing_event(struct ir_raw_event ev)
return !ev.carrier_report && !ev.reset;
}
-#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000)
#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
/* functions for IR encoders */
@@ -322,20 +321,20 @@ void ir_raw_init(void);
#ifdef CONFIG_LIRC
int lirc_dev_init(void);
void lirc_dev_exit(void);
-void ir_lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev);
-void ir_lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc);
-int ir_lirc_register(struct rc_dev *dev);
-void ir_lirc_unregister(struct rc_dev *dev);
+void lirc_raw_event(struct rc_dev *dev, struct ir_raw_event ev);
+void lirc_scancode_event(struct rc_dev *dev, struct lirc_scancode *lsc);
+int lirc_register(struct rc_dev *dev);
+void lirc_unregister(struct rc_dev *dev);
struct rc_dev *rc_dev_get_from_fd(int fd);
#else
static inline int lirc_dev_init(void) { return 0; }
static inline void lirc_dev_exit(void) {}
-static inline void ir_lirc_raw_event(struct rc_dev *dev,
- struct ir_raw_event ev) { }
-static inline void ir_lirc_scancode_event(struct rc_dev *dev,
- struct lirc_scancode *lsc) { }
-static inline int ir_lirc_register(struct rc_dev *dev) { return 0; }
-static inline void ir_lirc_unregister(struct rc_dev *dev) { }
+static inline void lirc_raw_event(struct rc_dev *dev,
+ struct ir_raw_event ev) { }
+static inline void lirc_scancode_event(struct rc_dev *dev,
+ struct lirc_scancode *lsc) { }
+static inline int lirc_register(struct rc_dev *dev) { return 0; }
+static inline void lirc_unregister(struct rc_dev *dev) { }
#endif
/*
diff --git a/drivers/media/rc/rc-ir-raw.c b/drivers/media/rc/rc-ir-raw.c
index 39dd46bbd0c1..c65bba4ec473 100644
--- a/drivers/media/rc/rc-ir-raw.c
+++ b/drivers/media/rc/rc-ir-raw.c
@@ -42,7 +42,7 @@ static int ir_raw_event_thread(void *data)
if (dev->enabled_protocols &
handler->protocols || !handler->protocols)
handler->decode(dev, ev);
- ir_lirc_raw_event(dev, ev);
+ lirc_raw_event(dev, ev);
raw->prev_ev = ev;
}
mutex_unlock(&ir_raw_handler_lock);
@@ -77,7 +77,7 @@ int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
return -EINVAL;
dev_dbg(&dev->dev, "sample: (%05dus %s)\n",
- TO_US(ev->duration), TO_STR(ev->pulse));
+ ev->duration, TO_STR(ev->pulse));
if (!kfifo_put(&dev->raw->kfifo, *ev)) {
dev_err(&dev->dev, "IR event FIFO is full!\n");
@@ -108,7 +108,7 @@ int ir_raw_event_store_edge(struct rc_dev *dev, bool pulse)
return -EINVAL;
now = ktime_get();
- ev.duration = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
+ ev.duration = ktime_to_us(ktime_sub(now, dev->raw->last_event));
ev.pulse = !pulse;
return ir_raw_event_store_with_timeout(dev, &ev);
@@ -275,7 +275,7 @@ static int change_protocol(struct rc_dev *dev, u64 *rc_proto)
if (timeout == 0)
timeout = IR_DEFAULT_TIMEOUT;
else
- timeout += MS_TO_NS(10);
+ timeout += MS_TO_US(10);
if (timeout < dev->min_timeout)
timeout = dev->min_timeout;
@@ -561,17 +561,17 @@ static void ir_raw_edge_handle(struct timer_list *t)
spin_lock_irqsave(&dev->raw->edge_spinlock, flags);
interval = ktime_sub(ktime_get(), dev->raw->last_event);
- if (ktime_to_ns(interval) >= dev->timeout) {
+ if (ktime_to_us(interval) >= dev->timeout) {
struct ir_raw_event ev = {
.timeout = true,
- .duration = ktime_to_ns(interval)
+ .duration = ktime_to_us(interval)
};
ir_raw_event_store(dev, &ev);
} else {
mod_timer(&dev->raw->edge_handle,
- jiffies + nsecs_to_jiffies(dev->timeout -
- ktime_to_ns(interval)));
+ jiffies + usecs_to_jiffies(dev->timeout -
+ ktime_to_us(interval)));
}
spin_unlock_irqrestore(&dev->raw->edge_spinlock, flags);
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
index ef8b83b707df..1ba3f96ffa7d 100644
--- a/drivers/media/rc/rc-loopback.c
+++ b/drivers/media/rc/rc-loopback.c
@@ -113,7 +113,7 @@ static int loop_tx_ir(struct rc_dev *dev, unsigned *txbuf, unsigned count)
for (i = 0; i < count; i++) {
rawir.pulse = i % 2 ? false : true;
- rawir.duration = txbuf[i] * 1000;
+ rawir.duration = txbuf[i];
if (rawir.duration)
ir_raw_event_store_with_filter(dev, &rawir);
}
@@ -219,11 +219,11 @@ static int __init loop_init(void)
rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
rc->allowed_wakeup_protocols = RC_PROTO_BIT_ALL_IR_ENCODER;
rc->encode_wakeup = true;
- rc->timeout = 100 * 1000 * 1000; /* 100 ms */
+ rc->timeout = MS_TO_US(100); /* 100 ms */
rc->min_timeout = 1;
rc->max_timeout = UINT_MAX;
- rc->rx_resolution = 1000;
- rc->tx_resolution = 1000;
+ rc->rx_resolution = 1;
+ rc->tx_resolution = 1;
rc->s_tx_mask = loop_set_tx_mask;
rc->s_tx_carrier = loop_set_tx_carrier;
rc->s_tx_duty_cycle = loop_set_tx_duty_cycle;
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index dee8a9f3d80a..1d811e5ffb55 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -747,7 +747,7 @@ void rc_repeat(struct rc_dev *dev)
};
if (dev->allowed_protocols != RC_PROTO_BIT_CEC)
- ir_lirc_scancode_event(dev, &sc);
+ lirc_scancode_event(dev, &sc);
spin_lock_irqsave(&dev->keylock, flags);
@@ -791,7 +791,7 @@ static void ir_do_keydown(struct rc_dev *dev, enum rc_proto protocol,
};
if (dev->allowed_protocols != RC_PROTO_BIT_CEC)
- ir_lirc_scancode_event(dev, &sc);
+ lirc_scancode_event(dev, &sc);
if (new_event && dev->keypressed)
ir_do_keyup(dev, false);
@@ -1946,7 +1946,7 @@ int rc_register_device(struct rc_dev *dev)
* keycodes with rc_keydown, so lirc must be registered first.
*/
if (dev->allowed_protocols != RC_PROTO_BIT_CEC) {
- rc = ir_lirc_register(dev);
+ rc = lirc_register(dev);
if (rc < 0)
goto out_dev;
}
@@ -1972,7 +1972,7 @@ out_rx:
rc_free_rx_device(dev);
out_lirc:
if (dev->allowed_protocols != RC_PROTO_BIT_CEC)
- ir_lirc_unregister(dev);
+ lirc_unregister(dev);
out_dev:
device_del(&dev->dev);
out_rx_free:
@@ -2036,7 +2036,7 @@ void rc_unregister_device(struct rc_dev *dev)
* that userspace polling will get notified.
*/
if (dev->allowed_protocols != RC_PROTO_BIT_CEC)
- ir_lirc_unregister(dev);
+ lirc_unregister(dev);
device_del(&dev->dev);
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index aad9526f3754..2cf3377ec63a 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -340,7 +340,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
{
struct ir_raw_event rawir = {};
struct device *dev;
- unsigned int i, sig_size, single_len, offset, val;
+ unsigned int i, sig_size, offset, val;
u32 mod_freq;
dev = rr3->dev;
@@ -361,7 +361,6 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
for (i = 0; i < sig_size; i++) {
offset = rr3->irdata.sigdata[i];
val = get_unaligned_be16(&rr3->irdata.lens[offset]);
- single_len = redrat3_len_to_us(val);
/* we should always get pulse/space/pulse/space samples */
if (i % 2)
@@ -369,7 +368,7 @@ static void redrat3_process_ir_data(struct redrat3_dev *rr3)
else
rawir.pulse = true;
- rawir.duration = US_TO_NS(single_len);
+ rawir.duration = redrat3_len_to_us(val);
/* cap the value to IR_MAX_DURATION */
rawir.duration = (rawir.duration > IR_MAX_DURATION) ?
IR_MAX_DURATION : rawir.duration;
@@ -495,7 +494,7 @@ static u32 redrat3_get_timeout(struct redrat3_dev *rr3)
return timeout;
}
-static int redrat3_set_timeout(struct rc_dev *rc_dev, unsigned int timeoutns)
+static int redrat3_set_timeout(struct rc_dev *rc_dev, unsigned int timeoutus)
{
struct redrat3_dev *rr3 = rc_dev->priv;
struct usb_device *udev = rr3->udev;
@@ -507,7 +506,7 @@ static int redrat3_set_timeout(struct rc_dev *rc_dev, unsigned int timeoutns)
if (!timeout)
return -ENOMEM;
- *timeout = cpu_to_be32(redrat3_us_to_len(timeoutns / 1000));
+ *timeout = cpu_to_be32(redrat3_us_to_len(timeoutus));
ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), RR3_SET_IR_PARAM,
USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
RR3_IR_IO_SIG_TIMEOUT, 0, timeout, sizeof(*timeout),
@@ -947,15 +946,15 @@ static struct rc_dev *redrat3_init_rc_dev(struct redrat3_dev *rr3)
rc->dev.parent = dev;
rc->priv = rr3;
rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
- rc->min_timeout = MS_TO_NS(RR3_RX_MIN_TIMEOUT);
- rc->max_timeout = MS_TO_NS(RR3_RX_MAX_TIMEOUT);
- rc->timeout = US_TO_NS(redrat3_get_timeout(rr3));
+ rc->min_timeout = MS_TO_US(RR3_RX_MIN_TIMEOUT);
+ rc->max_timeout = MS_TO_US(RR3_RX_MAX_TIMEOUT);
+ rc->timeout = redrat3_get_timeout(rr3);
rc->s_timeout = redrat3_set_timeout;
rc->tx_ir = redrat3_transmit_ir;
rc->s_tx_carrier = redrat3_set_tx_carrier;
rc->s_carrier_report = redrat3_wideband_receiver;
rc->driver_name = DRIVER_NAME;
- rc->rx_resolution = US_TO_NS(2);
+ rc->rx_resolution = 2;
rc->map_name = RC_MAP_HAUPPAUGE;
ret = rc_register_device(rc);
diff --git a/drivers/media/rc/serial_ir.c b/drivers/media/rc/serial_ir.c
index d77507ba0fb5..8cc28c92d05d 100644
--- a/drivers/media/rc/serial_ir.c
+++ b/drivers/media/rc/serial_ir.c
@@ -269,7 +269,7 @@ static void frbwrite(unsigned int l, bool is_pulse)
if (ptr > 0 && is_pulse) {
pulse += l;
- if (pulse > 250000) {
+ if (pulse > 250) {
ev.duration = space;
ev.pulse = false;
ir_raw_event_store_with_filter(serial_ir.rcdev, &ev);
@@ -283,13 +283,13 @@ static void frbwrite(unsigned int l, bool is_pulse)
}
if (!is_pulse) {
if (ptr == 0) {
- if (l > 20000000) {
+ if (l > 20000) {
space = l;
ptr++;
return;
}
} else {
- if (l > 20000000) {
+ if (l > 20000) {
space += pulse;
if (space > IR_MAX_DURATION)
space = IR_MAX_DURATION;
@@ -376,7 +376,7 @@ static irqreturn_t serial_ir_irq_handler(int i, void *blah)
sense = sense ? 0 : 1;
}
} else {
- data = ktime_to_ns(delkt);
+ data = ktime_to_us(delkt);
}
frbwrite(data, !(dcd ^ sense));
serial_ir.lastkt = kt;
@@ -528,7 +528,7 @@ static int serial_ir_probe(struct platform_device *dev)
rcdev->min_timeout = 1;
rcdev->timeout = IR_DEFAULT_TIMEOUT;
rcdev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
- rcdev->rx_resolution = 250000;
+ rcdev->rx_resolution = 250;
serial_ir.rcdev = rcdev;
@@ -547,7 +547,7 @@ static int serial_ir_probe(struct platform_device *dev)
/* Reserve io region. */
if ((iommap &&
- (devm_request_mem_region(&dev->dev, iommap, 8 << ioshift,
+ (devm_request_mem_region(&dev->dev, iommap, 8UL << ioshift,
KBUILD_MODNAME) == NULL)) ||
(!iommap && (devm_request_region(&dev->dev, io, 8,
KBUILD_MODNAME) == NULL))) {
diff --git a/drivers/media/rc/sir_ir.c b/drivers/media/rc/sir_ir.c
index 80b3a6736dbd..6ec96dc34586 100644
--- a/drivers/media/rc/sir_ir.c
+++ b/drivers/media/rc/sir_ir.c
@@ -110,7 +110,7 @@ static void add_read_queue(int flag, unsigned long val)
} else {
val += TIME_CONST / 2;
}
- ev.duration = US_TO_NS(val);
+ ev.duration = val;
ir_raw_event_store_with_filter(rcdev, &ev);
}
diff --git a/drivers/media/rc/st_rc.c b/drivers/media/rc/st_rc.c
index 1dc4e2e33705..3237fef5d502 100644
--- a/drivers/media/rc/st_rc.c
+++ b/drivers/media/rc/st_rc.c
@@ -134,12 +134,12 @@ static irqreturn_t st_rc_rx_interrupt(int irq, void *data)
mark /= dev->sample_div;
}
- ev.duration = US_TO_NS(mark);
+ ev.duration = mark;
ev.pulse = true;
ir_raw_event_store(dev->rdev, &ev);
if (!last_symbol) {
- ev.duration = US_TO_NS(symbol);
+ ev.duration = symbol;
ev.pulse = false;
ir_raw_event_store(dev->rdev, &ev);
} else {
@@ -292,7 +292,7 @@ static int st_rc_probe(struct platform_device *pdev)
rdev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
/* rx sampling rate is 10Mhz */
rdev->rx_resolution = 100;
- rdev->timeout = US_TO_NS(MAX_SYMB_TIME);
+ rdev->timeout = MAX_SYMB_TIME;
rdev->priv = rc_dev;
rdev->open = st_rc_open;
rdev->close = st_rc_close;
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
index 79a41fc7161c..9f3cd9fb6b6e 100644
--- a/drivers/media/rc/streamzap.c
+++ b/drivers/media/rc/streamzap.c
@@ -137,7 +137,6 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
} else {
rawir.duration = delta;
rawir.duration -= sz->sum;
- rawir.duration = US_TO_NS(rawir.duration);
rawir.duration = (rawir.duration > IR_MAX_DURATION) ?
IR_MAX_DURATION : rawir.duration;
}
@@ -151,7 +150,6 @@ static void sz_push_full_pulse(struct streamzap_ir *sz,
rawir.duration = ((int) value) * SZ_RESOLUTION;
rawir.duration += SZ_RESOLUTION / 2;
sz->sum += rawir.duration;
- rawir.duration = US_TO_NS(rawir.duration);
rawir.duration = (rawir.duration > IR_MAX_DURATION) ?
IR_MAX_DURATION : rawir.duration;
sz_push(sz, rawir);
@@ -172,7 +170,6 @@ static void sz_push_full_space(struct streamzap_ir *sz,
rawir.duration = ((int) value) * SZ_RESOLUTION;
rawir.duration += SZ_RESOLUTION / 2;
sz->sum += rawir.duration;
- rawir.duration = US_TO_NS(rawir.duration);
sz_push(sz, rawir);
}
@@ -403,13 +400,12 @@ static int streamzap_probe(struct usb_interface *intf,
sz->decoder_state = PulseSpace;
/* FIXME: don't yet have a way to set this */
sz->timeout_enabled = true;
- sz->rdev->timeout = ((US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION) &
- IR_MAX_DURATION) | 0x03000000);
+ sz->rdev->timeout = SZ_TIMEOUT * SZ_RESOLUTION;
#if 0
/* not yet supported, depends on patches from maxim */
/* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
- sz->min_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION);
- sz->max_timeout = US_TO_NS(SZ_TIMEOUT * SZ_RESOLUTION);
+ sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION;
+ sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION;
#endif
sz->signal_start = ktime_get_real();
diff --git a/drivers/media/rc/sunxi-cir.c b/drivers/media/rc/sunxi-cir.c
index e222b4c98be4..ddee6ee37bab 100644
--- a/drivers/media/rc/sunxi-cir.c
+++ b/drivers/media/rc/sunxi-cir.c
@@ -241,8 +241,8 @@ static int sunxi_ir_probe(struct platform_device *pdev)
ir->rc->dev.parent = dev;
ir->rc->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
/* Frequency after IR internal divider with sample period in ns */
- ir->rc->rx_resolution = (1000000000ul / (b_clk_freq / 64));
- ir->rc->timeout = MS_TO_NS(SUNXI_IR_TIMEOUT);
+ ir->rc->rx_resolution = (USEC_PER_SEC / (b_clk_freq / 64));
+ ir->rc->timeout = MS_TO_US(SUNXI_IR_TIMEOUT);
ir->rc->driver_name = SUNXI_IR_DEV;
ret = rc_register_device(ir->rc);
diff --git a/drivers/media/rc/ttusbir.c b/drivers/media/rc/ttusbir.c
index 011a8b620d86..629787d53ee1 100644
--- a/drivers/media/rc/ttusbir.c
+++ b/drivers/media/rc/ttusbir.c
@@ -20,8 +20,8 @@
* messages per second (!), whether IR is idle or not.
*/
#define NUM_URBS 4
-#define NS_PER_BYTE 62500
-#define NS_PER_BIT (NS_PER_BYTE/8)
+#define US_PER_BYTE 62
+#define US_PER_BIT (US_PER_BYTE / 8)
struct ttusbir {
struct rc_dev *rc;
@@ -117,13 +117,13 @@ static void ttusbir_process_ir_data(struct ttusbir *tt, uint8_t *buf)
switch (v) {
case 0xfe:
rawir.pulse = false;
- rawir.duration = NS_PER_BYTE;
+ rawir.duration = US_PER_BYTE;
if (ir_raw_event_store_with_filter(tt->rc, &rawir))
event = true;
break;
case 0:
rawir.pulse = true;
- rawir.duration = NS_PER_BYTE;
+ rawir.duration = US_PER_BYTE;
if (ir_raw_event_store_with_filter(tt->rc, &rawir))
event = true;
break;
@@ -137,12 +137,12 @@ static void ttusbir_process_ir_data(struct ttusbir *tt, uint8_t *buf)
rawir.pulse = false;
}
- rawir.duration = NS_PER_BIT * (8 - b);
+ rawir.duration = US_PER_BIT * (8 - b);
if (ir_raw_event_store_with_filter(tt->rc, &rawir))
event = true;
rawir.pulse = !rawir.pulse;
- rawir.duration = NS_PER_BIT * b;
+ rawir.duration = US_PER_BIT * b;
if (ir_raw_event_store_with_filter(tt->rc, &rawir))
event = true;
break;
@@ -311,10 +311,10 @@ static int ttusbir_probe(struct usb_interface *intf,
rc->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
/*
- * The precision is NS_PER_BIT, but since every 8th bit can be
- * overwritten with garbage the accuracy is at best 2 * NS_PER_BIT.
+ * The precision is US_PER_BIT, but since every 8th bit can be
+ * overwritten with garbage the accuracy is at best 2 * US_PER_BIT.
*/
- rc->rx_resolution = NS_PER_BIT;
+ rc->rx_resolution = 2 * US_PER_BIT;
ret = rc_register_device(rc);
if (ret) {
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
index 630e376d3688..aed23ca0fa6c 100644
--- a/drivers/media/rc/winbond-cir.c
+++ b/drivers/media/rc/winbond-cir.c
@@ -354,7 +354,6 @@ wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
{
u8 irdata;
struct ir_raw_event rawir = {};
- unsigned duration;
/* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL) {
@@ -362,13 +361,12 @@ wbcir_irq_rx(struct wbcir_data *data, struct pnp_dev *device)
if (data->rxstate == WBCIR_RXSTATE_ERROR)
continue;
- duration = ((irdata & 0x7F) + 1) *
+ rawir.duration = ((irdata & 0x7F) + 1) *
(data->carrier_report_enabled ? 2 : 10);
rawir.pulse = irdata & 0x80 ? false : true;
- rawir.duration = US_TO_NS(duration);
if (rawir.pulse)
- data->pulse_duration += duration;
+ data->pulse_duration += rawir.duration;
ir_raw_event_store_with_filter(data->dev, &rawir);
}
@@ -519,7 +517,7 @@ wbcir_set_carrier_report(struct rc_dev *dev, int enable)
/* Set a higher sampling resolution if carrier reports are enabled */
wbcir_select_bank(data, WBCIR_BANK_2);
- data->dev->rx_resolution = US_TO_NS(enable ? 2 : 10);
+ data->dev->rx_resolution = enable ? 2 : 10;
outb(enable ? 0x03 : 0x0f, data->sbase + WBCIR_REG_SP3_BGDL);
outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
@@ -1076,7 +1074,7 @@ wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
data->dev->min_timeout = 1;
data->dev->timeout = IR_DEFAULT_TIMEOUT;
data->dev->max_timeout = 10 * IR_DEFAULT_TIMEOUT;
- data->dev->rx_resolution = US_TO_NS(2);
+ data->dev->rx_resolution = 2;
data->dev->allowed_protocols = RC_PROTO_BIT_ALL_IR_DECODER;
data->dev->allowed_wakeup_protocols = RC_PROTO_BIT_NEC |
RC_PROTO_BIT_NECX | RC_PROTO_BIT_NEC32 | RC_PROTO_BIT_RC5 |
diff --git a/drivers/media/rc/xbox_remote.c b/drivers/media/rc/xbox_remote.c
index 4a3f2cc4ef18..98d0b43608ad 100644
--- a/drivers/media/rc/xbox_remote.c
+++ b/drivers/media/rc/xbox_remote.c
@@ -157,7 +157,7 @@ static void xbox_remote_rc_init(struct xbox_remote *xbox_remote)
rdev->device_name = xbox_remote->rc_name;
rdev->input_phys = xbox_remote->rc_phys;
- rdev->timeout = MS_TO_NS(10);
+ rdev->timeout = MS_TO_US(10);
usb_to_input_id(xbox_remote->udev, &rdev->input_id);
rdev->dev.parent = &xbox_remote->interface->dev;
diff --git a/drivers/media/test-drivers/Kconfig b/drivers/media/test-drivers/Kconfig
index 188381c85593..e27d6602545d 100644
--- a/drivers/media/test-drivers/Kconfig
+++ b/drivers/media/test-drivers/Kconfig
@@ -24,3 +24,19 @@ config VIDEO_VIM2M
source "drivers/media/test-drivers/vicodec/Kconfig"
endif #V4L_TEST_DRIVERS
+
+menuconfig DVB_TEST_DRIVERS
+ bool "DVB test drivers"
+ depends on DVB_CORE && MEDIA_SUPPORT && I2C
+ help
+ Enables DVB test drivers.
+
+ This enables the DVB test drivers. They are meant as an aid for
+ DVB device driver writers and developers working on userspace
+ media applications.
+
+if DVB_TEST_DRIVERS
+
+source "drivers/media/test-drivers/vidtv/Kconfig"
+
+endif #DVB_TEST_DRIVERS
diff --git a/drivers/media/test-drivers/Makefile b/drivers/media/test-drivers/Makefile
index 74410d3a9f2d..9f0e4ebb2efe 100644
--- a/drivers/media/test-drivers/Makefile
+++ b/drivers/media/test-drivers/Makefile
@@ -7,3 +7,4 @@ obj-$(CONFIG_VIDEO_VIMC) += vimc/
obj-$(CONFIG_VIDEO_VIVID) += vivid/
obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o
obj-$(CONFIG_VIDEO_VICODEC) += vicodec/
+obj-$(CONFIG_DVB_VIDTV) += vidtv/
diff --git a/drivers/media/test-drivers/vicodec/vicodec-core.c b/drivers/media/test-drivers/vicodec/vicodec-core.c
index 71928e30dae8..0e115683f8da 100644
--- a/drivers/media/test-drivers/vicodec/vicodec-core.c
+++ b/drivers/media/test-drivers/vicodec/vicodec-core.c
@@ -1310,7 +1310,7 @@ static int vicodec_subscribe_event(struct v4l2_fh *fh,
case V4L2_EVENT_SOURCE_CHANGE:
if (ctx->is_enc)
return -EINVAL;
- /* fall through */
+ fallthrough;
case V4L2_EVENT_EOS:
if (ctx->is_stateless)
return -EINVAL;
@@ -1671,8 +1671,8 @@ static void vicodec_stop_streaming(struct vb2_queue *q)
ctx->comp_size = 0;
ctx->header_size = 0;
ctx->comp_magic_cnt = 0;
- ctx->comp_has_frame = 0;
- ctx->comp_has_next_frame = 0;
+ ctx->comp_has_frame = false;
+ ctx->comp_has_next_frame = false;
}
}
diff --git a/drivers/media/test-drivers/vidtv/Kconfig b/drivers/media/test-drivers/vidtv/Kconfig
new file mode 100644
index 000000000000..22c4fd39461f
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/Kconfig
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: GPL-2.0-only
+config DVB_VIDTV
+ tristate "Virtual DVB Driver (vidtv)"
+ depends on DVB_CORE && MEDIA_SUPPORT && I2C
+ help
+ The virtual DVB test driver serves as a reference DVB driver and helps
+ validate the existing APIs in the media subsystem. It can also aid developers
+ working on userspace applications.
+
+
+ When in doubt, say N.
diff --git a/drivers/media/test-drivers/vidtv/Makefile b/drivers/media/test-drivers/vidtv/Makefile
new file mode 100644
index 000000000000..330089e3b70c
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/Makefile
@@ -0,0 +1,9 @@
+# SPDX-License-Identifier: GPL-2.0
+
+dvb-vidtv-tuner-objs := vidtv_tuner.o
+dvb-vidtv-demod-objs := vidtv_demod.o
+dvb-vidtv-bridge-objs := vidtv_bridge.o vidtv_common.o vidtv_ts.o vidtv_psi.o \
+ vidtv_pes.o vidtv_s302m.o vidtv_channel.o vidtv_mux.o
+
+obj-$(CONFIG_DVB_VIDTV) += dvb-vidtv-tuner.o dvb-vidtv-demod.o \
+ dvb-vidtv-bridge.o
diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.c b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
new file mode 100644
index 000000000000..74b054947bbe
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.c
@@ -0,0 +1,566 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The Virtual DTV test driver serves as a reference DVB driver and helps
+ * validate the existing APIs in the media subsystem. It can also aid
+ * developers working on userspace applications.
+ *
+ * When this module is loaded, it will attempt to modprobe 'dvb_vidtv_tuner' and 'dvb_vidtv_demod'.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/dev_printk.h>
+#include <linux/time.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+
+#include "vidtv_bridge.h"
+#include "vidtv_demod.h"
+#include "vidtv_tuner.h"
+#include "vidtv_ts.h"
+#include "vidtv_mux.h"
+#include "vidtv_common.h"
+
+//#define MUX_BUF_MAX_SZ
+//#define MUX_BUF_MIN_SZ
+#define TUNER_DEFAULT_ADDR 0x68
+#define DEMOD_DEFAULT_ADDR 0x60
+
+/* LNBf fake parameters: ranges used by an Universal (extended) European LNBf */
+#define LNB_CUT_FREQUENCY 11700000
+#define LNB_LOW_FREQ 9750000
+#define LNB_HIGH_FREQ 10600000
+
+
+static unsigned int drop_tslock_prob_on_low_snr;
+module_param(drop_tslock_prob_on_low_snr, uint, 0);
+MODULE_PARM_DESC(drop_tslock_prob_on_low_snr,
+ "Probability of losing the TS lock if the signal quality is bad");
+
+static unsigned int recover_tslock_prob_on_good_snr;
+module_param(recover_tslock_prob_on_good_snr, uint, 0);
+MODULE_PARM_DESC(recover_tslock_prob_on_good_snr,
+ "Probability recovering the TS lock when the signal improves");
+
+static unsigned int mock_power_up_delay_msec;
+module_param(mock_power_up_delay_msec, uint, 0);
+MODULE_PARM_DESC(mock_power_up_delay_msec, "Simulate a power up delay");
+
+static unsigned int mock_tune_delay_msec;
+module_param(mock_tune_delay_msec, uint, 0);
+MODULE_PARM_DESC(mock_tune_delay_msec, "Simulate a tune delay");
+
+static unsigned int vidtv_valid_dvb_t_freqs[NUM_VALID_TUNER_FREQS] = {
+ 474000000
+};
+
+module_param_array(vidtv_valid_dvb_t_freqs, uint, NULL, 0);
+MODULE_PARM_DESC(vidtv_valid_dvb_t_freqs,
+ "Valid DVB-T frequencies to simulate, in Hz");
+
+static unsigned int vidtv_valid_dvb_c_freqs[NUM_VALID_TUNER_FREQS] = {
+ 474000000
+};
+
+module_param_array(vidtv_valid_dvb_c_freqs, uint, NULL, 0);
+MODULE_PARM_DESC(vidtv_valid_dvb_c_freqs,
+ "Valid DVB-C frequencies to simulate, in Hz");
+
+static unsigned int vidtv_valid_dvb_s_freqs[NUM_VALID_TUNER_FREQS] = {
+ 11362000
+};
+module_param_array(vidtv_valid_dvb_s_freqs, uint, NULL, 0);
+MODULE_PARM_DESC(vidtv_valid_dvb_s_freqs,
+ "Valid DVB-S/S2 frequencies to simulate at Ku-Band, in kHz");
+
+static unsigned int max_frequency_shift_hz;
+module_param(max_frequency_shift_hz, uint, 0);
+MODULE_PARM_DESC(max_frequency_shift_hz,
+ "Maximum shift in HZ allowed when tuning in a channel");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums);
+
+/*
+ * Influences the signal acquisition time. See ISO/IEC 13818-1 : 2000. p. 113.
+ */
+static unsigned int si_period_msec = 40;
+module_param(si_period_msec, uint, 0);
+MODULE_PARM_DESC(si_period_msec, "How often to send SI packets. Default: 40ms");
+
+static unsigned int pcr_period_msec = 40;
+module_param(pcr_period_msec, uint, 0);
+MODULE_PARM_DESC(pcr_period_msec, "How often to send PCR packets. Default: 40ms");
+
+static unsigned int mux_rate_kbytes_sec = 4096;
+module_param(mux_rate_kbytes_sec, uint, 0);
+MODULE_PARM_DESC(mux_rate_kbytes_sec, "Mux rate: will pad stream if below");
+
+static unsigned int pcr_pid = 0x200;
+module_param(pcr_pid, uint, 0);
+MODULE_PARM_DESC(pcr_pid, "PCR PID for all channels: defaults to 0x200");
+
+static unsigned int mux_buf_sz_pkts;
+module_param(mux_buf_sz_pkts, uint, 0);
+MODULE_PARM_DESC(mux_buf_sz_pkts, "Size for the internal mux buffer in multiples of 188 bytes");
+
+#define MUX_BUF_MIN_SZ 90164
+#define MUX_BUF_MAX_SZ (MUX_BUF_MIN_SZ * 10)
+
+static u32 vidtv_bridge_mux_buf_sz_for_mux_rate(void)
+{
+ u32 max_elapsed_time_msecs = VIDTV_MAX_SLEEP_USECS / USEC_PER_MSEC;
+ u32 nbytes_expected;
+ u32 mux_buf_sz = mux_buf_sz_pkts * TS_PACKET_LEN;
+
+ nbytes_expected = mux_rate_kbytes_sec;
+ nbytes_expected *= max_elapsed_time_msecs;
+
+ mux_buf_sz = roundup(nbytes_expected, TS_PACKET_LEN);
+ mux_buf_sz += mux_buf_sz / 10;
+
+ if (mux_buf_sz < MUX_BUF_MIN_SZ)
+ mux_buf_sz = MUX_BUF_MIN_SZ;
+
+ if (mux_buf_sz > MUX_BUF_MAX_SZ)
+ mux_buf_sz = MUX_BUF_MAX_SZ;
+
+ return mux_buf_sz;
+}
+
+static bool vidtv_bridge_check_demod_lock(struct vidtv_dvb *dvb, u32 n)
+{
+ enum fe_status status;
+
+ dvb->fe[n]->ops.read_status(dvb->fe[n], &status);
+
+ return status == (FE_HAS_SIGNAL |
+ FE_HAS_CARRIER |
+ FE_HAS_VITERBI |
+ FE_HAS_SYNC |
+ FE_HAS_LOCK);
+}
+
+static void
+vidtv_bridge_on_new_pkts_avail(void *priv, u8 *buf, u32 npkts)
+{
+ /*
+ * called on a separate thread by the mux when new packets become
+ * available
+ */
+ struct vidtv_dvb *dvb = (struct vidtv_dvb *)priv;
+
+ /* drop packets if we lose the lock */
+ if (vidtv_bridge_check_demod_lock(dvb, 0))
+ dvb_dmx_swfilter_packets(&dvb->demux, buf, npkts);
+}
+
+static int vidtv_start_streaming(struct vidtv_dvb *dvb)
+{
+ struct vidtv_mux_init_args mux_args = {0};
+ struct device *dev = &dvb->pdev->dev;
+ u32 mux_buf_sz;
+
+ if (dvb->streaming) {
+ dev_warn_ratelimited(dev, "Already streaming. Skipping.\n");
+ return 0;
+ }
+
+ mux_buf_sz = (mux_buf_sz_pkts) ? mux_buf_sz_pkts : vidtv_bridge_mux_buf_sz_for_mux_rate();
+
+ mux_args.mux_rate_kbytes_sec = mux_rate_kbytes_sec;
+ mux_args.on_new_packets_available_cb = vidtv_bridge_on_new_pkts_avail;
+ mux_args.mux_buf_sz = mux_buf_sz;
+ mux_args.pcr_period_usecs = pcr_period_msec * 1000;
+ mux_args.si_period_usecs = si_period_msec * 1000;
+ mux_args.pcr_pid = pcr_pid;
+ mux_args.transport_stream_id = VIDTV_DEFAULT_TS_ID;
+ mux_args.priv = dvb;
+
+ dvb->streaming = true;
+ dvb->mux = vidtv_mux_init(dvb->fe[0], dev, mux_args);
+ vidtv_mux_start_thread(dvb->mux);
+
+ dev_dbg_ratelimited(dev, "Started streaming\n");
+ return 0;
+}
+
+static int vidtv_stop_streaming(struct vidtv_dvb *dvb)
+{
+ struct device *dev = &dvb->pdev->dev;
+
+ dvb->streaming = false;
+ vidtv_mux_stop_thread(dvb->mux);
+ vidtv_mux_destroy(dvb->mux);
+ dvb->mux = NULL;
+
+ dev_dbg_ratelimited(dev, "Stopped streaming\n");
+ return 0;
+}
+
+static int vidtv_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct vidtv_dvb *dvb = demux->priv;
+ int rc;
+ int ret;
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ mutex_lock(&dvb->feed_lock);
+
+ dvb->nfeeds++;
+ rc = dvb->nfeeds;
+
+ if (dvb->nfeeds == 1) {
+ ret = vidtv_start_streaming(dvb);
+ if (ret < 0)
+ rc = ret;
+ }
+
+ mutex_unlock(&dvb->feed_lock);
+ return rc;
+}
+
+static int vidtv_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct vidtv_dvb *dvb = demux->priv;
+ int err = 0;
+
+ mutex_lock(&dvb->feed_lock);
+ dvb->nfeeds--;
+
+ if (!dvb->nfeeds)
+ err = vidtv_stop_streaming(dvb);
+
+ mutex_unlock(&dvb->feed_lock);
+ return err;
+}
+
+static struct dvb_frontend *vidtv_get_frontend_ptr(struct i2c_client *c)
+{
+ /* the demod will set this when its probe function runs */
+ struct vidtv_demod_state *state = i2c_get_clientdata(c);
+
+ return &state->frontend;
+}
+
+static int vidtv_master_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msgs[],
+ int num)
+{
+ return 0;
+}
+
+static u32 vidtv_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm vidtv_i2c_algorithm = {
+ .master_xfer = vidtv_master_xfer,
+ .functionality = vidtv_i2c_func,
+};
+
+static int vidtv_bridge_i2c_register_adap(struct vidtv_dvb *dvb)
+{
+ struct i2c_adapter *i2c_adapter = &dvb->i2c_adapter;
+
+ strscpy(i2c_adapter->name, "vidtv_i2c", sizeof(i2c_adapter->name));
+ i2c_adapter->owner = THIS_MODULE;
+ i2c_adapter->algo = &vidtv_i2c_algorithm;
+ i2c_adapter->algo_data = NULL;
+ i2c_adapter->timeout = 500;
+ i2c_adapter->retries = 3;
+ i2c_adapter->dev.parent = &dvb->pdev->dev;
+
+ i2c_set_adapdata(i2c_adapter, dvb);
+ return i2c_add_adapter(&dvb->i2c_adapter);
+}
+
+static int vidtv_bridge_register_adap(struct vidtv_dvb *dvb)
+{
+ int ret = 0;
+
+ ret = dvb_register_adapter(&dvb->adapter,
+ KBUILD_MODNAME,
+ THIS_MODULE,
+ &dvb->i2c_adapter.dev,
+ adapter_nums);
+
+ return ret;
+}
+
+static int vidtv_bridge_dmx_init(struct vidtv_dvb *dvb)
+{
+ dvb->demux.dmx.capabilities = DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING;
+
+ dvb->demux.priv = dvb;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = vidtv_start_feed;
+ dvb->demux.stop_feed = vidtv_stop_feed;
+
+ return dvb_dmx_init(&dvb->demux);
+}
+
+static int vidtv_bridge_dmxdev_init(struct vidtv_dvb *dvb)
+{
+ dvb->dmx_dev.filternum = 256;
+ dvb->dmx_dev.demux = &dvb->demux.dmx;
+ dvb->dmx_dev.capabilities = 0;
+
+ return dvb_dmxdev_init(&dvb->dmx_dev, &dvb->adapter);
+}
+
+static int vidtv_bridge_probe_demod(struct vidtv_dvb *dvb, u32 n)
+{
+ struct vidtv_demod_config cfg = {};
+
+ cfg.drop_tslock_prob_on_low_snr = drop_tslock_prob_on_low_snr;
+ cfg.recover_tslock_prob_on_good_snr = recover_tslock_prob_on_good_snr;
+
+ dvb->i2c_client_demod[n] = dvb_module_probe("dvb_vidtv_demod",
+ NULL,
+ &dvb->i2c_adapter,
+ DEMOD_DEFAULT_ADDR,
+ &cfg);
+
+ /* driver will not work anyways so bail out */
+ if (!dvb->i2c_client_demod[n])
+ return -ENODEV;
+
+ /* retrieve a ptr to the frontend state */
+ dvb->fe[n] = vidtv_get_frontend_ptr(dvb->i2c_client_demod[n]);
+
+ return 0;
+}
+
+static int vidtv_bridge_probe_tuner(struct vidtv_dvb *dvb, u32 n)
+{
+ struct vidtv_tuner_config cfg = {};
+ u32 freq;
+ int i;
+
+ cfg.fe = dvb->fe[n];
+ cfg.mock_power_up_delay_msec = mock_power_up_delay_msec;
+ cfg.mock_tune_delay_msec = mock_tune_delay_msec;
+
+ /* TODO: check if the frequencies are at a valid range */
+
+ memcpy(cfg.vidtv_valid_dvb_t_freqs,
+ vidtv_valid_dvb_t_freqs,
+ sizeof(vidtv_valid_dvb_t_freqs));
+
+ memcpy(cfg.vidtv_valid_dvb_c_freqs,
+ vidtv_valid_dvb_c_freqs,
+ sizeof(vidtv_valid_dvb_c_freqs));
+
+ /*
+ * Convert Satellite frequencies from Ku-band in kHZ into S-band
+ * frequencies in Hz.
+ */
+ for (i = 0; i < ARRAY_SIZE(vidtv_valid_dvb_s_freqs); i++) {
+ freq = vidtv_valid_dvb_s_freqs[i];
+ if (freq) {
+ if (freq < LNB_CUT_FREQUENCY)
+ freq = abs(freq - LNB_LOW_FREQ);
+ else
+ freq = abs(freq - LNB_HIGH_FREQ);
+ }
+ cfg.vidtv_valid_dvb_s_freqs[i] = freq;
+ }
+
+ cfg.max_frequency_shift_hz = max_frequency_shift_hz;
+
+ dvb->i2c_client_tuner[n] = dvb_module_probe("dvb_vidtv_tuner",
+ NULL,
+ &dvb->i2c_adapter,
+ TUNER_DEFAULT_ADDR,
+ &cfg);
+
+ return (dvb->i2c_client_tuner[n]) ? 0 : -ENODEV;
+}
+
+static int vidtv_bridge_dvb_init(struct vidtv_dvb *dvb)
+{
+ int ret;
+ int i;
+ int j;
+
+ ret = vidtv_bridge_i2c_register_adap(dvb);
+ if (ret < 0)
+ goto fail_i2c;
+
+ ret = vidtv_bridge_register_adap(dvb);
+ if (ret < 0)
+ goto fail_adapter;
+
+ for (i = 0; i < NUM_FE; ++i) {
+ ret = vidtv_bridge_probe_demod(dvb, i);
+ if (ret < 0)
+ goto fail_demod_probe;
+
+ ret = vidtv_bridge_probe_tuner(dvb, i);
+ if (ret < 0)
+ goto fail_tuner_probe;
+
+ ret = dvb_register_frontend(&dvb->adapter, dvb->fe[i]);
+ if (ret < 0)
+ goto fail_fe;
+ }
+
+ ret = vidtv_bridge_dmx_init(dvb);
+ if (ret < 0)
+ goto fail_dmx;
+
+ ret = vidtv_bridge_dmxdev_init(dvb);
+ if (ret < 0)
+ goto fail_dmx_dev;
+
+ for (j = 0; j < NUM_FE; ++j) {
+ ret = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx,
+ &dvb->dmx_fe[j]);
+ if (ret < 0)
+ goto fail_dmx_conn;
+
+ /*
+ * The source of the demux is a frontend connected
+ * to the demux.
+ */
+ dvb->dmx_fe[j].source = DMX_FRONTEND_0;
+ }
+
+ return ret;
+
+fail_dmx_conn:
+ for (j = j - 1; j >= 0; --j)
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx,
+ &dvb->dmx_fe[j]);
+fail_dmx_dev:
+ dvb_dmxdev_release(&dvb->dmx_dev);
+fail_dmx:
+ dvb_dmx_release(&dvb->demux);
+fail_fe:
+ for (j = i; j >= 0; --j)
+ dvb_unregister_frontend(dvb->fe[j]);
+fail_tuner_probe:
+ for (j = i; j >= 0; --j)
+ if (dvb->i2c_client_tuner[j])
+ dvb_module_release(dvb->i2c_client_tuner[j]);
+
+fail_demod_probe:
+ for (j = i; j >= 0; --j)
+ if (dvb->i2c_client_demod[j])
+ dvb_module_release(dvb->i2c_client_demod[j]);
+
+fail_adapter:
+ dvb_unregister_adapter(&dvb->adapter);
+
+fail_i2c:
+ i2c_del_adapter(&dvb->i2c_adapter);
+
+ return ret;
+}
+
+static int vidtv_bridge_probe(struct platform_device *pdev)
+{
+ struct vidtv_dvb *dvb;
+ int ret;
+
+ dvb = kzalloc(sizeof(*dvb), GFP_KERNEL);
+ if (!dvb)
+ return -ENOMEM;
+
+ dvb->pdev = pdev;
+
+ ret = vidtv_bridge_dvb_init(dvb);
+ if (ret < 0)
+ goto err_dvb;
+
+ mutex_init(&dvb->feed_lock);
+
+ platform_set_drvdata(pdev, dvb);
+
+ dev_info(&pdev->dev, "Successfully initialized vidtv!\n");
+ return ret;
+
+err_dvb:
+ kfree(dvb);
+ return ret;
+}
+
+static int vidtv_bridge_remove(struct platform_device *pdev)
+{
+ struct vidtv_dvb *dvb;
+ u32 i;
+
+ dvb = platform_get_drvdata(pdev);
+
+ mutex_destroy(&dvb->feed_lock);
+
+ for (i = 0; i < NUM_FE; ++i) {
+ dvb_unregister_frontend(dvb->fe[i]);
+ dvb_module_release(dvb->i2c_client_tuner[i]);
+ dvb_module_release(dvb->i2c_client_demod[i]);
+ }
+
+ dvb_dmxdev_release(&dvb->dmx_dev);
+ dvb_dmx_release(&dvb->demux);
+ dvb_unregister_adapter(&dvb->adapter);
+
+ return 0;
+}
+
+static void vidtv_bridge_dev_release(struct device *dev)
+{
+}
+
+static struct platform_device vidtv_bridge_dev = {
+ .name = "vidtv_bridge",
+ .dev.release = vidtv_bridge_dev_release,
+};
+
+static struct platform_driver vidtv_bridge_driver = {
+ .driver = {
+ .name = "vidtv_bridge",
+ .suppress_bind_attrs = true,
+ },
+ .probe = vidtv_bridge_probe,
+ .remove = vidtv_bridge_remove,
+};
+
+static void __exit vidtv_bridge_exit(void)
+{
+ platform_driver_unregister(&vidtv_bridge_driver);
+ platform_device_unregister(&vidtv_bridge_dev);
+}
+
+static int __init vidtv_bridge_init(void)
+{
+ int ret;
+
+ ret = platform_device_register(&vidtv_bridge_dev);
+ if (ret)
+ return ret;
+
+ ret = platform_driver_register(&vidtv_bridge_driver);
+ if (ret)
+ platform_device_unregister(&vidtv_bridge_dev);
+
+ return ret;
+}
+
+module_init(vidtv_bridge_init);
+module_exit(vidtv_bridge_exit);
+
+MODULE_DESCRIPTION("Virtual Digital TV Test Driver");
+MODULE_AUTHOR("Daniel W. S. Almeida");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("vidtv");
+MODULE_ALIAS("dvb_vidtv");
diff --git a/drivers/media/test-drivers/vidtv/vidtv_bridge.h b/drivers/media/test-drivers/vidtv/vidtv_bridge.h
new file mode 100644
index 000000000000..78fe8472fa37
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_bridge.h
@@ -0,0 +1,63 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The Virtual DTV test driver serves as a reference DVB driver and helps
+ * validate the existing APIs in the media subsystem. It can also aid
+ * developers working on userspace applications.
+ *
+ * When this module is loaded, it will attempt to modprobe 'dvb_vidtv_tuner' and 'dvb_vidtv_demod'.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#ifndef VIDTV_BRIDGE_H
+#define VIDTV_BRIDGE_H
+
+/*
+ * For now, only one frontend is supported. See vidtv_start_streaming()
+ */
+#define NUM_FE 1
+
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/types.h>
+#include <media/dmxdev.h>
+#include <media/dvb_demux.h>
+#include <media/dvb_frontend.h>
+#include "vidtv_mux.h"
+
+/**
+ * struct vidtv_dvb - Vidtv bridge state
+ * @pdev: The platform device. Obtained when the bridge is probed.
+ * @fe: The frontends. Obtained when probing the demodulator modules.
+ * @adapter: Represents a DTV adapter. See 'dvb_register_adapter'.
+ * @demux: The demux used by the dvb_dmx_swfilter_packets() call.
+ * @dmx_dev: Represents a demux device.
+ * @dmx_frontend: The frontends associated with the demux.
+ * @i2c_adapter: The i2c_adapter associated with the bridge driver.
+ * @i2c_client_demod: The i2c_clients associated with the demodulator modules.
+ * @i2c_client_tuner: The i2c_clients associated with the tuner modules.
+ * @nfeeds: The number of feeds active.
+ * @feed_lock: Protects access to the start/stop stream logic/data.
+ * @streaming: Whether we are streaming now.
+ * @mux: The abstraction responsible for delivering MPEG TS packets to the bridge.
+ */
+struct vidtv_dvb {
+ struct platform_device *pdev;
+ struct dvb_frontend *fe[NUM_FE];
+ struct dvb_adapter adapter;
+ struct dvb_demux demux;
+ struct dmxdev dmx_dev;
+ struct dmx_frontend dmx_fe[NUM_FE];
+ struct i2c_adapter i2c_adapter;
+ struct i2c_client *i2c_client_demod[NUM_FE];
+ struct i2c_client *i2c_client_tuner[NUM_FE];
+
+ u32 nfeeds;
+ struct mutex feed_lock; /* Protects access to the start/stop stream logic/data. */
+
+ bool streaming;
+
+ struct vidtv_mux *mux;
+};
+
+#endif // VIDTV_BRIDG_H
diff --git a/drivers/media/test-drivers/vidtv/vidtv_channel.c b/drivers/media/test-drivers/vidtv/vidtv_channel.c
new file mode 100644
index 000000000000..f2b97cf08e87
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_channel.c
@@ -0,0 +1,310 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Vidtv serves as a reference DVB driver and helps validate the existing APIs
+ * in the media subsystem. It can also aid developers working on userspace
+ * applications.
+ *
+ * This file contains the code for a 'channel' abstraction.
+ *
+ * When vidtv boots, it will create some hardcoded channels.
+ * Their services will be concatenated to populate the SDT.
+ * Their programs will be concatenated to populate the PAT
+ * For each program in the PAT, a PMT section will be created
+ * The PMT section for a channel will be assigned its streams.
+ * Every stream will have its corresponding encoder polled to produce TS packets
+ * These packets may be interleaved by the mux and then delivered to the bridge
+ *
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/dev_printk.h>
+#include <linux/ratelimit.h>
+
+#include "vidtv_channel.h"
+#include "vidtv_psi.h"
+#include "vidtv_encoder.h"
+#include "vidtv_mux.h"
+#include "vidtv_common.h"
+#include "vidtv_s302m.h"
+
+static void vidtv_channel_encoder_destroy(struct vidtv_encoder *e)
+{
+ struct vidtv_encoder *curr = e;
+ struct vidtv_encoder *tmp = NULL;
+
+ while (curr) {
+ /* forward the call to the derived type */
+ tmp = curr;
+ curr = curr->next;
+ tmp->destroy(tmp);
+ }
+}
+
+#define ENCODING_ISO8859_15 "\x0b"
+
+struct vidtv_channel
+*vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id)
+{
+ /*
+ * init an audio only channel with a s302m encoder
+ */
+ const u16 s302m_service_id = 0x880;
+ const u16 s302m_program_num = 0x880;
+ const u16 s302m_program_pid = 0x101; /* packet id for PMT*/
+ const u16 s302m_es_pid = 0x111; /* packet id for the ES */
+ const __be32 s302m_fid = cpu_to_be32(VIDTV_S302M_FORMAT_IDENTIFIER);
+
+ char *name = ENCODING_ISO8859_15 "Beethoven";
+ char *provider = ENCODING_ISO8859_15 "LinuxTV.org";
+
+ struct vidtv_channel *s302m = kzalloc(sizeof(*s302m), GFP_KERNEL);
+ struct vidtv_s302m_encoder_init_args encoder_args = {};
+
+ s302m->name = kstrdup(name, GFP_KERNEL);
+
+ s302m->service = vidtv_psi_sdt_service_init(NULL, s302m_service_id);
+
+ s302m->service->descriptor = (struct vidtv_psi_desc *)
+ vidtv_psi_service_desc_init(NULL,
+ DIGITAL_TELEVISION_SERVICE,
+ name,
+ provider);
+
+ s302m->transport_stream_id = transport_stream_id;
+
+ s302m->program = vidtv_psi_pat_program_init(NULL,
+ s302m_service_id,
+ s302m_program_pid);
+
+ s302m->program_num = s302m_program_num;
+
+ s302m->streams = vidtv_psi_pmt_stream_init(NULL,
+ STREAM_PRIVATE_DATA,
+ s302m_es_pid);
+
+ s302m->streams->descriptor = (struct vidtv_psi_desc *)
+ vidtv_psi_registration_desc_init(NULL,
+ s302m_fid,
+ NULL,
+ 0);
+ encoder_args.es_pid = s302m_es_pid;
+
+ s302m->encoders = vidtv_s302m_encoder_init(encoder_args);
+
+ if (head) {
+ while (head->next)
+ head = head->next;
+
+ head->next = s302m;
+ }
+
+ return s302m;
+}
+
+static struct vidtv_psi_table_sdt_service
+*vidtv_channel_sdt_serv_cat_into_new(struct vidtv_mux *m)
+{
+ /* Concatenate the services */
+ const struct vidtv_channel *cur_chnl = m->channels;
+
+ struct vidtv_psi_table_sdt_service *curr = NULL;
+ struct vidtv_psi_table_sdt_service *head = NULL;
+ struct vidtv_psi_table_sdt_service *tail = NULL;
+
+ struct vidtv_psi_desc *desc = NULL;
+ u16 service_id;
+
+ if (!cur_chnl)
+ return NULL;
+
+ while (cur_chnl) {
+ curr = cur_chnl->service;
+
+ if (!curr)
+ dev_warn_ratelimited(m->dev,
+ "No services found for channel %s\n", cur_chnl->name);
+
+ while (curr) {
+ service_id = be16_to_cpu(curr->service_id);
+ tail = vidtv_psi_sdt_service_init(tail, service_id);
+
+ desc = vidtv_psi_desc_clone(curr->descriptor);
+ vidtv_psi_desc_assign(&tail->descriptor, desc);
+
+ if (!head)
+ head = tail;
+
+ curr = curr->next;
+ }
+
+ cur_chnl = cur_chnl->next;
+ }
+
+ return head;
+}
+
+static struct vidtv_psi_table_pat_program*
+vidtv_channel_pat_prog_cat_into_new(struct vidtv_mux *m)
+{
+ /* Concatenate the programs */
+ const struct vidtv_channel *cur_chnl = m->channels;
+ struct vidtv_psi_table_pat_program *curr = NULL;
+ struct vidtv_psi_table_pat_program *head = NULL;
+ struct vidtv_psi_table_pat_program *tail = NULL;
+ u16 serv_id;
+ u16 pid;
+
+ if (!cur_chnl)
+ return NULL;
+
+ while (cur_chnl) {
+ curr = cur_chnl->program;
+
+ if (!curr)
+ dev_warn_ratelimited(m->dev,
+ "No programs found for channel %s\n",
+ cur_chnl->name);
+
+ while (curr) {
+ serv_id = be16_to_cpu(curr->service_id);
+ pid = vidtv_psi_get_pat_program_pid(curr);
+ tail = vidtv_psi_pat_program_init(tail,
+ serv_id,
+ pid);
+
+ if (!head)
+ head = tail;
+
+ curr = curr->next;
+ }
+
+ cur_chnl = cur_chnl->next;
+ }
+
+ return head;
+}
+
+static void
+vidtv_channel_pmt_match_sections(struct vidtv_channel *channels,
+ struct vidtv_psi_table_pmt **sections,
+ u32 nsections)
+{
+ /*
+ * Match channels to their respective PMT sections, then assign the
+ * streams
+ */
+ struct vidtv_psi_table_pmt *curr_section = NULL;
+ struct vidtv_channel *cur_chnl = channels;
+
+ struct vidtv_psi_table_pmt_stream *s = NULL;
+ struct vidtv_psi_table_pmt_stream *head = NULL;
+ struct vidtv_psi_table_pmt_stream *tail = NULL;
+
+ struct vidtv_psi_desc *desc = NULL;
+ u32 j;
+ u16 curr_id;
+ u16 e_pid; /* elementary stream pid */
+
+ while (cur_chnl) {
+ for (j = 0; j < nsections; ++j) {
+ curr_section = sections[j];
+
+ if (!curr_section)
+ continue;
+
+ curr_id = be16_to_cpu(curr_section->header.id);
+
+ /* we got a match */
+ if (curr_id == cur_chnl->program_num) {
+ s = cur_chnl->streams;
+
+ /* clone the streams for the PMT */
+ while (s) {
+ e_pid = vidtv_psi_pmt_stream_get_elem_pid(s);
+ tail = vidtv_psi_pmt_stream_init(tail,
+ s->type,
+ e_pid);
+
+ if (!head)
+ head = tail;
+
+ desc = vidtv_psi_desc_clone(s->descriptor);
+ vidtv_psi_desc_assign(&tail->descriptor, desc);
+
+ s = s->next;
+ }
+
+ vidtv_psi_pmt_stream_assign(curr_section, head);
+ break;
+ }
+ }
+
+ cur_chnl = cur_chnl->next;
+ }
+}
+
+void vidtv_channel_si_init(struct vidtv_mux *m)
+{
+ struct vidtv_psi_table_pat_program *programs = NULL;
+ struct vidtv_psi_table_sdt_service *services = NULL;
+
+ m->si.pat = vidtv_psi_pat_table_init(m->transport_stream_id);
+
+ m->si.sdt = vidtv_psi_sdt_table_init(m->transport_stream_id);
+
+ programs = vidtv_channel_pat_prog_cat_into_new(m);
+ services = vidtv_channel_sdt_serv_cat_into_new(m);
+
+ /* assemble all programs and assign to PAT */
+ vidtv_psi_pat_program_assign(m->si.pat, programs);
+
+ /* assemble all services and assign to SDT */
+ vidtv_psi_sdt_service_assign(m->si.sdt, services);
+
+ m->si.pmt_secs = vidtv_psi_pmt_create_sec_for_each_pat_entry(m->si.pat, m->pcr_pid);
+
+ vidtv_channel_pmt_match_sections(m->channels,
+ m->si.pmt_secs,
+ m->si.pat->programs);
+}
+
+void vidtv_channel_si_destroy(struct vidtv_mux *m)
+{
+ u32 i;
+ u16 num_programs = m->si.pat->programs;
+
+ vidtv_psi_pat_table_destroy(m->si.pat);
+
+ for (i = 0; i < num_programs; ++i)
+ vidtv_psi_pmt_table_destroy(m->si.pmt_secs[i]);
+
+ kfree(m->si.pmt_secs);
+ vidtv_psi_sdt_table_destroy(m->si.sdt);
+}
+
+void vidtv_channels_init(struct vidtv_mux *m)
+{
+ /* this is the place to add new 'channels' for vidtv */
+ m->channels = vidtv_channel_s302m_init(NULL, m->transport_stream_id);
+}
+
+void vidtv_channels_destroy(struct vidtv_mux *m)
+{
+ struct vidtv_channel *curr = m->channels;
+ struct vidtv_channel *tmp = NULL;
+
+ while (curr) {
+ kfree(curr->name);
+ vidtv_psi_sdt_service_destroy(curr->service);
+ vidtv_psi_pat_program_destroy(curr->program);
+ vidtv_psi_pmt_stream_destroy(curr->streams);
+ vidtv_channel_encoder_destroy(curr->encoders);
+
+ tmp = curr;
+ curr = curr->next;
+ kfree(tmp);
+ }
+}
diff --git a/drivers/media/test-drivers/vidtv/vidtv_channel.h b/drivers/media/test-drivers/vidtv/vidtv_channel.h
new file mode 100644
index 000000000000..2c3cba4313b0
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_channel.h
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Vidtv serves as a reference DVB driver and helps validate the existing APIs
+ * in the media subsystem. It can also aid developers working on userspace
+ * applications.
+ *
+ * This file contains the code for a 'channel' abstraction.
+ *
+ * When vidtv boots, it will create some hardcoded channels.
+ * Their services will be concatenated to populate the SDT.
+ * Their programs will be concatenated to populate the PAT
+ * For each program in the PAT, a PMT section will be created
+ * The PMT section for a channel will be assigned its streams.
+ * Every stream will have its corresponding encoder polled to produce TS packets
+ * These packets may be interleaved by the mux and then delivered to the bridge
+ *
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#ifndef VIDTV_CHANNEL_H
+#define VIDTV_CHANNEL_H
+
+#include <linux/types.h>
+#include "vidtv_psi.h"
+#include "vidtv_encoder.h"
+#include "vidtv_mux.h"
+
+/**
+ * struct vidtv_channel - A 'channel' abstraction
+ *
+ * When vidtv boots, it will create some hardcoded channels.
+ * Their services will be concatenated to populate the SDT.
+ * Their programs will be concatenated to populate the PAT
+ * For each program in the PAT, a PMT section will be created
+ * The PMT section for a channel will be assigned its streams.
+ * Every stream will have its corresponding encoder polled to produce TS packets
+ * These packets may be interleaved by the mux and then delivered to the bridge
+ *
+ * @transport_stream_id: a number to identify the TS, chosen at will.
+ * @service: A _single_ service. Will be concatenated into the SDT.
+ * @program_num: The link between PAT, PMT and SDT.
+ * @program: A _single_ program with one or more streams associated with it.
+ * Will be concatenated into the PAT.
+ * @streams: A stream loop used to populate the PMT section for 'program'
+ * @encoders: A encoder loop. There must be one encoder for each stream.
+ * @next: Optionally chain this channel.
+ */
+struct vidtv_channel {
+ char *name;
+ u16 transport_stream_id;
+ struct vidtv_psi_table_sdt_service *service;
+ u16 program_num;
+ struct vidtv_psi_table_pat_program *program;
+ struct vidtv_psi_table_pmt_stream *streams;
+ struct vidtv_encoder *encoders;
+ struct vidtv_channel *next;
+};
+
+/**
+ * vidtv_channel_si_init - Init the PSI tables from the channels in the mux
+ * @m: The mux containing the channels.
+ */
+void vidtv_channel_si_init(struct vidtv_mux *m);
+void vidtv_channel_si_destroy(struct vidtv_mux *m);
+
+/**
+ * vidtv_channels_init - Init hardcoded, fake 'channels'.
+ * @m: The mux to store the channels into.
+ */
+void vidtv_channels_init(struct vidtv_mux *m);
+struct vidtv_channel
+*vidtv_channel_s302m_init(struct vidtv_channel *head, u16 transport_stream_id);
+void vidtv_channels_destroy(struct vidtv_mux *m);
+
+#endif //VIDTV_CHANNEL_H
diff --git a/drivers/media/test-drivers/vidtv/vidtv_common.c b/drivers/media/test-drivers/vidtv/vidtv_common.c
new file mode 100644
index 000000000000..63b3055bd715
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_common.c
@@ -0,0 +1,89 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The Virtual DVB test driver serves as a reference DVB driver and helps
+ * validate the existing APIs in the media subsystem. It can also aid
+ * developers working on userspace applications.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__
+
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "vidtv_common.h"
+
+/**
+ * vidtv_memcpy() - wrapper routine to be used by MPEG-TS
+ * generator, in order to avoid going past the
+ * output buffer.
+ * @to: Starting element to where a MPEG-TS packet will
+ * be copied.
+ * @to_offset: Starting position of the @to buffer to be filled.
+ * @to_size: Size of the @to buffer.
+ * @from: Starting element of the buffer to be copied.
+ * @len: Number of elements to be copy from @from buffer
+ * into @to+ @to_offset buffer.
+ *
+ * Note:
+ * Real digital TV demod drivers should not have memcpy
+ * wrappers. We use it here because emulating MPEG-TS
+ * generation at kernelspace requires some extra care.
+ *
+ * Return:
+ * Returns the number of bytes written
+ */
+u32 vidtv_memcpy(void *to,
+ size_t to_offset,
+ size_t to_size,
+ const void *from,
+ size_t len)
+{
+ if (unlikely(to_offset + len > to_size)) {
+ pr_err_ratelimited("overflow detected, skipping. Try increasing the buffer size. Needed %zu, had %zu\n",
+ to_offset + len,
+ to_size);
+ return 0;
+ }
+
+ memcpy(to + to_offset, from, len);
+ return len;
+}
+
+/**
+ * vidtv_memset() - wrapper routine to be used by MPEG-TS
+ * generator, in order to avoid going past the
+ * output buffer.
+ * @to: Starting element to set
+ * @to_offset: Starting position of the @to buffer to be filled.
+ * @to_size: Size of the @to buffer.
+ * @c: The value to set the memory to.
+ * @len: Number of elements to be copy from @from buffer
+ * into @to+ @to_offset buffer.
+ *
+ * Note:
+ * Real digital TV demod drivers should not have memset
+ * wrappers. We use it here because emulating MPEG-TS
+ * generation at kernelspace requires some extra care.
+ *
+ * Return:
+ * Returns the number of bytes written
+ */
+u32 vidtv_memset(void *to,
+ size_t to_offset,
+ size_t to_size,
+ const int c,
+ size_t len)
+{
+ if (unlikely(to_offset + len > to_size)) {
+ pr_err_ratelimited("overflow detected, skipping. Try increasing the buffer size. Needed %zu, had %zu\n",
+ to_offset + len,
+ to_size);
+ return 0;
+ }
+
+ memset(to + to_offset, c, len);
+ return len;
+}
diff --git a/drivers/media/test-drivers/vidtv/vidtv_common.h b/drivers/media/test-drivers/vidtv/vidtv_common.h
new file mode 100644
index 000000000000..818e7f2b9ec5
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_common.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The Virtual DVB test driver serves as a reference DVB driver and helps
+ * validate the existing APIs in the media subsystem. It can also aid
+ * developers working on userspace applications.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#ifndef VIDTV_COMMON_H
+#define VIDTV_COMMON_H
+
+#include <linux/types.h>
+
+#define CLOCK_UNIT_90KHZ 90000
+#define CLOCK_UNIT_27MHZ 27000000
+#define VIDTV_SLEEP_USECS 10000
+#define VIDTV_MAX_SLEEP_USECS (2 * VIDTV_SLEEP_USECS)
+#define VIDTV_DEFAULT_TS_ID 0x744
+
+u32 vidtv_memcpy(void *to,
+ size_t to_offset,
+ size_t to_size,
+ const void *from,
+ size_t len);
+
+u32 vidtv_memset(void *to,
+ size_t to_offset,
+ size_t to_size,
+ int c,
+ size_t len);
+
+#endif // VIDTV_COMMON_H
diff --git a/drivers/media/test-drivers/vidtv/vidtv_demod.c b/drivers/media/test-drivers/vidtv/vidtv_demod.c
new file mode 100644
index 000000000000..eba7fe1a1b48
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_demod.c
@@ -0,0 +1,464 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * The Virtual DVB test driver serves as a reference DVB driver and helps
+ * validate the existing APIs in the media subsystem. It can also aid
+ * developers working on userspace applications.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ * Based on the example driver written by Emard <emard@softhome.net>
+ */
+
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/printk.h>
+#include <linux/random.h>
+#include <linux/ratelimit.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/workqueue.h>
+#include <media/dvb_frontend.h>
+
+#include "vidtv_demod.h"
+
+#define POLL_THRD_TIME 2000 /* ms */
+
+static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_c_cnr_2_qual[] = {
+ /* from libdvbv5 source code, in milli db */
+ { QAM_256, FEC_NONE, 34000, 38000},
+ { QAM_64, FEC_NONE, 30000, 34000},
+};
+
+static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_s_cnr_2_qual[] = {
+ /* from libdvbv5 source code, in milli db */
+ { QPSK, FEC_1_2, 7000, 10000},
+ { QPSK, FEC_2_3, 9000, 12000},
+ { QPSK, FEC_3_4, 10000, 13000},
+ { QPSK, FEC_5_6, 11000, 14000},
+ { QPSK, FEC_7_8, 12000, 15000},
+};
+
+static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_s2_cnr_2_qual[] = {
+ /* from libdvbv5 source code, in milli db */
+ { QPSK, FEC_1_2, 9000, 12000},
+ { QPSK, FEC_2_3, 11000, 14000},
+ { QPSK, FEC_3_4, 12000, 15000},
+ { QPSK, FEC_5_6, 12000, 15000},
+ { QPSK, FEC_8_9, 13000, 16000},
+ { QPSK, FEC_9_10, 13500, 16500},
+ { PSK_8, FEC_2_3, 14500, 17500},
+ { PSK_8, FEC_3_4, 16000, 19000},
+ { PSK_8, FEC_5_6, 17500, 20500},
+ { PSK_8, FEC_8_9, 19000, 22000},
+};
+
+static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_t_cnr_2_qual[] = {
+ /* from libdvbv5 source code, in milli db*/
+ { QPSK, FEC_1_2, 4100, 5900},
+ { QPSK, FEC_2_3, 6100, 9600},
+ { QPSK, FEC_3_4, 7200, 12400},
+ { QPSK, FEC_5_6, 8500, 15600},
+ { QPSK, FEC_7_8, 9200, 17500},
+ { QAM_16, FEC_1_2, 9800, 11800},
+ { QAM_16, FEC_2_3, 12100, 15300},
+ { QAM_16, FEC_3_4, 13400, 18100},
+ { QAM_16, FEC_5_6, 14800, 21300},
+ { QAM_16, FEC_7_8, 15700, 23600},
+ { QAM_64, FEC_1_2, 14000, 16000},
+ { QAM_64, FEC_2_3, 19900, 25400},
+ { QAM_64, FEC_3_4, 24900, 27900},
+ { QAM_64, FEC_5_6, 21300, 23300},
+ { QAM_64, FEC_7_8, 22000, 24000},
+};
+
+static const struct vidtv_demod_cnr_to_qual_s *vidtv_match_cnr_s(struct dvb_frontend *fe)
+{
+ const struct vidtv_demod_cnr_to_qual_s *cnr2qual = NULL;
+ struct device *dev = fe->dvb->device;
+ struct dtv_frontend_properties *c;
+ u32 array_size = 0;
+ u32 i;
+
+ c = &fe->dtv_property_cache;
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ cnr2qual = vidtv_demod_t_cnr_2_qual;
+ array_size = ARRAY_SIZE(vidtv_demod_t_cnr_2_qual);
+ break;
+
+ case SYS_DVBS:
+ cnr2qual = vidtv_demod_s_cnr_2_qual;
+ array_size = ARRAY_SIZE(vidtv_demod_s_cnr_2_qual);
+ break;
+
+ case SYS_DVBS2:
+ cnr2qual = vidtv_demod_s2_cnr_2_qual;
+ array_size = ARRAY_SIZE(vidtv_demod_s2_cnr_2_qual);
+ break;
+
+ case SYS_DVBC_ANNEX_A:
+ cnr2qual = vidtv_demod_c_cnr_2_qual;
+ array_size = ARRAY_SIZE(vidtv_demod_c_cnr_2_qual);
+ break;
+
+ default:
+ dev_warn_ratelimited(dev,
+ "%s: unsupported delivery system: %u\n",
+ __func__,
+ c->delivery_system);
+ break;
+ }
+
+ for (i = 0; i < array_size; i++)
+ if (cnr2qual[i].modulation == c->modulation &&
+ cnr2qual[i].fec == c->fec_inner)
+ return &cnr2qual[i];
+
+ return NULL; /* not found */
+}
+
+static void vidtv_clean_stats(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ /* Fill the length of each status counter */
+
+ /* Signal is always available */
+ c->strength.len = 1;
+ c->strength.stat[0].scale = FE_SCALE_DECIBEL;
+ c->strength.stat[0].svalue = 0;
+
+ /* Usually available only after Viterbi lock */
+ c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->cnr.stat[0].svalue = 0;
+ c->cnr.len = 1;
+
+ /* Those depends on full lock */
+ c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_error.stat[0].uvalue = 0;
+ c->pre_bit_error.len = 1;
+ c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->pre_bit_count.stat[0].uvalue = 0;
+ c->pre_bit_count.len = 1;
+ c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_error.stat[0].uvalue = 0;
+ c->post_bit_error.len = 1;
+ c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->post_bit_count.stat[0].uvalue = 0;
+ c->post_bit_count.len = 1;
+ c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_error.stat[0].uvalue = 0;
+ c->block_error.len = 1;
+ c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+ c->block_count.stat[0].uvalue = 0;
+ c->block_count.len = 1;
+}
+
+static void vidtv_demod_update_stats(struct dvb_frontend *fe)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct vidtv_demod_state *state = fe->demodulator_priv;
+ u32 scale;
+
+ if (state->status & FE_HAS_LOCK) {
+ scale = FE_SCALE_COUNTER;
+ c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+ } else {
+ scale = FE_SCALE_NOT_AVAILABLE;
+ c->cnr.stat[0].scale = scale;
+ }
+
+ c->pre_bit_error.stat[0].scale = scale;
+ c->pre_bit_count.stat[0].scale = scale;
+ c->post_bit_error.stat[0].scale = scale;
+ c->post_bit_count.stat[0].scale = scale;
+ c->block_error.stat[0].scale = scale;
+ c->block_count.stat[0].scale = scale;
+
+ /*
+ * Add a 0.5% of randomness at the signal strength and CNR,
+ * and make them different, as we want to have something closer
+ * to a real case scenario.
+ *
+ * Also, usually, signal strength is a negative number in dBm.
+ */
+ c->strength.stat[0].svalue = state->tuner_cnr;
+ c->strength.stat[0].svalue -= prandom_u32_max(state->tuner_cnr / 50);
+ c->strength.stat[0].svalue -= 68000; /* Adjust to a better range */
+
+ c->cnr.stat[0].svalue = state->tuner_cnr;
+ c->cnr.stat[0].svalue -= prandom_u32_max(state->tuner_cnr / 50);
+
+}
+
+static int vidtv_demod_read_status(struct dvb_frontend *fe,
+ enum fe_status *status)
+{
+ struct vidtv_demod_state *state = fe->demodulator_priv;
+ const struct vidtv_demod_cnr_to_qual_s *cnr2qual = NULL;
+ struct vidtv_demod_config *config = &state->config;
+ u16 snr = 0;
+
+ /* Simulate random lost of signal due to a bad-tuned channel */
+ cnr2qual = vidtv_match_cnr_s(&state->frontend);
+
+ if (cnr2qual && state->tuner_cnr < cnr2qual->cnr_good &&
+ state->frontend.ops.tuner_ops.get_rf_strength) {
+ state->frontend.ops.tuner_ops.get_rf_strength(&state->frontend,
+ &snr);
+
+ if (snr < cnr2qual->cnr_ok) {
+ /* eventually lose the TS lock */
+ if (prandom_u32_max(100) < config->drop_tslock_prob_on_low_snr)
+ state->status = 0;
+ } else {
+ /* recover if the signal improves */
+ if (prandom_u32_max(100) <
+ config->recover_tslock_prob_on_good_snr)
+ state->status = FE_HAS_SIGNAL |
+ FE_HAS_CARRIER |
+ FE_HAS_VITERBI |
+ FE_HAS_SYNC |
+ FE_HAS_LOCK;
+ }
+ }
+
+ vidtv_demod_update_stats(&state->frontend);
+
+ *status = state->status;
+
+ return 0;
+}
+
+static int vidtv_demod_read_signal_strength(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+ *strength = c->strength.stat[0].uvalue;
+
+ return 0;
+}
+
+/*
+ * NOTE:
+ * This is implemented here just to be used as an example for real
+ * demod drivers.
+ *
+ * Should only be implemented if it actually reads something from the hardware.
+ * Also, it should check for the locks, in order to avoid report wrong data
+ * to userspace.
+ */
+static int vidtv_demod_get_frontend(struct dvb_frontend *fe,
+ struct dtv_frontend_properties *p)
+{
+ return 0;
+}
+
+static int vidtv_demod_set_frontend(struct dvb_frontend *fe)
+{
+ struct vidtv_demod_state *state = fe->demodulator_priv;
+ u32 tuner_status = 0;
+ int ret;
+
+ if (!fe->ops.tuner_ops.set_params)
+ return 0;
+
+ fe->ops.tuner_ops.set_params(fe);
+
+ /* store the CNR returned by the tuner */
+ ret = fe->ops.tuner_ops.get_rf_strength(fe, &state->tuner_cnr);
+ if (ret < 0)
+ return ret;
+
+ fe->ops.tuner_ops.get_status(fe, &tuner_status);
+ state->status = (state->tuner_cnr > 0) ? FE_HAS_SIGNAL |
+ FE_HAS_CARRIER |
+ FE_HAS_VITERBI |
+ FE_HAS_SYNC |
+ FE_HAS_LOCK :
+ 0;
+
+ vidtv_demod_update_stats(fe);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ return 0;
+}
+
+/*
+ * NOTE:
+ * This is implemented here just to be used as an example for real
+ * demod drivers.
+ *
+ * Should only be implemented if the demod has support for DVB-S or DVB-S2
+ */
+static int vidtv_demod_set_tone(struct dvb_frontend *fe,
+ enum fe_sec_tone_mode tone)
+{
+ return 0;
+}
+
+/*
+ * NOTE:
+ * This is implemented here just to be used as an example for real
+ * demod drivers.
+ *
+ * Should only be implemented if the demod has support for DVB-S or DVB-S2
+ */
+static int vidtv_demod_set_voltage(struct dvb_frontend *fe,
+ enum fe_sec_voltage voltage)
+{
+ return 0;
+}
+
+/*
+ * NOTE:
+ * This is implemented here just to be used as an example for real
+ * demod drivers.
+ *
+ * Should only be implemented if the demod has support for DVB-S or DVB-S2
+ */
+static int vidtv_send_diseqc_msg(struct dvb_frontend *fe,
+ struct dvb_diseqc_master_cmd *cmd)
+{
+ return 0;
+}
+
+/*
+ * NOTE:
+ * This is implemented here just to be used as an example for real
+ * demod drivers.
+ *
+ * Should only be implemented if the demod has support for DVB-S or DVB-S2
+ */
+static int vidtv_diseqc_send_burst(struct dvb_frontend *fe,
+ enum fe_sec_mini_cmd burst)
+{
+ return 0;
+}
+
+static void vidtv_demod_release(struct dvb_frontend *fe)
+{
+ struct vidtv_demod_state *state = fe->demodulator_priv;
+
+ kfree(state);
+}
+
+static const struct dvb_frontend_ops vidtv_demod_ops = {
+ .delsys = {
+ SYS_DVBT,
+ SYS_DVBT2,
+ SYS_DVBC_ANNEX_A,
+ SYS_DVBS,
+ SYS_DVBS2,
+ },
+
+ .info = {
+ .name = "Dummy demod for DVB-T/T2/C/S/S2",
+ .frequency_min_hz = 51 * MHz,
+ .frequency_max_hz = 2150 * MHz,
+ .frequency_stepsize_hz = 62500,
+ .frequency_tolerance_hz = 29500 * kHz,
+ .symbol_rate_min = 1000000,
+ .symbol_rate_max = 45000000,
+
+ .caps = FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_4_5 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_6_7 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_8_9 |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_INVERSION_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = vidtv_demod_release,
+
+ .set_frontend = vidtv_demod_set_frontend,
+ .get_frontend = vidtv_demod_get_frontend,
+
+ .read_status = vidtv_demod_read_status,
+ .read_signal_strength = vidtv_demod_read_signal_strength,
+
+ /* For DVB-S/S2 */
+ .set_voltage = vidtv_demod_set_voltage,
+ .set_tone = vidtv_demod_set_tone,
+ .diseqc_send_master_cmd = vidtv_send_diseqc_msg,
+ .diseqc_send_burst = vidtv_diseqc_send_burst,
+
+};
+
+static const struct i2c_device_id vidtv_demod_i2c_id_table[] = {
+ {"dvb_vidtv_demod", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, vidtv_demod_i2c_id_table);
+
+static int vidtv_demod_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct vidtv_tuner_config *config = client->dev.platform_data;
+ struct vidtv_demod_state *state;
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops,
+ &vidtv_demod_ops,
+ sizeof(struct dvb_frontend_ops));
+
+ memcpy(&state->config, config, sizeof(state->config));
+
+ state->frontend.demodulator_priv = state;
+ i2c_set_clientdata(client, state);
+
+ vidtv_clean_stats(&state->frontend);
+
+ return 0;
+}
+
+static int vidtv_demod_i2c_remove(struct i2c_client *client)
+{
+ struct vidtv_demod_state *state = i2c_get_clientdata(client);
+
+ kfree(state);
+
+ return 0;
+}
+
+static struct i2c_driver vidtv_demod_i2c_driver = {
+ .driver = {
+ .name = "dvb_vidtv_demod",
+ .suppress_bind_attrs = true,
+ },
+ .probe = vidtv_demod_i2c_probe,
+ .remove = vidtv_demod_i2c_remove,
+ .id_table = vidtv_demod_i2c_id_table,
+};
+
+module_i2c_driver(vidtv_demod_i2c_driver);
+
+MODULE_DESCRIPTION("Virtual DVB Demodulator Driver");
+MODULE_AUTHOR("Daniel W. S. Almeida");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/test-drivers/vidtv/vidtv_demod.h b/drivers/media/test-drivers/vidtv/vidtv_demod.h
new file mode 100644
index 000000000000..87651b0193e6
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_demod.h
@@ -0,0 +1,69 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * The Virtual DTV test driver serves as a reference DVB driver and helps
+ * validate the existing APIs in the media subsystem. It can also aid
+ * developers working on userspace applications.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ * Based on the example driver written by Emard <emard@softhome.net>
+ */
+
+#ifndef VIDTV_DEMOD_H
+#define VIDTV_DEMOD_H
+
+#include <linux/dvb/frontend.h>
+#include <media/dvb_frontend.h>
+
+/**
+ * struct vidtv_demod_cnr_to_qual_s - Map CNR values to a given combination of
+ * modulation and fec_inner
+ * @modulation: see enum fe_modulation
+ * @fec: see enum fe_fec_rate
+ *
+ * This struct matches values for 'good' and 'ok' CNRs given the combination
+ * of modulation and fec_inner in use. We might simulate some noise if the
+ * signal quality is not too good.
+ *
+ * The values were taken from libdvbv5.
+ */
+struct vidtv_demod_cnr_to_qual_s {
+ u32 modulation;
+ u32 fec;
+ u32 cnr_ok;
+ u32 cnr_good;
+};
+
+/**
+ * struct vidtv_demod_config - Configuration used to init the demod
+ * @drop_tslock_prob_on_low_snr: probability of losing the lock due to low snr
+ * @recover_tslock_prob_on_good_snr: probability of recovering when the signal
+ * improves
+ *
+ * The configuration used to init the demodulator module, usually filled
+ * by a bridge driver. For vidtv, this is filled by vidtv_bridge before the
+ * demodulator module is probed.
+ */
+struct vidtv_demod_config {
+ u8 drop_tslock_prob_on_low_snr;
+ u8 recover_tslock_prob_on_good_snr;
+};
+
+/**
+ * struct vidtv_demod_state - The demodulator state
+ * @frontend: The frontend structure allocated by the demod.
+ * @config: The config used to init the demod.
+ * @poll_snr: The task responsible for periodically checking the simulated
+ * signal quality, eventually dropping or reacquiring the TS lock.
+ * @status: the demod status.
+ * @cold_start: Whether the demod has not been init yet.
+ * @poll_snr_thread_running: Whether the task responsible for periodically
+ * checking the simulated signal quality is running.
+ * @poll_snr_thread_restart: Whether we should restart the poll_snr task.
+ */
+struct vidtv_demod_state {
+ struct dvb_frontend frontend;
+ struct vidtv_demod_config config;
+ enum fe_status status;
+ u16 tuner_cnr;
+};
+#endif // VIDTV_DEMOD_H
diff --git a/drivers/media/test-drivers/vidtv/vidtv_encoder.h b/drivers/media/test-drivers/vidtv/vidtv_encoder.h
new file mode 100644
index 000000000000..65d81daef4c3
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_encoder.h
@@ -0,0 +1,166 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Vidtv serves as a reference DVB driver and helps validate the existing APIs
+ * in the media subsystem. It can also aid developers working on userspace
+ * applications.
+ *
+ * This file contains a generic encoder type that can provide data for a stream
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#ifndef VIDTV_ENCODER_H
+#define VIDTV_ENCODER_H
+
+#include <linux/types.h>
+
+enum vidtv_encoder_id {
+ /* add IDs here when implementing new encoders */
+ S302M,
+};
+
+struct vidtv_access_unit {
+ u32 num_samples;
+ u64 pts;
+ u64 dts;
+ u32 nbytes;
+ u32 offset;
+ struct vidtv_access_unit *next;
+};
+
+/* Some musical notes, used by a tone generator */
+enum musical_notes {
+ NOTE_SILENT = 0,
+
+ NOTE_C_2 = 65,
+ NOTE_CS_2 = 69,
+ NOTE_D_2 = 73,
+ NOTE_DS_2 = 78,
+ NOTE_E_2 = 82,
+ NOTE_F_2 = 87,
+ NOTE_FS_2 = 93,
+ NOTE_G_2 = 98,
+ NOTE_GS_2 = 104,
+ NOTE_A_2 = 110,
+ NOTE_AS_2 = 117,
+ NOTE_B_2 = 123,
+ NOTE_C_3 = 131,
+ NOTE_CS_3 = 139,
+ NOTE_D_3 = 147,
+ NOTE_DS_3 = 156,
+ NOTE_E_3 = 165,
+ NOTE_F_3 = 175,
+ NOTE_FS_3 = 185,
+ NOTE_G_3 = 196,
+ NOTE_GS_3 = 208,
+ NOTE_A_3 = 220,
+ NOTE_AS_3 = 233,
+ NOTE_B_3 = 247,
+ NOTE_C_4 = 262,
+ NOTE_CS_4 = 277,
+ NOTE_D_4 = 294,
+ NOTE_DS_4 = 311,
+ NOTE_E_4 = 330,
+ NOTE_F_4 = 349,
+ NOTE_FS_4 = 370,
+ NOTE_G_4 = 392,
+ NOTE_GS_4 = 415,
+ NOTE_A_4 = 440,
+ NOTE_AS_4 = 466,
+ NOTE_B_4 = 494,
+ NOTE_C_5 = 523,
+ NOTE_CS_5 = 554,
+ NOTE_D_5 = 587,
+ NOTE_DS_5 = 622,
+ NOTE_E_5 = 659,
+ NOTE_F_5 = 698,
+ NOTE_FS_5 = 740,
+ NOTE_G_5 = 784,
+ NOTE_GS_5 = 831,
+ NOTE_A_5 = 880,
+ NOTE_AS_5 = 932,
+ NOTE_B_5 = 988,
+ NOTE_C_6 = 1047,
+ NOTE_CS_6 = 1109,
+ NOTE_D_6 = 1175,
+ NOTE_DS_6 = 1245,
+ NOTE_E_6 = 1319,
+ NOTE_F_6 = 1397,
+ NOTE_FS_6 = 1480,
+ NOTE_G_6 = 1568,
+ NOTE_GS_6 = 1661,
+ NOTE_A_6 = 1760,
+ NOTE_AS_6 = 1865,
+ NOTE_B_6 = 1976,
+ NOTE_C_7 = 2093
+};
+
+/**
+ * struct vidtv_encoder - A generic encoder type.
+ * @id: So we can cast to a concrete implementation when needed.
+ * @name: Usually the same as the stream name.
+ * @encoder_buf: The encoder internal buffer for the access units.
+ * @encoder_buf_sz: The encoder buffer size, in bytes
+ * @encoder_buf_offset: Our byte position in the encoder buffer.
+ * @sample_count: How many samples we have encoded in total.
+ * @src_buf: The source of raw data to be encoded, encoder might set a
+ * default if null.
+ * @src_buf_offset: Our position in the source buffer.
+ * @is_video_encoder: Whether this a video encoder (as opposed to audio)
+ * @ctx: Encoder-specific state.
+ * @stream_id: Examples: Audio streams (0xc0-0xdf), Video streams
+ * (0xe0-0xef).
+ * @es_id: The TS PID to use for the elementary stream in this encoder.
+ * @encode: Prepare enough AUs for the given amount of time.
+ * @clear: Clear the encoder output.
+ * @sync: Attempt to synchronize with this encoder.
+ * @sampling_rate_hz: The sampling rate (or fps, if video) used.
+ * @last_sample_cb: Called when the encoder runs out of data.This is
+ * so the source can read data in a
+ * piecemeal fashion instead of having to
+ * provide it all at once.
+ * @destroy: Destroy this encoder, freeing allocated resources.
+ * @next: Next in the chain
+ */
+struct vidtv_encoder {
+ enum vidtv_encoder_id id;
+ char *name;
+
+ u8 *encoder_buf;
+ u32 encoder_buf_sz;
+ u32 encoder_buf_offset;
+
+ u64 sample_count;
+ int last_duration;
+ int note_offset;
+ enum musical_notes last_tone;
+
+ struct vidtv_access_unit *access_units;
+
+ void *src_buf;
+ u32 src_buf_sz;
+ u32 src_buf_offset;
+
+ bool is_video_encoder;
+ void *ctx;
+
+ __be16 stream_id;
+
+ __be16 es_pid;
+
+ void *(*encode)(struct vidtv_encoder *e);
+
+ u32 (*clear)(struct vidtv_encoder *e);
+
+ struct vidtv_encoder *sync;
+
+ u32 sampling_rate_hz;
+
+ void (*last_sample_cb)(u32 sample_no);
+
+ void (*destroy)(struct vidtv_encoder *e);
+
+ struct vidtv_encoder *next;
+};
+
+#endif /* VIDTV_ENCODER_H */
diff --git a/drivers/media/test-drivers/vidtv/vidtv_mux.c b/drivers/media/test-drivers/vidtv/vidtv_mux.c
new file mode 100644
index 000000000000..082740ae9d44
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_mux.c
@@ -0,0 +1,474 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Vidtv serves as a reference DVB driver and helps validate the existing APIs
+ * in the media subsystem. It can also aid developers working on userspace
+ * applications.
+ *
+ * This file contains the multiplexer logic for TS packets from different
+ * elementary streams
+ *
+ * Loosely based on libavcodec/mpegtsenc.c
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/dev_printk.h>
+#include <linux/ratelimit.h>
+#include <linux/delay.h>
+#include <linux/vmalloc.h>
+#include <linux/math64.h>
+
+#include "vidtv_mux.h"
+#include "vidtv_ts.h"
+#include "vidtv_pes.h"
+#include "vidtv_encoder.h"
+#include "vidtv_channel.h"
+#include "vidtv_common.h"
+#include "vidtv_psi.h"
+
+static struct vidtv_mux_pid_ctx
+*vidtv_mux_get_pid_ctx(struct vidtv_mux *m, u16 pid)
+{
+ struct vidtv_mux_pid_ctx *ctx;
+
+ hash_for_each_possible(m->pid_ctx, ctx, h, pid)
+ if (ctx->pid == pid)
+ return ctx;
+ return NULL;
+}
+
+static struct vidtv_mux_pid_ctx
+*vidtv_mux_create_pid_ctx_once(struct vidtv_mux *m, u16 pid)
+{
+ struct vidtv_mux_pid_ctx *ctx;
+
+ ctx = vidtv_mux_get_pid_ctx(m, pid);
+
+ if (ctx)
+ goto end;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ ctx->pid = pid;
+ ctx->cc = 0;
+ hash_add(m->pid_ctx, &ctx->h, pid);
+
+end:
+ return ctx;
+}
+
+static void vidtv_mux_pid_ctx_init(struct vidtv_mux *m)
+{
+ struct vidtv_psi_table_pat_program *p = m->si.pat->program;
+ u16 pid;
+
+ hash_init(m->pid_ctx);
+ /* push the pcr pid ctx */
+ vidtv_mux_create_pid_ctx_once(m, m->pcr_pid);
+ /* push the null packet pid ctx */
+ vidtv_mux_create_pid_ctx_once(m, TS_NULL_PACKET_PID);
+ /* push the PAT pid ctx */
+ vidtv_mux_create_pid_ctx_once(m, VIDTV_PAT_PID);
+ /* push the SDT pid ctx */
+ vidtv_mux_create_pid_ctx_once(m, VIDTV_SDT_PID);
+
+ /* add a ctx for all PMT sections */
+ while (p) {
+ pid = vidtv_psi_get_pat_program_pid(p);
+ vidtv_mux_create_pid_ctx_once(m, pid);
+ p = p->next;
+ }
+}
+
+static void vidtv_mux_pid_ctx_destroy(struct vidtv_mux *m)
+{
+ int bkt;
+ struct vidtv_mux_pid_ctx *ctx;
+ struct hlist_node *tmp;
+
+ hash_for_each_safe(m->pid_ctx, bkt, tmp, ctx, h) {
+ hash_del(&ctx->h);
+ kfree(ctx);
+ }
+}
+
+static void vidtv_mux_update_clk(struct vidtv_mux *m)
+{
+ /* call this at every thread iteration */
+ u64 elapsed_time;
+
+ m->timing.past_jiffies = m->timing.current_jiffies;
+ m->timing.current_jiffies = get_jiffies_64();
+
+ elapsed_time = jiffies_to_usecs(m->timing.current_jiffies -
+ m->timing.past_jiffies);
+
+ /* update the 27Mhz clock proportionally to the elapsed time */
+ m->timing.clk += (CLOCK_UNIT_27MHZ / USEC_PER_SEC) * elapsed_time;
+}
+
+static u32 vidtv_mux_push_si(struct vidtv_mux *m)
+{
+ u32 initial_offset = m->mux_buf_offset;
+
+ struct vidtv_mux_pid_ctx *pat_ctx;
+ struct vidtv_mux_pid_ctx *pmt_ctx;
+ struct vidtv_mux_pid_ctx *sdt_ctx;
+
+ struct vidtv_psi_pat_write_args pat_args = {};
+ struct vidtv_psi_pmt_write_args pmt_args = {};
+ struct vidtv_psi_sdt_write_args sdt_args = {};
+
+ u32 nbytes; /* the number of bytes written by this function */
+ u16 pmt_pid;
+ u32 i;
+
+ pat_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_PAT_PID);
+ sdt_ctx = vidtv_mux_get_pid_ctx(m, VIDTV_SDT_PID);
+
+ pat_args.buf = m->mux_buf;
+ pat_args.offset = m->mux_buf_offset;
+ pat_args.pat = m->si.pat;
+ pat_args.buf_sz = m->mux_buf_sz;
+ pat_args.continuity_counter = &pat_ctx->cc;
+
+ m->mux_buf_offset += vidtv_psi_pat_write_into(pat_args);
+
+ for (i = 0; i < m->si.pat->programs; ++i) {
+ pmt_pid = vidtv_psi_pmt_get_pid(m->si.pmt_secs[i],
+ m->si.pat);
+
+ if (pmt_pid > TS_LAST_VALID_PID) {
+ dev_warn_ratelimited(m->dev,
+ "PID: %d not found\n", pmt_pid);
+ continue;
+ }
+
+ pmt_ctx = vidtv_mux_get_pid_ctx(m, pmt_pid);
+
+ pmt_args.buf = m->mux_buf;
+ pmt_args.offset = m->mux_buf_offset;
+ pmt_args.pmt = m->si.pmt_secs[i];
+ pmt_args.pid = pmt_pid;
+ pmt_args.buf_sz = m->mux_buf_sz;
+ pmt_args.continuity_counter = &pmt_ctx->cc;
+ pmt_args.pcr_pid = m->pcr_pid;
+
+ /* write each section into buffer */
+ m->mux_buf_offset += vidtv_psi_pmt_write_into(pmt_args);
+ }
+
+ sdt_args.buf = m->mux_buf;
+ sdt_args.offset = m->mux_buf_offset;
+ sdt_args.sdt = m->si.sdt;
+ sdt_args.buf_sz = m->mux_buf_sz;
+ sdt_args.continuity_counter = &sdt_ctx->cc;
+
+ m->mux_buf_offset += vidtv_psi_sdt_write_into(sdt_args);
+
+ nbytes = m->mux_buf_offset - initial_offset;
+
+ m->num_streamed_si++;
+
+ return nbytes;
+}
+
+static u32 vidtv_mux_push_pcr(struct vidtv_mux *m)
+{
+ struct pcr_write_args args = {};
+ struct vidtv_mux_pid_ctx *ctx;
+ u32 nbytes = 0;
+
+ ctx = vidtv_mux_get_pid_ctx(m, m->pcr_pid);
+ args.dest_buf = m->mux_buf;
+ args.pid = m->pcr_pid;
+ args.buf_sz = m->mux_buf_sz;
+ args.continuity_counter = &ctx->cc;
+
+ /* the 27Mhz clock will feed both parts of the PCR bitfield */
+ args.pcr = m->timing.clk;
+
+ nbytes += vidtv_ts_pcr_write_into(args);
+ m->mux_buf_offset += nbytes;
+
+ m->num_streamed_pcr++;
+
+ return nbytes;
+}
+
+static bool vidtv_mux_should_push_pcr(struct vidtv_mux *m)
+{
+ u64 next_pcr_at;
+
+ if (m->num_streamed_pcr == 0)
+ return true;
+
+ next_pcr_at = m->timing.start_jiffies +
+ usecs_to_jiffies(m->num_streamed_pcr *
+ m->timing.pcr_period_usecs);
+
+ return time_after64(m->timing.current_jiffies, next_pcr_at);
+}
+
+static bool vidtv_mux_should_push_si(struct vidtv_mux *m)
+{
+ u64 next_si_at;
+
+ if (m->num_streamed_si == 0)
+ return true;
+
+ next_si_at = m->timing.start_jiffies +
+ usecs_to_jiffies(m->num_streamed_si *
+ m->timing.si_period_usecs);
+
+ return time_after64(m->timing.current_jiffies, next_si_at);
+}
+
+static u32 vidtv_mux_packetize_access_units(struct vidtv_mux *m,
+ struct vidtv_encoder *e)
+{
+ u32 nbytes = 0;
+
+ struct pes_write_args args = {};
+ u32 initial_offset = m->mux_buf_offset;
+ struct vidtv_access_unit *au = e->access_units;
+
+ u8 *buf = NULL;
+ struct vidtv_mux_pid_ctx *pid_ctx = vidtv_mux_create_pid_ctx_once(m,
+ be16_to_cpu(e->es_pid));
+
+ args.dest_buf = m->mux_buf;
+ args.dest_buf_sz = m->mux_buf_sz;
+ args.pid = be16_to_cpu(e->es_pid);
+ args.encoder_id = e->id;
+ args.continuity_counter = &pid_ctx->cc;
+ args.stream_id = be16_to_cpu(e->stream_id);
+ args.send_pts = true;
+
+ while (au) {
+ buf = e->encoder_buf + au->offset;
+ args.from = buf;
+ args.access_unit_len = au->nbytes;
+ args.dest_offset = m->mux_buf_offset;
+ args.pts = au->pts;
+ args.pcr = m->timing.clk;
+
+ m->mux_buf_offset += vidtv_pes_write_into(args);
+
+ au = au->next;
+ }
+
+ /*
+ * clear the encoder state once the ES data has been written to the mux
+ * buffer
+ */
+ e->clear(e);
+
+ nbytes = m->mux_buf_offset - initial_offset;
+ return nbytes;
+}
+
+static u32 vidtv_mux_poll_encoders(struct vidtv_mux *m)
+{
+ u32 nbytes = 0;
+ u32 au_nbytes;
+ struct vidtv_channel *cur_chnl = m->channels;
+ struct vidtv_encoder *e = NULL;
+
+ while (cur_chnl) {
+ e = cur_chnl->encoders;
+
+ while (e) {
+ e->encode(e);
+ /* get the TS packets into the mux buffer */
+ au_nbytes = vidtv_mux_packetize_access_units(m, e);
+ nbytes += au_nbytes;
+ m->mux_buf_offset += au_nbytes;
+ /* grab next encoder */
+ e = e->next;
+ }
+
+ /* grab the next channel */
+ cur_chnl = cur_chnl->next;
+ }
+
+ return nbytes;
+}
+
+static u32 vidtv_mux_pad_with_nulls(struct vidtv_mux *m, u32 npkts)
+{
+ struct null_packet_write_args args = {};
+ u32 initial_offset = m->mux_buf_offset;
+ u32 nbytes; /* the number of bytes written by this function */
+ u32 i;
+ struct vidtv_mux_pid_ctx *ctx;
+
+ ctx = vidtv_mux_get_pid_ctx(m, TS_NULL_PACKET_PID);
+
+ args.dest_buf = m->mux_buf;
+ args.buf_sz = m->mux_buf_sz;
+ args.continuity_counter = &ctx->cc;
+ args.dest_offset = m->mux_buf_offset;
+
+ for (i = 0; i < npkts; ++i) {
+ m->mux_buf_offset += vidtv_ts_null_write_into(args);
+ args.dest_offset = m->mux_buf_offset;
+ }
+
+ nbytes = m->mux_buf_offset - initial_offset;
+
+ /* sanity check */
+ if (nbytes != npkts * TS_PACKET_LEN)
+ dev_err_ratelimited(m->dev, "%d != %d\n",
+ nbytes, npkts * TS_PACKET_LEN);
+
+ return nbytes;
+}
+
+static void vidtv_mux_clear(struct vidtv_mux *m)
+{
+ /* clear the packets currently in the mux */
+ memset(m->mux_buf, 0, m->mux_buf_sz * sizeof(*m->mux_buf));
+ /* point to the beginning of the buffer again */
+ m->mux_buf_offset = 0;
+}
+
+#define ERR_RATE 10000000
+static void vidtv_mux_tick(struct work_struct *work)
+{
+ struct vidtv_mux *m = container_of(work,
+ struct vidtv_mux,
+ mpeg_thread);
+ struct dtv_frontend_properties *c = &m->fe->dtv_property_cache;
+ u32 nbytes;
+ u32 npkts;
+ u32 tot_bits = 0;
+
+ while (m->streaming) {
+ nbytes = 0;
+
+ vidtv_mux_update_clk(m);
+
+ if (vidtv_mux_should_push_pcr(m))
+ nbytes += vidtv_mux_push_pcr(m);
+
+ if (vidtv_mux_should_push_si(m))
+ nbytes += vidtv_mux_push_si(m);
+
+ nbytes += vidtv_mux_poll_encoders(m);
+ nbytes += vidtv_mux_pad_with_nulls(m, 256);
+
+ npkts = nbytes / TS_PACKET_LEN;
+
+ /* if the buffer is not aligned there is a bug somewhere */
+ if (nbytes % TS_PACKET_LEN)
+ dev_err_ratelimited(m->dev, "Misaligned buffer\n");
+
+ if (m->on_new_packets_available_cb)
+ m->on_new_packets_available_cb(m->priv,
+ m->mux_buf,
+ npkts);
+
+ vidtv_mux_clear(m);
+
+ /*
+ * Update bytes and packet counts at DVBv5 stats
+ *
+ * For now, both pre and post bit counts are identical,
+ * but post BER count can be lower than pre BER, if the error
+ * correction logic discards packages.
+ */
+ c->pre_bit_count.stat[0].uvalue = nbytes * 8;
+ c->post_bit_count.stat[0].uvalue = nbytes * 8;
+ c->block_count.stat[0].uvalue += npkts;
+
+ /*
+ * Even without any visible errors for the user, the pre-BER
+ * stats usually have an error range up to 1E-6. So,
+ * add some random error increment count to it.
+ *
+ * Please notice that this is a poor guy's implementation,
+ * as it will produce one corrected bit error every time
+ * ceil(total bytes / ERR_RATE) is incremented, without
+ * any sort of (pseudo-)randomness.
+ */
+ tot_bits += nbytes * 8;
+ if (tot_bits > ERR_RATE) {
+ c->pre_bit_error.stat[0].uvalue++;
+ tot_bits -= ERR_RATE;
+ }
+
+ usleep_range(VIDTV_SLEEP_USECS, VIDTV_MAX_SLEEP_USECS);
+ }
+}
+
+void vidtv_mux_start_thread(struct vidtv_mux *m)
+{
+ if (m->streaming) {
+ dev_warn_ratelimited(m->dev, "Already streaming. Skipping.\n");
+ return;
+ }
+
+ m->streaming = true;
+ m->timing.start_jiffies = get_jiffies_64();
+ schedule_work(&m->mpeg_thread);
+}
+
+void vidtv_mux_stop_thread(struct vidtv_mux *m)
+{
+ if (m->streaming) {
+ m->streaming = false; /* thread will quit */
+ cancel_work_sync(&m->mpeg_thread);
+ }
+}
+
+struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe,
+ struct device *dev,
+ struct vidtv_mux_init_args args)
+{
+ struct vidtv_mux *m = kzalloc(sizeof(*m), GFP_KERNEL);
+
+ m->dev = dev;
+ m->fe = fe;
+ m->timing.pcr_period_usecs = args.pcr_period_usecs;
+ m->timing.si_period_usecs = args.si_period_usecs;
+
+ m->mux_rate_kbytes_sec = args.mux_rate_kbytes_sec;
+
+ m->on_new_packets_available_cb = args.on_new_packets_available_cb;
+
+ m->mux_buf = vzalloc(args.mux_buf_sz);
+ m->mux_buf_sz = args.mux_buf_sz;
+
+ m->pcr_pid = args.pcr_pid;
+ m->transport_stream_id = args.transport_stream_id;
+ m->priv = args.priv;
+ m->timing.current_jiffies = get_jiffies_64();
+
+ if (args.channels)
+ m->channels = args.channels;
+ else
+ vidtv_channels_init(m);
+
+ /* will alloc data for pmt_sections after initializing pat */
+ vidtv_channel_si_init(m);
+
+ INIT_WORK(&m->mpeg_thread, vidtv_mux_tick);
+
+ vidtv_mux_pid_ctx_init(m);
+
+ return m;
+}
+
+void vidtv_mux_destroy(struct vidtv_mux *m)
+{
+ vidtv_mux_stop_thread(m);
+ vidtv_mux_pid_ctx_destroy(m);
+ vidtv_channel_si_destroy(m);
+ vidtv_channels_destroy(m);
+ vfree(m->mux_buf);
+ kfree(m);
+}
diff --git a/drivers/media/test-drivers/vidtv/vidtv_mux.h b/drivers/media/test-drivers/vidtv/vidtv_mux.h
new file mode 100644
index 000000000000..2caa60623e97
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_mux.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Vidtv serves as a reference DVB driver and helps validate the existing APIs
+ * in the media subsystem. It can also aid developers working on userspace
+ * applications.
+ *
+ * This file contains the muxer logic for TS packets from different
+ * elementary streams.
+ *
+ * Loosely based on libavcodec/mpegtsenc.c
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#ifndef VIDTV_MUX_H
+#define VIDTV_MUX_H
+
+#include <linux/types.h>
+#include <linux/hashtable.h>
+#include <linux/workqueue.h>
+#include <media/dvb_frontend.h>
+
+#include "vidtv_psi.h"
+
+/**
+ * struct vidtv_mux_timing - Timing related information
+ *
+ * This is used to decide when PCR or PSI packets should be sent. This will also
+ * provide storage for the clock, which is used to compute the value for the PCR.
+ *
+ * @start_jiffies: The value of 'jiffies' when we started the mux thread.
+ * @current_jiffies: The value of 'jiffies' for the current iteration.
+ * @past_jiffies: The value of 'jiffies' for the past iteration.
+ * @clk: A 27Mhz clock from which we will drive the PCR. Updated proportionally
+ * on every iteration.
+ * @pcr_period_usecs: How often we should send PCR packets.
+ * @si_period_usecs: How often we should send PSI packets.
+ */
+struct vidtv_mux_timing {
+ u64 start_jiffies;
+ u64 current_jiffies;
+ u64 past_jiffies;
+
+ u64 clk;
+
+ u64 pcr_period_usecs;
+ u64 si_period_usecs;
+};
+
+/**
+ * struct vidtv_mux_si - Store the PSI context.
+ *
+ * This is used to store the PAT, PMT sections and SDT in use by the muxer.
+ *
+ * The muxer acquire these by looking into the hardcoded channels in
+ * vidtv_channel and then periodically sends the TS packets for them>
+ *
+ * @pat: The PAT in use by the muxer.
+ * @pmt_secs: The PMT sections in use by the muxer. One for each program in the PAT.
+ * @sdt: The SDT in use by the muxer.
+ */
+struct vidtv_mux_si {
+ /* the SI tables */
+ struct vidtv_psi_table_pat *pat;
+ struct vidtv_psi_table_pmt **pmt_secs; /* the PMT sections */
+ struct vidtv_psi_table_sdt *sdt;
+};
+
+/**
+ * struct vidtv_mux_pid_ctx - Store the context for a given TS PID.
+ * @pid: The TS PID.
+ * @cc: The continuity counter for this PID. It is incremented on every TS
+ * pack and it will wrap around at 0xf0. If the decoder notices a sudden jump in
+ * this counter this will trigger a discontinuity state.
+ * @h: This is embedded in a hash table, mapping pid -> vidtv_mux_pid_ctx
+ */
+struct vidtv_mux_pid_ctx {
+ u16 pid;
+ u8 cc; /* continuity counter */
+ struct hlist_node h;
+};
+
+/**
+ * struct vidtv_mux - A muxer abstraction loosely based in libavcodec/mpegtsenc.c
+ * @mux_rate_kbytes_sec: The bit rate for the TS, in kbytes.
+ * @timing: Keeps track of timing related information.
+ * @pid_ctx: A hash table to keep track of per-PID metadata.
+ * @on_new_packets_available_cb: A callback to inform of new TS packets ready.
+ * @mux_buf: A pointer to a buffer for this muxer. TS packets are stored there
+ * and then passed on to the bridge driver.
+ * @mux_buf_sz: The size for 'mux_buf'.
+ * @mux_buf_offset: The current offset into 'mux_buf'.
+ * @channels: The channels associated with this muxer.
+ * @si: Keeps track of the PSI context.
+ * @num_streamed_pcr: Number of PCR packets streamed.
+ * @num_streamed_si: The number of PSI packets streamed.
+ * @mpeg_thread: Thread responsible for the muxer loop.
+ * @streaming: whether 'mpeg_thread' is running.
+ * @pcr_pid: The TS PID used for the PSI packets. All channels will share the
+ * same PCR.
+ * @transport_stream_id: The transport stream ID
+ * @priv: Private data.
+ */
+struct vidtv_mux {
+ struct dvb_frontend *fe;
+ struct device *dev;
+
+ struct vidtv_mux_timing timing;
+
+ u32 mux_rate_kbytes_sec;
+
+ DECLARE_HASHTABLE(pid_ctx, 3);
+
+ void (*on_new_packets_available_cb)(void *priv, u8 *buf, u32 npackets);
+
+ u8 *mux_buf;
+ u32 mux_buf_sz;
+ u32 mux_buf_offset;
+
+ struct vidtv_channel *channels;
+
+ struct vidtv_mux_si si;
+ u64 num_streamed_pcr;
+ u64 num_streamed_si;
+
+ struct work_struct mpeg_thread;
+ bool streaming;
+
+ u16 pcr_pid;
+ u16 transport_stream_id;
+ void *priv;
+};
+
+/**
+ * struct vidtv_mux_init_args - Arguments used to inix the muxer.
+ * @mux_rate_kbytes_sec: The bit rate for the TS, in kbytes.
+ * @on_new_packets_available_cb: A callback to inform of new TS packets ready.
+ * @mux_buf_sz: The size for 'mux_buf'.
+ * @pcr_period_usecs: How often we should send PCR packets.
+ * @si_period_usecs: How often we should send PSI packets.
+ * @pcr_pid: The TS PID used for the PSI packets. All channels will share the
+ * same PCR.
+ * @transport_stream_id: The transport stream ID
+ * @channels: an optional list of channels to use
+ * @priv: Private data.
+ */
+struct vidtv_mux_init_args {
+ u32 mux_rate_kbytes_sec;
+ void (*on_new_packets_available_cb)(void *priv, u8 *buf, u32 npackets);
+ u32 mux_buf_sz;
+ u64 pcr_period_usecs;
+ u64 si_period_usecs;
+ u16 pcr_pid;
+ u16 transport_stream_id;
+ struct vidtv_channel *channels;
+ void *priv;
+};
+
+struct vidtv_mux *vidtv_mux_init(struct dvb_frontend *fe,
+ struct device *dev,
+ struct vidtv_mux_init_args args);
+void vidtv_mux_destroy(struct vidtv_mux *m);
+
+void vidtv_mux_start_thread(struct vidtv_mux *m);
+void vidtv_mux_stop_thread(struct vidtv_mux *m);
+
+#endif //VIDTV_MUX_H
diff --git a/drivers/media/test-drivers/vidtv/vidtv_pes.c b/drivers/media/test-drivers/vidtv/vidtv_pes.c
new file mode 100644
index 000000000000..1c75f88070e9
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_pes.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Vidtv serves as a reference DVB driver and helps validate the existing APIs
+ * in the media subsystem. It can also aid developers working on userspace
+ * applications.
+ *
+ * This file contains the logic to translate the ES data for one access unit
+ * from an encoder into MPEG TS packets. It does so by first encapsulating it
+ * with a PES header and then splitting it into TS packets.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__
+
+#include <linux/types.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <asm/byteorder.h>
+
+#include "vidtv_pes.h"
+#include "vidtv_common.h"
+#include "vidtv_encoder.h"
+#include "vidtv_ts.h"
+
+#define PRIVATE_STREAM_1_ID 0xbd /* private_stream_1. See SMPTE 302M-2007 p.6 */
+#define PES_HEADER_MAX_STUFFING_BYTES 32
+#define PES_TS_HEADER_MAX_STUFFING_BYTES 182
+
+static u32 vidtv_pes_op_get_len(bool send_pts, bool send_dts)
+{
+ u32 len = 0;
+
+ /* the flags must always be sent */
+ len += sizeof(struct vidtv_pes_optional);
+
+ /* From all optionals, we might send these for now */
+ if (send_pts && send_dts)
+ len += sizeof(struct vidtv_pes_optional_pts_dts);
+ else if (send_pts)
+ len += sizeof(struct vidtv_pes_optional_pts);
+
+ return len;
+}
+
+#define SIZE_PCR (6 + sizeof(struct vidtv_mpeg_ts_adaption))
+
+static u32 vidtv_pes_h_get_len(bool send_pts, bool send_dts)
+{
+ u32 len = 0;
+
+ /* PES header length notwithstanding stuffing bytes */
+
+ len += sizeof(struct vidtv_mpeg_pes);
+ len += vidtv_pes_op_get_len(send_pts, send_dts);
+
+ return len;
+}
+
+static u32 vidtv_pes_write_header_stuffing(struct pes_header_write_args args)
+{
+ /*
+ * This is a fixed 8-bit value equal to '0xFF' that can be inserted
+ * by the encoder, for example to meet the requirements of the channel.
+ * It is discarded by the decoder. No more than 32 stuffing bytes shall
+ * be present in one PES packet header.
+ */
+ if (args.n_pes_h_s_bytes > PES_HEADER_MAX_STUFFING_BYTES) {
+ pr_warn_ratelimited("More than %d stuffing bytes in PES packet header\n",
+ PES_HEADER_MAX_STUFFING_BYTES);
+ args.n_pes_h_s_bytes = PES_HEADER_MAX_STUFFING_BYTES;
+ }
+
+ return vidtv_memset(args.dest_buf,
+ args.dest_offset,
+ args.dest_buf_sz,
+ TS_FILL_BYTE,
+ args.n_pes_h_s_bytes);
+}
+
+static u32 vidtv_pes_write_pts_dts(struct pes_header_write_args args)
+{
+ u32 nbytes = 0; /* the number of bytes written by this function */
+
+ struct vidtv_pes_optional_pts pts = {};
+ struct vidtv_pes_optional_pts_dts pts_dts = {};
+ void *op = NULL;
+ size_t op_sz = 0;
+ u64 mask1;
+ u64 mask2;
+ u64 mask3;
+
+ if (!args.send_pts && args.send_dts)
+ return 0;
+
+ mask1 = GENMASK_ULL(32, 30);
+ mask2 = GENMASK_ULL(29, 15);
+ mask3 = GENMASK_ULL(14, 0);
+
+ /* see ISO/IEC 13818-1 : 2000 p. 32 */
+ if (args.send_pts && args.send_dts) {
+ pts_dts.pts1 = (0x3 << 4) | ((args.pts & mask1) >> 29) | 0x1;
+ pts_dts.pts2 = cpu_to_be16(((args.pts & mask2) >> 14) | 0x1);
+ pts_dts.pts3 = cpu_to_be16(((args.pts & mask3) << 1) | 0x1);
+
+ pts_dts.dts1 = (0x1 << 4) | ((args.dts & mask1) >> 29) | 0x1;
+ pts_dts.dts2 = cpu_to_be16(((args.dts & mask2) >> 14) | 0x1);
+ pts_dts.dts3 = cpu_to_be16(((args.dts & mask3) << 1) | 0x1);
+
+ op = &pts_dts;
+ op_sz = sizeof(pts_dts);
+
+ } else if (args.send_pts) {
+ pts.pts1 = (0x1 << 5) | ((args.pts & mask1) >> 29) | 0x1;
+ pts.pts2 = cpu_to_be16(((args.pts & mask2) >> 14) | 0x1);
+ pts.pts3 = cpu_to_be16(((args.pts & mask3) << 1) | 0x1);
+
+ op = &pts;
+ op_sz = sizeof(pts);
+ }
+
+ /* copy PTS/DTS optional */
+ nbytes += vidtv_memcpy(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ op,
+ op_sz);
+
+ return nbytes;
+}
+
+static u32 vidtv_pes_write_h(struct pes_header_write_args args)
+{
+ u32 nbytes = 0; /* the number of bytes written by this function */
+
+ struct vidtv_mpeg_pes pes_header = {};
+ struct vidtv_pes_optional pes_optional = {};
+ struct pes_header_write_args pts_dts_args = args;
+ u32 stream_id = (args.encoder_id == S302M) ? PRIVATE_STREAM_1_ID : args.stream_id;
+ u16 pes_opt_bitfield = 0x01 << 15;
+
+ pes_header.bitfield = cpu_to_be32((PES_START_CODE_PREFIX << 8) | stream_id);
+
+ pes_header.length = cpu_to_be16(vidtv_pes_op_get_len(args.send_pts,
+ args.send_dts) +
+ args.access_unit_len);
+
+ if (args.send_pts && args.send_dts)
+ pes_opt_bitfield |= (0x3 << 6);
+ else if (args.send_pts)
+ pes_opt_bitfield |= (0x1 << 7);
+
+ pes_optional.bitfield = cpu_to_be16(pes_opt_bitfield);
+ pes_optional.length = vidtv_pes_op_get_len(args.send_pts, args.send_dts) +
+ args.n_pes_h_s_bytes -
+ sizeof(struct vidtv_pes_optional);
+
+ /* copy header */
+ nbytes += vidtv_memcpy(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ &pes_header,
+ sizeof(pes_header));
+
+ /* copy optional header bits */
+ nbytes += vidtv_memcpy(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ &pes_optional,
+ sizeof(pes_optional));
+
+ /* copy the timing information */
+ pts_dts_args.dest_offset = args.dest_offset + nbytes;
+ nbytes += vidtv_pes_write_pts_dts(pts_dts_args);
+
+ /* write any PES header stuffing */
+ nbytes += vidtv_pes_write_header_stuffing(args);
+
+ return nbytes;
+}
+
+static u32 vidtv_pes_write_pcr_bits(u8 *to, u32 to_offset, u64 pcr)
+{
+ /* Exact same from ffmpeg. PCR is a counter driven by a 27Mhz clock */
+ u64 div;
+ u64 rem;
+ u8 *buf = to + to_offset;
+ u64 pcr_low;
+ u64 pcr_high;
+
+ div = div64_u64_rem(pcr, 300, &rem);
+
+ pcr_low = rem; /* pcr_low = pcr % 300 */
+ pcr_high = div; /* pcr_high = pcr / 300 */
+
+ *buf++ = pcr_high >> 25;
+ *buf++ = pcr_high >> 17;
+ *buf++ = pcr_high >> 9;
+ *buf++ = pcr_high >> 1;
+ *buf++ = pcr_high << 7 | pcr_low >> 8 | 0x7e;
+ *buf++ = pcr_low;
+
+ return 6;
+}
+
+static u32 vidtv_pes_write_stuffing(struct pes_ts_header_write_args *args,
+ u32 dest_offset, bool need_pcr,
+ u64 *last_pcr)
+{
+ struct vidtv_mpeg_ts_adaption ts_adap = {};
+ int stuff_nbytes;
+ u32 nbytes = 0;
+
+ if (!args->n_stuffing_bytes)
+ return 0;
+
+ ts_adap.random_access = 1;
+
+ /* length _immediately_ following 'adaptation_field_length' */
+ if (need_pcr) {
+ ts_adap.PCR = 1;
+ ts_adap.length = SIZE_PCR;
+ } else {
+ ts_adap.length = sizeof(ts_adap);
+ }
+ stuff_nbytes = args->n_stuffing_bytes - ts_adap.length;
+
+ ts_adap.length -= sizeof(ts_adap.length);
+
+ if (unlikely(stuff_nbytes < 0))
+ stuff_nbytes = 0;
+
+ ts_adap.length += stuff_nbytes;
+
+ /* write the adap after the TS header */
+ nbytes += vidtv_memcpy(args->dest_buf,
+ dest_offset + nbytes,
+ args->dest_buf_sz,
+ &ts_adap,
+ sizeof(ts_adap));
+
+ /* write the optional PCR */
+ if (need_pcr) {
+ nbytes += vidtv_pes_write_pcr_bits(args->dest_buf,
+ dest_offset + nbytes,
+ args->pcr);
+
+ *last_pcr = args->pcr;
+ }
+
+ /* write the stuffing bytes, if are there anything left */
+ if (stuff_nbytes)
+ nbytes += vidtv_memset(args->dest_buf,
+ dest_offset + nbytes,
+ args->dest_buf_sz,
+ TS_FILL_BYTE,
+ stuff_nbytes);
+
+ /*
+ * The n_stuffing_bytes contain a pre-calculated value of
+ * the amount of data that this function would read, made from
+ * vidtv_pes_h_get_len(). If something went wrong, print a warning
+ */
+ if (nbytes != args->n_stuffing_bytes)
+ pr_warn_ratelimited("write size was %d, expected %d\n",
+ nbytes, args->n_stuffing_bytes);
+
+ return nbytes;
+}
+
+static u32 vidtv_pes_write_ts_h(struct pes_ts_header_write_args args,
+ bool need_pcr, u64 *last_pcr)
+{
+ /* number of bytes written by this function */
+ u32 nbytes = 0;
+ struct vidtv_mpeg_ts ts_header = {};
+ u16 payload_start = !args.wrote_pes_header;
+
+ ts_header.sync_byte = TS_SYNC_BYTE;
+ ts_header.bitfield = cpu_to_be16((payload_start << 14) | args.pid);
+ ts_header.scrambling = 0;
+ ts_header.adaptation_field = (args.n_stuffing_bytes) > 0;
+ ts_header.payload = (args.n_stuffing_bytes) < PES_TS_HEADER_MAX_STUFFING_BYTES;
+
+ ts_header.continuity_counter = *args.continuity_counter;
+
+ vidtv_ts_inc_cc(args.continuity_counter);
+
+ /* write the TS header */
+ nbytes += vidtv_memcpy(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ &ts_header,
+ sizeof(ts_header));
+
+ /* write stuffing, if any */
+ nbytes += vidtv_pes_write_stuffing(&args, args.dest_offset + nbytes,
+ need_pcr, last_pcr);
+
+ return nbytes;
+}
+
+u32 vidtv_pes_write_into(struct pes_write_args args)
+{
+ u32 unaligned_bytes = (args.dest_offset % TS_PACKET_LEN);
+ struct pes_ts_header_write_args ts_header_args = {};
+ struct pes_header_write_args pes_header_args = {};
+ u32 remaining_len = args.access_unit_len;
+ bool wrote_pes_header = false;
+ u64 last_pcr = args.pcr;
+ bool need_pcr = true;
+ u32 available_space;
+ u32 payload_size;
+ u32 stuff_bytes;
+ u32 nbytes = 0;
+
+ if (unaligned_bytes) {
+ pr_warn_ratelimited("buffer is misaligned, while starting PES\n");
+
+ /* forcibly align and hope for the best */
+ nbytes += vidtv_memset(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ TS_FILL_BYTE,
+ TS_PACKET_LEN - unaligned_bytes);
+ }
+
+ if (args.send_dts && !args.send_pts) {
+ pr_warn_ratelimited("forbidden value '01' for PTS_DTS flags\n");
+ args.send_pts = true;
+ args.pts = args.dts;
+ }
+
+ /* see SMPTE 302M clause 6.4 */
+ if (args.encoder_id == S302M) {
+ args.send_dts = false;
+ args.send_pts = true;
+ }
+
+ while (remaining_len) {
+ available_space = TS_PAYLOAD_LEN;
+ /*
+ * The amount of space initially available in the TS packet.
+ * if this is the beginning of the PES packet, take into account
+ * the space needed for the TS header _and_ for the PES header
+ */
+ if (!wrote_pes_header)
+ available_space -= vidtv_pes_h_get_len(args.send_pts,
+ args.send_dts);
+
+ /*
+ * if the encoder has inserted stuffing bytes in the PES
+ * header, account for them.
+ */
+ available_space -= args.n_pes_h_s_bytes;
+
+ /* Take the extra adaptation into account if need to send PCR */
+ if (need_pcr) {
+ available_space -= SIZE_PCR;
+ stuff_bytes = SIZE_PCR;
+ } else {
+ stuff_bytes = 0;
+ }
+
+ /*
+ * how much of the _actual_ payload should be written in this
+ * packet.
+ */
+ if (remaining_len >= available_space) {
+ payload_size = available_space;
+ } else {
+ /* Last frame should ensure 188-bytes PS alignment */
+ payload_size = remaining_len;
+ stuff_bytes += available_space - payload_size;
+
+ /*
+ * Ensure that the stuff bytes will be within the
+ * allowed range, decrementing the number of payload
+ * bytes to write if needed.
+ */
+ if (stuff_bytes > PES_TS_HEADER_MAX_STUFFING_BYTES) {
+ u32 tmp = stuff_bytes - PES_TS_HEADER_MAX_STUFFING_BYTES;
+
+ stuff_bytes = PES_TS_HEADER_MAX_STUFFING_BYTES;
+ payload_size -= tmp;
+ }
+ }
+
+ /* write ts header */
+ ts_header_args.dest_buf = args.dest_buf;
+ ts_header_args.dest_offset = args.dest_offset + nbytes;
+ ts_header_args.dest_buf_sz = args.dest_buf_sz;
+ ts_header_args.pid = args.pid;
+ ts_header_args.pcr = args.pcr;
+ ts_header_args.continuity_counter = args.continuity_counter;
+ ts_header_args.wrote_pes_header = wrote_pes_header;
+ ts_header_args.n_stuffing_bytes = stuff_bytes;
+
+ nbytes += vidtv_pes_write_ts_h(ts_header_args, need_pcr,
+ &last_pcr);
+
+ need_pcr = false;
+
+ if (!wrote_pes_header) {
+ /* write the PES header only once */
+ pes_header_args.dest_buf = args.dest_buf;
+
+ pes_header_args.dest_offset = args.dest_offset +
+ nbytes;
+
+ pes_header_args.dest_buf_sz = args.dest_buf_sz;
+ pes_header_args.encoder_id = args.encoder_id;
+ pes_header_args.send_pts = args.send_pts;
+ pes_header_args.pts = args.pts;
+ pes_header_args.send_dts = args.send_dts;
+ pes_header_args.dts = args.dts;
+ pes_header_args.stream_id = args.stream_id;
+ pes_header_args.n_pes_h_s_bytes = args.n_pes_h_s_bytes;
+ pes_header_args.access_unit_len = args.access_unit_len;
+
+ nbytes += vidtv_pes_write_h(pes_header_args);
+ wrote_pes_header = true;
+ }
+
+ /* write as much of the payload as we possibly can */
+ nbytes += vidtv_memcpy(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ args.from,
+ payload_size);
+
+ args.from += payload_size;
+
+ remaining_len -= payload_size;
+ }
+
+ return nbytes;
+}
diff --git a/drivers/media/test-drivers/vidtv/vidtv_pes.h b/drivers/media/test-drivers/vidtv/vidtv_pes.h
new file mode 100644
index 000000000000..0ea9e863024d
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_pes.h
@@ -0,0 +1,191 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Vidtv serves as a reference DVB driver and helps validate the existing APIs
+ * in the media subsystem. It can also aid developers working on userspace
+ * applications.
+ *
+ * This file contains the logic to translate the ES data for one access unit
+ * from an encoder into MPEG TS packets. It does so by first encapsulating it
+ * with a PES header and then splitting it into TS packets.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#ifndef VIDTV_PES_H
+#define VIDTV_PES_H
+
+#include <asm/byteorder.h>
+#include <linux/types.h>
+
+#include "vidtv_common.h"
+
+#define PES_MAX_LEN 65536 /* Set 'length' to 0 if greater. Only possible for video. */
+#define PES_START_CODE_PREFIX 0x001 /* 00 00 01 */
+
+/* Used when sending PTS, but not DTS */
+struct vidtv_pes_optional_pts {
+ u8 pts1;
+ __be16 pts2;
+ __be16 pts3;
+} __packed;
+
+/* Used when sending both PTS and DTS */
+struct vidtv_pes_optional_pts_dts {
+ u8 pts1;
+ __be16 pts2;
+ __be16 pts3;
+
+ u8 dts1;
+ __be16 dts2;
+ __be16 dts3;
+} __packed;
+
+/* PES optional flags */
+struct vidtv_pes_optional {
+ /*
+ * These flags show which components are actually
+ * present in the "optional fields" in the optional PES
+ * header and which are not
+ *
+ * u16 two:2; //0x2
+ * u16 PES_scrambling_control:2;
+ * u16 PES_priority:1;
+ * u16 data_alignment_indicator:1; // unused
+ * u16 copyright:1;
+ * u16 original_or_copy:1;
+ * u16 PTS_DTS:2;
+ * u16 ESCR:1;
+ * u16 ES_rate:1;
+ * u16 DSM_trick_mode:1;
+ * u16 additional_copy_info:1;
+ * u16 PES_CRC:1;
+ * u16 PES_extension:1;
+ */
+ __be16 bitfield;
+ u8 length;
+} __packed;
+
+/* The PES header */
+struct vidtv_mpeg_pes {
+ __be32 bitfield; /* packet_start_code_prefix:24, stream_id: 8 */
+ /* after this field until the end of the PES data payload */
+ __be16 length;
+ struct vidtv_pes_optional optional[];
+} __packed;
+
+/**
+ * struct pes_header_write_args - Arguments to write a PES header.
+ * @dest_buf: The buffer to write into.
+ * @dest_offset: where to start writing in the dest_buffer.
+ * @dest_buf_sz: The size of the dest_buffer
+ * @encoder_id: Encoder id (see vidtv_encoder.h)
+ * @send_pts: Should we send PTS?
+ * @pts: PTS value to send.
+ * @send_dts: Should we send DTS?
+ * @dts: DTS value to send.
+ * @stream_id: The stream id to use. Ex: Audio streams (0xc0-0xdf), Video
+ * streams (0xe0-0xef).
+ * @n_pes_h_s_bytes: Padding bytes. Might be used by an encoder if needed, gets
+ * discarded by the decoder.
+ * @access_unit_len: The size of _one_ access unit (with any headers it might need)
+ */
+struct pes_header_write_args {
+ void *dest_buf;
+ u32 dest_offset;
+ u32 dest_buf_sz;
+ u32 encoder_id;
+
+ bool send_pts;
+ u64 pts;
+
+ bool send_dts;
+ u64 dts;
+
+ u16 stream_id;
+ /* might be used by an encoder if needed, gets discarded by decoder */
+ u32 n_pes_h_s_bytes;
+ u32 access_unit_len;
+};
+
+/**
+ * struct pes_ts_header_write_args - Arguments to write a TS header.
+ * @dest_buf: The buffer to write into.
+ * @dest_offset: where to start writing in the dest_buffer.
+ * @dest_buf_sz: The size of the dest_buffer
+ * @pid: The PID to use for the TS packets.
+ * @continuity_counter: Incremented on every new TS packet.
+ * @n_pes_h_s_bytes: Padding bytes. Might be used by an encoder if needed, gets
+ * discarded by the decoder.
+ */
+struct pes_ts_header_write_args {
+ void *dest_buf;
+ u32 dest_offset;
+ u32 dest_buf_sz;
+ u16 pid;
+ u8 *continuity_counter;
+ bool wrote_pes_header;
+ u32 n_stuffing_bytes;
+ u64 pcr;
+};
+
+/**
+ * struct pes_write_args - Arguments for the packetizer.
+ * @dest_buf: The buffer to write into.
+ * @from: A pointer to the encoder buffer containing one access unit.
+ * @access_unit_len: The size of _one_ access unit (with any headers it might need)
+ * @dest_offset: where to start writing in the dest_buffer.
+ * @dest_buf_sz: The size of the dest_buffer
+ * @pid: The PID to use for the TS packets.
+ * @encoder_id: Encoder id (see vidtv_encoder.h)
+ * @continuity_counter: Incremented on every new TS packet.
+ * @stream_id: The stream id to use. Ex: Audio streams (0xc0-0xdf), Video
+ * streams (0xe0-0xef).
+ * @send_pts: Should we send PTS?
+ * @pts: PTS value to send.
+ * @send_dts: Should we send DTS?
+ * @dts: DTS value to send.
+ * @n_pes_h_s_bytes: Padding bytes. Might be used by an encoder if needed, gets
+ * discarded by the decoder.
+ */
+struct pes_write_args {
+ void *dest_buf;
+ void *from;
+ u32 access_unit_len;
+
+ u32 dest_offset;
+ u32 dest_buf_sz;
+ u16 pid;
+
+ u32 encoder_id;
+
+ u8 *continuity_counter;
+
+ u16 stream_id;
+
+ bool send_pts;
+ u64 pts;
+
+ bool send_dts;
+ u64 dts;
+
+ u32 n_pes_h_s_bytes;
+ u64 pcr;
+};
+
+/**
+ * vidtv_pes_write_into - Write a PES packet as MPEG-TS packets into a buffer.
+ * @args: The args to use when writing
+ *
+ * This function translate the ES data for one access unit
+ * from an encoder into MPEG TS packets. It does so by first encapsulating it
+ * with a PES header and then splitting it into TS packets.
+ *
+ * The data is then written into the buffer pointed to by 'args.buf'
+ *
+ * Return: The number of bytes written into the buffer. This is usually NOT
+ * equal to the size of the access unit, since we need space for PES headers, TS headers
+ * and padding bytes, if any.
+ */
+u32 vidtv_pes_write_into(struct pes_write_args args);
+
+#endif // VIDTV_PES_H
diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.c b/drivers/media/test-drivers/vidtv/vidtv_psi.c
new file mode 100644
index 000000000000..82cf67dd27c0
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_psi.c
@@ -0,0 +1,1322 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * This file contains the logic to work with MPEG Program-Specific Information.
+ * These are defined both in ISO/IEC 13818-1 (systems) and ETSI EN 300 468.
+ * PSI is carried in the form of table structures, and although each table might
+ * technically be broken into one or more sections, we do not do this here,
+ * hence 'table' and 'section' are interchangeable for vidtv.
+ *
+ * This code currently supports three tables: PAT, PMT and SDT. These are the
+ * bare minimum to get userspace to recognize our MPEG transport stream. It can
+ * be extended to support more PSI tables in the future.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__
+
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/crc32.h>
+#include <linux/string.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/string.h>
+#include <asm/byteorder.h>
+
+#include "vidtv_psi.h"
+#include "vidtv_common.h"
+#include "vidtv_ts.h"
+
+#define CRC_SIZE_IN_BYTES 4
+#define MAX_VERSION_NUM 32
+
+static const u32 CRC_LUT[256] = {
+ /* from libdvbv5 */
+ 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, 0x130476dc, 0x17c56b6b,
+ 0x1a864db2, 0x1e475005, 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
+ 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, 0x4c11db70, 0x48d0c6c7,
+ 0x4593e01e, 0x4152fda9, 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
+ 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, 0x791d4014, 0x7ddc5da3,
+ 0x709f7b7a, 0x745e66cd, 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
+ 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, 0xbe2b5b58, 0xbaea46ef,
+ 0xb7a96036, 0xb3687d81, 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
+ 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, 0xc7361b4c, 0xc3f706fb,
+ 0xceb42022, 0xca753d95, 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
+ 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, 0x34867077, 0x30476dc0,
+ 0x3d044b19, 0x39c556ae, 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
+ 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, 0x018aeb13, 0x054bf6a4,
+ 0x0808d07d, 0x0cc9cdca, 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
+ 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, 0x5e9f46bf, 0x5a5e5b08,
+ 0x571d7dd1, 0x53dc6066, 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
+ 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, 0xbfa1b04b, 0xbb60adfc,
+ 0xb6238b25, 0xb2e29692, 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
+ 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, 0xe0b41de7, 0xe4750050,
+ 0xe9362689, 0xedf73b3e, 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
+ 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, 0xd5b88683, 0xd1799b34,
+ 0xdc3abded, 0xd8fba05a, 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
+ 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, 0x4f040d56, 0x4bc510e1,
+ 0x46863638, 0x42472b8f, 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
+ 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, 0x36194d42, 0x32d850f5,
+ 0x3f9b762c, 0x3b5a6b9b, 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
+ 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, 0xf12f560e, 0xf5ee4bb9,
+ 0xf8ad6d60, 0xfc6c70d7, 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
+ 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, 0xc423cd6a, 0xc0e2d0dd,
+ 0xcda1f604, 0xc960ebb3, 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
+ 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, 0x9b3660c6, 0x9ff77d71,
+ 0x92b45ba8, 0x9675461f, 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
+ 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, 0x4e8ee645, 0x4a4ffbf2,
+ 0x470cdd2b, 0x43cdc09c, 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
+ 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, 0x119b4be9, 0x155a565e,
+ 0x18197087, 0x1cd86d30, 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
+ 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, 0x2497d08d, 0x2056cd3a,
+ 0x2d15ebe3, 0x29d4f654, 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
+ 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, 0xe3a1cbc1, 0xe760d676,
+ 0xea23f0af, 0xeee2ed18, 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
+ 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, 0x9abc8bd5, 0x9e7d9662,
+ 0x933eb0bb, 0x97ffad0c, 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
+ 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
+};
+
+static inline u32 dvb_crc32(u32 crc, u8 *data, u32 len)
+{
+ /* from libdvbv5 */
+ while (len--)
+ crc = (crc << 8) ^ CRC_LUT[((crc >> 24) ^ *data++) & 0xff];
+ return crc;
+}
+
+static void vidtv_psi_update_version_num(struct vidtv_psi_table_header *h)
+{
+ h->version++;
+}
+
+static inline u16 vidtv_psi_sdt_serv_get_desc_loop_len(struct vidtv_psi_table_sdt_service *s)
+{
+ u16 mask;
+ u16 ret;
+
+ mask = GENMASK(11, 0);
+
+ ret = be16_to_cpu(s->bitfield) & mask;
+ return ret;
+}
+
+static inline u16 vidtv_psi_pmt_stream_get_desc_loop_len(struct vidtv_psi_table_pmt_stream *s)
+{
+ u16 mask;
+ u16 ret;
+
+ mask = GENMASK(9, 0);
+
+ ret = be16_to_cpu(s->bitfield2) & mask;
+ return ret;
+}
+
+static inline u16 vidtv_psi_pmt_get_desc_loop_len(struct vidtv_psi_table_pmt *p)
+{
+ u16 mask;
+ u16 ret;
+
+ mask = GENMASK(9, 0);
+
+ ret = be16_to_cpu(p->bitfield2) & mask;
+ return ret;
+}
+
+static inline u16 vidtv_psi_get_sec_len(struct vidtv_psi_table_header *h)
+{
+ u16 mask;
+ u16 ret;
+
+ mask = GENMASK(11, 0);
+
+ ret = be16_to_cpu(h->bitfield) & mask;
+ return ret;
+}
+
+inline u16 vidtv_psi_get_pat_program_pid(struct vidtv_psi_table_pat_program *p)
+{
+ u16 mask;
+ u16 ret;
+
+ mask = GENMASK(12, 0);
+
+ ret = be16_to_cpu(p->bitfield) & mask;
+ return ret;
+}
+
+inline u16 vidtv_psi_pmt_stream_get_elem_pid(struct vidtv_psi_table_pmt_stream *s)
+{
+ u16 mask;
+ u16 ret;
+
+ mask = GENMASK(12, 0);
+
+ ret = be16_to_cpu(s->bitfield) & mask;
+ return ret;
+}
+
+static inline void vidtv_psi_set_desc_loop_len(__be16 *bitfield, u16 new_len, u8 desc_len_nbits)
+{
+ u16 mask;
+ __be16 new;
+
+ mask = GENMASK(15, desc_len_nbits);
+
+ new = cpu_to_be16((be16_to_cpu(*bitfield) & mask) | new_len);
+ *bitfield = new;
+}
+
+static void vidtv_psi_set_sec_len(struct vidtv_psi_table_header *h, u16 new_len)
+{
+ u16 old_len = vidtv_psi_get_sec_len(h);
+ __be16 new;
+ u16 mask;
+
+ mask = GENMASK(15, 13);
+
+ new = cpu_to_be16((be16_to_cpu(h->bitfield) & mask) | new_len);
+
+ if (old_len > MAX_SECTION_LEN)
+ pr_warn_ratelimited("section length: %d > %d, old len was %d\n",
+ new_len,
+ MAX_SECTION_LEN,
+ old_len);
+
+ h->bitfield = new;
+}
+
+static u32 vidtv_psi_ts_psi_write_into(struct psi_write_args args)
+{
+ /*
+ * Packetize PSI sections into TS packets:
+ * push a TS header (4bytes) every 184 bytes
+ * manage the continuity_counter
+ * add stuffing (i.e. padding bytes) after the CRC
+ */
+
+ u32 nbytes_past_boundary = (args.dest_offset % TS_PACKET_LEN);
+ bool aligned = (nbytes_past_boundary == 0);
+ struct vidtv_mpeg_ts ts_header = {};
+
+ /* number of bytes written by this function */
+ u32 nbytes = 0;
+ /* how much there is left to write */
+ u32 remaining_len = args.len;
+ /* how much we can be written in this packet */
+ u32 payload_write_len = 0;
+ /* where we are in the source */
+ u32 payload_offset = 0;
+
+ const u16 PAYLOAD_START = args.new_psi_section;
+
+ if (!args.crc && !args.is_crc)
+ pr_warn_ratelimited("Missing CRC for chunk\n");
+
+ if (args.crc)
+ *args.crc = dvb_crc32(*args.crc, args.from, args.len);
+
+ if (args.new_psi_section && !aligned) {
+ pr_warn_ratelimited("Cannot write a new PSI section in a misaligned buffer\n");
+
+ /* forcibly align and hope for the best */
+ nbytes += vidtv_memset(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ TS_FILL_BYTE,
+ TS_PACKET_LEN - nbytes_past_boundary);
+ }
+
+ while (remaining_len) {
+ nbytes_past_boundary = (args.dest_offset + nbytes) % TS_PACKET_LEN;
+ aligned = (nbytes_past_boundary == 0);
+
+ if (aligned) {
+ /* if at a packet boundary, write a new TS header */
+ ts_header.sync_byte = TS_SYNC_BYTE;
+ ts_header.bitfield = cpu_to_be16((PAYLOAD_START << 14) | args.pid);
+ ts_header.scrambling = 0;
+ ts_header.continuity_counter = *args.continuity_counter;
+ ts_header.payload = 1;
+ /* no adaptation field */
+ ts_header.adaptation_field = 0;
+
+ /* copy the header */
+ nbytes += vidtv_memcpy(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ &ts_header,
+ sizeof(ts_header));
+ /*
+ * This will trigger a discontinuity if the buffer is full,
+ * effectively dropping the packet.
+ */
+ vidtv_ts_inc_cc(args.continuity_counter);
+ }
+
+ /* write the pointer_field in the first byte of the payload */
+ if (args.new_psi_section)
+ nbytes += vidtv_memset(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ 0x0,
+ 1);
+
+ /* write as much of the payload as possible */
+ nbytes_past_boundary = (args.dest_offset + nbytes) % TS_PACKET_LEN;
+ payload_write_len = min(TS_PACKET_LEN - nbytes_past_boundary, remaining_len);
+
+ nbytes += vidtv_memcpy(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ args.from + payload_offset,
+ payload_write_len);
+
+ /* 'payload_write_len' written from a total of 'len' requested*/
+ remaining_len -= payload_write_len;
+ payload_offset += payload_write_len;
+ }
+
+ /*
+ * fill the rest of the packet if there is any remaining space unused
+ */
+
+ nbytes_past_boundary = (args.dest_offset + nbytes) % TS_PACKET_LEN;
+
+ if (args.is_crc)
+ nbytes += vidtv_memset(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.dest_buf_sz,
+ TS_FILL_BYTE,
+ TS_PACKET_LEN - nbytes_past_boundary);
+
+ return nbytes;
+}
+
+static u32 table_section_crc32_write_into(struct crc32_write_args args)
+{
+ /* the CRC is the last entry in the section */
+ u32 nbytes = 0;
+ struct psi_write_args psi_args = {};
+
+ psi_args.dest_buf = args.dest_buf;
+ psi_args.from = &args.crc;
+ psi_args.len = CRC_SIZE_IN_BYTES;
+ psi_args.dest_offset = args.dest_offset;
+ psi_args.pid = args.pid;
+ psi_args.new_psi_section = false;
+ psi_args.continuity_counter = args.continuity_counter;
+ psi_args.is_crc = true;
+ psi_args.dest_buf_sz = args.dest_buf_sz;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ return nbytes;
+}
+
+struct vidtv_psi_desc_service *vidtv_psi_service_desc_init(struct vidtv_psi_desc *head,
+ enum service_type service_type,
+ char *service_name,
+ char *provider_name)
+{
+ struct vidtv_psi_desc_service *desc;
+ u32 service_name_len = service_name ? strlen(service_name) : 0;
+ u32 provider_name_len = provider_name ? strlen(provider_name) : 0;
+
+ desc = kzalloc(sizeof(*desc), GFP_KERNEL);
+
+ desc->type = SERVICE_DESCRIPTOR;
+
+ desc->length = sizeof_field(struct vidtv_psi_desc_service, service_type)
+ + sizeof_field(struct vidtv_psi_desc_service, provider_name_len)
+ + provider_name_len
+ + sizeof_field(struct vidtv_psi_desc_service, service_name_len)
+ + service_name_len;
+
+ desc->service_type = service_type;
+
+ desc->service_name_len = service_name_len;
+
+ if (service_name && service_name_len)
+ desc->service_name = kstrdup(service_name, GFP_KERNEL);
+
+ desc->provider_name_len = provider_name_len;
+
+ if (provider_name && provider_name_len)
+ desc->provider_name = kstrdup(provider_name, GFP_KERNEL);
+
+ if (head) {
+ while (head->next)
+ head = head->next;
+
+ head->next = (struct vidtv_psi_desc *)desc;
+ }
+ return desc;
+}
+
+struct vidtv_psi_desc_registration
+*vidtv_psi_registration_desc_init(struct vidtv_psi_desc *head,
+ __be32 format_id,
+ u8 *additional_ident_info,
+ u32 additional_info_len)
+{
+ struct vidtv_psi_desc_registration *desc;
+
+ desc = kzalloc(sizeof(*desc) + sizeof(format_id) + additional_info_len, GFP_KERNEL);
+
+ desc->type = REGISTRATION_DESCRIPTOR;
+
+ desc->length = sizeof_field(struct vidtv_psi_desc_registration, format_id)
+ + additional_info_len;
+
+ desc->format_id = format_id;
+
+ if (additional_ident_info && additional_info_len)
+ memcpy(desc->additional_identification_info,
+ additional_ident_info,
+ additional_info_len);
+
+ if (head) {
+ while (head->next)
+ head = head->next;
+
+ head->next = (struct vidtv_psi_desc *)desc;
+ }
+
+ return desc;
+}
+
+struct vidtv_psi_desc *vidtv_psi_desc_clone(struct vidtv_psi_desc *desc)
+{
+ struct vidtv_psi_desc *head = NULL;
+ struct vidtv_psi_desc *prev = NULL;
+ struct vidtv_psi_desc *curr = NULL;
+
+ struct vidtv_psi_desc_service *service;
+
+ while (desc) {
+ switch (desc->type) {
+ case SERVICE_DESCRIPTOR:
+ service = (struct vidtv_psi_desc_service *)desc;
+ curr = (struct vidtv_psi_desc *)
+ vidtv_psi_service_desc_init(head,
+ service->service_type,
+ service->service_name,
+ service->provider_name);
+ break;
+
+ case REGISTRATION_DESCRIPTOR:
+ default:
+ curr = kzalloc(sizeof(*desc) + desc->length, GFP_KERNEL);
+ memcpy(curr, desc, sizeof(*desc) + desc->length);
+ break;
+ }
+
+ if (curr)
+ curr->next = NULL;
+ if (!head)
+ head = curr;
+ if (prev)
+ prev->next = curr;
+
+ prev = curr;
+ desc = desc->next;
+ }
+
+ return head;
+}
+
+void vidtv_psi_desc_destroy(struct vidtv_psi_desc *desc)
+{
+ struct vidtv_psi_desc *curr = desc;
+ struct vidtv_psi_desc *tmp = NULL;
+
+ while (curr) {
+ tmp = curr;
+ curr = curr->next;
+
+ switch (tmp->type) {
+ case SERVICE_DESCRIPTOR:
+ kfree(((struct vidtv_psi_desc_service *)tmp)->provider_name);
+ kfree(((struct vidtv_psi_desc_service *)tmp)->service_name);
+
+ break;
+ case REGISTRATION_DESCRIPTOR:
+ /* nothing to do */
+ break;
+
+ default:
+ pr_warn_ratelimited("Possible leak: not handling descriptor type %d\n",
+ tmp->type);
+ break;
+ }
+
+ kfree(tmp);
+ }
+}
+
+static u16
+vidtv_psi_desc_comp_loop_len(struct vidtv_psi_desc *desc)
+{
+ u32 length = 0;
+
+ if (!desc)
+ return 0;
+
+ while (desc) {
+ length += sizeof_field(struct vidtv_psi_desc, type);
+ length += sizeof_field(struct vidtv_psi_desc, length);
+ length += desc->length; /* from 'length' field until the end of the descriptor */
+ desc = desc->next;
+ }
+
+ return length;
+}
+
+void vidtv_psi_desc_assign(struct vidtv_psi_desc **to,
+ struct vidtv_psi_desc *desc)
+{
+ if (desc == *to)
+ return;
+
+ if (*to)
+ vidtv_psi_desc_destroy(*to);
+
+ *to = desc;
+}
+
+void vidtv_pmt_desc_assign(struct vidtv_psi_table_pmt *pmt,
+ struct vidtv_psi_desc **to,
+ struct vidtv_psi_desc *desc)
+{
+ vidtv_psi_desc_assign(to, desc);
+ vidtv_psi_pmt_table_update_sec_len(pmt);
+
+ if (vidtv_psi_get_sec_len(&pmt->header) > MAX_SECTION_LEN)
+ vidtv_psi_desc_assign(to, NULL);
+
+ vidtv_psi_update_version_num(&pmt->header);
+}
+
+void vidtv_sdt_desc_assign(struct vidtv_psi_table_sdt *sdt,
+ struct vidtv_psi_desc **to,
+ struct vidtv_psi_desc *desc)
+{
+ vidtv_psi_desc_assign(to, desc);
+ vidtv_psi_sdt_table_update_sec_len(sdt);
+
+ if (vidtv_psi_get_sec_len(&sdt->header) > MAX_SECTION_LEN)
+ vidtv_psi_desc_assign(to, NULL);
+
+ vidtv_psi_update_version_num(&sdt->header);
+}
+
+static u32 vidtv_psi_desc_write_into(struct desc_write_args args)
+{
+ /* the number of bytes written by this function */
+ u32 nbytes = 0;
+ struct psi_write_args psi_args = {};
+
+ psi_args.dest_buf = args.dest_buf;
+ psi_args.from = &args.desc->type;
+
+ psi_args.len = sizeof_field(struct vidtv_psi_desc, type) +
+ sizeof_field(struct vidtv_psi_desc, length);
+
+ psi_args.dest_offset = args.dest_offset + nbytes;
+ psi_args.pid = args.pid;
+ psi_args.new_psi_section = false;
+ psi_args.continuity_counter = args.continuity_counter;
+ psi_args.is_crc = false;
+ psi_args.dest_buf_sz = args.dest_buf_sz;
+ psi_args.crc = args.crc;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ switch (args.desc->type) {
+ case SERVICE_DESCRIPTOR:
+ psi_args.dest_offset = args.dest_offset + nbytes;
+ psi_args.len = sizeof_field(struct vidtv_psi_desc_service, service_type) +
+ sizeof_field(struct vidtv_psi_desc_service, provider_name_len);
+ psi_args.from = &((struct vidtv_psi_desc_service *)args.desc)->service_type;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ psi_args.dest_offset = args.dest_offset + nbytes;
+ psi_args.len = ((struct vidtv_psi_desc_service *)args.desc)->provider_name_len;
+ psi_args.from = ((struct vidtv_psi_desc_service *)args.desc)->provider_name;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ psi_args.dest_offset = args.dest_offset + nbytes;
+ psi_args.len = sizeof_field(struct vidtv_psi_desc_service, service_name_len);
+ psi_args.from = &((struct vidtv_psi_desc_service *)args.desc)->service_name_len;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ psi_args.dest_offset = args.dest_offset + nbytes;
+ psi_args.len = ((struct vidtv_psi_desc_service *)args.desc)->service_name_len;
+ psi_args.from = ((struct vidtv_psi_desc_service *)args.desc)->service_name;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+ break;
+
+ case REGISTRATION_DESCRIPTOR:
+ default:
+ psi_args.dest_offset = args.dest_offset + nbytes;
+ psi_args.len = args.desc->length;
+ psi_args.from = &args.desc->data;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+ break;
+ }
+
+ return nbytes;
+}
+
+static u32
+vidtv_psi_table_header_write_into(struct header_write_args args)
+{
+ /* the number of bytes written by this function */
+ u32 nbytes = 0;
+ struct psi_write_args psi_args = {};
+
+ psi_args.dest_buf = args.dest_buf;
+ psi_args.from = args.h;
+ psi_args.len = sizeof(struct vidtv_psi_table_header);
+ psi_args.dest_offset = args.dest_offset;
+ psi_args.pid = args.pid;
+ psi_args.new_psi_section = true;
+ psi_args.continuity_counter = args.continuity_counter;
+ psi_args.is_crc = false;
+ psi_args.dest_buf_sz = args.dest_buf_sz;
+ psi_args.crc = args.crc;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ return nbytes;
+}
+
+void
+vidtv_psi_pat_table_update_sec_len(struct vidtv_psi_table_pat *pat)
+{
+ /* see ISO/IEC 13818-1 : 2000 p.43 */
+ u16 length = 0;
+ u32 i;
+
+ /* from immediately after 'section_length' until 'last_section_number'*/
+ length += PAT_LEN_UNTIL_LAST_SECTION_NUMBER;
+
+ /* do not count the pointer */
+ for (i = 0; i < pat->programs; ++i)
+ length += sizeof(struct vidtv_psi_table_pat_program) -
+ sizeof(struct vidtv_psi_table_pat_program *);
+
+ length += CRC_SIZE_IN_BYTES;
+
+ vidtv_psi_set_sec_len(&pat->header, length);
+}
+
+void vidtv_psi_pmt_table_update_sec_len(struct vidtv_psi_table_pmt *pmt)
+{
+ /* see ISO/IEC 13818-1 : 2000 p.46 */
+ u16 length = 0;
+ struct vidtv_psi_table_pmt_stream *s = pmt->stream;
+ u16 desc_loop_len;
+
+ /* from immediately after 'section_length' until 'program_info_length'*/
+ length += PMT_LEN_UNTIL_PROGRAM_INFO_LENGTH;
+
+ desc_loop_len = vidtv_psi_desc_comp_loop_len(pmt->descriptor);
+ vidtv_psi_set_desc_loop_len(&pmt->bitfield2, desc_loop_len, 10);
+
+ length += desc_loop_len;
+
+ while (s) {
+ /* skip both pointers at the end */
+ length += sizeof(struct vidtv_psi_table_pmt_stream) -
+ sizeof(struct vidtv_psi_desc *) -
+ sizeof(struct vidtv_psi_table_pmt_stream *);
+
+ desc_loop_len = vidtv_psi_desc_comp_loop_len(s->descriptor);
+ vidtv_psi_set_desc_loop_len(&s->bitfield2, desc_loop_len, 10);
+
+ length += desc_loop_len;
+
+ s = s->next;
+ }
+
+ length += CRC_SIZE_IN_BYTES;
+
+ vidtv_psi_set_sec_len(&pmt->header, length);
+}
+
+void vidtv_psi_sdt_table_update_sec_len(struct vidtv_psi_table_sdt *sdt)
+{
+ /* see ETSI EN 300 468 V 1.10.1 p.24 */
+ u16 length = 0;
+ struct vidtv_psi_table_sdt_service *s = sdt->service;
+ u16 desc_loop_len;
+
+ /*
+ * from immediately after 'section_length' until
+ * 'reserved_for_future_use'
+ */
+ length += SDT_LEN_UNTIL_RESERVED_FOR_FUTURE_USE;
+
+ while (s) {
+ /* skip both pointers at the end */
+ length += sizeof(struct vidtv_psi_table_sdt_service) -
+ sizeof(struct vidtv_psi_desc *) -
+ sizeof(struct vidtv_psi_table_sdt_service *);
+
+ desc_loop_len = vidtv_psi_desc_comp_loop_len(s->descriptor);
+ vidtv_psi_set_desc_loop_len(&s->bitfield, desc_loop_len, 12);
+
+ length += desc_loop_len;
+
+ s = s->next;
+ }
+
+ length += CRC_SIZE_IN_BYTES;
+
+ vidtv_psi_set_sec_len(&sdt->header, length);
+}
+
+struct vidtv_psi_table_pat_program*
+vidtv_psi_pat_program_init(struct vidtv_psi_table_pat_program *head,
+ u16 service_id,
+ u16 program_map_pid)
+{
+ struct vidtv_psi_table_pat_program *program;
+ const u16 RESERVED = 0x07;
+
+ program = kzalloc(sizeof(*program), GFP_KERNEL);
+
+ program->service_id = cpu_to_be16(service_id);
+
+ /* pid for the PMT section in the TS */
+ program->bitfield = cpu_to_be16((RESERVED << 13) | program_map_pid);
+ program->next = NULL;
+
+ if (head) {
+ while (head->next)
+ head = head->next;
+
+ head->next = program;
+ }
+
+ return program;
+}
+
+void
+vidtv_psi_pat_program_destroy(struct vidtv_psi_table_pat_program *p)
+{
+ struct vidtv_psi_table_pat_program *curr = p;
+ struct vidtv_psi_table_pat_program *tmp = NULL;
+
+ while (curr) {
+ tmp = curr;
+ curr = curr->next;
+ kfree(tmp);
+ }
+}
+
+void
+vidtv_psi_pat_program_assign(struct vidtv_psi_table_pat *pat,
+ struct vidtv_psi_table_pat_program *p)
+{
+ /* This function transfers ownership of p to the table */
+
+ u16 program_count = 0;
+ struct vidtv_psi_table_pat_program *program = p;
+
+ if (p == pat->program)
+ return;
+
+ while (program) {
+ ++program_count;
+ program = program->next;
+ }
+
+ pat->programs = program_count;
+ pat->program = p;
+
+ /* Recompute section length */
+ vidtv_psi_pat_table_update_sec_len(pat);
+
+ if (vidtv_psi_get_sec_len(&pat->header) > MAX_SECTION_LEN)
+ vidtv_psi_pat_program_assign(pat, NULL);
+
+ vidtv_psi_update_version_num(&pat->header);
+}
+
+struct vidtv_psi_table_pat *vidtv_psi_pat_table_init(u16 transport_stream_id)
+{
+ struct vidtv_psi_table_pat *pat = kzalloc(sizeof(*pat), GFP_KERNEL);
+ const u16 SYNTAX = 0x1;
+ const u16 ZERO = 0x0;
+ const u16 ONES = 0x03;
+
+ pat->header.table_id = 0x0;
+
+ pat->header.bitfield = cpu_to_be16((SYNTAX << 15) | (ZERO << 14) | (ONES << 12));
+ pat->header.id = cpu_to_be16(transport_stream_id);
+ pat->header.current_next = 0x1;
+
+ pat->header.version = 0x1f;
+
+ pat->header.one2 = 0x03;
+ pat->header.section_id = 0x0;
+ pat->header.last_section = 0x0;
+
+ pat->programs = 0;
+
+ vidtv_psi_pat_table_update_sec_len(pat);
+
+ return pat;
+}
+
+u32 vidtv_psi_pat_write_into(struct vidtv_psi_pat_write_args args)
+{
+ /* the number of bytes written by this function */
+ u32 nbytes = 0;
+ const u16 pat_pid = VIDTV_PAT_PID;
+ u32 crc = 0xffffffff;
+
+ struct vidtv_psi_table_pat_program *p = args.pat->program;
+
+ struct header_write_args h_args = {};
+ struct psi_write_args psi_args = {};
+ struct crc32_write_args c_args = {};
+
+ vidtv_psi_pat_table_update_sec_len(args.pat);
+
+ h_args.dest_buf = args.buf;
+ h_args.dest_offset = args.offset;
+ h_args.h = &args.pat->header;
+ h_args.pid = pat_pid;
+ h_args.continuity_counter = args.continuity_counter;
+ h_args.dest_buf_sz = args.buf_sz;
+ h_args.crc = &crc;
+
+ nbytes += vidtv_psi_table_header_write_into(h_args);
+
+ /* note that the field 'u16 programs' is not really part of the PAT */
+
+ psi_args.dest_buf = args.buf;
+ psi_args.pid = pat_pid;
+ psi_args.new_psi_section = false;
+ psi_args.continuity_counter = args.continuity_counter;
+ psi_args.is_crc = false;
+ psi_args.dest_buf_sz = args.buf_sz;
+ psi_args.crc = &crc;
+
+ while (p) {
+ /* copy the PAT programs */
+ psi_args.from = p;
+ /* skip the pointer */
+ psi_args.len = sizeof(*p) -
+ sizeof(struct vidtv_psi_table_pat_program *);
+ psi_args.dest_offset = args.offset + nbytes;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ p = p->next;
+ }
+
+ c_args.dest_buf = args.buf;
+ c_args.dest_offset = args.offset + nbytes;
+ c_args.crc = cpu_to_be32(crc);
+ c_args.pid = pat_pid;
+ c_args.continuity_counter = args.continuity_counter;
+ c_args.dest_buf_sz = args.buf_sz;
+
+ /* Write the CRC32 at the end */
+ nbytes += table_section_crc32_write_into(c_args);
+
+ return nbytes;
+}
+
+void
+vidtv_psi_pat_table_destroy(struct vidtv_psi_table_pat *p)
+{
+ vidtv_psi_pat_program_destroy(p->program);
+ kfree(p);
+}
+
+struct vidtv_psi_table_pmt_stream*
+vidtv_psi_pmt_stream_init(struct vidtv_psi_table_pmt_stream *head,
+ enum vidtv_psi_stream_types stream_type,
+ u16 es_pid)
+{
+ struct vidtv_psi_table_pmt_stream *stream;
+ const u16 RESERVED1 = 0x07;
+ const u16 RESERVED2 = 0x0f;
+ const u16 ZERO = 0x0;
+ u16 desc_loop_len;
+
+ stream = kzalloc(sizeof(*stream), GFP_KERNEL);
+
+ stream->type = stream_type;
+
+ stream->bitfield = cpu_to_be16((RESERVED1 << 13) | es_pid);
+
+ desc_loop_len = vidtv_psi_desc_comp_loop_len(stream->descriptor);
+
+ stream->bitfield2 = cpu_to_be16((RESERVED2 << 12) |
+ (ZERO << 10) |
+ desc_loop_len);
+ stream->next = NULL;
+
+ if (head) {
+ while (head->next)
+ head = head->next;
+
+ head->next = stream;
+ }
+
+ return stream;
+}
+
+void vidtv_psi_pmt_stream_destroy(struct vidtv_psi_table_pmt_stream *s)
+{
+ struct vidtv_psi_table_pmt_stream *curr_stream = s;
+ struct vidtv_psi_table_pmt_stream *tmp_stream = NULL;
+
+ while (curr_stream) {
+ tmp_stream = curr_stream;
+ curr_stream = curr_stream->next;
+ vidtv_psi_desc_destroy(tmp_stream->descriptor);
+ kfree(tmp_stream);
+ }
+}
+
+void vidtv_psi_pmt_stream_assign(struct vidtv_psi_table_pmt *pmt,
+ struct vidtv_psi_table_pmt_stream *s)
+{
+ /* This function transfers ownership of s to the table */
+ if (s == pmt->stream)
+ return;
+
+ pmt->stream = s;
+ vidtv_psi_pmt_table_update_sec_len(pmt);
+
+ if (vidtv_psi_get_sec_len(&pmt->header) > MAX_SECTION_LEN)
+ vidtv_psi_pmt_stream_assign(pmt, NULL);
+
+ vidtv_psi_update_version_num(&pmt->header);
+}
+
+u16 vidtv_psi_pmt_get_pid(struct vidtv_psi_table_pmt *section,
+ struct vidtv_psi_table_pat *pat)
+{
+ struct vidtv_psi_table_pat_program *program = pat->program;
+
+ /*
+ * service_id is the same as program_number in the
+ * corresponding program_map_section
+ * see ETSI EN 300 468 v1.15.1 p. 24
+ */
+ while (program) {
+ if (program->service_id == section->header.id)
+ return vidtv_psi_get_pat_program_pid(program);
+
+ program = program->next;
+ }
+
+ return TS_LAST_VALID_PID + 1; /* not found */
+}
+
+struct vidtv_psi_table_pmt *vidtv_psi_pmt_table_init(u16 program_number,
+ u16 pcr_pid)
+{
+ struct vidtv_psi_table_pmt *pmt = kzalloc(sizeof(*pmt), GFP_KERNEL);
+ const u16 SYNTAX = 0x1;
+ const u16 ZERO = 0x0;
+ const u16 ONES = 0x03;
+ const u16 RESERVED1 = 0x07;
+ const u16 RESERVED2 = 0x0f;
+ u16 desc_loop_len;
+
+ if (!pcr_pid)
+ pcr_pid = 0x1fff;
+
+ pmt->header.table_id = 0x2;
+
+ pmt->header.bitfield = cpu_to_be16((SYNTAX << 15) | (ZERO << 14) | (ONES << 12));
+
+ pmt->header.id = cpu_to_be16(program_number);
+ pmt->header.current_next = 0x1;
+
+ pmt->header.version = 0x1f;
+
+ pmt->header.one2 = ONES;
+ pmt->header.section_id = 0;
+ pmt->header.last_section = 0;
+
+ pmt->bitfield = cpu_to_be16((RESERVED1 << 13) | pcr_pid);
+
+ desc_loop_len = vidtv_psi_desc_comp_loop_len(pmt->descriptor);
+
+ pmt->bitfield2 = cpu_to_be16((RESERVED2 << 12) |
+ (ZERO << 10) |
+ desc_loop_len);
+
+ vidtv_psi_pmt_table_update_sec_len(pmt);
+
+ return pmt;
+}
+
+u32 vidtv_psi_pmt_write_into(struct vidtv_psi_pmt_write_args args)
+{
+ /* the number of bytes written by this function */
+ u32 nbytes = 0;
+ u32 crc = 0xffffffff;
+
+ struct vidtv_psi_desc *table_descriptor = args.pmt->descriptor;
+ struct vidtv_psi_table_pmt_stream *stream = args.pmt->stream;
+ struct vidtv_psi_desc *stream_descriptor = (stream) ?
+ args.pmt->stream->descriptor :
+ NULL;
+
+ struct header_write_args h_args = {};
+ struct psi_write_args psi_args = {};
+ struct desc_write_args d_args = {};
+ struct crc32_write_args c_args = {};
+
+ vidtv_psi_pmt_table_update_sec_len(args.pmt);
+
+ h_args.dest_buf = args.buf;
+ h_args.dest_offset = args.offset;
+ h_args.h = &args.pmt->header;
+ h_args.pid = args.pid;
+ h_args.continuity_counter = args.continuity_counter;
+ h_args.dest_buf_sz = args.buf_sz;
+ h_args.crc = &crc;
+
+ nbytes += vidtv_psi_table_header_write_into(h_args);
+
+ /* write the two bitfields */
+ psi_args.dest_buf = args.buf;
+ psi_args.from = &args.pmt->bitfield;
+ psi_args.len = sizeof_field(struct vidtv_psi_table_pmt, bitfield) +
+ sizeof_field(struct vidtv_psi_table_pmt, bitfield2);
+
+ psi_args.dest_offset = args.offset + nbytes;
+ psi_args.pid = args.pid;
+ psi_args.new_psi_section = false;
+ psi_args.continuity_counter = args.continuity_counter;
+ psi_args.is_crc = false;
+ psi_args.dest_buf_sz = args.buf_sz;
+ psi_args.crc = &crc;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ while (table_descriptor) {
+ /* write the descriptors, if any */
+ d_args.dest_buf = args.buf;
+ d_args.dest_offset = args.offset + nbytes;
+ d_args.desc = table_descriptor;
+ d_args.pid = args.pid;
+ d_args.continuity_counter = args.continuity_counter;
+ d_args.dest_buf_sz = args.buf_sz;
+ d_args.crc = &crc;
+
+ nbytes += vidtv_psi_desc_write_into(d_args);
+
+ table_descriptor = table_descriptor->next;
+ }
+
+ while (stream) {
+ /* write the streams, if any */
+ psi_args.from = stream;
+ psi_args.len = sizeof_field(struct vidtv_psi_table_pmt_stream, type) +
+ sizeof_field(struct vidtv_psi_table_pmt_stream, bitfield) +
+ sizeof_field(struct vidtv_psi_table_pmt_stream, bitfield2);
+ psi_args.dest_offset = args.offset + nbytes;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ while (stream_descriptor) {
+ /* write the stream descriptors, if any */
+ d_args.dest_buf = args.buf;
+ d_args.dest_offset = args.offset + nbytes;
+ d_args.desc = stream_descriptor;
+ d_args.pid = args.pid;
+ d_args.continuity_counter = args.continuity_counter;
+ d_args.dest_buf_sz = args.buf_sz;
+ d_args.crc = &crc;
+
+ nbytes += vidtv_psi_desc_write_into(d_args);
+
+ stream_descriptor = stream_descriptor->next;
+ }
+
+ stream = stream->next;
+ }
+
+ c_args.dest_buf = args.buf;
+ c_args.dest_offset = args.offset + nbytes;
+ c_args.crc = cpu_to_be32(crc);
+ c_args.pid = args.pid;
+ c_args.continuity_counter = args.continuity_counter;
+ c_args.dest_buf_sz = args.buf_sz;
+
+ /* Write the CRC32 at the end */
+ nbytes += table_section_crc32_write_into(c_args);
+
+ return nbytes;
+}
+
+void vidtv_psi_pmt_table_destroy(struct vidtv_psi_table_pmt *pmt)
+{
+ vidtv_psi_desc_destroy(pmt->descriptor);
+ vidtv_psi_pmt_stream_destroy(pmt->stream);
+ kfree(pmt);
+}
+
+struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 transport_stream_id)
+{
+ struct vidtv_psi_table_sdt *sdt = kzalloc(sizeof(*sdt), GFP_KERNEL);
+ const u16 SYNTAX = 0x1;
+ const u16 ONE = 0x1;
+ const u16 ONES = 0x03;
+ const u16 RESERVED = 0xff;
+
+ sdt->header.table_id = 0x42;
+
+ sdt->header.bitfield = cpu_to_be16((SYNTAX << 15) | (ONE << 14) | (ONES << 12));
+
+ /*
+ * This is a 16-bit field which serves as a label for identification
+ * of the TS, about which the SDT informs, from any other multiplex
+ * within the delivery system.
+ */
+ sdt->header.id = cpu_to_be16(transport_stream_id);
+ sdt->header.current_next = ONE;
+
+ sdt->header.version = 0x1f;
+
+ sdt->header.one2 = ONES;
+ sdt->header.section_id = 0;
+ sdt->header.last_section = 0;
+
+ /*
+ * FIXME: The network_id range from 0xFF01 to 0xFFFF is used to
+ * indicate temporary private use. For now, let's use the first
+ * value.
+ * This can be changed to something more useful, when support for
+ * NIT gets added
+ */
+ sdt->network_id = cpu_to_be16(0xff01);
+ sdt->reserved = RESERVED;
+
+ vidtv_psi_sdt_table_update_sec_len(sdt);
+
+ return sdt;
+}
+
+u32 vidtv_psi_sdt_write_into(struct vidtv_psi_sdt_write_args args)
+{
+ u32 nbytes = 0;
+ u16 sdt_pid = VIDTV_SDT_PID; /* see ETSI EN 300 468 v1.15.1 p. 11 */
+
+ u32 crc = 0xffffffff;
+
+ struct vidtv_psi_table_sdt_service *service = args.sdt->service;
+ struct vidtv_psi_desc *service_desc = (args.sdt->service) ?
+ args.sdt->service->descriptor :
+ NULL;
+
+ struct header_write_args h_args = {};
+ struct psi_write_args psi_args = {};
+ struct desc_write_args d_args = {};
+ struct crc32_write_args c_args = {};
+
+ vidtv_psi_sdt_table_update_sec_len(args.sdt);
+
+ h_args.dest_buf = args.buf;
+ h_args.dest_offset = args.offset;
+ h_args.h = &args.sdt->header;
+ h_args.pid = sdt_pid;
+ h_args.continuity_counter = args.continuity_counter;
+ h_args.dest_buf_sz = args.buf_sz;
+ h_args.crc = &crc;
+
+ nbytes += vidtv_psi_table_header_write_into(h_args);
+
+ psi_args.dest_buf = args.buf;
+ psi_args.from = &args.sdt->network_id;
+
+ psi_args.len = sizeof_field(struct vidtv_psi_table_sdt, network_id) +
+ sizeof_field(struct vidtv_psi_table_sdt, reserved);
+
+ psi_args.dest_offset = args.offset + nbytes;
+ psi_args.pid = sdt_pid;
+ psi_args.new_psi_section = false;
+ psi_args.continuity_counter = args.continuity_counter;
+ psi_args.is_crc = false;
+ psi_args.dest_buf_sz = args.buf_sz;
+ psi_args.crc = &crc;
+
+ /* copy u16 network_id + u8 reserved)*/
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ while (service) {
+ /* copy the services, if any */
+ psi_args.from = service;
+ /* skip both pointers at the end */
+ psi_args.len = sizeof(struct vidtv_psi_table_sdt_service) -
+ sizeof(struct vidtv_psi_desc *) -
+ sizeof(struct vidtv_psi_table_sdt_service *);
+ psi_args.dest_offset = args.offset + nbytes;
+
+ nbytes += vidtv_psi_ts_psi_write_into(psi_args);
+
+ while (service_desc) {
+ /* copy the service descriptors, if any */
+ d_args.dest_buf = args.buf;
+ d_args.dest_offset = args.offset + nbytes;
+ d_args.desc = service_desc;
+ d_args.pid = sdt_pid;
+ d_args.continuity_counter = args.continuity_counter;
+ d_args.dest_buf_sz = args.buf_sz;
+ d_args.crc = &crc;
+
+ nbytes += vidtv_psi_desc_write_into(d_args);
+
+ service_desc = service_desc->next;
+ }
+
+ service = service->next;
+ }
+
+ c_args.dest_buf = args.buf;
+ c_args.dest_offset = args.offset + nbytes;
+ c_args.crc = cpu_to_be32(crc);
+ c_args.pid = sdt_pid;
+ c_args.continuity_counter = args.continuity_counter;
+ c_args.dest_buf_sz = args.buf_sz;
+
+ /* Write the CRC at the end */
+ nbytes += table_section_crc32_write_into(c_args);
+
+ return nbytes;
+}
+
+void vidtv_psi_sdt_table_destroy(struct vidtv_psi_table_sdt *sdt)
+{
+ vidtv_psi_sdt_service_destroy(sdt->service);
+ kfree(sdt);
+}
+
+struct vidtv_psi_table_sdt_service
+*vidtv_psi_sdt_service_init(struct vidtv_psi_table_sdt_service *head,
+ u16 service_id)
+{
+ struct vidtv_psi_table_sdt_service *service;
+
+ service = kzalloc(sizeof(*service), GFP_KERNEL);
+
+ /*
+ * ETSI 300 468: this is a 16bit field which serves as a label to
+ * identify this service from any other service within the TS.
+ * The service id is the same as the program number in the
+ * corresponding program_map_section
+ */
+ service->service_id = cpu_to_be16(service_id);
+ service->EIT_schedule = 0x0;
+ service->EIT_present_following = 0x0;
+ service->reserved = 0x3f;
+
+ service->bitfield = cpu_to_be16(RUNNING << 13);
+
+ if (head) {
+ while (head->next)
+ head = head->next;
+
+ head->next = service;
+ }
+
+ return service;
+}
+
+void
+vidtv_psi_sdt_service_destroy(struct vidtv_psi_table_sdt_service *service)
+{
+ struct vidtv_psi_table_sdt_service *curr = service;
+ struct vidtv_psi_table_sdt_service *tmp = NULL;
+
+ while (curr) {
+ tmp = curr;
+ curr = curr->next;
+ vidtv_psi_desc_destroy(tmp->descriptor);
+ kfree(tmp);
+ }
+}
+
+void
+vidtv_psi_sdt_service_assign(struct vidtv_psi_table_sdt *sdt,
+ struct vidtv_psi_table_sdt_service *service)
+{
+ if (service == sdt->service)
+ return;
+
+ sdt->service = service;
+
+ /* recompute section length */
+ vidtv_psi_sdt_table_update_sec_len(sdt);
+
+ if (vidtv_psi_get_sec_len(&sdt->header) > MAX_SECTION_LEN)
+ vidtv_psi_sdt_service_assign(sdt, NULL);
+
+ vidtv_psi_update_version_num(&sdt->header);
+}
+
+struct vidtv_psi_table_pmt**
+vidtv_psi_pmt_create_sec_for_each_pat_entry(struct vidtv_psi_table_pat *pat, u16 pcr_pid)
+
+{
+ /*
+ * PMTs contain information about programs. For each program,
+ * there is one PMT section. This function will create a section
+ * for each program found in the PAT
+ */
+ struct vidtv_psi_table_pat_program *program = pat->program;
+ struct vidtv_psi_table_pmt **pmt_secs;
+ u32 i = 0;
+
+ /* a section for each program_id */
+ pmt_secs = kcalloc(pat->programs,
+ sizeof(struct vidtv_psi_table_pmt *),
+ GFP_KERNEL);
+
+ while (program) {
+ pmt_secs[i] = vidtv_psi_pmt_table_init(be16_to_cpu(program->service_id), pcr_pid);
+ ++i;
+ program = program->next;
+ }
+
+ return pmt_secs;
+}
+
+struct vidtv_psi_table_pmt
+*vidtv_psi_find_pmt_sec(struct vidtv_psi_table_pmt **pmt_sections,
+ u16 nsections,
+ u16 program_num)
+{
+ /* find the PMT section associated with 'program_num' */
+ struct vidtv_psi_table_pmt *sec = NULL;
+ u32 i;
+
+ for (i = 0; i < nsections; ++i) {
+ sec = pmt_sections[i];
+ if (be16_to_cpu(sec->header.id) == program_num)
+ return sec;
+ }
+
+ return NULL; /* not found */
+}
diff --git a/drivers/media/test-drivers/vidtv/vidtv_psi.h b/drivers/media/test-drivers/vidtv/vidtv_psi.h
new file mode 100644
index 000000000000..3f962cc78278
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_psi.h
@@ -0,0 +1,577 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * This file contains the logic to work with MPEG Program-Specific Information.
+ * These are defined both in ISO/IEC 13818-1 (systems) and ETSI EN 300 468.
+ * PSI is carried in the form of table structures, and although each table might
+ * technically be broken into one or more sections, we do not do this here,
+ * hence 'table' and 'section' are interchangeable for vidtv.
+ *
+ * This code currently supports three tables: PAT, PMT and SDT. These are the
+ * bare minimum to get userspace to recognize our MPEG transport stream. It can
+ * be extended to support more PSI tables in the future.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#ifndef VIDTV_PSI_H
+#define VIDTV_PSI_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+/*
+ * all section lengths start immediately after the 'section_length' field
+ * see ISO/IEC 13818-1 : 2000 and ETSI EN 300 468 V 1.10.1 for
+ * reference
+ */
+#define PAT_LEN_UNTIL_LAST_SECTION_NUMBER 5
+#define PMT_LEN_UNTIL_PROGRAM_INFO_LENGTH 9
+#define SDT_LEN_UNTIL_RESERVED_FOR_FUTURE_USE 8
+#define MAX_SECTION_LEN 1021
+#define VIDTV_PAT_PID 0 /* mandated by the specs */
+#define VIDTV_SDT_PID 0x0011 /* mandated by the specs */
+
+enum vidtv_psi_descriptors {
+ REGISTRATION_DESCRIPTOR = 0x05, /* See ISO/IEC 13818-1 section 2.6.8 */
+ SERVICE_DESCRIPTOR = 0x48, /* See ETSI EN 300 468 section 6.2.33 */
+};
+
+enum vidtv_psi_stream_types {
+ STREAM_PRIVATE_DATA = 0x06, /* see ISO/IEC 13818-1 2000 p. 48 */
+};
+
+/**
+ * struct vidtv_psi_desc - A generic PSI descriptor type.
+ * The descriptor length is an 8-bit field specifying the total number of bytes of the data portion
+ * of the descriptor following the byte defining the value of this field.
+ */
+struct vidtv_psi_desc {
+ struct vidtv_psi_desc *next;
+ u8 type;
+ u8 length;
+ u8 data[];
+} __packed;
+
+/**
+ * struct vidtv_psi_desc_service - Service descriptor.
+ * See ETSI EN 300 468 section 6.2.33.
+ */
+struct vidtv_psi_desc_service {
+ struct vidtv_psi_desc *next;
+ u8 type;
+ u8 length;
+
+ u8 service_type;
+ u8 provider_name_len;
+ char *provider_name;
+ u8 service_name_len;
+ char *service_name;
+} __packed;
+
+/**
+ * struct vidtv_psi_desc_registration - A registration descriptor.
+ * See ISO/IEC 13818-1 section 2.6.8
+ */
+struct vidtv_psi_desc_registration {
+ struct vidtv_psi_desc *next;
+ u8 type;
+ u8 length;
+
+ /*
+ * The format_identifier is a 32-bit value obtained from a Registration
+ * Authority as designated by ISO/IEC JTC 1/SC 29.
+ */
+ __be32 format_id;
+ /*
+ * The meaning of additional_identification_info bytes, if any, are
+ * defined by the assignee of that format_identifier, and once defined
+ * they shall not change.
+ */
+ u8 additional_identification_info[];
+} __packed;
+
+/**
+ * struct vidtv_psi_table_header - A header that is present for all PSI tables.
+ */
+struct vidtv_psi_table_header {
+ u8 table_id;
+
+ __be16 bitfield; /* syntax: 1, zero: 1, one: 2, section_length: 13 */
+
+ __be16 id; /* TS ID */
+ u8 current_next:1;
+ u8 version:5;
+ u8 one2:2;
+ u8 section_id; /* section_number */
+ u8 last_section; /* last_section_number */
+} __packed;
+
+/**
+ * struct vidtv_psi_table_pat_program - A single program in the PAT
+ * See ISO/IEC 13818-1 : 2000 p.43
+ */
+struct vidtv_psi_table_pat_program {
+ __be16 service_id;
+ __be16 bitfield; /* reserved: 3, program_map_pid/network_pid: 13 */
+ struct vidtv_psi_table_pat_program *next;
+} __packed;
+
+/**
+ * struct vidtv_psi_table_pat - The Program Allocation Table (PAT)
+ * See ISO/IEC 13818-1 : 2000 p.43
+ */
+struct vidtv_psi_table_pat {
+ struct vidtv_psi_table_header header;
+ u16 programs; /* Included by libdvbv5, not part of the table and not actually serialized */
+ struct vidtv_psi_table_pat_program *program;
+} __packed;
+
+/**
+ * struct vidtv_psi_table_sdt_service - Represents a service in the SDT.
+ * see ETSI EN 300 468 v1.15.1 section 5.2.3.
+ */
+struct vidtv_psi_table_sdt_service {
+ __be16 service_id;
+ u8 EIT_present_following:1;
+ u8 EIT_schedule:1;
+ u8 reserved:6;
+ __be16 bitfield; /* running_status: 3, free_ca:1, desc_loop_len:12 */
+ struct vidtv_psi_desc *descriptor;
+ struct vidtv_psi_table_sdt_service *next;
+} __packed;
+
+/**
+ * struct vidtv_psi_table_sdt - Represents the Service Description Table
+ * see ETSI EN 300 468 v1.15.1 section 5.2.3.
+ */
+
+struct vidtv_psi_table_sdt {
+ struct vidtv_psi_table_header header;
+ __be16 network_id; /* original_network_id */
+ u8 reserved;
+ struct vidtv_psi_table_sdt_service *service;
+} __packed;
+
+/**
+ * enum service_running_status - Status of a SDT service.
+ * see ETSI EN 300 468 v1.15.1 section 5.2.3 table 6.
+ */
+enum service_running_status {
+ RUNNING = 0x4,
+};
+
+/**
+ * enum service_type - The type of a SDT service.
+ * see ETSI EN 300 468 v1.15.1 section 6.2.33, table 81.
+ */
+enum service_type {
+ /* see ETSI EN 300 468 v1.15.1 p. 77 */
+ DIGITAL_TELEVISION_SERVICE = 0x1,
+};
+
+/**
+ * struct vidtv_psi_table_pmt_stream - A single stream in the PMT.
+ * See ISO/IEC 13818-1 : 2000 p.46.
+ */
+struct vidtv_psi_table_pmt_stream {
+ u8 type;
+ __be16 bitfield; /* reserved: 3, elementary_pid: 13 */
+ __be16 bitfield2; /*reserved: 4, zero: 2, desc_length: 10 */
+ struct vidtv_psi_desc *descriptor;
+ struct vidtv_psi_table_pmt_stream *next;
+} __packed;
+
+/**
+ * struct vidtv_psi_table_pmt - The Program Map Table (PMT).
+ * See ISO/IEC 13818-1 : 2000 p.46.
+ */
+struct vidtv_psi_table_pmt {
+ struct vidtv_psi_table_header header;
+ __be16 bitfield; /* reserved:3, pcr_pid: 13 */
+ __be16 bitfield2; /* reserved: 4, zero: 2, desc_len: 10 */
+ struct vidtv_psi_desc *descriptor;
+ struct vidtv_psi_table_pmt_stream *stream;
+} __packed;
+
+/**
+ * struct psi_write_args - Arguments for the PSI packetizer.
+ * @dest_buf: The buffer to write into.
+ * @from: PSI data to be copied.
+ * @len: How much to write.
+ * @dest_offset: where to start writing in the dest_buffer.
+ * @pid: TS packet ID.
+ * @new_psi_section: Set when starting a table section.
+ * @continuity_counter: Incremented on every new packet.
+ * @is_crc: Set when writing the CRC at the end.
+ * @dest_buf_sz: The size of the dest_buffer
+ * @crc: a pointer to store the crc for this chunk
+ */
+struct psi_write_args {
+ void *dest_buf;
+ void *from;
+ size_t len;
+ u32 dest_offset;
+ u16 pid;
+ bool new_psi_section;
+ u8 *continuity_counter;
+ bool is_crc;
+ u32 dest_buf_sz;
+ u32 *crc;
+};
+
+/**
+ * struct desc_write_args - Arguments in order to write a descriptor.
+ * @dest_buf: The buffer to write into.
+ * @dest_offset: where to start writing in the dest_buffer.
+ * @desc: A pointer to the descriptor
+ * @pid: TS packet ID.
+ * @continuity_counter: Incremented on every new packet.
+ * @dest_buf_sz: The size of the dest_buffer
+ * @crc: a pointer to store the crc for this chunk
+ */
+struct desc_write_args {
+ void *dest_buf;
+ u32 dest_offset;
+ struct vidtv_psi_desc *desc;
+ u16 pid;
+ u8 *continuity_counter;
+ u32 dest_buf_sz;
+ u32 *crc;
+};
+
+/**
+ * struct crc32_write_args - Arguments in order to write the CRC at the end of
+ * the PSI tables.
+ * @dest_buf: The buffer to write into.
+ * @dest_offset: where to start writing in the dest_buffer.
+ * @crc: the CRC value to write
+ * @pid: TS packet ID.
+ * @continuity_counter: Incremented on every new packet.
+ * @dest_buf_sz: The size of the dest_buffer
+ */
+struct crc32_write_args {
+ void *dest_buf;
+ u32 dest_offset;
+ __be32 crc;
+ u16 pid;
+ u8 *continuity_counter;
+ u32 dest_buf_sz;
+};
+
+/**
+ * struct header_write_args - Arguments in order to write the common table
+ * header
+ * @dest_buf: The buffer to write into.
+ * @dest_offset: where to start writing in the dest_buffer.
+ * @h: a pointer to the header.
+ * @pid: TS packet ID.
+ * @continuity_counter: Incremented on every new packet.
+ * @dest_buf_sz: The size of the dest_buffer
+ * @crc: a pointer to store the crc for this chunk
+ */
+struct header_write_args {
+ void *dest_buf;
+ u32 dest_offset;
+ struct vidtv_psi_table_header *h;
+ u16 pid;
+ u8 *continuity_counter;
+ u32 dest_buf_sz;
+ u32 *crc;
+};
+
+struct vidtv_psi_desc_service *vidtv_psi_service_desc_init(struct vidtv_psi_desc *head,
+ enum service_type service_type,
+ char *service_name,
+ char *provider_name);
+
+struct vidtv_psi_desc_registration
+*vidtv_psi_registration_desc_init(struct vidtv_psi_desc *head,
+ __be32 format_id,
+ u8 *additional_ident_info,
+ u32 additional_info_len);
+
+struct vidtv_psi_table_pat_program
+*vidtv_psi_pat_program_init(struct vidtv_psi_table_pat_program *head,
+ u16 service_id,
+ u16 program_map_pid);
+
+struct vidtv_psi_table_pmt_stream*
+vidtv_psi_pmt_stream_init(struct vidtv_psi_table_pmt_stream *head,
+ enum vidtv_psi_stream_types stream_type,
+ u16 es_pid);
+
+struct vidtv_psi_table_pat *vidtv_psi_pat_table_init(u16 transport_stream_id);
+
+struct vidtv_psi_table_pmt *vidtv_psi_pmt_table_init(u16 program_number,
+ u16 pcr_pid);
+
+struct vidtv_psi_table_sdt *vidtv_psi_sdt_table_init(u16 transport_stream_id);
+
+struct vidtv_psi_table_sdt_service*
+vidtv_psi_sdt_service_init(struct vidtv_psi_table_sdt_service *head,
+ u16 service_id);
+
+void
+vidtv_psi_desc_destroy(struct vidtv_psi_desc *desc);
+
+void
+vidtv_psi_pat_program_destroy(struct vidtv_psi_table_pat_program *p);
+
+void
+vidtv_psi_pat_table_destroy(struct vidtv_psi_table_pat *p);
+
+void
+vidtv_psi_pmt_stream_destroy(struct vidtv_psi_table_pmt_stream *s);
+
+void
+vidtv_psi_pmt_table_destroy(struct vidtv_psi_table_pmt *pmt);
+
+void
+vidtv_psi_sdt_table_destroy(struct vidtv_psi_table_sdt *sdt);
+
+void
+vidtv_psi_sdt_service_destroy(struct vidtv_psi_table_sdt_service *service);
+
+/**
+ * vidtv_psi_sdt_service_assign - Assigns the service loop to the SDT.
+ * @sdt: The SDT to assign to.
+ * @service: The service loop (one or more services)
+ *
+ * This will free the previous service loop in the table.
+ * This will assign ownership of the service loop to the table, i.e. the table
+ * will free this service loop when a call to its destroy function is made.
+ */
+void
+vidtv_psi_sdt_service_assign(struct vidtv_psi_table_sdt *sdt,
+ struct vidtv_psi_table_sdt_service *service);
+
+/**
+ * vidtv_psi_desc_assign - Assigns a descriptor loop at some point
+ * @to: Where to assign this descriptor loop to
+ * @desc: The descriptor loop that will be assigned.
+ *
+ * This will free the loop in 'to', if any.
+ */
+void vidtv_psi_desc_assign(struct vidtv_psi_desc **to,
+ struct vidtv_psi_desc *desc);
+
+/**
+ * vidtv_psi_pmt_desc_assign - Assigns a descriptor loop at some point in a PMT section.
+ * @pmt: The PMT section that will contain the descriptor loop
+ * @to: Where in the PMT to assign this descriptor loop to
+ * @desc: The descriptor loop that will be assigned.
+ *
+ * This will free the loop in 'to', if any.
+ * This will assign ownership of the loop to the table, i.e. the table
+ * will free this loop when a call to its destroy function is made.
+ */
+void vidtv_pmt_desc_assign(struct vidtv_psi_table_pmt *pmt,
+ struct vidtv_psi_desc **to,
+ struct vidtv_psi_desc *desc);
+
+/**
+ * vidtv_psi_sdt_desc_assign - Assigns a descriptor loop at some point in a SDT.
+ * @sdt: The SDT that will contain the descriptor loop
+ * @to: Where in the PMT to assign this descriptor loop to
+ * @desc: The descriptor loop that will be assigned.
+ *
+ * This will free the loop in 'to', if any.
+ * This will assign ownership of the loop to the table, i.e. the table
+ * will free this loop when a call to its destroy function is made.
+ */
+void vidtv_sdt_desc_assign(struct vidtv_psi_table_sdt *sdt,
+ struct vidtv_psi_desc **to,
+ struct vidtv_psi_desc *desc);
+
+/**
+ * vidtv_psi_pat_program_assign - Assigns the program loop to the PAT.
+ * @pat: The PAT to assign to.
+ * @p: The program loop (one or more programs)
+ *
+ * This will free the previous program loop in the table.
+ * This will assign ownership of the program loop to the table, i.e. the table
+ * will free this program loop when a call to its destroy function is made.
+ */
+void vidtv_psi_pat_program_assign(struct vidtv_psi_table_pat *pat,
+ struct vidtv_psi_table_pat_program *p);
+
+/**
+ * vidtv_psi_pmt_stream_assign - Assigns the stream loop to the PAT.
+ * @pmt: The PMT to assign to.
+ * @s: The stream loop (one or more streams)
+ *
+ * This will free the previous stream loop in the table.
+ * This will assign ownership of the stream loop to the table, i.e. the table
+ * will free this stream loop when a call to its destroy function is made.
+ */
+void vidtv_psi_pmt_stream_assign(struct vidtv_psi_table_pmt *pmt,
+ struct vidtv_psi_table_pmt_stream *s);
+
+struct vidtv_psi_desc *vidtv_psi_desc_clone(struct vidtv_psi_desc *desc);
+
+/**
+ * vidtv_psi_create_sec_for_each_pat_entry - Create a PMT section for each
+ * program found in the PAT
+ * @pat: The PAT to look for programs.
+ * @s: The stream loop (one or more streams)
+ * @pcr_pid: packet ID for the PCR to be used for the program described in this
+ * PMT section
+ */
+struct vidtv_psi_table_pmt**
+vidtv_psi_pmt_create_sec_for_each_pat_entry(struct vidtv_psi_table_pat *pat, u16 pcr_pid);
+
+/**
+ * vidtv_psi_pmt_get_pid - Get the TS PID for a PMT section.
+ * @section: The PMT section whose PID we want to retrieve.
+ * @pat: The PAT table to look into.
+ *
+ * Returns: the TS PID for 'section'
+ */
+u16 vidtv_psi_pmt_get_pid(struct vidtv_psi_table_pmt *section,
+ struct vidtv_psi_table_pat *pat);
+
+/**
+ * vidtv_psi_pat_table_update_sec_len - Recompute and update the PAT section length.
+ * @pat: The PAT whose length is to be updated.
+ *
+ * This will traverse the table and accumulate the length of its components,
+ * which is then used to replace the 'section_length' field.
+ *
+ * If section_length > MAX_SECTION_LEN, the operation fails.
+ */
+void vidtv_psi_pat_table_update_sec_len(struct vidtv_psi_table_pat *pat);
+
+/**
+ * vidtv_psi_pmt_table_update_sec_len - Recompute and update the PMT section length.
+ * @pmt: The PMT whose length is to be updated.
+ *
+ * This will traverse the table and accumulate the length of its components,
+ * which is then used to replace the 'section_length' field.
+ *
+ * If section_length > MAX_SECTION_LEN, the operation fails.
+ */
+void vidtv_psi_pmt_table_update_sec_len(struct vidtv_psi_table_pmt *pmt);
+
+/**
+ * vidtv_psi_sdt_table_update_sec_len - Recompute and update the SDT section length.
+ * @sdt: The SDT whose length is to be updated.
+ *
+ * This will traverse the table and accumulate the length of its components,
+ * which is then used to replace the 'section_length' field.
+ *
+ * If section_length > MAX_SECTION_LEN, the operation fails.
+ */
+void vidtv_psi_sdt_table_update_sec_len(struct vidtv_psi_table_sdt *sdt);
+
+/**
+ * struct vidtv_psi_pat_write_args - Arguments for writing a PAT table
+ * @buf: The destination buffer.
+ * @offset: The offset into the destination buffer.
+ * @pat: A pointer to the PAT.
+ * @buf_sz: The size of the destination buffer.
+ * @continuity_counter: A pointer to the CC. Incremented on every new packet.
+ *
+ */
+struct vidtv_psi_pat_write_args {
+ char *buf;
+ u32 offset;
+ struct vidtv_psi_table_pat *pat;
+ u32 buf_sz;
+ u8 *continuity_counter;
+};
+
+/**
+ * vidtv_psi_pat_write_into - Write PAT as MPEG-TS packets into a buffer.
+ * @args: An instance of struct vidtv_psi_pat_write_args
+ *
+ * This function writes the MPEG TS packets for a PAT table into a buffer.
+ * Calling code will usually generate the PAT via a call to its init function
+ * and thus is responsible for freeing it.
+ *
+ * Return: The number of bytes written into the buffer. This is NOT
+ * equal to the size of the PAT, since more space is needed for TS headers during TS
+ * encapsulation.
+ */
+u32 vidtv_psi_pat_write_into(struct vidtv_psi_pat_write_args args);
+
+/**
+ * struct vidtv_psi_sdt_write_args - Arguments for writing a SDT table
+ * @buf: The destination buffer.
+ * @offset: The offset into the destination buffer.
+ * @sdt: A pointer to the SDT.
+ * @buf_sz: The size of the destination buffer.
+ * @continuity_counter: A pointer to the CC. Incremented on every new packet.
+ *
+ */
+
+struct vidtv_psi_sdt_write_args {
+ char *buf;
+ u32 offset;
+ struct vidtv_psi_table_sdt *sdt;
+ u32 buf_sz;
+ u8 *continuity_counter;
+};
+
+/**
+ * vidtv_psi_sdt_write_into - Write SDT as MPEG-TS packets into a buffer.
+ * @args: an instance of struct vidtv_psi_sdt_write_args
+ *
+ * This function writes the MPEG TS packets for a SDT table into a buffer.
+ * Calling code will usually generate the SDT via a call to its init function
+ * and thus is responsible for freeing it.
+ *
+ * Return: The number of bytes written into the buffer. This is NOT
+ * equal to the size of the SDT, since more space is needed for TS headers during TS
+ * encapsulation.
+ */
+u32 vidtv_psi_sdt_write_into(struct vidtv_psi_sdt_write_args args);
+
+/**
+ * struct vidtv_psi_pmt_write_args - Arguments for writing a PMT section
+ * @buf: The destination buffer.
+ * @offset: The offset into the destination buffer.
+ * @pmt: A pointer to the PMT.
+ * @buf_sz: The size of the destination buffer.
+ * @continuity_counter: A pointer to the CC. Incremented on every new packet.
+ *
+ */
+struct vidtv_psi_pmt_write_args {
+ char *buf;
+ u32 offset;
+ struct vidtv_psi_table_pmt *pmt;
+ u16 pid;
+ u32 buf_sz;
+ u8 *continuity_counter;
+ u16 pcr_pid;
+};
+
+/**
+ * vidtv_psi_pmt_write_into - Write PMT as MPEG-TS packets into a buffer.
+ * @args: an instance of struct vidtv_psi_pmt_write_args
+ *
+ * This function writes the MPEG TS packets for a PMT section into a buffer.
+ * Calling code will usually generate the PMT section via a call to its init function
+ * and thus is responsible for freeing it.
+ *
+ * Return: The number of bytes written into the buffer. This is NOT
+ * equal to the size of the PMT section, since more space is needed for TS headers
+ * during TS encapsulation.
+ */
+u32 vidtv_psi_pmt_write_into(struct vidtv_psi_pmt_write_args args);
+
+/**
+ * vidtv_psi_find_pmt_sec - Finds the PMT section for 'program_num'
+ * @pmt_sections: The sections to look into.
+ * @nsections: The number of sections.
+ * @program_num: The 'program_num' from PAT pointing to a PMT section.
+ *
+ * Return: A pointer to the PMT, if found, or NULL.
+ */
+struct vidtv_psi_table_pmt *vidtv_psi_find_pmt_sec(struct vidtv_psi_table_pmt **pmt_sections,
+ u16 nsections,
+ u16 program_num);
+
+u16 vidtv_psi_get_pat_program_pid(struct vidtv_psi_table_pat_program *p);
+u16 vidtv_psi_pmt_stream_get_elem_pid(struct vidtv_psi_table_pmt_stream *s);
+
+#endif // VIDTV_PSI_H
diff --git a/drivers/media/test-drivers/vidtv/vidtv_s302m.c b/drivers/media/test-drivers/vidtv/vidtv_s302m.c
new file mode 100644
index 000000000000..a447ccbd68d5
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_s302m.c
@@ -0,0 +1,502 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Vidtv serves as a reference DVB driver and helps validate the existing APIs
+ * in the media subsystem. It can also aid developers working on userspace
+ * applications.
+ *
+ * This file contains the code for an AES3 (also known as AES/EBU) encoder.
+ * It is based on EBU Tech 3250 and SMPTE 302M technical documents.
+ *
+ * This encoder currently supports 16bit AES3 subframes using 16bit signed
+ * integers.
+ *
+ * Note: AU stands for Access Unit, and AAU stands for Audio Access Unit
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__
+
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/crc32.h>
+#include <linux/vmalloc.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/fixp-arith.h>
+
+#include <linux/math64.h>
+#include <asm/byteorder.h>
+
+#include "vidtv_s302m.h"
+#include "vidtv_encoder.h"
+#include "vidtv_common.h"
+
+#define S302M_SAMPLING_RATE_HZ 48000
+#define PES_PRIVATE_STREAM_1 0xbd /* PES: private_stream_1 */
+#define S302M_BLOCK_SZ 192
+#define S302M_SIN_LUT_NUM_ELEM 1024
+
+/* these are retrieved empirically from ffmpeg/libavcodec */
+#define FF_S302M_DEFAULT_NUM_FRAMES 1115
+#define FF_S302M_DEFAULT_PTS_INCREMENT 2090
+#define FF_S302M_DEFAULT_PTS_OFFSET 100000
+
+/* Used by the tone generator: number of samples for PI */
+#define PI 180
+
+static const u8 reverse[256] = {
+ /* from ffmpeg */
+ 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0,
+ 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
+ 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, 0x04, 0x84, 0x44, 0xC4,
+ 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
+ 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, 0x1C, 0x9C, 0x5C, 0xDC,
+ 0x3C, 0xBC, 0x7C, 0xFC, 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
+ 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, 0x0A, 0x8A, 0x4A, 0xCA,
+ 0x2A, 0xAA, 0x6A, 0xEA, 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
+ 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6,
+ 0x36, 0xB6, 0x76, 0xF6, 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
+ 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, 0x01, 0x81, 0x41, 0xC1,
+ 0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
+ 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99, 0x59, 0xD9,
+ 0x39, 0xB9, 0x79, 0xF9, 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
+ 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, 0x0D, 0x8D, 0x4D, 0xCD,
+ 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
+ 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3,
+ 0x33, 0xB3, 0x73, 0xF3, 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
+ 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, 0x07, 0x87, 0x47, 0xC7,
+ 0x27, 0xA7, 0x67, 0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
+ 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF,
+ 0x3F, 0xBF, 0x7F, 0xFF,
+};
+
+struct tone_duration {
+ enum musical_notes note;
+ int duration;
+};
+
+#define COMPASS 120 /* beats per minute (Allegro) */
+static const struct tone_duration beethoven_5th_symphony[] = {
+ { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128},
+ { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128},
+ { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128},
+ { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128},
+ { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128},
+ { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128},
+ { NOTE_GS_5, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128},
+ { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_5, 128},
+ { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128},
+ { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128},
+ { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128},
+ { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128},
+ { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128},
+ { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128},
+ { NOTE_C_6, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128},
+ { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_SILENT, 128},
+
+ { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128},
+ { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128},
+ { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128},
+ { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128},
+ { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128},
+ { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128},
+ { NOTE_GS_5, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128},
+ { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_5, 128},
+ { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128},
+ { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_B_5, 128},
+ { NOTE_D_6, 128}, { NOTE_C_6, 128}, { NOTE_A_3, 128},
+ { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_C_5, 128},
+ { NOTE_E_5, 128}, { NOTE_A_5, 128}, { NOTE_E_3, 128},
+ { NOTE_E_4, 128}, { NOTE_GS_4, 128}, { NOTE_E_5, 128},
+ { NOTE_C_6, 128}, { NOTE_B_5, 128}, { NOTE_A_3, 128},
+ { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_B_4, 128},
+ { NOTE_C_5, 128}, { NOTE_D_5, 128}, { NOTE_C_4, 128},
+ { NOTE_G_4, 128}, { NOTE_C_5, 128}, { NOTE_G_4, 128},
+ { NOTE_F_5, 128}, { NOTE_E_5, 128}, { NOTE_G_3, 128},
+ { NOTE_G_4, 128}, { NOTE_B_3, 128}, { NOTE_F_4, 128},
+ { NOTE_E_5, 128}, { NOTE_D_5, 128}, { NOTE_A_3, 128},
+ { NOTE_E_4, 128}, { NOTE_A_4, 128}, { NOTE_E_4, 128},
+ { NOTE_D_5, 128}, { NOTE_C_5, 128}, { NOTE_E_3, 128},
+ { NOTE_E_4, 128}, { NOTE_E_5, 255}, { NOTE_E_6, 128},
+ { NOTE_E_5, 128}, { NOTE_E_6, 128}, { NOTE_E_5, 255},
+ { NOTE_DS_5, 128}, { NOTE_E_5, 128}, { NOTE_DS_6, 128},
+ { NOTE_E_6, 128}, { NOTE_DS_5, 128}, { NOTE_E_5, 128},
+ { NOTE_DS_6, 128}, { NOTE_E_6, 128}, { NOTE_DS_6, 128},
+ { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128},
+ { NOTE_B_5, 128}, { NOTE_D_6, 128}, { NOTE_C_6, 128},
+ { NOTE_A_3, 128}, { NOTE_E_4, 128}, { NOTE_A_4, 128},
+ { NOTE_C_5, 128}, { NOTE_E_5, 128}, { NOTE_A_5, 128},
+ { NOTE_E_3, 128}, { NOTE_E_4, 128}, { NOTE_GS_4, 128},
+ { NOTE_E_5, 128}, { NOTE_GS_5, 128}, { NOTE_B_5, 128},
+ { NOTE_A_3, 128}, { NOTE_E_4, 128}, { NOTE_A_4, 128},
+ { NOTE_E_5, 128}, { NOTE_E_6, 128}, { NOTE_DS_6, 128},
+ { NOTE_E_6, 128}, { NOTE_DS_6, 128}, { NOTE_E_6, 128},
+ { NOTE_B_5, 128}, { NOTE_D_6, 128}, { NOTE_C_6, 128},
+ { NOTE_A_3, 128}, { NOTE_E_4, 128}, { NOTE_A_4, 128},
+ { NOTE_C_5, 128}, { NOTE_E_5, 128}, { NOTE_A_5, 128},
+ { NOTE_E_3, 128}, { NOTE_E_4, 128}, { NOTE_GS_4, 128},
+ { NOTE_E_5, 128}, { NOTE_C_6, 128}, { NOTE_B_5, 128},
+ { NOTE_C_5, 255}, { NOTE_C_5, 255}, { NOTE_SILENT, 512},
+};
+
+static struct vidtv_access_unit *vidtv_s302m_access_unit_init(struct vidtv_access_unit *head)
+{
+ struct vidtv_access_unit *au = kzalloc(sizeof(*au), GFP_KERNEL);
+
+ if (head) {
+ while (head->next)
+ head = head->next;
+
+ head->next = au;
+ }
+
+ return au;
+}
+
+static void vidtv_s302m_access_unit_destroy(struct vidtv_encoder *e)
+{
+ struct vidtv_access_unit *head = e->access_units;
+ struct vidtv_access_unit *tmp = NULL;
+
+ while (head) {
+ tmp = head;
+ head = head->next;
+ kfree(tmp);
+ }
+
+ e->access_units = NULL;
+}
+
+static void vidtv_s302m_alloc_au(struct vidtv_encoder *e)
+{
+ struct vidtv_access_unit *sync_au = NULL;
+ struct vidtv_access_unit *temp = NULL;
+
+ if (e->sync && e->sync->is_video_encoder) {
+ sync_au = e->sync->access_units;
+
+ while (sync_au) {
+ temp = vidtv_s302m_access_unit_init(e->access_units);
+ if (!e->access_units)
+ e->access_units = temp;
+
+ sync_au = sync_au->next;
+ }
+
+ return;
+ }
+
+ e->access_units = vidtv_s302m_access_unit_init(NULL);
+}
+
+static void
+vidtv_s302m_compute_sample_count_from_video(struct vidtv_encoder *e)
+{
+ struct vidtv_access_unit *au = e->access_units;
+ struct vidtv_access_unit *sync_au = e->sync->access_units;
+ u32 vau_duration_usecs;
+ u32 sample_duration_usecs;
+ u32 s;
+
+ vau_duration_usecs = USEC_PER_SEC / e->sync->sampling_rate_hz;
+ sample_duration_usecs = USEC_PER_SEC / e->sampling_rate_hz;
+
+ while (au && sync_au) {
+ s = DIV_ROUND_UP(vau_duration_usecs, sample_duration_usecs);
+ au->num_samples = s;
+ au = au->next;
+ sync_au = sync_au->next;
+ }
+}
+
+static void vidtv_s302m_compute_pts_from_video(struct vidtv_encoder *e)
+{
+ struct vidtv_access_unit *au = e->access_units;
+ struct vidtv_access_unit *sync_au = e->sync->access_units;
+
+ /* use the same pts from the video access unit*/
+ while (au && sync_au) {
+ au->pts = sync_au->pts;
+ au = au->next;
+ sync_au = sync_au->next;
+ }
+}
+
+static u16 vidtv_s302m_get_sample(struct vidtv_encoder *e)
+{
+ u16 sample;
+ int pos;
+
+ if (!e->src_buf) {
+ /*
+ * Simple tone generator: play the tones at the
+ * beethoven_5th_symphony array.
+ */
+ if (e->last_duration <= 0) {
+ if (e->src_buf_offset >= ARRAY_SIZE(beethoven_5th_symphony))
+ e->src_buf_offset = 0;
+
+ e->last_tone = beethoven_5th_symphony[e->src_buf_offset].note;
+ e->last_duration = beethoven_5th_symphony[e->src_buf_offset].duration * S302M_SAMPLING_RATE_HZ / COMPASS / 5;
+ e->src_buf_offset++;
+ e->note_offset = 0;
+ } else {
+ e->last_duration--;
+ }
+
+ /* Handle silent */
+ if (!e->last_tone) {
+ e->src_buf_offset = 0;
+ return 0x8000;
+ }
+
+ pos = (2 * PI * e->note_offset * e->last_tone / S302M_SAMPLING_RATE_HZ);
+
+ if (pos == 360)
+ e->note_offset = 0;
+ else
+ e->note_offset++;
+
+ return (fixp_sin32(pos % (2 * PI)) >> 16) + 0x8000;
+ }
+
+ /* bug somewhere */
+ if (e->src_buf_offset > e->src_buf_sz) {
+ pr_err_ratelimited("overflow detected: %d > %d, wrapping.\n",
+ e->src_buf_offset,
+ e->src_buf_sz);
+
+ e->src_buf_offset = 0;
+ }
+
+ if (e->src_buf_offset >= e->src_buf_sz) {
+ /* let the source know we are out of data */
+ if (e->last_sample_cb)
+ e->last_sample_cb(e->sample_count);
+
+ e->src_buf_offset = 0;
+ }
+
+ sample = *(u16 *)(e->src_buf + e->src_buf_offset);
+
+ return sample;
+}
+
+static u32 vidtv_s302m_write_frame(struct vidtv_encoder *e,
+ u16 sample)
+{
+ u32 nbytes = 0;
+ struct vidtv_s302m_frame_16 f = {};
+ struct vidtv_s302m_ctx *ctx = e->ctx;
+
+ /* from ffmpeg: see s302enc.c */
+
+ u8 vucf = ctx->frame_index == 0 ? 0x10 : 0;
+
+ f.data[0] = sample & 0xFF;
+ f.data[1] = (sample & 0xFF00) >> 8;
+ f.data[2] = ((sample & 0x0F) << 4) | vucf;
+ f.data[3] = (sample & 0x0FF0) >> 4;
+ f.data[4] = (sample & 0xF000) >> 12;
+
+ f.data[0] = reverse[f.data[0]];
+ f.data[1] = reverse[f.data[1]];
+ f.data[2] = reverse[f.data[2]];
+ f.data[3] = reverse[f.data[3]];
+ f.data[4] = reverse[f.data[4]];
+
+ nbytes += vidtv_memcpy(e->encoder_buf,
+ e->encoder_buf_offset,
+ VIDTV_S302M_BUF_SZ,
+ &f,
+ sizeof(f));
+
+ e->encoder_buf_offset += nbytes;
+
+ ctx->frame_index++;
+ if (ctx->frame_index >= S302M_BLOCK_SZ)
+ ctx->frame_index = 0;
+
+ return nbytes;
+}
+
+static u32 vidtv_s302m_write_h(struct vidtv_encoder *e, u32 p_sz)
+{
+ struct vidtv_smpte_s302m_es h = {};
+ u32 nbytes = 0;
+
+ /* 2 channels, ident: 0, 16 bits per sample */
+ h.bitfield = cpu_to_be32((p_sz << 16));
+
+ nbytes += vidtv_memcpy(e->encoder_buf,
+ e->encoder_buf_offset,
+ e->encoder_buf_sz,
+ &h,
+ sizeof(h));
+
+ e->encoder_buf_offset += nbytes;
+ return nbytes;
+}
+
+static void vidtv_s302m_write_frames(struct vidtv_encoder *e)
+{
+ struct vidtv_access_unit *au = e->access_units;
+ struct vidtv_s302m_ctx *ctx = e->ctx;
+ u32 nbytes_per_unit = 0;
+ u32 nbytes = 0;
+ u32 au_sz = 0;
+ u16 sample;
+ u32 j;
+
+ while (au) {
+ au_sz = au->num_samples *
+ sizeof(struct vidtv_s302m_frame_16);
+
+ nbytes_per_unit = vidtv_s302m_write_h(e, au_sz);
+
+ for (j = 0; j < au->num_samples; ++j) {
+ sample = vidtv_s302m_get_sample(e);
+ nbytes_per_unit += vidtv_s302m_write_frame(e, sample);
+
+ if (e->src_buf)
+ e->src_buf_offset += sizeof(u16);
+
+ e->sample_count++;
+ }
+
+ au->nbytes = nbytes_per_unit;
+
+ if (au_sz + sizeof(struct vidtv_smpte_s302m_es) != nbytes_per_unit) {
+ pr_warn_ratelimited("write size was %u, expected %zu\n",
+ nbytes_per_unit,
+ au_sz + sizeof(struct vidtv_smpte_s302m_es));
+ }
+
+ nbytes += nbytes_per_unit;
+ au->offset = nbytes - nbytes_per_unit;
+
+ nbytes_per_unit = 0;
+ ctx->au_count++;
+
+ au = au->next;
+ }
+}
+
+static void *vidtv_s302m_encode(struct vidtv_encoder *e)
+{
+ /*
+ * According to SMPTE 302M, an audio access unit is specified as those
+ * AES3 words that are associated with a corresponding video frame.
+ * Therefore, there is one audio access unit for every video access unit
+ * in the corresponding video encoder ('sync'), using the same values
+ * for PTS as used by the video encoder.
+ *
+ * Assuming that it is also possible to send audio without any
+ * associated video, as in a radio-like service, a single audio access unit
+ * is created with values for 'num_samples' and 'pts' taken empirically from
+ * ffmpeg
+ */
+
+ struct vidtv_s302m_ctx *ctx = e->ctx;
+
+ vidtv_s302m_access_unit_destroy(e);
+ vidtv_s302m_alloc_au(e);
+
+ if (e->sync && e->sync->is_video_encoder) {
+ vidtv_s302m_compute_sample_count_from_video(e);
+ vidtv_s302m_compute_pts_from_video(e);
+ } else {
+ e->access_units->num_samples = FF_S302M_DEFAULT_NUM_FRAMES;
+ e->access_units->pts = (ctx->au_count * FF_S302M_DEFAULT_PTS_INCREMENT) +
+ FF_S302M_DEFAULT_PTS_OFFSET;
+ }
+
+ vidtv_s302m_write_frames(e);
+
+ return e->encoder_buf;
+}
+
+static u32 vidtv_s302m_clear(struct vidtv_encoder *e)
+{
+ struct vidtv_access_unit *au = e->access_units;
+ u32 count = 0;
+
+ while (au) {
+ count++;
+ au = au->next;
+ }
+
+ vidtv_s302m_access_unit_destroy(e);
+ memset(e->encoder_buf, 0, VIDTV_S302M_BUF_SZ);
+ e->encoder_buf_offset = 0;
+
+ return count;
+}
+
+struct vidtv_encoder
+*vidtv_s302m_encoder_init(struct vidtv_s302m_encoder_init_args args)
+{
+ struct vidtv_encoder *e = kzalloc(sizeof(*e), GFP_KERNEL);
+ u32 priv_sz = sizeof(struct vidtv_s302m_ctx);
+
+ e->id = S302M;
+
+ if (args.name)
+ e->name = kstrdup(args.name, GFP_KERNEL);
+
+ e->encoder_buf = vzalloc(VIDTV_S302M_BUF_SZ);
+ e->encoder_buf_sz = VIDTV_S302M_BUF_SZ;
+ e->encoder_buf_offset = 0;
+
+ e->sample_count = 0;
+ e->last_duration = 0;
+
+ e->src_buf = (args.src_buf) ? args.src_buf : NULL;
+ e->src_buf_sz = (args.src_buf) ? args.src_buf_sz : 0;
+ e->src_buf_offset = 0;
+
+ e->is_video_encoder = false;
+ e->ctx = kzalloc(priv_sz, GFP_KERNEL);
+
+ e->encode = vidtv_s302m_encode;
+ e->clear = vidtv_s302m_clear;
+
+ e->es_pid = cpu_to_be16(args.es_pid);
+ e->stream_id = cpu_to_be16(PES_PRIVATE_STREAM_1);
+
+ e->sync = args.sync;
+ e->sampling_rate_hz = S302M_SAMPLING_RATE_HZ;
+
+ e->last_sample_cb = args.last_sample_cb;
+
+ e->destroy = vidtv_s302m_encoder_destroy;
+
+ if (args.head) {
+ while (args.head->next)
+ args.head = args.head->next;
+
+ args.head->next = e;
+ }
+
+ e->next = NULL;
+
+ return e;
+}
+
+void vidtv_s302m_encoder_destroy(struct vidtv_encoder *e)
+{
+ if (e->id != S302M) {
+ pr_err_ratelimited("Encoder type mismatch, skipping.\n");
+ return;
+ }
+
+ vidtv_s302m_access_unit_destroy(e);
+ kfree(e->name);
+ vfree(e->encoder_buf);
+ kfree(e->ctx);
+ kfree(e);
+}
diff --git a/drivers/media/test-drivers/vidtv/vidtv_s302m.h b/drivers/media/test-drivers/vidtv/vidtv_s302m.h
new file mode 100644
index 000000000000..eca5e3150ede
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_s302m.h
@@ -0,0 +1,92 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Vidtv serves as a reference DVB driver and helps validate the existing APIs
+ * in the media subsystem. It can also aid developers working on userspace
+ * applications.
+ *
+ * This file contains the code for an AES3 (also known as AES/EBU) encoder.
+ * It is based on EBU Tech 3250 and SMPTE 302M technical documents.
+ *
+ * This encoder currently supports 16bit AES3 subframes using 16bit signed
+ * integers.
+ *
+ * Note: AU stands for Access Unit, and AAU stands for Audio Access Unit
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#ifndef VIDTV_S302M_H
+#define VIDTV_S302M_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#include "vidtv_encoder.h"
+
+/* see SMPTE 302M 2007 clause 7.3 */
+#define VIDTV_S302M_BUF_SZ 65024
+
+/* see ETSI TS 102 154 v.1.2.1 clause 7.3.5 */
+#define VIDTV_S302M_FORMAT_IDENTIFIER 0x42535344
+
+/**
+ * struct vidtv_s302m_ctx - s302m encoder context.
+ * @enc: A pointer to the containing encoder structure.
+ * @frame_index: The current frame in a block
+ * @au_count: The total number of access units encoded up to now
+ */
+struct vidtv_s302m_ctx {
+ struct vidtv_encoder *enc;
+ u32 frame_index;
+ u32 au_count;
+};
+
+/**
+ * struct vidtv_smpte_s302m_es - s302m MPEG Elementary Stream header.
+ *
+ * See SMPTE 302M 2007 table 1.
+ */
+struct vidtv_smpte_s302m_es {
+ /*
+ *
+ * audio_packet_size:16;
+ * num_channels:2;
+ * channel_identification:8;
+ * bits_per_sample:2; // 0x0 for 16bits
+ * zero:4;
+ */
+ __be32 bitfield;
+} __packed;
+
+struct vidtv_s302m_frame_16 {
+ u8 data[5];
+} __packed;
+
+/**
+ * struct vidtv_s302m_encoder_init_args - Args for the s302m encoder.
+ *
+ * @name: A name to identify this particular instance
+ * @src_buf: The source buffer, encoder will default to a sine wave if this is NULL.
+ * @src_buf_sz: The size of the source buffer.
+ * @es_pid: The MPEG Elementary Stream PID to use.
+ * @sync: Attempt to synchronize audio with this video encoder, if not NULL.
+ * @last_sample_cb: A callback called when the encoder runs out of data.
+ * @head: Add to this chain
+ */
+struct vidtv_s302m_encoder_init_args {
+ char *name;
+ void *src_buf;
+ u32 src_buf_sz;
+ u16 es_pid;
+ struct vidtv_encoder *sync;
+ void (*last_sample_cb)(u32 sample_no);
+
+ struct vidtv_encoder *head;
+};
+
+struct vidtv_encoder
+*vidtv_s302m_encoder_init(struct vidtv_s302m_encoder_init_args args);
+
+void vidtv_s302m_encoder_destroy(struct vidtv_encoder *encoder);
+
+#endif /* VIDTV_S302M_H */
diff --git a/drivers/media/test-drivers/vidtv/vidtv_ts.c b/drivers/media/test-drivers/vidtv/vidtv_ts.c
new file mode 100644
index 000000000000..190b9e4438dc
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_ts.c
@@ -0,0 +1,137 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The Virtual DVB test driver serves as a reference DVB driver and helps
+ * validate the existing APIs in the media subsystem. It can also aid
+ * developers working on userspace applications.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s, %d: " fmt, __func__, __LINE__
+
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+#include <linux/types.h>
+#include <linux/math64.h>
+#include <asm/byteorder.h>
+
+#include "vidtv_ts.h"
+#include "vidtv_common.h"
+
+static u32 vidtv_ts_write_pcr_bits(u8 *to, u32 to_offset, u64 pcr)
+{
+ /* Exact same from ffmpeg. PCR is a counter driven by a 27Mhz clock */
+ u64 div;
+ u64 rem;
+ u8 *buf = to + to_offset;
+ u64 pcr_low;
+ u64 pcr_high;
+
+ div = div64_u64_rem(pcr, 300, &rem);
+
+ pcr_low = rem; /* pcr_low = pcr % 300 */
+ pcr_high = div; /* pcr_high = pcr / 300 */
+
+ *buf++ = pcr_high >> 25;
+ *buf++ = pcr_high >> 17;
+ *buf++ = pcr_high >> 9;
+ *buf++ = pcr_high >> 1;
+ *buf++ = pcr_high << 7 | pcr_low >> 8 | 0x7e;
+ *buf++ = pcr_low;
+
+ return 6;
+}
+
+void vidtv_ts_inc_cc(u8 *continuity_counter)
+{
+ ++*continuity_counter;
+ if (*continuity_counter > TS_CC_MAX_VAL)
+ *continuity_counter = 0;
+}
+
+u32 vidtv_ts_null_write_into(struct null_packet_write_args args)
+{
+ u32 nbytes = 0;
+ struct vidtv_mpeg_ts ts_header = {};
+
+ ts_header.sync_byte = TS_SYNC_BYTE;
+ ts_header.bitfield = cpu_to_be16(TS_NULL_PACKET_PID);
+ ts_header.payload = 1;
+ ts_header.continuity_counter = *args.continuity_counter;
+
+ /* copy TS header */
+ nbytes += vidtv_memcpy(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.buf_sz,
+ &ts_header,
+ sizeof(ts_header));
+
+ vidtv_ts_inc_cc(args.continuity_counter);
+
+ /* fill the rest with empty data */
+ nbytes += vidtv_memset(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.buf_sz,
+ TS_FILL_BYTE,
+ TS_PACKET_LEN - nbytes);
+
+ /* we should have written exactly _one_ 188byte packet */
+ if (nbytes != TS_PACKET_LEN)
+ pr_warn_ratelimited("Expected exactly %d bytes, got %d\n",
+ TS_PACKET_LEN,
+ nbytes);
+
+ return nbytes;
+}
+
+u32 vidtv_ts_pcr_write_into(struct pcr_write_args args)
+{
+ u32 nbytes = 0;
+ struct vidtv_mpeg_ts ts_header = {};
+ struct vidtv_mpeg_ts_adaption ts_adap = {};
+
+ ts_header.sync_byte = TS_SYNC_BYTE;
+ ts_header.bitfield = cpu_to_be16(args.pid);
+ ts_header.scrambling = 0;
+ /* cc is not incremented, but it is needed. see 13818-1 clause 2.4.3.3 */
+ ts_header.continuity_counter = *args.continuity_counter;
+ ts_header.payload = 0;
+ ts_header.adaptation_field = 1;
+
+ /* 13818-1 clause 2.4.3.5 */
+ ts_adap.length = 183;
+ ts_adap.PCR = 1;
+
+ /* copy TS header */
+ nbytes += vidtv_memcpy(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.buf_sz,
+ &ts_header,
+ sizeof(ts_header));
+
+ /* write the adap after the TS header */
+ nbytes += vidtv_memcpy(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.buf_sz,
+ &ts_adap,
+ sizeof(ts_adap));
+
+ /* write the PCR optional */
+ nbytes += vidtv_ts_write_pcr_bits(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.pcr);
+
+ nbytes += vidtv_memset(args.dest_buf,
+ args.dest_offset + nbytes,
+ args.buf_sz,
+ TS_FILL_BYTE,
+ TS_PACKET_LEN - nbytes);
+
+ /* we should have written exactly _one_ 188byte packet */
+ if (nbytes != TS_PACKET_LEN)
+ pr_warn_ratelimited("Expected exactly %d bytes, got %d\n",
+ TS_PACKET_LEN,
+ nbytes);
+
+ return nbytes;
+}
diff --git a/drivers/media/test-drivers/vidtv/vidtv_ts.h b/drivers/media/test-drivers/vidtv/vidtv_ts.h
new file mode 100644
index 000000000000..83dcc9183b45
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_ts.h
@@ -0,0 +1,108 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The Virtual DVB test driver serves as a reference DVB driver and helps
+ * validate the existing APIs in the media subsystem. It can also aid
+ * developers working on userspace applications.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#ifndef VIDTV_TS_H
+#define VIDTV_TS_H
+
+#include <linux/types.h>
+#include <asm/byteorder.h>
+
+#define TS_SYNC_BYTE 0x47
+#define TS_PACKET_LEN 188
+#define TS_PAYLOAD_LEN 184
+#define TS_NULL_PACKET_PID 0x1fff
+#define TS_CC_MAX_VAL 0x0f /* 4 bits */
+#define TS_LAST_VALID_PID 8191
+#define TS_FILL_BYTE 0xff /* the byte used in packet stuffing */
+
+struct vidtv_mpeg_ts_adaption {
+ u8 length;
+ struct {
+ u8 extension:1;
+ u8 private_data:1;
+ u8 splicing_point:1;
+ u8 OPCR:1;
+ u8 PCR:1;
+ u8 priority:1;
+ u8 random_access:1;
+ u8 discontinued:1;
+ } __packed;
+ u8 data[];
+} __packed;
+
+struct vidtv_mpeg_ts {
+ u8 sync_byte;
+ __be16 bitfield; /* tei: 1, payload_start:1 priority: 1, pid:13 */
+ struct {
+ u8 continuity_counter:4;
+ u8 payload:1;
+ u8 adaptation_field:1;
+ u8 scrambling:2;
+ } __packed;
+ struct vidtv_mpeg_ts_adaption adaption[];
+} __packed;
+
+/**
+ * struct pcr_write_args - Arguments for the pcr_write_into function.
+ * @dest_buf: The buffer to write into.
+ * @dest_offset: The byte offset into the buffer.
+ * @pid: The TS PID for the PCR packets.
+ * @buf_sz: The size of the buffer in bytes.
+ * @countinuity_counter: The TS continuity_counter.
+ * @pcr: A sample from the system clock.
+ */
+struct pcr_write_args {
+ void *dest_buf;
+ u32 dest_offset;
+ u16 pid;
+ u32 buf_sz;
+ u8 *continuity_counter;
+ u64 pcr;
+};
+
+/**
+ * struct null_packet_write_args - Arguments for the null_write_into function
+ * @dest_buf: The buffer to write into.
+ * @dest_offset: The byte offset into the buffer.
+ * @buf_sz: The size of the buffer in bytes.
+ * @countinuity_counter: The TS continuity_counter.
+ */
+struct null_packet_write_args {
+ void *dest_buf;
+ u32 dest_offset;
+ u32 buf_sz;
+ u8 *continuity_counter;
+};
+
+/* Increment the continuity counter */
+void vidtv_ts_inc_cc(u8 *continuity_counter);
+
+/**
+ * vidtv_ts_null_write_into - Write a TS null packet into a buffer.
+ * @args: the arguments to use when writing.
+ *
+ * This function will write a null packet into a buffer. This is usually used to
+ * pad TS streams.
+ *
+ * Return: The number of bytes written into the buffer.
+ */
+u32 vidtv_ts_null_write_into(struct null_packet_write_args args);
+
+/**
+ * vidtv_ts_pcr_write_into - Write a PCR packet into a buffer.
+ * @args: the arguments to use when writing.
+ *
+ * This function will write a PCR packet into a buffer. This is used to
+ * synchronize the clocks between encoders and decoders.
+ *
+ * Return: The number of bytes written into the buffer.
+ */
+u32 vidtv_ts_pcr_write_into(struct pcr_write_args args);
+
+#endif //VIDTV_TS_H
diff --git a/drivers/media/test-drivers/vidtv/vidtv_tuner.c b/drivers/media/test-drivers/vidtv/vidtv_tuner.c
new file mode 100644
index 000000000000..9bc49e099f65
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_tuner.c
@@ -0,0 +1,438 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * The Virtual DVB test driver serves as a reference DVB driver and helps
+ * validate the existing APIs in the media subsystem. It can also aid
+ * developers working on userspace applications.
+ *
+ * The vidtv tuner should support common TV standards such as
+ * DVB-T/T2/S/S2, ISDB-T and ATSC when completed.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#include <linux/errno.h>
+#include <linux/i2c.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <media/dvb_frontend.h>
+#include <linux/printk.h>
+#include <linux/ratelimit.h>
+
+#include "vidtv_tuner.h"
+
+struct vidtv_tuner_cnr_to_qual_s {
+ /* attempt to use the same values as libdvbv5 */
+ u32 modulation;
+ u32 fec;
+ u32 cnr_ok;
+ u32 cnr_good;
+};
+
+static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_c_cnr_2_qual[] = {
+ /* from libdvbv5 source code, in milli db */
+ { QAM_256, FEC_NONE, 34000, 38000},
+ { QAM_64, FEC_NONE, 30000, 34000},
+};
+
+static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_s_cnr_2_qual[] = {
+ /* from libdvbv5 source code, in milli db */
+ { QPSK, FEC_1_2, 7000, 10000},
+ { QPSK, FEC_2_3, 9000, 12000},
+ { QPSK, FEC_3_4, 10000, 13000},
+ { QPSK, FEC_5_6, 11000, 14000},
+ { QPSK, FEC_7_8, 12000, 15000},
+};
+
+static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_s2_cnr_2_qual[] = {
+ /* from libdvbv5 source code, in milli db */
+ { QPSK, FEC_1_2, 9000, 12000},
+ { QPSK, FEC_2_3, 11000, 14000},
+ { QPSK, FEC_3_4, 12000, 15000},
+ { QPSK, FEC_5_6, 12000, 15000},
+ { QPSK, FEC_8_9, 13000, 16000},
+ { QPSK, FEC_9_10, 13500, 16500},
+ { PSK_8, FEC_2_3, 14500, 17500},
+ { PSK_8, FEC_3_4, 16000, 19000},
+ { PSK_8, FEC_5_6, 17500, 20500},
+ { PSK_8, FEC_8_9, 19000, 22000},
+};
+
+static const struct vidtv_tuner_cnr_to_qual_s vidtv_tuner_t_cnr_2_qual[] = {
+ /* from libdvbv5 source code, in milli db*/
+ { QPSK, FEC_1_2, 4100, 5900},
+ { QPSK, FEC_2_3, 6100, 9600},
+ { QPSK, FEC_3_4, 7200, 12400},
+ { QPSK, FEC_5_6, 8500, 15600},
+ { QPSK, FEC_7_8, 9200, 17500},
+ { QAM_16, FEC_1_2, 9800, 11800},
+ { QAM_16, FEC_2_3, 12100, 15300},
+ { QAM_16, FEC_3_4, 13400, 18100},
+ { QAM_16, FEC_5_6, 14800, 21300},
+ { QAM_16, FEC_7_8, 15700, 23600},
+ { QAM_64, FEC_1_2, 14000, 16000},
+ { QAM_64, FEC_2_3, 19900, 25400},
+ { QAM_64, FEC_3_4, 24900, 27900},
+ { QAM_64, FEC_5_6, 21300, 23300},
+ { QAM_64, FEC_7_8, 22000, 24000},
+};
+
+/**
+ * struct vidtv_tuner_hardware_state - Simulate the tuner hardware status
+ * @asleep: whether the tuner is asleep, i.e whether _sleep() or _suspend() was
+ * called.
+ * @lock_status: Whether the tuner has managed to lock on the requested
+ * frequency.
+ * @if_frequency: The tuner's intermediate frequency. Hardcoded for the purposes
+ * of simulation.
+ * @tuned_frequency: The actual tuned frequency.
+ * @bandwidth: The actual bandwidth.
+ *
+ * This structure is meant to simulate the status of the tuner hardware, as if
+ * we had a physical tuner hardware.
+ */
+struct vidtv_tuner_hardware_state {
+ bool asleep;
+ u32 lock_status;
+ u32 if_frequency;
+ u32 tuned_frequency;
+ u32 bandwidth;
+};
+
+/**
+ * struct vidtv_tuner_dev - The tuner struct
+ * @fe: A pointer to the dvb_frontend structure allocated by vidtv_demod
+ * @hw_state: A struct to simulate the tuner's hardware state as if we had a
+ * physical tuner hardware.
+ * @config: The configuration used to start the tuner module, usually filled
+ * by a bridge driver. For vidtv, this is filled by vidtv_bridge before the
+ * tuner module is probed.
+ */
+struct vidtv_tuner_dev {
+ struct dvb_frontend *fe;
+ struct vidtv_tuner_hardware_state hw_state;
+ struct vidtv_tuner_config config;
+};
+
+static struct vidtv_tuner_dev*
+vidtv_tuner_get_dev(struct dvb_frontend *fe)
+{
+ return i2c_get_clientdata(fe->tuner_priv);
+}
+
+static int vidtv_tuner_check_frequency_shift(struct dvb_frontend *fe)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct vidtv_tuner_config config = tuner_dev->config;
+ u32 *valid_freqs = NULL;
+ u32 array_sz = 0;
+ u32 i;
+ u32 shift;
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ valid_freqs = config.vidtv_valid_dvb_t_freqs;
+ array_sz = ARRAY_SIZE(config.vidtv_valid_dvb_t_freqs);
+ break;
+ case SYS_DVBS:
+ case SYS_DVBS2:
+ valid_freqs = config.vidtv_valid_dvb_s_freqs;
+ array_sz = ARRAY_SIZE(config.vidtv_valid_dvb_s_freqs);
+ break;
+ case SYS_DVBC_ANNEX_A:
+ valid_freqs = config.vidtv_valid_dvb_c_freqs;
+ array_sz = ARRAY_SIZE(config.vidtv_valid_dvb_c_freqs);
+ break;
+
+ default:
+ dev_warn(fe->dvb->device,
+ "%s: unsupported delivery system: %u\n",
+ __func__,
+ c->delivery_system);
+
+ return -EINVAL;
+ }
+
+ for (i = 0; i < array_sz; i++) {
+ if (!valid_freqs[i])
+ break;
+ shift = abs(c->frequency - valid_freqs[i]);
+
+ if (!shift)
+ return 0;
+
+ /*
+ * This will provide a value from 0 to 100 that would
+ * indicate how far is the tuned frequency from the
+ * right one.
+ */
+ if (shift < config.max_frequency_shift_hz)
+ return shift * 100 / config.max_frequency_shift_hz;
+ }
+
+ return -EINVAL;
+}
+
+static int
+vidtv_tuner_get_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+ const struct vidtv_tuner_cnr_to_qual_s *cnr2qual = NULL;
+ struct device *dev = fe->dvb->device;
+ u32 array_size = 0;
+ s32 shift;
+ u32 i;
+
+ shift = vidtv_tuner_check_frequency_shift(fe);
+ if (shift < 0) {
+ tuner_dev->hw_state.lock_status = 0;
+ *strength = 0;
+ return 0;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ cnr2qual = vidtv_tuner_t_cnr_2_qual;
+ array_size = ARRAY_SIZE(vidtv_tuner_t_cnr_2_qual);
+ break;
+
+ case SYS_DVBS:
+ cnr2qual = vidtv_tuner_s_cnr_2_qual;
+ array_size = ARRAY_SIZE(vidtv_tuner_s_cnr_2_qual);
+ break;
+
+ case SYS_DVBS2:
+ cnr2qual = vidtv_tuner_s2_cnr_2_qual;
+ array_size = ARRAY_SIZE(vidtv_tuner_s2_cnr_2_qual);
+ break;
+
+ case SYS_DVBC_ANNEX_A:
+ cnr2qual = vidtv_tuner_c_cnr_2_qual;
+ array_size = ARRAY_SIZE(vidtv_tuner_c_cnr_2_qual);
+ break;
+
+ default:
+ dev_warn_ratelimited(dev,
+ "%s: unsupported delivery system: %u\n",
+ __func__,
+ c->delivery_system);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < array_size; i++) {
+ if (cnr2qual[i].modulation != c->modulation ||
+ cnr2qual[i].fec != c->fec_inner)
+ continue;
+
+ if (!shift) {
+ *strength = cnr2qual[i].cnr_good;
+ return 0;
+ }
+ /*
+ * Channel tuned at wrong frequency. Simulate that the
+ * Carrier S/N ratio is not too good.
+ */
+
+ *strength = cnr2qual[i].cnr_ok -
+ (cnr2qual[i].cnr_good - cnr2qual[i].cnr_ok);
+ return 0;
+ }
+
+ /*
+ * do a linear interpolation between 34dB and 10dB if we can't
+ * match against the table
+ */
+ *strength = 34000 - 24000 * shift / 100;
+ return 0;
+}
+
+static int vidtv_tuner_init(struct dvb_frontend *fe)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+ struct vidtv_tuner_config config = tuner_dev->config;
+
+ msleep_interruptible(config.mock_power_up_delay_msec);
+
+ tuner_dev->hw_state.asleep = false;
+ tuner_dev->hw_state.if_frequency = 5000;
+
+ return 0;
+}
+
+static int vidtv_tuner_sleep(struct dvb_frontend *fe)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+
+ tuner_dev->hw_state.asleep = true;
+ return 0;
+}
+
+static int vidtv_tuner_suspend(struct dvb_frontend *fe)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+
+ tuner_dev->hw_state.asleep = true;
+ return 0;
+}
+
+static int vidtv_tuner_resume(struct dvb_frontend *fe)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+
+ tuner_dev->hw_state.asleep = false;
+ return 0;
+}
+
+static int vidtv_tuner_set_params(struct dvb_frontend *fe)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+ struct vidtv_tuner_config config = tuner_dev->config;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ s32 shift;
+
+ u32 min_freq = fe->ops.tuner_ops.info.frequency_min_hz;
+ u32 max_freq = fe->ops.tuner_ops.info.frequency_max_hz;
+ u32 min_bw = fe->ops.tuner_ops.info.bandwidth_min;
+ u32 max_bw = fe->ops.tuner_ops.info.bandwidth_max;
+
+ if (c->frequency < min_freq || c->frequency > max_freq ||
+ c->bandwidth_hz < min_bw || c->bandwidth_hz > max_bw) {
+ tuner_dev->hw_state.lock_status = 0;
+ return -EINVAL;
+ }
+
+ tuner_dev->hw_state.tuned_frequency = c->frequency;
+ tuner_dev->hw_state.bandwidth = c->bandwidth_hz;
+ tuner_dev->hw_state.lock_status = TUNER_STATUS_LOCKED;
+
+ msleep_interruptible(config.mock_tune_delay_msec);
+
+ shift = vidtv_tuner_check_frequency_shift(fe);
+ if (shift < 0) {
+ tuner_dev->hw_state.lock_status = 0;
+ return shift;
+ }
+
+ return 0;
+}
+
+static int vidtv_tuner_set_config(struct dvb_frontend *fe,
+ void *priv_cfg)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+
+ memcpy(&tuner_dev->config, priv_cfg, sizeof(tuner_dev->config));
+
+ return 0;
+}
+
+static int vidtv_tuner_get_frequency(struct dvb_frontend *fe,
+ u32 *frequency)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+
+ *frequency = tuner_dev->hw_state.tuned_frequency;
+
+ return 0;
+}
+
+static int vidtv_tuner_get_bandwidth(struct dvb_frontend *fe,
+ u32 *bandwidth)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+
+ *bandwidth = tuner_dev->hw_state.bandwidth;
+
+ return 0;
+}
+
+static int vidtv_tuner_get_if_frequency(struct dvb_frontend *fe,
+ u32 *frequency)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+
+ *frequency = tuner_dev->hw_state.if_frequency;
+
+ return 0;
+}
+
+static int vidtv_tuner_get_status(struct dvb_frontend *fe, u32 *status)
+{
+ struct vidtv_tuner_dev *tuner_dev = vidtv_tuner_get_dev(fe);
+
+ *status = tuner_dev->hw_state.lock_status;
+
+ return 0;
+}
+
+static const struct dvb_tuner_ops vidtv_tuner_ops = {
+ .init = vidtv_tuner_init,
+ .sleep = vidtv_tuner_sleep,
+ .suspend = vidtv_tuner_suspend,
+ .resume = vidtv_tuner_resume,
+ .set_params = vidtv_tuner_set_params,
+ .set_config = vidtv_tuner_set_config,
+ .get_bandwidth = vidtv_tuner_get_bandwidth,
+ .get_frequency = vidtv_tuner_get_frequency,
+ .get_if_frequency = vidtv_tuner_get_if_frequency,
+ .get_status = vidtv_tuner_get_status,
+ .get_rf_strength = vidtv_tuner_get_signal_strength
+};
+
+static const struct i2c_device_id vidtv_tuner_i2c_id_table[] = {
+ {"dvb_vidtv_tuner", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, vidtv_tuner_i2c_id_table);
+
+static int vidtv_tuner_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct vidtv_tuner_config *config = client->dev.platform_data;
+ struct dvb_frontend *fe = config->fe;
+ struct vidtv_tuner_dev *tuner_dev = NULL;
+
+ tuner_dev = kzalloc(sizeof(*tuner_dev), GFP_KERNEL);
+ if (!tuner_dev)
+ return -ENOMEM;
+
+ tuner_dev->fe = config->fe;
+ i2c_set_clientdata(client, tuner_dev);
+
+ memcpy(&fe->ops.tuner_ops,
+ &vidtv_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ memcpy(&tuner_dev->config, config, sizeof(tuner_dev->config));
+ fe->tuner_priv = client;
+
+ return 0;
+}
+
+static int vidtv_tuner_i2c_remove(struct i2c_client *client)
+{
+ struct vidtv_tuner_dev *tuner_dev = i2c_get_clientdata(client);
+
+ kfree(tuner_dev);
+
+ return 0;
+}
+
+static struct i2c_driver vidtv_tuner_i2c_driver = {
+ .driver = {
+ .name = "dvb_vidtv_tuner",
+ .suppress_bind_attrs = true,
+ },
+ .probe = vidtv_tuner_i2c_probe,
+ .remove = vidtv_tuner_i2c_remove,
+ .id_table = vidtv_tuner_i2c_id_table,
+};
+module_i2c_driver(vidtv_tuner_i2c_driver);
+
+MODULE_DESCRIPTION("Virtual DVB Tuner");
+MODULE_AUTHOR("Daniel W. S. Almeida");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/test-drivers/vidtv/vidtv_tuner.h b/drivers/media/test-drivers/vidtv/vidtv_tuner.h
new file mode 100644
index 000000000000..8455b2d564b3
--- /dev/null
+++ b/drivers/media/test-drivers/vidtv/vidtv_tuner.h
@@ -0,0 +1,43 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * The Virtual DTV test driver serves as a reference DVB driver and helps
+ * validate the existing APIs in the media subsystem. It can also aid
+ * developers working on userspace applications.
+ *
+ * Copyright (C) 2020 Daniel W. S. Almeida
+ */
+
+#ifndef VIDTV_TUNER_H
+#define VIDTV_TUNER_H
+
+#include <linux/types.h>
+#include <media/dvb_frontend.h>
+
+#define NUM_VALID_TUNER_FREQS 8
+
+/**
+ * struct vidtv_tuner_config - Configuration used to init the tuner.
+ * @fe: A pointer to the dvb_frontend structure allocated by vidtv_demod.
+ * @mock_power_up_delay_msec: Simulate a power-up delay.
+ * @mock_tune_delay_msec: Simulate a tune delay.
+ * @vidtv_valid_dvb_t_freqs: The valid DVB-T frequencies to simulate.
+ * @vidtv_valid_dvb_c_freqs: The valid DVB-C frequencies to simulate.
+ * @vidtv_valid_dvb_s_freqs: The valid DVB-S frequencies to simulate.
+ * @max_frequency_shift_hz: The maximum frequency shift in HZ allowed when
+ * tuning in a channel
+ *
+ * The configuration used to init the tuner module, usually filled
+ * by a bridge driver. For vidtv, this is filled by vidtv_bridge before the
+ * tuner module is probed.
+ */
+struct vidtv_tuner_config {
+ struct dvb_frontend *fe;
+ u32 mock_power_up_delay_msec;
+ u32 mock_tune_delay_msec;
+ u32 vidtv_valid_dvb_t_freqs[NUM_VALID_TUNER_FREQS];
+ u32 vidtv_valid_dvb_c_freqs[NUM_VALID_TUNER_FREQS];
+ u32 vidtv_valid_dvb_s_freqs[NUM_VALID_TUNER_FREQS];
+ u8 max_frequency_shift_hz;
+};
+
+#endif //VIDTV_TUNER_H
diff --git a/drivers/media/test-drivers/vimc/vimc-capture.c b/drivers/media/test-drivers/vimc/vimc-capture.c
index c63496b17b9a..5e9fd902cd37 100644
--- a/drivers/media/test-drivers/vimc/vimc-capture.c
+++ b/drivers/media/test-drivers/vimc/vimc-capture.c
@@ -351,8 +351,7 @@ static void vimc_cap_unregister(struct vimc_ent_device *ved)
struct vimc_cap_device *vcap =
container_of(ved, struct vimc_cap_device, ved);
- vb2_queue_release(&vcap->queue);
- video_unregister_device(&vcap->vdev);
+ vb2_video_unregister_device(&vcap->vdev);
}
static void *vimc_cap_process_frame(struct vimc_ent_device *ved,
@@ -477,13 +476,11 @@ static struct vimc_ent_device *vimc_cap_add(struct vimc_device *vimc,
if (ret) {
dev_err(vimc->mdev.dev, "%s: video register failed (err=%d)\n",
vcap->vdev.name, ret);
- goto err_release_queue;
+ goto err_clean_m_ent;
}
return &vcap->ved;
-err_release_queue:
- vb2_queue_release(q);
err_clean_m_ent:
media_entity_cleanup(&vcap->vdev.entity);
err_free_vcap:
diff --git a/drivers/media/test-drivers/vivid/vivid-core.c b/drivers/media/test-drivers/vivid/vivid-core.c
index f7ee37e9508d..aa8d350fd682 100644
--- a/drivers/media/test-drivers/vivid/vivid-core.c
+++ b/drivers/media/test-drivers/vivid/vivid-core.c
@@ -832,56 +832,16 @@ static int vivid_create_queue(struct vivid_dev *dev,
return vb2_queue_init(q);
}
-static int vivid_create_instance(struct platform_device *pdev, int inst)
+static int vivid_detect_feature_set(struct vivid_dev *dev, int inst,
+ unsigned node_type,
+ bool *has_tuner,
+ bool *has_modulator,
+ int *ccs_cap,
+ int *ccs_out,
+ unsigned in_type_counter[4],
+ unsigned out_type_counter[4])
{
- static const struct v4l2_dv_timings def_dv_timings =
- V4L2_DV_BT_CEA_1280X720P60;
- unsigned in_type_counter[4] = { 0, 0, 0, 0 };
- unsigned out_type_counter[4] = { 0, 0, 0, 0 };
- int ccs_cap = ccs_cap_mode[inst];
- int ccs_out = ccs_out_mode[inst];
- bool has_tuner;
- bool has_modulator;
- struct vivid_dev *dev;
- struct video_device *vfd;
- unsigned node_type = node_types[inst];
- v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0;
- int ret;
int i;
-#ifdef CONFIG_VIDEO_VIVID_CEC
- unsigned int cec_tx_bus_cnt = 0;
-#endif
-
- /* allocate main vivid state structure */
- dev = kzalloc(sizeof(*dev), GFP_KERNEL);
- if (!dev)
- return -ENOMEM;
-
- dev->inst = inst;
-
-#ifdef CONFIG_MEDIA_CONTROLLER
- dev->v4l2_dev.mdev = &dev->mdev;
-
- /* Initialize media device */
- strscpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model));
- snprintf(dev->mdev.bus_info, sizeof(dev->mdev.bus_info),
- "platform:%s-%03d", VIVID_MODULE_NAME, inst);
- dev->mdev.dev = &pdev->dev;
- media_device_init(&dev->mdev);
- dev->mdev.ops = &vivid_media_ops;
-#endif
-
- /* register v4l2_device */
- snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
- "%s-%03d", VIVID_MODULE_NAME, inst);
- ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
- if (ret) {
- kfree(dev);
- return ret;
- }
- dev->v4l2_dev.release = vivid_dev_release;
-
- /* start detecting feature set */
/* do we use single- or multi-planar? */
dev->multiplanar = multiplanar[inst] > 1;
@@ -947,14 +907,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
!dev->has_vid_cap && !dev->has_meta_cap) {
v4l2_warn(&dev->v4l2_dev,
"Webcam or HDMI input without video or metadata nodes\n");
- kfree(dev);
return -EINVAL;
}
if ((in_type_counter[TV] || in_type_counter[SVID]) &&
!dev->has_vid_cap && !dev->has_vbi_cap && !dev->has_meta_cap) {
v4l2_warn(&dev->v4l2_dev,
"TV or S-Video input without video, VBI or metadata nodes\n");
- kfree(dev);
return -EINVAL;
}
@@ -976,13 +934,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
!dev->has_vid_out && !dev->has_vbi_out && !dev->has_meta_out) {
v4l2_warn(&dev->v4l2_dev,
"S-Video output without video, VBI or metadata nodes\n");
- kfree(dev);
return -EINVAL;
}
if (out_type_counter[HDMI] && !dev->has_vid_out && !dev->has_meta_out) {
v4l2_warn(&dev->v4l2_dev,
"HDMI output without video or metadata nodes\n");
- kfree(dev);
return -EINVAL;
}
@@ -999,25 +955,25 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->has_tv_tuner = in_type_counter[TV];
/* do we have a tuner? */
- has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) ||
- dev->has_radio_rx || dev->has_sdr_cap;
+ *has_tuner = ((dev->has_vid_cap || dev->has_vbi_cap) && in_type_counter[TV]) ||
+ dev->has_radio_rx || dev->has_sdr_cap;
/* do we have a modulator? */
- has_modulator = dev->has_radio_tx;
+ *has_modulator = dev->has_radio_tx;
if (dev->has_vid_cap)
/* do we have a framebuffer for overlay testing? */
dev->has_fb = node_type & 0x10000;
/* can we do crop/compose/scaling while capturing? */
- if (no_error_inj && ccs_cap == -1)
- ccs_cap = 7;
+ if (no_error_inj && *ccs_cap == -1)
+ *ccs_cap = 7;
/* if ccs_cap == -1, then the user can select it using controls */
- if (ccs_cap != -1) {
- dev->has_crop_cap = ccs_cap & 1;
- dev->has_compose_cap = ccs_cap & 2;
- dev->has_scaler_cap = ccs_cap & 4;
+ if (*ccs_cap != -1) {
+ dev->has_crop_cap = *ccs_cap & 1;
+ dev->has_compose_cap = *ccs_cap & 2;
+ dev->has_scaler_cap = *ccs_cap & 4;
v4l2_info(&dev->v4l2_dev, "Capture Crop: %c Compose: %c Scaler: %c\n",
dev->has_crop_cap ? 'Y' : 'N',
dev->has_compose_cap ? 'Y' : 'N',
@@ -1025,14 +981,14 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
}
/* can we do crop/compose/scaling with video output? */
- if (no_error_inj && ccs_out == -1)
- ccs_out = 7;
+ if (no_error_inj && *ccs_out == -1)
+ *ccs_out = 7;
/* if ccs_out == -1, then the user can select it using controls */
- if (ccs_out != -1) {
- dev->has_crop_out = ccs_out & 1;
- dev->has_compose_out = ccs_out & 2;
- dev->has_scaler_out = ccs_out & 4;
+ if (*ccs_out != -1) {
+ dev->has_crop_out = *ccs_out & 1;
+ dev->has_compose_out = *ccs_out & 2;
+ dev->has_scaler_out = *ccs_out & 4;
v4l2_info(&dev->v4l2_dev, "Output Crop: %c Compose: %c Scaler: %c\n",
dev->has_crop_out ? 'Y' : 'N',
dev->has_compose_out ? 'Y' : 'N',
@@ -1042,8 +998,11 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
/* do we create a touch capture device */
dev->has_touch_cap = node_type & 0x80000;
- /* end detecting feature set */
+ return 0;
+}
+static void vivid_set_capabilities(struct vivid_dev *dev)
+{
if (dev->has_vid_cap) {
/* set up the capabilities of the video capture device */
dev->vid_cap_caps = dev->multiplanar ?
@@ -1122,58 +1081,14 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->touch_cap_caps |= dev->multiplanar ?
V4L2_CAP_VIDEO_CAPTURE_MPLANE : V4L2_CAP_VIDEO_CAPTURE;
}
+}
- ret = -ENOMEM;
- /* initialize the test pattern generator */
- tpg_init(&dev->tpg, 640, 360);
- if (tpg_alloc(&dev->tpg, array_size(MAX_WIDTH, MAX_ZOOM)))
- goto free_dev;
- dev->scaled_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM));
- if (!dev->scaled_line)
- goto free_dev;
- dev->blended_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM));
- if (!dev->blended_line)
- goto free_dev;
-
- /* load the edid */
- dev->edid = vmalloc(array_size(256, 128));
- if (!dev->edid)
- goto free_dev;
-
- while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width)
- dev->query_dv_timings_size++;
-
- /*
- * Create a char pointer array that points to the names of all the
- * preset timings
- */
- dev->query_dv_timings_qmenu = kmalloc_array(dev->query_dv_timings_size,
- sizeof(char *), GFP_KERNEL);
- /*
- * Create a string array containing the names of all the preset
- * timings. Each name is max 31 chars long (+ terminating 0).
- */
- dev->query_dv_timings_qmenu_strings =
- kmalloc_array(dev->query_dv_timings_size, 32, GFP_KERNEL);
-
- if (!dev->query_dv_timings_qmenu ||
- !dev->query_dv_timings_qmenu_strings)
- goto free_dev;
-
- for (i = 0; i < dev->query_dv_timings_size; i++) {
- const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt;
- char *p = dev->query_dv_timings_qmenu_strings + i * 32;
- u32 htot, vtot;
-
- dev->query_dv_timings_qmenu[i] = p;
-
- htot = V4L2_DV_BT_FRAME_WIDTH(bt);
- vtot = V4L2_DV_BT_FRAME_HEIGHT(bt);
- snprintf(p, 32, "%ux%u%s%u",
- bt->width, bt->height, bt->interlaced ? "i" : "p",
- (u32)bt->pixelclock / (htot * vtot));
- }
-
+static void vivid_disable_unused_ioctls(struct vivid_dev *dev,
+ bool has_tuner,
+ bool has_modulator,
+ unsigned in_type_counter[4],
+ unsigned out_type_counter[4])
+{
/* disable invalid ioctls based on the feature set */
if (!dev->has_audio_inputs) {
v4l2_disable_ioctl(&dev->vid_cap_dev, VIDIOC_S_AUDIO);
@@ -1260,112 +1175,52 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_S_PARM);
v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMESIZES);
v4l2_disable_ioctl(&dev->touch_cap_dev, VIDIOC_ENUM_FRAMEINTERVALS);
+}
- /* configure internal data */
- dev->fmt_cap = &vivid_formats[0];
- dev->fmt_out = &vivid_formats[0];
- if (!dev->multiplanar)
- vivid_formats[0].data_offset[0] = 0;
- dev->webcam_size_idx = 1;
- dev->webcam_ival_idx = 3;
- tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
- dev->std_out = V4L2_STD_PAL;
- if (dev->input_type[0] == TV || dev->input_type[0] == SVID)
- tvnorms_cap = V4L2_STD_ALL;
- if (dev->output_type[0] == SVID)
- tvnorms_out = V4L2_STD_ALL;
- for (i = 0; i < MAX_INPUTS; i++) {
- dev->dv_timings_cap[i] = def_dv_timings;
- dev->std_cap[i] = V4L2_STD_PAL;
- }
- dev->dv_timings_out = def_dv_timings;
- dev->tv_freq = 2804 /* 175.25 * 16 */;
- dev->tv_audmode = V4L2_TUNER_MODE_STEREO;
- dev->tv_field_cap = V4L2_FIELD_INTERLACED;
- dev->tv_field_out = V4L2_FIELD_INTERLACED;
- dev->radio_rx_freq = 95000 * 16;
- dev->radio_rx_audmode = V4L2_TUNER_MODE_STEREO;
- if (dev->has_radio_tx) {
- dev->radio_tx_freq = 95500 * 16;
- dev->radio_rds_loop = false;
- }
- dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS;
- dev->sdr_adc_freq = 300000;
- dev->sdr_fm_freq = 50000000;
- dev->sdr_pixelformat = V4L2_SDR_FMT_CU8;
- dev->sdr_buffersize = SDR_CAP_SAMPLES_PER_BUF * 2;
-
- dev->edid_max_blocks = dev->edid_blocks = 2;
- memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid));
- dev->radio_rds_init_time = ktime_get();
-
- /* create all controls */
- ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj,
- in_type_counter[TV] || in_type_counter[SVID] ||
- out_type_counter[SVID],
- in_type_counter[HDMI] || out_type_counter[HDMI]);
- if (ret)
- goto unreg_dev;
+static int vivid_init_dv_timings(struct vivid_dev *dev)
+{
+ int i;
- /* enable/disable interface specific controls */
- if (dev->num_outputs && dev->output_type[0] != HDMI)
- v4l2_ctrl_activate(dev->ctrl_display_present, false);
- if (dev->num_inputs && dev->input_type[0] != HDMI) {
- v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false);
- v4l2_ctrl_activate(dev->ctrl_dv_timings, false);
- } else if (dev->num_inputs && dev->input_type[0] == HDMI) {
- v4l2_ctrl_activate(dev->ctrl_std_signal_mode, false);
- v4l2_ctrl_activate(dev->ctrl_standard, false);
- }
+ while (v4l2_dv_timings_presets[dev->query_dv_timings_size].bt.width)
+ dev->query_dv_timings_size++;
/*
- * update the capture and output formats to do a proper initial
- * configuration.
+ * Create a char pointer array that points to the names of all the
+ * preset timings
*/
- vivid_update_format_cap(dev, false);
- vivid_update_format_out(dev);
-
- /* initialize overlay */
- dev->fb_cap.fmt.width = dev->src_rect.width;
- dev->fb_cap.fmt.height = dev->src_rect.height;
- dev->fb_cap.fmt.pixelformat = dev->fmt_cap->fourcc;
- dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
- dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
+ dev->query_dv_timings_qmenu = kmalloc_array(dev->query_dv_timings_size,
+ sizeof(char *), GFP_KERNEL);
+ /*
+ * Create a string array containing the names of all the preset
+ * timings. Each name is max 31 chars long (+ terminating 0).
+ */
+ dev->query_dv_timings_qmenu_strings =
+ kmalloc_array(dev->query_dv_timings_size, 32, GFP_KERNEL);
- /* update touch configuration */
- dev->timeperframe_tch_cap.numerator = 1;
- dev->timeperframe_tch_cap.denominator = 10;
- vivid_set_touch(dev, 0);
+ if (!dev->query_dv_timings_qmenu ||
+ !dev->query_dv_timings_qmenu_strings)
+ return -ENOMEM;
- /* initialize locks */
- spin_lock_init(&dev->slock);
- mutex_init(&dev->mutex);
+ for (i = 0; i < dev->query_dv_timings_size; i++) {
+ const struct v4l2_bt_timings *bt = &v4l2_dv_timings_presets[i].bt;
+ char *p = dev->query_dv_timings_qmenu_strings + i * 32;
+ u32 htot, vtot;
- /* init dma queues */
- INIT_LIST_HEAD(&dev->vid_cap_active);
- INIT_LIST_HEAD(&dev->vid_out_active);
- INIT_LIST_HEAD(&dev->vbi_cap_active);
- INIT_LIST_HEAD(&dev->vbi_out_active);
- INIT_LIST_HEAD(&dev->sdr_cap_active);
- INIT_LIST_HEAD(&dev->meta_cap_active);
- INIT_LIST_HEAD(&dev->meta_out_active);
- INIT_LIST_HEAD(&dev->touch_cap_active);
+ dev->query_dv_timings_qmenu[i] = p;
- INIT_LIST_HEAD(&dev->cec_work_list);
- spin_lock_init(&dev->cec_slock);
- /*
- * Same as create_singlethread_workqueue, but now I can use the
- * string formatting of alloc_ordered_workqueue.
- */
- dev->cec_workqueue =
- alloc_ordered_workqueue("vivid-%03d-cec", WQ_MEM_RECLAIM, inst);
- if (!dev->cec_workqueue) {
- ret = -ENOMEM;
- goto unreg_dev;
+ htot = V4L2_DV_BT_FRAME_WIDTH(bt);
+ vtot = V4L2_DV_BT_FRAME_HEIGHT(bt);
+ snprintf(p, 32, "%ux%u%s%u",
+ bt->width, bt->height, bt->interlaced ? "i" : "p",
+ (u32)bt->pixelclock / (htot * vtot));
}
- if (allocators[inst] == 1)
- dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+ return 0;
+}
+
+static int vivid_create_queues(struct vivid_dev *dev)
+{
+ int ret;
/* start creating the vb2 queues */
if (dev->has_vid_cap) {
@@ -1374,7 +1229,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
V4L2_BUF_TYPE_VIDEO_CAPTURE, 2,
&vivid_vid_cap_qops);
if (ret)
- goto unreg_dev;
+ return ret;
}
if (dev->has_vid_out) {
@@ -1383,7 +1238,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
V4L2_BUF_TYPE_VIDEO_OUTPUT, 2,
&vivid_vid_out_qops);
if (ret)
- goto unreg_dev;
+ return ret;
}
if (dev->has_vbi_cap) {
@@ -1392,7 +1247,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
V4L2_BUF_TYPE_VBI_CAPTURE, 2,
&vivid_vbi_cap_qops);
if (ret)
- goto unreg_dev;
+ return ret;
}
if (dev->has_vbi_out) {
@@ -1401,7 +1256,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
V4L2_BUF_TYPE_VBI_OUTPUT, 2,
&vivid_vbi_out_qops);
if (ret)
- goto unreg_dev;
+ return ret;
}
if (dev->has_sdr_cap) {
@@ -1410,7 +1265,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
V4L2_BUF_TYPE_SDR_CAPTURE, 8,
&vivid_sdr_cap_qops);
if (ret)
- goto unreg_dev;
+ return ret;
}
if (dev->has_meta_cap) {
@@ -1419,7 +1274,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
V4L2_BUF_TYPE_META_CAPTURE, 2,
&vivid_meta_cap_qops);
if (ret)
- goto unreg_dev;
+ return ret;
}
if (dev->has_meta_out) {
@@ -1428,7 +1283,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
V4L2_BUF_TYPE_META_OUTPUT, 1,
&vivid_meta_out_qops);
if (ret)
- goto unreg_dev;
+ return ret;
}
if (dev->has_touch_cap) {
@@ -1437,63 +1292,31 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
V4L2_BUF_TYPE_VIDEO_CAPTURE, 1,
&vivid_touch_cap_qops);
if (ret)
- goto unreg_dev;
+ return ret;
}
if (dev->has_fb) {
/* Create framebuffer for testing capture/output overlay */
ret = vivid_fb_init(dev);
if (ret)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev, "Framebuffer device registered as fb%d\n",
dev->fb_info.node);
}
+ return 0;
+}
-#ifdef CONFIG_VIDEO_VIVID_CEC
- if (dev->has_vid_cap && in_type_counter[HDMI]) {
- struct cec_adapter *adap;
-
- adap = vivid_cec_alloc_adap(dev, 0, false);
- ret = PTR_ERR_OR_ZERO(adap);
- if (ret < 0)
- goto unreg_dev;
- dev->cec_rx_adap = adap;
- }
-
- if (dev->has_vid_out) {
- for (i = 0; i < dev->num_outputs; i++) {
- struct cec_adapter *adap;
-
- if (dev->output_type[i] != HDMI)
- continue;
-
- dev->cec_output2bus_map[i] = cec_tx_bus_cnt;
- adap = vivid_cec_alloc_adap(dev, cec_tx_bus_cnt, true);
- ret = PTR_ERR_OR_ZERO(adap);
- if (ret < 0) {
- for (i = 0; i < dev->num_outputs; i++)
- cec_delete_adapter(dev->cec_tx_adap[i]);
- goto unreg_dev;
- }
-
- dev->cec_tx_adap[cec_tx_bus_cnt] = adap;
- cec_tx_bus_cnt++;
- }
- }
-#endif
-
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out);
- v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap);
+static int vivid_create_devnodes(struct platform_device *pdev,
+ struct vivid_dev *dev, int inst,
+ unsigned int cec_tx_bus_cnt,
+ v4l2_std_id tvnorms_cap,
+ v4l2_std_id tvnorms_out,
+ unsigned in_type_counter[4],
+ unsigned out_type_counter[4])
+{
+ struct video_device *vfd;
+ int ret;
- /* finally start creating the device nodes */
if (dev->has_vid_cap) {
vfd = &dev->vid_cap_dev;
snprintf(vfd->name, sizeof(vfd->name),
@@ -1517,7 +1340,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->vid_cap_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&vfd->entity, 1, &dev->vid_cap_pad);
if (ret)
- goto unreg_dev;
+ return ret;
#endif
#ifdef CONFIG_VIDEO_VIVID_CEC
@@ -1526,7 +1349,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (ret < 0) {
cec_delete_adapter(dev->cec_rx_adap);
dev->cec_rx_adap = NULL;
- goto unreg_dev;
+ return ret;
}
cec_s_phys_addr(dev->cec_rx_adap, 0, false);
v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI input 0\n",
@@ -1536,12 +1359,15 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_cap_nr[inst]);
if (ret < 0)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
video_device_node_name(vfd));
}
if (dev->has_vid_out) {
+#ifdef CONFIG_VIDEO_VIVID_CEC
+ int i;
+#endif
vfd = &dev->vid_out_dev;
snprintf(vfd->name, sizeof(vfd->name),
"vivid-%03d-vid-out", inst);
@@ -1565,7 +1391,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->vid_out_pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&vfd->entity, 1, &dev->vid_out_pad);
if (ret)
- goto unreg_dev;
+ return ret;
#endif
#ifdef CONFIG_VIDEO_VIVID_CEC
@@ -1576,7 +1402,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
cec_delete_adapter(dev->cec_tx_adap[i]);
dev->cec_tx_adap[i] = NULL;
}
- goto unreg_dev;
+ return ret;
}
v4l2_info(&dev->v4l2_dev, "CEC adapter %s registered for HDMI output %d\n",
dev_name(&dev->cec_tx_adap[i]->devnode.dev), i);
@@ -1589,7 +1415,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
ret = video_register_device(vfd, VFL_TYPE_VIDEO, vid_out_nr[inst]);
if (ret < 0)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s\n",
video_device_node_name(vfd));
}
@@ -1612,12 +1438,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->vbi_cap_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&vfd->entity, 1, &dev->vbi_cap_pad);
if (ret)
- goto unreg_dev;
+ return ret;
#endif
ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_cap_nr[inst]);
if (ret < 0)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s, supports %s VBI\n",
video_device_node_name(vfd),
(dev->has_raw_vbi_cap && dev->has_sliced_vbi_cap) ?
@@ -1644,12 +1470,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->vbi_out_pad.flags = MEDIA_PAD_FL_SOURCE;
ret = media_entity_pads_init(&vfd->entity, 1, &dev->vbi_out_pad);
if (ret)
- goto unreg_dev;
+ return ret;
#endif
ret = video_register_device(vfd, VFL_TYPE_VBI, vbi_out_nr[inst]);
if (ret < 0)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev, "V4L2 output device registered as %s, supports %s VBI\n",
video_device_node_name(vfd),
(dev->has_raw_vbi_out && dev->has_sliced_vbi_out) ?
@@ -1674,12 +1500,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
dev->sdr_cap_pad.flags = MEDIA_PAD_FL_SINK;
ret = media_entity_pads_init(&vfd->entity, 1, &dev->sdr_cap_pad);
if (ret)
- goto unreg_dev;
+ return ret;
#endif
ret = video_register_device(vfd, VFL_TYPE_SDR, sdr_cap_nr[inst]);
if (ret < 0)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev, "V4L2 capture device registered as %s\n",
video_device_node_name(vfd));
}
@@ -1698,7 +1524,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_rx_nr[inst]);
if (ret < 0)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev, "V4L2 receiver device registered as %s\n",
video_device_node_name(vfd));
}
@@ -1718,7 +1544,7 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
ret = video_register_device(vfd, VFL_TYPE_RADIO, radio_tx_nr[inst]);
if (ret < 0)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev, "V4L2 transmitter device registered as %s\n",
video_device_node_name(vfd));
}
@@ -1741,12 +1567,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
ret = media_entity_pads_init(&vfd->entity, 1,
&dev->meta_cap_pad);
if (ret)
- goto unreg_dev;
+ return ret;
#endif
ret = video_register_device(vfd, VFL_TYPE_VIDEO,
meta_cap_nr[inst]);
if (ret < 0)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev,
"V4L2 metadata capture device registered as %s\n",
video_device_node_name(vfd));
@@ -1771,12 +1597,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
ret = media_entity_pads_init(&vfd->entity, 1,
&dev->meta_out_pad);
if (ret)
- goto unreg_dev;
+ return ret;
#endif
ret = video_register_device(vfd, VFL_TYPE_VIDEO,
meta_out_nr[inst]);
if (ret < 0)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev,
"V4L2 metadata output device registered as %s\n",
video_device_node_name(vfd));
@@ -1800,12 +1626,12 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
ret = media_entity_pads_init(&vfd->entity, 1,
&dev->touch_cap_pad);
if (ret)
- goto unreg_dev;
+ return ret;
#endif
ret = video_register_device(vfd, VFL_TYPE_TOUCH,
touch_cap_nr[inst]);
if (ret < 0)
- goto unreg_dev;
+ return ret;
v4l2_info(&dev->v4l2_dev,
"V4L2 touch capture device registered as %s\n",
video_device_node_name(vfd));
@@ -1817,26 +1643,268 @@ static int vivid_create_instance(struct platform_device *pdev, int inst)
if (ret) {
dev_err(dev->mdev.dev,
"media device register failed (err=%d)\n", ret);
+ return ret;
+ }
+#endif
+ return 0;
+}
+
+static int vivid_create_instance(struct platform_device *pdev, int inst)
+{
+ static const struct v4l2_dv_timings def_dv_timings =
+ V4L2_DV_BT_CEA_1280X720P60;
+ unsigned in_type_counter[4] = { 0, 0, 0, 0 };
+ unsigned out_type_counter[4] = { 0, 0, 0, 0 };
+ int ccs_cap = ccs_cap_mode[inst];
+ int ccs_out = ccs_out_mode[inst];
+ bool has_tuner;
+ bool has_modulator;
+ struct vivid_dev *dev;
+ unsigned node_type = node_types[inst];
+ v4l2_std_id tvnorms_cap = 0, tvnorms_out = 0;
+ unsigned int cec_tx_bus_cnt = 0;
+ int ret;
+ int i;
+
+ /* allocate main vivid state structure */
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return -ENOMEM;
+
+ dev->inst = inst;
+
+#ifdef CONFIG_MEDIA_CONTROLLER
+ dev->v4l2_dev.mdev = &dev->mdev;
+
+ /* Initialize media device */
+ strscpy(dev->mdev.model, VIVID_MODULE_NAME, sizeof(dev->mdev.model));
+ snprintf(dev->mdev.bus_info, sizeof(dev->mdev.bus_info),
+ "platform:%s-%03d", VIVID_MODULE_NAME, inst);
+ dev->mdev.dev = &pdev->dev;
+ media_device_init(&dev->mdev);
+ dev->mdev.ops = &vivid_media_ops;
+#endif
+
+ /* register v4l2_device */
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+ "%s-%03d", VIVID_MODULE_NAME, inst);
+ ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
+ if (ret) {
+ kfree(dev);
+ return ret;
+ }
+ dev->v4l2_dev.release = vivid_dev_release;
+
+ ret = vivid_detect_feature_set(dev, inst, node_type,
+ &has_tuner, &has_modulator,
+ &ccs_cap, &ccs_out,
+ in_type_counter, out_type_counter);
+ if (ret)
+ goto free_dev;
+
+ vivid_set_capabilities(dev);
+
+ ret = -ENOMEM;
+ /* initialize the test pattern generator */
+ tpg_init(&dev->tpg, 640, 360);
+ if (tpg_alloc(&dev->tpg, array_size(MAX_WIDTH, MAX_ZOOM)))
+ goto free_dev;
+ dev->scaled_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM));
+ if (!dev->scaled_line)
+ goto free_dev;
+ dev->blended_line = vzalloc(array_size(MAX_WIDTH, MAX_ZOOM));
+ if (!dev->blended_line)
+ goto free_dev;
+
+ /* load the edid */
+ dev->edid = vmalloc(array_size(256, 128));
+ if (!dev->edid)
+ goto free_dev;
+
+ ret = vivid_init_dv_timings(dev);
+ if (ret < 0)
+ goto free_dev;
+
+ vivid_disable_unused_ioctls(dev, has_tuner, has_modulator,
+ in_type_counter, out_type_counter);
+
+ /* configure internal data */
+ dev->fmt_cap = &vivid_formats[0];
+ dev->fmt_out = &vivid_formats[0];
+ if (!dev->multiplanar)
+ vivid_formats[0].data_offset[0] = 0;
+ dev->webcam_size_idx = 1;
+ dev->webcam_ival_idx = 3;
+ tpg_s_fourcc(&dev->tpg, dev->fmt_cap->fourcc);
+ dev->std_out = V4L2_STD_PAL;
+ if (dev->input_type[0] == TV || dev->input_type[0] == SVID)
+ tvnorms_cap = V4L2_STD_ALL;
+ if (dev->output_type[0] == SVID)
+ tvnorms_out = V4L2_STD_ALL;
+ for (i = 0; i < MAX_INPUTS; i++) {
+ dev->dv_timings_cap[i] = def_dv_timings;
+ dev->std_cap[i] = V4L2_STD_PAL;
+ }
+ dev->dv_timings_out = def_dv_timings;
+ dev->tv_freq = 2804 /* 175.25 * 16 */;
+ dev->tv_audmode = V4L2_TUNER_MODE_STEREO;
+ dev->tv_field_cap = V4L2_FIELD_INTERLACED;
+ dev->tv_field_out = V4L2_FIELD_INTERLACED;
+ dev->radio_rx_freq = 95000 * 16;
+ dev->radio_rx_audmode = V4L2_TUNER_MODE_STEREO;
+ if (dev->has_radio_tx) {
+ dev->radio_tx_freq = 95500 * 16;
+ dev->radio_rds_loop = false;
+ }
+ dev->radio_tx_subchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_RDS;
+ dev->sdr_adc_freq = 300000;
+ dev->sdr_fm_freq = 50000000;
+ dev->sdr_pixelformat = V4L2_SDR_FMT_CU8;
+ dev->sdr_buffersize = SDR_CAP_SAMPLES_PER_BUF * 2;
+
+ dev->edid_max_blocks = dev->edid_blocks = 2;
+ memcpy(dev->edid, vivid_hdmi_edid, sizeof(vivid_hdmi_edid));
+ dev->radio_rds_init_time = ktime_get();
+
+ /* create all controls */
+ ret = vivid_create_controls(dev, ccs_cap == -1, ccs_out == -1, no_error_inj,
+ in_type_counter[TV] || in_type_counter[SVID] ||
+ out_type_counter[SVID],
+ in_type_counter[HDMI] || out_type_counter[HDMI]);
+ if (ret)
goto unreg_dev;
+
+ /* enable/disable interface specific controls */
+ if (dev->num_outputs && dev->output_type[0] != HDMI)
+ v4l2_ctrl_activate(dev->ctrl_display_present, false);
+ if (dev->num_inputs && dev->input_type[0] != HDMI) {
+ v4l2_ctrl_activate(dev->ctrl_dv_timings_signal_mode, false);
+ v4l2_ctrl_activate(dev->ctrl_dv_timings, false);
+ } else if (dev->num_inputs && dev->input_type[0] == HDMI) {
+ v4l2_ctrl_activate(dev->ctrl_std_signal_mode, false);
+ v4l2_ctrl_activate(dev->ctrl_standard, false);
+ }
+
+ /*
+ * update the capture and output formats to do a proper initial
+ * configuration.
+ */
+ vivid_update_format_cap(dev, false);
+ vivid_update_format_out(dev);
+
+ /* initialize overlay */
+ dev->fb_cap.fmt.width = dev->src_rect.width;
+ dev->fb_cap.fmt.height = dev->src_rect.height;
+ dev->fb_cap.fmt.pixelformat = dev->fmt_cap->fourcc;
+ dev->fb_cap.fmt.bytesperline = dev->src_rect.width * tpg_g_twopixelsize(&dev->tpg, 0) / 2;
+ dev->fb_cap.fmt.sizeimage = dev->src_rect.height * dev->fb_cap.fmt.bytesperline;
+
+ /* update touch configuration */
+ dev->timeperframe_tch_cap.numerator = 1;
+ dev->timeperframe_tch_cap.denominator = 10;
+ vivid_set_touch(dev, 0);
+
+ /* initialize locks */
+ spin_lock_init(&dev->slock);
+ mutex_init(&dev->mutex);
+
+ /* init dma queues */
+ INIT_LIST_HEAD(&dev->vid_cap_active);
+ INIT_LIST_HEAD(&dev->vid_out_active);
+ INIT_LIST_HEAD(&dev->vbi_cap_active);
+ INIT_LIST_HEAD(&dev->vbi_out_active);
+ INIT_LIST_HEAD(&dev->sdr_cap_active);
+ INIT_LIST_HEAD(&dev->meta_cap_active);
+ INIT_LIST_HEAD(&dev->meta_out_active);
+ INIT_LIST_HEAD(&dev->touch_cap_active);
+
+ INIT_LIST_HEAD(&dev->cec_work_list);
+ spin_lock_init(&dev->cec_slock);
+ /*
+ * Same as create_singlethread_workqueue, but now I can use the
+ * string formatting of alloc_ordered_workqueue.
+ */
+ dev->cec_workqueue = alloc_ordered_workqueue("vivid-%03d-cec",
+ WQ_MEM_RECLAIM, inst);
+ if (!dev->cec_workqueue) {
+ ret = -ENOMEM;
+ goto unreg_dev;
+ }
+
+ if (allocators[inst] == 1)
+ dma_coerce_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
+
+ ret = vivid_create_queues(dev);
+ if (ret)
+ goto unreg_dev;
+
+#ifdef CONFIG_VIDEO_VIVID_CEC
+ if (dev->has_vid_cap && in_type_counter[HDMI]) {
+ struct cec_adapter *adap;
+
+ adap = vivid_cec_alloc_adap(dev, 0, false);
+ ret = PTR_ERR_OR_ZERO(adap);
+ if (ret < 0)
+ goto unreg_dev;
+ dev->cec_rx_adap = adap;
+ }
+
+ if (dev->has_vid_out) {
+ for (i = 0; i < dev->num_outputs; i++) {
+ struct cec_adapter *adap;
+
+ if (dev->output_type[i] != HDMI)
+ continue;
+
+ dev->cec_output2bus_map[i] = cec_tx_bus_cnt;
+ adap = vivid_cec_alloc_adap(dev, cec_tx_bus_cnt, true);
+ ret = PTR_ERR_OR_ZERO(adap);
+ if (ret < 0) {
+ for (i = 0; i < dev->num_outputs; i++)
+ cec_delete_adapter(dev->cec_tx_adap[i]);
+ goto unreg_dev;
+ }
+
+ dev->cec_tx_adap[cec_tx_bus_cnt] = adap;
+ cec_tx_bus_cnt++;
+ }
}
#endif
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_cap);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vid_out);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_cap);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_vbi_out);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_rx);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_radio_tx);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_sdr_cap);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_cap);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_meta_out);
+ v4l2_ctrl_handler_setup(&dev->ctrl_hdl_touch_cap);
+
+ /* finally start creating the device nodes */
+ ret = vivid_create_devnodes(pdev, dev, inst, cec_tx_bus_cnt,
+ tvnorms_cap, tvnorms_out,
+ in_type_counter, out_type_counter);
+ if (ret)
+ goto unreg_dev;
+
/* Now that everything is fine, let's add it to device list */
vivid_devs[inst] = dev;
return 0;
unreg_dev:
- video_unregister_device(&dev->touch_cap_dev);
- video_unregister_device(&dev->meta_out_dev);
- video_unregister_device(&dev->meta_cap_dev);
+ vb2_video_unregister_device(&dev->touch_cap_dev);
+ vb2_video_unregister_device(&dev->meta_out_dev);
+ vb2_video_unregister_device(&dev->meta_cap_dev);
video_unregister_device(&dev->radio_tx_dev);
video_unregister_device(&dev->radio_rx_dev);
- video_unregister_device(&dev->sdr_cap_dev);
- video_unregister_device(&dev->vbi_out_dev);
- video_unregister_device(&dev->vbi_cap_dev);
- video_unregister_device(&dev->vid_out_dev);
- video_unregister_device(&dev->vid_cap_dev);
+ vb2_video_unregister_device(&dev->sdr_cap_dev);
+ vb2_video_unregister_device(&dev->vbi_out_dev);
+ vb2_video_unregister_device(&dev->vbi_cap_dev);
+ vb2_video_unregister_device(&dev->vid_out_dev);
+ vb2_video_unregister_device(&dev->vid_cap_dev);
cec_unregister_adapter(dev->cec_rx_adap);
for (i = 0; i < MAX_OUTPUTS; i++)
cec_unregister_adapter(dev->cec_tx_adap[i]);
@@ -1907,27 +1975,27 @@ static int vivid_remove(struct platform_device *pdev)
if (dev->has_vid_cap) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->vid_cap_dev));
- video_unregister_device(&dev->vid_cap_dev);
+ vb2_video_unregister_device(&dev->vid_cap_dev);
}
if (dev->has_vid_out) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->vid_out_dev));
- video_unregister_device(&dev->vid_out_dev);
+ vb2_video_unregister_device(&dev->vid_out_dev);
}
if (dev->has_vbi_cap) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->vbi_cap_dev));
- video_unregister_device(&dev->vbi_cap_dev);
+ vb2_video_unregister_device(&dev->vbi_cap_dev);
}
if (dev->has_vbi_out) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->vbi_out_dev));
- video_unregister_device(&dev->vbi_out_dev);
+ vb2_video_unregister_device(&dev->vbi_out_dev);
}
if (dev->has_sdr_cap) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->sdr_cap_dev));
- video_unregister_device(&dev->sdr_cap_dev);
+ vb2_video_unregister_device(&dev->sdr_cap_dev);
}
if (dev->has_radio_rx) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
@@ -1948,17 +2016,17 @@ static int vivid_remove(struct platform_device *pdev)
if (dev->has_meta_cap) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->meta_cap_dev));
- video_unregister_device(&dev->meta_cap_dev);
+ vb2_video_unregister_device(&dev->meta_cap_dev);
}
if (dev->has_meta_out) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->meta_out_dev));
- video_unregister_device(&dev->meta_out_dev);
+ vb2_video_unregister_device(&dev->meta_out_dev);
}
if (dev->has_touch_cap) {
v4l2_info(&dev->v4l2_dev, "unregistering %s\n",
video_device_node_name(&dev->touch_cap_dev));
- video_unregister_device(&dev->touch_cap_dev);
+ vb2_video_unregister_device(&dev->touch_cap_dev);
}
cec_unregister_adapter(dev->cec_rx_adap);
for (j = 0; j < MAX_OUTPUTS; j++)
diff --git a/drivers/media/test-drivers/vivid/vivid-meta-out.c b/drivers/media/test-drivers/vivid/vivid-meta-out.c
index ff8a039aba72..95835b52b58f 100644
--- a/drivers/media/test-drivers/vivid/vivid-meta-out.c
+++ b/drivers/media/test-drivers/vivid/vivid-meta-out.c
@@ -164,10 +164,11 @@ void vivid_meta_out_process(struct vivid_dev *dev,
{
struct vivid_meta_out_buf *meta = vb2_plane_vaddr(&buf->vb.vb2_buf, 0);
- tpg_s_brightness(&dev->tpg, meta->brightness);
- tpg_s_contrast(&dev->tpg, meta->contrast);
- tpg_s_saturation(&dev->tpg, meta->saturation);
- tpg_s_hue(&dev->tpg, meta->hue);
+ v4l2_ctrl_s_ctrl(dev->brightness, meta->brightness);
+ v4l2_ctrl_s_ctrl(dev->contrast, meta->contrast);
+ v4l2_ctrl_s_ctrl(dev->saturation, meta->saturation);
+ v4l2_ctrl_s_ctrl(dev->hue, meta->hue);
+
dprintk(dev, 2, " %s brightness %u contrast %u saturation %u hue %d\n",
__func__, meta->brightness, meta->contrast,
meta->saturation, meta->hue);
diff --git a/drivers/media/test-drivers/vivid/vivid-vbi-gen.c b/drivers/media/test-drivers/vivid/vivid-vbi-gen.c
index acc98445a1fa..a141369a7a63 100644
--- a/drivers/media/test-drivers/vivid/vivid-vbi-gen.c
+++ b/drivers/media/test-drivers/vivid/vivid-vbi-gen.c
@@ -298,7 +298,7 @@ void vivid_vbi_gen_sliced(struct vivid_vbi_gen_data *vbi,
switch (frame) {
case 0:
vivid_vbi_gen_set_time_of_day(vbi->time_of_day_packet);
- /* fall through */
+ fallthrough;
case 1 ... 7:
data1->data[0] = vbi->time_of_day_packet[frame * 2];
data1->data[1] = vbi->time_of_day_packet[frame * 2 + 1];
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-cap.c b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
index e94beef008c8..eadf28ab1e39 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-cap.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-cap.c
@@ -560,6 +560,7 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
unsigned factor = 1;
unsigned w, h;
unsigned p;
+ bool user_set_csc = !!(mp->flags & V4L2_PIX_FMT_FLAG_SET_CSC);
fmt = vivid_get_format(dev, mp->pixelformat);
if (!fmt) {
@@ -633,13 +634,30 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
(fmt->bit_depth[p] / fmt->vdownsampling[p])) /
(fmt->bit_depth[0] / fmt->vdownsampling[0]);
- mp->colorspace = vivid_colorspace_cap(dev);
- if (fmt->color_enc == TGP_COLOR_ENC_HSV)
- mp->hsv_enc = vivid_hsv_enc_cap(dev);
- else
+ if (!user_set_csc || !v4l2_is_colorspace_valid(mp->colorspace))
+ mp->colorspace = vivid_colorspace_cap(dev);
+
+ if (!user_set_csc || !v4l2_is_xfer_func_valid(mp->xfer_func))
+ mp->xfer_func = vivid_xfer_func_cap(dev);
+
+ if (fmt->color_enc == TGP_COLOR_ENC_HSV) {
+ if (!user_set_csc || !v4l2_is_hsv_enc_valid(mp->hsv_enc))
+ mp->hsv_enc = vivid_hsv_enc_cap(dev);
+ } else if (fmt->color_enc == TGP_COLOR_ENC_YCBCR) {
+ if (!user_set_csc || !v4l2_is_ycbcr_enc_valid(mp->ycbcr_enc))
+ mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev);
+ } else {
mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev);
- mp->xfer_func = vivid_xfer_func_cap(dev);
- mp->quantization = vivid_quantization_cap(dev);
+ }
+
+ if (fmt->color_enc == TGP_COLOR_ENC_YCBCR ||
+ fmt->color_enc == TGP_COLOR_ENC_RGB) {
+ if (!user_set_csc || !v4l2_is_quant_valid(mp->quantization))
+ mp->quantization = vivid_quantization_cap(dev);
+ } else {
+ mp->quantization = vivid_quantization_cap(dev);
+ }
+
memset(mp->reserved, 0, sizeof(mp->reserved));
return 0;
}
@@ -769,6 +787,14 @@ int vivid_s_fmt_vid_cap(struct file *file, void *priv,
if (vivid_is_sdtv_cap(dev))
dev->tv_field_cap = mp->field;
tpg_update_mv_step(&dev->tpg);
+ dev->tpg.colorspace = mp->colorspace;
+ dev->tpg.xfer_func = mp->xfer_func;
+ if (dev->fmt_cap->color_enc == TGP_COLOR_ENC_YCBCR)
+ dev->tpg.ycbcr_enc = mp->ycbcr_enc;
+ else
+ dev->tpg.hsv_enc = mp->hsv_enc;
+ dev->tpg.quantization = mp->quantization;
+
return 0;
}
diff --git a/drivers/media/test-drivers/vivid/vivid-vid-common.c b/drivers/media/test-drivers/vivid/vivid-vid-common.c
index 76b0be670ebb..19701fe72030 100644
--- a/drivers/media/test-drivers/vivid/vivid-vid-common.c
+++ b/drivers/media/test-drivers/vivid/vivid-vid-common.c
@@ -920,6 +920,31 @@ int vivid_enum_fmt_vid(struct file *file, void *priv,
fmt = &vivid_formats[f->index];
f->pixelformat = fmt->fourcc;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE)
+ return 0;
+ /*
+ * For capture devices, we support the CSC API.
+ * We allow userspace to:
+ * 1. set the colorspace
+ * 2. set the xfer_func
+ * 3. set the ycbcr_enc on YUV formats
+ * 4. set the hsv_enc on HSV formats
+ * 5. set the quantization on YUV and RGB formats
+ */
+ f->flags |= V4L2_FMT_FLAG_CSC_COLORSPACE;
+ f->flags |= V4L2_FMT_FLAG_CSC_XFER_FUNC;
+
+ if (fmt->color_enc == TGP_COLOR_ENC_YCBCR) {
+ f->flags |= V4L2_FMT_FLAG_CSC_YCBCR_ENC;
+ f->flags |= V4L2_FMT_FLAG_CSC_QUANTIZATION;
+ } else if (fmt->color_enc == TGP_COLOR_ENC_HSV) {
+ f->flags |= V4L2_FMT_FLAG_CSC_HSV_ENC;
+ } else if (fmt->color_enc == TGP_COLOR_ENC_RGB) {
+ f->flags |= V4L2_FMT_FLAG_CSC_QUANTIZATION;
+ }
+
return 0;
}
diff --git a/drivers/media/tuners/fc0011.c b/drivers/media/tuners/fc0011.c
index b7b5b33b11f4..eaa3bbc903d7 100644
--- a/drivers/media/tuners/fc0011.c
+++ b/drivers/media/tuners/fc0011.c
@@ -250,7 +250,7 @@ static int fc0011_set_params(struct dvb_frontend *fe)
dev_warn(&priv->i2c->dev, "Unsupported bandwidth %u kHz. Using 6000 kHz.\n",
bandwidth);
bandwidth = 6000;
- /* fallthrough */
+ fallthrough;
case 6000:
regs[FC11_REG_VCOSEL] |= FC11_VCOSEL_BW6M;
break;
diff --git a/drivers/media/tuners/qt1010.c b/drivers/media/tuners/qt1010.c
index e48faf942830..3853a3d43d4f 100644
--- a/drivers/media/tuners/qt1010.c
+++ b/drivers/media/tuners/qt1010.c
@@ -222,23 +222,24 @@ static int qt1010_init_meas1(struct qt1010_priv *priv,
{ QT1010_WR, reg, reg_init_val },
{ QT1010_WR, 0x1e, 0x00 },
{ QT1010_WR, 0x1e, oper },
- { QT1010_RD, reg, 0xff }
};
for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
- if (i2c_data[i].oper == QT1010_WR) {
- err = qt1010_writereg(priv, i2c_data[i].reg,
- i2c_data[i].val);
- } else {
- err = qt1010_readreg(priv, i2c_data[i].reg, &val2);
- }
- if (err) return err;
+ err = qt1010_writereg(priv, i2c_data[i].reg,
+ i2c_data[i].val);
+ if (err)
+ return err;
}
+ err = qt1010_readreg(priv, reg, &val2);
+ if (err)
+ return err;
do {
val1 = val2;
err = qt1010_readreg(priv, reg, &val2);
- if (err) return err;
+ if (err)
+ return err;
+
dev_dbg(&priv->i2c->dev, "%s: compare reg:%02x %02x %02x\n",
__func__, reg, val1, val2);
} while (val1 != val2);
@@ -250,7 +251,7 @@ static int qt1010_init_meas1(struct qt1010_priv *priv,
static int qt1010_init_meas2(struct qt1010_priv *priv,
u8 reg_init_val, u8 *retval)
{
- u8 i, val;
+ u8 i, val = 0xff;
int err;
qt1010_i2c_oper_t i2c_data[] = {
{ QT1010_WR, 0x07, reg_init_val },
@@ -261,6 +262,7 @@ static int qt1010_init_meas2(struct qt1010_priv *priv,
{ QT1010_WR, 0x1e, 0x00 },
{ QT1010_WR, 0x22, 0xff }
};
+
for (i = 0; i < ARRAY_SIZE(i2c_data); i++) {
if (i2c_data[i].oper == QT1010_WR) {
err = qt1010_writereg(priv, i2c_data[i].reg,
@@ -268,7 +270,8 @@ static int qt1010_init_meas2(struct qt1010_priv *priv,
} else {
err = qt1010_readreg(priv, i2c_data[i].reg, &val);
}
- if (err) return err;
+ if (err)
+ return err;
}
*retval = val;
return 0;
diff --git a/drivers/media/tuners/tda18271-fe.c b/drivers/media/tuners/tda18271-fe.c
index 471aaf71fdef..f0371d004b36 100644
--- a/drivers/media/tuners/tda18271-fe.c
+++ b/drivers/media/tuners/tda18271-fe.c
@@ -948,7 +948,7 @@ static int tda18271_set_params(struct dvb_frontend *fe)
break;
case SYS_DVBC_ANNEX_B:
bw = 6000000;
- /* fall through */
+ fallthrough;
case SYS_DVBC_ANNEX_A:
case SYS_DVBC_ANNEX_C:
if (bw <= 6000000) {
diff --git a/drivers/media/tuners/tuner-simple.c b/drivers/media/tuners/tuner-simple.c
index b6e70fada3fb..8fb186b25d6a 100644
--- a/drivers/media/tuners/tuner-simple.c
+++ b/drivers/media/tuners/tuner-simple.c
@@ -500,7 +500,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
case TUNER_TENA_9533_DI:
case TUNER_YMEC_TVF_5533MF:
tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
- return 0;
+ return -EINVAL;
case TUNER_PHILIPS_FM1216ME_MK3:
case TUNER_PHILIPS_FM1236_MK3:
case TUNER_PHILIPS_FMD1216ME_MK3:
@@ -702,7 +702,8 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
TUNER_RATIO_SELECT_50; /* 50 kHz step */
/* Bandswitch byte */
- simple_radio_bandswitch(fe, &buffer[0]);
+ if (simple_radio_bandswitch(fe, &buffer[0]))
+ return 0;
/* Convert from 1/16 kHz V4L steps to 1/20 MHz (=50 kHz) PLL steps
freq * (1 Mhz / 16000 V4L steps) * (20 PLL steps / 1 MHz) =
diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c
index 4befa920246c..3d3368202cd0 100644
--- a/drivers/media/usb/au0828/au0828-input.c
+++ b/drivers/media/usb/au0828/au0828-input.c
@@ -104,11 +104,11 @@ static int au8522_rc_andor(struct au0828_rc *ir, u16 reg, u8 mask, u8 value)
/* Remote Controller time units */
-#define AU8522_UNIT 200000 /* ns */
-#define NEC_START_SPACE (4500000 / AU8522_UNIT)
-#define NEC_START_PULSE (562500 * 16)
+#define AU8522_UNIT 200 /* us */
+#define NEC_START_SPACE (4500 / AU8522_UNIT)
+#define NEC_START_PULSE (563 * 16)
#define RC5_START_SPACE (4 * AU8522_UNIT)
-#define RC5_START_PULSE 888888
+#define RC5_START_PULSE 889
static int au0828_get_key_au8522(struct au0828_rc *ir)
{
diff --git a/drivers/media/usb/au0828/au0828-video.c b/drivers/media/usb/au0828/au0828-video.c
index 51b8d14fb4dc..aa5bc6a2ae20 100644
--- a/drivers/media/usb/au0828/au0828-video.c
+++ b/drivers/media/usb/au0828/au0828-video.c
@@ -938,8 +938,8 @@ int au0828_analog_unregister(struct au0828_dev *dev)
return 0;
mutex_lock(&au0828_sysfs_lock);
- video_unregister_device(&dev->vdev);
- video_unregister_device(&dev->vbi_dev);
+ vb2_video_unregister_device(&dev->vdev);
+ vb2_video_unregister_device(&dev->vbi_dev);
mutex_unlock(&au0828_sysfs_lock);
v4l2_device_disconnect(&dev->v4l2_dev);
@@ -2011,8 +2011,7 @@ int au0828_analog_register(struct au0828_dev *dev,
if (retval != 0) {
dprintk(1, "unable to register video device (error = %d).\n",
retval);
- ret = -ENODEV;
- goto err_reg_vdev;
+ return -ENODEV;
}
/* Register the vbi device */
@@ -2040,10 +2039,7 @@ int au0828_analog_register(struct au0828_dev *dev,
return 0;
err_reg_vbi_dev:
- video_unregister_device(&dev->vdev);
-err_reg_vdev:
- vb2_queue_release(&dev->vb_vidq);
- vb2_queue_release(&dev->vb_vbiq);
+ vb2_video_unregister_device(&dev->vdev);
return ret;
}
diff --git a/drivers/media/usb/b2c2/flexcop-usb.c b/drivers/media/usb/b2c2/flexcop-usb.c
index e3234d169065..e731243267e4 100644
--- a/drivers/media/usb/b2c2/flexcop-usb.c
+++ b/drivers/media/usb/b2c2/flexcop-usb.c
@@ -419,10 +419,9 @@ static void flexcop_usb_transfer_exit(struct flexcop_usb *fc_usb)
usb_free_urb(fc_usb->iso_urb[i]);
}
- if (fc_usb->iso_buffer != NULL)
- usb_free_coherent(fc_usb->udev,
- fc_usb->buffer_size, fc_usb->iso_buffer,
- fc_usb->dma_addr);
+ usb_free_coherent(fc_usb->udev, fc_usb->buffer_size,
+ fc_usb->iso_buffer, fc_usb->dma_addr);
+
}
static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb)
@@ -513,6 +512,8 @@ static int flexcop_usb_init(struct flexcop_usb *fc_usb)
if (fc_usb->uintf->cur_altsetting->desc.bNumEndpoints < 1)
return -ENODEV;
+ if (!usb_endpoint_is_isoc_in(&fc_usb->uintf->cur_altsetting->endpoint[1].desc))
+ return -ENODEV;
switch (fc_usb->udev->speed) {
case USB_SPEED_LOW:
diff --git a/drivers/media/usb/b2c2/flexcop-usb.h b/drivers/media/usb/b2c2/flexcop-usb.h
index e86faa0e06ca..2f230bf72252 100644
--- a/drivers/media/usb/b2c2/flexcop-usb.h
+++ b/drivers/media/usb/b2c2/flexcop-usb.h
@@ -15,7 +15,7 @@
#define B2C2_USB_CTRL_PIPE_IN usb_rcvctrlpipe(fc_usb->udev, 0)
#define B2C2_USB_CTRL_PIPE_OUT usb_sndctrlpipe(fc_usb->udev, 0)
-#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev, 0x81)
+#define B2C2_USB_DATA_PIPE usb_rcvisocpipe(fc_usb->udev, 1)
struct flexcop_usb {
struct usb_device *udev;
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 982cb56e97e9..05d91caaed0c 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -115,11 +115,9 @@ void cx231xx_init_extension(struct cx231xx *dev)
struct cx231xx_ops *ops = NULL;
mutex_lock(&cx231xx_devlist_mutex);
- if (!list_empty(&cx231xx_extension_devlist)) {
- list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
- if (ops->init)
- ops->init(dev);
- }
+ list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
+ if (ops->init)
+ ops->init(dev);
}
mutex_unlock(&cx231xx_devlist_mutex);
}
@@ -129,11 +127,9 @@ void cx231xx_close_extension(struct cx231xx *dev)
struct cx231xx_ops *ops = NULL;
mutex_lock(&cx231xx_devlist_mutex);
- if (!list_empty(&cx231xx_extension_devlist)) {
- list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
- if (ops->fini)
- ops->fini(dev);
- }
+ list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
+ if (ops->fini)
+ ops->fini(dev);
}
mutex_unlock(&cx231xx_devlist_mutex);
}
diff --git a/drivers/media/usb/dvb-usb-v2/af9015.c b/drivers/media/usb/dvb-usb-v2/af9015.c
index c427b9031e42..c70b3cef3176 100644
--- a/drivers/media/usb/dvb-usb-v2/af9015.c
+++ b/drivers/media/usb/dvb-usb-v2/af9015.c
@@ -43,7 +43,7 @@ static int af9015_ctrl_msg(struct dvb_usb_device *d, struct req_t *req)
case READ_I2C:
write = 0;
state->buf[2] |= 0x01; /* set I2C direction */
- /* fall through */
+ fallthrough;
case WRITE_I2C:
state->buf[0] = READ_WRITE_I2C;
break;
diff --git a/drivers/media/usb/dvb-usb-v2/gl861.c b/drivers/media/usb/dvb-usb-v2/gl861.c
index b7ca236174f3..0c434259c36f 100644
--- a/drivers/media/usb/dvb-usb-v2/gl861.c
+++ b/drivers/media/usb/dvb-usb-v2/gl861.c
@@ -41,7 +41,7 @@ static int gl861_ctrl_msg(struct dvb_usb_device *d, u8 request, u16 value,
switch (request) {
case CMD_WRITE:
memcpy(ctx->buf, data, size);
- /* Fall through */
+ fallthrough;
case CMD_WRITE_SHORT:
pipe = usb_sndctrlpipe(d->udev, 0);
requesttype = USB_TYPE_VENDOR | USB_DIR_OUT;
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index 8a3c0eeed959..5a7a9522d46d 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -687,7 +687,7 @@ static const char *lme_firmware_switch(struct dvb_usb_device *d, int cold)
cold = 0;
break;
}
- /* fall through */
+ fallthrough;
case TUNER_LG:
fw_lme = fw_lg;
ret = request_firmware(&fw, fw_lme, &udev->dev);
@@ -710,7 +710,7 @@ static const char *lme_firmware_switch(struct dvb_usb_device *d, int cold)
cold = 0;
break;
}
- /* fall through */
+ fallthrough;
case TUNER_LG:
fw_lme = fw_c_lg;
ret = request_firmware(&fw, fw_lme, &udev->dev);
@@ -718,7 +718,7 @@ static const char *lme_firmware_switch(struct dvb_usb_device *d, int cold)
st->dvb_usb_lme2510_firmware = TUNER_LG;
break;
}
- /* fall through */
+ fallthrough;
case TUNER_S0194:
fw_lme = fw_c_s0194;
ret = request_firmware(&fw, fw_lme, &udev->dev);
@@ -1018,7 +1018,7 @@ static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
}
break;
}
- /* fall through */
+ fallthrough;
case 0x22f0:
st->i2c_gate = 5;
adap->fe[0] = dvb_attach(m88rs2000_attach,
diff --git a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
index 0b7dda99e410..ef489c566b75 100644
--- a/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
+++ b/drivers/media/usb/dvb-usb-v2/mxl111sf-gpio.c
@@ -632,7 +632,7 @@ int mxl111sf_set_gpio(struct mxl111sf_state *state, int gpio, int val)
default:
mxl_printk(KERN_ERR,
"gpio_port_expander undefined, assuming PCA9534");
- /* fall-thru */
+ fallthrough;
case mxl111sf_PCA9534:
return pca9534_set_gpio(state, gpio, val);
case mxl111sf_gpio_hw:
@@ -693,7 +693,7 @@ int mxl111sf_init_port_expander(struct mxl111sf_state *state)
default:
mxl_printk(KERN_ERR,
"gpio_port_expander undefined, assuming PCA9534");
- /* fall-thru */
+ fallthrough;
case mxl111sf_PCA9534:
return pca9534_init_port_expander(state);
case mxl111sf_gpio_hw:
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 2080f6ef4be1..91460e4d0c30 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -1781,7 +1781,7 @@ static int rtl2832u_rc_query(struct dvb_usb_device *d)
/* pass data to Kernel IR decoder */
for (i = 0; i < len; i++) {
ev.pulse = buf[i] >> 7;
- ev.duration = 50800 * (buf[i] & 0x7f);
+ ev.duration = 51 * (buf[i] & 0x7f);
ir_raw_event_store_with_filter(d->rc_dev, &ev);
}
@@ -1809,7 +1809,7 @@ static int rtl2832u_get_rc_config(struct dvb_usb_device *d,
rc->query = rtl2832u_rc_query;
rc->interval = 200;
/* we program idle len to 0xc0, set timeout to one less */
- rc->timeout = 0xbf * 50800;
+ rc->timeout = 0xbf * 51;
return 0;
}
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
index 25ba03edcb5c..7498110142e4 100644
--- a/drivers/media/usb/dvb-usb/Kconfig
+++ b/drivers/media/usb/dvb-usb/Kconfig
@@ -279,6 +279,7 @@ config DVB_USB_PCTV452E
tristate "Pinnacle PCTV HDTV Pro USB device/TT Connect S2-3600"
depends on DVB_USB
select TTPCI_EEPROM
+ select DVB_ISL6423 if MEDIA_SUBDRV_AUTOSELECT
select DVB_LNBP22 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STB0899 if MEDIA_SUBDRV_AUTOSELECT
select DVB_STB6100 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/usb/dvb-usb/cxusb-analog.c b/drivers/media/usb/dvb-usb/cxusb-analog.c
index 001cae648797..e93183ddd797 100644
--- a/drivers/media/usb/dvb-usb/cxusb-analog.c
+++ b/drivers/media/usb/dvb-usb/cxusb-analog.c
@@ -1615,8 +1615,6 @@ static void cxusb_medion_videodev_release(struct video_device *vdev)
cxusb_vprintk(dvbdev, OPS, "video device release\n");
- vb2_queue_release(vdev->queue);
-
video_device_release(vdev);
}
@@ -1647,8 +1645,7 @@ static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev)
cxdev->videodev = video_device_alloc();
if (!cxdev->videodev) {
dev_err(&dvbdev->udev->dev, "video device alloc failed\n");
- ret = -ENOMEM;
- goto ret_qrelease;
+ return -ENOMEM;
}
cxdev->videodev->device_caps = videocaps;
@@ -1674,10 +1671,6 @@ static int cxusb_medion_register_analog_video(struct dvb_usb_device *dvbdev)
ret_vrelease:
video_device_release(cxdev->videodev);
-
-ret_qrelease:
- vb2_queue_release(&cxdev->videoqueue);
-
return ret;
}
@@ -1820,7 +1813,7 @@ int cxusb_medion_register_analog(struct dvb_usb_device *dvbdev)
return 0;
ret_vunreg:
- video_unregister_device(cxdev->videodev);
+ vb2_video_unregister_device(cxdev->videodev);
ret_unregister:
v4l2_device_put(&cxdev->v4l2dev);
@@ -1836,7 +1829,7 @@ void cxusb_medion_unregister_analog(struct dvb_usb_device *dvbdev)
cxusb_vprintk(dvbdev, OPS, "unregistering analog\n");
video_unregister_device(cxdev->radiodev);
- video_unregister_device(cxdev->videodev);
+ vb2_video_unregister_device(cxdev->videodev);
v4l2_device_put(&cxdev->v4l2dev);
wait_for_completion(&cxdev->v4l2_release);
diff --git a/drivers/media/usb/dvb-usb/dib0700_devices.c b/drivers/media/usb/dvb-usb/dib0700_devices.c
index 52e648e2713a..d3288c107906 100644
--- a/drivers/media/usb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/usb/dvb-usb/dib0700_devices.c
@@ -1738,14 +1738,9 @@ static int dib809x_tuner_attach(struct dvb_usb_adapter *adap)
struct dib0700_adapter_state *st = adap->priv;
struct i2c_adapter *tun_i2c = st->dib8000_ops.get_i2c_master(adap->fe_adap[0].fe, DIBX000_I2C_INTERFACE_TUNER, 1);
- if (adap->id == 0) {
- if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
- return -ENODEV;
- } else {
- /* FIXME: check if it is fe_adap[1] */
- if (dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config) == NULL)
- return -ENODEV;
- }
+ /* FIXME: if adap->id != 0, check if it is fe_adap[1] */
+ if (!dvb_attach(dib0090_register, adap->fe_adap[0].fe, tun_i2c, &dib809x_dib0090_config))
+ return -ENODEV;
st->set_param_save = adap->fe_adap[0].fe->ops.tuner_ops.set_params;
adap->fe_adap[0].fe->ops.tuner_ops.set_params = dib8096_set_param_override;
diff --git a/drivers/media/usb/dvb-usb/pctv452e.c b/drivers/media/usb/dvb-usb/pctv452e.c
index 441d878fc22c..9b78b40abc6d 100644
--- a/drivers/media/usb/dvb-usb/pctv452e.c
+++ b/drivers/media/usb/dvb-usb/pctv452e.c
@@ -20,6 +20,7 @@
#include "stb6100.h"
#include "stb6100_cfg.h"
/* FE Power */
+#include "isl6423.h"
#include "lnbp22.h"
#include <media/dvb_ca_en50221.h>
@@ -83,6 +84,13 @@ static struct stb0899_postproc pctv45e_postproc[] = {
{ 0, 0 }
};
+static struct isl6423_config pctv452e_isl6423_config = {
+ .current_max = SEC_CURRENT_515m,
+ .curlim = SEC_CURRENT_LIM_ON,
+ .mod_extern = 1,
+ .addr = 0x08,
+};
+
/*
* stores all private variables for communication with the PCTV452e DVB-S2
*/
@@ -909,15 +917,23 @@ static int pctv452e_frontend_attach(struct dvb_usb_adapter *a)
&a->dev->i2c_adap);
if (!a->fe_adap[0].fe)
return -ENODEV;
- if ((dvb_attach(lnbp22_attach, a->fe_adap[0].fe,
- &a->dev->i2c_adap)) == NULL)
- err("Cannot attach lnbp22\n");
id = a->dev->desc->warm_ids[0];
- if (USB_VID_TECHNOTREND == id->idVendor
- && USB_PID_TECHNOTREND_CONNECT_S2_3650_CI == id->idProduct)
+ if (id->idVendor == USB_VID_TECHNOTREND &&
+ id->idProduct == USB_PID_TECHNOTREND_CONNECT_S2_3650_CI) {
+ if (dvb_attach(lnbp22_attach,
+ a->fe_adap[0].fe,
+ &a->dev->i2c_adap) == NULL) {
+ err("Cannot attach lnbp22\n");
+ }
/* Error ignored. */
tt3650_ci_init(a);
+ } else if (dvb_attach(isl6423_attach,
+ a->fe_adap[0].fe,
+ &a->dev->i2c_adap,
+ &pctv452e_isl6423_config) == NULL) {
+ err("Cannot attach isl6423\n");
+ }
return 0;
}
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index f172120db2aa..a9ed26ce1be6 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -656,14 +656,14 @@ unlock:
for (i = 1; i < ARRAY_SIZE(state->buf); i++) {
if (buf[i] == 0xff) {
ev.pulse = 0;
- ev.duration = 888888*2;
+ ev.duration = 889 * 2;
ir_raw_event_store(d->rc_dev, &ev);
break;
}
ev.pulse = !ev.pulse;
ev.duration = (buf[i] * FIRMWARE_CLOCK_DIVISOR *
- FIRMWARE_CLOCK_TICK) / 1000;
+ FIRMWARE_CLOCK_TICK) / (1000 * 1000);
ir_raw_event_store(d->rc_dev, &ev);
}
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 6833b5bfe293..dc968fd5ace9 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -362,13 +362,13 @@ static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
return -ENODEV;
switch (cmd) {
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
- case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
atomic_set(&dev->adev.stream_started, 1);
break;
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
- case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
atomic_set(&dev->adev.stream_started, 0);
break;
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index a8c321d11827..5144888ae36f 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -2519,6 +2519,26 @@ const struct em28xx_board em28xx_boards[] = {
.amux = EM28XX_AMUX_LINE_IN,
} },
},
+ /*
+ * 1f4d:1abe MyGica iGrabber
+ * (same as several other EM2860 devices)
+ * Empia EM2860, Philips SAA7113, Empia EMP202, No Tuner
+ */
+ [EM2860_BOARD_MYGICA_IGRABBER] = {
+ .name = "MyGica iGrabber",
+ .vchannels = 2,
+ .tuner_type = TUNER_ABSENT,
+ .decoder = EM28XX_SAA711X,
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_LINE_IN,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = SAA7115_SVIDEO3,
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
+ },
};
EXPORT_SYMBOL_GPL(em28xx_boards);
@@ -2698,6 +2718,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2860_BOARD_EASYCAP },
{ USB_DEVICE(0x1b80, 0xe425),
.driver_info = EM2874_BOARD_MAXMEDIA_UB425_TC },
+ { USB_DEVICE(0x1f4d, 0x1abe),
+ .driver_info = EM2860_BOARD_MYGICA_IGRABBER },
{ USB_DEVICE(0x2304, 0x0242),
.driver_info = EM2884_BOARD_PCTV_510E },
{ USB_DEVICE(0x2013, 0x0251),
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index acbb62397314..55a46faaf7b7 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -151,6 +151,7 @@
#define EM2882_BOARD_ZOLID_HYBRID_TV_STICK 102
#define EM2861_BOARD_MAGIX_VIDEOWANDLER2 103
#define EM28178_BOARD_PCTV_461E_V2 104
+#define EM2860_BOARD_MYGICA_IGRABBER 105
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
diff --git a/drivers/media/usb/go7007/go7007-driver.c b/drivers/media/usb/go7007/go7007-driver.c
index 153a0c3e3da6..f1767be9d868 100644
--- a/drivers/media/usb/go7007/go7007-driver.c
+++ b/drivers/media/usb/go7007/go7007-driver.c
@@ -643,7 +643,7 @@ void go7007_parse_video_stream(struct go7007 *go, u8 *buf, int length)
case 0xD8:
if (go->format == V4L2_PIX_FMT_MJPEG)
vb = frame_boundary(go, vb);
- /* fall through */
+ fallthrough;
default:
store_byte(vb, 0xFF);
store_byte(vb, buf[i]);
diff --git a/drivers/media/usb/gspca/mr97310a.c b/drivers/media/usb/gspca/mr97310a.c
index 464aa61cd914..3553788e8542 100644
--- a/drivers/media/usb/gspca/mr97310a.c
+++ b/drivers/media/usb/gspca/mr97310a.c
@@ -510,7 +510,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
switch (gspca_dev->pixfmt.width) {
case 160:
data[9] |= 0x04; /* reg 8, 2:1 scale down from 320 */
- /* fall through */
+ fallthrough;
case 320:
default:
data[3] = 0x28; /* reg 2, H size/8 */
@@ -520,7 +520,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
break;
case 176:
data[9] |= 0x04; /* reg 8, 2:1 scale down from 352 */
- /* fall through */
+ fallthrough;
case 352:
data[3] = 0x2c; /* reg 2, H size/8 */
data[4] = 0x48; /* reg 3, V size/4 */
@@ -607,10 +607,10 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
switch (gspca_dev->pixfmt.width) {
case 160:
data[9] |= 0x0c; /* reg 8, 4:1 scale down */
- /* fall through */
+ fallthrough;
case 320:
data[9] |= 0x04; /* reg 8, 2:1 scale down */
- /* fall through */
+ fallthrough;
case 640:
default:
data[3] = 0x50; /* reg 2, H size/8 */
@@ -627,7 +627,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
case 176:
data[9] |= 0x04; /* reg 8, 2:1 scale down */
- /* fall through */
+ fallthrough;
case 352:
data[3] = 0x2c; /* reg 2, H size */
data[4] = 0x48; /* reg 3, V size */
diff --git a/drivers/media/usb/gspca/nw80x.c b/drivers/media/usb/gspca/nw80x.c
index 880f569bda30..0f5f2464ac7a 100644
--- a/drivers/media/usb/gspca/nw80x.c
+++ b/drivers/media/usb/gspca/nw80x.c
@@ -2019,7 +2019,7 @@ static int sd_init_controls(struct gspca_dev *gspca_dev)
V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
gspca_dev->gain = v4l2_ctrl_new_std(hdl, &sd_ctrl_ops,
V4L2_CID_GAIN, 0, 253, 1, 128);
- /* fall through */
+ fallthrough;
case Cvideopro:
case DvcV6:
case Kritter:
diff --git a/drivers/media/usb/gspca/ov519.c b/drivers/media/usb/gspca/ov519.c
index 0afe70a3f9a2..cd6776c3163b 100644
--- a/drivers/media/usb/gspca/ov519.c
+++ b/drivers/media/usb/gspca/ov519.c
@@ -2004,7 +2004,7 @@ static void reg_w(struct sd *sd, u16 index, u16 value)
break;
case BRIDGE_OVFX2:
req = 0x0a;
- /* fall through */
+ fallthrough;
case BRIDGE_W9968CF:
gspca_dbg(gspca_dev, D_USBO, "SET %02x %04x %04x\n",
req, value, index);
@@ -3528,7 +3528,7 @@ static void ov511_mode_init_regs(struct sd *sd)
case SEN_OV76BE:
if (sd->gspca_dev.pixfmt.width == 320)
interlaced = 1;
- /* Fall through */
+ fallthrough;
case SEN_OV6630:
case SEN_OV7610:
case SEN_OV7670:
@@ -3541,7 +3541,7 @@ static void ov511_mode_init_regs(struct sd *sd)
break;
}
/* For 640x480 case */
- /* fall through */
+ fallthrough;
default:
/* case 20: */
/* case 15: */
diff --git a/drivers/media/usb/gspca/sn9c20x.c b/drivers/media/usb/gspca/sn9c20x.c
index 2a6d0a1265a7..bfd194c61819 100644
--- a/drivers/media/usb/gspca/sn9c20x.c
+++ b/drivers/media/usb/gspca/sn9c20x.c
@@ -1637,7 +1637,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
break;
case SENSOR_HV7131R:
sd->i2c_intf = 0x81; /* i2c 400 Kb/s */
- /* fall through */
+ fallthrough;
default:
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
diff --git a/drivers/media/usb/gspca/sunplus.c b/drivers/media/usb/gspca/sunplus.c
index f4a4222f0d2e..ace3da40006e 100644
--- a/drivers/media/usb/gspca/sunplus.c
+++ b/drivers/media/usb/gspca/sunplus.c
@@ -551,7 +551,7 @@ static void init_ctl_reg(struct gspca_dev *gspca_dev)
case BRIDGE_SPCA504:
case BRIDGE_SPCA504C:
pollreg = 0;
- /* fall through */
+ fallthrough;
default:
/* case BRIDGE_SPCA533: */
/* case BRIDGE_SPCA504B: */
@@ -634,7 +634,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
reg_w_riv(gspca_dev, 0x00, 0x2000, 0x00);
reg_w_riv(gspca_dev, 0x00, 0x2301, 0x13);
reg_w_riv(gspca_dev, 0x00, 0x2306, 0x00);
- /* fall through */
+ fallthrough;
case BRIDGE_SPCA533:
spca504B_PollingDataReady(gspca_dev);
spca50x_GetFirmware(gspca_dev);
diff --git a/drivers/media/usb/gspca/xirlink_cit.c b/drivers/media/usb/gspca/xirlink_cit.c
index c579b100f066..cc87c24dd24c 100644
--- a/drivers/media/usb/gspca/xirlink_cit.c
+++ b/drivers/media/usb/gspca/xirlink_cit.c
@@ -1409,7 +1409,7 @@ static int cit_restart_stream(struct gspca_dev *gspca_dev)
case CIT_MODEL0:
case CIT_MODEL1:
cit_write_reg(gspca_dev, 0x0001, 0x0114);
- /* Fall through */
+ fallthrough;
case CIT_MODEL2:
case CIT_MODEL4:
cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */
@@ -2725,7 +2725,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
break;
case CIT_MODEL2:
v4l2_ctrl_grab(sd->lighting, false);
- /* Fall through! */
+ fallthrough;
case CIT_MODEL4:
cit_model2_Packet1(gspca_dev, 0x0030, 0x0004);
diff --git a/drivers/media/usb/gspca/zc3xx.c b/drivers/media/usb/gspca/zc3xx.c
index 15a2449d536f..aa285d5d6c0d 100644
--- a/drivers/media/usb/gspca/zc3xx.c
+++ b/drivers/media/usb/gspca/zc3xx.c
@@ -6766,7 +6766,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_HV7131R:
case SENSOR_TAS5130C:
reg_r(gspca_dev, 0x0008);
- /* fall through */
+ fallthrough;
case SENSOR_PO2030:
reg_w(gspca_dev, 0x03, 0x0008);
break;
@@ -6815,7 +6815,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_TAS5130C:
reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */
reg_w(gspca_dev, 0x15, 0x01ae);
- /* fall through */
+ fallthrough;
case SENSOR_PAS202B:
case SENSOR_PO2030:
/* reg_w(gspca_dev, 0x40, ZC3XX_R117_GGAIN); in win traces */
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index 1cfb7cf64131..f4a727918e35 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -864,10 +864,9 @@ static int ctrl_std_sym_to_val(struct pvr2_ctrl *cptr,
const char *bufPtr,unsigned int bufSize,
int *mskp,int *valp)
{
- int ret;
v4l2_std_id id;
- ret = pvr2_std_str_to_id(&id,bufPtr,bufSize);
- if (ret < 0) return ret;
+ if (!pvr2_std_str_to_id(&id, bufPtr, bufSize))
+ return -EINVAL;
if (mskp) *mskp = id;
if (valp) *valp = id;
return 0;
diff --git a/drivers/media/usb/pwc/pwc-v4l.c b/drivers/media/usb/pwc/pwc-v4l.c
index 2f135d533af6..71b719d363a5 100644
--- a/drivers/media/usb/pwc/pwc-v4l.c
+++ b/drivers/media/usb/pwc/pwc-v4l.c
@@ -554,7 +554,7 @@ static int pwc_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
if (!DEVICE_USE_CODEC3(pdev->type))
break;
/* For CODEC3 where autogain also controls expo */
- /* fall through */
+ fallthrough;
case V4L2_CID_EXPOSURE_AUTO:
if (pdev->exposure_valid && time_before(jiffies,
pdev->last_exposure_update + HZ / 4)) {
diff --git a/drivers/media/usb/siano/smsusb.c b/drivers/media/usb/siano/smsusb.c
index 9ba3a2ae36e5..df4c5dcba39c 100644
--- a/drivers/media/usb/siano/smsusb.c
+++ b/drivers/media/usb/siano/smsusb.c
@@ -430,7 +430,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
break;
case SMS_UNKNOWN_TYPE:
pr_err("Unspecified sms device type!\n");
- /* fall-thru */
+ fallthrough;
default:
dev->buffer_size = USB2_BUFFER_SIZE;
dev->response_alignment = align;
diff --git a/drivers/media/usb/tm6000/tm6000-alsa.c b/drivers/media/usb/tm6000/tm6000-alsa.c
index c26a0ff60a64..3a2df36ef1db 100644
--- a/drivers/media/usb/tm6000/tm6000-alsa.c
+++ b/drivers/media/usb/tm6000/tm6000-alsa.c
@@ -272,13 +272,13 @@ static int snd_tm6000_card_trigger(struct snd_pcm_substream *substream, int cmd)
int err = 0;
switch (cmd) {
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
- case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ case SNDRV_PCM_TRIGGER_RESUME:
case SNDRV_PCM_TRIGGER_START:
atomic_set(&core->stream_started, 1);
break;
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH: /* fall through */
- case SNDRV_PCM_TRIGGER_SUSPEND: /* fall through */
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
case SNDRV_PCM_TRIGGER_STOP:
atomic_set(&core->stream_started, 0);
break;
diff --git a/drivers/media/usb/tm6000/tm6000-core.c b/drivers/media/usb/tm6000/tm6000-core.c
index 2c723706f8c8..5c8cbc5d6f72 100644
--- a/drivers/media/usb/tm6000/tm6000-core.c
+++ b/drivers/media/usb/tm6000/tm6000-core.c
@@ -853,11 +853,9 @@ int tm6000_call_fillbuf(struct tm6000_core *dev, enum tm6000_ops_type type,
/* FIXME: tm6000_extension_devlist_lock should be a spinlock */
- if (!list_empty(&tm6000_extension_devlist)) {
- list_for_each_entry(ops, &tm6000_extension_devlist, next) {
- if (ops->fillbuf && ops->type == type)
- ops->fillbuf(dev, buf, size);
- }
+ list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+ if (ops->fillbuf && ops->type == type)
+ ops->fillbuf(dev, buf, size);
}
return 0;
@@ -898,11 +896,9 @@ void tm6000_init_extension(struct tm6000_core *dev)
struct tm6000_ops *ops = NULL;
mutex_lock(&tm6000_devlist_mutex);
- if (!list_empty(&tm6000_extension_devlist)) {
- list_for_each_entry(ops, &tm6000_extension_devlist, next) {
- if (ops->init)
- ops->init(dev);
- }
+ list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+ if (ops->init)
+ ops->init(dev);
}
mutex_unlock(&tm6000_devlist_mutex);
}
@@ -912,11 +908,9 @@ void tm6000_close_extension(struct tm6000_core *dev)
struct tm6000_ops *ops = NULL;
mutex_lock(&tm6000_devlist_mutex);
- if (!list_empty(&tm6000_extension_devlist)) {
- list_for_each_entry(ops, &tm6000_extension_devlist, next) {
- if (ops->fini)
- ops->fini(dev);
- }
+ list_for_each_entry(ops, &tm6000_extension_devlist, next) {
+ if (ops->fini)
+ ops->fini(dev);
}
mutex_unlock(&tm6000_devlist_mutex);
}
diff --git a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
index 4e56ff83566b..9e016b71aa91 100644
--- a/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/usb/ttusb-budget/dvb-ttusb-budget.c
@@ -5,6 +5,9 @@
* Copyright (c) 2002 Holger Waechtler <holger@convergence.de>
* Copyright (c) 2003 Felix Domke <tmbinc@elitedvb.net>
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/wait.h>
@@ -59,7 +62,12 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-#define dprintk(x...) do { if (debug) printk(KERN_DEBUG x); } while (0)
+#define dprintk(fmt, arg...) do { \
+ if (debug) \
+ printk(KERN_DEBUG pr_fmt("%s: " fmt), \
+ __func__, ##arg); \
+} while (0)
+
#define ISO_BUF_COUNT 4
#define FRAMES_PER_ISO_BUF 4
@@ -72,6 +80,9 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define TTUSB_REV_2_2 0x22
#define TTUSB_BUDGET_NAME "ttusb_stc_fw"
+#define MAX_SEND 0x28
+#define MAX_RCV 0x20
+
/*
* since we're casting (struct ttusb*) <-> (struct dvb_demux*) around
* the dvb_demux field must be the first in struct!!
@@ -119,87 +130,70 @@ struct ttusb {
int cc; /* MuxCounter - will increment on EVERY MUX PACKET */
/* (including stuffing. yes. really.) */
- u8 last_result[32];
+ u8 send_buf[MAX_SEND];
+ u8 last_result[MAX_RCV];
int revision;
struct dvb_frontend* fe;
};
-/* ugly workaround ... don't know why it's necessary to read */
-/* all result codes. */
-
-static int ttusb_cmd(struct ttusb *ttusb,
- const u8 * data, int len, int needresult)
+static int ttusb_cmd(struct ttusb *ttusb, u8 *data, int len, int len_result)
{
int actual_len;
int err;
- int i;
-
- if (debug >= 3) {
- printk(KERN_DEBUG ">");
- for (i = 0; i < len; ++i)
- printk(KERN_CONT " %02x", data[i]);
- printk(KERN_CONT "\n");
- }
if (mutex_lock_interruptible(&ttusb->semusb) < 0)
return -EAGAIN;
+ if (debug >= 3)
+ dprintk("> %*ph\n", len, data);
+
+ memcpy(data, ttusb->send_buf, len);
+
err = usb_bulk_msg(ttusb->dev, ttusb->bulk_out_pipe,
- (u8 *) data, len, &actual_len, 1000);
+ ttusb->send_buf, len, &actual_len, 1000);
if (err != 0) {
- dprintk("%s: usb_bulk_msg(send) failed, err == %i!\n",
- __func__, err);
- mutex_unlock(&ttusb->semusb);
- return err;
+ dprintk("usb_bulk_msg(send) failed, err == %i!\n", err);
+ goto err;
}
if (actual_len != len) {
- dprintk("%s: only wrote %d of %d bytes\n", __func__,
+ err = -EIO;
+ dprintk("only wrote %d of %d bytes\n",
actual_len, len);
- mutex_unlock(&ttusb->semusb);
- return -1;
+ goto err;
}
err = usb_bulk_msg(ttusb->dev, ttusb->bulk_in_pipe,
- ttusb->last_result, 32, &actual_len, 1000);
+ ttusb->last_result, MAX_RCV, &actual_len, 1000);
if (err != 0) {
- printk("%s: failed, receive error %d\n", __func__,
- err);
- mutex_unlock(&ttusb->semusb);
- return err;
+ pr_err("cmd xter failed, receive error %d\n", err);
+ goto err;
}
if (debug >= 3) {
actual_len = ttusb->last_result[3] + 4;
- printk(KERN_DEBUG "<");
- for (i = 0; i < actual_len; ++i)
- printk(KERN_CONT " %02x", ttusb->last_result[i]);
- printk(KERN_CONT "\n");
+ dprintk("< %*ph\n", actual_len, ttusb->last_result);
}
- if (!needresult)
- mutex_unlock(&ttusb->semusb);
- return 0;
-}
+ if (len_result)
+ memcpy(ttusb->send_buf, ttusb->last_result, len_result);
-static int ttusb_result(struct ttusb *ttusb, u8 * data, int len)
-{
- memcpy(data, ttusb->last_result, len);
+err:
mutex_unlock(&ttusb->semusb);
- return 0;
+ return err;
}
static int ttusb_i2c_msg(struct ttusb *ttusb,
u8 addr, u8 * snd_buf, u8 snd_len, u8 * rcv_buf,
u8 rcv_len)
{
- u8 b[0x28];
+ u8 b[MAX_SEND];
u8 id = ++ttusb->c;
int i, err;
- if (snd_len > 0x28 - 7 || rcv_len > 0x20 - 7)
+ if (snd_len > MAX_SEND - 7 || rcv_len > MAX_RCV - 7)
return -EINVAL;
b[0] = 0xaa;
@@ -213,22 +207,19 @@ static int ttusb_i2c_msg(struct ttusb *ttusb,
for (i = 0; i < snd_len; i++)
b[7 + i] = snd_buf[i];
- err = ttusb_cmd(ttusb, b, snd_len + 7, 1);
+ err = ttusb_cmd(ttusb, b, snd_len + 7, MAX_RCV);
if (err)
return -EREMOTEIO;
- err = ttusb_result(ttusb, b, 0x20);
-
/* check if the i2c transaction was successful */
if ((snd_len != b[5]) || (rcv_len != b[6])) return -EREMOTEIO;
if (rcv_len > 0) {
if (err || b[0] != 0x55 || b[1] != id) {
- dprintk
- ("%s: usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ",
- __func__, err, id);
+ dprintk("usb_bulk_msg(recv) failed, err == %i, id == %02x, b == ",
+ err, id);
return -EREMOTEIO;
}
@@ -272,7 +263,7 @@ static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, int num
snd_buf, snd_len, rcv_buf, rcv_len);
if (err < rcv_len) {
- dprintk("%s: i == %i\n", __func__, i);
+ dprintk("i == %i\n", i);
break;
}
@@ -292,7 +283,7 @@ static int ttusb_boot_dsp(struct ttusb *ttusb)
err = request_firmware(&fw, "ttusb-budget/dspbootcode.bin",
&ttusb->dev->dev);
if (err) {
- printk(KERN_ERR "ttusb-budget: failed to request firmware\n");
+ pr_err("failed to request firmware\n");
return err;
}
@@ -332,8 +323,7 @@ static int ttusb_boot_dsp(struct ttusb *ttusb)
done:
release_firmware(fw);
if (err) {
- dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
- __func__, err);
+ dprintk("usb_bulk_msg() failed, return value %i!\n", err);
}
return err;
@@ -400,8 +390,6 @@ static int ttusb_init_controller(struct ttusb *ttusb)
/* i2c write read: 5 bytes, addr 0x10, 0x02 bytes write, 1 bytes read. */
u8 b3[] =
{ 0xaa, ++ttusb->c, 0x31, 5, 0x10, 0x02, 0x01, 0x00, 0x1e };
- u8 b4[] =
- { 0x55, ttusb->c, 0x31, 4, 0x10, 0x02, 0x01, 0x00, 0x1e };
u8 get_version[] = { 0xaa, ++ttusb->c, 0x17, 5, 0, 0, 0, 0, 0 };
u8 get_dsp_version[0x20] =
@@ -422,44 +410,35 @@ static int ttusb_init_controller(struct ttusb *ttusb)
if ((err = ttusb_cmd(ttusb, b2, sizeof(b2), 0)))
return err;
- if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 1)))
- return err;
-
- err = ttusb_result(ttusb, b4, sizeof(b4));
-
- if ((err = ttusb_cmd(ttusb, get_version, sizeof(get_version), 1)))
+ if ((err = ttusb_cmd(ttusb, b3, sizeof(b3), 0)))
return err;
- if ((err = ttusb_result(ttusb, get_version, sizeof(get_version))))
+ if ((err = ttusb_cmd(ttusb, get_version,
+ sizeof(get_version), sizeof(get_version))))
return err;
- dprintk("%s: stc-version: %c%c%c%c%c\n", __func__,
- get_version[4], get_version[5], get_version[6],
- get_version[7], get_version[8]);
+ dprintk("stc-version: %c%c%c%c%c\n", get_version[4], get_version[5],
+ get_version[6], get_version[7], get_version[8]);
if (memcmp(get_version + 4, "V 0.0", 5) &&
memcmp(get_version + 4, "V 1.1", 5) &&
memcmp(get_version + 4, "V 2.1", 5) &&
memcmp(get_version + 4, "V 2.2", 5)) {
- printk
- ("%s: unknown STC version %c%c%c%c%c, please report!\n",
- __func__, get_version[4], get_version[5],
- get_version[6], get_version[7], get_version[8]);
+ pr_err("unknown STC version %c%c%c%c%c, please report!\n",
+ get_version[4], get_version[5],
+ get_version[6], get_version[7], get_version[8]);
}
ttusb->revision = ((get_version[6] - '0') << 4) |
(get_version[8] - '0');
err =
- ttusb_cmd(ttusb, get_dsp_version, sizeof(get_dsp_version), 1);
+ ttusb_cmd(ttusb, get_dsp_version,
+ sizeof(get_dsp_version), sizeof(get_dsp_version));
if (err)
return err;
- err =
- ttusb_result(ttusb, get_dsp_version, sizeof(get_dsp_version));
- if (err)
- return err;
- printk("%s: dsp-version: %c%c%c\n", __func__,
+ pr_info("dsp-version: %c%c%c\n",
get_dsp_version[4], get_dsp_version[5], get_dsp_version[6]);
return 0;
}
@@ -481,8 +460,7 @@ static int ttusb_send_diseqc(struct dvb_frontend* fe,
/* Diseqc */
if ((err = ttusb_cmd(ttusb, b, 4 + b[3], 0))) {
- dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
- __func__, err);
+ dprintk("usb_bulk_msg() failed, return value %i!\n", err);
}
return err;
@@ -499,8 +477,7 @@ static int ttusb_update_lnb(struct ttusb *ttusb)
/* SetLNB */
if ((err = ttusb_cmd(ttusb, b, sizeof(b), 0))) {
- dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
- __func__, err);
+ dprintk("usb_bulk_msg() failed, return value %i!\n", err);
}
return err;
@@ -534,8 +511,7 @@ static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq)
err = ttusb_cmd(ttusb, b, sizeof(b), 0);
if (err) {
- dprintk("%s: usb_bulk_msg() failed, return value %i!\n",
- __func__, err);
+ dprintk("usb_bulk_msg() failed, return value %i!\n", err);
}
}
#endif
@@ -559,7 +535,7 @@ static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
int i;
if (len < 4 || len & 0x1) {
- pr_warn("%s: muxpack has invalid len %d\n", __func__, len);
+ pr_warn("muxpack has invalid len %d\n", len);
numinvalid++;
return;
}
@@ -567,8 +543,7 @@ static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
for (i = 0; i < len; i += 2)
csum ^= le16_to_cpup((__le16 *) (muxpack + i));
if (csum) {
- printk("%s: muxpack with incorrect checksum, ignoring\n",
- __func__);
+ pr_warn("muxpack with incorrect checksum, ignoring\n");
numinvalid++;
return;
}
@@ -576,8 +551,8 @@ static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
cc = (muxpack[len - 4] << 8) | muxpack[len - 3];
cc &= 0x7FFF;
if ((cc != ttusb->cc) && (ttusb->cc != -1))
- printk("%s: cc discontinuity (%d frames missing)\n",
- __func__, (cc - ttusb->cc) & 0x7FFF);
+ pr_warn("cc discontinuity (%d frames missing)\n",
+ (cc - ttusb->cc) & 0x7FFF);
ttusb->cc = (cc + 1) & 0x7FFF;
if (muxpack[0] & 0x80) {
#ifdef TTUSB_HWSECTIONS
@@ -598,7 +573,7 @@ static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
!!(ttusb->muxpack[1] & 1))
data++;
#warning TODO: pusi
- printk("cc: %04x\n", (data[0] << 8) | data[1]);
+ dprintk("cc: %04x\n", (data[0] << 8) | data[1]);
#endif
numsec++;
} else if (muxpack[0] == 0x47) {
@@ -617,7 +592,7 @@ static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
dvb_dmx_swfilter_packets(&ttusb->dvb_demux, muxpack, 1);
} else if (muxpack[0] != 0) {
numinvalid++;
- printk("illegal muxpack type %02x\n", muxpack[0]);
+ pr_err("illegal muxpack type %02x\n", muxpack[0]);
} else
numstuff++;
}
@@ -627,7 +602,7 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
int maxwork = 1024;
while (len) {
if (!(maxwork--)) {
- printk("%s: too much work\n", __func__);
+ pr_err("too much work\n");
break;
}
@@ -641,10 +616,7 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
else {
ttusb->mux_state = 0;
if (ttusb->insync) {
- dprintk("%s: %02x\n",
- __func__, data[-1]);
- printk(KERN_INFO "%s: lost sync.\n",
- __func__);
+ pr_info("lost sync.\n");
ttusb->insync = 0;
}
}
@@ -700,10 +672,8 @@ static void ttusb_process_frame(struct ttusb *ttusb, u8 * data, int len)
ttusb->muxpack[1] + 2 +
4;
else {
- dprintk
- ("%s: invalid state: first byte is %x\n",
- __func__,
- ttusb->muxpack[0]);
+ dprintk("invalid state: first byte is %x\n",
+ ttusb->muxpack[0]);
ttusb->mux_state = 0;
}
}
@@ -752,12 +722,6 @@ static void ttusb_iso_irq(struct urb *urb)
if (!ttusb->iso_streaming)
return;
-#if 0
- printk("%s: status %d, errcount == %d, length == %i\n",
- __func__,
- urb->status, urb->error_count, urb->actual_length);
-#endif
-
if (!urb->status) {
for (i = 0; i < urb->number_of_packets; ++i) {
numpkt++;
@@ -830,7 +794,7 @@ static int ttusb_start_iso_xfer(struct ttusb *ttusb)
int i, j, err, buffer_offset = 0;
if (ttusb->iso_streaming) {
- printk("%s: iso xfer already running!\n", __func__);
+ pr_err("iso xfer already running!\n");
return 0;
}
@@ -864,9 +828,8 @@ static int ttusb_start_iso_xfer(struct ttusb *ttusb)
for (i = 0; i < ISO_BUF_COUNT; i++) {
if ((err = usb_submit_urb(ttusb->iso_urb[i], GFP_ATOMIC))) {
ttusb_stop_iso_xfer(ttusb);
- printk
- ("%s: failed urb submission (%i: err = %i)!\n",
- __func__, i, err);
+ pr_err("failed urb submission (%i: err = %i)!\n",
+ i, err);
return err;
}
}
@@ -1426,7 +1389,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
- printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n");
+ pr_err("dvbc_philips_tdm1316l_pll_set Error 1\n");
return -EIO;
}
@@ -1435,7 +1398,7 @@ static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe)
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
- printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n");
+ pr_err("dvbc_philips_tdm1316l_pll_set Error 2\n");
return -EIO;
}
@@ -1612,12 +1575,12 @@ static void frontend_init(struct ttusb* ttusb)
}
if (ttusb->fe == NULL) {
- printk("dvb-ttusb-budget: A frontend driver was not found for device [%04x:%04x]\n",
+ pr_err("no frontend driver found for device [%04x:%04x]\n",
le16_to_cpu(ttusb->dev->descriptor.idVendor),
le16_to_cpu(ttusb->dev->descriptor.idProduct));
} else {
if (dvb_register_frontend(&ttusb->adapter, ttusb->fe)) {
- printk("dvb-ttusb-budget: Frontend registration failed!\n");
+ pr_err("Frontend registration failed!\n");
dvb_frontend_detach(ttusb->fe);
ttusb->fe = NULL;
}
@@ -1637,7 +1600,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
struct ttusb *ttusb;
int result;
- dprintk("%s: TTUSB DVB connected\n", __func__);
+ dprintk("TTUSB DVB connected\n");
udev = interface_to_usbdev(intf);
@@ -1659,14 +1622,14 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
result = ttusb_alloc_iso_urbs(ttusb);
if (result < 0) {
- dprintk("%s: ttusb_alloc_iso_urbs - failed\n", __func__);
+ dprintk("ttusb_alloc_iso_urbs - failed\n");
mutex_unlock(&ttusb->semi2c);
kfree(ttusb);
return result;
}
if (ttusb_init_controller(ttusb))
- printk("ttusb_init_controller: error\n");
+ pr_err("ttusb_init_controller: error\n");
mutex_unlock(&ttusb->semi2c);
@@ -1711,7 +1674,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
result = dvb_dmx_init(&ttusb->dvb_demux);
if (result < 0) {
- printk("ttusb_dvb: dvb_dmx_init failed (errno = %d)\n", result);
+ pr_err("dvb_dmx_init failed (errno = %d)\n", result);
result = -ENODEV;
goto err_i2c_del_adapter;
}
@@ -1722,14 +1685,14 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
result = dvb_dmxdev_init(&ttusb->dmxdev, &ttusb->adapter);
if (result < 0) {
- printk("ttusb_dvb: dvb_dmxdev_init failed (errno = %d)\n",
+ pr_err("dvb_dmxdev_init failed (errno = %d)\n",
result);
result = -ENODEV;
goto err_release_dmx;
}
if (dvb_net_init(&ttusb->adapter, &ttusb->dvbnet, &ttusb->dvb_demux.dmx)) {
- printk("ttusb_dvb: dvb_net_init failed!\n");
+ pr_err("dvb_net_init failed!\n");
result = -ENODEV;
goto err_release_dmxdev;
}
@@ -1778,7 +1741,7 @@ static void ttusb_disconnect(struct usb_interface *intf)
kfree(ttusb);
- dprintk("%s: TTUSB DVB disconnected\n", __func__);
+ dprintk("TTUSB DVB disconnected\n");
}
static const struct usb_device_id ttusb_table[] = {
diff --git a/drivers/media/usb/ttusb-dec/ttusb_dec.c b/drivers/media/usb/ttusb-dec/ttusb_dec.c
index b8d39b2f777f..df6c5e4a0f05 100644
--- a/drivers/media/usb/ttusb-dec/ttusb_dec.c
+++ b/drivers/media/usb/ttusb-dec/ttusb_dec.c
@@ -769,9 +769,9 @@ static void ttusb_dec_process_urb_frame(struct ttusb_dec *dec, u8 *b,
}
}
-static void ttusb_dec_process_urb_frame_list(unsigned long data)
+static void ttusb_dec_process_urb_frame_list(struct tasklet_struct *t)
{
- struct ttusb_dec *dec = (struct ttusb_dec *)data;
+ struct ttusb_dec *dec = from_tasklet(dec, t, urb_tasklet);
struct list_head *item;
struct urb_frame *frame;
unsigned long flags;
@@ -1209,8 +1209,7 @@ static void ttusb_dec_init_tasklet(struct ttusb_dec *dec)
{
spin_lock_init(&dec->urb_frame_list_lock);
INIT_LIST_HEAD(&dec->urb_frame_list);
- tasklet_init(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list,
- (unsigned long)dec);
+ tasklet_setup(&dec->urb_tasklet, ttusb_dec_process_urb_frame_list);
}
static int ttusb_init_rc( struct ttusb_dec *dec)
diff --git a/drivers/media/usb/usbtv/usbtv-core.c b/drivers/media/usb/usbtv/usbtv-core.c
index ee9c656d121f..2308c0b4f5e7 100644
--- a/drivers/media/usb/usbtv/usbtv-core.c
+++ b/drivers/media/usb/usbtv/usbtv-core.c
@@ -113,7 +113,8 @@ static int usbtv_probe(struct usb_interface *intf,
usbtv_audio_fail:
/* we must not free at this point */
- usb_get_dev(usbtv->udev);
+ v4l2_device_get(&usbtv->v4l2_dev);
+ /* this will undo the v4l2_device_get() */
usbtv_video_free(usbtv);
usbtv_video_fail:
diff --git a/drivers/media/usb/usbtv/usbtv-video.c b/drivers/media/usb/usbtv/usbtv-video.c
index c89efcd46163..3b4a2e769230 100644
--- a/drivers/media/usb/usbtv/usbtv-video.c
+++ b/drivers/media/usb/usbtv/usbtv-video.c
@@ -872,7 +872,6 @@ static void usbtv_release(struct v4l2_device *v4l2_dev)
v4l2_device_unregister(&usbtv->v4l2_dev);
v4l2_ctrl_handler_free(&usbtv->ctrl);
- vb2_queue_release(&usbtv->vb2q);
kfree(usbtv);
}
@@ -954,7 +953,6 @@ vdev_fail:
v4l2_fail:
ctrl_fail:
v4l2_ctrl_handler_free(&usbtv->ctrl);
- vb2_queue_release(&usbtv->vb2q);
return ret;
}
@@ -965,7 +963,7 @@ void usbtv_video_free(struct usbtv *usbtv)
mutex_lock(&usbtv->v4l2_lock);
usbtv_stop(usbtv);
- video_unregister_device(&usbtv->vdev);
+ vb2_video_unregister_device(&usbtv->vdev);
v4l2_device_disconnect(&usbtv->v4l2_dev);
mutex_unlock(&usbtv->v4l2_lock);
diff --git a/drivers/media/usb/uvc/uvc_ctrl.c b/drivers/media/usb/uvc/uvc_ctrl.c
index e399b9fad757..f479d8971dfb 100644
--- a/drivers/media/usb/uvc/uvc_ctrl.c
+++ b/drivers/media/usb/uvc/uvc_ctrl.c
@@ -773,12 +773,16 @@ static s32 uvc_get_le_value(struct uvc_control_mapping *mapping,
offset &= 7;
mask = ((1LL << bits) - 1) << offset;
- for (; bits > 0; data++) {
+ while (1) {
u8 byte = *data & mask;
value |= offset > 0 ? (byte >> offset) : (byte << (-offset));
bits -= 8 - (offset > 0 ? offset : 0);
+ if (bits <= 0)
+ break;
+
offset -= 8;
mask = (1 << bits) - 1;
+ data++;
}
/* Sign-extend the value if needed. */
@@ -1844,30 +1848,35 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
{
struct uvc_entity *entity;
struct uvc_control *ctrl;
- unsigned int i, found = 0;
+ unsigned int i;
+ bool found;
u32 reqflags;
u16 size;
u8 *data = NULL;
int ret;
/* Find the extension unit. */
+ found = false;
list_for_each_entry(entity, &chain->entities, chain) {
if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT &&
- entity->id == xqry->unit)
+ entity->id == xqry->unit) {
+ found = true;
break;
+ }
}
- if (entity->id != xqry->unit) {
+ if (!found) {
uvc_trace(UVC_TRACE_CONTROL, "Extension unit %u not found.\n",
xqry->unit);
return -ENOENT;
}
/* Find the control and perform delayed initialization if needed. */
+ found = false;
for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i];
if (ctrl->index == xqry->selector - 1) {
- found = 1;
+ found = true;
break;
}
}
@@ -2011,25 +2020,14 @@ int uvc_ctrl_restore_values(struct uvc_device *dev)
static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
const struct uvc_control_info *info)
{
- int ret = 0;
-
ctrl->info = *info;
INIT_LIST_HEAD(&ctrl->info.mappings);
/* Allocate an array to save control values (cur, def, max, etc.) */
ctrl->uvc_data = kzalloc(ctrl->info.size * UVC_CTRL_DATA_LAST + 1,
GFP_KERNEL);
- if (ctrl->uvc_data == NULL) {
- ret = -ENOMEM;
- goto done;
- }
-
- /*
- * Retrieve control flags from the device. Ignore errors and work with
- * default flag values from the uvc_ctrl array when the device doesn't
- * properly implement GET_INFO on standard controls.
- */
- uvc_ctrl_get_flags(dev, ctrl, &ctrl->info);
+ if (!ctrl->uvc_data)
+ return -ENOMEM;
ctrl->initialized = 1;
@@ -2037,10 +2035,7 @@ static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
"entity %u\n", ctrl->info.entity, ctrl->info.selector,
dev->udev->devpath, ctrl->entity->id);
-done:
- if (ret < 0)
- kfree(ctrl->uvc_data);
- return ret;
+ return 0;
}
/*
@@ -2253,6 +2248,13 @@ static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl)
if (uvc_entity_match_guid(ctrl->entity, info->entity) &&
ctrl->index == info->index) {
uvc_ctrl_add_info(dev, ctrl, info);
+ /*
+ * Retrieve control flags from the device. Ignore errors
+ * and work with default flag values from the uvc_ctrl
+ * array when the device doesn't properly implement
+ * GET_INFO on standard controls.
+ */
+ uvc_ctrl_get_flags(dev, ctrl, &ctrl->info);
break;
}
}
diff --git a/drivers/media/usb/uvc/uvc_debugfs.c b/drivers/media/usb/uvc/uvc_debugfs.c
index 2b8af4b54117..1a1258d4ffca 100644
--- a/drivers/media/usb/uvc/uvc_debugfs.c
+++ b/drivers/media/usb/uvc/uvc_debugfs.c
@@ -73,7 +73,6 @@ static struct dentry *uvc_debugfs_root_dir;
void uvc_debugfs_init_stream(struct uvc_streaming *stream)
{
struct usb_device *udev = stream->dev->udev;
- struct dentry *dent;
char dir_name[33];
if (uvc_debugfs_root_dir == NULL)
@@ -82,22 +81,11 @@ void uvc_debugfs_init_stream(struct uvc_streaming *stream)
snprintf(dir_name, sizeof(dir_name), "%u-%u-%u", udev->bus->busnum,
udev->devnum, stream->intfnum);
- dent = debugfs_create_dir(dir_name, uvc_debugfs_root_dir);
- if (IS_ERR_OR_NULL(dent)) {
- uvc_printk(KERN_INFO, "Unable to create debugfs %s "
- "directory.\n", dir_name);
- return;
- }
-
- stream->debugfs_dir = dent;
+ stream->debugfs_dir = debugfs_create_dir(dir_name,
+ uvc_debugfs_root_dir);
- dent = debugfs_create_file("stats", 0444, stream->debugfs_dir,
- stream, &uvc_debugfs_stats_fops);
- if (IS_ERR_OR_NULL(dent)) {
- uvc_printk(KERN_INFO, "Unable to create debugfs stats file.\n");
- uvc_debugfs_cleanup_stream(stream);
- return;
- }
+ debugfs_create_file("stats", 0444, stream->debugfs_dir, stream,
+ &uvc_debugfs_stats_fops);
}
void uvc_debugfs_cleanup_stream(struct uvc_streaming *stream)
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 431d86e1c94b..ddb9eaa11be7 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -214,6 +214,11 @@ static struct uvc_format_desc uvc_fmts[] = {
.guid = UVC_GUID_FORMAT_CNF4,
.fcc = V4L2_PIX_FMT_CNF4,
},
+ {
+ .name = "HEVC",
+ .guid = UVC_GUID_FORMAT_HEVC,
+ .fcc = V4L2_PIX_FMT_HEVC,
+ },
};
/* ------------------------------------------------------------------------
@@ -248,10 +253,10 @@ static struct uvc_format_desc *uvc_format_by_guid(const u8 guid[16])
return NULL;
}
-static u32 uvc_colorspace(const u8 primaries)
+static enum v4l2_colorspace uvc_colorspace(const u8 primaries)
{
- static const u8 colorprimaries[] = {
- 0,
+ static const enum v4l2_colorspace colorprimaries[] = {
+ V4L2_COLORSPACE_DEFAULT, /* Unspecified */
V4L2_COLORSPACE_SRGB,
V4L2_COLORSPACE_470_SYSTEM_M,
V4L2_COLORSPACE_470_SYSTEM_BG,
@@ -262,7 +267,61 @@ static u32 uvc_colorspace(const u8 primaries)
if (primaries < ARRAY_SIZE(colorprimaries))
return colorprimaries[primaries];
- return 0;
+ return V4L2_COLORSPACE_DEFAULT; /* Reserved */
+}
+
+static enum v4l2_xfer_func uvc_xfer_func(const u8 transfer_characteristics)
+{
+ /*
+ * V4L2 does not currently have definitions for all possible values of
+ * UVC transfer characteristics. If v4l2_xfer_func is extended with new
+ * values, the mapping below should be updated.
+ *
+ * Substitutions are taken from the mapping given for
+ * V4L2_XFER_FUNC_DEFAULT documented in videodev2.h.
+ */
+ static const enum v4l2_xfer_func xfer_funcs[] = {
+ V4L2_XFER_FUNC_DEFAULT, /* Unspecified */
+ V4L2_XFER_FUNC_709,
+ V4L2_XFER_FUNC_709, /* Substitution for BT.470-2 M */
+ V4L2_XFER_FUNC_709, /* Substitution for BT.470-2 B, G */
+ V4L2_XFER_FUNC_709, /* Substitution for SMPTE 170M */
+ V4L2_XFER_FUNC_SMPTE240M,
+ V4L2_XFER_FUNC_NONE,
+ V4L2_XFER_FUNC_SRGB,
+ };
+
+ if (transfer_characteristics < ARRAY_SIZE(xfer_funcs))
+ return xfer_funcs[transfer_characteristics];
+
+ return V4L2_XFER_FUNC_DEFAULT; /* Reserved */
+}
+
+static enum v4l2_ycbcr_encoding uvc_ycbcr_enc(const u8 matrix_coefficients)
+{
+ /*
+ * V4L2 does not currently have definitions for all possible values of
+ * UVC matrix coefficients. If v4l2_ycbcr_encoding is extended with new
+ * values, the mapping below should be updated.
+ *
+ * Substitutions are taken from the mapping given for
+ * V4L2_YCBCR_ENC_DEFAULT documented in videodev2.h.
+ *
+ * FCC is assumed to be close enough to 601.
+ */
+ static const enum v4l2_ycbcr_encoding ycbcr_encs[] = {
+ V4L2_YCBCR_ENC_DEFAULT, /* Unspecified */
+ V4L2_YCBCR_ENC_709,
+ V4L2_YCBCR_ENC_601, /* Substitution for FCC */
+ V4L2_YCBCR_ENC_601, /* Substitution for BT.470-2 B, G */
+ V4L2_YCBCR_ENC_601,
+ V4L2_YCBCR_ENC_SMPTE240M,
+ };
+
+ if (matrix_coefficients < ARRAY_SIZE(ycbcr_encs))
+ return ycbcr_encs[matrix_coefficients];
+
+ return V4L2_YCBCR_ENC_DEFAULT; /* Reserved */
}
/* Simplify a fraction using a simple continued fraction decomposition. The
@@ -284,7 +343,7 @@ void uvc_simplify_fraction(u32 *numerator, u32 *denominator,
return;
/* Convert the fraction to a simple continued fraction. See
- * http://mathforum.org/dr.math/faq/faq.fractions.html
+ * https://mathforum.org/dr.math/faq/faq.fractions.html
* Stop if the current term is bigger than or equal to the given
* threshold.
*/
@@ -704,6 +763,8 @@ static int uvc_parse_format(struct uvc_device *dev,
}
format->colorspace = uvc_colorspace(buffer[3]);
+ format->xfer_func = uvc_xfer_func(buffer[4]);
+ format->ycbcr_enc = uvc_ycbcr_enc(buffer[5]);
buflen -= buffer[0];
buffer += buffer[0];
diff --git a/drivers/media/usb/uvc/uvc_entity.c b/drivers/media/usb/uvc/uvc_entity.c
index b4499cddeffe..ca3a9c2eec27 100644
--- a/drivers/media/usb/uvc/uvc_entity.c
+++ b/drivers/media/usb/uvc/uvc_entity.c
@@ -73,10 +73,45 @@ static int uvc_mc_init_entity(struct uvc_video_chain *chain,
int ret;
if (UVC_ENTITY_TYPE(entity) != UVC_TT_STREAMING) {
+ u32 function;
+
v4l2_subdev_init(&entity->subdev, &uvc_subdev_ops);
strscpy(entity->subdev.name, entity->name,
sizeof(entity->subdev.name));
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case UVC_VC_SELECTOR_UNIT:
+ function = MEDIA_ENT_F_VID_MUX;
+ break;
+ case UVC_VC_PROCESSING_UNIT:
+ case UVC_VC_EXTENSION_UNIT:
+ /* For lack of a better option. */
+ function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER;
+ break;
+ case UVC_COMPOSITE_CONNECTOR:
+ case UVC_COMPONENT_CONNECTOR:
+ function = MEDIA_ENT_F_CONN_COMPOSITE;
+ break;
+ case UVC_SVIDEO_CONNECTOR:
+ function = MEDIA_ENT_F_CONN_SVIDEO;
+ break;
+ case UVC_ITT_CAMERA:
+ function = MEDIA_ENT_F_CAM_SENSOR;
+ break;
+ case UVC_TT_VENDOR_SPECIFIC:
+ case UVC_ITT_VENDOR_SPECIFIC:
+ case UVC_ITT_MEDIA_TRANSPORT_INPUT:
+ case UVC_OTT_VENDOR_SPECIFIC:
+ case UVC_OTT_DISPLAY:
+ case UVC_OTT_MEDIA_TRANSPORT_OUTPUT:
+ case UVC_EXTERNAL_VENDOR_SPECIFIC:
+ default:
+ function = MEDIA_ENT_F_V4L2_SUBDEV_UNKNOWN;
+ break;
+ }
+
+ entity->subdev.entity.function = function;
+
ret = media_entity_pads_init(&entity->subdev.entity,
entity->num_pads, entity->pads);
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 0335e69b70ab..fa06bfa174ad 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -247,12 +247,44 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
if (ret < 0)
goto done;
+ /* After the probe, update fmt with the values returned from
+ * negotiation with the device.
+ */
+ for (i = 0; i < stream->nformats; ++i) {
+ if (probe->bFormatIndex == stream->format[i].index) {
+ format = &stream->format[i];
+ break;
+ }
+ }
+
+ if (i == stream->nformats) {
+ uvc_trace(UVC_TRACE_FORMAT, "Unknown bFormatIndex %u\n",
+ probe->bFormatIndex);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < format->nframes; ++i) {
+ if (probe->bFrameIndex == format->frame[i].bFrameIndex) {
+ frame = &format->frame[i];
+ break;
+ }
+ }
+
+ if (i == format->nframes) {
+ uvc_trace(UVC_TRACE_FORMAT, "Unknown bFrameIndex %u\n",
+ probe->bFrameIndex);
+ return -EINVAL;
+ }
+
fmt->fmt.pix.width = frame->wWidth;
fmt->fmt.pix.height = frame->wHeight;
fmt->fmt.pix.field = V4L2_FIELD_NONE;
fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(format, frame);
fmt->fmt.pix.sizeimage = probe->dwMaxVideoFrameSize;
+ fmt->fmt.pix.pixelformat = format->fcc;
fmt->fmt.pix.colorspace = format->colorspace;
+ fmt->fmt.pix.xfer_func = format->xfer_func;
+ fmt->fmt.pix.ycbcr_enc = format->ycbcr_enc;
if (uvc_format != NULL)
*uvc_format = format;
@@ -289,6 +321,8 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream,
fmt->fmt.pix.bytesperline = uvc_v4l2_get_bytesperline(format, frame);
fmt->fmt.pix.sizeimage = stream->ctrl.dwMaxVideoFrameSize;
fmt->fmt.pix.colorspace = format->colorspace;
+ fmt->fmt.pix.xfer_func = format->xfer_func;
+ fmt->fmt.pix.ycbcr_enc = format->ycbcr_enc;
done:
mutex_unlock(&stream->mutex);
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index a65d5353a441..a6a441d92b94 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -622,7 +622,7 @@ static u16 uvc_video_clock_host_sof(const struct uvc_clock_sample *sample)
* to avoid losing precision in the division. Similarly, the host timestamp is
* computed with
*
- * TS = ((TS2 - TS1) * PTS + TS1 * SOF2 - TS2 * SOF1) / (SOF2 - SOF1) (2)
+ * TS = ((TS2 - TS1) * SOF + TS1 * SOF2 - TS2 * SOF1) / (SOF2 - SOF1) (2)
*
* SOF values are coded on 11 bits by USB. We extend their precision with 16
* decimal bits, leading to a 11.16 coding.
@@ -1509,11 +1509,11 @@ static void uvc_video_complete(struct urb *urb)
default:
uvc_printk(KERN_WARNING, "Non-zero status (%d) in video "
"completion handler.\n", urb->status);
- /* fall through */
+ fallthrough;
case -ENOENT: /* usb_poison_urb() called. */
if (stream->frozen)
return;
- /* fall through */
+ fallthrough;
case -ECONNRESET: /* usb_unlink_urb() called. */
case -ESHUTDOWN: /* The endpoint is being disabled. */
uvc_queue_cancel(queue, urb->status == -ESHUTDOWN);
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 6ab972c643e3..a3dfacf069c4 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -165,6 +165,10 @@
{0x32, 0x00, 0x00, 0x00, 0x02, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+#define UVC_GUID_FORMAT_HEVC \
+ { 'H', 'E', 'V', 'C', 0x00, 0x00, 0x10, 0x00, \
+ 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71}
+
/* ------------------------------------------------------------------------
* Driver specific constants.
@@ -370,7 +374,9 @@ struct uvc_format {
u8 type;
u8 index;
u8 bpp;
- u8 colorspace;
+ enum v4l2_colorspace colorspace;
+ enum v4l2_xfer_func xfer_func;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
u32 fcc;
u32 flags;
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index 593bcf6c3735..a99e82ec9ab6 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -246,9 +246,6 @@ struct v4l2_format32 {
* @memory: buffer memory type
* @format: frame format, for which buffers are requested
* @capabilities: capabilities of this buffer type.
- * @flags: additional buffer management attributes (ignored unless the
- * queue has V4L2_BUF_CAP_SUPPORTS_MMAP_CACHE_HINTS capability and
- * configured for MMAP streaming I/O).
* @reserved: future extensions
*/
struct v4l2_create_buffers32 {
@@ -257,8 +254,7 @@ struct v4l2_create_buffers32 {
__u32 memory; /* enum v4l2_memory */
struct v4l2_format32 format;
__u32 capabilities;
- __u32 flags;
- __u32 reserved[6];
+ __u32 reserved[7];
};
static int __bufsize_v4l2_format(struct v4l2_format32 __user *p32, u32 *size)
@@ -359,8 +355,7 @@ static int get_v4l2_create32(struct v4l2_create_buffers __user *p64,
{
if (!access_ok(p32, sizeof(*p32)) ||
copy_in_user(p64, p32,
- offsetof(struct v4l2_create_buffers32, format)) ||
- assign_in_user(&p64->flags, &p32->flags))
+ offsetof(struct v4l2_create_buffers32, format)))
return -EFAULT;
return __get_v4l2_format32(&p64->format, &p32->format,
aux_buf, aux_space);
@@ -422,7 +417,6 @@ static int put_v4l2_create32(struct v4l2_create_buffers __user *p64,
copy_in_user(p32, p64,
offsetof(struct v4l2_create_buffers32, format)) ||
assign_in_user(&p32->capabilities, &p64->capabilities) ||
- assign_in_user(&p32->flags, &p64->flags) ||
copy_in_user(p32->reserved, p64->reserved, sizeof(p64->reserved)))
return -EFAULT;
return __put_v4l2_format32(&p64->format, &p32->format);
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 45a2403aa039..bd7f330c941c 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -200,6 +200,7 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
static const char * const mpeg_video_bitrate_mode[] = {
"Variable Bitrate",
"Constant Bitrate",
+ "Constant Quality",
NULL
};
static const char * const mpeg_stream_type[] = {
@@ -474,6 +475,23 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
"3",
NULL,
};
+ static const char * const vp9_level[] = {
+ "1",
+ "1.1",
+ "2",
+ "2.1",
+ "3",
+ "3.1",
+ "4",
+ "4.1",
+ "5",
+ "5.1",
+ "5.2",
+ "6",
+ "6.1",
+ "6.2",
+ NULL,
+ };
static const char * const flash_led_mode[] = {
"Off",
@@ -590,6 +608,12 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
"External",
NULL,
};
+ static const char * const mpeg_video_frame_skip[] = {
+ "Disabled",
+ "Level Limit",
+ "VBV/CPB Limit",
+ NULL,
+ };
switch (id) {
case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
@@ -651,6 +675,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
return flash_strobe_source;
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
return header_mode;
+ case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
+ return mpeg_video_frame_skip;
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
return multi_slice;
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
@@ -685,6 +711,8 @@ const char * const *v4l2_ctrl_get_menu(u32 id)
return vp8_profile;
case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
return vp9_profile;
+ case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
+ return vp9_level;
case V4L2_CID_JPEG_CHROMA_SUBSAMPLING:
return jpeg_chroma_subsampling;
case V4L2_CID_DV_TX_MODE:
@@ -832,6 +860,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure";
case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown";
case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode";
+ case V4L2_CID_MPEG_VIDEO_CONSTANT_QUALITY: return "Constant Quality";
case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate";
case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate";
case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
@@ -844,6 +873,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_MB_RC_ENABLE: return "H264 MB Level Rate Control";
case V4L2_CID_MPEG_VIDEO_HEADER_MODE: return "Sequence Header Mode";
case V4L2_CID_MPEG_VIDEO_MAX_REF_PIC: return "Max Number of Reference Pics";
+ case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE: return "Frame Skip Mode";
case V4L2_CID_MPEG_VIDEO_H263_I_FRAME_QP: return "H263 I-Frame QP Value";
case V4L2_CID_MPEG_VIDEO_H263_P_FRAME_QP: return "H263 P-Frame QP Value";
case V4L2_CID_MPEG_VIDEO_H263_B_FRAME_QP: return "H263 B-Frame QP Value";
@@ -897,6 +927,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS: return "H264 Decode Parameters";
case V4L2_CID_MPEG_VIDEO_H264_DECODE_MODE: return "H264 Decode Mode";
case V4L2_CID_MPEG_VIDEO_H264_START_CODE: return "H264 Start Code";
+ case V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS: return "H264 Prediction Weight Table";
case V4L2_CID_MPEG_VIDEO_MPEG2_LEVEL: return "MPEG2 Level";
case V4L2_CID_MPEG_VIDEO_MPEG2_PROFILE: return "MPEG2 Profile";
case V4L2_CID_MPEG_VIDEO_MPEG4_I_FRAME_QP: return "MPEG4 I-Frame QP Value";
@@ -938,6 +969,7 @@ const char *v4l2_ctrl_get_name(u32 id)
case V4L2_CID_MPEG_VIDEO_VPX_P_FRAME_QP: return "VPX P-Frame QP Value";
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE: return "VP8 Profile";
case V4L2_CID_MPEG_VIDEO_VP9_PROFILE: return "VP9 Profile";
+ case V4L2_CID_MPEG_VIDEO_VP9_LEVEL: return "VP9 Level";
case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER: return "VP8 Frame Header";
/* HEVC controls */
@@ -1265,6 +1297,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_FLASH_LED_MODE:
case V4L2_CID_FLASH_STROBE_SOURCE:
case V4L2_CID_MPEG_VIDEO_HEADER_MODE:
+ case V4L2_CID_MPEG_VIDEO_FRAME_SKIP_MODE:
case V4L2_CID_MPEG_VIDEO_MULTI_SLICE_MODE:
case V4L2_CID_MPEG_VIDEO_H264_ENTROPY_MODE:
case V4L2_CID_MPEG_VIDEO_H264_LEVEL:
@@ -1294,6 +1327,7 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_VPX_GOLDEN_FRAME_SEL:
case V4L2_CID_MPEG_VIDEO_VP8_PROFILE:
case V4L2_CID_MPEG_VIDEO_VP9_PROFILE:
+ case V4L2_CID_MPEG_VIDEO_VP9_LEVEL:
case V4L2_CID_DETECT_MD_MODE:
case V4L2_CID_MPEG_VIDEO_HEVC_PROFILE:
case V4L2_CID_MPEG_VIDEO_HEVC_LEVEL:
@@ -1412,6 +1446,9 @@ void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
case V4L2_CID_MPEG_VIDEO_H264_DECODE_PARAMS:
*type = V4L2_CTRL_TYPE_H264_DECODE_PARAMS;
break;
+ case V4L2_CID_MPEG_VIDEO_H264_PRED_WEIGHTS:
+ *type = V4L2_CTRL_TYPE_H264_PRED_WEIGHTS;
+ break;
case V4L2_CID_MPEG_VIDEO_VP8_FRAME_HEADER:
*type = V4L2_CTRL_TYPE_VP8_FRAME_HEADER;
break;
@@ -1721,6 +1758,8 @@ static void std_log(const struct v4l2_ctrl *ctrl)
#define zero_padding(s) \
memset(&(s).padding, 0, sizeof((s).padding))
+#define zero_reserved(s) \
+ memset(&(s).reserved, 0, sizeof((s).reserved))
/*
* Compound controls validation requires setting unused fields/flags to zero
@@ -1731,6 +1770,8 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
{
struct v4l2_ctrl_mpeg2_slice_params *p_mpeg2_slice_params;
struct v4l2_ctrl_vp8_frame_header *p_vp8_frame_header;
+ struct v4l2_ctrl_h264_slice_params *p_h264_slice_params;
+ struct v4l2_ctrl_h264_decode_params *p_h264_dec_params;
struct v4l2_ctrl_hevc_sps *p_hevc_sps;
struct v4l2_ctrl_hevc_pps *p_hevc_pps;
struct v4l2_ctrl_hevc_slice_params *p_hevc_slice_params;
@@ -1790,8 +1831,25 @@ static int std_validate_compound(const struct v4l2_ctrl *ctrl, u32 idx,
case V4L2_CTRL_TYPE_H264_SPS:
case V4L2_CTRL_TYPE_H264_PPS:
case V4L2_CTRL_TYPE_H264_SCALING_MATRIX:
+ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+ break;
+
case V4L2_CTRL_TYPE_H264_SLICE_PARAMS:
+ p_h264_slice_params = p;
+
+ zero_reserved(*p_h264_slice_params);
+ break;
+
case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
+ p_h264_dec_params = p;
+
+ for (i = 0; i < V4L2_H264_NUM_DPB_ENTRIES; i++) {
+ struct v4l2_h264_dpb_entry *dpb_entry =
+ &p_h264_dec_params->dpb[i];
+
+ zero_reserved(*dpb_entry);
+ }
+ zero_reserved(*p_h264_dec_params);
break;
case V4L2_CTRL_TYPE_VP8_FRAME_HEADER:
@@ -2553,6 +2611,9 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
case V4L2_CTRL_TYPE_H264_DECODE_PARAMS:
elem_size = sizeof(struct v4l2_ctrl_h264_decode_params);
break;
+ case V4L2_CTRL_TYPE_H264_PRED_WEIGHTS:
+ elem_size = sizeof(struct v4l2_ctrl_h264_pred_weights);
+ break;
case V4L2_CTRL_TYPE_VP8_FRAME_HEADER:
elem_size = sizeof(struct v4l2_ctrl_vp8_frame_header);
break;
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index a4c3c77c1894..d7bbe33840cb 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -547,8 +547,8 @@ int v4l2_fwnode_endpoint_alloc_parse(struct fwnode_handle *fwnode,
}
for (i = 0; i < vep->nr_of_link_frequencies; i++)
- pr_info("link-frequencies %u value %llu\n", i,
- vep->link_frequencies[i]);
+ pr_debug("link-frequencies %u value %llu\n", i,
+ vep->link_frequencies[i]);
}
pr_debug("===== end parsing endpoint %pfw\n", fwnode);
diff --git a/drivers/media/v4l2-core/v4l2-h264.c b/drivers/media/v4l2-core/v4l2-h264.c
index edf6225f0522..5633a242520a 100644
--- a/drivers/media/v4l2-core/v4l2-h264.c
+++ b/drivers/media/v4l2-core/v4l2-h264.c
@@ -18,14 +18,12 @@
*
* @b: the builder context to initialize
* @dec_params: decode parameters control
- * @slice_params: first slice parameters control
* @sps: SPS control
* @dpb: DPB to use when creating the reference list
*/
void
v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
const struct v4l2_ctrl_h264_decode_params *dec_params,
- const struct v4l2_ctrl_h264_slice_params *slice_params,
const struct v4l2_ctrl_h264_sps *sps,
const struct v4l2_h264_dpb_entry dpb[V4L2_H264_NUM_DPB_ENTRIES])
{
@@ -33,13 +31,13 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
unsigned int i;
max_frame_num = 1 << (sps->log2_max_frame_num_minus4 + 4);
- cur_frame_num = slice_params->frame_num;
+ cur_frame_num = dec_params->frame_num;
memset(b, 0, sizeof(*b));
- if (!(slice_params->flags & V4L2_H264_SLICE_FLAG_FIELD_PIC))
+ if (!(dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_FIELD_PIC))
b->cur_pic_order_count = min(dec_params->bottom_field_order_cnt,
dec_params->top_field_order_cnt);
- else if (slice_params->flags & V4L2_H264_SLICE_FLAG_BOTTOM_FIELD)
+ else if (dec_params->flags & V4L2_H264_DECODE_PARAM_FLAG_BOTTOM_FIELD)
b->cur_pic_order_count = dec_params->bottom_field_order_cnt;
else
b->cur_pic_order_count = dec_params->top_field_order_cnt;
@@ -66,10 +64,10 @@ v4l2_h264_init_reflist_builder(struct v4l2_h264_reflist_builder *b,
else
b->refs[i].frame_num = dpb[i].frame_num;
- if (!(dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_FIELD))
+ if (dpb[i].fields == V4L2_H264_FRAME_REF)
pic_order_count = min(dpb[i].top_field_order_cnt,
dpb[i].bottom_field_order_cnt);
- else if (dpb[i].flags & V4L2_H264_DPB_ENTRY_FLAG_BOTTOM_FIELD)
+ else if (dpb[i].fields & V4L2_H264_BOTTOM_FIELD_REF)
pic_order_count = dpb[i].bottom_field_order_cnt;
else
pic_order_count = dpb[i].top_field_order_cnt;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index f74b42280892..eeff398fbdcc 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -2042,6 +2042,9 @@ static int v4l_reqbufs(const struct v4l2_ioctl_ops *ops,
if (ret)
return ret;
+
+ CLEAR_AFTER_FIELD(p, capabilities);
+
return ops->vidioc_reqbufs(file, fh, p);
}
@@ -2081,7 +2084,7 @@ static int v4l_create_bufs(const struct v4l2_ioctl_ops *ops,
if (ret)
return ret;
- CLEAR_AFTER_FIELD(create, flags);
+ CLEAR_AFTER_FIELD(create, capabilities);
v4l_sanitize_format(&create->format);
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index 95a8f2dc5341..b221b4e438a1 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -43,6 +43,10 @@ module_param(debug, bool, 0644);
#define TRANS_ABORT (1 << 2)
+/* The job queue is not running new jobs */
+#define QUEUE_PAUSED (1 << 0)
+
+
/* Offset base for buffers on the destination queue - used to distinguish
* between source and destination buffers when mmapping - they receive the same
* offsets but for different queues */
@@ -84,6 +88,7 @@ static const char * const m2m_entity_name[] = {
* @job_queue: instances queued to run
* @job_spinlock: protects job_queue
* @job_work: worker to run queued jobs.
+ * @job_queue_flags: flags of the queue status, %QUEUE_PAUSED.
* @m2m_ops: driver callbacks
*/
struct v4l2_m2m_dev {
@@ -101,6 +106,7 @@ struct v4l2_m2m_dev {
struct list_head job_queue;
spinlock_t job_spinlock;
struct work_struct job_work;
+ unsigned long job_queue_flags;
const struct v4l2_m2m_ops *m2m_ops;
};
@@ -263,6 +269,12 @@ static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev)
return;
}
+ if (m2m_dev->job_queue_flags & QUEUE_PAUSED) {
+ spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+ dprintk("Running new jobs is paused\n");
+ return;
+ }
+
m2m_dev->curr_ctx = list_first_entry(&m2m_dev->job_queue,
struct v4l2_m2m_ctx, queue);
m2m_dev->curr_ctx->job_flags |= TRANS_RUNNING;
@@ -528,6 +540,34 @@ unlock:
}
EXPORT_SYMBOL(v4l2_m2m_buf_done_and_job_finish);
+void v4l2_m2m_suspend(struct v4l2_m2m_dev *m2m_dev)
+{
+ unsigned long flags;
+ struct v4l2_m2m_ctx *curr_ctx;
+
+ spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
+ m2m_dev->job_queue_flags |= QUEUE_PAUSED;
+ curr_ctx = m2m_dev->curr_ctx;
+ spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+
+ if (curr_ctx)
+ wait_event(curr_ctx->finished,
+ !(curr_ctx->job_flags & TRANS_RUNNING));
+}
+EXPORT_SYMBOL(v4l2_m2m_suspend);
+
+void v4l2_m2m_resume(struct v4l2_m2m_dev *m2m_dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
+ m2m_dev->job_queue_flags &= ~QUEUE_PAUSED;
+ spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+
+ v4l2_m2m_try_run(m2m_dev);
+}
+EXPORT_SYMBOL(v4l2_m2m_resume);
+
int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
struct v4l2_requestbuffers *reqbufs)
{
@@ -841,7 +881,6 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file,
struct poll_table_struct *wait)
{
struct vb2_queue *src_q, *dst_q;
- struct vb2_buffer *src_vb = NULL, *dst_vb = NULL;
__poll_t rc = 0;
unsigned long flags;
@@ -862,34 +901,17 @@ static __poll_t v4l2_m2m_poll_for_data(struct file *file,
list_empty(&dst_q->queued_list)))
return EPOLLERR;
- spin_lock_irqsave(&dst_q->done_lock, flags);
- if (list_empty(&dst_q->done_list)) {
- /*
- * If the last buffer was dequeued from the capture queue,
- * return immediately. DQBUF will return -EPIPE.
- */
- if (dst_q->last_buffer_dequeued) {
- spin_unlock_irqrestore(&dst_q->done_lock, flags);
- return EPOLLIN | EPOLLRDNORM;
- }
- }
- spin_unlock_irqrestore(&dst_q->done_lock, flags);
-
spin_lock_irqsave(&src_q->done_lock, flags);
if (!list_empty(&src_q->done_list))
- src_vb = list_first_entry(&src_q->done_list, struct vb2_buffer,
- done_entry);
- if (src_vb && (src_vb->state == VB2_BUF_STATE_DONE
- || src_vb->state == VB2_BUF_STATE_ERROR))
rc |= EPOLLOUT | EPOLLWRNORM;
spin_unlock_irqrestore(&src_q->done_lock, flags);
spin_lock_irqsave(&dst_q->done_lock, flags);
- if (!list_empty(&dst_q->done_list))
- dst_vb = list_first_entry(&dst_q->done_list, struct vb2_buffer,
- done_entry);
- if (dst_vb && (dst_vb->state == VB2_BUF_STATE_DONE
- || dst_vb->state == VB2_BUF_STATE_ERROR))
+ /*
+ * If the last buffer was dequeued from the capture queue, signal
+ * userspace. DQBUF(CAPTURE) will return -EPIPE.
+ */
+ if (!list_empty(&dst_q->done_list) || dst_q->last_buffer_dequeued)
rc |= EPOLLIN | EPOLLRDNORM;
spin_unlock_irqrestore(&dst_q->done_lock, flags);
diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c
index 6b989fe5a0a9..a7d508e74d6b 100644
--- a/drivers/media/v4l2-core/v4l2-subdev.c
+++ b/drivers/media/v4l2-core/v4l2-subdev.c
@@ -309,6 +309,20 @@ static int call_enum_dv_timings(struct v4l2_subdev *sd,
sd->ops->pad->enum_dv_timings(sd, dvt);
}
+static int call_get_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_config *config)
+{
+ return check_pad(sd, pad) ? :
+ sd->ops->pad->get_mbus_config(sd, pad, config);
+}
+
+static int call_set_mbus_config(struct v4l2_subdev *sd, unsigned int pad,
+ struct v4l2_mbus_config *config)
+{
+ return check_pad(sd, pad) ? :
+ sd->ops->pad->get_mbus_config(sd, pad, config);
+}
+
static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
.get_fmt = call_get_fmt,
.set_fmt = call_set_fmt,
@@ -321,6 +335,8 @@ static const struct v4l2_subdev_pad_ops v4l2_subdev_call_pad_wrappers = {
.set_edid = call_set_edid,
.dv_timings_cap = call_dv_timings_cap,
.enum_dv_timings = call_enum_dv_timings,
+ .get_mbus_config = call_get_mbus_config,
+ .set_mbus_config = call_set_mbus_config,
};
static const struct v4l2_subdev_video_ops v4l2_subdev_call_video_wrappers = {
diff --git a/drivers/media/v4l2-core/videobuf-dma-sg.c b/drivers/media/v4l2-core/videobuf-dma-sg.c
index 46ff19df9f53..8dd0562de287 100644
--- a/drivers/media/v4l2-core/videobuf-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf-dma-sg.c
@@ -180,7 +180,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
if (rw == READ)
flags |= FOLL_WRITE;
- dprintk(1, "init user [0x%lx+0x%lx => %d pages]\n",
+ dprintk(1, "init user [0x%lx+0x%lx => %lu pages]\n",
data, size, dma->nr_pages);
err = pin_user_pages(data & PAGE_MASK, dma->nr_pages,
@@ -188,7 +188,7 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
if (err != dma->nr_pages) {
dma->nr_pages = (err >= 0) ? err : 0;
- dprintk(1, "pin_user_pages: err=%d [%d]\n", err,
+ dprintk(1, "pin_user_pages: err=%d [%lu]\n", err,
dma->nr_pages);
return err < 0 ? err : -EINVAL;
}
@@ -208,11 +208,11 @@ static int videobuf_dma_init_user(struct videobuf_dmabuf *dma, int direction,
}
static int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
- int nr_pages)
+ unsigned long nr_pages)
{
int i;
- dprintk(1, "init kernel [%d pages]\n", nr_pages);
+ dprintk(1, "init kernel [%lu pages]\n", nr_pages);
dma->direction = direction;
dma->vaddr_pages = kcalloc(nr_pages, sizeof(*dma->vaddr_pages),
@@ -238,11 +238,11 @@ static int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
dma->vaddr = vmap(dma->vaddr_pages, nr_pages, VM_MAP | VM_IOREMAP,
PAGE_KERNEL);
if (NULL == dma->vaddr) {
- dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
+ dprintk(1, "vmalloc_32(%lu pages) failed\n", nr_pages);
goto out_free_pages;
}
- dprintk(1, "vmalloc is at addr %p, size=%d\n",
+ dprintk(1, "vmalloc is at addr %p, size=%lu\n",
dma->vaddr, nr_pages << PAGE_SHIFT);
memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
@@ -267,9 +267,9 @@ out_free_pages:
}
static int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
- dma_addr_t addr, int nr_pages)
+ dma_addr_t addr, unsigned long nr_pages)
{
- dprintk(1, "init overlay [%d pages @ bus 0x%lx]\n",
+ dprintk(1, "init overlay [%lu pages @ bus 0x%lx]\n",
nr_pages, (unsigned long)addr);
dma->direction = direction;
@@ -500,9 +500,11 @@ static int __videobuf_iolock(struct videobuf_queue *q,
struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf)
{
- int err, pages;
- dma_addr_t bus;
struct videobuf_dma_sg_memory *mem = vb->priv;
+ unsigned long pages;
+ dma_addr_t bus;
+ int err;
+
BUG_ON(!mem);
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);