summaryrefslogtreecommitdiff
path: root/drivers/media/platform/soc_camera/tegra_camera/vi2.c
diff options
context:
space:
mode:
authorBryan Wu <pengw@nvidia.com>2013-10-08 15:39:41 -0700
committerBryan Wu <pengw@nvidia.com>2013-11-01 17:33:47 -0700
commitb08a2f71e74e0bef904f706d642f55465e4856d4 (patch)
tree64c1b9e6baaeaf98567ea7d6a78624d4671b5105 /drivers/media/platform/soc_camera/tegra_camera/vi2.c
parent469dfbc86b478fea6c7a129761828c79eb7ac3a7 (diff)
media: tegra v4l2 camera: refactor driver code
Reconstruct the driver for Tegra V4L2 camera driver: - remove old driver file tegra_v4l2_camera.c - create driver file vi.c for VI/CSI (T20/T30/T114/T148) - create driver file vi2.c for VI2/CSI2 (T124) Bug 1377330 Change-Id: If030cf98e700b9201caa60328be822bc10610e74 Signed-off-by: Bryan Wu <pengw@nvidia.com> Reviewed-on: http://git-master/r/289329 GVS: Gerrit_Virtual_Submit Reviewed-by: Allen Martin <amartin@nvidia.com>
Diffstat (limited to 'drivers/media/platform/soc_camera/tegra_camera/vi2.c')
-rw-r--r--drivers/media/platform/soc_camera/tegra_camera/vi2.c817
1 files changed, 817 insertions, 0 deletions
diff --git a/drivers/media/platform/soc_camera/tegra_camera/vi2.c b/drivers/media/platform/soc_camera/tegra_camera/vi2.c
new file mode 100644
index 000000000000..754a4bef9a71
--- /dev/null
+++ b/drivers/media/platform/soc_camera/tegra_camera/vi2.c
@@ -0,0 +1,817 @@
+/*
+ * Copyright (c) 2013, 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/platform_device.h>
+
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/tegra_v4l2_camera.h>
+
+#include <mach/clk.h>
+
+#include "nvhost_syncpt.h"
+#include "common.h"
+
+#define TEGRA_SYNCPT_CSI_WAIT_TIMEOUT 200
+
+#define TEGRA_VI_SYNCPT_CSI_A NVSYNCPT_VI_0_3
+#define TEGRA_VI_SYNCPT_CSI_B NVSYNCPT_VI_1_3
+
+#define TEGRA_VI_CFG_VI_INCR_SYNCPT 0x000
+#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
+
+static int vi2_port_is_valid(int port)
+{
+ return (((port) >= TEGRA_CAMERA_PORT_CSI_A) &&
+ ((port) <= TEGRA_CAMERA_PORT_CSI_E));
+}
+
+/* Clock settings for camera */
+static struct tegra_camera_clk vi2_clks0[] = {
+ {
+ .name = "vi",
+ .freq = 150000000,
+ .use_devname = 1,
+ },
+ {
+ .name = "vi_sensor",
+ .freq = 24000000,
+ },
+ {
+ .name = "csi",
+ .freq = 0,
+ .use_devname = 1,
+ },
+ {
+ .name = "isp",
+ .freq = 0,
+ },
+ {
+ .name = "csus",
+ .freq = 0,
+ .use_devname = 1,
+ },
+ {
+ .name = "sclk",
+ .freq = 80000000,
+ },
+ {
+ .name = "emc",
+ .freq = 375000000,
+ },
+ {
+ .name = "cilab",
+ .freq = 102000000,
+ .use_devname = 1,
+ },
+ /* Always put "p11_d" at the end */
+ {
+ .name = "pll_d",
+ .freq = 0,
+ },
+};
+
+static struct tegra_camera_clk vi2_clks1[] = {
+ {
+ .name = "vi",
+ .freq = 150000000,
+ .use_devname = 1,
+ },
+ {
+ .name = "vi_sensor",
+ .freq = 24000000,
+ },
+ {
+ .name = "csi",
+ .freq = 0,
+ .use_devname = 1,
+ },
+ {
+ .name = "isp",
+ .freq = 0,
+ },
+ {
+ .name = "sclk",
+ .freq = 80000000,
+ },
+ {
+ .name = "emc",
+ .freq = 375000000,
+ },
+ {
+ .name = "cilcd",
+ .freq = 0,
+ .use_devname = 1,
+ },
+ {
+ .name = "cile",
+ .freq = 0,
+ .use_devname = 1,
+ },
+ /* Always put "p11_d" at the end */
+ {
+ .name = "pll_d",
+ .freq = 0,
+ },
+};
+
+#define MAX_DEVID_LENGTH 16
+
+static int vi2_clks_init(struct tegra_camera_dev *cam)
+{
+ struct platform_device *pdev = cam->ndev;
+ char devname[MAX_DEVID_LENGTH];
+ struct tegra_camera_clk *clks;
+ int i;
+
+ snprintf(devname, MAX_DEVID_LENGTH,
+ (pdev->id <= 0) ? "tegra_%s" : "tegra_%s.%d",
+ pdev->name, pdev->id);
+
+ switch (pdev->id) {
+ case 0:
+ cam->num_clks = ARRAY_SIZE(vi2_clks0);
+ cam->clks = vi2_clks0;
+ break;
+ case 1:
+ cam->num_clks = ARRAY_SIZE(vi2_clks1);
+ cam->clks = vi2_clks1;
+ break;
+ default:
+ dev_err(&pdev->dev, "Wrong device ID %d\n", pdev->id);
+ return -ENODEV;
+ }
+
+ for (i = 0; i < cam->num_clks; i++) {
+ clks = &cam->clks[i];
+
+ if (clks->use_devname)
+ 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);
+ }
+
+ if (clks->freq > 0)
+ clk_set_rate(clks->clk, clks->freq);
+ }
+
+ 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 (cam->tpg_mode) {
+ clks = &cam->clks[i];
+ if (clks->clk) {
+ clk_prepare_enable(clks->clk);
+ 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_save_syncpts(struct tegra_camera_dev *cam)
+{
+ cam->syncpt_csi_a =
+ nvhost_syncpt_read_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_CSI_A);
+
+ cam->syncpt_csi_b =
+ nvhost_syncpt_read_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_CSI_B);
+}
+
+static void vi2_incr_syncpts(struct tegra_camera_dev *cam)
+{
+ nvhost_syncpt_cpu_incr_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_CSI_A);
+
+ nvhost_syncpt_cpu_incr_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_CSI_B);
+}
+
+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_CILA_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_PIXEL_PARSER_A_STATUS, 0xFFFFFFFF);
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_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;
+
+ 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_INPUT_STREAM_A_CONTROL,
+ 0x3f0000 | (pdata->lanes - 1));
+ if (pdata->lanes == 4)
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x22020101);
+ else
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x22020201);
+
+ /* VI_MWA_REQ_DONE */
+ TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT,
+ (0x4 << 8) | TEGRA_VI_SYNCPT_CSI_A);
+
+ 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);
+
+ /* output format A8B8G8R8, only support direct to mem */
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_IMAGE_DEF, (64 << 16) | 0x1);
+ /* input format is RGB888 */
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_CSI_IMAGE_DT, 36);
+ }
+
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_CSI_IMAGE_SIZE,
+ (icd->user_height << 16) | icd->user_width);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_CSI_IMAGE_SIZE_WC,
+ icd->user_width * 3);
+
+ 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;
+
+ 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, 0x280301f0);
+ 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_INPUT_STREAM_B_CONTROL,
+ 0x3f0000 | (pdata->lanes - 1));
+ if (pdata->lanes == 4)
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x21010202);
+ else if (pdata->lanes == 1 && pdata->port == TEGRA_CAMERA_PORT_CSI_E)
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x12020202);
+ else
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x22010202);
+
+ /* VI_MWB_REQ_DONE */
+ TC_VI_REG_WT(cam, TEGRA_VI_CFG_VI_INCR_SYNCPT,
+ (0x5 << 8) | TEGRA_VI_SYNCPT_CSI_B);
+
+ 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);
+
+ /* output format A8B8G8R8, only support direct to mem */
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_IMAGE_DEF, (64 << 16) | 0x1);
+ /* input format is RGB888 */
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_CSI_IMAGE_DT, 36);
+ }
+
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_CSI_IMAGE_SIZE,
+ (icd->user_height << 16) | icd->user_width);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_CSI_IMAGE_SIZE_WC,
+ icd->user_width * 3);
+
+ 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;
+
+ /*
+ * MIPI pad controls
+ * MIPI_CAL_MIPI_BIAS_PAD_CFG0_0 MIPI_BIAS_PAD_E_VCLAMP_REF 1
+ * MIPI_CAL_MIPI_BIAS_PAD_CFG2_0 PAD_PDVREG 0
+ */
+
+ /*
+ * 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);
+
+ /*
+ * 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);
+
+ /* Common programming set for any config */
+ TC_VI_REG_WT(cam, TEGRA_CSI_CLKEN_OVERRIDE, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x22020202);
+ 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);
+ 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);
+
+ /*
+ * TODO: these values should be different with different
+ * sensor connected.
+ * Hardcode THS settle value just for TPG testing
+ */
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILA_CONTROL0, 0x8);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILB_CONTROL0, 0x8);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILC_CONTROL0, 0xa);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILD_CONTROL0, 0xa);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILE_CONTROL0, 0xa);
+
+ /* 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)
+ return vi2_capture_setup_csi_1(cam, icd);
+ else
+ return -ENODEV;
+}
+
+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 = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+
+ 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_RGB32:
+ 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;
+ }
+ break;
+
+ default:
+ dev_err(&cam->ndev->dev, "Wrong host format %d\n",
+ icd->current_fmt->host_fmt->fourcc);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+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;
+
+ 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) {
+ cam->syncpt_csi_a++;
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
+ 0x0000f005);
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_0_SINGLE_SHOT, 0x1);
+ err = nvhost_syncpt_wait_timeout_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_CSI_A,
+ cam->syncpt_csi_a,
+ TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
+ NULL,
+ NULL);
+ } else if (port == TEGRA_CAMERA_PORT_CSI_B) {
+ cam->syncpt_csi_b++;
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
+ 0x0000f005);
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SINGLE_SHOT, 0x1);
+ err = nvhost_syncpt_wait_timeout_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_CSI_B,
+ cam->syncpt_csi_b,
+ TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
+ NULL,
+ NULL);
+ }
+
+ if (!err)
+ return 0;
+
+ err = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_A_STATUS);
+ if (err)
+ pr_err("TEGRA_CSI_CSI_CIL_A_STATUS 0x%08x\n", err);
+ err = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CILA_STATUS);
+ if (err)
+ pr_err("TEGRA_CSI_CSI_CILA_STATUS 0x%08x\n", err);
+ err = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_B_STATUS);
+ if (err)
+ pr_err("TEGRA_CSI_CSI_CIL_B_STATUS 0x%08x\n", err);
+ err = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_C_STATUS);
+ if (err)
+ pr_err("TEGRA_CSI_CSI_CIL_C_STATUS 0x%08x\n", err);
+ err = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_D_STATUS);
+ if (err)
+ pr_err("TEGRA_CSI_CSI_CIL_D_STATUS 0x%08x\n", err);
+ err = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_CIL_E_STATUS);
+ if (err)
+ pr_err("TEGRA_CSI_CSI_CIL_E_STATUS 0x%08x\n", err);
+
+ err = TC_VI_REG_RD(cam, TEGRA_CSI_CSI_PIXEL_PARSER_A_STATUS);
+ if (err)
+ pr_err("TEGRA_CSI_CSI_PIXEL_PARSER_A_STATUS 0x%08x\n", err);
+
+ err = TC_VI_REG_RD(cam, TEGRA_VI_CSI_0_ERROR_STATUS);
+ if (err)
+ pr_err("TEGRA_VI_CSI_0_ERROR_STATUS 0x%08x\n", err);
+
+ return err;
+}
+
+static int vi2_capture_stop(struct tegra_camera_dev *cam, int port)
+{
+ if (port == TEGRA_CAMERA_PORT_CSI_A)
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
+ 0x0000f002);
+ else if (port == TEGRA_CAMERA_PORT_CSI_B)
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
+ 0x0000f002);
+
+ return 0;
+}
+
+/* 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_VI_CSI_0_SW_RESET, 0x1F);
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_1_SW_RESET, 0x1F);
+
+ udelay(10);
+}
+
+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,
+
+ .save_syncpts = vi2_save_syncpts,
+ .incr_syncpts = vi2_incr_syncpts,
+
+ .port_is_valid = vi2_port_is_valid,
+};
+
+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;
+}