From 6d03a247468059b0e59c821ef39e6762d4d6fc30 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Wed, 19 Jun 2024 23:00:51 +0200 Subject: Merging upstream version 6.9.2. Signed-off-by: Daniel Baumann --- drivers/media/platform/amphion/vdec.c | 4 +- drivers/media/platform/atmel/atmel-isi.c | 4 +- drivers/media/platform/cadence/cdns-csi2rx.c | 43 +- .../media/platform/chips-media/wave5/wave5-hw.c | 2 +- .../platform/chips-media/wave5/wave5-vpu-enc.c | 2 +- .../media/platform/chips-media/wave5/wave5-vpu.c | 6 +- drivers/media/platform/intel/pxa_camera.c | 2 +- drivers/media/platform/marvell/Kconfig | 2 + .../media/platform/mediatek/jpeg/mtk_jpeg_core.h | 1 - .../media/platform/mediatek/mdp3/mdp_cfg_data.c | 729 +++++++- drivers/media/platform/mediatek/mdp3/mdp_reg_aal.h | 25 + .../media/platform/mediatek/mdp3/mdp_reg_color.h | 31 + drivers/media/platform/mediatek/mdp3/mdp_reg_fg.h | 23 + drivers/media/platform/mediatek/mdp3/mdp_reg_hdr.h | 31 + .../media/platform/mediatek/mdp3/mdp_reg_merge.h | 25 + drivers/media/platform/mediatek/mdp3/mdp_reg_ovl.h | 25 + drivers/media/platform/mediatek/mdp3/mdp_reg_pad.h | 21 + .../media/platform/mediatek/mdp3/mdp_reg_rdma.h | 24 + drivers/media/platform/mediatek/mdp3/mdp_reg_rsz.h | 2 + .../media/platform/mediatek/mdp3/mdp_reg_tdshp.h | 34 + .../media/platform/mediatek/mdp3/mdp_reg_wrot.h | 8 + .../media/platform/mediatek/mdp3/mdp_sm_mt8195.h | 283 +++ drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h | 4 + .../media/platform/mediatek/mdp3/mtk-mdp3-cfg.h | 2 + .../media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c | 440 ++++- .../media/platform/mediatek/mdp3/mtk-mdp3-cmdq.h | 1 + .../media/platform/mediatek/mdp3/mtk-mdp3-comp.c | 895 ++++++++- .../media/platform/mediatek/mdp3/mtk-mdp3-comp.h | 93 +- .../media/platform/mediatek/mdp3/mtk-mdp3-core.c | 142 +- .../media/platform/mediatek/mdp3/mtk-mdp3-core.h | 50 +- .../media/platform/mediatek/mdp3/mtk-mdp3-m2m.c | 15 + .../media/platform/mediatek/mdp3/mtk-mdp3-regs.c | 18 + .../media/platform/mediatek/mdp3/mtk-mdp3-regs.h | 1 + .../media/platform/mediatek/mdp3/mtk-mdp3-vpu.c | 3 +- .../mediatek/vcodec/decoder/mtk_vcodec_dec.h | 1 - .../vcodec/decoder/mtk_vcodec_dec_stateless.c | 14 +- .../mediatek/vcodec/decoder/vdec/vdec_vp8_if.c | 2 +- .../mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c | 1 - .../mediatek/vcodec/decoder/vdec/vdec_vp9_if.c | 11 +- .../vcodec/decoder/vdec/vdec_vp9_req_lat_if.c | 5 +- .../platform/mediatek/vcodec/decoder/vdec_vpu_if.h | 1 - .../mediatek/vcodec/encoder/mtk_vcodec_enc.h | 1 - drivers/media/platform/nuvoton/npcm-video.c | 6 +- drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 16 + drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h | 1 + .../media/platform/nxp/imx8-isi/imx8-isi-core.c | 6 +- drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c | 8 +- drivers/media/platform/qcom/venus/core.c | 12 +- drivers/media/platform/qcom/venus/core.h | 8 +- drivers/media/platform/qcom/venus/pm_helpers.c | 48 +- drivers/media/platform/renesas/Kconfig | 16 + drivers/media/platform/renesas/Makefile | 1 + drivers/media/platform/renesas/rcar-csi2.c | 1959 ++++++++++++++++++++ drivers/media/platform/renesas/rcar-isp.c | 1 + drivers/media/platform/renesas/rcar-vin/Kconfig | 16 - drivers/media/platform/renesas/rcar-vin/Makefile | 1 - .../media/platform/renesas/rcar-vin/rcar-csi2.c | 1959 -------------------- drivers/media/platform/renesas/rcar-vin/rcar-vin.h | 2 +- .../media/platform/renesas/rzg2l-cru/rzg2l-cru.h | 3 - .../media/platform/renesas/rzg2l-cru/rzg2l-csi2.c | 37 +- .../media/platform/renesas/rzg2l-cru/rzg2l-ip.c | 18 +- .../media/platform/renesas/rzg2l-cru/rzg2l-video.c | 83 +- .../platform/rockchip/rkisp1/rkisp1-capture.c | 216 ++- .../media/platform/rockchip/rkisp1/rkisp1-common.h | 35 +- .../media/platform/rockchip/rkisp1/rkisp1-dev.c | 71 +- .../media/platform/rockchip/rkisp1/rkisp1-isp.c | 131 +- .../media/platform/rockchip/rkisp1/rkisp1-regs.h | 36 + .../platform/rockchip/rkisp1/rkisp1-resizer.c | 19 +- .../platform/samsung/exynos4-is/fimc-capture.c | 52 +- .../media/platform/samsung/exynos4-is/fimc-core.c | 23 +- .../media/platform/samsung/exynos4-is/fimc-core.h | 23 +- .../media/platform/samsung/exynos4-is/fimc-is.c | 2 +- .../platform/samsung/exynos4-is/fimc-isp-video.c | 2 +- .../platform/samsung/exynos4-is/fimc-lite-reg.c | 13 +- .../platform/samsung/exynos4-is/fimc-lite-reg.h | 12 +- .../media/platform/samsung/exynos4-is/fimc-lite.c | 2 +- .../media/platform/samsung/exynos4-is/fimc-lite.h | 3 - .../media/platform/samsung/exynos4-is/fimc-m2m.c | 23 +- .../media/platform/samsung/exynos4-is/fimc-reg.c | 38 +- .../media/platform/samsung/exynos4-is/fimc-reg.h | 10 +- .../media/platform/samsung/exynos4-is/mipi-csis.c | 3 +- drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c | 76 +- .../media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c | 8 +- .../media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h | 2 +- .../platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c | 6 +- .../platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h | 2 +- .../platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c | 8 +- .../platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h | 2 +- .../platform/samsung/s5p-mfc/s5p_mfc_common.h | 15 +- .../media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c | 26 +- .../media/platform/samsung/s5p-mfc/s5p_mfc_dec.c | 20 +- .../media/platform/samsung/s5p-mfc/s5p_mfc_dec.h | 3 +- .../media/platform/samsung/s5p-mfc/s5p_mfc_enc.c | 12 +- .../media/platform/samsung/s5p-mfc/s5p_mfc_enc.h | 3 +- .../media/platform/samsung/s5p-mfc/s5p_mfc_opr.c | 7 +- .../platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c | 28 +- .../platform/samsung/s5p-mfc/s5p_mfc_opr_v5.h | 2 +- .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c | 36 +- .../platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h | 2 +- .../media/platform/samsung/s5p-mfc/s5p_mfc_pm.c | 51 +- .../media/platform/samsung/s5p-mfc/s5p_mfc_pm.h | 8 +- drivers/media/platform/st/stm32/stm32-dcmi.c | 4 +- .../platform/st/stm32/stm32-dcmipp/dcmipp-core.c | 6 +- drivers/media/platform/ti/davinci/vpif.c | 3 +- .../media/platform/ti/j721e-csi2rx/j721e-csi2rx.c | 35 +- drivers/media/platform/verisilicon/Kconfig | 14 +- drivers/media/platform/verisilicon/Makefile | 3 + drivers/media/platform/verisilicon/hantro.h | 1 - drivers/media/platform/verisilicon/hantro_drv.c | 4 + .../platform/verisilicon/hantro_g1_h264_dec.c | 2 +- drivers/media/platform/verisilicon/hantro_hw.h | 2 + .../verisilicon/rockchip_vpu2_hw_h264_dec.c | 2 +- .../platform/verisilicon/rockchip_vpu981_regs.h | 2 +- .../media/platform/verisilicon/stm32mp25_vpu_hw.c | 186 ++ drivers/media/platform/xilinx/Kconfig | 4 +- 115 files changed, 5829 insertions(+), 2698 deletions(-) create mode 100644 drivers/media/platform/mediatek/mdp3/mdp_reg_aal.h create mode 100644 drivers/media/platform/mediatek/mdp3/mdp_reg_color.h create mode 100644 drivers/media/platform/mediatek/mdp3/mdp_reg_fg.h create mode 100644 drivers/media/platform/mediatek/mdp3/mdp_reg_hdr.h create mode 100644 drivers/media/platform/mediatek/mdp3/mdp_reg_merge.h create mode 100644 drivers/media/platform/mediatek/mdp3/mdp_reg_ovl.h create mode 100644 drivers/media/platform/mediatek/mdp3/mdp_reg_pad.h create mode 100644 drivers/media/platform/mediatek/mdp3/mdp_reg_tdshp.h create mode 100644 drivers/media/platform/mediatek/mdp3/mdp_sm_mt8195.h create mode 100644 drivers/media/platform/renesas/rcar-csi2.c delete mode 100644 drivers/media/platform/renesas/rcar-vin/rcar-csi2.c create mode 100644 drivers/media/platform/verisilicon/stm32mp25_vpu_hw.c (limited to 'drivers/media/platform') diff --git a/drivers/media/platform/amphion/vdec.c b/drivers/media/platform/amphion/vdec.c index 133d77d1ea..a57f9f4f3b 100644 --- a/drivers/media/platform/amphion/vdec.c +++ b/drivers/media/platform/amphion/vdec.c @@ -1595,9 +1595,11 @@ static int vdec_stop_session(struct vpu_inst *inst, u32 type) if (V4L2_TYPE_IS_OUTPUT(type)) { vdec_update_state(inst, VPU_CODEC_STATE_SEEK, 0); vdec->drain = 0; + vdec_abort(inst); } else { if (inst->state != VPU_CODEC_STATE_DYAMIC_RESOLUTION_CHANGE) { - vdec_abort(inst); + if (vb2_is_streaming(v4l2_m2m_get_src_vq(inst->fh.m2m_ctx))) + vdec_abort(inst); vdec->eos_received = 0; } vdec_clear_slots(inst); diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c index f8450a8ccd..c1108df72d 100644 --- a/drivers/media/platform/atmel/atmel-isi.c +++ b/drivers/media/platform/atmel/atmel-isi.c @@ -834,7 +834,7 @@ static int atmel_isi_parse_dt(struct atmel_isi *isi, isi->pdata.full_mode = 1; isi->pdata.frate = ISI_CFG1_FRATE_CAPTURE_ALL; - np = of_graph_get_next_endpoint(np, NULL); + np = of_graph_get_endpoint_by_regs(np, 0, -1); if (!np) { dev_err(&pdev->dev, "Could not find the endpoint\n"); return -EINVAL; @@ -1158,7 +1158,7 @@ static int isi_graph_init(struct atmel_isi *isi) struct device_node *ep; int ret; - ep = of_graph_get_next_endpoint(isi->dev->of_node, NULL); + ep = of_graph_get_endpoint_by_regs(isi->dev->of_node, 0, -1); if (!ep) return -EINVAL; diff --git a/drivers/media/platform/cadence/cdns-csi2rx.c b/drivers/media/platform/cadence/cdns-csi2rx.c index 5be75bd4ad..2d7b0508cc 100644 --- a/drivers/media/platform/cadence/cdns-csi2rx.c +++ b/drivers/media/platform/cadence/cdns-csi2rx.c @@ -114,10 +114,14 @@ static const struct csi2rx_fmt formats[] = { { .code = MEDIA_BUS_FMT_SGBRG8_1X8, .bpp = 8, }, { .code = MEDIA_BUS_FMT_SGRBG8_1X8, .bpp = 8, }, { .code = MEDIA_BUS_FMT_SRGGB8_1X8, .bpp = 8, }, + { .code = MEDIA_BUS_FMT_Y8_1X8, .bpp = 8, }, { .code = MEDIA_BUS_FMT_SBGGR10_1X10, .bpp = 10, }, { .code = MEDIA_BUS_FMT_SGBRG10_1X10, .bpp = 10, }, { .code = MEDIA_BUS_FMT_SGRBG10_1X10, .bpp = 10, }, { .code = MEDIA_BUS_FMT_SRGGB10_1X10, .bpp = 10, }, + { .code = MEDIA_BUS_FMT_RGB565_1X16, .bpp = 16, }, + { .code = MEDIA_BUS_FMT_RGB888_1X24, .bpp = 24, }, + { .code = MEDIA_BUS_FMT_BGR888_1X24, .bpp = 24, }, }; static const struct csi2rx_fmt *csi2rx_get_fmt_by_code(u32 code) @@ -235,6 +239,10 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) writel(reg, csi2rx->base + CSI2RX_STATIC_CFG_REG); + ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true); + if (ret) + goto err_disable_pclk; + /* Enable DPHY clk and data lanes. */ if (csi2rx->dphy) { reg = CSI2RX_DPHY_CL_EN | CSI2RX_DPHY_CL_RST; @@ -244,13 +252,6 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) } writel(reg, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); - - ret = csi2rx_configure_ext_dphy(csi2rx); - if (ret) { - dev_err(csi2rx->dev, - "Failed to configure external DPHY: %d\n", ret); - goto err_disable_pclk; - } } /* @@ -290,9 +291,14 @@ static int csi2rx_start(struct csi2rx_priv *csi2rx) reset_control_deassert(csi2rx->sys_rst); - ret = v4l2_subdev_call(csi2rx->source_subdev, video, s_stream, true); - if (ret) - goto err_disable_sysclk; + if (csi2rx->dphy) { + ret = csi2rx_configure_ext_dphy(csi2rx); + if (ret) { + dev_err(csi2rx->dev, + "Failed to configure external DPHY: %d\n", ret); + goto err_disable_sysclk; + } + } clk_disable_unprepare(csi2rx->p_clk); @@ -306,10 +312,6 @@ err_disable_pixclk: clk_disable_unprepare(csi2rx->pixel_clk[i - 1]); } - if (csi2rx->dphy) { - writel(0, csi2rx->base + CSI2RX_DPHY_LANE_CTRL_REG); - phy_power_off(csi2rx->dphy); - } err_disable_pclk: clk_disable_unprepare(csi2rx->p_clk); @@ -391,6 +393,18 @@ out: return ret; } +static int csi2rx_enum_mbus_code(struct v4l2_subdev *subdev, + struct v4l2_subdev_state *state, + struct v4l2_subdev_mbus_code_enum *code_enum) +{ + if (code_enum->index >= ARRAY_SIZE(formats)) + return -EINVAL; + + code_enum->code = formats[code_enum->index].code; + + return 0; +} + static int csi2rx_set_fmt(struct v4l2_subdev *subdev, struct v4l2_subdev_state *state, struct v4l2_subdev_format *format) @@ -441,6 +455,7 @@ static int csi2rx_init_state(struct v4l2_subdev *subdev, } static const struct v4l2_subdev_pad_ops csi2rx_pad_ops = { + .enum_mbus_code = csi2rx_enum_mbus_code, .get_fmt = v4l2_subdev_get_fmt, .set_fmt = csi2rx_set_fmt, }; diff --git a/drivers/media/platform/chips-media/wave5/wave5-hw.c b/drivers/media/platform/chips-media/wave5/wave5-hw.c index f1e022fb14..2d82791f57 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-hw.c +++ b/drivers/media/platform/chips-media/wave5/wave5-hw.c @@ -2315,7 +2315,7 @@ static bool wave5_vpu_enc_check_common_param_valid(struct vpu_instance *inst, param->intra_refresh_mode); return false; } - }; + } return true; invalid_refresh_argument: diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c index f29cfa3af9..8bbf9d10b4 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu-enc.c @@ -92,7 +92,7 @@ static int switch_state(struct vpu_instance *inst, enum vpu_instance_state state break; case VPU_INST_STATE_STOP: break; - }; + } dev_dbg(inst->dev->dev, "Switch state from %s to %s.\n", state_to_str(inst->state), state_to_str(state)); diff --git a/drivers/media/platform/chips-media/wave5/wave5-vpu.c b/drivers/media/platform/chips-media/wave5/wave5-vpu.c index 0d90b5820b..1b3df5b042 100644 --- a/drivers/media/platform/chips-media/wave5/wave5-vpu.c +++ b/drivers/media/platform/chips-media/wave5/wave5-vpu.c @@ -250,7 +250,7 @@ err_clk_dis: return ret; } -static int wave5_vpu_remove(struct platform_device *pdev) +static void wave5_vpu_remove(struct platform_device *pdev) { struct vpu_device *dev = dev_get_drvdata(&pdev->dev); @@ -262,8 +262,6 @@ static int wave5_vpu_remove(struct platform_device *pdev) v4l2_device_unregister(&dev->v4l2_dev); wave5_vdi_release(&pdev->dev); ida_destroy(&dev->inst_ida); - - return 0; } static const struct wave5_match_data ti_wave521c_data = { @@ -283,7 +281,7 @@ static struct platform_driver wave5_vpu_driver = { .of_match_table = of_match_ptr(wave5_dt_ids), }, .probe = wave5_vpu_probe, - .remove = wave5_vpu_remove, + .remove_new = wave5_vpu_remove, }; module_platform_driver(wave5_vpu_driver); diff --git a/drivers/media/platform/intel/pxa_camera.c b/drivers/media/platform/intel/pxa_camera.c index 59b89e421d..d904952bf0 100644 --- a/drivers/media/platform/intel/pxa_camera.c +++ b/drivers/media/platform/intel/pxa_camera.c @@ -2207,7 +2207,7 @@ static int pxa_camera_pdata_from_dt(struct device *dev, pcdev->mclk = mclk_rate; } - np = of_graph_get_next_endpoint(np, NULL); + np = of_graph_get_endpoint_by_regs(np, 0, -1); if (!np) { dev_err(dev, "could not find endpoint\n"); return -EINVAL; diff --git a/drivers/media/platform/marvell/Kconfig b/drivers/media/platform/marvell/Kconfig index d6499ffe30..d31f4730f2 100644 --- a/drivers/media/platform/marvell/Kconfig +++ b/drivers/media/platform/marvell/Kconfig @@ -7,6 +7,7 @@ config VIDEO_CAFE_CCIC depends on V4L_PLATFORM_DRIVERS depends on PCI && I2C && VIDEO_DEV depends on COMMON_CLK + select V4L2_ASYNC select VIDEO_OV7670 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG @@ -24,6 +25,7 @@ config VIDEO_MMP_CAMERA depends on COMMON_CLK select VIDEO_OV7670 if MEDIA_SUBDRV_AUTOSELECT && VIDEO_CAMERA_SENSOR select I2C_GPIO + select V4L2_ASYNC select VIDEOBUF2_VMALLOC select VIDEOBUF2_DMA_CONTIG select VIDEOBUF2_DMA_SG diff --git a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h index 8ba6e757e1..8877eb39e8 100644 --- a/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h +++ b/drivers/media/platform/mediatek/jpeg/mtk_jpeg_core.h @@ -144,7 +144,6 @@ struct mtk_jpegdec_clk { * @jpegenc_irq: jpeg encode irq num * @job_timeout_work: encode timeout workqueue * @hw_param: jpeg encode hw parameters - * @hw_rdy: record hw ready * @hw_state: record hw state * @hw_lock: spinlock protecting the hw device resource */ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c b/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c index 502eeae0bf..ecca52b453 100644 --- a/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c +++ b/drivers/media/platform/mediatek/mdp3/mdp_cfg_data.c @@ -46,18 +46,114 @@ enum mt8183_mdp_comp_id { MT8183_MDP_COMP_WROT1, /* 25 */ }; +enum mt8195_mdp_comp_id { + /* MT8195 Comp id */ + /* ISP */ + MT8195_MDP_COMP_WPEI = 0, + MT8195_MDP_COMP_WPEO, /* 1 */ + MT8195_MDP_COMP_WPEI2, /* 2 */ + MT8195_MDP_COMP_WPEO2, /* 3 */ + + /* MDP */ + MT8195_MDP_COMP_CAMIN, /* 4 */ + MT8195_MDP_COMP_CAMIN2, /* 5 */ + MT8195_MDP_COMP_SPLIT, /* 6 */ + MT8195_MDP_COMP_SPLIT2, /* 7 */ + MT8195_MDP_COMP_RDMA0, /* 8 */ + MT8195_MDP_COMP_RDMA1, /* 9 */ + MT8195_MDP_COMP_RDMA2, /* 10 */ + MT8195_MDP_COMP_RDMA3, /* 11 */ + MT8195_MDP_COMP_STITCH, /* 12 */ + MT8195_MDP_COMP_FG0, /* 13 */ + MT8195_MDP_COMP_FG1, /* 14 */ + MT8195_MDP_COMP_FG2, /* 15 */ + MT8195_MDP_COMP_FG3, /* 16 */ + MT8195_MDP_COMP_TO_SVPP2MOUT, /* 17 */ + MT8195_MDP_COMP_TO_SVPP3MOUT, /* 18 */ + MT8195_MDP_COMP_TO_WARP0MOUT, /* 19 */ + MT8195_MDP_COMP_TO_WARP1MOUT, /* 20 */ + MT8195_MDP_COMP_VPP0_SOUT, /* 21 */ + MT8195_MDP_COMP_VPP1_SOUT, /* 22 */ + MT8195_MDP_COMP_PQ0_SOUT, /* 23 */ + MT8195_MDP_COMP_PQ1_SOUT, /* 24 */ + MT8195_MDP_COMP_HDR0, /* 25 */ + MT8195_MDP_COMP_HDR1, /* 26 */ + MT8195_MDP_COMP_HDR2, /* 27 */ + MT8195_MDP_COMP_HDR3, /* 28 */ + MT8195_MDP_COMP_AAL0, /* 29 */ + MT8195_MDP_COMP_AAL1, /* 30 */ + MT8195_MDP_COMP_AAL2, /* 31 */ + MT8195_MDP_COMP_AAL3, /* 32 */ + MT8195_MDP_COMP_RSZ0, /* 33 */ + MT8195_MDP_COMP_RSZ1, /* 34 */ + MT8195_MDP_COMP_RSZ2, /* 35 */ + MT8195_MDP_COMP_RSZ3, /* 36 */ + MT8195_MDP_COMP_TDSHP0, /* 37 */ + MT8195_MDP_COMP_TDSHP1, /* 38 */ + MT8195_MDP_COMP_TDSHP2, /* 39 */ + MT8195_MDP_COMP_TDSHP3, /* 40 */ + MT8195_MDP_COMP_COLOR0, /* 41 */ + MT8195_MDP_COMP_COLOR1, /* 42 */ + MT8195_MDP_COMP_COLOR2, /* 43 */ + MT8195_MDP_COMP_COLOR3, /* 44 */ + MT8195_MDP_COMP_OVL0, /* 45 */ + MT8195_MDP_COMP_OVL1, /* 46 */ + MT8195_MDP_COMP_PAD0, /* 47 */ + MT8195_MDP_COMP_PAD1, /* 48 */ + MT8195_MDP_COMP_PAD2, /* 49 */ + MT8195_MDP_COMP_PAD3, /* 50 */ + MT8195_MDP_COMP_TCC0, /* 51 */ + MT8195_MDP_COMP_TCC1, /* 52 */ + MT8195_MDP_COMP_WROT0, /* 53 */ + MT8195_MDP_COMP_WROT1, /* 54 */ + MT8195_MDP_COMP_WROT2, /* 55 */ + MT8195_MDP_COMP_WROT3, /* 56 */ + MT8195_MDP_COMP_MERGE2, /* 57 */ + MT8195_MDP_COMP_MERGE3, /* 58 */ + + MT8195_MDP_COMP_VDO0DL0, /* 59 */ + MT8195_MDP_COMP_VDO1DL0, /* 60 */ + MT8195_MDP_COMP_VDO0DL1, /* 61 */ + MT8195_MDP_COMP_VDO1DL1, /* 62 */ +}; + static const struct of_device_id mt8183_mdp_probe_infra[MDP_INFRA_MAX] = { [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8183-mmsys" }, [MDP_INFRA_MUTEX] = { .compatible = "mediatek,mt8183-disp-mutex" }, [MDP_INFRA_SCP] = { .compatible = "mediatek,mt8183-scp" } }; +static const struct of_device_id mt8195_mdp_probe_infra[MDP_INFRA_MAX] = { + [MDP_INFRA_MMSYS] = { .compatible = "mediatek,mt8195-vppsys0" }, + [MDP_INFRA_MMSYS2] = { .compatible = "mediatek,mt8195-vppsys1" }, + [MDP_INFRA_MUTEX] = { .compatible = "mediatek,mt8195-vpp-mutex" }, + [MDP_INFRA_MUTEX2] = { .compatible = "mediatek,mt8195-vpp-mutex" }, + [MDP_INFRA_SCP] = { .compatible = "mediatek,mt8195-scp" } +}; + static const struct mdp_platform_config mt8183_plat_cfg = { .rdma_support_10bit = true, .rdma_rsz1_sram_sharing = true, .rdma_upsample_repeat_only = true, + .rdma_event_num = 1, .rsz_disable_dcm_small_sample = false, .wrot_filter_constraint = false, + .wrot_event_num = 1, +}; + +static const struct mdp_platform_config mt8195_plat_cfg = { + .rdma_support_10bit = true, + .rdma_rsz1_sram_sharing = false, + .rdma_upsample_repeat_only = false, + .rdma_esl_setting = true, + .rdma_event_num = 4, + .rsz_disable_dcm_small_sample = false, + .rsz_etc_control = true, + .wrot_filter_constraint = false, + .wrot_event_num = 4, + .tdshp_hist_num = 17, + .tdshp_constrain = true, + .tdshp_contour = true, }; static const u32 mt8183_mutex_idx[MDP_MAX_COMP_COUNT] = { @@ -71,81 +167,384 @@ static const u32 mt8183_mutex_idx[MDP_MAX_COMP_COUNT] = { [MDP_COMP_CCORR0] = MUTEX_MOD_IDX_MDP_CCORR0, }; +static const u32 mt8195_mutex_idx[MDP_MAX_COMP_COUNT] = { + [MDP_COMP_RDMA0] = MUTEX_MOD_IDX_MDP_RDMA0, + [MDP_COMP_RDMA1] = MUTEX_MOD_IDX_MDP_RDMA1, + [MDP_COMP_RDMA2] = MUTEX_MOD_IDX_MDP_RDMA2, + [MDP_COMP_RDMA3] = MUTEX_MOD_IDX_MDP_RDMA3, + [MDP_COMP_STITCH] = MUTEX_MOD_IDX_MDP_STITCH0, + [MDP_COMP_FG0] = MUTEX_MOD_IDX_MDP_FG0, + [MDP_COMP_FG1] = MUTEX_MOD_IDX_MDP_FG1, + [MDP_COMP_FG2] = MUTEX_MOD_IDX_MDP_FG2, + [MDP_COMP_FG3] = MUTEX_MOD_IDX_MDP_FG3, + [MDP_COMP_HDR0] = MUTEX_MOD_IDX_MDP_HDR0, + [MDP_COMP_HDR1] = MUTEX_MOD_IDX_MDP_HDR1, + [MDP_COMP_HDR2] = MUTEX_MOD_IDX_MDP_HDR2, + [MDP_COMP_HDR3] = MUTEX_MOD_IDX_MDP_HDR3, + [MDP_COMP_AAL0] = MUTEX_MOD_IDX_MDP_AAL0, + [MDP_COMP_AAL1] = MUTEX_MOD_IDX_MDP_AAL1, + [MDP_COMP_AAL2] = MUTEX_MOD_IDX_MDP_AAL2, + [MDP_COMP_AAL3] = MUTEX_MOD_IDX_MDP_AAL3, + [MDP_COMP_RSZ0] = MUTEX_MOD_IDX_MDP_RSZ0, + [MDP_COMP_RSZ1] = MUTEX_MOD_IDX_MDP_RSZ1, + [MDP_COMP_RSZ2] = MUTEX_MOD_IDX_MDP_RSZ2, + [MDP_COMP_RSZ3] = MUTEX_MOD_IDX_MDP_RSZ3, + [MDP_COMP_MERGE2] = MUTEX_MOD_IDX_MDP_MERGE2, + [MDP_COMP_MERGE3] = MUTEX_MOD_IDX_MDP_MERGE3, + [MDP_COMP_TDSHP0] = MUTEX_MOD_IDX_MDP_TDSHP0, + [MDP_COMP_TDSHP1] = MUTEX_MOD_IDX_MDP_TDSHP1, + [MDP_COMP_TDSHP2] = MUTEX_MOD_IDX_MDP_TDSHP2, + [MDP_COMP_TDSHP3] = MUTEX_MOD_IDX_MDP_TDSHP3, + [MDP_COMP_COLOR0] = MUTEX_MOD_IDX_MDP_COLOR0, + [MDP_COMP_COLOR1] = MUTEX_MOD_IDX_MDP_COLOR1, + [MDP_COMP_COLOR2] = MUTEX_MOD_IDX_MDP_COLOR2, + [MDP_COMP_COLOR3] = MUTEX_MOD_IDX_MDP_COLOR3, + [MDP_COMP_OVL0] = MUTEX_MOD_IDX_MDP_OVL0, + [MDP_COMP_OVL1] = MUTEX_MOD_IDX_MDP_OVL1, + [MDP_COMP_PAD0] = MUTEX_MOD_IDX_MDP_PAD0, + [MDP_COMP_PAD1] = MUTEX_MOD_IDX_MDP_PAD1, + [MDP_COMP_PAD2] = MUTEX_MOD_IDX_MDP_PAD2, + [MDP_COMP_PAD3] = MUTEX_MOD_IDX_MDP_PAD3, + [MDP_COMP_TCC0] = MUTEX_MOD_IDX_MDP_TCC0, + [MDP_COMP_TCC1] = MUTEX_MOD_IDX_MDP_TCC1, + [MDP_COMP_WROT0] = MUTEX_MOD_IDX_MDP_WROT0, + [MDP_COMP_WROT1] = MUTEX_MOD_IDX_MDP_WROT1, + [MDP_COMP_WROT2] = MUTEX_MOD_IDX_MDP_WROT2, + [MDP_COMP_WROT3] = MUTEX_MOD_IDX_MDP_WROT3, +}; + static const struct mdp_comp_data mt8183_mdp_comp_data[MDP_MAX_COMP_COUNT] = { [MDP_COMP_WPEI] = { - {MDP_COMP_TYPE_WPEI, 0, MT8183_MDP_COMP_WPEI}, + {MDP_COMP_TYPE_WPEI, 0, MT8183_MDP_COMP_WPEI, MDP_MM_SUBSYS_0}, {0, 0, 0} }, [MDP_COMP_WPEO] = { - {MDP_COMP_TYPE_EXTO, 2, MT8183_MDP_COMP_WPEO}, + {MDP_COMP_TYPE_EXTO, 2, MT8183_MDP_COMP_WPEO, MDP_MM_SUBSYS_0}, {0, 0, 0} }, [MDP_COMP_WPEI2] = { - {MDP_COMP_TYPE_WPEI, 1, MT8183_MDP_COMP_WPEI2}, + {MDP_COMP_TYPE_WPEI, 1, MT8183_MDP_COMP_WPEI2, MDP_MM_SUBSYS_0}, {0, 0, 0} }, [MDP_COMP_WPEO2] = { - {MDP_COMP_TYPE_EXTO, 3, MT8183_MDP_COMP_WPEO2}, + {MDP_COMP_TYPE_EXTO, 3, MT8183_MDP_COMP_WPEO2, MDP_MM_SUBSYS_0}, {0, 0, 0} }, [MDP_COMP_ISP_IMGI] = { - {MDP_COMP_TYPE_IMGI, 0, MT8183_MDP_COMP_ISP_IMGI}, + {MDP_COMP_TYPE_IMGI, 0, MT8183_MDP_COMP_ISP_IMGI, MDP_MM_SUBSYS_0}, {0, 0, 4} }, [MDP_COMP_ISP_IMGO] = { - {MDP_COMP_TYPE_EXTO, 0, MT8183_MDP_COMP_ISP_IMGO}, + {MDP_COMP_TYPE_EXTO, 0, MT8183_MDP_COMP_ISP_IMGO, MDP_MM_SUBSYS_0}, {0, 0, 4} }, [MDP_COMP_ISP_IMG2O] = { - {MDP_COMP_TYPE_EXTO, 1, MT8183_MDP_COMP_ISP_IMG2O}, + {MDP_COMP_TYPE_EXTO, 1, MT8183_MDP_COMP_ISP_IMG2O, MDP_MM_SUBSYS_0}, {0, 0, 0} }, [MDP_COMP_CAMIN] = { - {MDP_COMP_TYPE_DL_PATH, 0, MT8183_MDP_COMP_CAMIN}, + {MDP_COMP_TYPE_DL_PATH, 0, MT8183_MDP_COMP_CAMIN, MDP_MM_SUBSYS_0}, {2, 2, 1} }, [MDP_COMP_CAMIN2] = { - {MDP_COMP_TYPE_DL_PATH, 1, MT8183_MDP_COMP_CAMIN2}, + {MDP_COMP_TYPE_DL_PATH, 1, MT8183_MDP_COMP_CAMIN2, MDP_MM_SUBSYS_0}, {2, 4, 1} }, [MDP_COMP_RDMA0] = { - {MDP_COMP_TYPE_RDMA, 0, MT8183_MDP_COMP_RDMA0}, + {MDP_COMP_TYPE_RDMA, 0, MT8183_MDP_COMP_RDMA0, MDP_MM_SUBSYS_0}, {2, 0, 0} }, [MDP_COMP_CCORR0] = { - {MDP_COMP_TYPE_CCORR, 0, MT8183_MDP_COMP_CCORR0}, + {MDP_COMP_TYPE_CCORR, 0, MT8183_MDP_COMP_CCORR0, MDP_MM_SUBSYS_0}, {1, 0, 0} }, [MDP_COMP_RSZ0] = { - {MDP_COMP_TYPE_RSZ, 0, MT8183_MDP_COMP_RSZ0}, + {MDP_COMP_TYPE_RSZ, 0, MT8183_MDP_COMP_RSZ0, MDP_MM_SUBSYS_0}, {1, 0, 0} }, [MDP_COMP_RSZ1] = { - {MDP_COMP_TYPE_RSZ, 1, MT8183_MDP_COMP_RSZ1}, + {MDP_COMP_TYPE_RSZ, 1, MT8183_MDP_COMP_RSZ1, MDP_MM_SUBSYS_0}, {1, 0, 0} }, [MDP_COMP_TDSHP0] = { - {MDP_COMP_TYPE_TDSHP, 0, MT8183_MDP_COMP_TDSHP0}, + {MDP_COMP_TYPE_TDSHP, 0, MT8183_MDP_COMP_TDSHP0, MDP_MM_SUBSYS_0}, {0, 0, 0} }, [MDP_COMP_PATH0_SOUT] = { - {MDP_COMP_TYPE_PATH, 0, MT8183_MDP_COMP_PATH0_SOUT}, + {MDP_COMP_TYPE_PATH, 0, MT8183_MDP_COMP_PATH0_SOUT, MDP_MM_SUBSYS_0}, {0, 0, 0} }, [MDP_COMP_PATH1_SOUT] = { - {MDP_COMP_TYPE_PATH, 1, MT8183_MDP_COMP_PATH1_SOUT}, + {MDP_COMP_TYPE_PATH, 1, MT8183_MDP_COMP_PATH1_SOUT, MDP_MM_SUBSYS_0}, {0, 0, 0} }, [MDP_COMP_WROT0] = { - {MDP_COMP_TYPE_WROT, 0, MT8183_MDP_COMP_WROT0}, + {MDP_COMP_TYPE_WROT, 0, MT8183_MDP_COMP_WROT0, MDP_MM_SUBSYS_0}, {1, 0, 0} }, [MDP_COMP_WDMA] = { - {MDP_COMP_TYPE_WDMA, 0, MT8183_MDP_COMP_WDMA}, + {MDP_COMP_TYPE_WDMA, 0, MT8183_MDP_COMP_WDMA, MDP_MM_SUBSYS_0}, {1, 0, 0} }, }; +static const struct mdp_comp_data mt8195_mdp_comp_data[MDP_MAX_COMP_COUNT] = { + [MDP_COMP_WPEI] = { + {MDP_COMP_TYPE_WPEI, 0, MT8195_MDP_COMP_WPEI, MDP_MM_SUBSYS_0}, + {0, 0, 0} + }, + [MDP_COMP_WPEO] = { + {MDP_COMP_TYPE_EXTO, 2, MT8195_MDP_COMP_WPEO, MDP_MM_SUBSYS_0}, + {0, 0, 0} + }, + [MDP_COMP_WPEI2] = { + {MDP_COMP_TYPE_WPEI, 1, MT8195_MDP_COMP_WPEI2, MDP_MM_SUBSYS_0}, + {0, 0, 0} + }, + [MDP_COMP_WPEO2] = { + {MDP_COMP_TYPE_EXTO, 3, MT8195_MDP_COMP_WPEO2, MDP_MM_SUBSYS_0}, + {0, 0, 0} + }, + [MDP_COMP_CAMIN] = { + {MDP_COMP_TYPE_DL_PATH, 0, MT8195_MDP_COMP_CAMIN, MDP_MM_SUBSYS_0}, + {3, 3, 0} + }, + [MDP_COMP_CAMIN2] = { + {MDP_COMP_TYPE_DL_PATH, 1, MT8195_MDP_COMP_CAMIN2, MDP_MM_SUBSYS_0}, + {3, 6, 0} + }, + [MDP_COMP_SPLIT] = { + {MDP_COMP_TYPE_SPLIT, 0, MT8195_MDP_COMP_SPLIT, MDP_MM_SUBSYS_1}, + {7, 0, 0} + }, + [MDP_COMP_SPLIT2] = { + {MDP_COMP_TYPE_SPLIT, 1, MT8195_MDP_COMP_SPLIT2, MDP_MM_SUBSYS_1}, + {7, 0, 0} + }, + [MDP_COMP_RDMA0] = { + {MDP_COMP_TYPE_RDMA, 0, MT8195_MDP_COMP_RDMA0, MDP_MM_SUBSYS_0}, + {3, 0, 0} + }, + [MDP_COMP_RDMA1] = { + {MDP_COMP_TYPE_RDMA, 1, MT8195_MDP_COMP_RDMA1, MDP_MM_SUBSYS_1}, + {3, 0, 0} + }, + [MDP_COMP_RDMA2] = { + {MDP_COMP_TYPE_RDMA, 2, MT8195_MDP_COMP_RDMA2, MDP_MM_SUBSYS_1}, + {3, 0, 0} + }, + [MDP_COMP_RDMA3] = { + {MDP_COMP_TYPE_RDMA, 3, MT8195_MDP_COMP_RDMA3, MDP_MM_SUBSYS_1}, + {3, 0, 0} + }, + [MDP_COMP_STITCH] = { + {MDP_COMP_TYPE_STITCH, 0, MT8195_MDP_COMP_STITCH, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_FG0] = { + {MDP_COMP_TYPE_FG, 0, MT8195_MDP_COMP_FG0, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_FG1] = { + {MDP_COMP_TYPE_FG, 1, MT8195_MDP_COMP_FG1, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_FG2] = { + {MDP_COMP_TYPE_FG, 2, MT8195_MDP_COMP_FG2, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_FG3] = { + {MDP_COMP_TYPE_FG, 3, MT8195_MDP_COMP_FG3, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_HDR0] = { + {MDP_COMP_TYPE_HDR, 0, MT8195_MDP_COMP_HDR0, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_HDR1] = { + {MDP_COMP_TYPE_HDR, 1, MT8195_MDP_COMP_HDR1, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_HDR2] = { + {MDP_COMP_TYPE_HDR, 2, MT8195_MDP_COMP_HDR2, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_HDR3] = { + {MDP_COMP_TYPE_HDR, 3, MT8195_MDP_COMP_HDR3, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_AAL0] = { + {MDP_COMP_TYPE_AAL, 0, MT8195_MDP_COMP_AAL0, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_AAL1] = { + {MDP_COMP_TYPE_AAL, 1, MT8195_MDP_COMP_AAL1, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_AAL2] = { + {MDP_COMP_TYPE_AAL, 2, MT8195_MDP_COMP_AAL2, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_AAL3] = { + {MDP_COMP_TYPE_AAL, 3, MT8195_MDP_COMP_AAL3, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_RSZ0] = { + {MDP_COMP_TYPE_RSZ, 0, MT8195_MDP_COMP_RSZ0, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_RSZ1] = { + {MDP_COMP_TYPE_RSZ, 1, MT8195_MDP_COMP_RSZ1, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_RSZ2] = { + {MDP_COMP_TYPE_RSZ, 2, MT8195_MDP_COMP_RSZ2, MDP_MM_SUBSYS_1}, + {2, 0, 0}, + {MDP_COMP_MERGE2, true, true} + }, + [MDP_COMP_RSZ3] = { + {MDP_COMP_TYPE_RSZ, 3, MT8195_MDP_COMP_RSZ3, MDP_MM_SUBSYS_1}, + {2, 0, 0}, + {MDP_COMP_MERGE3, true, true} + }, + [MDP_COMP_TDSHP0] = { + {MDP_COMP_TYPE_TDSHP, 0, MT8195_MDP_COMP_TDSHP0, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_TDSHP1] = { + {MDP_COMP_TYPE_TDSHP, 1, MT8195_MDP_COMP_TDSHP1, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_TDSHP2] = { + {MDP_COMP_TYPE_TDSHP, 2, MT8195_MDP_COMP_TDSHP2, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_TDSHP3] = { + {MDP_COMP_TYPE_TDSHP, 3, MT8195_MDP_COMP_TDSHP3, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_COLOR0] = { + {MDP_COMP_TYPE_COLOR, 0, MT8195_MDP_COMP_COLOR0, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_COLOR1] = { + {MDP_COMP_TYPE_COLOR, 1, MT8195_MDP_COMP_COLOR1, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_COLOR2] = { + {MDP_COMP_TYPE_COLOR, 2, MT8195_MDP_COMP_COLOR2, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_COLOR3] = { + {MDP_COMP_TYPE_COLOR, 3, MT8195_MDP_COMP_COLOR3, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_OVL0] = { + {MDP_COMP_TYPE_OVL, 0, MT8195_MDP_COMP_OVL0, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_OVL1] = { + {MDP_COMP_TYPE_OVL, 1, MT8195_MDP_COMP_OVL1, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_PAD0] = { + {MDP_COMP_TYPE_PAD, 0, MT8195_MDP_COMP_PAD0, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_PAD1] = { + {MDP_COMP_TYPE_PAD, 1, MT8195_MDP_COMP_PAD1, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_PAD2] = { + {MDP_COMP_TYPE_PAD, 2, MT8195_MDP_COMP_PAD2, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_PAD3] = { + {MDP_COMP_TYPE_PAD, 3, MT8195_MDP_COMP_PAD3, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_TCC0] = { + {MDP_COMP_TYPE_TCC, 0, MT8195_MDP_COMP_TCC0, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_TCC1] = { + {MDP_COMP_TYPE_TCC, 1, MT8195_MDP_COMP_TCC1, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_WROT0] = { + {MDP_COMP_TYPE_WROT, 0, MT8195_MDP_COMP_WROT0, MDP_MM_SUBSYS_0}, + {1, 0, 0} + }, + [MDP_COMP_WROT1] = { + {MDP_COMP_TYPE_WROT, 1, MT8195_MDP_COMP_WROT1, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_WROT2] = { + {MDP_COMP_TYPE_WROT, 2, MT8195_MDP_COMP_WROT2, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_WROT3] = { + {MDP_COMP_TYPE_WROT, 3, MT8195_MDP_COMP_WROT3, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_MERGE2] = { + {MDP_COMP_TYPE_MERGE, 0, MT8195_MDP_COMP_MERGE2, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_MERGE3] = { + {MDP_COMP_TYPE_MERGE, 1, MT8195_MDP_COMP_MERGE3, MDP_MM_SUBSYS_1}, + {1, 0, 0} + }, + [MDP_COMP_PQ0_SOUT] = { + {MDP_COMP_TYPE_DUMMY, 0, MT8195_MDP_COMP_PQ0_SOUT, MDP_MM_SUBSYS_0}, + {0, 0, 0} + }, + [MDP_COMP_PQ1_SOUT] = { + {MDP_COMP_TYPE_DUMMY, 1, MT8195_MDP_COMP_PQ1_SOUT, MDP_MM_SUBSYS_1}, + {0, 0, 0} + }, + [MDP_COMP_TO_WARP0MOUT] = { + {MDP_COMP_TYPE_DUMMY, 2, MT8195_MDP_COMP_TO_WARP0MOUT, MDP_MM_SUBSYS_0}, + {0, 0, 0} + }, + [MDP_COMP_TO_WARP1MOUT] = { + {MDP_COMP_TYPE_DUMMY, 3, MT8195_MDP_COMP_TO_WARP1MOUT, MDP_MM_SUBSYS_0}, + {0, 0, 0} + }, + [MDP_COMP_TO_SVPP2MOUT] = { + {MDP_COMP_TYPE_DUMMY, 4, MT8195_MDP_COMP_TO_SVPP2MOUT, MDP_MM_SUBSYS_1}, + {0, 0, 0} + }, + [MDP_COMP_TO_SVPP3MOUT] = { + {MDP_COMP_TYPE_DUMMY, 5, MT8195_MDP_COMP_TO_SVPP3MOUT, MDP_MM_SUBSYS_1}, + {0, 0, 0} + }, + [MDP_COMP_VPP0_SOUT] = { + {MDP_COMP_TYPE_PATH, 0, MT8195_MDP_COMP_VPP0_SOUT, MDP_MM_SUBSYS_1}, + {4, 9, 0} + }, + [MDP_COMP_VPP1_SOUT] = { + {MDP_COMP_TYPE_PATH, 1, MT8195_MDP_COMP_VPP1_SOUT, MDP_MM_SUBSYS_0}, + {2, 13, 0} + }, + [MDP_COMP_VDO0DL0] = { + {MDP_COMP_TYPE_DL_PATH, 0, MT8195_MDP_COMP_VDO0DL0, MDP_MM_SUBSYS_1}, + {1, 15, 0} + }, + [MDP_COMP_VDO1DL0] = { + {MDP_COMP_TYPE_DL_PATH, 0, MT8195_MDP_COMP_VDO1DL0, MDP_MM_SUBSYS_1}, + {1, 17, 0} + }, + [MDP_COMP_VDO0DL1] = { + {MDP_COMP_TYPE_DL_PATH, 0, MT8195_MDP_COMP_VDO0DL1, MDP_MM_SUBSYS_1}, + {1, 18, 0} + }, + [MDP_COMP_VDO1DL1] = { + {MDP_COMP_TYPE_DL_PATH, 0, MT8195_MDP_COMP_VDO1DL1, MDP_MM_SUBSYS_1}, + {1, 16, 0} + }, +}; + static const struct of_device_id mt8183_sub_comp_dt_ids[] = { { .compatible = "mediatek,mt8183-mdp3-wdma", @@ -157,6 +556,10 @@ static const struct of_device_id mt8183_sub_comp_dt_ids[] = { {} }; +static const struct of_device_id mt8195_sub_comp_dt_ids[] = { + {} +}; + /* * All 10-bit related formats are not added in the basic format list, * please add the corresponding format settings before use. @@ -382,6 +785,222 @@ static const struct mdp_format mt8183_formats[] = { } }; +static const struct mdp_format mt8195_formats[] = { + { + .pixelformat = V4L2_PIX_FMT_GREY, + .mdp_color = MDP_COLOR_GREY, + .depth = { 8 }, + .row_depth = { 8 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_RGB565X, + .mdp_color = MDP_COLOR_BGR565, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_RGB565, + .mdp_color = MDP_COLOR_RGB565, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_RGB24, + .mdp_color = MDP_COLOR_RGB888, + .depth = { 24 }, + .row_depth = { 24 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_BGR24, + .mdp_color = MDP_COLOR_BGR888, + .depth = { 24 }, + .row_depth = { 24 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_ABGR32, + .mdp_color = MDP_COLOR_BGRA8888, + .depth = { 32 }, + .row_depth = { 32 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_ARGB32, + .mdp_color = MDP_COLOR_ARGB8888, + .depth = { 32 }, + .row_depth = { 32 }, + .num_planes = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_UYVY, + .mdp_color = MDP_COLOR_UYVY, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_VYUY, + .mdp_color = MDP_COLOR_VYUY, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YUYV, + .mdp_color = MDP_COLOR_YUYV, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YVYU, + .mdp_color = MDP_COLOR_YVYU, + .depth = { 16 }, + .row_depth = { 16 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YUV420, + .mdp_color = MDP_COLOR_I420, + .depth = { 12 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YVU420, + .mdp_color = MDP_COLOR_YV12, + .depth = { 12 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV12, + .mdp_color = MDP_COLOR_NV12, + .depth = { 12 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV21, + .mdp_color = MDP_COLOR_NV21, + .depth = { 12 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV16, + .mdp_color = MDP_COLOR_NV16, + .depth = { 16 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV61, + .mdp_color = MDP_COLOR_NV61, + .depth = { 16 }, + .row_depth = { 8 }, + .num_planes = 1, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV12M, + .mdp_color = MDP_COLOR_NV12, + .depth = { 8, 4 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_MM21, + .mdp_color = MDP_COLOR_420_BLK, + .depth = { 8, 4 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 6, + .halign = 6, + .flags = MDP_FMT_FLAG_OUTPUT, + }, { + .pixelformat = V4L2_PIX_FMT_NV21M, + .mdp_color = MDP_COLOR_NV21, + .depth = { 8, 4 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV16M, + .mdp_color = MDP_COLOR_NV16, + .depth = { 8, 8 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_NV61M, + .mdp_color = MDP_COLOR_NV61, + .depth = { 8, 8 }, + .row_depth = { 8, 8 }, + .num_planes = 2, + .walign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YUV420M, + .mdp_color = MDP_COLOR_I420, + .depth = { 8, 2, 2 }, + .row_depth = { 8, 4, 4 }, + .num_planes = 3, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YVU420M, + .mdp_color = MDP_COLOR_YV12, + .depth = { 8, 2, 2 }, + .row_depth = { 8, 4, 4 }, + .num_planes = 3, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YUV422M, + .mdp_color = MDP_COLOR_I422, + .depth = { 8, 4, 4 }, + .row_depth = { 8, 4, 4 }, + .num_planes = 3, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + }, { + .pixelformat = V4L2_PIX_FMT_YVU422M, + .mdp_color = MDP_COLOR_YV16, + .depth = { 8, 4, 4 }, + .row_depth = { 8, 4, 4 }, + .num_planes = 3, + .walign = 1, + .halign = 1, + .flags = MDP_FMT_FLAG_OUTPUT | MDP_FMT_FLAG_CAPTURE, + } +}; + static const struct mdp_limit mt8183_mdp_def_limit = { .out_limit = { .wmin = 16, @@ -401,15 +1020,54 @@ static const struct mdp_limit mt8183_mdp_def_limit = { .v_scale_down_max = 128, }; +static const struct mdp_limit mt8195_mdp_def_limit = { + .out_limit = { + .wmin = 64, + .hmin = 64, + .wmax = 8192, + .hmax = 8192, + }, + .cap_limit = { + .wmin = 64, + .hmin = 64, + .wmax = 8192, + .hmax = 8192, + }, + .h_scale_up_max = 64, + .v_scale_up_max = 64, + .h_scale_down_max = 128, + .v_scale_down_max = 128, +}; + static const struct mdp_pipe_info mt8183_pipe_info[] = { - [MDP_PIPE_WPEI] = {MDP_PIPE_WPEI, 0}, - [MDP_PIPE_WPEI2] = {MDP_PIPE_WPEI2, 1}, - [MDP_PIPE_IMGI] = {MDP_PIPE_IMGI, 2}, - [MDP_PIPE_RDMA0] = {MDP_PIPE_RDMA0, 3} + [MDP_PIPE_WPEI] = {MDP_PIPE_WPEI, MDP_MM_SUBSYS_0, 0}, + [MDP_PIPE_WPEI2] = {MDP_PIPE_WPEI2, MDP_MM_SUBSYS_0, 1}, + [MDP_PIPE_IMGI] = {MDP_PIPE_IMGI, MDP_MM_SUBSYS_0, 2}, + [MDP_PIPE_RDMA0] = {MDP_PIPE_RDMA0, MDP_MM_SUBSYS_0, 3} +}; + +static const struct mdp_pipe_info mt8195_pipe_info[] = { + [MDP_PIPE_WPEI] = {MDP_PIPE_WPEI, MDP_MM_SUBSYS_0, 0}, + [MDP_PIPE_WPEI2] = {MDP_PIPE_WPEI2, MDP_MM_SUBSYS_0, 1}, + [MDP_PIPE_IMGI] = {MDP_PIPE_IMGI, MDP_MM_SUBSYS_0, 2}, + [MDP_PIPE_RDMA0] = {MDP_PIPE_RDMA0, MDP_MM_SUBSYS_0, 3}, + [MDP_PIPE_RDMA1] = {MDP_PIPE_RDMA1, MDP_MM_SUBSYS_1, 0}, + [MDP_PIPE_RDMA2] = {MDP_PIPE_RDMA2, MDP_MM_SUBSYS_1, 1}, + [MDP_PIPE_RDMA3] = {MDP_PIPE_RDMA3, MDP_MM_SUBSYS_1, 2}, + [MDP_PIPE_SPLIT] = {MDP_PIPE_SPLIT, MDP_MM_SUBSYS_1, 3}, + [MDP_PIPE_SPLIT2] = {MDP_PIPE_SPLIT2, MDP_MM_SUBSYS_1, 4}, + [MDP_PIPE_VPP1_SOUT] = {MDP_PIPE_VPP1_SOUT, MDP_MM_SUBSYS_0, 4}, + [MDP_PIPE_VPP0_SOUT] = {MDP_PIPE_VPP0_SOUT, MDP_MM_SUBSYS_1, 5}, +}; + +static const struct v4l2_rect mt8195_mdp_pp_criteria = { + .width = 1920, + .height = 1080, }; const struct mtk_mdp_driver_data mt8183_mdp_driver_data = { .mdp_plat_id = MT8183, + .mdp_con_res = 0x14001000, .mdp_probe_infra = mt8183_mdp_probe_infra, .mdp_cfg = &mt8183_plat_cfg, .mdp_mutex_table_idx = mt8183_mutex_idx, @@ -421,6 +1079,25 @@ const struct mtk_mdp_driver_data mt8183_mdp_driver_data = { .def_limit = &mt8183_mdp_def_limit, .pipe_info = mt8183_pipe_info, .pipe_info_len = ARRAY_SIZE(mt8183_pipe_info), + .pp_used = MDP_PP_USED_1, +}; + +const struct mtk_mdp_driver_data mt8195_mdp_driver_data = { + .mdp_plat_id = MT8195, + .mdp_con_res = 0x14001000, + .mdp_probe_infra = mt8195_mdp_probe_infra, + .mdp_sub_comp_dt_ids = mt8195_sub_comp_dt_ids, + .mdp_cfg = &mt8195_plat_cfg, + .mdp_mutex_table_idx = mt8195_mutex_idx, + .comp_data = mt8195_mdp_comp_data, + .comp_data_len = ARRAY_SIZE(mt8195_mdp_comp_data), + .format = mt8195_formats, + .format_len = ARRAY_SIZE(mt8195_formats), + .def_limit = &mt8195_mdp_def_limit, + .pipe_info = mt8195_pipe_info, + .pipe_info_len = ARRAY_SIZE(mt8195_pipe_info), + .pp_criteria = &mt8195_mdp_pp_criteria, + .pp_used = MDP_PP_USED_2, }; s32 mdp_cfg_get_id_inner(struct mdp_dev *mdp_dev, enum mtk_mdp_comp_id id) @@ -451,3 +1128,11 @@ enum mtk_mdp_comp_id mdp_cfg_get_id_public(struct mdp_dev *mdp_dev, s32 inner_id err_public_id: return public_id; } + +bool mdp_cfg_comp_is_dummy(struct mdp_dev *mdp_dev, s32 inner_id) +{ + enum mtk_mdp_comp_id id = mdp_cfg_get_id_public(mdp_dev, inner_id); + enum mdp_comp_type type = mdp_dev->mdp_data->comp_data[id].match.type; + + return (type == MDP_COMP_TYPE_DUMMY); +} diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_aal.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_aal.h new file mode 100644 index 0000000000..4b9513e545 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_aal.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu + */ + +#ifndef __MDP_REG_AAL_H__ +#define __MDP_REG_AAL_H__ + +#define MDP_AAL_EN (0x000) +#define MDP_AAL_CFG (0x020) +#define MDP_AAL_SIZE (0x030) +#define MDP_AAL_OUTPUT_SIZE (0x034) +#define MDP_AAL_OUTPUT_OFFSET (0x038) +#define MDP_AAL_CFG_MAIN (0x200) + +/* MASK */ +#define MDP_AAL_EN_MASK (0x01) +#define MDP_AAL_CFG_MASK (0x70FF00B3) +#define MDP_AAL_SIZE_MASK (0x1FFF1FFF) +#define MDP_AAL_OUTPUT_SIZE_MASK (0x1FFF1FFF) +#define MDP_AAL_OUTPUT_OFFSET_MASK (0x0FF00FF) +#define MDP_AAL_CFG_MAIN_MASK (0x0FE) + +#endif // __MDP_REG_AAL_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_color.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_color.h new file mode 100644 index 0000000000..f72503975b --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_color.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu + */ + +#ifndef __MDP_REG_COLOR_H__ +#define __MDP_REG_COLOR_H__ + +#define MDP_COLOR_WIN_X_MAIN (0x40C) +#define MDP_COLOR_WIN_Y_MAIN (0x410) +#define MDP_COLOR_START (0xC00) +#define MDP_COLOR_INTEN (0xC04) +#define MDP_COLOR_OUT_SEL (0xC0C) +#define MDP_COLOR_INTERNAL_IP_WIDTH (0xC50) +#define MDP_COLOR_INTERNAL_IP_HEIGHT (0xC54) +#define MDP_COLOR_CM1_EN (0xC60) +#define MDP_COLOR_CM2_EN (0xCA0) + +/* MASK */ +#define MDP_COLOR_WIN_X_MAIN_MASK (0xFFFFFFFF) +#define MDP_COLOR_WIN_Y_MAIN_MASK (0xFFFFFFFF) +#define MDP_COLOR_START_MASK (0x0FF013F) +#define MDP_COLOR_INTEN_MASK (0x07) +#define MDP_COLOR_OUT_SEL_MASK (0x0777) +#define MDP_COLOR_INTERNAL_IP_WIDTH_MASK (0x03FFF) +#define MDP_COLOR_INTERNAL_IP_HEIGHT_MASK (0x03FFF) +#define MDP_COLOR_CM1_EN_MASK (0x03) +#define MDP_COLOR_CM2_EN_MASK (0x017) + +#endif // __MDP_REG_COLOR_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_fg.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_fg.h new file mode 100644 index 0000000000..d90bcad33a --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_fg.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu + */ + +#ifndef __MDP_REG_FG_H__ +#define __MDP_REG_FG_H__ + +#define MDP_FG_TRIGGER (0x0) +#define MDP_FG_FG_CTRL_0 (0x20) +#define MDP_FG_FG_CK_EN (0x24) +#define MDP_FG_TILE_INFO_0 (0x418) +#define MDP_FG_TILE_INFO_1 (0x41c) + +/* MASK */ +#define MDP_FG_TRIGGER_MASK (0x00000007) +#define MDP_FG_FG_CTRL_0_MASK (0x00000033) +#define MDP_FG_FG_CK_EN_MASK (0x0000000F) +#define MDP_FG_TILE_INFO_0_MASK (0xFFFFFFFF) +#define MDP_FG_TILE_INFO_1_MASK (0xFFFFFFFF) + +#endif //__MDP_REG_FG_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_hdr.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_hdr.h new file mode 100644 index 0000000000..c19fbba39f --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_hdr.h @@ -0,0 +1,31 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu + */ + +#ifndef __MDP_REG_HDR_H__ +#define __MDP_REG_HDR_H__ + +#define MDP_HDR_TOP (0x000) +#define MDP_HDR_RELAY (0x004) +#define MDP_HDR_SIZE_0 (0x014) +#define MDP_HDR_SIZE_1 (0x018) +#define MDP_HDR_SIZE_2 (0x01C) +#define MDP_HDR_HIST_CTRL_0 (0x020) +#define MDP_HDR_HIST_CTRL_1 (0x024) +#define MDP_HDR_HIST_ADDR (0x0DC) +#define MDP_HDR_TILE_POS (0x118) + +/* MASK */ +#define MDP_HDR_RELAY_MASK (0x01) +#define MDP_HDR_TOP_MASK (0xFF0FEB6D) +#define MDP_HDR_SIZE_0_MASK (0x1FFF1FFF) +#define MDP_HDR_SIZE_1_MASK (0x1FFF1FFF) +#define MDP_HDR_SIZE_2_MASK (0x1FFF1FFF) +#define MDP_HDR_HIST_CTRL_0_MASK (0x1FFF1FFF) +#define MDP_HDR_HIST_CTRL_1_MASK (0x1FFF1FFF) +#define MDP_HDR_HIST_ADDR_MASK (0xBF3F2F3F) +#define MDP_HDR_TILE_POS_MASK (0x1FFF1FFF) + +#endif // __MDP_REG_HDR_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_merge.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_merge.h new file mode 100644 index 0000000000..46be27e2a6 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_merge.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu + */ + +#ifndef __MDP_REG_MERGE_H__ +#define __MDP_REG_MERGE_H__ + +#define MDP_MERGE_ENABLE (0x000) +#define MDP_MERGE_CFG_0 (0x010) +#define MDP_MERGE_CFG_4 (0x020) +#define MDP_MERGE_CFG_12 (0x040) +#define MDP_MERGE_CFG_24 (0x070) +#define MDP_MERGE_CFG_25 (0x074) + +/* MASK */ +#define MDP_MERGE_ENABLE_MASK (0xFFFFFFFF) +#define MDP_MERGE_CFG_0_MASK (0xFFFFFFFF) +#define MDP_MERGE_CFG_4_MASK (0xFFFFFFFF) +#define MDP_MERGE_CFG_12_MASK (0xFFFFFFFF) +#define MDP_MERGE_CFG_24_MASK (0xFFFFFFFF) +#define MDP_MERGE_CFG_25_MASK (0xFFFFFFFF) + +#endif //__MDP_REG_MERGE_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_ovl.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_ovl.h new file mode 100644 index 0000000000..21d2d03232 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_ovl.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu + */ + +#ifndef __MDP_REG_OVL_H__ +#define __MDP_REG_OVL_H__ + +#define MDP_OVL_EN (0x00c) +#define MDP_OVL_ROI_SIZE (0x020) +#define MDP_OVL_DP_CON (0x024) +#define MDP_OVL_SRC_CON (0x02c) +#define MDP_OVL_L0_CON (0x030) +#define MDP_OVL_L0_SRC_SIZE (0x038) + +/* MASK */ +#define MDP_OVL_DP_CON_MASK (0x0FFFFFFF) +#define MDP_OVL_EN_MASK (0xB07D07B1) +#define MDP_OVL_L0_CON_MASK (0xFFFFFFFF) +#define MDP_OVL_L0_SRC_SIZE_MASK (0x1FFF1FFF) +#define MDP_OVL_ROI_SIZE_MASK (0x1FFF1FFF) +#define MDP_OVL_SRC_CON_MASK (0x0000031F) + +#endif //__MDP_REG_OVL_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_pad.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_pad.h new file mode 100644 index 0000000000..0e89f1db19 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_pad.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu + */ + +#ifndef __MDP_REG_PAD_H__ +#define __MDP_REG_PAD_H__ + +#define MDP_PAD_CON (0x000) +#define MDP_PAD_PIC_SIZE (0x004) +#define MDP_PAD_W_SIZE (0x008) +#define MDP_PAD_H_SIZE (0x00c) + +/* MASK */ +#define MDP_PAD_CON_MASK (0x00000007) +#define MDP_PAD_PIC_SIZE_MASK (0xFFFFFFFF) +#define MDP_PAD_W_SIZE_MASK (0x1FFF1FFF) +#define MDP_PAD_H_SIZE_MASK (0x1FFF1FFF) + +#endif // __MDP_REG_PAD_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_rdma.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_rdma.h index be4065e252..0affb2a3b9 100644 --- a/drivers/media/platform/mediatek/mdp3/mdp_reg_rdma.h +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_rdma.h @@ -26,6 +26,18 @@ #define MDP_RDMA_SRC_OFFSET_2 0x128 #define MDP_RDMA_SRC_OFFSET_0_P 0x148 #define MDP_RDMA_TRANSFORM_0 0x200 +#define MDP_RDMA_DMABUF_CON_0 0x240 +#define MDP_RDMA_ULTRA_TH_HIGH_CON_0 0x248 +#define MDP_RDMA_ULTRA_TH_LOW_CON_0 0x250 +#define MDP_RDMA_DMABUF_CON_1 0x258 +#define MDP_RDMA_ULTRA_TH_HIGH_CON_1 0x260 +#define MDP_RDMA_ULTRA_TH_LOW_CON_1 0x268 +#define MDP_RDMA_DMABUF_CON_2 0x270 +#define MDP_RDMA_ULTRA_TH_HIGH_CON_2 0x278 +#define MDP_RDMA_ULTRA_TH_LOW_CON_2 0x280 +#define MDP_RDMA_DMABUF_CON_3 0x288 +#define MDP_RDMA_ULTRA_TH_HIGH_CON_3 0x290 +#define MDP_RDMA_ULTRA_TH_LOW_CON_3 0x298 #define MDP_RDMA_RESV_DUMMY_0 0x2a0 #define MDP_RDMA_MON_STA_1 0x408 #define MDP_RDMA_SRC_BASE_0 0xf00 @@ -54,6 +66,18 @@ #define MDP_RDMA_SRC_OFFSET_2_MASK 0xffffffff #define MDP_RDMA_SRC_OFFSET_0_P_MASK 0xffffffff #define MDP_RDMA_TRANSFORM_0_MASK 0xff110777 +#define MDP_RDMA_DMABUF_CON_0_MASK 0x0fff00ff +#define MDP_RDMA_ULTRA_TH_HIGH_CON_0_MASK 0x3fffffff +#define MDP_RDMA_ULTRA_TH_LOW_CON_0_MASK 0x3fffffff +#define MDP_RDMA_DMABUF_CON_1_MASK 0x0f7f007f +#define MDP_RDMA_ULTRA_TH_HIGH_CON_1_MASK 0x3fffffff +#define MDP_RDMA_ULTRA_TH_LOW_CON_1_MASK 0x3fffffff +#define MDP_RDMA_DMABUF_CON_2_MASK 0x0f3f003f +#define MDP_RDMA_ULTRA_TH_HIGH_CON_2_MASK 0x3fffffff +#define MDP_RDMA_ULTRA_TH_LOW_CON_2_MASK 0x3fffffff +#define MDP_RDMA_DMABUF_CON_3_MASK 0x0f3f003f +#define MDP_RDMA_ULTRA_TH_HIGH_CON_3_MASK 0x3fffffff +#define MDP_RDMA_ULTRA_TH_LOW_CON_3_MASK 0x3fffffff #define MDP_RDMA_RESV_DUMMY_0_MASK 0xffffffff #define MDP_RDMA_MON_STA_1_MASK 0xffffffff #define MDP_RDMA_SRC_BASE_0_MASK 0xffffffff diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_rsz.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_rsz.h index 484f6d6064..187531db8e 100644 --- a/drivers/media/platform/mediatek/mdp3/mdp_reg_rsz.h +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_rsz.h @@ -20,6 +20,7 @@ #define PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET 0x02c #define PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET 0x030 #define PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET 0x034 +#define RSZ_ETC_CONTROL 0x22c /* MASK */ #define PRZ_ENABLE_MASK 0x00010001 @@ -35,5 +36,6 @@ #define PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET_MASK 0x001fffff #define PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET_MASK 0x0000ffff #define PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET_MASK 0x001fffff +#define RSZ_ETC_CONTROL_MASK 0xff770000 #endif // __MDP_REG_RSZ_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_tdshp.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_tdshp.h new file mode 100644 index 0000000000..83b5f9b432 --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_tdshp.h @@ -0,0 +1,34 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2022 MediaTek Inc. + * Author: Ping-Hsun Wu + */ + +#ifndef __MDP_REG_TDSHP_H__ +#define __MDP_REG_TDSHP_H__ + +#define MDP_HIST_CFG_00 (0x064) +#define MDP_HIST_CFG_01 (0x068) +#define MDP_TDSHP_CTRL (0x100) +#define MDP_TDSHP_CFG (0x110) +#define MDP_TDSHP_INPUT_SIZE (0x120) +#define MDP_TDSHP_OUTPUT_OFFSET (0x124) +#define MDP_TDSHP_OUTPUT_SIZE (0x128) +#define MDP_LUMA_HIST_INIT (0x200) +#define MDP_DC_TWO_D_W1_RESULT_INIT (0x260) +#define MDP_CONTOUR_HIST_INIT (0x398) + +/* MASK */ +#define MDP_HIST_CFG_00_MASK (0xFFFFFFFF) +#define MDP_HIST_CFG_01_MASK (0xFFFFFFFF) +#define MDP_LUMA_HIST_MASK (0xFFFFFFFF) +#define MDP_TDSHP_CTRL_MASK (0x07) +#define MDP_TDSHP_CFG_MASK (0x03F7) +#define MDP_TDSHP_INPUT_SIZE_MASK (0x1FFF1FFF) +#define MDP_TDSHP_OUTPUT_OFFSET_MASK (0x0FF00FF) +#define MDP_TDSHP_OUTPUT_SIZE_MASK (0x1FFF1FFF) +#define MDP_LUMA_HIST_INIT_MASK (0xFFFFFFFF) +#define MDP_DC_TWO_D_W1_RESULT_INIT_MASK (0x007FFFFF) +#define MDP_CONTOUR_HIST_INIT_MASK (0xFFFFFFFF) + +#endif // __MDP_REG_TDSHP_H__ diff --git a/drivers/media/platform/mediatek/mdp3/mdp_reg_wrot.h b/drivers/media/platform/mediatek/mdp3/mdp_reg_wrot.h index 6d3ff0e2b6..b6f016d2c2 100644 --- a/drivers/media/platform/mediatek/mdp3/mdp_reg_wrot.h +++ b/drivers/media/platform/mediatek/mdp3/mdp_reg_wrot.h @@ -17,14 +17,18 @@ #define VIDO_STRIDE 0x030 #define VIDO_OFST_ADDR_C 0x038 #define VIDO_STRIDE_C 0x03c +#define VIDO_CTRL_2 0x048 #define VIDO_DITHER 0x054 #define VIDO_STRIDE_V 0x06c #define VIDO_OFST_ADDR_V 0x068 #define VIDO_RSV_1 0x070 +#define VIDO_DMA_PREULTRA 0x074 #define VIDO_IN_SIZE 0x078 #define VIDO_ROT_EN 0x07c #define VIDO_FIFO_TEST 0x080 #define VIDO_MAT_CTRL 0x084 +#define VIDO_SCAN_10BIT 0x0dc +#define VIDO_PENDING_ZERO 0x0e0 #define VIDO_BASE_ADDR 0xf00 #define VIDO_BASE_ADDR_C 0xf04 #define VIDO_BASE_ADDR_V 0xf08 @@ -40,14 +44,18 @@ #define VIDO_STRIDE_MASK 0x0000ffff #define VIDO_OFST_ADDR_C_MASK 0x0fffffff #define VIDO_STRIDE_C_MASK 0x0000ffff +#define VIDO_CTRL_2_MASK 0x0000000f #define VIDO_DITHER_MASK 0xff000001 #define VIDO_STRIDE_V_MASK 0x0000ffff #define VIDO_OFST_ADDR_V_MASK 0x0fffffff #define VIDO_RSV_1_MASK 0xffffffff +#define VIDO_DMA_PREULTRA_MASK 0x00ffffff #define VIDO_IN_SIZE_MASK 0x1fff1fff #define VIDO_ROT_EN_MASK 0x00000001 #define VIDO_FIFO_TEST_MASK 0x00000fff #define VIDO_MAT_CTRL_MASK 0x000000f3 +#define VIDO_SCAN_10BIT_MASK 0x0000000f +#define VIDO_PENDING_ZERO_MASK 0x07ffffff #define VIDO_BASE_ADDR_MASK 0xffffffff #define VIDO_BASE_ADDR_C_MASK 0xffffffff #define VIDO_BASE_ADDR_V_MASK 0xffffffff diff --git a/drivers/media/platform/mediatek/mdp3/mdp_sm_mt8195.h b/drivers/media/platform/mediatek/mdp3/mdp_sm_mt8195.h new file mode 100644 index 0000000000..b09f48222d --- /dev/null +++ b/drivers/media/platform/mediatek/mdp3/mdp_sm_mt8195.h @@ -0,0 +1,283 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* + * Copyright (c) 2023 MediaTek Inc. + * Author: Ping-Hsun Wu + */ + +#ifndef __MDP_SM_MT8195_H__ +#define __MDP_SM_MT8195_H__ + +#include "mtk-mdp3-type.h" + +/* + * ISP-MDP generic output information + * MD5 of the target SCP prebuild: + * a49ec487e458b5971880f1b63dc2a9d5 + */ + +#define IMG_MAX_SUBFRAMES_8195 20 + +struct img_comp_frame_8195 { + u32 output_disable; + u32 bypass; + u32 in_width; + u32 in_height; + u32 out_width; + u32 out_height; + struct img_crop crop; + u32 in_total_width; + u32 out_total_width; +} __packed; + +struct img_comp_subfrm_8195 { + u32 tile_disable; + struct img_region in; + struct img_region out; + struct img_offset luma; + struct img_offset chroma; + s32 out_vertical; /* Output vertical index */ + s32 out_horizontal; /* Output horizontal index */ +} __packed; + +struct mdp_rdma_subfrm_8195 { + u32 offset[IMG_MAX_PLANES]; + u32 offset_0_p; + u32 src; + u32 clip; + u32 clip_ofst; + u32 in_tile_xleft; + u32 in_tile_ytop; +} __packed; + +struct mdp_rdma_data_8195 { + u32 src_ctrl; + u32 comp_ctrl; + u32 control; + u32 iova[IMG_MAX_PLANES]; + u32 iova_end[IMG_MAX_PLANES]; + u32 mf_bkgd; + u32 mf_bkgd_in_pxl; + u32 sf_bkgd; + u32 ufo_dec_y; + u32 ufo_dec_c; + u32 transform; + u32 dmabuf_con0; + u32 ultra_th_high_con0; + u32 ultra_th_low_con0; + u32 dmabuf_con1; + u32 ultra_th_high_con1; + u32 ultra_th_low_con1; + u32 dmabuf_con2; + u32 ultra_th_high_con2; + u32 ultra_th_low_con2; + u32 dmabuf_con3; + struct mdp_rdma_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_fg_subfrm_8195 { + u32 info_0; + u32 info_1; +} __packed; + +struct mdp_fg_data_8195 { + u32 ctrl_0; + u32 ck_en; + struct mdp_fg_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_hdr_subfrm_8195 { + u32 win_size; + u32 src; + u32 clip_ofst0; + u32 clip_ofst1; + u32 hist_ctrl_0; + u32 hist_ctrl_1; + u32 hdr_top; + u32 hist_addr; +} __packed; + +struct mdp_hdr_data_8195 { + u32 top; + u32 relay; + struct mdp_hdr_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_aal_subfrm_8195 { + u32 src; + u32 clip; + u32 clip_ofst; +} __packed; + +struct mdp_aal_data_8195 { + u32 cfg_main; + u32 cfg; + struct mdp_aal_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_rsz_subfrm_8195 { + u32 control2; + u32 src; + u32 clip; + u32 hdmirx_en; + u32 luma_h_int_ofst; + u32 luma_h_sub_ofst; + u32 luma_v_int_ofst; + u32 luma_v_sub_ofst; + u32 chroma_h_int_ofst; + u32 chroma_h_sub_ofst; + u32 rsz_switch; + u32 merge_cfg; +} __packed; + +struct mdp_rsz_data_8195 { + u32 coeff_step_x; + u32 coeff_step_y; + u32 control1; + u32 control2; + u32 etc_control; + u32 prz_enable; + u32 ibse_softclip; + u32 tap_adapt; + u32 ibse_gaincontrol1; + u32 ibse_gaincontrol2; + u32 ibse_ylevel_1; + u32 ibse_ylevel_2; + u32 ibse_ylevel_3; + u32 ibse_ylevel_4; + u32 ibse_ylevel_5; + struct mdp_rsz_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_tdshp_subfrm_8195 { + u32 src; + u32 clip; + u32 clip_ofst; + u32 hist_cfg_0; + u32 hist_cfg_1; +} __packed; + +struct mdp_tdshp_data_8195 { + u32 cfg; + struct mdp_tdshp_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_color_subfrm_8195 { + u32 in_hsize; + u32 in_vsize; +} __packed; + +struct mdp_color_data_8195 { + u32 start; + struct mdp_color_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_ovl_subfrm_8195 { + u32 L0_src_size; + u32 roi_size; +} __packed; + +struct mdp_ovl_data_8195 { + u32 L0_con; + u32 src_con; + struct mdp_ovl_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_pad_subfrm_8195 { + u32 pic_size; +} __packed; + +struct mdp_pad_data_8195 { + struct mdp_pad_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_tcc_subfrm_8195 { + u32 pic_size; +} __packed; + +struct mdp_tcc_data_8195 { + struct mdp_tcc_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_wrot_subfrm_8195 { + u32 offset[IMG_MAX_PLANES]; + u32 src; + u32 clip; + u32 clip_ofst; + u32 main_buf; +} __packed; + +struct mdp_wrot_data_8195 { + u32 iova[IMG_MAX_PLANES]; + u32 control; + u32 stride[IMG_MAX_PLANES]; + u32 mat_ctrl; + u32 fifo_test; + u32 filter; + u32 pre_ultra; + u32 framesize; + u32 afbc_yuvtrans; + u32 scan_10bit; + u32 pending_zero; + u32 bit_number; + u32 pvric; + u32 vpp02vpp1; + struct mdp_wrot_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct mdp_wdma_subfrm_8195 { + u32 offset[IMG_MAX_PLANES]; + u32 src; + u32 clip; + u32 clip_ofst; +} __packed; + +struct mdp_wdma_data_8195 { + u32 wdma_cfg; + u32 iova[IMG_MAX_PLANES]; + u32 w_in_byte; + u32 uv_stride; + struct mdp_wdma_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct isp_data_8195 { + u64 dl_flags; /* 1 << (enum mdp_comp_type) */ + u32 smxi_iova[4]; + u32 cq_idx; + u32 cq_iova; + u32 tpipe_iova[IMG_MAX_SUBFRAMES_8195]; +} __packed; + +struct img_compparam_8195 { + u32 type; /* enum mdp_comp_id */ + u32 id; /* engine alias_id */ + u32 input; + u32 outputs[IMG_MAX_HW_OUTPUTS]; + u32 num_outputs; + struct img_comp_frame_8195 frame; + struct img_comp_subfrm_8195 subfrms[IMG_MAX_SUBFRAMES_8195]; + u32 num_subfrms; + union { + struct mdp_rdma_data_8195 rdma; + struct mdp_fg_data_8195 fg; + struct mdp_hdr_data_8195 hdr; + struct mdp_aal_data_8195 aal; + struct mdp_rsz_data_8195 rsz; + struct mdp_tdshp_data_8195 tdshp; + struct mdp_color_data_8195 color; + struct mdp_ovl_data_8195 ovl; + struct mdp_pad_data_8195 pad; + struct mdp_tcc_data_8195 tcc; + struct mdp_wrot_data_8195 wrot; + struct mdp_wdma_data_8195 wdma; + struct isp_data_8195 isp; + }; +} __packed; + +struct img_config_8195 { + struct img_compparam_8195 components[IMG_MAX_COMPONENTS]; + u32 num_components; + struct img_mmsys_ctrl ctrls[IMG_MAX_SUBFRAMES_8195]; + u32 num_subfrms; +} __packed; + +#endif /* __MDP_SM_MT8195_H__ */ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h index 22b8b9a10e..f83ac40830 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h +++ b/drivers/media/platform/mediatek/mdp3/mtk-img-ipi.h @@ -10,6 +10,7 @@ #include #include "mdp_sm_mt8183.h" +#include "mdp_sm_mt8195.h" #include "mtk-mdp3-type.h" /* ISP-MDP generic input information */ @@ -115,6 +116,7 @@ struct img_frameparam { /* Platform config indicator */ #define MT8183 8183 +#define MT8195 8195 #define CFG_CHECK(plat, p_id) ((plat) == (p_id)) @@ -137,12 +139,14 @@ struct img_frameparam { struct img_config { union { struct img_config_8183 config_8183; + struct img_config_8195 config_8195; }; } __packed; struct img_compparam { union { struct img_compparam_8183 comp_8183; + struct img_compparam_8195 comp_8195; }; } __packed; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h index dee57cc4a9..49cdf45f6e 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cfg.h @@ -10,11 +10,13 @@ #include extern const struct mtk_mdp_driver_data mt8183_mdp_driver_data; +extern const struct mtk_mdp_driver_data mt8195_mdp_driver_data; struct mdp_dev; enum mtk_mdp_comp_id; s32 mdp_cfg_get_id_inner(struct mdp_dev *mdp_dev, enum mtk_mdp_comp_id id); enum mtk_mdp_comp_id mdp_cfg_get_id_public(struct mdp_dev *mdp_dev, s32 id); +bool mdp_cfg_comp_is_dummy(struct mdp_dev *mdp_dev, s32 inner_id); #endif /* __MTK_MDP3_CFG_H__ */ diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c index 6adac857a4..1d64bac34b 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.c @@ -6,6 +6,7 @@ #include #include +#include "mtk-mdp3-cfg.h" #include "mtk-mdp3-cmdq.h" #include "mtk-mdp3-comp.h" #include "mtk-mdp3-core.h" @@ -39,85 +40,192 @@ static bool is_output_disabled(int p_id, const struct img_compparam *param, u32 num = CFG_COMP(MT8183, param, num_subfrms); dis_output = CFG_COMP(MT8183, param, frame.output_disable); dis_tile = CFG_COMP(MT8183, param, frame.output_disable); + } else if (CFG_CHECK(MT8195, p_id)) { + num = CFG_COMP(MT8195, param, num_subfrms); + dis_output = CFG_COMP(MT8195, param, frame.output_disable); + dis_tile = CFG_COMP(MT8195, param, frame.output_disable); } return (count < num) ? (dis_output || dis_tile) : true; } -static int mdp_path_subfrm_require(const struct mdp_path *path, - struct mdp_cmdq_cmd *cmd, - s32 *mutex_id, u32 count) +static struct mtk_mutex *__get_mutex(const struct mdp_dev *mdp_dev, + const struct mdp_pipe_info *p) { - const int p_id = path->mdp_dev->mdp_data->mdp_plat_id; - const struct mdp_comp_ctx *ctx; - const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data; - struct device *dev = &path->mdp_dev->pdev->dev; - struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex; - int id, index; - u32 num_comp = 0; + return mdp_dev->mm_subsys[p->sub_id].mdp_mutex[p->mutex_id]; +} - if (CFG_CHECK(MT8183, p_id)) - num_comp = CFG_GET(MT8183, path->config, num_components); +static u8 __get_pp_num(enum mdp_stream_type type) +{ + switch (type) { + case MDP_STREAM_TYPE_DUAL_BITBLT: + return MDP_PP_USED_2; + default: + return MDP_PP_USED_1; + } +} - /* Decide which mutex to use based on the current pipeline */ - switch (path->comps[0].comp->public_id) { +static enum mdp_pipe_id __get_pipe(const struct mdp_dev *mdp_dev, + enum mtk_mdp_comp_id id) +{ + enum mdp_pipe_id pipe_id; + + switch (id) { case MDP_COMP_RDMA0: - index = MDP_PIPE_RDMA0; + pipe_id = MDP_PIPE_RDMA0; break; case MDP_COMP_ISP_IMGI: - index = MDP_PIPE_IMGI; + pipe_id = MDP_PIPE_IMGI; break; case MDP_COMP_WPEI: - index = MDP_PIPE_WPEI; + pipe_id = MDP_PIPE_WPEI; break; case MDP_COMP_WPEI2: - index = MDP_PIPE_WPEI2; + pipe_id = MDP_PIPE_WPEI2; + break; + case MDP_COMP_RDMA1: + pipe_id = MDP_PIPE_RDMA1; + break; + case MDP_COMP_RDMA2: + pipe_id = MDP_PIPE_RDMA2; + break; + case MDP_COMP_RDMA3: + pipe_id = MDP_PIPE_RDMA3; break; default: - dev_err(dev, "Unknown pipeline and no mutex is assigned"); - return -EINVAL; + /* Avoid exceptions when operating MUTEX */ + pipe_id = MDP_PIPE_RDMA0; + dev_err(&mdp_dev->pdev->dev, "Unknown pipeline id %d", id); + break; + } + + return pipe_id; +} + +static struct img_config *__get_config_offset(struct mdp_dev *mdp, + struct mdp_cmdq_param *param, + u8 pp_idx) +{ + const int p_id = mdp->mdp_data->mdp_plat_id; + struct device *dev = &mdp->pdev->dev; + void *cfg_c, *cfg_n; + long bound = mdp->vpu.config_size; + + if (pp_idx >= mdp->mdp_data->pp_used) + goto err_param; + + if (CFG_CHECK(MT8183, p_id)) + cfg_c = CFG_OFST(MT8183, param->config, pp_idx); + else if (CFG_CHECK(MT8195, p_id)) + cfg_c = CFG_OFST(MT8195, param->config, pp_idx); + else + goto err_param; + + if (CFG_CHECK(MT8183, p_id)) + cfg_n = CFG_OFST(MT8183, param->config, pp_idx + 1); + else if (CFG_CHECK(MT8195, p_id)) + cfg_n = CFG_OFST(MT8195, param->config, pp_idx + 1); + else + goto err_param; + + if ((long)cfg_n - (long)mdp->vpu.config > bound) { + dev_err(dev, "config offset %ld OOB %ld\n", (long)cfg_n, bound); + cfg_c = ERR_PTR(-EFAULT); } - *mutex_id = data->pipe_info[index].mutex_id; + + return (struct img_config *)cfg_c; + +err_param: + cfg_c = ERR_PTR(-EINVAL); + return (struct img_config *)cfg_c; +} + +static int mdp_path_subfrm_require(const struct mdp_path *path, + struct mdp_cmdq_cmd *cmd, + struct mdp_pipe_info *p, u32 count) +{ + const int p_id = path->mdp_dev->mdp_data->mdp_plat_id; + const struct mdp_comp_ctx *ctx; + const struct mtk_mdp_driver_data *data = path->mdp_dev->mdp_data; + struct mtk_mutex *mutex; + int id, index; + u32 num_comp = 0; + + if (CFG_CHECK(MT8183, p_id)) + num_comp = CFG_GET(MT8183, path->config, num_components); + else if (CFG_CHECK(MT8195, p_id)) + num_comp = CFG_GET(MT8195, path->config, num_components); + + /* Decide which mutex to use based on the current pipeline */ + index = __get_pipe(path->mdp_dev, path->comps[0].comp->public_id); + memcpy(p, &data->pipe_info[index], sizeof(struct mdp_pipe_info)); + mutex = __get_mutex(path->mdp_dev, p); /* Set mutex mod */ for (index = 0; index < num_comp; index++) { + s32 inner_id = MDP_COMP_NONE; + const u32 *mutex_idx; + const struct mdp_comp_blend *b; + + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[index].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[index].type); + + if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id)) + continue; + ctx = &path->comps[index]; if (is_output_disabled(p_id, ctx->param, count)) continue; + + mutex_idx = data->mdp_mutex_table_idx; id = ctx->comp->public_id; - mtk_mutex_write_mod(mutex[*mutex_id], - data->mdp_mutex_table_idx[id], false); + mtk_mutex_write_mod(mutex, mutex_idx[id], false); + + b = &data->comp_data[id].blend; + if (b && b->aid_mod) + mtk_mutex_write_mod(mutex, mutex_idx[b->b_id], false); } - mtk_mutex_write_sof(mutex[*mutex_id], - MUTEX_SOF_IDX_SINGLE_MODE); + mtk_mutex_write_sof(mutex, MUTEX_SOF_IDX_SINGLE_MODE); return 0; } static int mdp_path_subfrm_run(const struct mdp_path *path, struct mdp_cmdq_cmd *cmd, - s32 *mutex_id, u32 count) + struct mdp_pipe_info *p, u32 count) { const int p_id = path->mdp_dev->mdp_data->mdp_plat_id; const struct mdp_comp_ctx *ctx; struct device *dev = &path->mdp_dev->pdev->dev; - struct mtk_mutex **mutex = path->mdp_dev->mdp_mutex; + struct mtk_mutex *mutex; int index; u32 num_comp = 0; s32 event; + s32 inner_id = MDP_COMP_NONE; - if (-1 == *mutex_id) { + if (-1 == p->mutex_id) { dev_err(dev, "Incorrect mutex id"); return -EINVAL; } if (CFG_CHECK(MT8183, p_id)) num_comp = CFG_GET(MT8183, path->config, num_components); + else if (CFG_CHECK(MT8195, p_id)) + num_comp = CFG_GET(MT8195, path->config, num_components); /* Wait WROT SRAM shared to DISP RDMA */ /* Clear SOF event for each engine */ for (index = 0; index < num_comp; index++) { + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[index].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[index].type); + + if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id)) + continue; ctx = &path->comps[index]; if (is_output_disabled(p_id, ctx->param, count)) continue; @@ -127,10 +235,18 @@ static int mdp_path_subfrm_run(const struct mdp_path *path, } /* Enable the mutex */ - mtk_mutex_enable_by_cmdq(mutex[*mutex_id], (void *)&cmd->pkt); + mutex = __get_mutex(path->mdp_dev, p); + mtk_mutex_enable_by_cmdq(mutex, (void *)&cmd->pkt); /* Wait SOF events and clear mutex modules (optional) */ for (index = 0; index < num_comp; index++) { + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[index].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[index].type); + + if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id)) + continue; ctx = &path->comps[index]; if (is_output_disabled(p_id, ctx->param, count)) continue; @@ -151,13 +267,26 @@ static int mdp_path_ctx_init(struct mdp_dev *mdp, struct mdp_path *path) if (CFG_CHECK(MT8183, p_id)) num_comp = CFG_GET(MT8183, path->config, num_components); + else if (CFG_CHECK(MT8195, p_id)) + num_comp = CFG_GET(MT8195, path->config, num_components); if (num_comp < 1) return -EINVAL; for (index = 0; index < num_comp; index++) { + s32 inner_id = MDP_COMP_NONE; + + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[index].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[index].type); + + if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id)) + continue; if (CFG_CHECK(MT8183, p_id)) param = (void *)CFG_ADDR(MT8183, path->config, components[index]); + else if (CFG_CHECK(MT8195, p_id)) + param = (void *)CFG_ADDR(MT8195, path->config, components[index]); ret = mdp_comp_ctx_config(mdp, &path->comps[index], param, path->param); if (ret) @@ -174,18 +303,23 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, const struct img_mmsys_ctrl *ctrl = NULL; const struct img_mux *set; struct mdp_comp_ctx *ctx; - s32 mutex_id; + struct mdp_pipe_info pipe; int index, ret; u32 num_comp = 0; + s32 inner_id = MDP_COMP_NONE; if (CFG_CHECK(MT8183, p_id)) num_comp = CFG_GET(MT8183, path->config, num_components); + else if (CFG_CHECK(MT8195, p_id)) + num_comp = CFG_GET(MT8195, path->config, num_components); if (CFG_CHECK(MT8183, p_id)) ctrl = CFG_ADDR(MT8183, path->config, ctrls[count]); + else if (CFG_CHECK(MT8195, p_id)) + ctrl = CFG_ADDR(MT8195, path->config, ctrls[count]); /* Acquire components */ - ret = mdp_path_subfrm_require(path, cmd, &mutex_id, count); + ret = mdp_path_subfrm_require(path, cmd, &pipe, count); if (ret) return ret; /* Enable mux settings */ @@ -196,6 +330,13 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, } /* Config sub-frame information */ for (index = (num_comp - 1); index >= 0; index--) { + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[index].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[index].type); + + if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id)) + continue; ctx = &path->comps[index]; if (is_output_disabled(p_id, ctx->param, count)) continue; @@ -204,11 +345,18 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, return ret; } /* Run components */ - ret = mdp_path_subfrm_run(path, cmd, &mutex_id, count); + ret = mdp_path_subfrm_run(path, cmd, &pipe, count); if (ret) return ret; /* Wait components done */ for (index = 0; index < num_comp; index++) { + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[index].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[index].type); + + if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id)) + continue; ctx = &path->comps[index]; if (is_output_disabled(p_id, ctx->param, count)) continue; @@ -218,6 +366,13 @@ static int mdp_path_config_subfrm(struct mdp_cmdq_cmd *cmd, } /* Advance to the next sub-frame */ for (index = 0; index < num_comp; index++) { + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[index].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[index].type); + + if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id)) + continue; ctx = &path->comps[index]; ret = call_op(ctx, advance_subfrm, cmd, count); if (ret) @@ -241,16 +396,28 @@ static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd, int index, count, ret; u32 num_comp = 0; u32 num_sub = 0; + s32 inner_id = MDP_COMP_NONE; if (CFG_CHECK(MT8183, p_id)) num_comp = CFG_GET(MT8183, path->config, num_components); + else if (CFG_CHECK(MT8195, p_id)) + num_comp = CFG_GET(MT8195, path->config, num_components); if (CFG_CHECK(MT8183, p_id)) num_sub = CFG_GET(MT8183, path->config, num_subfrms); + else if (CFG_CHECK(MT8195, p_id)) + num_sub = CFG_GET(MT8195, path->config, num_subfrms); /* Config path frame */ /* Reset components */ for (index = 0; index < num_comp; index++) { + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[index].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[index].type); + + if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id)) + continue; ctx = &path->comps[index]; ret = call_op(ctx, init_comp, cmd); if (ret) @@ -262,8 +429,18 @@ static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd, u32 out = 0; ctx = &path->comps[index]; + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[index].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[index].type); + + if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id)) + continue; + if (CFG_CHECK(MT8183, p_id)) out = CFG_COMP(MT8183, ctx->param, outputs[0]); + else if (CFG_CHECK(MT8195, p_id)) + out = CFG_COMP(MT8195, ctx->param, outputs[0]); compose = path->composes[out]; ret = call_op(ctx, config_frame, cmd, compose); @@ -279,6 +456,13 @@ static int mdp_path_config(struct mdp_dev *mdp, struct mdp_cmdq_cmd *cmd, } /* Post processing information */ for (index = 0; index < num_comp; index++) { + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[index].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[index].type); + + if (mdp_cfg_comp_is_dummy(path->mdp_dev, inner_id)) + continue; ctx = &path->comps[index]; ret = call_op(ctx, post_process, cmd); if (ret) @@ -328,18 +512,31 @@ static void mdp_auto_release_work(struct work_struct *work) { struct mdp_cmdq_cmd *cmd; struct mdp_dev *mdp; - int id; + struct mtk_mutex *mutex; + enum mdp_pipe_id pipe_id; cmd = container_of(work, struct mdp_cmdq_cmd, auto_release_work); mdp = cmd->mdp; - id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; - mtk_mutex_unprepare(mdp->mdp_mutex[id]); + pipe_id = __get_pipe(mdp, cmd->comps[0].public_id); + mutex = __get_mutex(mdp, &mdp->mdp_data->pipe_info[pipe_id]); + mtk_mutex_unprepare(mutex); mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, cmd->num_comps); - atomic_dec(&mdp->job_count); - wake_up(&mdp->callback_wq); + if (atomic_dec_and_test(&mdp->job_count)) { + if (cmd->mdp_ctx) + mdp_m2m_job_finish(cmd->mdp_ctx); + + if (cmd->user_cmdq_cb) { + struct cmdq_cb_data user_cb_data; + + user_cb_data.sta = cmd->data->sta; + user_cb_data.pkt = cmd->data->pkt; + cmd->user_cmdq_cb(user_cb_data); + } + wake_up(&mdp->callback_wq); + } mdp_cmdq_pkt_destroy(&cmd->pkt); kfree(cmd->comps); @@ -354,7 +551,7 @@ static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg) struct cmdq_cb_data *data; struct mdp_dev *mdp; struct device *dev; - int id; + enum mdp_pipe_id pipe_id; if (!mssg) { pr_info("%s:no callback data\n", __func__); @@ -363,30 +560,23 @@ static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg) data = (struct cmdq_cb_data *)mssg; cmd = container_of(data->pkt, struct mdp_cmdq_cmd, pkt); + cmd->data = data; mdp = cmd->mdp; dev = &mdp->pdev->dev; - if (cmd->mdp_ctx) - mdp_m2m_job_finish(cmd->mdp_ctx); - - if (cmd->user_cmdq_cb) { - struct cmdq_cb_data user_cb_data; - - user_cb_data.sta = data->sta; - user_cb_data.pkt = data->pkt; - cmd->user_cmdq_cb(user_cb_data); - } - INIT_WORK(&cmd->auto_release_work, mdp_auto_release_work); if (!queue_work(mdp->clock_wq, &cmd->auto_release_work)) { + struct mtk_mutex *mutex; + dev_err(dev, "%s:queue_work fail!\n", __func__); - id = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; - mtk_mutex_unprepare(mdp->mdp_mutex[id]); + pipe_id = __get_pipe(mdp, cmd->comps[0].public_id); + mutex = __get_mutex(mdp, &mdp->mdp_data->pipe_info[pipe_id]); + mtk_mutex_unprepare(mutex); mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, cmd->num_comps); - atomic_dec(&mdp->job_count); - wake_up(&mdp->callback_wq); + if (atomic_dec_and_test(&mdp->job_count)) + wake_up(&mdp->callback_wq); mdp_cmdq_pkt_destroy(&cmd->pkt); kfree(cmd->comps); @@ -396,34 +586,48 @@ static void mdp_handle_cmdq_callback(struct mbox_client *cl, void *mssg) } } -int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param) +static struct mdp_cmdq_cmd *mdp_cmdq_prepare(struct mdp_dev *mdp, + struct mdp_cmdq_param *param, + u8 pp_idx) { struct mdp_path *path = NULL; struct mdp_cmdq_cmd *cmd = NULL; struct mdp_comp *comps = NULL; struct device *dev = &mdp->pdev->dev; const int p_id = mdp->mdp_data->mdp_plat_id; - int i, ret; - u32 num_comp = 0; - - atomic_inc(&mdp->job_count); - if (atomic_read(&mdp->suspended)) { - atomic_dec(&mdp->job_count); - return -ECANCELED; + struct img_config *config; + struct mtk_mutex *mutex = NULL; + enum mdp_pipe_id pipe_id; + int i, ret = -ECANCELED; + u32 num_comp; + + config = __get_config_offset(mdp, param, pp_idx); + if (IS_ERR(config)) { + ret = PTR_ERR(config); + goto err_uninit; } + if (CFG_CHECK(MT8183, p_id)) + num_comp = CFG_GET(MT8183, config, num_components); + else if (CFG_CHECK(MT8195, p_id)) + num_comp = CFG_GET(MT8195, config, num_components); + else + goto err_uninit; + cmd = kzalloc(sizeof(*cmd), GFP_KERNEL); if (!cmd) { ret = -ENOMEM; - goto err_cancel_job; + goto err_uninit; } - ret = mdp_cmdq_pkt_create(mdp->cmdq_clt, &cmd->pkt, SZ_16K); + ret = mdp_cmdq_pkt_create(mdp->cmdq_clt[pp_idx], &cmd->pkt, SZ_16K); if (ret) goto err_free_cmd; if (CFG_CHECK(MT8183, p_id)) { num_comp = CFG_GET(MT8183, param->config, num_components); + } else if (CFG_CHECK(MT8195, p_id)) { + num_comp = CFG_GET(MT8195, param->config, num_components); } else { ret = -EINVAL; goto err_destroy_pkt; @@ -440,15 +644,8 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param) goto err_free_comps; } - i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; - ret = mtk_mutex_prepare(mdp->mdp_mutex[i]); - if (ret) { - dev_err(dev, "Fail to enable mutex clk\n"); - goto err_free_path; - } - path->mdp_dev = mdp; - path->config = param->config; + path->config = config; path->param = param->param; for (i = 0; i < param->param->num_outputs; i++) { path->bounds[i].left = 0; @@ -462,22 +659,40 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param) } ret = mdp_path_ctx_init(mdp, path); if (ret) { - dev_err(dev, "mdp_path_ctx_init error\n"); + dev_err(dev, "mdp_path_ctx_init error %d\n", pp_idx); + goto err_free_path; + } + + pipe_id = __get_pipe(mdp, path->comps[0].comp->public_id); + mutex = __get_mutex(mdp, &mdp->mdp_data->pipe_info[pipe_id]); + ret = mtk_mutex_prepare(mutex); + if (ret) { + dev_err(dev, "Fail to enable mutex %d clk\n", pp_idx); goto err_free_path; } ret = mdp_path_config(mdp, cmd, path); if (ret) { - dev_err(dev, "mdp_path_config error\n"); + dev_err(dev, "mdp_path_config error %d\n", pp_idx); goto err_free_path; } cmdq_pkt_finalize(&cmd->pkt); - for (i = 0; i < num_comp; i++) + for (i = 0; i < num_comp; i++) { + s32 inner_id = MDP_COMP_NONE; + + if (CFG_CHECK(MT8183, p_id)) + inner_id = CFG_GET(MT8183, path->config, components[i].type); + else if (CFG_CHECK(MT8195, p_id)) + inner_id = CFG_GET(MT8195, path->config, components[i].type); + + if (mdp_cfg_comp_is_dummy(mdp, inner_id)) + continue; memcpy(&comps[i], path->comps[i].comp, sizeof(struct mdp_comp)); + } - mdp->cmdq_clt->client.rx_callback = mdp_handle_cmdq_callback; + mdp->cmdq_clt[pp_idx]->client.rx_callback = mdp_handle_cmdq_callback; cmd->mdp = mdp; cmd->user_cmdq_cb = param->cmdq_cb; cmd->user_cb_data = param->cb_data; @@ -485,29 +700,12 @@ int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param) cmd->num_comps = num_comp; cmd->mdp_ctx = param->mdp_ctx; - ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd->comps, cmd->num_comps); - if (ret) - goto err_free_path; - - dma_sync_single_for_device(mdp->cmdq_clt->chan->mbox->dev, - cmd->pkt.pa_base, cmd->pkt.cmd_buf_size, - DMA_TO_DEVICE); - ret = mbox_send_message(mdp->cmdq_clt->chan, &cmd->pkt); - if (ret < 0) { - dev_err(dev, "mbox send message fail %d!\n", ret); - goto err_clock_off; - } - mbox_client_txdone(mdp->cmdq_clt->chan, 0); - kfree(path); - return 0; + return cmd; -err_clock_off: - mdp_comp_clocks_off(&mdp->pdev->dev, cmd->comps, - cmd->num_comps); err_free_path: - i = mdp->mdp_data->pipe_info[MDP_PIPE_RDMA0].mutex_id; - mtk_mutex_unprepare(mdp->mdp_mutex[i]); + if (mutex) + mtk_mutex_unprepare(mutex); kfree(path); err_free_comps: kfree(comps); @@ -515,8 +713,58 @@ err_destroy_pkt: mdp_cmdq_pkt_destroy(&cmd->pkt); err_free_cmd: kfree(cmd); +err_uninit: + return ERR_PTR(ret); +} + +int mdp_cmdq_send(struct mdp_dev *mdp, struct mdp_cmdq_param *param) +{ + struct mdp_cmdq_cmd *cmd[MDP_PP_MAX] = {NULL}; + struct device *dev = &mdp->pdev->dev; + int i, ret; + u8 pp_used = __get_pp_num(param->param->type); + + atomic_set(&mdp->job_count, pp_used); + if (atomic_read(&mdp->suspended)) { + atomic_set(&mdp->job_count, 0); + return -ECANCELED; + } + + for (i = 0; i < pp_used; i++) { + cmd[i] = mdp_cmdq_prepare(mdp, param, i); + if (IS_ERR_OR_NULL(cmd[i])) { + ret = PTR_ERR(cmd[i]); + goto err_cancel_job; + } + } + + for (i = 0; i < pp_used; i++) { + ret = mdp_comp_clocks_on(&mdp->pdev->dev, cmd[i]->comps, cmd[i]->num_comps); + if (ret) + goto err_clock_off; + } + + for (i = 0; i < pp_used; i++) { + dma_sync_single_for_device(mdp->cmdq_clt[i]->chan->mbox->dev, + cmd[i]->pkt.pa_base, cmd[i]->pkt.cmd_buf_size, + DMA_TO_DEVICE); + + ret = mbox_send_message(mdp->cmdq_clt[i]->chan, &cmd[i]->pkt); + if (ret < 0) { + dev_err(dev, "mbox send message fail %d!\n", ret); + i = pp_used; + goto err_clock_off; + } + mbox_client_txdone(mdp->cmdq_clt[i]->chan, 0); + } + return 0; + +err_clock_off: + while (--i >= 0) + mdp_comp_clocks_off(&mdp->pdev->dev, cmd[i]->comps, + cmd[i]->num_comps); err_cancel_job: - atomic_dec(&mdp->job_count); + atomic_set(&mdp->job_count, 0); return ret; } diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.h index 43475b862d..53a30ad7e0 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.h +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-cmdq.h @@ -29,6 +29,7 @@ struct mdp_cmdq_cmd { struct cmdq_pkt pkt; s32 *event; struct mdp_dev *mdp; + struct cmdq_cb_data *data; void (*user_cmdq_cb)(struct cmdq_cb_data data); void *user_cb_data; struct mdp_comp *comps; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c index 575c8d52ac..8f62fb1671 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.c @@ -13,11 +13,19 @@ #include "mtk-mdp3-core.h" #include "mtk-mdp3-regs.h" -#include "mdp_reg_rdma.h" +#include "mdp_reg_aal.h" #include "mdp_reg_ccorr.h" +#include "mdp_reg_color.h" +#include "mdp_reg_fg.h" +#include "mdp_reg_hdr.h" +#include "mdp_reg_merge.h" +#include "mdp_reg_ovl.h" +#include "mdp_reg_pad.h" +#include "mdp_reg_rdma.h" #include "mdp_reg_rsz.h" -#include "mdp_reg_wrot.h" +#include "mdp_reg_tdshp.h" #include "mdp_reg_wdma.h" +#include "mdp_reg_wrot.h" static u32 mdp_comp_alias_id[MDP_COMP_TYPE_COUNT]; static int p_id; @@ -85,6 +93,7 @@ static int config_rdma_frame(struct mdp_comp_ctx *ctx, bool en_ufo = MDP_COLOR_IS_UFP(colorformat); phys_addr_t base = ctx->comp->reg_base; u8 subsys_id = ctx->comp->subsys_id; + u32 rdma_con_mask = 0; u32 reg = 0; if (mdp_cfg && mdp_cfg->rdma_support_10bit) { @@ -105,6 +114,8 @@ static int config_rdma_frame(struct mdp_comp_ctx *ctx, /* Setup source frame info */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.src_ctrl); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.src_ctrl); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_CON, reg, 0x03C8FE0F); @@ -113,69 +124,163 @@ static int config_rdma_frame(struct mdp_comp_ctx *ctx, /* Setup source buffer base */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.ufo_dec_y); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.ufo_dec_y); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_UFO_DEC_LENGTH_BASE_Y, reg, 0xFFFFFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.ufo_dec_c); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.ufo_dec_c); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_UFO_DEC_LENGTH_BASE_C, reg, 0xFFFFFFFF); + /* Set 10bit source frame pitch */ if (block10bit) { if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.mf_bkgd_in_pxl); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.mf_bkgd_in_pxl); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_BKGD_SIZE_IN_PXL, reg, 0x001FFFFF); } } - if (CFG_CHECK(MT8183, p_id)) + if (CFG_CHECK(MT8183, p_id)) { reg = CFG_COMP(MT8183, ctx->param, rdma.control); + rdma_con_mask = 0x1110; + } else if (CFG_CHECK(MT8195, p_id)) { + reg = CFG_COMP(MT8195, ctx->param, rdma.control); + rdma_con_mask = 0x1130; + } MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_CON, reg, - 0x1110); + rdma_con_mask); + /* Setup source buffer base */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.iova[0]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.iova[0]); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_0, reg, 0xFFFFFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.iova[1]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.iova[1]); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_1, reg, 0xFFFFFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.iova[2]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.iova[2]); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_BASE_2, reg, 0xFFFFFFFF); + /* Setup source buffer end */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.iova_end[0]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.iova_end[0]); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_0, reg, 0xFFFFFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.iova_end[1]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.iova_end[1]); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_1, reg, 0xFFFFFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.iova_end[2]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.iova_end[2]); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_END_2, reg, 0xFFFFFFFF); + /* Setup source frame pitch */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.mf_bkgd); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.mf_bkgd); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_BKGD_SIZE_IN_BYTE, reg, 0x001FFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.sf_bkgd); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.sf_bkgd); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SF_BKGD_SIZE_IN_BYTE, reg, 0x001FFFFF); + /* Setup color transform */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.transform); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.transform); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_TRANSFORM_0, reg, 0x0F110000); + if (!mdp_cfg || !mdp_cfg->rdma_esl_setting) + goto rdma_config_done; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.dmabuf_con0); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_DMABUF_CON_0, + reg, 0x0FFF00FF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.ultra_th_high_con0); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_ULTRA_TH_HIGH_CON_0, + reg, 0x3FFFFFFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.ultra_th_low_con0); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_ULTRA_TH_LOW_CON_0, + reg, 0x3FFFFFFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.dmabuf_con1); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_DMABUF_CON_1, + reg, 0x0F7F007F); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.ultra_th_high_con1); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_ULTRA_TH_HIGH_CON_1, + reg, 0x3FFFFFFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.ultra_th_low_con1); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_ULTRA_TH_LOW_CON_1, + reg, 0x3FFFFFFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.dmabuf_con2); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_DMABUF_CON_2, + reg, 0x0F3F003F); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.ultra_th_high_con2); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_ULTRA_TH_HIGH_CON_2, + reg, 0x3FFFFFFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.ultra_th_low_con2); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_ULTRA_TH_LOW_CON_2, + reg, 0x3FFFFFFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.dmabuf_con3); + MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_DMABUF_CON_3, + reg, 0x0F3F003F); + +rdma_config_done: return 0; } @@ -197,6 +302,8 @@ static int config_rdma_subfrm(struct mdp_comp_ctx *ctx, /* Set Y pixel offset */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].offset[0]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.subfrms[index].offset[0]); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_0, reg, 0xFFFFFFFF); @@ -205,6 +312,8 @@ static int config_rdma_subfrm(struct mdp_comp_ctx *ctx, if (mdp_cfg->rdma_support_10bit && block10bit && en_ufo) { if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].offset_0_p); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.subfrms[index].offset_0_p); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_0_P, reg, 0xFFFFFFFF); @@ -214,32 +323,49 @@ static int config_rdma_subfrm(struct mdp_comp_ctx *ctx, /* Set U pixel offset */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].offset[1]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.subfrms[index].offset[1]); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_1, reg, 0xFFFFFFFF); + /* Set V pixel offset */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].offset[2]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.subfrms[index].offset[2]); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_SRC_OFFSET_2, reg, 0xFFFFFFFF); + /* Set source size */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].src); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.subfrms[index].src); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_SRC_SIZE, reg, 0x1FFF1FFF); + /* Set target size */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].clip); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.subfrms[index].clip); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_CLIP_SIZE, reg, 0x1FFF1FFF); + /* Set crop offset */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rdma.subfrms[index].clip_ofst); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rdma.subfrms[index].clip_ofst); MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_MF_OFFSET_1, reg, 0x003F001F); if (CFG_CHECK(MT8183, p_id)) { csf_l = CFG_COMP(MT8183, ctx->param, subfrms[index].in.left); csf_r = CFG_COMP(MT8183, ctx->param, subfrms[index].in.right); + } else if (CFG_CHECK(MT8195, p_id)) { + csf_l = CFG_COMP(MT8195, ctx->param, subfrms[index].in.left); + csf_r = CFG_COMP(MT8195, ctx->param, subfrms[index].in.right); } if (mdp_cfg && mdp_cfg->rdma_upsample_repeat_only) if ((csf_r - csf_l + 1) > 320) @@ -251,14 +377,20 @@ static int config_rdma_subfrm(struct mdp_comp_ctx *ctx, static int wait_rdma_event(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) { + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); struct device *dev = &ctx->comp->mdp_dev->pdev->dev; phys_addr_t base = ctx->comp->reg_base; u8 subsys_id = ctx->comp->subsys_id; - if (ctx->comp->alias_id == 0) - MM_REG_WAIT(cmd, ctx->comp->gce_event[MDP_GCE_EVENT_EOF]); - else - dev_err(dev, "Do not support RDMA1_DONE event\n"); + if (!mdp_cfg) + return -EINVAL; + + if (ctx->comp->alias_id >= mdp_cfg->rdma_event_num) { + dev_err(dev, "Invalid RDMA event %d\n", ctx->comp->alias_id); + return -EINVAL; + } + + MM_REG_WAIT(cmd, ctx->comp->gce_event[MDP_GCE_EVENT_EOF]); /* Disable RDMA */ MM_REG_WRITE(cmd, subsys_id, base, MDP_RDMA_EN, 0x0, BIT(0)); @@ -283,6 +415,14 @@ static int init_rsz(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, 0x0, BIT(16)); /* Enable RSZ */ MM_REG_WRITE(cmd, subsys_id, base, PRZ_ENABLE, BIT(0), BIT(0)); + + if (CFG_CHECK(MT8195, p_id)) { + struct device *dev; + + dev = ctx->comp->mdp_dev->mm_subsys[MDP_MM_SUBSYS_1].mmsys; + mtk_mmsys_vpp_rsz_dcm_config(dev, true, NULL); + } + return 0; } @@ -290,13 +430,19 @@ static int config_rsz_frame(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd, const struct v4l2_rect *compose) { + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); phys_addr_t base = ctx->comp->reg_base; u8 subsys_id = ctx->comp->subsys_id; bool bypass = FALSE; u32 reg = 0; + if (mdp_cfg && mdp_cfg->rsz_etc_control) + MM_REG_WRITE(cmd, subsys_id, base, RSZ_ETC_CONTROL, 0x0, 0xFFFFFFFF); + if (CFG_CHECK(MT8183, p_id)) bypass = CFG_COMP(MT8183, ctx->param, frame.bypass); + else if (CFG_CHECK(MT8195, p_id)) + bypass = CFG_COMP(MT8195, ctx->param, frame.bypass); if (bypass) { /* Disable RSZ */ @@ -306,20 +452,32 @@ static int config_rsz_frame(struct mdp_comp_ctx *ctx, if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rsz.control1); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rsz.control1); MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_1, reg, 0x03FFFDF3); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rsz.control2); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rsz.control2); MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_2, reg, 0x0FFFC290); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rsz.coeff_step_x); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rsz.coeff_step_x); MM_REG_WRITE(cmd, subsys_id, base, PRZ_HORIZONTAL_COEFF_STEP, reg, 0x007FFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rsz.coeff_step_y); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rsz.coeff_step_y); MM_REG_WRITE(cmd, subsys_id, base, PRZ_VERTICAL_COEFF_STEP, reg, 0x007FFFFF); + return 0; } @@ -331,19 +489,28 @@ static int config_rsz_subfrm(struct mdp_comp_ctx *ctx, u8 subsys_id = ctx->comp->subsys_id; u32 csf_l = 0, csf_r = 0; u32 reg = 0; + u32 id; if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rsz.subfrms[index].control2); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rsz.subfrms[index].control2); MM_REG_WRITE(cmd, subsys_id, base, PRZ_CONTROL_2, reg, 0x00003800); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rsz.subfrms[index].src); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rsz.subfrms[index].src); MM_REG_WRITE(cmd, subsys_id, base, PRZ_INPUT_IMAGE, reg, 0xFFFFFFFF); if (CFG_CHECK(MT8183, p_id)) { csf_l = CFG_COMP(MT8183, ctx->param, subfrms[index].in.left); csf_r = CFG_COMP(MT8183, ctx->param, subfrms[index].in.right); + } else if (CFG_CHECK(MT8195, p_id)) { + csf_l = CFG_COMP(MT8195, ctx->param, subfrms[index].in.left); + csf_r = CFG_COMP(MT8195, ctx->param, subfrms[index].in.right); } if (mdp_cfg && mdp_cfg->rsz_disable_dcm_small_sample) if ((csf_r - csf_l + 1) <= 16) @@ -352,37 +519,99 @@ static int config_rsz_subfrm(struct mdp_comp_ctx *ctx, if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, subfrms[index].luma.left); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, subfrms[index].luma.left); MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_HORIZONTAL_INTEGER_OFFSET, reg, 0xFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, subfrms[index].luma.left_subpix); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, subfrms[index].luma.left_subpix); MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_HORIZONTAL_SUBPIXEL_OFFSET, reg, 0x1FFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, subfrms[index].luma.top); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, subfrms[index].luma.top); MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_VERTICAL_INTEGER_OFFSET, reg, 0xFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, subfrms[index].luma.top_subpix); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, subfrms[index].luma.top_subpix); MM_REG_WRITE(cmd, subsys_id, base, PRZ_LUMA_VERTICAL_SUBPIXEL_OFFSET, reg, 0x1FFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, subfrms[index].chroma.left); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, subfrms[index].chroma.left); MM_REG_WRITE(cmd, subsys_id, base, PRZ_CHROMA_HORIZONTAL_INTEGER_OFFSET, reg, 0xFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, subfrms[index].chroma.left_subpix); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, subfrms[index].chroma.left_subpix); MM_REG_WRITE(cmd, subsys_id, base, PRZ_CHROMA_HORIZONTAL_SUBPIXEL_OFFSET, reg, 0x1FFFFF); if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, rsz.subfrms[index].clip); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rsz.subfrms[index].clip); MM_REG_WRITE(cmd, subsys_id, base, PRZ_OUTPUT_IMAGE, reg, 0xFFFFFFFF); + if (CFG_CHECK(MT8195, p_id)) { + struct device *dev; + struct mdp_comp *merge; + const struct mtk_mdp_driver_data *data = ctx->comp->mdp_dev->mdp_data; + enum mtk_mdp_comp_id public_id = ctx->comp->public_id; + + switch (public_id) { + case MDP_COMP_RSZ2: + merge = ctx->comp->mdp_dev->comp[MDP_COMP_MERGE2]; + break; + case MDP_COMP_RSZ3: + merge = ctx->comp->mdp_dev->comp[MDP_COMP_MERGE3]; + break; + default: + goto rsz_subfrm_done; + } + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rsz.subfrms[index].rsz_switch); + + id = data->comp_data[public_id].match.alias_id; + dev = ctx->comp->mdp_dev->mm_subsys[MDP_MM_SUBSYS_1].mmsys; + mtk_mmsys_vpp_rsz_merge_config(dev, id, reg, NULL); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, rsz.subfrms[index].merge_cfg); + MM_REG_WRITE(cmd, merge->subsys_id, merge->reg_base, + MDP_MERGE_CFG_0, reg, 0xFFFFFFFF); + MM_REG_WRITE(cmd, merge->subsys_id, merge->reg_base, + MDP_MERGE_CFG_4, reg, 0xFFFFFFFF); + MM_REG_WRITE(cmd, merge->subsys_id, merge->reg_base, + MDP_MERGE_CFG_24, reg, 0xFFFFFFFF); + MM_REG_WRITE(cmd, merge->subsys_id, merge->reg_base, + MDP_MERGE_CFG_25, reg, 0xFFFFFFFF); + + /* Bypass mode */ + MM_REG_WRITE(cmd, merge->subsys_id, merge->reg_base, + MDP_MERGE_CFG_12, BIT(0), 0xFFFFFFFF); + MM_REG_WRITE(cmd, merge->subsys_id, merge->reg_base, + MDP_MERGE_ENABLE, BIT(0), 0xFFFFFFFF); + } + +rsz_subfrm_done: return 0; } @@ -399,6 +628,9 @@ static int advance_rsz_subfrm(struct mdp_comp_ctx *ctx, if (CFG_CHECK(MT8183, p_id)) { csf_l = CFG_COMP(MT8183, ctx->param, subfrms[index].in.left); csf_r = CFG_COMP(MT8183, ctx->param, subfrms[index].in.right); + } else if (CFG_CHECK(MT8195, p_id)) { + csf_l = CFG_COMP(MT8195, ctx->param, subfrms[index].in.left); + csf_r = CFG_COMP(MT8195, ctx->param, subfrms[index].in.right); } if ((csf_r - csf_l + 1) <= 16) @@ -425,6 +657,11 @@ static int init_wrot(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) /* Reset WROT */ MM_REG_WRITE(cmd, subsys_id, base, VIDO_SOFT_RST, BIT(0), BIT(0)); MM_REG_POLL(cmd, subsys_id, base, VIDO_SOFT_RST_STAT, BIT(0), BIT(0)); + + /* Reset setting */ + if (CFG_CHECK(MT8195, p_id)) + MM_REG_WRITE(cmd, subsys_id, base, VIDO_CTRL, 0x0, 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, base, VIDO_SOFT_RST, 0x0, BIT(0)); MM_REG_POLL(cmd, subsys_id, base, VIDO_SOFT_RST_STAT, 0x0, BIT(0)); return 0; @@ -442,57 +679,118 @@ static int config_wrot_frame(struct mdp_comp_ctx *ctx, /* Write frame base address */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.iova[0]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.iova[0]); MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR, reg, 0xFFFFFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.iova[1]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.iova[1]); MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR_C, reg, 0xFFFFFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.iova[2]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.iova[2]); MM_REG_WRITE(cmd, subsys_id, base, VIDO_BASE_ADDR_V, reg, 0xFFFFFFFF); + + if (mdp_cfg && mdp_cfg->wrot_support_10bit) { + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.scan_10bit); + MM_REG_WRITE(cmd, subsys_id, base, VIDO_SCAN_10BIT, + reg, 0x0000000F); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.pending_zero); + MM_REG_WRITE(cmd, subsys_id, base, VIDO_PENDING_ZERO, + reg, 0x04000000); + } + + if (CFG_CHECK(MT8195, p_id)) { + reg = CFG_COMP(MT8195, ctx->param, wrot.bit_number); + MM_REG_WRITE(cmd, subsys_id, base, VIDO_CTRL_2, + reg, 0x00000007); + } + /* Write frame related registers */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.control); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.control); MM_REG_WRITE(cmd, subsys_id, base, VIDO_CTRL, reg, 0xF131510F); + + /* Write pre-ultra threshold */ + if (CFG_CHECK(MT8195, p_id)) { + reg = CFG_COMP(MT8195, ctx->param, wrot.pre_ultra); + MM_REG_WRITE(cmd, subsys_id, base, VIDO_DMA_PREULTRA, reg, + 0x00FFFFFF); + } + /* Write frame Y pitch */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.stride[0]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.stride[0]); MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE, reg, 0x0000FFFF); + /* Write frame UV pitch */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.stride[1]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.stride[1]); MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE_C, reg, 0xFFFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.stride[2]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.stride[2]); MM_REG_WRITE(cmd, subsys_id, base, VIDO_STRIDE_V, reg, 0xFFFF); + /* Write matrix control */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.mat_ctrl); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.mat_ctrl); MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAT_CTRL, reg, 0xF3); /* Set the fixed ALPHA as 0xFF */ MM_REG_WRITE(cmd, subsys_id, base, VIDO_DITHER, 0xFF000000, 0xFF000000); + /* Set VIDO_EOL_SEL */ MM_REG_WRITE(cmd, subsys_id, base, VIDO_RSV_1, BIT(31), BIT(31)); + /* Set VIDO_FIFO_TEST */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.fifo_test); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.fifo_test); + if (reg != 0) MM_REG_WRITE(cmd, subsys_id, base, VIDO_FIFO_TEST, reg, 0xFFF); + /* Filter enable */ if (mdp_cfg && mdp_cfg->wrot_filter_constraint) { if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.filter); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.filter); MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE, reg, 0x77); + + /* Turn off WROT DMA DCM */ + if (CFG_CHECK(MT8195, p_id)) + MM_REG_WRITE(cmd, subsys_id, base, VIDO_ROT_EN, + (0x1 << 23) + (0x1 << 20), 0x900000); } return 0; @@ -508,35 +806,54 @@ static int config_wrot_subfrm(struct mdp_comp_ctx *ctx, /* Write Y pixel offset */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].offset[0]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.subfrms[index].offset[0]); MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR, reg, 0x0FFFFFFF); + /* Write U pixel offset */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].offset[1]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.subfrms[index].offset[1]); MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR_C, reg, 0x0FFFFFFF); + /* Write V pixel offset */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].offset[2]); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.subfrms[index].offset[2]); MM_REG_WRITE(cmd, subsys_id, base, VIDO_OFST_ADDR_V, reg, 0x0FFFFFFF); + /* Write source size */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].src); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.subfrms[index].src); MM_REG_WRITE(cmd, subsys_id, base, VIDO_IN_SIZE, reg, 0x1FFF1FFF); + /* Write target size */ if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].clip); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.subfrms[index].clip); MM_REG_WRITE(cmd, subsys_id, base, VIDO_TAR_SIZE, reg, 0x1FFF1FFF); + if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].clip_ofst); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.subfrms[index].clip_ofst); MM_REG_WRITE(cmd, subsys_id, base, VIDO_CROP_OFST, reg, 0x1FFF1FFF); if (CFG_CHECK(MT8183, p_id)) reg = CFG_COMP(MT8183, ctx->param, wrot.subfrms[index].main_buf); + else if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, wrot.subfrms[index].main_buf); MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE, reg, 0x1FFF7F00); @@ -553,10 +870,15 @@ static int wait_wrot_event(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) phys_addr_t base = ctx->comp->reg_base; u8 subsys_id = ctx->comp->subsys_id; - if (ctx->comp->alias_id == 0) - MM_REG_WAIT(cmd, ctx->comp->gce_event[MDP_GCE_EVENT_EOF]); - else - dev_err(dev, "Do not support WROT1_DONE event\n"); + if (!mdp_cfg) + return -EINVAL; + + if (ctx->comp->alias_id >= mdp_cfg->wrot_event_num) { + dev_err(dev, "Invalid WROT event %d!\n", ctx->comp->alias_id); + return -EINVAL; + } + + MM_REG_WAIT(cmd, ctx->comp->gce_event[MDP_GCE_EVENT_EOF]); if (mdp_cfg && mdp_cfg->wrot_filter_constraint) MM_REG_WRITE(cmd, subsys_id, base, VIDO_MAIN_BUF_SIZE, 0x0, @@ -697,6 +1019,171 @@ static const struct mdp_comp_ops wdma_ops = { .wait_comp_event = wait_wdma_event, }; +static int reset_luma_hist(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + const struct mdp_platform_config *mdp_cfg = __get_plat_cfg(ctx); + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 hist_num, i; + + if (!mdp_cfg) + return -EINVAL; + + hist_num = mdp_cfg->tdshp_hist_num; + + /* Reset histogram */ + for (i = 0; i <= hist_num; i++) + MM_REG_WRITE_MASK(cmd, subsys_id, base, + (MDP_LUMA_HIST_INIT + (i << 2)), + 0, 0xFFFFFFFF); + + if (mdp_cfg->tdshp_constrain) + MM_REG_WRITE(cmd, subsys_id, base, + MDP_DC_TWO_D_W1_RESULT_INIT, 0, 0xFFFFFFFF); + + if (mdp_cfg->tdshp_contour) + for (i = 0; i < hist_num; i++) + MM_REG_WRITE_MASK(cmd, subsys_id, base, + (MDP_CONTOUR_HIST_INIT + (i << 2)), + 0, 0xFFFFFFFF); + + return 0; +} + +static int init_tdshp(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + + MM_REG_WRITE(cmd, subsys_id, base, MDP_TDSHP_CTRL, BIT(0), BIT(0)); + /* Enable FIFO */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_TDSHP_CFG, BIT(1), BIT(1)); + + return reset_luma_hist(ctx, cmd); +} + +static int config_tdshp_frame(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, tdshp.cfg); + MM_REG_WRITE(cmd, subsys_id, base, MDP_TDSHP_CFG, reg, BIT(0)); + + return 0; +} + +static int config_tdshp_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, tdshp.subfrms[index].src); + MM_REG_WRITE(cmd, subsys_id, base, MDP_TDSHP_INPUT_SIZE, + reg, MDP_TDSHP_INPUT_SIZE_MASK); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, tdshp.subfrms[index].clip_ofst); + MM_REG_WRITE(cmd, subsys_id, base, MDP_TDSHP_OUTPUT_OFFSET, + reg, 0x00FF00FF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, tdshp.subfrms[index].clip); + MM_REG_WRITE(cmd, subsys_id, base, MDP_TDSHP_OUTPUT_SIZE, + reg, MDP_TDSHP_OUTPUT_SIZE_MASK); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, tdshp.subfrms[index].hist_cfg_0); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HIST_CFG_00, reg, 0xFFFFFFFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, tdshp.subfrms[index].hist_cfg_1); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HIST_CFG_01, reg, 0xFFFFFFFF); + + return 0; +} + +static const struct mdp_comp_ops tdshp_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_tdshp, + .config_frame = config_tdshp_frame, + .config_subfrm = config_tdshp_subfrm, +}; + +static int init_color(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + + MM_REG_WRITE(cmd, subsys_id, base, + MDP_COLOR_START, 0x1, BIT(1) | BIT(0)); + MM_REG_WRITE(cmd, subsys_id, base, + MDP_COLOR_WIN_X_MAIN, 0xFFFF0000, 0xFFFFFFFF); + MM_REG_WRITE(cmd, subsys_id, base, + MDP_COLOR_WIN_Y_MAIN, 0xFFFF0000, 0xFFFFFFFF); + + /* Reset color matrix */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_COLOR_CM1_EN, 0x0, BIT(0)); + MM_REG_WRITE(cmd, subsys_id, base, MDP_COLOR_CM2_EN, 0x0, BIT(0)); + + /* Enable interrupt */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_COLOR_INTEN, 0x7, 0x7); + + MM_REG_WRITE(cmd, subsys_id, base, MDP_COLOR_OUT_SEL, 0x333, 0x333); + + return 0; +} + +static int config_color_frame(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, color.start); + MM_REG_WRITE(cmd, subsys_id, base, MDP_COLOR_START, + reg, MDP_COLOR_START_MASK); + + return 0; +} + +static int config_color_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, color.subfrms[index].in_hsize); + MM_REG_WRITE(cmd, subsys_id, base, MDP_COLOR_INTERNAL_IP_WIDTH, + reg, 0x00003FFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, color.subfrms[index].in_vsize); + MM_REG_WRITE(cmd, subsys_id, base, MDP_COLOR_INTERNAL_IP_HEIGHT, + reg, 0x00003FFF); + + return 0; +} + +static const struct mdp_comp_ops color_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_color, + .config_frame = config_color_frame, + .config_subfrm = config_color_subfrm, +}; + static int init_ccorr(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) { phys_addr_t base = ctx->comp->reg_base; @@ -738,12 +1225,318 @@ static const struct mdp_comp_ops ccorr_ops = { .config_subfrm = config_ccorr_subfrm, }; +static int init_aal(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + + /* Always set MDP_AAL enable to 1 */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_AAL_EN, BIT(0), BIT(0)); + + return 0; +} + +static int config_aal_frame(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, aal.cfg_main); + MM_REG_WRITE(cmd, subsys_id, base, MDP_AAL_CFG_MAIN, reg, BIT(7)); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, aal.cfg); + MM_REG_WRITE(cmd, subsys_id, base, MDP_AAL_CFG, reg, BIT(0)); + + return 0; +} + +static int config_aal_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, aal.subfrms[index].src); + MM_REG_WRITE(cmd, subsys_id, base, MDP_AAL_SIZE, + reg, MDP_AAL_SIZE_MASK); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, aal.subfrms[index].clip_ofst); + MM_REG_WRITE(cmd, subsys_id, base, MDP_AAL_OUTPUT_OFFSET, + reg, 0x00FF00FF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, aal.subfrms[index].clip); + MM_REG_WRITE(cmd, subsys_id, base, MDP_AAL_OUTPUT_SIZE, + reg, MDP_AAL_OUTPUT_SIZE_MASK); + + return 0; +} + +static const struct mdp_comp_ops aal_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_aal, + .config_frame = config_aal_frame, + .config_subfrm = config_aal_subfrm, +}; + +static int init_hdr(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + + /* Always set MDP_HDR enable to 1 */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_TOP, BIT(0), BIT(0)); + + return 0; +} + +static int config_hdr_frame(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, hdr.top); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_TOP, reg, BIT(29) | BIT(28)); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, hdr.relay); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_RELAY, reg, BIT(0)); + + return 0; +} + +static int config_hdr_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, hdr.subfrms[index].win_size); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_TILE_POS, + reg, MDP_HDR_TILE_POS_MASK); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, hdr.subfrms[index].src); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_SIZE_0, reg, 0x1FFF1FFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, hdr.subfrms[index].clip_ofst0); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_SIZE_1, reg, 0x1FFF1FFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, hdr.subfrms[index].clip_ofst1); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_SIZE_2, reg, 0x1FFF1FFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, hdr.subfrms[index].hist_ctrl_0); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_HIST_CTRL_0, reg, 0x00003FFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, hdr.subfrms[index].hist_ctrl_1); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_HIST_CTRL_1, reg, 0x00003FFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, hdr.subfrms[index].hdr_top); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_TOP, reg, BIT(6) | BIT(5)); + + /* Enable histogram */ + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, hdr.subfrms[index].hist_addr); + MM_REG_WRITE(cmd, subsys_id, base, MDP_HDR_HIST_ADDR, reg, BIT(9)); + + return 0; +} + +static const struct mdp_comp_ops hdr_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_hdr, + .config_frame = config_hdr_frame, + .config_subfrm = config_hdr_subfrm, +}; + +static int init_fg(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + + MM_REG_WRITE(cmd, subsys_id, base, MDP_FG_TRIGGER, BIT(2), BIT(2)); + MM_REG_WRITE(cmd, subsys_id, base, MDP_FG_TRIGGER, 0x0, BIT(2)); + + return 0; +} + +static int config_fg_frame(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, fg.ctrl_0); + MM_REG_WRITE(cmd, subsys_id, base, MDP_FG_FG_CTRL_0, reg, BIT(0)); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, fg.ck_en); + MM_REG_WRITE(cmd, subsys_id, base, MDP_FG_FG_CK_EN, reg, 0x7); + + return 0; +} + +static int config_fg_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, fg.subfrms[index].info_0); + MM_REG_WRITE(cmd, subsys_id, base, MDP_FG_TILE_INFO_0, reg, 0xFFFFFFFF); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, fg.subfrms[index].info_1); + MM_REG_WRITE(cmd, subsys_id, base, MDP_FG_TILE_INFO_1, reg, 0xFFFFFFFF); + + return 0; +} + +static const struct mdp_comp_ops fg_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_fg, + .config_frame = config_fg_frame, + .config_subfrm = config_fg_subfrm, +}; + +static int init_ovl(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + + MM_REG_WRITE(cmd, subsys_id, base, MDP_OVL_EN, + BIT(0), MDP_OVL_EN_MASK); + + /* Set to relay mode */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_OVL_SRC_CON, + BIT(9), MDP_OVL_SRC_CON_MASK); + MM_REG_WRITE(cmd, subsys_id, base, MDP_OVL_DP_CON, + BIT(0), MDP_OVL_DP_CON_MASK); + + return 0; +} + +static int config_ovl_frame(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, + const struct v4l2_rect *compose) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, ovl.L0_con); + MM_REG_WRITE(cmd, subsys_id, base, MDP_OVL_L0_CON, reg, BIT(29) | BIT(28)); + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, ovl.src_con); + MM_REG_WRITE(cmd, subsys_id, base, MDP_OVL_SRC_CON, reg, BIT(0)); + + return 0; +} + +static int config_ovl_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, ovl.subfrms[index].L0_src_size); + MM_REG_WRITE(cmd, subsys_id, base, MDP_OVL_L0_SRC_SIZE, + reg, MDP_OVL_L0_SRC_SIZE_MASK); + + /* Setup output size */ + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, ovl.subfrms[index].roi_size); + MM_REG_WRITE(cmd, subsys_id, base, MDP_OVL_ROI_SIZE, + reg, MDP_OVL_ROI_SIZE_MASK); + + return 0; +} + +static const struct mdp_comp_ops ovl_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_ovl, + .config_frame = config_ovl_frame, + .config_subfrm = config_ovl_subfrm, +}; + +static int init_pad(struct mdp_comp_ctx *ctx, struct mdp_cmdq_cmd *cmd) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + + MM_REG_WRITE(cmd, subsys_id, base, MDP_PAD_CON, + BIT(1), MDP_PAD_CON_MASK); + /* Reset */ + MM_REG_WRITE(cmd, subsys_id, base, MDP_PAD_W_SIZE, + 0, MDP_PAD_W_SIZE_MASK); + MM_REG_WRITE(cmd, subsys_id, base, MDP_PAD_H_SIZE, + 0, MDP_PAD_H_SIZE_MASK); + + return 0; +} + +static int config_pad_subfrm(struct mdp_comp_ctx *ctx, + struct mdp_cmdq_cmd *cmd, u32 index) +{ + phys_addr_t base = ctx->comp->reg_base; + u16 subsys_id = ctx->comp->subsys_id; + u32 reg = 0; + + if (CFG_CHECK(MT8195, p_id)) + reg = CFG_COMP(MT8195, ctx->param, pad.subfrms[index].pic_size); + MM_REG_WRITE(cmd, subsys_id, base, MDP_PAD_PIC_SIZE, + reg, MDP_PAD_PIC_SIZE_MASK); + + return 0; +} + +static const struct mdp_comp_ops pad_ops = { + .get_comp_flag = get_comp_flag, + .init_comp = init_pad, + .config_subfrm = config_pad_subfrm, +}; + static const struct mdp_comp_ops *mdp_comp_ops[MDP_COMP_TYPE_COUNT] = { [MDP_COMP_TYPE_RDMA] = &rdma_ops, [MDP_COMP_TYPE_RSZ] = &rsz_ops, [MDP_COMP_TYPE_WROT] = &wrot_ops, [MDP_COMP_TYPE_WDMA] = &wdma_ops, + [MDP_COMP_TYPE_TDSHP] = &tdshp_ops, + [MDP_COMP_TYPE_COLOR] = &color_ops, [MDP_COMP_TYPE_CCORR] = &ccorr_ops, + [MDP_COMP_TYPE_AAL] = &aal_ops, + [MDP_COMP_TYPE_HDR] = &hdr_ops, + [MDP_COMP_TYPE_FG] = &fg_ops, + [MDP_COMP_TYPE_OVL] = &ovl_ops, + [MDP_COMP_TYPE_PAD] = &pad_ops, }; static const struct of_device_id mdp_comp_dt_ids[] __maybe_unused = { @@ -762,6 +1555,42 @@ static const struct of_device_id mdp_comp_dt_ids[] __maybe_unused = { }, { .compatible = "mediatek,mt8183-mdp3-wdma", .data = (void *)MDP_COMP_TYPE_WDMA, + }, { + .compatible = "mediatek,mt8195-mdp3-rdma", + .data = (void *)MDP_COMP_TYPE_RDMA, + }, { + .compatible = "mediatek,mt8195-mdp3-split", + .data = (void *)MDP_COMP_TYPE_SPLIT, + }, { + .compatible = "mediatek,mt8195-mdp3-stitch", + .data = (void *)MDP_COMP_TYPE_STITCH, + }, { + .compatible = "mediatek,mt8195-mdp3-fg", + .data = (void *)MDP_COMP_TYPE_FG, + }, { + .compatible = "mediatek,mt8195-mdp3-hdr", + .data = (void *)MDP_COMP_TYPE_HDR, + }, { + .compatible = "mediatek,mt8195-mdp3-aal", + .data = (void *)MDP_COMP_TYPE_AAL, + }, { + .compatible = "mediatek,mt8195-mdp3-merge", + .data = (void *)MDP_COMP_TYPE_MERGE, + }, { + .compatible = "mediatek,mt8195-mdp3-tdshp", + .data = (void *)MDP_COMP_TYPE_TDSHP, + }, { + .compatible = "mediatek,mt8195-mdp3-color", + .data = (void *)MDP_COMP_TYPE_COLOR, + }, { + .compatible = "mediatek,mt8195-mdp3-ovl", + .data = (void *)MDP_COMP_TYPE_OVL, + }, { + .compatible = "mediatek,mt8195-mdp3-padding", + .data = (void *)MDP_COMP_TYPE_PAD, + }, { + .compatible = "mediatek,mt8195-mdp3-tcc", + .data = (void *)MDP_COMP_TYPE_TCC, }, {} }; @@ -853,9 +1682,26 @@ int mdp_comp_clocks_on(struct device *dev, struct mdp_comp *comps, int num) int i, ret; for (i = 0; i < num; i++) { + struct mdp_dev *m = comps[i].mdp_dev; + enum mtk_mdp_comp_id id; + const struct mdp_comp_blend *b; + + /* Bypass the dummy component*/ + if (!m) + continue; + ret = mdp_comp_clock_on(dev, &comps[i]); if (ret) return ret; + + id = comps[i].public_id; + b = &m->mdp_data->comp_data[id].blend; + + if (b && b->aid_clk) { + ret = mdp_comp_clock_on(dev, m->comp[b->b_id]); + if (ret) + return ret; + } } return 0; @@ -865,8 +1711,23 @@ void mdp_comp_clocks_off(struct device *dev, struct mdp_comp *comps, int num) { int i; - for (i = 0; i < num; i++) + for (i = 0; i < num; i++) { + struct mdp_dev *m = comps[i].mdp_dev; + enum mtk_mdp_comp_id id; + const struct mdp_comp_blend *b; + + /* Bypass the dummy component*/ + if (!m) + continue; + mdp_comp_clock_off(dev, &comps[i]); + + id = comps[i].public_id; + b = &m->mdp_data->comp_data[id].blend; + + if (b && b->aid_clk) + mdp_comp_clock_off(dev, m->comp[b->b_id]); + } } static int mdp_get_subsys_id(struct mdp_dev *mdp, struct device *dev, @@ -1174,6 +2035,8 @@ int mdp_comp_ctx_config(struct mdp_dev *mdp, struct mdp_comp_ctx *ctx, if (CFG_CHECK(MT8183, p_id)) arg = CFG_COMP(MT8183, param, type); + else if (CFG_CHECK(MT8195, p_id)) + arg = CFG_COMP(MT8195, param, type); else return -EINVAL; public_id = mdp_cfg_get_id_public(mdp, arg); @@ -1191,16 +2054,22 @@ int mdp_comp_ctx_config(struct mdp_dev *mdp, struct mdp_comp_ctx *ctx, ctx->param = param; if (CFG_CHECK(MT8183, p_id)) arg = CFG_COMP(MT8183, param, input); + else if (CFG_CHECK(MT8195, p_id)) + arg = CFG_COMP(MT8195, param, input); else return -EINVAL; ctx->input = &frame->inputs[arg]; if (CFG_CHECK(MT8183, p_id)) idx = CFG_COMP(MT8183, param, num_outputs); + else if (CFG_CHECK(MT8195, p_id)) + idx = CFG_COMP(MT8195, param, num_outputs); else return -EINVAL; for (i = 0; i < idx; i++) { if (CFG_CHECK(MT8183, p_id)) arg = CFG_COMP(MT8183, param, outputs[i]); + else if (CFG_CHECK(MT8195, p_id)) + arg = CFG_COMP(MT8195, param, outputs[i]); else return -EINVAL; ctx->outputs[i] = &frame->outputs[arg]; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h index 20d2bcb77e..3e5d2da1c8 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-comp.h @@ -84,22 +84,66 @@ enum mtk_mdp_comp_id { MDP_COMP_CAMIN, /* 9 */ MDP_COMP_CAMIN2, /* 10 */ MDP_COMP_RDMA0, /* 11 */ - MDP_COMP_AAL0, /* 12 */ - MDP_COMP_CCORR0, /* 13 */ - MDP_COMP_RSZ0, /* 14 */ - MDP_COMP_RSZ1, /* 15 */ - MDP_COMP_TDSHP0, /* 16 */ - MDP_COMP_COLOR0, /* 17 */ - MDP_COMP_PATH0_SOUT, /* 18 */ - MDP_COMP_PATH1_SOUT, /* 19 */ - MDP_COMP_WROT0, /* 20 */ - MDP_COMP_WDMA, /* 21 */ - - /* Dummy Engine */ - MDP_COMP_RDMA1, /* 22 */ - MDP_COMP_RSZ2, /* 23 */ - MDP_COMP_TDSHP1, /* 24 */ - MDP_COMP_WROT1, /* 25 */ + MDP_COMP_RDMA1, /* 12 */ + MDP_COMP_RDMA2, /* 13 */ + MDP_COMP_RDMA3, /* 14 */ + MDP_COMP_AAL0, /* 15 */ + MDP_COMP_AAL1, /* 16 */ + MDP_COMP_AAL2, /* 17 */ + MDP_COMP_AAL3, /* 18 */ + MDP_COMP_CCORR0, /* 19 */ + MDP_COMP_RSZ0, /* 20 */ + MDP_COMP_RSZ1, /* 21 */ + MDP_COMP_RSZ2, /* 22 */ + MDP_COMP_RSZ3, /* 23 */ + MDP_COMP_TDSHP0, /* 24 */ + MDP_COMP_TDSHP1, /* 25 */ + MDP_COMP_TDSHP2, /* 26 */ + MDP_COMP_TDSHP3, /* 27 */ + MDP_COMP_COLOR0, /* 28 */ + MDP_COMP_COLOR1, /* 29 */ + MDP_COMP_COLOR2, /* 30 */ + MDP_COMP_COLOR3, /* 31 */ + MDP_COMP_PATH0_SOUT, /* 32 */ + MDP_COMP_PATH1_SOUT, /* 33 */ + MDP_COMP_WROT0, /* 34 */ + MDP_COMP_WROT1, /* 35 */ + MDP_COMP_WROT2, /* 36 */ + MDP_COMP_WROT3, /* 37 */ + MDP_COMP_WDMA, /* 38 */ + MDP_COMP_SPLIT, /* 39 */ + MDP_COMP_SPLIT2, /* 40 */ + MDP_COMP_STITCH, /* 41 */ + MDP_COMP_FG0, /* 42 */ + MDP_COMP_FG1, /* 43 */ + MDP_COMP_FG2, /* 44 */ + MDP_COMP_FG3, /* 45 */ + MDP_COMP_TO_SVPP2MOUT, /* 46 */ + MDP_COMP_TO_SVPP3MOUT, /* 47 */ + MDP_COMP_TO_WARP0MOUT, /* 48 */ + MDP_COMP_TO_WARP1MOUT, /* 49 */ + MDP_COMP_VPP0_SOUT, /* 50 */ + MDP_COMP_VPP1_SOUT, /* 51 */ + MDP_COMP_PQ0_SOUT, /* 52 */ + MDP_COMP_PQ1_SOUT, /* 53 */ + MDP_COMP_HDR0, /* 54 */ + MDP_COMP_HDR1, /* 55 */ + MDP_COMP_HDR2, /* 56 */ + MDP_COMP_HDR3, /* 57 */ + MDP_COMP_OVL0, /* 58 */ + MDP_COMP_OVL1, /* 59 */ + MDP_COMP_PAD0, /* 60 */ + MDP_COMP_PAD1, /* 61 */ + MDP_COMP_PAD2, /* 62 */ + MDP_COMP_PAD3, /* 63 */ + MDP_COMP_TCC0, /* 64 */ + MDP_COMP_TCC1, /* 65 */ + MDP_COMP_MERGE2, /* 66 */ + MDP_COMP_MERGE3, /* 67 */ + MDP_COMP_VDO0DL0, /* 68 */ + MDP_COMP_VDO1DL0, /* 69 */ + MDP_COMP_VDO0DL1, /* 70 */ + MDP_COMP_VDO1DL1, /* 71 */ MDP_MAX_COMP_COUNT /* ALWAYS keep at the end */ }; @@ -117,12 +161,21 @@ enum mdp_comp_type { MDP_COMP_TYPE_COLOR, MDP_COMP_TYPE_DRE, MDP_COMP_TYPE_CCORR, + MDP_COMP_TYPE_AAL, + MDP_COMP_TYPE_TCC, MDP_COMP_TYPE_HDR, + MDP_COMP_TYPE_SPLIT, + MDP_COMP_TYPE_STITCH, + MDP_COMP_TYPE_FG, + MDP_COMP_TYPE_OVL, + MDP_COMP_TYPE_PAD, + MDP_COMP_TYPE_MERGE, MDP_COMP_TYPE_IMGI, MDP_COMP_TYPE_WPEI, MDP_COMP_TYPE_EXTO, /* External path */ MDP_COMP_TYPE_DL_PATH, /* Direct-link path */ + MDP_COMP_TYPE_DUMMY, MDP_COMP_TYPE_COUNT /* ALWAYS keep at the end */ }; @@ -138,6 +191,7 @@ struct mdp_comp_match { enum mdp_comp_type type; u32 alias_id; s32 inner_id; + s32 subsys_id; }; /* Used to describe the item order in MDP property */ @@ -147,9 +201,16 @@ struct mdp_comp_info { u32 dts_reg_ofst; }; +struct mdp_comp_blend { + enum mtk_mdp_comp_id b_id; + bool aid_mod; + bool aid_clk; +}; + struct mdp_comp_data { struct mdp_comp_match match; struct mdp_comp_info info; + struct mdp_comp_blend blend; }; struct mdp_comp_ops; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c index 94f4ed7852..5209f531ef 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.c @@ -21,14 +21,21 @@ static const struct of_device_id mdp_of_ids[] = { { .compatible = "mediatek,mt8183-mdp3-rdma", .data = &mt8183_mdp_driver_data, }, + { .compatible = "mediatek,mt8195-mdp3-rdma", + .data = &mt8195_mdp_driver_data, + }, + { .compatible = "mediatek,mt8195-mdp3-wrot", + .data = &mt8195_mdp_driver_data, + }, {}, }; MODULE_DEVICE_TABLE(of, mdp_of_ids); static struct platform_device *__get_pdev_by_id(struct platform_device *pdev, + struct platform_device *from, enum mdp_infra_id id) { - struct device_node *node; + struct device_node *node, *f = NULL; struct platform_device *mdp_pdev = NULL; const struct mtk_mdp_driver_data *mdp_data; const char *compat; @@ -46,9 +53,14 @@ static struct platform_device *__get_pdev_by_id(struct platform_device *pdev, dev_err(&pdev->dev, "have no driver data to find node\n"); return NULL; } + compat = mdp_data->mdp_probe_infra[id].compatible; + if (strlen(compat) == 0) + return NULL; - node = of_find_compatible_node(NULL, NULL, compat); + if (from) + f = from->dev.of_node; + node = of_find_compatible_node(f, NULL, compat); if (WARN_ON(!node)) { dev_err(&pdev->dev, "find node from id %d failed\n", id); return NULL; @@ -130,6 +142,10 @@ void mdp_video_device_release(struct video_device *vdev) struct mdp_dev *mdp = (struct mdp_dev *)video_get_drvdata(vdev); int i; + for (i = 0; i < mdp->mdp_data->pp_used; i++) + if (mdp->cmdq_clt[i]) + cmdq_mbox_destroy(mdp->cmdq_clt[i]); + scp_put(mdp->scp); destroy_workqueue(mdp->job_wq); @@ -140,19 +156,72 @@ void mdp_video_device_release(struct video_device *vdev) vb2_dma_contig_clear_max_seg_size(&mdp->pdev->dev); mdp_comp_destroy(mdp); - for (i = 0; i < MDP_PIPE_MAX; i++) - mtk_mutex_put(mdp->mdp_mutex[i]); + for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) { + enum mdp_mm_subsys_id idx; + struct mtk_mutex *m; + u32 m_id; + + idx = mdp->mdp_data->pipe_info[i].sub_id; + m_id = mdp->mdp_data->pipe_info[i].mutex_id; + m = mdp->mm_subsys[idx].mdp_mutex[m_id]; + if (!IS_ERR_OR_NULL(m)) + mtk_mutex_put(m); + } mdp_vpu_shared_mem_free(&mdp->vpu); v4l2_m2m_release(mdp->m2m_dev); kfree(mdp); } +static int mdp_mm_subsys_deploy(struct mdp_dev *mdp, enum mdp_infra_id id) +{ + struct platform_device *mm_pdev = NULL; + struct device **dev; + int i; + + if (!mdp) + return -EINVAL; + + for (i = 0; i < MDP_MM_SUBSYS_MAX; i++) { + const char *compat; + enum mdp_infra_id sub_id = id + i; + + switch (id) { + case MDP_INFRA_MMSYS: + dev = &mdp->mm_subsys[i].mmsys; + break; + case MDP_INFRA_MUTEX: + dev = &mdp->mm_subsys[i].mutex; + break; + default: + dev_err(&mdp->pdev->dev, "Unknown infra id %d", id); + return -EINVAL; + } + + /* + * Not every chip has multiple multimedia subsystems, so + * the config may be null. + */ + compat = mdp->mdp_data->mdp_probe_infra[sub_id].compatible; + if (strlen(compat) == 0) + continue; + + mm_pdev = __get_pdev_by_id(mdp->pdev, mm_pdev, sub_id); + if (WARN_ON(!mm_pdev)) + return -ENODEV; + + *dev = &mm_pdev->dev; + } + + return 0; +} + static int mdp_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct mdp_dev *mdp; struct platform_device *mm_pdev; + struct resource *res; int ret, i, mutex_id; mdp = kzalloc(sizeof(*mdp), GFP_KERNEL); @@ -164,25 +233,34 @@ static int mdp_probe(struct platform_device *pdev) mdp->pdev = pdev; mdp->mdp_data = of_device_get_match_data(&pdev->dev); - mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MMSYS); - if (!mm_pdev) { - ret = -ENODEV; - goto err_destroy_device; + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); + if (res->start != mdp->mdp_data->mdp_con_res) { + platform_set_drvdata(pdev, mdp); + goto success_return; } - mdp->mdp_mmsys = &mm_pdev->dev; - mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_MUTEX); - if (WARN_ON(!mm_pdev)) { - ret = -ENODEV; + ret = mdp_mm_subsys_deploy(mdp, MDP_INFRA_MMSYS); + if (ret) goto err_destroy_device; - } + + ret = mdp_mm_subsys_deploy(mdp, MDP_INFRA_MUTEX); + if (ret) + goto err_destroy_device; + for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) { + enum mdp_mm_subsys_id idx; + struct mtk_mutex **m; + + idx = mdp->mdp_data->pipe_info[i].sub_id; mutex_id = mdp->mdp_data->pipe_info[i].mutex_id; - if (!IS_ERR_OR_NULL(mdp->mdp_mutex[mutex_id])) + m = &mdp->mm_subsys[idx].mdp_mutex[mutex_id]; + + if (!IS_ERR_OR_NULL(*m)) continue; - mdp->mdp_mutex[mutex_id] = mtk_mutex_get(&mm_pdev->dev); - if (IS_ERR(mdp->mdp_mutex[mutex_id])) { - ret = PTR_ERR(mdp->mdp_mutex[mutex_id]); + + *m = mtk_mutex_get(mdp->mm_subsys[idx].mutex); + if (IS_ERR(*m)) { + ret = PTR_ERR(*m); goto err_free_mutex; } } @@ -210,7 +288,7 @@ static int mdp_probe(struct platform_device *pdev) mdp->scp = scp_get(pdev); if (!mdp->scp) { - mm_pdev = __get_pdev_by_id(pdev, MDP_INFRA_SCP); + mm_pdev = __get_pdev_by_id(pdev, NULL, MDP_INFRA_SCP); if (WARN_ON(!mm_pdev)) { dev_err(&pdev->dev, "Could not get scp device\n"); ret = -ENODEV; @@ -225,10 +303,12 @@ static int mdp_probe(struct platform_device *pdev) mutex_init(&mdp->vpu_lock); mutex_init(&mdp->m2m_lock); - mdp->cmdq_clt = cmdq_mbox_create(dev, 0); - if (IS_ERR(mdp->cmdq_clt)) { - ret = PTR_ERR(mdp->cmdq_clt); - goto err_put_scp; + for (i = 0; i < mdp->mdp_data->pp_used; i++) { + mdp->cmdq_clt[i] = cmdq_mbox_create(dev, i); + if (IS_ERR(mdp->cmdq_clt[i])) { + ret = PTR_ERR(mdp->cmdq_clt[i]); + goto err_mbox_destroy; + } } init_waitqueue_head(&mdp->callback_wq); @@ -250,14 +330,15 @@ static int mdp_probe(struct platform_device *pdev) goto err_unregister_device; } +success_return: dev_dbg(dev, "mdp-%d registered successfully\n", pdev->id); return 0; err_unregister_device: v4l2_device_unregister(&mdp->v4l2_dev); err_mbox_destroy: - cmdq_mbox_destroy(mdp->cmdq_clt); -err_put_scp: + while (--i >= 0) + cmdq_mbox_destroy(mdp->cmdq_clt[i]); scp_put(mdp->scp); err_destroy_clock_wq: destroy_workqueue(mdp->clock_wq); @@ -266,9 +347,16 @@ err_destroy_job_wq: err_deinit_comp: mdp_comp_destroy(mdp); err_free_mutex: - for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) - if (!IS_ERR_OR_NULL(mdp->mdp_mutex[i])) - mtk_mutex_put(mdp->mdp_mutex[i]); + for (i = 0; i < mdp->mdp_data->pipe_info_len; i++) { + enum mdp_mm_subsys_id idx; + struct mtk_mutex *m; + + idx = mdp->mdp_data->pipe_info[i].sub_id; + mutex_id = mdp->mdp_data->pipe_info[i].mutex_id; + m = mdp->mm_subsys[idx].mdp_mutex[mutex_id]; + if (!IS_ERR_OR_NULL(m)) + mtk_mutex_put(m); + } err_destroy_device: kfree(mdp); err_return: diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h index 7e21d226ce..8c09e984fd 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-core.h @@ -19,12 +19,24 @@ #define MDP_PHANDLE_NAME "mediatek,mdp3" enum mdp_infra_id { + /* + * Due to the sequential nature of function "mdp_mm_subsys_deploy", + * adding new enum. necessitates careful consideration. + */ MDP_INFRA_MMSYS, + MDP_INFRA_MMSYS2, MDP_INFRA_MUTEX, + MDP_INFRA_MUTEX2, MDP_INFRA_SCP, MDP_INFRA_MAX }; +enum mdp_mm_subsys_id { + MDP_MM_SUBSYS_0, + MDP_MM_SUBSYS_1, + MDP_MM_SUBSYS_MAX, +}; + enum mdp_buffer_usage { MDP_BUFFER_USAGE_HW_READ, MDP_BUFFER_USAGE_MDP, @@ -37,8 +49,16 @@ struct mdp_platform_config { bool rdma_support_10bit; bool rdma_rsz1_sram_sharing; bool rdma_upsample_repeat_only; + bool rdma_esl_setting; + u32 rdma_event_num; bool rsz_disable_dcm_small_sample; + bool rsz_etc_control; bool wrot_filter_constraint; + bool wrot_support_10bit; + u32 wrot_event_num; + u32 tdshp_hist_num; + bool tdshp_constrain; + bool tdshp_contour; }; /* indicate which mutex is used by each pipepline */ @@ -47,11 +67,27 @@ enum mdp_pipe_id { MDP_PIPE_WPEI2, MDP_PIPE_IMGI, MDP_PIPE_RDMA0, + MDP_PIPE_RDMA1, + MDP_PIPE_RDMA2, + MDP_PIPE_RDMA3, + MDP_PIPE_SPLIT, + MDP_PIPE_SPLIT2, + MDP_PIPE_VPP0_SOUT, + MDP_PIPE_VPP1_SOUT, MDP_PIPE_MAX }; +/* MDP parallel pipe control */ +enum { + MDP_PP_USED_1 = 1, + MDP_PP_USED_2 = 2, +}; + +#define MDP_PP_MAX MDP_PP_USED_2 + struct mtk_mdp_driver_data { const int mdp_plat_id; + const resource_size_t mdp_con_res; const struct of_device_id *mdp_probe_infra; const struct mdp_platform_config *mdp_cfg; const u32 *mdp_mutex_table_idx; @@ -63,12 +99,19 @@ struct mtk_mdp_driver_data { const struct mdp_limit *def_limit; const struct mdp_pipe_info *pipe_info; unsigned int pipe_info_len; + const struct v4l2_rect *pp_criteria; + const u8 pp_used; +}; + +struct mdp_mm_subsys { + struct device *mmsys; + struct device *mutex; + struct mtk_mutex *mdp_mutex[MDP_PIPE_MAX]; }; struct mdp_dev { struct platform_device *pdev; - struct device *mdp_mmsys; - struct mtk_mutex *mdp_mutex[MDP_PIPE_MAX]; + struct mdp_mm_subsys mm_subsys[MDP_MM_SUBSYS_MAX]; struct mdp_comp *comp[MDP_MAX_COMP_COUNT]; const struct mtk_mdp_driver_data *mdp_data; @@ -82,7 +125,7 @@ struct mdp_dev { s32 vpu_count; u32 id_count; struct ida mdp_ida; - struct cmdq_client *cmdq_clt; + struct cmdq_client *cmdq_clt[MDP_PP_MAX]; wait_queue_head_t callback_wq; struct v4l2_device v4l2_dev; @@ -96,6 +139,7 @@ struct mdp_dev { struct mdp_pipe_info { enum mdp_pipe_id pipe_id; + enum mdp_mm_subsys_id sub_id; u32 mutex_id; }; diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c index a298c1b15b..35a8b059bd 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-m2m.c @@ -87,6 +87,9 @@ static void mdp_m2m_device_run(void *priv) dst_vb = v4l2_m2m_next_dst_buf(ctx->m2m_ctx); mdp_set_dst_config(¶m.outputs[0], frame, &dst_vb->vb2_buf); + if (mdp_check_pp_enable(ctx->mdp_dev, frame)) + param.type = MDP_STREAM_TYPE_DUAL_BITBLT; + ret = mdp_vpu_process(&ctx->mdp_dev->vpu, ¶m); if (ret) { dev_err(&ctx->mdp_dev->pdev->dev, @@ -101,6 +104,18 @@ static void mdp_m2m_device_run(void *priv) task.cb_data = NULL; task.mdp_ctx = ctx; + if (atomic_read(&ctx->mdp_dev->job_count)) { + ret = wait_event_timeout(ctx->mdp_dev->callback_wq, + !atomic_read(&ctx->mdp_dev->job_count), + 2 * HZ); + if (ret == 0) { + dev_err(&ctx->mdp_dev->pdev->dev, + "%d jobs not yet done\n", + atomic_read(&ctx->mdp_dev->job_count)); + goto worker_end; + } + } + ret = mdp_cmdq_send(ctx->mdp_dev, &task); if (ret) { dev_err(&ctx->mdp_dev->pdev->dev, diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c index 9b436b911d..657356f877 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.c @@ -304,6 +304,24 @@ int mdp_check_scaling_ratio(const struct v4l2_rect *crop, return 0; } +bool mdp_check_pp_enable(struct mdp_dev *mdp, struct mdp_frame *frame) +{ + u32 s, r1, r2; + + if (!mdp || !frame) + return false; + + if (!mdp->mdp_data->pp_criteria) + return false; + + s = mdp->mdp_data->pp_criteria->width * + mdp->mdp_data->pp_criteria->height; + r1 = frame->crop.c.width * frame->crop.c.height; + r2 = frame->compose.width * frame->compose.height; + + return (r1 >= s || r2 >= s); +} + /* Stride that is accepted by MDP HW */ static u32 mdp_fmt_get_stride(const struct mdp_format *fmt, u32 bytesperline, unsigned int plane) diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h index e9ab8ac2c0..b0c8f9f008 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-regs.h @@ -368,6 +368,7 @@ int mdp_try_crop(struct mdp_m2m_ctx *ctx, struct v4l2_rect *r, int mdp_check_scaling_ratio(const struct v4l2_rect *crop, const struct v4l2_rect *compose, s32 rotation, const struct mdp_limit *limit); +bool mdp_check_pp_enable(struct mdp_dev *mdp, struct mdp_frame *frame); void mdp_set_src_config(struct img_input *in, struct mdp_frame *frame, struct vb2_buffer *vb); void mdp_set_dst_config(struct img_output *out, diff --git a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c index 49fc2e9d45..da3a892ad8 100644 --- a/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c +++ b/drivers/media/platform/mediatek/mdp3/mtk-mdp3-vpu.c @@ -198,6 +198,7 @@ int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp, }; struct mdp_dev *mdp = vpu_to_mdp(vpu); int err; + u8 pp_num = mdp->mdp_data->pp_used; init_completion(&vpu->ipi_acked); vpu->scp = scp; @@ -211,7 +212,7 @@ int mdp_vpu_dev_init(struct mdp_vpu_dev *vpu, struct mtk_scp *scp, mutex_lock(vpu->lock); vpu->work_size = ALIGN(vpu->work_size, 64); vpu->param_size = ALIGN(sizeof(struct img_ipi_frameparam), 64); - vpu->config_size = ALIGN(sizeof(struct img_config), 64); + vpu->config_size = ALIGN(sizeof(struct img_config) * pp_num, 64); err = mdp_vpu_shared_mem_alloc(vpu); mutex_unlock(vpu->lock); if (err) { diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h index ece27c880e..1af075fc01 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec.h @@ -39,7 +39,6 @@ struct vdec_fb { /** * struct mtk_video_dec_buf - Private data related to each VB2 buffer. * @m2m_buf: M2M buffer - * @list: link list * @used: Capture buffer contain decoded frame data and keep in * codec data structure * @queued_in_vb2: Capture buffer is queue in vb2 diff --git a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c index d54b383379..b903e39fee 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/mtk_vcodec_dec_stateless.c @@ -566,7 +566,7 @@ static void mtk_vcodec_dec_fill_h264_level(struct v4l2_ctrl_config *cfg, default: cfg->max = V4L2_MPEG_VIDEO_H264_LEVEL_4_1; break; - }; + } } static void mtk_vcodec_dec_fill_h264_profile(struct v4l2_ctrl_config *cfg, @@ -580,7 +580,7 @@ static void mtk_vcodec_dec_fill_h264_profile(struct v4l2_ctrl_config *cfg, default: cfg->max = V4L2_MPEG_VIDEO_H264_PROFILE_HIGH; break; - }; + } } static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg, @@ -596,7 +596,7 @@ static void mtk_vcodec_dec_fill_h265_level(struct v4l2_ctrl_config *cfg, default: cfg->max = V4L2_MPEG_VIDEO_HEVC_LEVEL_4; break; - }; + } } static void mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg, @@ -610,7 +610,7 @@ static void mtk_vcodec_dec_fill_h265_profile(struct v4l2_ctrl_config *cfg, default: cfg->max = V4L2_MPEG_VIDEO_HEVC_PROFILE_MAIN_STILL_PICTURE; break; - }; + } } static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg, @@ -630,7 +630,7 @@ static void mtk_vcodec_dec_fill_vp9_level(struct v4l2_ctrl_config *cfg, default: cfg->max = V4L2_MPEG_VIDEO_VP9_LEVEL_4_0; break; - }; + } } static void mtk_vcodec_dec_fill_vp9_profile(struct v4l2_ctrl_config *cfg, @@ -644,7 +644,7 @@ static void mtk_vcodec_dec_fill_vp9_profile(struct v4l2_ctrl_config *cfg, default: cfg->max = V4L2_MPEG_VIDEO_VP9_PROFILE_1; break; - }; + } } static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, @@ -680,7 +680,7 @@ static void mtk_vcodec_dec_reset_controls(struct v4l2_ctrl_config *cfg, break; default: break; - }; + } } static int mtk_vcodec_dec_ctrls_setup(struct mtk_vcodec_dec_ctx *ctx) diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c index 19407f9bc7..987b3d71b6 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_if.c @@ -449,7 +449,7 @@ static int vdec_vp8_decode(void *h_vdec, struct mtk_vcodec_mem *bs, inst->frm_cnt, y_fb_dma, c_fb_dma, fb); inst->cur_fb = fb; - dec->bs_dma = (unsigned long)bs->dma_addr; + dec->bs_dma = (uint64_t)bs->dma_addr; dec->bs_sz = bs->size; dec->cur_y_fb_dma = y_fb_dma; dec->cur_c_fb_dma = c_fb_dma; diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c index f64b21c071..f677e499fe 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp8_req_if.c @@ -37,7 +37,6 @@ * @bs_sz: bitstream size * @resolution_changed:resolution change flag 1 - changed, 0 - not change * @frame_header_type: current frame header type - * @wait_key_frame: wait key frame coming * @crc: used to check whether hardware's status is right * @reserved: reserved, currently unused */ diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_if.c index 55355fa700..039082f600 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_if.c @@ -16,6 +16,7 @@ #include "../vdec_drv_base.h" #include "../vdec_vpu_if.h" +#define VP9_MAX_SUPER_FRAMES_NUM 8 #define VP9_SUPER_FRAME_BS_SZ 64 #define MAX_VP9_DPB_SIZE 9 @@ -133,11 +134,11 @@ struct vp9_sf_ref_fb { */ struct vdec_vp9_vsi { unsigned char sf_bs_buf[VP9_SUPER_FRAME_BS_SZ]; - struct vp9_sf_ref_fb sf_ref_fb[VP9_MAX_FRM_BUF_NUM-1]; + struct vp9_sf_ref_fb sf_ref_fb[VP9_MAX_SUPER_FRAMES_NUM]; int sf_next_ref_fb_idx; unsigned int sf_frm_cnt; - unsigned int sf_frm_offset[VP9_MAX_FRM_BUF_NUM-1]; - unsigned int sf_frm_sz[VP9_MAX_FRM_BUF_NUM-1]; + unsigned int sf_frm_offset[VP9_MAX_SUPER_FRAMES_NUM]; + unsigned int sf_frm_sz[VP9_MAX_SUPER_FRAMES_NUM]; unsigned int sf_frm_idx; unsigned int sf_init; struct vdec_fb fb; @@ -526,7 +527,7 @@ static void vp9_swap_frm_bufs(struct vdec_vp9_inst *inst) /* if this super frame and it is not last sub-frame, get next fb for * sub-frame decode */ - if (vsi->sf_frm_cnt > 0 && vsi->sf_frm_idx != vsi->sf_frm_cnt - 1) + if (vsi->sf_frm_cnt > 0 && vsi->sf_frm_idx != vsi->sf_frm_cnt) vsi->sf_next_ref_fb_idx = vp9_get_sf_ref_fb(inst); } @@ -735,7 +736,7 @@ static void get_free_fb(struct vdec_vp9_inst *inst, struct vdec_fb **out_fb) static int validate_vsi_array_indexes(struct vdec_vp9_inst *inst, struct vdec_vp9_vsi *vsi) { - if (vsi->sf_frm_idx >= VP9_MAX_FRM_BUF_NUM - 1) { + if (vsi->sf_frm_idx > VP9_MAX_SUPER_FRAMES_NUM) { mtk_vdec_err(inst->ctx, "Invalid vsi->sf_frm_idx=%u.", vsi->sf_frm_idx); return -EIO; } diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c index 69d37b93bd..eea709d938 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec/vdec_vp9_req_lat_if.c @@ -141,7 +141,6 @@ struct vdec_vp9_slice_frame_counts { * @skip: skip counts. * @y_mode: Y prediction mode counts. * @filter: interpolation filter counts. - * @mv_joint: motion vector joint counts. * @sign: motion vector sign counts. * @classes: motion vector class counts. * @class0: motion vector class0 bit counts. @@ -1075,7 +1074,7 @@ static int vdec_vp9_slice_setup_tile_buffer(struct vdec_vp9_slice_instance *inst unsigned int mi_row; unsigned int mi_col; unsigned int offset; - unsigned int pa; + dma_addr_t pa; unsigned int size; struct vdec_vp9_slice_tiles *tiles; unsigned char *pos; @@ -1110,7 +1109,7 @@ static int vdec_vp9_slice_setup_tile_buffer(struct vdec_vp9_slice_instance *inst pos = va + offset; end = va + bs->size; /* truncated */ - pa = (unsigned int)bs->dma_addr + offset; + pa = bs->dma_addr + offset; tb = instance->tile.va; for (i = 0; i < rows; i++) { for (j = 0; j < cols; j++) { diff --git a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.h b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.h index fbb3f34a73..aa7d08afc2 100644 --- a/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.h +++ b/drivers/media/platform/mediatek/vcodec/decoder/vdec_vpu_if.h @@ -22,7 +22,6 @@ struct mtk_vcodec_dec_ctx; * in place of inst_addr in messages. * @signaled : 1 - Host has received ack message from VPU, 0 - not received * @ctx : context for v4l2 layer integration - * @dev : platform device of VPU * @wq : wait queue to wait VPU message ack * @handler : ipi handler for each decoder * @codec_type : use codec type to separate different codecs diff --git a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.h b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.h index 82246401ed..908d8179b2 100644 --- a/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.h +++ b/drivers/media/platform/mediatek/vcodec/encoder/mtk_vcodec_enc.h @@ -26,7 +26,6 @@ /** * struct mtk_video_enc_buf - Private data related to each VB2 buffer. * @m2m_buf: M2M buffer - * @list: list that buffer link to * @param_change: Types of encode parameter change before encoding this * buffer * @enc_params: Encode parameters changed before encode this buffer diff --git a/drivers/media/platform/nuvoton/npcm-video.c b/drivers/media/platform/nuvoton/npcm-video.c index a1fcb616b2..60fbb91400 100644 --- a/drivers/media/platform/nuvoton/npcm-video.c +++ b/drivers/media/platform/nuvoton/npcm-video.c @@ -1785,7 +1785,7 @@ static int npcm_video_probe(struct platform_device *pdev) return 0; } -static int npcm_video_remove(struct platform_device *pdev) +static void npcm_video_remove(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct v4l2_device *v4l2_dev = dev_get_drvdata(dev); @@ -1798,8 +1798,6 @@ static int npcm_video_remove(struct platform_device *pdev) if (video->ece.enable) npcm_video_ece_stop(video); of_reserved_mem_device_release(dev); - - return 0; } static const struct of_device_id npcm_video_match[] = { @@ -1816,7 +1814,7 @@ static struct platform_driver npcm_video_driver = { .of_match_table = npcm_video_match, }, .probe = npcm_video_probe, - .remove = npcm_video_remove, + .remove_new = npcm_video_remove, }; module_platform_driver(npcm_video_driver); diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 64112b6329..cc97790ed3 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -1373,6 +1373,8 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, q_data_cap->crop.top = 0; q_data_cap->crop.width = jpeg_src_buf->w; q_data_cap->crop.height = jpeg_src_buf->h; + q_data_cap->bytesperline[0] = 0; + q_data_cap->bytesperline[1] = 0; /* * align up the resolution for CAST IP, @@ -1752,6 +1754,14 @@ static u32 mxc_jpeg_get_image_format(struct device *dev, static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision) { + u32 bytesperline[2]; + + bytesperline[0] = q->bytesperline[0]; + bytesperline[1] = q->bytesperline[0]; /*imx-jpeg only support the same line pitch*/ + v4l_bound_align_image(&bytesperline[0], 0, MXC_JPEG_MAX_LINE, 2, + &bytesperline[1], 0, MXC_JPEG_MAX_LINE, 2, + 0); + /* Bytes distance between the leftmost pixels in two adjacent lines */ if (q->fmt->fourcc == V4L2_PIX_FMT_JPEG) { /* bytesperline unused for compressed formats */ @@ -1775,6 +1785,12 @@ static void mxc_jpeg_bytesperline(struct mxc_jpeg_q_data *q, u32 precision) q->bytesperline[0] = q->w_adjusted * DIV_ROUND_UP(precision, 8); q->bytesperline[1] = 0; } + + if (q->fmt->fourcc != V4L2_PIX_FMT_JPEG) { + q->bytesperline[0] = max(q->bytesperline[0], bytesperline[0]); + if (q->fmt->mem_planes > 1) + q->bytesperline[1] = max(q->bytesperline[1], bytesperline[1]); + } } static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q) diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index dc4afeeff5..86e324b21a 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -22,6 +22,7 @@ #define MXC_JPEG_MIN_HEIGHT 64 #define MXC_JPEG_MAX_WIDTH 0x2000 #define MXC_JPEG_MAX_HEIGHT 0x2000 +#define MXC_JPEG_MAX_LINE 0x8000 #define MXC_JPEG_MAX_CFG_STREAM 0x1000 #define MXC_JPEG_H_ALIGN 3 #define MXC_JPEG_W_ALIGN 3 diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c index f73facb97d..c201399504 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-core.c @@ -506,7 +506,7 @@ err_pm: return ret; } -static int mxc_isi_remove(struct platform_device *pdev) +static void mxc_isi_remove(struct platform_device *pdev) { struct mxc_isi_dev *isi = platform_get_drvdata(pdev); unsigned int i; @@ -523,8 +523,6 @@ static int mxc_isi_remove(struct platform_device *pdev) mxc_isi_v4l2_cleanup(isi); pm_runtime_disable(isi->dev); - - return 0; } static const struct of_device_id mxc_isi_of_match[] = { @@ -537,7 +535,7 @@ MODULE_DEVICE_TABLE(of, mxc_isi_of_match); static struct platform_driver mxc_isi_driver = { .probe = mxc_isi_probe, - .remove = mxc_isi_remove, + .remove_new = mxc_isi_remove, .driver = { .of_match_table = mxc_isi_of_match, .name = MXC_ISI_DRIVER_NAME, diff --git a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c index 19e80b95ff..5623914f95 100644 --- a/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c +++ b/drivers/media/platform/nxp/imx8-isi/imx8-isi-hw.c @@ -215,8 +215,7 @@ static void mxc_isi_channel_set_csc(struct mxc_isi_pipe *pipe, [MXC_ISI_ENC_RGB] = "RGB", [MXC_ISI_ENC_YUV] = "YUV", }; - const u32 *coeffs; - bool cscen = true; + const u32 *coeffs = NULL; u32 val; val = mxc_isi_read(pipe, CHNL_IMG_CTRL); @@ -235,14 +234,13 @@ static void mxc_isi_channel_set_csc(struct mxc_isi_pipe *pipe, val |= CHNL_IMG_CTRL_CSC_MODE(CHNL_IMG_CTRL_CSC_MODE_RGB2YCBCR); } else { /* Bypass CSC */ - cscen = false; val |= CHNL_IMG_CTRL_CSC_BYPASS; } dev_dbg(pipe->isi->dev, "CSC: %s -> %s\n", encodings[in_encoding], encodings[out_encoding]); - if (cscen) { + if (coeffs) { mxc_isi_write(pipe, CHNL_CSC_COEFF0, coeffs[0]); mxc_isi_write(pipe, CHNL_CSC_COEFF1, coeffs[1]); mxc_isi_write(pipe, CHNL_CSC_COEFF2, coeffs[2]); @@ -253,7 +251,7 @@ static void mxc_isi_channel_set_csc(struct mxc_isi_pipe *pipe, mxc_isi_write(pipe, CHNL_IMG_CTRL, val); - *bypass = !cscen; + *bypass = !coeffs; } void mxc_isi_channel_set_alpha(struct mxc_isi_pipe *pipe, u8 alpha) diff --git a/drivers/media/platform/qcom/venus/core.c b/drivers/media/platform/qcom/venus/core.c index a712dd4f02..ce206b7097 100644 --- a/drivers/media/platform/qcom/venus/core.c +++ b/drivers/media/platform/qcom/venus/core.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -114,7 +115,8 @@ static void venus_sys_error_handler(struct work_struct *work) pm_runtime_put_sync(core->dev); for (i = 0; i < max_attempts; i++) { - if (!core->pmdomains[0] || !pm_runtime_active(core->pmdomains[0])) + if (!core->pmdomains || + !pm_runtime_active(core->pmdomains->pd_devs[0])) break; usleep_range(1000, 1500); } @@ -705,7 +707,7 @@ static const struct venus_resources sdm845_res_v2 = { .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, .vcodec1_clks = { "vcodec1_core", "vcodec1_bus" }, .vcodec_clks_num = 2, - .vcodec_pmdomains = { "venus", "vcodec0", "vcodec1" }, + .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0", "vcodec1" }, .vcodec_pmdomains_num = 3, .opp_pmdomain = (const char *[]) { "cx", NULL }, .vcodec_num = 2, @@ -754,7 +756,7 @@ static const struct venus_resources sc7180_res = { .clks_num = 3, .vcodec0_clks = { "vcodec0_core", "vcodec0_bus" }, .vcodec_clks_num = 2, - .vcodec_pmdomains = { "venus", "vcodec0" }, + .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, .opp_pmdomain = (const char *[]) { "cx", NULL }, .vcodec_num = 1, @@ -811,7 +813,7 @@ static const struct venus_resources sm8250_res = { .resets_num = 2, .vcodec0_clks = { "vcodec0_core" }, .vcodec_clks_num = 1, - .vcodec_pmdomains = { "venus", "vcodec0" }, + .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, .opp_pmdomain = (const char *[]) { "mx", NULL }, .vcodec_num = 1, @@ -870,7 +872,7 @@ static const struct venus_resources sc7280_res = { .clks_num = 3, .vcodec0_clks = {"vcodec_core", "vcodec_bus"}, .vcodec_clks_num = 2, - .vcodec_pmdomains = { "venus", "vcodec0" }, + .vcodec_pmdomains = (const char *[]) { "venus", "vcodec0" }, .vcodec_pmdomains_num = 2, .opp_pmdomain = (const char *[]) { "cx", NULL }, .vcodec_num = 1, diff --git a/drivers/media/platform/qcom/venus/core.h b/drivers/media/platform/qcom/venus/core.h index 4a633261ec..6a77de3744 100644 --- a/drivers/media/platform/qcom/venus/core.h +++ b/drivers/media/platform/qcom/venus/core.h @@ -25,7 +25,6 @@ #define VIDC_CLKS_NUM_MAX 4 #define VIDC_VCODEC_CLKS_NUM_MAX 2 -#define VIDC_PMDOMAINS_NUM_MAX 3 #define VIDC_RESETS_NUM_MAX 2 extern int venus_fw_debug; @@ -72,7 +71,7 @@ struct venus_resources { const char * const vcodec0_clks[VIDC_VCODEC_CLKS_NUM_MAX]; const char * const vcodec1_clks[VIDC_VCODEC_CLKS_NUM_MAX]; unsigned int vcodec_clks_num; - const char * const vcodec_pmdomains[VIDC_PMDOMAINS_NUM_MAX]; + const char **vcodec_pmdomains; unsigned int vcodec_pmdomains_num; const char **opp_pmdomain; unsigned int vcodec_num; @@ -134,7 +133,7 @@ struct venus_format { * @video_path: an interconnect handle to video to/from memory path * @cpucfg_path: an interconnect handle to cpu configuration path * @has_opp_table: does OPP table exist - * @pmdomains: an array of pmdomains struct device pointers + * @pmdomains: a pointer to a list of pmdomains * @opp_dl_venus: an device-link for device OPP * @opp_pmdomain: an OPP power-domain * @resets: an array of reset signals @@ -187,7 +186,7 @@ struct venus_core { struct icc_path *video_path; struct icc_path *cpucfg_path; bool has_opp_table; - struct device *pmdomains[VIDC_PMDOMAINS_NUM_MAX]; + struct dev_pm_domain_list *pmdomains; struct device_link *opp_dl_venus; struct device *opp_pmdomain; struct reset_control *resets[VIDC_RESETS_NUM_MAX]; @@ -428,7 +427,6 @@ enum venus_inst_modes { * @error: an error returned during last HFI sync operation * @session_error: a flag rised by HFI interface in case of session error * @ops: HFI operations - * @priv: a private for HFI operations callbacks * @session_type: the type of the session (decoder or encoder) * @hprop: a union used as a holder by get property * @core_acquired: the Core has been acquired diff --git a/drivers/media/platform/qcom/venus/pm_helpers.c b/drivers/media/platform/qcom/venus/pm_helpers.c index a1b127caa9..5028220594 100644 --- a/drivers/media/platform/qcom/venus/pm_helpers.c +++ b/drivers/media/platform/qcom/venus/pm_helpers.c @@ -455,7 +455,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask) if (ret) return ret; - ret = pm_runtime_put_sync(core->pmdomains[1]); + ret = pm_runtime_put_sync(core->pmdomains->pd_devs[1]); if (ret < 0) return ret; } @@ -471,7 +471,7 @@ static int poweroff_coreid(struct venus_core *core, unsigned int coreid_mask) if (ret) return ret; - ret = pm_runtime_put_sync(core->pmdomains[2]); + ret = pm_runtime_put_sync(core->pmdomains->pd_devs[2]); if (ret < 0) return ret; } @@ -484,7 +484,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) int ret; if (coreid_mask & VIDC_CORE_ID_1) { - ret = pm_runtime_get_sync(core->pmdomains[1]); + ret = pm_runtime_get_sync(core->pmdomains->pd_devs[1]); if (ret < 0) return ret; @@ -502,7 +502,7 @@ static int poweron_coreid(struct venus_core *core, unsigned int coreid_mask) } if (coreid_mask & VIDC_CORE_ID_2) { - ret = pm_runtime_get_sync(core->pmdomains[2]); + ret = pm_runtime_get_sync(core->pmdomains->pd_devs[2]); if (ret < 0) return ret; @@ -860,19 +860,18 @@ static int vcodec_domains_get(struct venus_core *core) struct device **opp_virt_dev; struct device *dev = core->dev; const struct venus_resources *res = core->res; - struct device *pd; - unsigned int i; + struct dev_pm_domain_attach_data vcodec_data = { + .pd_names = res->vcodec_pmdomains, + .num_pd_names = res->vcodec_pmdomains_num, + .pd_flags = PD_FLAG_NO_DEV_LINK, + }; if (!res->vcodec_pmdomains_num) goto skip_pmdomains; - for (i = 0; i < res->vcodec_pmdomains_num; i++) { - pd = dev_pm_domain_attach_by_name(dev, - res->vcodec_pmdomains[i]); - if (IS_ERR_OR_NULL(pd)) - return pd ? PTR_ERR(pd) : -ENODATA; - core->pmdomains[i] = pd; - } + ret = dev_pm_domain_attach_list(dev, &vcodec_data, &core->pmdomains); + if (ret < 0) + return ret; skip_pmdomains: if (!core->res->opp_pmdomain) @@ -896,30 +895,14 @@ skip_pmdomains: return 0; opp_attach_err: - 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); - } - + dev_pm_domain_detach_list(core->pmdomains); return ret; } static void vcodec_domains_put(struct venus_core *core) { - const struct venus_resources *res = core->res; - unsigned int i; + dev_pm_domain_detach_list(core->pmdomains); - if (!res->vcodec_pmdomains_num) - goto skip_pmdomains; - - 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); - } - -skip_pmdomains: if (!core->has_opp_table) return; @@ -1035,7 +1018,8 @@ static void core_put_v4(struct venus_core *core) static int core_power_v4(struct venus_core *core, int on) { struct device *dev = core->dev; - struct device *pmctrl = core->pmdomains[0]; + struct device *pmctrl = core->pmdomains ? + core->pmdomains->pd_devs[0] : NULL; int ret = 0; if (on == POWER_ON) { diff --git a/drivers/media/platform/renesas/Kconfig b/drivers/media/platform/renesas/Kconfig index ed788e991f..c7fc718a30 100644 --- a/drivers/media/platform/renesas/Kconfig +++ b/drivers/media/platform/renesas/Kconfig @@ -14,6 +14,22 @@ config VIDEO_RENESAS_CEU help This is a v4l2 driver for the Renesas CEU Interface +config VIDEO_RCAR_CSI2 + tristate "R-Car MIPI CSI-2 Receiver" + depends on V4L_PLATFORM_DRIVERS + depends on VIDEO_DEV && OF + depends on ARCH_RENESAS || COMPILE_TEST + select MEDIA_CONTROLLER + select VIDEO_V4L2_SUBDEV_API + select RESET_CONTROLLER + select V4L2_FWNODE + help + Support for Renesas R-Car MIPI CSI-2 receiver. + 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. + config VIDEO_RCAR_ISP tristate "R-Car Image Signal Processor (ISP)" depends on V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/renesas/Makefile b/drivers/media/platform/renesas/Makefile index 55854e8688..50774a2033 100644 --- a/drivers/media/platform/renesas/Makefile +++ b/drivers/media/platform/renesas/Makefile @@ -7,6 +7,7 @@ obj-y += rcar-vin/ obj-y += rzg2l-cru/ obj-y += vsp1/ +obj-$(CONFIG_VIDEO_RCAR_CSI2) += rcar-csi2.o obj-$(CONFIG_VIDEO_RCAR_DRIF) += rcar_drif.o obj-$(CONFIG_VIDEO_RCAR_ISP) += rcar-isp.o obj-$(CONFIG_VIDEO_RENESAS_CEU) += renesas-ceu.o diff --git a/drivers/media/platform/renesas/rcar-csi2.c b/drivers/media/platform/renesas/rcar-csi2.c new file mode 100644 index 0000000000..582d5e35db --- /dev/null +++ b/drivers/media/platform/renesas/rcar-csi2.c @@ -0,0 +1,1959 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Driver for Renesas R-Car MIPI CSI-2 Receiver + * + * Copyright (C) 2018 Renesas Electronics Corp. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +struct rcar_csi2; + +/* Register offsets and bits */ + +/* Control Timing Select */ +#define TREF_REG 0x00 +#define TREF_TREF BIT(0) + +/* Software Reset */ +#define SRST_REG 0x04 +#define SRST_SRST BIT(0) + +/* PHY Operation Control */ +#define PHYCNT_REG 0x08 +#define PHYCNT_SHUTDOWNZ BIT(17) +#define PHYCNT_RSTZ BIT(16) +#define PHYCNT_ENABLECLK BIT(4) +#define PHYCNT_ENABLE_3 BIT(3) +#define PHYCNT_ENABLE_2 BIT(2) +#define PHYCNT_ENABLE_1 BIT(1) +#define PHYCNT_ENABLE_0 BIT(0) + +/* Checksum Control */ +#define CHKSUM_REG 0x0c +#define CHKSUM_ECC_EN BIT(1) +#define CHKSUM_CRC_EN BIT(0) + +/* + * Channel Data Type Select + * VCDT[0-15]: Channel 0 VCDT[16-31]: Channel 1 + * VCDT2[0-15]: Channel 2 VCDT2[16-31]: Channel 3 + */ +#define VCDT_REG 0x10 +#define VCDT2_REG 0x14 +#define VCDT_VCDTN_EN BIT(15) +#define VCDT_SEL_VC(n) (((n) & 0x3) << 8) +#define VCDT_SEL_DTN_ON BIT(6) +#define VCDT_SEL_DT(n) (((n) & 0x3f) << 0) + +/* Frame Data Type Select */ +#define FRDT_REG 0x18 + +/* Field Detection Control */ +#define FLD_REG 0x1c +#define FLD_FLD_NUM(n) (((n) & 0xff) << 16) +#define FLD_DET_SEL(n) (((n) & 0x3) << 4) +#define FLD_FLD_EN4 BIT(3) +#define FLD_FLD_EN3 BIT(2) +#define FLD_FLD_EN2 BIT(1) +#define FLD_FLD_EN BIT(0) + +/* Automatic Standby Control */ +#define ASTBY_REG 0x20 + +/* Long Data Type Setting 0 */ +#define LNGDT0_REG 0x28 + +/* Long Data Type Setting 1 */ +#define LNGDT1_REG 0x2c + +/* Interrupt Enable */ +#define INTEN_REG 0x30 +#define INTEN_INT_AFIFO_OF BIT(27) +#define INTEN_INT_ERRSOTHS BIT(4) +#define INTEN_INT_ERRSOTSYNCHS BIT(3) + +/* Interrupt Source Mask */ +#define INTCLOSE_REG 0x34 + +/* Interrupt Status Monitor */ +#define INTSTATE_REG 0x38 +#define INTSTATE_INT_ULPS_START BIT(7) +#define INTSTATE_INT_ULPS_END BIT(6) + +/* Interrupt Error Status Monitor */ +#define INTERRSTATE_REG 0x3c + +/* Short Packet Data */ +#define SHPDAT_REG 0x40 + +/* Short Packet Count */ +#define SHPCNT_REG 0x44 + +/* LINK Operation Control */ +#define LINKCNT_REG 0x48 +#define LINKCNT_MONITOR_EN BIT(31) +#define LINKCNT_REG_MONI_PACT_EN BIT(25) +#define LINKCNT_ICLK_NONSTOP BIT(24) + +/* Lane Swap */ +#define LSWAP_REG 0x4c +#define LSWAP_L3SEL(n) (((n) & 0x3) << 6) +#define LSWAP_L2SEL(n) (((n) & 0x3) << 4) +#define LSWAP_L1SEL(n) (((n) & 0x3) << 2) +#define LSWAP_L0SEL(n) (((n) & 0x3) << 0) + +/* PHY Test Interface Write Register */ +#define PHTW_REG 0x50 +#define PHTW_DWEN BIT(24) +#define PHTW_TESTDIN_DATA(n) (((n & 0xff)) << 16) +#define PHTW_CWEN BIT(8) +#define PHTW_TESTDIN_CODE(n) ((n & 0xff)) + +#define PHYFRX_REG 0x64 +#define PHYFRX_FORCERX_MODE_3 BIT(3) +#define PHYFRX_FORCERX_MODE_2 BIT(2) +#define PHYFRX_FORCERX_MODE_1 BIT(1) +#define PHYFRX_FORCERX_MODE_0 BIT(0) + +/* V4H BASE registers */ +#define V4H_N_LANES_REG 0x0004 +#define V4H_CSI2_RESETN_REG 0x0008 +#define V4H_PHY_MODE_REG 0x001c +#define V4H_PHY_SHUTDOWNZ_REG 0x0040 +#define V4H_DPHY_RSTZ_REG 0x0044 +#define V4H_FLDC_REG 0x0804 +#define V4H_FLDD_REG 0x0808 +#define V4H_IDIC_REG 0x0810 +#define V4H_PHY_EN_REG 0x2000 + +#define V4H_ST_PHYST_REG 0x2814 +#define V4H_ST_PHYST_ST_PHY_READY BIT(31) +#define V4H_ST_PHYST_ST_STOPSTATE_3 BIT(3) +#define V4H_ST_PHYST_ST_STOPSTATE_2 BIT(2) +#define V4H_ST_PHYST_ST_STOPSTATE_1 BIT(1) +#define V4H_ST_PHYST_ST_STOPSTATE_0 BIT(0) + +/* V4H PPI registers */ +#define V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(n) (0x21800 + ((n) * 2)) /* n = 0 - 9 */ +#define V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG 0x21822 +#define V4H_PPI_CALIBCTRL_RW_COMMON_BG_0_REG 0x2184c +#define V4H_PPI_RW_LPDCOCAL_TIMEBASE_REG 0x21c02 +#define V4H_PPI_RW_LPDCOCAL_NREF_REG 0x21c04 +#define V4H_PPI_RW_LPDCOCAL_NREF_RANGE_REG 0x21c06 +#define V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG 0x21c0a +#define V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG 0x21c0c +#define V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG 0x21c10 +#define V4H_PPI_RW_COMMON_CFG_REG 0x21c6c +#define V4H_PPI_RW_TERMCAL_CFG_0_REG 0x21c80 +#define V4H_PPI_RW_OFFSETCAL_CFG_0_REG 0x21ca0 + +/* V4H CORE registers */ +#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(n) (0x22040 + ((n) * 2)) /* n = 0 - 15 */ +#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(n) (0x22440 + ((n) * 2)) /* n = 0 - 15 */ +#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(n) (0x22840 + ((n) * 2)) /* n = 0 - 15 */ +#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(n) (0x22c40 + ((n) * 2)) /* n = 0 - 15 */ +#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(n) (0x23040 + ((n) * 2)) /* n = 0 - 15 */ +#define V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(n) (0x23840 + ((n) * 2)) /* n = 0 - 11 */ +#define V4H_CORE_DIG_RW_COMMON_REG(n) (0x23880 + ((n) * 2)) /* n = 0 - 15 */ +#define V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(n) (0x239e0 + ((n) * 2)) /* n = 0 - 3 */ +#define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG 0x2a400 +#define V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG 0x2a60c + +/* V4H C-PHY */ +#define V4H_CORE_DIG_RW_TRIO0_REG(n) (0x22100 + ((n) * 2)) /* n = 0 - 3 */ +#define V4H_CORE_DIG_RW_TRIO1_REG(n) (0x22500 + ((n) * 2)) /* n = 0 - 3 */ +#define V4H_CORE_DIG_RW_TRIO2_REG(n) (0x22900 + ((n) * 2)) /* n = 0 - 3 */ +#define V4H_CORE_DIG_CLANE_0_RW_LP_0_REG 0x2a080 +#define V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(n) (0x2a100 + ((n) * 2)) /* n = 0 - 6 */ +#define V4H_CORE_DIG_CLANE_1_RW_LP_0_REG 0x2a480 +#define V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(n) (0x2a500 + ((n) * 2)) /* n = 0 - 6 */ +#define V4H_CORE_DIG_CLANE_2_RW_LP_0_REG 0x2a880 +#define V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(n) (0x2a900 + ((n) * 2)) /* n = 0 - 6 */ + +struct rcsi2_cphy_setting { + u16 msps; + u16 rx2; + u16 trio0; + u16 trio1; + u16 trio2; + u16 lane27; + u16 lane29; +}; + +static const struct rcsi2_cphy_setting cphy_setting_table_r8a779g0[] = { + { .msps = 80, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0134, .trio2 = 0x6a, .lane27 = 0x0000, .lane29 = 0x0a24 }, + { .msps = 100, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x00f5, .trio2 = 0x55, .lane27 = 0x0000, .lane29 = 0x0a24 }, + { .msps = 200, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0077, .trio2 = 0x2b, .lane27 = 0x0000, .lane29 = 0x0a44 }, + { .msps = 300, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x004d, .trio2 = 0x1d, .lane27 = 0x0000, .lane29 = 0x0a44 }, + { .msps = 400, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0038, .trio2 = 0x16, .lane27 = 0x0000, .lane29 = 0x0a64 }, + { .msps = 500, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x002b, .trio2 = 0x12, .lane27 = 0x0000, .lane29 = 0x0a64 }, + { .msps = 600, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0023, .trio2 = 0x0f, .lane27 = 0x0000, .lane29 = 0x0a64 }, + { .msps = 700, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x001d, .trio2 = 0x0d, .lane27 = 0x0000, .lane29 = 0x0a84 }, + { .msps = 800, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0018, .trio2 = 0x0c, .lane27 = 0x0000, .lane29 = 0x0a84 }, + { .msps = 900, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0015, .trio2 = 0x0b, .lane27 = 0x0000, .lane29 = 0x0a84 }, + { .msps = 1000, .rx2 = 0x3e, .trio0 = 0x024a, .trio1 = 0x0012, .trio2 = 0x0a, .lane27 = 0x0400, .lane29 = 0x0a84 }, + { .msps = 1100, .rx2 = 0x44, .trio0 = 0x024a, .trio1 = 0x000f, .trio2 = 0x09, .lane27 = 0x0800, .lane29 = 0x0a84 }, + { .msps = 1200, .rx2 = 0x4a, .trio0 = 0x024a, .trio1 = 0x000e, .trio2 = 0x08, .lane27 = 0x0c00, .lane29 = 0x0a84 }, + { .msps = 1300, .rx2 = 0x51, .trio0 = 0x024a, .trio1 = 0x000c, .trio2 = 0x08, .lane27 = 0x0c00, .lane29 = 0x0aa4 }, + { .msps = 1400, .rx2 = 0x57, .trio0 = 0x024a, .trio1 = 0x000b, .trio2 = 0x07, .lane27 = 0x1000, .lane29 = 0x0aa4 }, + { .msps = 1500, .rx2 = 0x5d, .trio0 = 0x044a, .trio1 = 0x0009, .trio2 = 0x07, .lane27 = 0x1000, .lane29 = 0x0aa4 }, + { .msps = 1600, .rx2 = 0x63, .trio0 = 0x044a, .trio1 = 0x0008, .trio2 = 0x07, .lane27 = 0x1400, .lane29 = 0x0aa4 }, + { .msps = 1700, .rx2 = 0x6a, .trio0 = 0x044a, .trio1 = 0x0007, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 }, + { .msps = 1800, .rx2 = 0x70, .trio0 = 0x044a, .trio1 = 0x0007, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 }, + { .msps = 1900, .rx2 = 0x76, .trio0 = 0x044a, .trio1 = 0x0006, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 }, + { .msps = 2000, .rx2 = 0x7c, .trio0 = 0x044a, .trio1 = 0x0005, .trio2 = 0x06, .lane27 = 0x1800, .lane29 = 0x0aa4 }, + { .msps = 2100, .rx2 = 0x83, .trio0 = 0x044a, .trio1 = 0x0005, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, + { .msps = 2200, .rx2 = 0x89, .trio0 = 0x064a, .trio1 = 0x0004, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, + { .msps = 2300, .rx2 = 0x8f, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, + { .msps = 2400, .rx2 = 0x95, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, + { .msps = 2500, .rx2 = 0x9c, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0aa4 }, + { .msps = 2600, .rx2 = 0xa2, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, + { .msps = 2700, .rx2 = 0xa8, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, + { .msps = 2800, .rx2 = 0xae, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, + { .msps = 2900, .rx2 = 0xb5, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, + { .msps = 3000, .rx2 = 0xbb, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, + { .msps = 3100, .rx2 = 0xc1, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, + { .msps = 3200, .rx2 = 0xc7, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, + { .msps = 3300, .rx2 = 0xce, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, + { .msps = 3400, .rx2 = 0xd4, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, + { .msps = 3500, .rx2 = 0xda, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, + { /* sentinel */ }, +}; + +struct phtw_value { + u16 data; + u16 code; +}; + +struct rcsi2_mbps_reg { + u16 mbps; + u16 reg; +}; + +static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = { + { .mbps = 1500, .reg = 0xcc }, + { .mbps = 1550, .reg = 0x1d }, + { .mbps = 1600, .reg = 0x27 }, + { .mbps = 1650, .reg = 0x30 }, + { .mbps = 1700, .reg = 0x39 }, + { .mbps = 1750, .reg = 0x42 }, + { .mbps = 1800, .reg = 0x4b }, + { .mbps = 1850, .reg = 0x55 }, + { .mbps = 1900, .reg = 0x5e }, + { .mbps = 1950, .reg = 0x67 }, + { .mbps = 2000, .reg = 0x71 }, + { .mbps = 2050, .reg = 0x79 }, + { .mbps = 2100, .reg = 0x83 }, + { .mbps = 2150, .reg = 0x8c }, + { .mbps = 2200, .reg = 0x95 }, + { .mbps = 2250, .reg = 0x9e }, + { .mbps = 2300, .reg = 0xa7 }, + { .mbps = 2350, .reg = 0xb0 }, + { .mbps = 2400, .reg = 0xba }, + { .mbps = 2450, .reg = 0xc3 }, + { .mbps = 2500, .reg = 0xcc }, + { /* sentinel */ }, +}; + +static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { + { .mbps = 80, .reg = 0x86 }, + { .mbps = 90, .reg = 0x86 }, + { .mbps = 100, .reg = 0x87 }, + { .mbps = 110, .reg = 0x87 }, + { .mbps = 120, .reg = 0x88 }, + { .mbps = 130, .reg = 0x88 }, + { .mbps = 140, .reg = 0x89 }, + { .mbps = 150, .reg = 0x89 }, + { .mbps = 160, .reg = 0x8a }, + { .mbps = 170, .reg = 0x8a }, + { .mbps = 180, .reg = 0x8b }, + { .mbps = 190, .reg = 0x8b }, + { .mbps = 205, .reg = 0x8c }, + { .mbps = 220, .reg = 0x8d }, + { .mbps = 235, .reg = 0x8e }, + { .mbps = 250, .reg = 0x8e }, + { /* sentinel */ }, +}; + +static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { + { .mbps = 80, .reg = 0x00 }, + { .mbps = 90, .reg = 0x20 }, + { .mbps = 100, .reg = 0x40 }, + { .mbps = 110, .reg = 0x02 }, + { .mbps = 130, .reg = 0x22 }, + { .mbps = 140, .reg = 0x42 }, + { .mbps = 150, .reg = 0x04 }, + { .mbps = 170, .reg = 0x24 }, + { .mbps = 180, .reg = 0x44 }, + { .mbps = 200, .reg = 0x06 }, + { .mbps = 220, .reg = 0x26 }, + { .mbps = 240, .reg = 0x46 }, + { .mbps = 250, .reg = 0x08 }, + { .mbps = 270, .reg = 0x28 }, + { .mbps = 300, .reg = 0x0a }, + { .mbps = 330, .reg = 0x2a }, + { .mbps = 360, .reg = 0x4a }, + { .mbps = 400, .reg = 0x0c }, + { .mbps = 450, .reg = 0x2c }, + { .mbps = 500, .reg = 0x0e }, + { .mbps = 550, .reg = 0x2e }, + { .mbps = 600, .reg = 0x10 }, + { .mbps = 650, .reg = 0x30 }, + { .mbps = 700, .reg = 0x12 }, + { .mbps = 750, .reg = 0x32 }, + { .mbps = 800, .reg = 0x52 }, + { .mbps = 850, .reg = 0x72 }, + { .mbps = 900, .reg = 0x14 }, + { .mbps = 950, .reg = 0x34 }, + { .mbps = 1000, .reg = 0x54 }, + { .mbps = 1050, .reg = 0x74 }, + { .mbps = 1125, .reg = 0x16 }, + { /* sentinel */ }, +}; + +/* PHY Test Interface Clear */ +#define PHTC_REG 0x58 +#define PHTC_TESTCLR BIT(0) + +/* PHY Frequency Control */ +#define PHYPLL_REG 0x68 +#define PHYPLL_HSFREQRANGE(n) ((n) << 16) + +static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = { + { .mbps = 80, .reg = 0x00 }, + { .mbps = 90, .reg = 0x10 }, + { .mbps = 100, .reg = 0x20 }, + { .mbps = 110, .reg = 0x30 }, + { .mbps = 120, .reg = 0x01 }, + { .mbps = 130, .reg = 0x11 }, + { .mbps = 140, .reg = 0x21 }, + { .mbps = 150, .reg = 0x31 }, + { .mbps = 160, .reg = 0x02 }, + { .mbps = 170, .reg = 0x12 }, + { .mbps = 180, .reg = 0x22 }, + { .mbps = 190, .reg = 0x32 }, + { .mbps = 205, .reg = 0x03 }, + { .mbps = 220, .reg = 0x13 }, + { .mbps = 235, .reg = 0x23 }, + { .mbps = 250, .reg = 0x33 }, + { .mbps = 275, .reg = 0x04 }, + { .mbps = 300, .reg = 0x14 }, + { .mbps = 325, .reg = 0x25 }, + { .mbps = 350, .reg = 0x35 }, + { .mbps = 400, .reg = 0x05 }, + { .mbps = 450, .reg = 0x16 }, + { .mbps = 500, .reg = 0x26 }, + { .mbps = 550, .reg = 0x37 }, + { .mbps = 600, .reg = 0x07 }, + { .mbps = 650, .reg = 0x18 }, + { .mbps = 700, .reg = 0x28 }, + { .mbps = 750, .reg = 0x39 }, + { .mbps = 800, .reg = 0x09 }, + { .mbps = 850, .reg = 0x19 }, + { .mbps = 900, .reg = 0x29 }, + { .mbps = 950, .reg = 0x3a }, + { .mbps = 1000, .reg = 0x0a }, + { .mbps = 1050, .reg = 0x1a }, + { .mbps = 1100, .reg = 0x2a }, + { .mbps = 1150, .reg = 0x3b }, + { .mbps = 1200, .reg = 0x0b }, + { .mbps = 1250, .reg = 0x1b }, + { .mbps = 1300, .reg = 0x2b }, + { .mbps = 1350, .reg = 0x3c }, + { .mbps = 1400, .reg = 0x0c }, + { .mbps = 1450, .reg = 0x1c }, + { .mbps = 1500, .reg = 0x2c }, + { .mbps = 1550, .reg = 0x3d }, + { .mbps = 1600, .reg = 0x0d }, + { .mbps = 1650, .reg = 0x1d }, + { .mbps = 1700, .reg = 0x2e }, + { .mbps = 1750, .reg = 0x3e }, + { .mbps = 1800, .reg = 0x0e }, + { .mbps = 1850, .reg = 0x1e }, + { .mbps = 1900, .reg = 0x2f }, + { .mbps = 1950, .reg = 0x3f }, + { .mbps = 2000, .reg = 0x0f }, + { .mbps = 2050, .reg = 0x40 }, + { .mbps = 2100, .reg = 0x41 }, + { .mbps = 2150, .reg = 0x42 }, + { .mbps = 2200, .reg = 0x43 }, + { .mbps = 2300, .reg = 0x45 }, + { .mbps = 2350, .reg = 0x46 }, + { .mbps = 2400, .reg = 0x47 }, + { .mbps = 2450, .reg = 0x48 }, + { .mbps = 2500, .reg = 0x49 }, + { /* sentinel */ }, +}; + +static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = { + { .mbps = 80, .reg = 0x00 }, + { .mbps = 90, .reg = 0x10 }, + { .mbps = 100, .reg = 0x20 }, + { .mbps = 110, .reg = 0x30 }, + { .mbps = 120, .reg = 0x01 }, + { .mbps = 130, .reg = 0x11 }, + { .mbps = 140, .reg = 0x21 }, + { .mbps = 150, .reg = 0x31 }, + { .mbps = 160, .reg = 0x02 }, + { .mbps = 170, .reg = 0x12 }, + { .mbps = 180, .reg = 0x22 }, + { .mbps = 190, .reg = 0x32 }, + { .mbps = 205, .reg = 0x03 }, + { .mbps = 220, .reg = 0x13 }, + { .mbps = 235, .reg = 0x23 }, + { .mbps = 250, .reg = 0x33 }, + { .mbps = 275, .reg = 0x04 }, + { .mbps = 300, .reg = 0x14 }, + { .mbps = 325, .reg = 0x25 }, + { .mbps = 350, .reg = 0x35 }, + { .mbps = 400, .reg = 0x05 }, + { .mbps = 450, .reg = 0x16 }, + { .mbps = 500, .reg = 0x26 }, + { .mbps = 550, .reg = 0x37 }, + { .mbps = 600, .reg = 0x07 }, + { .mbps = 650, .reg = 0x18 }, + { .mbps = 700, .reg = 0x28 }, + { .mbps = 750, .reg = 0x39 }, + { .mbps = 800, .reg = 0x09 }, + { .mbps = 850, .reg = 0x19 }, + { .mbps = 900, .reg = 0x29 }, + { .mbps = 950, .reg = 0x3a }, + { .mbps = 1000, .reg = 0x0a }, + { .mbps = 1050, .reg = 0x1a }, + { .mbps = 1100, .reg = 0x2a }, + { .mbps = 1150, .reg = 0x3b }, + { .mbps = 1200, .reg = 0x0b }, + { .mbps = 1250, .reg = 0x1b }, + { .mbps = 1300, .reg = 0x2b }, + { .mbps = 1350, .reg = 0x3c }, + { .mbps = 1400, .reg = 0x0c }, + { .mbps = 1450, .reg = 0x1c }, + { .mbps = 1500, .reg = 0x2c }, + { /* sentinel */ }, +}; + +static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = { + { .mbps = 80, .reg = 0x00 }, + { .mbps = 90, .reg = 0x10 }, + { .mbps = 100, .reg = 0x20 }, + { .mbps = 110, .reg = 0x30 }, + { .mbps = 120, .reg = 0x01 }, + { .mbps = 130, .reg = 0x11 }, + { .mbps = 140, .reg = 0x21 }, + { .mbps = 150, .reg = 0x31 }, + { .mbps = 160, .reg = 0x02 }, + { .mbps = 170, .reg = 0x12 }, + { .mbps = 180, .reg = 0x22 }, + { .mbps = 190, .reg = 0x32 }, + { .mbps = 205, .reg = 0x03 }, + { .mbps = 220, .reg = 0x13 }, + { .mbps = 235, .reg = 0x23 }, + { .mbps = 250, .reg = 0x33 }, + { .mbps = 275, .reg = 0x04 }, + { .mbps = 300, .reg = 0x14 }, + { .mbps = 325, .reg = 0x05 }, + { .mbps = 350, .reg = 0x15 }, + { .mbps = 400, .reg = 0x25 }, + { .mbps = 450, .reg = 0x06 }, + { .mbps = 500, .reg = 0x16 }, + { .mbps = 550, .reg = 0x07 }, + { .mbps = 600, .reg = 0x17 }, + { .mbps = 650, .reg = 0x08 }, + { .mbps = 700, .reg = 0x18 }, + { .mbps = 750, .reg = 0x09 }, + { .mbps = 800, .reg = 0x19 }, + { .mbps = 850, .reg = 0x29 }, + { .mbps = 900, .reg = 0x39 }, + { .mbps = 950, .reg = 0x0a }, + { .mbps = 1000, .reg = 0x1a }, + { .mbps = 1050, .reg = 0x2a }, + { .mbps = 1100, .reg = 0x3a }, + { .mbps = 1150, .reg = 0x0b }, + { .mbps = 1200, .reg = 0x1b }, + { .mbps = 1250, .reg = 0x2b }, + { .mbps = 1300, .reg = 0x3b }, + { .mbps = 1350, .reg = 0x0c }, + { .mbps = 1400, .reg = 0x1c }, + { .mbps = 1450, .reg = 0x2c }, + { .mbps = 1500, .reg = 0x3c }, + { /* sentinel */ }, +}; + +/* PHY ESC Error Monitor */ +#define PHEERM_REG 0x74 + +/* PHY Clock Lane Monitor */ +#define PHCLM_REG 0x78 +#define PHCLM_STOPSTATECKL BIT(0) + +/* PHY Data Lane Monitor */ +#define PHDLM_REG 0x7c + +/* CSI0CLK Frequency Configuration Preset Register */ +#define CSI0CLKFCPR_REG 0x260 +#define CSI0CLKFREQRANGE(n) ((n & 0x3f) << 16) + +struct rcar_csi2_format { + u32 code; + unsigned int datatype; + unsigned int bpp; +}; + +static const struct rcar_csi2_format rcar_csi2_formats[] = { + { + .code = MEDIA_BUS_FMT_RGB888_1X24, + .datatype = MIPI_CSI2_DT_RGB888, + .bpp = 24, + }, { + .code = MEDIA_BUS_FMT_UYVY8_1X16, + .datatype = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + }, { + .code = MEDIA_BUS_FMT_YUYV8_1X16, + .datatype = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + }, { + .code = MEDIA_BUS_FMT_UYVY8_2X8, + .datatype = MIPI_CSI2_DT_YUV422_8B, + .bpp = 16, + }, { + .code = MEDIA_BUS_FMT_YUYV10_2X10, + .datatype = MIPI_CSI2_DT_YUV422_8B, + .bpp = 20, + }, { + .code = MEDIA_BUS_FMT_Y10_1X10, + .datatype = MIPI_CSI2_DT_RAW10, + .bpp = 10, + }, { + .code = MEDIA_BUS_FMT_SBGGR8_1X8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, { + .code = MEDIA_BUS_FMT_SGBRG8_1X8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, { + .code = MEDIA_BUS_FMT_SGRBG8_1X8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, { + .code = MEDIA_BUS_FMT_SRGGB8_1X8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, { + .code = MEDIA_BUS_FMT_Y8_1X8, + .datatype = MIPI_CSI2_DT_RAW8, + .bpp = 8, + }, +}; + +static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code) +{ + unsigned int i; + + for (i = 0; i < ARRAY_SIZE(rcar_csi2_formats); i++) + if (rcar_csi2_formats[i].code == code) + return &rcar_csi2_formats[i]; + + return NULL; +} + +enum rcar_csi2_pads { + RCAR_CSI2_SINK, + RCAR_CSI2_SOURCE_VC0, + RCAR_CSI2_SOURCE_VC1, + RCAR_CSI2_SOURCE_VC2, + RCAR_CSI2_SOURCE_VC3, + NR_OF_RCAR_CSI2_PAD, +}; + +struct rcar_csi2_info { + int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); + int (*phy_post_init)(struct rcar_csi2 *priv); + int (*start_receiver)(struct rcar_csi2 *priv); + void (*enter_standby)(struct rcar_csi2 *priv); + const struct rcsi2_mbps_reg *hsfreqrange; + unsigned int csi0clkfreqrange; + unsigned int num_channels; + bool clear_ulps; + bool use_isp; + bool support_dphy; + bool support_cphy; +}; + +struct rcar_csi2 { + struct device *dev; + void __iomem *base; + const struct rcar_csi2_info *info; + struct reset_control *rstc; + + struct v4l2_subdev subdev; + struct media_pad pads[NR_OF_RCAR_CSI2_PAD]; + + struct v4l2_async_notifier notifier; + struct v4l2_subdev *remote; + unsigned int remote_pad; + + int channel_vc[4]; + + struct mutex lock; /* Protects mf and stream_count. */ + struct v4l2_mbus_framefmt mf; + int stream_count; + + bool cphy; + unsigned short lanes; + unsigned char lane_swap[4]; +}; + +static inline struct rcar_csi2 *sd_to_csi2(struct v4l2_subdev *sd) +{ + return container_of(sd, struct rcar_csi2, subdev); +} + +static inline struct rcar_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n) +{ + return container_of(n, struct rcar_csi2, notifier); +} + +static u32 rcsi2_read(struct rcar_csi2 *priv, unsigned int reg) +{ + return ioread32(priv->base + reg); +} + +static void rcsi2_write(struct rcar_csi2 *priv, unsigned int reg, u32 data) +{ + iowrite32(data, priv->base + reg); +} + +static void rcsi2_write16(struct rcar_csi2 *priv, unsigned int reg, u16 data) +{ + iowrite16(data, priv->base + reg); +} + +static void rcsi2_enter_standby_gen3(struct rcar_csi2 *priv) +{ + rcsi2_write(priv, PHYCNT_REG, 0); + rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); +} + +static void rcsi2_enter_standby(struct rcar_csi2 *priv) +{ + if (priv->info->enter_standby) + priv->info->enter_standby(priv); + + reset_control_assert(priv->rstc); + usleep_range(100, 150); + pm_runtime_put(priv->dev); +} + +static int rcsi2_exit_standby(struct rcar_csi2 *priv) +{ + int ret; + + ret = pm_runtime_resume_and_get(priv->dev); + if (ret < 0) + return ret; + + reset_control_deassert(priv->rstc); + + return 0; +} + +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 << lanes) - 1; + + if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) && + (rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask) + return 0; + + usleep_range(1000, 2000); + } + + dev_err(priv->dev, "Timeout waiting for LP-11 state\n"); + + return -ETIMEDOUT; +} + +static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) +{ + const struct rcsi2_mbps_reg *hsfreq; + const struct rcsi2_mbps_reg *hsfreq_prev = NULL; + + if (mbps < priv->info->hsfreqrange->mbps) + dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps", + mbps, priv->info->hsfreqrange->mbps); + + for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) { + if (hsfreq->mbps >= mbps) + break; + hsfreq_prev = hsfreq; + } + + if (!hsfreq->mbps) { + dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); + return -ERANGE; + } + + if (hsfreq_prev && + ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps))) + hsfreq = hsfreq_prev; + + rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg)); + + return 0; +} + +static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, + unsigned int lanes) +{ + struct v4l2_subdev *source; + struct v4l2_ctrl *ctrl; + u64 mbps; + + if (!priv->remote) + return -ENODEV; + + source = priv->remote; + + /* Read the pixel rate control from remote. */ + ctrl = v4l2_ctrl_find(source->ctrl_handler, V4L2_CID_PIXEL_RATE); + if (!ctrl) { + dev_err(priv->dev, "no pixel rate control in subdev %s\n", + source->name); + return -EINVAL; + } + + /* + * Calculate the phypll in mbps. + * link_freq = (pixel_rate * bits_per_sample) / (2 * nr_of_lanes) + * bps = link_freq * 2 + */ + mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp; + do_div(mbps, lanes * 1000000); + + /* Adjust for C-PHY, divide by 2.8. */ + if (priv->cphy) + mbps = div_u64(mbps * 5, 14); + + return mbps; +} + +static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, + unsigned int *lanes) +{ + struct v4l2_mbus_config mbus_config = { 0 }; + 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; + } + + switch (mbus_config.type) { + case V4L2_MBUS_CSI2_CPHY: + if (!priv->cphy) + return -EINVAL; + break; + case V4L2_MBUS_CSI2_DPHY: + if (priv->cphy) + return -EINVAL; + break; + default: + dev_err(priv->dev, "Unsupported media bus type %u\n", + mbus_config.type); + return -EINVAL; + } + + if (mbus_config.bus.mipi_csi2.num_data_lanes > priv->lanes) { + dev_err(priv->dev, + "Unsupported mbus config: too many data lanes %u\n", + mbus_config.bus.mipi_csi2.num_data_lanes); + return -EINVAL; + } + + *lanes = mbus_config.bus.mipi_csi2.num_data_lanes; + + return 0; +} + +static int rcsi2_start_receiver_gen3(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; + + dev_dbg(priv->dev, "Input size (%ux%u%c)\n", + priv->mf.width, priv->mf.height, + priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i'); + + /* Code is validated in set_fmt. */ + format = rcsi2_code_to_fmt(priv->mf.code); + if (!format) + return -EINVAL; + + /* + * Enable all supported CSI-2 channels with virtual channel and + * data type matching. + * + * NOTE: It's not possible to get individual datatype for each + * source virtual channel. Once this is possible in V4L2 + * it should be used here. + */ + for (i = 0; i < priv->info->num_channels; i++) { + u32 vcdt_part; + + if (priv->channel_vc[i] < 0) + continue; + + vcdt_part = VCDT_SEL_VC(priv->channel_vc[i]) | VCDT_VCDTN_EN | + VCDT_SEL_DTN_ON | VCDT_SEL_DT(format->datatype); + + /* Store in correct reg and offset. */ + if (i < 2) + vcdt |= vcdt_part << ((i % 2) * 16); + else + vcdt2 |= vcdt_part << ((i % 2) * 16); + } + + if (priv->mf.field == V4L2_FIELD_ALTERNATE) { + fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2 + | FLD_FLD_EN; + + if (priv->mf.height == 240) + fld |= FLD_FLD_NUM(0); + else + 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 << lanes) - 1; + + mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); + if (mbps < 0) + return mbps; + + /* Enable interrupts. */ + rcsi2_write(priv, INTEN_REG, INTEN_INT_AFIFO_OF | INTEN_INT_ERRSOTHS + | INTEN_INT_ERRSOTSYNCHS); + + /* Init */ + rcsi2_write(priv, TREF_REG, TREF_TREF); + rcsi2_write(priv, PHTC_REG, 0); + + /* Configure */ + if (!priv->info->use_isp) { + rcsi2_write(priv, VCDT_REG, vcdt); + if (vcdt2) + rcsi2_write(priv, VCDT2_REG, vcdt2); + } + + /* Lanes are zero indexed. */ + rcsi2_write(priv, LSWAP_REG, + LSWAP_L0SEL(priv->lane_swap[0] - 1) | + LSWAP_L1SEL(priv->lane_swap[1] - 1) | + LSWAP_L2SEL(priv->lane_swap[2] - 1) | + LSWAP_L3SEL(priv->lane_swap[3] - 1)); + + /* Start */ + if (priv->info->init_phtw) { + ret = priv->info->init_phtw(priv, mbps); + if (ret) + return ret; + } + + if (priv->info->hsfreqrange) { + ret = rcsi2_set_phypll(priv, mbps); + if (ret) + return ret; + } + + if (priv->info->csi0clkfreqrange) + rcsi2_write(priv, CSI0CLKFCPR_REG, + CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange)); + + if (priv->info->use_isp) + rcsi2_write(priv, PHYFRX_REG, + PHYFRX_FORCERX_MODE_3 | PHYFRX_FORCERX_MODE_2 | + PHYFRX_FORCERX_MODE_1 | PHYFRX_FORCERX_MODE_0); + + rcsi2_write(priv, PHYCNT_REG, phycnt); + rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN | + LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP); + rcsi2_write(priv, FLD_REG, fld); + rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ); + rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); + + ret = rcsi2_wait_phy_start(priv, lanes); + if (ret) + return ret; + + if (priv->info->use_isp) + rcsi2_write(priv, PHYFRX_REG, 0); + + /* Run post PHY start initialization, if needed. */ + if (priv->info->phy_post_init) { + ret = priv->info->phy_post_init(priv); + if (ret) + return ret; + } + + /* Clear Ultra Low Power interrupt. */ + if (priv->info->clear_ulps) + rcsi2_write(priv, INTSTATE_REG, + INTSTATE_INT_ULPS_START | + INTSTATE_INT_ULPS_END); + return 0; +} + +static int rcsi2_wait_phy_start_v4h(struct rcar_csi2 *priv, u32 match) +{ + unsigned int timeout; + u32 status; + + for (timeout = 0; timeout <= 10; timeout++) { + status = rcsi2_read(priv, V4H_ST_PHYST_REG); + if ((status & match) == match) + return 0; + + usleep_range(1000, 2000); + } + + return -ETIMEDOUT; +} + +static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps) +{ + const struct rcsi2_cphy_setting *conf; + + for (conf = cphy_setting_table_r8a779g0; conf->msps != 0; conf++) { + if (conf->msps > msps) + break; + } + + if (!conf->msps) { + dev_err(priv->dev, "Unsupported PHY speed for msps setting (%u Msps)", msps); + return -ERANGE; + } + + /* C-PHY specific */ + rcsi2_write16(priv, V4H_CORE_DIG_RW_COMMON_REG(7), 0x0155); + rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(7), 0x0068); + rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(8), 0x0010); + + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_LP_0_REG, 0x463c); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_LP_0_REG, 0x463c); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_LP_0_REG, 0x463c); + + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(0), 0x00d5); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(0), 0x00d5); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(0), 0x00d5); + + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(1), 0x0013); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(1), 0x0013); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(1), 0x0013); + + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(5), 0x0013); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(5), 0x0013); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(5), 0x0013); + + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(6), 0x000a); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(6), 0x000a); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(6), 0x000a); + + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(2), conf->rx2); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(2), conf->rx2); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(2), conf->rx2); + + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(2), 0x0001); + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(2), 0); + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(2), 0x0001); + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(2), 0x0001); + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(2), 0); + + rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(0), conf->trio0); + rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(0), conf->trio0); + rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(0), conf->trio0); + + rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(2), conf->trio2); + rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(2), conf->trio2); + rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(2), conf->trio2); + + rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(1), conf->trio1); + rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(1), conf->trio1); + rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(1), conf->trio1); + + /* + * Configure pin-swap. + * TODO: This registers is not documented yet, the values should depend + * on the 'clock-lanes' and 'data-lanes' devicetree properties. + */ + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG, 0xf5); + rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG, 0x5000); + + /* Leave Shutdown mode */ + rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0)); + rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0)); + + /* Wait for calibration */ + if (rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_PHY_READY)) { + dev_err(priv->dev, "PHY calibration failed\n"); + return -ETIMEDOUT; + } + + /* C-PHY setting - analog programing*/ + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(9), conf->lane29); + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(7), conf->lane27); + + return 0; +} + +static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv) +{ + const struct rcar_csi2_format *format; + unsigned int lanes; + int msps; + int ret; + + /* Calculate parameters */ + format = rcsi2_code_to_fmt(priv->mf.code); + if (!format) + return -EINVAL; + + ret = rcsi2_get_active_lanes(priv, &lanes); + if (ret) + return ret; + + msps = rcsi2_calc_mbps(priv, format->bpp, lanes); + if (msps < 0) + return msps; + + /* Reset LINK and PHY*/ + rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0); + rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0); + rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0); + + /* PHY static setting */ + rcsi2_write(priv, V4H_PHY_EN_REG, BIT(0)); + rcsi2_write(priv, V4H_FLDC_REG, 0); + rcsi2_write(priv, V4H_FLDD_REG, 0); + rcsi2_write(priv, V4H_IDIC_REG, 0); + rcsi2_write(priv, V4H_PHY_MODE_REG, BIT(0)); + rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1); + + /* Reset CSI2 */ + rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0)); + + /* Registers static setting through APB */ + /* Common setting */ + rcsi2_write16(priv, V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(0), 0x1bfd); + rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG, 0x0233); + rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(6), 0x0027); + rcsi2_write16(priv, V4H_PPI_CALIBCTRL_RW_COMMON_BG_0_REG, 0x01f4); + rcsi2_write16(priv, V4H_PPI_RW_TERMCAL_CFG_0_REG, 0x0013); + rcsi2_write16(priv, V4H_PPI_RW_OFFSETCAL_CFG_0_REG, 0x0003); + rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_TIMEBASE_REG, 0x004f); + rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_NREF_REG, 0x0320); + rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_NREF_RANGE_REG, 0x000f); + rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG, 0xfe18); + rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG, 0x0c3c); + rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG, 0x0105); + rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(6), 0x1000); + rcsi2_write16(priv, V4H_PPI_RW_COMMON_CFG_REG, 0x0003); + + /* C-PHY settings */ + ret = rcsi2_c_phy_setting_v4h(priv, msps); + if (ret) + return ret; + + rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 | + V4H_ST_PHYST_ST_STOPSTATE_1 | + V4H_ST_PHYST_ST_STOPSTATE_2); + + return 0; +} + +static int rcsi2_start(struct rcar_csi2 *priv) +{ + int ret; + + ret = rcsi2_exit_standby(priv); + if (ret < 0) + return ret; + + ret = priv->info->start_receiver(priv); + if (ret) { + rcsi2_enter_standby(priv); + return ret; + } + + ret = v4l2_subdev_call(priv->remote, video, s_stream, 1); + if (ret) { + rcsi2_enter_standby(priv); + return ret; + } + + return 0; +} + +static void rcsi2_stop(struct rcar_csi2 *priv) +{ + rcsi2_enter_standby(priv); + v4l2_subdev_call(priv->remote, video, s_stream, 0); +} + +static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) +{ + struct rcar_csi2 *priv = sd_to_csi2(sd); + int ret = 0; + + mutex_lock(&priv->lock); + + if (!priv->remote) { + ret = -ENODEV; + goto out; + } + + if (enable && priv->stream_count == 0) { + ret = rcsi2_start(priv); + if (ret) + goto out; + } else if (!enable && priv->stream_count == 1) { + rcsi2_stop(priv); + } + + priv->stream_count += enable ? 1 : -1; +out: + mutex_unlock(&priv->lock); + + return ret; +} + +static int rcsi2_set_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct rcar_csi2 *priv = sd_to_csi2(sd); + struct v4l2_mbus_framefmt *framefmt; + + mutex_lock(&priv->lock); + + if (!rcsi2_code_to_fmt(format->format.code)) + format->format.code = rcar_csi2_formats[0].code; + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { + priv->mf = format->format; + } else { + framefmt = v4l2_subdev_state_get_format(sd_state, 0); + *framefmt = format->format; + } + + mutex_unlock(&priv->lock); + + return 0; +} + +static int rcsi2_get_pad_format(struct v4l2_subdev *sd, + struct v4l2_subdev_state *sd_state, + struct v4l2_subdev_format *format) +{ + struct rcar_csi2 *priv = sd_to_csi2(sd); + + mutex_lock(&priv->lock); + + if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) + format->format = priv->mf; + else + format->format = *v4l2_subdev_state_get_format(sd_state, 0); + + mutex_unlock(&priv->lock); + + return 0; +} + +static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = { + .s_stream = rcsi2_s_stream, +}; + +static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = { + .set_fmt = rcsi2_set_pad_format, + .get_fmt = rcsi2_get_pad_format, +}; + +static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = { + .video = &rcar_csi2_video_ops, + .pad = &rcar_csi2_pad_ops, +}; + +static irqreturn_t rcsi2_irq(int irq, void *data) +{ + struct rcar_csi2 *priv = data; + u32 status, err_status; + + status = rcsi2_read(priv, INTSTATE_REG); + err_status = rcsi2_read(priv, INTERRSTATE_REG); + + if (!status) + return IRQ_HANDLED; + + rcsi2_write(priv, INTSTATE_REG, status); + + if (!err_status) + return IRQ_HANDLED; + + rcsi2_write(priv, INTERRSTATE_REG, err_status); + + dev_info(priv->dev, "Transfer error, restarting CSI-2 receiver\n"); + + return IRQ_WAKE_THREAD; +} + +static irqreturn_t rcsi2_irq_thread(int irq, void *data) +{ + struct rcar_csi2 *priv = data; + + mutex_lock(&priv->lock); + rcsi2_stop(priv); + usleep_range(1000, 2000); + if (rcsi2_start(priv)) + dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n"); + mutex_unlock(&priv->lock); + + return IRQ_HANDLED; +} + +/* ----------------------------------------------------------------------------- + * Async handling and registration of subdevices and links. + */ + +static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asc) +{ + struct rcar_csi2 *priv = notifier_to_csi2(notifier); + int pad; + + pad = media_entity_get_fwnode_pad(&subdev->entity, asc->match.fwnode, + MEDIA_PAD_FL_SOURCE); + if (pad < 0) { + dev_err(priv->dev, "Failed to find pad for %s\n", subdev->name); + return pad; + } + + priv->remote = subdev; + priv->remote_pad = pad; + + dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad); + + return media_create_pad_link(&subdev->entity, pad, + &priv->subdev.entity, 0, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); +} + +static void rcsi2_notify_unbind(struct v4l2_async_notifier *notifier, + struct v4l2_subdev *subdev, + struct v4l2_async_connection *asc) +{ + struct rcar_csi2 *priv = notifier_to_csi2(notifier); + + priv->remote = NULL; + + dev_dbg(priv->dev, "Unbind %s\n", subdev->name); +} + +static const struct v4l2_async_notifier_operations rcar_csi2_notify_ops = { + .bound = rcsi2_notify_bound, + .unbind = rcsi2_notify_unbind, +}; + +static int rcsi2_parse_v4l2(struct rcar_csi2 *priv, + struct v4l2_fwnode_endpoint *vep) +{ + unsigned int i; + + /* Only port 0 endpoint 0 is valid. */ + if (vep->base.port || vep->base.id) + return -ENOTCONN; + + priv->lanes = vep->bus.mipi_csi2.num_data_lanes; + + switch (vep->bus_type) { + case V4L2_MBUS_CSI2_DPHY: + if (!priv->info->support_dphy) { + dev_err(priv->dev, "D-PHY not supported\n"); + return -EINVAL; + } + + if (priv->lanes != 1 && priv->lanes != 2 && priv->lanes != 4) { + dev_err(priv->dev, + "Unsupported number of data-lanes for D-PHY: %u\n", + priv->lanes); + return -EINVAL; + } + + priv->cphy = false; + break; + case V4L2_MBUS_CSI2_CPHY: + if (!priv->info->support_cphy) { + dev_err(priv->dev, "C-PHY not supported\n"); + return -EINVAL; + } + + if (priv->lanes != 3) { + dev_err(priv->dev, + "Unsupported number of data-lanes for C-PHY: %u\n", + priv->lanes); + return -EINVAL; + } + + priv->cphy = true; + break; + default: + dev_err(priv->dev, "Unsupported bus: %u\n", vep->bus_type); + return -EINVAL; + } + + for (i = 0; i < ARRAY_SIZE(priv->lane_swap); i++) { + priv->lane_swap[i] = i < priv->lanes ? + vep->bus.mipi_csi2.data_lanes[i] : i; + + /* Check for valid lane number. */ + if (priv->lane_swap[i] < 1 || priv->lane_swap[i] > 4) { + dev_err(priv->dev, "data-lanes must be in 1-4 range\n"); + return -EINVAL; + } + } + + return 0; +} + +static int rcsi2_parse_dt(struct rcar_csi2 *priv) +{ + struct v4l2_async_connection *asc; + struct fwnode_handle *fwnode; + struct fwnode_handle *ep; + struct v4l2_fwnode_endpoint v4l2_ep = { + .bus_type = V4L2_MBUS_UNKNOWN, + }; + int ret; + + ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev), 0, 0, 0); + if (!ep) { + dev_err(priv->dev, "Not connected to subdevice\n"); + return -EINVAL; + } + + ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep); + if (ret) { + dev_err(priv->dev, "Could not parse v4l2 endpoint\n"); + fwnode_handle_put(ep); + return -EINVAL; + } + + ret = rcsi2_parse_v4l2(priv, &v4l2_ep); + if (ret) { + fwnode_handle_put(ep); + return ret; + } + + fwnode = fwnode_graph_get_remote_endpoint(ep); + fwnode_handle_put(ep); + + dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode)); + + v4l2_async_subdev_nf_init(&priv->notifier, &priv->subdev); + priv->notifier.ops = &rcar_csi2_notify_ops; + + asc = v4l2_async_nf_add_fwnode(&priv->notifier, fwnode, + struct v4l2_async_connection); + fwnode_handle_put(fwnode); + if (IS_ERR(asc)) + return PTR_ERR(asc); + + ret = v4l2_async_nf_register(&priv->notifier); + if (ret) + v4l2_async_nf_cleanup(&priv->notifier); + + return ret; +} + +/* ----------------------------------------------------------------------------- + * PHTW initialization sequences. + * + * NOTE: Magic values are from the datasheet and lack documentation. + */ + +static int rcsi2_phtw_write(struct rcar_csi2 *priv, u16 data, u16 code) +{ + unsigned int timeout; + + rcsi2_write(priv, PHTW_REG, + PHTW_DWEN | PHTW_TESTDIN_DATA(data) | + PHTW_CWEN | PHTW_TESTDIN_CODE(code)); + + /* Wait for DWEN and CWEN to be cleared by hardware. */ + for (timeout = 0; timeout <= 20; timeout++) { + if (!(rcsi2_read(priv, PHTW_REG) & (PHTW_DWEN | PHTW_CWEN))) + return 0; + + usleep_range(1000, 2000); + } + + dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n"); + + return -ETIMEDOUT; +} + +static int rcsi2_phtw_write_array(struct rcar_csi2 *priv, + const struct phtw_value *values) +{ + const struct phtw_value *value; + int ret; + + for (value = values; value->data || value->code; value++) { + ret = rcsi2_phtw_write(priv, value->data, value->code); + if (ret) + return ret; + } + + return 0; +} + +static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps, + const struct rcsi2_mbps_reg *values, u16 code) +{ + const struct rcsi2_mbps_reg *value; + const struct rcsi2_mbps_reg *prev_value = NULL; + + for (value = values; value->mbps; value++) { + if (value->mbps >= mbps) + break; + prev_value = value; + } + + if (prev_value && + ((mbps - prev_value->mbps) <= (value->mbps - mbps))) + value = prev_value; + + if (!value->mbps) { + dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); + return -ERANGE; + } + + return rcsi2_phtw_write(priv, value->reg, code); +} + +static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, + unsigned int mbps) +{ + static const struct phtw_value step1[] = { + { .data = 0xcc, .code = 0xe2 }, + { .data = 0x01, .code = 0xe3 }, + { .data = 0x11, .code = 0xe4 }, + { .data = 0x01, .code = 0xe5 }, + { .data = 0x10, .code = 0x04 }, + { /* sentinel */ }, + }; + + static const struct phtw_value step2[] = { + { .data = 0x38, .code = 0x08 }, + { .data = 0x01, .code = 0x00 }, + { .data = 0x4b, .code = 0xac }, + { .data = 0x03, .code = 0x00 }, + { .data = 0x80, .code = 0x07 }, + { /* sentinel */ }, + }; + + int ret; + + ret = rcsi2_phtw_write_array(priv, step1); + if (ret) + return ret; + + if (mbps != 0 && mbps <= 250) { + ret = rcsi2_phtw_write(priv, 0x39, 0x05); + if (ret) + return ret; + + ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_h3_v3h_m3n, + 0xf1); + if (ret) + return ret; + } + + return rcsi2_phtw_write_array(priv, step2); +} + +static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) +{ + return __rcsi2_init_phtw_h3_v3h_m3n(priv, mbps); +} + +static int rcsi2_init_phtw_h3es2(struct rcar_csi2 *priv, unsigned int mbps) +{ + return __rcsi2_init_phtw_h3_v3h_m3n(priv, 0); +} + +static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) +{ + return rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44); +} + +static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv) +{ + static const struct phtw_value step1[] = { + { .data = 0xee, .code = 0x34 }, + { .data = 0xee, .code = 0x44 }, + { .data = 0xee, .code = 0x54 }, + { .data = 0xee, .code = 0x84 }, + { .data = 0xee, .code = 0x94 }, + { /* sentinel */ }, + }; + + return rcsi2_phtw_write_array(priv, step1); +} + +static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, + unsigned int mbps) +{ + /* In case of 1500Mbps or less */ + static const struct phtw_value step1[] = { + { .data = 0xcc, .code = 0xe2 }, + { /* sentinel */ }, + }; + + static const struct phtw_value step2[] = { + { .data = 0x01, .code = 0xe3 }, + { .data = 0x11, .code = 0xe4 }, + { .data = 0x01, .code = 0xe5 }, + { /* sentinel */ }, + }; + + /* In case of 1500Mbps or less */ + static const struct phtw_value step3[] = { + { .data = 0x38, .code = 0x08 }, + { /* sentinel */ }, + }; + + static const struct phtw_value step4[] = { + { .data = 0x01, .code = 0x00 }, + { .data = 0x4b, .code = 0xac }, + { .data = 0x03, .code = 0x00 }, + { .data = 0x80, .code = 0x07 }, + { /* sentinel */ }, + }; + + int ret; + + if (mbps != 0 && mbps <= 1500) + ret = rcsi2_phtw_write_array(priv, step1); + else + ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3u, 0xe2); + if (ret) + return ret; + + ret = rcsi2_phtw_write_array(priv, step2); + if (ret) + return ret; + + if (mbps != 0 && mbps <= 1500) { + ret = rcsi2_phtw_write_array(priv, step3); + if (ret) + return ret; + } + + ret = rcsi2_phtw_write_array(priv, step4); + if (ret) + return ret; + + return ret; +} + +/* ----------------------------------------------------------------------------- + * Platform Device Driver. + */ + +static int rcsi2_link_setup(struct media_entity *entity, + const struct media_pad *local, + const struct media_pad *remote, u32 flags) +{ + struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); + struct rcar_csi2 *priv = sd_to_csi2(sd); + struct video_device *vdev; + int channel, vc; + u32 id; + + if (!is_media_entity_v4l2_video_device(remote->entity)) { + dev_err(priv->dev, "Remote is not a video device\n"); + return -EINVAL; + } + + vdev = media_entity_to_video_device(remote->entity); + + if (of_property_read_u32(vdev->dev_parent->of_node, "renesas,id", &id)) { + dev_err(priv->dev, "No renesas,id, can't configure routing\n"); + return -EINVAL; + } + + channel = id % 4; + + if (flags & MEDIA_LNK_FL_ENABLED) { + if (media_pad_remote_pad_first(local)) { + dev_dbg(priv->dev, + "Each VC can only be routed to one output channel\n"); + return -EINVAL; + } + + vc = local->index - 1; + + dev_dbg(priv->dev, "Route VC%d to VIN%u on output channel %d\n", + vc, id, channel); + } else { + vc = -1; + } + + priv->channel_vc[channel] = vc; + + return 0; +} + +static const struct media_entity_operations rcar_csi2_entity_ops = { + .link_setup = rcsi2_link_setup, + .link_validate = v4l2_subdev_link_validate, +}; + +static int rcsi2_probe_resources(struct rcar_csi2 *priv, + struct platform_device *pdev) +{ + int irq, ret; + + priv->base = devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(priv->base)) + return PTR_ERR(priv->base); + + irq = platform_get_irq(pdev, 0); + if (irq < 0) + return irq; + + ret = devm_request_threaded_irq(&pdev->dev, irq, rcsi2_irq, + rcsi2_irq_thread, IRQF_SHARED, + KBUILD_MODNAME, priv); + if (ret) + return ret; + + priv->rstc = devm_reset_control_get(&pdev->dev, NULL); + + return PTR_ERR_OR_ZERO(priv->rstc); +} + +static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { + .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, + .start_receiver = rcsi2_start_receiver_gen3, + .enter_standby = rcsi2_enter_standby_gen3, + .hsfreqrange = hsfreqrange_h3_v3h_m3n, + .csi0clkfreqrange = 0x20, + .num_channels = 4, + .clear_ulps = true, + .support_dphy = true, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { + .init_phtw = rcsi2_init_phtw_h3es2, + .start_receiver = rcsi2_start_receiver_gen3, + .enter_standby = rcsi2_enter_standby_gen3, + .hsfreqrange = hsfreqrange_h3_v3h_m3n, + .csi0clkfreqrange = 0x20, + .num_channels = 4, + .clear_ulps = true, + .support_dphy = true, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { + .start_receiver = rcsi2_start_receiver_gen3, + .enter_standby = rcsi2_enter_standby_gen3, + .hsfreqrange = hsfreqrange_m3w, + .num_channels = 4, + .support_dphy = true, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = { + .start_receiver = rcsi2_start_receiver_gen3, + .enter_standby = rcsi2_enter_standby_gen3, + .hsfreqrange = hsfreqrange_m3w, + .num_channels = 4, + .support_dphy = true, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { + .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, + .start_receiver = rcsi2_start_receiver_gen3, + .enter_standby = rcsi2_enter_standby_gen3, + .hsfreqrange = hsfreqrange_h3_v3h_m3n, + .csi0clkfreqrange = 0x20, + .num_channels = 4, + .clear_ulps = true, + .support_dphy = true, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { + .init_phtw = rcsi2_init_phtw_v3m_e3, + .phy_post_init = rcsi2_phy_post_init_v3m_e3, + .start_receiver = rcsi2_start_receiver_gen3, + .enter_standby = rcsi2_enter_standby_gen3, + .num_channels = 4, + .support_dphy = true, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = { + .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, + .start_receiver = rcsi2_start_receiver_gen3, + .enter_standby = rcsi2_enter_standby_gen3, + .hsfreqrange = hsfreqrange_h3_v3h_m3n, + .csi0clkfreqrange = 0x20, + .clear_ulps = true, + .support_dphy = true, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { + .init_phtw = rcsi2_init_phtw_v3m_e3, + .phy_post_init = rcsi2_phy_post_init_v3m_e3, + .start_receiver = rcsi2_start_receiver_gen3, + .enter_standby = rcsi2_enter_standby_gen3, + .num_channels = 2, + .support_dphy = true, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = { + .init_phtw = rcsi2_init_phtw_v3u, + .start_receiver = rcsi2_start_receiver_gen3, + .enter_standby = rcsi2_enter_standby_gen3, + .hsfreqrange = hsfreqrange_v3u, + .csi0clkfreqrange = 0x20, + .clear_ulps = true, + .use_isp = true, + .support_dphy = true, +}; + +static const struct rcar_csi2_info rcar_csi2_info_r8a779g0 = { + .start_receiver = rcsi2_start_receiver_v4h, + .use_isp = true, + .support_cphy = true, +}; + +static const struct of_device_id rcar_csi2_of_table[] = { + { + .compatible = "renesas,r8a774a1-csi2", + .data = &rcar_csi2_info_r8a7796, + }, + { + .compatible = "renesas,r8a774b1-csi2", + .data = &rcar_csi2_info_r8a77965, + }, + { + .compatible = "renesas,r8a774c0-csi2", + .data = &rcar_csi2_info_r8a77990, + }, + { + .compatible = "renesas,r8a774e1-csi2", + .data = &rcar_csi2_info_r8a7795, + }, + { + .compatible = "renesas,r8a7795-csi2", + .data = &rcar_csi2_info_r8a7795, + }, + { + .compatible = "renesas,r8a7796-csi2", + .data = &rcar_csi2_info_r8a7796, + }, + { + .compatible = "renesas,r8a77961-csi2", + .data = &rcar_csi2_info_r8a77961, + }, + { + .compatible = "renesas,r8a77965-csi2", + .data = &rcar_csi2_info_r8a77965, + }, + { + .compatible = "renesas,r8a77970-csi2", + .data = &rcar_csi2_info_r8a77970, + }, + { + .compatible = "renesas,r8a77980-csi2", + .data = &rcar_csi2_info_r8a77980, + }, + { + .compatible = "renesas,r8a77990-csi2", + .data = &rcar_csi2_info_r8a77990, + }, + { + .compatible = "renesas,r8a779a0-csi2", + .data = &rcar_csi2_info_r8a779a0, + }, + { + .compatible = "renesas,r8a779g0-csi2", + .data = &rcar_csi2_info_r8a779g0, + }, + { /* sentinel */ }, +}; +MODULE_DEVICE_TABLE(of, rcar_csi2_of_table); + +static const struct soc_device_attribute r8a7795[] = { + { + .soc_id = "r8a7795", .revision = "ES2.*", + .data = &rcar_csi2_info_r8a7795es2, + }, + { /* sentinel */ } +}; + +static int rcsi2_probe(struct platform_device *pdev) +{ + const struct soc_device_attribute *attr; + struct rcar_csi2 *priv; + unsigned int i, num_pads; + int ret; + + priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->info = of_device_get_match_data(&pdev->dev); + + /* + * The different ES versions of r8a7795 (H3) behave differently but + * share the same compatible string. + */ + attr = soc_device_match(r8a7795); + if (attr) + priv->info = attr->data; + + priv->dev = &pdev->dev; + + mutex_init(&priv->lock); + priv->stream_count = 0; + + ret = rcsi2_probe_resources(priv, pdev); + if (ret) { + dev_err(priv->dev, "Failed to get resources\n"); + goto error_mutex; + } + + platform_set_drvdata(pdev, priv); + + ret = rcsi2_parse_dt(priv); + if (ret) + goto error_mutex; + + priv->subdev.owner = THIS_MODULE; + priv->subdev.dev = &pdev->dev; + v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops); + v4l2_set_subdevdata(&priv->subdev, &pdev->dev); + snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s", + KBUILD_MODNAME, dev_name(&pdev->dev)); + priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; + + priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; + priv->subdev.entity.ops = &rcar_csi2_entity_ops; + + num_pads = priv->info->use_isp ? 2 : NR_OF_RCAR_CSI2_PAD; + + priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; + for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++) + priv->pads[i].flags = MEDIA_PAD_FL_SOURCE; + + ret = media_entity_pads_init(&priv->subdev.entity, num_pads, + priv->pads); + if (ret) + goto error_async; + + for (i = 0; i < ARRAY_SIZE(priv->channel_vc); i++) + priv->channel_vc[i] = -1; + + pm_runtime_enable(&pdev->dev); + + ret = v4l2_async_register_subdev(&priv->subdev); + if (ret < 0) + goto error_async; + + dev_info(priv->dev, "%d lanes found\n", priv->lanes); + + return 0; + +error_async: + v4l2_async_nf_unregister(&priv->notifier); + v4l2_async_nf_cleanup(&priv->notifier); +error_mutex: + mutex_destroy(&priv->lock); + + return ret; +} + +static void rcsi2_remove(struct platform_device *pdev) +{ + struct rcar_csi2 *priv = platform_get_drvdata(pdev); + + v4l2_async_nf_unregister(&priv->notifier); + v4l2_async_nf_cleanup(&priv->notifier); + v4l2_async_unregister_subdev(&priv->subdev); + + pm_runtime_disable(&pdev->dev); + + mutex_destroy(&priv->lock); +} + +static struct platform_driver rcar_csi2_pdrv = { + .remove_new = rcsi2_remove, + .probe = rcsi2_probe, + .driver = { + .name = "rcar-csi2", + .suppress_bind_attrs = true, + .of_match_table = rcar_csi2_of_table, + }, +}; + +module_platform_driver(rcar_csi2_pdrv); + +MODULE_AUTHOR("Niklas Söderlund "); +MODULE_DESCRIPTION("Renesas R-Car MIPI CSI-2 receiver driver"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/renesas/rcar-isp.c b/drivers/media/platform/renesas/rcar-isp.c index 530d65fc54..4512ac338c 100644 --- a/drivers/media/platform/renesas/rcar-isp.c +++ b/drivers/media/platform/renesas/rcar-isp.c @@ -518,6 +518,7 @@ static void risp_remove(struct platform_device *pdev) static struct platform_driver rcar_isp_driver = { .driver = { .name = "rcar-isp", + .suppress_bind_attrs = true, .of_match_table = risp_of_id_table, }, .probe = risp_probe, diff --git a/drivers/media/platform/renesas/rcar-vin/Kconfig b/drivers/media/platform/renesas/rcar-vin/Kconfig index de55fe63d8..2ec857ab83 100644 --- a/drivers/media/platform/renesas/rcar-vin/Kconfig +++ b/drivers/media/platform/renesas/rcar-vin/Kconfig @@ -1,20 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 -config VIDEO_RCAR_CSI2 - tristate "R-Car MIPI CSI-2 Receiver" - depends on V4L_PLATFORM_DRIVERS - depends on VIDEO_DEV && OF - depends on ARCH_RENESAS || COMPILE_TEST - select MEDIA_CONTROLLER - select VIDEO_V4L2_SUBDEV_API - select RESET_CONTROLLER - select V4L2_FWNODE - help - Support for Renesas R-Car MIPI CSI-2 receiver. - 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. - config VIDEO_RCAR_VIN tristate "R-Car Video Input (VIN) Driver" depends on V4L_PLATFORM_DRIVERS diff --git a/drivers/media/platform/renesas/rcar-vin/Makefile b/drivers/media/platform/renesas/rcar-vin/Makefile index 00d809f5d2..5938ad6290 100644 --- a/drivers/media/platform/renesas/rcar-vin/Makefile +++ b/drivers/media/platform/renesas/rcar-vin/Makefile @@ -1,5 +1,4 @@ # SPDX-License-Identifier: GPL-2.0 rcar-vin-objs = rcar-core.o rcar-dma.o rcar-v4l2.o -obj-$(CONFIG_VIDEO_RCAR_CSI2) += rcar-csi2.o obj-$(CONFIG_VIDEO_RCAR_VIN) += rcar-vin.o diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c b/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c deleted file mode 100644 index 582d5e35db..0000000000 --- a/drivers/media/platform/renesas/rcar-vin/rcar-csi2.c +++ /dev/null @@ -1,1959 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -/* - * Driver for Renesas R-Car MIPI CSI-2 Receiver - * - * Copyright (C) 2018 Renesas Electronics Corp. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -struct rcar_csi2; - -/* Register offsets and bits */ - -/* Control Timing Select */ -#define TREF_REG 0x00 -#define TREF_TREF BIT(0) - -/* Software Reset */ -#define SRST_REG 0x04 -#define SRST_SRST BIT(0) - -/* PHY Operation Control */ -#define PHYCNT_REG 0x08 -#define PHYCNT_SHUTDOWNZ BIT(17) -#define PHYCNT_RSTZ BIT(16) -#define PHYCNT_ENABLECLK BIT(4) -#define PHYCNT_ENABLE_3 BIT(3) -#define PHYCNT_ENABLE_2 BIT(2) -#define PHYCNT_ENABLE_1 BIT(1) -#define PHYCNT_ENABLE_0 BIT(0) - -/* Checksum Control */ -#define CHKSUM_REG 0x0c -#define CHKSUM_ECC_EN BIT(1) -#define CHKSUM_CRC_EN BIT(0) - -/* - * Channel Data Type Select - * VCDT[0-15]: Channel 0 VCDT[16-31]: Channel 1 - * VCDT2[0-15]: Channel 2 VCDT2[16-31]: Channel 3 - */ -#define VCDT_REG 0x10 -#define VCDT2_REG 0x14 -#define VCDT_VCDTN_EN BIT(15) -#define VCDT_SEL_VC(n) (((n) & 0x3) << 8) -#define VCDT_SEL_DTN_ON BIT(6) -#define VCDT_SEL_DT(n) (((n) & 0x3f) << 0) - -/* Frame Data Type Select */ -#define FRDT_REG 0x18 - -/* Field Detection Control */ -#define FLD_REG 0x1c -#define FLD_FLD_NUM(n) (((n) & 0xff) << 16) -#define FLD_DET_SEL(n) (((n) & 0x3) << 4) -#define FLD_FLD_EN4 BIT(3) -#define FLD_FLD_EN3 BIT(2) -#define FLD_FLD_EN2 BIT(1) -#define FLD_FLD_EN BIT(0) - -/* Automatic Standby Control */ -#define ASTBY_REG 0x20 - -/* Long Data Type Setting 0 */ -#define LNGDT0_REG 0x28 - -/* Long Data Type Setting 1 */ -#define LNGDT1_REG 0x2c - -/* Interrupt Enable */ -#define INTEN_REG 0x30 -#define INTEN_INT_AFIFO_OF BIT(27) -#define INTEN_INT_ERRSOTHS BIT(4) -#define INTEN_INT_ERRSOTSYNCHS BIT(3) - -/* Interrupt Source Mask */ -#define INTCLOSE_REG 0x34 - -/* Interrupt Status Monitor */ -#define INTSTATE_REG 0x38 -#define INTSTATE_INT_ULPS_START BIT(7) -#define INTSTATE_INT_ULPS_END BIT(6) - -/* Interrupt Error Status Monitor */ -#define INTERRSTATE_REG 0x3c - -/* Short Packet Data */ -#define SHPDAT_REG 0x40 - -/* Short Packet Count */ -#define SHPCNT_REG 0x44 - -/* LINK Operation Control */ -#define LINKCNT_REG 0x48 -#define LINKCNT_MONITOR_EN BIT(31) -#define LINKCNT_REG_MONI_PACT_EN BIT(25) -#define LINKCNT_ICLK_NONSTOP BIT(24) - -/* Lane Swap */ -#define LSWAP_REG 0x4c -#define LSWAP_L3SEL(n) (((n) & 0x3) << 6) -#define LSWAP_L2SEL(n) (((n) & 0x3) << 4) -#define LSWAP_L1SEL(n) (((n) & 0x3) << 2) -#define LSWAP_L0SEL(n) (((n) & 0x3) << 0) - -/* PHY Test Interface Write Register */ -#define PHTW_REG 0x50 -#define PHTW_DWEN BIT(24) -#define PHTW_TESTDIN_DATA(n) (((n & 0xff)) << 16) -#define PHTW_CWEN BIT(8) -#define PHTW_TESTDIN_CODE(n) ((n & 0xff)) - -#define PHYFRX_REG 0x64 -#define PHYFRX_FORCERX_MODE_3 BIT(3) -#define PHYFRX_FORCERX_MODE_2 BIT(2) -#define PHYFRX_FORCERX_MODE_1 BIT(1) -#define PHYFRX_FORCERX_MODE_0 BIT(0) - -/* V4H BASE registers */ -#define V4H_N_LANES_REG 0x0004 -#define V4H_CSI2_RESETN_REG 0x0008 -#define V4H_PHY_MODE_REG 0x001c -#define V4H_PHY_SHUTDOWNZ_REG 0x0040 -#define V4H_DPHY_RSTZ_REG 0x0044 -#define V4H_FLDC_REG 0x0804 -#define V4H_FLDD_REG 0x0808 -#define V4H_IDIC_REG 0x0810 -#define V4H_PHY_EN_REG 0x2000 - -#define V4H_ST_PHYST_REG 0x2814 -#define V4H_ST_PHYST_ST_PHY_READY BIT(31) -#define V4H_ST_PHYST_ST_STOPSTATE_3 BIT(3) -#define V4H_ST_PHYST_ST_STOPSTATE_2 BIT(2) -#define V4H_ST_PHYST_ST_STOPSTATE_1 BIT(1) -#define V4H_ST_PHYST_ST_STOPSTATE_0 BIT(0) - -/* V4H PPI registers */ -#define V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(n) (0x21800 + ((n) * 2)) /* n = 0 - 9 */ -#define V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG 0x21822 -#define V4H_PPI_CALIBCTRL_RW_COMMON_BG_0_REG 0x2184c -#define V4H_PPI_RW_LPDCOCAL_TIMEBASE_REG 0x21c02 -#define V4H_PPI_RW_LPDCOCAL_NREF_REG 0x21c04 -#define V4H_PPI_RW_LPDCOCAL_NREF_RANGE_REG 0x21c06 -#define V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG 0x21c0a -#define V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG 0x21c0c -#define V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG 0x21c10 -#define V4H_PPI_RW_COMMON_CFG_REG 0x21c6c -#define V4H_PPI_RW_TERMCAL_CFG_0_REG 0x21c80 -#define V4H_PPI_RW_OFFSETCAL_CFG_0_REG 0x21ca0 - -/* V4H CORE registers */ -#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(n) (0x22040 + ((n) * 2)) /* n = 0 - 15 */ -#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(n) (0x22440 + ((n) * 2)) /* n = 0 - 15 */ -#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(n) (0x22840 + ((n) * 2)) /* n = 0 - 15 */ -#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(n) (0x22c40 + ((n) * 2)) /* n = 0 - 15 */ -#define V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(n) (0x23040 + ((n) * 2)) /* n = 0 - 15 */ -#define V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(n) (0x23840 + ((n) * 2)) /* n = 0 - 11 */ -#define V4H_CORE_DIG_RW_COMMON_REG(n) (0x23880 + ((n) * 2)) /* n = 0 - 15 */ -#define V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(n) (0x239e0 + ((n) * 2)) /* n = 0 - 3 */ -#define V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG 0x2a400 -#define V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG 0x2a60c - -/* V4H C-PHY */ -#define V4H_CORE_DIG_RW_TRIO0_REG(n) (0x22100 + ((n) * 2)) /* n = 0 - 3 */ -#define V4H_CORE_DIG_RW_TRIO1_REG(n) (0x22500 + ((n) * 2)) /* n = 0 - 3 */ -#define V4H_CORE_DIG_RW_TRIO2_REG(n) (0x22900 + ((n) * 2)) /* n = 0 - 3 */ -#define V4H_CORE_DIG_CLANE_0_RW_LP_0_REG 0x2a080 -#define V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(n) (0x2a100 + ((n) * 2)) /* n = 0 - 6 */ -#define V4H_CORE_DIG_CLANE_1_RW_LP_0_REG 0x2a480 -#define V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(n) (0x2a500 + ((n) * 2)) /* n = 0 - 6 */ -#define V4H_CORE_DIG_CLANE_2_RW_LP_0_REG 0x2a880 -#define V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(n) (0x2a900 + ((n) * 2)) /* n = 0 - 6 */ - -struct rcsi2_cphy_setting { - u16 msps; - u16 rx2; - u16 trio0; - u16 trio1; - u16 trio2; - u16 lane27; - u16 lane29; -}; - -static const struct rcsi2_cphy_setting cphy_setting_table_r8a779g0[] = { - { .msps = 80, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0134, .trio2 = 0x6a, .lane27 = 0x0000, .lane29 = 0x0a24 }, - { .msps = 100, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x00f5, .trio2 = 0x55, .lane27 = 0x0000, .lane29 = 0x0a24 }, - { .msps = 200, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0077, .trio2 = 0x2b, .lane27 = 0x0000, .lane29 = 0x0a44 }, - { .msps = 300, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x004d, .trio2 = 0x1d, .lane27 = 0x0000, .lane29 = 0x0a44 }, - { .msps = 400, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0038, .trio2 = 0x16, .lane27 = 0x0000, .lane29 = 0x0a64 }, - { .msps = 500, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x002b, .trio2 = 0x12, .lane27 = 0x0000, .lane29 = 0x0a64 }, - { .msps = 600, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0023, .trio2 = 0x0f, .lane27 = 0x0000, .lane29 = 0x0a64 }, - { .msps = 700, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x001d, .trio2 = 0x0d, .lane27 = 0x0000, .lane29 = 0x0a84 }, - { .msps = 800, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0018, .trio2 = 0x0c, .lane27 = 0x0000, .lane29 = 0x0a84 }, - { .msps = 900, .rx2 = 0x38, .trio0 = 0x024a, .trio1 = 0x0015, .trio2 = 0x0b, .lane27 = 0x0000, .lane29 = 0x0a84 }, - { .msps = 1000, .rx2 = 0x3e, .trio0 = 0x024a, .trio1 = 0x0012, .trio2 = 0x0a, .lane27 = 0x0400, .lane29 = 0x0a84 }, - { .msps = 1100, .rx2 = 0x44, .trio0 = 0x024a, .trio1 = 0x000f, .trio2 = 0x09, .lane27 = 0x0800, .lane29 = 0x0a84 }, - { .msps = 1200, .rx2 = 0x4a, .trio0 = 0x024a, .trio1 = 0x000e, .trio2 = 0x08, .lane27 = 0x0c00, .lane29 = 0x0a84 }, - { .msps = 1300, .rx2 = 0x51, .trio0 = 0x024a, .trio1 = 0x000c, .trio2 = 0x08, .lane27 = 0x0c00, .lane29 = 0x0aa4 }, - { .msps = 1400, .rx2 = 0x57, .trio0 = 0x024a, .trio1 = 0x000b, .trio2 = 0x07, .lane27 = 0x1000, .lane29 = 0x0aa4 }, - { .msps = 1500, .rx2 = 0x5d, .trio0 = 0x044a, .trio1 = 0x0009, .trio2 = 0x07, .lane27 = 0x1000, .lane29 = 0x0aa4 }, - { .msps = 1600, .rx2 = 0x63, .trio0 = 0x044a, .trio1 = 0x0008, .trio2 = 0x07, .lane27 = 0x1400, .lane29 = 0x0aa4 }, - { .msps = 1700, .rx2 = 0x6a, .trio0 = 0x044a, .trio1 = 0x0007, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 }, - { .msps = 1800, .rx2 = 0x70, .trio0 = 0x044a, .trio1 = 0x0007, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 }, - { .msps = 1900, .rx2 = 0x76, .trio0 = 0x044a, .trio1 = 0x0006, .trio2 = 0x06, .lane27 = 0x1400, .lane29 = 0x0aa4 }, - { .msps = 2000, .rx2 = 0x7c, .trio0 = 0x044a, .trio1 = 0x0005, .trio2 = 0x06, .lane27 = 0x1800, .lane29 = 0x0aa4 }, - { .msps = 2100, .rx2 = 0x83, .trio0 = 0x044a, .trio1 = 0x0005, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, - { .msps = 2200, .rx2 = 0x89, .trio0 = 0x064a, .trio1 = 0x0004, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, - { .msps = 2300, .rx2 = 0x8f, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, - { .msps = 2400, .rx2 = 0x95, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1800, .lane29 = 0x0aa4 }, - { .msps = 2500, .rx2 = 0x9c, .trio0 = 0x064a, .trio1 = 0x0003, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0aa4 }, - { .msps = 2600, .rx2 = 0xa2, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, - { .msps = 2700, .rx2 = 0xa8, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x05, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, - { .msps = 2800, .rx2 = 0xae, .trio0 = 0x064a, .trio1 = 0x0002, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, - { .msps = 2900, .rx2 = 0xb5, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, - { .msps = 3000, .rx2 = 0xbb, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, - { .msps = 3100, .rx2 = 0xc1, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, - { .msps = 3200, .rx2 = 0xc7, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, - { .msps = 3300, .rx2 = 0xce, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, - { .msps = 3400, .rx2 = 0xd4, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, - { .msps = 3500, .rx2 = 0xda, .trio0 = 0x084a, .trio1 = 0x0001, .trio2 = 0x04, .lane27 = 0x1c00, .lane29 = 0x0ad4 }, - { /* sentinel */ }, -}; - -struct phtw_value { - u16 data; - u16 code; -}; - -struct rcsi2_mbps_reg { - u16 mbps; - u16 reg; -}; - -static const struct rcsi2_mbps_reg phtw_mbps_v3u[] = { - { .mbps = 1500, .reg = 0xcc }, - { .mbps = 1550, .reg = 0x1d }, - { .mbps = 1600, .reg = 0x27 }, - { .mbps = 1650, .reg = 0x30 }, - { .mbps = 1700, .reg = 0x39 }, - { .mbps = 1750, .reg = 0x42 }, - { .mbps = 1800, .reg = 0x4b }, - { .mbps = 1850, .reg = 0x55 }, - { .mbps = 1900, .reg = 0x5e }, - { .mbps = 1950, .reg = 0x67 }, - { .mbps = 2000, .reg = 0x71 }, - { .mbps = 2050, .reg = 0x79 }, - { .mbps = 2100, .reg = 0x83 }, - { .mbps = 2150, .reg = 0x8c }, - { .mbps = 2200, .reg = 0x95 }, - { .mbps = 2250, .reg = 0x9e }, - { .mbps = 2300, .reg = 0xa7 }, - { .mbps = 2350, .reg = 0xb0 }, - { .mbps = 2400, .reg = 0xba }, - { .mbps = 2450, .reg = 0xc3 }, - { .mbps = 2500, .reg = 0xcc }, - { /* sentinel */ }, -}; - -static const struct rcsi2_mbps_reg phtw_mbps_h3_v3h_m3n[] = { - { .mbps = 80, .reg = 0x86 }, - { .mbps = 90, .reg = 0x86 }, - { .mbps = 100, .reg = 0x87 }, - { .mbps = 110, .reg = 0x87 }, - { .mbps = 120, .reg = 0x88 }, - { .mbps = 130, .reg = 0x88 }, - { .mbps = 140, .reg = 0x89 }, - { .mbps = 150, .reg = 0x89 }, - { .mbps = 160, .reg = 0x8a }, - { .mbps = 170, .reg = 0x8a }, - { .mbps = 180, .reg = 0x8b }, - { .mbps = 190, .reg = 0x8b }, - { .mbps = 205, .reg = 0x8c }, - { .mbps = 220, .reg = 0x8d }, - { .mbps = 235, .reg = 0x8e }, - { .mbps = 250, .reg = 0x8e }, - { /* sentinel */ }, -}; - -static const struct rcsi2_mbps_reg phtw_mbps_v3m_e3[] = { - { .mbps = 80, .reg = 0x00 }, - { .mbps = 90, .reg = 0x20 }, - { .mbps = 100, .reg = 0x40 }, - { .mbps = 110, .reg = 0x02 }, - { .mbps = 130, .reg = 0x22 }, - { .mbps = 140, .reg = 0x42 }, - { .mbps = 150, .reg = 0x04 }, - { .mbps = 170, .reg = 0x24 }, - { .mbps = 180, .reg = 0x44 }, - { .mbps = 200, .reg = 0x06 }, - { .mbps = 220, .reg = 0x26 }, - { .mbps = 240, .reg = 0x46 }, - { .mbps = 250, .reg = 0x08 }, - { .mbps = 270, .reg = 0x28 }, - { .mbps = 300, .reg = 0x0a }, - { .mbps = 330, .reg = 0x2a }, - { .mbps = 360, .reg = 0x4a }, - { .mbps = 400, .reg = 0x0c }, - { .mbps = 450, .reg = 0x2c }, - { .mbps = 500, .reg = 0x0e }, - { .mbps = 550, .reg = 0x2e }, - { .mbps = 600, .reg = 0x10 }, - { .mbps = 650, .reg = 0x30 }, - { .mbps = 700, .reg = 0x12 }, - { .mbps = 750, .reg = 0x32 }, - { .mbps = 800, .reg = 0x52 }, - { .mbps = 850, .reg = 0x72 }, - { .mbps = 900, .reg = 0x14 }, - { .mbps = 950, .reg = 0x34 }, - { .mbps = 1000, .reg = 0x54 }, - { .mbps = 1050, .reg = 0x74 }, - { .mbps = 1125, .reg = 0x16 }, - { /* sentinel */ }, -}; - -/* PHY Test Interface Clear */ -#define PHTC_REG 0x58 -#define PHTC_TESTCLR BIT(0) - -/* PHY Frequency Control */ -#define PHYPLL_REG 0x68 -#define PHYPLL_HSFREQRANGE(n) ((n) << 16) - -static const struct rcsi2_mbps_reg hsfreqrange_v3u[] = { - { .mbps = 80, .reg = 0x00 }, - { .mbps = 90, .reg = 0x10 }, - { .mbps = 100, .reg = 0x20 }, - { .mbps = 110, .reg = 0x30 }, - { .mbps = 120, .reg = 0x01 }, - { .mbps = 130, .reg = 0x11 }, - { .mbps = 140, .reg = 0x21 }, - { .mbps = 150, .reg = 0x31 }, - { .mbps = 160, .reg = 0x02 }, - { .mbps = 170, .reg = 0x12 }, - { .mbps = 180, .reg = 0x22 }, - { .mbps = 190, .reg = 0x32 }, - { .mbps = 205, .reg = 0x03 }, - { .mbps = 220, .reg = 0x13 }, - { .mbps = 235, .reg = 0x23 }, - { .mbps = 250, .reg = 0x33 }, - { .mbps = 275, .reg = 0x04 }, - { .mbps = 300, .reg = 0x14 }, - { .mbps = 325, .reg = 0x25 }, - { .mbps = 350, .reg = 0x35 }, - { .mbps = 400, .reg = 0x05 }, - { .mbps = 450, .reg = 0x16 }, - { .mbps = 500, .reg = 0x26 }, - { .mbps = 550, .reg = 0x37 }, - { .mbps = 600, .reg = 0x07 }, - { .mbps = 650, .reg = 0x18 }, - { .mbps = 700, .reg = 0x28 }, - { .mbps = 750, .reg = 0x39 }, - { .mbps = 800, .reg = 0x09 }, - { .mbps = 850, .reg = 0x19 }, - { .mbps = 900, .reg = 0x29 }, - { .mbps = 950, .reg = 0x3a }, - { .mbps = 1000, .reg = 0x0a }, - { .mbps = 1050, .reg = 0x1a }, - { .mbps = 1100, .reg = 0x2a }, - { .mbps = 1150, .reg = 0x3b }, - { .mbps = 1200, .reg = 0x0b }, - { .mbps = 1250, .reg = 0x1b }, - { .mbps = 1300, .reg = 0x2b }, - { .mbps = 1350, .reg = 0x3c }, - { .mbps = 1400, .reg = 0x0c }, - { .mbps = 1450, .reg = 0x1c }, - { .mbps = 1500, .reg = 0x2c }, - { .mbps = 1550, .reg = 0x3d }, - { .mbps = 1600, .reg = 0x0d }, - { .mbps = 1650, .reg = 0x1d }, - { .mbps = 1700, .reg = 0x2e }, - { .mbps = 1750, .reg = 0x3e }, - { .mbps = 1800, .reg = 0x0e }, - { .mbps = 1850, .reg = 0x1e }, - { .mbps = 1900, .reg = 0x2f }, - { .mbps = 1950, .reg = 0x3f }, - { .mbps = 2000, .reg = 0x0f }, - { .mbps = 2050, .reg = 0x40 }, - { .mbps = 2100, .reg = 0x41 }, - { .mbps = 2150, .reg = 0x42 }, - { .mbps = 2200, .reg = 0x43 }, - { .mbps = 2300, .reg = 0x45 }, - { .mbps = 2350, .reg = 0x46 }, - { .mbps = 2400, .reg = 0x47 }, - { .mbps = 2450, .reg = 0x48 }, - { .mbps = 2500, .reg = 0x49 }, - { /* sentinel */ }, -}; - -static const struct rcsi2_mbps_reg hsfreqrange_h3_v3h_m3n[] = { - { .mbps = 80, .reg = 0x00 }, - { .mbps = 90, .reg = 0x10 }, - { .mbps = 100, .reg = 0x20 }, - { .mbps = 110, .reg = 0x30 }, - { .mbps = 120, .reg = 0x01 }, - { .mbps = 130, .reg = 0x11 }, - { .mbps = 140, .reg = 0x21 }, - { .mbps = 150, .reg = 0x31 }, - { .mbps = 160, .reg = 0x02 }, - { .mbps = 170, .reg = 0x12 }, - { .mbps = 180, .reg = 0x22 }, - { .mbps = 190, .reg = 0x32 }, - { .mbps = 205, .reg = 0x03 }, - { .mbps = 220, .reg = 0x13 }, - { .mbps = 235, .reg = 0x23 }, - { .mbps = 250, .reg = 0x33 }, - { .mbps = 275, .reg = 0x04 }, - { .mbps = 300, .reg = 0x14 }, - { .mbps = 325, .reg = 0x25 }, - { .mbps = 350, .reg = 0x35 }, - { .mbps = 400, .reg = 0x05 }, - { .mbps = 450, .reg = 0x16 }, - { .mbps = 500, .reg = 0x26 }, - { .mbps = 550, .reg = 0x37 }, - { .mbps = 600, .reg = 0x07 }, - { .mbps = 650, .reg = 0x18 }, - { .mbps = 700, .reg = 0x28 }, - { .mbps = 750, .reg = 0x39 }, - { .mbps = 800, .reg = 0x09 }, - { .mbps = 850, .reg = 0x19 }, - { .mbps = 900, .reg = 0x29 }, - { .mbps = 950, .reg = 0x3a }, - { .mbps = 1000, .reg = 0x0a }, - { .mbps = 1050, .reg = 0x1a }, - { .mbps = 1100, .reg = 0x2a }, - { .mbps = 1150, .reg = 0x3b }, - { .mbps = 1200, .reg = 0x0b }, - { .mbps = 1250, .reg = 0x1b }, - { .mbps = 1300, .reg = 0x2b }, - { .mbps = 1350, .reg = 0x3c }, - { .mbps = 1400, .reg = 0x0c }, - { .mbps = 1450, .reg = 0x1c }, - { .mbps = 1500, .reg = 0x2c }, - { /* sentinel */ }, -}; - -static const struct rcsi2_mbps_reg hsfreqrange_m3w[] = { - { .mbps = 80, .reg = 0x00 }, - { .mbps = 90, .reg = 0x10 }, - { .mbps = 100, .reg = 0x20 }, - { .mbps = 110, .reg = 0x30 }, - { .mbps = 120, .reg = 0x01 }, - { .mbps = 130, .reg = 0x11 }, - { .mbps = 140, .reg = 0x21 }, - { .mbps = 150, .reg = 0x31 }, - { .mbps = 160, .reg = 0x02 }, - { .mbps = 170, .reg = 0x12 }, - { .mbps = 180, .reg = 0x22 }, - { .mbps = 190, .reg = 0x32 }, - { .mbps = 205, .reg = 0x03 }, - { .mbps = 220, .reg = 0x13 }, - { .mbps = 235, .reg = 0x23 }, - { .mbps = 250, .reg = 0x33 }, - { .mbps = 275, .reg = 0x04 }, - { .mbps = 300, .reg = 0x14 }, - { .mbps = 325, .reg = 0x05 }, - { .mbps = 350, .reg = 0x15 }, - { .mbps = 400, .reg = 0x25 }, - { .mbps = 450, .reg = 0x06 }, - { .mbps = 500, .reg = 0x16 }, - { .mbps = 550, .reg = 0x07 }, - { .mbps = 600, .reg = 0x17 }, - { .mbps = 650, .reg = 0x08 }, - { .mbps = 700, .reg = 0x18 }, - { .mbps = 750, .reg = 0x09 }, - { .mbps = 800, .reg = 0x19 }, - { .mbps = 850, .reg = 0x29 }, - { .mbps = 900, .reg = 0x39 }, - { .mbps = 950, .reg = 0x0a }, - { .mbps = 1000, .reg = 0x1a }, - { .mbps = 1050, .reg = 0x2a }, - { .mbps = 1100, .reg = 0x3a }, - { .mbps = 1150, .reg = 0x0b }, - { .mbps = 1200, .reg = 0x1b }, - { .mbps = 1250, .reg = 0x2b }, - { .mbps = 1300, .reg = 0x3b }, - { .mbps = 1350, .reg = 0x0c }, - { .mbps = 1400, .reg = 0x1c }, - { .mbps = 1450, .reg = 0x2c }, - { .mbps = 1500, .reg = 0x3c }, - { /* sentinel */ }, -}; - -/* PHY ESC Error Monitor */ -#define PHEERM_REG 0x74 - -/* PHY Clock Lane Monitor */ -#define PHCLM_REG 0x78 -#define PHCLM_STOPSTATECKL BIT(0) - -/* PHY Data Lane Monitor */ -#define PHDLM_REG 0x7c - -/* CSI0CLK Frequency Configuration Preset Register */ -#define CSI0CLKFCPR_REG 0x260 -#define CSI0CLKFREQRANGE(n) ((n & 0x3f) << 16) - -struct rcar_csi2_format { - u32 code; - unsigned int datatype; - unsigned int bpp; -}; - -static const struct rcar_csi2_format rcar_csi2_formats[] = { - { - .code = MEDIA_BUS_FMT_RGB888_1X24, - .datatype = MIPI_CSI2_DT_RGB888, - .bpp = 24, - }, { - .code = MEDIA_BUS_FMT_UYVY8_1X16, - .datatype = MIPI_CSI2_DT_YUV422_8B, - .bpp = 16, - }, { - .code = MEDIA_BUS_FMT_YUYV8_1X16, - .datatype = MIPI_CSI2_DT_YUV422_8B, - .bpp = 16, - }, { - .code = MEDIA_BUS_FMT_UYVY8_2X8, - .datatype = MIPI_CSI2_DT_YUV422_8B, - .bpp = 16, - }, { - .code = MEDIA_BUS_FMT_YUYV10_2X10, - .datatype = MIPI_CSI2_DT_YUV422_8B, - .bpp = 20, - }, { - .code = MEDIA_BUS_FMT_Y10_1X10, - .datatype = MIPI_CSI2_DT_RAW10, - .bpp = 10, - }, { - .code = MEDIA_BUS_FMT_SBGGR8_1X8, - .datatype = MIPI_CSI2_DT_RAW8, - .bpp = 8, - }, { - .code = MEDIA_BUS_FMT_SGBRG8_1X8, - .datatype = MIPI_CSI2_DT_RAW8, - .bpp = 8, - }, { - .code = MEDIA_BUS_FMT_SGRBG8_1X8, - .datatype = MIPI_CSI2_DT_RAW8, - .bpp = 8, - }, { - .code = MEDIA_BUS_FMT_SRGGB8_1X8, - .datatype = MIPI_CSI2_DT_RAW8, - .bpp = 8, - }, { - .code = MEDIA_BUS_FMT_Y8_1X8, - .datatype = MIPI_CSI2_DT_RAW8, - .bpp = 8, - }, -}; - -static const struct rcar_csi2_format *rcsi2_code_to_fmt(unsigned int code) -{ - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(rcar_csi2_formats); i++) - if (rcar_csi2_formats[i].code == code) - return &rcar_csi2_formats[i]; - - return NULL; -} - -enum rcar_csi2_pads { - RCAR_CSI2_SINK, - RCAR_CSI2_SOURCE_VC0, - RCAR_CSI2_SOURCE_VC1, - RCAR_CSI2_SOURCE_VC2, - RCAR_CSI2_SOURCE_VC3, - NR_OF_RCAR_CSI2_PAD, -}; - -struct rcar_csi2_info { - int (*init_phtw)(struct rcar_csi2 *priv, unsigned int mbps); - int (*phy_post_init)(struct rcar_csi2 *priv); - int (*start_receiver)(struct rcar_csi2 *priv); - void (*enter_standby)(struct rcar_csi2 *priv); - const struct rcsi2_mbps_reg *hsfreqrange; - unsigned int csi0clkfreqrange; - unsigned int num_channels; - bool clear_ulps; - bool use_isp; - bool support_dphy; - bool support_cphy; -}; - -struct rcar_csi2 { - struct device *dev; - void __iomem *base; - const struct rcar_csi2_info *info; - struct reset_control *rstc; - - struct v4l2_subdev subdev; - struct media_pad pads[NR_OF_RCAR_CSI2_PAD]; - - struct v4l2_async_notifier notifier; - struct v4l2_subdev *remote; - unsigned int remote_pad; - - int channel_vc[4]; - - struct mutex lock; /* Protects mf and stream_count. */ - struct v4l2_mbus_framefmt mf; - int stream_count; - - bool cphy; - unsigned short lanes; - unsigned char lane_swap[4]; -}; - -static inline struct rcar_csi2 *sd_to_csi2(struct v4l2_subdev *sd) -{ - return container_of(sd, struct rcar_csi2, subdev); -} - -static inline struct rcar_csi2 *notifier_to_csi2(struct v4l2_async_notifier *n) -{ - return container_of(n, struct rcar_csi2, notifier); -} - -static u32 rcsi2_read(struct rcar_csi2 *priv, unsigned int reg) -{ - return ioread32(priv->base + reg); -} - -static void rcsi2_write(struct rcar_csi2 *priv, unsigned int reg, u32 data) -{ - iowrite32(data, priv->base + reg); -} - -static void rcsi2_write16(struct rcar_csi2 *priv, unsigned int reg, u16 data) -{ - iowrite16(data, priv->base + reg); -} - -static void rcsi2_enter_standby_gen3(struct rcar_csi2 *priv) -{ - rcsi2_write(priv, PHYCNT_REG, 0); - rcsi2_write(priv, PHTC_REG, PHTC_TESTCLR); -} - -static void rcsi2_enter_standby(struct rcar_csi2 *priv) -{ - if (priv->info->enter_standby) - priv->info->enter_standby(priv); - - reset_control_assert(priv->rstc); - usleep_range(100, 150); - pm_runtime_put(priv->dev); -} - -static int rcsi2_exit_standby(struct rcar_csi2 *priv) -{ - int ret; - - ret = pm_runtime_resume_and_get(priv->dev); - if (ret < 0) - return ret; - - reset_control_deassert(priv->rstc); - - return 0; -} - -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 << lanes) - 1; - - if ((rcsi2_read(priv, PHCLM_REG) & PHCLM_STOPSTATECKL) && - (rcsi2_read(priv, PHDLM_REG) & lane_mask) == lane_mask) - return 0; - - usleep_range(1000, 2000); - } - - dev_err(priv->dev, "Timeout waiting for LP-11 state\n"); - - return -ETIMEDOUT; -} - -static int rcsi2_set_phypll(struct rcar_csi2 *priv, unsigned int mbps) -{ - const struct rcsi2_mbps_reg *hsfreq; - const struct rcsi2_mbps_reg *hsfreq_prev = NULL; - - if (mbps < priv->info->hsfreqrange->mbps) - dev_warn(priv->dev, "%u Mbps less than min PHY speed %u Mbps", - mbps, priv->info->hsfreqrange->mbps); - - for (hsfreq = priv->info->hsfreqrange; hsfreq->mbps != 0; hsfreq++) { - if (hsfreq->mbps >= mbps) - break; - hsfreq_prev = hsfreq; - } - - if (!hsfreq->mbps) { - dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); - return -ERANGE; - } - - if (hsfreq_prev && - ((mbps - hsfreq_prev->mbps) <= (hsfreq->mbps - mbps))) - hsfreq = hsfreq_prev; - - rcsi2_write(priv, PHYPLL_REG, PHYPLL_HSFREQRANGE(hsfreq->reg)); - - return 0; -} - -static int rcsi2_calc_mbps(struct rcar_csi2 *priv, unsigned int bpp, - unsigned int lanes) -{ - struct v4l2_subdev *source; - struct v4l2_ctrl *ctrl; - u64 mbps; - - if (!priv->remote) - return -ENODEV; - - source = priv->remote; - - /* Read the pixel rate control from remote. */ - ctrl = v4l2_ctrl_find(source->ctrl_handler, V4L2_CID_PIXEL_RATE); - if (!ctrl) { - dev_err(priv->dev, "no pixel rate control in subdev %s\n", - source->name); - return -EINVAL; - } - - /* - * Calculate the phypll in mbps. - * link_freq = (pixel_rate * bits_per_sample) / (2 * nr_of_lanes) - * bps = link_freq * 2 - */ - mbps = v4l2_ctrl_g_ctrl_int64(ctrl) * bpp; - do_div(mbps, lanes * 1000000); - - /* Adjust for C-PHY, divide by 2.8. */ - if (priv->cphy) - mbps = div_u64(mbps * 5, 14); - - return mbps; -} - -static int rcsi2_get_active_lanes(struct rcar_csi2 *priv, - unsigned int *lanes) -{ - struct v4l2_mbus_config mbus_config = { 0 }; - 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; - } - - switch (mbus_config.type) { - case V4L2_MBUS_CSI2_CPHY: - if (!priv->cphy) - return -EINVAL; - break; - case V4L2_MBUS_CSI2_DPHY: - if (priv->cphy) - return -EINVAL; - break; - default: - dev_err(priv->dev, "Unsupported media bus type %u\n", - mbus_config.type); - return -EINVAL; - } - - if (mbus_config.bus.mipi_csi2.num_data_lanes > priv->lanes) { - dev_err(priv->dev, - "Unsupported mbus config: too many data lanes %u\n", - mbus_config.bus.mipi_csi2.num_data_lanes); - return -EINVAL; - } - - *lanes = mbus_config.bus.mipi_csi2.num_data_lanes; - - return 0; -} - -static int rcsi2_start_receiver_gen3(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; - - dev_dbg(priv->dev, "Input size (%ux%u%c)\n", - priv->mf.width, priv->mf.height, - priv->mf.field == V4L2_FIELD_NONE ? 'p' : 'i'); - - /* Code is validated in set_fmt. */ - format = rcsi2_code_to_fmt(priv->mf.code); - if (!format) - return -EINVAL; - - /* - * Enable all supported CSI-2 channels with virtual channel and - * data type matching. - * - * NOTE: It's not possible to get individual datatype for each - * source virtual channel. Once this is possible in V4L2 - * it should be used here. - */ - for (i = 0; i < priv->info->num_channels; i++) { - u32 vcdt_part; - - if (priv->channel_vc[i] < 0) - continue; - - vcdt_part = VCDT_SEL_VC(priv->channel_vc[i]) | VCDT_VCDTN_EN | - VCDT_SEL_DTN_ON | VCDT_SEL_DT(format->datatype); - - /* Store in correct reg and offset. */ - if (i < 2) - vcdt |= vcdt_part << ((i % 2) * 16); - else - vcdt2 |= vcdt_part << ((i % 2) * 16); - } - - if (priv->mf.field == V4L2_FIELD_ALTERNATE) { - fld = FLD_DET_SEL(1) | FLD_FLD_EN4 | FLD_FLD_EN3 | FLD_FLD_EN2 - | FLD_FLD_EN; - - if (priv->mf.height == 240) - fld |= FLD_FLD_NUM(0); - else - 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 << lanes) - 1; - - mbps = rcsi2_calc_mbps(priv, format->bpp, lanes); - if (mbps < 0) - return mbps; - - /* Enable interrupts. */ - rcsi2_write(priv, INTEN_REG, INTEN_INT_AFIFO_OF | INTEN_INT_ERRSOTHS - | INTEN_INT_ERRSOTSYNCHS); - - /* Init */ - rcsi2_write(priv, TREF_REG, TREF_TREF); - rcsi2_write(priv, PHTC_REG, 0); - - /* Configure */ - if (!priv->info->use_isp) { - rcsi2_write(priv, VCDT_REG, vcdt); - if (vcdt2) - rcsi2_write(priv, VCDT2_REG, vcdt2); - } - - /* Lanes are zero indexed. */ - rcsi2_write(priv, LSWAP_REG, - LSWAP_L0SEL(priv->lane_swap[0] - 1) | - LSWAP_L1SEL(priv->lane_swap[1] - 1) | - LSWAP_L2SEL(priv->lane_swap[2] - 1) | - LSWAP_L3SEL(priv->lane_swap[3] - 1)); - - /* Start */ - if (priv->info->init_phtw) { - ret = priv->info->init_phtw(priv, mbps); - if (ret) - return ret; - } - - if (priv->info->hsfreqrange) { - ret = rcsi2_set_phypll(priv, mbps); - if (ret) - return ret; - } - - if (priv->info->csi0clkfreqrange) - rcsi2_write(priv, CSI0CLKFCPR_REG, - CSI0CLKFREQRANGE(priv->info->csi0clkfreqrange)); - - if (priv->info->use_isp) - rcsi2_write(priv, PHYFRX_REG, - PHYFRX_FORCERX_MODE_3 | PHYFRX_FORCERX_MODE_2 | - PHYFRX_FORCERX_MODE_1 | PHYFRX_FORCERX_MODE_0); - - rcsi2_write(priv, PHYCNT_REG, phycnt); - rcsi2_write(priv, LINKCNT_REG, LINKCNT_MONITOR_EN | - LINKCNT_REG_MONI_PACT_EN | LINKCNT_ICLK_NONSTOP); - rcsi2_write(priv, FLD_REG, fld); - rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ); - rcsi2_write(priv, PHYCNT_REG, phycnt | PHYCNT_SHUTDOWNZ | PHYCNT_RSTZ); - - ret = rcsi2_wait_phy_start(priv, lanes); - if (ret) - return ret; - - if (priv->info->use_isp) - rcsi2_write(priv, PHYFRX_REG, 0); - - /* Run post PHY start initialization, if needed. */ - if (priv->info->phy_post_init) { - ret = priv->info->phy_post_init(priv); - if (ret) - return ret; - } - - /* Clear Ultra Low Power interrupt. */ - if (priv->info->clear_ulps) - rcsi2_write(priv, INTSTATE_REG, - INTSTATE_INT_ULPS_START | - INTSTATE_INT_ULPS_END); - return 0; -} - -static int rcsi2_wait_phy_start_v4h(struct rcar_csi2 *priv, u32 match) -{ - unsigned int timeout; - u32 status; - - for (timeout = 0; timeout <= 10; timeout++) { - status = rcsi2_read(priv, V4H_ST_PHYST_REG); - if ((status & match) == match) - return 0; - - usleep_range(1000, 2000); - } - - return -ETIMEDOUT; -} - -static int rcsi2_c_phy_setting_v4h(struct rcar_csi2 *priv, int msps) -{ - const struct rcsi2_cphy_setting *conf; - - for (conf = cphy_setting_table_r8a779g0; conf->msps != 0; conf++) { - if (conf->msps > msps) - break; - } - - if (!conf->msps) { - dev_err(priv->dev, "Unsupported PHY speed for msps setting (%u Msps)", msps); - return -ERANGE; - } - - /* C-PHY specific */ - rcsi2_write16(priv, V4H_CORE_DIG_RW_COMMON_REG(7), 0x0155); - rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(7), 0x0068); - rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(8), 0x0010); - - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_LP_0_REG, 0x463c); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_LP_0_REG, 0x463c); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_LP_0_REG, 0x463c); - - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(0), 0x00d5); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(0), 0x00d5); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(0), 0x00d5); - - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(1), 0x0013); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(1), 0x0013); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(1), 0x0013); - - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(5), 0x0013); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(5), 0x0013); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(5), 0x0013); - - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(6), 0x000a); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(6), 0x000a); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(6), 0x000a); - - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_0_RW_HS_RX_REG(2), conf->rx2); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_RX_REG(2), conf->rx2); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_2_RW_HS_RX_REG(2), conf->rx2); - - rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(2), 0x0001); - rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE1_CTRL_2_REG(2), 0); - rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE2_CTRL_2_REG(2), 0x0001); - rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE3_CTRL_2_REG(2), 0x0001); - rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE4_CTRL_2_REG(2), 0); - - rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(0), conf->trio0); - rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(0), conf->trio0); - rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(0), conf->trio0); - - rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(2), conf->trio2); - rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(2), conf->trio2); - rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(2), conf->trio2); - - rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO0_REG(1), conf->trio1); - rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO1_REG(1), conf->trio1); - rcsi2_write16(priv, V4H_CORE_DIG_RW_TRIO2_REG(1), conf->trio1); - - /* - * Configure pin-swap. - * TODO: This registers is not documented yet, the values should depend - * on the 'clock-lanes' and 'data-lanes' devicetree properties. - */ - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_CFG_0_REG, 0xf5); - rcsi2_write16(priv, V4H_CORE_DIG_CLANE_1_RW_HS_TX_6_REG, 0x5000); - - /* Leave Shutdown mode */ - rcsi2_write(priv, V4H_DPHY_RSTZ_REG, BIT(0)); - rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, BIT(0)); - - /* Wait for calibration */ - if (rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_PHY_READY)) { - dev_err(priv->dev, "PHY calibration failed\n"); - return -ETIMEDOUT; - } - - /* C-PHY setting - analog programing*/ - rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(9), conf->lane29); - rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_LANE0_CTRL_2_REG(7), conf->lane27); - - return 0; -} - -static int rcsi2_start_receiver_v4h(struct rcar_csi2 *priv) -{ - const struct rcar_csi2_format *format; - unsigned int lanes; - int msps; - int ret; - - /* Calculate parameters */ - format = rcsi2_code_to_fmt(priv->mf.code); - if (!format) - return -EINVAL; - - ret = rcsi2_get_active_lanes(priv, &lanes); - if (ret) - return ret; - - msps = rcsi2_calc_mbps(priv, format->bpp, lanes); - if (msps < 0) - return msps; - - /* Reset LINK and PHY*/ - rcsi2_write(priv, V4H_CSI2_RESETN_REG, 0); - rcsi2_write(priv, V4H_DPHY_RSTZ_REG, 0); - rcsi2_write(priv, V4H_PHY_SHUTDOWNZ_REG, 0); - - /* PHY static setting */ - rcsi2_write(priv, V4H_PHY_EN_REG, BIT(0)); - rcsi2_write(priv, V4H_FLDC_REG, 0); - rcsi2_write(priv, V4H_FLDD_REG, 0); - rcsi2_write(priv, V4H_IDIC_REG, 0); - rcsi2_write(priv, V4H_PHY_MODE_REG, BIT(0)); - rcsi2_write(priv, V4H_N_LANES_REG, lanes - 1); - - /* Reset CSI2 */ - rcsi2_write(priv, V4H_CSI2_RESETN_REG, BIT(0)); - - /* Registers static setting through APB */ - /* Common setting */ - rcsi2_write16(priv, V4H_CORE_DIG_ANACTRL_RW_COMMON_ANACTRL_REG(0), 0x1bfd); - rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_STARTUP_1_1_REG, 0x0233); - rcsi2_write16(priv, V4H_PPI_STARTUP_RW_COMMON_DPHY_REG(6), 0x0027); - rcsi2_write16(priv, V4H_PPI_CALIBCTRL_RW_COMMON_BG_0_REG, 0x01f4); - rcsi2_write16(priv, V4H_PPI_RW_TERMCAL_CFG_0_REG, 0x0013); - rcsi2_write16(priv, V4H_PPI_RW_OFFSETCAL_CFG_0_REG, 0x0003); - rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_TIMEBASE_REG, 0x004f); - rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_NREF_REG, 0x0320); - rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_NREF_RANGE_REG, 0x000f); - rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_TWAIT_CONFIG_REG, 0xfe18); - rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_VT_CONFIG_REG, 0x0c3c); - rcsi2_write16(priv, V4H_PPI_RW_LPDCOCAL_COARSE_CFG_REG, 0x0105); - rcsi2_write16(priv, V4H_CORE_DIG_IOCTRL_RW_AFE_CB_CTRL_2_REG(6), 0x1000); - rcsi2_write16(priv, V4H_PPI_RW_COMMON_CFG_REG, 0x0003); - - /* C-PHY settings */ - ret = rcsi2_c_phy_setting_v4h(priv, msps); - if (ret) - return ret; - - rcsi2_wait_phy_start_v4h(priv, V4H_ST_PHYST_ST_STOPSTATE_0 | - V4H_ST_PHYST_ST_STOPSTATE_1 | - V4H_ST_PHYST_ST_STOPSTATE_2); - - return 0; -} - -static int rcsi2_start(struct rcar_csi2 *priv) -{ - int ret; - - ret = rcsi2_exit_standby(priv); - if (ret < 0) - return ret; - - ret = priv->info->start_receiver(priv); - if (ret) { - rcsi2_enter_standby(priv); - return ret; - } - - ret = v4l2_subdev_call(priv->remote, video, s_stream, 1); - if (ret) { - rcsi2_enter_standby(priv); - return ret; - } - - return 0; -} - -static void rcsi2_stop(struct rcar_csi2 *priv) -{ - rcsi2_enter_standby(priv); - v4l2_subdev_call(priv->remote, video, s_stream, 0); -} - -static int rcsi2_s_stream(struct v4l2_subdev *sd, int enable) -{ - struct rcar_csi2 *priv = sd_to_csi2(sd); - int ret = 0; - - mutex_lock(&priv->lock); - - if (!priv->remote) { - ret = -ENODEV; - goto out; - } - - if (enable && priv->stream_count == 0) { - ret = rcsi2_start(priv); - if (ret) - goto out; - } else if (!enable && priv->stream_count == 1) { - rcsi2_stop(priv); - } - - priv->stream_count += enable ? 1 : -1; -out: - mutex_unlock(&priv->lock); - - return ret; -} - -static int rcsi2_set_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct rcar_csi2 *priv = sd_to_csi2(sd); - struct v4l2_mbus_framefmt *framefmt; - - mutex_lock(&priv->lock); - - if (!rcsi2_code_to_fmt(format->format.code)) - format->format.code = rcar_csi2_formats[0].code; - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) { - priv->mf = format->format; - } else { - framefmt = v4l2_subdev_state_get_format(sd_state, 0); - *framefmt = format->format; - } - - mutex_unlock(&priv->lock); - - return 0; -} - -static int rcsi2_get_pad_format(struct v4l2_subdev *sd, - struct v4l2_subdev_state *sd_state, - struct v4l2_subdev_format *format) -{ - struct rcar_csi2 *priv = sd_to_csi2(sd); - - mutex_lock(&priv->lock); - - if (format->which == V4L2_SUBDEV_FORMAT_ACTIVE) - format->format = priv->mf; - else - format->format = *v4l2_subdev_state_get_format(sd_state, 0); - - mutex_unlock(&priv->lock); - - return 0; -} - -static const struct v4l2_subdev_video_ops rcar_csi2_video_ops = { - .s_stream = rcsi2_s_stream, -}; - -static const struct v4l2_subdev_pad_ops rcar_csi2_pad_ops = { - .set_fmt = rcsi2_set_pad_format, - .get_fmt = rcsi2_get_pad_format, -}; - -static const struct v4l2_subdev_ops rcar_csi2_subdev_ops = { - .video = &rcar_csi2_video_ops, - .pad = &rcar_csi2_pad_ops, -}; - -static irqreturn_t rcsi2_irq(int irq, void *data) -{ - struct rcar_csi2 *priv = data; - u32 status, err_status; - - status = rcsi2_read(priv, INTSTATE_REG); - err_status = rcsi2_read(priv, INTERRSTATE_REG); - - if (!status) - return IRQ_HANDLED; - - rcsi2_write(priv, INTSTATE_REG, status); - - if (!err_status) - return IRQ_HANDLED; - - rcsi2_write(priv, INTERRSTATE_REG, err_status); - - dev_info(priv->dev, "Transfer error, restarting CSI-2 receiver\n"); - - return IRQ_WAKE_THREAD; -} - -static irqreturn_t rcsi2_irq_thread(int irq, void *data) -{ - struct rcar_csi2 *priv = data; - - mutex_lock(&priv->lock); - rcsi2_stop(priv); - usleep_range(1000, 2000); - if (rcsi2_start(priv)) - dev_warn(priv->dev, "Failed to restart CSI-2 receiver\n"); - mutex_unlock(&priv->lock); - - return IRQ_HANDLED; -} - -/* ----------------------------------------------------------------------------- - * Async handling and registration of subdevices and links. - */ - -static int rcsi2_notify_bound(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_connection *asc) -{ - struct rcar_csi2 *priv = notifier_to_csi2(notifier); - int pad; - - pad = media_entity_get_fwnode_pad(&subdev->entity, asc->match.fwnode, - MEDIA_PAD_FL_SOURCE); - if (pad < 0) { - dev_err(priv->dev, "Failed to find pad for %s\n", subdev->name); - return pad; - } - - priv->remote = subdev; - priv->remote_pad = pad; - - dev_dbg(priv->dev, "Bound %s pad: %d\n", subdev->name, pad); - - return media_create_pad_link(&subdev->entity, pad, - &priv->subdev.entity, 0, - MEDIA_LNK_FL_ENABLED | - MEDIA_LNK_FL_IMMUTABLE); -} - -static void rcsi2_notify_unbind(struct v4l2_async_notifier *notifier, - struct v4l2_subdev *subdev, - struct v4l2_async_connection *asc) -{ - struct rcar_csi2 *priv = notifier_to_csi2(notifier); - - priv->remote = NULL; - - dev_dbg(priv->dev, "Unbind %s\n", subdev->name); -} - -static const struct v4l2_async_notifier_operations rcar_csi2_notify_ops = { - .bound = rcsi2_notify_bound, - .unbind = rcsi2_notify_unbind, -}; - -static int rcsi2_parse_v4l2(struct rcar_csi2 *priv, - struct v4l2_fwnode_endpoint *vep) -{ - unsigned int i; - - /* Only port 0 endpoint 0 is valid. */ - if (vep->base.port || vep->base.id) - return -ENOTCONN; - - priv->lanes = vep->bus.mipi_csi2.num_data_lanes; - - switch (vep->bus_type) { - case V4L2_MBUS_CSI2_DPHY: - if (!priv->info->support_dphy) { - dev_err(priv->dev, "D-PHY not supported\n"); - return -EINVAL; - } - - if (priv->lanes != 1 && priv->lanes != 2 && priv->lanes != 4) { - dev_err(priv->dev, - "Unsupported number of data-lanes for D-PHY: %u\n", - priv->lanes); - return -EINVAL; - } - - priv->cphy = false; - break; - case V4L2_MBUS_CSI2_CPHY: - if (!priv->info->support_cphy) { - dev_err(priv->dev, "C-PHY not supported\n"); - return -EINVAL; - } - - if (priv->lanes != 3) { - dev_err(priv->dev, - "Unsupported number of data-lanes for C-PHY: %u\n", - priv->lanes); - return -EINVAL; - } - - priv->cphy = true; - break; - default: - dev_err(priv->dev, "Unsupported bus: %u\n", vep->bus_type); - return -EINVAL; - } - - for (i = 0; i < ARRAY_SIZE(priv->lane_swap); i++) { - priv->lane_swap[i] = i < priv->lanes ? - vep->bus.mipi_csi2.data_lanes[i] : i; - - /* Check for valid lane number. */ - if (priv->lane_swap[i] < 1 || priv->lane_swap[i] > 4) { - dev_err(priv->dev, "data-lanes must be in 1-4 range\n"); - return -EINVAL; - } - } - - return 0; -} - -static int rcsi2_parse_dt(struct rcar_csi2 *priv) -{ - struct v4l2_async_connection *asc; - struct fwnode_handle *fwnode; - struct fwnode_handle *ep; - struct v4l2_fwnode_endpoint v4l2_ep = { - .bus_type = V4L2_MBUS_UNKNOWN, - }; - int ret; - - ep = fwnode_graph_get_endpoint_by_id(dev_fwnode(priv->dev), 0, 0, 0); - if (!ep) { - dev_err(priv->dev, "Not connected to subdevice\n"); - return -EINVAL; - } - - ret = v4l2_fwnode_endpoint_parse(ep, &v4l2_ep); - if (ret) { - dev_err(priv->dev, "Could not parse v4l2 endpoint\n"); - fwnode_handle_put(ep); - return -EINVAL; - } - - ret = rcsi2_parse_v4l2(priv, &v4l2_ep); - if (ret) { - fwnode_handle_put(ep); - return ret; - } - - fwnode = fwnode_graph_get_remote_endpoint(ep); - fwnode_handle_put(ep); - - dev_dbg(priv->dev, "Found '%pOF'\n", to_of_node(fwnode)); - - v4l2_async_subdev_nf_init(&priv->notifier, &priv->subdev); - priv->notifier.ops = &rcar_csi2_notify_ops; - - asc = v4l2_async_nf_add_fwnode(&priv->notifier, fwnode, - struct v4l2_async_connection); - fwnode_handle_put(fwnode); - if (IS_ERR(asc)) - return PTR_ERR(asc); - - ret = v4l2_async_nf_register(&priv->notifier); - if (ret) - v4l2_async_nf_cleanup(&priv->notifier); - - return ret; -} - -/* ----------------------------------------------------------------------------- - * PHTW initialization sequences. - * - * NOTE: Magic values are from the datasheet and lack documentation. - */ - -static int rcsi2_phtw_write(struct rcar_csi2 *priv, u16 data, u16 code) -{ - unsigned int timeout; - - rcsi2_write(priv, PHTW_REG, - PHTW_DWEN | PHTW_TESTDIN_DATA(data) | - PHTW_CWEN | PHTW_TESTDIN_CODE(code)); - - /* Wait for DWEN and CWEN to be cleared by hardware. */ - for (timeout = 0; timeout <= 20; timeout++) { - if (!(rcsi2_read(priv, PHTW_REG) & (PHTW_DWEN | PHTW_CWEN))) - return 0; - - usleep_range(1000, 2000); - } - - dev_err(priv->dev, "Timeout waiting for PHTW_DWEN and/or PHTW_CWEN\n"); - - return -ETIMEDOUT; -} - -static int rcsi2_phtw_write_array(struct rcar_csi2 *priv, - const struct phtw_value *values) -{ - const struct phtw_value *value; - int ret; - - for (value = values; value->data || value->code; value++) { - ret = rcsi2_phtw_write(priv, value->data, value->code); - if (ret) - return ret; - } - - return 0; -} - -static int rcsi2_phtw_write_mbps(struct rcar_csi2 *priv, unsigned int mbps, - const struct rcsi2_mbps_reg *values, u16 code) -{ - const struct rcsi2_mbps_reg *value; - const struct rcsi2_mbps_reg *prev_value = NULL; - - for (value = values; value->mbps; value++) { - if (value->mbps >= mbps) - break; - prev_value = value; - } - - if (prev_value && - ((mbps - prev_value->mbps) <= (value->mbps - mbps))) - value = prev_value; - - if (!value->mbps) { - dev_err(priv->dev, "Unsupported PHY speed (%u Mbps)", mbps); - return -ERANGE; - } - - return rcsi2_phtw_write(priv, value->reg, code); -} - -static int __rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, - unsigned int mbps) -{ - static const struct phtw_value step1[] = { - { .data = 0xcc, .code = 0xe2 }, - { .data = 0x01, .code = 0xe3 }, - { .data = 0x11, .code = 0xe4 }, - { .data = 0x01, .code = 0xe5 }, - { .data = 0x10, .code = 0x04 }, - { /* sentinel */ }, - }; - - static const struct phtw_value step2[] = { - { .data = 0x38, .code = 0x08 }, - { .data = 0x01, .code = 0x00 }, - { .data = 0x4b, .code = 0xac }, - { .data = 0x03, .code = 0x00 }, - { .data = 0x80, .code = 0x07 }, - { /* sentinel */ }, - }; - - int ret; - - ret = rcsi2_phtw_write_array(priv, step1); - if (ret) - return ret; - - if (mbps != 0 && mbps <= 250) { - ret = rcsi2_phtw_write(priv, 0x39, 0x05); - if (ret) - return ret; - - ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_h3_v3h_m3n, - 0xf1); - if (ret) - return ret; - } - - return rcsi2_phtw_write_array(priv, step2); -} - -static int rcsi2_init_phtw_h3_v3h_m3n(struct rcar_csi2 *priv, unsigned int mbps) -{ - return __rcsi2_init_phtw_h3_v3h_m3n(priv, mbps); -} - -static int rcsi2_init_phtw_h3es2(struct rcar_csi2 *priv, unsigned int mbps) -{ - return __rcsi2_init_phtw_h3_v3h_m3n(priv, 0); -} - -static int rcsi2_init_phtw_v3m_e3(struct rcar_csi2 *priv, unsigned int mbps) -{ - return rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3m_e3, 0x44); -} - -static int rcsi2_phy_post_init_v3m_e3(struct rcar_csi2 *priv) -{ - static const struct phtw_value step1[] = { - { .data = 0xee, .code = 0x34 }, - { .data = 0xee, .code = 0x44 }, - { .data = 0xee, .code = 0x54 }, - { .data = 0xee, .code = 0x84 }, - { .data = 0xee, .code = 0x94 }, - { /* sentinel */ }, - }; - - return rcsi2_phtw_write_array(priv, step1); -} - -static int rcsi2_init_phtw_v3u(struct rcar_csi2 *priv, - unsigned int mbps) -{ - /* In case of 1500Mbps or less */ - static const struct phtw_value step1[] = { - { .data = 0xcc, .code = 0xe2 }, - { /* sentinel */ }, - }; - - static const struct phtw_value step2[] = { - { .data = 0x01, .code = 0xe3 }, - { .data = 0x11, .code = 0xe4 }, - { .data = 0x01, .code = 0xe5 }, - { /* sentinel */ }, - }; - - /* In case of 1500Mbps or less */ - static const struct phtw_value step3[] = { - { .data = 0x38, .code = 0x08 }, - { /* sentinel */ }, - }; - - static const struct phtw_value step4[] = { - { .data = 0x01, .code = 0x00 }, - { .data = 0x4b, .code = 0xac }, - { .data = 0x03, .code = 0x00 }, - { .data = 0x80, .code = 0x07 }, - { /* sentinel */ }, - }; - - int ret; - - if (mbps != 0 && mbps <= 1500) - ret = rcsi2_phtw_write_array(priv, step1); - else - ret = rcsi2_phtw_write_mbps(priv, mbps, phtw_mbps_v3u, 0xe2); - if (ret) - return ret; - - ret = rcsi2_phtw_write_array(priv, step2); - if (ret) - return ret; - - if (mbps != 0 && mbps <= 1500) { - ret = rcsi2_phtw_write_array(priv, step3); - if (ret) - return ret; - } - - ret = rcsi2_phtw_write_array(priv, step4); - if (ret) - return ret; - - return ret; -} - -/* ----------------------------------------------------------------------------- - * Platform Device Driver. - */ - -static int rcsi2_link_setup(struct media_entity *entity, - const struct media_pad *local, - const struct media_pad *remote, u32 flags) -{ - struct v4l2_subdev *sd = media_entity_to_v4l2_subdev(entity); - struct rcar_csi2 *priv = sd_to_csi2(sd); - struct video_device *vdev; - int channel, vc; - u32 id; - - if (!is_media_entity_v4l2_video_device(remote->entity)) { - dev_err(priv->dev, "Remote is not a video device\n"); - return -EINVAL; - } - - vdev = media_entity_to_video_device(remote->entity); - - if (of_property_read_u32(vdev->dev_parent->of_node, "renesas,id", &id)) { - dev_err(priv->dev, "No renesas,id, can't configure routing\n"); - return -EINVAL; - } - - channel = id % 4; - - if (flags & MEDIA_LNK_FL_ENABLED) { - if (media_pad_remote_pad_first(local)) { - dev_dbg(priv->dev, - "Each VC can only be routed to one output channel\n"); - return -EINVAL; - } - - vc = local->index - 1; - - dev_dbg(priv->dev, "Route VC%d to VIN%u on output channel %d\n", - vc, id, channel); - } else { - vc = -1; - } - - priv->channel_vc[channel] = vc; - - return 0; -} - -static const struct media_entity_operations rcar_csi2_entity_ops = { - .link_setup = rcsi2_link_setup, - .link_validate = v4l2_subdev_link_validate, -}; - -static int rcsi2_probe_resources(struct rcar_csi2 *priv, - struct platform_device *pdev) -{ - int irq, ret; - - priv->base = devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(priv->base)) - return PTR_ERR(priv->base); - - irq = platform_get_irq(pdev, 0); - if (irq < 0) - return irq; - - ret = devm_request_threaded_irq(&pdev->dev, irq, rcsi2_irq, - rcsi2_irq_thread, IRQF_SHARED, - KBUILD_MODNAME, priv); - if (ret) - return ret; - - priv->rstc = devm_reset_control_get(&pdev->dev, NULL); - - return PTR_ERR_OR_ZERO(priv->rstc); -} - -static const struct rcar_csi2_info rcar_csi2_info_r8a7795 = { - .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, - .start_receiver = rcsi2_start_receiver_gen3, - .enter_standby = rcsi2_enter_standby_gen3, - .hsfreqrange = hsfreqrange_h3_v3h_m3n, - .csi0clkfreqrange = 0x20, - .num_channels = 4, - .clear_ulps = true, - .support_dphy = true, -}; - -static const struct rcar_csi2_info rcar_csi2_info_r8a7795es2 = { - .init_phtw = rcsi2_init_phtw_h3es2, - .start_receiver = rcsi2_start_receiver_gen3, - .enter_standby = rcsi2_enter_standby_gen3, - .hsfreqrange = hsfreqrange_h3_v3h_m3n, - .csi0clkfreqrange = 0x20, - .num_channels = 4, - .clear_ulps = true, - .support_dphy = true, -}; - -static const struct rcar_csi2_info rcar_csi2_info_r8a7796 = { - .start_receiver = rcsi2_start_receiver_gen3, - .enter_standby = rcsi2_enter_standby_gen3, - .hsfreqrange = hsfreqrange_m3w, - .num_channels = 4, - .support_dphy = true, -}; - -static const struct rcar_csi2_info rcar_csi2_info_r8a77961 = { - .start_receiver = rcsi2_start_receiver_gen3, - .enter_standby = rcsi2_enter_standby_gen3, - .hsfreqrange = hsfreqrange_m3w, - .num_channels = 4, - .support_dphy = true, -}; - -static const struct rcar_csi2_info rcar_csi2_info_r8a77965 = { - .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, - .start_receiver = rcsi2_start_receiver_gen3, - .enter_standby = rcsi2_enter_standby_gen3, - .hsfreqrange = hsfreqrange_h3_v3h_m3n, - .csi0clkfreqrange = 0x20, - .num_channels = 4, - .clear_ulps = true, - .support_dphy = true, -}; - -static const struct rcar_csi2_info rcar_csi2_info_r8a77970 = { - .init_phtw = rcsi2_init_phtw_v3m_e3, - .phy_post_init = rcsi2_phy_post_init_v3m_e3, - .start_receiver = rcsi2_start_receiver_gen3, - .enter_standby = rcsi2_enter_standby_gen3, - .num_channels = 4, - .support_dphy = true, -}; - -static const struct rcar_csi2_info rcar_csi2_info_r8a77980 = { - .init_phtw = rcsi2_init_phtw_h3_v3h_m3n, - .start_receiver = rcsi2_start_receiver_gen3, - .enter_standby = rcsi2_enter_standby_gen3, - .hsfreqrange = hsfreqrange_h3_v3h_m3n, - .csi0clkfreqrange = 0x20, - .clear_ulps = true, - .support_dphy = true, -}; - -static const struct rcar_csi2_info rcar_csi2_info_r8a77990 = { - .init_phtw = rcsi2_init_phtw_v3m_e3, - .phy_post_init = rcsi2_phy_post_init_v3m_e3, - .start_receiver = rcsi2_start_receiver_gen3, - .enter_standby = rcsi2_enter_standby_gen3, - .num_channels = 2, - .support_dphy = true, -}; - -static const struct rcar_csi2_info rcar_csi2_info_r8a779a0 = { - .init_phtw = rcsi2_init_phtw_v3u, - .start_receiver = rcsi2_start_receiver_gen3, - .enter_standby = rcsi2_enter_standby_gen3, - .hsfreqrange = hsfreqrange_v3u, - .csi0clkfreqrange = 0x20, - .clear_ulps = true, - .use_isp = true, - .support_dphy = true, -}; - -static const struct rcar_csi2_info rcar_csi2_info_r8a779g0 = { - .start_receiver = rcsi2_start_receiver_v4h, - .use_isp = true, - .support_cphy = true, -}; - -static const struct of_device_id rcar_csi2_of_table[] = { - { - .compatible = "renesas,r8a774a1-csi2", - .data = &rcar_csi2_info_r8a7796, - }, - { - .compatible = "renesas,r8a774b1-csi2", - .data = &rcar_csi2_info_r8a77965, - }, - { - .compatible = "renesas,r8a774c0-csi2", - .data = &rcar_csi2_info_r8a77990, - }, - { - .compatible = "renesas,r8a774e1-csi2", - .data = &rcar_csi2_info_r8a7795, - }, - { - .compatible = "renesas,r8a7795-csi2", - .data = &rcar_csi2_info_r8a7795, - }, - { - .compatible = "renesas,r8a7796-csi2", - .data = &rcar_csi2_info_r8a7796, - }, - { - .compatible = "renesas,r8a77961-csi2", - .data = &rcar_csi2_info_r8a77961, - }, - { - .compatible = "renesas,r8a77965-csi2", - .data = &rcar_csi2_info_r8a77965, - }, - { - .compatible = "renesas,r8a77970-csi2", - .data = &rcar_csi2_info_r8a77970, - }, - { - .compatible = "renesas,r8a77980-csi2", - .data = &rcar_csi2_info_r8a77980, - }, - { - .compatible = "renesas,r8a77990-csi2", - .data = &rcar_csi2_info_r8a77990, - }, - { - .compatible = "renesas,r8a779a0-csi2", - .data = &rcar_csi2_info_r8a779a0, - }, - { - .compatible = "renesas,r8a779g0-csi2", - .data = &rcar_csi2_info_r8a779g0, - }, - { /* sentinel */ }, -}; -MODULE_DEVICE_TABLE(of, rcar_csi2_of_table); - -static const struct soc_device_attribute r8a7795[] = { - { - .soc_id = "r8a7795", .revision = "ES2.*", - .data = &rcar_csi2_info_r8a7795es2, - }, - { /* sentinel */ } -}; - -static int rcsi2_probe(struct platform_device *pdev) -{ - const struct soc_device_attribute *attr; - struct rcar_csi2 *priv; - unsigned int i, num_pads; - int ret; - - priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); - if (!priv) - return -ENOMEM; - - priv->info = of_device_get_match_data(&pdev->dev); - - /* - * The different ES versions of r8a7795 (H3) behave differently but - * share the same compatible string. - */ - attr = soc_device_match(r8a7795); - if (attr) - priv->info = attr->data; - - priv->dev = &pdev->dev; - - mutex_init(&priv->lock); - priv->stream_count = 0; - - ret = rcsi2_probe_resources(priv, pdev); - if (ret) { - dev_err(priv->dev, "Failed to get resources\n"); - goto error_mutex; - } - - platform_set_drvdata(pdev, priv); - - ret = rcsi2_parse_dt(priv); - if (ret) - goto error_mutex; - - priv->subdev.owner = THIS_MODULE; - priv->subdev.dev = &pdev->dev; - v4l2_subdev_init(&priv->subdev, &rcar_csi2_subdev_ops); - v4l2_set_subdevdata(&priv->subdev, &pdev->dev); - snprintf(priv->subdev.name, sizeof(priv->subdev.name), "%s %s", - KBUILD_MODNAME, dev_name(&pdev->dev)); - priv->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE; - - priv->subdev.entity.function = MEDIA_ENT_F_PROC_VIDEO_PIXEL_FORMATTER; - priv->subdev.entity.ops = &rcar_csi2_entity_ops; - - num_pads = priv->info->use_isp ? 2 : NR_OF_RCAR_CSI2_PAD; - - priv->pads[RCAR_CSI2_SINK].flags = MEDIA_PAD_FL_SINK; - for (i = RCAR_CSI2_SOURCE_VC0; i < num_pads; i++) - priv->pads[i].flags = MEDIA_PAD_FL_SOURCE; - - ret = media_entity_pads_init(&priv->subdev.entity, num_pads, - priv->pads); - if (ret) - goto error_async; - - for (i = 0; i < ARRAY_SIZE(priv->channel_vc); i++) - priv->channel_vc[i] = -1; - - pm_runtime_enable(&pdev->dev); - - ret = v4l2_async_register_subdev(&priv->subdev); - if (ret < 0) - goto error_async; - - dev_info(priv->dev, "%d lanes found\n", priv->lanes); - - return 0; - -error_async: - v4l2_async_nf_unregister(&priv->notifier); - v4l2_async_nf_cleanup(&priv->notifier); -error_mutex: - mutex_destroy(&priv->lock); - - return ret; -} - -static void rcsi2_remove(struct platform_device *pdev) -{ - struct rcar_csi2 *priv = platform_get_drvdata(pdev); - - v4l2_async_nf_unregister(&priv->notifier); - v4l2_async_nf_cleanup(&priv->notifier); - v4l2_async_unregister_subdev(&priv->subdev); - - pm_runtime_disable(&pdev->dev); - - mutex_destroy(&priv->lock); -} - -static struct platform_driver rcar_csi2_pdrv = { - .remove_new = rcsi2_remove, - .probe = rcsi2_probe, - .driver = { - .name = "rcar-csi2", - .suppress_bind_attrs = true, - .of_match_table = rcar_csi2_of_table, - }, -}; - -module_platform_driver(rcar_csi2_pdrv); - -MODULE_AUTHOR("Niklas Söderlund "); -MODULE_DESCRIPTION("Renesas R-Car MIPI CSI-2 receiver driver"); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h index 997a66318a..792336dada 100644 --- a/drivers/media/platform/renesas/rcar-vin/rcar-vin.h +++ b/drivers/media/platform/renesas/rcar-vin/rcar-vin.h @@ -59,7 +59,7 @@ enum rvin_isp_id { #define RVIN_REMOTES_MAX \ (((unsigned int)RVIN_CSI_MAX) > ((unsigned int)RVIN_ISP_MAX) ? \ - (unsigned int)RVIN_CSI_MAX : (unsigned int)RVIN_ISP_MAX) + RVIN_CSI_MAX : RVIN_ISP_MAX) /** * enum rvin_dma_state - DMA states diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h index 811603f18a..a5a99b0043 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-cru.h @@ -133,9 +133,6 @@ struct rzg2l_cru_dev { struct v4l2_pix_format format; }; -void rzg2l_cru_vclk_unprepare(struct rzg2l_cru_dev *cru); -int rzg2l_cru_vclk_prepare(struct rzg2l_cru_dev *cru); - int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru); void rzg2l_cru_stop_image_processing(struct rzg2l_cru_dev *cru); diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c index d20f4eff93..e68fcdaea2 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-csi2.c @@ -108,6 +108,7 @@ struct rzg2l_csi2 { struct reset_control *presetn; struct reset_control *cmn_rstb; struct clk *sysclk; + struct clk *vclk; unsigned long vclk_rate; struct v4l2_subdev subdev; @@ -361,7 +362,7 @@ static int rzg2l_csi2_dphy_setting(struct v4l2_subdev *sd, bool on) return rzg2l_csi2_dphy_disable(csi2); } -static void rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2) +static int rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2) { unsigned long vclk_rate = csi2->vclk_rate / HZ_PER_MHZ; u32 frrskw, frrclk, frrskw_coeff, frrclk_coeff; @@ -386,11 +387,15 @@ static void rzg2l_csi2_mipi_link_enable(struct rzg2l_csi2 *csi2) rzg2l_csi2_write(csi2, CSI2nDTEL, 0xf778ff0f); rzg2l_csi2_write(csi2, CSI2nDTEH, 0x00ffff1f); + clk_disable_unprepare(csi2->vclk); + /* Enable LINK reception */ rzg2l_csi2_write(csi2, CSI2nMCT3, CSI2nMCT3_RXEN); + + return clk_prepare_enable(csi2->vclk); } -static void rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2) +static int rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2) { unsigned int timeout = VSRSTS_RETRIES; @@ -409,18 +414,21 @@ static void rzg2l_csi2_mipi_link_disable(struct rzg2l_csi2 *csi2) if (!timeout) dev_err(csi2->dev, "Clearing CSI2nRTST.VSRSTS timed out\n"); + + return 0; } static int rzg2l_csi2_mipi_link_setting(struct v4l2_subdev *sd, bool on) { struct rzg2l_csi2 *csi2 = sd_to_csi2(sd); + int ret; if (on) - rzg2l_csi2_mipi_link_enable(csi2); + ret = rzg2l_csi2_mipi_link_enable(csi2); else - rzg2l_csi2_mipi_link_disable(csi2); + ret = rzg2l_csi2_mipi_link_disable(csi2); - return 0; + return ret; } static int rzg2l_csi2_s_stream(struct v4l2_subdev *sd, int enable) @@ -731,7 +739,6 @@ static const struct media_entity_operations rzg2l_csi2_entity_ops = { static int rzg2l_csi2_probe(struct platform_device *pdev) { struct rzg2l_csi2 *csi2; - struct clk *vclk; int ret; csi2 = devm_kzalloc(&pdev->dev, sizeof(*csi2), GFP_KERNEL); @@ -757,12 +764,11 @@ static int rzg2l_csi2_probe(struct platform_device *pdev) return dev_err_probe(&pdev->dev, PTR_ERR(csi2->sysclk), "Failed to get system clk\n"); - vclk = clk_get(&pdev->dev, "video"); - if (IS_ERR(vclk)) - return dev_err_probe(&pdev->dev, PTR_ERR(vclk), + csi2->vclk = devm_clk_get(&pdev->dev, "video"); + if (IS_ERR(csi2->vclk)) + return dev_err_probe(&pdev->dev, PTR_ERR(csi2->vclk), "Failed to get video clock\n"); - csi2->vclk_rate = clk_get_rate(vclk); - clk_put(vclk); + csi2->vclk_rate = clk_get_rate(csi2->vclk); csi2->dev = &pdev->dev; @@ -834,7 +840,7 @@ static void rzg2l_csi2_remove(struct platform_device *pdev) pm_runtime_disable(&pdev->dev); } -static int __maybe_unused rzg2l_csi2_pm_runtime_suspend(struct device *dev) +static int rzg2l_csi2_pm_runtime_suspend(struct device *dev) { struct rzg2l_csi2 *csi2 = dev_get_drvdata(dev); @@ -843,7 +849,7 @@ static int __maybe_unused rzg2l_csi2_pm_runtime_suspend(struct device *dev) return 0; } -static int __maybe_unused rzg2l_csi2_pm_runtime_resume(struct device *dev) +static int rzg2l_csi2_pm_runtime_resume(struct device *dev) { struct rzg2l_csi2 *csi2 = dev_get_drvdata(dev); @@ -851,7 +857,8 @@ static int __maybe_unused rzg2l_csi2_pm_runtime_resume(struct device *dev) } static const struct dev_pm_ops rzg2l_csi2_pm_ops = { - SET_RUNTIME_PM_OPS(rzg2l_csi2_pm_runtime_suspend, rzg2l_csi2_pm_runtime_resume, NULL) + RUNTIME_PM_OPS(rzg2l_csi2_pm_runtime_suspend, + rzg2l_csi2_pm_runtime_resume, NULL) }; static const struct of_device_id rzg2l_csi2_of_table[] = { @@ -865,7 +872,7 @@ static struct platform_driver rzg2l_csi2_pdrv = { .driver = { .name = "rzg2l-csi2", .of_match_table = rzg2l_csi2_of_table, - .pm = &rzg2l_csi2_pm_ops, + .pm = pm_ptr(&rzg2l_csi2_pm_ops), }, }; diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c index 9f351a0589..ac8ebae4ed 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-ip.c @@ -5,6 +5,7 @@ * Copyright (C) 2022 Renesas Electronics Corp. */ +#include #include "rzg2l-cru.h" struct rzg2l_cru_ip_format { @@ -71,26 +72,17 @@ static int rzg2l_cru_ip_s_stream(struct v4l2_subdev *sd, int enable) if (ret) return ret; + fsleep(1000); + ret = rzg2l_cru_start_image_processing(cru); if (ret) { v4l2_subdev_call(cru->ip.remote, video, post_streamoff); return ret; } - rzg2l_cru_vclk_unprepare(cru); - ret = v4l2_subdev_call(cru->ip.remote, video, s_stream, enable); - if (ret == -ENOIOCTLCMD) - ret = 0; - if (!ret) { - ret = rzg2l_cru_vclk_prepare(cru); - if (!ret) - return 0; - } else { - /* enable back vclk so that s_stream in error path disables it */ - if (rzg2l_cru_vclk_prepare(cru)) - dev_err(cru->dev, "Failed to enable vclk\n"); - } + if (!ret || ret == -ENOIOCTLCMD) + return 0; s_stream_ret = ret; diff --git a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c index d0ffa90bc6..b16b8af6e8 100644 --- a/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c +++ b/drivers/media/platform/renesas/rzg2l-cru/rzg2l-video.c @@ -430,13 +430,6 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru) spin_lock_irqsave(&cru->qlock, flags); - /* Initialize image convert */ - ret = rzg2l_cru_initialize_image_conv(cru, fmt); - if (ret) { - spin_unlock_irqrestore(&cru->qlock, flags); - return ret; - } - /* Select a video input */ rzg2l_cru_write(cru, CRUnCTRL, CRUnCTRL_VINSEL(0)); @@ -450,6 +443,13 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru) /* Initialize the AXI master */ rzg2l_cru_initialize_axi(cru); + /* Initialize image convert */ + ret = rzg2l_cru_initialize_image_conv(cru, fmt); + if (ret) { + spin_unlock_irqrestore(&cru->qlock, flags); + return ret; + } + /* Enable interrupt */ rzg2l_cru_write(cru, CRUnIE, CRUnIE_EFE); @@ -461,16 +461,6 @@ int rzg2l_cru_start_image_processing(struct rzg2l_cru_dev *cru) return 0; } -void rzg2l_cru_vclk_unprepare(struct rzg2l_cru_dev *cru) -{ - clk_disable_unprepare(cru->vclk); -} - -int rzg2l_cru_vclk_prepare(struct rzg2l_cru_dev *cru) -{ - return clk_prepare_enable(cru->vclk); -} - static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on) { struct media_pipeline *pipe; @@ -499,39 +489,24 @@ static int rzg2l_cru_set_stream(struct rzg2l_cru_dev *cru, int on) video_device_pipeline_stop(&cru->vdev); - pm_runtime_put_sync(cru->dev); - clk_disable_unprepare(cru->vclk); - return stream_off_ret; } - ret = pm_runtime_resume_and_get(cru->dev); - if (ret) - return ret; - - ret = clk_prepare_enable(cru->vclk); - if (ret) - goto err_pm_put; - ret = rzg2l_cru_mc_validate_format(cru, sd, pad); if (ret) - goto err_vclk_disable; + return ret; pipe = media_entity_pipeline(&sd->entity) ? : &cru->vdev.pipe; ret = video_device_pipeline_start(&cru->vdev, pipe); if (ret) - goto err_vclk_disable; + return ret; ret = v4l2_subdev_call(sd, video, pre_streamon, 0); - if (ret == -ENOIOCTLCMD) - ret = 0; - if (ret) + if (ret && ret != -ENOIOCTLCMD) goto pipe_line_stop; ret = v4l2_subdev_call(sd, video, s_stream, 1); - if (ret == -ENOIOCTLCMD) - ret = 0; - if (ret) + if (ret && ret != -ENOIOCTLCMD) goto err_s_stream; return 0; @@ -542,12 +517,6 @@ err_s_stream: pipe_line_stop: video_device_pipeline_stop(&cru->vdev); -err_vclk_disable: - clk_disable_unprepare(cru->vclk); - -err_pm_put: - pm_runtime_put_sync(cru->dev); - return ret; } @@ -646,25 +615,33 @@ static int rzg2l_cru_start_streaming_vq(struct vb2_queue *vq, unsigned int count struct rzg2l_cru_dev *cru = vb2_get_drv_priv(vq); int ret; + ret = pm_runtime_resume_and_get(cru->dev); + if (ret) + return ret; + + ret = clk_prepare_enable(cru->vclk); + if (ret) + goto err_pm_put; + /* Release reset state */ ret = reset_control_deassert(cru->aresetn); if (ret) { dev_err(cru->dev, "failed to deassert aresetn\n"); - return ret; + goto err_vclk_disable; } ret = reset_control_deassert(cru->presetn); if (ret) { reset_control_assert(cru->aresetn); dev_err(cru->dev, "failed to deassert presetn\n"); - return ret; + goto assert_aresetn; } ret = request_irq(cru->image_conv_irq, rzg2l_cru_irq, IRQF_SHARED, KBUILD_MODNAME, cru); if (ret) { dev_err(cru->dev, "failed to request irq\n"); - goto assert_resets; + goto assert_presetn; } /* Allocate scratch buffer. */ @@ -696,10 +673,18 @@ out: free_image_conv_irq: free_irq(cru->image_conv_irq, cru); -assert_resets: +assert_presetn: reset_control_assert(cru->presetn); + +assert_aresetn: reset_control_assert(cru->aresetn); +err_vclk_disable: + clk_disable_unprepare(cru->vclk); + +err_pm_put: + pm_runtime_put_sync(cru->dev); + return ret; } @@ -714,9 +699,11 @@ static void rzg2l_cru_stop_streaming_vq(struct vb2_queue *vq) cru->scratch, cru->scratch_phys); free_irq(cru->image_conv_irq, cru); - reset_control_assert(cru->presetn); - return_unused_buffers(cru, VB2_BUF_STATE_ERROR); + + reset_control_assert(cru->presetn); + clk_disable_unprepare(cru->vclk); + pm_runtime_put_sync(cru->dev); } static const struct vb2_ops rzg2l_cru_qops = { diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c index c381c22135..2bddb4fa8a 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-capture.c @@ -47,13 +47,18 @@ enum rkisp1_plane { * @fourcc: pixel format * @fmt_type: helper filed for pixel format * @uv_swap: if cb cr swapped, for yuv + * @yc_swap: if y and cb/cr swapped, for yuv + * @byte_swap: if byte pairs are swapped, for raw * @write_format: defines how YCbCr self picture data is written to memory - * @output_format: defines sp output format + * @output_format: defines the output format (RKISP1_CIF_MI_INIT_MP_OUTPUT_* for + * the main path and RKISP1_MI_CTRL_SP_OUTPUT_* for the self path) * @mbus: the mbus code on the src resizer pad that matches the pixel format */ struct rkisp1_capture_fmt_cfg { u32 fourcc; - u8 uv_swap; + u32 uv_swap : 1; + u32 yc_swap : 1; + u32 byte_swap : 1; u32 write_format; u32 output_format; u32 mbus; @@ -94,36 +99,50 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = { .fourcc = V4L2_PIX_FMT_YUYV, .uv_swap = 0, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .uv_swap = 0, + .yc_swap = 1, + .write_format = RKISP1_MI_CTRL_MP_WRITE_YUVINT, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422, .mbus = MEDIA_BUS_FMT_YUYV8_2X8, }, { .fourcc = V4L2_PIX_FMT_YUV422P, .uv_swap = 0, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422, .mbus = MEDIA_BUS_FMT_YUYV8_2X8, }, { .fourcc = V4L2_PIX_FMT_NV16, .uv_swap = 0, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422, .mbus = MEDIA_BUS_FMT_YUYV8_2X8, }, { .fourcc = V4L2_PIX_FMT_NV61, .uv_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422, .mbus = MEDIA_BUS_FMT_YUYV8_2X8, }, { .fourcc = V4L2_PIX_FMT_NV16M, .uv_swap = 0, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422, .mbus = MEDIA_BUS_FMT_YUYV8_2X8, }, { .fourcc = V4L2_PIX_FMT_NV61M, .uv_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422, .mbus = MEDIA_BUS_FMT_YUYV8_2X8, }, { .fourcc = V4L2_PIX_FMT_YVU422M, .uv_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422, .mbus = MEDIA_BUS_FMT_YUYV8_2X8, }, /* yuv400 */ @@ -131,6 +150,7 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = { .fourcc = V4L2_PIX_FMT_GREY, .uv_swap = 0, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV400, .mbus = MEDIA_BUS_FMT_YUYV8_2X8, }, /* yuv420 */ @@ -138,81 +158,107 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_mp_fmts[] = { .fourcc = V4L2_PIX_FMT_NV21, .uv_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420, .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, }, { .fourcc = V4L2_PIX_FMT_NV12, .uv_swap = 0, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420, .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, }, { .fourcc = V4L2_PIX_FMT_NV21M, .uv_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420, .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, }, { .fourcc = V4L2_PIX_FMT_NV12M, .uv_swap = 0, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_SPLA, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420, .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, }, { .fourcc = V4L2_PIX_FMT_YUV420, .uv_swap = 0, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420, .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, }, { .fourcc = V4L2_PIX_FMT_YVU420, .uv_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420, .mbus = MEDIA_BUS_FMT_YUYV8_1_5X8, }, /* raw */ { .fourcc = V4L2_PIX_FMT_SRGGB8, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8, .mbus = MEDIA_BUS_FMT_SRGGB8_1X8, }, { .fourcc = V4L2_PIX_FMT_SGRBG8, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8, .mbus = MEDIA_BUS_FMT_SGRBG8_1X8, }, { .fourcc = V4L2_PIX_FMT_SGBRG8, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8, .mbus = MEDIA_BUS_FMT_SGBRG8_1X8, }, { .fourcc = V4L2_PIX_FMT_SBGGR8, .write_format = RKISP1_MI_CTRL_MP_WRITE_YUV_PLA_OR_RAW8, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8, .mbus = MEDIA_BUS_FMT_SBGGR8_1X8, }, { .fourcc = V4L2_PIX_FMT_SRGGB10, + .byte_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10, .mbus = MEDIA_BUS_FMT_SRGGB10_1X10, }, { .fourcc = V4L2_PIX_FMT_SGRBG10, + .byte_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10, .mbus = MEDIA_BUS_FMT_SGRBG10_1X10, }, { .fourcc = V4L2_PIX_FMT_SGBRG10, + .byte_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10, .mbus = MEDIA_BUS_FMT_SGBRG10_1X10, }, { .fourcc = V4L2_PIX_FMT_SBGGR10, + .byte_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10, .mbus = MEDIA_BUS_FMT_SBGGR10_1X10, }, { .fourcc = V4L2_PIX_FMT_SRGGB12, + .byte_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12, .mbus = MEDIA_BUS_FMT_SRGGB12_1X12, }, { .fourcc = V4L2_PIX_FMT_SGRBG12, + .byte_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12, .mbus = MEDIA_BUS_FMT_SGRBG12_1X12, }, { .fourcc = V4L2_PIX_FMT_SGBRG12, + .byte_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12, .mbus = MEDIA_BUS_FMT_SGBRG12_1X12, }, { .fourcc = V4L2_PIX_FMT_SBGGR12, + .byte_swap = 1, .write_format = RKISP1_MI_CTRL_MP_WRITE_RAW12, + .output_format = RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12, .mbus = MEDIA_BUS_FMT_SBGGR12_1X12, }, }; @@ -229,6 +275,13 @@ static const struct rkisp1_capture_fmt_cfg rkisp1_sp_fmts[] = { .write_format = RKISP1_MI_CTRL_SP_WRITE_INT, .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, .mbus = MEDIA_BUS_FMT_YUYV8_2X8, + }, { + .fourcc = V4L2_PIX_FMT_UYVY, + .uv_swap = 0, + .yc_swap = 1, + .write_format = RKISP1_MI_CTRL_SP_WRITE_INT, + .output_format = RKISP1_MI_CTRL_SP_OUTPUT_YUV422, + .mbus = MEDIA_BUS_FMT_YUYV8_2X8, }, { .fourcc = V4L2_PIX_FMT_YUV422P, .uv_swap = 0, @@ -442,6 +495,14 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap) rkisp1_write(rkisp1, cap->config->mi.cr_size_init, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); + if (rkisp1_has_feature(rkisp1, MAIN_STRIDE)) { + rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_LLENGTH, cap->stride); + rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_PIC_WIDTH, pixm->width); + rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_PIC_HEIGHT, pixm->height); + rkisp1_write(rkisp1, RKISP1_CIF_MI_MP_Y_PIC_SIZE, + cap->stride * pixm->height); + } + rkisp1_irq_frame_end_enable(cap); /* set uv swapping for semiplanar formats */ @@ -454,6 +515,25 @@ static void rkisp1_mp_config(struct rkisp1_capture *cap) rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg); } + /* + * U/V swapping with the MI_XTD_FORMAT_CTRL register only works for + * NV12/NV21 and NV16/NV61, so instead use byte swap to support UYVY. + * YVYU and VYUY cannot be supported with this method. + */ + if (rkisp1_has_feature(rkisp1, MAIN_STRIDE)) { + reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT); + if (cap->pix.cfg->yc_swap || cap->pix.cfg->byte_swap) + reg |= RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_BYTES; + else + reg &= ~RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_BYTES; + + reg |= RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_LSB_ALIGNMENT; + rkisp1_write(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT, reg); + + rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT, + cap->pix.cfg->output_format); + } + rkisp1_mi_config_ctrl(cap); reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); @@ -479,11 +559,11 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap) rkisp1_write(rkisp1, cap->config->mi.cr_size_init, rkisp1_pixfmt_comp_size(pixm, RKISP1_PLANE_CR)); - rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->sp_y_stride); + rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_LLENGTH, cap->stride); rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_WIDTH, pixm->width); rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_HEIGHT, pixm->height); rkisp1_write(rkisp1, RKISP1_CIF_MI_SP_Y_PIC_SIZE, - cap->sp_y_stride * pixm->height); + cap->stride * pixm->height); rkisp1_irq_frame_end_enable(cap); @@ -497,6 +577,20 @@ static void rkisp1_sp_config(struct rkisp1_capture *cap) rkisp1_write(rkisp1, RKISP1_CIF_MI_XTD_FORMAT_CTRL, reg); } + /* + * U/V swapping with the MI_XTD_FORMAT_CTRL register only works for + * NV12/NV21 and NV16/NV61, so instead use byte swap to support UYVY. + * YVYU and VYUY cannot be supported with this method. + */ + if (rkisp1_has_feature(rkisp1, MAIN_STRIDE)) { + reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT); + if (cap->pix.cfg->yc_swap) + reg |= RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_BYTES; + else + reg &= ~RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_BYTES; + rkisp1_write(rkisp1, RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT, reg); + } + rkisp1_mi_config_ctrl(cap); mi_ctrl = rkisp1_read(rkisp1, RKISP1_CIF_MI_CTRL); @@ -640,11 +734,13 @@ static void rkisp1_dummy_buf_destroy(struct rkisp1_capture *cap) static void rkisp1_set_next_buf(struct rkisp1_capture *cap) { + u8 shift = rkisp1_has_feature(cap->rkisp1, DMA_34BIT) ? 2 : 0; + cap->buf.curr = cap->buf.next; cap->buf.next = NULL; if (!list_empty(&cap->buf.queue)) { - u32 *buff_addr; + dma_addr_t *buff_addr; cap->buf.next = list_first_entry(&cap->buf.queue, struct rkisp1_buffer, queue); list_del(&cap->buf.next->queue); @@ -652,7 +748,7 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap) buff_addr = cap->buf.next->buff_addr; rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init, - buff_addr[RKISP1_PLANE_Y]); + buff_addr[RKISP1_PLANE_Y] >> shift); /* * In order to support grey format we capture * YUV422 planar format from the camera and @@ -661,17 +757,17 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap) if (cap->pix.cfg->fourcc == V4L2_PIX_FMT_GREY) { rkisp1_write(cap->rkisp1, cap->config->mi.cb_base_ad_init, - cap->buf.dummy.dma_addr); + cap->buf.dummy.dma_addr >> shift); rkisp1_write(cap->rkisp1, cap->config->mi.cr_base_ad_init, - cap->buf.dummy.dma_addr); + cap->buf.dummy.dma_addr >> shift); } else { rkisp1_write(cap->rkisp1, cap->config->mi.cb_base_ad_init, - buff_addr[RKISP1_PLANE_CB]); + buff_addr[RKISP1_PLANE_CB] >> shift); rkisp1_write(cap->rkisp1, cap->config->mi.cr_base_ad_init, - buff_addr[RKISP1_PLANE_CR]); + buff_addr[RKISP1_PLANE_CR] >> shift); } } else { /* @@ -679,11 +775,11 @@ static void rkisp1_set_next_buf(struct rkisp1_capture *cap) * throw data if there is no available buffer. */ rkisp1_write(cap->rkisp1, cap->config->mi.y_base_ad_init, - cap->buf.dummy.dma_addr); + cap->buf.dummy.dma_addr >> shift); rkisp1_write(cap->rkisp1, cap->config->mi.cb_base_ad_init, - cap->buf.dummy.dma_addr); + cap->buf.dummy.dma_addr >> shift); rkisp1_write(cap->rkisp1, cap->config->mi.cr_base_ad_init, - cap->buf.dummy.dma_addr); + cap->buf.dummy.dma_addr >> shift); } /* Set plane offsets */ @@ -722,6 +818,7 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx) { struct device *dev = ctx; struct rkisp1_device *rkisp1 = dev_get_drvdata(dev); + unsigned int dev_count = rkisp1_path_count(rkisp1); unsigned int i; u32 status; @@ -734,7 +831,7 @@ irqreturn_t rkisp1_capture_isr(int irq, void *ctx) rkisp1_write(rkisp1, RKISP1_CIF_MI_ICR, status); - for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); ++i) { + for (i = 0; i < dev_count; ++i) { struct rkisp1_capture *cap = &rkisp1->capture_devs[i]; if (!(status & RKISP1_CIF_MI_FRAME(cap))) @@ -891,6 +988,7 @@ static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap) { struct rkisp1_device *rkisp1 = cap->rkisp1; struct rkisp1_capture *other = &rkisp1->capture_devs[cap->id ^ 1]; + bool has_self_path = rkisp1_has_feature(rkisp1, SELF_PATH); cap->ops->set_data_path(cap); cap->ops->config(cap); @@ -899,19 +997,40 @@ static void rkisp1_cap_stream_enable(struct rkisp1_capture *cap) spin_lock_irq(&cap->buf.lock); rkisp1_set_next_buf(cap); cap->ops->enable(cap); - /* It's safe to configure ACTIVE and SHADOW registers for the - * first stream. While when the second is starting, do NOT - * force update because it also updates the first one. + + /* + * It's safe to configure ACTIVE and SHADOW registers for the first + * stream. While when the second is starting, do NOT force update + * because it also updates the first one. * - * The latter case would drop one more buffer(that is 2) since - * there's no buffer in a shadow register when the second FE received. - * This's also required because the second FE maybe corrupt - * especially when run at 120fps. + * The latter case would drop one more buffer(that is 2) since there's + * no buffer in a shadow register when the second FE received. This's + * also required because the second FE maybe corrupt especially when + * run at 120fps. */ - if (!other->is_streaming) { - /* force cfg update */ - rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT, - RKISP1_CIF_MI_INIT_SOFT_UPD); + if (!has_self_path || !other->is_streaming) { + u32 reg; + + /* + * Force cfg update. + * + * The ISP8000 (implementing the MAIN_STRIDE feature) as a + * mp_output_format field in the CIF_MI_INIT register that must + * be preserved. It can be read back, but it is not clear what + * other register bits will return. Mask them out. + * + * On Rockchip platforms, the CIF_MI_INIT register is marked as + * write-only and reads as zeros. We can skip reading it. + */ + if (rkisp1_has_feature(rkisp1, MAIN_STRIDE)) + reg = rkisp1_read(rkisp1, RKISP1_CIF_MI_INIT) + & RKISP1_CIF_MI_INIT_MP_OUTPUT_MASK; + else + reg = 0; + + reg |= RKISP1_CIF_MI_INIT_SOFT_UPD; + rkisp1_write(rkisp1, RKISP1_CIF_MI_INIT, reg); + rkisp1_set_next_buf(cap); } spin_unlock_irq(&cap->buf.lock); @@ -1095,8 +1214,8 @@ static const struct vb2_ops rkisp1_vb2_ops = { */ static const struct v4l2_format_info * -rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm, - enum rkisp1_stream_id id) +rkisp1_fill_pixfmt(const struct rkisp1_capture *cap, + struct v4l2_pix_format_mplane *pixm) { struct v4l2_plane_pix_format *plane_y = &pixm->plane_fmt[0]; const struct v4l2_format_info *info; @@ -1109,10 +1228,13 @@ rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm, /* * The SP supports custom strides, expressed as a number of pixels for - * the Y plane. Clamp the stride to a reasonable value to avoid integer - * overflows when calculating the bytesperline and sizeimage values. + * the Y plane, and so does the MP in ISP versions that have the + * MAIN_STRIDE feature. Clamp the stride to a reasonable value to avoid + * integer overflows when calculating the bytesperline and sizeimage + * values. */ - if (id == RKISP1_SELFPATH) + if (cap->id == RKISP1_SELFPATH || + rkisp1_has_feature(cap->rkisp1, MAIN_STRIDE)) stride = clamp(DIV_ROUND_UP(plane_y->bytesperline, info->bpp[0]), pixm->width, 65536U); else @@ -1147,10 +1269,14 @@ rkisp1_fill_pixfmt(struct v4l2_pix_format_mplane *pixm, static const struct rkisp1_capture_fmt_cfg * rkisp1_find_fmt_cfg(const struct rkisp1_capture *cap, const u32 pixelfmt) { + bool yc_swap_support = rkisp1_has_feature(cap->rkisp1, MAIN_STRIDE); unsigned int i; for (i = 0; i < cap->config->fmt_size; i++) { - if (cap->config->fmts[i].fourcc == pixelfmt) + const struct rkisp1_capture_fmt_cfg *fmt = &cap->config->fmts[i]; + + if (fmt->fourcc == pixelfmt && + (!fmt->yc_swap || yc_swap_support)) return &cap->config->fmts[i]; } return NULL; @@ -1187,7 +1313,7 @@ static void rkisp1_try_fmt(const struct rkisp1_capture *cap, pixm->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT; pixm->quantization = V4L2_QUANTIZATION_DEFAULT; - info = rkisp1_fill_pixfmt(pixm, cap->id); + info = rkisp1_fill_pixfmt(cap, pixm); if (fmt_cfg) *fmt_cfg = fmt; @@ -1199,12 +1325,9 @@ static void rkisp1_set_fmt(struct rkisp1_capture *cap, struct v4l2_pix_format_mplane *pixm) { rkisp1_try_fmt(cap, pixm, &cap->pix.cfg, &cap->pix.info); - cap->pix.fmt = *pixm; - /* SP supports custom stride in number of pixels of the Y plane */ - if (cap->id == RKISP1_SELFPATH) - cap->sp_y_stride = pixm->plane_fmt[0].bytesperline / - cap->pix.info->bpp[0]; + cap->pix.fmt = *pixm; + cap->stride = pixm->plane_fmt[0].bytesperline / cap->pix.info->bpp[0]; } static int rkisp1_try_fmt_vid_cap_mplane(struct file *file, void *fh, @@ -1222,23 +1345,29 @@ static int rkisp1_enum_fmt_vid_cap_mplane(struct file *file, void *priv, { struct rkisp1_capture *cap = video_drvdata(file); const struct rkisp1_capture_fmt_cfg *fmt = NULL; + bool yc_swap_support = rkisp1_has_feature(cap->rkisp1, MAIN_STRIDE); unsigned int i, n = 0; - if (!f->mbus_code) { - if (f->index >= cap->config->fmt_size) - return -EINVAL; + if (f->index >= cap->config->fmt_size) + return -EINVAL; + if (!f->mbus_code && yc_swap_support) { fmt = &cap->config->fmts[f->index]; f->pixelformat = fmt->fourcc; return 0; } for (i = 0; i < cap->config->fmt_size; i++) { - if (cap->config->fmts[i].mbus != f->mbus_code) + fmt = &cap->config->fmts[i]; + + if (f->mbus_code && fmt->mbus != f->mbus_code) + continue; + + if (!yc_swap_support && fmt->yc_swap) continue; if (n++ == f->index) { - f->pixelformat = cap->config->fmts[i].fourcc; + f->pixelformat = fmt->fourcc; return 0; } } @@ -1501,10 +1630,11 @@ rkisp1_capture_init(struct rkisp1_device *rkisp1, enum rkisp1_stream_id id) int rkisp1_capture_devs_register(struct rkisp1_device *rkisp1) { + unsigned int dev_count = rkisp1_path_count(rkisp1); unsigned int i; int ret; - for (i = 0; i < ARRAY_SIZE(rkisp1->capture_devs); i++) { + for (i = 0; i < dev_count; i++) { struct rkisp1_capture *cap = &rkisp1->capture_devs[i]; rkisp1_capture_init(rkisp1, i); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h index b757f75ede..26573f6ae5 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-common.h @@ -24,6 +24,7 @@ #include "rkisp1-regs.h" struct dentry; +struct regmap; /* * flags on the 'direction' field in struct rkisp1_mbus_info' that indicate @@ -110,6 +111,10 @@ enum rkisp1_isp_pad { * enum rkisp1_feature - ISP features * * @RKISP1_FEATURE_MIPI_CSI2: The ISP has an internal MIPI CSI-2 receiver + * @RKISP1_FEATURE_MAIN_STRIDE: The ISP supports configurable stride on the main path + * @RKISP1_FEATURE_SELF_PATH: The ISP has a self path + * @RKISP1_FEATURE_DUAL_CROP: The ISP has the dual crop block at the resizer input + * @RKISP1_FEATURE_DMA_34BIT: The ISP uses 34-bit DMA addresses * * The ISP features are stored in a bitmask in &rkisp1_info.features and allow * the driver to implement support for features present in some ISP versions @@ -117,8 +122,15 @@ enum rkisp1_isp_pad { */ enum rkisp1_feature { RKISP1_FEATURE_MIPI_CSI2 = BIT(0), + RKISP1_FEATURE_MAIN_STRIDE = BIT(1), + RKISP1_FEATURE_SELF_PATH = BIT(2), + RKISP1_FEATURE_DUAL_CROP = BIT(3), + RKISP1_FEATURE_DMA_34BIT = BIT(4), }; +#define rkisp1_has_feature(rkisp1, feature) \ + ((rkisp1)->info->features & RKISP1_FEATURE_##feature) + /* * struct rkisp1_info - Model-specific ISP Information * @@ -229,7 +241,7 @@ struct rkisp1_vdev_node { struct rkisp1_buffer { struct vb2_v4l2_buffer vb; struct list_head queue; - u32 buff_addr[VIDEO_MAX_PLANES]; + dma_addr_t buff_addr[VIDEO_MAX_PLANES]; }; /* @@ -263,7 +275,7 @@ struct rkisp1_device; * handler to stop the streaming by waiting on the 'done' wait queue. * If the irq handler is not called, the stream is stopped by the callback * after timeout. - * @sp_y_stride: the selfpath allows to configure a y stride that is longer than the image width. + * @stride: the line stride for the first plane, in pixel units * @buf.lock: lock to protect buf.queue * @buf.queue: queued buffer list * @buf.dummy: dummy space to store dropped data @@ -284,7 +296,7 @@ struct rkisp1_capture { bool is_streaming; bool is_stopping; wait_queue_head_t done; - unsigned int sp_y_stride; + unsigned int stride; struct { /* protects queue, curr and next */ spinlock_t lock; @@ -435,6 +447,8 @@ struct rkisp1_debug { * @dev: a pointer to the struct device * @clk_size: number of clocks * @clks: array of clocks + * @gasket: the gasket - i.MX8MP only + * @gasket_id: the gasket ID (0 or 1) - i.MX8MP only * @v4l2_dev: v4l2_device variable * @media_dev: media_device variable * @notifier: a notifier to register on the v4l2-async API to be notified on the sensor @@ -457,6 +471,8 @@ struct rkisp1_device { struct device *dev; unsigned int clk_size; struct clk_bulk_data clks[RKISP1_MAX_BUS_CLK]; + struct regmap *gasket; + unsigned int gasket_id; struct v4l2_device v4l2_dev; struct media_device media_dev; struct v4l2_async_notifier notifier; @@ -526,6 +542,19 @@ int rkisp1_cap_enum_mbus_codes(struct rkisp1_capture *cap, */ const struct rkisp1_mbus_info *rkisp1_mbus_info_get_by_index(unsigned int index); +/* + * rkisp1_path_count - Return the number of paths supported by the device + * + * Some devices only have a main path, while other device have both a main path + * and a self path. This function returns the number of paths that this device + * has, based on the feature flags. It should be used insted of checking + * ARRAY_SIZE of capture_devs/resizer_devs. + */ +static inline unsigned int rkisp1_path_count(struct rkisp1_device *rkisp1) +{ + return rkisp1_has_feature(rkisp1, SELF_PATH) ? 2 : 1; +} + /* * rkisp1_sd_adjust_crop_rect - adjust a rectangle to fit into another rectangle. * diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c index 73cf08a740..bb0202386c 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-dev.c @@ -10,6 +10,7 @@ #include #include +#include #include #include #include @@ -207,7 +208,7 @@ static int rkisp1_subdev_notifier_register(struct rkisp1_device *rkisp1) switch (reg) { case 0: /* MIPI CSI-2 port */ - if (!(rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2)) { + if (!rkisp1_has_feature(rkisp1, MIPI_CSI2)) { dev_err(rkisp1->dev, "internal CSI must be available for port 0\n"); ret = -EINVAL; @@ -358,10 +359,11 @@ static const struct dev_pm_ops rkisp1_pm_ops = { static int rkisp1_create_links(struct rkisp1_device *rkisp1) { + unsigned int dev_count = rkisp1_path_count(rkisp1); unsigned int i; int ret; - if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { + if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) { /* Link the CSI receiver to the ISP. */ ret = media_create_pad_link(&rkisp1->csi.sd.entity, RKISP1_CSI_PAD_SRC, @@ -373,7 +375,7 @@ static int rkisp1_create_links(struct rkisp1_device *rkisp1) } /* create ISP->RSZ->CAP links */ - for (i = 0; i < 2; i++) { + for (i = 0; i < dev_count; i++) { struct media_entity *resizer = &rkisp1->resizer_devs[i].sd.entity; struct media_entity *capture = @@ -413,7 +415,7 @@ static int rkisp1_create_links(struct rkisp1_device *rkisp1) static void rkisp1_entities_unregister(struct rkisp1_device *rkisp1) { - if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) + if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) rkisp1_csi_unregister(rkisp1); rkisp1_params_unregister(rkisp1); rkisp1_stats_unregister(rkisp1); @@ -446,7 +448,7 @@ static int rkisp1_entities_register(struct rkisp1_device *rkisp1) if (ret) goto error; - if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) { + if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) { ret = rkisp1_csi_register(rkisp1); if (ret) goto error; @@ -505,7 +507,9 @@ static const struct rkisp1_info px30_isp_info = { .isrs = px30_isp_isrs, .isr_size = ARRAY_SIZE(px30_isp_isrs), .isp_ver = RKISP1_V12, - .features = RKISP1_FEATURE_MIPI_CSI2, + .features = RKISP1_FEATURE_MIPI_CSI2 + | RKISP1_FEATURE_SELF_PATH + | RKISP1_FEATURE_DUAL_CROP, }; static const char * const rk3399_isp_clks[] = { @@ -524,7 +528,29 @@ static const struct rkisp1_info rk3399_isp_info = { .isrs = rk3399_isp_isrs, .isr_size = ARRAY_SIZE(rk3399_isp_isrs), .isp_ver = RKISP1_V10, - .features = RKISP1_FEATURE_MIPI_CSI2, + .features = RKISP1_FEATURE_MIPI_CSI2 + | RKISP1_FEATURE_SELF_PATH + | RKISP1_FEATURE_DUAL_CROP, +}; + +static const char * const imx8mp_isp_clks[] = { + "isp", + "hclk", + "aclk", +}; + +static const struct rkisp1_isr_data imx8mp_isp_isrs[] = { + { NULL, rkisp1_isr, BIT(RKISP1_IRQ_ISP) | BIT(RKISP1_IRQ_MI) }, +}; + +static const struct rkisp1_info imx8mp_isp_info = { + .clks = imx8mp_isp_clks, + .clk_size = ARRAY_SIZE(imx8mp_isp_clks), + .isrs = imx8mp_isp_isrs, + .isr_size = ARRAY_SIZE(imx8mp_isp_isrs), + .isp_ver = RKISP1_V_IMX8MP, + .features = RKISP1_FEATURE_MAIN_STRIDE + | RKISP1_FEATURE_DMA_34BIT, }; static const struct of_device_id rkisp1_of_match[] = { @@ -536,6 +562,10 @@ static const struct of_device_id rkisp1_of_match[] = { .compatible = "rockchip,rk3399-cif-isp", .data = &rk3399_isp_info, }, + { + .compatible = "fsl,imx8mp-isp", + .data = &imx8mp_isp_info, + }, {}, }; MODULE_DEVICE_TABLE(of, rkisp1_of_match); @@ -547,6 +577,7 @@ static int rkisp1_probe(struct platform_device *pdev) struct rkisp1_device *rkisp1; struct v4l2_device *v4l2_dev; unsigned int i; + u64 dma_mask; int ret, irq; u32 cif_id; @@ -560,6 +591,13 @@ static int rkisp1_probe(struct platform_device *pdev) dev_set_drvdata(dev, rkisp1); rkisp1->dev = dev; + dma_mask = rkisp1_has_feature(rkisp1, DMA_34BIT) ? DMA_BIT_MASK(34) : + DMA_BIT_MASK(32); + + ret = dma_set_mask_and_coherent(dev, dma_mask); + if (ret) + return ret; + mutex_init(&rkisp1->stream_lock); rkisp1->base_addr = devm_platform_ioremap_resource(pdev, 0); @@ -596,6 +634,21 @@ static int rkisp1_probe(struct platform_device *pdev) return ret; rkisp1->clk_size = info->clk_size; + if (info->isp_ver == RKISP1_V_IMX8MP) { + unsigned int id; + + rkisp1->gasket = syscon_regmap_lookup_by_phandle_args(dev->of_node, + "fsl,blk-ctrl", + 1, &id); + if (IS_ERR(rkisp1->gasket)) { + ret = PTR_ERR(rkisp1->gasket); + dev_err(dev, "failed to get gasket: %d\n", ret); + return ret; + } + + rkisp1->gasket_id = id; + } + pm_runtime_enable(&pdev->dev); ret = pm_runtime_resume_and_get(&pdev->dev); @@ -650,7 +703,7 @@ static int rkisp1_probe(struct platform_device *pdev) err_unreg_entities: rkisp1_entities_unregister(rkisp1); err_cleanup_csi: - if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) + if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) rkisp1_csi_cleanup(rkisp1); err_unreg_media_dev: media_device_unregister(&rkisp1->media_dev); @@ -671,7 +724,7 @@ static void rkisp1_remove(struct platform_device *pdev) v4l2_async_nf_cleanup(&rkisp1->notifier); rkisp1_entities_unregister(rkisp1); - if (rkisp1->info->features & RKISP1_FEATURE_MIPI_CSI2) + if (rkisp1_has_feature(rkisp1, MIPI_CSI2)) rkisp1_csi_cleanup(rkisp1); rkisp1_debug_cleanup(rkisp1); diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c index 78a1f7a149..e45a213baf 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-isp.c @@ -10,6 +10,7 @@ #include #include +#include #include #include @@ -53,6 +54,115 @@ * +---------------------------------------------------------+ */ +/* ----------------------------------------------------------------------------- + * Media block control (i.MX8MP only) + */ + +#define ISP_DEWARP_CONTROL 0x0138 + +#define ISP_DEWARP_CONTROL_MIPI_CSI2_HS_POLARITY BIT(22) +#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_RISING (0 << 20) +#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_NEGATIVE (1 << 20) +#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_POSITIVE (2 << 20) +#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_FALLING (3 << 20) +#define ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_MASK GENMASK(21, 20) +#define ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE BIT(19) +#define ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE(dt) ((dt) << 13) +#define ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE_MASK GENMASK(18, 13) + +#define ISP_DEWARP_CONTROL_MIPI_CSI1_HS_POLARITY BIT(12) +#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_RISING (0 << 10) +#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_NEGATIVE (1 << 10) +#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_POSITIVE (2 << 10) +#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_FALLING (3 << 10) +#define ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_MASK GENMASK(11, 10) +#define ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE BIT(9) +#define ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE(dt) ((dt) << 3) +#define ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE_MASK GENMASK(8, 3) + +#define ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE BIT(1) +#define ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE BIT(0) + +static int rkisp1_gasket_enable(struct rkisp1_device *rkisp1, + struct media_pad *source) +{ + struct v4l2_subdev *source_sd; + struct v4l2_mbus_frame_desc fd; + unsigned int dt; + u32 mask; + u32 val; + int ret; + + /* + * Configure and enable the gasket with the CSI-2 data type. Set the + * vsync polarity as active high, as that is what the ISP is configured + * to expect in ISP_ACQ_PROP. Enable left justification, as the i.MX8MP + * ISP has a 16-bit wide input and expects data to be left-aligned. + */ + + source_sd = media_entity_to_v4l2_subdev(source->entity); + ret = v4l2_subdev_call(source_sd, pad, get_frame_desc, + source->index, &fd); + if (ret) { + dev_err(rkisp1->dev, + "failed to get frame descriptor from '%s':%u: %d\n", + source_sd->name, 0, ret); + return ret; + } + + if (fd.num_entries != 1) { + dev_err(rkisp1->dev, "invalid frame descriptor for '%s':%u\n", + source_sd->name, 0); + return -EINVAL; + } + + dt = fd.entry[0].bus.csi2.dt; + + if (rkisp1->gasket_id == 0) { + mask = ISP_DEWARP_CONTROL_MIPI_CSI1_HS_POLARITY + | ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_MASK + | ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE + | ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE_MASK + | ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE; + val = ISP_DEWARP_CONTROL_MIPI_CSI1_VS_SEL_POSITIVE + | ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE + | ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE(dt); + } else { + mask = ISP_DEWARP_CONTROL_MIPI_CSI2_HS_POLARITY + | ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_MASK + | ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE + | ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE_MASK + | ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE; + val = ISP_DEWARP_CONTROL_MIPI_CSI2_VS_SEL_POSITIVE + | ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE + | ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE(dt); + } + + regmap_update_bits(rkisp1->gasket, ISP_DEWARP_CONTROL, mask, val); + + return 0; +} + +static void rkisp1_gasket_disable(struct rkisp1_device *rkisp1) +{ + u32 mask; + u32 val; + + if (rkisp1->gasket_id == 1) { + mask = ISP_DEWARP_CONTROL_MIPI_ISP2_LEFT_JUST_MODE + | ISP_DEWARP_CONTROL_MIPI_ISP2_DATA_TYPE_MASK + | ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE; + val = ISP_DEWARP_CONTROL_GPR_ISP_1_DISABLE; + } else { + mask = ISP_DEWARP_CONTROL_MIPI_ISP1_LEFT_JUST_MODE + | ISP_DEWARP_CONTROL_MIPI_ISP1_DATA_TYPE_MASK + | ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE; + val = ISP_DEWARP_CONTROL_GPR_ISP_0_DISABLE; + } + + regmap_update_bits(rkisp1->gasket, ISP_DEWARP_CONTROL, mask, val); +} + /* ---------------------------------------------------------------------------- * Camera Interface registers configurations */ @@ -291,6 +401,9 @@ static void rkisp1_isp_stop(struct rkisp1_isp *isp) RKISP1_CIF_VI_IRCL_MIPI_SW_RST | RKISP1_CIF_VI_IRCL_ISP_SW_RST); rkisp1_write(rkisp1, RKISP1_CIF_VI_IRCL, 0x0); + + if (rkisp1->info->isp_ver == RKISP1_V_IMX8MP) + rkisp1_gasket_disable(rkisp1); } static void rkisp1_config_clk(struct rkisp1_isp *isp) @@ -315,16 +428,24 @@ static void rkisp1_config_clk(struct rkisp1_isp *isp) } } -static void rkisp1_isp_start(struct rkisp1_isp *isp, - struct v4l2_subdev_state *sd_state) +static int rkisp1_isp_start(struct rkisp1_isp *isp, + struct v4l2_subdev_state *sd_state, + struct media_pad *source) { struct rkisp1_device *rkisp1 = isp->rkisp1; const struct v4l2_mbus_framefmt *src_fmt; const struct rkisp1_mbus_info *src_info; u32 val; + int ret; rkisp1_config_clk(isp); + if (rkisp1->info->isp_ver == RKISP1_V_IMX8MP) { + ret = rkisp1_gasket_enable(rkisp1, source); + if (ret) + return ret; + } + /* Activate ISP */ val = rkisp1_read(rkisp1, RKISP1_CIF_ISP_CTRL); val |= RKISP1_CIF_ISP_CTRL_ISP_CFG_UPD | @@ -338,6 +459,8 @@ static void rkisp1_isp_start(struct rkisp1_isp *isp, if (src_info->pixel_enc != V4L2_PIXEL_ENC_BAYER) rkisp1_params_post_configure(&rkisp1->params); + + return 0; } /* ---------------------------------------------------------------------------- @@ -848,7 +971,9 @@ static int rkisp1_isp_s_stream(struct v4l2_subdev *sd, int enable) if (ret) goto out_unlock; - rkisp1_isp_start(isp, sd_state); + ret = rkisp1_isp_start(isp, sd_state, source_pad); + if (ret) + goto out_unlock; ret = v4l2_subdev_call(rkisp1->source, video, s_stream, true); if (ret) { diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h index bea69a0d76..fccf4c17ee 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-regs.h @@ -144,6 +144,15 @@ /* MI_INIT */ #define RKISP1_CIF_MI_INIT_SKIP BIT(2) #define RKISP1_CIF_MI_INIT_SOFT_UPD BIT(4) +#define RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV400 (0 << 5) +#define RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV420 (1 << 5) +#define RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV422 (2 << 5) +#define RKISP1_CIF_MI_INIT_MP_OUTPUT_YUV444 (3 << 5) +#define RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW12 (4 << 5) +#define RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW8 (5 << 5) +#define RKISP1_CIF_MI_INIT_MP_OUTPUT_JPEG (6 << 5) +#define RKISP1_CIF_MI_INIT_MP_OUTPUT_RAW10 (7 << 5) +#define RKISP1_CIF_MI_INIT_MP_OUTPUT_MASK (15 << 5) /* MI_CTRL_SHD */ #define RKISP1_CIF_MI_CTRL_SHD_MP_IN_ENABLED BIT(0) @@ -207,6 +216,24 @@ #define RKISP1_CIF_MI_XTD_FMT_CTRL_SP_CB_CR_SWAP BIT(1) #define RKISP1_CIF_MI_XTD_FMT_CTRL_DMA_CB_CR_SWAP BIT(2) +/* MI_OUTPUT_ALIGN_FORMAT */ +#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_LSB_ALIGNMENT BIT(0) +#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_BYTES BIT(1) +#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_WORDS BIT(2) +#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_MP_BYTE_SWAP_DWORDS BIT(3) +#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_BYTES BIT(4) +#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_WORDS BIT(5) +#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_SP_BYTE_SWAP_DWORDS BIT(6) +#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_DMA_BYTE_SWAP_BYTES BIT(7) +#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_DMA_BYTE_SWAP_WORDS BIT(8) +#define RKISP1_CIF_OUTPUT_ALIGN_FORMAT_DMA_BYTE_SWAP_DWORDS BIT(9) + +/* MI_MP_OUTPUT_FIFO_SIZE */ +#define RKISP1_CIF_MI_MP_OUTPUT_FIFO_SIZE_OUTPUT_FIFO_DEPTH_FULL (0 << 0) +#define RKISP1_CIF_MI_MP_OUTPUT_FIFO_SIZE_OUTPUT_FIFO_DEPTH_HALF (1 << 0) +#define RKISP1_CIF_MI_MP_OUTPUT_FIFO_SIZE_OUTPUT_FIFO_DEPTH_QUARTER (2 << 0) +#define RKISP1_CIF_MI_MP_OUTPUT_FIFO_SIZE_OUTPUT_FIFO_DEPTH_EIGHT (3 << 0) + /* VI_CCL */ #define RKISP1_CIF_CCL_CIF_CLK_DIS BIT(2) /* VI_ISP_CLK_CTRL */ @@ -1000,6 +1027,15 @@ #define RKISP1_CIF_MI_SP_CB_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000140) #define RKISP1_CIF_MI_SP_CR_BASE_AD_INIT2 (RKISP1_CIF_MI_BASE + 0x00000144) #define RKISP1_CIF_MI_XTD_FORMAT_CTRL (RKISP1_CIF_MI_BASE + 0x00000148) +#define RKISP1_CIF_MI_MP_HANDSHAKE_0 (RKISP1_CIF_MI_BASE + 0x0000014C) +#define RKISP1_CIF_MI_MP_Y_LLENGTH (RKISP1_CIF_MI_BASE + 0x00000150) +#define RKISP1_CIF_MI_MP_Y_SLICE_OFFSET (RKISP1_CIF_MI_BASE + 0x00000154) +#define RKISP1_CIF_MI_MP_C_SLICE_OFFSET (RKISP1_CIF_MI_BASE + 0x00000158) +#define RKISP1_CIF_MI_OUTPUT_ALIGN_FORMAT (RKISP1_CIF_MI_BASE + 0x0000015C) +#define RKISP1_CIF_MI_MP_OUTPUT_FIFO_SIZE (RKISP1_CIF_MI_BASE + 0x00000160) +#define RKISP1_CIF_MI_MP_Y_PIC_WIDTH (RKISP1_CIF_MI_BASE + 0x00000164) +#define RKISP1_CIF_MI_MP_Y_PIC_HEIGHT (RKISP1_CIF_MI_BASE + 0x00000168) +#define RKISP1_CIF_MI_MP_Y_PIC_SIZE (RKISP1_CIF_MI_BASE + 0x0000016C) #define RKISP1_CIF_SMIA_BASE 0x00001a00 #define RKISP1_CIF_SMIA_CTRL (RKISP1_CIF_SMIA_BASE + 0x00000000) diff --git a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c index a8e3777013..6f3931ca5b 100644 --- a/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c +++ b/drivers/media/platform/rockchip/rkisp1/rkisp1-resizer.c @@ -444,11 +444,12 @@ static void rkisp1_rsz_set_sink_crop(struct rkisp1_resizer *rsz, sink_fmt = v4l2_subdev_state_get_format(sd_state, RKISP1_RSZ_PAD_SINK); sink_crop = v4l2_subdev_state_get_crop(sd_state, RKISP1_RSZ_PAD_SINK); - /* Not crop for MP bayer raw data */ + /* Not crop for MP bayer raw data, or for devices lacking dual crop. */ mbus_info = rkisp1_mbus_info_get_by_code(sink_fmt->code); - if (rsz->id == RKISP1_MAINPATH && - mbus_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) { + if ((rsz->id == RKISP1_MAINPATH && + mbus_info->pixel_enc == V4L2_PIXEL_ENC_BAYER) || + !rkisp1_has_feature(rsz->rkisp1, DUAL_CROP)) { sink_crop->left = 0; sink_crop->top = 0; sink_crop->width = sink_fmt->width; @@ -631,21 +632,24 @@ static int rkisp1_rsz_s_stream(struct v4l2_subdev *sd, int enable) struct rkisp1_device *rkisp1 = rsz->rkisp1; struct rkisp1_capture *other = &rkisp1->capture_devs[rsz->id ^ 1]; enum rkisp1_shadow_regs_when when = RKISP1_SHADOW_REGS_SYNC; + bool has_self_path = rkisp1_has_feature(rkisp1, SELF_PATH); struct v4l2_subdev_state *sd_state; if (!enable) { - rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); + if (rkisp1_has_feature(rkisp1, DUAL_CROP)) + rkisp1_dcrop_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); rkisp1_rsz_disable(rsz, RKISP1_SHADOW_REGS_ASYNC); return 0; } - if (other->is_streaming) + if (has_self_path && other->is_streaming) when = RKISP1_SHADOW_REGS_ASYNC; sd_state = v4l2_subdev_lock_and_get_active_state(sd); rkisp1_rsz_config(rsz, sd_state, when); - rkisp1_dcrop_config(rsz, sd_state); + if (rkisp1_has_feature(rkisp1, DUAL_CROP)) + rkisp1_dcrop_config(rsz, sd_state); v4l2_subdev_unlock_state(sd_state); @@ -731,10 +735,11 @@ err_entity_cleanup: int rkisp1_resizer_devs_register(struct rkisp1_device *rkisp1) { + unsigned int dev_count = rkisp1_path_count(rkisp1); unsigned int i; int ret; - for (i = 0; i < ARRAY_SIZE(rkisp1->resizer_devs); i++) { + for (i = 0; i < dev_count; i++) { struct rkisp1_resizer *rsz = &rkisp1->resizer_devs[i]; rsz->rkisp1 = rkisp1; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c index 05cafba1c7..ffa4ea2138 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-capture.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-capture.c @@ -180,7 +180,7 @@ void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf) struct fimc_vid_cap *cap = &fimc->vid_cap; struct fimc_pipeline *p = to_fimc_pipeline(cap->ve.pipe); struct v4l2_subdev *csis = p->subdevs[IDX_CSIS]; - struct fimc_frame *f = &cap->ctx->d_frame; + const struct fimc_frame *f = &cap->ctx->d_frame; struct fimc_vid_buffer *v_buf; if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) { @@ -342,8 +342,8 @@ static int queue_setup(struct vb2_queue *vq, unsigned int sizes[], struct device *alloc_devs[]) { struct fimc_ctx *ctx = vq->drv_priv; - struct fimc_frame *frame = &ctx->d_frame; - struct fimc_fmt *fmt = frame->fmt; + const struct fimc_frame *frame = &ctx->d_frame; + const struct fimc_fmt *fmt = frame->fmt; unsigned long wh = frame->f_width * frame->f_height; int i; @@ -559,18 +559,18 @@ static const struct v4l2_file_operations fimc_capture_fops = { * Format and crop negotiation helpers */ -static struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, - u32 *width, u32 *height, - u32 *code, u32 *fourcc, int pad) +static const struct fimc_fmt *fimc_capture_try_format(struct fimc_ctx *ctx, + u32 *width, u32 *height, + u32 *code, u32 *fourcc, int pad) { bool rotation = ctx->rotation == 90 || ctx->rotation == 270; struct fimc_dev *fimc = ctx->fimc_dev; const struct fimc_variant *var = fimc->variant; const struct fimc_pix_limit *pl = var->pix_limit; - struct fimc_frame *dst = &ctx->d_frame; + const struct fimc_frame *dst = &ctx->d_frame; u32 depth, min_w, max_w, min_h, align_h = 3; + const struct fimc_fmt *ffmt; u32 mask = FMT_FLAGS_CAM; - struct fimc_fmt *ffmt; /* Conversion from/to JPEG or User Defined format is not supported */ if (code && ctx->s_frame.fmt && pad == FIMC_SD_PAD_SOURCE && @@ -644,7 +644,7 @@ static void fimc_capture_try_selection(struct fimc_ctx *ctx, struct fimc_dev *fimc = ctx->fimc_dev; const struct fimc_variant *var = fimc->variant; const struct fimc_pix_limit *pl = var->pix_limit; - struct fimc_frame *sink = &ctx->s_frame; + const struct fimc_frame *sink = &ctx->s_frame; u32 max_w, max_h, min_w = 0, min_h = 0, min_sz; u32 align_sz = 0, align_h = 4; u32 max_sc_h, max_sc_v; @@ -722,7 +722,7 @@ static int fimc_cap_querycap(struct file *file, void *priv, static int fimc_cap_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct fimc_fmt *fmt; + const struct fimc_fmt *fmt; fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM | FMT_FLAGS_M2M, f->index); @@ -757,7 +757,7 @@ static struct media_entity *fimc_pipeline_get_head(struct media_entity *me) */ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, struct v4l2_mbus_framefmt *tfmt, - struct fimc_fmt **fmt_id, + const struct fimc_fmt **fmt_id, bool set) { struct fimc_dev *fimc = ctx->fimc_dev; @@ -768,8 +768,8 @@ static int fimc_pipeline_try_format(struct fimc_ctx *ctx, : V4L2_SUBDEV_FORMAT_TRY, }; struct v4l2_mbus_framefmt *mf = &sfmt.format; + const struct fimc_fmt *ffmt; struct media_entity *me; - struct fimc_fmt *ffmt; struct media_pad *pad; int ret, i = 1; u32 fcc; @@ -903,8 +903,8 @@ static int fimc_cap_g_fmt_mplane(struct file *file, void *fh, */ static int __video_try_or_set_format(struct fimc_dev *fimc, struct v4l2_format *f, bool try, - struct fimc_fmt **inp_fmt, - struct fimc_fmt **out_fmt) + const struct fimc_fmt **inp_fmt, + const struct fimc_fmt **out_fmt) { struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; struct fimc_vid_cap *vc = &fimc->vid_cap; @@ -986,7 +986,7 @@ static int fimc_cap_try_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { struct fimc_dev *fimc = video_drvdata(file); - struct fimc_fmt *out_fmt = NULL, *inp_fmt = NULL; + const struct fimc_fmt *out_fmt = NULL, *inp_fmt = NULL; return __video_try_or_set_format(fimc, f, true, &inp_fmt, &out_fmt); } @@ -1010,9 +1010,9 @@ static int __fimc_capture_set_format(struct fimc_dev *fimc, { struct fimc_vid_cap *vc = &fimc->vid_cap; struct fimc_ctx *ctx = vc->ctx; - struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; + const struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; struct fimc_frame *ff = &ctx->d_frame; - struct fimc_fmt *inp_fmt = NULL; + const struct fimc_fmt *inp_fmt = NULL; int ret, i; if (vb2_is_busy(&fimc->vid_cap.vbq)) @@ -1132,7 +1132,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) /* Don't call FIMC subdev operation to avoid nested locking */ if (sd == &vc->subdev) { - struct fimc_frame *ff = &vc->ctx->s_frame; + const struct fimc_frame *ff = &vc->ctx->s_frame; sink_fmt.format.width = ff->f_width; sink_fmt.format.height = ff->f_height; sink_fmt.format.code = ff->fmt ? ff->fmt->mbus_code : 0; @@ -1158,7 +1158,7 @@ static int fimc_pipeline_validate(struct fimc_dev *fimc) if (sd == p->subdevs[IDX_SENSOR] && fimc_user_defined_mbus_fmt(src_fmt.format.code)) { struct v4l2_plane_pix_format plane_fmt[FIMC_MAX_PLANES]; - struct fimc_frame *frame = &vc->ctx->d_frame; + const struct fimc_frame *frame = &vc->ctx->d_frame; unsigned int i; ret = fimc_get_sensor_frame_desc(sd, plane_fmt, @@ -1263,7 +1263,7 @@ static int fimc_cap_g_selection(struct file *file, void *fh, { struct fimc_dev *fimc = video_drvdata(file); struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct fimc_frame *f = &ctx->s_frame; + const struct fimc_frame *f = &ctx->s_frame; if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) return -EINVAL; @@ -1460,7 +1460,7 @@ static int fimc_subdev_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_state *sd_state, struct v4l2_subdev_mbus_code_enum *code) { - struct fimc_fmt *fmt; + const struct fimc_fmt *fmt; fmt = fimc_find_format(NULL, NULL, FMT_FLAGS_CAM, code->index); if (!fmt) @@ -1475,7 +1475,7 @@ static int fimc_subdev_get_fmt(struct v4l2_subdev *sd, { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct fimc_frame *ff = &ctx->s_frame; + const struct fimc_frame *ff = &ctx->s_frame; struct v4l2_mbus_framefmt *mf; if (fmt->which == V4L2_SUBDEV_FORMAT_TRY) { @@ -1519,7 +1519,7 @@ static int fimc_subdev_set_fmt(struct v4l2_subdev *sd, struct fimc_vid_cap *vc = &fimc->vid_cap; struct fimc_ctx *ctx = vc->ctx; struct fimc_frame *ff; - struct fimc_fmt *ffmt; + const struct fimc_fmt *ffmt; dbg("pad%d: code: 0x%x, %dx%d", fmt->pad, mf->code, mf->width, mf->height); @@ -1582,7 +1582,7 @@ static int fimc_subdev_get_selection(struct v4l2_subdev *sd, { struct fimc_dev *fimc = v4l2_get_subdevdata(sd); struct fimc_ctx *ctx = fimc->vid_cap.ctx; - struct fimc_frame *f = &ctx->s_frame; + const struct fimc_frame *f = &ctx->s_frame; struct v4l2_rect *r = &sel->r; struct v4l2_rect *try_sel; @@ -1715,9 +1715,9 @@ static int fimc_register_capture_device(struct fimc_dev *fimc, { struct video_device *vfd = &fimc->vid_cap.ve.vdev; struct vb2_queue *q = &fimc->vid_cap.vbq; - struct fimc_ctx *ctx; struct fimc_vid_cap *vid_cap; - struct fimc_fmt *fmt; + const struct fimc_fmt *fmt; + struct fimc_ctx *ctx; int ret = -ENOMEM; ctx = kzalloc(sizeof(*ctx), GFP_KERNEL); diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.c b/drivers/media/platform/samsung/exynos4-is/fimc-core.c index 0be687b01c..aae74b501a 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-core.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.c @@ -29,11 +29,11 @@ #include "fimc-reg.h" #include "media-dev.h" -static char *fimc_clocks[MAX_FIMC_CLOCKS] = { +static const char *fimc_clocks[MAX_FIMC_CLOCKS] = { "sclk_fimc", "fimc" }; -static struct fimc_fmt fimc_formats[] = { +static const struct fimc_fmt fimc_formats[] = { { .fourcc = V4L2_PIX_FMT_RGB565, .depth = { 16 }, @@ -180,7 +180,7 @@ static struct fimc_fmt fimc_formats[] = { }, }; -struct fimc_fmt *fimc_get_format(unsigned int index) +const struct fimc_fmt *fimc_get_format(unsigned int index) { if (index >= ARRAY_SIZE(fimc_formats)) return NULL; @@ -228,8 +228,8 @@ int fimc_set_scaler_info(struct fimc_ctx *ctx) const struct fimc_variant *variant = ctx->fimc_dev->variant; struct device *dev = &ctx->fimc_dev->pdev->dev; struct fimc_scaler *sc = &ctx->scaler; - struct fimc_frame *s_frame = &ctx->s_frame; - struct fimc_frame *d_frame = &ctx->d_frame; + const struct fimc_frame *s_frame = &ctx->s_frame; + const struct fimc_frame *d_frame = &ctx->d_frame; int tx, ty, sx, sy; int ret; @@ -326,7 +326,7 @@ out: /* The color format (colplanes, memplanes) must be already configured. */ int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, - struct fimc_frame *frame, struct fimc_addr *addr) + const struct fimc_frame *frame, struct fimc_addr *addr) { int ret = 0; u32 pix_size; @@ -670,7 +670,7 @@ void fimc_alpha_ctrl_update(struct fimc_ctx *ctx) v4l2_ctrl_unlock(ctrl); } -void __fimc_get_format(struct fimc_frame *frame, struct v4l2_format *f) +void __fimc_get_format(const struct fimc_frame *frame, struct v4l2_format *f) { struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; int i; @@ -695,7 +695,7 @@ void __fimc_get_format(struct fimc_frame *frame, struct v4l2_format *f) * @height: requested pixel height * @pix: multi-plane format to adjust */ -void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, +void fimc_adjust_mplane_format(const struct fimc_fmt *fmt, u32 width, u32 height, struct v4l2_pix_format_mplane *pix) { u32 bytesperline = 0; @@ -752,10 +752,11 @@ void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, * @mask: the color flags to match * @index: offset in the fimc_formats array, ignored if negative */ -struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code, - unsigned int mask, int index) +const struct fimc_fmt *fimc_find_format(const u32 *pixelformat, + const u32 *mbus_code, + unsigned int mask, int index) { - struct fimc_fmt *fmt, *def_fmt = NULL; + const struct fimc_fmt *fmt, *def_fmt = NULL; unsigned int i; int id = 0; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-core.h b/drivers/media/platform/samsung/exynos4-is/fimc-core.h index 2b0760add0..63385152a2 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-core.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-core.h @@ -257,7 +257,7 @@ struct fimc_frame { unsigned int bytesperline[VIDEO_MAX_PLANES]; struct fimc_addr addr; struct fimc_dma_offset dma_offset; - struct fimc_fmt *fmt; + const struct fimc_fmt *fmt; u8 alpha; }; @@ -515,7 +515,7 @@ static inline void set_frame_crop(struct fimc_frame *f, f->height = height; } -static inline u32 fimc_get_format_depth(struct fimc_fmt *ff) +static inline u32 fimc_get_format_depth(const struct fimc_fmt *ff) { u32 i, depth = 0; @@ -557,7 +557,7 @@ static inline bool fimc_ctx_state_is_set(u32 mask, struct fimc_ctx *ctx) return ret; } -static inline int tiled_fmt(struct fimc_fmt *fmt) +static inline int tiled_fmt(const struct fimc_fmt *fmt) { return fmt->fourcc == V4L2_PIX_FMT_NV12MT; } @@ -575,7 +575,7 @@ static inline bool fimc_user_defined_mbus_fmt(u32 code) } /* Return the alpha component bit mask */ -static inline int fimc_get_alpha_mask(struct fimc_fmt *fmt) +static inline int fimc_get_alpha_mask(const struct fimc_fmt *fmt) { switch (fmt->color) { case FIMC_FMT_RGB444: return 0x0f; @@ -610,25 +610,24 @@ static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx, /* -----------------------------------------------------*/ /* fimc-core.c */ -int fimc_vidioc_enum_fmt_mplane(struct file *file, void *priv, - struct v4l2_fmtdesc *f); int fimc_ctrls_create(struct fimc_ctx *ctx); void fimc_ctrls_delete(struct fimc_ctx *ctx); void fimc_ctrls_activate(struct fimc_ctx *ctx, bool active); void fimc_alpha_ctrl_update(struct fimc_ctx *ctx); -void __fimc_get_format(struct fimc_frame *frame, struct v4l2_format *f); -void fimc_adjust_mplane_format(struct fimc_fmt *fmt, u32 width, u32 height, +void __fimc_get_format(const struct fimc_frame *frame, struct v4l2_format *f); +void fimc_adjust_mplane_format(const struct fimc_fmt *fmt, u32 width, u32 height, struct v4l2_pix_format_mplane *pix); -struct fimc_fmt *fimc_find_format(const u32 *pixelformat, const u32 *mbus_code, - unsigned int mask, int index); -struct fimc_fmt *fimc_get_format(unsigned int index); +const struct fimc_fmt *fimc_find_format(const u32 *pixelformat, + const u32 *mbus_code, + unsigned int mask, int index); +const struct fimc_fmt *fimc_get_format(unsigned int index); int fimc_check_scaler_ratio(struct fimc_ctx *ctx, int sw, int sh, int dw, int dh, int rotation); int fimc_set_scaler_info(struct fimc_ctx *ctx); int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags); int fimc_prepare_addr(struct fimc_ctx *ctx, struct vb2_buffer *vb, - struct fimc_frame *frame, struct fimc_addr *addr); + const struct fimc_frame *frame, struct fimc_addr *addr); void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f); void fimc_set_yuv_order(struct fimc_ctx *ctx); void fimc_capture_irq_handler(struct fimc_dev *fimc, int deq_buf); diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-is.c b/drivers/media/platform/samsung/exynos4-is/fimc-is.c index a08c87ef6e..39aab66791 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-is.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-is.c @@ -175,7 +175,7 @@ static int fimc_is_parse_sensor_config(struct fimc_is *is, unsigned int index, return -EINVAL; } - ep = of_graph_get_next_endpoint(node, NULL); + ep = of_graph_get_endpoint_by_regs(node, 0, -1); if (!ep) return -ENXIO; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c index 8fa26969c4..06c4352562 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-isp-video.c @@ -40,7 +40,7 @@ static int isp_video_capture_queue_setup(struct vb2_queue *vq, unsigned int sizes[], struct device *alloc_devs[]) { struct fimc_isp *isp = vb2_get_drv_priv(vq); - struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt; + const struct v4l2_pix_format_mplane *vid_fmt = &isp->video_capture.pixfmt; const struct fimc_fmt *fmt = isp->video_capture.format; unsigned int wh, i; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite-reg.c index 57996b4104..2483277a6c 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite-reg.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite-reg.c @@ -124,7 +124,7 @@ static const u32 src_pixfmt_map[8][3] = { }; /* Set camera input pixel format and resolution */ -void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f) +void flite_hw_set_source_format(struct fimc_lite *dev, const struct flite_frame *f) { u32 pixelcode = f->fmt->mbus_code; int i = ARRAY_SIZE(src_pixfmt_map); @@ -155,7 +155,7 @@ void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f) } /* Set the camera host input window offsets (cropping) */ -void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f) +void flite_hw_set_window_offset(struct fimc_lite *dev, const struct flite_frame *f) { u32 hoff2, voff2; u32 cfg; @@ -186,7 +186,7 @@ static void flite_hw_set_camera_port(struct fimc_lite *dev, int id) /* Select serial or parallel bus, camera port (A,B) and set signals polarity */ void flite_hw_set_camera_bus(struct fimc_lite *dev, - struct fimc_source_info *si) + const struct fimc_source_info *si) { u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL); unsigned int flags = si->flags; @@ -226,7 +226,8 @@ static void flite_hw_set_pack12(struct fimc_lite *dev, int on) writel(cfg, dev->regs + FLITE_REG_CIODMAFMT); } -static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) +static void flite_hw_set_out_order(struct fimc_lite *dev, + const struct flite_frame *f) { static const u32 pixcode[4][2] = { { MEDIA_BUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR }, @@ -244,7 +245,7 @@ static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f) writel(cfg | pixcode[i][1], dev->regs + FLITE_REG_CIODMAFMT); } -void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f) +void flite_hw_set_dma_window(struct fimc_lite *dev, const struct flite_frame *f) { u32 cfg; @@ -294,7 +295,7 @@ void flite_hw_mask_dma_buffer(struct fimc_lite *dev, u32 index) } /* Enable/disable output DMA, set output pixel size and offsets (composition) */ -void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f, +void flite_hw_set_output_dma(struct fimc_lite *dev, const struct flite_frame *f, bool enable) { u32 cfg = readl(dev->regs + FLITE_REG_CIGCTRL); diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite-reg.h b/drivers/media/platform/samsung/exynos4-is/fimc-lite-reg.h index c5656e9027..c5ec36dfb2 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite-reg.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite-reg.h @@ -133,15 +133,13 @@ void flite_hw_set_interrupt_mask(struct fimc_lite *dev); void flite_hw_capture_start(struct fimc_lite *dev); void flite_hw_capture_stop(struct fimc_lite *dev); void flite_hw_set_camera_bus(struct fimc_lite *dev, - struct fimc_source_info *s_info); -void flite_hw_set_camera_polarity(struct fimc_lite *dev, - struct fimc_source_info *cam); -void flite_hw_set_window_offset(struct fimc_lite *dev, struct flite_frame *f); -void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f); + const struct fimc_source_info *s_info); +void flite_hw_set_window_offset(struct fimc_lite *dev, const struct flite_frame *f); +void flite_hw_set_source_format(struct fimc_lite *dev, const struct flite_frame *f); -void flite_hw_set_output_dma(struct fimc_lite *dev, struct flite_frame *f, +void flite_hw_set_output_dma(struct fimc_lite *dev, const struct flite_frame *f, bool enable); -void flite_hw_set_dma_window(struct fimc_lite *dev, struct flite_frame *f); +void flite_hw_set_dma_window(struct fimc_lite *dev, const struct flite_frame *f); void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on); void flite_hw_dump_regs(struct fimc_lite *dev, const char *label); void flite_hw_set_dma_buffer(struct fimc_lite *dev, struct flite_buffer *buf); diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c index 7898c9bebb..d1d860fa34 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.c @@ -738,7 +738,7 @@ static int fimc_lite_try_fmt_mplane(struct file *file, void *fh, static int fimc_lite_s_fmt_mplane(struct file *file, void *priv, struct v4l2_format *f) { - struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; + const struct v4l2_pix_format_mplane *pixm = &f->fmt.pix_mp; struct fimc_lite *fimc = video_drvdata(file); struct flite_frame *frame = &fimc->out_frame; const struct fimc_fmt *fmt = NULL; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-lite.h b/drivers/media/platform/samsung/exynos4-is/fimc-lite.h index ddf29e0b5b..2d96fb00a5 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-lite.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-lite.h @@ -117,8 +117,6 @@ struct flite_buffer { * @ctrl_handler: v4l2 control handler * @test_pattern: test pattern controls * @index: FIMC-LITE platform device index - * @pipeline: video capture pipeline data structure - * @pipeline_ops: media pipeline ops for the video node driver * @slock: spinlock protecting this data structure and the hw registers * @lock: mutex serializing video device and the subdev operations * @clock: FIMC-LITE gate clock @@ -134,7 +132,6 @@ struct flite_buffer { * @active_buf_q: the queue head of buffers scheduled in hardware * @vb_queue: vb2 buffers queue * @buf_index: helps to keep track of the DMA start address register index - * @active_buf_count: number of video buffers scheduled in hardware * @frame_count: the captured frames counter * @reqbufs_count: the number of buffers requested with REQBUFS ioctl * @events: event info diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c index df8e2aa454..199997eec1 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-m2m.c @@ -170,7 +170,7 @@ static int fimc_queue_setup(struct vb2_queue *vq, unsigned int sizes[], struct device *alloc_devs[]) { struct fimc_ctx *ctx = vb2_get_drv_priv(vq); - struct fimc_frame *f; + const struct fimc_frame *f; int i; f = ctx_get_frame(ctx, vq->type); @@ -192,7 +192,7 @@ static int fimc_queue_setup(struct vb2_queue *vq, static int fimc_buf_prepare(struct vb2_buffer *vb) { struct fimc_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue); - struct fimc_frame *frame; + const struct fimc_frame *frame; int i; frame = ctx_get_frame(ctx, vb->vb2_queue->type); @@ -237,7 +237,7 @@ static int fimc_m2m_querycap(struct file *file, void *fh, static int fimc_m2m_enum_fmt(struct file *file, void *priv, struct v4l2_fmtdesc *f) { - struct fimc_fmt *fmt; + const struct fimc_fmt *fmt; fmt = fimc_find_format(NULL, NULL, get_m2m_fmt_flags(f->type), f->index); @@ -252,7 +252,7 @@ static int fimc_m2m_g_fmt_mplane(struct file *file, void *fh, struct v4l2_format *f) { struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_frame *frame = ctx_get_frame(ctx, f->type); + const struct fimc_frame *frame = ctx_get_frame(ctx, f->type); if (IS_ERR(frame)) return PTR_ERR(frame); @@ -266,7 +266,7 @@ static int fimc_try_fmt_mplane(struct fimc_ctx *ctx, struct v4l2_format *f) struct fimc_dev *fimc = ctx->fimc_dev; const struct fimc_variant *variant = fimc->variant; struct v4l2_pix_format_mplane *pix = &f->fmt.pix_mp; - struct fimc_fmt *fmt; + const struct fimc_fmt *fmt; u32 max_w, mod_x, mod_y; if (!IS_M2M(f->type)) @@ -314,8 +314,9 @@ static int fimc_m2m_try_fmt_mplane(struct file *file, void *fh, return fimc_try_fmt_mplane(ctx, f); } -static void __set_frame_format(struct fimc_frame *frame, struct fimc_fmt *fmt, - struct v4l2_pix_format_mplane *pixm) +static void __set_frame_format(struct fimc_frame *frame, + const struct fimc_fmt *fmt, + const struct v4l2_pix_format_mplane *pixm) { int i; @@ -340,7 +341,7 @@ static int fimc_m2m_s_fmt_mplane(struct file *file, void *fh, { struct fimc_ctx *ctx = fh_to_ctx(fh); struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_fmt *fmt; + const struct fimc_fmt *fmt; struct vb2_queue *vq; struct fimc_frame *frame; int ret; @@ -378,7 +379,7 @@ static int fimc_m2m_g_selection(struct file *file, void *fh, struct v4l2_selection *s) { struct fimc_ctx *ctx = fh_to_ctx(fh); - struct fimc_frame *frame; + const struct fimc_frame *frame; frame = ctx_get_frame(ctx, s->type); if (IS_ERR(frame)) @@ -428,7 +429,7 @@ static int fimc_m2m_try_selection(struct fimc_ctx *ctx, struct v4l2_selection *s) { struct fimc_dev *fimc = ctx->fimc_dev; - struct fimc_frame *f; + const struct fimc_frame *f; u32 min_size, halign, depth = 0; int i; @@ -588,7 +589,7 @@ static int fimc_m2m_set_default_format(struct fimc_ctx *ctx) .sizeimage = 800 * 4 * 600, }, }; - struct fimc_fmt *fmt; + const struct fimc_fmt *fmt; fmt = fimc_find_format(&pixm.pixelformat, NULL, FMT_FLAGS_M2M, 0); if (!fmt) diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-reg.c b/drivers/media/platform/samsung/exynos4-is/fimc-reg.c index 95165a2cc7..b4ee39e471 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-reg.c +++ b/drivers/media/platform/samsung/exynos4-is/fimc-reg.c @@ -105,7 +105,7 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx) { u32 cfg; struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; + const struct fimc_frame *frame = &ctx->d_frame; dbg("w= %d, h= %d color: %d", frame->width, frame->height, frame->fmt->color); @@ -147,7 +147,7 @@ void fimc_hw_set_target_format(struct fimc_ctx *ctx) static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; + const struct fimc_frame *frame = &ctx->d_frame; u32 cfg; cfg = (frame->f_height << 16) | frame->f_width; @@ -166,9 +166,9 @@ static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx) void fimc_hw_set_out_dma(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; - struct fimc_dma_offset *offset = &frame->dma_offset; - struct fimc_fmt *fmt = frame->fmt; + const struct fimc_frame *frame = &ctx->d_frame; + const struct fimc_dma_offset *offset = &frame->dma_offset; + const struct fimc_fmt *fmt = frame->fmt; u32 cfg; /* Set the input dma offsets. */ @@ -248,8 +248,8 @@ static void fimc_hw_set_scaler(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; struct fimc_scaler *sc = &ctx->scaler; - struct fimc_frame *src_frame = &ctx->s_frame; - struct fimc_frame *dst_frame = &ctx->d_frame; + const struct fimc_frame *src_frame = &ctx->s_frame; + const struct fimc_frame *dst_frame = &ctx->d_frame; u32 cfg = readl(dev->regs + FIMC_REG_CISCCTRL); @@ -388,7 +388,7 @@ void fimc_hw_set_effect(struct fimc_ctx *ctx) void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->d_frame; + const struct fimc_frame *frame = &ctx->d_frame; u32 cfg; if (!(frame->fmt->flags & FMT_HAS_ALPHA)) @@ -403,7 +403,7 @@ void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx) static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->s_frame; + const struct fimc_frame *frame = &ctx->s_frame; u32 cfg_o = 0; u32 cfg_r = 0; @@ -420,8 +420,8 @@ static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx) void fimc_hw_set_in_dma(struct fimc_ctx *ctx) { struct fimc_dev *dev = ctx->fimc_dev; - struct fimc_frame *frame = &ctx->s_frame; - struct fimc_dma_offset *offset = &frame->dma_offset; + const struct fimc_frame *frame = &ctx->s_frame; + const struct fimc_dma_offset *offset = &frame->dma_offset; u32 cfg; /* Set the pixel offsets. */ @@ -526,7 +526,7 @@ void fimc_hw_set_output_path(struct fimc_ctx *ctx) writel(cfg, dev->regs + FIMC_REG_CISCCTRL); } -void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *addr) +void fimc_hw_set_input_addr(struct fimc_dev *dev, const struct fimc_addr *addr) { u32 cfg = readl(dev->regs + FIMC_REG_CIREAL_ISIZE); cfg |= FIMC_REG_CIREAL_ISIZE_ADDR_CH_DIS; @@ -541,7 +541,7 @@ void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *addr) } void fimc_hw_set_output_addr(struct fimc_dev *dev, - struct fimc_addr *addr, int index) + const struct fimc_addr *addr, int index) { int i = (index == -1) ? 0 : index; do { @@ -554,7 +554,7 @@ void fimc_hw_set_output_addr(struct fimc_dev *dev, } int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, - struct fimc_source_info *cam) + const struct fimc_source_info *cam) { u32 cfg = readl(fimc->regs + FIMC_REG_CIGCTRL); @@ -598,8 +598,8 @@ static const struct mbus_pixfmt_desc pix_desc[] = { int fimc_hw_set_camera_source(struct fimc_dev *fimc, struct fimc_source_info *source) { - struct fimc_vid_cap *vc = &fimc->vid_cap; - struct fimc_frame *f = &vc->ctx->s_frame; + const struct fimc_vid_cap *vc = &fimc->vid_cap; + const struct fimc_frame *f = &vc->ctx->s_frame; u32 bus_width, cfg = 0; int i; @@ -648,7 +648,7 @@ int fimc_hw_set_camera_source(struct fimc_dev *fimc, return 0; } -void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) +void fimc_hw_set_camera_offset(struct fimc_dev *fimc, const struct fimc_frame *f) { u32 hoff2, voff2; @@ -668,9 +668,9 @@ void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f) } int fimc_hw_set_camera_type(struct fimc_dev *fimc, - struct fimc_source_info *source) + const struct fimc_source_info *source) { - struct fimc_vid_cap *vid_cap = &fimc->vid_cap; + const struct fimc_vid_cap *vid_cap = &fimc->vid_cap; u32 csis_data_alignment = 32; u32 cfg, tmp; diff --git a/drivers/media/platform/samsung/exynos4-is/fimc-reg.h b/drivers/media/platform/samsung/exynos4-is/fimc-reg.h index b9b33aa1f1..9714f43096 100644 --- a/drivers/media/platform/samsung/exynos4-is/fimc-reg.h +++ b/drivers/media/platform/samsung/exynos4-is/fimc-reg.h @@ -302,16 +302,16 @@ void fimc_hw_set_rgb_alpha(struct fimc_ctx *ctx); void fimc_hw_set_in_dma(struct fimc_ctx *ctx); void fimc_hw_set_input_path(struct fimc_ctx *ctx); void fimc_hw_set_output_path(struct fimc_ctx *ctx); -void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *addr); -void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *addr, +void fimc_hw_set_input_addr(struct fimc_dev *fimc, const struct fimc_addr *addr); +void fimc_hw_set_output_addr(struct fimc_dev *fimc, const struct fimc_addr *addr, int index); int fimc_hw_set_camera_source(struct fimc_dev *fimc, struct fimc_source_info *cam); -void fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f); +void fimc_hw_set_camera_offset(struct fimc_dev *fimc, const struct fimc_frame *f); int fimc_hw_set_camera_polarity(struct fimc_dev *fimc, - struct fimc_source_info *cam); + const struct fimc_source_info *cam); int fimc_hw_set_camera_type(struct fimc_dev *fimc, - struct fimc_source_info *cam); + const struct fimc_source_info *cam); void fimc_hw_clear_irq(struct fimc_dev *dev); void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on); void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on); diff --git a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c index aae8a8b2c0..4b9b20ba35 100644 --- a/drivers/media/platform/samsung/exynos4-is/mipi-csis.c +++ b/drivers/media/platform/samsung/exynos4-is/mipi-csis.c @@ -727,7 +727,8 @@ static int s5pcsis_parse_dt(struct platform_device *pdev, &state->max_num_lanes)) return -EINVAL; - node = of_graph_get_next_endpoint(node, NULL); + /* from port@3 or port@4 */ + node = of_graph_get_endpoint_by_regs(node, -1, -1); if (!node) { dev_err(&pdev->dev, "No port node at %pOF\n", pdev->dev.of_node); diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c index fbb047eadf..50451984d5 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc.c @@ -183,7 +183,7 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) mfc_err("Error: some instance may be closing/opening\n"); spin_lock_irqsave(&dev->irqlock, flags); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); for (i = 0; i < MFC_NUM_CONTEXTS; i++) { ctx = dev->ctx[i]; @@ -211,9 +211,9 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work) mfc_err("Failed to reload FW\n"); goto unlock; } - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); ret = s5p_mfc_init_hw(dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); if (ret) mfc_err("Failed to reinit FW\n"); } @@ -393,7 +393,7 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx, s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); return; } @@ -465,7 +465,7 @@ leave_handle_frame: s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); wake_up_ctx(ctx, reason, err); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); /* if suspending, wake up device and do not try_run again*/ if (test_bit(0, &dev->enter_suspend)) wake_up_dev(dev, reason, err); @@ -509,7 +509,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev, } WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); wake_up_dev(dev, reason, err); } @@ -565,7 +565,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx, s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); clear_work_bit(ctx); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); wake_up_ctx(ctx, reason, err); } @@ -601,7 +601,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, } WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); wake_up(&ctx->queue); if (ctx->src_queue_cnt >= 1 && ctx->dst_queue_cnt >= 1) @@ -610,7 +610,7 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx, } else { WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); wake_up(&ctx->queue); } @@ -638,7 +638,7 @@ static void s5p_mfc_handle_stream_complete(struct s5p_mfc_ctx *ctx) WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); wake_up(&ctx->queue); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } @@ -690,7 +690,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv) } s5p_mfc_hw_call(dev->mfc_ops, clear_int_flags, dev); WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); wake_up_ctx(ctx, reason, err); s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } else { @@ -754,7 +754,7 @@ irq_cleanup_hw: if (test_and_clear_bit(0, &dev->hw_lock) == 0) mfc_err("Failed to unlock hw\n"); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); clear_work_bit(ctx); wake_up(&ctx->queue); @@ -841,20 +841,20 @@ static int s5p_mfc_open(struct file *file) dev->watchdog_timer.expires = jiffies + msecs_to_jiffies(MFC_WATCHDOG_INTERVAL); add_timer(&dev->watchdog_timer); - ret = s5p_mfc_power_on(); + ret = s5p_mfc_power_on(dev); if (ret < 0) { mfc_err("power on failed\n"); goto err_pwr_enable; } - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); ret = s5p_mfc_load_firmware(dev); if (ret) { - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); goto err_load_fw; } /* Init the FW */ ret = s5p_mfc_init_hw(dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); if (ret) goto err_init_hw; } @@ -931,7 +931,7 @@ err_init_hw: err_load_fw: err_pwr_enable: if (dev->num_inst == 1) { - if (s5p_mfc_power_off() < 0) + if (s5p_mfc_power_off(dev) < 0) mfc_err("power off failed\n"); del_timer_sync(&dev->watchdog_timer); } @@ -963,7 +963,7 @@ static int s5p_mfc_release(struct file *file) vb2_queue_release(&ctx->vq_src); vb2_queue_release(&ctx->vq_dst); if (dev) { - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); /* Mark context as idle */ clear_work_bit_irqsave(ctx); @@ -983,12 +983,12 @@ static int s5p_mfc_release(struct file *file) mfc_debug(2, "Last instance\n"); s5p_mfc_deinit_hw(dev); del_timer_sync(&dev->watchdog_timer); - s5p_mfc_clock_off(); - if (s5p_mfc_power_off() < 0) + s5p_mfc_clock_off(dev); + if (s5p_mfc_power_off(dev) < 0) mfc_err("Power off failed\n"); } else { mfc_debug(2, "Shutting down clock\n"); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); } } if (dev) @@ -1520,20 +1520,20 @@ static const struct dev_pm_ops s5p_mfc_pm_ops = { SET_SYSTEM_SLEEP_PM_OPS(s5p_mfc_suspend, s5p_mfc_resume) }; -static struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { +static const struct s5p_mfc_buf_size_v5 mfc_buf_size_v5 = { .h264_ctx = MFC_H264_CTX_BUF_SIZE, .non_h264_ctx = MFC_CTX_BUF_SIZE, .dsc = DESC_BUF_SIZE, .shm = SHARED_BUF_SIZE, }; -static struct s5p_mfc_buf_size buf_size_v5 = { +static const struct s5p_mfc_buf_size buf_size_v5 = { .fw = MAX_FW_SIZE, .cpb = MAX_CPB_SIZE, .priv = &mfc_buf_size_v5, }; -static struct s5p_mfc_variant mfc_drvdata_v5 = { +static const struct s5p_mfc_variant mfc_drvdata_v5 = { .version = MFC_VERSION, .version_bit = MFC_V5_BIT, .port_num = MFC_NUM_PORTS, @@ -1544,7 +1544,7 @@ static struct s5p_mfc_variant mfc_drvdata_v5 = { .use_clock_gating = true, }; -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { +static const struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { .dev_ctx = MFC_CTX_BUF_SIZE_V6, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V6, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V6, @@ -1552,13 +1552,13 @@ static struct s5p_mfc_buf_size_v6 mfc_buf_size_v6 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V6, }; -static struct s5p_mfc_buf_size buf_size_v6 = { +static const struct s5p_mfc_buf_size buf_size_v6 = { .fw = MAX_FW_SIZE_V6, .cpb = MAX_CPB_SIZE_V6, .priv = &mfc_buf_size_v6, }; -static struct s5p_mfc_variant mfc_drvdata_v6 = { +static const struct s5p_mfc_variant mfc_drvdata_v6 = { .version = MFC_VERSION_V6, .version_bit = MFC_V6_BIT, .port_num = MFC_NUM_PORTS_V6, @@ -1573,7 +1573,7 @@ static struct s5p_mfc_variant mfc_drvdata_v6 = { .num_clocks = 1, }; -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { +static const struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { .dev_ctx = MFC_CTX_BUF_SIZE_V7, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V7, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V7, @@ -1581,13 +1581,13 @@ static struct s5p_mfc_buf_size_v6 mfc_buf_size_v7 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V7, }; -static struct s5p_mfc_buf_size buf_size_v7 = { +static const struct s5p_mfc_buf_size buf_size_v7 = { .fw = MAX_FW_SIZE_V7, .cpb = MAX_CPB_SIZE_V7, .priv = &mfc_buf_size_v7, }; -static struct s5p_mfc_variant mfc_drvdata_v7 = { +static const struct s5p_mfc_variant mfc_drvdata_v7 = { .version = MFC_VERSION_V7, .version_bit = MFC_V7_BIT, .port_num = MFC_NUM_PORTS_V7, @@ -1597,7 +1597,7 @@ static struct s5p_mfc_variant mfc_drvdata_v7 = { .num_clocks = 1, }; -static struct s5p_mfc_variant mfc_drvdata_v7_3250 = { +static const struct s5p_mfc_variant mfc_drvdata_v7_3250 = { .version = MFC_VERSION_V7, .version_bit = MFC_V7_BIT, .port_num = MFC_NUM_PORTS_V7, @@ -1607,7 +1607,7 @@ static struct s5p_mfc_variant mfc_drvdata_v7_3250 = { .num_clocks = 2, }; -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { +static const struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { .dev_ctx = MFC_CTX_BUF_SIZE_V8, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V8, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V8, @@ -1615,13 +1615,13 @@ static struct s5p_mfc_buf_size_v6 mfc_buf_size_v8 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V8, }; -static struct s5p_mfc_buf_size buf_size_v8 = { +static const struct s5p_mfc_buf_size buf_size_v8 = { .fw = MAX_FW_SIZE_V8, .cpb = MAX_CPB_SIZE_V8, .priv = &mfc_buf_size_v8, }; -static struct s5p_mfc_variant mfc_drvdata_v8 = { +static const struct s5p_mfc_variant mfc_drvdata_v8 = { .version = MFC_VERSION_V8, .version_bit = MFC_V8_BIT, .port_num = MFC_NUM_PORTS_V8, @@ -1631,7 +1631,7 @@ static struct s5p_mfc_variant mfc_drvdata_v8 = { .num_clocks = 1, }; -static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { +static const struct s5p_mfc_variant mfc_drvdata_v8_5433 = { .version = MFC_VERSION_V8, .version_bit = MFC_V8_BIT, .port_num = MFC_NUM_PORTS_V8, @@ -1641,7 +1641,7 @@ static struct s5p_mfc_variant mfc_drvdata_v8_5433 = { .num_clocks = 3, }; -static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { +static const struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { .dev_ctx = MFC_CTX_BUF_SIZE_V10, .h264_dec_ctx = MFC_H264_DEC_CTX_BUF_SIZE_V10, .other_dec_ctx = MFC_OTHER_DEC_CTX_BUF_SIZE_V10, @@ -1650,13 +1650,13 @@ static struct s5p_mfc_buf_size_v6 mfc_buf_size_v10 = { .other_enc_ctx = MFC_OTHER_ENC_CTX_BUF_SIZE_V10, }; -static struct s5p_mfc_buf_size buf_size_v10 = { +static const struct s5p_mfc_buf_size buf_size_v10 = { .fw = MAX_FW_SIZE_V10, .cpb = MAX_CPB_SIZE_V10, .priv = &mfc_buf_size_v10, }; -static struct s5p_mfc_variant mfc_drvdata_v10 = { +static const struct s5p_mfc_variant mfc_drvdata_v10 = { .version = MFC_VERSION_V10, .version_bit = MFC_V10_BIT, .port_num = MFC_NUM_PORTS_V10, diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c index 774c573dc0..196d8c9964 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.c @@ -12,14 +12,10 @@ #include "s5p_mfc_cmd_v5.h" #include "s5p_mfc_cmd_v6.h" -static struct s5p_mfc_hw_cmds *s5p_mfc_cmds; - void s5p_mfc_init_hw_cmds(struct s5p_mfc_dev *dev) { if (IS_MFCV6_PLUS(dev)) - s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v6(); + dev->mfc_cmds = s5p_mfc_init_hw_cmds_v6(); else - s5p_mfc_cmds = s5p_mfc_init_hw_cmds_v5(); - - dev->mfc_cmds = s5p_mfc_cmds; + dev->mfc_cmds = s5p_mfc_init_hw_cmds_v5(); } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h index 945d12fdce..172c5a63b5 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd.h @@ -19,7 +19,7 @@ struct s5p_mfc_cmd_args { struct s5p_mfc_hw_cmds { int (*cmd_host2risc)(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args); + const struct s5p_mfc_cmd_args *args); int (*sys_init_cmd)(struct s5p_mfc_dev *dev); int (*sleep_cmd)(struct s5p_mfc_dev *dev); int (*wakeup_cmd)(struct s5p_mfc_dev *dev); diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c index 327e54e706..82ee6d300c 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.c @@ -14,7 +14,7 @@ /* This function is used to send a command to the MFC */ static int s5p_mfc_cmd_host2risc_v5(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args) + const struct s5p_mfc_cmd_args *args) { int cur_cmd; unsigned long timeout; @@ -148,7 +148,7 @@ static int s5p_mfc_close_inst_cmd_v5(struct s5p_mfc_ctx *ctx) } /* Initialize cmd function pointers for MFC v5 */ -static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v5 = { +static const struct s5p_mfc_hw_cmds s5p_mfc_cmds_v5 = { .cmd_host2risc = s5p_mfc_cmd_host2risc_v5, .sys_init_cmd = s5p_mfc_sys_init_cmd_v5, .sleep_cmd = s5p_mfc_sleep_cmd_v5, @@ -157,7 +157,7 @@ static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v5 = { .close_inst_cmd = s5p_mfc_close_inst_cmd_v5, }; -struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void) +const struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void) { return &s5p_mfc_cmds_v5; } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h index 6eafa514ae..c626376053 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v5.h @@ -11,6 +11,6 @@ #include "s5p_mfc_common.h" -struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void); +const struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v5(void); #endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c index f8588e52df..47bc3014b5 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.c @@ -15,7 +15,7 @@ #include "s5p_mfc_cmd_v6.h" static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, - struct s5p_mfc_cmd_args *args) + const struct s5p_mfc_cmd_args *args) { mfc_debug(2, "Issue the command: %d\n", cmd); @@ -32,7 +32,7 @@ static int s5p_mfc_cmd_host2risc_v6(struct s5p_mfc_dev *dev, int cmd, static int s5p_mfc_sys_init_cmd_v6(struct s5p_mfc_dev *dev) { struct s5p_mfc_cmd_args h2r_args; - struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + const struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; int ret; ret = s5p_mfc_hw_call(dev->mfc_ops, alloc_dev_context_buffer, dev); @@ -154,7 +154,7 @@ static int s5p_mfc_close_inst_cmd_v6(struct s5p_mfc_ctx *ctx) } /* Initialize cmd function pointers for MFC v6 */ -static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v6 = { +static const struct s5p_mfc_hw_cmds s5p_mfc_cmds_v6 = { .cmd_host2risc = s5p_mfc_cmd_host2risc_v6, .sys_init_cmd = s5p_mfc_sys_init_cmd_v6, .sleep_cmd = s5p_mfc_sleep_cmd_v6, @@ -163,7 +163,7 @@ static struct s5p_mfc_hw_cmds s5p_mfc_cmds_v6 = { .close_inst_cmd = s5p_mfc_close_inst_cmd_v6, }; -struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void) +const struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void) { return &s5p_mfc_cmds_v6; } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h index 9dc44460cc..29083436f5 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_cmd_v6.h @@ -11,6 +11,6 @@ #include "s5p_mfc_common.h" -struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void); +const struct s5p_mfc_hw_cmds *s5p_mfc_init_hw_cmds_v6(void); #endif /* S5P_MFC_CMD_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h index 59450b324f..3cc2a4f5c4 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_common.h @@ -221,15 +221,15 @@ struct s5p_mfc_buf_size_v6 { struct s5p_mfc_buf_size { unsigned int fw; unsigned int cpb; - void *priv; + const void *priv; }; struct s5p_mfc_variant { unsigned int version; unsigned int port_num; u32 version_bit; - struct s5p_mfc_buf_size *buf_size; - char *fw_name[MFC_FW_MAX_VERSIONS]; + const struct s5p_mfc_buf_size *buf_size; + const char *fw_name[MFC_FW_MAX_VERSIONS]; const char *clk_names[MFC_MAX_CLOCKS]; int num_clocks; bool use_clock_gating; @@ -340,8 +340,8 @@ struct s5p_mfc_dev { struct s5p_mfc_priv_buf ctx_buf; int warn_start; - struct s5p_mfc_hw_ops *mfc_ops; - struct s5p_mfc_hw_cmds *mfc_cmds; + const struct s5p_mfc_hw_ops *mfc_ops; + const struct s5p_mfc_hw_cmds *mfc_cmds; const struct s5p_mfc_regs *mfc_regs; enum s5p_mfc_fw_ver fw_ver; bool fw_get_done; @@ -612,7 +612,6 @@ struct s5p_mfc_codec_ops { * @chroma_dpb_size: dpb buffer size for chroma * @me_buffer_size: size of the motion estimation buffer * @tmv_buffer_size: size of temporal predictor motion vector buffer - * @frame_type: used to force the type of the next encoded frame * @ref_queue: list of the reference buffers for encoding * @force_frame_type: encoder's frame type forcing control * @ref_queue_cnt: number of the buffers in the reference list @@ -639,8 +638,8 @@ struct s5p_mfc_ctx { unsigned int int_err; wait_queue_head_t queue; - struct s5p_mfc_fmt *src_fmt; - struct s5p_mfc_fmt *dst_fmt; + const struct s5p_mfc_fmt *src_fmt; + const struct s5p_mfc_fmt *dst_fmt; struct vb2_queue vq_src; struct vb2_queue vq_dst; diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c index 503487f34a..625d77b2be 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_ctrl.c @@ -221,7 +221,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) /* 0. MFC reset */ mfc_debug(2, "MFC reset..\n"); - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); dev->risc_on = 0; ret = s5p_mfc_reset(dev); if (ret) { @@ -249,7 +249,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) { mfc_err("Failed to load firmware\n"); s5p_mfc_reset(dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); return -EIO; } s5p_mfc_clean_dev_int_flags(dev); @@ -258,14 +258,14 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) if (ret) { mfc_err("Failed to send command to MFC - timeout\n"); s5p_mfc_reset(dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); return ret; } mfc_debug(2, "Ok, now will wait for completion of hardware init\n"); if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_SYS_INIT_RET)) { mfc_err("Failed to init hardware\n"); s5p_mfc_reset(dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); return -EIO; } dev->int_cond = 0; @@ -275,7 +275,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) mfc_err("Failed to init firmware - error: %d int: %d\n", dev->int_err, dev->int_type); s5p_mfc_reset(dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); return -EIO; } if (IS_MFCV6_PLUS(dev)) @@ -285,7 +285,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) mfc_debug(2, "MFC F/W version : %02xyy, %02xmm, %02xdd\n", (ver >> 16) & 0xFF, (ver >> 8) & 0xFF, ver & 0xFF); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); mfc_debug_leave(); return 0; } @@ -294,12 +294,12 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev) /* Deinitialize hardware */ void s5p_mfc_deinit_hw(struct s5p_mfc_dev *dev) { - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); s5p_mfc_reset(dev); s5p_mfc_hw_call(dev->mfc_ops, release_dev_context_buffer, dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); } int s5p_mfc_sleep(struct s5p_mfc_dev *dev) @@ -307,7 +307,7 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) int ret; mfc_debug_enter(); - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); s5p_mfc_clean_dev_int_flags(dev); ret = s5p_mfc_hw_call(dev->mfc_cmds, sleep_cmd, dev); if (ret) { @@ -318,7 +318,7 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev) mfc_err("Failed to sleep\n"); return -EIO; } - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); dev->int_cond = 0; if (dev->int_err != 0 || dev->int_type != S5P_MFC_R2H_CMD_SLEEP_RET) { @@ -390,12 +390,12 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) mfc_debug_enter(); /* 0. MFC reset */ mfc_debug(2, "MFC reset..\n"); - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); dev->risc_on = 0; ret = s5p_mfc_reset(dev); if (ret) { mfc_err("Failed to reset MFC - timeout\n"); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); return ret; } mfc_debug(2, "Done MFC reset..\n"); @@ -410,7 +410,7 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev) else ret = s5p_mfc_wait_wakeup(dev); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); if (ret) return ret; diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c index 3957f28d45..91e102d4ec 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.c @@ -27,7 +27,7 @@ #include "s5p_mfc_opr.h" #include "s5p_mfc_pm.h" -static struct s5p_mfc_fmt formats[] = { +static const struct s5p_mfc_fmt formats[] = { { .fourcc = V4L2_PIX_FMT_NV12MT_16X16, .codec_mode = S5P_MFC_CODEC_NONE, @@ -177,7 +177,7 @@ static struct s5p_mfc_fmt formats[] = { #define NUM_FORMATS ARRAY_SIZE(formats) /* Find selected format description */ -static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) +static const struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) { unsigned int i; @@ -406,7 +406,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_fmt *fmt; + const struct s5p_mfc_fmt *fmt; mfc_debug(2, "Type is %d\n", f->type); if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) { @@ -445,7 +445,7 @@ static int vidioc_s_fmt(struct file *file, void *priv, struct v4l2_format *f) struct s5p_mfc_ctx *ctx = fh_to_ctx(priv); int ret = 0; struct v4l2_pix_format_mplane *pix_mp; - struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; + const struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; mfc_debug_enter(); ret = vidioc_try_fmt(file, priv, f); @@ -496,7 +496,7 @@ static int reqbufs_output(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, { int ret = 0; - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); if (reqbufs->count == 0) { mfc_debug(2, "Freeing buffers\n"); @@ -533,7 +533,7 @@ static int reqbufs_output(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, ret = -EINVAL; } out: - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); if (ret) mfc_err("Failed allocating buffers for OUTPUT queue\n"); return ret; @@ -544,7 +544,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, { int ret = 0; - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); if (reqbufs->count == 0) { mfc_debug(2, "Freeing buffers\n"); @@ -587,7 +587,7 @@ static int reqbufs_capture(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx, ret = -EINVAL; } out: - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); if (ret) mfc_err("Failed allocating buffers for CAPTURE queue\n"); return ret; @@ -1159,7 +1159,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } -static struct vb2_ops s5p_mfc_dec_qops = { +static const struct vb2_ops s5p_mfc_dec_qops = { .queue_setup = s5p_mfc_queue_setup, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, @@ -1174,7 +1174,7 @@ const struct s5p_mfc_codec_ops *get_dec_codec_ops(void) return &decoder_codec_ops; } -struct vb2_ops *get_dec_queue_ops(void) +const struct vb2_ops *get_dec_queue_ops(void) { return &s5p_mfc_dec_qops; } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.h index 0c52ab46cf..47a6eb9a8f 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_dec.h @@ -10,9 +10,8 @@ #define S5P_MFC_DEC_H_ const struct s5p_mfc_codec_ops *get_dec_codec_ops(void); -struct vb2_ops *get_dec_queue_ops(void); +const struct vb2_ops *get_dec_queue_ops(void); const struct v4l2_ioctl_ops *get_dec_v4l2_ioctl_ops(void); -struct s5p_mfc_fmt *get_dec_def_fmt(bool src); int s5p_mfc_dec_ctrls_setup(struct s5p_mfc_ctx *ctx); void s5p_mfc_dec_ctrls_delete(struct s5p_mfc_ctx *ctx); void s5p_mfc_dec_init(struct s5p_mfc_ctx *ctx); diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c index ef8bb40b97..81cbb36fb3 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.c @@ -30,7 +30,7 @@ #define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12M #define DEF_DST_FMT_ENC V4L2_PIX_FMT_H264 -static struct s5p_mfc_fmt formats[] = { +static const struct s5p_mfc_fmt formats[] = { { .fourcc = V4L2_PIX_FMT_NV12MT_16X16, .codec_mode = S5P_MFC_CODEC_NONE, @@ -111,7 +111,7 @@ static struct s5p_mfc_fmt formats[] = { }; #define NUM_FORMATS ARRAY_SIZE(formats) -static struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) +static const struct s5p_mfc_fmt *find_format(struct v4l2_format *f, unsigned int t) { unsigned int i; @@ -1431,7 +1431,7 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f) static int vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f) { struct s5p_mfc_dev *dev = video_drvdata(file); - struct s5p_mfc_fmt *fmt; + const struct s5p_mfc_fmt *fmt; struct v4l2_pix_format_mplane *pix_fmt_mp = &f->fmt.pix_mp; if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) { @@ -2392,7 +2392,7 @@ static const struct v4l2_ioctl_ops s5p_mfc_enc_ioctl_ops = { .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; -static int check_vb_with_fmt(struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) +static int check_vb_with_fmt(const struct s5p_mfc_fmt *fmt, struct vb2_buffer *vb) { int i; @@ -2650,7 +2650,7 @@ static void s5p_mfc_buf_queue(struct vb2_buffer *vb) s5p_mfc_hw_call(dev->mfc_ops, try_run, dev); } -static struct vb2_ops s5p_mfc_enc_qops = { +static const struct vb2_ops s5p_mfc_enc_qops = { .queue_setup = s5p_mfc_queue_setup, .wait_prepare = vb2_ops_wait_prepare, .wait_finish = vb2_ops_wait_finish, @@ -2666,7 +2666,7 @@ const struct s5p_mfc_codec_ops *get_enc_codec_ops(void) return &encoder_codec_ops; } -struct vb2_ops *get_enc_queue_ops(void) +const struct vb2_ops *get_enc_queue_ops(void) { return &s5p_mfc_enc_qops; } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.h index 3f1b1a037a..62d6db67fd 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_enc.h @@ -10,9 +10,8 @@ #define S5P_MFC_ENC_H_ const struct s5p_mfc_codec_ops *get_enc_codec_ops(void); -struct vb2_ops *get_enc_queue_ops(void); +const struct vb2_ops *get_enc_queue_ops(void); const struct v4l2_ioctl_ops *get_enc_v4l2_ioctl_ops(void); -struct s5p_mfc_fmt *get_enc_def_fmt(bool src); int s5p_mfc_enc_ctrls_setup(struct s5p_mfc_ctx *ctx); void s5p_mfc_enc_ctrls_delete(struct s5p_mfc_ctx *ctx); void s5p_mfc_enc_init(struct s5p_mfc_ctx *ctx); diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.c index 6739623011..5ba791fa36 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr.c @@ -14,18 +14,15 @@ #include "s5p_mfc_opr_v5.h" #include "s5p_mfc_opr_v6.h" -static struct s5p_mfc_hw_ops *s5p_mfc_ops; - void s5p_mfc_init_hw_ops(struct s5p_mfc_dev *dev) { if (IS_MFCV6_PLUS(dev)) { - s5p_mfc_ops = s5p_mfc_init_hw_ops_v6(); + dev->mfc_ops = s5p_mfc_init_hw_ops_v6(); dev->warn_start = S5P_FIMV_ERR_WARNINGS_START_V6; } else { - s5p_mfc_ops = s5p_mfc_init_hw_ops_v5(); + dev->mfc_ops = s5p_mfc_init_hw_ops_v5(); dev->warn_start = S5P_FIMV_ERR_WARNINGS_START; } - dev->mfc_ops = s5p_mfc_ops; } void s5p_mfc_init_regs(struct s5p_mfc_dev *dev) diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c index fcfaf125a5..365f552e60 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.c @@ -34,7 +34,7 @@ static int s5p_mfc_alloc_dec_temp_buffers_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + const struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; int ret; ctx->dsc.size = buf_size->dsc; @@ -200,7 +200,7 @@ static void s5p_mfc_release_codec_buffers_v5(struct s5p_mfc_ctx *ctx) static int s5p_mfc_alloc_instance_buffer_v5(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + const struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; int ret; if (ctx->codec_mode == S5P_MFC_CODEC_H264_DEC || @@ -345,7 +345,7 @@ static void s5p_mfc_enc_calc_src_size_v5(struct s5p_mfc_ctx *ctx) static void s5p_mfc_set_dec_desc_buffer(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; + const struct s5p_mfc_buf_size_v5 *buf_size = dev->variant->buf_size->priv; mfc_write(dev, OFFSETA(ctx->dsc.dma), S5P_FIMV_SI_CH0_DESC_ADR); mfc_write(dev, buf_size->dsc, S5P_FIMV_SI_CH0_DESC_SIZE); @@ -676,7 +676,7 @@ static int s5p_mfc_set_enc_ref_buffer_v5(struct s5p_mfc_ctx *ctx) static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; + const struct s5p_mfc_enc_params *p = &ctx->enc_params; unsigned int reg; unsigned int shm; @@ -759,8 +759,8 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; + const struct s5p_mfc_enc_params *p = &ctx->enc_params; + const struct s5p_mfc_h264_enc_params *p_264 = &p->codec.h264; unsigned int reg; unsigned int shm; @@ -916,8 +916,8 @@ static int s5p_mfc_set_enc_params_h264(struct s5p_mfc_ctx *ctx) static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; + const struct s5p_mfc_enc_params *p = &ctx->enc_params; + const struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; unsigned int reg; unsigned int shm; unsigned int framerate; @@ -995,8 +995,8 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; + const struct s5p_mfc_enc_params *p = &ctx->enc_params; + const struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; unsigned int reg; unsigned int shm; @@ -1348,7 +1348,7 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) * Last frame has already been sent to MFC. * Now obtaining frames from MFC buffer */ - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); s5p_mfc_clean_ctx_int_flags(ctx); if (ctx->type == MFCINST_DECODER) { @@ -1424,7 +1424,7 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev) * scheduled, reduce the clock count as no one will * ever do this, because no interrupt related to this try_run * will ever come from hardware. */ - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); } } @@ -1593,7 +1593,7 @@ static unsigned int s5p_mfc_get_crop_info_v_v5(struct s5p_mfc_ctx *ctx) } /* Initialize opr function pointers for MFC v5 */ -static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { +static const struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v5, .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v5, .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v5, @@ -1633,7 +1633,7 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v5 = { .get_crop_info_v = s5p_mfc_get_crop_info_v_v5, }; -struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void) +const struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void) { return &s5p_mfc_ops_v5; } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.h index b53d376ead..0b98c61967 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v5.h @@ -78,5 +78,5 @@ enum MFC_SHM_OFS { FRAME_PACK_SEI_INFO = 0x17c, /* E */ }; -struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void); +const struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v5(void); #endif /* S5P_MFC_OPR_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c index fd945211d2..73f7af674c 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.c @@ -383,7 +383,7 @@ static void s5p_mfc_release_codec_buffers_v6(struct s5p_mfc_ctx *ctx) static int s5p_mfc_alloc_instance_buffer_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; - struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + const struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; int ret; mfc_debug_enter(); @@ -443,7 +443,7 @@ static void s5p_mfc_release_instance_buffer_v6(struct s5p_mfc_ctx *ctx) /* Allocate context buffers for SYS_INIT */ static int s5p_mfc_alloc_dev_context_buffer_v6(struct s5p_mfc_dev *dev) { - struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; + const struct s5p_mfc_buf_size_v6 *buf_size = dev->variant->buf_size->priv; int ret; mfc_debug_enter(); @@ -587,7 +587,7 @@ static int s5p_mfc_set_dec_stream_buffer_v6(struct s5p_mfc_ctx *ctx, { struct s5p_mfc_dev *dev = ctx->dev; const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; + const struct s5p_mfc_buf_size *buf_size = dev->variant->buf_size; mfc_debug_enter(); mfc_debug(2, "inst_no: %d, buf_addr: 0x%08x,\n" @@ -863,7 +863,7 @@ static int s5p_mfc_set_enc_params(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; + const struct s5p_mfc_enc_params *p = &ctx->enc_params; unsigned int reg = 0; mfc_debug_enter(); @@ -1349,8 +1349,8 @@ static int s5p_mfc_set_enc_params_mpeg4(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; + const struct s5p_mfc_enc_params *p = &ctx->enc_params; + const struct s5p_mfc_mpeg4_enc_params *p_mpeg4 = &p->codec.mpeg4; unsigned int reg = 0; mfc_debug_enter(); @@ -1431,8 +1431,8 @@ static int s5p_mfc_set_enc_params_h263(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; + const struct s5p_mfc_enc_params *p = &ctx->enc_params; + const struct s5p_mfc_mpeg4_enc_params *p_h263 = &p->codec.mpeg4; unsigned int reg = 0; mfc_debug_enter(); @@ -1501,8 +1501,8 @@ static int s5p_mfc_set_enc_params_vp8(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_vp8_enc_params *p_vp8 = &p->codec.vp8; + const struct s5p_mfc_enc_params *p = &ctx->enc_params; + const struct s5p_mfc_vp8_enc_params *p_vp8 = &p->codec.vp8; unsigned int reg = 0; unsigned int val = 0; @@ -1897,8 +1897,8 @@ static int s5p_mfc_h264_set_aso_slice_order_v6(struct s5p_mfc_ctx *ctx) { struct s5p_mfc_dev *dev = ctx->dev; const struct s5p_mfc_regs *mfc_regs = dev->mfc_regs; - struct s5p_mfc_enc_params *p = &ctx->enc_params; - struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; + const struct s5p_mfc_enc_params *p = &ctx->enc_params; + const struct s5p_mfc_h264_enc_params *p_h264 = &p->codec.h264; int i; if (p_h264->aso) { @@ -2165,7 +2165,7 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) /* Last frame has already been sent to MFC * Now obtaining frames from MFC buffer */ - s5p_mfc_clock_on(); + s5p_mfc_clock_on(dev); s5p_mfc_clean_ctx_int_flags(ctx); if (ctx->type == MFCINST_DECODER) { @@ -2245,7 +2245,7 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev) * scheduled, reduce the clock count as no one will * ever do this, because no interrupt related to this try_run * will ever come from hardware. */ - s5p_mfc_clock_off(); + s5p_mfc_clock_off(dev); } } @@ -2261,9 +2261,9 @@ s5p_mfc_read_info_v6(struct s5p_mfc_ctx *ctx, unsigned long ofs) { int ret; - s5p_mfc_clock_on(); + s5p_mfc_clock_on(ctx->dev); ret = readl((void __iomem *)ofs); - s5p_mfc_clock_off(); + s5p_mfc_clock_off(ctx->dev); return ret; } @@ -2657,7 +2657,7 @@ done: } /* Initialize opr function pointers for MFC v6 */ -static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { +static const struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { .alloc_dec_temp_buffers = s5p_mfc_alloc_dec_temp_buffers_v6, .release_dec_desc_buffer = s5p_mfc_release_dec_desc_buffer_v6, .alloc_codec_buffers = s5p_mfc_alloc_codec_buffers_v6, @@ -2701,7 +2701,7 @@ static struct s5p_mfc_hw_ops s5p_mfc_ops_v6 = { .get_e_min_scratch_buf_size = s5p_mfc_get_e_min_scratch_buf_size, }; -struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) +const struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void) { return &s5p_mfc_ops_v6; } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h index 94ecb0e6e7..7fc1307675 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_opr_v6.h @@ -51,6 +51,6 @@ #define FRAME_DELTA_DEFAULT 1 -struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); +const struct s5p_mfc_hw_ops *s5p_mfc_init_hw_ops_v6(void); const struct s5p_mfc_regs *s5p_mfc_init_regs_v6_plus(struct s5p_mfc_dev *dev); #endif /* S5P_MFC_OPR_V6_H_ */ diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c index 187849841a..ae42414083 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.c @@ -14,17 +14,11 @@ #include "s5p_mfc_debug.h" #include "s5p_mfc_pm.h" -static struct s5p_mfc_pm *pm; -static struct s5p_mfc_dev *p_dev; -static atomic_t clk_ref; - int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) { + struct s5p_mfc_pm *pm = &dev->pm; int i; - pm = &dev->pm; - p_dev = dev; - pm->num_clocks = dev->variant->num_clocks; pm->clk_names = dev->variant->clk_names; pm->device = &dev->plat_dev->dev; @@ -49,70 +43,63 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev) pm->clock_gate = pm->clocks[0]; pm_runtime_enable(pm->device); - atomic_set(&clk_ref, 0); return 0; } void s5p_mfc_final_pm(struct s5p_mfc_dev *dev) { - pm_runtime_disable(pm->device); + pm_runtime_disable(dev->pm.device); } -int s5p_mfc_clock_on(void) +int s5p_mfc_clock_on(struct s5p_mfc_dev *dev) { - atomic_inc(&clk_ref); - mfc_debug(3, "+ %d\n", atomic_read(&clk_ref)); - - return clk_enable(pm->clock_gate); + return clk_enable(dev->pm.clock_gate); } -void s5p_mfc_clock_off(void) +void s5p_mfc_clock_off(struct s5p_mfc_dev *dev) { - atomic_dec(&clk_ref); - mfc_debug(3, "- %d\n", atomic_read(&clk_ref)); - - clk_disable(pm->clock_gate); + clk_disable(dev->pm.clock_gate); } -int s5p_mfc_power_on(void) +int s5p_mfc_power_on(struct s5p_mfc_dev *dev) { int i, ret = 0; - ret = pm_runtime_resume_and_get(pm->device); + ret = pm_runtime_resume_and_get(dev->pm.device); if (ret < 0) return ret; /* clock control */ - for (i = 0; i < pm->num_clocks; i++) { - ret = clk_prepare_enable(pm->clocks[i]); + for (i = 0; i < dev->pm.num_clocks; i++) { + ret = clk_prepare_enable(dev->pm.clocks[i]); if (ret < 0) { mfc_err("clock prepare failed for clock: %s\n", - pm->clk_names[i]); + dev->pm.clk_names[i]); goto err; } } /* prepare for software clock gating */ - clk_disable(pm->clock_gate); + clk_disable(dev->pm.clock_gate); return 0; err: while (--i >= 0) - clk_disable_unprepare(pm->clocks[i]); - pm_runtime_put(pm->device); + clk_disable_unprepare(dev->pm.clocks[i]); + pm_runtime_put(dev->pm.device); return ret; } -int s5p_mfc_power_off(void) +int s5p_mfc_power_off(struct s5p_mfc_dev *dev) { int i; /* finish software clock gating */ - clk_enable(pm->clock_gate); + clk_enable(dev->pm.clock_gate); - for (i = 0; i < pm->num_clocks; i++) - clk_disable_unprepare(pm->clocks[i]); + for (i = 0; i < dev->pm.num_clocks; i++) + clk_disable_unprepare(dev->pm.clocks[i]); - return pm_runtime_put_sync(pm->device); + return pm_runtime_put_sync(dev->pm.device); } diff --git a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.h b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.h index 4159d2364e..9c71036f03 100644 --- a/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.h +++ b/drivers/media/platform/samsung/s5p-mfc/s5p_mfc_pm.h @@ -12,9 +12,9 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev); void s5p_mfc_final_pm(struct s5p_mfc_dev *dev); -int s5p_mfc_clock_on(void); -void s5p_mfc_clock_off(void); -int s5p_mfc_power_on(void); -int s5p_mfc_power_off(void); +int s5p_mfc_clock_on(struct s5p_mfc_dev *dev); +void s5p_mfc_clock_off(struct s5p_mfc_dev *dev); +int s5p_mfc_power_on(struct s5p_mfc_dev *dev); +int s5p_mfc_power_off(struct s5p_mfc_dev *dev); #endif /* S5P_MFC_PM_H_ */ diff --git a/drivers/media/platform/st/stm32/stm32-dcmi.c b/drivers/media/platform/st/stm32/stm32-dcmi.c index c4610e3055..ff3331af94 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmi.c +++ b/drivers/media/platform/st/stm32/stm32-dcmi.c @@ -1855,7 +1855,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi) struct device_node *ep; int ret; - ep = of_graph_get_next_endpoint(dcmi->dev->of_node, NULL); + ep = of_graph_get_endpoint_by_regs(dcmi->dev->of_node, 0, -1); if (!ep) { dev_err(dcmi->dev, "Failed to get next endpoint\n"); return -EINVAL; @@ -1907,7 +1907,7 @@ static int dcmi_probe(struct platform_device *pdev) "Could not get reset control\n"); /* Get bus characteristics from devicetree */ - np = of_graph_get_next_endpoint(np, NULL); + np = of_graph_get_endpoint_by_regs(np, 0, -1); if (!np) { dev_err(&pdev->dev, "Could not find the endpoint\n"); return -ENODEV; diff --git a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c index 32c6619be9..bce821eb71 100644 --- a/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c +++ b/drivers/media/platform/st/stm32/stm32-dcmipp/dcmipp-core.c @@ -517,7 +517,7 @@ static int dcmipp_probe(struct platform_device *pdev) return 0; } -static int dcmipp_remove(struct platform_device *pdev) +static void dcmipp_remove(struct platform_device *pdev) { struct dcmipp_device *dcmipp = platform_get_drvdata(pdev); unsigned int i; @@ -534,8 +534,6 @@ static int dcmipp_remove(struct platform_device *pdev) media_device_cleanup(&dcmipp->mdev); v4l2_device_unregister(&dcmipp->v4l2_dev); - - return 0; } static int dcmipp_runtime_suspend(struct device *dev) @@ -588,7 +586,7 @@ static const struct dev_pm_ops dcmipp_pm_ops = { static struct platform_driver dcmipp_pdrv = { .probe = dcmipp_probe, - .remove = dcmipp_remove, + .remove_new = dcmipp_remove, .driver = { .name = DCMIPP_PDEV_NAME, .of_match_table = dcmipp_of_match, diff --git a/drivers/media/platform/ti/davinci/vpif.c b/drivers/media/platform/ti/davinci/vpif.c index 63cdfed37b..f4e1fa76bf 100644 --- a/drivers/media/platform/ti/davinci/vpif.c +++ b/drivers/media/platform/ti/davinci/vpif.c @@ -465,8 +465,7 @@ static int vpif_probe(struct platform_device *pdev) * so their devices need to be registered manually here * for their legacy platform_drivers to work. */ - endpoint = of_graph_get_next_endpoint(pdev->dev.of_node, - endpoint); + endpoint = of_graph_get_endpoint_by_regs(pdev->dev.of_node, 0, -1); if (!endpoint) return 0; of_node_put(endpoint); diff --git a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c index 59b30fc431..6da83d0cff 100644 --- a/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c +++ b/drivers/media/platform/ti/j721e-csi2rx/j721e-csi2rx.c @@ -158,6 +158,12 @@ static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { .csi_dt = MIPI_CSI2_DT_RAW8, .bpp = 8, .size = SHIM_DMACNTX_SIZE_8, + }, { + .fourcc = V4L2_PIX_FMT_GREY, + .code = MEDIA_BUS_FMT_Y8_1X8, + .csi_dt = MIPI_CSI2_DT_RAW8, + .bpp = 8, + .size = SHIM_DMACNTX_SIZE_8, }, { .fourcc = V4L2_PIX_FMT_SBGGR10, .code = MEDIA_BUS_FMT_SBGGR10_1X10, @@ -182,6 +188,24 @@ static const struct ti_csi2rx_fmt ti_csi2rx_formats[] = { .csi_dt = MIPI_CSI2_DT_RAW10, .bpp = 16, .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_RGB565X, + .code = MEDIA_BUS_FMT_RGB565_1X16, + .csi_dt = MIPI_CSI2_DT_RGB565, + .bpp = 16, + .size = SHIM_DMACNTX_SIZE_16, + }, { + .fourcc = V4L2_PIX_FMT_XBGR32, + .code = MEDIA_BUS_FMT_RGB888_1X24, + .csi_dt = MIPI_CSI2_DT_RGB888, + .bpp = 32, + .size = SHIM_DMACNTX_SIZE_32, + }, { + .fourcc = V4L2_PIX_FMT_RGBX32, + .code = MEDIA_BUS_FMT_BGR888_1X24, + .csi_dt = MIPI_CSI2_DT_RGB888, + .bpp = 32, + .size = SHIM_DMACNTX_SIZE_32, }, /* More formats can be supported but they are not listed for now. */ @@ -1065,7 +1089,6 @@ static void ti_csi2rx_cleanup_vb2q(struct ti_csi2rx_dev *csi) static int ti_csi2rx_probe(struct platform_device *pdev) { struct ti_csi2rx_dev *csi; - struct resource *res; int ret; csi = devm_kzalloc(&pdev->dev, sizeof(*csi), GFP_KERNEL); @@ -1076,9 +1099,7 @@ static int ti_csi2rx_probe(struct platform_device *pdev) platform_set_drvdata(pdev, csi); mutex_init(&csi->mutex); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - csi->shim = devm_ioremap_resource(&pdev->dev, res); + csi->shim = devm_platform_ioremap_resource(pdev, 0); if (IS_ERR(csi->shim)) { ret = PTR_ERR(csi->shim); goto err_mutex; @@ -1121,7 +1142,7 @@ err_mutex: return ret; } -static int ti_csi2rx_remove(struct platform_device *pdev) +static void ti_csi2rx_remove(struct platform_device *pdev) { struct ti_csi2rx_dev *csi = platform_get_drvdata(pdev); @@ -1133,8 +1154,6 @@ static int ti_csi2rx_remove(struct platform_device *pdev) ti_csi2rx_cleanup_dma(csi); mutex_destroy(&csi->mutex); - - return 0; } static const struct of_device_id ti_csi2rx_of_match[] = { @@ -1145,7 +1164,7 @@ MODULE_DEVICE_TABLE(of, ti_csi2rx_of_match); static struct platform_driver ti_csi2rx_pdrv = { .probe = ti_csi2rx_probe, - .remove = ti_csi2rx_remove, + .remove_new = ti_csi2rx_remove, .driver = { .name = TI_CSI2RX_MODULE_NAME, .of_match_table = ti_csi2rx_of_match, diff --git a/drivers/media/platform/verisilicon/Kconfig b/drivers/media/platform/verisilicon/Kconfig index 24b927d8f1..9a34d14c6e 100644 --- a/drivers/media/platform/verisilicon/Kconfig +++ b/drivers/media/platform/verisilicon/Kconfig @@ -4,7 +4,7 @@ comment "Verisilicon media platform drivers" config VIDEO_HANTRO tristate "Hantro VPU driver" - depends on ARCH_MXC || ARCH_ROCKCHIP || ARCH_AT91 || ARCH_SUNXI || COMPILE_TEST + depends on ARCH_MXC || ARCH_ROCKCHIP || ARCH_AT91 || ARCH_SUNXI || ARCH_STM32 || COMPILE_TEST depends on V4L_MEM2MEM_DRIVERS depends on VIDEO_DEV select MEDIA_CONTROLLER @@ -15,8 +15,8 @@ config VIDEO_HANTRO select V4L2_VP9 help Support for the Hantro IP based Video Processing Units present on - Rockchip and NXP i.MX8M SoCs, which accelerate video and image - encoding and decoding. + Rockchip, NXP i.MX8M and STM32MP25 SoCs, which accelerate video + and image encoding and decoding. To compile this driver as a module, choose M here: the module will be called hantro-vpu. @@ -51,3 +51,11 @@ config VIDEO_HANTRO_SUNXI default y help Enable support for H6 SoC. + +config VIDEO_HANTRO_STM32MP25 + bool "Hantro STM32MP25 support" + depends on VIDEO_HANTRO + depends on ARCH_STM32 || COMPILE_TEST + default y + help + Enable support for STM32MP25 SoCs. diff --git a/drivers/media/platform/verisilicon/Makefile b/drivers/media/platform/verisilicon/Makefile index 6ad2ef8859..eb38a1833b 100644 --- a/drivers/media/platform/verisilicon/Makefile +++ b/drivers/media/platform/verisilicon/Makefile @@ -39,3 +39,6 @@ hantro-vpu-$(CONFIG_VIDEO_HANTRO_ROCKCHIP) += \ hantro-vpu-$(CONFIG_VIDEO_HANTRO_SUNXI) += \ sunxi_vpu_hw.o + +hantro-vpu-$(CONFIG_VIDEO_HANTRO_STM32MP25) += \ + stm32mp25_vpu_hw.o diff --git a/drivers/media/platform/verisilicon/hantro.h b/drivers/media/platform/verisilicon/hantro.h index 6f5eb975d0..811260dc3c 100644 --- a/drivers/media/platform/verisilicon/hantro.h +++ b/drivers/media/platform/verisilicon/hantro.h @@ -237,7 +237,6 @@ struct hantro_dev { * @codec_ops: Set of operations related to codec mode. * @postproc: Post-processing context. * @h264_dec: H.264-decoding context. - * @jpeg_enc: JPEG-encoding context. * @mpeg2_dec: MPEG-2-decoding context. * @vp8_dec: VP8-decoding context. * @hevc_dec: HEVC-decoding context. diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c index db3df6cc45..34b123dafd 100644 --- a/drivers/media/platform/verisilicon/hantro_drv.c +++ b/drivers/media/platform/verisilicon/hantro_drv.c @@ -735,6 +735,10 @@ static const struct of_device_id of_hantro_match[] = { #endif #ifdef CONFIG_VIDEO_HANTRO_SUNXI { .compatible = "allwinner,sun50i-h6-vpu-g2", .data = &sunxi_vpu_variant, }, +#endif +#ifdef CONFIG_VIDEO_HANTRO_STM32MP25 + { .compatible = "st,stm32mp25-vdec", .data = &stm32mp25_vdec_variant, }, + { .compatible = "st,stm32mp25-venc", .data = &stm32mp25_venc_variant, }, #endif { /* sentinel */ } }; diff --git a/drivers/media/platform/verisilicon/hantro_g1_h264_dec.c b/drivers/media/platform/verisilicon/hantro_g1_h264_dec.c index 9de7f05eff..ad5c1a6634 100644 --- a/drivers/media/platform/verisilicon/hantro_g1_h264_dec.c +++ b/drivers/media/platform/verisilicon/hantro_g1_h264_dec.c @@ -243,7 +243,7 @@ static void set_buffers(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) vdpu_write_relaxed(vpu, dst_dma + offset, G1_REG_ADDR_DIR_MV); } - /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */ + /* Auxiliary buffer prepared in hantro_h264_dec_init(). */ vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, G1_REG_ADDR_QTABLE); } diff --git a/drivers/media/platform/verisilicon/hantro_hw.h b/drivers/media/platform/verisilicon/hantro_hw.h index 9aec8a79ac..7737320cc8 100644 --- a/drivers/media/platform/verisilicon/hantro_hw.h +++ b/drivers/media/platform/verisilicon/hantro_hw.h @@ -408,6 +408,8 @@ extern const struct hantro_variant rk3568_vpu_variant; extern const struct hantro_variant rk3588_vpu981_variant; extern const struct hantro_variant sama5d4_vdec_variant; extern const struct hantro_variant sunxi_vpu_variant; +extern const struct hantro_variant stm32mp25_vdec_variant; +extern const struct hantro_variant stm32mp25_venc_variant; extern const struct hantro_postproc_ops hantro_g1_postproc_ops; extern const struct hantro_postproc_ops hantro_g2_postproc_ops; diff --git a/drivers/media/platform/verisilicon/rockchip_vpu2_hw_h264_dec.c b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_h264_dec.c index 46c1a83bcc..6da87f5184 100644 --- a/drivers/media/platform/verisilicon/rockchip_vpu2_hw_h264_dec.c +++ b/drivers/media/platform/verisilicon/rockchip_vpu2_hw_h264_dec.c @@ -460,7 +460,7 @@ static void set_buffers(struct hantro_ctx *ctx, struct vb2_v4l2_buffer *src_buf) vdpu_write_relaxed(vpu, dst_dma + offset, VDPU_REG_DIR_MV_BASE); } - /* Auxiliary buffer prepared in hantro_g1_h264_dec_prepare_table(). */ + /* Auxiliary buffer prepared in hantro_h264_dec_init(). */ vdpu_write_relaxed(vpu, ctx->h264_dec.priv.dma, VDPU_REG_QTABLE_BASE); } diff --git a/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h b/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h index 182e6c830f..850ff0f844 100644 --- a/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h +++ b/drivers/media/platform/verisilicon/rockchip_vpu981_regs.h @@ -118,7 +118,7 @@ #define av1_mcomp_filt_type AV1_DEC_REG(11, 8, 0x7) #define av1_multicore_expect_context_update AV1_DEC_REG(11, 11, 0x1) #define av1_multicore_sbx_offset AV1_DEC_REG(11, 12, 0x7f) -#define av1_ulticore_tile_col AV1_DEC_REG(11, 19, 0x7f) +#define av1_multicore_tile_col AV1_DEC_REG(11, 19, 0x7f) #define av1_transform_mode AV1_DEC_REG(11, 27, 0x7) #define av1_dec_tile_size_mag AV1_DEC_REG(11, 30, 0x3) diff --git a/drivers/media/platform/verisilicon/stm32mp25_vpu_hw.c b/drivers/media/platform/verisilicon/stm32mp25_vpu_hw.c new file mode 100644 index 0000000000..833821120b --- /dev/null +++ b/drivers/media/platform/verisilicon/stm32mp25_vpu_hw.c @@ -0,0 +1,186 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * STM32MP25 video codec driver + * + * Copyright (C) STMicroelectronics SA 2024 + * Authors: Hugues Fruchet + * for STMicroelectronics. + * + */ + +#include "hantro.h" +#include "hantro_jpeg.h" +#include "hantro_h1_regs.h" + +/* + * Supported formats. + */ + +static const struct hantro_fmt stm32mp25_vdec_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_NV12, + .codec_mode = HANTRO_MODE_NONE, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, + .step_height = MB_DIM, + }, + }, + { + .fourcc = V4L2_PIX_FMT_VP8_FRAME, + .codec_mode = HANTRO_MODE_VP8_DEC, + .max_depth = 2, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, + .step_height = MB_DIM, + }, + }, + { + .fourcc = V4L2_PIX_FMT_H264_SLICE, + .codec_mode = HANTRO_MODE_H264_DEC, + .max_depth = 2, + .frmsize = { + .min_width = FMT_MIN_WIDTH, + .max_width = FMT_FHD_WIDTH, + .step_width = MB_DIM, + .min_height = FMT_MIN_HEIGHT, + .max_height = FMT_FHD_HEIGHT, + .step_height = MB_DIM, + }, + }, +}; + +static const struct hantro_fmt stm32mp25_venc_fmts[] = { + { + .fourcc = V4L2_PIX_FMT_YUV420M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUV420P, + }, + { + .fourcc = V4L2_PIX_FMT_NV12M, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUV420SP, + }, + { + .fourcc = V4L2_PIX_FMT_YUYV, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = ROCKCHIP_VPU_ENC_FMT_YUYV422, + }, + { + .fourcc = V4L2_PIX_FMT_UYVY, + .codec_mode = HANTRO_MODE_NONE, + .enc_fmt = ROCKCHIP_VPU_ENC_FMT_UYVY422, + }, + { + .fourcc = V4L2_PIX_FMT_JPEG, + .codec_mode = HANTRO_MODE_JPEG_ENC, + .max_depth = 2, + .header_size = JPEG_HEADER_SIZE, + .frmsize = { + .min_width = 96, + .max_width = FMT_4K_WIDTH, + .step_width = MB_DIM, + .min_height = 96, + .max_height = FMT_4K_HEIGHT, + .step_height = MB_DIM, + }, + }, +}; + +static irqreturn_t stm32mp25_venc_irq(int irq, void *dev_id) +{ + struct hantro_dev *vpu = dev_id; + enum vb2_buffer_state state; + u32 status; + + status = vepu_read(vpu, H1_REG_INTERRUPT); + state = (status & H1_REG_INTERRUPT_FRAME_RDY) ? + VB2_BUF_STATE_DONE : VB2_BUF_STATE_ERROR; + + vepu_write(vpu, H1_REG_INTERRUPT_BIT, H1_REG_INTERRUPT); + + hantro_irq_done(vpu, state); + + return IRQ_HANDLED; +} + +static void stm32mp25_venc_reset(struct hantro_ctx *ctx) +{ + struct hantro_dev *vpu = ctx->dev; + + reset_control_reset(vpu->resets); +} + +/* + * Supported codec ops. + */ + +static const struct hantro_codec_ops stm32mp25_vdec_codec_ops[] = { + [HANTRO_MODE_VP8_DEC] = { + .run = hantro_g1_vp8_dec_run, + .reset = hantro_g1_reset, + .init = hantro_vp8_dec_init, + .exit = hantro_vp8_dec_exit, + }, + [HANTRO_MODE_H264_DEC] = { + .run = hantro_g1_h264_dec_run, + .reset = hantro_g1_reset, + .init = hantro_h264_dec_init, + .exit = hantro_h264_dec_exit, + }, +}; + +static const struct hantro_codec_ops stm32mp25_venc_codec_ops[] = { + [HANTRO_MODE_JPEG_ENC] = { + .run = hantro_h1_jpeg_enc_run, + .reset = stm32mp25_venc_reset, + .done = hantro_h1_jpeg_enc_done, + }, +}; + +/* + * Variants. + */ + +static const struct hantro_irq stm32mp25_vdec_irqs[] = { + { "vdec", hantro_g1_irq }, +}; + +static const char * const stm32mp25_vdec_clk_names[] = { "vdec-clk" }; + +const struct hantro_variant stm32mp25_vdec_variant = { + .dec_fmts = stm32mp25_vdec_fmts, + .num_dec_fmts = ARRAY_SIZE(stm32mp25_vdec_fmts), + .codec = HANTRO_VP8_DECODER | HANTRO_H264_DECODER, + .codec_ops = stm32mp25_vdec_codec_ops, + .irqs = stm32mp25_vdec_irqs, + .num_irqs = ARRAY_SIZE(stm32mp25_vdec_irqs), + .clk_names = stm32mp25_vdec_clk_names, + .num_clocks = ARRAY_SIZE(stm32mp25_vdec_clk_names), +}; + +static const struct hantro_irq stm32mp25_venc_irqs[] = { + { "venc", stm32mp25_venc_irq }, +}; + +static const char * const stm32mp25_venc_clk_names[] = { + "venc-clk" +}; + +const struct hantro_variant stm32mp25_venc_variant = { + .enc_fmts = stm32mp25_venc_fmts, + .num_enc_fmts = ARRAY_SIZE(stm32mp25_venc_fmts), + .codec = HANTRO_JPEG_ENCODER, + .codec_ops = stm32mp25_venc_codec_ops, + .irqs = stm32mp25_venc_irqs, + .num_irqs = ARRAY_SIZE(stm32mp25_venc_irqs), + .clk_names = stm32mp25_venc_clk_names, + .num_clocks = ARRAY_SIZE(stm32mp25_venc_clk_names) +}; diff --git a/drivers/media/platform/xilinx/Kconfig b/drivers/media/platform/xilinx/Kconfig index 93ef78bf62..601edd9acd 100644 --- a/drivers/media/platform/xilinx/Kconfig +++ b/drivers/media/platform/xilinx/Kconfig @@ -26,10 +26,10 @@ config VIDEO_XILINX_TPG depends on VIDEO_XILINX select VIDEO_XILINX_VTC help - Driver for the Xilinx Video Test Pattern Generator + Driver for the Xilinx Video Test Pattern Generator config VIDEO_XILINX_VTC tristate "Xilinx Video Timing Controller" depends on VIDEO_XILINX help - Driver for the Xilinx Video Timing Controller + Driver for the Xilinx Video Timing Controller -- cgit v1.2.3