/* * Copyright (c) 2013-2015, NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, * version 2, as published by the Free Software Foundation. * * This program is distributed in the hope it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for * more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include #include #include #include #include #include #include #include #include "nvhost_syncpt.h" #include "common.h" #define TEGRA_SYNCPT_CSI_WAIT_TIMEOUT 200 #define TEGRA_VI_CFG_VI_INCR_SYNCPT 0x000 #define VI_MWA_REQ_DONE (4 << 8) #define VI_MWB_REQ_DONE (5 << 8) #define VI_MWA_ACK_DONE (6 << 8) #define VI_MWB_ACK_DONE (7 << 8) #define VI_ISPA_DONE (8 << 8) #define VI_CSI_PPA_FRAME_START (9 << 8) #define VI_CSI_PPB_FRAME_START (10 << 8) #define VI_CSI_PPA_LINE_START (11 << 8) #define VI_CSI_PPB_LINE_START (12 << 8) #define TEGRA_VI_CFG_VI_INCR_SYNCPT_CNTRL 0x004 #define TEGRA_VI_CFG_VI_INCR_SYNCPT_ERROR 0x008 #define TEGRA_VI_CFG_CTXSW 0x020 #define TEGRA_VI_CFG_INTSTATUS 0x024 #define TEGRA_VI_CFG_PWM_CONTROL 0x038 #define TEGRA_VI_CFG_PWM_HIGH_PULSE 0x03c #define TEGRA_VI_CFG_PWM_LOW_PULSE 0x040 #define TEGRA_VI_CFG_PWM_SELECT_PULSE_A 0x044 #define TEGRA_VI_CFG_PWM_SELECT_PULSE_B 0x048 #define TEGRA_VI_CFG_PWM_SELECT_PULSE_C 0x04c #define TEGRA_VI_CFG_PWM_SELECT_PULSE_D 0x050 #define TEGRA_VI_CFG_VGP1 0x064 #define TEGRA_VI_CFG_VGP2 0x068 #define TEGRA_VI_CFG_VGP3 0x06c #define TEGRA_VI_CFG_VGP4 0x070 #define TEGRA_VI_CFG_VGP5 0x074 #define TEGRA_VI_CFG_VGP6 0x078 #define TEGRA_VI_CFG_INTERRUPT_MASK 0x08c #define TEGRA_VI_CFG_INTERRUPT_TYPE_SELECT 0x090 #define TEGRA_VI_CFG_INTERRUPT_POLARITY_SELECT 0x094 #define TEGRA_VI_CFG_INTERRUPT_STATUS 0x098 #define TEGRA_VI_CFG_VGP_SYNCPT_CONFIG 0x0ac #define TEGRA_VI_CFG_VI_SW_RESET 0x0b4 #define TEGRA_VI_CFG_CG_CTRL 0x0b8 #define TEGRA_VI_CFG_VI_MCCIF_FIFOCTRL 0x0e4 #define TEGRA_VI_CFG_TIMEOUT_WCOAL_VI 0x0e8 #define TEGRA_VI_CFG_DVFS 0x0f0 #define TEGRA_VI_CFG_RESERVE 0x0f4 #define TEGRA_VI_CFG_RESERVE_1 0x0f8 #define TEGRA_VI_CSI_0_SW_RESET 0x100 #define TEGRA_VI_CSI_0_SINGLE_SHOT 0x104 #define TEGRA_VI_CSI_0_SINGLE_SHOT_STATE_UPDATE 0x108 #define TEGRA_VI_CSI_0_IMAGE_DEF 0x10c #define TEGRA_VI_CSI_0_RGB2Y_CTRL 0x110 #define TEGRA_VI_CSI_0_MEM_TILING 0x114 #define TEGRA_VI_CSI_0_CSI_IMAGE_SIZE 0x118 #define TEGRA_VI_CSI_0_CSI_IMAGE_SIZE_WC 0x11c #define TEGRA_VI_CSI_0_CSI_IMAGE_DT 0x120 #define TEGRA_VI_CSI_0_SURFACE0_OFFSET_MSB 0x124 #define TEGRA_VI_CSI_0_SURFACE0_OFFSET_LSB 0x128 #define TEGRA_VI_CSI_0_SURFACE1_OFFSET_MSB 0x12c #define TEGRA_VI_CSI_0_SURFACE1_OFFSET_LSB 0x130 #define TEGRA_VI_CSI_0_SURFACE2_OFFSET_MSB 0x134 #define TEGRA_VI_CSI_0_SURFACE2_OFFSET_LSB 0x138 #define TEGRA_VI_CSI_0_SURFACE0_BF_OFFSET_MSB 0x13c #define TEGRA_VI_CSI_0_SURFACE0_BF_OFFSET_LSB 0x140 #define TEGRA_VI_CSI_0_SURFACE1_BF_OFFSET_MSB 0x144 #define TEGRA_VI_CSI_0_SURFACE1_BF_OFFSET_LSB 0x148 #define TEGRA_VI_CSI_0_SURFACE2_BF_OFFSET_MSB 0x14c #define TEGRA_VI_CSI_0_SURFACE2_BF_OFFSET_LSB 0x150 #define TEGRA_VI_CSI_0_SURFACE0_STRIDE 0x154 #define TEGRA_VI_CSI_0_SURFACE1_STRIDE 0x158 #define TEGRA_VI_CSI_0_SURFACE2_STRIDE 0x15c #define TEGRA_VI_CSI_0_SURFACE_HEIGHT0 0x160 #define TEGRA_VI_CSI_0_ISPINTF_CONFIG 0x164 #define TEGRA_VI_CSI_0_ERROR_STATUS 0x184 #define TEGRA_VI_CSI_0_ERROR_INT_MASK 0x188 #define TEGRA_VI_CSI_0_WD_CTRL 0x18c #define TEGRA_VI_CSI_0_WD_PERIOD 0x190 #define TEGRA_VI_CSI_1_SW_RESET 0x200 #define TEGRA_VI_CSI_1_SINGLE_SHOT 0x204 #define TEGRA_VI_CSI_1_SINGLE_SHOT_STATE_UPDATE 0x208 #define TEGRA_VI_CSI_1_IMAGE_DEF 0x20c #define TEGRA_VI_CSI_1_RGB2Y_CTRL 0x210 #define TEGRA_VI_CSI_1_MEM_TILING 0x214 #define TEGRA_VI_CSI_1_CSI_IMAGE_SIZE 0x218 #define TEGRA_VI_CSI_1_CSI_IMAGE_SIZE_WC 0x21c #define TEGRA_VI_CSI_1_CSI_IMAGE_DT 0x220 #define TEGRA_VI_CSI_1_SURFACE0_OFFSET_MSB 0x224 #define TEGRA_VI_CSI_1_SURFACE0_OFFSET_LSB 0x228 #define TEGRA_VI_CSI_1_SURFACE1_OFFSET_MSB 0x22c #define TEGRA_VI_CSI_1_SURFACE1_OFFSET_LSB 0x230 #define TEGRA_VI_CSI_1_SURFACE2_OFFSET_MSB 0x234 #define TEGRA_VI_CSI_1_SURFACE2_OFFSET_LSB 0x238 #define TEGRA_VI_CSI_1_SURFACE0_BF_OFFSET_MSB 0x23c #define TEGRA_VI_CSI_1_SURFACE0_BF_OFFSET_LSB 0x240 #define TEGRA_VI_CSI_1_SURFACE1_BF_OFFSET_MSB 0x244 #define TEGRA_VI_CSI_1_SURFACE1_BF_OFFSET_LSB 0x248 #define TEGRA_VI_CSI_1_SURFACE2_BF_OFFSET_MSB 0x24c #define TEGRA_VI_CSI_1_SURFACE2_BF_OFFSET_LSB 0x250 #define TEGRA_VI_CSI_1_SURFACE0_STRIDE 0x254 #define TEGRA_VI_CSI_1_SURFACE1_STRIDE 0x258 #define TEGRA_VI_CSI_1_SURFACE2_STRIDE 0x25c #define TEGRA_VI_CSI_1_SURFACE_HEIGHT0 0x260 #define TEGRA_VI_CSI_1_ISPINTF_CONFIG 0x264 #define TEGRA_VI_CSI_1_ERROR_STATUS 0x284 #define TEGRA_VI_CSI_1_ERROR_INT_MASK 0x288 #define TEGRA_VI_CSI_1_WD_CTRL 0x28c #define TEGRA_VI_CSI_1_WD_PERIOD 0x290 #define TEGRA_CSI_CSI_CAP_CIL 0x808 #define TEGRA_CSI_CSI_CAP_CSI 0x818 #define TEGRA_CSI_CSI_CAP_PP 0x828 #define TEGRA_CSI_INPUT_STREAM_A_CONTROL 0x838 #define TEGRA_CSI_PIXEL_STREAM_A_CONTROL0 0x83c #define TEGRA_CSI_PIXEL_STREAM_A_CONTROL1 0x840 #define TEGRA_CSI_PIXEL_STREAM_A_GAP 0x844 #define TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND 0x848 #define TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME 0x84c #define TEGRA_CSI_CSI_PIXEL_PARSER_A_INTERRUPT_MASK 0x850 #define TEGRA_CSI_CSI_PIXEL_PARSER_A_STATUS 0x854 #define TEGRA_CSI_CSI_SW_SENSOR_A_RESET 0x858 #define TEGRA_CSI_INPUT_STREAM_B_CONTROL 0x86c #define TEGRA_CSI_PIXEL_STREAM_B_CONTROL0 0x870 #define TEGRA_CSI_PIXEL_STREAM_B_CONTROL1 0x874 #define TEGRA_CSI_PIXEL_STREAM_B_GAP 0x878 #define TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND 0x87c #define TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME 0x880 #define TEGRA_CSI_CSI_PIXEL_PARSER_B_INTERRUPT_MASK 0x884 #define TEGRA_CSI_CSI_PIXEL_PARSER_B_STATUS 0x888 #define TEGRA_CSI_CSI_SW_SENSOR_B_RESET 0x88c #define TEGRA_CSI_PHY_CIL_COMMAND 0x908 #define TEGRA_CSI_CIL_PAD_CONFIG0 0x90c #define TEGRA_CSI_CILA_PAD_CONFIG0 0x92c #define TEGRA_CSI_CILA_PAD_CONFIG1 0x930 #define TEGRA_CSI_PHY_CILA_CONTROL0 0x934 #define TEGRA_CSI_CSI_CIL_A_INTERRUPT_MASK 0x938 #define TEGRA_CSI_CSI_CIL_A_STATUS 0x93c #define TEGRA_CSI_CSI_CILA_STATUS 0x940 #define TEGRA_CSI_CIL_A_ESCAPE_MODE_COMMAND 0x944 #define TEGRA_CSI_CIL_A_ESCAPE_MODE_DATA 0x948 #define TEGRA_CSI_CSICIL_SW_SENSOR_A_RESET 0x94c #define TEGRA_CSI_CILB_PAD_CONFIG0 0x960 #define TEGRA_CSI_CILB_PAD_CONFIG1 0x964 #define TEGRA_CSI_PHY_CILB_CONTROL0 0x968 #define TEGRA_CSI_CSI_CIL_B_INTERRUPT_MASK 0x96c #define TEGRA_CSI_CSI_CIL_B_STATUS 0x970 #define TEGRA_CSI_CSI_CILB_STATUS 0x974 #define TEGRA_CSI_CIL_B_ESCAPE_MODE_COMMAND 0x978 #define TEGRA_CSI_CIL_B_ESCAPE_MODE_DATA 0x97c #define TEGRA_CSI_CSICIL_SW_SENSOR_B_RESET 0x980 #define TEGRA_CSI_CILC_PAD_CONFIG0 0x994 #define TEGRA_CSI_CILC_PAD_CONFIG1 0x998 #define TEGRA_CSI_PHY_CILC_CONTROL0 0x99c #define TEGRA_CSI_CSI_CIL_C_INTERRUPT_MASK 0x9a0 #define TEGRA_CSI_CSI_CIL_C_STATUS 0x9a4 #define TEGRA_CSI_CSI_CILC_STATUS 0x9a8 #define TEGRA_CSI_CIL_C_ESCAPE_MODE_COMMAND 0x9ac #define TEGRA_CSI_CIL_C_ESCAPE_MODE_DATA 0x9b0 #define TEGRA_CSI_CSICIL_SW_SENSOR_C_RESET 0x9b4 #define TEGRA_CSI_CILD_PAD_CONFIG0 0x9c8 #define TEGRA_CSI_CILD_PAD_CONFIG1 0x9cc #define TEGRA_CSI_PHY_CILD_CONTROL0 0x9d0 #define TEGRA_CSI_CSI_CIL_D_INTERRUPT_MASK 0x9d4 #define TEGRA_CSI_CSI_CIL_D_STATUS 0x9d8 #define TEGRA_CSI_CSI_CILD_STATUS 0x9dc #define TEGRA_CSI_CIL_D_ESCAPE_MODE_COMMAND 0x9ec #define TEGRA_CSI_CIL_D_ESCAPE_MODE_DATA 0x9f0 #define TEGRA_CSI_CSICIL_SW_SENSOR_D_RESET 0x9f4 #define TEGRA_CSI_CILE_PAD_CONFIG0 0xa08 #define TEGRA_CSI_CILE_PAD_CONFIG1 0xa0c #define TEGRA_CSI_PHY_CILE_CONTROL0 0xa10 #define TEGRA_CSI_CSI_CIL_E_INTERRUPT_MASK 0xa14 #define TEGRA_CSI_CSI_CIL_E_STATUS 0xa18 #define TEGRA_CSI_CIL_E_ESCAPE_MODE_COMMAND 0xa1c #define TEGRA_CSI_CIL_E_ESCAPE_MODE_DATA 0xa20 #define TEGRA_CSI_CSICIL_SW_SENSOR_E_RESET 0xa24 #define TEGRA_CSI_PATTERN_GENERATOR_CTRL_A 0xa68 #define TEGRA_CSI_PG_BLANK_A 0xa6c #define TEGRA_CSI_PG_PHASE_A 0xa70 #define TEGRA_CSI_PG_RED_FREQ_A 0xa74 #define TEGRA_CSI_PG_RED_FREQ_RATE_A 0xa78 #define TEGRA_CSI_PG_GREEN_FREQ_A 0xa7c #define TEGRA_CSI_PG_GREEN_FREQ_RATE_A 0xa80 #define TEGRA_CSI_PG_BLUE_FREQ_A 0xa84 #define TEGRA_CSI_PG_BLUE_FREQ_RATE_A 0xa88 #define TEGRA_CSI_PATTERN_GENERATOR_CTRL_B 0xa9c #define TEGRA_CSI_PG_BLANK_B 0xaa0 #define TEGRA_CSI_PG_PHASE_B 0xaa4 #define TEGRA_CSI_PG_RED_FREQ_B 0xaa8 #define TEGRA_CSI_PG_RED_FREQ_RATE_B 0xaac #define TEGRA_CSI_PG_GREEN_FREQ_B 0xab0 #define TEGRA_CSI_PG_GREEN_FREQ_RATE_B 0xab4 #define TEGRA_CSI_PG_BLUE_FREQ_B 0xab8 #define TEGRA_CSI_PG_BLUE_FREQ_RATE_B 0xabc #define TEGRA_CSI_DPCM_CTRL_A 0xad0 #define TEGRA_CSI_DPCM_CTRL_B 0xad4 #define TEGRA_CSI_STALL_COUNTER 0xae8 #define TEGRA_CSI_CSI_READONLY_STATUS 0xaec #define TEGRA_CSI_CSI_SW_STATUS_RESET 0xaf0 #define TEGRA_CSI_CLKEN_OVERRIDE 0xaf4 #define TEGRA_CSI_DEBUG_CONTROL 0xaf8 #define TEGRA_CSI_DEBUG_COUNTER_0 0xafc #define TEGRA_CSI_DEBUG_COUNTER_1 0xb00 #define TEGRA_CSI_DEBUG_COUNTER_2 0xb04 /* These go into the TEGRA_VI_CSI_n_IMAGE_DEF registers bits 23:16 */ #define TEGRA_IMAGE_FORMAT_T_L8 16 #define TEGRA_IMAGE_FORMAT_T_R16_I 32 #define TEGRA_IMAGE_FORMAT_T_B5G6R5 33 #define TEGRA_IMAGE_FORMAT_T_R5G6B5 34 #define TEGRA_IMAGE_FORMAT_T_A1B5G5R5 35 #define TEGRA_IMAGE_FORMAT_T_A1R5G5B5 36 #define TEGRA_IMAGE_FORMAT_T_B5G5R5A1 37 #define TEGRA_IMAGE_FORMAT_T_R5G5B5A1 38 #define TEGRA_IMAGE_FORMAT_T_A4B4G4R4 39 #define TEGRA_IMAGE_FORMAT_T_A4R4G4B4 40 #define TEGRA_IMAGE_FORMAT_T_B4G4R4A4 41 #define TEGRA_IMAGE_FORMAT_T_R4G4B4A4 42 #define TEGRA_IMAGE_FORMAT_T_A8B8G8R8 64 #define TEGRA_IMAGE_FORMAT_T_A8R8G8B8 65 #define TEGRA_IMAGE_FORMAT_T_B8G8R8A8 66 #define TEGRA_IMAGE_FORMAT_T_R8G8B8A8 67 #define TEGRA_IMAGE_FORMAT_T_A2B10G10R10 68 #define TEGRA_IMAGE_FORMAT_T_A2R10G10B10 69 #define TEGRA_IMAGE_FORMAT_T_B10G10R10A2 70 #define TEGRA_IMAGE_FORMAT_T_R10G10B10A2 71 #define TEGRA_IMAGE_FORMAT_T_A8Y8U8V8 193 #define TEGRA_IMAGE_FORMAT_T_V8U8Y8A8 194 #define TEGRA_IMAGE_FORMAT_T_A2Y10U10V10 197 #define TEGRA_IMAGE_FORMAT_T_V10U10Y10A2 198 #define TEGRA_IMAGE_FORMAT_T_Y8_U8__Y8_V8 200 #define TEGRA_IMAGE_FORMAT_T_Y8_V8__Y8_U8 201 #define TEGRA_IMAGE_FORMAT_T_U8_Y8__V8_Y8 202 #define TEGRA_IMAGE_FORMAT_T_T_V8_Y8__U8_Y8 203 #define TEGRA_IMAGE_FORMAT_T_T_Y8__U8__V8_N444 224 #define TEGRA_IMAGE_FORMAT_T_Y8__U8V8_N444 225 #define TEGRA_IMAGE_FORMAT_T_Y8__V8U8_N444 226 #define TEGRA_IMAGE_FORMAT_T_Y8__U8__V8_N422 227 #define TEGRA_IMAGE_FORMAT_T_Y8__U8V8_N422 228 #define TEGRA_IMAGE_FORMAT_T_Y8__V8U8_N422 229 #define TEGRA_IMAGE_FORMAT_T_Y8__U8__V8_N420 230 #define TEGRA_IMAGE_FORMAT_T_Y8__U8V8_N420 231 #define TEGRA_IMAGE_FORMAT_T_Y8__V8U8_N420 232 #define TEGRA_IMAGE_FORMAT_T_X2Lc10Lb10La10 233 #define TEGRA_IMAGE_FORMAT_T_A2R6R6R6R6R6 234 /* These go into the TEGRA_VI_CSI_n_CSI_IMAGE_DT registers bits 7:0 */ #define TEGRA_IMAGE_DT_YUV420_8 24 #define TEGRA_IMAGE_DT_YUV420_10 25 #define TEGRA_IMAGE_DT_YUV420CSPS_8 28 #define TEGRA_IMAGE_DT_YUV420CSPS_10 29 #define TEGRA_IMAGE_DT_YUV422_8 30 #define TEGRA_IMAGE_DT_YUV422_10 31 #define TEGRA_IMAGE_DT_RGB444 32 #define TEGRA_IMAGE_DT_RGB555 33 #define TEGRA_IMAGE_DT_RGB565 34 #define TEGRA_IMAGE_DT_RGB666 35 #define TEGRA_IMAGE_DT_RGB888 36 #define TEGRA_IMAGE_DT_RAW6 40 #define TEGRA_IMAGE_DT_RAW7 41 #define TEGRA_IMAGE_DT_RAW8 42 #define TEGRA_IMAGE_DT_RAW10 43 #define TEGRA_IMAGE_DT_RAW12 44 #define TEGRA_IMAGE_DT_RAW14 45 #define MIPI_CAL_CTRL 0x00 #define STARTCAL (1 << 0) #define CLKEN_OVR (1 << 4) #define MIPI_CAL_AUTOCAL_CTRL0 0x04 #define CIL_MIPI_CAL_STATUS 0x08 #define CAL_DONE (1 << 16) #define CIL_MIPI_CAL_STATUS_2 0x0c #define CILA_MIPI_CAL_CONFIG 0x14 #define SELA (1 << 21) #define CILB_MIPI_CAL_CONFIG 0x18 #define SELB (1 << 21) #define CILC_MIPI_CAL_CONFIG 0x1c #define SELC (1 << 21) #define CILD_MIPI_CAL_CONFIG 0x20 #define SELD (1 << 21) #define CILE_MIPI_CAL_CONFIG 0x24 #define SELE (1 << 21) #define DSIA_MIPI_CAL_CONFIG 0x38 #define SELDSIA (1 << 21) #define DSIB_MIPI_CAL_CONFIG 0x3c #define SELDSIB (1 << 21) #define MIPI_BIAS_PAD_CFG0 0x58 #define E_VCLAMP_REF (1 << 0) #define MIPI_BIAS_PAD_CFG1 0x5c #define MIPI_BIAS_PAD_CFG2 0x60 #define PDVREG (1 << 1) #define DSIA_MIPI_CAL_CONFIG_2 0x64 #define CLKSELDSIA (1 << 21) #define DSIB_MIPI_CAL_CONFIG_2 0x68 #define CLKSELDSIB (1 << 21) #define CILC_MIPI_CAL_CONFIG_2 0x6c #define CLKSELC (1 << 21) #define CILD_MIPI_CAL_CONFIG_2 0x70 #define CLKSELD (1 << 21) #define CSIE_MIPI_CAL_CONFIG_2 0x74 #define CLKSELE (1 << 21) #define MIPI_CAL_BASE 0x700e3000 static const struct regmap_config mipi_cal_config = { .reg_bits = 32, .reg_stride = 4, .val_bits = 32, .cache_type = REGCACHE_RBTREE, }; static int vi2_port_is_valid(int port) { return (((port) >= TEGRA_CAMERA_PORT_CSI_A) && ((port) <= TEGRA_CAMERA_PORT_CSI_C)); } /* Clock settings for camera */ static struct tegra_camera_clk vi2_clks0[] = { { .name = "vi", .freq = 408000000, .use_devname = 1, }, { .name = "vi_sensor", .freq = 24000000, }, { .name = "csi", .freq = 408000000, .use_devname = 1, }, { .name = "isp", .freq = 0, }, { .name = "csus", .freq = 0, .use_devname = 1, }, { .name = "sclk", .freq = 80000000, }, { .name = "emc", .freq = 300000000, }, { .name = "cilab", .freq = 102000000, .use_devname = 1, }, /* Always put "p11_d" at the end */ { .name = "pll_d", .freq = 927000000, }, }; static struct tegra_camera_clk vi2_clks1[] = { { .name = "vi", .freq = 408000000, .use_devname = 1, }, { .name = "vi_sensor2", .freq = 24000000, }, { .name = "csi", .freq = 408000000, .use_devname = 1, }, { .name = "isp", .freq = 0, }, { .name = "sclk", .freq = 80000000, }, { .name = "emc", .freq = 300000000, }, { .name = "cilcd", .freq = 102000000, .use_devname = 1, }, { .name = "cile", .freq = 102000000, .use_devname = 1, }, /* Always put "p11_d" at the end */ { .name = "pll_d", .freq = 927000000, }, }; #define MAX_DEVID_LENGTH 16 static int vi2_clks_init(struct tegra_camera_dev *cam, int port) { struct platform_device *pdev = cam->ndev; struct tegra_camera_clk *clks; int i; switch (port) { case TEGRA_CAMERA_PORT_CSI_A: cam->num_clks = ARRAY_SIZE(vi2_clks0); cam->clks = vi2_clks0; break; case TEGRA_CAMERA_PORT_CSI_B: case TEGRA_CAMERA_PORT_CSI_C: cam->num_clks = ARRAY_SIZE(vi2_clks1); cam->clks = vi2_clks1; break; default: dev_err(&pdev->dev, "Wrong port number %d\n", port); return -ENODEV; } for (i = 0; i < cam->num_clks; i++) { clks = &cam->clks[i]; if (clks->use_devname) { char devname[MAX_DEVID_LENGTH]; snprintf(devname, MAX_DEVID_LENGTH, "tegra_%s", dev_name(&pdev->dev)); clks->clk = clk_get_sys(devname, clks->name); } else clks->clk = clk_get(&pdev->dev, clks->name); if (IS_ERR_OR_NULL(clks->clk)) { dev_err(&pdev->dev, "Failed to get clock %s.\n", clks->name); return PTR_ERR(clks->clk); } } return 0; } static void vi2_clks_deinit(struct tegra_camera_dev *cam) { struct tegra_camera_clk *clks; int i; for (i = 0; i < cam->num_clks; i++) { clks = &cam->clks[i]; if (clks->clk) clk_put(clks->clk); } } static void vi2_clks_enable(struct tegra_camera_dev *cam) { struct tegra_camera_clk *clks; int i; for (i = 0; i < cam->num_clks - 1; i++) { clks = &cam->clks[i]; if (clks->clk) clk_prepare_enable(clks->clk); if (clks->freq > 0) clk_set_rate(clks->clk, clks->freq); } if (cam->tpg_mode) { clks = &cam->clks[i]; if (clks->clk) { clk_prepare_enable(clks->clk); if (clks->freq > 0) clk_set_rate(clks->clk, clks->freq); tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_PLLD_CSI_OUT_ENB, 1); tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_PLLD_DSI_OUT_ENB, 1); tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_MIPI_CSI_OUT_ENB, 0); } } } static void vi2_clks_disable(struct tegra_camera_dev *cam) { struct tegra_camera_clk *clks; int i; for (i = 0; i < cam->num_clks - 1; i++) { clks = &cam->clks[i]; if (clks->clk) clk_disable_unprepare(clks->clk); } if (cam->tpg_mode) { clks = &cam->clks[i]; if (clks->clk) { tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_MIPI_CSI_OUT_ENB, 1); tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_PLLD_CSI_OUT_ENB, 0); tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_PLLD_DSI_OUT_ENB, 0); clk_disable_unprepare(clks->clk); } } } static void vi2_init_syncpts(struct tegra_camera_dev *cam) { cam->syncpt_id_csi_a = nvhost_get_syncpt_client_managed("vi_csi_A"); cam->syncpt_id_csi_b = nvhost_get_syncpt_client_managed("vi_csi_B"); } static void vi2_free_syncpts(struct tegra_camera_dev *cam) { nvhost_free_syncpt(cam->syncpt_id_csi_a); nvhost_free_syncpt(cam->syncpt_id_csi_b); } static void vi2_incr_syncpts(struct tegra_camera_dev *cam) { return; } static void vi2_capture_clean(struct tegra_camera_dev *cam) { /* Clean up status */ TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_A_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_B_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_C_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_D_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_E_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CILA_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CILB_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CILC_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CILD_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_PIXEL_PARSER_A_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_PIXEL_PARSER_B_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_ERROR_STATUS, 0xFFFFFFFF); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_ERROR_STATUS, 0xFFFFFFFF); } static int vi2_capture_setup_csi_0(struct tegra_camera_dev *cam, struct soc_camera_device *icd) { struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc; struct tegra_camera_platform_data *pdata = ssdesc->drv_priv; int format = 0, data_type = 0, image_size = 0; u32 val; /* * PAD_CILA_PDVCLAMP 0, PAD_CILA_PDIO_CLK 0, * PAD_CILA_PDIO 0, PAD_AB_BK_MODE 1 */ TC_VI_REG_WT(cam, TEGRA_CSI_CILA_PAD_CONFIG0, 0x10000); /* PAD_CILB_PDVCLAMP 0, PAD_CILB_PDIO_CLK 0, PAD_CILB_PDIO 0 */ TC_VI_REG_WT(cam, TEGRA_CSI_CILB_PAD_CONFIG0, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_A_INTERRUPT_MASK, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_B_INTERRUPT_MASK, 0x0); #ifdef DEBUG TC_VI_REG_WT(cam, TEGRA_CSI_DEBUG_CONTROL, 0x3 | (0x1 << 5) | (0x40 << 8)); #endif TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILA_CONTROL0, 0x49); TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILB_CONTROL0, 0x49); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0xf007); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_PIXEL_PARSER_A_INTERRUPT_MASK, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, 0x280301f0); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0xf007); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1, 0x11); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x140000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_INPUT_STREAM_A_CONTROL, 0x3f0000 | (pdata->lanes - 1)); /* Shared register */ val = TC_VI_REG_RD(cam, TEGRA_CSI_PHY_CIL_COMMAND); if (pdata->lanes == 4) TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, (val & 0xFFFF0000) | 0x0101); else TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, (val & 0xFFFF0000) | 0x0201); if (cam->tpg_mode) { TC_VI_REG_WT(cam, TEGRA_CSI_PATTERN_GENERATOR_CTRL_A, ((cam->tpg_mode - 1) << 2) | 0x1); TC_VI_REG_WT(cam, TEGRA_CSI_PG_PHASE_A, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PG_RED_FREQ_A, 0x100010); TC_VI_REG_WT(cam, TEGRA_CSI_PG_RED_FREQ_RATE_A, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PG_GREEN_FREQ_A, 0x100010); TC_VI_REG_WT(cam, TEGRA_CSI_PG_GREEN_FREQ_RATE_A, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PG_BLUE_FREQ_A, 0x100010); TC_VI_REG_WT(cam, TEGRA_CSI_PG_BLUE_FREQ_RATE_A, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x22020202); format = TEGRA_IMAGE_FORMAT_T_A8B8G8R8; data_type = TEGRA_IMAGE_DT_RGB888; image_size = icd->user_width * 3; } else if ((icd->current_fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) || (icd->current_fmt->code == V4L2_MBUS_FMT_VYUY8_2X8) || (icd->current_fmt->code == V4L2_MBUS_FMT_YUYV8_2X8) || (icd->current_fmt->code == V4L2_MBUS_FMT_YVYU8_2X8)) { format = TEGRA_IMAGE_FORMAT_T_U8_Y8__V8_Y8; data_type = TEGRA_IMAGE_DT_YUV422_8; image_size = icd->user_width * 2; } else if ((icd->current_fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8) || (icd->current_fmt->code == V4L2_MBUS_FMT_SGBRG8_1X8)) { format = TEGRA_IMAGE_FORMAT_T_L8; data_type = TEGRA_IMAGE_DT_RAW8; image_size = icd->user_width; } else if ((icd->current_fmt->code == V4L2_MBUS_FMT_SBGGR10_1X10) || (icd->current_fmt->code == V4L2_MBUS_FMT_SRGGB10_1X10)) { format = TEGRA_IMAGE_FORMAT_T_R16_I; data_type = TEGRA_IMAGE_DT_RAW10; image_size = (icd->user_width * 10) >> 3; } TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_IMAGE_DEF, ((format << 16) | 0x1)); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_CSI_IMAGE_DT, data_type); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_CSI_IMAGE_SIZE_WC, image_size); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_CSI_IMAGE_SIZE, (icd->user_height << 16) | icd->user_width); /* Start pixel parser in single shot mode at beginning */ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0xf005); return 0; } static int vi2_capture_setup_csi_1(struct tegra_camera_dev *cam, struct soc_camera_device *icd) { struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc; struct tegra_camera_platform_data *pdata = ssdesc->drv_priv; int format = 0, data_type = 0, image_size = 0; u32 val; /* * PAD_CILC_PDVCLAMP 0, PAD_CILC_PDIO_CLK 0, * PAD_CILC_PDIO 0, PAD_CD_BK_MODE 1 */ TC_VI_REG_WT(cam, TEGRA_CSI_CILC_PAD_CONFIG0, 0x10000); /* PAD_CILD_PDVCLAMP 0, PAD_CILD_PDIO_CLK 0, PAD_CILD_PDIO 0 */ TC_VI_REG_WT(cam, TEGRA_CSI_CILD_PAD_CONFIG0, 0x0); /* PAD_CILE_PDVCLAMP 0, PAD_CILE_PDIO_CLK 0, PAD_CILE_PDIO 0 */ TC_VI_REG_WT(cam, TEGRA_CSI_CILE_PAD_CONFIG0, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_C_INTERRUPT_MASK, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_D_INTERRUPT_MASK, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_E_INTERRUPT_MASK, 0x0); #ifdef DEBUG TC_VI_REG_WT(cam, TEGRA_CSI_DEBUG_CONTROL, 0x5 | (0x1 << 5) | (0x50 << 8)); #endif if (pdata->port == TEGRA_CAMERA_PORT_CSI_B) { TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILC_CONTROL0, 0x49); TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILD_CONTROL0, 0x49); } else if (pdata->port == TEGRA_CAMERA_PORT_CSI_C) TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILE_CONTROL0, 0x49); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0xf007); TC_VI_REG_WT(cam, TEGRA_CSI_CSI_PIXEL_PARSER_B_INTERRUPT_MASK, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0, 0x280301f1); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0xf007); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1, 0x11); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x140000); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_INPUT_STREAM_B_CONTROL, 0x3f0000 | (pdata->lanes - 1)); /* Shared register */ val = TC_VI_REG_RD(cam, TEGRA_CSI_PHY_CIL_COMMAND); if (pdata->lanes == 4) TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, (val & 0x0000FFFF) | 0x21010000); else if (pdata->lanes == 1 && pdata->port == TEGRA_CAMERA_PORT_CSI_C) TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, (val & 0x0000FFFF) | 0x12020000); else TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, (val & 0x0000FFFF) | 0x22010000); if (cam->tpg_mode) { TC_VI_REG_WT(cam, TEGRA_CSI_PATTERN_GENERATOR_CTRL_B, ((cam->tpg_mode - 1) << 2) | 0x1); TC_VI_REG_WT(cam, TEGRA_CSI_PG_PHASE_B, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PG_RED_FREQ_B, 0x100010); TC_VI_REG_WT(cam, TEGRA_CSI_PG_RED_FREQ_RATE_B, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PG_GREEN_FREQ_B, 0x100010); TC_VI_REG_WT(cam, TEGRA_CSI_PG_GREEN_FREQ_RATE_B, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PG_BLUE_FREQ_B, 0x100010); TC_VI_REG_WT(cam, TEGRA_CSI_PG_BLUE_FREQ_RATE_B, 0x0); TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x22020202); format = TEGRA_IMAGE_FORMAT_T_A8B8G8R8; data_type = TEGRA_IMAGE_DT_RGB888; image_size = icd->user_width * 3; } else if ((icd->current_fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) || (icd->current_fmt->code == V4L2_MBUS_FMT_VYUY8_2X8) || (icd->current_fmt->code == V4L2_MBUS_FMT_YUYV8_2X8) || (icd->current_fmt->code == V4L2_MBUS_FMT_YVYU8_2X8)) { format = TEGRA_IMAGE_FORMAT_T_U8_Y8__V8_Y8; data_type = TEGRA_IMAGE_DT_YUV422_8; image_size = icd->user_width * 2; } else if ((icd->current_fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8) || (icd->current_fmt->code == V4L2_MBUS_FMT_SGBRG8_1X8)) { format = TEGRA_IMAGE_FORMAT_T_L8; data_type = TEGRA_IMAGE_DT_RAW8; image_size = icd->user_width; } else if ((icd->current_fmt->code == V4L2_MBUS_FMT_SBGGR10_1X10) || (icd->current_fmt->code == V4L2_MBUS_FMT_SRGGB10_1X10)) { format = TEGRA_IMAGE_FORMAT_T_R16_I; data_type = TEGRA_IMAGE_DT_RAW10; image_size = icd->user_width * 10 / 8; } TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_IMAGE_DEF, ((format << 16) | 0x1)); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_CSI_IMAGE_DT, data_type); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_CSI_IMAGE_SIZE_WC, image_size); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_CSI_IMAGE_SIZE, (icd->user_height << 16) | icd->user_width); /* Start pixel parser in single shot mode at beginning */ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0xf005); return 0; } static int vi2_capture_setup(struct tegra_camera_dev *cam) { struct vb2_buffer *vb = cam->active; struct tegra_camera_buffer *buf = to_tegra_vb(vb); struct soc_camera_device *icd = buf->icd; struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc; struct tegra_camera_platform_data *pdata = ssdesc->drv_priv; int port = pdata->port; /* Skip VI2/CSI2 setup for second and later frame capture */ if (!cam->sof) return 0; /* Setup registers for CSI-A and CSI-B inputs */ if (port == TEGRA_CAMERA_PORT_CSI_A) return vi2_capture_setup_csi_0(cam, icd); else if (port == TEGRA_CAMERA_PORT_CSI_B || port == TEGRA_CAMERA_PORT_CSI_C) return vi2_capture_setup_csi_1(cam, icd); else return -ENODEV; } static s32 vi2_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf) { s32 bytes_per_line = soc_mbus_bytes_per_line(width, mf); if (bytes_per_line % 64) bytes_per_line = bytes_per_line + (64 - (bytes_per_line % 64)); return bytes_per_line; } static int vi2_capture_buffer_setup(struct tegra_camera_dev *cam, struct tegra_camera_buffer *buf) { struct soc_camera_device *icd = buf->icd; int bytes_per_line = vi2_bytes_per_line(icd->user_width, icd->current_fmt->host_fmt); struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc; struct tegra_camera_platform_data *pdata = ssdesc->drv_priv; int port = pdata->port; switch (icd->current_fmt->host_fmt->fourcc) { case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YVU420: /* FIXME: Setup YUV buffer */ case V4L2_PIX_FMT_UYVY: case V4L2_PIX_FMT_VYUY: case V4L2_PIX_FMT_YUYV: case V4L2_PIX_FMT_YVYU: case V4L2_PIX_FMT_SBGGR8: case V4L2_PIX_FMT_SGBRG8: case V4L2_PIX_FMT_SBGGR10: case V4L2_PIX_FMT_SRGGB10: case V4L2_PIX_FMT_RGB32: if (port == TEGRA_CAMERA_PORT_CSI_A) { switch (buf->output_channel) { case 0: TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SURFACE0_OFFSET_MSB, 0x0); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SURFACE0_OFFSET_LSB, buf->buffer_addr); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SURFACE0_STRIDE, bytes_per_line); break; case 1: TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SURFACE1_OFFSET_MSB, 0x0); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SURFACE1_OFFSET_LSB, buf->buffer_addr); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SURFACE1_STRIDE, bytes_per_line); break; case 2: TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SURFACE2_OFFSET_MSB, 0x0); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SURFACE2_OFFSET_LSB, buf->buffer_addr); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SURFACE2_STRIDE, bytes_per_line); break; } } else if (port == TEGRA_CAMERA_PORT_CSI_B || port == TEGRA_CAMERA_PORT_CSI_C) { switch (buf->output_channel) { case 0: TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SURFACE0_OFFSET_MSB, 0x0); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SURFACE0_OFFSET_LSB, buf->buffer_addr); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SURFACE0_STRIDE, bytes_per_line); break; case 1: TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SURFACE1_OFFSET_MSB, 0x0); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SURFACE1_OFFSET_LSB, buf->buffer_addr); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SURFACE1_STRIDE, bytes_per_line); break; case 2: TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SURFACE2_OFFSET_MSB, 0x0); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SURFACE2_OFFSET_LSB, buf->buffer_addr); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SURFACE2_STRIDE, bytes_per_line); break; } } break; default: dev_err(&cam->ndev->dev, "Wrong host format %d\n", icd->current_fmt->host_fmt->fourcc); return -EINVAL; } return 0; } static void vi2_capture_error_status(struct tegra_camera_dev *cam) { u32 val; #ifdef DEBUG val = TC_VI_REG_RD(cam, TEGRA_CSI_DEBUG_COUNTER_0); pr_err("TEGRA_CSI_DEBUG_COUNTER_0 0x%08x\n", val); #endif val = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_A_STATUS); pr_err("TEGRA_CSI_CSI_CIL_A_STATUS 0x%08x\n", val); val = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CILA_STATUS); pr_err("TEGRA_CSI_CSI_CILA_STATUS 0x%08x\n", val); val = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_B_STATUS); pr_err("TEGRA_CSI_CSI_CIL_B_STATUS 0x%08x\n", val); val = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_C_STATUS); pr_err("TEGRA_CSI_CSI_CIL_C_STATUS 0x%08x\n", val); val = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_D_STATUS); pr_err("TEGRA_CSI_CSI_CIL_D_STATUS 0x%08x\n", val); val = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_E_STATUS); pr_err("TEGRA_CSI_CSI_CIL_E_STATUS 0x%08x\n", val); val = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_PIXEL_PARSER_A_STATUS); pr_err("TEGRA_CSI_CSI_PIXEL_PARSER_A_STATUS 0x%08x\n", val); val = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_PIXEL_PARSER_B_STATUS); pr_err("TEGRA_CSI_CSI_PIXEL_PARSER_B_STATUS 0x%08x\n", val); val = TC_VI_REG_RD(cam, TEGRA_VI_CSI_0_ERROR_STATUS); pr_err("TEGRA_VI_CSI_0_ERROR_STATUS 0x%08x\n", val); val = TC_VI_REG_RD(cam, TEGRA_VI_CSI_1_ERROR_STATUS); pr_err("TEGRA_VI_CSI_1_ERROR_STATUS 0x%08x\n", val); } static int vi2_capture_start(struct tegra_camera_dev *cam, struct tegra_camera_buffer *buf) { struct soc_camera_device *icd = buf->icd; struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc; struct tegra_camera_platform_data *pdata = ssdesc->drv_priv; int port = pdata->port; int err; u32 val; err = vi2_capture_buffer_setup(cam, buf); if (err < 0) return err; /* Only wait on CSI frame end syncpt if we're using CSI. */ if (port == TEGRA_CAMERA_PORT_CSI_A) { if (!nvhost_syncpt_read_ext_check(cam->ndev, cam->syncpt_id_csi_a, &val)) cam->syncpt_csi_a = nvhost_syncpt_incr_max_ext( cam->ndev, cam->syncpt_id_csi_a, 1); TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT, VI_CSI_PPA_FRAME_START | cam->syncpt_id_csi_a); TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SINGLE_SHOT, 0x1); err = nvhost_syncpt_wait_timeout_ext(cam->ndev, cam->syncpt_id_csi_a, cam->syncpt_csi_a, TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, NULL, NULL); } else if (port == TEGRA_CAMERA_PORT_CSI_B || port == TEGRA_CAMERA_PORT_CSI_C) { if (!nvhost_syncpt_read_ext_check(cam->ndev, cam->syncpt_id_csi_b, &val)) cam->syncpt_csi_b = nvhost_syncpt_incr_max_ext( cam->ndev, cam->syncpt_id_csi_b, 1); TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT, VI_CSI_PPB_FRAME_START | cam->syncpt_id_csi_b); TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SINGLE_SHOT, 0x1); err = nvhost_syncpt_wait_timeout_ext(cam->ndev, cam->syncpt_id_csi_b, cam->syncpt_csi_b, TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, NULL, NULL); } /* Mark SOF flag to Zero after we captured the FIRST frame */ if (cam->sof) cam->sof = 0; /* Capture syncpt timeout err, then dump error status */ if (err) { if (port == TEGRA_CAMERA_PORT_CSI_A) dev_err(&cam->ndev->dev, "CSI_A syncpt timeout, syncpt = %d, err = %d\n", cam->syncpt_csi_a, err); else if (port == TEGRA_CAMERA_PORT_CSI_B || port == TEGRA_CAMERA_PORT_CSI_C) dev_err(&cam->ndev->dev, "CSI_B/CSI_C syncpt timeout, syncpt = %d, err = %d\n", cam->syncpt_csi_b, err); vi2_capture_error_status(cam); } return err; } static int vi2_capture_stop(struct tegra_camera_dev *cam, int port) { u32 val; int err = 0; if (port == TEGRA_CAMERA_PORT_CSI_A) { if (!nvhost_syncpt_read_ext_check(cam->ndev, cam->syncpt_id_csi_a, &val)) cam->syncpt_csi_a = nvhost_syncpt_incr_max_ext( cam->ndev, cam->syncpt_id_csi_a, 1); /* * Make sure recieve VI_MWA_ACK_DONE of the last frame before * stop and dequeue buffer, otherwise MC error will shows up * for the last frame. */ TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT, VI_MWA_ACK_DONE | cam->syncpt_id_csi_a); /* * Ignore error here and just stop pixel parser after waiting, * even if it's timeout */ err = nvhost_syncpt_wait_timeout_ext(cam->ndev, cam->syncpt_id_csi_a, cam->syncpt_csi_a, TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, NULL, NULL); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0xf002); } else if (port == TEGRA_CAMERA_PORT_CSI_B || port == TEGRA_CAMERA_PORT_CSI_C) { if (!nvhost_syncpt_read_ext_check(cam->ndev, cam->syncpt_id_csi_b, &val)) cam->syncpt_csi_b = nvhost_syncpt_incr_max_ext( cam->ndev, cam->syncpt_id_csi_b, 1); /* * Make sure recieve VI_MWB_ACK_DONE of the last frame before * stop and dequeue buffer, otherwise MC error will shows up * for the last frame. */ TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT, VI_MWB_ACK_DONE | cam->syncpt_id_csi_b); /* * Ignore error here and just stop pixel parser after waiting, * even if it's timeout */ err = nvhost_syncpt_wait_timeout_ext(cam->ndev, cam->syncpt_id_csi_b, cam->syncpt_csi_b, TEGRA_SYNCPT_CSI_WAIT_TIMEOUT, NULL, NULL); TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0xf002); } return err; } /* Reset VI2/CSI2 when activating, no sepecial ops for deactiving */ static void vi2_sw_reset(struct tegra_camera_dev *cam) { /* T12_CG_2ND_LEVEL_EN */ TC_VI_REG_WT(cam, TEGRA_VI_CFG_CG_CTRL, 1); TC_VI_REG_WT(cam, TEGRA_CSI_CLKEN_OVERRIDE, 0x0); udelay(10); } static int vi2_mipi_calibration(struct tegra_camera_dev *cam) { void __iomem *mipi_cal; struct regmap *regs; struct platform_device *pdev = cam->ndev; struct vb2_buffer *vb = cam->active; struct tegra_camera_buffer *buf = to_tegra_vb(vb); struct soc_camera_device *icd = buf->icd; struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc; struct tegra_camera_platform_data *pdata = ssdesc->drv_priv; int port = pdata->port; u32 val; struct clk *clk_mipi_cal = NULL, *clk_72mhz = NULL; int retry = 500; /* TPG mode doesn't need any calibration */ if (cam->tpg_mode) return 0; /* Get clks for MIPI Calibration */ clk_mipi_cal = clk_get_sys("mipi-cal", NULL); if (IS_ERR_OR_NULL(clk_mipi_cal)) { dev_err(&pdev->dev, "cannot get mipi-cal clk.\n"); return PTR_ERR(clk_mipi_cal); } clk_72mhz = clk_get_sys("clk72mhz", NULL); if (IS_ERR_OR_NULL(clk_72mhz)) { dev_err(&pdev->dev, "cannot get 72MHz clk.\n"); return PTR_ERR(clk_72mhz); } /* Map registers */ mipi_cal = ioremap(MIPI_CAL_BASE, 0x100); if (!mipi_cal) return -ENOMEM; regs = devm_regmap_init_mmio(&pdev->dev, mipi_cal, &mipi_cal_config); if (IS_ERR(regs)) { dev_err(&pdev->dev, "regmap init failed\n"); iounmap(mipi_cal); return PTR_ERR(regs); } /* Enable MIPI Calibration clocks */ if (clk_mipi_cal) clk_prepare_enable(clk_mipi_cal); if (clk_72mhz) clk_prepare_enable(clk_72mhz); /* MIPI_CAL_CLKEN_OVR = 1 */ regmap_update_bits(regs, MIPI_CAL_CTRL, CLKEN_OVR, CLKEN_OVR); /* Clear MIPI CAL status flags */ regmap_write(regs, CIL_MIPI_CAL_STATUS, 0xF1F10000); regmap_update_bits(regs, DSIA_MIPI_CAL_CONFIG, SELDSIA, 0); regmap_update_bits(regs, DSIB_MIPI_CAL_CONFIG, SELDSIB, 0); regmap_update_bits(regs, MIPI_BIAS_PAD_CFG0, E_VCLAMP_REF, E_VCLAMP_REF); regmap_update_bits(regs, MIPI_BIAS_PAD_CFG2, PDVREG, 0); regmap_update_bits(regs, CILA_MIPI_CAL_CONFIG, SELA, 0); regmap_update_bits(regs, DSIA_MIPI_CAL_CONFIG_2, CLKSELDSIA, 0); regmap_update_bits(regs, CILB_MIPI_CAL_CONFIG, SELB, 0); regmap_update_bits(regs, DSIB_MIPI_CAL_CONFIG_2, CLKSELDSIB, 0); regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG, SELC, 0); regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG_2, CLKSELC, 0); regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG, SELD, 0); regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG_2, CLKSELD, 0); regmap_update_bits(regs, CILE_MIPI_CAL_CONFIG, SELE, 0); regmap_update_bits(regs, CSIE_MIPI_CAL_CONFIG_2, CLKSELE, 0); /* Select the CIL pad for auto calibration */ switch (port) { case TEGRA_CAMERA_PORT_CSI_A: regmap_update_bits(regs, CILA_MIPI_CAL_CONFIG, SELA, SELA); regmap_update_bits(regs, DSIA_MIPI_CAL_CONFIG_2, CLKSELDSIA, 0); if (pdata->lanes > 2) { regmap_update_bits(regs, CILB_MIPI_CAL_CONFIG, SELB, SELB); regmap_update_bits(regs, DSIB_MIPI_CAL_CONFIG_2, CLKSELDSIB, 0); } break; case TEGRA_CAMERA_PORT_CSI_B: regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG, SELC, SELC); regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG_2, CLKSELC, 0); if (pdata->lanes > 2) { regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG, SELD, SELD); regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG_2, CLKSELD, 0); } break; case TEGRA_CAMERA_PORT_CSI_C: regmap_update_bits(regs, CILE_MIPI_CAL_CONFIG, SELE, SELE); regmap_update_bits(regs, CSIE_MIPI_CAL_CONFIG_2, CLKSELE, CLKSELE); break; default: dev_err(&pdev->dev, "wrong port %d\n", port); } /* Trigger calibration */ regmap_update_bits(regs, MIPI_CAL_CTRL, STARTCAL, STARTCAL); while (--retry) { regmap_read(regs, CIL_MIPI_CAL_STATUS, &val); if (val & CAL_DONE) break; usleep_range(200, 300); } /* Cleanup: un-select to avoid interference with DSI */ regmap_update_bits(regs, CILA_MIPI_CAL_CONFIG, SELA, 0); regmap_update_bits(regs, DSIA_MIPI_CAL_CONFIG_2, CLKSELDSIA, CLKSELDSIA); regmap_update_bits(regs, CILB_MIPI_CAL_CONFIG, SELB, 0); regmap_update_bits(regs, DSIB_MIPI_CAL_CONFIG_2, CLKSELDSIB, CLKSELDSIB); regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG, SELC, 0); regmap_update_bits(regs, CILC_MIPI_CAL_CONFIG_2, CLKSELC, CLKSELC); regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG, SELD, 0); regmap_update_bits(regs, CILD_MIPI_CAL_CONFIG_2, CLKSELD, CLKSELD); regmap_update_bits(regs, CILE_MIPI_CAL_CONFIG, SELE, 0); regmap_update_bits(regs, CSIE_MIPI_CAL_CONFIG_2, CLKSELE, 0); /* Disable clocks */ if (clk_mipi_cal) clk_disable_unprepare(clk_mipi_cal); if (clk_72mhz) clk_disable_unprepare(clk_72mhz); if (!retry) { dev_err(&pdev->dev, "MIPI calibration timeout!\n"); return -EBUSY; } dev_dbg(&pdev->dev, "MIPI calibration for CSI is done\n"); return 0; } struct tegra_camera_ops vi2_ops = { .clks_init = vi2_clks_init, .clks_deinit = vi2_clks_deinit, .clks_enable = vi2_clks_enable, .clks_disable = vi2_clks_disable, .capture_clean = vi2_capture_clean, .capture_setup = vi2_capture_setup, .capture_start = vi2_capture_start, .capture_stop = vi2_capture_stop, .activate = vi2_sw_reset, .init_syncpts = vi2_init_syncpts, .free_syncpts = vi2_free_syncpts, .incr_syncpts = vi2_incr_syncpts, .port_is_valid = vi2_port_is_valid, .mipi_calibration = vi2_mipi_calibration, }; int vi2_register(struct tegra_camera_dev *cam) { /* Init regulator */ cam->regulator_name = "avdd_dsi_csi"; /* Init VI2/CSI2 ops */ cam->ops = &vi2_ops; return 0; }