summaryrefslogtreecommitdiff
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
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>
-rw-r--r--drivers/media/platform/soc_camera/Kconfig14
-rw-r--r--drivers/media/platform/soc_camera/Makefile4
-rw-r--r--drivers/media/platform/soc_camera/tegra_camera/Kconfig6
-rw-r--r--drivers/media/platform/soc_camera/tegra_camera/Makefile7
-rw-r--r--drivers/media/platform/soc_camera/tegra_camera/common.c968
-rw-r--r--drivers/media/platform/soc_camera/tegra_camera/common.h121
-rw-r--r--drivers/media/platform/soc_camera/tegra_camera/vi.c1075
-rw-r--r--drivers/media/platform/soc_camera/tegra_camera/vi2.c817
-rw-r--r--drivers/media/platform/soc_camera/tegra_v4l2_camera.c1998
-rw-r--r--include/media/tegra_v4l2_camera.h3
-rw-r--r--include/uapi/linux/v4l2-mediabus.h4
11 files changed, 3002 insertions, 2015 deletions
diff --git a/drivers/media/platform/soc_camera/Kconfig b/drivers/media/platform/soc_camera/Kconfig
index 74eb64784a77..b51b274e9a7d 100644
--- a/drivers/media/platform/soc_camera/Kconfig
+++ b/drivers/media/platform/soc_camera/Kconfig
@@ -58,13 +58,6 @@ config VIDEO_SH_MOBILE_CEU
---help---
This is a v4l2 driver for the SuperH Mobile CEU Interface
-config VIDEO_TEGRA
- tristate "Tegra soc_camera host driver"
- depends on VIDEO_DEV && ARCH_TEGRA && SOC_CAMERA && HAS_DMA && HAVE_CLK
- select VIDEOBUF2_DMA_NVMAP
- ---help---
- This is a v4l2 driver for the Tegra camera interface
-
config VIDEO_OMAP1
tristate "OMAP1 Camera Interface driver"
depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA
@@ -92,9 +85,4 @@ config VIDEO_ATMEL_ISI
This module makes the ATMEL Image Sensor Interface available
as a v4l2 device.
-config VIDEO_TEGRA
- tristate "Tegra soc_camera host driver"
- depends on VIDEO_DEV && ARCH_TEGRA && SOC_CAMERA && HAS_DMA && HAVE_CLK
- select VIDEOBUF2_DMA_CONTIG
- ---help---
- This is a v4l2 driver for the Tegra camera interface
+source "drivers/media/platform/soc_camera/tegra_camera/Kconfig"
diff --git a/drivers/media/platform/soc_camera/Makefile b/drivers/media/platform/soc_camera/Makefile
index a660d2889088..4146e1a33597 100644
--- a/drivers/media/platform/soc_camera/Makefile
+++ b/drivers/media/platform/soc_camera/Makefile
@@ -6,12 +6,10 @@ obj-$(CONFIG_VIDEO_ATMEL_ISI) += atmel-isi.o
obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o
obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o
obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
-obj-$(CONFIG_VIDEO_TEGRA) += tegra_v4l2_camera.o
obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
-obj-$(CONFIG_VIDEO_TEGRA) += tegra_v4l2_camera.o
+obj-$(CONFIG_VIDEO_TEGRA) += tegra_camera/
ccflags-y += -I$(srctree)/drivers/media/i2c/soc_camera
-ccflags-y += -I$(srctree)/drivers/video/tegra/host
diff --git a/drivers/media/platform/soc_camera/tegra_camera/Kconfig b/drivers/media/platform/soc_camera/tegra_camera/Kconfig
new file mode 100644
index 000000000000..9ebe344f2043
--- /dev/null
+++ b/drivers/media/platform/soc_camera/tegra_camera/Kconfig
@@ -0,0 +1,6 @@
+config VIDEO_TEGRA
+ tristate "Tegra soc_camera host driver"
+ depends on VIDEO_DEV && ARCH_TEGRA && SOC_CAMERA && HAS_DMA && HAVE_CLK
+ select VIDEOBUF2_DMA_CONTIG
+ ---help---
+ This is a v4l2 driver for the Tegra camera interface
diff --git a/drivers/media/platform/soc_camera/tegra_camera/Makefile b/drivers/media/platform/soc_camera/tegra_camera/Makefile
new file mode 100644
index 000000000000..552f489f6ed3
--- /dev/null
+++ b/drivers/media/platform/soc_camera/tegra_camera/Makefile
@@ -0,0 +1,7 @@
+# Makefile for Tegra SoC camera driver
+
+tegra_camera-objs += common.o vi.o vi2.o
+
+obj-$(CONFIG_VIDEO_TEGRA) += tegra_camera.o
+
+ccflags-y += -I$(srctree)/drivers/video/tegra/host
diff --git a/drivers/media/platform/soc_camera/tegra_camera/common.c b/drivers/media/platform/soc_camera/tegra_camera/common.c
new file mode 100644
index 000000000000..2db4627c07a8
--- /dev/null
+++ b/drivers/media/platform/soc_camera/tegra_camera/common.c
@@ -0,0 +1,968 @@
+/*
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/nvhost.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_platform.h>
+
+#include <mach/powergate.h>
+#include <mach/pm_domains.h>
+
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/videobuf2-dma-contig.h>
+#include <media/tegra_v4l2_camera.h>
+
+#include "dev.h"
+#include "bus_client.h"
+#include "t114/t114.h"
+#include "t124/t124.h"
+
+#include "common.h"
+
+static int tpg_mode;
+module_param(tpg_mode, int, 0644);
+
+#define TEGRA_CAM_DRV_NAME "vi"
+#define TEGRA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
+
+#define TEGRA_SYNCPT_RETRY_COUNT 10
+
+static const struct soc_mbus_pixelfmt tegra_camera_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .name = "YUV422 (UYVY) packed",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .name = "YUV422 (VYUY) packed",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .name = "YUV422 (YUYV) packed",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .name = "YUV422 (YVYU) packed",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .name = "YUV420 (YU12) planar",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YVU420,
+ .name = "YVU420 (YV12) planar",
+ .bits_per_sample = 12,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .name = "Bayer 8 BGBG.. GRGR..",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SGBRG8,
+ .name = "Bayer 8 GBGB.. RGRG..",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_SBGGR10,
+ .name = "Bayer 10 BGBG.. GRGR..",
+ .bits_per_sample = 16,
+ .packing = SOC_MBUS_PACKING_EXTEND16,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .name = "RGBA 8-8-8-8",
+ .bits_per_sample = 32,
+ .packing = SOC_MBUS_PACKING_NONE,
+ .order = SOC_MBUS_ORDER_LE,
+ },
+};
+
+static void tegra_camera_activate(struct tegra_camera_dev *cam)
+{
+ struct tegra_camera_ops *cam_ops = cam->ops;
+
+ nvhost_module_busy_ext(cam->ndev);
+
+ /* Enable external power */
+ if (cam->reg)
+ regulator_enable(cam->reg);
+
+ if (cam_ops->activate)
+ cam_ops->activate(cam);
+
+ /* Unpowergate VE */
+ tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
+
+ if (cam_ops->clks_enable)
+ cam_ops->clks_enable(cam);
+
+ if (cam_ops->capture_clean)
+ cam_ops->capture_clean(cam);
+
+ if (cam_ops->save_syncpts)
+ cam_ops->save_syncpts(cam);
+}
+
+static void tegra_camera_deactivate(struct tegra_camera_dev *cam)
+{
+ struct tegra_camera_ops *cam_ops = cam->ops;
+
+ if (cam_ops->clks_disable)
+ cam_ops->clks_disable(cam);
+
+ if (cam_ops->deactivate)
+ cam_ops->deactivate(cam);
+
+ /* Powergate VE */
+ tegra_powergate_partition(TEGRA_POWERGATE_VENC);
+
+ /* Disable external power */
+ if (cam->reg)
+ regulator_disable(cam->reg);
+
+ nvhost_module_idle_ext(cam->ndev);
+}
+
+static int tegra_camera_capture_frame(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;
+ int retry = TEGRA_SYNCPT_RETRY_COUNT;
+ int err;
+
+ /* Setup capture registers */
+ cam->ops->capture_setup(cam);
+
+ while (retry) {
+ err = cam->ops->capture_start(cam, buf);
+ /* Capturing succeed, stop capturing */
+ cam->ops->capture_stop(cam, port);
+ if (err) {
+ retry--;
+
+ cam->ops->incr_syncpts(cam);
+ cam->ops->save_syncpts(cam);
+
+ continue;
+ }
+ break;
+ }
+
+ /* Reset hardware for too many errors */
+ if (!retry) {
+ tegra_camera_deactivate(cam);
+ mdelay(5);
+ tegra_camera_activate(cam);
+ if (cam->active)
+ cam->ops->capture_setup(cam);
+ }
+
+ spin_lock_irq(&cam->videobuf_queue_lock);
+
+ vb = cam->active;
+ do_gettimeofday(&vb->v4l2_buf.timestamp);
+ vb->v4l2_buf.field = cam->field;
+ if (port == TEGRA_CAMERA_PORT_CSI_A)
+ vb->v4l2_buf.sequence = cam->sequence_a++;
+ else if (port == TEGRA_CAMERA_PORT_CSI_B)
+ vb->v4l2_buf.sequence = cam->sequence_b++;
+
+ vb2_buffer_done(vb, err < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
+ list_del_init(&buf->queue);
+
+ cam->num_frames++;
+
+ spin_unlock_irq(&cam->videobuf_queue_lock);
+
+ return err;
+}
+
+static void tegra_camera_work(struct work_struct *work)
+{
+ struct tegra_camera_dev *cam =
+ container_of(work, struct tegra_camera_dev, work);
+ struct tegra_camera_buffer *buf;
+
+ while (1) {
+ mutex_lock(&cam->work_mutex);
+
+ spin_lock_irq(&cam->videobuf_queue_lock);
+ if (list_empty(&cam->capture)) {
+ cam->active = NULL;
+ spin_unlock_irq(&cam->videobuf_queue_lock);
+ mutex_unlock(&cam->work_mutex);
+ return;
+ }
+
+ buf = list_entry(cam->capture.next, struct tegra_camera_buffer,
+ queue);
+ cam->active = &buf->vb;
+ spin_unlock_irq(&cam->videobuf_queue_lock);
+
+ tegra_camera_capture_frame(cam);
+
+ mutex_unlock(&cam->work_mutex);
+ }
+}
+
+static int tegra_camera_init_buffer(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);
+ struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc;
+ struct tegra_camera_platform_data *pdata = ssdesc->drv_priv;
+
+ switch (icd->current_fmt->host_fmt->fourcc) {
+ 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:
+ buf->buffer_addr = vb2_dma_contig_plane_dma_addr(&buf->vb, 0);
+ buf->start_addr = buf->buffer_addr;
+
+ if (pdata->flip_v)
+ buf->start_addr += bytes_per_line *
+ (icd->user_height-1);
+
+ if (pdata->flip_h)
+ buf->start_addr += bytes_per_line - 1;
+
+ break;
+
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ buf->buffer_addr = vb2_dma_contig_plane_dma_addr(&buf->vb, 0);
+ buf->buffer_addr_u = buf->buffer_addr +
+ icd->user_width * icd->user_height;
+ buf->buffer_addr_v = buf->buffer_addr_u +
+ (icd->user_width * icd->user_height) / 4;
+
+ /* For YVU420, we swap the locations of the U and V planes. */
+ if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_YVU420) {
+ dma_addr_t temp = buf->buffer_addr_u;
+ buf->buffer_addr_u = buf->buffer_addr_v;
+ buf->buffer_addr_v = temp;
+ }
+
+ buf->start_addr = buf->buffer_addr;
+ buf->start_addr_u = buf->buffer_addr_u;
+ buf->start_addr_v = buf->buffer_addr_v;
+
+ if (pdata->flip_v) {
+ buf->start_addr += icd->user_width *
+ (icd->user_height - 1);
+
+ buf->start_addr_u += ((icd->user_width/2) *
+ ((icd->user_height/2) - 1));
+
+ buf->start_addr_v += ((icd->user_width/2) *
+ ((icd->user_height/2) - 1));
+ }
+
+ if (pdata->flip_h) {
+ buf->start_addr += icd->user_width - 1;
+
+ buf->start_addr_u += (icd->user_width/2) - 1;
+
+ buf->start_addr_v += (icd->user_width/2) - 1;
+ }
+
+ break;
+
+ default:
+ dev_err(icd->parent, "Wrong host format %d\n",
+ icd->current_fmt->host_fmt->fourcc);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/*
+ * Videobuf operations
+ */
+static int tegra_camera_videobuf_setup(struct vb2_queue *vq,
+ const struct v4l2_format *fmt,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ void *alloc_ctxs[])
+{
+ struct soc_camera_device *icd = container_of(vq,
+ struct soc_camera_device,
+ vb2_vidq);
+ struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc;
+ struct tegra_camera_platform_data *pdata = ssdesc->drv_priv;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct tegra_camera_dev *cam = ici->priv;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ if (bytes_per_line < 0)
+ return bytes_per_line;
+
+ *num_planes = 1;
+
+ if (pdata->port == TEGRA_CAMERA_PORT_CSI_A)
+ cam->sequence_a = 0;
+ else if (pdata->port == TEGRA_CAMERA_PORT_CSI_B)
+ cam->sequence_b = 0;
+ sizes[0] = bytes_per_line * icd->user_height;
+ alloc_ctxs[0] = cam->alloc_ctx;
+
+ if (!*num_buffers)
+ *num_buffers = 2;
+
+ return 0;
+}
+
+static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb)
+{
+ struct soc_camera_device *icd = container_of(vb->vb2_queue,
+ struct soc_camera_device,
+ vb2_vidq);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct tegra_camera_dev *cam = ici->priv;
+ struct tegra_camera_buffer *buf = to_tegra_vb(vb);
+ struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc;
+ struct tegra_camera_platform_data *pdata = ssdesc->drv_priv;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ unsigned long size;
+
+ if (bytes_per_line < 0)
+ return bytes_per_line;
+
+ buf->icd = icd;
+
+ if (!pdata) {
+ dev_err(icd->parent, "No platform data for this device!\n");
+ return -EINVAL;
+ }
+
+ if (!cam->ops->port_is_valid(pdata->port)) {
+ dev_err(icd->parent,
+ "Invalid camera port %d in platform data\n",
+ pdata->port);
+ return -EINVAL;
+ }
+
+#ifdef PREFILL_BUFFER
+ dev_info(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
+ vb, vb2_plane_vaddr(vb, 0), vb2_plane_size(vb, 0));
+
+ /*
+ * This can be useful if you want to see if we actually fill
+ * the buffer with something
+ */
+ if (vb2_plane_vaddr(vb, 0))
+ memset(vb2_plane_vaddr(vb, 0), 0xbd, vb2_plane_size(vb, 0));
+#endif
+
+ if (!icd->current_fmt) {
+ dev_err(icd->parent, "%s NULL format point\n", __func__);
+ return -EINVAL;
+ }
+
+ size = icd->user_height * bytes_per_line;
+
+ if (vb2_plane_size(vb, 0) < size) {
+ dev_err(icd->parent, "Buffer too small (%lu < %lu)\n",
+ vb2_plane_size(vb, 0), size);
+ return -ENOBUFS;
+ }
+
+ vb2_set_plane_payload(vb, 0, size);
+
+ return tegra_camera_init_buffer(buf);
+}
+
+static void tegra_camera_videobuf_queue(struct vb2_buffer *vb)
+{
+ struct soc_camera_device *icd = container_of(vb->vb2_queue,
+ struct soc_camera_device,
+ vb2_vidq);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct tegra_camera_dev *cam = ici->priv;
+ struct tegra_camera_buffer *buf = to_tegra_vb(vb);
+
+ spin_lock_irq(&cam->videobuf_queue_lock);
+ list_add_tail(&buf->queue, &cam->capture);
+ schedule_work(&cam->work);
+ spin_unlock_irq(&cam->videobuf_queue_lock);
+}
+
+static void tegra_camera_videobuf_release(struct vb2_buffer *vb)
+{
+ struct soc_camera_device *icd = container_of(vb->vb2_queue,
+ struct soc_camera_device,
+ vb2_vidq);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct tegra_camera_buffer *buf = to_tegra_vb(vb);
+ struct tegra_camera_dev *cam = ici->priv;
+
+ mutex_lock(&cam->work_mutex);
+
+ spin_lock_irq(&cam->videobuf_queue_lock);
+
+ if (cam->active == vb)
+ cam->active = NULL;
+
+ /*
+ * Doesn't hurt also if the list is empty, but it hurts, if queuing the
+ * buffer failed, and .buf_init() hasn't been called
+ */
+ if (buf->queue.next)
+ list_del_init(&buf->queue);
+
+ spin_unlock_irq(&cam->videobuf_queue_lock);
+
+ mutex_unlock(&cam->work_mutex);
+}
+
+static int tegra_camera_videobuf_init(struct vb2_buffer *vb)
+{
+ /* This is for locking debugging only */
+ INIT_LIST_HEAD(&to_tegra_vb(vb)->queue);
+
+ return 0;
+}
+
+static int tegra_camera_stop_streaming(struct vb2_queue *q)
+{
+ struct soc_camera_device *icd = container_of(q,
+ struct soc_camera_device,
+ vb2_vidq);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct tegra_camera_dev *cam = ici->priv;
+ struct list_head *buf_head, *tmp;
+
+
+ mutex_lock(&cam->work_mutex);
+
+ spin_lock_irq(&cam->videobuf_queue_lock);
+ list_for_each_safe(buf_head, tmp, &cam->capture) {
+ struct tegra_camera_buffer *buf = container_of(buf_head,
+ struct tegra_camera_buffer,
+ queue);
+ if (buf->icd == icd)
+ list_del_init(buf_head);
+ }
+ spin_unlock_irq(&cam->videobuf_queue_lock);
+
+ if (cam->active) {
+ struct tegra_camera_buffer *buf = to_tegra_vb(cam->active);
+ if (buf->icd == icd)
+ cam->active = NULL;
+ }
+
+ mutex_unlock(&cam->work_mutex);
+
+ return 0;
+}
+
+static struct vb2_ops tegra_camera_videobuf_ops = {
+ .queue_setup = tegra_camera_videobuf_setup,
+ .buf_prepare = tegra_camera_videobuf_prepare,
+ .buf_queue = tegra_camera_videobuf_queue,
+ .buf_cleanup = tegra_camera_videobuf_release,
+ .buf_init = tegra_camera_videobuf_init,
+ .wait_prepare = soc_camera_unlock,
+ .wait_finish = soc_camera_lock,
+ .stop_streaming = tegra_camera_stop_streaming,
+};
+
+/*
+ * SOC camera host operations
+ */
+static int tegra_camera_init_videobuf(struct vb2_queue *q,
+ struct soc_camera_device *icd)
+{
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR;
+ q->drv_priv = icd;
+ q->ops = &tegra_camera_videobuf_ops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct tegra_camera_buffer);
+ q->timestamp_type = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+
+ return vb2_queue_init(q);
+}
+
+/*
+ * Called with .video_lock held
+ */
+static int tegra_camera_add_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct tegra_camera_dev *cam = ici->priv;
+
+ if (!cam->enable_refcnt) {
+ pm_runtime_get_sync(ici->v4l2_dev.dev);
+ tegra_camera_activate(cam);
+ cam->num_frames = 0;
+ }
+ cam->enable_refcnt++;
+
+ return 0;
+}
+
+/* Called with .video_lock held */
+static void tegra_camera_remove_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct tegra_camera_dev *cam = ici->priv;
+
+ cam->enable_refcnt--;
+ if (!cam->enable_refcnt) {
+ cancel_work_sync(&cam->work);
+ tegra_camera_deactivate(cam);
+ pm_runtime_put_sync(ici->v4l2_dev.dev);
+ }
+}
+
+static int tegra_camera_set_bus_param(struct soc_camera_device *icd)
+{
+ return 0;
+}
+
+static int tegra_camera_get_formats(struct soc_camera_device *icd,
+ unsigned int idx,
+ struct soc_camera_format_xlate *xlate)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->parent;
+ int formats = 0;
+ int ret;
+ enum v4l2_mbus_pixelcode code;
+ int k;
+
+ ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+ if (ret != 0)
+ /* No more formats */
+ return 0;
+
+ switch (code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGBRG8_1X8:
+ case V4L2_MBUS_FMT_SBGGR10_1X10:
+ case V4L2_MBUS_FMT_RGBA8888_4X8_LE:
+ formats += ARRAY_SIZE(tegra_camera_formats);
+ for (k = 0;
+ xlate && (k < ARRAY_SIZE(tegra_camera_formats));
+ k++) {
+ xlate->host_fmt = &tegra_camera_formats[k];
+ xlate->code = code;
+ xlate++;
+
+ dev_dbg(dev, "Providing format %s using code %d\n",
+ tegra_camera_formats[k].name, code);
+ }
+ break;
+ default:
+ dev_err(dev, "Not supporting %d\n", code);
+ return 0;
+ }
+
+ return formats;
+}
+
+static void tegra_camera_put_formats(struct soc_camera_device *icd)
+{
+ kfree(icd->host_priv);
+ icd->host_priv = NULL;
+}
+
+static int tegra_camera_set_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct device *dev = icd->parent;
+ struct soc_camera_host *ici = to_soc_camera_host(dev);
+ struct tegra_camera_dev *cam = ici->priv;
+
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ const struct soc_camera_format_xlate *xlate = NULL;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate) {
+ dev_warn(dev, "Format %x not found\n", pix->pixelformat);
+ return -EINVAL;
+ }
+
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+ if (IS_ERR_VALUE(ret)) {
+ dev_warn(dev, "Failed to configure for format %x\n",
+ pix->pixelformat);
+ return ret;
+ }
+
+ if (mf.code != xlate->code) {
+ dev_warn(dev, "mf.code = %d, xlate->code = %d, mismatch\n",
+ mf.code, xlate->code);
+ return -EINVAL;
+ }
+
+ icd->user_width = mf.width;
+ icd->user_height = mf.height;
+ icd->current_fmt = xlate;
+
+ cam->field = pix->field;
+
+ return ret;
+}
+
+static int tegra_camera_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_mbus_framefmt mf;
+ __u32 pixfmt = pix->pixelformat;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (!xlate) {
+ dev_warn(icd->parent, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+ xlate->host_fmt);
+ if (pix->bytesperline < 0)
+ return pix->bytesperline;
+ pix->sizeimage = pix->height * pix->bytesperline;
+
+ /* limit to sensor capabilities */
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ if (IS_ERR_VALUE(ret))
+ return ret;
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ pix->colorspace = mf.colorspace;
+ /*
+ * width and height could have been changed, therefore update the
+ * bytesperline and sizeimage here.
+ */
+ pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+ xlate->host_fmt);
+ pix->sizeimage = pix->height * pix->bytesperline;
+
+ switch (mf.field) {
+ case V4L2_FIELD_ANY:
+ case V4L2_FIELD_NONE:
+ pix->field = V4L2_FIELD_NONE;
+ break;
+ default:
+ /* TODO: support interlaced at least in pass-through mode */
+ dev_err(icd->parent, "Field type %d unsupported.\n",
+ mf.field);
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int tegra_camera_reqbufs(struct soc_camera_device *icd,
+ struct v4l2_requestbuffers *p)
+{
+ return 0;
+}
+
+static unsigned int tegra_camera_poll(struct file *file, poll_table *pt)
+{
+ struct soc_camera_device *icd = file->private_data;
+
+ return vb2_poll(&icd->vb2_vidq, file, pt);
+}
+
+static int tegra_camera_querycap(struct soc_camera_host *ici,
+ struct v4l2_capability *cap)
+{
+ strlcpy(cap->card, TEGRA_CAM_DRV_NAME, sizeof(cap->card));
+ cap->version = TEGRA_CAM_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static struct soc_camera_host_ops tegra_soc_camera_host_ops = {
+ .owner = THIS_MODULE,
+ .init_videobuf2 = tegra_camera_init_videobuf,
+ .add = tegra_camera_add_device,
+ .remove = tegra_camera_remove_device,
+ .set_bus_param = tegra_camera_set_bus_param,
+ .get_formats = tegra_camera_get_formats,
+ .put_formats = tegra_camera_put_formats,
+ .set_fmt = tegra_camera_set_fmt,
+ .try_fmt = tegra_camera_try_fmt,
+ .reqbufs = tegra_camera_reqbufs,
+ .poll = tegra_camera_poll,
+ .querycap = tegra_camera_querycap,
+};
+
+static struct of_device_id tegra_vi_of_match[] = {
+#ifdef TEGRA_11X_OR_HIGHER_CONFIG
+ { .compatible = "nvidia,tegra114-vi",
+ .data = (struct nvhost_device_data *)&t11_vi_info },
+#endif
+#ifdef TEGRA_14X_OR_HIGHER_CONFIG
+ { .compatible = "nvidia,tegra148-vi",
+ .data = (struct nvhost_device_data *)&t14_vi_info },
+#endif
+#ifdef TEGRA_12X_OR_HIGHER_CONFIG
+ { .compatible = "nvidia,tegra124-vi",
+ .data = (struct nvhost_device_data *)&t124_vi_info },
+#endif
+ { },
+};
+
+static int tegra_camera_probe(struct platform_device *pdev)
+{
+ struct tegra_camera_dev *cam;
+ struct nvhost_device_data *ndata = NULL;
+ int err = 0;
+
+ if (pdev->dev.of_node) {
+ const struct of_device_id *match;
+
+ match = of_match_device(tegra_vi_of_match, &pdev->dev);
+ if (match)
+ ndata = (struct nvhost_device_data *) match->data;
+ } else
+ ndata = pdev->dev.platform_data;
+
+ if (!ndata) {
+ dev_err(&pdev->dev, "No nvhost device data!\n");
+ err = -EINVAL;
+ goto exit;
+ }
+
+ cam = kzalloc(sizeof(struct tegra_camera_dev), GFP_KERNEL);
+ if (!cam) {
+ dev_err(&pdev->dev, "couldn't allocate cam\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ cam->ndata = ndata;
+ cam->ndev = pdev;
+
+ cam->ici.priv = cam;
+ cam->ici.v4l2_dev.dev = &pdev->dev;
+ cam->ici.nr = pdev->id;
+ cam->ici.drv_name = dev_name(&pdev->dev);
+ cam->ici.ops = &tegra_soc_camera_host_ops;
+
+ cam->tpg_mode = tpg_mode;
+
+ INIT_LIST_HEAD(&cam->capture);
+ INIT_WORK(&cam->work, tegra_camera_work);
+ spin_lock_init(&cam->videobuf_queue_lock);
+ mutex_init(&cam->work_mutex);
+
+ if (pdev->dev.of_node) {
+ int cplen;
+ const char *compat;
+ compat = of_get_property(pdev->dev.of_node,
+ "compatible", &cplen);
+
+ if (!strcmp(compat, "nvidia,tegra124-vi"))
+ vi2_register(cam);
+ else
+ vi_register(cam);
+ } else {
+#ifdef TEGRA_12X_OR_HIGHER_CONFIG
+ /* Register VI/CSI or VI2/CSI2 structs */
+ vi2_register(cam);
+#else
+ vi_register(cam);
+#endif
+ }
+
+ /* Init Clocks */
+ cam->ops->clks_init(cam);
+
+ /* Init Regulator */
+ cam->reg = devm_regulator_get(&pdev->dev, cam->regulator_name);
+ if (IS_ERR_OR_NULL(cam->reg)) {
+ dev_err(&pdev->dev, "%s: couldn't get regulator %s, err %ld\n",
+ __func__, cam->regulator_name, PTR_ERR(cam->reg));
+ cam->reg = NULL;
+ goto exit_deinit_clk;
+ }
+
+ platform_set_drvdata(pdev, ndata);
+ err = nvhost_client_device_get_resources(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "%s: nvhost get resources failed %d\n",
+ __func__, err);
+ goto exit_deinit_clk;
+ }
+
+ err = nvhost_client_device_init(pdev);
+ if (err) {
+ dev_err(&pdev->dev, "%s: nvhost init failed %d\n",
+ __func__, err);
+ goto exit_deinit_clk;
+ }
+
+ cam->reg_base = ndata->aperture[0];
+
+ tegra_pd_add_device(&pdev->dev);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, ndata->clockgate_delay);
+ pm_runtime_enable(&pdev->dev);
+
+ cam->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
+ if (IS_ERR(cam->alloc_ctx)) {
+ err = PTR_ERR(cam->alloc_ctx);
+ goto exit_pm_disable;
+ }
+
+ platform_set_drvdata(pdev, cam);
+ err = soc_camera_host_register(&cam->ici);
+ if (IS_ERR_VALUE(err))
+ goto exit_cleanup_alloc_ctx;
+
+ dev_notice(&pdev->dev, "Tegra camera driver loaded.\n");
+
+ return err;
+
+exit_cleanup_alloc_ctx:
+ platform_set_drvdata(pdev, cam->ndata);
+ vb2_dma_contig_cleanup_ctx(cam->alloc_ctx);
+exit_pm_disable:
+ pm_runtime_disable(&pdev->dev);
+exit_deinit_clk:
+ cam->ops->clks_deinit(cam);
+ kfree(cam);
+exit:
+ return err;
+}
+
+static int tegra_camera_remove(struct platform_device *pdev)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(&pdev->dev);
+ struct tegra_camera_dev *cam = container_of(ici,
+ struct tegra_camera_dev, ici);
+
+ soc_camera_host_unregister(ici);
+
+ platform_set_drvdata(pdev, cam->ndata);
+ nvhost_client_device_release(pdev);
+
+ vb2_dma_contig_cleanup_ctx(cam->alloc_ctx);
+
+ pm_runtime_disable(&pdev->dev);
+
+ if (cam->ops)
+ cam->ops->clks_deinit(cam);
+
+ kfree(cam);
+
+ dev_notice(&pdev->dev, "Tegra camera host driver unloaded\n");
+
+ return 0;
+}
+
+static struct platform_driver tegra_camera_driver = {
+ .driver = {
+ .name = TEGRA_CAM_DRV_NAME,
+ .owner = THIS_MODULE,
+#ifdef CONFIG_OF
+ .of_match_table = tegra_vi_of_match,
+#endif
+ },
+ .probe = tegra_camera_probe,
+ .remove = tegra_camera_remove,
+};
+
+static int __init tegra_camera_init(void)
+{
+ return platform_driver_register(&tegra_camera_driver);
+}
+
+static void __exit tegra_camera_exit(void)
+{
+ platform_driver_unregister(&tegra_camera_driver);
+}
+
+module_init(tegra_camera_init);
+module_exit(tegra_camera_exit);
+
+MODULE_DESCRIPTION("TEGRA SoC Camera Host driver");
+MODULE_AUTHOR("Bryan Wu <pengw@nvidia.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("nvhost:" TEGRA_CAM_DRV_NAME);
diff --git a/drivers/media/platform/soc_camera/tegra_camera/common.h b/drivers/media/platform/soc_camera/tegra_camera/common.h
new file mode 100644
index 000000000000..94a3f46bbf92
--- /dev/null
+++ b/drivers/media/platform/soc_camera/tegra_camera/common.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2012-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/>.
+ */
+
+#ifndef _TEGRA_CAMERA_COMMON_H_
+#define _TEGRA_CAMERA_COMMON_H_
+
+#include <linux/videodev2.h>
+
+#include <media/videobuf2-dma-contig.h>
+#include <media/soc_camera.h>
+
+/* Buffer for one video frame */
+struct tegra_camera_buffer {
+ struct vb2_buffer vb; /* v4l buffer must be first */
+ struct list_head queue;
+ struct soc_camera_device *icd;
+ int output_channel;
+
+ /*
+ * Various buffer addresses shadowed so we don't have to recalculate
+ * per frame. These are calculated during videobuf_prepare.
+ */
+ dma_addr_t buffer_addr;
+ dma_addr_t buffer_addr_u;
+ dma_addr_t buffer_addr_v;
+ dma_addr_t start_addr;
+ dma_addr_t start_addr_u;
+ dma_addr_t start_addr_v;
+};
+
+static struct tegra_camera_buffer *to_tegra_vb(struct vb2_buffer *vb)
+{
+ return container_of(vb, struct tegra_camera_buffer, vb);
+}
+
+struct tegra_camera_dev;
+
+struct tegra_camera_clk {
+ const char *name;
+ struct clk *clk;
+ u32 freq;
+ int use_devname;
+};
+
+struct tegra_camera_ops {
+ int (*clks_init)(struct tegra_camera_dev *cam);
+ void (*clks_deinit)(struct tegra_camera_dev *cam);
+ void (*clks_enable)(struct tegra_camera_dev *cam);
+ void (*clks_disable)(struct tegra_camera_dev *cam);
+
+ void (*capture_clean)(struct tegra_camera_dev *vi2_cam);
+ int (*capture_setup)(struct tegra_camera_dev *vi2_cam);
+ int (*capture_start)(struct tegra_camera_dev *vi2_cam,
+ struct tegra_camera_buffer *buf);
+ int (*capture_stop)(struct tegra_camera_dev *vi2_cam, int port);
+
+ void (*incr_syncpts)(struct tegra_camera_dev *vi2_cam);
+ void (*save_syncpts)(struct tegra_camera_dev *vi2_cam);
+
+ void (*activate)(struct tegra_camera_dev *vi2_cam);
+ void (*deactivate)(struct tegra_camera_dev *vi2_cam);
+ int (*port_is_valid)(int port);
+};
+
+struct tegra_camera_dev {
+ struct soc_camera_host ici;
+ struct platform_device *ndev;
+ struct nvhost_device_data *ndata;
+
+ struct regulator *reg;
+ const char *regulator_name;
+
+ struct tegra_camera_clk *clks;
+ int num_clks;
+
+ struct tegra_camera_ops *ops;
+
+ void __iomem *reg_base;
+ spinlock_t videobuf_queue_lock;
+ struct list_head capture;
+ struct vb2_buffer *active;
+ struct vb2_alloc_ctx *alloc_ctx;
+ enum v4l2_field field;
+ int sequence_a;
+ int sequence_b;
+
+ struct work_struct work;
+ struct mutex work_mutex;
+
+ u32 syncpt_csi_a;
+ u32 syncpt_csi_b;
+ u32 syncpt_vip;
+
+ /* Debug */
+ int num_frames;
+ int enable_refcnt;
+
+ /* Test Pattern Generator mode */
+ int tpg_mode;
+};
+
+#define TC_VI_REG_RD(dev, offset) readl(dev->reg_base + offset)
+#define TC_VI_REG_WT(dev, offset, val) writel(val, dev->reg_base + offset)
+
+int vi2_register(struct tegra_camera_dev *cam);
+int vi_register(struct tegra_camera_dev *cam);
+
+#endif
diff --git a/drivers/media/platform/soc_camera/tegra_camera/vi.c b/drivers/media/platform/soc_camera/tegra_camera/vi.c
new file mode 100644
index 000000000000..9792d1869538
--- /dev/null
+++ b/drivers/media/platform/soc_camera/tegra_camera/vi.c
@@ -0,0 +1,1075 @@
+/*
+ * 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_VI_WAIT_TIMEOUT 200
+#define TEGRA_SYNCPT_CSI_WAIT_TIMEOUT 200
+
+#define TEGRA_VIP_H_ACTIVE_START 0x98
+#define TEGRA_VIP_V_ACTIVE_START 0x10
+
+/* SYNCPTs 12-17 are reserved for VI. */
+#define TEGRA_VI_SYNCPT_VI NVSYNCPT_VI_ISP_2
+#define TEGRA_VI_SYNCPT_CSI_A NVSYNCPT_VI_ISP_3
+#define TEGRA_VI_SYNCPT_CSI_B NVSYNCPT_VI_ISP_4
+
+/* Tegra CSI-MIPI registers. */
+#define TEGRA_VI_OUT_1_INCR_SYNCPT 0x000
+#define TEGRA_VI_OUT_1_INCR_SYNCPT_CNTRL 0x004
+#define TEGRA_VI_OUT_1_INCR_SYNCPT_ERROR 0x008
+#define TEGRA_VI_OUT_2_INCR_SYNCPT 0x020
+#define TEGRA_VI_OUT_2_INCR_SYNCPT_CNTRL 0x024
+#define TEGRA_VI_OUT_2_INCR_SYNCPT_ERROR 0x028
+#define TEGRA_VI_MISC_INCR_SYNCPT 0x040
+#define TEGRA_VI_MISC_INCR_SYNCPT_CNTRL 0x044
+#define TEGRA_VI_MISC_INCR_SYNCPT_ERROR 0x048
+#define TEGRA_VI_CONT_SYNCPT_OUT_1 0x060
+#define TEGRA_VI_CONT_SYNCPT_OUT_2 0x064
+#define TEGRA_VI_CONT_SYNCPT_VIP_VSYNC 0x068
+#define TEGRA_VI_CONT_SYNCPT_VI2EPP 0x06c
+#define TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_START 0x070
+#define TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_END 0x074
+#define TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_START 0x078
+#define TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_END 0x07c
+#define TEGRA_VI_CTXSW 0x080
+#define TEGRA_VI_INTSTATUS 0x084
+#define TEGRA_VI_VI_INPUT_CONTROL 0x088
+#define TEGRA_VI_VI_CORE_CONTROL 0x08c
+#define TEGRA_VI_VI_FIRST_OUTPUT_CONTROL 0x090
+#define TEGRA_VI_VI_SECOND_OUTPUT_CONTROL 0x094
+#define TEGRA_VI_HOST_INPUT_FRAME_SIZE 0x098
+#define TEGRA_VI_HOST_H_ACTIVE 0x09c
+#define TEGRA_VI_HOST_V_ACTIVE 0x0a0
+#define TEGRA_VI_VIP_H_ACTIVE 0x0a4
+#define TEGRA_VI_VIP_V_ACTIVE 0x0a8
+#define TEGRA_VI_VI_PEER_CONTROL 0x0ac
+#define TEGRA_VI_VI_DMA_SELECT 0x0b0
+#define TEGRA_VI_HOST_DMA_WRITE_BUFFER 0x0b4
+#define TEGRA_VI_HOST_DMA_BASE_ADDRESS 0x0b8
+#define TEGRA_VI_HOST_DMA_WRITE_BUFFER_STATUS 0x0bc
+#define TEGRA_VI_HOST_DMA_WRITE_PEND_BUFCOUNT 0x0c0
+#define TEGRA_VI_VB0_START_ADDRESS_FIRST 0x0c4
+#define TEGRA_VI_VB0_BASE_ADDRESS_FIRST 0x0c8
+#define TEGRA_VI_VB0_START_ADDRESS_U 0x0cc
+#define TEGRA_VI_VB0_BASE_ADDRESS_U 0x0d0
+#define TEGRA_VI_VB0_START_ADDRESS_V 0x0d4
+#define TEGRA_VI_VB0_BASE_ADDRESS_V 0x0d8
+#define TEGRA_VI_VB_SCRATCH_ADDRESS_UV 0x0dc
+#define TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE 0x0e0
+#define TEGRA_VI_VB0_COUNT_FIRST 0x0e4
+#define TEGRA_VI_VB0_SIZE_FIRST 0x0e8
+#define TEGRA_VI_VB0_BUFFER_STRIDE_FIRST 0x0ec
+#define TEGRA_VI_VB0_START_ADDRESS_SECOND 0x0f0
+#define TEGRA_VI_VB0_BASE_ADDRESS_SECOND 0x0f4
+#define TEGRA_VI_SECOND_OUTPUT_FRAME_SIZE 0x0f8
+#define TEGRA_VI_VB0_COUNT_SECOND 0x0fc
+#define TEGRA_VI_VB0_SIZE_SECOND 0x100
+#define TEGRA_VI_VB0_BUFFER_STRIDE_SECOND 0x104
+#define TEGRA_VI_H_LPF_CONTROL 0x108
+#define TEGRA_VI_H_DOWNSCALE_CONTROL 0x10c
+#define TEGRA_VI_V_DOWNSCALE_CONTROL 0x110
+#define TEGRA_VI_CSC_Y 0x114
+#define TEGRA_VI_CSC_UV_R 0x118
+#define TEGRA_VI_CSC_UV_G 0x11c
+#define TEGRA_VI_CSC_UV_B 0x120
+#define TEGRA_VI_CSC_ALPHA 0x124
+#define TEGRA_VI_HOST_VSYNC 0x128
+#define TEGRA_VI_COMMAND 0x12c
+#define TEGRA_VI_HOST_FIFO_STATUS 0x130
+#define TEGRA_VI_INTERRUPT_MASK 0x134
+#define TEGRA_VI_INTERRUPT_TYPE_SELECT 0x138
+#define TEGRA_VI_INTERRUPT_POLARITY_SELECT 0x13c
+#define TEGRA_VI_INTERRUPT_STATUS 0x140
+#define TEGRA_VI_VIP_INPUT_STATUS 0x144
+#define TEGRA_VI_VIDEO_BUFFER_STATUS 0x148
+#define TEGRA_VI_SYNC_OUTPUT 0x14c
+#define TEGRA_VI_VVS_OUTPUT_DELAY 0x150
+#define TEGRA_VI_PWM_CONTROL 0x154
+#define TEGRA_VI_PWM_SELECT_PULSE_A 0x158
+#define TEGRA_VI_PWM_SELECT_PULSE_B 0x15c
+#define TEGRA_VI_PWM_SELECT_PULSE_C 0x160
+#define TEGRA_VI_PWM_SELECT_PULSE_D 0x164
+#define TEGRA_VI_VI_DATA_INPUT_CONTROL 0x168
+#define TEGRA_VI_PIN_INPUT_ENABLE 0x16c
+#define TEGRA_VI_PIN_OUTPUT_ENABLE 0x170
+#define TEGRA_VI_PIN_INVERSION 0x174
+#define TEGRA_VI_PIN_INPUT_DATA 0x178
+#define TEGRA_VI_PIN_OUTPUT_DATA 0x17c
+#define TEGRA_VI_PIN_OUTPUT_SELECT 0x180
+#define TEGRA_VI_RAISE_VIP_BUFFER_FIRST_OUTPUT 0x184
+#define TEGRA_VI_RAISE_VIP_FRAME_FIRST_OUTPUT 0x188
+#define TEGRA_VI_RAISE_VIP_BUFFER_SECOND_OUTPUT 0x18c
+#define TEGRA_VI_RAISE_VIP_FRAME_SECOND_OUTPUT 0x190
+#define TEGRA_VI_RAISE_HOST_FIRST_OUTPUT 0x194
+#define TEGRA_VI_RAISE_HOST_SECOND_OUTPUT 0x198
+#define TEGRA_VI_RAISE_EPP 0x19c
+#define TEGRA_VI_CAMERA_CONTROL 0x1a0
+#define TEGRA_VI_VI_ENABLE 0x1a4
+#define TEGRA_VI_VI_ENABLE_2 0x1a8
+#define TEGRA_VI_VI_RAISE 0x1ac
+#define TEGRA_VI_Y_FIFO_WRITE 0x1b0
+#define TEGRA_VI_U_FIFO_WRITE 0x1b4
+#define TEGRA_VI_V_FIFO_WRITE 0x1b8
+#define TEGRA_VI_VI_MCCIF_FIFOCTRL 0x1bc
+#define TEGRA_VI_TIMEOUT_WCOAL_VI 0x1c0
+#define TEGRA_VI_MCCIF_VIRUV_HP 0x1c4
+#define TEGRA_VI_MCCIF_VIWSB_HP 0x1c8
+#define TEGRA_VI_MCCIF_VIWU_HP 0x1cc
+#define TEGRA_VI_MCCIF_VIWV_HP 0x1d0
+#define TEGRA_VI_MCCIF_VIWY_HP 0x1d4
+#define TEGRA_VI_CSI_PPA_RAISE_FRAME_START 0x1d8
+#define TEGRA_VI_CSI_PPA_RAISE_FRAME_END 0x1dc
+#define TEGRA_VI_CSI_PPB_RAISE_FRAME_START 0x1e0
+#define TEGRA_VI_CSI_PBB_RAISE_FRAME_END 0x1e4
+#define TEGRA_VI_CSI_PPA_H_ACTIVE 0x1e8
+#define TEGRA_VI_CSI_PPA_V_ACTIVE 0x1ec
+#define TEGRA_VI_CSI_PPB_H_ACTIVE 0x1f0
+#define TEGRA_VI_CSI_PPB_V_ACTIVE 0x1f4
+#define TEGRA_VI_ISP_H_ACTIVE 0x1f8
+#define TEGRA_VI_ISP_V_ACTIVE 0x1fc
+#define TEGRA_VI_STREAM_1_RESOURCE_DEFINE 0x200
+#define TEGRA_VI_STREAM_2_RESOURCE_DEFINE 0x204
+#define TEGRA_VI_RAISE_STREAM_1_DONE 0x208
+#define TEGRA_VI_RAISE_STREAM_2_DONE 0x20c
+#define TEGRA_VI_TS_MODE 0x210
+#define TEGRA_VI_TS_CONTROL 0x214
+#define TEGRA_VI_TS_PACKET_COUNT 0x218
+#define TEGRA_VI_TS_ERROR_COUNT 0x21c
+#define TEGRA_VI_TS_CPU_FLOW_CTL 0x220
+#define TEGRA_VI_VB0_CHROMA_BUFFER_STRIDE_FIRST 0x224
+#define TEGRA_VI_VB0_CHROMA_LINE_STRIDE_FIRST 0x228
+#define TEGRA_VI_EPP_LINES_PER_BUFFER 0x22c
+#define TEGRA_VI_BUFFER_RELEASE_OUTPUT1 0x230
+#define TEGRA_VI_BUFFER_RELEASE_OUTPUT2 0x234
+#define TEGRA_VI_DEBUG_FLOW_CONTROL_COUNTER_OUTPUT1 0x238
+#define TEGRA_VI_DEBUG_FLOW_CONTROL_COUNTER_OUTPUT2 0x23c
+#define TEGRA_VI_TERMINATE_BW_FIRST 0x240
+#define TEGRA_VI_TERMINATE_BW_SECOND 0x244
+#define TEGRA_VI_VB0_FIRST_BUFFER_ADDR_MODE 0x248
+#define TEGRA_VI_VB0_SECOND_BUFFER_ADDR_MODE 0x24c
+#define TEGRA_VI_RESERVE 0x250
+#define TEGRA_VI_RESERVE_1 0x254
+#define TEGRA_VI_RESERVE_2 0x258
+#define TEGRA_VI_RESERVE_3 0x25c
+#define TEGRA_VI_RESERVE_4 0x260
+#define TEGRA_VI_MCCIF_VIRUV_HYST 0x264
+#define TEGRA_VI_MCCIF_VIWSB_HYST 0x268
+#define TEGRA_VI_MCCIF_VIWU_HYST 0x26c
+#define TEGRA_VI_MCCIF_VIWV_HYST 0x270
+#define TEGRA_VI_MCCIF_VIWY_HYST 0x274
+
+#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL 0x800
+#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL 0x808
+#define TEGRA_CSI_INPUT_STREAM_A_CONTROL 0x810
+#define TEGRA_CSI_PIXEL_STREAM_A_CONTROL0 0x818
+#define TEGRA_CSI_PIXEL_STREAM_A_CONTROL1 0x81c
+#define TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT 0x820
+#define TEGRA_CSI_PIXEL_STREAM_A_GAP 0x824
+#define TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND 0x828
+#define TEGRA_CSI_INPUT_STREAM_B_CONTROL 0x83c
+#define TEGRA_CSI_PIXEL_STREAM_B_CONTROL0 0x844
+#define TEGRA_CSI_PIXEL_STREAM_B_CONTROL1 0x848
+#define TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT 0x84c
+#define TEGRA_CSI_PIXEL_STREAM_B_GAP 0x850
+#define TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND 0x854
+#define TEGRA_CSI_PHY_CIL_COMMAND 0x868
+#define TEGRA_CSI_PHY_CILA_CONTROL0 0x86c
+#define TEGRA_CSI_PHY_CILB_CONTROL0 0x870
+#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x878
+#define TEGRA_CSI_CSI_CIL_STATUS 0x87c
+#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK 0x880
+#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK 0x884
+#define TEGRA_CSI_CSI_READONLY_STATUS 0x888
+#define TEGRA_CSI_ESCAPE_MODE_COMMAND 0x88c
+#define TEGRA_CSI_ESCAPE_MODE_DATA 0x890
+#define TEGRA_CSI_CILA_PAD_CONFIG0 0x894
+#define TEGRA_CSI_CILA_PAD_CONFIG1 0x898
+#define TEGRA_CSI_CILB_PAD_CONFIG0 0x89c
+#define TEGRA_CSI_CILB_PAD_CONFIG1 0x8a0
+#define TEGRA_CSI_CIL_PAD_CONFIG 0x8a4
+#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG 0x8a8
+#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG 0x8ac
+#define TEGRA_CSI_CIL_MIPI_CAL_STATUS 0x8b0
+#define TEGRA_CSI_CLKEN_OVERRIDE 0x8b4
+#define TEGRA_CSI_DEBUG_CONTROL 0x8b8
+#define TEGRA_CSI_DEBUG_COUNTER 0x8bc
+#define TEGRA_CSI_DEBUG_COUNTER_1 0x8c0
+#define TEGRA_CSI_DEBUG_COUNTER_2 0x8c4
+#define TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME 0x8c8
+#define TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME 0x8cc
+#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x8d0
+
+/* Test Pattern Generator of CSI */
+#define TEGRA_CSI_PATTERN_GENERATOR_CTRL_A 0x940
+#define TEGRA_CSI_PG_BLANK_A 0x944
+#define TEGRA_CSI_PG_PHASE_A 0x948
+#define TEGRA_CSI_PG_RED_FREQ_A 0x94c
+#define TEGRA_CSI_PG_RED_FREQ_RATE_A 0x950
+#define TEGRA_CSI_PG_GREEN_FREQ_A 0x954
+#define TEGRA_CSI_PG_GREEN_FREQ_RATE_A 0x958
+#define TEGRA_CSI_PG_BLUE_FREQ_A 0x95c
+#define TEGRA_CSI_PG_BLUE_FREQ_RATE_A 0x960
+#define TEGRA_CSI_PATTERN_GENERATOR_CTRL_B 0x974
+#define TEGRA_CSI_PG_BLANK_B 0x978
+#define TEGRA_CSI_PG_PHASE_B 0x97c
+#define TEGRA_CSI_PG_RED_FREQ_B 0x980
+#define TEGRA_CSI_PG_RED_FREQ_RATE_B 0x984
+#define TEGRA_CSI_PG_GREEN_FREQ_B 0x988
+#define TEGRA_CSI_PG_GREEN_FREQ_RATE_B 0x98c
+#define TEGRA_CSI_PG_BLUE_FREQ_B 0x990
+#define TEGRA_CSI_PG_BLUE_FREQ_RATE_B 0x994
+
+static int vi_port_is_valid(int port)
+{
+ return (((port) >= TEGRA_CAMERA_PORT_CSI_A) &&
+ ((port) <= TEGRA_CAMERA_PORT_VIP));
+}
+
+static int vi_port_is_csi(int port)
+{
+ return (((port) == TEGRA_CAMERA_PORT_CSI_A) ||
+ ((port) == TEGRA_CAMERA_PORT_CSI_B));
+}
+
+/* Clock settings for camera */
+static struct tegra_camera_clk vi_clks[] = {
+ {
+ .name = "vi",
+ .freq = 150000000,
+ },
+ {
+ .name = "vi_sensor",
+ .freq = 24000000,
+ },
+ {
+ .name = "csi",
+ .freq = 0,
+ },
+ {
+ .name = "isp",
+ .freq = 0,
+ },
+ {
+ .name = "csus",
+ .freq = 0,
+ },
+ {
+ .name = "sclk",
+ .freq = 80000000,
+ },
+ {
+ .name = "emc",
+ .freq = 375000000,
+ },
+#ifdef TEGRA_11X_OR_HIGHER_CONFIG
+ {
+ .name = "cilab",
+ .freq = 102000000,
+ },
+ {
+ .name = "cilcd",
+ .freq = 0,
+ },
+ {
+ .name = "cile",
+ .freq = 0,
+ },
+ /* Always put "p11_d2" at the end */
+ {
+ .name = "pll_d2",
+ .freq = 0,
+ },
+#endif
+};
+
+static int vi_clks_init(struct tegra_camera_dev *cam)
+{
+ struct platform_device *pdev = cam->ndev;
+ struct tegra_camera_clk *clks;
+ int i;
+
+ cam->num_clks = ARRAY_SIZE(vi_clks);
+ cam->clks = vi_clks;
+
+ for (i = 0; i < cam->num_clks; i++) {
+ clks = &cam->clks[i];
+ clks->clk = devm_clk_get(&pdev->dev, clks->name);
+ if (IS_ERR_OR_NULL(clks->clk)) {
+ clks->clk = NULL;
+ 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 vi_clks_deinit(struct tegra_camera_dev *cam)
+{
+ /* We don't need cleanup for devm_clk_get() */
+ return;
+}
+
+static void vi_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);
+ }
+
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+#define TEGRA_APB_MISC_BASE 0x70000000
+ {
+ u32 val;
+ void __iomem *apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+
+ val = readl(apb_misc + 0x42c);
+ writel(val | 0x1, apb_misc + 0x42c);
+ }
+#endif
+
+ if (cam->tpg_mode) {
+ clks = &cam->clks[i];
+ if (clks->clk) {
+ clk_prepare_enable(clks->clk);
+#ifdef TEGRA_11X_OR_HIGHER_CONFIG
+ 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);
+#else
+ /*
+ * bit 25: 0 = pd2vi_Clk,
+ * 1 = vi_sensor_clk
+ * bit 24: 0 = internal clock,
+ * 1 = external clock (pd2vi_clk)
+ */
+ tegra_clk_cfg_ex(clks->clk, TEGRA_CLK_VI_INP_SEL, 2);
+#endif
+ }
+ }
+}
+
+static void vi_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) {
+#ifdef TEGRA_11X_OR_HIGHER_CONFIG
+ 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);
+#endif
+ clk_disable_unprepare(clks->clk);
+ }
+ }
+}
+
+static void vi_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);
+
+ cam->syncpt_vip =
+ nvhost_syncpt_read_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_VI);
+}
+
+static void vi_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);
+
+ nvhost_syncpt_cpu_incr_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_VI);
+}
+
+static void vi_capture_clean(struct tegra_camera_dev *cam)
+{
+ TC_VI_REG_WT(cam, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_STATUS, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CSI_READONLY_STATUS, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_ESCAPE_MODE_DATA, 0x0);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_DEBUG_CONTROL, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_DEBUG_COUNTER, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_DEBUG_COUNTER_1, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_DEBUG_COUNTER_2, 0x0);
+}
+
+static void vi_capture_setup_csi_a(struct tegra_camera_dev *cam,
+ struct soc_camera_device *icd,
+ u32 hdr)
+{
+ struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc;
+ struct tegra_camera_platform_data *pdata = ssdesc->drv_priv;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_INPUT_STREAM_A_CONTROL, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILA_CONTROL0, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CILA_PAD_CONFIG0, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CILA_PAD_CONFIG1, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME, 0x0);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_CORE_CONTROL, 0x02000000);
+
+ /* CSI-A H_ACTIVE and V_ACTIVE */
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_PPA_H_ACTIVE,
+ (icd->user_width << 16));
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_PPA_V_ACTIVE,
+ (icd->user_height << 16));
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1,
+ 0x1); /* Frame # for top field detect for interlaced */
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT,
+ bytes_per_line);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x00140000);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME,
+ ((icd->user_height + cam->tpg_mode) << 16));
+
+ /* pad 0s enabled, virtual channel ID 00 */
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0,
+ (0x1 << 16) | /* Output 1 pixel per clock */
+ (hdr << 8) | /* If hdr shows wrong fmt, use right value */
+ (0x1 << 7) | /* Check header CRC */
+ (0x1 << 6) | /* Use word count field in the header */
+ (0x1 << 5) | /* Look at data identifier byte in hdr */
+ (0x1 << 4)); /* Expect packet header */
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_INPUT_STREAM_A_CONTROL,
+ (0x3f << 16) | /* Skip packet threshold */
+ (pdata->lanes - 1));
+
+ /* Use 0x00000022 for continuous clock mode. */
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILA_CONTROL0,
+ (pdata->continuous_clk << 5) |
+ 0x5); /* Clock settle time */
+
+ TC_VI_REG_WT(cam, TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_END,
+ (0x1 << 8) | /* Enable continuous syncpt */
+ TEGRA_VI_SYNCPT_CSI_A);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x00020001);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x0000f002);
+
+ 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, 0x00800080);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PG_RED_FREQ_RATE_A, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PG_GREEN_FREQ_A, 0x00800080);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PG_GREEN_FREQ_RATE_A, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PG_BLUE_FREQ_A, 0x00800080);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PG_BLUE_FREQ_RATE_A, 0x0);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PG_BLANK_A, 0x0000FFFF);
+ }
+
+}
+
+static void vi_capture_setup_csi_b(struct tegra_camera_dev *cam,
+ struct soc_camera_device *icd,
+ u32 hdr)
+{
+ struct soc_camera_subdev_desc *ssdesc = &icd->sdesc->subdev_desc;
+ struct tegra_camera_platform_data *pdata = ssdesc->drv_priv;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_INPUT_STREAM_B_CONTROL, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILB_CONTROL0, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CILB_PAD_CONFIG0, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CILB_PAD_CONFIG1, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME, 0x0);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_CORE_CONTROL, 0x04000000);
+
+ /* CSI-B H_ACTIVE and V_ACTIVE */
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_PPB_H_ACTIVE,
+ (icd->user_width << 16));
+ TC_VI_REG_WT(cam, TEGRA_VI_CSI_PPB_V_ACTIVE,
+ (icd->user_height << 16));
+
+ /* pad 0s enabled, virtual channel ID 00 */
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0,
+ (0x1 << 16) | /* Output 1 pixel per clock */
+ (hdr << 8) | /* If hdr shows wrong fmt, use right value */
+ (0x1 << 7) | /* Check header CRC */
+ (0x1 << 6) | /* Use word count field in the header */
+ (0x1 << 5) | /* Look at data identifier byte in hdr */
+ (0x1 << 4) | /* Expect packet header */
+ 0x1); /* Set PPB stream source to CSI B */
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1,
+ 0x1); /* Frame # for top field detect for interlaced */
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT,
+ bytes_per_line);
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x00140000);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME,
+ (icd->user_height << 16) |
+ (0x100 << 4) | /* Wait 0x100 vi clks for timeout */
+ 0x1); /* Enable line timeout */
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_INPUT_STREAM_B_CONTROL,
+ (0x3f << 16) | /* Skip packet threshold */
+ (pdata->lanes - 1));
+
+ /* Use 0x00000022 for continuous clock mode. */
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CILB_CONTROL0,
+ (pdata->continuous_clk << 5) |
+ 0x5); /* Clock settle time */
+
+ TC_VI_REG_WT(cam, TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_END,
+ (0x1 << 8) | /* Enable continuous syncpt */
+ TEGRA_VI_SYNCPT_CSI_B);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_PHY_CIL_COMMAND, 0x00010002);
+
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x0000f002);
+}
+
+static void vi_capture_setup_vip(struct tegra_camera_dev *cam,
+ struct soc_camera_device *icd,
+ u32 input_control)
+{
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_CORE_CONTROL, 0x00000000);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_INPUT_CONTROL,
+ (1 << 27) | /* field detect */
+ (1 << 25) | /* hsync/vsync decoded from data (BT.656) */
+ (1 << 1) | /* VIP_INPUT_ENABLE */
+ input_control);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000000);
+ TC_VI_REG_WT(cam, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000000);
+
+ /* VIP H_ACTIVE and V_ACTIVE */
+ TC_VI_REG_WT(cam, TEGRA_VI_VIP_H_ACTIVE,
+ (icd->user_width << 16) |
+ TEGRA_VIP_H_ACTIVE_START);
+ TC_VI_REG_WT(cam, TEGRA_VI_VIP_V_ACTIVE,
+ (icd->user_height << 16) |
+ TEGRA_VIP_V_ACTIVE_START);
+
+ /*
+ * For VIP, D9..D2 is mapped to the video decoder's P7..P0.
+ * Disable/mask out the other Dn wires.
+ */
+ TC_VI_REG_WT(cam, TEGRA_VI_PIN_INPUT_ENABLE, 0x000003fc);
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_DATA_INPUT_CONTROL, 0x000003fc);
+ TC_VI_REG_WT(cam, TEGRA_VI_PIN_INVERSION, 0x00000000);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_CONT_SYNCPT_VIP_VSYNC,
+ (0x1 << 8) | /* Enable continuous syncpt */
+ TEGRA_VI_SYNCPT_VI);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_CAMERA_CONTROL, 0x00000004);
+}
+
+static int vi_capture_output_channel_setup(
+ 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 port = pdata->port;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ const struct soc_camera_format_xlate *current_fmt = icd->current_fmt;
+ u32 output_fourcc = current_fmt->host_fmt->fourcc;
+ u32 output_format, output_control;
+ struct tegra_camera_buffer *buf = to_tegra_vb(cam->active);
+
+ switch (output_fourcc) {
+ case V4L2_PIX_FMT_UYVY:
+ output_format = 0x3; /* Default to YUV422 */
+ break;
+ case V4L2_PIX_FMT_VYUY:
+ output_format = (0x1 << 17) | 0x3;
+ break;
+ case V4L2_PIX_FMT_YUYV:
+ output_format = (0x2 << 17) | 0x3;
+ break;
+ case V4L2_PIX_FMT_YVYU:
+ output_format = (0x3 << 17) | 0x3;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ output_format = 0x6; /* YUV420 planar */
+ break;
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SGBRG8:
+ case V4L2_PIX_FMT_SBGGR10:
+ /* Use second output channel for RAW8/RAW10 */
+ buf->output_channel = 1;
+
+ if (port == TEGRA_CAMERA_PORT_CSI_A)
+ output_format = 0x7;
+ else if (port == TEGRA_CAMERA_PORT_CSI_B)
+ output_format = 0x8;
+ else
+ output_format = 0x9;
+ break;
+ default:
+ dev_err(&cam->ndev->dev, "Wrong output format %d\n",
+ output_fourcc);
+ return -EINVAL;
+ }
+
+ output_control = (pdata->flip_v ? (0x1 << 20) : 0) |
+ (pdata->flip_h ? (0x1 << 19) : 0) |
+ output_format;
+
+ if (buf->output_channel == 0) {
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL,
+ output_control);
+ /*
+ * Set up frame size. Bits 31:16 are the number of lines, and
+ * bits 15:0 are the number of pixels per line.
+ */
+ TC_VI_REG_WT(cam, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE,
+ (icd->user_height << 16) | icd->user_width);
+
+ /* First output memory enabled */
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_ENABLE, 0x00000000);
+
+ /* Set the number of frames in the buffer. */
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_COUNT_FIRST, 0x00000001);
+
+ /* Set up buffer frame size. */
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_SIZE_FIRST,
+ (icd->user_height << 16) | icd->user_width);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
+ (icd->user_height * bytes_per_line));
+
+ TC_VI_REG_WT(cam, TEGRA_VI_CONT_SYNCPT_OUT_1,
+ (0x1 << 8) | /* Enable continuous syncpt */
+ TEGRA_VI_SYNCPT_VI);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_ENABLE, 0x00000000);
+ } else if (buf->output_channel == 1) {
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_SECOND_OUTPUT_CONTROL,
+ output_control);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_SECOND_OUTPUT_FRAME_SIZE,
+ (icd->user_height << 16) | icd->user_width);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_ENABLE_2, 0x00000000);
+
+ /* Set the number of frames in the buffer. */
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_COUNT_SECOND, 0x00000001);
+
+ /* Set up buffer frame size. */
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_SIZE_SECOND,
+ (icd->user_height << 16) | icd->user_width);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_BUFFER_STRIDE_SECOND,
+ (icd->user_height * bytes_per_line));
+
+ TC_VI_REG_WT(cam, TEGRA_VI_CONT_SYNCPT_OUT_2,
+ (0x1 << 8) | /* Enable continuous syncpt */
+ TEGRA_VI_SYNCPT_VI);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_ENABLE_2, 0x00000000);
+ } else {
+ dev_err(&cam->ndev->dev, "Wrong output channel %d\n",
+ buf->output_channel);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+static int vi_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;
+ const struct soc_camera_format_xlate *current_fmt = icd->current_fmt;
+ enum v4l2_mbus_pixelcode input_code = current_fmt->code;
+ u32 hdr, input_control = 0x0;
+
+ switch (input_code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ input_control |= 0x2 << 8;
+ hdr = 30;
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ input_control |= 0x3 << 8;
+ hdr = 30;
+ break;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ input_control |= 0x0;
+ hdr = 30;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ input_control |= 0x1 << 8;
+ hdr = 30;
+ break;
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGBRG8_1X8:
+ input_control |= 0x2 << 2; /* Input Format = Bayer */
+ hdr = 42;
+ break;
+ case V4L2_MBUS_FMT_SBGGR10_1X10:
+ input_control |= 0x2 << 2; /* Input Format = Bayer */
+ hdr = 43;
+ break;
+ default:
+ dev_err(&cam->ndev->dev, "Input format %d is not supported\n",
+ input_code);
+ return -EINVAL;
+ }
+
+ /*
+ * Set up low pass filter. Use 0x240 for chromaticity and 0x240
+ * for luminance, which is the default and means not to touch
+ * anything.
+ */
+ TC_VI_REG_WT(cam, TEGRA_VI_H_LPF_CONTROL, 0x02400240);
+
+ /* Set up raise-on-edge, so we get an interrupt on end of frame. */
+ TC_VI_REG_WT(cam, TEGRA_VI_VI_RAISE, 0x00000001);
+
+ /* Setup registers for CSI-A, CSI-B and VIP inputs */
+ if (port == TEGRA_CAMERA_PORT_CSI_A)
+ vi_capture_setup_csi_a(cam, icd, hdr);
+ else if (port == TEGRA_CAMERA_PORT_CSI_B)
+ vi_capture_setup_csi_b(cam, icd, hdr);
+ else
+ vi_capture_setup_vip(cam, icd, input_control);
+
+ /* Setup registers for output channels */
+ return vi_capture_output_channel_setup(cam, icd);
+}
+
+static int vi_capture_buffer_setup(struct tegra_camera_dev *cam,
+ struct tegra_camera_buffer *buf)
+{
+ struct soc_camera_device *icd = buf->icd;
+
+ switch (icd->current_fmt->host_fmt->fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_BASE_ADDRESS_U,
+ buf->buffer_addr_u);
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_START_ADDRESS_U,
+ buf->start_addr_u);
+
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_BASE_ADDRESS_V,
+ buf->buffer_addr_v);
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_START_ADDRESS_V,
+ buf->start_addr_v);
+
+ 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:
+ /* output 1 */
+ if (buf->output_channel == 0) {
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_BASE_ADDRESS_FIRST,
+ buf->buffer_addr);
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_START_ADDRESS_FIRST,
+ buf->start_addr);
+ /* output 2 */
+ } else if (buf->output_channel == 1) {
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_BASE_ADDRESS_SECOND,
+ buf->buffer_addr);
+ TC_VI_REG_WT(cam, TEGRA_VI_VB0_START_ADDRESS_SECOND,
+ buf->start_addr);
+ } else {
+ dev_err(&cam->ndev->dev, "Wrong output channel %d\n",
+ buf->output_channel);
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ dev_err(&cam->ndev->dev, "Wrong host format %d\n",
+ icd->current_fmt->host_fmt->fourcc);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vi_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 = vi_capture_buffer_setup(cam, buf);
+ if (err < 0)
+ return err;
+ /*
+ * Only wait on CSI frame end syncpt if we're using CSI. Otherwise,
+ * wait on VIP VSYNC syncpt.
+ */
+ if (port == TEGRA_CAMERA_PORT_CSI_A) {
+ cam->syncpt_csi_a++;
+ TC_VI_REG_WT(cam, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
+ 0x0000f005);
+ 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);
+ err = nvhost_syncpt_wait_timeout_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_CSI_B,
+ cam->syncpt_csi_b,
+ TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
+ NULL,
+ NULL);
+ } else {
+ cam->syncpt_vip++;
+ TC_VI_REG_WT(cam, TEGRA_VI_CAMERA_CONTROL,
+ 0x00000001);
+ err = nvhost_syncpt_wait_timeout_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_VI,
+ cam->syncpt_csi_a,
+ TEGRA_SYNCPT_VI_WAIT_TIMEOUT,
+ NULL,
+ NULL);
+ }
+
+ if (!err)
+ return 0;
+
+ if (vi_port_is_csi(port)) {
+ u32 ppstatus;
+ u32 cilstatus;
+ u32 rostatus;
+
+ dev_warn(&icd->vdev->dev, "Timeout on CSI syncpt\n");
+ dev_warn(&icd->vdev->dev, "buffer_addr = 0x%08x\n",
+ buf->buffer_addr);
+
+ ppstatus = TC_VI_REG_RD(cam,
+ TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
+ cilstatus = TC_VI_REG_RD(cam,
+ TEGRA_CSI_CSI_CIL_STATUS);
+ rostatus = TC_VI_REG_RD(cam,
+ TEGRA_CSI_CSI_READONLY_STATUS);
+
+ dev_warn(&icd->vdev->dev,
+ "PPSTATUS = 0x%08x, "
+ "CILSTATUS = 0x%08x, "
+ "ROSTATUS = 0x%08x\n",
+ ppstatus, cilstatus, rostatus);
+ } else {
+ u32 vip_input_status;
+
+ dev_warn(&cam->ndev->dev, "Timeout on VI syncpt\n");
+ dev_warn(&cam->ndev->dev, "buffer_addr = 0x%08x\n",
+ buf->buffer_addr);
+
+ vip_input_status = TC_VI_REG_RD(cam,
+ TEGRA_VI_VIP_INPUT_STATUS);
+
+ dev_warn(&cam->ndev->dev,
+ "VIP_INPUT_STATUS = 0x%08x\n",
+ vip_input_status);
+ }
+
+ return err;
+}
+
+static int vi_capture_stop(struct tegra_camera_dev *cam, int port)
+{
+ struct tegra_camera_buffer *buf = to_tegra_vb(cam->active);
+ int err;
+
+ if (vi_port_is_csi(port))
+ err = nvhost_syncpt_wait_timeout_ext(cam->ndev,
+ TEGRA_VI_SYNCPT_VI,
+ cam->syncpt_vip,
+ TEGRA_SYNCPT_VI_WAIT_TIMEOUT,
+ NULL,
+ NULL);
+ else
+ err = 0;
+
+ if (err) {
+ u32 buffer_addr;
+ u32 ppstatus;
+ u32 cilstatus;
+
+ dev_warn(&cam->ndev->dev, "Timeout on VI syncpt\n");
+
+ if (buf->output_channel == 0)
+ buffer_addr = TC_VI_REG_RD(cam,
+ TEGRA_VI_VB0_BASE_ADDRESS_FIRST);
+ else if (buf->output_channel == 1)
+ buffer_addr = TC_VI_REG_RD(cam,
+ TEGRA_VI_VB0_BASE_ADDRESS_SECOND);
+ else {
+ dev_err(&cam->ndev->dev, "Wrong output channel %d\n",
+ buf->output_channel);
+ return -EINVAL;
+ }
+
+ dev_warn(&cam->ndev->dev, "buffer_addr = 0x%08x\n",
+ buffer_addr);
+
+ ppstatus = TC_VI_REG_RD(cam,
+ TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
+ cilstatus = TC_VI_REG_RD(cam,
+ TEGRA_CSI_CSI_CIL_STATUS);
+ dev_warn(&cam->ndev->dev,
+ "PPSTATUS = 0x%08x, CILSTATUS = 0x%08x\n",
+ ppstatus, cilstatus);
+ }
+
+ return err;
+}
+
+static void vi_unpowergate(struct tegra_camera_dev *cam)
+{
+ /*
+ * Powergating DIS must powergate VE partition. Camera
+ * module needs to increase the ref-count of disa to
+ * avoid itself powergated by DIS inadvertently.
+ */
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
+ tegra_unpowergate_partition(TEGRA_POWERGATE_DISA);
+#endif
+}
+
+static void vi_powergate(struct tegra_camera_dev *cam)
+{
+#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
+ tegra_powergate_partition(TEGRA_POWERGATE_DISA);
+#endif
+}
+
+struct tegra_camera_ops vi_ops = {
+ .clks_init = vi_clks_init,
+ .clks_deinit = vi_clks_deinit,
+ .clks_enable = vi_clks_enable,
+ .clks_disable = vi_clks_disable,
+
+ .capture_clean = vi_capture_clean,
+ .capture_setup = vi_capture_setup,
+ .capture_start = vi_capture_start,
+ .capture_stop = vi_capture_stop,
+
+ .activate = vi_unpowergate,
+ .deactivate = vi_powergate,
+
+ .save_syncpts = vi_save_syncpts,
+ .incr_syncpts = vi_incr_syncpts,
+
+ .port_is_valid = vi_port_is_valid,
+};
+
+int vi_register(struct tegra_camera_dev *cam)
+{
+ /* Init regulator */
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ cam->regulator_name = "vcsi";
+#else
+ cam->regulator_name = "avdd_dsi_csi";
+#endif
+
+ /* Init VI/CSI ops */
+ cam->ops = &vi_ops;
+
+ return 0;
+}
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;
+}
diff --git a/drivers/media/platform/soc_camera/tegra_v4l2_camera.c b/drivers/media/platform/soc_camera/tegra_v4l2_camera.c
deleted file mode 100644
index a551af56d889..000000000000
--- a/drivers/media/platform/soc_camera/tegra_v4l2_camera.c
+++ /dev/null
@@ -1,1998 +0,0 @@
-/*
- * Copyright (c) 2012-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/kernel.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/pm_runtime.h>
-#include <linux/nvhost.h>
-#include <linux/of.h>
-#include <linux/of_device.h>
-#include <linux/of_platform.h>
-#include <linux/tegra-powergate.h>
-
-#include <mach/pm_domains.h>
-
-#include <media/soc_camera.h>
-#include <media/soc_mediabus.h>
-#include <media/videobuf2-dma-contig.h>
-#include <media/tegra_v4l2_camera.h>
-
-#include "dev.h"
-#include "bus_client.h"
-#include "nvhost_syncpt.h"
-#include "t20/t20.h"
-#include "t30/t30.h"
-#include "t114/t114.h"
-
-#define TEGRA_CAM_DRV_NAME "vi"
-#define TEGRA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
-
-#define TEGRA_SYNCPT_VI_WAIT_TIMEOUT 200
-#define TEGRA_SYNCPT_CSI_WAIT_TIMEOUT 200
-
-#define TEGRA_SYNCPT_RETRY_COUNT 10
-
-#define TEGRA_VIP_H_ACTIVE_START 0x98
-#define TEGRA_VIP_V_ACTIVE_START 0x10
-
-/* SYNCPTs 12-17 are reserved for VI. */
-#define TEGRA_VI_SYNCPT_VI NVSYNCPT_VI_ISP_2
-#define TEGRA_VI_SYNCPT_CSI_A NVSYNCPT_VI_ISP_3
-#define TEGRA_VI_SYNCPT_CSI_B NVSYNCPT_VI_ISP_4
-
-/* Tegra CSI-MIPI registers. */
-#define TEGRA_VI_OUT_1_INCR_SYNCPT 0x0000
-#define TEGRA_VI_OUT_1_INCR_SYNCPT_CNTRL 0x0004
-#define TEGRA_VI_OUT_1_INCR_SYNCPT_ERROR 0x0008
-#define TEGRA_VI_OUT_2_INCR_SYNCPT 0x0020
-#define TEGRA_VI_OUT_2_INCR_SYNCPT_CNTRL 0x0024
-#define TEGRA_VI_OUT_2_INCR_SYNCPT_ERROR 0x0028
-#define TEGRA_VI_MISC_INCR_SYNCPT 0x0040
-#define TEGRA_VI_MISC_INCR_SYNCPT_CNTRL 0x0044
-#define TEGRA_VI_MISC_INCR_SYNCPT_ERROR 0x0048
-#define TEGRA_VI_CONT_SYNCPT_OUT_1 0x0060
-#define TEGRA_VI_CONT_SYNCPT_OUT_2 0x0064
-#define TEGRA_VI_CONT_SYNCPT_VIP_VSYNC 0x0068
-#define TEGRA_VI_CONT_SYNCPT_VI2EPP 0x006c
-#define TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_START 0x0070
-#define TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_END 0x0074
-#define TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_START 0x0078
-#define TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_END 0x007c
-#define TEGRA_VI_CTXSW 0x0080
-#define TEGRA_VI_INTSTATUS 0x0084
-#define TEGRA_VI_VI_INPUT_CONTROL 0x0088
-#define TEGRA_VI_VI_CORE_CONTROL 0x008c
-#define TEGRA_VI_VI_FIRST_OUTPUT_CONTROL 0x0090
-#define TEGRA_VI_VI_SECOND_OUTPUT_CONTROL 0x0094
-#define TEGRA_VI_HOST_INPUT_FRAME_SIZE 0x0098
-#define TEGRA_VI_HOST_H_ACTIVE 0x009c
-#define TEGRA_VI_HOST_V_ACTIVE 0x00a0
-#define TEGRA_VI_VIP_H_ACTIVE 0x00a4
-#define TEGRA_VI_VIP_V_ACTIVE 0x00a8
-#define TEGRA_VI_VI_PEER_CONTROL 0x00ac
-#define TEGRA_VI_VI_DMA_SELECT 0x00b0
-#define TEGRA_VI_HOST_DMA_WRITE_BUFFER 0x00b4
-#define TEGRA_VI_HOST_DMA_BASE_ADDRESS 0x00b8
-#define TEGRA_VI_HOST_DMA_WRITE_BUFFER_STATUS 0x00bc
-#define TEGRA_VI_HOST_DMA_WRITE_PEND_BUFCOUNT 0x00c0
-#define TEGRA_VI_VB0_START_ADDRESS_FIRST 0x00c4
-#define TEGRA_VI_VB0_BASE_ADDRESS_FIRST 0x00c8
-#define TEGRA_VI_VB0_START_ADDRESS_U 0x00cc
-#define TEGRA_VI_VB0_BASE_ADDRESS_U 0x00d0
-#define TEGRA_VI_VB0_START_ADDRESS_V 0x00d4
-#define TEGRA_VI_VB0_BASE_ADDRESS_V 0x00d8
-#define TEGRA_VI_VB_SCRATCH_ADDRESS_UV 0x00dc
-#define TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE 0x00e0
-#define TEGRA_VI_VB0_COUNT_FIRST 0x00e4
-#define TEGRA_VI_VB0_SIZE_FIRST 0x00e8
-#define TEGRA_VI_VB0_BUFFER_STRIDE_FIRST 0x00ec
-#define TEGRA_VI_VB0_START_ADDRESS_SECOND 0x00f0
-#define TEGRA_VI_VB0_BASE_ADDRESS_SECOND 0x00f4
-#define TEGRA_VI_SECOND_OUTPUT_FRAME_SIZE 0x00f8
-#define TEGRA_VI_VB0_COUNT_SECOND 0x00fc
-#define TEGRA_VI_VB0_SIZE_SECOND 0x0100
-#define TEGRA_VI_VB0_BUFFER_STRIDE_SECOND 0x0104
-#define TEGRA_VI_H_LPF_CONTROL 0x0108
-#define TEGRA_VI_H_DOWNSCALE_CONTROL 0x010c
-#define TEGRA_VI_V_DOWNSCALE_CONTROL 0x0110
-#define TEGRA_VI_CSC_Y 0x0114
-#define TEGRA_VI_CSC_UV_R 0x0118
-#define TEGRA_VI_CSC_UV_G 0x011c
-#define TEGRA_VI_CSC_UV_B 0x0120
-#define TEGRA_VI_CSC_ALPHA 0x0124
-#define TEGRA_VI_HOST_VSYNC 0x0128
-#define TEGRA_VI_COMMAND 0x012c
-#define TEGRA_VI_HOST_FIFO_STATUS 0x0130
-#define TEGRA_VI_INTERRUPT_MASK 0x0134
-#define TEGRA_VI_INTERRUPT_TYPE_SELECT 0x0138
-#define TEGRA_VI_INTERRUPT_POLARITY_SELECT 0x013c
-#define TEGRA_VI_INTERRUPT_STATUS 0x0140
-#define TEGRA_VI_VIP_INPUT_STATUS 0x0144
-#define TEGRA_VI_VIDEO_BUFFER_STATUS 0x0148
-#define TEGRA_VI_SYNC_OUTPUT 0x014c
-#define TEGRA_VI_VVS_OUTPUT_DELAY 0x0150
-#define TEGRA_VI_PWM_CONTROL 0x0154
-#define TEGRA_VI_PWM_SELECT_PULSE_A 0x0158
-#define TEGRA_VI_PWM_SELECT_PULSE_B 0x015c
-#define TEGRA_VI_PWM_SELECT_PULSE_C 0x0160
-#define TEGRA_VI_PWM_SELECT_PULSE_D 0x0164
-#define TEGRA_VI_VI_DATA_INPUT_CONTROL 0x0168
-#define TEGRA_VI_PIN_INPUT_ENABLE 0x016c
-#define TEGRA_VI_PIN_OUTPUT_ENABLE 0x0170
-#define TEGRA_VI_PIN_INVERSION 0x0174
-#define TEGRA_VI_PIN_INPUT_DATA 0x0178
-#define TEGRA_VI_PIN_OUTPUT_DATA 0x017c
-#define TEGRA_VI_PIN_OUTPUT_SELECT 0x0180
-#define TEGRA_VI_RAISE_VIP_BUFFER_FIRST_OUTPUT 0x0184
-#define TEGRA_VI_RAISE_VIP_FRAME_FIRST_OUTPUT 0x0188
-#define TEGRA_VI_RAISE_VIP_BUFFER_SECOND_OUTPUT 0x018c
-#define TEGRA_VI_RAISE_VIP_FRAME_SECOND_OUTPUT 0x0190
-#define TEGRA_VI_RAISE_HOST_FIRST_OUTPUT 0x0194
-#define TEGRA_VI_RAISE_HOST_SECOND_OUTPUT 0x0198
-#define TEGRA_VI_RAISE_EPP 0x019c
-#define TEGRA_VI_CAMERA_CONTROL 0x01a0
-#define TEGRA_VI_VI_ENABLE 0x01a4
-#define TEGRA_VI_VI_ENABLE_2 0x01a8
-#define TEGRA_VI_VI_RAISE 0x01ac
-#define TEGRA_VI_Y_FIFO_WRITE 0x01b0
-#define TEGRA_VI_U_FIFO_WRITE 0x01b4
-#define TEGRA_VI_V_FIFO_WRITE 0x01b8
-#define TEGRA_VI_VI_MCCIF_FIFOCTRL 0x01bc
-#define TEGRA_VI_TIMEOUT_WCOAL_VI 0x01c0
-#define TEGRA_VI_MCCIF_VIRUV_HP 0x01c4
-#define TEGRA_VI_MCCIF_VIWSB_HP 0x01c8
-#define TEGRA_VI_MCCIF_VIWU_HP 0x01cc
-#define TEGRA_VI_MCCIF_VIWV_HP 0x01d0
-#define TEGRA_VI_MCCIF_VIWY_HP 0x01d4
-#define TEGRA_VI_CSI_PPA_RAISE_FRAME_START 0x01d8
-#define TEGRA_VI_CSI_PPA_RAISE_FRAME_END 0x01dc
-#define TEGRA_VI_CSI_PPB_RAISE_FRAME_START 0x01e0
-#define TEGRA_VI_CSI_PBB_RAISE_FRAME_END 0x01e4
-#define TEGRA_VI_CSI_PPA_H_ACTIVE 0x01e8
-#define TEGRA_VI_CSI_PPA_V_ACTIVE 0x01ec
-#define TEGRA_VI_CSI_PPB_H_ACTIVE 0x01f0
-#define TEGRA_VI_CSI_PPB_V_ACTIVE 0x01f4
-#define TEGRA_VI_ISP_H_ACTIVE 0x01f8
-#define TEGRA_VI_ISP_V_ACTIVE 0x01fc
-#define TEGRA_VI_STREAM_1_RESOURCE_DEFINE 0x0200
-#define TEGRA_VI_STREAM_2_RESOURCE_DEFINE 0x0204
-#define TEGRA_VI_RAISE_STREAM_1_DONE 0x0208
-#define TEGRA_VI_RAISE_STREAM_2_DONE 0x020c
-#define TEGRA_VI_TS_MODE 0x0210
-#define TEGRA_VI_TS_CONTROL 0x0214
-#define TEGRA_VI_TS_PACKET_COUNT 0x0218
-#define TEGRA_VI_TS_ERROR_COUNT 0x021c
-#define TEGRA_VI_TS_CPU_FLOW_CTL 0x0220
-#define TEGRA_VI_VB0_CHROMA_BUFFER_STRIDE_FIRST 0x0224
-#define TEGRA_VI_VB0_CHROMA_LINE_STRIDE_FIRST 0x0228
-#define TEGRA_VI_EPP_LINES_PER_BUFFER 0x022c
-#define TEGRA_VI_BUFFER_RELEASE_OUTPUT1 0x0230
-#define TEGRA_VI_BUFFER_RELEASE_OUTPUT2 0x0234
-#define TEGRA_VI_DEBUG_FLOW_CONTROL_COUNTER_OUTPUT1 0x0238
-#define TEGRA_VI_DEBUG_FLOW_CONTROL_COUNTER_OUTPUT2 0x023c
-#define TEGRA_VI_TERMINATE_BW_FIRST 0x0240
-#define TEGRA_VI_TERMINATE_BW_SECOND 0x0244
-#define TEGRA_VI_VB0_FIRST_BUFFER_ADDR_MODE 0x0248
-#define TEGRA_VI_VB0_SECOND_BUFFER_ADDR_MODE 0x024c
-#define TEGRA_VI_RESERVE_0 0x0250
-#define TEGRA_VI_RESERVE_1 0x0254
-#define TEGRA_VI_RESERVE_2 0x0258
-#define TEGRA_VI_RESERVE_3 0x025c
-#define TEGRA_VI_RESERVE_4 0x0260
-#define TEGRA_VI_MCCIF_VIRUV_HYST 0x0264
-#define TEGRA_VI_MCCIF_VIWSB_HYST 0x0268
-#define TEGRA_VI_MCCIF_VIWU_HYST 0x026c
-#define TEGRA_VI_MCCIF_VIWV_HYST 0x0270
-#define TEGRA_VI_MCCIF_VIWY_HYST 0x0274
-
-#define TEGRA_CSI_VI_INPUT_STREAM_CONTROL 0x0800
-#define TEGRA_CSI_HOST_INPUT_STREAM_CONTROL 0x0808
-#define TEGRA_CSI_INPUT_STREAM_A_CONTROL 0x0810
-#define TEGRA_CSI_PIXEL_STREAM_A_CONTROL0 0x0818
-#define TEGRA_CSI_PIXEL_STREAM_A_CONTROL1 0x081c
-#define TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT 0x0820
-#define TEGRA_CSI_PIXEL_STREAM_A_GAP 0x0824
-#define TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND 0x0828
-#define TEGRA_CSI_INPUT_STREAM_B_CONTROL 0x083c
-#define TEGRA_CSI_PIXEL_STREAM_B_CONTROL0 0x0844
-#define TEGRA_CSI_PIXEL_STREAM_B_CONTROL1 0x0848
-#define TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT 0x084c
-#define TEGRA_CSI_PIXEL_STREAM_B_GAP 0x0850
-#define TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND 0x0854
-#define TEGRA_CSI_PHY_CIL_COMMAND 0x0868
-#define TEGRA_CSI_PHY_CILA_CONTROL0 0x086c
-#define TEGRA_CSI_PHY_CILB_CONTROL0 0x0870
-#define TEGRA_CSI_CSI_PIXEL_PARSER_STATUS 0x0878
-#define TEGRA_CSI_CSI_CIL_STATUS 0x087c
-#define TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK 0x0880
-#define TEGRA_CSI_CSI_CIL_INTERRUPT_MASK 0x0884
-#define TEGRA_CSI_CSI_READONLY_STATUS 0x0888
-#define TEGRA_CSI_ESCAPE_MODE_COMMAND 0x088c
-#define TEGRA_CSI_ESCAPE_MODE_DATA 0x0890
-#define TEGRA_CSI_CILA_PAD_CONFIG0 0x0894
-#define TEGRA_CSI_CILA_PAD_CONFIG1 0x0898
-#define TEGRA_CSI_CILB_PAD_CONFIG0 0x089c
-#define TEGRA_CSI_CILB_PAD_CONFIG1 0x08a0
-#define TEGRA_CSI_CIL_PAD_CONFIG 0x08a4
-#define TEGRA_CSI_CILA_MIPI_CAL_CONFIG 0x08a8
-#define TEGRA_CSI_CILB_MIPI_CAL_CONFIG 0x08ac
-#define TEGRA_CSI_CIL_MIPI_CAL_STATUS 0x08b0
-#define TEGRA_CSI_CLKEN_OVERRIDE 0x08b4
-#define TEGRA_CSI_DEBUG_CONTROL 0x08b8
-#define TEGRA_CSI_DEBUG_COUNTER_0 0x08bc
-#define TEGRA_CSI_DEBUG_COUNTER_1 0x08c0
-#define TEGRA_CSI_DEBUG_COUNTER_2 0x08c4
-#define TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME 0x08c8
-#define TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME 0x08cc
-#define TEGRA_CSI_DSI_MIPI_CAL_CONFIG 0x08d0
-
-#define TC_VI_REG_RD(DEV, REG) readl(DEV->vi_base + REG)
-#define TC_VI_REG_WT(DEV, REG, VAL) writel(VAL, DEV->vi_base + REG)
-
-#define tegra_camera_port_is_valid(port) \
- (((port) >= TEGRA_CAMERA_PORT_CSI_A) && \
- ((port) <= TEGRA_CAMERA_PORT_VIP))
-
-#define tegra_camera_port_is_csi(port) \
- (((port) == TEGRA_CAMERA_PORT_CSI_A) || \
- ((port) == TEGRA_CAMERA_PORT_CSI_B))
-
-/*
- * Structures
- */
-
-/* buffer for one video frame */
-struct tegra_buffer {
- struct vb2_buffer vb; /* v4l buffer must be first */
- struct list_head queue;
- struct soc_camera_device *icd;
- int output_channel;
-
- /*
- * Various buffer addresses shadowed so we don't have to recalculate
- * per frame. These are calculated during videobuf_prepare.
- */
- dma_addr_t buffer_addr;
- dma_addr_t buffer_addr_u;
- dma_addr_t buffer_addr_v;
- dma_addr_t start_addr;
- dma_addr_t start_addr_u;
- dma_addr_t start_addr_v;
-};
-
-struct tegra_camera_dev {
- struct soc_camera_host ici;
- struct platform_device *ndev;
- struct nvhost_device_data *ndata;
-
- struct clk *clk_vi;
- struct clk *clk_vi_sensor;
- struct clk *clk_csi;
- struct clk *clk_isp;
- struct clk *clk_csus;
- struct clk *clk_sclk;
- struct clk *clk_emc;
-
- struct regulator *reg;
-
- void __iomem *vi_base;
- spinlock_t videobuf_queue_lock;
- struct list_head capture;
- struct vb2_buffer *active;
- struct vb2_alloc_ctx *alloc_ctx;
- enum v4l2_field field;
- int sequence_a;
- int sequence_b;
-
- struct work_struct work;
- struct mutex work_mutex;
-
- u32 syncpt_vi;
- u32 syncpt_csi_a;
- u32 syncpt_csi_b;
-
- /* Debug */
- int num_frames;
- int enable_refcnt;
-};
-
-static const struct soc_mbus_pixelfmt tegra_camera_formats[] = {
- {
- .fourcc = V4L2_PIX_FMT_UYVY,
- .name = "YUV422 (UYVY) packed",
- .bits_per_sample = 16,
- .packing = SOC_MBUS_PACKING_NONE,
- .order = SOC_MBUS_ORDER_LE,
- },
- {
- .fourcc = V4L2_PIX_FMT_VYUY,
- .name = "YUV422 (VYUY) packed",
- .bits_per_sample = 16,
- .packing = SOC_MBUS_PACKING_NONE,
- .order = SOC_MBUS_ORDER_LE,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUYV,
- .name = "YUV422 (YUYV) packed",
- .bits_per_sample = 16,
- .packing = SOC_MBUS_PACKING_NONE,
- .order = SOC_MBUS_ORDER_LE,
- },
- {
- .fourcc = V4L2_PIX_FMT_YVYU,
- .name = "YUV422 (YVYU) packed",
- .bits_per_sample = 16,
- .packing = SOC_MBUS_PACKING_NONE,
- .order = SOC_MBUS_ORDER_LE,
- },
- {
- .fourcc = V4L2_PIX_FMT_YUV420,
- .name = "YUV420 (YU12) planar",
- .bits_per_sample = 12,
- .packing = SOC_MBUS_PACKING_NONE,
- .order = SOC_MBUS_ORDER_LE,
- },
- {
- .fourcc = V4L2_PIX_FMT_YVU420,
- .name = "YVU420 (YV12) planar",
- .bits_per_sample = 12,
- .packing = SOC_MBUS_PACKING_NONE,
- .order = SOC_MBUS_ORDER_LE,
- },
-
- /* For RAW8 and RAW10 output, we always output 16-bit (2 bytes). */
- {
- .fourcc = V4L2_PIX_FMT_SBGGR8,
- .name = "Bayer 8 BGBG.. GRGR..",
- .bits_per_sample = 16,
- .packing = SOC_MBUS_PACKING_EXTEND16,
- .order = SOC_MBUS_ORDER_LE,
- },
- {
- .fourcc = V4L2_PIX_FMT_SBGGR10,
- .name = "Bayer 10 BGBG.. GRGR..",
- .bits_per_sample = 16,
- .packing = SOC_MBUS_PACKING_EXTEND16,
- .order = SOC_MBUS_ORDER_LE,
- },
-
-};
-
-static struct tegra_buffer *to_tegra_vb(struct vb2_buffer *vb)
-{
- return container_of(vb, struct tegra_buffer, vb);
-}
-
-static void tegra_camera_save_syncpts(struct tegra_camera_dev *pcdev)
-{
- pcdev->syncpt_csi_a =
- nvhost_syncpt_read_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_A);
-
- pcdev->syncpt_csi_b =
- nvhost_syncpt_read_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_B);
-
- pcdev->syncpt_vi =
- nvhost_syncpt_read_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_VI);
-}
-
-static void tegra_camera_incr_syncpts(struct tegra_camera_dev *pcdev)
-{
- nvhost_syncpt_cpu_incr_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_A);
-
- nvhost_syncpt_cpu_incr_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_B);
-
- nvhost_syncpt_cpu_incr_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_VI);
-}
-
-static void tegra_camera_capture_clean(struct tegra_camera_dev *pcdev)
-{
- TC_VI_REG_WT(pcdev, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_INTERRUPT_MASK, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_INTERRUPT_MASK, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_READONLY_STATUS, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_ESCAPE_MODE_COMMAND, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_ESCAPE_MODE_DATA, 0x0);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_PAD_CONFIG, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_CONTROL, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_COUNTER_0, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_COUNTER_1, 0x0);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_DEBUG_COUNTER_2, 0x0);
-}
-
-static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev,
- struct soc_camera_device *icd,
- u32 hdr)
-{
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_A_CONTROL, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILA_CONTROL0, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_PAD_CONFIG0, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_PAD_CONFIG1, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME, 0x0);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x02000000);
-
- /* CSI-A H_ACTIVE and V_ACTIVE */
- TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_H_ACTIVE,
- (icd->user_width << 16));
- TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPA_V_ACTIVE,
- (icd->user_height << 16));
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL1,
- 0x1); /* Frame # for top field detect for interlaced */
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_WORD_COUNT,
- bytes_per_line);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_GAP, 0x00140000);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_EXPECTED_FRAME,
- (icd->user_height << 16) |
- (0x100 << 4) | /* Wait 0x100 vi clks for timeout */
- 0x1); /* Enable line timeout */
-
- /* pad 0s enabled, virtual channel ID 00 */
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0,
- (0x1 << 16) | /* Output 1 pixel per clock */
- (hdr << 8) | /* If hdr shows wrong fmt, use right value */
- (0x1 << 7) | /* Check header CRC */
- (0x1 << 6) | /* Use word count field in the header */
- (0x1 << 5) | /* Look at data identifier byte in hdr */
- (0x1 << 4)); /* Expect packet header */
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_A_CONTROL,
- (0x3f << 16) | /* Skip packet threshold */
- (pdata->lanes - 1));
-
- /* Use 0x00000022 for continuous clock mode. */
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILA_CONTROL0,
- (pdata->continuous_clk << 5) |
- 0x5); /* Clock settle time */
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_CSI_PPA_FRAME_END,
- (0x1 << 8) | /* Enable continuous syncpt */
- TEGRA_VI_SYNCPT_CSI_A);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CIL_COMMAND, 0x00020001);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND, 0x0000f002);
-}
-
-static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev,
- struct soc_camera_device *icd,
- u32 hdr)
-{
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_B_CONTROL, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILB_CONTROL0, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_PAD_CONFIG0, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_PAD_CONFIG1, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME, 0x0);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x04000000);
-
- /* CSI-B H_ACTIVE and V_ACTIVE */
- TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_H_ACTIVE,
- (icd->user_width << 16));
- TC_VI_REG_WT(pcdev, TEGRA_VI_CSI_PPB_V_ACTIVE,
- (icd->user_height << 16));
-
- /* pad 0s enabled, virtual channel ID 00 */
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL0,
- (0x1 << 16) | /* Output 1 pixel per clock */
- (hdr << 8) | /* If hdr shows wrong fmt, use right value */
- (0x1 << 7) | /* Check header CRC */
- (0x1 << 6) | /* Use word count field in the header */
- (0x1 << 5) | /* Look at data identifier byte in hdr */
- (0x1 << 4) | /* Expect packet header */
- 0x1); /* Set PPB stream source to CSI B */
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_CONTROL1,
- 0x1); /* Frame # for top field detect for interlaced */
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_WORD_COUNT,
- bytes_per_line);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_GAP, 0x00140000);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_B_EXPECTED_FRAME,
- (icd->user_height << 16) |
- (0x100 << 4) | /* Wait 0x100 vi clks for timeout */
- 0x1); /* Enable line timeout */
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_B_CONTROL,
- (0x3f << 16) | /* Skip packet threshold */
- (pdata->lanes - 1));
-
- /* Use 0x00000022 for continuous clock mode. */
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILB_CONTROL0,
- (pdata->continuous_clk << 5) |
- 0x5); /* Clock settle time */
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_CSI_PPB_FRAME_END,
- (0x1 << 8) | /* Enable continuous syncpt */
- TEGRA_VI_SYNCPT_CSI_B);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CIL_COMMAND, 0x00010002);
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND, 0x0000f002);
-}
-
-static void tegra_camera_capture_setup_vip(struct tegra_camera_dev *pcdev,
- struct soc_camera_device *icd,
- u32 input_control)
-{
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x00000000);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL,
- (1 << 27) | /* field detect */
- (1 << 25) | /* hsync/vsync decoded from data (BT.656) */
- (1 << 1) | /* VIP_INPUT_ENABLE */
- input_control);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000000);
-
- /* VIP H_ACTIVE and V_ACTIVE */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VIP_H_ACTIVE,
- (icd->user_width << 16) |
- TEGRA_VIP_H_ACTIVE_START);
- TC_VI_REG_WT(pcdev, TEGRA_VI_VIP_V_ACTIVE,
- (icd->user_height << 16) |
- TEGRA_VIP_V_ACTIVE_START);
-
- /*
- * For VIP, D9..D2 is mapped to the video decoder's P7..P0.
- * Disable/mask out the other Dn wires.
- */
- TC_VI_REG_WT(pcdev, TEGRA_VI_PIN_INPUT_ENABLE, 0x000003fc);
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_DATA_INPUT_CONTROL, 0x000003fc);
- TC_VI_REG_WT(pcdev, TEGRA_VI_PIN_INVERSION, 0x00000000);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_VIP_VSYNC,
- (0x1 << 8) | /* Enable continuous syncpt */
- TEGRA_VI_SYNCPT_VI);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL, 0x00000004);
-}
-
-static int tegra_camera_capture_output_channel_setup(
- struct tegra_camera_dev *pcdev,
- struct soc_camera_device *icd)
-{
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int port = pdata->port;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
- const struct soc_camera_format_xlate *current_fmt = icd->current_fmt;
- u32 output_fourcc = current_fmt->host_fmt->fourcc;
- u32 output_format, output_control;
- struct tegra_buffer *buf = to_tegra_vb(pcdev->active);
-
- switch (output_fourcc) {
- case V4L2_PIX_FMT_UYVY:
- output_format = 0x3; /* Default to YUV422 */
- break;
- case V4L2_PIX_FMT_VYUY:
- output_format = (0x1 << 17) | 0x3;
- break;
- case V4L2_PIX_FMT_YUYV:
- output_format = (0x2 << 17) | 0x3;
- break;
- case V4L2_PIX_FMT_YVYU:
- output_format = (0x3 << 17) | 0x3;
- break;
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- output_format = 0x6; /* YUV420 planar */
- break;
- case V4L2_PIX_FMT_SBGGR8:
- case V4L2_PIX_FMT_SBGGR10:
- /* Use second output channel for RAW8/RAW10 */
- buf->output_channel = 1;
-
- if (port == TEGRA_CAMERA_PORT_CSI_A)
- output_format = 0x7;
- else if (port == TEGRA_CAMERA_PORT_CSI_B)
- output_format = 0x8;
- else
- output_format = 0x9;
- break;
- default:
- dev_err(&pcdev->ndev->dev, "Wrong output format %d\n",
- output_fourcc);
- return -EINVAL;
- }
-
- output_control = (pdata->flip_v ? (0x1 << 20) : 0) |
- (pdata->flip_h ? (0x1 << 19) : 0) |
- output_format;
-
- if (buf->output_channel == 0) {
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL,
- output_control);
- /*
- * Set up frame size. Bits 31:16 are the number of lines, and
- * bits 15:0 are the number of pixels per line.
- */
- TC_VI_REG_WT(pcdev, TEGRA_VI_FIRST_OUTPUT_FRAME_SIZE,
- (icd->user_height << 16) | icd->user_width);
-
- /* First output memory enabled */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000);
-
- /* Set the number of frames in the buffer. */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_COUNT_FIRST, 0x00000001);
-
- /* Set up buffer frame size. */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_SIZE_FIRST,
- (icd->user_height << 16) | icd->user_width);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
- (icd->user_height * bytes_per_line));
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_1,
- (0x1 << 8) | /* Enable continuous syncpt */
- TEGRA_VI_SYNCPT_VI);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000);
- } else if (buf->output_channel == 1) {
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_SECOND_OUTPUT_CONTROL,
- output_control);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_SECOND_OUTPUT_FRAME_SIZE,
- (icd->user_height << 16) | icd->user_width);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE_2, 0x00000000);
-
- /* Set the number of frames in the buffer. */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_COUNT_SECOND, 0x00000001);
-
- /* Set up buffer frame size. */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_SIZE_SECOND,
- (icd->user_height << 16) | icd->user_width);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_SECOND,
- (icd->user_height * bytes_per_line));
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_CONT_SYNCPT_OUT_2,
- (0x1 << 8) | /* Enable continuous syncpt */
- TEGRA_VI_SYNCPT_VI);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE_2, 0x00000000);
- } else {
- dev_err(&pcdev->ndev->dev, "Wrong output channel %d\n",
- buf->output_channel);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int tegra_camera_capture_setup(struct tegra_camera_dev *pcdev)
-{
- struct vb2_buffer *vb = pcdev->active;
- struct tegra_buffer *buf = to_tegra_vb(vb);
- struct soc_camera_device *icd = buf->icd;
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int port = pdata->port;
- const struct soc_camera_format_xlate *current_fmt = icd->current_fmt;
- enum v4l2_mbus_pixelcode input_code = current_fmt->code;
- u32 hdr, input_control = 0x0;
-
- switch (input_code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
- input_control |= 0x2 << 8;
- hdr = 30;
- break;
- case V4L2_MBUS_FMT_VYUY8_2X8:
- input_control |= 0x3 << 8;
- hdr = 30;
- break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
- input_control |= 0x0;
- hdr = 30;
- break;
- case V4L2_MBUS_FMT_YVYU8_2X8:
- input_control |= 0x1 << 8;
- hdr = 30;
- break;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- input_control |= 0x2 << 2; /* Input Format = Bayer */
- hdr = 42;
- break;
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- input_control |= 0x2 << 2; /* Input Format = Bayer */
- hdr = 43;
- break;
- default:
- dev_err(&pcdev->ndev->dev, "Input format %d is not supported\n",
- input_code);
- return -EINVAL;
- }
-
- /*
- * Set up low pass filter. Use 0x240 for chromaticity and 0x240
- * for luminance, which is the default and means not to touch
- * anything.
- */
- TC_VI_REG_WT(pcdev, TEGRA_VI_H_LPF_CONTROL, 0x02400240);
-
- /* Set up raise-on-edge, so we get an interrupt on end of frame. */
- TC_VI_REG_WT(pcdev, TEGRA_VI_VI_RAISE, 0x00000001);
-
- /* Cleanup registers */
- tegra_camera_capture_clean(pcdev);
-
- /* Setup registers for CSI-A, CSI-B and VIP inputs */
- if (port == TEGRA_CAMERA_PORT_CSI_A)
- tegra_camera_capture_setup_csi_a(pcdev, icd, hdr);
- else if (port == TEGRA_CAMERA_PORT_CSI_B)
- tegra_camera_capture_setup_csi_b(pcdev, icd, hdr);
- else
- tegra_camera_capture_setup_vip(pcdev, icd, input_control);
-
- /* Setup registers for output channels */
- return tegra_camera_capture_output_channel_setup(pcdev, icd);
-}
-
-static int tegra_camera_capture_buffer_setup(struct tegra_camera_dev *pcdev,
- struct tegra_buffer *buf)
-{
- struct soc_camera_device *icd = buf->icd;
-
- switch (icd->current_fmt->host_fmt->fourcc) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_U,
- buf->buffer_addr_u);
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_U,
- buf->start_addr_u);
-
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_V,
- buf->buffer_addr_v);
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_V,
- buf->start_addr_v);
-
- 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_SBGGR10:
- /* output 1 */
- if (buf->output_channel == 0) {
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_FIRST,
- buf->buffer_addr);
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_FIRST,
- buf->start_addr);
- /* output 2 */
- } else if (buf->output_channel == 1) {
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BASE_ADDRESS_SECOND,
- buf->buffer_addr);
- TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_START_ADDRESS_SECOND,
- buf->start_addr);
- } else {
- dev_err(&pcdev->ndev->dev, "Wrong output channel %d\n",
- buf->output_channel);
- return -EINVAL;
- }
- break;
-
- default:
- dev_err(&pcdev->ndev->dev, "Wrong host format %d\n",
- icd->current_fmt->host_fmt->fourcc);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev,
- struct tegra_buffer *buf)
-{
- struct soc_camera_device *icd = buf->icd;
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int port = pdata->port;
- int err;
-
- err = tegra_camera_capture_buffer_setup(pcdev, buf);
- if (err < 0)
- return err;
- /*
- * Only wait on CSI frame end syncpt if we're using CSI. Otherwise,
- * wait on VIP VSYNC syncpt.
- */
- if (port == TEGRA_CAMERA_PORT_CSI_A) {
- pcdev->syncpt_csi_a++;
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
- 0x0000f005);
- err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_A,
- pcdev->syncpt_csi_a,
- TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
- NULL,
- NULL);
- } else if (port == TEGRA_CAMERA_PORT_CSI_B) {
- pcdev->syncpt_csi_b++;
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
- 0x0000f005);
- err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_B,
- pcdev->syncpt_csi_b,
- TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
- NULL,
- NULL);
- } else {
- pcdev->syncpt_vi++;
- TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL,
- 0x00000001);
- err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_VI,
- pcdev->syncpt_csi_a,
- TEGRA_SYNCPT_VI_WAIT_TIMEOUT,
- NULL,
- NULL);
- }
-
- if (!err)
- return 0;
-
- if (tegra_camera_port_is_csi(port)) {
- u32 ppstatus;
- u32 cilstatus;
- u32 rostatus;
-
- dev_warn(&icd->vdev->dev, "Timeout on CSI syncpt\n");
- dev_warn(&icd->vdev->dev, "buffer_addr = 0x%08x\n",
- buf->buffer_addr);
-
- ppstatus = TC_VI_REG_RD(pcdev,
- TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
- cilstatus = TC_VI_REG_RD(pcdev,
- TEGRA_CSI_CSI_CIL_STATUS);
- rostatus = TC_VI_REG_RD(pcdev,
- TEGRA_CSI_CSI_READONLY_STATUS);
-
- dev_warn(&icd->vdev->dev,
- "PPSTATUS = 0x%08x, "
- "CILSTATUS = 0x%08x, "
- "ROSTATUS = 0x%08x\n",
- ppstatus, cilstatus, rostatus);
- } else {
- u32 vip_input_status;
-
- dev_warn(&pcdev->ndev->dev, "Timeout on VI syncpt\n");
- dev_warn(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n",
- buf->buffer_addr);
-
- vip_input_status = TC_VI_REG_RD(pcdev,
- TEGRA_VI_VIP_INPUT_STATUS);
-
- dev_warn(&pcdev->ndev->dev,
- "VIP_INPUT_STATUS = 0x%08x\n",
- vip_input_status);
- }
-
- return err;
-}
-
-static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port)
-{
- int err;
- struct tegra_buffer *buf = to_tegra_vb(pcdev->active);
-
- if (port == TEGRA_CAMERA_PORT_CSI_A)
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
- 0x0000f002);
- else if (port == TEGRA_CAMERA_PORT_CSI_B)
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
- 0x0000f002);
- else
- TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL,
- 0x00000005);
-
- if (tegra_camera_port_is_csi(port))
- err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_VI,
- pcdev->syncpt_vi,
- TEGRA_SYNCPT_VI_WAIT_TIMEOUT,
- NULL,
- NULL);
- else
- err = 0;
-
- if (err) {
- u32 buffer_addr;
- u32 ppstatus;
- u32 cilstatus;
-
- dev_warn(&pcdev->ndev->dev, "Timeout on VI syncpt\n");
-
- if (buf->output_channel == 0)
- buffer_addr = TC_VI_REG_RD(pcdev,
- TEGRA_VI_VB0_BASE_ADDRESS_FIRST);
- else if (buf->output_channel == 1)
- buffer_addr = TC_VI_REG_RD(pcdev,
- TEGRA_VI_VB0_BASE_ADDRESS_SECOND);
- else {
- dev_err(&pcdev->ndev->dev, "Wrong output channel %d\n",
- buf->output_channel);
- return -EINVAL;
- }
-
- dev_warn(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n",
- buffer_addr);
-
- ppstatus = TC_VI_REG_RD(pcdev,
- TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
- cilstatus = TC_VI_REG_RD(pcdev,
- TEGRA_CSI_CSI_CIL_STATUS);
- dev_warn(&pcdev->ndev->dev,
- "PPSTATUS = 0x%08x, CILSTATUS = 0x%08x\n",
- ppstatus, cilstatus);
- }
-
- return err;
-}
-
-static void tegra_camera_activate(struct tegra_camera_dev *pcdev)
-{
- nvhost_module_busy_ext(pcdev->ndev);
-
- /* Enable external power */
- regulator_enable(pcdev->reg);
-
- /*
- * Powergating DIS must powergate VE partition. Camera
- * module needs to increase the ref-count of disa to
- * avoid itself powergated by DIS inadvertently.
- */
-#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
- tegra_unpowergate_partition(TEGRA_POWERGATE_DISA);
-#endif
- /* Unpowergate VE */
- tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
-
- /* Turn on relevant clocks. */
- clk_set_rate(pcdev->clk_vi, 150000000);
- clk_prepare_enable(pcdev->clk_vi);
- clk_set_rate(pcdev->clk_vi_sensor, 24000000);
- clk_prepare_enable(pcdev->clk_vi_sensor);
- clk_prepare_enable(pcdev->clk_csi);
- clk_prepare_enable(pcdev->clk_isp);
- clk_prepare_enable(pcdev->clk_csus);
- clk_set_rate(pcdev->clk_sclk, 80000000);
- clk_prepare_enable(pcdev->clk_sclk);
- clk_set_rate(pcdev->clk_sclk, 375000000);
- clk_prepare_enable(pcdev->clk_emc);
-
- /* Save current syncpt values. */
- tegra_camera_save_syncpts(pcdev);
-}
-
-static void tegra_camera_deactivate(struct tegra_camera_dev *pcdev)
-{
- /* Turn off relevant clocks. */
- clk_disable_unprepare(pcdev->clk_vi);
- clk_disable_unprepare(pcdev->clk_vi_sensor);
- clk_disable_unprepare(pcdev->clk_csi);
- clk_disable_unprepare(pcdev->clk_isp);
- clk_disable_unprepare(pcdev->clk_csus);
- clk_disable_unprepare(pcdev->clk_sclk);
- clk_disable_unprepare(pcdev->clk_emc);
-
- /* Powergate VE */
- tegra_powergate_partition(TEGRA_POWERGATE_VENC);
-#if defined(CONFIG_ARCH_TEGRA_11x_SOC) || defined(CONFIG_ARCH_TEGRA_14x_SOC)
- tegra_powergate_partition(TEGRA_POWERGATE_DISA);
-#endif
-
- /* Disable external power */
- regulator_disable(pcdev->reg);
-
- nvhost_module_idle_ext(pcdev->ndev);
-}
-
-static int tegra_camera_capture_frame(struct tegra_camera_dev *pcdev)
-{
- struct vb2_buffer *vb = pcdev->active;
- struct tegra_buffer *buf = to_tegra_vb(vb);
- struct soc_camera_device *icd = buf->icd;
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int port = pdata->port;
- int retry = TEGRA_SYNCPT_RETRY_COUNT;
- int err;
-
- while (retry) {
- err = tegra_camera_capture_start(pcdev, buf);
- /* Capturing succeed, stop capturing */
- if (!err)
- err = tegra_camera_capture_stop(pcdev, port);
- /* Capturing failed, stop and retry */
- else {
- retry--;
-
- /* Stop streaming. */
- if (port == TEGRA_CAMERA_PORT_CSI_A) {
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
- 0x0000f002);
- /* Clear status registers. */
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_CSI_PIXEL_PARSER_STATUS,
- 0xffffffff);
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_CSI_CIL_STATUS,
- 0xffffffff);
- } else if (port == TEGRA_CAMERA_PORT_CSI_B) {
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
- 0x0000f002);
- /* Clear status registers. */
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_CSI_PIXEL_PARSER_STATUS,
- 0xffffffff);
- TC_VI_REG_WT(pcdev,
- TEGRA_CSI_CSI_CIL_STATUS,
- 0xffffffff);
- } else {
- TC_VI_REG_WT(pcdev,
- TEGRA_VI_CAMERA_CONTROL,
- 0x00000005);
- }
-
- tegra_camera_incr_syncpts(pcdev);
- tegra_camera_save_syncpts(pcdev);
-
- continue;
- }
-
- break;
- }
-
- /* Reset hardware for too many errors */
- if (!retry) {
- tegra_camera_deactivate(pcdev);
- mdelay(5);
- tegra_camera_activate(pcdev);
- if (pcdev->active)
- tegra_camera_capture_setup(pcdev);
- }
-
- spin_lock_irq(&pcdev->videobuf_queue_lock);
-
- do_gettimeofday(&vb->v4l2_buf.timestamp);
- vb->v4l2_buf.field = pcdev->field;
- if (port == TEGRA_CAMERA_PORT_CSI_A)
- vb->v4l2_buf.sequence = pcdev->sequence_a++;
- else if (port == TEGRA_CAMERA_PORT_CSI_B)
- vb->v4l2_buf.sequence = pcdev->sequence_b++;
-
- vb2_buffer_done(vb, err < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
- list_del_init(&buf->queue);
-
- pcdev->num_frames++;
-
- spin_unlock_irq(&pcdev->videobuf_queue_lock);
-
- return err;
-}
-
-static void tegra_camera_work(struct work_struct *work)
-{
- struct tegra_camera_dev *pcdev =
- container_of(work, struct tegra_camera_dev, work);
- struct tegra_buffer *buf;
-
- while (1) {
- mutex_lock(&pcdev->work_mutex);
-
- spin_lock_irq(&pcdev->videobuf_queue_lock);
- if (list_empty(&pcdev->capture)) {
- pcdev->active = NULL;
- spin_unlock_irq(&pcdev->videobuf_queue_lock);
- mutex_unlock(&pcdev->work_mutex);
- return;
- }
-
- buf = list_entry(pcdev->capture.next, struct tegra_buffer,
- queue);
- pcdev->active = &buf->vb;
- spin_unlock_irq(&pcdev->videobuf_queue_lock);
-
- tegra_camera_capture_setup(pcdev);
- tegra_camera_capture_frame(pcdev);
-
- mutex_unlock(&pcdev->work_mutex);
- }
-}
-
-static int tegra_camera_init_buffer(struct tegra_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);
- struct tegra_camera_platform_data *pdata = icd->link->priv;
-
- switch (icd->current_fmt->host_fmt->fourcc) {
- 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_SBGGR10:
- buf->buffer_addr = vb2_dma_contig_plane_dma_addr(&buf->vb, 0);
- buf->start_addr = buf->buffer_addr;
-
- if (pdata->flip_v)
- buf->start_addr += bytes_per_line *
- (icd->user_height-1);
-
- if (pdata->flip_h)
- buf->start_addr += bytes_per_line - 1;
-
- break;
-
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- buf->buffer_addr = vb2_dma_contig_plane_dma_addr(&buf->vb, 0);
- buf->buffer_addr_u = buf->buffer_addr +
- icd->user_width * icd->user_height;
- buf->buffer_addr_v = buf->buffer_addr_u +
- (icd->user_width * icd->user_height) / 4;
-
- /* For YVU420, we swap the locations of the U and V planes. */
- if (icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_YVU420) {
- dma_addr_t temp = buf->buffer_addr_u;
- buf->buffer_addr_u = buf->buffer_addr_v;
- buf->buffer_addr_v = temp;
- }
-
- buf->start_addr = buf->buffer_addr;
- buf->start_addr_u = buf->buffer_addr_u;
- buf->start_addr_v = buf->buffer_addr_v;
-
- if (pdata->flip_v) {
- buf->start_addr += icd->user_width *
- (icd->user_height - 1);
-
- buf->start_addr_u += ((icd->user_width/2) *
- ((icd->user_height/2) - 1));
-
- buf->start_addr_v += ((icd->user_width/2) *
- ((icd->user_height/2) - 1));
- }
-
- if (pdata->flip_h) {
- buf->start_addr += icd->user_width - 1;
-
- buf->start_addr_u += (icd->user_width/2) - 1;
-
- buf->start_addr_v += (icd->user_width/2) - 1;
- }
-
- break;
-
- default:
- dev_err(icd->parent, "Wrong host format %d\n",
- icd->current_fmt->host_fmt->fourcc);
- return -EINVAL;
- }
-
- return 0;
-}
-
-/*
- * Videobuf operations
- */
-static int tegra_camera_videobuf_setup(struct vb2_queue *vq,
- const struct v4l2_format *fmt,
- unsigned int *num_buffers,
- unsigned int *num_planes,
- unsigned int sizes[],
- void *alloc_ctxs[])
-{
- struct soc_camera_device *icd = container_of(vq,
- struct soc_camera_device,
- vb2_vidq);
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct tegra_camera_dev *pcdev = ici->priv;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
- if (bytes_per_line < 0)
- return bytes_per_line;
-
- *num_planes = 1;
-
- if (pdata->port == TEGRA_CAMERA_PORT_CSI_A)
- pcdev->sequence_a = 0;
- else if (pdata->port == TEGRA_CAMERA_PORT_CSI_B)
- pcdev->sequence_b = 0;
- sizes[0] = bytes_per_line * icd->user_height;
- alloc_ctxs[0] = pcdev->alloc_ctx;
-
- if (!*num_buffers)
- *num_buffers = 2;
-
- return 0;
-}
-
-static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb)
-{
- struct soc_camera_device *icd = container_of(vb->vb2_queue,
- struct soc_camera_device,
- vb2_vidq);
- struct tegra_buffer *buf = to_tegra_vb(vb);
- struct tegra_camera_platform_data *pdata = icd->link->priv;
- int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
- icd->current_fmt->host_fmt);
- unsigned long size;
-
- if (bytes_per_line < 0)
- return bytes_per_line;
-
- buf->icd = icd;
-
- if (!pdata) {
- dev_err(icd->parent, "No platform data for this device!\n");
- return -EINVAL;
- }
-
- if (!tegra_camera_port_is_valid(pdata->port)) {
- dev_err(icd->parent,
- "Invalid camera port %d in platform data\n",
- pdata->port);
- return -EINVAL;
- }
-
- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
- vb, vb2_plane_vaddr(vb, 0), vb2_plane_size(vb, 0));
-
-#ifdef PREFILL_BUFFER
- /*
- * This can be useful if you want to see if we actually fill
- * the buffer with something
- */
- if (vb2_plane_vaddr(vb, 0))
- memset(vb2_plane_vaddr(vb, 0), 0xbd, vb2_plane_size(vb, 0));
-#endif
-
- if (!icd->current_fmt) {
- dev_err(icd->parent, "%s NULL format point\n", __func__);
- return -EINVAL;
- }
-
- size = icd->user_height * bytes_per_line;
-
- if (vb2_plane_size(vb, 0) < size) {
- dev_err(icd->parent, "Buffer too small (%lu < %lu)\n",
- vb2_plane_size(vb, 0), size);
- return -ENOBUFS;
- }
-
- vb2_set_plane_payload(vb, 0, size);
-
- return tegra_camera_init_buffer(buf);
-}
-
-static void tegra_camera_videobuf_queue(struct vb2_buffer *vb)
-{
- struct soc_camera_device *icd = container_of(vb->vb2_queue,
- struct soc_camera_device,
- vb2_vidq);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct tegra_camera_dev *pcdev = ici->priv;
- struct tegra_buffer *buf = to_tegra_vb(vb);
-
- dev_dbg(icd->parent, "%s (vb=0x%p) 0x%p %lu\n", __func__,
- vb, vb2_plane_vaddr(vb, 0), vb2_get_plane_payload(vb, 0));
-
- spin_lock_irq(&pcdev->videobuf_queue_lock);
- list_add_tail(&buf->queue, &pcdev->capture);
- schedule_work(&pcdev->work);
- spin_unlock_irq(&pcdev->videobuf_queue_lock);
-
- dev_dbg(icd->parent, "Finished tegra_camera_videobuf_queue()\n");
-}
-
-static void tegra_camera_videobuf_release(struct vb2_buffer *vb)
-{
- struct soc_camera_device *icd = container_of(vb->vb2_queue,
- struct soc_camera_device,
- vb2_vidq);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct tegra_buffer *buf = to_tegra_vb(vb);
- struct tegra_camera_dev *pcdev = ici->priv;
-
- dev_dbg(icd->parent, "In tegra_camera_videobuf_release()\n");
-
- mutex_lock(&pcdev->work_mutex);
-
- spin_lock_irq(&pcdev->videobuf_queue_lock);
-
- if (pcdev->active == vb)
- pcdev->active = NULL;
-
- /*
- * Doesn't hurt also if the list is empty, but it hurts, if queuing the
- * buffer failed, and .buf_init() hasn't been called
- */
- if (buf->queue.next)
- list_del_init(&buf->queue);
-
- spin_unlock_irq(&pcdev->videobuf_queue_lock);
-
- mutex_unlock(&pcdev->work_mutex);
-
- dev_dbg(icd->parent, "Finished tegra_camera_videobuf_release()\n");
-}
-
-static int tegra_camera_videobuf_init(struct vb2_buffer *vb)
-{
- /* This is for locking debugging only */
- INIT_LIST_HEAD(&to_tegra_vb(vb)->queue);
-
- return 0;
-}
-
-static int tegra_camera_stop_streaming(struct vb2_queue *q)
-{
- struct soc_camera_device *icd = container_of(q,
- struct soc_camera_device,
- vb2_vidq);
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct tegra_camera_dev *pcdev = ici->priv;
- struct list_head *buf_head, *tmp;
-
-
- mutex_lock(&pcdev->work_mutex);
-
- spin_lock_irq(&pcdev->videobuf_queue_lock);
- list_for_each_safe(buf_head, tmp, &pcdev->capture) {
- struct tegra_buffer *buf = container_of(buf_head,
- struct tegra_buffer,
- queue);
- if (buf->icd == icd)
- list_del_init(buf_head);
- }
- spin_unlock_irq(&pcdev->videobuf_queue_lock);
-
- if (pcdev->active) {
- struct tegra_buffer *buf = to_tegra_vb(pcdev->active);
- if (buf->icd == icd)
- pcdev->active = NULL;
- }
-
- mutex_unlock(&pcdev->work_mutex);
-
- return 0;
-}
-
-static struct vb2_ops tegra_camera_videobuf_ops = {
- .queue_setup = tegra_camera_videobuf_setup,
- .buf_prepare = tegra_camera_videobuf_prepare,
- .buf_queue = tegra_camera_videobuf_queue,
- .buf_cleanup = tegra_camera_videobuf_release,
- .buf_init = tegra_camera_videobuf_init,
- .wait_prepare = soc_camera_unlock,
- .wait_finish = soc_camera_lock,
- .stop_streaming = tegra_camera_stop_streaming,
-};
-
-/*
- * SOC camera host operations
- */
-static int tegra_camera_init_videobuf(struct vb2_queue *q,
- struct soc_camera_device *icd)
-{
- dev_dbg(icd->parent, "In tegra_camera_init_videobuf()\n");
-
- q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- q->io_modes = VB2_MMAP | VB2_USERPTR;
- q->drv_priv = icd;
- q->ops = &tegra_camera_videobuf_ops;
- q->mem_ops = &vb2_dma_contig_memops;
- q->buf_struct_size = sizeof(struct tegra_buffer);
-
- dev_dbg(icd->parent, "Finished tegra_camera_init_videobuf()\n");
-
- return vb2_queue_init(q);
-}
-
-/*
- * Called with .video_lock held
- */
-static int tegra_camera_add_device(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct tegra_camera_dev *pcdev = ici->priv;
-
- if (!pcdev->enable_refcnt) {
- pm_runtime_get_sync(ici->v4l2_dev.dev);
- tegra_camera_activate(pcdev);
- pcdev->num_frames = 0;
- }
- pcdev->enable_refcnt++;
-
- dev_dbg(icd->parent, "TEGRA Camera host attached to camera %d\n",
- icd->devnum);
-
- return 0;
-}
-
-/* Called with .video_lock held */
-static void tegra_camera_remove_device(struct soc_camera_device *icd)
-{
- struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
- struct tegra_camera_dev *pcdev = ici->priv;
-
- pcdev->enable_refcnt--;
- if (!pcdev->enable_refcnt) {
- cancel_work_sync(&pcdev->work);
- tegra_camera_deactivate(pcdev);
- pm_runtime_put_sync(ici->v4l2_dev.dev);
- }
-
- dev_dbg(icd->parent, "Frames captured: %d\n", pcdev->num_frames);
-
- dev_dbg(icd->parent, "TEGRA camera host detached from camera %d\n",
- icd->devnum);
-}
-
-static int tegra_camera_set_bus_param(struct soc_camera_device *icd)
-{
- return 0;
-}
-
-static int tegra_camera_get_formats(struct soc_camera_device *icd,
- unsigned int idx,
- struct soc_camera_format_xlate *xlate)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct device *dev = icd->parent;
- int formats = 0;
- int ret;
- enum v4l2_mbus_pixelcode code;
- const struct soc_mbus_pixelfmt *fmt;
- int k;
-
- ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
- if (ret != 0)
- /* No more formats */
- return 0;
-
- fmt = soc_mbus_get_fmtdesc(code);
- if (!fmt) {
- dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
- return 0;
- }
-
- switch (code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
- case V4L2_MBUS_FMT_VYUY8_2X8:
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_YVYU8_2X8:
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- formats += ARRAY_SIZE(tegra_camera_formats);
- for (k = 0;
- xlate && (k < ARRAY_SIZE(tegra_camera_formats));
- k++) {
- xlate->host_fmt = &tegra_camera_formats[k];
- xlate->code = code;
- xlate++;
-
- dev_info(dev, "Providing format %s using code %d\n",
- tegra_camera_formats[k].name, code);
- }
- break;
- default:
- dev_info(dev, "Not supporting %s\n", fmt->name);
- return 0;
- }
-
- return formats;
-}
-
-static void tegra_camera_put_formats(struct soc_camera_device *icd)
-{
- kfree(icd->host_priv);
- icd->host_priv = NULL;
-}
-
-static int tegra_camera_set_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- struct device *dev = icd->parent;
- struct soc_camera_host *ici = to_soc_camera_host(dev);
- struct tegra_camera_dev *pcdev = ici->priv;
-
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- const struct soc_camera_format_xlate *xlate = NULL;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_mbus_framefmt mf;
- int ret;
-
- dev_dbg(dev, "In tegra_camera_set_fmt()\n");
-
- xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
- if (!xlate) {
- dev_warn(dev, "Format %x not found\n", pix->pixelformat);
- return -EINVAL;
- }
-
- mf.width = pix->width;
- mf.height = pix->height;
- mf.field = pix->field;
- mf.colorspace = pix->colorspace;
- mf.code = xlate->code;
-
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
- if (IS_ERR_VALUE(ret)) {
- dev_warn(dev, "Failed to configure for format %x\n",
- pix->pixelformat);
- return ret;
- }
-
- if (mf.code != xlate->code) {
- dev_warn(dev, "mf.code = %d, xlate->code = %d, mismatch\n",
- mf.code, xlate->code);
- return -EINVAL;
- }
-
- icd->user_width = mf.width;
- icd->user_height = mf.height;
- icd->current_fmt = xlate;
-
- pcdev->field = pix->field;
-
- dev_dbg(dev, "Finished tegra_camera_set_fmt(), returning %d\n", ret);
-
- return ret;
-}
-
-static int tegra_camera_try_fmt(struct soc_camera_device *icd,
- struct v4l2_format *f)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- const struct soc_camera_format_xlate *xlate;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- struct v4l2_mbus_framefmt mf;
- __u32 pixfmt = pix->pixelformat;
- int ret;
-
- dev_dbg(icd->parent, "In tegra_camera_try_fmt()\n");
-
- xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
- if (!xlate) {
- dev_warn(icd->parent, "Format %x not found\n", pixfmt);
- return -EINVAL;
- }
-
- pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
- xlate->host_fmt);
- if (pix->bytesperline < 0)
- return pix->bytesperline;
- pix->sizeimage = pix->height * pix->bytesperline;
-
- /* limit to sensor capabilities */
- mf.width = pix->width;
- mf.height = pix->height;
- mf.field = pix->field;
- mf.colorspace = pix->colorspace;
- mf.code = xlate->code;
-
- ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
- if (IS_ERR_VALUE(ret))
- return ret;
-
- pix->width = mf.width;
- pix->height = mf.height;
- pix->colorspace = mf.colorspace;
- /*
- * width and height could have been changed, therefore update the
- * bytesperline and sizeimage here.
- */
- pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
- xlate->host_fmt);
- pix->sizeimage = pix->height * pix->bytesperline;
-
- switch (mf.field) {
- case V4L2_FIELD_ANY:
- case V4L2_FIELD_NONE:
- pix->field = V4L2_FIELD_NONE;
- break;
- default:
- /* TODO: support interlaced at least in pass-through mode */
- dev_err(icd->parent, "Field type %d unsupported.\n",
- mf.field);
- return -EINVAL;
- }
-
- dev_dbg(icd->parent,
- "Finished tegra_camera_try_fmt(), returning %d\n", ret);
-
- return ret;
-}
-
-static int tegra_camera_reqbufs(struct soc_camera_device *icd,
- struct v4l2_requestbuffers *p)
-{
- return 0;
-}
-
-static unsigned int tegra_camera_poll(struct file *file, poll_table *pt)
-{
- struct soc_camera_device *icd = file->private_data;
-
- return vb2_poll(&icd->vb2_vidq, file, pt);
-}
-
-static int tegra_camera_querycap(struct soc_camera_host *ici,
- struct v4l2_capability *cap)
-{
- strlcpy(cap->card, TEGRA_CAM_DRV_NAME, sizeof(cap->card));
- cap->version = TEGRA_CAM_VERSION_CODE;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
-
- return 0;
-}
-
-static struct soc_camera_host_ops tegra_soc_camera_host_ops = {
- .owner = THIS_MODULE,
- .init_videobuf2 = tegra_camera_init_videobuf,
- .add = tegra_camera_add_device,
- .remove = tegra_camera_remove_device,
- .set_bus_param = tegra_camera_set_bus_param,
- .get_formats = tegra_camera_get_formats,
- .put_formats = tegra_camera_put_formats,
- .set_fmt = tegra_camera_set_fmt,
- .try_fmt = tegra_camera_try_fmt,
- .reqbufs = tegra_camera_reqbufs,
- .poll = tegra_camera_poll,
- .querycap = tegra_camera_querycap,
-};
-
-static struct of_device_id tegra_vi_of_match[] = {
-#ifdef TEGRA_2X_OR_HIGHER_CONFIG
- { .compatible = "nvidia,tegra20-vi",
- .data = (struct nvhost_device_data *)&t20_vi_info },
-#endif
-#ifdef TEGRA_3X_OR_HIGHER_CONFIG
- { .compatible = "nvidia,tegra30-vi",
- .data = (struct nvhost_device_data *)&t30_vi_info },
-#endif
-#ifdef TEGRA_11X_OR_HIGHER_CONFIG
- { .compatible = "nvidia,tegra114-vi",
- .data = (struct nvhost_device_data *)&t11_vi_info },
-#endif
-#ifdef TEGRA_14X_OR_HIGHER_CONFIG
- { .compatible = "nvidia,tegra148-vi",
- .data = (struct nvhost_device_data *)&t14_vi_info },
-#endif
- { },
-};
-
-static int tegra_camera_probe(struct platform_device *pdev)
-{
- struct tegra_camera_dev *pcdev;
- struct nvhost_device_data *ndata = NULL;
- int err = 0;
-
- if (pdev->dev.of_node) {
- const struct of_device_id *match;
-
- match = of_match_device(tegra_vi_of_match, &pdev->dev);
- if (match)
- ndata = match->data;
- } else
- ndata = pdev->dev.platform_data;
-
- if (!ndata) {
- dev_err(&pdev->dev, "No nvhost device data!\n");
- err = -EINVAL;
- goto exit;
- }
-
- pcdev = kzalloc(sizeof(struct tegra_camera_dev), GFP_KERNEL);
- if (!pcdev) {
- dev_err(&pdev->dev, "Could not allocate pcdev\n");
- err = -ENOMEM;
- goto exit;
- }
-
- pcdev->ndata = ndata;
- pcdev->ndev = pdev;
-
- pcdev->ici.priv = pcdev;
- pcdev->ici.v4l2_dev.dev = &pdev->dev;
- pcdev->ici.nr = pdev->id;
- pcdev->ici.drv_name = dev_name(&pdev->dev);
- pcdev->ici.ops = &tegra_soc_camera_host_ops;
-
- INIT_LIST_HEAD(&pcdev->capture);
- INIT_WORK(&pcdev->work, tegra_camera_work);
- spin_lock_init(&pcdev->videobuf_queue_lock);
- mutex_init(&pcdev->work_mutex);
-
- pcdev->clk_vi = clk_get(&pdev->dev, "vi");
- if (IS_ERR_OR_NULL(pcdev->clk_vi)) {
- dev_err(&pdev->dev, "Failed to get vi clock.\n");
- goto exit_free_pcdev;
- }
-
- pcdev->clk_vi_sensor = clk_get(&pdev->dev, "vi_sensor");
- if (IS_ERR_OR_NULL(pcdev->clk_vi_sensor)) {
- dev_err(&pdev->dev, "Failed to get vi_sensor clock.\n");
- goto exit_put_clk_vi;
- }
-
- pcdev->clk_csi = clk_get(&pdev->dev, "csi");
- if (IS_ERR_OR_NULL(pcdev->clk_csi)) {
- dev_err(&pdev->dev, "Failed to get csi clock.\n");
- goto exit_put_clk_vi_sensor;
- }
-
- pcdev->clk_isp = clk_get(&pdev->dev, "isp");
- if (IS_ERR_OR_NULL(pcdev->clk_isp)) {
- dev_err(&pdev->dev, "Failed to get isp clock.\n");
- goto exit_put_clk_csi;
- }
-
- pcdev->clk_csus = clk_get(&pdev->dev, "csus");
- if (IS_ERR_OR_NULL(pcdev->clk_csus)) {
- dev_err(&pdev->dev, "Failed to get csus clock.\n");
- goto exit_put_clk_isp;
- }
-
- pcdev->clk_sclk = clk_get(&pdev->dev, "sclk");
- if (IS_ERR_OR_NULL(pcdev->clk_sclk)) {
- dev_err(&pdev->dev, "Failed to get sclk clock.\n");
- goto exit_put_clk_csus;
- }
-
- pcdev->clk_emc = clk_get(&pdev->dev, "emc");
- if (IS_ERR_OR_NULL(pcdev->clk_emc)) {
- dev_err(&pdev->dev, "Failed to get emc clock.\n");
- goto exit_put_clk_sclk;
- }
-
- clk_set_rate(pcdev->clk_vi, 150000000);
- clk_set_rate(pcdev->clk_vi_sensor, 24000000);
-
- /* Get regulator pointer */
-#ifdef CONFIG_ARCH_TEGRA_2x_SOC
- pcdev->reg = regulator_get(&pdev->dev, "vcsi");
-#else
- pcdev->reg = regulator_get(&pdev->dev, "avdd_dsi_csi");
-#endif
- if (IS_ERR_OR_NULL(pcdev->reg)) {
- dev_err(&pdev->dev, "%s: couldn't get regulator\n",
- __func__);
- goto exit_put_clk_emc;
- }
-
- platform_set_drvdata(pdev, ndata);
- err = nvhost_client_device_get_resources(pdev);
- if (err) {
- dev_err(&pdev->dev, "%s: nvhost get resources failed %d\n",
- __func__, err);
- goto exit_put_regulator;
- }
-
- err = nvhost_client_device_init(pdev);
- if (err) {
- dev_err(&pdev->dev, "%s: nvhost init failed %d\n",
- __func__, err);
- goto exit_put_regulator;
- }
-
- pcdev->vi_base = ndata->aperture[0];
-
- tegra_pd_add_device(&pdev->dev);
- pm_runtime_use_autosuspend(&pdev->dev);
- pm_runtime_set_autosuspend_delay(&pdev->dev, ndata->clockgate_delay);
- pm_runtime_enable(&pdev->dev);
-
- pcdev->alloc_ctx = vb2_dma_contig_init_ctx(&pdev->dev);
- if (IS_ERR(pcdev->alloc_ctx)) {
- err = PTR_ERR(pcdev->alloc_ctx);
- goto exit_pm_disable;
- }
-
- platform_set_drvdata(pdev, pcdev);
- err = soc_camera_host_register(&pcdev->ici);
- if (IS_ERR_VALUE(err))
- goto exit_cleanup_alloc_ctx;
-
- dev_notice(&pdev->dev, "Tegra camera driver loaded.\n");
-
- return err;
-
-exit_cleanup_alloc_ctx:
- platform_set_drvdata(pdev, pcdev->ndata);
- vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
-exit_pm_disable:
- pm_runtime_disable(&pdev->dev);
-exit_put_regulator:
- regulator_put(pcdev->reg);
-exit_put_clk_emc:
- clk_put(pcdev->clk_emc);
-exit_put_clk_sclk:
- clk_put(pcdev->clk_sclk);
-exit_put_clk_csus:
- clk_put(pcdev->clk_csus);
-exit_put_clk_isp:
- clk_put(pcdev->clk_isp);
-exit_put_clk_csi:
- clk_put(pcdev->clk_csi);
-exit_put_clk_vi_sensor:
- clk_put(pcdev->clk_vi_sensor);
-exit_put_clk_vi:
- clk_put(pcdev->clk_vi);
-exit_free_pcdev:
- kfree(pcdev);
-exit:
- return err;
-}
-
-static int tegra_camera_remove(struct platform_device *pdev)
-{
- struct soc_camera_host *ici = to_soc_camera_host(&pdev->dev);
- struct tegra_camera_dev *pcdev = container_of(ici,
- struct tegra_camera_dev, ici);
-
- soc_camera_host_unregister(ici);
-
- platform_set_drvdata(pdev, pcdev->ndata);
- nvhost_client_device_release(pdev);
-
- vb2_dma_contig_cleanup_ctx(pcdev->alloc_ctx);
-
- pm_runtime_disable(&pdev->dev);
-
- regulator_put(pcdev->reg);
-
- clk_put(pcdev->clk_emc);
- clk_put(pcdev->clk_sclk);
- clk_put(pcdev->clk_csus);
- clk_put(pcdev->clk_isp);
- clk_put(pcdev->clk_csi);
- clk_put(pcdev->clk_vi_sensor);
- clk_put(pcdev->clk_vi);
-
- kfree(pcdev);
-
- dev_notice(&pdev->dev, "Tegra camera host driver unloaded\n");
-
- return 0;
-}
-
-#ifdef CONFIG_PM_FISH
-static int tegra_camera_suspend(struct platform_device *pdev,
- pm_message_t state)
-{
- struct soc_camera_host *ici = to_soc_camera_host(&pdev->dev);
- struct tegra_camera_dev *pcdev = container_of(ici,
- struct tegra_camera_dev, ici);
-
- mutex_lock(&pcdev->work_mutex);
-
- /* We only need to do something if a camera sensor is attached. */
- if (pcdev->icd) {
- /* Suspend the camera sensor. */
- WARN_ON(!pcdev->icd->ops->suspend);
- pcdev->icd->ops->suspend(pcdev->icd, state);
- }
-
- return 0;
-}
-
-static int tegra_camera_resume(struct platform_device *pdev)
-{
- struct soc_camera_host *ici = to_soc_camera_host(&pdev->dev);
- struct tegra_camera_dev *pcdev = container_of(ici,
- struct tegra_camera_dev, ici);
-
- /* We only need to do something if a camera sensor is attached. */
- if (pcdev->icd) {
- /* Resume the camera host. */
- tegra_camera_save_syncpts(pcdev);
- if (pcdev->active)
- tegra_camera_capture_setup(pcdev);
-
- /* Resume the camera sensor. */
- WARN_ON(!pcdev->icd->ops->resume);
- pcdev->icd->ops->resume(pcdev->icd);
- }
-
- mutex_unlock(&pcdev->work_mutex);
-
- return 0;
-}
-#endif
-
-static struct platform_driver tegra_camera_driver = {
- .driver = {
- .name = TEGRA_CAM_DRV_NAME,
- .owner = THIS_MODULE,
-#ifdef CONFIG_OF
- .of_match_table = tegra_vi_of_match,
-#endif
- },
- .probe = tegra_camera_probe,
- .remove = tegra_camera_remove,
-#ifdef CONFIG_PM_FISH
- .suspend = tegra_camera_suspend,
- .resume = tegra_camera_resume,
-#endif
-};
-
-
-static int __init tegra_camera_init(void)
-{
- return platform_driver_register(&tegra_camera_driver);
-}
-
-static void __exit tegra_camera_exit(void)
-{
- platform_driver_unregister(&tegra_camera_driver);
-}
-
-module_init(tegra_camera_init);
-module_exit(tegra_camera_exit);
-
-MODULE_DESCRIPTION("TEGRA SoC Camera Host driver");
-MODULE_AUTHOR("Andrew Chew <achew@nvidia.com>");
-MODULE_AUTHOR("Bryan Wu <pengw@nvidia.com>");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("nvhost:" TEGRA_CAM_DRV_NAME);
diff --git a/include/media/tegra_v4l2_camera.h b/include/media/tegra_v4l2_camera.h
index 9e4b65c362b3..7e25f97531ee 100644
--- a/include/media/tegra_v4l2_camera.h
+++ b/include/media/tegra_v4l2_camera.h
@@ -23,6 +23,9 @@
enum tegra_camera_port {
TEGRA_CAMERA_PORT_CSI_A = 1,
TEGRA_CAMERA_PORT_CSI_B,
+ TEGRA_CAMERA_PORT_CSI_C,
+ TEGRA_CAMERA_PORT_CSI_D,
+ TEGRA_CAMERA_PORT_CSI_E,
TEGRA_CAMERA_PORT_VIP,
};
diff --git a/include/uapi/linux/v4l2-mediabus.h b/include/uapi/linux/v4l2-mediabus.h
index 6ee63d09b32d..b1fedf8a5409 100644
--- a/include/uapi/linux/v4l2-mediabus.h
+++ b/include/uapi/linux/v4l2-mediabus.h
@@ -37,7 +37,7 @@
enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_FIXED = 0x0001,
- /* RGB - next is 0x100d */
+ /* RGB - next is 0x100f */
V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001,
V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003,
@@ -50,6 +50,8 @@ enum v4l2_mbus_pixelcode {
V4L2_MBUS_FMT_RGB888_1X24 = 0x100a,
V4L2_MBUS_FMT_RGB888_2X12_BE = 0x100b,
V4L2_MBUS_FMT_RGB888_2X12_LE = 0x100c,
+ V4L2_MBUS_FMT_RGBA8888_4X8_BE = 0x100d,
+ V4L2_MBUS_FMT_RGBA8888_4X8_LE = 0x100e,
/* YUV (including grey) - next is 0x2017 */
V4L2_MBUS_FMT_Y8_1X8 = 0x2001,