// SPDX-License-Identifier: GPL-2.0 /* * drivers/video/rockchip/video/vehicle_cif.c * * mipi_dphy/csi_host/vicap driver for vehicle * * Copyright (C) 2022 Rockchip Electronics Co., Ltd. * Authors: * Jianwei Fan * */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "vehicle-csi2-dphy-common.h" #include "vehicle_cif.h" #include "vehicle_flinger.h" #include "vehicle_main.h" #include #include #include #include #include #include #include #include #include #include "vehicle_samsung_dcphy_common.h" #define CIF_DG VEHICLE_DG #define CIF_ERR VEHICLE_DGERR static struct vehicle_cif *g_cif; #define write_reg(base, addr, val) \ writel(val, (addr) + (base)) #define read_reg(base, addr) \ readl((addr) + (base)) #define vehicle_write_csihost_reg(base, addr, val) write_reg(base, addr, val) #define vehicle_read_csihost_reg(base, addr) read_reg(base, addr) //define cif clk and rst static const char * const rk3568_cif_clks[] = { "aclk_cif", "hclk_cif", "dclk_cif", "iclk_cif_g", }; static const char * const rk3568_cif_rsts[] = { "rst_cif_a", "rst_cif_h", "rst_cif_d", "rst_cif_p", "rst_cif_i", }; static const char * const rk3588_cif_clks[] = { "aclk_cif", "hclk_cif", "dclk_cif", }; static const char * const rk3588_cif_rsts[] = { "rst_cif_a", "rst_cif_h", "rst_cif_d", }; static const char * const rk3562_cif_clks[] = { "aclk_cif", "hclk_cif", "dclk_cif", "csirx0_data", "csirx1_data", "csirx2_data", "csirx3_data", }; static const char * const rk3562_cif_rsts[] = { "rst_cif_a", "rst_cif_h", "rst_cif_d", "rst_cif_i0", "rst_cif_i1", "rst_cif_i2", "rst_cif_i3", }; static const char * const rk3576_cif_clks[] = { "aclk_cif", "hclk_cif", "dclk_cif", "i0clk_cif", "i1clk_cif", "i2clk_cif", "i3clk_cif", "i4clk_cif", }; static const char * const rk3576_cif_rsts[] = { "rst_cif_a", "rst_cif_h", "rst_cif_d", "rst_cif_iclk0", "rst_cif_iclk1", "rst_cif_iclk2", "rst_cif_iclk3", "rst_cif_iclk4", }; //define dphy and csi clks/rst static struct clk_bulk_data rk3568_csi2_dphy_hw_clks[] = { { .id = "pclk" }, }; static struct clk_bulk_data rk3568_csi2_clks[] = { { .id = "pclk_csi2host" }, }; static const char * const rk3568_csi2_rsts[] = { "srst_csihost_p", }; static struct clk_bulk_data rk3588_csi2_dphy_hw_clks[] = { { .id = "pclk" }, }; static const char * const rk3588_csi2_dphy_hw_rsts[] = { "srst_csiphy", "srst_p_csiphy", }; static struct clk_bulk_data rk3588_csi2_clks[] = { { .id = "pclk_csi2host" }, }; static struct clk_bulk_data rk3588_csi2_dcphy_clks[] = { { .id = "pclk_csi2host" }, { .id = "iclk_csi2host" }, }; static const char * const rk3588_csi2_rsts[] = { "srst_csihost_p", "srst_csihost_vicap", }; static struct clk_bulk_data rk3562_csi2_dphy_hw_clks[] = { { .id = "pclk" }, }; static const char * const rk3562_csi2_dphy_hw_rsts[] = { "srst_p_csiphy", }; static struct clk_bulk_data rk3562_csi2_clks[] = { { .id = "pclk_csi2host" }, }; static const char * const rk3562_csi2_rsts[] = { "srst_csihost_p", }; static struct clk_bulk_data rk3576_csi2_dphy_hw_clks[] = { { .id = "pclk" }, }; static const char * const rk3576_csi2_dphy_hw_rsts[] = { "srst_p_csiphy", }; static struct clk_bulk_data rk3576_csi2_clks[] = { { .id = "pclk_csi2host" }, }; static struct clk_bulk_data rk3576_csi2_dcphy_clks[] = { { .id = "pclk_csi2host" }, { .id = "iclk_csi2host" }, }; static const char * const rk3576_csi2_rsts[] = { "srst_csihost_p", }; //define cif regs static const struct vehicle_cif_reg rk3568_cif_regs[] = { [CIF_REG_DVP_CTRL] = CIF_REG_NAME(CIF_CTRL, "CIF_REG_DVP_CTRL"), [CIF_REG_DVP_INTEN] = CIF_REG_NAME(CIF_INTEN, "CIF_REG_DVP_INTEN"), [CIF_REG_DVP_INTSTAT] = CIF_REG_NAME(CIF_INTSTAT, "CIF_REG_DVP_INTSTAT"), [CIF_REG_DVP_FOR] = CIF_REG_NAME(CIF_FOR, "CIF_REG_DVP_FOR"), [CIF_REG_DVP_MULTI_ID] = CIF_REG_NAME(CIF_MULTI_ID, "CIF_REG_DVP_MULTI_ID"), [CIF_REG_DVP_FRM0_ADDR_Y] = CIF_REG_NAME(CIF_FRM0_ADDR_Y, "CIF_REG_DVP_FRM0_ADDR_Y"), [CIF_REG_DVP_FRM0_ADDR_UV] = CIF_REG_NAME(CIF_FRM0_ADDR_UV, "CIF_REG_DVP_FRM0_ADDR_UV"), [CIF_REG_DVP_FRM1_ADDR_Y] = CIF_REG_NAME(CIF_FRM1_ADDR_Y, "CIF_REG_DVP_FRM1_ADDR_Y"), [CIF_REG_DVP_FRM1_ADDR_UV] = CIF_REG_NAME(CIF_FRM1_ADDR_UV, "CIF_REG_DVP_FRM1_ADDR_UV"), [CIF_REG_DVP_VIR_LINE_WIDTH] = CIF_REG_NAME(CIF_VIR_LINE_WIDTH, "CIF_REG_DVP_VIR_LINE_WIDTH"), [CIF_REG_DVP_SET_SIZE] = CIF_REG_NAME(CIF_SET_SIZE, "CIF_REG_DVP_SET_SIZE"), [CIF_REG_DVP_LINE_INT_NUM] = CIF_REG_NAME(CIF_LINE_INT_NUM, "CIF_REG_DVP_LINE_INT_NUM"), [CIF_REG_DVP_LINE_CNT] = CIF_REG_NAME(CIF_LINE_CNT, "CIF_REG_DVP_LINE_CNT"), [CIF_REG_DVP_CROP] = CIF_REG_NAME(RV1126_CIF_CROP, "CIF_REG_DVP_CROP"), [CIF_REG_DVP_FIFO_ENTRY] = CIF_REG_NAME(RK3568_CIF_FIFO_ENTRY, "CIF_REG_DVP_FIFO_ENTRY"), [CIF_REG_DVP_FRAME_STATUS] = CIF_REG_NAME(RV1126_CIF_FRAME_STATUS, "CIF_REG_DVP_FRAME_STATUS"), [CIF_REG_DVP_CUR_DST] = CIF_REG_NAME(RV1126_CIF_CUR_DST, "CIF_REG_DVP_CUR_DST"), [CIF_REG_DVP_LAST_LINE] = CIF_REG_NAME(RV1126_CIF_LAST_LINE, "CIF_REG_DVP_LAST_LINE"), [CIF_REG_DVP_LAST_PIX] = CIF_REG_NAME(RV1126_CIF_LAST_PIX, "CIF_REG_DVP_LAST_PIX"), [CIF_REG_DVP_FRM0_ADDR_Y_ID1] = CIF_REG_NAME(CIF_FRM0_ADDR_Y_ID1, "CIF_REG_DVP_FRM0_ADDR_Y_ID1"), [CIF_REG_DVP_FRM0_ADDR_UV_ID1] = CIF_REG_NAME(CIF_FRM0_ADDR_UV_ID1, "CIF_REG_DVP_FRM0_ADDR_UV_ID1"), [CIF_REG_DVP_FRM1_ADDR_Y_ID1] = CIF_REG_NAME(CIF_FRM1_ADDR_Y_ID1, "CIF_REG_DVP_FRM1_ADDR_Y_ID1"), [CIF_REG_DVP_FRM1_ADDR_UV_ID1] = CIF_REG_NAME(CIF_FRM1_ADDR_UV_ID1, "CIF_REG_DVP_FRM1_ADDR_UV_ID1"), [CIF_REG_DVP_FRM0_ADDR_Y_ID2] = CIF_REG_NAME(CIF_FRM0_ADDR_Y_ID2, "CIF_REG_DVP_FRM0_ADDR_Y_ID2"), [CIF_REG_DVP_FRM0_ADDR_UV_ID2] = CIF_REG_NAME(CIF_FRM0_ADDR_UV_ID2, "CIF_REG_DVP_FRM0_ADDR_UV_ID2"), [CIF_REG_DVP_FRM1_ADDR_Y_ID2] = CIF_REG_NAME(CIF_FRM1_ADDR_Y_ID2, "CIF_REG_DVP_FRM1_ADDR_Y_ID2"), [CIF_REG_DVP_FRM1_ADDR_UV_ID2] = CIF_REG_NAME(CIF_FRM1_ADDR_UV_ID2, "CIF_REG_DVP_FRM1_ADDR_UV_ID2"), [CIF_REG_DVP_FRM0_ADDR_Y_ID3] = CIF_REG_NAME(CIF_FRM0_ADDR_Y_ID3, "CIF_REG_DVP_FRM0_ADDR_Y_ID3"), [CIF_REG_DVP_FRM0_ADDR_UV_ID3] = CIF_REG_NAME(CIF_FRM0_ADDR_UV_ID3, "CIF_REG_DVP_FRM0_ADDR_UV_ID3"), [CIF_REG_DVP_FRM1_ADDR_Y_ID3] = CIF_REG_NAME(CIF_FRM1_ADDR_Y_ID3, "CIF_REG_DVP_FRM1_ADDR_Y_ID3"), [CIF_REG_DVP_FRM1_ADDR_UV_ID3] = CIF_REG_NAME(CIF_FRM1_ADDR_UV_ID3, "CIF_REG_DVP_FRM1_ADDR_UV_ID3"), [CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG_NAME(CIF_CSI_ID0_CTRL0, "CIF_REG_MIPI_LVDS_ID0_CTRL0"), [CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG_NAME(CIF_CSI_ID0_CTRL1, "CIF_REG_MIPI_LVDS_ID0_CTRL1"), [CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG_NAME(CIF_CSI_ID1_CTRL0, "CIF_REG_MIPI_LVDS_ID1_CTRL0"), [CIF_REG_MIPI_LVDS_ID1_CTRL1] = CIF_REG_NAME(CIF_CSI_ID1_CTRL1, "CIF_REG_MIPI_LVDS_ID1_CTRL1"), [CIF_REG_MIPI_LVDS_ID2_CTRL0] = CIF_REG_NAME(CIF_CSI_ID2_CTRL0, "CIF_REG_MIPI_LVDS_ID2_CTRL0"), [CIF_REG_MIPI_LVDS_ID2_CTRL1] = CIF_REG_NAME(CIF_CSI_ID2_CTRL1, "CIF_REG_MIPI_LVDS_ID2_CTRL1"), [CIF_REG_MIPI_LVDS_ID3_CTRL0] = CIF_REG_NAME(CIF_CSI_ID3_CTRL0, "CIF_REG_MIPI_LVDS_ID3_CTRL0"), [CIF_REG_MIPI_LVDS_ID3_CTRL1] = CIF_REG_NAME(CIF_CSI_ID3_CTRL1, "CIF_REG_MIPI_LVDS_ID3_CTRL1"), [CIF_REG_MIPI_LVDS_CTRL] = CIF_REG_NAME(CIF_CSI_MIPI_LVDS_CTRL, "CIF_REG_MIPI_LVDS_CTRL"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_Y_ID0, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_Y_ID0, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_UV_ID0, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_UV_ID0, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_Y_ID0, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_Y_ID0, "CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_UV_ID0, "CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0"), [CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_UV_ID0, "CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_Y_ID1, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_Y_ID1, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_UV_ID1, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_UV_ID1, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_Y_ID1, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID1] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_Y_ID1, "CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID1] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_UV_ID1, "CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID1"), [CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID1] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_UV_ID1, "CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_Y_ID2, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_Y_ID2, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_UV_ID2, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_UV_ID2, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_Y_ID2, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID2] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_Y_ID2, "CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID2] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_UV_ID2, "CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID2"), [CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID2] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_UV_ID2, "CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_Y_ID3, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_Y_ID3, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3] = CIF_REG_NAME(CIF_CSI_FRM0_ADDR_UV_ID3, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3] = CIF_REG_NAME(CIF_CSI_FRM1_ADDR_UV_ID3, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_Y_ID3, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3"), [CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID3] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_Y_ID3, "CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID3"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID3] = CIF_REG_NAME(CIF_CSI_FRM0_VLW_UV_ID3, "CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID3"), [CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID3] = CIF_REG_NAME(CIF_CSI_FRM1_VLW_UV_ID3, "CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID3"), [CIF_REG_MIPI_LVDS_INTEN] = CIF_REG_NAME(CIF_CSI_INTEN, "CIF_REG_MIPI_LVDS_INTEN"), [CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG_NAME(CIF_CSI_INTSTAT, "CIF_REG_MIPI_LVDS_INTSTAT"), [CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG_NAME(CIF_CSI_LINE_INT_NUM_ID0_1, "CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1"), [CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG_NAME(CIF_CSI_LINE_INT_NUM_ID2_3, "CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3"), [CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG_NAME(CIF_CSI_LINE_CNT_ID0_1, "CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1"), [CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG_NAME(CIF_CSI_LINE_CNT_ID2_3, "CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3"), [CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG_NAME(CIF_CSI_ID0_CROP_START, "CIF_REG_MIPI_LVDS_ID0_CROP_START"), [CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG_NAME(CIF_CSI_ID1_CROP_START, "CIF_REG_MIPI_LVDS_ID1_CROP_START"), [CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG_NAME(CIF_CSI_ID2_CROP_START, "CIF_REG_MIPI_LVDS_ID2_CROP_START"), [CIF_REG_MIPI_LVDS_ID3_CROP_START] = CIF_REG_NAME(CIF_CSI_ID3_CROP_START, "CIF_REG_MIPI_LVDS_ID3_CROP_START"), [CIF_REG_MIPI_FRAME_NUM_VC0] = CIF_REG_NAME(CIF_CSI_FRAME_NUM_VC0, "CIF_REG_MIPI_FRAME_NUM_VC0"), [CIF_REG_MIPI_FRAME_NUM_VC1] = CIF_REG_NAME(CIF_CSI_FRAME_NUM_VC1, "CIF_REG_MIPI_FRAME_NUM_VC1"), [CIF_REG_MIPI_FRAME_NUM_VC2] = CIF_REG_NAME(CIF_CSI_FRAME_NUM_VC2, "CIF_REG_MIPI_FRAME_NUM_VC2"), [CIF_REG_MIPI_FRAME_NUM_VC3] = CIF_REG_NAME(CIF_CSI_FRAME_NUM_VC3, "CIF_REG_MIPI_FRAME_NUM_VC3"), [CIF_REG_Y_STAT_CONTROL] = CIF_REG_NAME(CIF_Y_STAT_CONTROL, "CIF_REG_Y_STAT_CONTROL"), [CIF_REG_Y_STAT_VALUE] = CIF_REG_NAME(CIF_Y_STAT_VALUE, "CIF_REG_Y_STAT_VALUE"), [CIF_REG_MMU_DTE_ADDR] = CIF_REG_NAME(CIF_MMU_DTE_ADDR, "CIF_REG_MMU_DTE_ADDR"), [CIF_REG_MMU_STATUS] = CIF_REG_NAME(CIF_MMU_STATUS, "CIF_REG_MMU_STATUS"), [CIF_REG_MMU_COMMAND] = CIF_REG_NAME(CIF_MMU_COMMAND, "CIF_REG_MMU_COMMAND"), [CIF_REG_MMU_PAGE_FAULT_ADDR] = CIF_REG_NAME(CIF_MMU_PAGE_FAULT_ADDR, "CIF_REG_MMU_PAGE_FAULT_ADDR"), [CIF_REG_MMU_ZAP_ONE_LINE] = CIF_REG_NAME(CIF_MMU_ZAP_ONE_LINE, "CIF_REG_MMU_ZAP_ONE_LINE"), [CIF_REG_MMU_INT_RAWSTAT] = CIF_REG_NAME(CIF_MMU_INT_RAWSTAT, "CIF_REG_MMU_INT_RAWSTAT"), [CIF_REG_MMU_INT_CLEAR] = CIF_REG_NAME(CIF_MMU_INT_CLEAR, "CIF_REG_MMU_INT_CLEAR"), [CIF_REG_MMU_INT_MASK] = CIF_REG_NAME(CIF_MMU_INT_MASK, "CIF_REG_MMU_INT_MASK"), [CIF_REG_MMU_INT_STATUS] = CIF_REG_NAME(CIF_MMU_INT_STATUS, "CIF_REG_MMU_INT_STATUS"), [CIF_REG_MMU_AUTO_GATING] = CIF_REG_NAME(CIF_MMU_AUTO_GATING, "CIF_REG_MMU_AUTO_GATING"), [CIF_REG_GRF_CIFIO_CON] = CIF_REG_NAME(CIF_GRF_VI_CON0, "CIF_REG_GRF_CIFIO_CON"), [CIF_REG_GRF_CIFIO_CON1] = CIF_REG_NAME(CIF_GRF_VI_CON1, "CIF_REG_GRF_CIFIO_CON1"), }; static const struct vehicle_cif_reg rk3588_cif_regs[] = { [CIF_REG_DVP_CTRL] = CIF_REG_NAME(DVP_CTRL, "CIF_REG_DVP_CTRL"), [CIF_REG_DVP_INTEN] = CIF_REG_NAME(DVP_INTEN, "CIF_REG_DVP_INTEN"), [CIF_REG_DVP_INTSTAT] = CIF_REG_NAME(DVP_INTSTAT, "CIF_REG_DVP_INTSTAT"), [CIF_REG_DVP_FOR] = CIF_REG_NAME(DVP_FOR, "CIF_REG_DVP_FOR"), [CIF_REG_DVP_MULTI_ID] = CIF_REG_NAME(DVP_MULTI_ID, "CIF_REG_DVP_MULTI_ID"), [CIF_REG_DVP_SAV_EAV] = CIF_REG_NAME(DVP_SAV_EAV, "CIF_REG_DVP_SAV_EAV"), [CIF_REG_DVP_FRM0_ADDR_Y] = CIF_REG_NAME(DVP_FRM0_ADDR_Y_ID0, "CIF_REG_DVP_FRM0_ADDR_Y"), [CIF_REG_DVP_FRM0_ADDR_UV] = CIF_REG_NAME(DVP_FRM0_ADDR_UV_ID0, "CIF_REG_DVP_FRM0_ADDR_UV"), [CIF_REG_DVP_FRM1_ADDR_Y] = CIF_REG_NAME(DVP_FRM1_ADDR_Y_ID0, "CIF_REG_DVP_FRM1_ADDR_Y"), [CIF_REG_DVP_FRM1_ADDR_UV] = CIF_REG_NAME(DVP_FRM1_ADDR_UV_ID0, "CIF_REG_DVP_FRM1_ADDR_UV"), [CIF_REG_DVP_FRM0_ADDR_Y_ID1] = CIF_REG_NAME(DVP_FRM0_ADDR_Y_ID1, "CIF_REG_DVP_FRM0_ADDR_Y_ID1"), [CIF_REG_DVP_FRM0_ADDR_UV_ID1] = CIF_REG_NAME(DVP_FRM0_ADDR_UV_ID1, "CIF_REG_DVP_FRM0_ADDR_UV_ID1"), [CIF_REG_DVP_FRM1_ADDR_Y_ID1] = CIF_REG_NAME(DVP_FRM1_ADDR_Y_ID1, "CIF_REG_DVP_FRM1_ADDR_Y_ID1"), [CIF_REG_DVP_FRM1_ADDR_UV_ID1] = CIF_REG_NAME(DVP_FRM1_ADDR_UV_ID1, "CIF_REG_DVP_FRM1_ADDR_UV_ID1"), [CIF_REG_DVP_FRM0_ADDR_Y_ID2] = CIF_REG_NAME(DVP_FRM0_ADDR_Y_ID2, "CIF_REG_DVP_FRM0_ADDR_Y_ID2"), [CIF_REG_DVP_FRM0_ADDR_UV_ID2] = CIF_REG_NAME(DVP_FRM0_ADDR_UV_ID2, "CIF_REG_DVP_FRM0_ADDR_UV_ID2"), [CIF_REG_DVP_FRM1_ADDR_Y_ID2] = CIF_REG_NAME(DVP_FRM1_ADDR_Y_ID2, "CIF_REG_DVP_FRM1_ADDR_Y_ID2"), [CIF_REG_DVP_FRM1_ADDR_UV_ID2] = CIF_REG_NAME(DVP_FRM1_ADDR_UV_ID2, "CIF_REG_DVP_FRM1_ADDR_UV_ID2"), [CIF_REG_DVP_FRM0_ADDR_Y_ID3] = CIF_REG_NAME(DVP_FRM0_ADDR_Y_ID3, "CIF_REG_DVP_FRM0_ADDR_Y_ID3"), [CIF_REG_DVP_FRM0_ADDR_UV_ID3] = CIF_REG_NAME(DVP_FRM0_ADDR_UV_ID3, "CIF_REG_DVP_FRM0_ADDR_UV_ID3"), [CIF_REG_DVP_FRM1_ADDR_Y_ID3] = CIF_REG_NAME(DVP_FRM1_ADDR_Y_ID3, "CIF_REG_DVP_FRM1_ADDR_Y_ID3"), [CIF_REG_DVP_FRM1_ADDR_UV_ID3] = CIF_REG_NAME(DVP_FRM1_ADDR_UV_ID3, "CIF_REG_DVP_FRM1_ADDR_UV_ID3"), [CIF_REG_DVP_VIR_LINE_WIDTH] = CIF_REG_NAME(DVP_VIR_LINE_WIDTH, "CIF_REG_DVP_VIR_LINE_WIDTH"), [CIF_REG_DVP_SET_SIZE] = CIF_REG_NAME(DVP_CROP_SIZE, "CIF_REG_DVP_SET_SIZE"), [CIF_REG_DVP_CROP] = CIF_REG_NAME(DVP_CROP, "CIF_REG_DVP_CROP"), [CIF_REG_DVP_LINE_INT_NUM] = CIF_REG_NAME(DVP_LINE_INT_NUM_01, "CIF_REG_DVP_LINE_INT_NUM"), [CIF_REG_DVP_LINE_INT_NUM1] = CIF_REG_NAME(DVP_LINE_INT_NUM_23, "CIF_REG_DVP_LINE_INT_NUM1"), [CIF_REG_DVP_LINE_CNT] = CIF_REG_NAME(DVP_LINE_INT_NUM_01, "CIF_REG_DVP_LINE_CNT"), [CIF_REG_DVP_LINE_CNT1] = CIF_REG_NAME(DVP_LINE_INT_NUM_23, "CIF_REG_DVP_LINE_CNT1"), [CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL0, "CIF_REG_MIPI_LVDS_ID0_CTRL0"), [CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL1, "CIF_REG_MIPI_LVDS_ID0_CTRL1"), [CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL0, "CIF_REG_MIPI_LVDS_ID1_CTRL0"), [CIF_REG_MIPI_LVDS_ID1_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL1, "CIF_REG_MIPI_LVDS_ID1_CTRL1"), [CIF_REG_MIPI_LVDS_ID2_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL0, "CIF_REG_MIPI_LVDS_ID2_CTRL0"), [CIF_REG_MIPI_LVDS_ID2_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL1, "CIF_REG_MIPI_LVDS_ID2_CTRL1"), [CIF_REG_MIPI_LVDS_ID3_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL0, "CIF_REG_MIPI_LVDS_ID3_CTRL0"), [CIF_REG_MIPI_LVDS_ID3_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL1, "CIF_REG_MIPI_LVDS_ID3_CTRL1"), [CIF_REG_MIPI_LVDS_CTRL] = CIF_REG_NAME(CSI_MIPI0_CTRL, "CIF_REG_MIPI_LVDS_CTRL"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID0, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID0, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID0, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID0, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_VLW_ID0, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID1, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID1, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID1, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID1, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_VLW_ID1, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID2, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID2, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID2, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID2, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_VLW_ID2, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID3, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID3, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID3, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID3, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_VLW_ID3, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3"), [CIF_REG_MIPI_LVDS_INTEN] = CIF_REG_NAME(CSI_MIPI0_INTEN, "CIF_REG_MIPI_LVDS_INTEN"), [CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG_NAME(CSI_MIPI0_INTSTAT, "CIF_REG_MIPI_LVDS_INTSTAT"), [CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID0_1, "CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1"), [CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID2_3, "CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3"), [CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID0_1, "CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1"), [CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID2_3, "CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3"), [CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID0_CROP_START, "CIF_REG_MIPI_LVDS_ID0_CROP_START"), [CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID1_CROP_START, "CIF_REG_MIPI_LVDS_ID1_CROP_START"), [CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID2_CROP_START, "CIF_REG_MIPI_LVDS_ID2_CROP_START"), [CIF_REG_MIPI_LVDS_ID3_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID3_CROP_START, "CIF_REG_MIPI_LVDS_ID3_CROP_START"), [CIF_REG_MIPI_FRAME_NUM_VC0] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC0, "CIF_REG_MIPI_FRAME_NUM_VC0"), [CIF_REG_MIPI_FRAME_NUM_VC1] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC1, "CIF_REG_MIPI_FRAME_NUM_VC1"), [CIF_REG_MIPI_FRAME_NUM_VC2] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC2, "CIF_REG_MIPI_FRAME_NUM_VC2"), [CIF_REG_MIPI_FRAME_NUM_VC3] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC3, "CIF_REG_MIPI_FRAME_NUM_VC3"), [CIF_REG_MIPI_EFFECT_CODE_ID0] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID0, "CIF_REG_MIPI_EFFECT_CODE_ID0"), [CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID1, "CIF_REG_MIPI_EFFECT_CODE_ID1"), [CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID2, "CIF_REG_MIPI_EFFECT_CODE_ID2"), [CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID3, "CIF_REG_MIPI_EFFECT_CODE_ID3"), [CIF_REG_MIPI_ON_PAD] = CIF_REG_NAME(CSI_MIPI0_ON_PAD, "CIF_REG_MIPI_ON_PAD"), [CIF_REG_GLB_CTRL] = CIF_REG_NAME(GLB_CTRL, "CIF_REG_GLB_CTRL"), [CIF_REG_GLB_INTEN] = CIF_REG_NAME(GLB_INTEN, "CIF_REG_GLB_INTEN"), [CIF_REG_GLB_INTST] = CIF_REG_NAME(GLB_INTST, "CIF_REG_GLB_INTST"), [CIF_REG_SCL_CH_CTRL] = CIF_REG_NAME(SCL_CH_CTRL, "CIF_REG_SCL_CH_CTRL"), [CIF_REG_SCL_CTRL] = CIF_REG_NAME(SCL_CTRL, "CIF_REG_SCL_CTRL"), [CIF_REG_SCL_FRM0_ADDR_CH0] = CIF_REG_NAME(SCL_FRM0_ADDR_CH0, "CIF_REG_SCL_FRM0_ADDR_CH0"), [CIF_REG_SCL_FRM1_ADDR_CH0] = CIF_REG_NAME(SCL_FRM1_ADDR_CH0, "CIF_REG_SCL_FRM1_ADDR_CH0"), [CIF_REG_SCL_VLW_CH0] = CIF_REG_NAME(SCL_VLW_CH0, "CIF_REG_SCL_VLW_CH0"), [CIF_REG_SCL_FRM0_ADDR_CH1] = CIF_REG_NAME(SCL_FRM0_ADDR_CH1, "CIF_REG_SCL_FRM0_ADDR_CH1"), [CIF_REG_SCL_FRM1_ADDR_CH1] = CIF_REG_NAME(SCL_FRM1_ADDR_CH1, "CIF_REG_SCL_FRM1_ADDR_CH1"), [CIF_REG_SCL_VLW_CH1] = CIF_REG_NAME(SCL_VLW_CH1, "CIF_REG_SCL_VLW_CH1"), [CIF_REG_SCL_FRM0_ADDR_CH2] = CIF_REG_NAME(SCL_FRM0_ADDR_CH2, "CIF_REG_SCL_FRM0_ADDR_CH2"), [CIF_REG_SCL_FRM1_ADDR_CH2] = CIF_REG_NAME(SCL_FRM1_ADDR_CH2, "CIF_REG_SCL_FRM1_ADDR_CH2"), [CIF_REG_SCL_VLW_CH2] = CIF_REG_NAME(SCL_VLW_CH2, "CIF_REG_SCL_VLW_CH2"), [CIF_REG_SCL_FRM0_ADDR_CH3] = CIF_REG_NAME(SCL_FRM0_ADDR_CH3, "CIF_REG_SCL_FRM0_ADDR_CH3"), [CIF_REG_SCL_FRM1_ADDR_CH3] = CIF_REG_NAME(SCL_FRM1_ADDR_CH3, "CIF_REG_SCL_FRM1_ADDR_CH3"), [CIF_REG_SCL_VLW_CH3] = CIF_REG_NAME(SCL_VLW_CH3, "CIF_REG_SCL_VLW_CH3"), [CIF_REG_SCL_BLC_CH0] = CIF_REG_NAME(SCL_BLC_CH0, "CIF_REG_SCL_BLC_CH0"), [CIF_REG_SCL_BLC_CH1] = CIF_REG_NAME(SCL_BLC_CH1, "CIF_REG_SCL_BLC_CH1"), [CIF_REG_SCL_BLC_CH2] = CIF_REG_NAME(SCL_BLC_CH2, "CIF_REG_SCL_BLC_CH2"), [CIF_REG_SCL_BLC_CH3] = CIF_REG_NAME(SCL_BLC_CH3, "CIF_REG_SCL_BLC_CH3"), [CIF_REG_TOISP0_CTRL] = CIF_REG_NAME(TOISP0_CH_CTRL, "CIF_REG_TOISP0_CTRL"), [CIF_REG_TOISP0_SIZE] = CIF_REG_NAME(TOISP0_CROP_SIZE, "CIF_REG_TOISP0_SIZE"), [CIF_REG_TOISP0_CROP] = CIF_REG_NAME(TOISP0_CROP, "CIF_REG_TOISP0_CROP"), [CIF_REG_TOISP1_CTRL] = CIF_REG_NAME(TOISP1_CH_CTRL, "CIF_REG_TOISP1_CTRL"), [CIF_REG_TOISP1_SIZE] = CIF_REG_NAME(TOISP1_CROP_SIZE, "CIF_REG_TOISP1_SIZE"), [CIF_REG_TOISP1_CROP] = CIF_REG_NAME(TOISP1_CROP, "CIF_REG_TOISP1_CROP"), [CIF_REG_GRF_CIFIO_CON] = CIF_REG_NAME(CIF_GRF_SOC_CON2, "CIF_REG_GRF_CIFIO_CON"), }; static const struct vehicle_cif_reg rk3562_cif_regs[] = { [CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL0, "CIF_REG_MIPI_LVDS_ID0_CTRL0"), [CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL1, "CIF_REG_MIPI_LVDS_ID0_CTRL1"), [CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL0, "CIF_REG_MIPI_LVDS_ID1_CTRL0"), [CIF_REG_MIPI_LVDS_ID1_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL1, "CIF_REG_MIPI_LVDS_ID1_CTRL1"), [CIF_REG_MIPI_LVDS_ID2_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL0, "CIF_REG_MIPI_LVDS_ID2_CTRL0"), [CIF_REG_MIPI_LVDS_ID2_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL1, "CIF_REG_MIPI_LVDS_ID2_CTRL1"), [CIF_REG_MIPI_LVDS_ID3_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL0, "CIF_REG_MIPI_LVDS_ID3_CTRL0"), [CIF_REG_MIPI_LVDS_ID3_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL1, "CIF_REG_MIPI_LVDS_ID3_CTRL1"), [CIF_REG_MIPI_LVDS_CTRL] = CIF_REG_NAME(CSI_MIPI0_CTRL, "CIF_REG_MIPI_LVDS_CTRL"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID0, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID0, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID0, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID0, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_VLW_ID0, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID1, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID1, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID1, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID1, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_VLW_ID1, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID2, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID2, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID2, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID2, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_VLW_ID2, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID3, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID3, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID3, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID3, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_VLW_ID3, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3"), [CIF_REG_MIPI_LVDS_INTEN] = CIF_REG_NAME(CSI_MIPI0_INTEN, "CIF_REG_MIPI_LVDS_INTEN"), [CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG_NAME(CSI_MIPI0_INTSTAT, "CIF_REG_MIPI_LVDS_INTSTAT"), [CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID0_1, "CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1"), [CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID2_3, "CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3"), [CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID0_1, "CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1"), [CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID2_3, "CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3"), [CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID0_CROP_START, "CIF_REG_MIPI_LVDS_ID0_CROP_START"), [CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID1_CROP_START, "CIF_REG_MIPI_LVDS_ID1_CROP_START"), [CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID2_CROP_START, "CIF_REG_MIPI_LVDS_ID2_CROP_START"), [CIF_REG_MIPI_LVDS_ID3_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID3_CROP_START, "CIF_REG_MIPI_LVDS_ID3_CROP_START"), [CIF_REG_MIPI_FRAME_NUM_VC0] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC0, "CIF_REG_MIPI_FRAME_NUM_VC0"), [CIF_REG_MIPI_FRAME_NUM_VC1] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC1, "CIF_REG_MIPI_FRAME_NUM_VC1"), [CIF_REG_MIPI_FRAME_NUM_VC2] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC2, "CIF_REG_MIPI_FRAME_NUM_VC2"), [CIF_REG_MIPI_FRAME_NUM_VC3] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC3, "CIF_REG_MIPI_FRAME_NUM_VC3"), [CIF_REG_MIPI_EFFECT_CODE_ID0] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID0, "CIF_REG_MIPI_EFFECT_CODE_ID0"), [CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID1, "CIF_REG_MIPI_EFFECT_CODE_ID1"), [CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID2, "CIF_REG_MIPI_EFFECT_CODE_ID2"), [CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID3, "CIF_REG_MIPI_EFFECT_CODE_ID3"), [CIF_REG_MIPI_ON_PAD] = CIF_REG_NAME(CSI_MIPI0_ON_PAD, "CIF_REG_MIPI_ON_PAD"), [CIF_REG_GLB_CTRL] = CIF_REG_NAME(GLB_CTRL, "CIF_REG_GLB_CTRL"), [CIF_REG_GLB_INTEN] = CIF_REG_NAME(GLB_INTEN, "CIF_REG_GLB_INTEN"), [CIF_REG_GLB_INTST] = CIF_REG_NAME(GLB_INTST, "CIF_REG_GLB_INTST"), [CIF_REG_SCL_CH_CTRL] = CIF_REG_NAME(SCL_CH_CTRL, "CIF_REG_SCL_CH_CTRL"), [CIF_REG_SCL_CTRL] = CIF_REG_NAME(SCL_CTRL, "CIF_REG_SCL_CTRL"), [CIF_REG_SCL_FRM0_ADDR_CH0] = CIF_REG_NAME(SCL_FRM0_ADDR_CH0, "CIF_REG_SCL_FRM0_ADDR_CH0"), [CIF_REG_SCL_FRM1_ADDR_CH0] = CIF_REG_NAME(SCL_FRM1_ADDR_CH0, "CIF_REG_SCL_FRM1_ADDR_CH0"), [CIF_REG_SCL_VLW_CH0] = CIF_REG_NAME(SCL_VLW_CH0, "CIF_REG_SCL_VLW_CH0"), [CIF_REG_SCL_BLC_CH0] = CIF_REG_NAME(SCL_BLC_CH0, "CIF_REG_SCL_BLC_CH0"), [CIF_REG_TOISP0_CTRL] = CIF_REG_NAME(TOISP0_CH_CTRL, "CIF_REG_TOISP0_CTRL"), [CIF_REG_TOISP0_SIZE] = CIF_REG_NAME(TOISP0_CROP_SIZE, "CIF_REG_TOISP0_SIZE"), [CIF_REG_TOISP0_CROP] = CIF_REG_NAME(TOISP0_CROP, "CIF_REG_TOISP0_CROP"), }; static const struct vehicle_cif_reg rk3576_cif_regs[] = { [CIF_REG_DVP_CTRL] = CIF_REG_NAME(DVP_CTRL, "CIF_REG_DVP_CTRL"), [CIF_REG_DVP_INTEN] = CIF_REG_NAME(DVP_INTEN, "CIF_REG_DVP_INTEN"), [CIF_REG_DVP_INTSTAT] = CIF_REG_NAME(DVP_INTSTAT, "CIF_REG_DVP_INTSTAT"), [CIF_REG_DVP_FOR] = CIF_REG_NAME(DVP_FOR, "CIF_REG_DVP_FOR"), [CIF_REG_DVP_SAV_EAV] = CIF_REG_NAME(DVP_SAV_EAV, "CIF_REG_DVP_SAV_EAV"), [CIF_REG_DVP_FRM0_ADDR_Y] = CIF_REG_NAME(DVP_FRM0_ADDR_Y_ID0, "CIF_REG_DVP_FRM0_ADDR_Y"), [CIF_REG_DVP_FRM0_ADDR_UV] = CIF_REG_NAME(DVP_FRM0_ADDR_UV_ID0, "CIF_REG_DVP_FRM0_ADDR_UV"), [CIF_REG_DVP_FRM1_ADDR_Y] = CIF_REG_NAME(DVP_FRM1_ADDR_Y_ID0, "CIF_REG_DVP_FRM1_ADDR_Y"), [CIF_REG_DVP_FRM1_ADDR_UV] = CIF_REG_NAME(DVP_FRM1_ADDR_UV_ID0, "CIF_REG_DVP_FRM1_ADDR_UV"), [CIF_REG_DVP_VIR_LINE_WIDTH] = CIF_REG_NAME(DVP_VIR_LINE_WIDTH, "CIF_REG_DVP_VIR_LINE_WIDTH"), [CIF_REG_DVP_SET_SIZE] = CIF_REG_NAME(DVP_CROP_SIZE, "CIF_REG_DVP_SET_SIZE"), [CIF_REG_DVP_CROP] = CIF_REG_NAME(DVP_CROP, "CIF_REG_DVP_CROP"), [CIF_REG_DVP_LINE_INT_NUM] = CIF_REG_NAME(DVP_LINE_INT_NUM_01, "CIF_REG_DVP_LINE_INT_NUM"), [CIF_REG_DVP_LINE_CNT] = CIF_REG_NAME(DVP_LINE_CNT_01, "CIF_REG_DVP_LINE_CNT"), [CIF_REG_MIPI_LVDS_ID0_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL0, "CIF_REG_MIPI_LVDS_ID0_CTRL0"), [CIF_REG_MIPI_LVDS_ID0_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID0_CTRL1, "CIF_REG_MIPI_LVDS_ID0_CTRL1"), [CIF_REG_MIPI_LVDS_ID1_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL0, "CIF_REG_MIPI_LVDS_ID1_CTRL0"), [CIF_REG_MIPI_LVDS_ID1_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID1_CTRL1, "CIF_REG_MIPI_LVDS_ID1_CTRL1"), [CIF_REG_MIPI_LVDS_ID2_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL0, "CIF_REG_MIPI_LVDS_ID2_CTRL0"), [CIF_REG_MIPI_LVDS_ID2_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID2_CTRL1, "CIF_REG_MIPI_LVDS_ID2_CTRL1"), [CIF_REG_MIPI_LVDS_ID3_CTRL0] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL0, "CIF_REG_MIPI_LVDS_ID3_CTRL0"), [CIF_REG_MIPI_LVDS_ID3_CTRL1] = CIF_REG_NAME(CSI_MIPI0_ID3_CTRL1, "CIF_REG_MIPI_LVDS_ID3_CTRL1"), [CIF_REG_MIPI_LVDS_CTRL] = CIF_REG_NAME(CSI_MIPI0_CTRL, "CIF_REG_MIPI_LVDS_CTRL"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID0, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID0, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID0, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID0, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0] = CIF_REG_NAME(CSI_MIPI0_VLW_ID0, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID1, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID1, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID1, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID1, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1] = CIF_REG_NAME(CSI_MIPI0_VLW_ID1, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID2, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID2, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID2, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID2, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2] = CIF_REG_NAME(CSI_MIPI0_VLW_ID2, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_Y_ID3, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_Y_ID3, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3"), [CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM0_ADDR_UV_ID3, "CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3"), [CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3] = CIF_REG_NAME(CSI_MIPI0_FRM1_ADDR_UV_ID3, "CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3"), [CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3] = CIF_REG_NAME(CSI_MIPI0_VLW_ID3, "CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3"), [CIF_REG_MIPI_LVDS_INTEN] = CIF_REG_NAME(CSI_MIPI0_INTEN, "CIF_REG_MIPI_LVDS_INTEN"), [CIF_REG_MIPI_LVDS_INTSTAT] = CIF_REG_NAME(CSI_MIPI0_INTSTAT, "CIF_REG_MIPI_LVDS_INTSTAT"), [CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID0_1_RK3576, "CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1"), [CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_INT_NUM_ID2_3_RK3576, "CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3"), [CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID0_1_RK3576, "CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1"), [CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3] = CIF_REG_NAME(CSI_MIPI0_LINE_CNT_ID2_3_RK3576, "CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID2_3"), [CIF_REG_MIPI_LVDS_ID0_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID0_CROP_START_RK3576, "CIF_REG_MIPI_LVDS_ID0_CROP_START"), [CIF_REG_MIPI_LVDS_ID1_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID1_CROP_START_RK3576, "CIF_REG_MIPI_LVDS_ID1_CROP_START"), [CIF_REG_MIPI_LVDS_ID2_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID2_CROP_START_RK3576, "CIF_REG_MIPI_LVDS_ID2_CROP_START"), [CIF_REG_MIPI_LVDS_ID3_CROP_START] = CIF_REG_NAME(CSI_MIPI0_ID3_CROP_START_RK3576, "CIF_REG_MIPI_LVDS_ID3_CROP_START"), [CIF_REG_MIPI_FRAME_NUM_VC0] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC0_RK3576, "CIF_REG_MIPI_FRAME_NUM_VC0"), [CIF_REG_MIPI_FRAME_NUM_VC1] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC1_RK3576, "CIF_REG_MIPI_FRAME_NUM_VC1"), [CIF_REG_MIPI_FRAME_NUM_VC2] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC2_RK3576, "CIF_REG_MIPI_FRAME_NUM_VC2"), [CIF_REG_MIPI_FRAME_NUM_VC3] = CIF_REG_NAME(CSI_MIPI0_FRAME_NUM_VC3_RK3576, "CIF_REG_MIPI_FRAME_NUM_VC3"), [CIF_REG_MIPI_EFFECT_CODE_ID0] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID0_RK3576, "CIF_REG_MIPI_EFFECT_CODE_ID0"), [CIF_REG_MIPI_EFFECT_CODE_ID1] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID1_RK3576, "CIF_REG_MIPI_EFFECT_CODE_ID1"), [CIF_REG_MIPI_EFFECT_CODE_ID2] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID2_RK3576, "CIF_REG_MIPI_EFFECT_CODE_ID2"), [CIF_REG_MIPI_EFFECT_CODE_ID3] = CIF_REG_NAME(CSI_MIPI0_EFFECT_CODE_ID3_RK3576, "CIF_REG_MIPI_EFFECT_CODE_ID3"), [CIF_REG_MIPI_ON_PAD] = CIF_REG_NAME(CSI_MIPI0_ON_PAD_RK3576, "CIF_REG_MIPI_ON_PAD"), [CIF_REG_MIPI_SET_SIZE_ID0] = CIF_REG_NAME(CSI_MIPI0_SET_FRAME_SIZE_ID0_RK3576, "CIF_REG_MIPI_SET_SIZE_ID0"), [CIF_REG_MIPI_SET_SIZE_ID1] = CIF_REG_NAME(CSI_MIPI0_SET_FRAME_SIZE_ID1_RK3576, "CIF_REG_MIPI_SET_SIZE_ID1"), [CIF_REG_MIPI_SET_SIZE_ID2] = CIF_REG_NAME(CSI_MIPI0_SET_FRAME_SIZE_ID2_RK3576, "CIF_REG_MIPI_SET_SIZE_ID2"), [CIF_REG_MIPI_SET_SIZE_ID3] = CIF_REG_NAME(CSI_MIPI0_SET_FRAME_SIZE_ID3_RK3576, "CIF_REG_MIPI_SET_SIZE_ID3"), [CIF_REG_GLB_CTRL] = CIF_REG_NAME(GLB_CTRL, "CIF_REG_GLB_CTRL"), [CIF_REG_GLB_INTEN] = CIF_REG_NAME(GLB_INTEN, "CIF_REG_GLB_INTEN"), [CIF_REG_GLB_INTST] = CIF_REG_NAME(GLB_INTST, "CIF_REG_GLB_INTST"), [CIF_REG_SCL_CH_CTRL] = CIF_REG_NAME(SCL_CH_CTRL, "CIF_REG_SCL_CH_CTRL"), [CIF_REG_SCL_CTRL] = CIF_REG_NAME(SCL_CTRL, "CIF_REG_SCL_CTRL"), [CIF_REG_SCL_FRM0_ADDR_CH0] = CIF_REG_NAME(SCL_FRM0_ADDR_CH0, "CIF_REG_SCL_FRM0_ADDR_CH0"), [CIF_REG_SCL_FRM1_ADDR_CH0] = CIF_REG_NAME(SCL_FRM1_ADDR_CH0, "CIF_REG_SCL_FRM1_ADDR_CH0"), [CIF_REG_SCL_VLW_CH0] = CIF_REG_NAME(SCL_VLW_CH0, "CIF_REG_SCL_VLW_CH0"), [CIF_REG_SCL_BLC_CH0] = CIF_REG_NAME(SCL_BLC_CH0, "CIF_REG_SCL_BLC_CH0"), [CIF_REG_TOISP0_CTRL] = CIF_REG_NAME(TOISP0_CH_CTRL, "CIF_REG_TOISP0_CTRL"), [CIF_REG_TOISP0_SIZE] = CIF_REG_NAME(TOISP0_CROP_SIZE, "CIF_REG_TOISP0_SIZE"), [CIF_REG_TOISP0_CROP] = CIF_REG_NAME(TOISP0_CROP, "CIF_REG_TOISP0_CROP"), [CIF_REG_GRF_CIFIO_CON] = CIF_REG_NAME(CIF_GRF_IOC_MISC_CON1_RK3576, "CIF_REG_GRF_CIFIO_CON"), }; //define dphy and csi regs static const struct grf_reg rk3568_grf_dphy_regs[] = { [GRF_DPHY_CSI2PHY_FORCERXMODE] = GRF_REG(GRF_VI_CON0, 4, 0), [GRF_DPHY_CSI2PHY_DATALANE_EN] = GRF_REG(GRF_VI_CON0, 4, 4), [GRF_DPHY_CSI2PHY_CLKLANE_EN] = GRF_REG(GRF_VI_CON0, 1, 8), [GRF_DPHY_CLK_INV_SEL] = GRF_REG(GRF_VI_CON0, 1, 9), [GRF_DPHY_CSI2PHY_CLKLANE1_EN] = GRF_REG(GRF_VI_CON0, 1, 10), [GRF_DPHY_CLK1_INV_SEL] = GRF_REG(GRF_VI_CON0, 1, 11), [GRF_DPHY_ISP_CSI2PHY_SEL] = GRF_REG(GRF_VI_CON1, 1, 12), [GRF_DPHY_CIF_CSI2PHY_SEL] = GRF_REG(GRF_VI_CON1, 1, 11), [GRF_DPHY_CSI2PHY_LANE_SEL] = GRF_REG(GRF_VI_CON1, 1, 7), }; static const struct csi2dphy_reg rk3568_csi2dphy_regs[] = { [CSI2PHY_REG_CTRL_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CTRL_LANE_ENABLE), [CSI2PHY_DUAL_CLK_EN] = CSI2PHY_REG(CSI2_DPHY_DUAL_CAL_EN), [CSI2PHY_CLK_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK_WR_THS_SETTLE), [CSI2PHY_CLK_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK_CALIB_EN), [CSI2PHY_LANE0_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_WR_THS_SETTLE), [CSI2PHY_LANE0_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_CALIB_EN), [CSI2PHY_LANE1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_WR_THS_SETTLE), [CSI2PHY_LANE1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_CALIB_EN), [CSI2PHY_LANE2_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_WR_THS_SETTLE), [CSI2PHY_LANE2_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_CALIB_EN), [CSI2PHY_LANE3_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_WR_THS_SETTLE), [CSI2PHY_LANE3_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_CALIB_EN), [CSI2PHY_CLK1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_WR_THS_SETTLE), [CSI2PHY_CLK1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_CALIB_EN), }; static const struct grf_reg rk3588_grf_dphy_regs[] = { [GRF_DPHY_CSI2PHY_FORCERXMODE] = GRF_REG(GRF_DPHY_CON0, 4, 0), [GRF_DPHY_CSI2PHY_DATALANE_EN] = GRF_REG(GRF_DPHY_CON0, 4, 4), [GRF_DPHY_CSI2PHY_DATALANE_EN0] = GRF_REG(GRF_DPHY_CON0, 2, 4), [GRF_DPHY_CSI2PHY_DATALANE_EN1] = GRF_REG(GRF_DPHY_CON0, 2, 6), [GRF_DPHY_CSI2PHY_CLKLANE_EN] = GRF_REG(GRF_DPHY_CON0, 1, 8), [GRF_DPHY_CLK_INV_SEL] = GRF_REG(GRF_DPHY_CON0, 1, 9), [GRF_DPHY_CSI2PHY_CLKLANE1_EN] = GRF_REG(GRF_DPHY_CON0, 1, 10), [GRF_DPHY_CLK1_INV_SEL] = GRF_REG(GRF_DPHY_CON0, 1, 11), [GRF_DPHY_CSI2PHY_LANE_SEL] = GRF_REG(GRF_SOC_CON2, 1, 6), [GRF_DPHY_CSI2PHY1_LANE_SEL] = GRF_REG(GRF_SOC_CON2, 1, 7), [GRF_DPHY_CSIHOST2_SEL] = GRF_REG(GRF_SOC_CON2, 1, 8), [GRF_DPHY_CSIHOST3_SEL] = GRF_REG(GRF_SOC_CON2, 1, 9), [GRF_DPHY_CSIHOST4_SEL] = GRF_REG(GRF_SOC_CON2, 1, 10), [GRF_DPHY_CSIHOST5_SEL] = GRF_REG(GRF_SOC_CON2, 1, 11), }; static const struct csi2dphy_reg rk3588_csi2dphy_regs[] = { [CSI2PHY_REG_CTRL_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CTRL_LANE_ENABLE), [CSI2PHY_DUAL_CLK_EN] = CSI2PHY_REG(CSI2_DPHY_DUAL_CAL_EN), [CSI2PHY_CLK_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK_WR_THS_SETTLE), [CSI2PHY_CLK_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK_CALIB_EN), [CSI2PHY_LANE0_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_WR_THS_SETTLE), [CSI2PHY_LANE0_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_CALIB_EN), [CSI2PHY_LANE1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_WR_THS_SETTLE), [CSI2PHY_LANE1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_CALIB_EN), [CSI2PHY_LANE2_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_WR_THS_SETTLE), [CSI2PHY_LANE2_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_CALIB_EN), [CSI2PHY_LANE3_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_WR_THS_SETTLE), [CSI2PHY_LANE3_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_CALIB_EN), [CSI2PHY_CLK1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_WR_THS_SETTLE), [CSI2PHY_CLK1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_CALIB_EN), [CSI2PHY_CLK1_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_LANE_EN), }; static const struct grf_reg rk3588_grf_dcphy_regs[] = { [GRF_CPHY_MODE] = GRF_REG(GRF_DCPHY_CON0, 9, 0), }; static const struct csi2dphy_reg rk3588_csi2dcphy_regs[] = { [CSI2PHY_CLK_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_CLK_WR_THS_SETTLE), [CSI2PHY_LANE0_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE0_WR_THS_SETTLE), [CSI2PHY_LANE0_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE0_WR_ERR_SOT_SYNC), [CSI2PHY_LANE1_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE1_WR_THS_SETTLE), [CSI2PHY_LANE1_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE1_WR_ERR_SOT_SYNC), [CSI2PHY_LANE2_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE2_WR_THS_SETTLE), [CSI2PHY_LANE2_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE2_WR_ERR_SOT_SYNC), [CSI2PHY_LANE3_THS_SETTLE] = CSI2PHY_REG(CSI2_DCPHY_LANE3_WR_THS_SETTLE), [CSI2PHY_LANE3_ERR_SOT_SYNC] = CSI2PHY_REG(CSI2_DCPHY_LANE3_WR_ERR_SOT_SYNC), [CSI2PHY_CLK_LANE_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_CLK_LANE_ENABLE), [CSI2PHY_DATA_LANE0_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE0_ENABLE), [CSI2PHY_DATA_LANE1_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE1_ENABLE), [CSI2PHY_DATA_LANE2_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE2_ENABLE), [CSI2PHY_DATA_LANE3_ENABLE] = CSI2PHY_REG(CSI2_DCPHY_DATA_LANE3_ENABLE), [CSI2PHY_S0C_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_S0C_GNR_CON1), [CSI2PHY_S0C_ANA_CON1] = CSI2PHY_REG(CSI2_DCPHY_S0C_ANA_CON1), [CSI2PHY_S0C_ANA_CON2] = CSI2PHY_REG(CSI2_DCPHY_S0C_ANA_CON2), [CSI2PHY_S0C_ANA_CON3] = CSI2PHY_REG(CSI2_DCPHY_S0C_ANA_CON3), [CSI2PHY_COMBO_S0D0_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_GNR_CON1), [CSI2PHY_COMBO_S0D0_ANA_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_ANA_CON1), [CSI2PHY_COMBO_S0D0_ANA_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_ANA_CON2), [CSI2PHY_COMBO_S0D0_ANA_CON3] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_ANA_CON3), [CSI2PHY_COMBO_S0D0_ANA_CON6] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_ANA_CON6), [CSI2PHY_COMBO_S0D0_ANA_CON7] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_ANA_CON7), [CSI2PHY_COMBO_S0D0_DESKEW_CON0] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_DESKEW_CON0), [CSI2PHY_COMBO_S0D0_DESKEW_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_DESKEW_CON2), [CSI2PHY_COMBO_S0D0_DESKEW_CON4] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_DESKEW_CON4), [CSI2PHY_COMBO_S0D0_CRC_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_CRC_CON1), [CSI2PHY_COMBO_S0D0_CRC_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D0_CRC_CON2), [CSI2PHY_COMBO_S0D1_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_GNR_CON1), [CSI2PHY_COMBO_S0D1_ANA_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_ANA_CON1), [CSI2PHY_COMBO_S0D1_ANA_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_ANA_CON2), [CSI2PHY_COMBO_S0D1_ANA_CON3] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_ANA_CON3), [CSI2PHY_COMBO_S0D1_ANA_CON6] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_ANA_CON6), [CSI2PHY_COMBO_S0D1_ANA_CON7] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_ANA_CON7), [CSI2PHY_COMBO_S0D1_DESKEW_CON0] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_DESKEW_CON0), [CSI2PHY_COMBO_S0D1_DESKEW_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_DESKEW_CON2), [CSI2PHY_COMBO_S0D1_DESKEW_CON4] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_DESKEW_CON4), [CSI2PHY_COMBO_S0D1_CRC_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_CRC_CON1), [CSI2PHY_COMBO_S0D1_CRC_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D1_CRC_CON2), [CSI2PHY_COMBO_S0D2_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_GNR_CON1), [CSI2PHY_COMBO_S0D2_ANA_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_ANA_CON1), [CSI2PHY_COMBO_S0D2_ANA_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_ANA_CON2), [CSI2PHY_COMBO_S0D2_ANA_CON3] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_ANA_CON3), [CSI2PHY_COMBO_S0D2_ANA_CON6] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_ANA_CON6), [CSI2PHY_COMBO_S0D2_ANA_CON7] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_ANA_CON7), [CSI2PHY_COMBO_S0D2_DESKEW_CON0] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_DESKEW_CON0), [CSI2PHY_COMBO_S0D2_DESKEW_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_DESKEW_CON2), [CSI2PHY_COMBO_S0D2_DESKEW_CON4] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_DESKEW_CON4), [CSI2PHY_COMBO_S0D2_CRC_CON1] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_CRC_CON1), [CSI2PHY_COMBO_S0D2_CRC_CON2] = CSI2PHY_REG(CSI2_DCPHY_COMBO_S0D2_CRC_CON2), [CSI2PHY_S0D3_GNR_CON1] = CSI2PHY_REG(CSI2_DCPHY_S0D3_GNR_CON1), [CSI2PHY_S0D3_ANA_CON1] = CSI2PHY_REG(CSI2_DCPHY_S0D3_ANA_CON1), [CSI2PHY_S0D3_ANA_CON2] = CSI2PHY_REG(CSI2_DCPHY_S0D3_ANA_CON2), [CSI2PHY_S0D3_ANA_CON3] = CSI2PHY_REG(CSI2_DCPHY_S0D3_ANA_CON3), [CSI2PHY_S0D3_DESKEW_CON0] = CSI2PHY_REG(CSI2_DCPHY_S0D3_DESKEW_CON0), [CSI2PHY_S0D3_DESKEW_CON2] = CSI2PHY_REG(CSI2_DCPHY_S0D3_DESKEW_CON2), [CSI2PHY_S0D3_DESKEW_CON4] = CSI2PHY_REG(CSI2_DCPHY_S0D3_DESKEW_CON4), }; static const struct grf_reg rk3562_grf_dphy_regs[] = { [GRF_DPHY_CSI2PHY_FORCERXMODE] = GRF_REG(RK3562_GRF_VI_CON0, 4, 0), [GRF_DPHY_CSI2PHY_DATALANE_EN] = GRF_REG(RK3562_GRF_VI_CON0, 4, 4), [GRF_DPHY_CSI2PHY_DATALANE_EN0] = GRF_REG(RK3562_GRF_VI_CON0, 2, 4), [GRF_DPHY_CSI2PHY_DATALANE_EN1] = GRF_REG(RK3562_GRF_VI_CON0, 2, 6), [GRF_DPHY_CSI2PHY_CLKLANE_EN] = GRF_REG(RK3562_GRF_VI_CON0, 1, 8), [GRF_DPHY_CLK_INV_SEL] = GRF_REG(RK3562_GRF_VI_CON0, 1, 9), [GRF_DPHY_CSI2PHY_CLKLANE1_EN] = GRF_REG(RK3562_GRF_VI_CON0, 1, 10), [GRF_DPHY_CLK1_INV_SEL] = GRF_REG(RK3562_GRF_VI_CON0, 1, 11), [GRF_DPHY_CSI2PHY_LANE_SEL] = GRF_REG(RK3562_GRF_VI_CON0, 1, 12), [GRF_DPHY_CSI2PHY1_LANE_SEL] = GRF_REG(RK3562_GRF_VI_CON0, 1, 13), [GRF_DPHY1_CSI2PHY_FORCERXMODE] = GRF_REG(RK3562_GRF_VI_CON1, 4, 0), [GRF_DPHY1_CSI2PHY_DATALANE_EN] = GRF_REG(RK3562_GRF_VI_CON1, 4, 4), [GRF_DPHY1_CSI2PHY_DATALANE_EN0] = GRF_REG(RK3562_GRF_VI_CON1, 2, 4), [GRF_DPHY1_CSI2PHY_DATALANE_EN1] = GRF_REG(RK3562_GRF_VI_CON1, 2, 6), [GRF_DPHY1_CSI2PHY_CLKLANE_EN] = GRF_REG(RK3562_GRF_VI_CON1, 1, 8), [GRF_DPHY1_CLK_INV_SEL] = GRF_REG(RK3562_GRF_VI_CON1, 1, 9), [GRF_DPHY1_CSI2PHY_CLKLANE1_EN] = GRF_REG(RK3562_GRF_VI_CON1, 1, 10), [GRF_DPHY1_CLK1_INV_SEL] = GRF_REG(RK3562_GRF_VI_CON1, 1, 11), }; static const struct csi2dphy_reg rk3562_csi2dphy_regs[] = { [CSI2PHY_REG_CTRL_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CTRL_LANE_ENABLE), [CSI2PHY_DUAL_CLK_EN] = CSI2PHY_REG(CSI2_DPHY_DUAL_CAL_EN), [CSI2PHY_CLK_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK_WR_THS_SETTLE), [CSI2PHY_CLK_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK_CALIB_EN), [CSI2PHY_LANE0_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_WR_THS_SETTLE), [CSI2PHY_LANE0_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE0_CALIB_EN), [CSI2PHY_LANE1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_WR_THS_SETTLE), [CSI2PHY_LANE1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE1_CALIB_EN), [CSI2PHY_LANE2_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_WR_THS_SETTLE), [CSI2PHY_LANE2_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE2_CALIB_EN), [CSI2PHY_LANE3_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_WR_THS_SETTLE), [CSI2PHY_LANE3_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_LANE3_CALIB_EN), [CSI2PHY_CLK1_THS_SETTLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_WR_THS_SETTLE), [CSI2PHY_CLK1_CALIB_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_CALIB_EN), [CSI2PHY_CLK1_LANE_ENABLE] = CSI2PHY_REG(CSI2_DPHY_CLK1_LANE_EN), }; static const struct grf_reg rk3576_grf_dphy_regs[] = { [GRF_DPHY_CSI2PHY_FORCERXMODE] = GRF_REG(GRF_DPHY_CON0, 4, 0), [GRF_DPHY_CSI2PHY_DATALANE_EN] = GRF_REG(GRF_DPHY_CON0, 4, 4), [GRF_DPHY_CSI2PHY_DATALANE_EN0] = GRF_REG(GRF_DPHY_CON0, 2, 4), [GRF_DPHY_CSI2PHY_DATALANE_EN1] = GRF_REG(GRF_DPHY_CON0, 2, 6), [GRF_DPHY_CSI2PHY_CLKLANE_EN] = GRF_REG(GRF_DPHY_CON0, 1, 8), [GRF_DPHY_CLK_INV_SEL] = GRF_REG(GRF_DPHY_CON0, 1, 9), [GRF_DPHY_CSI2PHY_CLKLANE1_EN] = GRF_REG(GRF_DPHY_CON0, 1, 10), [GRF_DPHY_CLK1_INV_SEL] = GRF_REG(GRF_DPHY_CON0, 1, 11), [GRF_DPHY_CSI2PHY_LANE_SEL] = GRF_REG(GRF_SOC_CON5_RK3576, 1, 1), [GRF_DPHY_CSI2PHY1_LANE_SEL] = GRF_REG(GRF_SOC_CON5_RK3576, 1, 2), }; //define dcphy params static struct rkmodule_csi_dphy_param rk3588_dcphy_param = { .vendor = PHY_VENDOR_SAMSUNG, .lp_vol_ref = 3, .lp_hys_sw = {3, 0, 0, 0}, .lp_escclk_pol_sel = {1, 0, 0, 0}, .skew_data_cal_clk = {0, 3, 3, 3}, .clk_hs_term_sel = 2, .data_hs_term_sel = {2, 2, 2, 2}, .reserved = {0}, }; /* These tables must be sorted by .range_h ascending. */ static const struct hsfreq_range rk3568_csi2_dphy_hw_hsfreq_ranges[] = { { 109, 0x02}, { 149, 0x03}, { 199, 0x06}, { 249, 0x06}, { 299, 0x06}, { 399, 0x08}, { 499, 0x0b}, { 599, 0x0e}, { 699, 0x10}, { 799, 0x12}, { 999, 0x16}, {1199, 0x1e}, {1399, 0x23}, {1599, 0x2d}, {1799, 0x32}, {1999, 0x37}, {2199, 0x3c}, {2399, 0x41}, {2499, 0x46} }; /* These tables must be sorted by .range_h ascending. */ static const struct hsfreq_range rk3588_csi2_dcphy_d_hw_hsfreq_ranges[] = { { 80, 0x105}, { 100, 0x106}, { 120, 0x107}, { 140, 0x108}, { 160, 0x109}, { 180, 0x10a}, { 200, 0x10b}, { 220, 0x10c}, { 240, 0x10d}, { 270, 0x10e}, { 290, 0x10f}, { 310, 0x110}, { 330, 0x111}, { 350, 0x112}, { 370, 0x113}, { 390, 0x114}, { 410, 0x115}, { 430, 0x116}, { 450, 0x117}, { 470, 0x118}, { 490, 0x119}, { 510, 0x11a}, { 540, 0x11b}, { 560, 0x11c}, { 580, 0x11d}, { 600, 0x11e}, { 620, 0x11f}, { 640, 0x120}, { 660, 0x121}, { 680, 0x122}, { 700, 0x123}, { 720, 0x124}, { 740, 0x125}, { 760, 0x126}, { 790, 0x127}, { 810, 0x128}, { 830, 0x129}, { 850, 0x12a}, { 870, 0x12b}, { 890, 0x12c}, { 910, 0x12d}, { 930, 0x12e}, { 950, 0x12f}, { 970, 0x130}, { 990, 0x131}, {1010, 0x132}, {1030, 0x133}, {1060, 0x134}, {1080, 0x135}, {1100, 0x136}, {1120, 0x137}, {1140, 0x138}, {1160, 0x139}, {1180, 0x13a}, {1200, 0x13b}, {1220, 0x13c}, {1240, 0x13d}, {1260, 0x13e}, {1280, 0x13f}, {1310, 0x140}, {1330, 0x141}, {1350, 0x142}, {1370, 0x143}, {1390, 0x144}, {1410, 0x145}, {1430, 0x146}, {1450, 0x147}, {1470, 0x148}, {1490, 0x149}, {1580, 0x007}, {1740, 0x008}, {1910, 0x009}, {2070, 0x00a}, {2240, 0x00b}, {2410, 0x00c}, {2570, 0x00d}, {2740, 0x00e}, {2910, 0x00f}, {3070, 0x010}, {3240, 0x011}, {3410, 0x012}, {3570, 0x013}, {3740, 0x014}, {3890, 0x015}, {4070, 0x016}, {4240, 0x017}, {4400, 0x018}, {4500, 0x019}, }; static struct csi2_dphy_hw rk3568_csi2_dphy_hw = { .dphy_clks = rk3568_csi2_dphy_hw_clks, .num_dphy_clks = ARRAY_SIZE(rk3568_csi2_dphy_hw_clks), .csi2_clks = rk3568_csi2_clks, .num_csi2_clks = ARRAY_SIZE(rk3568_csi2_clks), .csi2_rsts = rk3568_csi2_rsts, .num_csi2_rsts = ARRAY_SIZE(rk3568_csi2_rsts), .hsfreq_ranges = rk3568_csi2_dphy_hw_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3568_csi2_dphy_hw_hsfreq_ranges), .csi2dphy_regs = rk3568_csi2dphy_regs, .grf_regs = rk3568_grf_dphy_regs, .chip_id = CHIP_ID_RK3568, }; static struct csi2_dphy_hw rk3588_csi2_dphy_hw = { .dphy_clks = rk3588_csi2_dphy_hw_clks, .num_dphy_clks = ARRAY_SIZE(rk3588_csi2_dphy_hw_clks), .dphy_rsts = rk3588_csi2_dphy_hw_rsts, .num_dphy_rsts = ARRAY_SIZE(rk3588_csi2_dphy_hw_rsts), .csi2_clks = rk3588_csi2_clks, .num_csi2_clks = ARRAY_SIZE(rk3588_csi2_clks), .csi2_rsts = rk3588_csi2_rsts, .num_csi2_rsts = ARRAY_SIZE(rk3588_csi2_rsts), .hsfreq_ranges = rk3568_csi2_dphy_hw_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3568_csi2_dphy_hw_hsfreq_ranges), .csi2dphy_regs = rk3588_csi2dphy_regs, .grf_regs = rk3588_grf_dphy_regs, .chip_id = CHIP_ID_RK3588, }; static struct csi2_dphy_hw rk3588_csi2_dcphy_hw = { .dphy_clks = rk3588_csi2_dphy_hw_clks, .num_dphy_clks = ARRAY_SIZE(rk3588_csi2_dphy_hw_clks), .csi2_clks = rk3588_csi2_dcphy_clks, .num_csi2_clks = ARRAY_SIZE(rk3588_csi2_dcphy_clks), .csi2_rsts = rk3588_csi2_rsts, .num_csi2_rsts = ARRAY_SIZE(rk3588_csi2_rsts), .hsfreq_ranges = rk3588_csi2_dcphy_d_hw_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3588_csi2_dcphy_d_hw_hsfreq_ranges), .csi2dphy_regs = rk3588_csi2dcphy_regs, .grf_regs = rk3588_grf_dcphy_regs, .chip_id = CHIP_ID_RK3588_DCPHY, }; static struct csi2_dphy_hw rk3562_csi2_dphy_hw = { .dphy_clks = rk3562_csi2_dphy_hw_clks, .num_dphy_clks = ARRAY_SIZE(rk3562_csi2_dphy_hw_clks), .dphy_rsts = rk3562_csi2_dphy_hw_rsts, .num_dphy_rsts = ARRAY_SIZE(rk3562_csi2_dphy_hw_rsts), .csi2_clks = rk3562_csi2_clks, .num_csi2_clks = ARRAY_SIZE(rk3562_csi2_clks), .csi2_rsts = rk3562_csi2_rsts, .num_csi2_rsts = ARRAY_SIZE(rk3562_csi2_rsts), .hsfreq_ranges = rk3568_csi2_dphy_hw_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3568_csi2_dphy_hw_hsfreq_ranges), .csi2dphy_regs = rk3562_csi2dphy_regs, .grf_regs = rk3562_grf_dphy_regs, .chip_id = CHIP_ID_RK3562, }; static struct csi2_dphy_hw rk3576_csi2_dphy_hw = { .dphy_clks = rk3576_csi2_dphy_hw_clks, .num_dphy_clks = ARRAY_SIZE(rk3576_csi2_dphy_hw_clks), .dphy_rsts = rk3576_csi2_dphy_hw_rsts, .num_dphy_rsts = ARRAY_SIZE(rk3576_csi2_dphy_hw_rsts), .csi2_clks = rk3576_csi2_clks, .num_csi2_clks = ARRAY_SIZE(rk3576_csi2_clks), .csi2_rsts = rk3576_csi2_rsts, .num_csi2_rsts = ARRAY_SIZE(rk3576_csi2_rsts), .hsfreq_ranges = rk3568_csi2_dphy_hw_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3568_csi2_dphy_hw_hsfreq_ranges), .csi2dphy_regs = rk3588_csi2dphy_regs, .grf_regs = rk3576_grf_dphy_regs, .chip_id = CHIP_ID_RK3576, }; static struct csi2_dphy_hw rk3576_csi2_dcphy_hw = { .dphy_clks = rk3576_csi2_dphy_hw_clks, .num_dphy_clks = ARRAY_SIZE(rk3576_csi2_dphy_hw_clks), .csi2_clks = rk3576_csi2_dcphy_clks, .num_csi2_clks = ARRAY_SIZE(rk3576_csi2_dcphy_clks), .csi2_rsts = rk3576_csi2_rsts, .num_csi2_rsts = ARRAY_SIZE(rk3576_csi2_rsts), .hsfreq_ranges = rk3588_csi2_dcphy_d_hw_hsfreq_ranges, .num_hsfreq_ranges = ARRAY_SIZE(rk3588_csi2_dcphy_d_hw_hsfreq_ranges), .csi2dphy_regs = rk3588_csi2dcphy_regs, .grf_regs = rk3588_grf_dcphy_regs, .chip_id = CHIP_ID_RK3588_DCPHY, }; static const struct cif_input_fmt in_fmts[] = { { .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .dvp_fmt_val = YUV_INPUT_422 | YUV_INPUT_ORDER_YUYV, .csi_fmt_val = CSI_WRDDR_TYPE_YUV422, .csi_yuv_order = CSI_YUV_INPUT_ORDER_YUYV, .fmt_type = CIF_FMT_TYPE_YUV, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8, .dvp_fmt_val = YUV_INPUT_422 | YUV_INPUT_ORDER_YUYV, .csi_fmt_val = CSI_WRDDR_TYPE_YUV422, .csi_yuv_order = CSI_YUV_INPUT_ORDER_YUYV, .fmt_type = CIF_FMT_TYPE_YUV, .field = V4L2_FIELD_INTERLACED, }, { .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, .dvp_fmt_val = YUV_INPUT_422 | YUV_INPUT_ORDER_YVYU, .csi_fmt_val = CSI_WRDDR_TYPE_YUV422, .csi_yuv_order = CSI_YUV_INPUT_ORDER_YVYU, .fmt_type = CIF_FMT_TYPE_YUV, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8, .dvp_fmt_val = YUV_INPUT_422 | YUV_INPUT_ORDER_YVYU, .csi_fmt_val = CSI_WRDDR_TYPE_YUV422, .csi_yuv_order = CSI_YUV_INPUT_ORDER_YVYU, .fmt_type = CIF_FMT_TYPE_YUV, .field = V4L2_FIELD_INTERLACED, }, { .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .dvp_fmt_val = YUV_INPUT_422 | YUV_INPUT_ORDER_UYVY, .csi_fmt_val = CSI_WRDDR_TYPE_YUV422, .csi_yuv_order = CSI_YUV_INPUT_ORDER_UYVY, .fmt_type = CIF_FMT_TYPE_YUV, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8, .dvp_fmt_val = YUV_INPUT_422 | YUV_INPUT_ORDER_UYVY, .csi_fmt_val = CSI_WRDDR_TYPE_YUV422, .csi_yuv_order = CSI_YUV_INPUT_ORDER_UYVY, .fmt_type = CIF_FMT_TYPE_YUV, .field = V4L2_FIELD_INTERLACED, }, { .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, .dvp_fmt_val = YUV_INPUT_422 | YUV_INPUT_ORDER_VYUY, .csi_fmt_val = CSI_WRDDR_TYPE_YUV422, .csi_yuv_order = CSI_YUV_INPUT_ORDER_VYUY, .fmt_type = CIF_FMT_TYPE_YUV, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8, .dvp_fmt_val = YUV_INPUT_422 | YUV_INPUT_ORDER_VYUY, .csi_fmt_val = CSI_WRDDR_TYPE_YUV422, .csi_yuv_order = CSI_YUV_INPUT_ORDER_VYUY, .fmt_type = CIF_FMT_TYPE_YUV, .field = V4L2_FIELD_INTERLACED, }, { .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_8, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SGBRG8_1X8, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_8, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_8, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SRGGB8_1X8, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_8, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SBGGR10_1X10, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_10, .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SGBRG10_1X10, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_10, .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_10, .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SRGGB10_1X10, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_10, .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SBGGR12_1X12, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SGBRG12_1X12, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_SRGGB12_1X12, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_RGB888_1X24, .csi_fmt_val = CSI_WRDDR_TYPE_RGB888, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_Y8_1X8, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_8, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_Y10_1X10, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_10, .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, }, { .mbus_code = MEDIA_BUS_FMT_Y12_1X12, .dvp_fmt_val = INPUT_MODE_RAW | RAW_DATA_WIDTH_12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, .field = V4L2_FIELD_NONE, } }; static const struct cif_output_fmt out_fmts[] = { { .fourcc = V4L2_PIX_FMT_NV16, .cplanes = 2, .mplanes = 1, .fmt_val = YUV_OUTPUT_422 | UV_STORAGE_ORDER_UVUV, .bpp = { 8, 16 }, .csi_fmt_val = CSI_WRDDR_TYPE_YUV422, .fmt_type = CIF_FMT_TYPE_YUV, }, { .fourcc = V4L2_PIX_FMT_NV61, .fmt_val = YUV_OUTPUT_422 | UV_STORAGE_ORDER_VUVU, .cplanes = 2, .mplanes = 1, .bpp = { 8, 16 }, .csi_fmt_val = CSI_WRDDR_TYPE_YUV422, .fmt_type = CIF_FMT_TYPE_YUV, }, { .fourcc = V4L2_PIX_FMT_NV12, .fmt_val = YUV_OUTPUT_420 | UV_STORAGE_ORDER_UVUV, .cplanes = 2, .mplanes = 1, .bpp = { 8, 16 }, .csi_fmt_val = CSI_WRDDR_TYPE_YUV420SP, .fmt_type = CIF_FMT_TYPE_YUV, }, { .fourcc = V4L2_PIX_FMT_NV21, .fmt_val = YUV_OUTPUT_420 | UV_STORAGE_ORDER_VUVU, .cplanes = 2, .mplanes = 1, .bpp = { 8, 16 }, .csi_fmt_val = CSI_WRDDR_TYPE_YUV420SP, .fmt_type = CIF_FMT_TYPE_YUV, }, { .fourcc = V4L2_PIX_FMT_YUYV, .cplanes = 2, .mplanes = 1, .bpp = { 8, 16 }, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_YUV, }, { .fourcc = V4L2_PIX_FMT_YVYU, .cplanes = 2, .mplanes = 1, .bpp = { 8, 16 }, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_YUV, }, { .fourcc = V4L2_PIX_FMT_UYVY, .cplanes = 2, .mplanes = 1, .bpp = { 8, 16 }, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_YUV, }, { .fourcc = V4L2_PIX_FMT_VYUY, .cplanes = 2, .mplanes = 1, .bpp = { 8, 16 }, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_YUV, }, { .fourcc = V4L2_PIX_FMT_RGB24, .cplanes = 1, .mplanes = 1, .bpp = { 24 }, .csi_fmt_val = CSI_WRDDR_TYPE_RGB888, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_RGB565, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_BGR666, .cplanes = 1, .mplanes = 1, .bpp = { 18 }, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SRGGB8, .cplanes = 1, .mplanes = 1, .bpp = { 8 }, .raw_bpp = 8, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SGRBG8, .cplanes = 1, .mplanes = 1, .bpp = { 8 }, .raw_bpp = 8, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SGBRG8, .cplanes = 1, .mplanes = 1, .bpp = { 8 }, .raw_bpp = 8, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SBGGR8, .cplanes = 1, .mplanes = 1, .bpp = { 8 }, .raw_bpp = 8, .csi_fmt_val = CSI_WRDDR_TYPE_RAW8, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SRGGB10, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .raw_bpp = 10, .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SGRBG10, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .raw_bpp = 10, .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SGBRG10, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .raw_bpp = 10, .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SBGGR10, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .raw_bpp = 10, .csi_fmt_val = CSI_WRDDR_TYPE_RAW10, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SRGGB12, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .raw_bpp = 12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SGRBG12, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .raw_bpp = 12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SGBRG12, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .raw_bpp = 12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SBGGR12, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .raw_bpp = 12, .csi_fmt_val = CSI_WRDDR_TYPE_RAW12, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_SBGGR16, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .raw_bpp = 16, .fmt_type = CIF_FMT_TYPE_RAW, }, { .fourcc = V4L2_PIX_FMT_Y16, .cplanes = 1, .mplanes = 1, .bpp = { 16 }, .fmt_type = CIF_FMT_TYPE_RAW, } /* TODO: We can support NV12M/NV21M/NV16M/NV61M too */ }; static void rkcif_write_reg(struct vehicle_cif *cif, enum cif_reg_index index, u32 val) { void __iomem *base = cif->base; const struct vehicle_cif_reg *reg = &cif->cif_regs[index]; int csi_offset = 0; if (cif->inf_id == RKCIF_MIPI_LVDS && index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 && index <= CIF_REG_MIPI_ON_PAD) { if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { csi_offset = cif->csi_host_idx * 0x100; } else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) { if (cif->csi_host_idx < 3) csi_offset = cif->csi_host_idx * 0x200; else csi_offset = 0x500; } else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) { if (cif->csi_host_idx < 2) csi_offset = cif->csi_host_idx * 0x200; else csi_offset = 0x100 + cif->csi_host_idx * 0x100; } } if (index < CIF_REG_INDEX_MAX) { if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) { write_reg(base, reg->offset + csi_offset, val); } else { VEHICLE_INFO("write index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n", index, reg->name, val); } } VEHICLE_DG("@%s register[%s] offset(0x%x) csi_offset(0x%x) value:0x%x !\n", __func__, reg->name, reg->offset, csi_offset, val); } static void rkcif_write_reg_or(struct vehicle_cif *cif, enum cif_reg_index index, u32 val) { void __iomem *base = cif->base; const struct vehicle_cif_reg *reg = &cif->cif_regs[index]; unsigned int reg_val = 0x0; int csi_offset = 0; if (cif->inf_id == RKCIF_MIPI_LVDS && index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 && index <= CIF_REG_MIPI_ON_PAD) { if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { csi_offset = cif->csi_host_idx * 0x100; } else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) { if (cif->csi_host_idx < 3) csi_offset = cif->csi_host_idx * 0x200; else csi_offset = 0x500; } else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) { if (cif->csi_host_idx < 2) csi_offset = cif->csi_host_idx * 0x200; else csi_offset = 0x100 + cif->csi_host_idx * 0x100; } } if (index < CIF_REG_INDEX_MAX) { if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) { reg_val = read_reg(base, reg->offset + csi_offset); reg_val |= val; write_reg(base, reg->offset + csi_offset, reg_val); } else { VEHICLE_INFO("write index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n", index, reg->name, val); } } VEHICLE_DG("@%s register[%s] offset(0x%x) csi_offset(0x%x) value:0x%x !\n", __func__, reg->name, reg->offset, csi_offset, reg_val); } static void rkcif_write_reg_and(struct vehicle_cif *cif, enum cif_reg_index index, u32 val) { void __iomem *base = cif->base; const struct vehicle_cif_reg *reg = &cif->cif_regs[index]; unsigned int reg_val = 0x0; int csi_offset = 0; if (cif->inf_id == RKCIF_MIPI_LVDS && index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 && index <= CIF_REG_MIPI_ON_PAD) { if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { csi_offset = cif->csi_host_idx * 0x100; } else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) { if (cif->csi_host_idx < 3) csi_offset = cif->csi_host_idx * 0x200; else csi_offset = 0x500; } else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) { if (cif->csi_host_idx < 2) csi_offset = cif->csi_host_idx * 0x200; else csi_offset = 0x100 + cif->csi_host_idx * 0x100; } } if (index < CIF_REG_INDEX_MAX) { if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) { reg_val = read_reg(base, reg->offset + csi_offset); reg_val &= val; write_reg(base, reg->offset + csi_offset, reg_val); } else { VEHICLE_INFO("write index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n", index, reg->name, val); } } VEHICLE_DG("@%s register[%s] offset(0x%x) csi_offset(0x%x) value:0x%x !\n", __func__, reg->name, reg->offset, csi_offset, reg_val); } static unsigned int rkcif_read_reg(struct vehicle_cif *cif, enum cif_reg_index index) { unsigned int val = 0x0; void __iomem *base = cif->base; const struct vehicle_cif_reg *reg = &cif->cif_regs[index]; int csi_offset = 0; if (cif->inf_id == RKCIF_MIPI_LVDS && index >= CIF_REG_MIPI_LVDS_ID0_CTRL0 && index <= CIF_REG_MIPI_ON_PAD) { if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { csi_offset = cif->csi_host_idx * 0x100; } else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) { if (cif->csi_host_idx < 3) csi_offset = cif->csi_host_idx * 0x200; else csi_offset = 0x500; } else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) { if (cif->csi_host_idx < 2) csi_offset = cif->csi_host_idx * 0x200; else csi_offset = 0x100 + cif->csi_host_idx * 0x100; } } if (index < CIF_REG_INDEX_MAX) { if (index == CIF_REG_GLB_CTRL || index == CIF_REG_DVP_CTRL || reg->offset != 0x0) val = read_reg(base, reg->offset + csi_offset); else VEHICLE_INFO("read index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n", index, reg->name, val); } VEHICLE_DG("@%s register[%s] offset(0x%x) csi_offset(0x%x) value:0x%x !\n", __func__, reg->name, reg->offset, csi_offset, val); return val; } static void rkvehicle_cif_write_grf_reg(struct vehicle_cif *cif, enum cif_reg_index index, u32 val) { const struct vehicle_cif_reg *reg = &cif->cif_regs[index]; if (index < CIF_REG_INDEX_MAX) { if (index > CIF_REG_DVP_CTRL) { if (!IS_ERR(cif->regmap_grf)) regmap_write(cif->regmap_grf, reg->offset, val); } else { VEHICLE_INFO("write index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n", index, reg->name, val); } VEHICLE_DG("@%s reg[%s] offset(0x%x): 0x%x !\n", __func__, reg->name, reg->offset, val); } } static u32 rkvehicle_cif_read_grf_reg(struct vehicle_cif *cif, enum cif_reg_index index) { const struct vehicle_cif_reg *reg = &cif->cif_regs[index]; u32 val = 0xffff; if (index < CIF_REG_INDEX_MAX) { if (index > CIF_REG_DVP_CTRL) { if (!IS_ERR(cif->regmap_grf)) regmap_read(cif->regmap_grf, reg->offset, &val); } else { VEHICLE_INFO("read index(%d) reg[%s]: 0x%x failed, maybe useless!!!\n", index, reg->name, val); } VEHICLE_DG("@%s reg[%s] offset(0x%x): 0x%x !\n", __func__, reg->name, reg->offset, val); } return val; } static inline void write_csi2_dphy_reg(struct csi2_dphy_hw *hw, int index, u32 value) { const struct csi2dphy_reg *reg = &hw->csi2dphy_regs[index]; if ((index == CSI2PHY_REG_CTRL_LANE_ENABLE) || (index == CSI2PHY_CLK_LANE_ENABLE) || ((index != CSI2PHY_REG_CTRL_LANE_ENABLE) && (reg->offset != 0x0))) writel(value, hw->csi2_dphy_base + reg->offset); VEHICLE_DG("@%s offset(0x%x) reg val: 0x%x !\n", __func__, reg->offset, value); } static inline void write_csi2_dphy_reg_mask(struct csi2_dphy_hw *hw, int index, u32 value, u32 mask) { const struct csi2dphy_reg *reg = &hw->csi2dphy_regs[index]; u32 read_val = 0; read_val = readl(hw->csi2_dphy_base + reg->offset); read_val &= ~mask; read_val |= value; writel(read_val, hw->csi2_dphy_base + reg->offset); } static inline void read_csi2_dphy_reg(struct csi2_dphy_hw *hw, int index, u32 *value) { const struct csi2dphy_reg *reg = &hw->csi2dphy_regs[index]; if ((index == CSI2PHY_REG_CTRL_LANE_ENABLE) || (index == CSI2PHY_CLK_LANE_ENABLE) || ((index != CSI2PHY_REG_CTRL_LANE_ENABLE) && (reg->offset != 0x0))) *value = readl(hw->csi2_dphy_base + reg->offset); VEHICLE_DG("@%s offset(0x%x) reg val: 0x%x !\n", __func__, reg->offset, *value); } static void csi_mipidphy_wr_ths_settle(struct csi2_dphy_hw *hw, int hsfreq, enum csi2_dphy_lane lane) { unsigned int val = 0; unsigned int offset; switch (lane) { case CSI2_DPHY_LANE_CLOCK: offset = CSI2PHY_CLK_THS_SETTLE; break; case CSI2_DPHY_LANE_CLOCK1: offset = CSI2PHY_CLK1_THS_SETTLE; break; case CSI2_DPHY_LANE_DATA0: offset = CSI2PHY_LANE0_THS_SETTLE; break; case CSI2_DPHY_LANE_DATA1: offset = CSI2PHY_LANE1_THS_SETTLE; break; case CSI2_DPHY_LANE_DATA2: offset = CSI2PHY_LANE2_THS_SETTLE; break; case CSI2_DPHY_LANE_DATA3: offset = CSI2PHY_LANE3_THS_SETTLE; break; default: return; } read_csi2_dphy_reg(hw, offset, &val); val = (val & ~0x7f) | hsfreq; write_csi2_dphy_reg(hw, offset, val); } static void rkvehicle_cif_cfg_dvp_clk_sampling_edge(struct vehicle_cif *cif, enum rkcif_clk_edge edge) { u32 val = 0x0; if (!IS_ERR(cif->regmap_grf)) { if (cif->chip_id == CHIP_RK3568_VEHICLE_CIF) { if (edge == RKCIF_CLK_RISING) val = RK3568_CIF_PCLK_SAMPLING_EDGE_RISING; else val = RK3568_CIF_PCLK_SAMPLING_EDGE_FALLING; } if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { if (edge == RKCIF_CLK_RISING) val = RK3588_CIF_PCLK_SAMPLING_EDGE_RISING; else val = RK3588_CIF_PCLK_SAMPLING_EDGE_FALLING; } rkvehicle_cif_write_grf_reg(cif, CIF_REG_GRF_CIFIO_CON, val); } } static int rkcif_dvp_get_input_yuv_order(struct vehicle_cfg *cfg) { unsigned int mask; switch (cfg->mbus_code) { case MEDIA_BUS_FMT_UYVY8_2X8: mask = CSI_YUV_INPUT_ORDER_UYVY >> 11; break; case MEDIA_BUS_FMT_VYUY8_2X8: mask = CSI_YUV_INPUT_ORDER_VYUY >> 11; break; case MEDIA_BUS_FMT_YUYV8_2X8: mask = CSI_YUV_INPUT_ORDER_YUYV >> 11; break; case MEDIA_BUS_FMT_YVYU8_2X8: mask = CSI_YUV_INPUT_ORDER_YVYU >> 11; break; default: mask = CSI_YUV_INPUT_ORDER_UYVY >> 11; break; } return mask; } static int cif_stream_setup(struct vehicle_cif *cif) { struct vehicle_cfg *cfg = &cif->cif_cfg; u32 val, mbus_flags, xfer_mode = 0, yc_swap = 0, inputmode = 0, mipimode = 0, input_format = 0, output_format = 0, crop = 0, out_fmt_mask = 0, multi_id_en = BT656_1120_MULTI_ID_DISABLE, multi_id_mode = BT656_1120_MULTI_ID_MODE_1, multi_id_sel = BT656_1120_MULTI_ID_SEL_LSB, bt1120_edge_mode = BT1120_CLOCK_SINGLE_EDGES; u32 sav_detect = BT656_DETECT_SAV; u32 in_fmt_yuv_order = 0; mbus_flags = cfg->mbus_flags; /* set dvp clk sample edge */ if (mbus_flags & V4L2_MBUS_PCLK_SAMPLE_RISING) rkvehicle_cif_cfg_dvp_clk_sampling_edge(cif, RKCIF_CLK_RISING); else rkvehicle_cif_cfg_dvp_clk_sampling_edge(cif, RKCIF_CLK_FALLING); inputmode = cfg->input_format<<2; //INPUT_MODE_YUV or INPUT_MODE_BT656_YUV422 //YUV_INPUT_ORDER_UYVY, MEDIA_BUS_FMT_UYVY8_2X8, CCIR_INPUT_ORDER_ODD input_format = (cfg->yuv_order<<5) | YUV_INPUT_422 | (cfg->field_order<<9); if (cfg->output_format == CIF_OUTPUT_FORMAT_420) output_format = YUV_OUTPUT_420 | UV_STORAGE_ORDER_UVUV; else output_format = YUV_OUTPUT_422 | UV_STORAGE_ORDER_UVUV; if (cif->chip_id == CHIP_RK3568_VEHICLE_CIF) { val = cfg->vsync | (cfg->href<<1) | inputmode | mipimode | input_format | output_format | xfer_mode | yc_swap | multi_id_en | multi_id_sel | multi_id_mode | bt1120_edge_mode; } else { out_fmt_mask = (CSI_WRDDR_TYPE_YUV420SP_RK3588 << 11) | (CSI_YUV_OUTPUT_ORDER_UYVY << 1); in_fmt_yuv_order = rkcif_dvp_get_input_yuv_order(cfg); val = cfg->vsync | (cfg->href<<1) | inputmode | in_fmt_yuv_order | out_fmt_mask | yc_swap | multi_id_en | multi_id_sel | sav_detect | multi_id_mode | bt1120_edge_mode; } if (cif->chip_id >= CHIP_RK3576_VEHICLE_CIF) val |= DVP_UVDS_EN; rkcif_write_reg(cif, CIF_REG_DVP_FOR, val); rkcif_write_reg(cif, CIF_REG_DVP_VIR_LINE_WIDTH, cfg->width); rkcif_write_reg(cif, CIF_REG_DVP_SET_SIZE, cfg->width | (cfg->height << 16)); crop = (cfg->start_x | (cfg->start_y<<16)); rkcif_write_reg(cif, CIF_REG_DVP_CROP, crop); rkcif_write_reg(cif, CIF_REG_DVP_FRAME_STATUS, FRAME_STAT_CLS); if (cif->chip_id < CHIP_RK3588_VEHICLE_CIF) { rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, INTSTAT_CLS); rkcif_write_reg(cif, CIF_REG_DVP_SCL_CTRL, ENABLE_YUV_16BIT_BYPASS); rkcif_write_reg(cif, CIF_REG_DVP_INTEN, FRAME_END_EN | INTSTAT_ERR | PST_INF_FRAME_END); /* enable line int for sof */ rkcif_write_reg(cif, CIF_REG_DVP_LINE_INT_NUM, 0x1); rkcif_write_reg(cif, CIF_REG_DVP_INTEN, LINE_INT_EN); } else if (cif->chip_id < CHIP_RK3576_VEHICLE_CIF) { rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, 0x3c3ffff); rkcif_write_reg_or(cif, CIF_REG_DVP_INTEN, 0x033ffff);//0x3c3ffff } else { rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, 0x3c3ffff); rkcif_write_reg_or(cif, CIF_REG_DVP_INTEN, 0x3c3ff0f); } cif->interlaced_enable = false; return 0; } static inline void csi2_dphy_write_sys_grf_reg(struct csi2_dphy_hw *hw, int index, u8 value) { const struct grf_reg *reg = &hw->grf_regs[index]; unsigned int val = HIWORD_UPDATE(value, reg->mask, reg->shift); if (reg->shift) regmap_write(hw->regmap_sys_grf, reg->offset, val); } static inline void csi2_dphy_write_grf_reg(struct csi2_dphy_hw *hw, int index, u8 value) { const struct grf_reg *reg = &hw->grf_regs[index]; unsigned int val = HIWORD_UPDATE(value, reg->mask, reg->shift); if (reg->shift) regmap_write(hw->regmap_grf, reg->offset, val); } static inline u32 csi2_dphy_read_grf_reg(struct csi2_dphy_hw *hw, int index) { const struct grf_reg *reg = &hw->grf_regs[index]; unsigned int val = 0; if (reg->shift) { regmap_read(hw->regmap_grf, reg->offset, &val); val = (val >> reg->shift) & reg->mask; } return val; } static void csi2_dphy_config_dual_mode(struct vehicle_cif *cif) { struct csi2_dphy_hw *hw = cif->dphy_hw; u32 val; val = ~GRF_CSI2PHY_LANE_SEL_SPLIT; if (cif->dphy_hw->phy_index < 3) { csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_DATALANE_EN, GENMASK(cif->cif_cfg.lanes - 1, 0)); csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_CLKLANE_EN, 0x1); if (cif->chip_id != CHIP_RK3588_VEHICLE_CIF && cif->chip_id != CHIP_RK3576_VEHICLE_CIF) csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_LANE_SEL, val); else csi2_dphy_write_sys_grf_reg(hw, GRF_DPHY_CSI2PHY_LANE_SEL, val); } else { if (cif->chip_id <= CHIP_RK3588_VEHICLE_CIF || cif->chip_id == CHIP_RK3576_VEHICLE_CIF) { csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_DATALANE_EN, GENMASK(cif->cif_cfg.lanes - 1, 0)); csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_CLKLANE_EN, 0x1); } else { csi2_dphy_write_grf_reg(hw, GRF_DPHY1_CSI2PHY_DATALANE_EN, GENMASK(cif->cif_cfg.lanes - 1, 0)); csi2_dphy_write_grf_reg(hw, GRF_DPHY1_CSI2PHY_CLKLANE_EN, 0x1); } if (cif->chip_id != CHIP_RK3588_VEHICLE_CIF && cif->chip_id != CHIP_RK3576_VEHICLE_CIF) csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY1_LANE_SEL, val); else csi2_dphy_write_sys_grf_reg(hw, GRF_DPHY_CSI2PHY1_LANE_SEL, val); } } static int vehicle_csi2_dphy_stream_start(struct vehicle_cif *cif) { struct csi2_dphy_hw *hw = cif->dphy_hw; const struct hsfreq_range *hsfreq_ranges = hw->hsfreq_ranges; int num_hsfreq_ranges = hw->num_hsfreq_ranges; int i, hsfreq = 0; u32 val = 0, pre_val; mutex_lock(&hw->mutex); /* set data lane num and enable clock lane */ /* * for rk356x: dphy0 is used just for full mode, * dphy1 is used just for split mode,uses lane0_1, * dphy2 is used just for split mode,uses lane2_3 */ read_csi2_dphy_reg(hw, CSI2PHY_REG_CTRL_LANE_ENABLE, &pre_val); val |= (GENMASK(cif->cif_cfg.lanes - 1, 0) << CSI2_DPHY_CTRL_DATALANE_ENABLE_OFFSET_BIT) | (0x1 << CSI2_DPHY_CTRL_CLKLANE_ENABLE_OFFSET_BIT); val |= pre_val; write_csi2_dphy_reg(hw, CSI2PHY_REG_CTRL_LANE_ENABLE, val); if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { write_csi2_dphy_reg(hw, CSI2PHY_DUAL_CLK_EN, 0x1e); write_csi2_dphy_reg(hw, CSI2PHY_DUAL_CLK_EN, 0x1f); csi2_dphy_config_dual_mode(cif); } /* not into receive mode/wait stopstate */ csi2_dphy_write_grf_reg(hw, GRF_DPHY_CSI2PHY_FORCERXMODE, 0x0); /* enable calibration */ if (hw->data_rate_mbps > 1500) { write_csi2_dphy_reg(hw, CSI2PHY_CLK_CALIB_ENABLE, 0x80); if (cif->cif_cfg.lanes > 0x00) write_csi2_dphy_reg(hw, CSI2PHY_LANE0_CALIB_ENABLE, 0x80); if (cif->cif_cfg.lanes > 0x01) write_csi2_dphy_reg(hw, CSI2PHY_LANE1_CALIB_ENABLE, 0x80); if (cif->cif_cfg.lanes > 0x02) write_csi2_dphy_reg(hw, CSI2PHY_LANE2_CALIB_ENABLE, 0x80); if (cif->cif_cfg.lanes > 0x03) write_csi2_dphy_reg(hw, CSI2PHY_LANE3_CALIB_ENABLE, 0x80); } /* set clock lane and data lane */ for (i = 0; i < num_hsfreq_ranges; i++) { if (hsfreq_ranges[i].range_h >= hw->data_rate_mbps) { hsfreq = hsfreq_ranges[i].cfg_bit; break; } } if (i == num_hsfreq_ranges) { i = num_hsfreq_ranges - 1; dev_warn(hw->dev, "data rate: %lld mbps, max support %d mbps", hw->data_rate_mbps, hsfreq_ranges[i].range_h + 1); hsfreq = hsfreq_ranges[i].cfg_bit; } VEHICLE_DG("mipi data_rate_mbps %lld, matched bit(0x%0x), lanes(%d)\n", hw->data_rate_mbps, hsfreq, cif->cif_cfg.lanes); csi_mipidphy_wr_ths_settle(hw, hsfreq, CSI2_DPHY_LANE_CLOCK); if (cif->cif_cfg.lanes > 0x00) csi_mipidphy_wr_ths_settle(hw, hsfreq, CSI2_DPHY_LANE_DATA0); if (cif->cif_cfg.lanes > 0x01) csi_mipidphy_wr_ths_settle(hw, hsfreq, CSI2_DPHY_LANE_DATA1); if (cif->cif_cfg.lanes > 0x02) csi_mipidphy_wr_ths_settle(hw, hsfreq, CSI2_DPHY_LANE_DATA2); if (cif->cif_cfg.lanes > 0x03) csi_mipidphy_wr_ths_settle(hw, hsfreq, CSI2_DPHY_LANE_DATA3); atomic_inc(&hw->stream_cnt); mutex_unlock(&hw->mutex); return 0; } static void vehicle_samsung_dcphy_rx_config_settle(struct vehicle_cif *cif) { struct csi2_dphy_hw *hw = cif->dphy_hw; struct samsung_mipi_dcphy *samsung = hw->samsung_phy; const struct hsfreq_range *hsfreq_ranges = NULL; int num_hsfreq_ranges = 0; int i, hsfreq = 0; u32 sot_sync = 0; if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { hsfreq_ranges = hw->hsfreq_ranges; num_hsfreq_ranges = hw->num_hsfreq_ranges; sot_sync = 0x03; } /* set data lane */ for (i = 0; i < num_hsfreq_ranges; i++) { if (hsfreq_ranges[i].range_h >= hw->data_rate_mbps) { hsfreq = hsfreq_ranges[i].cfg_bit; break; } } /*clk settle fix to 0x301*/ if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) regmap_write(samsung->regmap, RX_CLK_THS_SETTLE, 0x301); if (cif->cif_cfg.lanes > 0x00) { regmap_update_bits(samsung->regmap, RX_LANE0_THS_SETTLE, 0x1ff, hsfreq); regmap_update_bits(samsung->regmap, RX_LANE0_ERR_SOT_SYNC, 0xff, sot_sync); } if (cif->cif_cfg.lanes > 0x01) { regmap_update_bits(samsung->regmap, RX_LANE1_THS_SETTLE, 0x1ff, hsfreq); regmap_update_bits(samsung->regmap, RX_LANE1_ERR_SOT_SYNC, 0xff, sot_sync); } if (cif->cif_cfg.lanes > 0x02) { regmap_update_bits(samsung->regmap, RX_LANE2_THS_SETTLE, 0x1ff, hsfreq); regmap_update_bits(samsung->regmap, RX_LANE2_ERR_SOT_SYNC, 0xff, sot_sync); } if (cif->cif_cfg.lanes > 0x03) { regmap_update_bits(samsung->regmap, RX_LANE3_THS_SETTLE, 0x1ff, hsfreq); regmap_update_bits(samsung->regmap, RX_LANE3_ERR_SOT_SYNC, 0xff, sot_sync); } } static int vehicle_samsung_dcphy_rx_config_common(struct vehicle_cif *cif) { struct csi2_dphy_hw *hw = cif->dphy_hw; struct samsung_mipi_dcphy *samsung = hw->samsung_phy; u32 dlysel = 0; int i = 0; if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { if (hw->data_rate_mbps < 1500) dlysel = 0; else if (hw->data_rate_mbps < 2000) dlysel = 3 << 8; else if (hw->data_rate_mbps < 3000) dlysel = 2 << 8; else if (hw->data_rate_mbps < 4000) dlysel = 1 << 8; else if (hw->data_rate_mbps < 6500) dlysel = 0; if (hw->dphy_param->clk_hs_term_sel > 0x7) { dev_err(hw->dev, "clk_hs_term_sel error param %d\n", hw->dphy_param->clk_hs_term_sel); return -EINVAL; } for (i = 0; i < cif->cif_cfg.lanes; i++) { if (hw->dphy_param->data_hs_term_sel[i] > 0x7) { dev_err(hw->dev, "data_hs_term_sel[%d] error param %d\n", i, hw->dphy_param->data_hs_term_sel[i]); return -EINVAL; } if (hw->dphy_param->lp_hys_sw[i] > 0x3) { dev_err(hw->dev, "lp_hys_sw[%d] error param %d\n", i, hw->dphy_param->lp_hys_sw[i]); return -EINVAL; } if (hw->dphy_param->lp_escclk_pol_sel[i] > 0x1) { dev_err(hw->dev, "lp_escclk_pol_sel[%d] error param %d\n", i, hw->dphy_param->lp_escclk_pol_sel[i]); return -EINVAL; } if (hw->dphy_param->skew_data_cal_clk[i] > 0x1f) { dev_err(hw->dev, "skew_data_cal_clk[%d] error param %d\n", i, hw->dphy_param->skew_data_cal_clk[i]); return -EINVAL; } } regmap_write(samsung->regmap, RX_S0C_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_S0C_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_S0C_ANA_CON2, hw->dphy_param->clk_hs_term_sel); regmap_write(samsung->regmap, RX_S0C_ANA_CON3, 0x0600); if (cif->cif_cfg.lanes > 0x00) { regmap_write(samsung->regmap, RX_COMBO_S0D0_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON2, dlysel | hw->dphy_param->data_hs_term_sel[0]); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON3, 0x0600 | (hw->dphy_param->lp_hys_sw[0] << 4) | (hw->dphy_param->lp_escclk_pol_sel[0] << 11)); regmap_write(samsung->regmap, RX_COMBO_S0D0_ANA_CON7, 0x40); regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON2, hw->dphy_param->skew_data_cal_clk[0]); if (hw->data_rate_mbps >= 1500 && cif->chip_id >= CHIP_RK3576_VEHICLE_CIF) { regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON0, BIT(0)); regmap_write(samsung->regmap, RX_COMBO_S0D0_DESKEW_CON4, 0x81A); } } if (cif->cif_cfg.lanes > 0x01) { regmap_write(samsung->regmap, RX_COMBO_S0D1_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON2, dlysel | hw->dphy_param->data_hs_term_sel[1]); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON3, 0x0600 | (hw->dphy_param->lp_hys_sw[1] << 4) | (hw->dphy_param->lp_escclk_pol_sel[1] << 11)); regmap_write(samsung->regmap, RX_COMBO_S0D1_ANA_CON7, 0x40); regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON2, hw->dphy_param->skew_data_cal_clk[1]); if (hw->data_rate_mbps >= 1500 && cif->chip_id >= CHIP_RK3576_VEHICLE_CIF) { regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON0, BIT(0)); regmap_write(samsung->regmap, RX_COMBO_S0D1_DESKEW_CON4, 0x81A); } } if (cif->cif_cfg.lanes > 0x02) { regmap_write(samsung->regmap, RX_COMBO_S0D2_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON2, dlysel | hw->dphy_param->data_hs_term_sel[2]); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON3, 0x0600 | (hw->dphy_param->lp_hys_sw[2] << 4) | (hw->dphy_param->lp_escclk_pol_sel[2] << 11)); regmap_write(samsung->regmap, RX_COMBO_S0D2_ANA_CON7, 0x40); regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON2, hw->dphy_param->skew_data_cal_clk[2]); if (hw->data_rate_mbps >= 1500 && cif->chip_id >= CHIP_RK3576_VEHICLE_CIF) { regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON0, BIT(0)); regmap_write(samsung->regmap, RX_COMBO_S0D2_DESKEW_CON4, 0x81A); } } if (cif->cif_cfg.lanes > 0x03) { regmap_write(samsung->regmap, RX_S0D3_GNR_CON1, 0x1450); regmap_write(samsung->regmap, RX_S0D3_ANA_CON1, 0x8000); regmap_write(samsung->regmap, RX_S0D3_ANA_CON2, dlysel | hw->dphy_param->data_hs_term_sel[3]); regmap_write(samsung->regmap, RX_S0D3_ANA_CON3, 0x0600 | (hw->dphy_param->lp_hys_sw[3] << 4) | (hw->dphy_param->lp_escclk_pol_sel[3] << 11)); regmap_write(samsung->regmap, RX_S0D3_DESKEW_CON2, hw->dphy_param->skew_data_cal_clk[3]); if (hw->data_rate_mbps >= 1500 && cif->chip_id >= CHIP_RK3576_VEHICLE_CIF) { regmap_write(samsung->regmap, RX_S0D3_DESKEW_CON0, BIT(0)); regmap_write(samsung->regmap, RX_S0D3_DESKEW_CON4, 0x81A); } } } return 0; } static int vehicle_samsung_dcphy_rx_lane_enable(struct vehicle_cif *cif) { struct csi2_dphy_hw *hw = cif->dphy_hw; struct samsung_mipi_dcphy *samsung = hw->samsung_phy; u32 sts; int ret = 0; if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) regmap_update_bits(samsung->regmap, RX_CLK_LANE_ENABLE, PHY_ENABLE, PHY_ENABLE); if (cif->cif_cfg.lanes > 0x00) regmap_update_bits(samsung->regmap, RX_DATA_LANE0_ENABLE, PHY_ENABLE, PHY_ENABLE); if (cif->cif_cfg.lanes > 0x01) regmap_update_bits(samsung->regmap, RX_DATA_LANE1_ENABLE, PHY_ENABLE, PHY_ENABLE); if (cif->cif_cfg.lanes > 0x02) regmap_update_bits(samsung->regmap, RX_DATA_LANE2_ENABLE, PHY_ENABLE, PHY_ENABLE); if (cif->cif_cfg.lanes > 0x03) regmap_update_bits(samsung->regmap, RX_DATA_LANE3_ENABLE, PHY_ENABLE, PHY_ENABLE); /*wait for clk lane ready*/ if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { ret = regmap_read_poll_timeout(samsung->regmap, RX_CLK_LANE_ENABLE, sts, (sts & PHY_READY), 200, 4000); if (ret < 0) { dev_err(samsung->dev, "phy rx clk lane is not locked\n"); return -EINVAL; } } /*wait for data lane ready*/ if (cif->cif_cfg.lanes > 0x00) { ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE0_ENABLE, sts, (sts & PHY_READY), 200, 2000); if (ret < 0) { dev_err(samsung->dev, "phy rx data lane 0 is not locked\n"); return -EINVAL; } } if (cif->cif_cfg.lanes > 0x01) { ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE1_ENABLE, sts, (sts & PHY_READY), 200, 2000); if (ret < 0) { dev_err(samsung->dev, "phy rx data lane 1 is not locked\n"); return -EINVAL; } } if (cif->cif_cfg.lanes > 0x02) { ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE2_ENABLE, sts, (sts & PHY_READY), 200, 2000); if (ret < 0) { dev_err(samsung->dev, "phy rx data lane 2 is not locked\n"); return -EINVAL; } } if (cif->cif_cfg.lanes > 0x03) { ret = regmap_read_poll_timeout(samsung->regmap, RX_DATA_LANE3_ENABLE, sts, (sts & PHY_READY), 200, 2000); if (ret < 0) { dev_err(samsung->dev, "phy rx data lane 3 is not locked\n"); return -EINVAL; } } return 0; } static void vehicle_samsung_mipi_dcphy_bias_block_enable(struct vehicle_cif *cif) { struct csi2_dphy_hw *hw = cif->dphy_hw; struct samsung_mipi_dcphy *samsung = hw->samsung_phy; struct csi2_dphy_hw *csi_dphy = samsung->dphy_vehicle[0]; u32 bias_con2 = 0x3223; if (csi_dphy && csi_dphy->dphy_param->lp_vol_ref != 3 && csi_dphy->dphy_param->lp_vol_ref < 0x7) { bias_con2 &= 0xfffffff8; bias_con2 |= csi_dphy->dphy_param->lp_vol_ref; dev_info(samsung->dev, "rx change lp_vol_ref to %d, it may cause tx exception\n", csi_dphy->dphy_param->lp_vol_ref); } regmap_write(samsung->regmap, BIAS_CON0, 0x0010); regmap_write(samsung->regmap, BIAS_CON1, 0x0110); regmap_write(samsung->regmap, BIAS_CON2, bias_con2); /* default output voltage select: * dphy: 400mv * cphy: 530mv */ if (samsung->c_option) regmap_update_bits(samsung->regmap, BIAS_CON4, I_MUX_SEL_MASK, I_MUX_SEL(2)); } static int vehicle_csi2_dcphy_stream_start(struct vehicle_cif *cif) { struct csi2_dphy_hw *hw = cif->dphy_hw; struct samsung_mipi_dcphy *samsung = hw->samsung_phy; int ret = 0; dev_info(hw->dev, "mipi dcphy stream on\n"); mutex_lock(&hw->mutex); if (samsung->s_phy_rst) reset_control_assert(samsung->s_phy_rst); vehicle_samsung_mipi_dcphy_bias_block_enable(cif); ret = vehicle_samsung_dcphy_rx_config_common(cif); if (ret) goto out_streamon; vehicle_samsung_dcphy_rx_config_settle(cif); ret = vehicle_samsung_dcphy_rx_lane_enable(cif); if (ret) goto out_streamon; if (samsung->s_phy_rst) reset_control_deassert(samsung->s_phy_rst); atomic_inc(&hw->stream_cnt); mutex_unlock(&hw->mutex); return 0; out_streamon: if (samsung->s_phy_rst) reset_control_deassert(samsung->s_phy_rst); mutex_unlock(&hw->mutex); dev_err(hw->dev, "stream on error\n"); return -EINVAL; } static int vehicle_csi2_dcphy_stream_stop(struct vehicle_cif *cif) { struct csi2_dphy_hw *hw = cif->dphy_hw; struct samsung_mipi_dcphy *samsung = hw->samsung_phy; dev_info(hw->dev, "mipi dcphy stream off\n"); if (atomic_dec_return(&hw->stream_cnt)) return 0; mutex_lock(&hw->mutex); if (samsung->s_phy_rst) reset_control_assert(samsung->s_phy_rst); if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) regmap_update_bits(samsung->regmap, RX_CLK_LANE_ENABLE, PHY_ENABLE, 0); if (cif->cif_cfg.lanes > 0x00) regmap_update_bits(samsung->regmap, RX_DATA_LANE0_ENABLE, PHY_ENABLE, 0); if (cif->cif_cfg.lanes > 0x01) regmap_update_bits(samsung->regmap, RX_DATA_LANE1_ENABLE, PHY_ENABLE, 0); if (cif->cif_cfg.lanes > 0x02) regmap_update_bits(samsung->regmap, RX_DATA_LANE2_ENABLE, PHY_ENABLE, 0); if (cif->cif_cfg.lanes > 0x03) regmap_update_bits(samsung->regmap, RX_DATA_LANE3_ENABLE, PHY_ENABLE, 0); if (samsung->s_phy_rst) reset_control_deassert(samsung->s_phy_rst); usleep_range(500, 1000); mutex_unlock(&hw->mutex); return 0; } static void vehicle_csi2_disable(struct vehicle_cif *cif) { void __iomem *base = cif->csi2_base; vehicle_write_csihost_reg(base, CSIHOST_RESETN, 0); vehicle_write_csihost_reg(base, CSIHOST_MSK1, 0xffffffff); vehicle_write_csihost_reg(base, CSIHOST_MSK2, 0xffffffff); } static void vehicle_csi2_enable(struct vehicle_cif *cif, enum host_type_t host_type) { struct csi2_dphy_hw *hw = cif->dphy_hw; void __iomem *base = hw->csi2_base; int lanes = cif->cif_cfg.lanes; vehicle_write_csihost_reg(base, CSIHOST_N_LANES, lanes - 1); if (host_type == RK_DSI_RXHOST) { vehicle_write_csihost_reg(base, CSIHOST_CONTROL, SW_CPHY_EN(0) | SW_DSI_EN(1) | SW_DATATYPE_FS(0x01) | SW_DATATYPE_FE(0x11) | SW_DATATYPE_LS(0x21) | SW_DATATYPE_LE(0x31)); /* Disable some error interrupt when HOST work on DSI RX mode */ vehicle_write_csihost_reg(base, CSIHOST_MSK1, 0xe00000f0); vehicle_write_csihost_reg(base, CSIHOST_MSK2, 0xff00); } else { vehicle_write_csihost_reg(base, CSIHOST_CONTROL, SW_CPHY_EN(0) | SW_DSI_EN(0) | SW_DATATYPE_FS(0x0) | SW_DATATYPE_FE(0x01) | SW_DATATYPE_LS(0x02) | SW_DATATYPE_LE(0x03)); vehicle_write_csihost_reg(base, CSIHOST_MSK1, 0); vehicle_write_csihost_reg(base, CSIHOST_MSK2, 0xf000); } vehicle_write_csihost_reg(base, CSIHOST_RESETN, 1); } static int vehicle_csi2_stream_start(struct vehicle_cif *cif) { struct csi2_dphy_hw *hw = cif->dphy_hw; enum host_type_t host_type; int i; host_type = RK_CSI_RXHOST; vehicle_csi2_enable(cif, host_type); for (i = 0; i < RK_CSI2_ERR_MAX; i++) hw->err_list[i].cnt = 0; return 0; } static void vehicle_cif_csi_get_vc_num(struct vehicle_cif *cif) { int vc_num = 0; unsigned int mbus_flags = cif->cif_cfg.mbus_flags; for (vc_num = 0; vc_num < RKCIF_MAX_CSI_CHANNEL; vc_num++) { if (mbus_flags & V4L2_MBUS_CSI2_CHANNEL_0) { cif->channels[vc_num].vc = vc_num; mbus_flags ^= V4L2_MBUS_CSI2_CHANNEL_0; continue; } if (mbus_flags & V4L2_MBUS_CSI2_CHANNEL_1) { cif->channels[vc_num].vc = vc_num; mbus_flags ^= V4L2_MBUS_CSI2_CHANNEL_1; continue; } if (mbus_flags & V4L2_MBUS_CSI2_CHANNEL_2) { cif->channels[vc_num].vc = vc_num; mbus_flags ^= V4L2_MBUS_CSI2_CHANNEL_2; continue; } if (mbus_flags & V4L2_MBUS_CSI2_CHANNEL_3) { cif->channels[vc_num].vc = vc_num; mbus_flags ^= V4L2_MBUS_CSI2_CHANNEL_3; continue; } } cif->num_channels = vc_num ? (vc_num - 1) : 1; if (cif->num_channels == 1) cif->channels[0].vc = 0; } static const struct cif_input_fmt *find_input_fmt(u32 mbus_code) { const struct cif_input_fmt *fmt; u32 i; for (i = 0; i < ARRAY_SIZE(in_fmts); i++) { fmt = &in_fmts[i]; if (mbus_code == fmt->mbus_code) return fmt; } return NULL; } static const struct cif_output_fmt *find_output_fmt(u32 pixelfmt) { const struct cif_output_fmt *fmt; u32 i; for (i = 0; i < ARRAY_SIZE(out_fmts); i++) { fmt = &out_fmts[i]; if (fmt->fourcc == pixelfmt) return fmt; } return NULL; } static enum cif_reg_index get_reg_index_of_id_ctrl0(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_ID0_CTRL0; break; case 1: index = CIF_REG_MIPI_LVDS_ID1_CTRL0; break; case 2: index = CIF_REG_MIPI_LVDS_ID2_CTRL0; break; case 3: index = CIF_REG_MIPI_LVDS_ID3_CTRL0; break; default: index = CIF_REG_MIPI_LVDS_ID0_CTRL0; break; } return index; } static enum cif_reg_index get_reg_index_of_id_ctrl1(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_ID0_CTRL1; break; case 1: index = CIF_REG_MIPI_LVDS_ID1_CTRL1; break; case 2: index = CIF_REG_MIPI_LVDS_ID2_CTRL1; break; case 3: index = CIF_REG_MIPI_LVDS_ID3_CTRL1; break; default: index = CIF_REG_MIPI_LVDS_ID0_CTRL1; break; } return index; } static enum cif_reg_index get_reg_index_of_frm0_y_addr(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0; break; case 1: index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID1; break; case 2: index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID2; break; case 3: index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID3; break; default: index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0; break; } return index; } static enum cif_reg_index get_reg_index_of_frm_num(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_FRAME_NUM_VC0; break; case 1: index = CIF_REG_MIPI_FRAME_NUM_VC1; break; case 2: index = CIF_REG_MIPI_FRAME_NUM_VC2; break; case 3: index = CIF_REG_MIPI_FRAME_NUM_VC3; break; default: index = CIF_REG_MIPI_FRAME_NUM_VC0; break; } return index; } static enum cif_reg_index get_reg_index_of_frm1_y_addr(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0; break; case 1: index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID1; break; case 2: index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID2; break; case 3: index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID3; break; default: index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0; break; } return index; } static enum cif_reg_index get_reg_index_of_frm0_uv_addr(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0; break; case 1: index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID1; break; case 2: index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID2; break; case 3: index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID3; break; default: index = CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0; break; } return index; } static enum cif_reg_index get_reg_index_of_frm1_uv_addr(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0; break; case 1: index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID1; break; case 2: index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID2; break; case 3: index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID3; break; default: index = CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0; break; } return index; } static enum cif_reg_index get_reg_index_of_frm0_y_vlw(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0; break; case 1: index = CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID1; break; case 2: index = CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID2; break; case 3: index = CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID3; break; default: index = CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0; break; } return index; } static enum cif_reg_index get_reg_index_of_frm1_y_vlw(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0; break; case 1: index = CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID1; break; case 2: index = CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID2; break; case 3: index = CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID3; break; default: index = CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0; break; } return index; } static enum cif_reg_index get_reg_index_of_frm0_uv_vlw(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0; break; case 1: index = CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID1; break; case 2: index = CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID2; break; case 3: index = CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID3; break; default: index = CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0; break; } return index; } static enum cif_reg_index get_reg_index_of_frm1_uv_vlw(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0; break; case 1: index = CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID1; break; case 2: index = CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID2; break; case 3: index = CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID3; break; default: index = CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0; break; } return index; } static enum cif_reg_index get_reg_index_of_id_crop_start(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_MIPI_LVDS_ID0_CROP_START; break; case 1: index = CIF_REG_MIPI_LVDS_ID1_CROP_START; break; case 2: index = CIF_REG_MIPI_LVDS_ID2_CROP_START; break; case 3: index = CIF_REG_MIPI_LVDS_ID3_CROP_START; break; default: index = CIF_REG_MIPI_LVDS_ID0_CROP_START; break; } return index; } static enum cif_reg_index get_dvp_reg_index_of_frm0_y_addr(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_DVP_FRM0_ADDR_Y; break; case 1: index = CIF_REG_DVP_FRM0_ADDR_Y_ID1; break; case 2: index = CIF_REG_DVP_FRM0_ADDR_Y_ID2; break; case 3: index = CIF_REG_DVP_FRM0_ADDR_Y_ID3; break; default: index = CIF_REG_DVP_FRM0_ADDR_Y; break; } return index; } static enum cif_reg_index get_dvp_reg_index_of_frm1_y_addr(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_DVP_FRM1_ADDR_Y; break; case 1: index = CIF_REG_DVP_FRM1_ADDR_Y_ID1; break; case 2: index = CIF_REG_DVP_FRM1_ADDR_Y_ID2; break; case 3: index = CIF_REG_DVP_FRM1_ADDR_Y_ID3; break; default: index = CIF_REG_DVP_FRM0_ADDR_Y; break; } return index; } static enum cif_reg_index get_dvp_reg_index_of_frm0_uv_addr(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_DVP_FRM0_ADDR_UV; break; case 1: index = CIF_REG_DVP_FRM0_ADDR_UV_ID1; break; case 2: index = CIF_REG_DVP_FRM0_ADDR_UV_ID2; break; case 3: index = CIF_REG_DVP_FRM0_ADDR_UV_ID3; break; default: index = CIF_REG_DVP_FRM0_ADDR_UV; break; } return index; } static enum cif_reg_index get_dvp_reg_index_of_frm1_uv_addr(int channel_id) { enum cif_reg_index index; switch (channel_id) { case 0: index = CIF_REG_DVP_FRM1_ADDR_UV; break; case 1: index = CIF_REG_DVP_FRM1_ADDR_UV_ID1; break; case 2: index = CIF_REG_DVP_FRM1_ADDR_UV_ID2; break; case 3: index = CIF_REG_DVP_FRM1_ADDR_UV_ID3; break; default: index = CIF_REG_DVP_FRM1_ADDR_UV; break; } return index; } static unsigned char get_data_type(u32 pixelformat, u8 cmd_mode_en) { switch (pixelformat) { /* csi raw8 */ case MEDIA_BUS_FMT_SBGGR8_1X8: case MEDIA_BUS_FMT_SGBRG8_1X8: case MEDIA_BUS_FMT_SGRBG8_1X8: case MEDIA_BUS_FMT_SRGGB8_1X8: return 0x2a; /* csi raw10 */ case MEDIA_BUS_FMT_SBGGR10_1X10: case MEDIA_BUS_FMT_SGBRG10_1X10: case MEDIA_BUS_FMT_SGRBG10_1X10: case MEDIA_BUS_FMT_SRGGB10_1X10: return 0x2b; /* csi raw12 */ case MEDIA_BUS_FMT_SBGGR12_1X12: case MEDIA_BUS_FMT_SGBRG12_1X12: case MEDIA_BUS_FMT_SGRBG12_1X12: case MEDIA_BUS_FMT_SRGGB12_1X12: return 0x2c; /* csi uyvy 422 */ case MEDIA_BUS_FMT_UYVY8_2X8: case MEDIA_BUS_FMT_VYUY8_2X8: case MEDIA_BUS_FMT_YUYV8_2X8: case MEDIA_BUS_FMT_YVYU8_2X8: return 0x1e; case MEDIA_BUS_FMT_RGB888_1X24: { if (cmd_mode_en) /* dsi command mode*/ return 0x39; else /* dsi video mode */ return 0x3e; } default: return 0x2b; } } #define UV_OFFSET (cif->cif_cfg.width * cif->cif_cfg.height) static int vehicle_cif_init_buffer(struct vehicle_cif *cif, int init, int csi_ch) { struct vehicle_rkcif_dummy_buffer *dummy_buf = &cif->dummy_buf; u32 frm0_addr_y, frm0_addr_uv; u32 frm1_addr_y, frm1_addr_uv; unsigned long y_addr, uv_addr; int i; if (cif->cif_cfg.buf_num < 2) return -EINVAL; if (cif->cif_cfg.buf_num > MAX_BUF_NUM) cif->cif_cfg.buf_num = MAX_BUF_NUM; for (i = 0 ; i < cif->cif_cfg.buf_num; i++) { cif->frame_buf[i] = cif->cif_cfg.buf_phy_addr[i]; if (cif->frame_buf[i] == 0) return -EINVAL; } cif->last_buf_index = 0; cif->current_buf_index = 1; if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { frm0_addr_y = get_reg_index_of_frm0_y_addr(csi_ch); frm0_addr_uv = get_reg_index_of_frm0_uv_addr(csi_ch); frm1_addr_y = get_reg_index_of_frm1_y_addr(csi_ch); frm1_addr_uv = get_reg_index_of_frm1_uv_addr(csi_ch); } else { frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(csi_ch); frm0_addr_uv = get_dvp_reg_index_of_frm0_uv_addr(csi_ch); frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(csi_ch); frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(csi_ch); } spin_lock(&cif->vbq_lock); y_addr = vehicle_flinger_request_cif_buffer(); if (y_addr) { uv_addr = y_addr + UV_OFFSET; rkcif_write_reg(cif, frm0_addr_y, y_addr); rkcif_write_reg(cif, frm0_addr_uv, uv_addr); cif->active[0] = y_addr; } else { rkcif_write_reg(cif, frm0_addr_y, dummy_buf->dma_addr); rkcif_write_reg(cif, frm0_addr_uv, dummy_buf->dma_addr); cif->active[0] = y_addr; } y_addr = vehicle_flinger_request_cif_buffer(); if (y_addr) { uv_addr = y_addr + UV_OFFSET; rkcif_write_reg(cif, frm1_addr_y, y_addr); rkcif_write_reg(cif, frm1_addr_uv, uv_addr); cif->active[1] = y_addr; } else { rkcif_write_reg(cif, frm1_addr_y, dummy_buf->dma_addr); rkcif_write_reg(cif, frm1_addr_uv, dummy_buf->dma_addr); cif->active[1] = y_addr; } if (cif->cif_cfg.type != V4L2_MBUS_CSI2_DPHY) { int ch_id; for (ch_id = 0; ch_id < 4; ch_id++) { if (ch_id == csi_ch) continue; rkcif_write_reg(cif, get_dvp_reg_index_of_frm0_y_addr(ch_id), dummy_buf->dma_addr); rkcif_write_reg(cif, get_dvp_reg_index_of_frm1_y_addr(ch_id), dummy_buf->dma_addr); rkcif_write_reg(cif, get_dvp_reg_index_of_frm0_uv_addr(ch_id), dummy_buf->dma_addr); rkcif_write_reg(cif, get_dvp_reg_index_of_frm1_uv_addr(ch_id), dummy_buf->dma_addr); } } spin_unlock(&cif->vbq_lock); return 0; } static int vehicle_cif_csi_channel_init(struct vehicle_cif *cif, struct vehicle_csi_channel_info *channel) { struct vehicle_cfg *cfg = &cif->cif_cfg; const struct cif_output_fmt *fmt; u32 fourcc; channel->enable = 1; channel->width = cfg->width; channel->height = cfg->height; cif->interlaced_enable = false; channel->cmd_mode_en = 0; /* default use DSI Video Mode */ channel->crop_en = 1; channel->crop_st_x = cfg->start_x; channel->crop_st_y = cfg->start_y; channel->width = cfg->width; channel->height = cfg->height; if (cfg->output_format == CIF_OUTPUT_FORMAT_420) { fmt = find_output_fmt(V4L2_PIX_FMT_NV12); if (!fmt) { VEHICLE_DGERR("can not find output format: 0x%x", V4L2_PIX_FMT_NV12); return -EINVAL; } } else { fmt = find_output_fmt(V4L2_PIX_FMT_NV16); if (!fmt) { VEHICLE_DGERR("can not find output format: 0x%x", V4L2_PIX_FMT_NV16); return -EINVAL; } } channel->fmt_val = fmt->csi_fmt_val; VEHICLE_INFO("%s, LINE=%d, channel->fmt_val = 0x%x, fmt->csi_fmt_val= 0x%x", __func__, __LINE__, channel->fmt_val, fmt->csi_fmt_val); /* * for mipi or lvds, when enable compact, the virtual width of raw10/raw12 * needs aligned with :ALIGN(bits_per_pixel * width / 8, 8), if enable 16bit mode * needs aligned with :ALIGN(bits_per_pixel * width * 2, 8), to optimize reading and * writing of ddr, aligned with 256 */ if (fmt->fmt_type == CIF_FMT_TYPE_RAW && channel->fmt_val != CSI_WRDDR_TYPE_RAW8) channel->virtual_width = ALIGN(channel->width * 2, 8); else channel->virtual_width = ALIGN(channel->width * fmt->bpp[0] / 8, 8); if (channel->fmt_val == CSI_WRDDR_TYPE_RGB888) channel->width = channel->width * fmt->bpp[0] / 8; /* * rk cif don't support output yuyv fmt data * if user request yuyv fmt, the input mode must be RAW8 * and the width is double Because the real input fmt is * yuyv */ fourcc = fmt->fourcc; if (fourcc == V4L2_PIX_FMT_YUYV || fourcc == V4L2_PIX_FMT_YVYU || fourcc == V4L2_PIX_FMT_UYVY || fourcc == V4L2_PIX_FMT_VYUY) { channel->fmt_val = CSI_WRDDR_TYPE_RAW8; channel->width *= 2; channel->virtual_width *= 2; } VEHICLE_DG("%s, LINE=%d, channel->fmt_val = 0x%x", __func__, __LINE__, channel->fmt_val); if (cfg->input_format == CIF_INPUT_FORMAT_PAL || cfg->input_format == CIF_INPUT_FORMAT_NTSC) { VEHICLE_INFO("CVBS IN PAL or NTSC config."); cif->interlaced_enable = true; if (!cif->use_hw_interlace) { channel->virtual_width *= 2; cif->interlaced_offset = channel->width; cif->interlaced_counts = 0; cif->interlaced_buffer = 0; channel->height /= 2; } VEHICLE_INFO("do denterlaced.\n"); } channel->data_type = get_data_type(cfg->mbus_code, channel->cmd_mode_en); return 0; } static int vehicle_cif_csi_channel_set(struct vehicle_cif *cif, struct vehicle_csi_channel_info *channel, enum v4l2_mbus_type mbus_type) { unsigned int val = 0x0; if (channel->id >= 4) return -EINVAL; if (!channel->enable) { rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(channel->id), CSI_DISABLE_CAPTURE); return 0; } rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTSTAT, ~(CSI_START_INTSTAT(channel->id) | CSI_DMA_END_INTSTAT(channel->id) | CSI_LINE_INTSTAT(channel->id))); /* 0. need set CIF_CSI_INTEN to 0x0 first */ rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTEN, 0x0); /* enable id0 frame start int for sof(long frame, for hdr) * vehicle don't need this */ if (channel->id == RKCIF_STREAM_MIPI_ID0) rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN, CSI_START_INTEN(channel->id)); rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1, 0x3fff << 16 | 0x3fff); rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3, 0x3fff << 16 | 0x3fff); rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN, CSI_DMA_END_INTEN(channel->id)); rkcif_write_reg(cif, CIF_REG_MIPI_WATER_LINE, CIF_MIPI_LVDS_SW_WATER_LINE_25_RK1808 | CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE_RK1808 | CIF_MIPI_LVDS_SW_HURRY_VALUE_RK1808(0x3) | CIF_MIPI_LVDS_SW_HURRY_ENABLE_RK1808); val = CIF_MIPI_LVDS_SW_PRESS_VALUE(0x3) | CIF_MIPI_LVDS_SW_PRESS_ENABLE | CIF_MIPI_LVDS_SW_HURRY_VALUE(0x3) | CIF_MIPI_LVDS_SW_HURRY_ENABLE | CIF_MIPI_LVDS_SW_WATER_LINE_25 | CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE; val &= ~CIF_MIPI_LVDS_SW_SEL_LVDS; rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_CTRL, val); rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN, CSI_ALL_ERROR_INTEN); rkcif_write_reg(cif, get_reg_index_of_id_ctrl1(channel->id), channel->width | (channel->height << 16)); rkcif_write_reg(cif, get_reg_index_of_frm0_y_vlw(channel->id), channel->virtual_width); rkcif_write_reg(cif, get_reg_index_of_frm1_y_vlw(channel->id), channel->virtual_width); rkcif_write_reg(cif, get_reg_index_of_frm0_uv_vlw(channel->id), channel->virtual_width); rkcif_write_reg(cif, get_reg_index_of_frm1_uv_vlw(channel->id), channel->virtual_width); if (channel->crop_en) rkcif_write_reg(cif, get_reg_index_of_id_crop_start(channel->id), channel->crop_st_y << 16 | channel->crop_st_x); return 0; } /*config reg for rk3588*/ static int vehicle_cif_csi_channel_set_v1(struct vehicle_cif *cif, struct vehicle_csi_channel_info *channel, enum v4l2_mbus_type mbus_type) { unsigned int val = 0x0; if (channel->id >= 4) return -EINVAL; if (!channel->enable) { rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(channel->id), CSI_DISABLE_CAPTURE); return 0; } rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTSTAT, ~(CSI_START_INTSTAT(channel->id) | CSI_DMA_END_INTSTAT(channel->id) | CSI_LINE_INTSTAT_V1(channel->id))); /* enable id0 frame start int for sof(long frame, for hdr) * vehicle don't need this */ if (channel->id == RKCIF_STREAM_MIPI_ID0) rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN, CSI_START_INTEN(channel->id)); rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1, 0x3fff << 16 | 0x3fff); rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3, 0x3fff << 16 | 0x3fff); rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN, CSI_DMA_END_INTEN(channel->id)); if (cif->chip_id > CHIP_RK3562_VEHICLE_CIF) { val = CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE | (CIF_MIPI_LVDS_SW_WATER_LINE_25 << 19); rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_CTRL, val); } else { val = CIF_MIPI_LVDS_SW_PRESS_VALUE_RK3588(0x3) | CIF_MIPI_LVDS_SW_PRESS_ENABLE | CIF_MIPI_LVDS_SW_HURRY_VALUE_RK3588(0x3) | CIF_MIPI_LVDS_SW_HURRY_ENABLE | CIF_MIPI_LVDS_SW_WATER_LINE_25 | CIF_MIPI_LVDS_SW_WATER_LINE_ENABLE; rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_CTRL, val); } rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTEN, CSI_ALL_ERROR_INTEN_V1); if (cif->chip_id < CHIP_RK3576_VEHICLE_CIF) rkcif_write_reg(cif, get_reg_index_of_id_ctrl1(channel->id), (channel->width) | (channel->height << 16)); else rkcif_write_reg(cif, CIF_REG_MIPI_SET_SIZE_ID0 + channel->id, (channel->width) | (channel->height << 16)); rkcif_write_reg(cif, get_reg_index_of_frm0_y_vlw(channel->id), channel->virtual_width); if (channel->crop_en) rkcif_write_reg(cif, get_reg_index_of_id_crop_start(channel->id), channel->crop_st_y << 16 | channel->crop_st_x); return 0; } static int vehicle_cif_stream_start(struct vehicle_cif *cif) { struct vehicle_csi_channel_info *channel; vehicle_cif_csi_get_vc_num(cif); /* just need init virtual channel 0 */ channel = &cif->channels[0]; channel->id = 0; vehicle_cif_csi_channel_init(cif, channel); if (cif->chip_id < CHIP_RK3588_VEHICLE_CIF) vehicle_cif_csi_channel_set(cif, channel, V4L2_MBUS_CSI2_DPHY); else vehicle_cif_csi_channel_set_v1(cif, channel, V4L2_MBUS_CSI2_DPHY); return 0; } static int cif_csi_stream_setup(struct vehicle_cif *cif) { vehicle_csi2_stream_start(cif); if (cif->dphy_hw->chip_id == CHIP_ID_RK3588_DCPHY) vehicle_csi2_dcphy_stream_start(cif); else vehicle_csi2_dphy_stream_start(cif); vehicle_cif_stream_start(cif); return 0; } static void vehicle_csi2_dphy_hw_do_reset(struct vehicle_cif *cif) { unsigned int i; struct csi2_dphy_hw *dphy_hw = cif->dphy_hw; for (i = 0; i < dphy_hw->num_dphy_rsts; i++) if (dphy_hw->dphy_rst[i]) reset_control_assert(dphy_hw->dphy_rst[i]); udelay(5); for (i = 0; i < dphy_hw->num_dphy_rsts; i++) if (dphy_hw->dphy_rst[i]) reset_control_deassert(dphy_hw->dphy_rst[i]); } static void vehicle_csi2_hw_soft_reset(struct vehicle_cif *cif) { unsigned int i; struct csi2_dphy_hw *dphy_hw = cif->dphy_hw; for (i = 0; i < dphy_hw->num_csi2_rsts; i++) if (dphy_hw->csi2_rst[i]) reset_control_assert(dphy_hw->csi2_rst[i]); udelay(5); for (i = 0; i < dphy_hw->num_csi2_rsts; i++) if (dphy_hw->csi2_rst[i]) reset_control_deassert(dphy_hw->csi2_rst[i]); } static int vehicle_csi2_dphy_stream_stop(struct vehicle_cif *cif) { struct csi2_dphy_hw *hw = cif->dphy_hw; mutex_lock(&hw->mutex); write_csi2_dphy_reg(hw, CSI2PHY_REG_CTRL_LANE_ENABLE, 0x01); if (cif->dphy_hw->chip_id >= CHIP_ID_RK3588) vehicle_csi2_dphy_hw_do_reset(cif); usleep_range(500, 1000); mutex_unlock(&hw->mutex); return 0; } static void vehicle_rkcif_disable_sys_clk(struct rk_cif_clk *clk) { int i; for (i = clk->clks_num - 1; i >= 0; i--) clk_disable_unprepare(clk->clks[i]); } static int vehicle_rkcif_enable_sys_clk(struct rk_cif_clk *clk) { int i, ret = -EINVAL; for (i = 0; i < clk->clks_num; i++) { ret = clk_prepare_enable(clk->clks[i]); if (ret < 0) goto err; } return 0; err: for (--i; i >= 0; --i) clk_disable_unprepare(clk->clks[i]); return ret; } /* sensor mclk set */ static void rkcif_s_mclk(struct vehicle_cif *cif, int on, int clk_rate) { int err = 0; struct device *dev = cif->dev; struct rk_cif_clk *clk = &cif->clk; //return ; if (on && !clk->on) { if (!IS_ERR(clk->xvclk)) { err = clk_set_rate(clk->xvclk, clk_rate); if (err < 0) dev_err(dev, "Failed to set xvclk rate (24MHz)\n"); } if (!IS_ERR(clk->xvclk)) { err = clk_prepare_enable(clk->xvclk); if (err < 0) dev_err(dev, "Failed to enable xvclk\n"); } } else { if (!IS_ERR(clk->xvclk)) clk_disable_unprepare(clk->xvclk); } usleep_range(2000, 5000); } static int rk_cif_mclk_ctrl(struct vehicle_cif *cif, int on, int clk_rate) { int err = 0; struct rk_cif_clk *clk = &cif->clk; if (on && !clk->on) { vehicle_rkcif_enable_sys_clk(clk); clk->on = true; } else if (!on && clk->on) { vehicle_rkcif_disable_sys_clk(clk); clk->on = false; } return err; } static void csi2_disable_dphy_clk(struct csi2_dphy_hw *hw) { int i; for (i = hw->num_dphy_clks - 1; i >= 0; i--) { clk_disable_unprepare(hw->dphy_clks[i].clk); VEHICLE_INFO("%s(%d) disable dphy clk: %s\n", __func__, __LINE__, hw->dphy_clks[i].id); } } static int csi2_enable_dphy_clk(struct csi2_dphy_hw *hw) { int i, ret = -EINVAL; for (i = 0; i < hw->num_dphy_clks; i++) { ret = clk_prepare_enable(hw->dphy_clks[i].clk); if (ret < 0) goto err; VEHICLE_INFO("%s(%d) enable dphy clk: %s\n", __func__, __LINE__, hw->dphy_clks[i].id); } return 0; err: VEHICLE_DGERR("%s(%d) enable dphy clk: %s err\n", __func__, __LINE__, hw->dphy_clks[i].id); for (--i; i >= 0; --i) clk_disable_unprepare(hw->dphy_clks[i].clk); return ret; } static void csi2_disable_clk(struct csi2_dphy_hw *hw) { int i; for (i = hw->num_csi2_clks - 1; i >= 0; i--) { clk_disable_unprepare(hw->csi2_clks[i].clk); VEHICLE_INFO("%s(%d) disable csi2 clk: %s\n", __func__, __LINE__, hw->csi2_clks[i].id); } } static int csi2_enable_clk(struct csi2_dphy_hw *hw) { int i, ret = -EINVAL; for (i = 0; i < hw->num_csi2_clks; i++) { ret = clk_prepare_enable(hw->csi2_clks[i].clk); if (ret < 0) goto err; VEHICLE_INFO("%s(%d) enable csi2 clk: %s\n", __func__, __LINE__, hw->csi2_clks[i].id); } return 0; err: VEHICLE_DGERR("%s(%d) enable csi2 clk: %s err\n", __func__, __LINE__, hw->csi2_clks[i].id); for (--i; i >= 0; --i) clk_disable_unprepare(hw->csi2_clks[i].clk); return ret; } static int vehicle_csi2_clk_ctrl(struct vehicle_cif *cif, int on) { int ret = 0; struct csi2_dphy_hw *dphy_hw = cif->dphy_hw; on = !!on; if (on) { ret = csi2_enable_dphy_clk(dphy_hw); if (ret < 0) { VEHICLE_DGERR("enable csi dphy clk failed!"); goto err; } ret = csi2_enable_clk(dphy_hw); if (ret < 0) { VEHICLE_DGERR("enable csi dphy clk failed!"); goto err; } dphy_hw->on = true; } else { csi2_disable_dphy_clk(dphy_hw); csi2_disable_clk(dphy_hw); dphy_hw->on = false; } return 0; err: return ret; } static int vehicle_csi2_stream_stop(struct vehicle_cif *cif) { vehicle_csi2_disable(cif); return 0; } static int vehicle_cif_stream_stop(struct vehicle_cif *cif) { return 0; } static int vehicle_cif_csi_stream_stop(struct vehicle_cif *cif) { vehicle_cif_stream_stop(cif); vehicle_csi2_stream_stop(cif); if (cif->dphy_hw->chip_id == CHIP_ID_RK3588_DCPHY) vehicle_csi2_dcphy_stream_stop(cif); else vehicle_csi2_dphy_stream_stop(cif); return 0; } static int vehicle_cif_csi2_s_stream(struct vehicle_cif *cif, int enable, enum v4l2_mbus_type mbus_type) { unsigned int val = 0x0; const struct cif_input_fmt *infmt; struct vehicle_csi_channel_info *channel; int id; channel = &cif->channels[0]; if (enable) { val = CSI_ENABLE_CAPTURE | channel->fmt_val | channel->cmd_mode_en << 4 | channel->crop_en << 5 | channel->id << 8 | channel->data_type << 10; val &= ~CSI_ENABLE_MIPI_COMPACT; infmt = find_input_fmt(cif->cif_cfg.mbus_code); if (!infmt) { VEHICLE_INFO("Input fmt is invalid, use default!\n"); val |= CSI_YUV_INPUT_ORDER_UYVY; } else { val |= infmt->csi_yuv_order; } rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(channel->id), val); cif->state = RKCIF_STATE_STREAMING; } else { id = channel->id; val = rkcif_read_reg(cif, get_reg_index_of_id_ctrl0(id)); val &= ~CSI_ENABLE_CAPTURE; rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(id), val); rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTSTAT, CSI_START_INTSTAT(id) | CSI_DMA_END_INTSTAT(id) | CSI_LINE_INTSTAT(id)); rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTEN, ~(CSI_START_INTEN(id) | CSI_DMA_END_INTEN(id) | CSI_LINE_INTEN(id))); rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTEN, ~CSI_ALL_ERROR_INTEN); cif->state = RKCIF_STATE_READY; } return 0; } static int vehicle_cif_csi2_s_stream_v1(struct vehicle_cif *cif, int enable, enum v4l2_mbus_type mbus_type) { unsigned int val = 0x0; const struct cif_input_fmt *infmt; struct vehicle_csi_channel_info *channel; struct vehicle_cfg *cfg = &cif->cif_cfg; int id; channel = &cif->channels[0]; if (enable) { if (cif->chip_id <= CHIP_RK3562_VEHICLE_CIF) { val = CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE | channel->cmd_mode_en << 26 | CSI_ENABLE_CROP_V1 | channel->id << 8 | channel->data_type << 10; infmt = find_input_fmt(cif->cif_cfg.mbus_code); if (!infmt) { VEHICLE_INFO("Input fmt is invalid, use default!\n"); val |= CSI_YUV_INPUT_ORDER_UYVY; } else { val |= infmt->csi_yuv_order | infmt->csi_fmt_val; } if (cfg->output_format == CIF_OUTPUT_FORMAT_420) { if (find_output_fmt(V4L2_PIX_FMT_NV12)) val |= CSI_WRDDR_TYPE_YUV420SP_RK3588 | CSI_YUV_OUTPUT_ORDER_UYVY; } else { if (find_output_fmt(V4L2_PIX_FMT_NV16)) val |= CSI_WRDDR_TYPE_YUV422SP_RK3588 | CSI_YUV_OUTPUT_ORDER_UYVY; } rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(channel->id), val); } else { val = CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE_RK3576 | CSI_ENABLE_CROP_RK3576; infmt = find_input_fmt(cif->cif_cfg.mbus_code); if (!infmt) { VEHICLE_INFO("Input fmt is invalid, use default!\n"); val |= CSI_YUV_INPUT_ORDER_UYVY; } else if (cif->interlaced_enable) { val |= (infmt->csi_yuv_order >> 4) | ((infmt->csi_fmt_val + 1) << 4); } else { val |= (infmt->csi_yuv_order >> 4) | (infmt->csi_fmt_val << 4); } if (cfg->output_format == CIF_OUTPUT_FORMAT_420) { if (find_output_fmt(V4L2_PIX_FMT_NV12)) val |= CSI_WRDDR_TYPE_YUV420SP_RK3588 << 3 | CSI_YUV_OUTPUT_ORDER_UYVY >> 4; } else { if (find_output_fmt(V4L2_PIX_FMT_NV16)) val |= CSI_WRDDR_TYPE_YUV422SP_RK3588 << 3 | CSI_YUV_OUTPUT_ORDER_UYVY >> 4; } if (cfg->output_format == CIF_OUTPUT_FORMAT_420) val |= CSI_UVDS_EN; rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(channel->id), val); val = channel->data_type << 2; rkcif_write_reg(cif, get_reg_index_of_id_ctrl1(channel->id), val); } rkcif_write_reg(cif, CIF_REG_MIPI_EFFECT_CODE_ID0, 0x02410251); rkcif_write_reg(cif, CIF_REG_MIPI_EFFECT_CODE_ID1, 0x02420252); cif->state = RKCIF_STATE_STREAMING; } else { id = channel->id; val = rkcif_read_reg(cif, get_reg_index_of_id_ctrl0(id)); if (cif->chip_id >= CHIP_RK3576_VEHICLE_CIF) val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE_RK3576); else val &= ~(CSI_ENABLE_CAPTURE | CSI_DMA_ENABLE); rkcif_write_reg(cif, get_reg_index_of_id_ctrl0(id), val); rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_INTSTAT, CSI_START_INTSTAT(id) | CSI_DMA_END_INTSTAT(id) | CSI_LINE_INTSTAT(id)); rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTEN, ~(CSI_START_INTEN(id) | CSI_DMA_END_INTEN(id) | CSI_LINE_INTEN(id))); rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_INTEN, ~CSI_ALL_ERROR_INTEN_V1); rkcif_write_reg_and(cif, CIF_REG_MIPI_LVDS_CTRL, ~CSI_ENABLE_CAPTURE); cif->state = RKCIF_STATE_READY; } return 0; } static int cif_interrupt_setup(struct vehicle_cif *cif) { rkcif_write_reg(cif, CIF_REG_DVP_INTEN, FRAME_END_EN | INTSTAT_ERR | PST_INF_FRAME_END); /* enable line int for sof */ rkcif_write_reg(cif, CIF_REG_DVP_LINE_INT_NUM, 0x1); rkcif_write_reg(cif, CIF_REG_DVP_INTEN, LINE_INT_EN); return 0; } static void vehicle_cif_dvp_dump_regs(struct vehicle_cif *cif) { int val; if (!vehicle_debug) return; val = rkcif_read_reg(cif, CIF_REG_DVP_CTRL); VEHICLE_DG("CIF_REG_DVP_CTRL = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_INTEN); VEHICLE_DG("CIF_REG_DVP_INTEN = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_INTSTAT); VEHICLE_DG("CIF_REG_DVP_INTSTAT = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_FOR); VEHICLE_DG("CIF_REG_DVP_FOR = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_MULTI_ID); VEHICLE_DG("CIF_REG_DVP_MULTI_ID = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_LINE_NUM_ADDR); VEHICLE_DG("CIF_REG_DVP_LINE_NUM_ADDR = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_FRM0_ADDR_Y); VEHICLE_DG("CIF_REG_DVP_FRM0_ADDR_Y = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_FRM0_ADDR_UV); VEHICLE_DG("CIF_REG_DVP_FRM0_ADDR_UV = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_FRM1_ADDR_Y); VEHICLE_DG("CIF_REG_DVP_FRM1_ADDR_Y = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_FRM1_ADDR_UV); VEHICLE_DG("CIF_REG_DVP_FRM1_ADDR_UV = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_VIR_LINE_WIDTH); VEHICLE_DG("CIF_REG_DVP_VIR_LINE_WIDTH = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_SET_SIZE); VEHICLE_DG("CIF_REG_DVP_SET_SIZE = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_LINE_INT_NUM); VEHICLE_DG("CIF_REG_DVP_LINE_INT_NUM = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_LINE_CNT); VEHICLE_DG("CIF_REG_DVP_LINE_CNT = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_CROP); VEHICLE_DG("CIF_REG_DVP_CROP = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_SCL_CTRL); VEHICLE_DG("CIF_REG_DVP_SCL_CTRL = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_FRAME_STATUS); VEHICLE_DG("CIF_REG_DVP_FRAME_STATUS = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_CUR_DST); VEHICLE_DG("CIF_REG_DVP_CUR_DST = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_LAST_LINE); VEHICLE_DG("CIF_REG_DVP_LAST_LINE = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_LAST_PIX); VEHICLE_DG("CIF_REG_DVP_LAST_PIX = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_SCL_VALID_NUM); VEHICLE_DG("CIF_REG_DVP_SCL_VALID_NUM = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_DVP_LINE_NUM_ADDR); VEHICLE_DG("CIF_REG_DVP_LINE_NUM_ADDR = 0X%x\r\n", val); /* read dvp clk sample edge */ val = rkvehicle_cif_read_grf_reg(cif, CIF_REG_GRF_CIFIO_CON); VEHICLE_DG("CIF_REG_GRF_CIFIO_CON = 0X%x\r\n", val); } static void vehicle_cif_csi2_dump_regs(struct vehicle_cif *cif) { int val = 0; void __iomem *csi2_base = cif->csi2_base; struct csi2_dphy_hw *hw = cif->dphy_hw; if (!vehicle_debug) return; /* 1. dump csi2-dphy regs */ if (cif->dphy_hw->chip_id == CHIP_ID_RK3588) { VEHICLE_DG("\n\n DUMP CSI-DPHY REGS: \r\n"); read_csi2_dphy_reg(hw, CSI2PHY_REG_CTRL_LANE_ENABLE, &val); VEHICLE_DG("CSI2PHY_REG_CTRL_LANE_ENABLE = 0x%x\r\n", val); read_csi2_dphy_reg(hw, CSI2PHY_DUAL_CLK_EN, &val); VEHICLE_DG("CSI2PHY_DUAL_CLK_EN = 0x%x\r\n", val); val = csi2_dphy_read_grf_reg(hw, GRF_DPHY_CSI2PHY_FORCERXMODE); VEHICLE_DG("GRF_DPHY_CSI2PHY_FORCERXMODE = 0x%x\r\n", val); val = csi2_dphy_read_grf_reg(hw, GRF_DPHY_CSI2PHY_LANE_SEL); VEHICLE_DG("GRF_DPHY_CSI2PHY_LANE_SEL = 0x%x\r\n", val); val = csi2_dphy_read_grf_reg(hw, GRF_DPHY_CSI2PHY_DATALANE_EN); VEHICLE_DG("GRF_DPHY_CSI2PHY_DATALANE_EN = 0x%x\r\n", val); val = csi2_dphy_read_grf_reg(hw, GRF_DPHY_CSI2PHY_CLKLANE_EN); VEHICLE_DG("GRF_DPHY_CSI2PHY_CLKLANE_EN = 0x%x\r\n", val); } /* 2. dump csi2 regs */ VEHICLE_DG("\n\n DUMP CSI2 REGS: \r\n"); val = vehicle_read_csihost_reg(csi2_base, CSIHOST_N_LANES); VEHICLE_DG("CSIHOST_N_LANES = 0x%x\r\n", val); val = vehicle_read_csihost_reg(csi2_base, CSIHOST_CONTROL); VEHICLE_DG("CSIHOST_CONTROL = 0x%x\r\n", val); val = vehicle_read_csihost_reg(csi2_base, CSIHOST_MSK1); VEHICLE_DG("CSIHOST_MSK1 = 0x%x\r\n", val); val = vehicle_read_csihost_reg(csi2_base, CSIHOST_MSK2); VEHICLE_DG("CSIHOST_MSK2 = 0x%x\r\n", val); val = vehicle_read_csihost_reg(csi2_base, CSIHOST_RESETN); VEHICLE_DG("CSIHOST_RESETN = 0x%x\r\n", val); /* 3. dump cif regs */ VEHICLE_DG("\n\n DUMP MIPI CIF REGS: \r\n"); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_CTRL); VEHICLE_DG("CIF_REG_MIPI_LVDS_CTRL = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_INTEN); VEHICLE_DG("CIF_REG_MIPI_LVDS_INTEN = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_INTSTAT); VEHICLE_DG("CIF_REG_MIPI_LVDS_INTSTAT = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_ID0_CTRL0); VEHICLE_DG("CIF_REG_MIPI_LVDS_ID0_CTRL0 = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_ID0_CTRL1); VEHICLE_DG("CIF_REG_MIPI_LVDS_ID0_CTRL1 = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1); VEHICLE_DG("CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID0_1 = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3); VEHICLE_DG("CIF_REG_MIPI_LVDS_LINE_INT_NUM_ID2_3 = 0x%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0); VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME0_VLW_Y_ID0 = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0); VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME0_VLW_UV_ID0 = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0); VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME1_VLW_Y_ID0 = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0); VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME1_VLW_UV_ID0 = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0); VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME0_ADDR_Y_ID0 = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0); VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME0_ADDR_UV_ID0 = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0); VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME1_ADDR_Y_ID0 = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0); VEHICLE_DG("CIF_REG_MIPI_LVDS_FRAME1_ADDR_UV_ID0 = 0X%x\r\n", val); val = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_ID0_CROP_START); VEHICLE_DG("CIF_REG_MIPI_LVDS_ID0_CROP_START = 0X%x\r\n", val); /* read dvp clk sample edge */ val = rkvehicle_cif_read_grf_reg(cif, CIF_REG_GRF_CIFIO_CON); VEHICLE_DG("CIF_REG_GRF_CIFIO_CON = 0X%x\r\n", val); } static int vehicle_cif_s_stream(struct vehicle_cif *cif, int enable) { int cif_ctrl_val; unsigned int dma_en = 0; cif->is_enabled = enable; VEHICLE_INFO("%s enable=%d\n", __func__, enable); if (enable) { cif->irqinfo.cifirq_idx = 0; cif->irqinfo.cifirq_normal_idx = 0; cif->irqinfo.cifirq_abnormal_idx = 0; cif->irqinfo.dmairq_idx = 0; cif->irqinfo.all_err_cnt = 0; cif->irqinfo.dvp_bus_err_cnt = 0; cif->irqinfo.dvp_overflow_cnt = 0; cif->irqinfo.dvp_pix_err_cnt = 0; cif->irqinfo.dvp_line_err_cnt = 0; cif->irqinfo.dvp_size_err_cnt = 0; cif->irqinfo.dvp_bwidth_lack_cnt = 0; cif->irqinfo.csi_size_err_cnt = 0; rkcif_write_reg(cif, CIF_REG_DVP_INTEN, FRAME_END_EN | INTSTAT_ERR | PST_INF_FRAME_END); if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { rkcif_write_reg(cif, CIF_REG_DVP_LINE_INT_NUM, 0x1); rkcif_write_reg_or(cif, CIF_REG_DVP_INTEN, 0x033ffff); } dma_en = DVP_DMA_EN; if (cif->chip_id < CHIP_RK3588_VEHICLE_CIF) { rkcif_write_reg(cif, CIF_REG_DVP_CTRL, AXI_BURST_16 | MODE_PINGPONG | ENABLE_CAPTURE); } else if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { rkcif_write_reg(cif, CIF_REG_DVP_CTRL, DVP_SW_WATER_LINE_25 | dma_en | DVP_PRESS_EN | DVP_HURRY_EN | DVP_SW_WATER_LINE_25 | DVP_SW_PRESS_VALUE(3) | DVP_SW_HURRY_VALUE(3) | ENABLE_CAPTURE); } else { dma_en = DVP_SW_DMA_EN_RK3676(0); rkcif_write_reg(cif, CIF_REG_DVP_CTRL, DVP_SW_WATER_LINE_25_RK3576 | DVP_SW_CAP_EN_RK3576(0) | dma_en | ENABLE_CAPTURE); } cif->frame_idx = 0; cif->state = RKCIF_STATE_STREAMING; } else { cif_ctrl_val = rkcif_read_reg(cif, CIF_REG_DVP_CTRL); cif_ctrl_val &= ~ENABLE_CAPTURE; rkcif_write_reg(cif, CIF_REG_DVP_CTRL, cif_ctrl_val); rkcif_write_reg(cif, CIF_REG_DVP_INTEN, 0); rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, 0x3ff); rkcif_write_reg(cif, CIF_REG_DVP_FRAME_STATUS, 0x0); cif->state = RKCIF_STATE_READY; } return 0; } static int vehicle_cif_create_dummy_buf(struct vehicle_cif *cif) { struct vehicle_rkcif_dummy_buffer *dummy_buf = &cif->dummy_buf; struct vehicle_cfg *cfg = &cif->cif_cfg; /* get a maximum plane size */ dummy_buf->size = cfg->width * cfg->height * 2; dummy_buf->vaddr = dma_alloc_coherent(cif->dev, dummy_buf->size, &dummy_buf->dma_addr, GFP_KERNEL); if (!dummy_buf->vaddr) { VEHICLE_DGERR("Failed to allocate the memory for dummy buffer\n"); return -ENOMEM; } VEHICLE_INFO("Allocate dummy buffer, size: 0x%08x\n", dummy_buf->size); return 0; } static void vehicle_cif_destroy_dummy_buf(struct vehicle_cif *cif) { struct vehicle_rkcif_dummy_buffer *dummy_buf = &cif->dummy_buf; VEHICLE_INFO("Destroy dummy buffer, size: 0x%08x\n", dummy_buf->size); if (dummy_buf->vaddr) dma_free_coherent(cif->dev, dummy_buf->size, dummy_buf->vaddr, dummy_buf->dma_addr); dummy_buf->dma_addr = 0; dummy_buf->vaddr = NULL; } static void vehicle_cif_hw_soft_reset(struct vehicle_cif *cif) { unsigned int i; struct rk_cif_clk *clk = &cif->clk; for (i = 0; i < clk->rsts_num; i++) if (clk->cif_rst[i]) reset_control_assert(clk->cif_rst[i]); udelay(10); for (i = 0; i < clk->rsts_num; i++) if (clk->cif_rst[i]) reset_control_deassert(clk->cif_rst[i]); } static void vehicle_rkcif_do_soft_reset(struct vehicle_cif *cif) { if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) rkcif_write_reg_or(cif, CIF_REG_MIPI_LVDS_CTRL, 0x000A0000); else rkcif_write_reg_or(cif, CIF_REG_DVP_CTRL, 0x000A0000); usleep_range(10, 20); VEHICLE_INFO("vicap do soft reset 0x%x\n", 0x000A0000); } static int vehicle_cif_do_stop_stream(struct vehicle_cif *cif) { if (!cif) return -1; if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF) { vehicle_cif_csi2_s_stream_v1(cif, 0, V4L2_MBUS_CSI2_DPHY); vehicle_cif_csi_stream_stop(cif); } else { vehicle_cif_csi2_s_stream(cif, 0, V4L2_MBUS_CSI2_DPHY); vehicle_cif_csi_stream_stop(cif); } } else { vehicle_cif_s_stream(cif, 0); } if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF) vehicle_rkcif_do_soft_reset(cif); vehicle_cif_destroy_dummy_buf(cif); return 0; } static int vehicle_cif_do_start_stream(struct vehicle_cif *cif) { int ret = 0; if (!cif) return -ENODEV; if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { /* 1. stream setup */ cif_csi_stream_setup(cif); /* 2. create dummy buf */ ret = vehicle_cif_create_dummy_buf(cif); if (ret < 0) VEHICLE_DGERR("Failed to create dummy_buf, %d\n", ret); /* 3. cif init buffer */ if (vehicle_cif_init_buffer(cif, 1, cif->channels[0].id) < 0) return -EINVAL; /* 4. dump cif regs */ vehicle_cif_csi2_dump_regs(cif); /* 5. start stream */ if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF) vehicle_cif_csi2_s_stream_v1(cif, 1, V4L2_MBUS_CSI2_DPHY); else vehicle_cif_csi2_s_stream(cif, 1, V4L2_MBUS_CSI2_DPHY); } else { /* 1. stream setup */ cif_stream_setup(cif); /* 2. create dummy buf */ ret = vehicle_cif_create_dummy_buf(cif); if (ret < 0) VEHICLE_DGERR("Failed to create dummy_buf, %d\n", ret); /* 3. cif init buffer */ if (vehicle_cif_init_buffer(cif, 1, 0) < 0) return -EINVAL; /* 4. enable interrupts */ if (cif->chip_id < CHIP_RK3588_VEHICLE_CIF) cif_interrupt_setup(cif); /* 5. dump cif regs */ vehicle_cif_dvp_dump_regs(cif); /* 6. start stream */ vehicle_cif_s_stream(cif, 1); } return 0; } static void vehicle_rkcif_disable_sys_clk(struct rk_cif_clk *clk); static int vehicle_rkcif_enable_sys_clk(struct rk_cif_clk *clk); static void vehicle_cif_reset(struct vehicle_cif *cif, int only_rst) { int ret = 0; mutex_lock(&cif->stream_lock); if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { VEHICLE_DG("%s enter, V4L2_MBUS_CSI2 reset need to do!\n", __func__); // goto unlock_reset; if (only_rst == 1) { vehicle_cif_hw_soft_reset(cif); } else { vehicle_cif_do_stop_stream(cif); vehicle_cif_hw_soft_reset(cif); vehicle_cif_do_start_stream(cif); } } else { int ctrl_reg, inten_reg, crop_reg, set_size_reg, for_reg; int vir_line_width_reg, scl_reg; int y0_reg, uv0_reg, y1_reg, uv1_reg; VEHICLE_DG("%s enter, do reset!\n", __func__); if (only_rst == 1) { vehicle_cif_hw_soft_reset(cif); } else { ctrl_reg = rkcif_read_reg(cif, CIF_REG_DVP_CTRL); if (ctrl_reg & ENABLE_CAPTURE) rkcif_write_reg(cif, CIF_REG_DVP_CTRL, ctrl_reg & ~ENABLE_CAPTURE); crop_reg = rkcif_read_reg(cif, CIF_REG_DVP_CROP); set_size_reg = rkcif_read_reg(cif, CIF_REG_DVP_SET_SIZE); inten_reg = rkcif_read_reg(cif, CIF_REG_DVP_INTEN); for_reg = rkcif_read_reg(cif, CIF_REG_DVP_FOR); vir_line_width_reg = rkcif_read_reg(cif, CIF_REG_DVP_VIR_LINE_WIDTH); scl_reg = rkcif_read_reg(cif, CIF_REG_DVP_SCL_CTRL); y0_reg = rkcif_read_reg(cif, CIF_REG_DVP_FRM0_ADDR_Y); uv0_reg = rkcif_read_reg(cif, CIF_REG_DVP_FRM0_ADDR_UV); y1_reg = rkcif_read_reg(cif, CIF_REG_DVP_FRM1_ADDR_Y); uv1_reg = rkcif_read_reg(cif, CIF_REG_DVP_FRM1_ADDR_UV); udelay(20); vehicle_cif_hw_soft_reset(cif); vehicle_rkcif_disable_sys_clk(&cif->clk); udelay(5); ret = vehicle_rkcif_enable_sys_clk(&cif->clk); if (ret < 0) { VEHICLE_DGERR("@%s, resume cif clk failed!\n", __func__); goto unlock_reset; } rkcif_write_reg(cif, CIF_REG_DVP_CTRL, ctrl_reg & ~ENABLE_CAPTURE); rkcif_write_reg(cif, CIF_REG_DVP_INTEN, inten_reg); rkcif_write_reg(cif, CIF_REG_DVP_CROP, crop_reg); rkcif_write_reg(cif, CIF_REG_DVP_SET_SIZE, set_size_reg); rkcif_write_reg(cif, CIF_REG_DVP_FOR, for_reg); rkcif_write_reg(cif, CIF_REG_DVP_VIR_LINE_WIDTH, vir_line_width_reg); rkcif_write_reg(cif, CIF_REG_DVP_SCL_CTRL, scl_reg); rkcif_write_reg(cif, CIF_REG_DVP_FRM0_ADDR_Y, y0_reg); rkcif_write_reg(cif, CIF_REG_DVP_FRM0_ADDR_UV, uv0_reg); rkcif_write_reg(cif, CIF_REG_DVP_FRM1_ADDR_Y, y1_reg); rkcif_write_reg(cif, CIF_REG_DVP_FRM1_ADDR_UV, uv1_reg); } } unlock_reset: mutex_unlock(&cif->stream_lock); } static void vehicle_cif_reset_delay(struct vehicle_cif *cif) { mdelay(10); vehicle_cif_reset(cif, 0); mdelay(10); vehicle_cif_s_stream(cif, 1); } static void cif_capture_en(char *reg, int enable) { int val = 0; val = read_reg(reg, CIF_REG_DVP_CTRL); if (enable == 1) write_reg(reg, CIF_REG_DVP_CTRL, val | ENABLE_CAPTURE); else write_reg(reg, CIF_REG_DVP_CTRL, val & (~ENABLE_CAPTURE)); } static void vehicle_cif_reset_work_func(struct work_struct *work) { struct vehicle_cif *cif = container_of(work, struct vehicle_cif, work.work); if (cif->stopping) return; atomic_set(&cif->reset_status, 1); vehicle_cif_reset_delay(cif); atomic_set(&cif->reset_status, 0); wake_up(&cif->wq_stopped); } int vehicle_wait_cif_reset_done(void) { struct vehicle_cif *cif = g_cif; int ret = 0, retry = 2; for (retry = 2; retry >= 0; retry--) { ret = wait_event_timeout(cif->wq_stopped, !atomic_read(&cif->reset_status), msecs_to_jiffies(200)); if (!ret) { VEHICLE_DG("%s wait cif reset timeout, left try times(%d)!\n", __func__, retry); } else { break; } } return 0; } static int cif_irq_error_process(struct vehicle_cif *cif, unsigned int reg_intstat) { VEHICLE_DG("%s cif->irqinfo.all_err_cnt(%lld)\n", __func__, cif->irqinfo.all_err_cnt); if (reg_intstat & INTSTAT_ERR) { cif->irqinfo.all_err_cnt++; if (reg_intstat & BUS_ERR) { cif->irqinfo.dvp_bus_err_cnt++; VEHICLE_DGERR("dvp bus err\n"); } if (reg_intstat & DVP_ALL_OVERFLOW) { cif->irqinfo.dvp_overflow_cnt++; VEHICLE_DGERR("dvp overflow err\n"); } if (reg_intstat & LINE_ERR) { cif->irqinfo.dvp_line_err_cnt++; VEHICLE_DGERR("dvp line err\n"); } if (reg_intstat & PIX_ERR) { cif->irqinfo.dvp_pix_err_cnt++; VEHICLE_DGERR("dvp pix err\n"); } if (cif->irqinfo.all_err_cnt < 10) { u32 mask; VEHICLE_DGERR("ERROR: DVP_ALL_ERROR:0x%x!!\n", reg_intstat); mask = rkcif_read_reg(cif, CIF_REG_DVP_INTEN); mask &= ~INTSTAT_ERR; rkcif_write_reg(cif, CIF_REG_DVP_INTEN, mask); return -2; } else if (cif->irqinfo.all_err_cnt >= 10) { u32 mask; mask = rkcif_read_reg(cif, CIF_REG_DVP_INTEN); mask &= ~INTSTAT_ERR; rkcif_write_reg(cif, CIF_REG_DVP_INTEN, mask); VEHICLE_DGERR("ERROR: DVP_ALL_ERROR:0x%x!!\n", reg_intstat); return -2; } } return 0; } static int vehicle_cif_csi2_g_mipi_id(unsigned int intstat) { if (intstat & CSI_FRAME_END_ID0) { if ((intstat & CSI_FRAME_END_ID0) == CSI_FRAME_END_ID0) VEHICLE_DG("frame0/1 trigger simultaneously in ID0\n"); return RKCIF_STREAM_MIPI_ID0; } if (intstat & CSI_FRAME_END_ID1) { if ((intstat & CSI_FRAME_END_ID1) == CSI_FRAME_END_ID1) VEHICLE_DG("frame0/1 trigger simultaneously in ID1\n"); return RKCIF_STREAM_MIPI_ID1; } if (intstat & CSI_FRAME_END_ID2) { if ((intstat & CSI_FRAME_END_ID2) == CSI_FRAME_END_ID2) VEHICLE_DG("frame0/1 trigger simultaneously in ID2\n"); return RKCIF_STREAM_MIPI_ID2; } if (intstat & CSI_FRAME_END_ID3) { if ((intstat & CSI_FRAME_END_ID3) == CSI_FRAME_END_ID3) VEHICLE_DG("frame0/1 trigger simultaneously in ID3\n"); return RKCIF_STREAM_MIPI_ID3; } return -EINVAL; } static __maybe_unused int rkcif_dvp_g_ch_id_by_fe(unsigned int intstat) { if (intstat & DVP_ALL_END_ID0) { if ((intstat & DVP_ALL_END_ID0) == DVP_ALL_END_ID0) VEHICLE_DG("frame0/1 trigger simultaneously in DVP ID0\n"); return RKCIF_STREAM_MIPI_ID0; } if (intstat & DVP_ALL_END_ID1) { if ((intstat & DVP_ALL_END_ID1) == DVP_ALL_END_ID1) VEHICLE_DG("frame0/1 trigger simultaneously in DVP ID1\n"); return RKCIF_STREAM_MIPI_ID1; } if (intstat & DVP_ALL_END_ID2) { if ((intstat & DVP_ALL_END_ID2) == DVP_ALL_END_ID2) VEHICLE_DG("frame0/1 trigger simultaneously in DVP ID2\n"); return RKCIF_STREAM_MIPI_ID2; } if (intstat & DVP_ALL_END_ID3) { if ((intstat & DVP_ALL_END_ID3) == DVP_ALL_END_ID3) VEHICLE_DG("frame0/1 trigger simultaneously in DVP ID3\n"); return RKCIF_STREAM_MIPI_ID3; } return -EINVAL; } static int vehicle_cif_next_buffer(struct vehicle_cif *cif, u32 frame_ready, int mipi_id) { u32 frm0_addr_y, frm0_addr_uv; u32 frm1_addr_y, frm1_addr_uv; unsigned long y_addr = 0, uv_addr = 0; static unsigned long temp_y_addr, temp_uv_addr; int commit_buf = 0; struct vehicle_rkcif_dummy_buffer *dummy_buf = &cif->dummy_buf; u32 frm_num_reg, frame_id = 0; VEHICLE_DG("@%s, enter, mipi_id(%d)\n", __func__, mipi_id); if ((frame_ready > 1) || (cif->cif_cfg.buf_num < 2) || (cif->cif_cfg.buf_num > MAX_BUF_NUM)) return 0; cif->last_buf_index = cif->current_buf_index; cif->current_buf_index = (cif->current_buf_index + 1) % cif->cif_cfg.buf_num; if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { frm0_addr_y = get_reg_index_of_frm0_y_addr(mipi_id); frm0_addr_uv = get_reg_index_of_frm0_uv_addr(mipi_id); frm1_addr_y = get_reg_index_of_frm1_y_addr(mipi_id); frm1_addr_uv = get_reg_index_of_frm1_uv_addr(mipi_id); frm_num_reg = get_reg_index_of_frm_num(mipi_id); frame_id = rkcif_read_reg(cif, frm_num_reg); VEHICLE_DG("@%s, frm_num_reg(0x%x), frame_id:0x%x\n", __func__, frm_num_reg, frame_id); } else { frm0_addr_y = get_dvp_reg_index_of_frm0_y_addr(mipi_id); frm0_addr_uv = get_dvp_reg_index_of_frm0_uv_addr(mipi_id); frm1_addr_y = get_dvp_reg_index_of_frm1_y_addr(mipi_id); frm1_addr_uv = get_dvp_reg_index_of_frm1_uv_addr(mipi_id); } spin_lock(&cif->vbq_lock); if (!cif->interlaced_enable || cif->use_hw_interlace) { temp_y_addr = vehicle_flinger_request_cif_buffer(); if (temp_y_addr == 0) { VEHICLE_INFO("%s,warnning request buffer failed\n", __func__); spin_unlock(&cif->vbq_lock); if (dummy_buf->vaddr) { if (frame_ready == 0) { rkcif_write_reg(cif, frm0_addr_y, dummy_buf->dma_addr); rkcif_write_reg(cif, frm0_addr_uv, dummy_buf->dma_addr); } else { rkcif_write_reg(cif, frm1_addr_y, dummy_buf->dma_addr); rkcif_write_reg(cif, frm1_addr_uv, dummy_buf->dma_addr); } VEHICLE_INFO("frame Drop to dummy buf\n"); } else { VEHICLE_INFO("dummy buf is null!\n"); } return -1; } temp_uv_addr = temp_y_addr + UV_OFFSET; y_addr = temp_y_addr; uv_addr = temp_uv_addr; commit_buf = 0; } else if (cif->interlaced_enable && !cif->use_hw_interlace) { if ((frame_id != 0 && (frame_id & 0xffff) % 2 == 0) || (frame_id == 0 && (cif->interlaced_counts % 2 == 0))) { temp_y_addr = vehicle_flinger_request_cif_buffer(); if (temp_y_addr == 0) { VEHICLE_DGERR("%s,warnning request buffer failed\n", __func__); spin_unlock(&cif->vbq_lock); return -1; } temp_uv_addr = temp_y_addr + UV_OFFSET; y_addr = temp_y_addr; uv_addr = temp_uv_addr; commit_buf = -1; //not ok yet } else { y_addr = temp_y_addr + cif->interlaced_offset; //uv_addr = temp_uv_addr; uv_addr = temp_uv_addr + cif->interlaced_offset; commit_buf = 0; //even & odd field add if (temp_y_addr == 0) { VEHICLE_DGERR("%s,warnning temp_y_addr is NULL!\n", __func__); spin_unlock(&cif->vbq_lock); return -1; } } WARN_ON(y_addr == cif->interlaced_offset); WARN_ON(uv_addr == cif->interlaced_offset); } if (frame_ready == 0) { rkcif_write_reg(cif, frm0_addr_y, y_addr); rkcif_write_reg(cif, frm0_addr_uv, uv_addr); cif->active[0] = temp_y_addr; } else { rkcif_write_reg(cif, frm1_addr_y, y_addr); rkcif_write_reg(cif, frm1_addr_uv, uv_addr); cif->active[1] = temp_y_addr; } cif->interlaced_counts++; spin_unlock(&cif->vbq_lock); return commit_buf; } /***************************** irq operation ******************************/ //discard the first few frames to solve display abnormality after different model camera switch static int drop_frames_number; static irqreturn_t rk_camera_irq(int irq, void *data) { struct vehicle_cif *cif = (struct vehicle_cif *)data; u32 lastline, lastpix, ctl; u32 cif_frmst, frmid, int_en; unsigned int intstat, i = 0xff; int frame_ready = 0; int frame_phase = 0; unsigned long addr; int mipi_id = 0; if (drop_frames_number > 0) { VEHICLE_INFO("%s discard the first few frames!\n", __func__); drop_frames_number--; goto IRQ_EXIT; } VEHICLE_DG("%s enter, cifirq_normal_idx(%ld) cif->frame_idx(%d)!\n", __func__, cif->irqinfo.cifirq_normal_idx, cif->frame_idx); if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { if (!cif->stopping) { if (cif->irqinfo.cifirq_normal_idx == cif->frame_idx) { cif->irqinfo.cifirq_abnormal_idx++; } else { cif->irqinfo.cifirq_normal_idx = cif->frame_idx; cif->irqinfo.cifirq_abnormal_idx = 0; } } intstat = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_INTSTAT); lastline = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1); /* clear all interrupts that has been triggered */ rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_INTSTAT, intstat); /* when not detect new FRAME_END continue over 5 irq, reset, it's abnormal */ if (cif->irqinfo.cifirq_abnormal_idx >= 5) { VEHICLE_DGERR( "ERROR: cifirq_abnormal_idx reach(%ld) consecutive, do reset work!!\n", cif->irqinfo.cifirq_abnormal_idx); // mod_delayed_work(system_wq, &cif->work, // msecs_to_jiffies(1)); cif->irqinfo.cifirq_abnormal_idx = 0; vehicle_cif_stat_change_notify(); goto IRQ_EXIT; } if (intstat & CSI_FIFO_OVERFLOW) { cif->irqinfo.csi_overflow_cnt++; VEHICLE_DGERR( "ERROR: csi fifo overflow, intstat:0x%x, lastline:%d!!\n", intstat, lastline); goto IRQ_EXIT; } if (intstat & CSI_BANDWIDTH_LACK) { cif->irqinfo.csi_bwidth_lack_cnt++; VEHICLE_DGERR( "ERROR: csi bandwidth lack, intstat:0x%x!!\n", intstat); if (cif->irqinfo.csi_bwidth_lack_cnt >= 5) { //do reset work // mod_delayed_work(system_wq, &cif->work, // msecs_to_jiffies(1)); } goto IRQ_EXIT; } if (intstat & CSI_ALL_ERROR_INTEN) { cif->irqinfo.all_err_cnt++; VEHICLE_DGERR( "ERROR: CSI_ALL_ERROR_INTEN:0x%x!!\n", intstat); goto IRQ_EXIT; } /* if do not reach frame dma end, return irq */ mipi_id = vehicle_cif_csi2_g_mipi_id(intstat); if (mipi_id < 0) goto IRQ_EXIT; for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { mipi_id = vehicle_cif_csi2_g_mipi_id(intstat); VEHICLE_DG(" i(%d) mipi_id(%d)\n", i, mipi_id); if (mipi_id < 0) continue; if (cif->stopping) { vehicle_cif_csi2_s_stream(cif, 0, V4L2_MBUS_CSI2_DPHY); cif->stopping = false; wake_up(&cif->wq_stopped); continue; } if (cif->state != RKCIF_STATE_STREAMING) continue; switch (mipi_id) { case RKCIF_STREAM_MIPI_ID0: frame_phase = SW_FRM_END_ID0(intstat); intstat &= ~CSI_FRAME_END_ID0; break; case RKCIF_STREAM_MIPI_ID1: frame_phase = SW_FRM_END_ID1(intstat); intstat &= ~CSI_FRAME_END_ID1; break; case RKCIF_STREAM_MIPI_ID2: frame_phase = SW_FRM_END_ID2(intstat); intstat &= ~CSI_FRAME_END_ID2; break; case RKCIF_STREAM_MIPI_ID3: frame_phase = SW_FRM_END_ID3(intstat); intstat &= ~CSI_FRAME_END_ID3; break; } if (frame_phase & CIF_CSI_FRAME1_READY) frame_ready = 1; else if (frame_phase & CIF_CSI_FRAME0_READY) frame_ready = 0; addr = cif->active[frame_ready]; if (vehicle_cif_next_buffer(cif, frame_ready, mipi_id) < 0) VEHICLE_DG("cif_nex_buffer error, do not commit %lx\n", addr); else vehicle_flinger_commit_cif_buffer(addr); } cif->frame_idx++; } else { intstat = rkcif_read_reg(cif, CIF_REG_DVP_INTSTAT); cif_frmst = rkcif_read_reg(cif, CIF_REG_DVP_FRAME_STATUS); lastline = rkcif_read_reg(cif, CIF_REG_DVP_LAST_LINE); lastline = CIF_FETCH_Y_LAST_LINE(lastline); lastpix = rkcif_read_reg(cif, CIF_REG_DVP_LAST_PIX); lastpix = CIF_FETCH_Y_LAST_LINE(lastpix); ctl = rkcif_read_reg(cif, CIF_REG_DVP_CTRL); VEHICLE_DG("lastline:%d, lastpix:%d, ctl:%d\n", lastline, lastpix, ctl); rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, intstat); if ((intstat & LINE_INT_END) && !(intstat & (FRAME_END))) { if ((intstat & (PRE_INF_FRAME_END | PST_INF_FRAME_END)) == 0x0) { if ((intstat & INTSTAT_ERR) == 0x0) { int_en = rkcif_read_reg(cif, CIF_REG_DVP_INTEN); int_en &= ~LINE_INT_EN; rkcif_write_reg(cif, CIF_REG_DVP_INTEN, int_en); } } } /* 0. error process */ if (cif_irq_error_process(cif, intstat) < 0) { VEHICLE_DGERR("irq error, to do... reset, intstat=%x\n", intstat); // mod_delayed_work(system_wq, &cif->work, // msecs_to_jiffies(1)); vehicle_cif_stat_change_notify(); goto IRQ_EXIT; } /* There are two irqs enabled: * - PST_INF_FRAME_END: cif FIFO is ready, * this is prior to FRAME_END * - FRAME_END: cif has saved frame to memory, * a frame ready */ if ((intstat & PST_INF_FRAME_END)) { cif->irqinfo.cifirq_idx++; if (cif->stopping) { /* To stop CIF ASAP, before FRAME_END irq */ vehicle_cif_s_stream(cif, 0); cif->stopping = false; wake_up(&cif->wq_stopped); goto IRQ_EXIT; } } if ((intstat & FRAME_END)) { int_en = rkcif_read_reg(cif, CIF_REG_DVP_INTEN); int_en |= LINE_INT_EN; rkcif_write_reg(cif, CIF_REG_DVP_INTEN, int_en); if (cif->stopping) { vehicle_cif_s_stream(cif, 0); cif->stopping = false; wake_up(&cif->wq_stopped); goto IRQ_EXIT; } frmid = CIF_GET_FRAME_ID(cif_frmst); if ((cif_frmst == 0xfffd0002) || (cif_frmst == 0xfffe0002)) { VEHICLE_DG("frmid:%d, frmstat:0x%x\n", frmid, cif_frmst); rkcif_write_reg(cif, CIF_REG_DVP_FRAME_STATUS, FRAME_STAT_CLS); } if ((!(cif_frmst & CIF_F0_READY) && !(cif_frmst & CIF_F1_READY))) { VEHICLE_DG("err f0 && f1 not ready\n"); cif_capture_en(cif->base, 0); rkcif_write_reg(cif, CIF_REG_DVP_INTEN, 0); mod_delayed_work(system_wq, &cif->work, msecs_to_jiffies(1)); goto IRQ_EXIT; } if (cif_frmst & CIF_F0_READY) frame_ready = 0; else frame_ready = 1; addr = cif->active[frame_ready]; if (vehicle_cif_next_buffer(cif, frame_ready, mipi_id) < 0) CIF_DG("cif_nex_buffer error, do not commit %lx\n", addr); else vehicle_flinger_commit_cif_buffer(addr); cif->frame_idx++; } } cif->irqinfo.all_frm_end_cnt++; IRQ_EXIT: return IRQ_HANDLED; } static irqreturn_t rk_camera_irq_v1(int irq, void *data) { struct vehicle_cif *cif = (struct vehicle_cif *)data; u32 lastline; unsigned int intstat, i = 0xff, bak_intstat = 0; int frame_ready = 0; int frame_phase = 0; unsigned long addr; int mipi_id = 0; if (drop_frames_number > 0) { VEHICLE_INFO("%s discard the first few frames!\n", __func__); drop_frames_number--; goto IRQ_EXIT; } VEHICLE_DG("%s enter, cifirq_normal_idx(%ld) cif->frame_idx(%d)!\n", __func__, cif->irqinfo.cifirq_normal_idx, cif->frame_idx); if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { if (!cif->stopping) { if (cif->irqinfo.cifirq_normal_idx == cif->frame_idx) { cif->irqinfo.cifirq_abnormal_idx++; } else { cif->irqinfo.cifirq_normal_idx = cif->frame_idx; cif->irqinfo.cifirq_abnormal_idx = 0; } } intstat = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_INTSTAT); lastline = rkcif_read_reg(cif, CIF_REG_MIPI_LVDS_LINE_LINE_CNT_ID0_1); /* clear all interrupts that has been triggered */ if (intstat) { bak_intstat = intstat; VEHICLE_DG("%s bak_intstat = %d!\n", __func__, bak_intstat); rkcif_write_reg(cif, CIF_REG_MIPI_LVDS_INTSTAT, intstat); } else { goto IRQ_EXIT; } /* when not detect new FRAME_END continue over 5 irq, reset, it's abnormal */ if (cif->irqinfo.cifirq_abnormal_idx >= 5) { VEHICLE_DGERR( "ERROR: cifirq_abnormal_idx reach(%ld) consecutive, do reset work!!\n", cif->irqinfo.cifirq_abnormal_idx); cif->irqinfo.cifirq_abnormal_idx = 0; vehicle_cif_stat_change_notify(); goto IRQ_EXIT; } if (intstat & CSI_SIZE_ERR) { cif->irqinfo.csi_size_err_cnt++; VEHICLE_DGERR("ERROR: csi size error, intstat:0x%x, lastline:%d!!\n", intstat, lastline); goto IRQ_EXIT; } if (intstat & CSI_FIFO_OVERFLOW_V1) { cif->irqinfo.csi_overflow_cnt++; VEHICLE_DGERR("ERROR: csi fifo overflow, intstat:0x%x, lastline:%d!!\n", intstat, lastline); goto IRQ_EXIT; } if (intstat & CSI_BANDWIDTH_LACK_V1) { cif->irqinfo.csi_bwidth_lack_cnt++; VEHICLE_DGERR("ERROR: csi bandwidth lack, intstat:0x%x!!\n", intstat); goto IRQ_EXIT; } if (intstat & CSI_ALL_ERROR_INTEN_V1) { cif->irqinfo.all_err_cnt++; VEHICLE_DGERR("ERROR: CSI_ALL_ERROR_INTEN:0x%x!!\n", intstat); goto IRQ_EXIT; } /* if do not reach frame dma end, return irq */ mipi_id = vehicle_cif_csi2_g_mipi_id(intstat); if (mipi_id < 0) goto IRQ_EXIT; for (i = 0; i < RKCIF_MAX_STREAM_MIPI; i++) { mipi_id = vehicle_cif_csi2_g_mipi_id(intstat); VEHICLE_DG(" i(%d) mipi_id(%d)\n", i, mipi_id); if (mipi_id < 0) continue; if (cif->stopping) { vehicle_cif_csi2_s_stream_v1(cif, 0, V4L2_MBUS_CSI2_DPHY); cif->stopping = false; wake_up(&cif->wq_stopped); continue; } if (cif->state != RKCIF_STATE_STREAMING) continue; switch (mipi_id) { case RKCIF_STREAM_MIPI_ID0: frame_phase = SW_FRM_END_ID0(intstat); intstat &= ~CSI_FRAME_END_ID0; break; case RKCIF_STREAM_MIPI_ID1: frame_phase = SW_FRM_END_ID1(intstat); intstat &= ~CSI_FRAME_END_ID1; break; case RKCIF_STREAM_MIPI_ID2: frame_phase = SW_FRM_END_ID2(intstat); intstat &= ~CSI_FRAME_END_ID2; break; case RKCIF_STREAM_MIPI_ID3: frame_phase = SW_FRM_END_ID3(intstat); intstat &= ~CSI_FRAME_END_ID3; break; } if (frame_phase & CIF_CSI_FRAME1_READY) frame_ready = 1; else if (frame_phase & CIF_CSI_FRAME0_READY) frame_ready = 0; addr = cif->active[frame_ready]; if (vehicle_cif_next_buffer(cif, frame_ready, mipi_id) < 0) VEHICLE_DGERR("cif_nex_buffer error, do not commit %lx\n", addr); else vehicle_flinger_commit_cif_buffer(addr); } cif->frame_idx++; } else { int ch_id; intstat = rkcif_read_reg(cif, CIF_REG_DVP_INTSTAT); rkcif_write_reg(cif, CIF_REG_DVP_INTSTAT, intstat); if (intstat & DVP_SIZE_ERR) { cif->irqinfo.dvp_size_err_cnt++; VEHICLE_DGERR("dvp size err intstat 0x%x\n", intstat); } if (intstat & DVP_FIFO_OVERFLOW) { cif->irqinfo.dvp_overflow_cnt++; VEHICLE_DGERR("dvp fifo overflow err intstat 0x%x\n", intstat); } if (intstat & DVP_BANDWIDTH_LACK) { cif->irqinfo.dvp_bwidth_lack_cnt++; VEHICLE_DGERR("dvp bandwidth lack err intstat 0x%x\n", intstat); } if (intstat & INTSTAT_ERR_RK3588) { cif->irqinfo.all_err_cnt++; VEHICLE_DGERR("ERROR: DVP_ALL_ERROR_INTEN:0x%x!!\n", intstat); } for (i = 0; i < RKCIF_MAX_STREAM_DVP; i++) { ch_id = rkcif_dvp_g_ch_id_by_fe(intstat); if (ch_id < 0) continue; if (cif->stopping) { vehicle_cif_s_stream(cif, 0); cif->stopping = false; wake_up(&cif->wq_stopped); continue; } if (cif->state != RKCIF_STATE_STREAMING) continue; switch (ch_id) { case RKCIF_STREAM_MIPI_ID0: frame_phase = SW_FRM_END_ID0(intstat); intstat &= ~DVP_ALL_END_ID0; break; case RKCIF_STREAM_MIPI_ID1: frame_phase = SW_FRM_END_ID1(intstat); intstat &= ~DVP_ALL_END_ID1; break; case RKCIF_STREAM_MIPI_ID2: frame_phase = SW_FRM_END_ID2(intstat); intstat &= ~DVP_ALL_END_ID2; break; case RKCIF_STREAM_MIPI_ID3: frame_phase = SW_FRM_END_ID3(intstat); intstat &= ~DVP_ALL_END_ID3; break; } if (frame_phase & CIF_F0_READY) frame_ready = 0; else frame_ready = 1; addr = cif->active[frame_ready]; if (vehicle_cif_next_buffer(cif, frame_ready, ch_id) < 0) VEHICLE_DGERR("cif_nex_buffer error, do not commit %lx\n", addr); else vehicle_flinger_commit_cif_buffer(addr); cif->frame_idx++; } } cif->irqinfo.all_frm_end_cnt++; IRQ_EXIT: return IRQ_HANDLED; } #define vehicle_csi2_err_strncat(dst_str, src_str) {\ if (strlen(dst_str) + strlen(src_str) < CSI_ERRSTR_LEN)\ strncat(dst_str, src_str, strlen(src_str)); } static void vehicle_csi2_find_err_vc(int val, char *vc_info) { int i; char cur_str[CSI_VCINFO_LEN] = {0}; memset(vc_info, 0, sizeof(*vc_info)); for (i = 0; i < 4; i++) { if ((val >> i) & 0x1) { snprintf(cur_str, CSI_VCINFO_LEN, " %d", i); if (strlen(vc_info) + strlen(cur_str) < CSI_VCINFO_LEN) strncat(vc_info, cur_str, strlen(cur_str)); } } } static void vehicle_csi2_err_print_work(struct work_struct *work) { struct vehicle_csi2_err_state_work *err_state = container_of(work, struct vehicle_csi2_err_state_work, work); pr_err("mipi_csi2: ERR%d:0x%x %s\n", err_state->err_num, err_state->err_val, err_state->err_str); if (err_state->err_num == 1) pr_info("mipi_csi2: err_stat:0x%lx\n", err_state->err_stat); } static irqreturn_t vehicle_csirx_irq1(int irq, void *data) { struct vehicle_cif *cif = (struct vehicle_cif *)data; struct csi2_dphy_hw *hw = cif->dphy_hw; struct csi2_err_stats *err_list = NULL; unsigned long err_stat = 0; u32 val; char err_str[CSI_ERRSTR_LEN] = {0}; char cur_str[CSI_ERRSTR_LEN] = {0}; char vc_info[CSI_VCINFO_LEN] = {0}; val = read_reg(hw->csi2_base, CSIHOST_ERR1); if (val) { write_reg(hw->csi2_base, CSIHOST_ERR1, 0x0); if (val & CSIHOST_ERR1_PHYERR_SPTSYNCHS) { err_list = &hw->err_list[RK_CSI2_ERR_SOTSYN]; err_list->cnt++; vehicle_csi2_find_err_vc(val & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(sot sync,lane:%s) ", vc_info); vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR1_ERR_BNDRY_MATCH) { err_list = &hw->err_list[RK_CSI2_ERR_FS_FE_MIS]; err_list->cnt++; vehicle_csi2_find_err_vc((val >> 4) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(fs/fe miss,vc:%s) ", vc_info); vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR1_ERR_SEQ) { err_list = &hw->err_list[RK_CSI2_ERR_FRM_SEQ_ERR]; err_list->cnt++; vehicle_csi2_find_err_vc((val >> 8) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(f_seq,vc:%s) ", vc_info); vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR1_ERR_FRM_DATA) { err_list = &hw->err_list[RK_CSI2_ERR_CRC_ONCE]; err_list->cnt++; vehicle_csi2_find_err_vc((val >> 12) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(err_data,vc:%s) ", vc_info); vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR1_ERR_CRC) { err_list = &hw->err_list[RK_CSI2_ERR_CRC]; err_list->cnt++; vehicle_csi2_find_err_vc((val >> 24) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(crc,vc:%s) ", vc_info); vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR1_ERR_ECC2) { err_list = &hw->err_list[RK_CSI2_ERR_CRC]; err_list->cnt++; snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc2) "); vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR1_ERR_CTRL) { vehicle_csi2_find_err_vc((val >> 16) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(ctrl,vc:%s) ", vc_info); vehicle_csi2_err_strncat(err_str, cur_str); } hw->err_list[RK_CSI2_ERR_ALL].cnt++; err_stat = ((hw->err_list[RK_CSI2_ERR_FS_FE_MIS].cnt & 0xff) << 8) | ((hw->err_list[RK_CSI2_ERR_ALL].cnt) & 0xff); cif->err_state.err_val = val; cif->err_state.err_num = 1; cif->err_state.err_stat = err_stat; strscpy(cif->err_state.err_str, err_str, CSI_ERRSTR_LEN); queue_work(cif->err_state.err_print_wq, &cif->err_state.work); } return IRQ_HANDLED; } static irqreturn_t vehicle_csirx_irq2(int irq, void *data) { struct vehicle_cif *cif = (struct vehicle_cif *)data; struct csi2_dphy_hw *hw = cif->dphy_hw; u32 val; char cur_str[CSI_ERRSTR_LEN] = {0}; char err_str[CSI_ERRSTR_LEN] = {0}; char vc_info[CSI_VCINFO_LEN] = {0}; val = read_reg(hw->csi2_base, CSIHOST_ERR2); if (val) { if (val & CSIHOST_ERR2_PHYERR_ESC) { vehicle_csi2_find_err_vc(val & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(ULPM,lane:%s) ", vc_info); vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR2_PHYERR_SOTHS) { vehicle_csi2_find_err_vc((val >> 4) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(sot,lane:%s) ", vc_info); vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR2_ECC_CORRECTED) { vehicle_csi2_find_err_vc((val >> 8) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(ecc,vc:%s) ", vc_info); vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR2_ERR_ID) { vehicle_csi2_find_err_vc((val >> 12) & 0xf, vc_info); snprintf(cur_str, CSI_ERRSTR_LEN, "(err id,vc:%s) ", vc_info); vehicle_csi2_err_strncat(err_str, cur_str); } if (val & CSIHOST_ERR2_PHYERR_CODEHS) { snprintf(cur_str, CSI_ERRSTR_LEN, "(err code) "); vehicle_csi2_err_strncat(err_str, cur_str); } cif->err_state.err_val = val; cif->err_state.err_num = 2; strscpy(cif->err_state.err_str, err_str, CSI_ERRSTR_LEN); queue_work(cif->err_state.err_print_wq, &cif->err_state.work); } return IRQ_HANDLED; } int vehicle_cif_reverse_open(struct vehicle_cfg *v_cfg) { int ret = 0; struct vehicle_cif *cif = g_cif; if (!cif) return -ENODEV; mutex_lock(&cif->stream_lock); memcpy(&cif->cif_cfg, v_cfg, sizeof(struct vehicle_cfg)); ret = pm_runtime_get_sync(cif->dev); if (ret < 0) { pm_runtime_put_noidle(cif->dev); VEHICLE_DGERR("%s pm_runtime_get_sync failed\n", __func__); goto exit; } /*get dcphy param*/ if (cif->dphy_hw->chip_id == CHIP_ID_RK3588_DCPHY) { if (cif->cif_cfg.dphy_param) { cif->dphy_hw->dphy_param = cif->cif_cfg.dphy_param; dev_info(cif->dev, "-----get dphy param from sensor----\n"); } else { cif->dphy_hw->dphy_param = &rk3588_dcphy_param; dev_info(cif->dev, "fail to get dphy param, used default value\n"); } } /* set ddr fix freq */ rockchip_set_system_status(SYS_STATUS_CIF0); vehicle_cif_hw_soft_reset(cif); if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { /* 0. set mipi-dphy data rate */ cif->dphy_hw->data_rate_mbps = cif->cif_cfg.mipi_freq * 2 / 1000 / 1000; /* 0. set csi2 & dphy clk */ vehicle_csi2_hw_soft_reset(cif); if (cif->dphy_hw->chip_id == CHIP_ID_RK3588 || cif->dphy_hw->chip_id >= CHIP_ID_RK3562) vehicle_csi2_dphy_hw_do_reset(cif); if (!cif->dphy_hw->on) vehicle_csi2_clk_ctrl(cif, 1); /* 1. stream setup */ cif_csi_stream_setup(cif); /* 2. create dummy buf */ ret = vehicle_cif_create_dummy_buf(cif); if (ret < 0) VEHICLE_DGERR("Failed to create dummy_buf, %d\n", ret); /* 3. cif init buffer */ if (vehicle_cif_init_buffer(cif, 1, cif->channels[0].id) < 0) goto exit; /* 4. dump cif regs */ vehicle_cif_csi2_dump_regs(cif); /* 5. start stream */ if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF) vehicle_cif_csi2_s_stream_v1(cif, 1, V4L2_MBUS_CSI2_DPHY); else vehicle_cif_csi2_s_stream(cif, 1, V4L2_MBUS_CSI2_DPHY); } else { /* 1. stream setup */ cif_stream_setup(cif); /* 2. create dummy buf */ ret = vehicle_cif_create_dummy_buf(cif); if (ret < 0) VEHICLE_DGERR("Failed to create dummy_buf, %d\n", ret); /* 2. cif init buffer */ if (vehicle_cif_init_buffer(cif, 1, 0) < 0) goto exit; /* 3. enable interrupts */ if (cif->chip_id < CHIP_RK3588_VEHICLE_CIF) cif_interrupt_setup(cif); /* 4. dump cif regs */ vehicle_cif_dvp_dump_regs(cif); /* 5. start stream */ vehicle_cif_s_stream(cif, 1); } cif->stopping = false; drop_frames_number = cif->drop_frames; mutex_unlock(&cif->stream_lock); return 0; exit: mutex_unlock(&cif->stream_lock); return -1; } int vehicle_cif_reverse_close(void) { int ret = 0; struct vehicle_cif *cif = g_cif; if (!cif) return -ENODEV; mutex_lock(&cif->stream_lock); VEHICLE_DG("%s cif reverse start closing\n", __func__); cif->stopping = true; cancel_delayed_work_sync(&(cif->work)); flush_delayed_work(&(cif->work)); cancel_work_sync(&cif->err_state.work); ret = wait_event_timeout(cif->wq_stopped, cif->state != RKCIF_STATE_STREAMING, msecs_to_jiffies(100)); if (!ret) { VEHICLE_DGERR("%s wait stream stop timeout!\n", __func__); if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF) vehicle_cif_csi2_s_stream_v1(cif, 0, V4L2_MBUS_CSI2_DPHY); else vehicle_cif_csi2_s_stream(cif, 0, V4L2_MBUS_CSI2_DPHY); } else { vehicle_cif_s_stream(cif, 0); } //cif->stopping = false; } if (cif->cif_cfg.type == V4L2_MBUS_CSI2_DPHY) { vehicle_cif_csi_stream_stop(cif); vehicle_csi2_hw_soft_reset(cif); if (cif->dphy_hw->chip_id == CHIP_ID_RK3588 || cif->dphy_hw->chip_id >= CHIP_ID_RK3562) vehicle_csi2_dphy_hw_do_reset(cif); if (cif->dphy_hw->on) vehicle_csi2_clk_ctrl(cif, 0); } vehicle_cif_destroy_dummy_buf(cif); //vehicle_csi2_hw_soft_reset(cif); //vehicle_cif_hw_soft_reset(cif); rockchip_clear_system_status(SYS_STATUS_CIF0); mutex_unlock(&cif->stream_lock); cif->stopping = false; return 0; } static void vehicle_cif_dphy_get_node(struct vehicle_cif *cif) { struct device_node *node = NULL; struct device_node *cp = NULL; struct device *dev = cif->dev; const char *status = NULL; node = of_parse_phandle(dev->of_node, "rockchip,cif-phy", 0); if (!node) { VEHICLE_DGERR("get cif-phy dts failed\n"); return; } for_each_child_of_node(node, cp) { of_property_read_string(cp, "status", &status); if (status && !strcmp(status, "disabled")) continue; else cif->phy_node = cp; VEHICLE_INFO("status: %s %s\n", cp->name, status); } } static int cif_parse_dt(struct vehicle_cif *cif) { struct device *dev = cif->dev; struct device_node *node; struct device_node *phy_node = cif->phy_node; struct device_node *cif_node; struct device_node *cis2_node; if (of_property_read_u32(dev->of_node, "cif,drop-frames", &cif->drop_frames)) { VEHICLE_INFO("%s:Get cif, drop-frames failed!\n", __func__); cif->drop_frames = 0; //default drop frames; } if (of_property_read_u32(dev->of_node, "cif,chip-id", &cif->chip_id)) { VEHICLE_INFO("%s:Get cif, chip_id failed!\n", __func__); cif->chip_id = CHIP_RK3588_VEHICLE_CIF; //default rk3588; } cif_node = of_parse_phandle(dev->of_node, "rockchip,cif", 0); cif->base = (char *)of_iomap(cif_node, 0); node = of_parse_phandle(dev->of_node, "rockchip,cru", 0); cif->cru_base = of_iomap(node, 0); node = of_parse_phandle(dev->of_node, "rockchip,grf", 0); cif->grf_base = of_iomap(node, 0); cif->regmap_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); if (IS_ERR(cif->regmap_grf)) VEHICLE_DGERR("unable to get rockchip,grf\n"); cif->irq = irq_of_parse_and_map(cif_node, 0); if (cif->irq < 0) { VEHICLE_DGERR("%s: request cif irq failed\n", __func__); iounmap(cif->base); iounmap(cif->cru_base); iounmap(cif->grf_base); return -ENODEV; } if (of_property_read_u32(phy_node, "csihost-idx", &cif->csi_host_idx)) { VEHICLE_INFO("Get %s csihost-idx failed! sensor link to dvp!!\n", phy_node->name); cif->inf_id = RKCIF_DVP; } else { cif->inf_id = RKCIF_MIPI_LVDS; VEHICLE_INFO("sensor link to %s!!\n", phy_node->name); } if (cif->inf_id == RKCIF_MIPI_LVDS) { if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF && !(cif->csi_host_idx == RKCIF_MIPI0_CSI2 || cif->csi_host_idx == RKCIF_MIPI1_CSI2)) { node = of_parse_phandle(phy_node, "rockchip,csi2-dphy", 0); cif->csi2_dphy_base = of_iomap(node, 0); cif->regmap_dphy_grf = syscon_regmap_lookup_by_phandle(phy_node, "rockchip,dphy-grf"); if (IS_ERR(cif->regmap_dphy_grf)) VEHICLE_INFO("unable to get rockchip,dphy-grf\n"); } else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF && cif->csi_host_idx != RKCIF_MIPI0_CSI2) { node = of_parse_phandle(phy_node, "rockchip,csi2-dphy", 0); cif->csi2_dphy_base = of_iomap(node, 0); cif->regmap_dphy_grf = syscon_regmap_lookup_by_phandle(phy_node, "rockchip,dphy-grf"); if (IS_ERR(cif->regmap_dphy_grf)) VEHICLE_INFO("unable to get rockchip,dphy-grf\n"); cif->dphy_sys_grf = syscon_regmap_lookup_by_phandle(phy_node, "rockchip,sys-grf"); if (IS_ERR(cif->dphy_sys_grf)) VEHICLE_INFO("unable to get rockchip,sys-grf\n"); } else if (cif->chip_id != CHIP_RK3588_VEHICLE_CIF && cif->chip_id != CHIP_RK3576_VEHICLE_CIF) { node = of_parse_phandle(phy_node, "rockchip,csi2-dphy", 0); cif->csi2_dphy_base = of_iomap(node, 0); } cis2_node = of_parse_phandle(phy_node, "rockchip,csi2", 0); cif->csi2_base = of_iomap(cis2_node, 0); cif->csi2_irq1 = irq_of_parse_and_map(cis2_node, 0); if (cif->csi2_irq1 < 0) { VEHICLE_DGERR("%s: request csi-intr1 failed\n", __func__); iounmap(cif->base); iounmap(cif->cru_base); iounmap(cif->grf_base); iounmap(cif->csi2_dphy_base); iounmap(cif->csi2_base); return -ENODEV; } cif->csi2_irq2 = irq_of_parse_and_map(cis2_node, 1); if (cif->csi2_irq2 < 0) { VEHICLE_DGERR("%s: request csi-intr2 failed\n", __func__); iounmap(cif->base); iounmap(cif->cru_base); iounmap(cif->grf_base); iounmap(cif->csi2_dphy_base); iounmap(cif->csi2_base); return -ENODEV; } } VEHICLE_DG("%s, drop_frames = %d\n", __func__, cif->drop_frames); return 0; } int vehicle_cif_init_mclk(struct vehicle_cif *cif) { struct device *dev = cif->dev; struct rk_cif_clk *clk = &cif->clk; /* sensor MCLK: * current use CLK_CIF_OUT */ vehicle_cif_dphy_get_node(cif); clk->xvclk = of_clk_get_by_name(cif->phy_node, "xvclk"); if (IS_ERR(clk->xvclk)) { dev_err(dev, "Failed to get sensor xvclk\n"); return -EINVAL; } rkcif_s_mclk(cif, 1, 24000000); VEHICLE_INFO("%s(%d): set sensor MCLK rate 24MHZ OK!\n", __func__, __LINE__); return 0; } static int vehicle_cif_deinit_mclk(struct vehicle_cif *cif) { struct rk_cif_clk *clk = &cif->clk; /* release sensor MCLK: * current use CLK_CIF_OUT */ if (!IS_ERR(clk->xvclk)) clk_disable_unprepare(clk->xvclk); clk_put(clk->xvclk); return 0; } int vehicle_cif_init(struct vehicle_cif *cif) { int ret; struct device *dev; struct rk_cif_clk *clk; struct csi2_dphy_hw *dphy_hw; struct clk *tmp_cif_clk = NULL; int i; int inf_id; if (!cif) return -ENODEV; dev = cif->dev; clk = &cif->clk; g_cif = cif; /* 0. dts parse */ if (cif_parse_dt(cif) < -1) { VEHICLE_DGERR("%s: cif_parse_dt failed\n", __func__); return -ENODEV; } inf_id = cif->inf_id; if (inf_id == RKCIF_MIPI_LVDS) { if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { if (cif->csi_host_idx == RKCIF_MIPI0_CSI2 || cif->csi_host_idx == RKCIF_MIPI1_CSI2) dphy_hw = &rk3588_csi2_dcphy_hw; else dphy_hw = &rk3588_csi2_dphy_hw; } else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) { dphy_hw = &rk3562_csi2_dphy_hw; } else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) { if (cif->csi_host_idx == RKCIF_MIPI0_CSI2) dphy_hw = &rk3576_csi2_dcphy_hw; else dphy_hw = &rk3576_csi2_dphy_hw; } else { dphy_hw = &rk3568_csi2_dphy_hw; } } /* 1. cif/csi2-dphy/csi2 clk setup */ if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { clk->clks_num = ARRAY_SIZE(rk3588_cif_clks); clk->rsts_num = ARRAY_SIZE(rk3588_cif_rsts); } else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) { clk->clks_num = ARRAY_SIZE(rk3562_cif_clks); clk->rsts_num = ARRAY_SIZE(rk3562_cif_rsts); } else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) { clk->clks_num = ARRAY_SIZE(rk3576_cif_clks); clk->rsts_num = ARRAY_SIZE(rk3576_cif_rsts); } else { clk->clks_num = ARRAY_SIZE(rk3568_cif_clks); clk->rsts_num = ARRAY_SIZE(rk3568_cif_rsts); } if (inf_id == RKCIF_MIPI_LVDS) { cif->dphy_hw = dphy_hw; dphy_hw->dev = cif->dev; /*get phy_index*/ if (cif->dphy_hw->chip_id == CHIP_ID_RK3588) { if (cif->csi_host_idx >= RKCIF_MIPI4_CSI2) cif->dphy_hw->phy_index = 3; else cif->dphy_hw->phy_index = 0; } else if (cif->dphy_hw->chip_id == CHIP_ID_RK3562) { if (cif->csi_host_idx >= RKCIF_MIPI2_CSI2) cif->dphy_hw->phy_index = 3; else cif->dphy_hw->phy_index = 0; } else if (cif->dphy_hw->chip_id == CHIP_ID_RK3576) { if (cif->csi_host_idx >= RKCIF_MIPI3_CSI2) cif->dphy_hw->phy_index = 3; else cif->dphy_hw->phy_index = 0; } else { cif->dphy_hw->phy_index = 0; } /*get mipi dcphy*/ if (cif->dphy_hw->chip_id == CHIP_ID_RK3588_DCPHY) { struct phy *dcphy = NULL; struct samsung_mipi_dcphy *dcphy_hw = NULL; dcphy = of_phy_get(cif->phy_node, "dcphy"); if (IS_ERR(dcphy)) { ret = PTR_ERR(dcphy); dev_err(dev, "failed to get mipi dcphy: %d\n", ret); return ret; } dcphy_hw = phy_get_drvdata(dcphy); dcphy_hw->dphy_vehicle[dcphy_hw->dphy_vehicle_num] = cif->dphy_hw; dcphy_hw->dphy_vehicle_num++; cif->dphy_hw->samsung_phy = dcphy_hw; } /* csi2 mipidphy rsts */ if (cif->dphy_hw->chip_id == CHIP_ID_RK3588 || cif->dphy_hw->chip_id == CHIP_ID_RK3562 || cif->dphy_hw->chip_id == CHIP_ID_RK3576) { for (i = 0; i < dphy_hw->num_dphy_rsts; i++) { struct reset_control *rst = NULL; rst = of_reset_control_get(cif->phy_node, dphy_hw->dphy_rsts[i]); if (IS_ERR(rst)) { dev_err(dev, "failed to get %s\n", dphy_hw->dphy_rsts[i]); return PTR_ERR(rst); } dphy_hw->dphy_rst[i] = rst; } } else { dev_info(dev, "use mipi dcphy, no need request rst\n"); } /* csi2 mipidphy clks */ for (i = 0; i < dphy_hw->num_dphy_clks; i++) { struct clk *tmp_clk = of_clk_get_by_name(cif->phy_node, dphy_hw->dphy_clks[i].id); if (IS_ERR(tmp_clk)) { dev_err(dev, "failed to get %s\n", dphy_hw->dphy_clks[i].id); return PTR_ERR(tmp_clk); } dev_info(dev, "clk get %s\n", dphy_hw->dphy_clks[i].id); dphy_hw->dphy_clks[i].clk = tmp_clk; } /* csi2 clks */ for (i = 0; i < dphy_hw->num_csi2_clks; i++) { struct clk *tmp_clk = of_clk_get_by_name(cif->phy_node, dphy_hw->csi2_clks[i].id); if (IS_ERR(tmp_clk)) { dev_err(dev, "failed to get %s\n", dphy_hw->csi2_clks[i].id); return PTR_ERR(tmp_clk); } dev_info(dev, "clk get %s\n", dphy_hw->csi2_clks[i].id); dphy_hw->csi2_clks[i].clk = tmp_clk; } /* csi2 rsts */ for (i = 0; i < dphy_hw->num_csi2_rsts; i++) { struct reset_control *rst = NULL; rst = of_reset_control_get(cif->phy_node, dphy_hw->csi2_rsts[i]); if (IS_ERR(rst)) { dev_err(dev, "failed to get %s\n", dphy_hw->csi2_rsts[i]); return PTR_ERR(rst); } dphy_hw->csi2_rst[i] = rst; } dphy_hw->on = false; } /* vicap clks */ if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { for (i = 0; i < clk->clks_num; i++) { tmp_cif_clk = devm_clk_get(dev, rk3588_cif_clks[i]); if (IS_ERR(tmp_cif_clk)) { dev_err(dev, "failed to get %s\n", rk3588_cif_clks[i]); return PTR_ERR(tmp_cif_clk); } clk->clks[i] = tmp_cif_clk; clk->on = false; } } else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) { for (i = 0; i < clk->clks_num; i++) { tmp_cif_clk = devm_clk_get(dev, rk3562_cif_clks[i]); if (IS_ERR(tmp_cif_clk)) { dev_err(dev, "failed to get %s\n", rk3562_cif_clks[i]); return PTR_ERR(tmp_cif_clk); } clk->clks[i] = tmp_cif_clk; clk->on = false; } } else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) { for (i = 0; i < clk->clks_num; i++) { tmp_cif_clk = devm_clk_get(dev, rk3576_cif_clks[i]); if (IS_ERR(tmp_cif_clk)) { dev_err(dev, "failed to get %s\n", rk3576_cif_clks[i]); return PTR_ERR(tmp_cif_clk); } clk->clks[i] = tmp_cif_clk; clk->on = false; } } else { for (i = 0; i < clk->clks_num; i++) { tmp_cif_clk = devm_clk_get(dev, rk3568_cif_clks[i]); if (IS_ERR(tmp_cif_clk)) { dev_err(dev, "failed to get %s\n", rk3568_cif_clks[i]); return PTR_ERR(tmp_cif_clk); } clk->clks[i] = tmp_cif_clk; clk->on = false; } } /* vicap rsts */ if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { for (i = 0; i < clk->rsts_num; i++) { struct reset_control *rst = NULL; if (rk3588_cif_rsts[i]) rst = devm_reset_control_get(dev, rk3588_cif_rsts[i]); if (IS_ERR(rst)) { dev_err(dev, "failed to get %s\n", rk3588_cif_rsts[i]); return PTR_ERR(rst); } clk->cif_rst[i] = rst; } } else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) { for (i = 0; i < clk->rsts_num; i++) { struct reset_control *rst = NULL; if (rk3562_cif_rsts[i]) rst = devm_reset_control_get(dev, rk3562_cif_rsts[i]); if (IS_ERR(rst)) { dev_err(dev, "failed to get %s\n", rk3562_cif_rsts[i]); return PTR_ERR(rst); } clk->cif_rst[i] = rst; } } else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) { for (i = 0; i < clk->rsts_num; i++) { struct reset_control *rst = NULL; if (rk3576_cif_rsts[i]) rst = devm_reset_control_get(dev, rk3576_cif_rsts[i]); if (IS_ERR(rst)) { dev_err(dev, "failed to get %s\n", rk3576_cif_rsts[i]); return PTR_ERR(rst); } clk->cif_rst[i] = rst; } } else { for (i = 0; i < clk->rsts_num; i++) { struct reset_control *rst = NULL; if (rk3568_cif_rsts[i]) rst = devm_reset_control_get(dev, rk3568_cif_rsts[i]); if (IS_ERR(rst)) { dev_err(dev, "failed to get %s\n", rk3568_cif_rsts[i]); return PTR_ERR(rst); } clk->cif_rst[i] = rst; } } /* 2. set cif clk & sensor mclk */ rk_cif_mclk_ctrl(cif, 1, 24000000); INIT_DELAYED_WORK(&cif->work, vehicle_cif_reset_work_func); if (inf_id == RKCIF_MIPI_LVDS) /* 2. set csi2 & dphy clk */ if (!cif->dphy_hw->on) vehicle_csi2_clk_ctrl(cif, 1); /* 3. request cif irq & mipi csi irq1-2 */ if (cif->chip_id >= CHIP_RK3588_VEHICLE_CIF) { ret = devm_request_irq(dev, cif->irq, rk_camera_irq_v1, IRQF_SHARED, "vehicle_cif", cif); if (ret < 0) { VEHICLE_DGERR("request cif irq failed!\n"); return -EINVAL; } } else { ret = devm_request_irq(dev, cif->irq, rk_camera_irq, IRQF_SHARED, "vehicle_cif", cif); if (ret < 0) { VEHICLE_DGERR("request cif irq failed!\n"); return -EINVAL; } } VEHICLE_DG("%s(%d):\n", __func__, __LINE__); if (inf_id == RKCIF_MIPI_LVDS) { ret = devm_request_irq(dev, cif->csi2_irq1, vehicle_csirx_irq1, IRQF_SHARED, "vehicle_csi_intr1", cif); if (ret < 0) { VEHICLE_DGERR("request csirx irq1 failed!\n"); return -EINVAL; } ret = devm_request_irq(dev, cif->csi2_irq2, vehicle_csirx_irq2, IRQF_SHARED, "vehicle_csi_intr2", cif); if (ret < 0) { VEHICLE_DGERR("request csirx irq2 failed!\n"); return -EINVAL; } } /* 4. set cif regs */ if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) cif->cif_regs = rk3588_cif_regs; else if (cif->chip_id == CHIP_RK3562_VEHICLE_CIF) cif->cif_regs = rk3562_cif_regs; else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) cif->cif_regs = rk3576_cif_regs; else cif->cif_regs = rk3568_cif_regs; if (inf_id == RKCIF_MIPI_LVDS) { /* 5. set csi2-mipi-dphy reg */ if (cif->dphy_hw->chip_id == CHIP_ID_RK3588 || cif->dphy_hw->chip_id == CHIP_ID_RK3568 || cif->dphy_hw->chip_id == CHIP_ID_RK3562 || cif->dphy_hw->chip_id == CHIP_ID_RK3576) cif->dphy_hw->csi2_dphy_base = cif->csi2_dphy_base; /* 7. set mipi-csi2 reg */ cif->dphy_hw->csi2_base = cif->csi2_base; /* 8. set dphy grf regmap */ if (cif->chip_id == CHIP_RK3588_VEHICLE_CIF) { if (cif->dphy_hw->chip_id == CHIP_ID_RK3588) { cif->dphy_hw->regmap_grf = cif->regmap_dphy_grf; cif->dphy_hw->regmap_sys_grf = cif->regmap_grf; } } else if (cif->chip_id == CHIP_RK3576_VEHICLE_CIF) { if (cif->dphy_hw->chip_id == CHIP_ID_RK3576) { cif->dphy_hw->regmap_grf = cif->regmap_dphy_grf; cif->dphy_hw->regmap_sys_grf = cif->dphy_sys_grf; } } else { cif->dphy_hw->regmap_grf = cif->regmap_grf; } mutex_init(&dphy_hw->mutex); } if (cif->inf_id == RKCIF_MIPI_LVDS && cif->chip_id <= CHIP_RK3562_VEHICLE_CIF) cif->use_hw_interlace = false; else cif->use_hw_interlace = true; /* 9. init waitqueue */ atomic_set(&cif->reset_status, 0); init_waitqueue_head(&cif->wq_stopped); spin_lock_init(&cif->vbq_lock); INIT_WORK(&cif->err_state.work, vehicle_csi2_err_print_work); cif->err_state.err_print_wq = create_workqueue("cis2_err_print_queue"); if (cif->err_state.err_print_wq == NULL) { dev_err(dev, "%s: %s create failed.\n", __func__, "csi2_err_print_wq"); } return 0; } int vehicle_cif_deinit(struct vehicle_cif *cif) { struct rk_cif_clk *clk = &cif->clk; struct device *dev = cif->dev; int i; struct csi2_dphy_hw *dphy_hw = cif->dphy_hw; int inf_id = cif->inf_id; // vehicle_cif_s_stream(cif, 0); // vehicle_cif_do_stop_stream(cif); /* set csi2-dphy csi cif clk & sensor mclk */ rk_cif_mclk_ctrl(cif, 0, 0); if (inf_id == RKCIF_MIPI_LVDS) if (cif->dphy_hw->on) vehicle_csi2_clk_ctrl(cif, 0); /* release sensor MCLK */ vehicle_cif_deinit_mclk(cif); /* vicap rsts release */ for (i = 0; i < clk->rsts_num; i++) reset_control_put(clk->cif_rst[i]); /* vicap clk release */ for (i = 0; i < clk->clks_num; i++) devm_clk_put(dev, clk->clks[i]); if (inf_id == RKCIF_MIPI_LVDS) { /*dcphy put*/ if (cif->dphy_hw->chip_id == CHIP_ID_RK3588_DCPHY) { struct samsung_mipi_dcphy *dcphy_hw = cif->dphy_hw->samsung_phy; struct csi2_dphy_hw *csi2_dphy = NULL; for (i = 0; i < dcphy_hw->dphy_vehicle_num; i++) { csi2_dphy = dcphy_hw->dphy_vehicle[i]; if (csi2_dphy) { dcphy_hw->dphy_vehicle[i] = NULL; dcphy_hw->dphy_vehicle_num--; break; } } } /* dphy clks release */ for (i = 0; i < dphy_hw->num_dphy_clks; i++) clk_put(dphy_hw->dphy_clks[i].clk); /* dphy rsts release */ if (cif->dphy_hw->chip_id == CHIP_ID_RK3588 || cif->dphy_hw->chip_id == CHIP_ID_RK3562 || cif->dphy_hw->chip_id == CHIP_ID_RK3576) { for (i = 0; i < dphy_hw->num_dphy_rsts; i++) reset_control_put(dphy_hw->dphy_rst[i]); } /* csi2 clks release */ for (i = 0; i < dphy_hw->num_csi2_clks; i++) clk_put(dphy_hw->csi2_clks[i].clk); /* csi2 resets release */ for (i = 0; i < dphy_hw->num_csi2_rsts; i++) reset_control_put(dphy_hw->csi2_rst[i]); mutex_destroy(&dphy_hw->mutex); } devm_free_irq(dev, cif->irq, cif); if (inf_id == RKCIF_MIPI_LVDS) { devm_free_irq(dev, cif->csi2_irq1, cif); devm_free_irq(dev, cif->csi2_irq2, cif); } if (cif->err_state.err_print_wq) { flush_workqueue(cif->err_state.err_print_wq); destroy_workqueue(cif->err_state.err_print_wq); } return 0; }