summaryrefslogtreecommitdiff
path: root/drivers/media/video/tegra_v4l2_camera.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/tegra_v4l2_camera.c')
-rw-r--r--drivers/media/video/tegra_v4l2_camera.c1198
1 files changed, 519 insertions, 679 deletions
diff --git a/drivers/media/video/tegra_v4l2_camera.c b/drivers/media/video/tegra_v4l2_camera.c
index 8f71d1702537..14a74cd6b7cc 100644
--- a/drivers/media/video/tegra_v4l2_camera.c
+++ b/drivers/media/video/tegra_v4l2_camera.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2012-2013, NVIDIA CORPORATION. All rights reserved.
+ * Copyright (c) 2012, 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,
@@ -14,7 +14,6 @@
* 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>
@@ -23,13 +22,14 @@
#include <linux/nvhost.h>
#include <mach/iomap.h>
-#include <mach/powergate.h>
#include <media/soc_camera.h>
#include <media/soc_mediabus.h>
#include <media/videobuf2-dma-nvmap.h>
#include <media/tegra_v4l2_camera.h>
+#include <mach/powergate.h>
+
#include "dev.h"
#include "bus_client.h"
#include "host1x/host1x_syncpt.h"
@@ -37,18 +37,22 @@
#define TEGRA_CAM_DRV_NAME "vi"
#define TEGRA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
-#define TEGRA_SYNCPT_VI_WAIT_TIMEOUT 200
+static unsigned int internal_sync = 0;
+module_param(internal_sync, int, 0644);
+MODULE_PARM_DESC(internal_sync, "enable internal vsync and hsync decoded " \
+ "from data");
+
+#define TEGRA_SYNCPT_VI_WAIT_TIMEOUT 25
#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
+#define TEGRA_VIP_H_ACTIVE_START 0x8F //0x98
+#define TEGRA_VIP_V_ACTIVE_START 0x12 //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
+#define TEGRA_VI_SYNCPT_CSI NVSYNCPT_VI_ISP_3
/* Tegra CSI-MIPI registers. */
#define TEGRA_VI_OUT_1_INCR_SYNCPT 0x0000
@@ -235,7 +239,10 @@
#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 TEGRA_CSI_MIPIBIAS_PAD_CONFIG0 0x08d4
+
+#define IS_INTERLACED ((pcdev->field == V4L2_FIELD_INTERLACED)\
+ || (pcdev->field == V4L2_FIELD_INTERLACED_BT)\
+ || (pcdev->field == V4L2_FIELD_INTERLACED_TB))
#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)
@@ -256,8 +263,6 @@
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
@@ -269,21 +274,20 @@ struct tegra_buffer {
dma_addr_t start_addr;
dma_addr_t start_addr_u;
dma_addr_t start_addr_v;
+ void* virtual_addr;
};
struct tegra_camera_dev {
struct soc_camera_host ici;
+ struct soc_camera_device *icd;
struct nvhost_device *ndev;
+ struct tegra_camera_platform_data *pdata;
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;
@@ -291,22 +295,16 @@ struct tegra_camera_dev {
struct vb2_buffer *active;
struct vb2_alloc_ctx *alloc_ctx;
enum v4l2_field field;
- int sequence_a;
- int sequence_b;
+ int sequence;
struct work_struct work;
struct mutex work_mutex;
u32 syncpt_vi;
- u32 syncpt_csi_a;
- u32 syncpt_csi_b;
+ u32 syncpt_csi;
/* Debug */
int num_frames;
- int enable_refcnt;
-
- /* CSI pad calibration flag */
- int cal_done;
};
static const struct soc_mbus_pixelfmt tegra_camera_formats[] = {
@@ -352,23 +350,6 @@ static const struct soc_mbus_pixelfmt tegra_camera_formats[] = {
.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)
@@ -378,13 +359,9 @@ static struct tegra_buffer *to_tegra_vb(struct vb2_buffer *vb)
static void tegra_camera_save_syncpts(struct tegra_camera_dev *pcdev)
{
- pcdev->syncpt_csi_a =
+ pcdev->syncpt_csi =
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);
+ TEGRA_VI_SYNCPT_CSI);
pcdev->syncpt_vi =
nvhost_syncpt_read_ext(pcdev->ndev,
@@ -394,65 +371,60 @@ static void tegra_camera_save_syncpts(struct tegra_camera_dev *pcdev)
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);
+ TEGRA_VI_SYNCPT_CSI);
nvhost_syncpt_cpu_incr_ext(pcdev->ndev,
TEGRA_VI_SYNCPT_VI);
}
-static void tegra_camera_capture_clean(struct tegra_camera_dev *pcdev)
+static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev,
+ int input_format,
+ int yuv_input_format)
{
- TC_VI_REG_WT(pcdev, TEGRA_CSI_VI_INPUT_STREAM_CONTROL, 0x00000000);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_HOST_INPUT_STREAM_CONTROL, 0x00000000);
+ struct soc_camera_device *icd = pcdev->icd;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
- 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_VI_VI_CORE_CONTROL, 0x02000000);
- 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_VI_VI_INPUT_CONTROL,
+ (yuv_input_format << 8) |
+ (input_format << 2));
- 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);
-}
+ TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000004);
+ TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000004);
-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);
+ /* 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));
+ /* CSI A */
+ 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_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_CIL_PAD_CONFIG, 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);
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000);
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000);
- /* 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));
+ /* pad1s enabled, virtual channel ID 00 */
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_A_CONTROL0,
+ (0x1 << 16) | /* Output 1 pixel per clock */
+ (0x1e << 8) | /* If hdr shows wrong fmt, use YUV422 */
+ (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_PIXEL_STREAM_A_CONTROL1,
0x1); /* Frame # for top field detect for interlaced */
@@ -466,27 +438,22 @@ static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev,
(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));
+ (pcdev->pdata->lanes - 1));
/* Use 0x00000022 for continuous clock mode. */
TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILA_CONTROL0,
- (pdata->continuous_clk << 5) |
+ (pcdev->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);
+ TEGRA_VI_SYNCPT_CSI);
+
+ 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_CSI_PHY_CIL_COMMAND, 0x00020001);
@@ -494,37 +461,49 @@ static void tegra_camera_capture_setup_csi_a(struct tegra_camera_dev *pcdev,
}
static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev,
- struct soc_camera_device *icd,
- u32 hdr)
+ int input_format,
+ int yuv_input_format)
{
- struct tegra_camera_platform_data *pdata = icd->link->priv;
+ struct soc_camera_device *icd = pcdev->icd;
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_CORE_CONTROL, 0x04000000);
+
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_INPUT_CONTROL,
+ (yuv_input_format << 8) |
+ (input_format << 2));
+
+ TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000008);
+ TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000008);
+
+ /* 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));
+
+ /* CSI B */
+ 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_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_CIL_PAD_CONFIG, 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));
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_CIL_MIPI_CAL_STATUS, 0x00000000);
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_CLKEN_OVERRIDE, 0x00000000);
- /* pad 0s enabled, virtual channel ID 00 */
+ /* pad1s 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 */
+ (0x1e << 8) | /* If hdr shows wrong fmt, use YUV422 */
(0x1 << 7) | /* Check header CRC */
(0x1 << 6) | /* Use word count field in the header */
(0x1 << 5) | /* Look at data identifier byte in hdr */
@@ -545,16 +524,20 @@ static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev,
TC_VI_REG_WT(pcdev, TEGRA_CSI_INPUT_STREAM_B_CONTROL,
(0x3f << 16) | /* Skip packet threshold */
- (pdata->lanes - 1));
+ (pcdev->pdata->lanes - 1));
/* Use 0x00000022 for continuous clock mode. */
TC_VI_REG_WT(pcdev, TEGRA_CSI_PHY_CILB_CONTROL0,
- (pdata->continuous_clk << 5) |
+ (pcdev->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);
+ TEGRA_VI_SYNCPT_CSI);
+
+ 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_CSI_PHY_CIL_COMMAND, 0x00010002);
@@ -562,17 +545,22 @@ static void tegra_camera_capture_setup_csi_b(struct tegra_camera_dev *pcdev,
}
static void tegra_camera_capture_setup_vip(struct tegra_camera_dev *pcdev,
- struct soc_camera_device *icd,
- u32 input_control)
+ int input_format,
+ int yuv_input_format)
{
+ struct soc_camera_device *icd = pcdev->icd;
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 << 27) | /* field detect */
+ (0 << 28) | /* 1 == top field is even field, 00 == odd */
+ ((internal_sync == 1) << 25) | /* 1 == hsync/vsync decoded
+ internally from data
+ (BT.656) */
+ (yuv_input_format << 8) |
(1 << 1) | /* VIP_INPUT_ENABLE */
- input_control);
+ (input_format << 2));
TC_VI_REG_WT(pcdev, TEGRA_VI_H_DOWNSCALE_CONTROL, 0x00000000);
TC_VI_REG_WT(pcdev, TEGRA_VI_V_DOWNSCALE_CONTROL, 0x00000000);
@@ -580,180 +568,80 @@ static void tegra_camera_capture_setup_vip(struct tegra_camera_dev *pcdev,
/* 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);
+ (TEGRA_VIP_H_ACTIVE_START - ((internal_sync == 1)?1:0)));
TC_VI_REG_WT(pcdev, TEGRA_VI_VIP_V_ACTIVE,
- (icd->user_height << 16) |
+ ( ( IS_INTERLACED ? (icd->user_height/2) : (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_PIN_INPUT_ENABLE, 0x000003fc | 0x6000); // D2..D9 + VSYNC + HSYNC
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,
+ 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_CAMERA_CONTROL, 0x00000004);
+// 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)
+static void tegra_camera_capture_setup(struct tegra_camera_dev *pcdev)
{
- 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);
+ struct soc_camera_device *icd = pcdev->icd;
const struct soc_camera_format_xlate *current_fmt = icd->current_fmt;
+ enum v4l2_mbus_pixelcode input_code = current_fmt->code;
u32 output_fourcc = current_fmt->host_fmt->fourcc;
- u32 output_format, output_control;
- struct tegra_buffer *buf = to_tegra_vb(pcdev->active);
+ int yuv_input_format = 0x0;
+ int input_format = 0x0; /* Default to YUV422 */
+ int yuv_output_format = 0x0;
+ int output_format = 0x3; /* Default to YUV422 */
+ int port = pcdev->pdata->port;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ int frame_count = 1;
+
+ switch (input_code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ yuv_input_format = 0x2;
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ yuv_input_format = 0x3;
+ break;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ yuv_input_format = 0x0;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ yuv_input_format = 0x1;
+ break;
+ default:
+ BUG_ON(1);
+ }
switch (output_fourcc) {
case V4L2_PIX_FMT_UYVY:
- output_format = 0x3; /* Default to YUV422 */
+ yuv_output_format = 0x0;
break;
case V4L2_PIX_FMT_VYUY:
- output_format = (0x1 << 17) | 0x3;
+ yuv_output_format = 0x1;
break;
case V4L2_PIX_FMT_YUYV:
- output_format = (0x2 << 17) | 0x3;
+ yuv_output_format = 0x2;
break;
case V4L2_PIX_FMT_YVYU:
- output_format = (0x3 << 17) | 0x3;
+ yuv_output_format = 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;
+ BUG_ON(1);
}
- 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;
- }
+ BUG_ON(!tegra_camera_port_is_valid(port));
/*
* Set up low pass filter. Use 0x240 for chromaticity and 0x240
@@ -765,25 +653,98 @@ static int tegra_camera_capture_setup(struct tegra_camera_dev *pcdev)
/* 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);
+ tegra_camera_capture_setup_csi_a(pcdev, input_format,
+ yuv_input_format);
else if (port == TEGRA_CAMERA_PORT_CSI_B)
- tegra_camera_capture_setup_csi_b(pcdev, icd, hdr);
+ tegra_camera_capture_setup_csi_b(pcdev, input_format,
+ yuv_input_format);
else
- tegra_camera_capture_setup_vip(pcdev, icd, input_control);
+ tegra_camera_capture_setup_vip(pcdev, input_format,
+ yuv_input_format);
+
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_FIRST_OUTPUT_CONTROL,
+ (pcdev->pdata->flip_v ? (0x1 << 20) : 0) |
+ (pcdev->pdata->flip_h ? (0x1 << 19) : 0) |
+ (yuv_output_format << 17) |
+ output_format);
+
+ // if the video is interlaced, then take two frames
+ frame_count = IS_INTERLACED ? 2 : 1;
+
+ /*
+ * 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/frame_count) << 16) | icd->user_width);
+
+ /* Set the number of frames in the buffer. */
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_COUNT_FIRST, frame_count);
+
+ /* Set up buffer frame size. */
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_SIZE_FIRST,
+ ((icd->user_height/frame_count) << 16) | icd->user_width);
+ if(output_fourcc == V4L2_PIX_FMT_YUV420 || output_fourcc == V4L2_PIX_FMT_YVU420) {
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
+ ((icd->user_height/frame_count) * icd->user_width) | (2<<30));
+ }
+ else {
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VB0_BUFFER_STRIDE_FIRST,
+ ((icd->user_height/frame_count) * bytes_per_line) | (2<<30));
+ }
+
+ /* First output memory enabled */
+ TC_VI_REG_WT(pcdev, TEGRA_VI_VI_ENABLE, 0x00000000);
- /* 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)
+//
+// make_interlaced
+//
+// make one interlaced frame out of two frames in the buffer @ addr
+// this function must be issued for Y, U and V buffers.
+//
+static void make_interlaced(uint8_t * addr, int width, int height) {
+ uint8_t starting_line_buf[width];
+ bool lines[height];
+ int i;
+ int destination_line, starting_line;
+ for (i = 1; i < height-1; i++) lines[i] = false;
+ lines[0] = true;
+ lines[height-1] = true;
+
+ #define real_line(i) ( (i % 2) ? ((i / 2) + (height/2)) : (i / 2) )
+ while (1) {
+ starting_line = -1;
+ for (i = 1; i < ((height)-1); i++) if (!lines[i]) {
+ starting_line = i;
+ break;
+ }
+ if (starting_line == -1) break; // all is done
+
+ memcpy(starting_line_buf, (void*) ((unsigned int)(addr) + (width*starting_line)), width);
+ destination_line = starting_line;
+ while (1) {
+ lines[destination_line] = true;
+ if (real_line(destination_line) == starting_line) {
+ memcpy(addr + width * destination_line, starting_line_buf, width);
+ break;
+ }
+ memcpy(addr + (width * destination_line), (void*) ((unsigned int)(addr) + (width * real_line(destination_line))), width);
+ destination_line = real_line(destination_line);
+ }
+ }
+}
+
+static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev,
+ struct tegra_buffer *buf)
{
- struct soc_camera_device *icd = buf->icd;
+ struct soc_camera_device *icd = pcdev->icd;
+ int port = pcdev->pdata->port;
+ int err;
+ int bytes_per_line;
+ uint8_t *src;
switch (icd->current_fmt->host_fmt->fourcc) {
case V4L2_PIX_FMT_YUV420:
@@ -802,90 +763,87 @@ static int tegra_camera_capture_buffer_setup(struct tegra_camera_dev *pcdev,
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;
+ 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);
+
+ break;
default:
- dev_err(&pcdev->ndev->dev, "Wrong host format %d\n",
- icd->current_fmt->host_fmt->fourcc);
- return -EINVAL;
+ BUG_ON(1);
}
- return 0;
-}
+ BUG_ON(!tegra_camera_port_is_valid(port));
-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;
+ if (port == TEGRA_CAMERA_PORT_CSI_A)
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
+ 0x0000f005);
+ else if (port == TEGRA_CAMERA_PORT_CSI_B)
+ TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
+ 0x0000f005);
+ else
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL,
+ 0x00000005); // start & stop
- 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);
- } else if (port == TEGRA_CAMERA_PORT_CSI_B) {
- pcdev->syncpt_csi_b++;
- TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPB_COMMAND,
- 0x0000f005);
+
+ pcdev->syncpt_vi++;
+ pcdev->syncpt_csi++;
+
+ if (tegra_camera_port_is_csi(port))
err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_CSI_B,
- pcdev->syncpt_csi_b,
- TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
- NULL);
- } else {
- pcdev->syncpt_vi++;
- TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL,
- 0x00000001);
+ TEGRA_VI_SYNCPT_CSI,
+ pcdev->syncpt_csi,
+ TEGRA_SYNCPT_CSI_WAIT_TIMEOUT,
+ NULL);
+ else
err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
- TEGRA_VI_SYNCPT_VI,
- pcdev->syncpt_csi_a,
- TEGRA_SYNCPT_VI_WAIT_TIMEOUT,
- NULL);
- }
+ TEGRA_VI_SYNCPT_VI,
+ pcdev->syncpt_vi,
+ TEGRA_SYNCPT_VI_WAIT_TIMEOUT,
+ NULL);
- if (!err)
- return 0;
+ if (IS_INTERLACED) {
+
+ TC_VI_REG_WT(pcdev, TEGRA_VI_CAMERA_CONTROL,
+ 0x00000005); // start & stop
+
+ pcdev->syncpt_vi++;
+ pcdev->syncpt_csi++;
+
+ err = nvhost_syncpt_wait_timeout_ext(pcdev->ndev,
+ TEGRA_VI_SYNCPT_VI,
+ pcdev->syncpt_vi,
+ TEGRA_SYNCPT_VI_WAIT_TIMEOUT,
+ NULL);
+
+ src = (uint8_t*)(buf->virtual_addr);
+ if(icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_YUV420 || icd->current_fmt->host_fmt->fourcc == V4L2_PIX_FMT_YVU420 ) {
+ make_interlaced(src, icd->user_width, icd->user_height); // Y
+ make_interlaced(src + icd->user_width * icd->user_height, icd->user_width, icd->user_height/4); // U
+ make_interlaced(src + icd->user_width * icd->user_height + (icd->user_width * icd->user_height)/4, icd->user_width, icd->user_height/4); // V
+ }
+ else {
+ bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ make_interlaced(src, bytes_per_line, icd->user_height); // Y
+ }
+ }
+
+ 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",
+ dev_err(&pcdev->ndev->dev, "Timeout on CSI syncpt\n");
+ dev_err(&pcdev->ndev->dev, "buffer_addr = 0x%08x\n",
buf->buffer_addr);
ppstatus = TC_VI_REG_RD(pcdev,
@@ -895,7 +853,7 @@ static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev,
rostatus = TC_VI_REG_RD(pcdev,
TEGRA_CSI_CSI_READONLY_STATUS);
- dev_warn(&icd->vdev->dev,
+ dev_err(&pcdev->ndev->dev,
"PPSTATUS = 0x%08x, "
"CILSTATUS = 0x%08x, "
"ROSTATUS = 0x%08x\n",
@@ -903,14 +861,14 @@ static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev,
} 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",
+ dev_err(&pcdev->ndev->dev, "Timeout on VI syncpt\n");
+ dev_err(&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,
+ dev_err(&pcdev->ndev->dev,
"VIP_INPUT_STATUS = 0x%08x\n",
vip_input_status);
}
@@ -918,10 +876,12 @@ static int tegra_camera_capture_start(struct tegra_camera_dev *pcdev,
return err;
}
-static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port)
+static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev)
{
+ int port = pcdev->pdata->port;
int err;
- struct tegra_buffer *buf = to_tegra_vb(pcdev->active);
+
+ BUG_ON(!tegra_camera_port_is_valid(port));
if (port == TEGRA_CAMERA_PORT_CSI_A)
TC_VI_REG_WT(pcdev, TEGRA_CSI_PIXEL_STREAM_PPA_COMMAND,
@@ -929,9 +889,9 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port)
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);
+// 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,
@@ -947,28 +907,17 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port)
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,
+ dev_err(&pcdev->ndev->dev, "Timeout on VI syncpt\n");
+ 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",
+ dev_err(&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,
+ dev_err(&pcdev->ndev->dev,
"PPSTATUS = 0x%08x, CILSTATUS = 0x%08x\n",
ppstatus, cilstatus);
}
@@ -976,132 +925,81 @@ static int tegra_camera_capture_stop(struct tegra_camera_dev *pcdev, int port)
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);
-
- /* Unpowergate VE */
- tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
-
- /* Turn on relevant clocks. */
- clk_set_rate(pcdev->clk_vi, 150000000);
- clk_enable(pcdev->clk_vi);
- clk_set_rate(pcdev->clk_vi_sensor, 24000000);
- clk_enable(pcdev->clk_vi_sensor);
- clk_enable(pcdev->clk_csi);
- clk_enable(pcdev->clk_isp);
- clk_enable(pcdev->clk_csus);
- clk_set_rate(pcdev->clk_sclk, 80000000);
- clk_enable(pcdev->clk_sclk);
- clk_set_rate(pcdev->clk_sclk, 375000000);
- clk_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(pcdev->clk_vi);
- clk_disable(pcdev->clk_vi_sensor);
- clk_disable(pcdev->clk_csi);
- clk_disable(pcdev->clk_isp);
- clk_disable(pcdev->clk_csus);
- clk_disable(pcdev->clk_sclk);
- clk_disable(pcdev->clk_emc);
-
- /* Powergate VE */
- tegra_powergate_partition(TEGRA_POWERGATE_VENC);
-
- /* Disable external power */
- regulator_disable(pcdev->reg);
-
- nvhost_module_idle_ext(pcdev->ndev);
-
- pcdev->cal_done = 0;
-}
-
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;
+ struct vb2_buffer *vb;
+ struct tegra_buffer *buf;
int retry = TEGRA_SYNCPT_RETRY_COUNT;
- int err;
+ int port = pcdev->pdata->port;
+ int err = 0;
- 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);
- }
+ if (!pcdev->active)
+ return 0;
- tegra_camera_incr_syncpts(pcdev);
- tegra_camera_save_syncpts(pcdev);
+ vb = pcdev->active;
+ buf = to_tegra_vb(vb);
- continue;
+ while (retry--) {
+ err = tegra_camera_capture_start(pcdev, buf);
+ if (err == 0) {
+ err = tegra_camera_capture_stop(pcdev);
+ if (err == 0) break;
}
- break;
- }
+ /* 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);
+ }
- /* 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);
+ tegra_camera_incr_syncpts(pcdev);
+ tegra_camera_save_syncpts(pcdev);
+ continue;
}
spin_lock_irq(&pcdev->videobuf_queue_lock);
+ /*
+ * If vb->state is VB2_BUF_STATE_ERROR, then the vb has already been
+ * removed, so we shouldn't remove it again.
+ */
+ if (vb->state != VB2_BUF_STATE_ERROR)
+ list_del_init(&buf->queue);
+
+ if (!list_empty(&pcdev->capture))
+ pcdev->active = &list_entry(pcdev->capture.next,
+ struct tegra_buffer, queue)->vb;
+ else
+ pcdev->active = NULL;
+
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++;
+ vb->v4l2_buf.sequence = pcdev->sequence++;
- vb2_buffer_done(vb, err < 0 ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
- list_del_init(&buf->queue);
+ vb2_buffer_done(vb, (err != 0) ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
pcdev->num_frames++;
@@ -1110,145 +1008,101 @@ static int tegra_camera_capture_frame(struct tegra_camera_dev *pcdev)
return err;
}
-static int tegra_camera_csi_pad_calibration(struct tegra_camera_dev *pcdev)
+static void tegra_camera_work(struct work_struct *work)
{
- 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 = 500;
- u32 data;
- int err = -EINVAL;
-
- TC_VI_REG_WT(pcdev, TEGRA_CSI_DSI_MIPI_CAL_CONFIG, 0x40300);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_MIPIBIAS_PAD_CONFIG0, 0x50700);
-
- if (port == TEGRA_CAMERA_PORT_CSI_B || pdata->lanes == 4)
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x200004);
-
- data = 0x2a000004;
- if (port == TEGRA_CAMERA_PORT_CSI_A)
- data |= 0x200000; /* MIPI_CAL_SELA */
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, data);
-
- /* Start calibration */
- data |= 0x80000000;
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, data);
+ struct tegra_camera_dev *pcdev =
+ container_of(work, struct tegra_camera_dev, work);
- while (retry--) {
- data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS);
- if ((data & 0x8000) == 0x8000)
- break;
- udelay(20);
- }
- if (!retry) {
- dev_warn(&pcdev->ndev->dev, "MIPI calibration timeout!\n");
- goto cal_out;
- }
+ mutex_lock(&pcdev->work_mutex);
- /* Clear status */
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, data);
- retry = 500;
- while (retry--) {
- data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS);
- if ((data & 0x8000) == 0x0)
- break;
- udelay(20);
- }
+ while (pcdev->active)
+ tegra_camera_capture_frame(pcdev);
- if (!retry) {
- dev_warn(&pcdev->ndev->dev,
- "Clear MIPI calibration status timeout!\n");
- goto cal_out;
- }
+ mutex_unlock(&pcdev->work_mutex);
+}
- data = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_PIXEL_PARSER_STATUS);
- err = TC_VI_REG_RD(pcdev, TEGRA_CSI_CSI_CIL_STATUS);
- if (data | err) {
- dev_warn(&pcdev->ndev->dev,
- "Calibration status not be cleared!\n");
- err = -EINVAL;
- goto cal_out;
- }
+static void tegra_camera_activate(struct tegra_camera_dev *pcdev)
+{
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ u32 val;
+ void __iomem *apb_misc;
+#endif
- /* Calibration succeed */
- err = 0;
+ nvhost_module_busy_ext(pcdev->ndev);
-cal_out:
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CSI_CIL_STATUS, data);
+#ifndef CONFIG_ARCH_TEGRA_2x_SOC
+ if(!tegra_powergate_is_powered(TEGRA_POWERGATE_VENC))
+ tegra_unpowergate_partition(TEGRA_POWERGATE_VENC);
+#endif
- /* un-select to avoid interference with DSI */
- if (port == TEGRA_CAMERA_PORT_CSI_B || pdata->lanes == 4)
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILB_MIPI_CAL_CONFIG, 0x4);
+ /* Turn on relevant clocks. */
+ clk_enable(pcdev->clk_vi);
+ clk_enable(pcdev->clk_vi_sensor);
+ clk_enable(pcdev->clk_csi);
+ clk_enable(pcdev->clk_isp);
+ clk_enable(pcdev->clk_csus);
- TC_VI_REG_WT(pcdev, TEGRA_CSI_CILA_MIPI_CAL_CONFIG, 0x2a000004);
+#ifdef CONFIG_ARCH_TEGRA_2x_SOC
+ apb_misc = IO_ADDRESS(TEGRA_APB_MISC_BASE);
+ val = readl(apb_misc + 0x42c);
+ writel(val | 0x1, apb_misc + 0x42c);
+#endif
- return err;
+ /* Save current syncpt values. */
+ tegra_camera_save_syncpts(pcdev);
}
-static void tegra_camera_work(struct work_struct *work)
+static void tegra_camera_deactivate(struct tegra_camera_dev *pcdev)
{
- struct tegra_camera_dev *pcdev =
- container_of(work, struct tegra_camera_dev, work);
- struct tegra_buffer *buf;
+ mutex_lock(&pcdev->work_mutex);
- 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;
- }
+ /* Cancel active buffer. */
+ if (pcdev->active) {
+ list_del_init(&to_tegra_vb(pcdev->active)->queue);
+ vb2_buffer_done(pcdev->active, VB2_BUF_STATE_ERROR);
+ pcdev->active = NULL;
+ }
- buf = list_entry(pcdev->capture.next, struct tegra_buffer,
- queue);
- pcdev->active = &buf->vb;
- spin_unlock_irq(&pcdev->videobuf_queue_lock);
+ mutex_unlock(&pcdev->work_mutex);
- tegra_camera_capture_setup(pcdev);
- if (!pcdev->cal_done) {
- tegra_camera_csi_pad_calibration(pcdev);
- pcdev->cal_done = 1;
- }
- tegra_camera_capture_frame(pcdev);
+ /* Turn off relevant clocks. */
+ clk_disable(pcdev->clk_vi);
+ clk_disable(pcdev->clk_vi_sensor);
+ clk_disable(pcdev->clk_csi);
+ clk_disable(pcdev->clk_isp);
+ clk_disable(pcdev->clk_csus);
+
+ nvhost_module_idle_ext(pcdev->ndev);
- mutex_unlock(&pcdev->work_mutex);
- }
}
-static int tegra_camera_init_buffer(struct tegra_buffer *buf)
+static void tegra_camera_init_buffer(struct tegra_camera_dev *pcdev,
+ struct tegra_buffer *buf)
{
- struct soc_camera_device *icd = buf->icd;
+ struct soc_camera_device *icd = pcdev->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;
+ buf->buffer_addr = vb2_dma_nvmap_plane_paddr(&buf->vb, 0); // physical addr
+ buf->virtual_addr = vb2_plane_vaddr(&buf->vb, 0); // save virtual addr for later interlace handling
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_nvmap_plane_paddr(&buf->vb, 0);
buf->start_addr = buf->buffer_addr;
- if (pdata->flip_v)
+ if (pcdev->pdata->flip_v)
buf->start_addr += bytes_per_line *
(icd->user_height-1);
- if (pdata->flip_h)
+ if (pcdev->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_nvmap_plane_paddr(&buf->vb, 0);
buf->buffer_addr_u = buf->buffer_addr +
icd->user_width * icd->user_height;
buf->buffer_addr_v = buf->buffer_addr_u +
@@ -1265,7 +1119,7 @@ static int tegra_camera_init_buffer(struct tegra_buffer *buf)
buf->start_addr_u = buf->buffer_addr_u;
buf->start_addr_v = buf->buffer_addr_v;
- if (pdata->flip_v) {
+ if (pcdev->pdata->flip_v) {
buf->start_addr += icd->user_width *
(icd->user_height - 1);
@@ -1276,7 +1130,7 @@ static int tegra_camera_init_buffer(struct tegra_buffer *buf)
((icd->user_height/2) - 1));
}
- if (pdata->flip_h) {
+ if (pcdev->pdata->flip_h) {
buf->start_addr += icd->user_width - 1;
buf->start_addr_u += (icd->user_width/2) - 1;
@@ -1287,12 +1141,8 @@ static int tegra_camera_init_buffer(struct tegra_buffer *buf)
break;
default:
- dev_err(icd->parent, "Wrong host format %d\n",
- icd->current_fmt->host_fmt->fourcc);
- return -EINVAL;
+ BUG_ON(1);
}
-
- return 0;
}
/*
@@ -1307,7 +1157,6 @@ static int tegra_camera_videobuf_setup(struct vb2_queue *vq,
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,
@@ -1320,16 +1169,20 @@ static int tegra_camera_videobuf_setup(struct vb2_queue *vq,
*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;
+ pcdev->sequence = 0;
sizes[0] = bytes_per_line * icd->user_height;
alloc_ctxs[0] = pcdev->alloc_ctx;
if (!*num_buffers)
*num_buffers = 2;
+ dev_dbg(icd->parent, "num_buffers=%u, size=%lu\n",
+ *num_buffers, sizes[0]);
+
+ tegra_camera_capture_setup(pcdev);
+
+ dev_dbg(icd->parent, "Finished tegra_camera_videobuf_setup()\n");
+
return 0;
}
@@ -1338,8 +1191,9 @@ 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;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
+ struct tegra_camera_dev *pcdev = ici->priv;
+ struct tegra_buffer *buf;
int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
icd->current_fmt->host_fmt);
unsigned long size;
@@ -1349,19 +1203,7 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb)
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;
- }
+ 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_plane_size(vb, 0));
@@ -1375,10 +1217,7 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb)
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;
- }
+ BUG_ON(NULL == icd->current_fmt);
size = icd->user_height * bytes_per_line;
@@ -1390,7 +1229,11 @@ static int tegra_camera_videobuf_prepare(struct vb2_buffer *vb)
vb2_set_plane_payload(vb, 0, size);
- return tegra_camera_init_buffer(buf);
+ tegra_camera_init_buffer(pcdev, buf);
+
+ dev_dbg(icd->parent, "Finished tegra_camera_videobuf_prepare()\n");
+
+ return 0;
}
static void tegra_camera_videobuf_queue(struct vb2_buffer *vb)
@@ -1402,12 +1245,18 @@ static void tegra_camera_videobuf_queue(struct vb2_buffer *vb)
struct tegra_camera_dev *pcdev = ici->priv;
struct tegra_buffer *buf = to_tegra_vb(vb);
+ dev_dbg(icd->parent, "In tegra_camera_videobuf_queue()\n");
+
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);
+
+ if (!pcdev->active) {
+ pcdev->active = vb;
+ schedule_work(&pcdev->work);
+ }
spin_unlock_irq(&pcdev->videobuf_queue_lock);
dev_dbg(icd->parent, "Finished tegra_camera_videobuf_queue()\n");
@@ -1462,24 +1311,16 @@ static int tegra_camera_stop_streaming(struct vb2_queue *q)
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;
- }
+ pcdev->active = NULL;
+
+ list_for_each_safe(buf_head, tmp, &pcdev->capture)
+ list_del_init(buf_head);
+
+ spin_unlock_irq(&pcdev->videobuf_queue_lock);
mutex_unlock(&pcdev->work_mutex);
@@ -1524,13 +1365,24 @@ 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;
+ int err;
- if (!pcdev->enable_refcnt) {
- pm_runtime_get_sync(ici->v4l2_dev.dev);
- tegra_camera_activate(pcdev);
- pcdev->num_frames = 0;
+ if (pcdev->icd)
+ return -EBUSY;
+
+ pm_runtime_get_sync(ici->v4l2_dev.dev);
+
+ if (pcdev->pdata->enable_camera) {
+ err = pcdev->pdata->enable_camera(pcdev->ndev);
+ if (IS_ERR_VALUE(err))
+ return err;
}
- pcdev->enable_refcnt++;
+
+ tegra_camera_activate(pcdev);
+
+ pcdev->icd = icd;
+
+ pcdev->num_frames = 0;
dev_dbg(icd->parent, "TEGRA Camera host attached to camera %d\n",
icd->devnum);
@@ -1544,12 +1396,14 @@ 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);
- }
+ tegra_camera_deactivate(pcdev);
+
+ pcdev->icd = NULL;
+
+ if (pcdev->pdata->disable_camera)
+ pcdev->pdata->disable_camera(pcdev->ndev);
+
+ pm_runtime_put_sync(ici->v4l2_dev.dev);
dev_dbg(icd->parent, "Frames captured: %d\n", pcdev->num_frames);
@@ -1591,8 +1445,6 @@ static int tegra_camera_get_formats(struct soc_camera_device *icd,
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));
@@ -1721,6 +1573,15 @@ static int tegra_camera_try_fmt(struct soc_camera_device *icd,
case V4L2_FIELD_NONE:
pix->field = V4L2_FIELD_NONE;
break;
+ case V4L2_FIELD_INTERLACED_BT:
+ pix->field = V4L2_FIELD_INTERLACED_BT;
+ break;
+ case V4L2_FIELD_INTERLACED_TB:
+ pix->field = V4L2_FIELD_INTERLACED_TB;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ pix->field = V4L2_FIELD_INTERLACED;
+ break;
default:
/* TODO: support interlaced at least in pass-through mode */
dev_err(icd->parent, "Field type %d unsupported.\n",
@@ -1785,7 +1646,8 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev,
goto exit;
}
- pcdev->ndev = ndev;
+ pcdev->pdata = ndev->dev.platform_data;
+ pcdev->ndev = ndev;
pcdev->ici.priv = pcdev;
pcdev->ici.v4l2_dev.dev = &ndev->dev;
@@ -1798,6 +1660,14 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev,
spin_lock_init(&pcdev->videobuf_queue_lock);
mutex_init(&pcdev->work_mutex);
+ nvhost_set_drvdata(ndev, pcdev);
+
+ if (!tegra_camera_port_is_valid(pcdev->pdata->port)) {
+ dev_err(&ndev->dev, "Invalid camera port %d in platform data\n",
+ pcdev->pdata->port);
+ goto exit_free_pcdev;
+ }
+
pcdev->clk_vi = clk_get_sys("tegra_camera", "vi");
if (IS_ERR_OR_NULL(pcdev->clk_vi)) {
dev_err(&ndev->dev, "Failed to get vi clock.\n");
@@ -1827,48 +1697,16 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev,
dev_err(&ndev->dev, "Failed to get csus clock.\n");
goto exit_put_clk_isp;
}
-
- pcdev->clk_sclk = clk_get_sys("tegra_camera", "sclk");
- if (IS_ERR_OR_NULL(pcdev->clk_sclk)) {
- dev_err(&ndev->dev, "Failed to get sclk clock.\n");
- goto exit_put_clk_csus;
- }
-
- pcdev->clk_emc = clk_get_sys("tegra_camera", "emc");
- if (IS_ERR_OR_NULL(pcdev->clk_emc)) {
- dev_err(&ndev->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(&ndev->dev, "vcsi");
-#else
- pcdev->reg = regulator_get(&ndev->dev, "avdd_dsi_csi");
-#endif
- if (IS_ERR_OR_NULL(pcdev->reg)) {
- dev_err(&ndev->dev, "%s: couldn't get regulator\n",
- __func__);
- goto exit_put_clk_emc;
- }
-
- nvhost_set_drvdata(ndev, pcdev);
err = nvhost_client_device_get_resources(ndev);
- if (err) {
- dev_err(&ndev->dev, "%s: nvhost get resources failed %d\n",
- __func__, err);
- goto exit_put_regulator;
- }
+ if (err)
+ goto exit_put_clk_csus;
- err = nvhost_client_device_init(ndev);
- if (err) {
- dev_err(&ndev->dev, "%s: nvhost init failed %d\n",
- __func__, err);
- goto exit_put_regulator;
- }
+ // initialize nvhost client device only the first time
+ if (ndev->power_attrib == NULL)
+ nvhost_client_device_init(ndev);
pcdev->vi_base = ndev->aperture;
@@ -1876,10 +1714,10 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev,
pm_runtime_enable(&ndev->dev);
pm_runtime_resume(&ndev->dev);
- pcdev->alloc_ctx = vb2_dma_nvmap_init_ctx(&ndev->dev);
+ pcdev->alloc_ctx = vb2_dma_nvmap_init_ctx(pcdev->ici.v4l2_dev.dev);
if (IS_ERR(pcdev->alloc_ctx)) {
err = PTR_ERR(pcdev->alloc_ctx);
- goto exit_pm_disable;
+ goto exit_put_resources;
}
err = soc_camera_host_register(&pcdev->ici);
@@ -1892,15 +1730,9 @@ static int __devinit tegra_camera_probe(struct nvhost_device *ndev,
exit_cleanup_alloc_ctx:
vb2_dma_nvmap_cleanup_ctx(pcdev->alloc_ctx);
-exit_pm_disable:
+exit_put_resources:
pm_runtime_disable(&ndev->dev);
nvhost_client_device_put_resources(ndev);
-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:
@@ -1963,6 +1795,11 @@ static int tegra_camera_suspend(struct nvhost_device *ndev, pm_message_t state)
/* Suspend the camera sensor. */
WARN_ON(!pcdev->icd->ops->suspend);
pcdev->icd->ops->suspend(pcdev->icd, state);
+
+ /* Power off the camera subsystem. */
+ pcdev->pdata->disable_camera(pcdev->ndev);
+
+ nvhost_module_idle_ext(nvhost_get_parent(ndev));
}
return 0;
@@ -1976,10 +1813,14 @@ static int tegra_camera_resume(struct nvhost_device *ndev)
/* We only need to do something if a camera sensor is attached. */
if (pcdev->icd) {
+ nvhost_module_busy_ext(nvhost_get_parent(ndev));
+
+ /* Power on the camera subsystem. */
+ pcdev->pdata->enable_camera(pcdev->ndev);
+
/* Resume the camera host. */
tegra_camera_save_syncpts(pcdev);
- if (pcdev->active)
- tegra_camera_capture_setup(pcdev);
+ tegra_camera_capture_setup(pcdev);
/* Resume the camera sensor. */
WARN_ON(!pcdev->icd->ops->resume);
@@ -2021,6 +1862,5 @@ 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);