summaryrefslogtreecommitdiff
path: root/drivers/media/sprd_dcam
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
committerYuval Adam <_@yuv.al>2017-08-30 08:25:59 +0000
commit8e4bff4cab0ddac6060645b0715210484d02ff40 (patch)
tree3a5c3024371a04692a3a6d9974d001cdff8ebf84 /drivers/media/sprd_dcam
Initial file dump from open source releaseHEADmaster
Diffstat (limited to 'drivers/media/sprd_dcam')
-rw-r--r--drivers/media/sprd_dcam/Kconfig48
-rwxr-xr-xdrivers/media/sprd_dcam/Makefile26
-rw-r--r--drivers/media/sprd_dcam/common/Makefile.inc15
-rwxr-xr-xdrivers/media/sprd_dcam/common/dcam_img.c3779
-rw-r--r--drivers/media/sprd_dcam/common/flash_test.c115
-rw-r--r--drivers/media/sprd_dcam/common/flash_test.h38
-rw-r--r--drivers/media/sprd_dcam/common/gen_scale_coef.c699
-rw-r--r--drivers/media/sprd_dcam/common/gen_scale_coef.h34
-rwxr-xr-xdrivers/media/sprd_dcam/common/parse_hwinfo.c353
-rwxr-xr-xdrivers/media/sprd_dcam/common/parse_hwinfo.h72
-rw-r--r--drivers/media/sprd_dcam/common/parse_hwinfo_tshark2.h47
-rw-r--r--drivers/media/sprd_dcam/common/sin_cos.c270
-rw-r--r--drivers/media/sprd_dcam/common/sin_cos.h74
-rwxr-xr-xdrivers/media/sprd_dcam/flash/Makefile82
-rw-r--r--drivers/media/sprd_dcam/flash/flash.h22
-rw-r--r--drivers/media/sprd_dcam/flash/flash_common.c44
-rw-r--r--drivers/media/sprd_dcam/flash/flash_gpio.c56
-rw-r--r--drivers/media/sprd_dcam/flash/flash_kanas_w.c66
-rw-r--r--drivers/media/sprd_dcam/flash/flash_parallel_connect_bg.c103
-rw-r--r--drivers/media/sprd_dcam/flash/flash_sgm3140.c64
-rw-r--r--drivers/media/sprd_dcam/flash/flash_sm5701.c48
-rw-r--r--drivers/media/sprd_dcam/flash/flash_sprd_sm5701.c48
-rw-r--r--drivers/media/sprd_dcam/flash/flash_vivalto.c53
-rw-r--r--drivers/media/sprd_dcam/pike/dcam_drv.c4549
-rwxr-xr-xdrivers/media/sprd_dcam/pike/dcam_drv.h448
-rw-r--r--drivers/media/sprd_dcam/pike/dcam_reg.h192
-rwxr-xr-xdrivers/media/sprd_dcam/sc8830/dcam_drv.h420
-rw-r--r--drivers/media/sprd_dcam/sharkl/dcam_drv.c4580
-rwxr-xr-xdrivers/media/sprd_dcam/sharkl/dcam_drv.h445
-rw-r--r--drivers/media/sprd_dcam/sharkl/dcam_reg.h205
-rw-r--r--drivers/media/sprd_dcam/tshark/dcam_drv.c4693
-rwxr-xr-xdrivers/media/sprd_dcam/tshark/dcam_drv.h449
-rwxr-xr-xdrivers/media/sprd_dcam/tshark/dcam_reg.h197
-rwxr-xr-xdrivers/media/sprd_dcam/tshark2/dcam_drv.c4913
-rwxr-xr-xdrivers/media/sprd_dcam/tshark2/dcam_drv.h454
-rwxr-xr-xdrivers/media/sprd_dcam/tshark2/dcam_reg.h216
36 files changed, 27917 insertions, 0 deletions
diff --git a/drivers/media/sprd_dcam/Kconfig b/drivers/media/sprd_dcam/Kconfig
new file mode 100644
index 00000000..2cc0ee36
--- /dev/null
+++ b/drivers/media/sprd_dcam/Kconfig
@@ -0,0 +1,48 @@
+if VIDEO_DCAM_SPRD
+choice
+ prompt "Camera resolution"
+ default CAMERA_5M
+
+config CAMERA_2M
+ bool "2M pixels"
+
+config CAMERA_3M
+ bool "3M pixels"
+
+config CAMERA_5M
+ bool "5M pixels"
+
+config CAMERA_8M
+ bool "8M pixels"
+
+
+endchoice
+
+choice
+ prompt "Camera capture mode"
+ default CAMERA_NON_ZSL
+
+config CAMERA_ZSL
+ bool "zsl capture"
+
+config CAMERA_NON_ZSL
+ bool "non zsl capture"
+
+endchoice
+
+choice
+ prompt "Sensor Output"
+ default SENSOR_OUTPUT_YUV
+
+config SENSOR_OUTPUT_RAW
+ bool "sensor outputs raw"
+
+config SENSOR_OUTPUT_YUV
+ bool "sensor outputs yuv"
+
+endchoice
+
+
+endif
+
+
diff --git a/drivers/media/sprd_dcam/Makefile b/drivers/media/sprd_dcam/Makefile
new file mode 100755
index 00000000..f0318e52
--- /dev/null
+++ b/drivers/media/sprd_dcam/Makefile
@@ -0,0 +1,26 @@
+# SC88XX Platform Support
+include drivers/media/sprd_dcam/common/Makefile.inc
+
+obj-y += sprd_dcam.o
+#ccflags-y += -Idrivers/media/sprd_dcam/common
+common-file := common/dcam_img.o common/parse_hwinfo.o common/gen_scale_coef.o common/sin_cos.o common/flash_test.o
+
+
+ifeq ($(CONFIG_ARCH_SCX30G),y)
+
+ifeq ($(CONFIG_ARCH_SCX20),y)
+sprd_dcam-objs := pike/dcam_drv.o $(common-file)
+else ifeq ($(CONFIG_ARCH_SCX30G2),y)
+sprd_dcam-objs := tshark2/dcam_drv.o $(common-file)
+else
+sprd_dcam-objs := tshark/dcam_drv.o $(common-file)
+endif
+
+else ifeq ($(CONFIG_ARCH_SCX35L),y)
+ifeq ($(CONFIG_ARCH_SCX35LT8),y)
+sprd_dcam-objs := tshark2/dcam_drv.o $(common-file)
+else
+sprd_dcam-objs := sharkl/dcam_drv.o $(common-file)
+endif
+endif
+obj-y += flash/
diff --git a/drivers/media/sprd_dcam/common/Makefile.inc b/drivers/media/sprd_dcam/common/Makefile.inc
new file mode 100644
index 00000000..16cf7800
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/Makefile.inc
@@ -0,0 +1,15 @@
+# SC88XX Platform Support
+
+ifeq ($(CONFIG_ARCH_SCX30G2),y)
+ccflags-y += -Idrivers/media/sprd_dcam/tshark
+DEFS = -DVERSION3D=1
+else ifeq ($(CONFIG_ARCH_SCX30G),y)
+ccflags-y += -Idrivers/media/sprd_dcam/tshark
+DEFS = -DVERSION3T=1
+else ifeq ($(CONFIG_ARCH_SCX35L),y)
+ccflags-y += -Idrivers/media/sprd_dcam/sharkl
+DEFS = -DVERSION3L=1
+endif
+
+ccflags-y += $(DEFS)
+ccflags-y += -Idrivers/media/sprd_dcam/common
diff --git a/drivers/media/sprd_dcam/common/dcam_img.c b/drivers/media/sprd_dcam/common/dcam_img.c
new file mode 100755
index 00000000..5ca10bd1
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/dcam_img.c
@@ -0,0 +1,3779 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+#include <linux/interrupt.h>
+#include <linux/kthread.h>
+#include <linux/highmem.h>
+#include <linux/freezer.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#ifndef CONFIG_64BIT
+#include <soc/sprd/board.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/adi.h>
+#endif
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/proc_fs.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
+#include <linux/vmalloc.h>
+#include "dcam_drv.h"
+
+#include <asm/io.h>
+
+
+#include <../flash/flash.h>
+#include <video/sprd_img.h>
+
+#include "../../sprd_sensor/csi2/csi_api.h"
+
+//#define LOCAL static
+#define LOCAL
+
+#define IMG_DEVICE_NAME "sprd_image"
+#define IMAGE_MINOR MISC_DYNAMIC_MINOR
+#define DCAM_INVALID_FOURCC 0xFFFFFFFF
+#define DCAM_MAJOR_VERSION 1
+#define DCAM_MINOR_VERSION 0
+#define DCAM_RELEASE 0
+#define DCAM_QUEUE_LENGTH 16
+#define DCAM_TIMING_LEN 16
+#if CONFIG_SC_FPGA
+#define DCAM_TIMEOUT (2000*100)
+#else
+#define DCAM_TIMEOUT 2000
+#endif
+
+#define DCAM_ZOOM_LEVEL_MAX 4
+#define DCAM_ZOOM_STEP(x, y) (((x) - (y)) / DCAM_ZOOM_LEVEL_MAX)
+#define DCAM_PIXEL_ALIGNED 4
+#define DCAM_WIDTH(w) ((w)& ~(DCAM_PIXEL_ALIGNED - 1))
+#define DCAM_HEIGHT(h) ((h)& ~(DCAM_PIXEL_ALIGNED - 1))
+
+#define DEBUG_STR "Error L %d, %s: \n"
+#define DEBUG_ARGS __LINE__,__FUNCTION__
+#define IMG_RTN_IF_ERR(n) \
+ do { \
+ if(unlikely(n)) { \
+ printk(DEBUG_STR,DEBUG_ARGS); \
+ goto exit; \
+ } \
+ } while(0)
+
+#define IMG_PRINT_IF_ERR(n) \
+ do { \
+ if(unlikely(n)) { \
+ printk(DEBUG_STR,DEBUG_ARGS); \
+ } \
+ } while(0)
+
+#define DCAM_VERSION \
+ KERNEL_VERSION(DCAM_MAJOR_VERSION, DCAM_MINOR_VERSION, DCAM_RELEASE)
+
+typedef int (*path_cfg_func)(enum dcam_cfg_id, void *);
+
+enum
+{
+ PATH_IDLE = 0x00,
+ PATH_RUN,
+};
+
+struct dcam_format {
+ char *name;
+ uint32_t fourcc;
+ int depth;
+};
+
+struct dcam_node {
+ uint32_t irq_flag;
+ uint32_t f_type;
+ uint32_t index;
+ uint32_t height;
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+ uint32_t yaddr_vir;
+ uint32_t uaddr_vir;
+ uint32_t vaddr_vir;
+ uint32_t invalid_flag;
+ struct timeval time;
+ uint32_t reserved;
+};
+
+struct dcam_queue {
+ struct dcam_node node[DCAM_QUEUE_LENGTH];
+ struct dcam_node *write;
+ struct dcam_node *read;
+ uint32_t wcnt;
+ uint32_t rcnt;
+};
+
+struct dcam_img_buf_addr {
+ struct dcam_addr frm_addr;
+ struct dcam_addr frm_addr_vir;
+};
+
+struct dcam_img_buf_queue {
+ struct dcam_img_buf_addr buf_addr[DCAM_FRM_CNT_MAX];
+ struct dcam_img_buf_addr *write;
+ struct dcam_img_buf_addr *read;
+ uint32_t wcnt;
+ uint32_t rcnt;
+};
+
+struct dcam_path_spec {
+ uint32_t is_work;
+ uint32_t is_from_isp;
+ uint32_t rot_mode;
+ uint32_t status;
+ struct dcam_size in_size;
+ struct dcam_path_dec img_deci;
+ struct dcam_rect in_rect;
+ struct dcam_rect in_rect_current;
+ struct dcam_rect in_rect_backup;
+ struct dcam_size out_size;
+ enum dcam_fmt out_fmt;
+ struct dcam_endian_sel end_sel;
+ uint32_t fourcc;
+ uint32_t pixel_depth;
+ uint32_t frm_id_base;
+ uint32_t frm_type;
+ uint32_t index[DCAM_FRM_CNT_MAX];
+ //struct dcam_addr frm_addr[DCAM_FRM_CNT_MAX];
+ //struct dcam_addr frm_addr_vir[DCAM_FRM_CNT_MAX];
+ struct dcam_img_buf_queue buf_queue;
+ struct dcam_addr frm_reserved_addr;
+ struct dcam_addr frm_reserved_addr_vir;
+ struct dcam_frame *frm_ptr[DCAM_FRM_CNT_MAX];
+ uint32_t frm_cnt_act;
+ uint32_t path_frm_deci;
+ uint32_t shrink;
+};
+
+struct dcam_info {
+ uint32_t if_mode;
+ uint32_t sn_mode;
+ uint32_t yuv_ptn;
+ uint32_t data_bits;
+ uint32_t is_loose;
+ uint32_t lane_num;
+ uint32_t pclk;
+ struct dcam_cap_sync_pol sync_pol;
+ uint32_t frm_deci;
+ struct dcam_cap_dec img_deci;
+ struct dcam_size cap_in_size;
+ struct dcam_rect cap_in_rect;
+ struct dcam_size cap_out_size;
+ struct dcam_size dst_size;
+ uint32_t pxl_fmt;
+ uint32_t need_isp_tool;
+ uint32_t need_isp;
+ uint32_t need_shrink;
+ struct dcam_rect path_input_rect;
+
+ struct dcam_path_spec dcam_path[DCAM_PATH_NUM];
+
+ uint32_t capture_mode;
+ uint32_t skip_number;
+ uint32_t flash_status;
+ uint32_t after_af;
+ uint32_t is_smooth_zoom;
+ struct timeval timestamp;
+};
+
+struct dcam_dev {
+ struct mutex dcam_mutex;
+ struct semaphore irq_sem;
+ atomic_t users;
+ struct dcam_info dcam_cxt;
+ atomic_t stream_on;
+ uint32_t stream_mode;
+ struct dcam_queue queue;
+ struct timer_list dcam_timer;
+ atomic_t run_flag;
+ uint32_t got_resizer;
+ struct proc_dir_entry* proc_file;
+ struct semaphore flash_thread_sem;
+ struct task_struct* flash_thread;
+ uint32_t is_flash_thread_stop;
+ uint32_t frame_skipped;
+ struct semaphore zoom_thread_sem;
+ struct task_struct* zoom_thread;
+ uint32_t is_zoom_thread_stop;
+ uint32_t zoom_level;
+ uint32_t channel_id;
+ void *driver_data;
+};
+
+#ifndef __SIMULATOR__
+LOCAL int sprd_img_tx_done(struct dcam_frame *frame, void* param);
+LOCAL int sprd_img_tx_error(struct dcam_frame *frame, void* param);
+LOCAL int sprd_img_no_mem(struct dcam_frame *frame, void* param);
+LOCAL int sprd_img_queue_write(struct dcam_queue *queue, struct dcam_node *node);
+LOCAL int sprd_img_queue_read(struct dcam_queue *queue, struct dcam_node *node);
+LOCAL int sprd_img_queue_disable(struct dcam_queue *queue, uint32_t channel_id);
+LOCAL int sprd_img_queue_enable(struct dcam_queue *queue, uint32_t channel_id);
+LOCAL int sprd_img_buf_queue_init(struct dcam_img_buf_queue *queue);
+LOCAL int sprd_img_queue_init(struct dcam_queue *queue);
+LOCAL int sprd_img_buf_queue_write(struct dcam_img_buf_queue *queue, struct dcam_img_buf_addr *buf_addr);
+LOCAL int sprd_img_buf_queue_read(struct dcam_img_buf_queue *queue, struct dcam_img_buf_addr *buf_addr);
+LOCAL int sprd_start_timer(struct timer_list *dcam_timer, uint32_t time_val);
+LOCAL int sprd_stop_timer(struct timer_list *dcam_timer);
+LOCAL int sprd_img_streampause(struct file *file, uint32_t channel_id, uint32_t reconfig_flag);
+LOCAL int sprd_img_streamresume(struct file *file, uint32_t channel_id);
+LOCAL int sprd_img_reg_isr(struct dcam_dev* param);
+LOCAL int sprd_img_reg_path2_isr(struct dcam_dev* param);
+LOCAL int sprd_img_unreg_isr(struct dcam_dev* param);
+LOCAL int sprd_img_unreg_path2_isr(struct dcam_dev* param);
+/*LOCAL int sprd_img_proc_read(char *page, char **start,off_t off, int count, int *eof, void *data);*/
+LOCAL void sprd_img_print_reg(void);
+LOCAL int sprd_img_start_zoom(struct dcam_frame *frame, void* param);
+LOCAL int sprd_img_path_cfg_output_addr(path_cfg_func path_cfg, struct dcam_path_spec* path_spec);
+
+LOCAL struct dcam_format dcam_img_fmt[] = {
+ {
+ .name = "4:2:2, packed, YUYV",
+ .fourcc = IMG_PIX_FMT_YUYV,
+ .depth = 16,
+ },
+ {
+ .name = "4:2:2, packed, YVYU",
+ .fourcc = IMG_PIX_FMT_YVYU,
+ .depth = 16,
+ },
+ {
+ .name = "4:2:2, packed, UYVY",
+ .fourcc = IMG_PIX_FMT_UYVY,
+ .depth = 16,
+ },
+ {
+ .name = "4:2:2, packed, VYUY",
+ .fourcc = IMG_PIX_FMT_VYUY,
+ .depth = 16,
+ },
+ {
+ .name = "YUV 4:2:2, planar, (Y-Cb-Cr)",
+ .fourcc = IMG_PIX_FMT_YUV422P,
+ .depth = 16,
+ },
+ {
+ .name = "YUV 4:2:0 planar (Y-CbCr)",
+ .fourcc = IMG_PIX_FMT_NV12,
+ .depth = 12,
+ },
+ {
+ .name = "YVU 4:2:0 planar (Y-CrCb)",
+ .fourcc = IMG_PIX_FMT_NV21,
+ .depth = 12,
+ },
+
+ {
+ .name = "YUV 4:2:0 planar (Y-Cb-Cr)",
+ .fourcc = IMG_PIX_FMT_YUV420,
+ .depth = 12,
+ },
+ {
+ .name = "YVU 4:2:0 planar (Y-Cr-Cb)",
+ .fourcc = IMG_PIX_FMT_YVU420,
+ .depth = 12,
+ },
+ {
+ .name = "RGB565 (LE)",
+ .fourcc = IMG_PIX_FMT_RGB565,
+ .depth = 16,
+ },
+ {
+ .name = "RGB565 (BE)",
+ .fourcc = IMG_PIX_FMT_RGB565X,
+ .depth = 16,
+ },
+ {
+ .name = "RawRGB",
+ .fourcc = IMG_PIX_FMT_GREY,
+ .depth = 8,
+ },
+ {
+ .name = "JPEG",
+ .fourcc = IMG_PIX_FMT_JPEG,
+ .depth = 8,
+ },
+};
+#else
+LOCAL struct dcam_format dcam_img_fmt[] = {
+ {"4:2:2, packed, YUYV", IMG_PIX_FMT_YUYV, 16},
+ {"4:2:2, packed, YVYU", IMG_PIX_FMT_YVYU, 16},
+ {"4:2:2, packed, UYVY", IMG_PIX_FMT_UYVY, 16},
+ {"4:2:2, packed, VYUY", IMG_PIX_FMT_VYUY, 16},
+ {"YUV 4:2:2, planar, (Y-Cb-Cr)", IMG_PIX_FMT_YUV422P, 16},
+ {"YUV 4:2:0 planar (Y-CbCr)", IMG_PIX_FMT_NV12, 12},
+ {"YVU 4:2:0 planar (Y-CrCb)", IMG_PIX_FMT_NV21, 12},
+ {"YUV 4:2:0 planar (Y-Cb-Cr)", IMG_PIX_FMT_YUV420, 12},
+ {"YVU 4:2:0 planar (Y-Cr-Cb)", IMG_PIX_FMT_YVU420, 12},
+ {"RGB565 (LE)", IMG_PIX_FMT_RGB565, 16},
+ {"RGB565 (BE)", IMG_PIX_FMT_RGB565X, 16},
+ {"RawRGB", IMG_PIX_FMT_GREY, 8},
+ {"JPEG", IMG_PIX_FMT_JPEG, 8}
+};
+#endif
+
+enum cmr_flash_status {
+ FLASH_CLOSE = 0x0,
+ FLASH_OPEN = 0x1,
+ FLASH_TORCH = 0x2, /*user only set flash to close/open/torch state */
+ FLASH_AUTO = 0x3,
+ FLASH_CLOSE_AFTER_OPEN = 0x10, /* following is set to sensor */
+ FLASH_HIGH_LIGHT = 0x11,
+ FLASH_OPEN_ON_RECORDING = 0x22,
+ FLASH_CLOSE_AFTER_AUTOFOCUS = 0x30,
+ FLASH_STATUS_MAX
+};
+
+#define DISCARD_FRAME_TIME (10000)
+
+LOCAL int img_get_timestamp(struct timeval *tv)
+{
+ struct timespec ts;
+
+ ktime_get_ts(&ts);
+ tv->tv_sec = ts.tv_sec;
+ tv->tv_usec = ts.tv_nsec / NSEC_PER_USEC;
+ return 0;
+}
+
+LOCAL int sprd_img_setflash(uint32_t flash_mode)
+{
+
+ switch (flash_mode) {
+ case FLASH_OPEN: /*flash on */
+ case FLASH_TORCH: /*for torch */
+ /*low light */
+ sprd_flash_on();
+ break;
+ case FLASH_HIGH_LIGHT:
+ /*high light */
+ sprd_flash_high_light();
+ break;
+ case FLASH_CLOSE_AFTER_OPEN: /*close flash */
+ case FLASH_CLOSE_AFTER_AUTOFOCUS:
+ case FLASH_CLOSE:
+ /*close the light */
+ sprd_flash_close();
+ break;
+ default:
+ printk("sprd_img_setflash unknow mode:flash_mode 0x%x \n", flash_mode);
+ break;
+ }
+
+ DCAM_TRACE("sprd_img_setflash: flash_mode 0x%x \n", flash_mode);
+
+ return 0;
+}
+
+LOCAL int sprd_img_opt_flash(struct dcam_frame *frame, void* param)
+{
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+ struct dcam_info *info = NULL;
+
+ if (dev == NULL) {
+ DCAM_TRACE("SPRD_IMG: sprd_img_opt_flash, dev is NULL \n");
+ return 0;
+ }
+
+ info = &dev->dcam_cxt;
+ if (info->flash_status < FLASH_STATUS_MAX) {
+ DCAM_TRACE("SPRD_IMG: sprd_img_opt_flash, status %d \n", info->flash_status);
+ if(info->flash_status == FLASH_CLOSE_AFTER_AUTOFOCUS) {
+ img_get_timestamp(&info->timestamp);
+ info->after_af = 1;
+ DCAM_TRACE("SPRD_IMG: sprd_img_opt_flash, time, %d %d \n",
+ (int)info->timestamp.tv_sec, (int)info->timestamp.tv_usec);
+ }
+ sprd_img_setflash(info->flash_status);
+ info->flash_status = FLASH_STATUS_MAX;
+ }
+
+ return 0;
+}
+
+LOCAL int sprd_img_start_flash(struct dcam_frame *frame, void* param)
+{
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+ struct dcam_info *info = NULL;
+ uint32_t need_light = 1;
+
+ if (dev == NULL) {
+ DCAM_TRACE("SPRD_IMG: sprd_img_start_flash, dev is NULL \n");
+ return -1;
+ }
+
+ info = &dev->dcam_cxt;
+ if (info->flash_status < FLASH_STATUS_MAX) {
+ if (FLASH_HIGH_LIGHT == info->flash_status) {
+ dev->frame_skipped ++;
+ if (dev->frame_skipped >= info->skip_number) {
+ //flash lighted at the last SOF before the right capture frame
+ DCAM_TRACE("V4L2: waiting finished \n");
+ } else {
+ need_light = 0;
+ DCAM_TRACE("V4L2: wait for the next SOF, %d ,%d \n",
+ dev->frame_skipped, info->skip_number);
+ }
+ }
+ if (need_light) {
+ up(&dev->flash_thread_sem);
+ }
+ }
+
+ return 0;
+}
+
+int flash_thread_loop(void *arg)
+{
+ struct dcam_dev *dev = (struct dcam_dev*)arg;
+
+ if (dev == NULL) {
+ DCAM_TRACE("SPRD_IMG: flash_thread_loop, dev is NULL \n");
+ return -1;
+ }
+ while (1) {
+ if (0 == down_interruptible(&dev->flash_thread_sem)) {
+ if (dev->is_flash_thread_stop) {
+ sprd_img_setflash(0);
+ DCAM_TRACE("SPRD_IMG: flash_thread_loop stop \n");
+ break;
+ }
+ sprd_img_opt_flash(NULL, arg);
+ } else {
+ DCAM_TRACE("SPRD_IMG: flash int!");
+ break;
+ }
+ }
+ dev->is_flash_thread_stop = 0;
+
+ return 0;
+}
+
+int dcam_create_flash_thread(void* param)
+{
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+
+ if (dev == NULL) {
+ DCAM_TRACE("SPRD_IMG: dcam_create_flash_thread, dev is NULL \n");
+ return -1;
+ }
+ dev->is_flash_thread_stop = 0;
+ sema_init(&dev->flash_thread_sem, 0);
+ dev->flash_thread = kthread_run(flash_thread_loop, param, "dcam_flash_thread");
+ if (IS_ERR(dev->flash_thread)) {
+ printk("SPRD_IMG: dcam_create_flash_thread error!\n");
+ return -1;
+ }
+ return 0;
+}
+
+int dcam_stop_flash_thread(void* param)
+{
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+ int cnt = 0;
+
+ if (dev == NULL) {
+ DCAM_TRACE("SPRD_IMG: sprd_img_opt_flash, dev is NULL \n");
+ return -1;
+ }
+ if (dev->flash_thread) {
+ dev->is_flash_thread_stop = 1;
+ up(&dev->flash_thread_sem);
+ if (0 != dev->is_flash_thread_stop) {
+ while (cnt < 500) {
+ cnt++;
+ if (0 == dev->is_flash_thread_stop)
+ break;
+ msleep(1);
+ }
+ }
+ dev->flash_thread = NULL;
+ }
+
+ return 0;
+}
+
+LOCAL int sprd_img_discard_frame(struct dcam_frame *frame, void* param)
+{
+ int ret = DCAM_RTN_PARA_ERR;
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+ struct dcam_info *info = NULL;
+ struct timeval timestamp;
+ uint32_t flag = 0;
+
+ info = &dev->dcam_cxt;
+ img_get_timestamp(&timestamp);
+ DCAM_TRACE("SPRD_IMG: sprd_img_discard_frame, time, %d %d \n",
+ (int)timestamp.tv_sec, (int)timestamp.tv_usec);
+ if ((timestamp.tv_sec == info->timestamp.tv_sec)
+ && (timestamp.tv_usec -info->timestamp.tv_usec >= DISCARD_FRAME_TIME)){
+ flag = 1;
+ } else if (timestamp.tv_sec > info->timestamp.tv_sec) {
+ if ((1000000 -info->timestamp.tv_sec) + timestamp.tv_sec >= DISCARD_FRAME_TIME) {
+ flag = 1;
+ }
+ }
+
+ if (flag) {
+ DCAM_TRACE("SPRD_IMG: sprd_img_discard_frame,unlock frame %p \n", frame);
+ //dcam_frame_unlock(frame);
+ ret = DCAM_RTN_SUCCESS;
+ }
+ return ret;
+}
+
+LOCAL struct dcam_format *sprd_img_get_format(uint32_t fourcc)
+{
+ struct dcam_format *fmt;
+ uint32_t i;
+
+ for (i = 0; i < ARRAY_SIZE(dcam_img_fmt); i++) {
+ fmt = &dcam_img_fmt[i];
+ if (fmt->fourcc == fourcc)
+ break;
+ }
+
+ if (unlikely(i == ARRAY_SIZE(dcam_img_fmt)))
+ return NULL;
+
+ return &dcam_img_fmt[i];
+}
+
+LOCAL uint32_t sprd_img_get_fourcc(struct dcam_path_spec *path)
+{
+ uint32_t fourcc = DCAM_INVALID_FOURCC;
+
+ switch (path->out_fmt) {
+ case DCAM_YUV422:
+ fourcc = IMG_PIX_FMT_YUV422P;
+ break;
+ case DCAM_YUV420:
+ if (likely(DCAM_ENDIAN_LITTLE == path->end_sel.uv_endian))
+ fourcc = IMG_PIX_FMT_NV12;
+ else
+ fourcc = IMG_PIX_FMT_NV21;
+ break;
+ case DCAM_YUV420_3FRAME:
+ fourcc = IMG_PIX_FMT_YUV420;
+ break;
+ case DCAM_RGB565:
+ if (likely(DCAM_ENDIAN_HALFBIG == path->end_sel.uv_endian))
+ fourcc = IMG_PIX_FMT_RGB565;
+ else
+ fourcc = IMG_PIX_FMT_RGB565X;
+ break;
+ case DCAM_RAWRGB:
+ fourcc = IMG_PIX_FMT_GREY;
+ break;
+ case DCAM_JPEG:
+ fourcc = IMG_PIX_FMT_JPEG;
+ break;
+ default:
+ break;
+ }
+ return fourcc;
+}
+
+LOCAL uint32_t sprd_img_get_deci_factor(uint32_t src_size, uint32_t dst_size)
+{
+ uint32_t factor = 0;
+
+ if (0 == src_size || 0 == dst_size) {
+ return factor;
+ }
+
+ for (factor = 0; factor < DCAM_CAP_X_DECI_FAC_MAX; factor ++) {
+ if (src_size < (uint32_t)(dst_size * (1 << factor))) {
+ break;
+ }
+ }
+
+ return factor;
+}
+
+LOCAL uint32_t sprd_img_endian_sel(uint32_t fourcc, struct dcam_path_spec *path)
+{
+ uint32_t depth = 0;
+
+ if (IMG_PIX_FMT_YUV422P == fourcc ||
+ IMG_PIX_FMT_RGB565 == fourcc ||
+ IMG_PIX_FMT_RGB565X == fourcc) {
+ depth = 16;
+ if (IMG_PIX_FMT_YUV422P == fourcc) {
+ path->out_fmt = DCAM_YUV422;
+ } else {
+ path->out_fmt = DCAM_RGB565;
+ if (IMG_PIX_FMT_RGB565 == fourcc) {
+ path->end_sel.y_endian = DCAM_ENDIAN_HALFBIG;
+ } else {
+ path->end_sel.y_endian = DCAM_ENDIAN_BIG;
+ }
+ }
+ } else {
+ depth = 12;
+ if (IMG_PIX_FMT_YUV420 == fourcc ||
+ IMG_PIX_FMT_YVU420 == fourcc) {
+ path->out_fmt = DCAM_YUV420_3FRAME;
+ } else {
+ path->out_fmt = DCAM_YUV420;
+ if (IMG_PIX_FMT_NV12 == fourcc) {
+ path->end_sel.uv_endian = DCAM_ENDIAN_LITTLE;
+ } else {
+ path->end_sel.uv_endian = DCAM_ENDIAN_HALFBIG;
+ }
+ }
+ }
+
+ return depth;
+}
+
+LOCAL int sprd_img_check_path0_cap(uint32_t fourcc,
+ struct sprd_img_format *f,
+ struct dcam_info *info)
+{
+ struct dcam_path_spec *path = &info->dcam_path[DCAM_PATH0];
+
+ DCAM_TRACE("SPRD_IMG: check format for path0 \n");
+
+ path->is_from_isp = f->need_isp;
+
+ path->frm_type = f->channel_id;
+ path->is_work = 0;
+
+ switch (fourcc) {
+ case IMG_PIX_FMT_GREY:
+ path->out_fmt = info->is_loose; // 0 - word/packet, 1 - half word
+ break;
+
+ case IMG_PIX_FMT_JPEG:
+ path->out_fmt = 0; // 0 - word, 1 - half word
+ path->end_sel.y_endian = DCAM_ENDIAN_LITTLE;
+ break;
+
+ case IMG_PIX_FMT_YUYV:
+ path->out_fmt = DCAM_OUTPUT_YVYU_1FRAME;
+ path->end_sel.y_endian = DCAM_ENDIAN_LITTLE;
+ break;
+
+ case IMG_PIX_FMT_NV21:
+ case IMG_PIX_FMT_NV12:
+ path->out_fmt = DCAM_OUTPUT_YUV420;
+ path->end_sel.y_endian = DCAM_ENDIAN_LITTLE;
+ if (IMG_PIX_FMT_NV12 == fourcc) {
+ path->end_sel.uv_endian = DCAM_ENDIAN_LITTLE;
+ } else {
+ path->end_sel.uv_endian = DCAM_ENDIAN_HALFBIG;
+ }
+ printk("SPRD_IMG: path->end_sel.uv_endian=%d \n", path->end_sel.uv_endian);
+ break;
+
+ default:
+ printk("SPRD_IMG: unsupported image format for path0 0x%x \n", fourcc);
+ return -EINVAL;
+ }
+ path->fourcc = fourcc;
+
+ DCAM_TRACE("SPRD_IMG: check format for path0: out_fmt=%d, is_loose=%d \n", path->out_fmt, info->is_loose);
+ path->out_size.w = f->width;
+ path->out_size.h = f->height;
+
+ path->is_work = 1;
+
+ return 0;
+}
+
+LOCAL int sprd_img_check_path1_cap(uint32_t fourcc,
+ struct sprd_img_format *f,
+ struct dcam_info *info)
+{
+ uint32_t maxw, maxh, tempw,temph;
+ uint32_t depth_pixel = 0;
+ struct dcam_path_spec *path = &info->dcam_path[DCAM_PATH1];
+ uint32_t need_recal = 0;
+
+ DCAM_TRACE("SPRD_IMG: check format for path1 \n");
+
+ path->frm_type = f->channel_id;
+ path->is_from_isp = f->need_isp;
+ path->rot_mode = f->reserved[0];
+ path->end_sel.y_endian = DCAM_ENDIAN_LITTLE;
+ path->end_sel.uv_endian = DCAM_ENDIAN_LITTLE;
+ path->is_work = 0;
+ path->pixel_depth = 0;
+ path->img_deci.x_factor = 0;
+ path->img_deci.y_factor = 0;
+ tempw = path->in_rect.w;
+ temph = path->in_rect.h;
+ info->img_deci.x_factor = 0;
+ f->need_binning = 0;
+ printk("zcf sprd_img_check_path1_cap rot_mode:%d\n",path->rot_mode);
+ /*app should fill in this field(fmt.pix.priv) to set the base index of frame buffer,
+ and lately this field will return the flag whether ISP is needed for this work path*/
+
+ switch (fourcc) {
+ case IMG_PIX_FMT_GREY:
+ case IMG_PIX_FMT_JPEG:
+ case IMG_PIX_FMT_YUYV:
+ case IMG_PIX_FMT_YVYU:
+ case IMG_PIX_FMT_UYVY:
+ case IMG_PIX_FMT_VYUY:
+ if (unlikely(f->width != tempw ||
+ f->height != temph)) {
+ /*need need scaling or triming*/
+ printk("SPRD_IMG: Can not scaling for this image fmt src %d %d, dst %d %d \n",
+ tempw,
+ temph,
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+
+ if (unlikely(DCAM_CAP_MODE_JPEG != info->sn_mode &&
+ IMG_PIX_FMT_JPEG == fourcc)) {
+ /* the output of sensor is not JPEG which is needed by app*/
+ printk("SPRD_IMG: It's not JPEG sensor \n");
+ return -EINVAL;
+ }
+
+ if (unlikely(DCAM_CAP_MODE_RAWRGB != info->sn_mode &&
+ IMG_PIX_FMT_GREY == fourcc)) {
+ /* the output of sensor is not RawRGB which is needed by app*/
+ printk("SPRD_IMG: It's not RawRGB sensor \n");
+ return -EINVAL;
+ }
+
+ if (IMG_PIX_FMT_GREY == fourcc) {
+ if (DCAM_CAP_IF_CSI2 == info->if_mode && 0 == info->is_loose) {
+ depth_pixel = 10;
+ } else {
+ depth_pixel = 16;
+ }
+ DCAM_TRACE("SPRD_IMG: RawRGB sensor, %d %d \n", info->is_loose, depth_pixel);
+ } else if (IMG_PIX_FMT_JPEG == fourcc) {
+ depth_pixel = 8;
+ } else {
+ depth_pixel = 16;
+ }
+
+ if (IMG_PIX_FMT_GREY == fourcc) {
+ path->out_fmt = DCAM_RAWRGB;
+ path->end_sel.y_endian = DCAM_ENDIAN_BIG;
+ } else {
+ path->out_fmt = DCAM_JPEG;
+ }
+ break;
+ case IMG_PIX_FMT_YUV422P:
+ case IMG_PIX_FMT_YUV420:
+ case IMG_PIX_FMT_YVU420:
+ case IMG_PIX_FMT_NV12:
+ case IMG_PIX_FMT_NV21:
+ case IMG_PIX_FMT_RGB565:
+ case IMG_PIX_FMT_RGB565X:
+ if (DCAM_CAP_MODE_RAWRGB == info->sn_mode &&
+ path->is_from_isp) {
+ if (unlikely(info->cap_out_size.w > DCAM_ISP_LINE_BUF_LENGTH)) {
+ if (0 == info->if_mode) {
+ /*CCIR CAP, no bining*/
+ printk("SPRD_IMG: CCIR CAP, no bining for this path, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ } else {
+ /*MIPI CAP, support 1/2 bining*/
+ DCAM_TRACE("Need Binning \n");
+ tempw = tempw >> 1;
+ if (unlikely(tempw > DCAM_ISP_LINE_BUF_LENGTH)) {
+ printk("SPRD_IMG: the width is out of ISP line buffer, %d %d \n",
+ tempw,
+ DCAM_ISP_LINE_BUF_LENGTH);
+ return -EINVAL;
+ }
+ info->img_deci.x_factor = 1;
+ f->need_binning = 1;
+ DCAM_TRACE("x_factor, %d \n", info->img_deci.x_factor);
+ path->in_size.w = path->in_size.w >> 1;
+ path->in_rect.x = path->in_rect.x >> 1;
+ path->in_rect.w = path->in_rect.w >> 1;
+ path->in_rect.w = path->in_rect.w & (~3);
+ }
+ }
+ }
+ if (DCAM_CAP_MODE_YUV == info->sn_mode ||
+ DCAM_CAP_MODE_SPI == info->sn_mode) {
+ if (tempw != f->width || temph != f->height) {
+ /*scaling needed*/
+ if (unlikely(f->width > DCAM_PATH1_LINE_BUF_LENGTH)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output width %d can not be more than %d \n",
+ f->width,
+ DCAM_PATH1_LINE_BUF_LENGTH);
+ return -EINVAL;
+ }
+
+ /* To check whether the output size is too lager*/
+ maxw = tempw * DCAM_SC_COEFF_UP_MAX;
+ maxh = temph * DCAM_SC_COEFF_UP_MAX;
+ if (unlikely(f->width > maxw || f->height > maxh)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output size is too large, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+
+ /* To check whether the output size is too small*/
+ maxw = f->width * DCAM_SC_COEFF_DOWN_MAX;
+ if (unlikely( tempw > maxw)) {
+ path->img_deci.x_factor = sprd_img_get_deci_factor(tempw, maxw);
+ if (path->img_deci.x_factor > DCAM_PATH_DECI_FAC_MAX) {
+ printk("SPRD_IMG: the output size is too small, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+ }
+
+ maxh = f->height * DCAM_SC_COEFF_DOWN_MAX;
+ if (unlikely(temph > maxh)) {
+ path->img_deci.y_factor = sprd_img_get_deci_factor(temph, maxh);
+ if (path->img_deci.y_factor > DCAM_PATH_DECI_FAC_MAX) {
+ printk("SPRD_IMG: the output size is too small, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+ }
+
+ if (path->img_deci.x_factor) {
+ tempw = path->in_rect.w >> 1;
+ need_recal = 1;
+ }
+
+ if (path->img_deci.y_factor) {
+ temph = path->in_rect.h >> 1;
+ need_recal = 1;
+ }
+
+ if (need_recal && (tempw != f->width || temph != f->height)) {
+ /*scaling needed*/
+ if (unlikely(f->width > DCAM_PATH1_LINE_BUF_LENGTH)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output width %d can not be more than %d \n",
+ f->width,
+ DCAM_PATH1_LINE_BUF_LENGTH);
+ return -EINVAL;
+ }
+ }
+ }
+ } else if (DCAM_CAP_MODE_RAWRGB == info->sn_mode) {
+ if (path->is_from_isp) {
+
+ if (tempw != f->width ||
+ temph != f->height) {
+ /*scaling needed*/
+ maxw = f->width * DCAM_SC_COEFF_DOWN_MAX;
+ maxw = maxw * (1 << DCAM_PATH_DECI_FAC_MAX);
+ maxh = f->height * DCAM_SC_COEFF_DOWN_MAX;
+ maxh = maxh * (1 << DCAM_PATH_DECI_FAC_MAX);
+ if (unlikely(tempw > maxw || temph > maxh)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output size is too small, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+
+ if (unlikely(f->width > DCAM_PATH1_LINE_BUF_LENGTH)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output width %d can not be more than %d \n",
+ f->width,
+ DCAM_PATH1_LINE_BUF_LENGTH);
+ return -EINVAL;
+ }
+
+ maxw = tempw * DCAM_SC_COEFF_UP_MAX;
+ maxh = temph * DCAM_SC_COEFF_UP_MAX;
+ if (unlikely(f->width > maxw || f->height > maxh)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output size is too large, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+ }
+ } else {
+ /*no ISP ,only RawRGB data can be sampled*/
+ printk("SPRD_IMG: RawRGB sensor, no ISP, format 0x%x can't be supported \n",
+ fourcc);
+ return -EINVAL;
+ }
+ }
+
+ depth_pixel = sprd_img_endian_sel(fourcc, path);
+ break;
+ default:
+ printk("SPRD_IMG: unsupported image format for path2 0x%x \n", fourcc);
+ return -EINVAL;
+ }
+
+ path->fourcc = fourcc;
+ path->pixel_depth = depth_pixel;
+ f->bytesperline = (f->width * depth_pixel) >> 3;
+ path->out_size.w = f->width;
+ path->out_size.h = f->height;
+ path->is_work = 1;
+ return 0;
+}
+
+LOCAL int sprd_img_check_path2_cap(uint32_t fourcc,
+ struct sprd_img_format *f,
+ struct dcam_info *info)
+{
+ uint32_t maxw, maxh, tempw,temph;
+ uint32_t depth_pixel = 0;
+ struct dcam_path_spec *path = &info->dcam_path[DCAM_PATH2];
+ uint32_t need_recal = 0;
+
+ //return -EINVAL;
+
+ DCAM_TRACE("SPRD_IMG: check format for path2 \n");
+
+ path->frm_type = f->channel_id;
+ path->is_from_isp = f->need_isp;
+ path->rot_mode= f->reserved[0];
+ path->end_sel.y_endian = DCAM_ENDIAN_LITTLE;
+ path->end_sel.uv_endian = DCAM_ENDIAN_LITTLE;
+ path->is_work = 0;
+ path->pixel_depth = 0;
+ printk("zcf sprd_img_check_path2_cap rot:%d\n",path->rot_mode);
+ if (info->img_deci.x_factor) {
+ tempw = path->in_rect.w >> 1;
+ path->in_size.w = path->in_size.w >> 1;
+ path->in_rect.w = path->in_rect.w >> 1;
+ path->in_rect.x = path->in_rect.x >> 1;
+ } else {
+ tempw = path->in_rect.w;
+ }
+ temph = path->in_rect.h;
+ switch (fourcc) {
+ case IMG_PIX_FMT_YUV422P:
+ case IMG_PIX_FMT_YUV420:
+ case IMG_PIX_FMT_YVU420:
+ case IMG_PIX_FMT_NV12:
+ case IMG_PIX_FMT_NV21:
+
+ if (DCAM_CAP_MODE_JPEG == info->sn_mode ||
+ info->sn_mode >= DCAM_CAP_MODE_MAX) {
+ return -EINVAL;
+ }
+
+ if (DCAM_CAP_MODE_RAWRGB == info->sn_mode) {
+ path->is_from_isp = 1;
+ }
+
+ if (DCAM_CAP_MODE_YUV == info->sn_mode ||
+ DCAM_CAP_MODE_SPI == info->sn_mode) {
+ if (tempw != f->width || temph != f->height) {
+ /*scaling needed*/
+ if (unlikely(f->width > DCAM_PATH2_LINE_BUF_LENGTH)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output width %d can not be more than %d \n",
+ f->width,
+ DCAM_PATH2_LINE_BUF_LENGTH);
+ return -EINVAL;
+ }
+
+ /* To check whether the output size is too lager*/
+ maxw = tempw * DCAM_SC_COEFF_UP_MAX;
+ maxh = temph * DCAM_SC_COEFF_UP_MAX;
+ if (unlikely(f->width > maxw || f->height > maxh)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output size is too large, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+
+ /* To check whether the output size is too small*/
+ maxw = f->width * DCAM_SC_COEFF_DOWN_MAX;
+ if (unlikely( tempw > maxw)) {
+ path->img_deci.x_factor = sprd_img_get_deci_factor(tempw, maxw);
+ if (path->img_deci.x_factor > DCAM_PATH_DECI_FAC_MAX) {
+ printk("SPRD_IMG: the output size is too small, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+ }
+
+ maxh = f->height * DCAM_SC_COEFF_DOWN_MAX;
+ if (unlikely(temph > maxh)) {
+ path->img_deci.y_factor = sprd_img_get_deci_factor(temph, maxh);
+ if (path->img_deci.y_factor > DCAM_PATH_DECI_FAC_MAX) {
+ printk("SPRD_IMG: the output size is too small, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+ }
+
+ if (path->img_deci.x_factor) {
+ tempw = path->in_rect.w >> 1;
+ need_recal = 1;
+ }
+
+ if (path->img_deci.y_factor) {
+ temph = path->in_rect.h >> 1;
+ need_recal = 1;
+ }
+
+ if (need_recal && (tempw != f->width || temph != f->height)) {
+ /*scaling needed*/
+ if (unlikely(f->width > DCAM_PATH2_LINE_BUF_LENGTH)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output width %d can not be more than %d \n",
+ f->width,
+ DCAM_PATH2_LINE_BUF_LENGTH);
+ return -EINVAL;
+ }
+ }
+ }
+ } else if (DCAM_CAP_MODE_RAWRGB == info->sn_mode) {
+ if (path->is_from_isp) {
+
+ if (tempw != f->width ||
+ temph != f->height) {
+ /*scaling needed*/
+ maxw = f->width * DCAM_SC_COEFF_DOWN_MAX;
+ maxw = maxw * (1 << DCAM_PATH_DECI_FAC_MAX);
+ maxh = f->height * DCAM_SC_COEFF_DOWN_MAX;
+ maxh = maxh * (1 << DCAM_PATH_DECI_FAC_MAX);
+ if (unlikely(tempw > maxw || temph > maxh)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output size is too small, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+
+ if (unlikely(f->width > DCAM_PATH2_LINE_BUF_LENGTH)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output width %d can not be more than %d \n",
+ f->width,
+ DCAM_PATH2_LINE_BUF_LENGTH);
+ return -EINVAL;
+ }
+
+ maxw = tempw * DCAM_SC_COEFF_UP_MAX;
+ maxh = temph * DCAM_SC_COEFF_UP_MAX;
+ if (unlikely(f->width > maxw || f->height > maxh)) {
+ /*out of scaling capbility*/
+ printk("SPRD_IMG: the output size is too large, %d %d \n",
+ f->width,
+ f->height);
+ return -EINVAL;
+ }
+ }
+ } else {
+ /*no ISP ,only RawRGB data can be sampled*/
+ printk("SPRD_IMG: RawRGB sensor, no ISP, format 0x%x can't be supported \n",
+ fourcc);
+ return -EINVAL;
+ }
+ }
+
+
+ depth_pixel = sprd_img_endian_sel(fourcc, path);
+ //path->end_sel.uv_endian = DCAM_ENDIAN_LITTLE; // tmp fix: output is vu, jpeg only support vu
+ break;
+ default:
+ printk("SPRD_IMG: unsupported image format for path2 0x%x \n", fourcc);
+ return -EINVAL;
+ }
+
+ path->fourcc = fourcc;
+ f->need_isp = path->is_from_isp;
+ path->pixel_depth = depth_pixel;
+ f->bytesperline = (f->width * depth_pixel) >> 3;
+ path->out_size.w = f->width;
+ path->out_size.h = f->height;
+ path->is_work = 1;
+
+ return 0;
+}
+
+LOCAL int sprd_img_cap_cfg(struct dcam_info* info)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ uint32_t param = 0;
+
+ if (NULL == info)
+ return -EINVAL;
+
+ ret = dcam_cap_cfg(DCAM_CAP_SYNC_POL, &info->sync_pol);
+ IMG_RTN_IF_ERR(ret);
+
+ if ((info->dcam_path[DCAM_PATH0].is_work && info->dcam_path[DCAM_PATH0].is_from_isp) ||
+ (info->dcam_path[DCAM_PATH1].is_work && info->dcam_path[DCAM_PATH1].is_from_isp) ||
+ (info->dcam_path[DCAM_PATH2].is_work && info->dcam_path[DCAM_PATH2].is_from_isp)) {
+ param = 1;
+ } else if (!info->dcam_path[DCAM_PATH0].is_work &&
+ !info->dcam_path[DCAM_PATH1].is_work &&
+ !info->dcam_path[DCAM_PATH2].is_work && (DCAM_CAP_MODE_RAWRGB == info->sn_mode)) {
+ param = 1;
+ } else {
+ param = 0;
+ }
+ ret = dcam_cap_cfg(DCAM_CAP_TO_ISP, &param);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = dcam_cap_cfg(DCAM_CAP_YUV_TYPE, &info->yuv_ptn);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = dcam_cap_cfg(DCAM_CAP_DATA_BITS, &info->data_bits);
+ IMG_RTN_IF_ERR(ret);
+
+ if (DCAM_CAP_MODE_RAWRGB == info->sn_mode &&
+ DCAM_CAP_IF_CSI2 == info->if_mode)
+ {
+ ret = dcam_cap_cfg(DCAM_CAP_DATA_PACKET, &info->is_loose);
+ IMG_RTN_IF_ERR(ret);
+ }
+
+ ret = dcam_cap_cfg(DCAM_CAP_FRM_DECI, &info->frm_deci);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = dcam_cap_cfg(DCAM_CAP_INPUT_RECT, &info->cap_in_rect);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = dcam_cap_cfg(DCAM_CAP_FRM_COUNT_CLR, NULL);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = dcam_cap_cfg(DCAM_CAP_PRE_SKIP_CNT, &info->skip_number);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = dcam_cap_cfg(DCAM_CAP_SAMPLE_MODE, &info->capture_mode);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = dcam_cap_cfg(DCAM_CAP_ZOOM_MODE, &info->is_smooth_zoom);
+
+ ret = dcam_cap_cfg(DCAM_CAP_IMAGE_XY_DECI, &info->img_deci);
+
+exit:
+ return ret;
+}
+
+LOCAL void sprd_img_frm_pop(struct dcam_frame *frame, void* param)
+{
+#if 0
+ uint32_t i = 0;
+ uint32_t frame_count = 0;
+ struct dcam_path_spec *path = NULL;
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+ struct dcam_info *info = NULL;
+
+ info = &dev->dcam_cxt;
+
+ switch (frame->type) {
+ case DCAM_PATH0:
+ path = &info->dcam_path[DCAM_PATH0];
+ break;
+ case DCAM_PATH1:
+ path = &info->dcam_path[DCAM_PATH1];
+ break;
+ case DCAM_PATH2:
+ path = &info->dcam_path[DCAM_PATH2];
+ break;
+ default:
+ printk("SPRD_IMG error: sprd_img_frm_pop, path 0x%x \n", frame->type);
+ return -EINVAL;
+ }
+ DCAM_TRACE("SPRD_IMG: sprd_img_frm_pop start, path 0x%x \n", frame->type);
+ DCAM_TRACE("SPRD_IMG: sprd_img_frm_pop, yaddr 0x%x 0x%x \n", frame->yaddr, path->frm_addr[0].yaddr);
+ if (frame->yaddr == path->frm_addr[0].yaddr) {
+ for (i = 0; i < path->frm_cnt_act - 1; i++) {
+ path->frm_addr[i] = path->frm_addr[i+1];
+ path->frm_addr_vir[i] = path->frm_addr_vir[i+1];
+ }
+ path->frm_cnt_act--;
+ memset(&path->frm_addr[path->frm_cnt_act], 0, sizeof(struct dcam_addr));
+ memset(&path->frm_addr_vir[path->frm_cnt_act], 0, sizeof(struct dcam_addr));
+ } else {
+ printk("SPRD_IMG error: sprd_img_frm_pop, yaddr 0x%x 0x%x \n", frame->yaddr, path->frm_addr[0].yaddr);
+ }
+ DCAM_TRACE("SPRD_IMG: sprd_img_frm_pop end, path 0x%x yaddr 0x%x \n", frame->type, frame->yaddr);
+#endif
+ return;
+}
+
+LOCAL int sprd_img_tx_done(struct dcam_frame *frame, void* param)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+ struct dcam_path_spec *path;
+ struct dcam_node node;
+ uint32_t fmr_index;
+ struct dcam_img_buf_addr buf_addr;
+ struct timeval time;
+
+ if (NULL == frame || NULL == param || 0 == atomic_read(&dev->stream_on))
+ return -EINVAL;
+ path = &dev->dcam_cxt.dcam_path[frame->type];
+ if (PATH_IDLE == path->status) {
+ return ret;
+ }
+
+ atomic_set(&dev->run_flag, 1);
+
+ img_get_timestamp(&time);
+ DCAM_TRACE("time, %ld %ld \n", (unsigned long)time.tv_sec, (unsigned long)time.tv_usec);
+
+ memset((void*)&node, 0, sizeof(struct dcam_node));
+ node.irq_flag = IMG_TX_DONE;
+ node.f_type = frame->type;
+ node.index = frame->fid;
+ node.height = frame->height;
+ node.yaddr = frame->yaddr;
+ node.uaddr = frame->uaddr;
+ node.vaddr = frame->vaddr;
+ node.yaddr_vir = frame->yaddr_vir;
+ node.uaddr_vir = frame->uaddr_vir;
+ node.vaddr_vir = frame->vaddr_vir;
+ node.time.tv_sec = time.tv_sec;
+ node.time.tv_usec = time.tv_usec;
+
+ DCAM_TRACE("SPRD_IMG: flag 0x%x type 0x%x index 0x%x \n",
+ node.irq_flag, node.f_type, node.index);
+
+/* path = &dev->dcam_cxt.dcam_path[frame->type];
+ ret = sprd_img_buf_queue_read(&path->buf_queue, &buf_addr);
+ if (ret)
+ return ret;
+
+ node.yaddr_vir = buf_addr.frm_addr_vir.yaddr;
+ node.uaddr_vir = buf_addr.frm_addr_vir.uaddr;
+ node.vaddr_vir = buf_addr.frm_addr_vir.vaddr;
+*/
+ if (DCAM_PATH0 == frame->type && DCAM_CAP_MODE_JPEG == dev->dcam_cxt.sn_mode) {
+ dcam_cap_get_info(DCAM_CAP_JPEG_GET_LENGTH, &node.reserved);
+ printk("SPRD_IMG: JPEG length 0x%x \n", node.reserved);
+ if (node.reserved < DCAM_JPEG_LENGTH_MIN) {
+ return sprd_img_tx_error(frame, param);
+ }
+ }
+
+ if (dev->dcam_cxt.after_af && DCAM_PATH1 == frame->type) {
+ ret = sprd_img_discard_frame(frame, param);
+ if (DCAM_RTN_SUCCESS == ret) {
+ dev->dcam_cxt.after_af = 0;
+ node.irq_flag = IMG_CANCELED_BUF;
+ }
+ }
+
+ ret = sprd_img_queue_write(&dev->queue, &node);
+ if (ret)
+ return ret;
+
+ up(&dev->irq_sem);
+ return ret;
+}
+
+LOCAL int sprd_img_tx_error(struct dcam_frame *frame, void* param)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+ struct dcam_path_spec *path;
+ struct dcam_node node;
+ struct dcam_img_buf_addr buf_addr;
+
+ if (NULL == param || 0 == atomic_read(&dev->stream_on))
+ return -EINVAL;
+
+ memset((void*)&node, 0, sizeof(struct dcam_node));
+ atomic_set(&dev->run_flag, 1);//to avoid time out processing
+ node.irq_flag = IMG_TX_ERR;
+ if (NULL != frame) {
+ node.f_type = frame->type;
+ node.index = frame->fid;
+ node.height = frame->height;
+ node.yaddr = frame->yaddr;
+ node.uaddr = frame->uaddr;
+ node.vaddr = frame->vaddr;
+ node.yaddr_vir = frame->yaddr_vir;
+ node.uaddr_vir = frame->uaddr_vir;
+ node.vaddr_vir = frame->vaddr_vir;
+
+/* path = &dev->dcam_cxt.dcam_path[frame->type];
+ ret = sprd_img_buf_queue_read(&path->buf_queue, &buf_addr);
+ if (ret)
+ return ret;
+
+ node.yaddr_vir = buf_addr.frm_addr_vir.yaddr;
+ node.uaddr_vir = buf_addr.frm_addr_vir.uaddr;
+ node.vaddr_vir = buf_addr.frm_addr_vir.vaddr;*/
+ }
+ ret = sprd_img_queue_write(&dev->queue, &node);
+ if (ret)
+ return ret;
+
+ up(&dev->irq_sem);
+
+ printk("SPRD_IMG: tx_error \n");
+ //mm_clk_register_trace();
+ return ret;
+}
+
+LOCAL int sprd_img_no_mem(struct dcam_frame *frame, void* param)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+ struct dcam_path_spec *path;
+ struct dcam_node node;
+ struct dcam_img_buf_addr buf_addr;
+
+ if (NULL == param || 0 == atomic_read(&dev->stream_on))
+ return -EINVAL;
+ atomic_set(&dev->run_flag, 1);//to avoid time out processing
+
+ memset((void*)&node, 0, sizeof(struct dcam_node));
+ node.irq_flag = IMG_NO_MEM;
+ node.f_type = frame->type;
+ node.index = frame->fid;
+ node.height = frame->height;
+ node.yaddr = frame->yaddr;
+ node.uaddr = frame->uaddr;
+ node.vaddr = frame->vaddr;
+ node.yaddr_vir = frame->yaddr_vir;
+ node.uaddr_vir = frame->uaddr_vir;
+ node.vaddr_vir = frame->vaddr_vir;
+
+
+/* path = &dev->dcam_cxt.dcam_path[frame->type];
+ ret = sprd_img_buf_queue_read(&path->buf_queue, &buf_addr);
+ if (ret)
+ return ret;
+
+ node.yaddr_vir = buf_addr.frm_addr_vir.yaddr;
+ node.uaddr_vir = buf_addr.frm_addr_vir.uaddr;
+ node.vaddr_vir = buf_addr.frm_addr_vir.vaddr;*/
+ ret = sprd_img_queue_write(&dev->queue, &node);
+ if (ret)
+ return ret;
+
+ up(&dev->irq_sem);
+ printk("SPRD_IMG: no mem \n");
+ return ret;
+}
+
+LOCAL int sprd_img_tx_stop(void* param)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+ struct dcam_node node;
+
+ memset((void*)&node, 0, sizeof(struct dcam_node));
+ node.irq_flag = IMG_TX_STOP;
+ ret = sprd_img_queue_write(&dev->queue, &node);
+ if (ret)
+ return ret;
+
+ up(&dev->irq_sem);
+
+ return ret;
+}
+
+LOCAL int sprd_img_reg_isr(struct dcam_dev* param)
+{
+ dcam_reg_isr(DCAM_PATH0_DONE, sprd_img_tx_done, param);
+ dcam_reg_isr(DCAM_PATH1_DONE, sprd_img_tx_done, param);
+ dcam_reg_isr(DCAM_PATH0_OV, sprd_img_tx_error, param);
+ dcam_reg_isr(DCAM_PATH1_OV, sprd_img_tx_error, param);
+ dcam_reg_isr(DCAM_ISP_OV, sprd_img_tx_error, param);
+ dcam_reg_isr(DCAM_MIPI_OV, sprd_img_tx_error, param);
+ dcam_reg_isr(DCAM_SN_LINE_ERR, sprd_img_tx_error, param);
+ dcam_reg_isr(DCAM_SN_FRAME_ERR, sprd_img_tx_error, param);
+ dcam_reg_isr(DCAM_JPEG_BUF_OV, sprd_img_no_mem, param);
+ dcam_reg_isr(DCAM_SN_EOF, sprd_img_start_flash, param);
+ dcam_reg_isr(DCAM_PATH1_SOF, sprd_img_start_zoom, param);
+
+ return 0;
+}
+
+LOCAL int sprd_img_reg_path2_isr(struct dcam_dev* param)
+{
+ dcam_reg_isr(DCAM_PATH2_DONE, sprd_img_tx_done, param);
+ dcam_reg_isr(DCAM_PATH2_OV, sprd_img_tx_error, param);
+
+ return 0;
+}
+
+LOCAL int sprd_img_unreg_isr(struct dcam_dev* param)
+{
+ dcam_reg_isr(DCAM_PATH0_DONE, NULL, param);
+ dcam_reg_isr(DCAM_PATH1_DONE, NULL, param);
+ dcam_reg_isr(DCAM_PATH0_OV, NULL, param);
+ dcam_reg_isr(DCAM_PATH1_OV, NULL, param);
+ dcam_reg_isr(DCAM_ISP_OV, NULL, param);
+ dcam_reg_isr(DCAM_MIPI_OV, NULL, param);
+ dcam_reg_isr(DCAM_SN_LINE_ERR, NULL, param);
+ dcam_reg_isr(DCAM_SN_FRAME_ERR, NULL, param);
+ dcam_reg_isr(DCAM_JPEG_BUF_OV, NULL, param);
+ dcam_reg_isr(DCAM_SN_EOF, NULL, param);
+ dcam_reg_isr(DCAM_PATH1_SOF, NULL, param);
+
+ return 0;
+}
+
+LOCAL int sprd_img_unreg_path2_isr(struct dcam_dev* param)
+{
+ dcam_reg_isr(DCAM_PATH2_DONE, NULL, NULL);
+ dcam_reg_isr(DCAM_PATH2_OV, NULL, NULL);
+
+ return 0;
+}
+
+LOCAL int sprd_img_path0_cfg(path_cfg_func path_cfg,
+ struct dcam_path_spec* path_spec)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ uint32_t param, i;
+
+ if (NULL == path_cfg || NULL == path_spec)
+ return -EINVAL;
+
+ if (path_spec->is_from_isp) {
+ param = 1;
+ } else {
+ param = 0;
+ }
+ ret = path_cfg(DCAM_PATH_SRC_SEL, &param);
+ /*IMG_RTN_IF_ERR(ret);*/
+
+ ret = path_cfg(DCAM_PATH_INPUT_SIZE, &path_spec->in_size);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_INPUT_RECT, &path_spec->in_rect);
+ /*IMG_RTN_IF_ERR(ret);*/
+
+ ret = path_cfg(DCAM_PATH_OUTPUT_FORMAT, &path_spec->out_fmt);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_FRAME_BASE_ID, &path_spec->frm_id_base);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_FRAME_TYPE, &path_spec->frm_type);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_DATA_ENDIAN, &path_spec->end_sel);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_FRM_DECI, &path_spec->path_frm_deci);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = sprd_img_path_cfg_output_addr(path_cfg, path_spec);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_OUTPUT_RESERVED_ADDR, &path_spec->frm_reserved_addr);
+
+ param = 1;
+ ret = path_cfg(DCAM_PATH_ENABLE, &param);
+
+exit:
+ return ret;
+}
+
+LOCAL int sprd_img_path_cfg(path_cfg_func path_cfg,
+ struct dcam_path_spec* path_spec)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ uint32_t param, i;
+
+ if (NULL == path_cfg || NULL == path_spec)
+ return -EINVAL;
+
+ if (path_spec->is_from_isp) {
+ param = 1;
+ } else {
+ param = 0;
+ }
+ ret = path_cfg(DCAM_PATH_SRC_SEL, &param);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_ROT_MODE, &path_spec->rot_mode);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_INPUT_SIZE, &path_spec->in_size);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_INPUT_RECT, &path_spec->in_rect);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_OUTPUT_SIZE, &path_spec->out_size);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_OUTPUT_FORMAT, &path_spec->out_fmt);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_FRAME_BASE_ID, &path_spec->frm_id_base);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_FRAME_TYPE, &path_spec->frm_type);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_DATA_ENDIAN, &path_spec->end_sel);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_FRM_DECI, &path_spec->path_frm_deci);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = sprd_img_path_cfg_output_addr(path_cfg, path_spec);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_OUTPUT_RESERVED_ADDR, &path_spec->frm_reserved_addr);
+
+ ret = path_cfg(DCAM_PATH_SHRINK, &path_spec->shrink);
+
+ param = 1;
+ ret = path_cfg(DCAM_PATH_ENABLE, &param);
+
+exit:
+ return ret;
+}
+
+LOCAL int sprd_img_path_lightly_cfg(path_cfg_func path_cfg,
+ struct dcam_path_spec* path_spec)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ uint32_t param;
+
+ if (NULL == path_cfg || NULL == path_spec)
+ return -EINVAL;
+
+ if (path_spec->is_from_isp) {
+ param = 1;
+ } else {
+ param = 0;
+ }
+ ret = path_cfg(DCAM_PATH_SRC_SEL, &param);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_INPUT_SIZE, &path_spec->in_size);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_INPUT_RECT, &path_spec->in_rect);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_OUTPUT_SIZE, &path_spec->out_size);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_OUTPUT_FORMAT, &path_spec->out_fmt);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_FRAME_BASE_ID, &path_spec->frm_id_base);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_FRAME_TYPE, &path_spec->frm_type);
+ IMG_RTN_IF_ERR(ret);
+
+ ret = path_cfg(DCAM_PATH_DATA_ENDIAN, &path_spec->end_sel);
+ IMG_RTN_IF_ERR(ret);
+
+exit:
+ return ret;
+}
+
+
+LOCAL int sprd_img_local_deinit(struct dcam_dev *dev)
+{
+ int ret = 0;
+ struct dcam_path_spec *path = &dev->dcam_cxt.dcam_path[DCAM_PATH1];
+ printk("SPRD_IMG: sprd_img_local_deinit, frm_cnt_act %d \n", path->frm_cnt_act);
+ if (unlikely(NULL == dev || NULL == path)) {
+ return -EINVAL;
+ }
+ path->is_work = 0;
+ path->frm_cnt_act = 0;
+ memset((void*)&path->frm_reserved_addr, 0, sizeof(struct dcam_addr));
+ sprd_img_buf_queue_init(&path->buf_queue);
+
+ path = &dev->dcam_cxt.dcam_path[DCAM_PATH2];
+ if (unlikely(NULL == path))
+ return -EINVAL;
+ path->is_work = 0;
+ path->frm_cnt_act = 0;
+ memset((void*)&path->frm_reserved_addr, 0, sizeof(struct dcam_addr));
+ sprd_img_buf_queue_init(&path->buf_queue);
+
+ path = &dev->dcam_cxt.dcam_path[DCAM_PATH0];
+ if (unlikely(NULL == path))
+ return -EINVAL;
+ path->is_work = 0;
+ path->frm_cnt_act = 0;
+ memset((void*)&path->frm_reserved_addr, 0, sizeof(struct dcam_addr));
+ sprd_img_buf_queue_init(&path->buf_queue);
+
+ ret = sprd_img_queue_init(&dev->queue);
+ if (unlikely(ret != 0)) {
+ printk("SPRD_IMG: Failed to init queue \n");
+ return -EINVAL;
+ }
+
+ printk("SPRD_IMG: sprd_img_local_deinit, frm_cnt_act %d \n", path->frm_cnt_act);
+
+ return 0;
+}
+
+LOCAL int sprd_img_queue_init(struct dcam_queue *queue)
+{
+ if (NULL == queue)
+ return -EINVAL;
+
+ memset(queue, 0, sizeof(*queue));
+ queue->write = &queue->node[0];
+ queue->read = &queue->node[0];
+
+ return 0;
+}
+
+LOCAL int sprd_img_queue_write(struct dcam_queue *queue, struct dcam_node *node)
+{
+ struct dcam_node *ori_node;
+ unsigned long lock_flag;
+
+ if (NULL == queue || NULL == node)
+ return -EINVAL;
+
+ ori_node = queue->write;
+ queue->wcnt++;
+ DCAM_TRACE("SPRD_IMG: sprd_img_queue_write \n");
+ *queue->write++ = *node;
+ if (queue->write > &queue->node[DCAM_QUEUE_LENGTH-1]) {
+ queue->write = &queue->node[0];
+ }
+
+ if (queue->write == queue->read) {
+ queue->write = ori_node;
+ printk("SPRD_IMG: warning, queue is full, cannot write, flag 0x%x type 0x%x index 0x%x wcht %d %d\n",
+ node->irq_flag, node->f_type, node->index, queue->wcnt, queue->rcnt);
+ }
+
+ return 0;
+}
+
+LOCAL int sprd_img_queue_read(struct dcam_queue *queue, struct dcam_node *node)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ int flag = 0;
+
+ if (NULL == queue || NULL == node)
+ return -EINVAL;
+
+ DCAM_TRACE("SPRD_IMG: sprd_img_queue_read \n");
+
+ if (queue->read != queue->write) {
+ flag = 1;
+ *node = *queue->read;
+ queue->read->yaddr = 0;
+ queue->read->yaddr_vir = 0;
+ queue->read++;
+ queue->rcnt++;
+ if (queue->read > &queue->node[DCAM_QUEUE_LENGTH-1]) {
+ queue->read = &queue->node[0];
+ }
+ }
+ if (!flag) {
+ ret = EAGAIN;
+ }
+ DCAM_TRACE("SPRD_IMG: sprd_img_queue_read type %d \n", node->f_type);
+ return ret;
+}
+
+LOCAL int sprd_img_queue_disable(struct dcam_queue *queue, uint32_t channel_id)
+{
+ struct dcam_node *cur_node;
+
+ if (NULL == queue)
+ return -EINVAL;
+
+ cur_node = queue->read;
+ while (cur_node != queue->write) {
+ if (channel_id == cur_node->f_type) {
+ cur_node->invalid_flag = 1;
+ }
+ if (cur_node >= &queue->node[DCAM_QUEUE_LENGTH-1]) {
+ cur_node = &queue->node[0];
+ } else {
+ cur_node++;
+ }
+ }
+
+
+ return 0;
+}
+
+LOCAL int sprd_img_queue_enable(struct dcam_queue *queue, uint32_t channel_id)
+{
+ struct dcam_node *cur_node;
+ unsigned int i = 0;
+
+ if (NULL == queue)
+ return -EINVAL;
+
+ for (i=0 ; i < DCAM_QUEUE_LENGTH ; i++) {
+ queue->node[i].invalid_flag = 0;
+ }
+
+ return 0;
+}
+
+LOCAL int sprd_img_buf_queue_init(struct dcam_img_buf_queue *queue)
+{
+ if (NULL == queue)
+ return -EINVAL;
+
+ printk("SPRD_IMG: sprd_img_buf_queue_init \n");
+ memset(queue, 0, sizeof(*queue));
+ queue->write = &queue->buf_addr[0];
+ queue->read = &queue->buf_addr[0];
+
+ return 0;
+}
+
+LOCAL int sprd_img_buf_queue_write(struct dcam_img_buf_queue *queue, struct dcam_img_buf_addr *buf_addr)
+{
+ struct dcam_img_buf_addr *ori_node;
+
+ if (NULL == queue || NULL == buf_addr)
+ return -EINVAL;
+
+ ori_node = queue->write;
+ DCAM_TRACE("SPRD_IMG: sprd_img_buf_queue_write \n");
+ *queue->write++ = *buf_addr;
+ queue->wcnt++;
+ if (queue->write > &queue->buf_addr[DCAM_FRM_CNT_MAX-1]) {
+ queue->write = &queue->buf_addr[0];
+ }
+
+ if (queue->write == queue->read) {
+ queue->write = ori_node;
+ printk("SPRD_IMG: warning, queue is full, cannot write %d %d", queue->wcnt, queue->rcnt);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+LOCAL int sprd_img_buf_queue_read(struct dcam_img_buf_queue *queue, struct dcam_img_buf_addr *buf_addr)
+{
+ int ret = DCAM_RTN_SUCCESS;
+
+ if (NULL == queue || NULL == buf_addr)
+ return -EINVAL;
+
+ DCAM_TRACE("SPRD_IMG: sprd_img_buf_queue_read \n");
+ if (queue->read != queue->write) {
+ *buf_addr = *queue->read++;
+ queue->rcnt++;
+ if (queue->read > &queue->buf_addr[DCAM_FRM_CNT_MAX-1]) {
+ queue->read = &queue->buf_addr[0];
+ }
+ } else {
+ printk("SPRD_IMG: buf_queue_read fail %d\n", queue->rcnt);
+ ret = EAGAIN;
+ }
+
+ DCAM_TRACE("SPRD_IMG: sprd_img_buf_queue_read \n");
+ return ret;
+}
+
+LOCAL int sprd_img_path_cfg_output_addr(path_cfg_func path_cfg, struct dcam_path_spec* path_spec)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_img_buf_addr *cur_node;
+ struct dcam_img_buf_queue *queue;
+ struct dcam_addr frm_addr;
+
+ if (NULL == path_cfg || NULL == path_spec)
+ return -EINVAL;
+
+ queue = &path_spec->buf_queue;
+
+ for (cur_node = queue->read; cur_node != queue->write; cur_node++) {
+ if (cur_node > &queue->buf_addr[DCAM_FRM_CNT_MAX-1]) {
+ cur_node = &queue->buf_addr[0];
+ }
+ frm_addr.yaddr = cur_node->frm_addr.yaddr;
+ frm_addr.uaddr = cur_node->frm_addr.uaddr;
+ frm_addr.vaddr = cur_node->frm_addr.vaddr;
+ frm_addr.yaddr_vir = cur_node->frm_addr_vir.yaddr;
+ frm_addr.uaddr_vir = cur_node->frm_addr_vir.uaddr;
+ frm_addr.vaddr_vir = cur_node->frm_addr_vir.vaddr;
+ ret = path_cfg(DCAM_PATH_OUTPUT_ADDR, &frm_addr);
+ IMG_RTN_IF_ERR(ret);
+ }
+
+exit:
+ return ret;
+}
+
+
+LOCAL int sprd_img_get_path_index(uint32_t channel_id)
+{
+ int path_index;
+
+ switch (channel_id) {
+ case DCAM_PATH0:
+ path_index = DCAM_PATH_IDX_0;
+ break;
+ case DCAM_PATH1:
+ path_index = DCAM_PATH_IDX_1;
+ break;
+ case DCAM_PATH2:
+ path_index = DCAM_PATH_IDX_2;
+ break;
+ default:
+ path_index = DCAM_PATH_IDX_NONE;
+ printk("SPRD_IMG: get path index error, invalid channel_id=0x%x \n", channel_id);
+ }
+ return path_index;
+}
+
+LOCAL int img_get_zoom_rect(struct dcam_rect *src_rect, struct dcam_rect *dst_rect, struct dcam_rect *output_rect, uint32_t zoom_level)
+{
+ uint32_t trim_width = 0;
+ uint32_t trim_height = 0;
+ uint32_t zoom_step_w = 0, zoom_step_h = 0;
+
+ if (NULL == src_rect || NULL == dst_rect || NULL == output_rect) {
+ printk("SPRD_IMG: img_get_zoom_rect: %p, %p, %p\n", src_rect, dst_rect, output_rect);
+ return -EINVAL;
+ }
+
+ if (0 == dst_rect->w || 0 == dst_rect->h) {
+ printk("SPRD_IMG: img_get_zoom_rect: dst0x%x, 0x%x\n", dst_rect->w, dst_rect->h);
+ return -EINVAL;
+ }
+
+ if (src_rect->w > dst_rect->w && src_rect->h > dst_rect->h) {
+ zoom_step_w = DCAM_ZOOM_STEP(src_rect->w, dst_rect->w);
+ zoom_step_w &= ~1;
+ zoom_step_w *= zoom_level;
+ trim_width = src_rect->w - zoom_step_w;
+
+ zoom_step_h = DCAM_ZOOM_STEP(src_rect->h, dst_rect->h);
+ zoom_step_h &= ~1;
+ zoom_step_h *= zoom_level;
+ trim_height = src_rect->h - zoom_step_h;
+
+ output_rect->x = src_rect->x + ((src_rect->w - trim_width) >> 1);
+ output_rect->y = src_rect->y + ((src_rect->h - trim_height) >> 1);
+ } else if (src_rect->w < dst_rect->w && src_rect->h < dst_rect->h) {
+ zoom_step_w = DCAM_ZOOM_STEP(dst_rect->w, src_rect->w);
+ zoom_step_w &= ~1;
+ zoom_step_w *= zoom_level;
+ trim_width = src_rect->w + zoom_step_w;
+
+ zoom_step_h = DCAM_ZOOM_STEP(dst_rect->h, src_rect->h);
+ zoom_step_h &= ~1;
+ zoom_step_h *= zoom_level;
+ trim_height = src_rect->h + zoom_step_h;
+
+ output_rect->x = src_rect->x - ((trim_width - src_rect->w) >> 1);
+ output_rect->y = src_rect->y - ((trim_height - src_rect->h) >> 1);
+ } else {
+ printk("SPRD_IMG: SPRD_IMG img_get_zoom_rect: param error\n");
+ return -EINVAL;
+ }
+
+ output_rect->x = DCAM_WIDTH(output_rect->x);
+ output_rect->y = DCAM_HEIGHT(output_rect->y);
+ output_rect->w = DCAM_WIDTH(trim_width);
+ output_rect->h = DCAM_HEIGHT(trim_height);
+ DCAM_TRACE("SPRD_IMG: zoom_level %d, trim rect, %d %d %d %d\n",
+ zoom_level,
+ output_rect->x,
+ output_rect->y,
+ output_rect->w,
+ output_rect->h);
+
+ return 0;
+}
+
+LOCAL int sprd_img_start_zoom(struct dcam_frame *frame, void* param)
+{
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+
+ if (dev == NULL) {
+ DCAM_TRACE("SPRD_IMG: sprd_img_start_zoom, dev is NULL \n");
+ return -1;
+ }
+ DCAM_TRACE("SPRD_IMG: start zoom level %d \n", dev->zoom_level);
+ if (dev->zoom_level <= DCAM_ZOOM_LEVEL_MAX && dev->dcam_cxt.is_smooth_zoom) {
+ up(&dev->zoom_thread_sem);
+ } else {
+ dcam_stop_sc_coeff();
+ }
+
+ return 0;
+}
+
+int sprd_img_zoom_thread_loop(void *arg)
+{
+ struct dcam_dev *dev = (struct dcam_dev*)arg;
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_rect zoom_rect = {0};
+ struct dcam_path_spec *path = NULL;
+ enum dcam_path_index path_index;
+
+ if (dev == NULL) {
+ printk("SPRD_IMG: zoom_thread_loop, dev is NULL \n");
+ return -1;
+ }
+ while (1) {
+ if (0 == down_interruptible(&dev->zoom_thread_sem)) {
+ DCAM_TRACE("SPRD_IMG: zoom thread level %d \n", dev->zoom_level);
+ if (dev->is_zoom_thread_stop) {
+ DCAM_TRACE("SPRD_IMG: zoom_thread_loop stop \n");
+ break;
+ }
+
+ if (dev->zoom_level > DCAM_ZOOM_LEVEL_MAX) {
+ continue;
+ }
+ mutex_lock(&dev->dcam_mutex);
+ path = &dev->dcam_cxt.dcam_path[dev->channel_id];
+ path_index = sprd_img_get_path_index(dev->channel_id);
+ if (dev->zoom_level < DCAM_ZOOM_LEVEL_MAX) {
+ ret = img_get_zoom_rect(&path->in_rect_backup, &path->in_rect, &zoom_rect, dev->zoom_level);
+ if (!ret) {
+ memcpy((void*)&path->in_rect_current, (void*)&zoom_rect, sizeof(struct dcam_rect));
+ dcam_update_path(path_index, &path->in_size, &zoom_rect, &path->out_size);
+ }
+ } else {
+ dcam_update_path(path_index, &path->in_size, &path->in_rect, &path->out_size);
+ memcpy((void*)&path->in_rect_backup, (void*)&path->in_rect, sizeof(struct dcam_rect));
+ memcpy((void*)&path->in_rect_current, (void*)&path->in_rect_backup, sizeof(struct dcam_rect));
+ }
+ dev->zoom_level++;
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: zoom thread level %d end \n", dev->zoom_level);
+
+ } else {
+ printk("SPRD_IMG: zoom int!");
+ break;
+ }
+ }
+ dev->is_zoom_thread_stop = 0;
+
+ return 0;
+}
+
+int sprd_img_create_zoom_thread(void* param)
+{
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+
+ if (dev == NULL) {
+ DCAM_TRACE("create_zoom_thread, dev is NULL \n");
+ return -1;
+ }
+ printk("SPRD_IMG: create_zoom_thread E!\n");
+
+ dev->is_zoom_thread_stop = 0;
+ dev->zoom_level = DCAM_ZOOM_LEVEL_MAX + 1;
+ sema_init(&dev->zoom_thread_sem, 0);
+ dev->zoom_thread = kthread_run(sprd_img_zoom_thread_loop, param, "img_zoom_thread");
+ if (IS_ERR(dev->zoom_thread)) {
+ printk("SPRD_IMG: create_zoom_thread error!\n");
+ return -1;
+ }
+ return 0;
+}
+
+int sprd_img_stop_zoom_thread(void* param)
+{
+ struct dcam_dev *dev = (struct dcam_dev*)param;
+ int cnt = 0;
+
+ if (dev == NULL) {
+ DCAM_TRACE("stop_zoom_thread, dev is NULL \n");
+ return -1;
+ }
+ DCAM_TRACE("SPRD_IMG: stop_zoom_thread E!\n");
+ if (dev->zoom_thread) {
+ dev->is_zoom_thread_stop = 1;
+ up(&dev->zoom_thread_sem);
+ if (dev->is_zoom_thread_stop != 0) {
+ while (cnt < 500) {
+ cnt++;
+ if (0 == dev->is_zoom_thread_stop)
+ break;
+ msleep(1);
+ }
+ }
+ dev->zoom_thread = NULL;
+ }
+
+ return 0;
+}
+
+LOCAL int sprd_img_update_video(struct file *file, uint32_t channel_id)
+{
+ struct dcam_dev *dev = file->private_data;
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_path_spec *path = NULL;
+ path_cfg_func path_cfg;
+ enum dcam_path_index path_index;
+
+
+ DCAM_TRACE("SPRD_IMG: sprd_img_update_video, channel=%d \n", channel_id);
+
+ mutex_lock(&dev->dcam_mutex);
+
+ path = &dev->dcam_cxt.dcam_path[channel_id];
+ path_index = sprd_img_get_path_index(channel_id);
+
+ if (DCAM_PATH0 == channel_id) {
+ path_cfg = dcam_path0_cfg;
+ } else if (DCAM_PATH1 == channel_id) {
+ path_cfg = dcam_path1_cfg;
+ }else if (DCAM_PATH2 == channel_id) {
+ path_cfg = dcam_path2_cfg;
+ }
+
+ if (dev->dcam_cxt.is_smooth_zoom && DCAM_PATH0 != channel_id) {
+ dev->zoom_level = 1;
+ dev->channel_id = channel_id;
+ if (0 == path->in_rect_backup.w || 0 == path->in_rect_backup.h) {
+ path->in_rect_backup.x = 0;
+ path->in_rect_backup.y = 0;
+ path->in_rect_backup.w = path->in_size.w;
+ path->in_rect_backup.h = path->in_size.h;
+ memcpy((void*)&path->in_rect_current, (void*)&path->in_rect_backup, sizeof(struct dcam_rect));
+ } else {
+ memcpy((void*)&path->in_rect_backup, (void*)&path->in_rect_current, sizeof(struct dcam_rect));
+ }
+
+ DCAM_TRACE("SPRD_IMG: in_size{%d %d}, in_rect{%d %d %d %d}, in_rect_backup{%d %d %d %d}, out_size{%d %d}\n",
+ path->in_size.w,
+ path->in_size.h,
+ path->in_rect.x,
+ path->in_rect.y,
+ path->in_rect.w,
+ path->in_rect.h,
+ path->in_rect_backup.x,
+ path->in_rect_backup.y,
+ path->in_rect_backup.w,
+ path->in_rect_backup.h,
+ path->out_size.w,
+ path->out_size.h);
+ } else {
+ DCAM_TRACE("SPRD_IMG: in_size{%d %d}, in_rect{%d %d %d %d}, out_size{%d %d}\n",
+ path->in_size.w,
+ path->in_size.h,
+ path->in_rect.x,
+ path->in_rect.y,
+ path->in_rect.w,
+ path->in_rect.h,
+ path->out_size.w,
+ path->out_size.h);
+ ret = dcam_update_path(path_index, &path->in_size, &path->in_rect, &path->out_size);
+ }
+
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: update video 0x%x \n", ret);
+ if (ret) {
+ printk("SPRD_IMG: Failed to update video 0x%x \n", ret);
+ }
+
+ return ret;
+}
+
+LOCAL int sprd_img_streampause(struct file *file, uint32_t channel_id, uint32_t reconfig_flag)
+{
+ struct dcam_dev *dev = file->private_data;
+ struct dcam_path_spec *path = NULL;
+ int ret = 0;
+ enum dcam_path_index path_index;
+
+ printk("SPRD_IMG: pause, channel %d ,recfg flag %d\n", channel_id, reconfig_flag);
+
+ path = &dev->dcam_cxt.dcam_path[channel_id];
+ path_index = sprd_img_get_path_index(channel_id);
+
+ if (PATH_RUN == path->status) {
+ path->status = PATH_IDLE;
+ ret = dcam_stop_path(path_index);
+ IMG_PRINT_IF_ERR(ret);
+ if ((reconfig_flag)/* && (DCAM_PATH2 == channel_id)*/) {
+ //path->is_work = 0;
+ path->frm_cnt_act = 0;
+ sprd_img_buf_queue_init(&path->buf_queue);
+ sprd_img_queue_disable(&dev->queue, channel_id);
+ ret = sprd_img_unreg_path2_isr(dev);
+ IMG_PRINT_IF_ERR(ret);
+ }
+
+ if (DCAM_PATH2 == channel_id && dev->got_resizer) {
+ dcam_rel_resizer();
+ dev->got_resizer = 0;
+ }
+ printk("SPRD_IMG: pause, channel=%d done \n", channel_id);
+ } else {
+ printk("SPRD_IMG: pause, path %d not running, status=%d \n",
+ channel_id, path->status);
+ }
+
+ return ret;
+}
+
+LOCAL int sprd_img_streamresume(struct file *file, uint32_t channel_id)
+{
+ struct dcam_dev *dev = NULL;
+ struct dcam_path_spec *path = NULL;
+ enum dcam_path_index path_index;
+ path_cfg_func path_cfg;
+ int ret = 0;
+ int on_flag = 1;
+
+ DCAM_TRACE("SPRD_IMG: resume, channel=%d \n", channel_id);
+
+ dev = file->private_data;
+ if (!dev) {
+ printk("SPRD_IMG: dev is NULL \n");
+ return -EFAULT;
+ }
+
+ path = &dev->dcam_cxt.dcam_path[channel_id];
+ path_index = sprd_img_get_path_index(channel_id);
+
+ if (unlikely(0 == atomic_read(&dev->stream_on))) {
+ printk("SPRD_IMG: resume stream not on\n");
+ ret = sprd_img_local_deinit(dev);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ }
+ on_flag = 0;
+ }
+ if (PATH_IDLE == path->status && on_flag) {
+ if (path->is_work) {
+ if (DCAM_PATH0 == channel_id) {
+ path_cfg = dcam_path0_cfg;
+ } else if (DCAM_PATH1 == channel_id) {
+ path_cfg = dcam_path1_cfg;
+ } else if (DCAM_PATH2 == channel_id) {
+ if (0 == dev->got_resizer) {
+ /* if not owned resiezer, try to get it */
+ if (unlikely(dcam_get_resizer(DCAM_WAIT_FOREVER))) {
+ /*no wait to get the controller of resizer, failed*/
+ printk("SPRD_IMG: resume, path2 has been occupied by other app \n");
+ return -EIO;
+ }
+ dev->got_resizer = 1;
+ }
+ ret = sprd_img_reg_path2_isr(dev);
+ IMG_PRINT_IF_ERR(ret);
+ path_cfg = dcam_path2_cfg;
+ } else {
+ printk("SPRD_IMG: resume, invalid channel_id=0x%x \n", channel_id);
+ return -EINVAL;
+ }
+
+ if (DCAM_PATH0 == channel_id) {
+ ret = sprd_img_path0_cfg(path_cfg, path);
+ } else {
+ ret = sprd_img_path_cfg(path_cfg, path);
+ }
+ sprd_img_queue_enable(&dev->queue, channel_id);
+ IMG_RTN_IF_ERR(ret);
+ ret = dcam_start_path(path_index);
+ IMG_PRINT_IF_ERR(ret);
+
+ path->status = PATH_RUN;
+ }else{
+ DCAM_TRACE("SPRD_IMG: resume, path %d no parameter, is_work=%d, cannot resume \n",
+ channel_id, path->is_work);
+ }
+ }else{
+ DCAM_TRACE("SPRD_IMG: resume, path %d not idle, status=%d, cannot resume \n",
+ channel_id, path->status);
+ }
+exit:
+ if (ret) {
+ DCAM_TRACE("SPRD_IMG: fail resume, path %d, ret = 0x%x\n", channel_id, ret);
+ }
+ return ret;
+}
+
+LOCAL void sprd_img_print_reg(void)
+{
+ uint32_t* reg_buf = NULL;
+ uint32_t reg_buf_len = 0x400;
+ int ret;
+ uint32_t print_len = 0, print_cnt = 0;
+
+ reg_buf = (uint32_t*)vzalloc(reg_buf_len);
+ if (NULL == reg_buf)
+ return;
+
+ ret = dcam_read_registers(reg_buf, &reg_buf_len);
+ if (ret) {
+ vfree(reg_buf);
+ return;
+ }
+
+ mm_clk_register_trace();
+ printk("dcam registers \n");
+ while (print_len < reg_buf_len) {
+ printk("offset 0x%03x : 0x%08x, 0x%08x, 0x%08x, 0x%08x \n",
+ print_len,
+ reg_buf[print_cnt],
+ reg_buf[print_cnt+1],
+ reg_buf[print_cnt+2],
+ reg_buf[print_cnt+3]);
+ print_cnt += 4;
+ print_len += 16;
+ }
+#if 0
+ ret = csi_read_registers(reg_buf, &reg_buf_len);
+ if (ret) {
+ vfree(reg_buf);
+ return;
+ }
+
+ print_len = 0;
+ print_cnt = 0;
+ printk("csi registers \n");
+ while (print_len < reg_buf_len) {
+ printk("offset 0x%3x : 0x%8x, 0x%8x, 0x%8x, 0x%8x \n",
+ print_len,
+ reg_buf[print_cnt],
+ reg_buf[print_cnt+1],
+ reg_buf[print_cnt+2],
+ reg_buf[print_cnt+3]);
+ print_cnt += 4;
+ print_len += 16;
+ }
+#endif
+ udelay(1);
+ vfree(reg_buf);
+
+ return;
+
+}
+LOCAL void sprd_timer_callback(unsigned long data)
+{
+ struct dcam_dev *dev = (struct dcam_dev*)data;
+ struct dcam_node node;
+ int ret = 0;
+
+ DCAM_TRACE("SPRD_IMG: sprd_timer_callback \n");
+
+ if (0 == data || 0 == atomic_read(&dev->stream_on)) {
+ printk("SPRD_IMG: timer cb error \n");
+ return;
+ }
+
+ if (0 == atomic_read(&dev->run_flag)) {
+ printk("DCAM timeout.\n");
+ node.irq_flag = IMG_TIMEOUT;
+ node.invalid_flag = 0;
+ ret = sprd_img_queue_write(&dev->queue, &node);
+ if (ret) {
+ printk("SPRD_IMG: timer cb write queue error \n");
+ }
+ up(&dev->irq_sem);
+ }
+}
+LOCAL int sprd_init_timer(struct timer_list *dcam_timer, unsigned long data)
+{
+ int ret = 0;
+
+ setup_timer(dcam_timer, sprd_timer_callback, data);
+ return ret;
+}
+LOCAL int sprd_start_timer(struct timer_list *dcam_timer, uint32_t time_val)
+{
+ int ret = 0;
+
+ DCAM_TRACE("SPRD_IMG: starting timer %ld \n",jiffies);
+ ret = mod_timer(dcam_timer, jiffies + msecs_to_jiffies(time_val));
+ if (ret) {
+ printk("SPRD_IMG: Error in mod_timer %d \n",ret);
+ }
+ return ret;
+}
+
+LOCAL int sprd_stop_timer(struct timer_list *dcam_timer)
+{
+ int ret = 0;
+
+ DCAM_TRACE("SPRD_IMG: stop timer \n");
+ del_timer_sync(dcam_timer);
+ return ret;
+}
+
+LOCAL int sprd_init_handle(struct dcam_dev *dev)
+{
+ struct dcam_info *info = &dev->dcam_cxt;
+ struct dcam_path_spec *path;
+ uint32_t i = 0;
+
+ if (NULL == info) {
+ printk("SPRD_IMG: init handle fail \n");
+ return -EINVAL;
+ }
+ info->flash_status = FLASH_STATUS_MAX;
+ info->after_af = 0;
+ for (i = 0; i < DCAM_PATH_MAX; i++) {
+ path = &info->dcam_path[i];
+ if (NULL == path) {
+ printk("SPRD_IMG: init path %d fail \n", i);
+ return -EINVAL;
+ }
+ memset((void*)path->frm_ptr,
+ 0,
+ (uint32_t)(DCAM_FRM_CNT_MAX * sizeof(struct dcam_frame*)));
+ path->frm_cnt_act = 0;
+ sprd_img_buf_queue_init(&path->buf_queue);
+ path->status = PATH_IDLE;
+ }
+ atomic_set(&dev->stream_on, 0);
+ dev->got_resizer = 0;
+ return 0;
+}
+
+LOCAL int sprd_img_k_open(struct inode *node, struct file *file)
+{
+ struct dcam_dev *dev = NULL;
+ struct miscdevice *md = file->private_data;
+ int ret = 0;
+
+ dev = vzalloc(sizeof(*dev));
+ if (!dev) {
+ ret = -ENOMEM;
+ printk("sprd_img_k_open fail alloc \n");
+ return ret;
+ }
+
+ mutex_init(&dev->dcam_mutex);
+ sema_init(&dev->irq_sem, 0);
+
+ if (unlikely(atomic_inc_return(&dev->users) > 1)) {
+ ret = -EBUSY;
+ goto exit;
+ }
+
+ DCAM_TRACE("sprd_img_k_open \n");
+ ret = dcam_module_en(md->this_device->of_node);
+ if (unlikely(ret != 0)) {
+ printk("SPRD_IMG: Failed to enable dcam module \n");
+ ret = -EIO;
+ goto exit;
+ }
+
+ ret = sprd_img_queue_init(&dev->queue);
+ if (unlikely(ret != 0)) {
+ printk("SPRD_IMG: Failed to init queue \n");
+ ret = -EIO;
+ goto exit;
+ }
+
+ ret = sprd_init_timer(&dev->dcam_timer,(unsigned long)dev);
+ if (unlikely(ret != 0)) {
+ printk("SPRD_IMG: Failed to init timer \n");
+ ret = -EIO;
+ goto exit;
+ }
+
+ ret = sprd_init_handle(dev);
+ if (unlikely(ret != 0)) {
+ printk("SPRD_IMG: Failed to init queue \n");
+ ret = -EIO;
+ goto exit;
+ }
+
+ ret = dcam_create_flash_thread(dev);
+ if (unlikely(ret != 0)) {
+ printk("SPRD_IMG: Failed to create flash thread \n");
+ ret = -EIO;
+ goto exit;
+ }
+
+ ret = sprd_img_create_zoom_thread(dev);
+ if (unlikely(ret != 0)) {
+ printk("SPRD_IMG: Failed to create zoom thread \n");
+ ret = -EIO;
+ goto exit;
+ }
+
+ dev->driver_data = (void*)md;
+ file->private_data = (void*)dev;
+
+exit:
+ if (unlikely(ret)) {
+ atomic_dec(&dev->users);
+ } else {
+#if 0
+ dev->proc_file = create_proc_read_entry(DCAM_PROC_FILE_NAME,
+ 0444,
+ NULL,
+ sprd_img_proc_read,
+ (void*)dev);
+ if (unlikely(NULL == dev->proc_file)) {
+ printk("SPRD_IMG: Can't create an entry for video0 in /proc \n");
+ ret = ENOMEM;
+ }
+#endif
+ }
+
+ DCAM_TRACE("sprd_img_k_open %d \n", ret);
+ return ret;
+}
+
+static int sprd_img_k_release(struct inode *node, struct file *file)
+{
+ struct dcam_dev *dev = NULL;
+ struct miscdevice *md = NULL;
+ int ret = 0;
+
+ DCAM_TRACE("SPRD_IMG: Close start\n");
+#if 0
+ if (dev->proc_file) {
+ DCAM_TRACE("SPRD_IMG: sprd_img_k_release \n");
+ remove_proc_entry(DCAM_PROC_FILE_NAME, NULL);
+ dev->proc_file = NULL;
+ }
+#endif
+
+ dev = file->private_data;
+ if (!dev)
+ goto exit;
+
+ md = dev->driver_data;
+
+ mutex_lock(&dev->dcam_mutex);
+ dcam_reset(DCAM_RST_ALL, 0);
+ if (dev->got_resizer) {
+ dcam_rel_resizer();
+ dev->got_resizer = 0;
+ sprd_img_unreg_path2_isr(dev);
+ }
+
+ atomic_set(&dev->stream_on, 0);
+ dcam_module_deinit(dev->dcam_cxt.if_mode, dev->dcam_cxt.sn_mode);
+ sprd_img_local_deinit(dev);
+ sema_init(&dev->irq_sem, 0);
+ ret = dcam_module_dis(md->this_device->of_node);
+ if (unlikely(0 != ret)) {
+ printk("SPRD_IMG: Failed to enable dcam module \n");
+ ret = -EIO;
+ }
+ sprd_stop_timer(&dev->dcam_timer);
+ atomic_dec(&dev->users);
+ dcam_stop_flash_thread(dev);
+ sprd_img_stop_zoom_thread(dev);
+ mutex_unlock(&dev->dcam_mutex);
+
+ vfree(dev);
+ dev = NULL;
+ file->private_data = NULL;
+
+exit:
+ DCAM_TRACE("SPRD_IMG: Close end.\n");
+ return ret;
+}
+
+static long sprd_img_k_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct dcam_dev *dev = NULL;
+ struct dcam_info *info = NULL;
+ uint32_t path_cnt;
+ uint32_t channel_id;
+ uint32_t mode;
+ uint32_t skip_num;
+ uint32_t freq_flag;
+ uint32_t flash_status;
+ uint32_t zoom;
+ struct sprd_img_parm parm;
+ struct sprd_img_size size;
+ struct sprd_img_rect rect;
+ struct dcam_path_spec *path = NULL;
+ struct dcam_rect *input_rect;
+ struct dcam_size *input_size;
+ path_cfg_func path_cfg;
+ int ret = DCAM_RTN_SUCCESS;
+
+ DCAM_TRACE("sprd_img_k_ioctl: cmd: 0x%x \n", cmd);
+
+ dev = file->private_data;
+ if (!dev) {
+ ret = -EFAULT;
+ printk("sprd_img_k_ioctl: dev is NULL \n");
+ goto exit;
+ }
+
+ info = &dev->dcam_cxt;
+
+ switch (cmd) {
+ case SPRD_IMG_IO_SET_MODE:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&mode, (uint32_t *)arg, sizeof(uint32_t));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ dev->dcam_cxt.capture_mode = mode;
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: capture mode %d \n", dev->dcam_cxt.capture_mode);
+ break;
+
+ case SPRD_IMG_IO_SET_FREQ_FLAG:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&freq_flag, (uint32_t *)arg, sizeof(uint32_t));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+#ifdef CONFIG_CPLL_1024M
+ dcam_set_highclk_flag(freq_flag);
+#endif
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: freq flag %d \n", freq_flag);
+ break;
+
+ case SPRD_IMG_IO_SET_SKIP_NUM:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&skip_num, (uint32_t *)arg, sizeof(uint32_t));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ dev->dcam_cxt.skip_number = skip_num;
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: cap skip number %d \n", dev->dcam_cxt.skip_number);
+ break;
+
+ case SPRD_IMG_IO_SET_SENSOR_SIZE:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&size, (struct sprd_img_size *)arg, sizeof(struct sprd_img_size));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ dev->dcam_cxt.cap_in_size.w = size.w;
+ dev->dcam_cxt.cap_in_size.h = size.h;
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: sensor size %d %d \n",
+ dev->dcam_cxt.cap_in_size.w,
+ dev->dcam_cxt.cap_in_size.h);
+ break;
+
+ case SPRD_IMG_IO_SET_SENSOR_TRIM:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&rect, (struct sprd_img_rect *)arg, sizeof(struct sprd_img_rect));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ dev->dcam_cxt.cap_in_rect.x = rect.x;
+ dev->dcam_cxt.cap_in_rect.y = rect.y;
+ dev->dcam_cxt.cap_in_rect.w = rect.w;
+ dev->dcam_cxt.cap_in_rect.h = rect.h;
+
+ dev->dcam_cxt.cap_out_size.w = dev->dcam_cxt.cap_in_rect.w;
+ dev->dcam_cxt.cap_out_size.h = dev->dcam_cxt.cap_in_rect.h;
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: sensor trim x y w h %d %d %d %d\n",
+ dev->dcam_cxt.cap_in_rect.x,
+ dev->dcam_cxt.cap_in_rect.y,
+ dev->dcam_cxt.cap_in_rect.w,
+ dev->dcam_cxt.cap_in_rect.h);
+ break;
+
+ case SPRD_IMG_IO_SET_FRM_ID_BASE:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&parm, (struct sprd_img_parm *)arg, sizeof(struct sprd_img_parm));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ switch (parm.channel_id) {
+ case DCAM_PATH0:
+ case DCAM_PATH1:
+ case DCAM_PATH2:
+ dev->dcam_cxt.dcam_path[parm.channel_id].frm_id_base = parm.frame_base_id;
+ break;
+ default:
+ printk("SPRD_IMG: Wrong channel ID, %d \n", parm.channel_id);
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: channel %d, base id 0x%x \n",
+ parm.channel_id,
+ parm.frame_base_id);
+ break;
+
+ case SPRD_IMG_IO_SET_CROP:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&parm, (struct sprd_img_parm *)arg, sizeof(struct sprd_img_parm));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+
+ if (unlikely(parm.crop_rect.x + parm.crop_rect.w > dev->dcam_cxt.cap_in_size.w ||
+ parm.crop_rect.y + parm.crop_rect.h > dev->dcam_cxt.cap_in_size.h)) {
+ mutex_unlock(&dev->dcam_mutex);
+ ret = -EINVAL;
+ goto exit;
+ }
+
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_SET_CROP, window %d %d %d %d \n",
+ parm.crop_rect.x,
+ parm.crop_rect.y,
+ parm.crop_rect.w,
+ parm.crop_rect.h);
+
+ switch (parm.channel_id) {
+ case DCAM_PATH0:
+ case DCAM_PATH1:
+ case DCAM_PATH2:
+ input_size = &dev->dcam_cxt.dcam_path[parm.channel_id].in_size;
+ input_rect = &dev->dcam_cxt.dcam_path[parm.channel_id].in_rect;
+ break;
+ default:
+ printk("SPRD_IMG: Wrong channel ID, %d \n", parm.channel_id);
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+
+ input_size->w = dev->dcam_cxt.cap_out_size.w;
+ input_size->h = dev->dcam_cxt.cap_out_size.h;
+ input_rect->x = parm.crop_rect.x;
+ input_rect->y = parm.crop_rect.y;
+ input_rect->w = parm.crop_rect.w;
+ input_rect->h = parm.crop_rect.h;
+
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_SET_CROP, Path %d, cap crop: cap_rect %d %d %d %d, cap_out:%d %d \n",
+ parm.channel_id, input_rect->x, input_rect->y,
+ input_rect->w, input_rect->h,
+ input_size->w, input_size->h);
+ mutex_unlock(&dev->dcam_mutex);
+ break;
+
+ case SPRD_IMG_IO_SET_FLASH:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&flash_status, (uint32_t *)arg, sizeof(uint32_t));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ dev->dcam_cxt.flash_status = flash_status;
+ mutex_unlock(&dev->dcam_mutex);
+ if ((dev->dcam_cxt.flash_status == FLASH_CLOSE_AFTER_OPEN)
+ || (dev->dcam_cxt.flash_status == FLASH_CLOSE)
+ || (dev->dcam_cxt.flash_status == FLASH_CLOSE_AFTER_AUTOFOCUS)) {
+ up(&dev->flash_thread_sem);
+ }
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_SET_FLASH, flash status %d \n", dev->dcam_cxt.flash_status);
+ break;
+
+ case SPRD_IMG_IO_SET_OUTPUT_SIZE:
+ DCAM_TRACE("SPRD_IMG: set output size \n");
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&parm, (struct sprd_img_parm *)arg, sizeof(struct sprd_img_parm));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ dev->dcam_cxt.dst_size.w = parm.dst_size.w;
+ dev->dcam_cxt.dst_size.h = parm.dst_size.h;
+ dev->dcam_cxt.pxl_fmt = parm.pixel_fmt;
+ dev->dcam_cxt.need_isp_tool = parm.need_isp_tool;
+ dev->dcam_cxt.need_isp = parm.need_isp;
+ dev->dcam_cxt.need_shrink = parm.shrink;
+ dev->dcam_cxt.path_input_rect.x = parm.crop_rect.x;
+ dev->dcam_cxt.path_input_rect.y = parm.crop_rect.y;
+ dev->dcam_cxt.path_input_rect.w = parm.crop_rect.w;
+ dev->dcam_cxt.path_input_rect.h = parm.crop_rect.h;
+ mutex_unlock(&dev->dcam_mutex);
+ break;
+
+ case SPRD_IMG_IO_SET_ZOOM_MODE:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&zoom, (uint32_t *)arg, sizeof(uint32_t));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ dev->dcam_cxt.is_smooth_zoom = zoom;
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_SET_ZOOM_MODE, zoom mode %d \n", dev->dcam_cxt.is_smooth_zoom);
+ break;
+
+ case SPRD_IMG_IO_SET_SENSOR_IF:
+ {
+ struct sprd_img_sensor_if sensor_if;
+
+ DCAM_TRACE("SPRD_IMG: set sensor if \n");
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&sensor_if, (struct sprd_img_sensor_if *)arg, sizeof(struct sprd_img_sensor_if));
+ if (unlikely(ret)) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+
+ if (IF_OPEN == sensor_if.res[0]) {
+ dev->dcam_cxt.if_mode = sensor_if.if_type;
+ dev->dcam_cxt.sn_mode = sensor_if.img_fmt;
+ dev->dcam_cxt.yuv_ptn = sensor_if.img_ptn;
+ dev->dcam_cxt.frm_deci = sensor_if.frm_deci;
+
+ DCAM_TRACE("SPRD_IMG: interface %d, mode %d frm_deci %d \n",
+ dev->dcam_cxt.if_mode,
+ dev->dcam_cxt.sn_mode,
+ dev->dcam_cxt.frm_deci);
+
+ if (DCAM_CAP_IF_CCIR == dev->dcam_cxt.if_mode) {
+ /* CCIR interface */
+ dev->dcam_cxt.sync_pol.vsync_pol = sensor_if.if_spec.ccir.v_sync_pol;
+ dev->dcam_cxt.sync_pol.hsync_pol = sensor_if.if_spec.ccir.h_sync_pol;
+ dev->dcam_cxt.sync_pol.pclk_pol = sensor_if.if_spec.ccir.pclk_pol;
+ dev->dcam_cxt.data_bits = 8;
+ DCAM_TRACE("SPRD_IMG: CIR interface, vsync %d hsync %d pclk %d psrc %d bits %d \n",
+ dev->dcam_cxt.sync_pol.vsync_pol,
+ dev->dcam_cxt.sync_pol.hsync_pol,
+ dev->dcam_cxt.sync_pol.pclk_pol,
+ dev->dcam_cxt.sync_pol.pclk_src,
+ dev->dcam_cxt.data_bits);
+ } else {
+ dev->dcam_cxt.sync_pol.need_href = sensor_if.if_spec.mipi.use_href;
+ dev->dcam_cxt.is_loose = sensor_if.if_spec.mipi.is_loose;
+ dev->dcam_cxt.data_bits = sensor_if.if_spec.mipi.bits_per_pxl;
+ dev->dcam_cxt.lane_num = sensor_if.if_spec.mipi.lane_num;
+ dev->dcam_cxt.pclk = sensor_if.if_spec.mipi.pclk;
+ DCAM_TRACE("SPRD_IMG: MIPI interface, ref %d is_loose %d bits %d lanes %d pclk %d\n",
+ dev->dcam_cxt.sync_pol.need_href,
+ dev->dcam_cxt.is_loose,
+ dev->dcam_cxt.data_bits,
+ dev->dcam_cxt.lane_num,
+ dev->dcam_cxt.pclk);
+ }
+ }
+ mutex_unlock(&dev->dcam_mutex);
+ break;
+ }
+
+ case SPRD_IMG_IO_SET_FRAME_ADDR:
+ DCAM_TRACE("SPRD_IMG: set frame addr \n");
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&parm, (struct sprd_img_parm *)arg, sizeof(struct sprd_img_parm));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+
+ switch (parm.channel_id) {
+ case DCAM_PATH0:
+ path = &info->dcam_path[DCAM_PATH0];
+ path_cnt = DCAM_PATH_0_FRM_CNT_MAX;
+ path_cfg = dcam_path0_cfg;
+ break;
+ case DCAM_PATH1:
+ path = &info->dcam_path[DCAM_PATH1];
+ path_cnt = DCAM_PATH_1_FRM_CNT_MAX;
+ path_cfg = dcam_path1_cfg;
+ break;
+ case DCAM_PATH2:
+ path = &info->dcam_path[DCAM_PATH2];
+ path_cnt = DCAM_PATH_2_FRM_CNT_MAX;
+ path_cfg = dcam_path2_cfg;
+ break;
+ default:
+ printk("SPRD_IMG error: SPRD_IMG_IO_SET_FRAME_ADDR, path 0x%x \n", parm.channel_id);
+ mutex_unlock(&dev->dcam_mutex);
+ return -EINVAL;
+ }
+
+
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_SET_FRAME_ADDR, status %d, frm_cnt_act %d \n",
+ path->status, path->frm_cnt_act);
+
+ if (unlikely(0 == parm.frame_addr.y)) {
+ printk("SPRD_IMG: No yaddr \n");
+ mutex_unlock(&dev->dcam_mutex);
+ ret = -EINVAL;
+ } else {
+ if (1 == parm.is_reserved_buf) {
+ path->frm_reserved_addr.yaddr = parm.frame_addr.y;
+ path->frm_reserved_addr.uaddr = parm.frame_addr.u;
+ path->frm_reserved_addr.vaddr = parm.frame_addr.v;
+ path->frm_reserved_addr_vir.yaddr = parm.frame_addr_vir.y;
+ path->frm_reserved_addr_vir.uaddr = parm.frame_addr_vir.u;
+ path->frm_reserved_addr_vir.vaddr = parm.frame_addr_vir.v;
+ } else {
+ struct dcam_addr frame_addr;
+ struct dcam_img_buf_addr buf_addr;
+
+ frame_addr.yaddr = parm.frame_addr.y;
+ frame_addr.uaddr = parm.frame_addr.u;
+ frame_addr.vaddr = parm.frame_addr.v;
+ frame_addr.yaddr_vir = parm.frame_addr_vir.y;
+ frame_addr.uaddr_vir = parm.frame_addr_vir.u;
+ frame_addr.vaddr_vir = parm.frame_addr_vir.v;
+
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_SET_FRAME_ADDR, yaddr: 0x%x, uaddr: 0x%x, vaddr: 0x%x\n",
+ parm.frame_addr.y,
+ parm.frame_addr.u,
+ parm.frame_addr.v);
+
+ if (unlikely(1 == atomic_read(&dev->stream_on)) && path->status == PATH_RUN) {
+ ret = path_cfg(DCAM_PATH_OUTPUT_ADDR, &frame_addr);
+ } else {
+ buf_addr.frm_addr.yaddr = parm.frame_addr.y;
+ buf_addr.frm_addr.uaddr = parm.frame_addr.u;
+ buf_addr.frm_addr.vaddr = parm.frame_addr.v;
+ buf_addr.frm_addr_vir.yaddr = parm.frame_addr_vir.y;
+ buf_addr.frm_addr_vir.uaddr = parm.frame_addr_vir.u;
+ buf_addr.frm_addr_vir.vaddr = parm.frame_addr_vir.v;
+ ret = sprd_img_buf_queue_write(&path->buf_queue, &buf_addr);
+ }
+ }
+ }
+ mutex_unlock(&dev->dcam_mutex);
+ break;
+
+ case SPRD_IMG_IO_PATH_FRM_DECI:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&parm, (struct sprd_img_parm *)arg, sizeof(struct sprd_img_parm));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ path = &dev->dcam_cxt.dcam_path[parm.channel_id];
+ path->path_frm_deci = 0;//parm.deci; // aiden tmp changes
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: channel %d, frm_deci=%d \n", parm.channel_id, path->path_frm_deci);
+ break;
+
+ case SPRD_IMG_IO_SET_SHRINK:
+ mutex_lock(&dev->dcam_mutex);
+ ret = copy_from_user(&parm, (struct sprd_img_parm *)arg, sizeof(struct sprd_img_parm));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+ path = &dev->dcam_cxt.dcam_path[parm.channel_id];
+ path->shrink = parm.shrink;
+ mutex_unlock(&dev->dcam_mutex);
+ DCAM_TRACE("SPRD_IMG: channel %d, shrink=%d \n", parm.channel_id, path->shrink);
+ break;
+
+ case SPRD_IMG_IO_PATH_PAUSE:
+ ret = copy_from_user(&parm, (struct sprd_img_parm *)arg, sizeof(struct sprd_img_parm));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ goto exit;
+ }
+ sprd_img_streampause(file, parm.channel_id, parm.reserved[0]);
+ break;
+
+ case SPRD_IMG_IO_PATH_RESUME:
+ ret = copy_from_user(&channel_id, (uint32_t *)arg, sizeof(uint32_t));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ goto exit;
+ }
+ sprd_img_streamresume(file, channel_id);
+ break;
+
+ case SPRD_IMG_IO_STREAM_ON:
+ {
+ struct dcam_path_spec *path_0 = NULL;
+ struct dcam_path_spec *path_1 = NULL;
+ struct dcam_path_spec *path_2 = NULL;
+
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_STREAM_ON \n");
+
+ mutex_lock(&dev->dcam_mutex);
+
+ path_0 = &dev->dcam_cxt.dcam_path[DCAM_PATH0];
+ path_1 = &dev->dcam_cxt.dcam_path[DCAM_PATH1];
+ path_2 = &dev->dcam_cxt.dcam_path[DCAM_PATH2];
+ memset((void*)path_0->frm_ptr,
+ 0,
+ (uint32_t)(DCAM_FRM_CNT_MAX * sizeof(struct dcam_frame*)));
+ memset((void*)path_1->frm_ptr,
+ 0,
+ (uint32_t)(DCAM_FRM_CNT_MAX * sizeof(struct dcam_frame*)));
+ memset((void*)path_2->frm_ptr,
+ 0,
+ (uint32_t)(DCAM_FRM_CNT_MAX * sizeof(struct dcam_frame*)));
+
+ DCAM_TRACE("SPRD_IMG: streamon, is_work: path_0 = %d, path_1 = %d, path_2 = %d, stream_on = %d \n",
+ path_0->is_work, path_1->is_work, path_2->is_work, atomic_read(&dev->stream_on));
+
+ memset((void*)&path_1->in_rect_backup, 0x00, sizeof(struct dcam_rect));
+ memset((void*)&path_1->in_rect_current, 0x00, sizeof(struct dcam_rect));
+
+ do {
+ /* dcam driver module initialization */
+ ret = dcam_module_init(dev->dcam_cxt.if_mode, dev->dcam_cxt.sn_mode);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+
+ ret = sprd_img_queue_init(&dev->queue);
+ if (unlikely(ret != 0)) {
+ printk("SPRD_IMG: Failed to init queue \n");
+ break;
+ }
+
+ if (path_0->is_work || path_1->is_work || path_2->is_work) {
+ ret = sprd_img_reg_isr(dev);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ }
+ /* config cap sub-module */
+ ret = sprd_img_cap_cfg(&dev->dcam_cxt);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+
+ /* config path1 sub-module if necessary*/
+ if (path_1->is_work) {
+ ret = sprd_img_path_cfg(dcam_path1_cfg, path_1);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ path_1->status = PATH_RUN;
+ } else {
+ ret = dcam_path1_cfg(DCAM_PATH_ENABLE, &path_1->is_work);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ }
+
+ /* config path2 sub-module if necessary*/
+ if (path_2->is_work) {
+ ret = sprd_img_path_cfg(dcam_path2_cfg, path_2);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ ret = sprd_img_reg_path2_isr(dev);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ path_2->status = PATH_RUN;
+ } else {
+ ret = dcam_path2_cfg(DCAM_PATH_ENABLE, &path_2->is_work);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ }
+
+ if (path_0->is_work) {
+ ret = sprd_img_path0_cfg(dcam_path0_cfg, path_0);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ path_0->status = PATH_RUN;
+ } else {
+ ret = dcam_path0_cfg(DCAM_PATH_ENABLE, &path_0->is_work);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ }
+ } while(0);
+ dev->frame_skipped = 0;
+ if (FLASH_HIGH_LIGHT == dev->dcam_cxt.flash_status) {
+ if (0 == dev->dcam_cxt.skip_number) {
+ sprd_img_start_flash(NULL, dev);
+ }
+ }
+
+ ret = dcam_start();
+ atomic_set(&dev->stream_on, 1);
+
+ if (ret) {
+ sprd_img_unreg_path2_isr(dev);
+ sprd_img_unreg_isr(dev);
+ printk("SPRD_IMG: Failed to start stream 0x%x \n", ret);
+ } else {
+ atomic_set(&dev->run_flag, 0);
+ if (path_0->is_work || path_1->is_work || path_2->is_work) {
+ sprd_start_timer(&dev->dcam_timer, DCAM_TIMEOUT);
+ }
+ }
+
+ mutex_unlock(&dev->dcam_mutex);
+ break;
+ }
+
+ case SPRD_IMG_IO_STREAM_OFF:
+ {
+ struct dcam_path_spec *path_0 = NULL;
+ struct dcam_path_spec *path_1 = NULL;
+ struct dcam_path_spec *path_2 = NULL;
+
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_STREAM_OFF \n");
+
+ mutex_lock(&dev->dcam_mutex);
+
+ path_0 = &dev->dcam_cxt.dcam_path[DCAM_PATH0];
+ path_1 = &dev->dcam_cxt.dcam_path[DCAM_PATH1];
+ path_2 = &dev->dcam_cxt.dcam_path[DCAM_PATH2];
+
+ DCAM_TRACE("SPRD_IMG: streamoff, is_work: path_0 = %d, path_1 = %d, path_2 = %d, stream_on = %d \n",
+ path_0->is_work, path_1->is_work, path_2->is_work, atomic_read(&dev->stream_on));
+
+ if (unlikely(0 == atomic_read(&dev->stream_on))) {
+ printk("SPRD_IMG: stream not on\n");
+ ret = sprd_img_local_deinit(dev);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ }
+ mutex_unlock(&dev->dcam_mutex);
+ goto exit;
+ }
+
+ do {
+ ret = sprd_stop_timer(&dev->dcam_timer);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ ret = dcam_stop();
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+
+ ret = dcam_stop_cap();
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+
+ ret = sprd_img_unreg_isr(dev);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+
+ if (path_1->is_work) {
+ path_1->status = PATH_IDLE;
+ path_1->is_work = 0;
+ }
+
+ if (path_2->is_work) {
+ path_2->status = PATH_IDLE;
+
+ if (dev->got_resizer) {
+ ret = sprd_img_unreg_path2_isr(dev);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ dcam_rel_resizer();
+ dev->got_resizer = 0;
+ }
+
+ path_2->is_work = 0;
+ }
+
+ if (path_0->is_work) {
+ path_0->status = PATH_IDLE;
+ path_0->is_work = 0;
+ }
+ DCAM_TRACE("SPRD_IMG: off, path work %d %d %d \n", path_0->is_work, path_1->is_work, path_2->is_work);
+ atomic_set(&dev->stream_on, 0);
+ #if 0
+ if (DCAM_CAP_IF_CSI2 == dev->dcam_cxt.if_mode) {
+ ret = csi_api_close();
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ }
+ #endif
+
+ ret = dcam_module_deinit(dev->dcam_cxt.if_mode, dev->dcam_cxt.sn_mode);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+
+ ret = sprd_img_local_deinit(dev);
+ if (unlikely(ret)) {
+ printk(DEBUG_STR,DEBUG_ARGS);
+ break;
+ }
+ } while(0);
+
+ mutex_unlock(&dev->dcam_mutex);
+ break;
+ }
+
+ case SPRD_IMG_IO_GET_FMT:
+ {
+ struct dcam_format *fmt;
+ struct sprd_img_get_fmt fmt_desc;
+
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_GET_FMT \n");
+ ret = copy_from_user(&fmt_desc, (struct sprd_img_get_fmt *)arg, sizeof(struct sprd_img_get_fmt));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ goto exit;
+ }
+ if (unlikely(fmt_desc.index >= ARRAY_SIZE(dcam_img_fmt)))
+ return -EINVAL;
+
+ fmt = &dcam_img_fmt[fmt_desc.index];
+ fmt_desc.fmt = fmt->fourcc;
+
+ ret = copy_to_user((struct sprd_img_get_fmt *)arg, &fmt_desc, sizeof(struct sprd_img_get_fmt));
+ break;
+ }
+
+ case SPRD_IMG_IO_GET_CH_ID:
+ {
+ struct dcam_path_spec *path_0 = NULL;
+ struct dcam_path_spec *path_1 = NULL;
+ struct dcam_path_spec *path_2 = NULL;
+ struct dcam_get_path_id path_id;
+
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_GET_CH_ID \n");
+ path_0 = &dev->dcam_cxt.dcam_path[DCAM_PATH0];
+ path_1 = &dev->dcam_cxt.dcam_path[DCAM_PATH1];
+ path_2 = &dev->dcam_cxt.dcam_path[DCAM_PATH2];
+
+ memset((void*)&path_id, 0, sizeof(struct dcam_get_path_id));
+ path_id.input_size.w = dev->dcam_cxt.cap_in_rect.w;
+ path_id.input_size.h = dev->dcam_cxt.cap_in_rect.h;
+ path_id.output_size.w = dev->dcam_cxt.dst_size.w;
+ path_id.output_size.h = dev->dcam_cxt.dst_size.h;
+ path_id.fourcc = dev->dcam_cxt.pxl_fmt;
+ path_id.need_isp_tool = dev->dcam_cxt.need_isp_tool;
+ path_id.need_isp = dev->dcam_cxt.need_isp;
+ path_id.need_shrink = dev->dcam_cxt.need_shrink;
+ path_id.input_trim.x = dev->dcam_cxt.path_input_rect.x;
+ path_id.input_trim.y = dev->dcam_cxt.path_input_rect.y;
+ path_id.input_trim.w = dev->dcam_cxt.path_input_rect.w;
+ path_id.input_trim.h = dev->dcam_cxt.path_input_rect.h;
+ DCAM_TRACE("SPRD_IMG: get param, path work %d %d %d \n", path_0->is_work, path_1->is_work, path_2->is_work);
+ path_id.is_path_work[DCAM_PATH0] = path_0->is_work;
+ path_id.is_path_work[DCAM_PATH1] = path_1->is_work;
+ path_id.is_path_work[DCAM_PATH2] = path_2->is_work;
+ ret = dcam_get_path_id(&path_id, &channel_id);
+ ret = copy_to_user((uint32_t *)arg, &channel_id, sizeof(uint32_t));
+ DCAM_TRACE("SPRD_IMG: get channel_id %d \n", channel_id);
+ break;
+ }
+
+ case SPRD_IMG_IO_GET_TIME:
+ {
+ struct timeval time;
+ struct sprd_img_time utime;
+
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_GET_TIME \n");
+ img_get_timestamp(&time);
+ utime.sec = time.tv_sec;
+ utime.usec = time.tv_usec;
+ ret = copy_to_user((struct sprd_img_time *)arg, &utime, sizeof(struct sprd_img_time));
+ break;
+ }
+
+ case SPRD_IMG_IO_CHECK_FMT:
+ {
+ struct dcam_format *fmt;
+ struct sprd_img_format img_format;
+
+ DCAM_TRACE("SPRD_IMG: SPRD_IMG_IO_CHECK_FMT \n");
+ ret = copy_from_user(&img_format, (struct sprd_img_format *)arg, sizeof(struct sprd_img_format));
+ if (ret) {
+ printk("sprd_img_k_ioctl: fail to get user info \n");
+ goto exit;
+ }
+
+ fmt = sprd_img_get_format(img_format.fourcc);
+ if (unlikely(!fmt)) {
+ printk("SPRD_IMG: Fourcc format (0x%08x) invalid. \n",
+ img_format.fourcc);
+ return -EINVAL;
+ }
+
+ if (DCAM_PATH1 == img_format.channel_id) {
+ mutex_lock(&dev->dcam_mutex);
+ ret = sprd_img_check_path1_cap(fmt->fourcc, &img_format, &dev->dcam_cxt);
+ mutex_unlock(&dev->dcam_mutex);
+ channel_id = DCAM_PATH1;
+ } else if (DCAM_PATH2 == img_format.channel_id) {
+ if (img_format.is_lightly) {
+ mutex_lock(&dev->dcam_mutex);
+ ret = sprd_img_check_path2_cap(fmt->fourcc, &img_format, &dev->dcam_cxt);
+ mutex_unlock(&dev->dcam_mutex);
+ } else {
+ if (unlikely(dcam_get_resizer(DCAM_WAIT_FOREVER))) {
+ /*no wait to get the controller of resizer, failed*/
+ printk("SPRD_IMG: path2 has been occupied by other app \n");
+ return -EIO;
+ }
+ dev->got_resizer = 1;
+ mutex_lock(&dev->dcam_mutex);
+ ret = sprd_img_check_path2_cap(fmt->fourcc, &img_format, &dev->dcam_cxt);
+ mutex_unlock(&dev->dcam_mutex);
+ if (ret) {
+ /*failed to set path2, release the controller of resizer*/
+ dcam_rel_resizer();
+ dev->got_resizer = 0;
+ }
+ }
+ channel_id = DCAM_PATH2;
+ } else if (DCAM_PATH0 == img_format.channel_id) {
+ mutex_lock(&dev->dcam_mutex);
+ ret = sprd_img_check_path0_cap(fmt->fourcc, &img_format, &dev->dcam_cxt);
+ mutex_unlock(&dev->dcam_mutex);
+ channel_id = DCAM_PATH0;
+ } else {
+ printk("SPRD_IMG: Buf type invalid. \n");
+ return -EINVAL;
+ }
+
+ memcpy((void*)&img_format.reserved[0], (void*)&dev->dcam_cxt.dcam_path[channel_id].end_sel, sizeof(struct dcam_endian_sel));
+ if ((0 == ret) && (0 != atomic_read(&dev->stream_on))) {
+ if (DCAM_PATH1 == channel_id || DCAM_PATH2 == channel_id) {
+ ret = sprd_img_update_video(file, channel_id);
+ }
+ }
+ ret = copy_to_user((struct sprd_img_format *)arg, &img_format, sizeof(struct sprd_img_format));
+ break;
+ }
+
+ default:
+ printk("sprd_img_k_ioctl: invalid cmd %d \n", cmd);
+ break;
+ }
+
+
+exit:
+ return ret;
+}
+
+ssize_t sprd_img_read(struct file *file, char __user *u_data, size_t cnt, loff_t *cnt_ret)
+{
+ struct dcam_dev *dev = file->private_data;
+ struct dcam_node node;
+ struct dcam_path_spec *path;
+ struct sprd_img_read_op read_op;
+ struct dcam_path_capability path_capability;
+ int fmr_index, i;
+ int ret = 0;
+
+ DCAM_TRACE("SPRD_IMG: sprd_img_read %ld, dev %p \n", cnt, dev);
+
+ if (!dev)
+ return -EFAULT;
+
+ if (cnt < sizeof(struct sprd_img_read_op)) {
+ printk("sprd_img_read: error, cnt %ld read_op %ld \n", cnt, sizeof(struct sprd_img_read_op));
+ return -EIO;
+ }
+
+ ret = copy_from_user(&read_op, (struct sprd_img_read_op *)u_data, sizeof(struct sprd_img_read_op));
+ if (ret) {
+ printk("sprd_img_read: fail to get user info \n");
+ return ret;
+ }
+
+ switch (read_op.cmd) {
+ case SPRD_IMG_GET_SCALE_CAP:
+ DCAM_TRACE("SPRD_IMG: get scale capbility \n");
+ read_op.parm.reserved[0] = DCAM_PATH2_LINE_BUF_LENGTH;
+ read_op.parm.reserved[1] = DCAM_SC_COEFF_UP_MAX;
+ read_op.parm.reserved[2] = DCAM_SCALING_THRESHOLD;
+ DCAM_TRACE("SPRD_IMG: sprd_img_read line threshold %d, sc factor %d, scaling %d.\n",
+ read_op.parm.reserved[0],
+ read_op.parm.reserved[1],
+ read_op.parm.reserved[2]);
+ break;
+
+ case SPRD_IMG_GET_FRM_BUFFER:
+ DCAM_TRACE("SPRD_IMG: read frame buffer \n");
+ memset(&read_op, 0, sizeof(struct sprd_img_read_op));
+ while (1) {
+ ret = down_interruptible(&dev->irq_sem);
+ if (0 == ret) {
+ break;
+ } else if (-EINTR == ret) {
+ read_op.evt = IMG_SYS_BUSY;
+ ret = DCAM_RTN_SUCCESS;
+ goto read_end;
+ }else {
+ printk("SPRD_IMG: read frame buffer, failed to down, %d \n", ret);
+ return -EPERM;
+ }
+ }
+
+ if (sprd_img_queue_read(&dev->queue, &node)) {
+ printk("SPRD_IMG: read frame buffer, queue is null \n");
+ read_op.evt = IMG_SYS_BUSY;
+ ret = DCAM_RTN_SUCCESS;
+ goto read_end;
+ } else {
+ if (node.invalid_flag) {
+ printk("SPRD_IMG: read frame buffer, invalid node\n");
+ read_op.evt = IMG_SYS_BUSY;
+ ret = DCAM_RTN_SUCCESS;
+ goto read_end;
+ }
+ }
+
+ DCAM_TRACE("SPRD_IMG: time, %ld %ld \n", (unsigned long)node.time.tv_sec, (unsigned long)node.time.tv_usec);
+
+ read_op.evt = node.irq_flag;
+ if (IMG_TX_DONE == read_op.evt || IMG_CANCELED_BUF == read_op.evt) {
+ read_op.parm.frame.channel_id = node.f_type;
+ path = &dev->dcam_cxt.dcam_path[read_op.parm.frame.channel_id];
+ DCAM_TRACE("SPRD_IMG: node, 0x%x %d %d \n", node, node.index, path->frm_id_base);
+ read_op.parm.frame.index = path->frm_id_base;//node.index;
+ read_op.parm.frame.height = node.height;
+ read_op.parm.frame.length = node.reserved;
+ read_op.parm.frame.sec = node.time.tv_sec;
+ read_op.parm.frame.usec = node.time.tv_usec;
+ //fmr_index = node.index - path->frm_id_base;
+ //read_op.parm.frame.real_index = path->index[fmr_index];
+ read_op.parm.frame.frm_base_id = path->frm_id_base;
+ read_op.parm.frame.img_fmt = path->fourcc;
+ read_op.parm.frame.yaddr = node.yaddr;
+ read_op.parm.frame.uaddr = node.uaddr;
+ read_op.parm.frame.vaddr = node.vaddr;
+ read_op.parm.frame.yaddr_vir = node.yaddr_vir;
+ read_op.parm.frame.uaddr_vir = node.uaddr_vir;
+ read_op.parm.frame.vaddr_vir = node.vaddr_vir;
+ DCAM_TRACE("index %d real_index %d frm_id_base %d fmr_index %d \n",
+ read_op.parm.frame.index,
+ read_op.parm.frame.real_index,
+ read_op.parm.frame.frm_base_id,
+ fmr_index);
+ } else {
+ if (IMG_TIMEOUT == read_op.evt ||
+ IMG_TX_ERR == read_op.evt)
+ sprd_img_print_reg();
+ }
+ DCAM_TRACE("SPRD_IMG: read frame buffer, evt 0x%x channel_id 0x%x index 0x%x \n",
+ read_op.evt,
+ read_op.parm.frame.channel_id,
+ read_op.parm.frame.index);
+ break;
+
+ case SPRD_IMG_GET_PATH_CAP:
+ DCAM_TRACE("SPRD_IMG: get path capbility \n");
+ dcam_get_path_capability(&path_capability);
+ read_op.parm.capability.count = path_capability.count;
+ for (i = 0; i< path_capability.count; i++) {
+ read_op.parm.capability.path_info[i].line_buf = path_capability.path_info[i].line_buf;
+ read_op.parm.capability.path_info[i].support_yuv = path_capability.path_info[i].support_yuv;
+ read_op.parm.capability.path_info[i].support_raw = path_capability.path_info[i].support_raw;
+ read_op.parm.capability.path_info[i].support_jpeg = path_capability.path_info[i].support_jpeg;
+ read_op.parm.capability.path_info[i].support_scaling = path_capability.path_info[i].support_scaling;
+ read_op.parm.capability.path_info[i].support_trim = path_capability.path_info[i].support_trim;
+ read_op.parm.capability.path_info[i].is_scaleing_path = path_capability.path_info[i].is_scaleing_path;
+ }
+ break;
+
+ default:
+ printk("SPRD_IMG: sprd_img_read, invalid cmd \n");
+ return EINVAL;
+ }
+read_end:
+ return copy_to_user((struct sprd_img_read_op *)u_data, &read_op, sizeof(struct sprd_img_read_op));
+}
+
+ssize_t sprd_img_write(struct file *file, const char __user * u_data, size_t cnt, loff_t *cnt_ret)
+{
+ struct dcam_dev *dev = file->private_data;
+ struct dcam_info *info = &dev->dcam_cxt;
+ struct dcam_path_spec *path;
+ struct sprd_img_write_op write_op;
+ uint32_t index;
+ int ret = 0;
+
+ DCAM_TRACE("SPRD_IMG: sprd_img_write %ld, dev %p \n", cnt, dev);
+
+ if (!dev)
+ return -EFAULT;
+
+ if (cnt < sizeof(struct sprd_img_write_op)) {
+ printk("sprd_img_write: error, cnt %ld read_op %ld \n", cnt, sizeof(struct sprd_img_write_op));
+ return -EIO;
+ }
+
+ ret = copy_from_user(&write_op, (struct sprd_img_write_op *)u_data, sizeof(struct sprd_img_write_op));
+ if (ret) {
+ printk("sprd_img_write: fail to get user info \n");
+ return ret;
+ }
+
+ switch (write_op.cmd) {
+ case SPRD_IMG_STOP_DCAM:
+ mutex_lock(&dev->dcam_mutex);
+ ret = sprd_img_tx_stop(dev);
+ if (ret)
+ ret = 0;
+ else
+ ret = 1;
+ mutex_unlock(&dev->dcam_mutex);
+ break;
+
+ case SPRD_IMG_FREE_FRAME:
+ if (0 == atomic_read(&dev->stream_on)) {
+ printk("SPRD_IMG: dev close, no need free!");
+ break;
+ }
+ switch (write_op.channel_id) {
+ case DCAM_PATH0:
+ case DCAM_PATH1:
+ case DCAM_PATH2:
+ path = &info->dcam_path[write_op.channel_id];
+ break;
+ default:
+ printk("SPRD_IMG: error free frame buffer, channel_id 0x%x \n", write_op.channel_id);
+ return -EINVAL;
+ }
+
+ if (PATH_IDLE == path->status) {
+ DCAM_TRACE("SPRD_IMG: error free frame buffer, wrong status, channel_id 0x%x \n",
+ write_op.channel_id);
+ return -EINVAL;
+ }
+
+ if (unlikely(write_op.index > path->frm_id_base + path->frm_cnt_act - 1)) {
+ printk("SPRD_IMG: error, index %d, frm_id_base %d frm_cnt_act %d \n",
+ write_op.index, path->frm_id_base, path->frm_cnt_act);
+ ret = -EINVAL;
+ } else if (write_op.index < path->frm_id_base) {
+ printk("SPRD_IMG: error, index %d, frm_id_base %d \n",
+ write_op.index, path->frm_id_base);
+ ret = -EINVAL;
+ } else {
+ index = write_op.index - path->frm_id_base;
+ if (path->frm_ptr[index]) {
+ dcam_frame_unlock(path->frm_ptr[index]);
+ }
+ DCAM_TRACE("SPRD_IMG: free frame buffer, channel_id 0x%x, index 0x%x \n",
+ write_op.channel_id, write_op.index);
+ }
+ break;
+
+ default:
+ printk("SPRD_IMG: cmd error! \n");
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+int32_t sprd_dcam_registers_dump(void *buf, uint32_t buf_len)
+{
+ if (NULL == buf || buf_len < 0x400) {
+ printk("%s input para is error", __FUNCTION__);
+ return -1;
+ }
+
+ uint32_t* reg_buf = (uint32_t*)buf;
+ uint32_t reg_buf_len = 0x400;
+ int ret;
+
+ ret = dcam_read_registers(reg_buf, &reg_buf_len);
+ if (ret) {
+ printk("dcam_read_registers return error: %d", ret);
+ return -1;
+ }
+
+ return reg_buf_len;
+}
+
+#if 0
+LOCAL int sprd_img_proc_read(char *page,
+ char **start,
+ off_t off,
+ int count,
+ int *eof,
+ void *data)
+{
+ int len = 0, ret;
+ struct dcam_dev *dev = (struct dcam_dev*)data;
+ uint32_t* reg_buf;
+ uint32_t reg_buf_len = 0x400;
+ uint32_t print_len = 0, print_cnt = 0;
+
+ (void)start; (void)off; (void)count; (void)eof;
+
+ len += sprintf(page + len, "Context for DCAM device \n");
+ len += sprintf(page + len, "*************************************************************** \n");
+ len += sprintf(page + len, "SPRD_ION_MM_SIZE: 0x%x \n", SPRD_ION_MM_SIZE);
+ len += sprintf(page + len, "the configuration of CAP \n");
+ len += sprintf(page + len, " 1. interface mode, %d \n", dev->dcam_cxt.if_mode);
+ len += sprintf(page + len, " 2. sensor mode, %d \n", dev->dcam_cxt.sn_mode);
+ len += sprintf(page + len, " 3. YUV pattern, %d \n", dev->dcam_cxt.yuv_ptn);
+ len += sprintf(page + len, " 4. sync polarities, v %d h %d p %d href %d \n",
+ dev->dcam_cxt.sync_pol.vsync_pol,
+ dev->dcam_cxt.sync_pol.hsync_pol,
+ dev->dcam_cxt.sync_pol.pclk_pol,
+ dev->dcam_cxt.sync_pol.need_href);
+ len += sprintf(page + len, " 5. Data bit-width, %d \n", dev->dcam_cxt.data_bits);
+ len += sprintf(page + len, " 6. need ISP, %d \n", dev->dcam_cxt.dcam_path[DCAM_PATH1].is_from_isp);
+ len += sprintf(page + len, "*************************************************************** \n");
+ len += sprintf(page + len, "the configuration of PATH1 \n");
+ len += sprintf(page + len, " 1. input rect, %d %d %d %d \n",
+ dev->dcam_cxt.dcam_path[DCAM_PATH1].in_rect.x,
+ dev->dcam_cxt.dcam_path[DCAM_PATH1].in_rect.y,
+ dev->dcam_cxt.dcam_path[DCAM_PATH1].in_rect.w,
+ dev->dcam_cxt.dcam_path[DCAM_PATH1].in_rect.h);
+ len += sprintf(page + len, " 2. output size, %d %d \n",
+ dev->dcam_cxt.dcam_path[DCAM_PATH1].out_size.w,
+ dev->dcam_cxt.dcam_path[DCAM_PATH1].out_size.h);
+ len += sprintf(page + len, " 3. output format, %d \n",
+ dev->dcam_cxt.dcam_path[DCAM_PATH1].out_fmt);
+ len += sprintf(page + len, " 4. frame base index, 0x%x \n", dev->dcam_cxt.dcam_path[DCAM_PATH1].frm_id_base);
+ len += sprintf(page + len, " 5. frame count, 0x%x \n", dev->dcam_cxt.dcam_path[DCAM_PATH1].frm_cnt_act);
+ len += sprintf(page + len, " 6. frame type, 0x%x \n", dev->dcam_cxt.dcam_path[DCAM_PATH1].frm_type);
+ for (print_cnt = 0; print_cnt < DCAM_PATH_1_FRM_CNT_MAX; print_cnt ++) {
+ len += sprintf(page + len, "%2d. frame buffer%d, 0x%08x 0x%08x 0x%08x \n",
+ (6 + print_cnt),
+ print_cnt,
+ dev->dcam_cxt.dcam_path[DCAM_PATH1].frm_addr[print_cnt].yaddr,
+ dev->dcam_cxt.dcam_path[DCAM_PATH1].frm_addr[print_cnt].uaddr,
+ dev->dcam_cxt.dcam_path[DCAM_PATH1].frm_addr[print_cnt].vaddr);
+ }
+
+ if (dev->dcam_cxt.dcam_path[DCAM_PATH2].is_work) {
+ len += sprintf(page + len, "*************************************************************** \n");
+ len += sprintf(page + len, "the configuration of PATH2 \n");
+ len += sprintf(page + len, " 1. input rect, %d %d %d %d \n",
+ dev->dcam_cxt.dcam_path[DCAM_PATH2].in_rect.x,
+ dev->dcam_cxt.dcam_path[DCAM_PATH2].in_rect.y,
+ dev->dcam_cxt.dcam_path[DCAM_PATH2].in_rect.w,
+ dev->dcam_cxt.dcam_path[DCAM_PATH2].in_rect.h);
+ len += sprintf(page + len, " 2. output size, %d %d \n",
+ dev->dcam_cxt.dcam_path[DCAM_PATH2].out_size.w,
+ dev->dcam_cxt.dcam_path[DCAM_PATH2].out_size.h);
+ len += sprintf(page + len, " 3. output format, %d \n",
+ dev->dcam_cxt.dcam_path[DCAM_PATH2].out_fmt);
+ len += sprintf(page + len, " 4. frame base index, 0x%x \n", dev->dcam_cxt.dcam_path[DCAM_PATH2].frm_id_base);
+ len += sprintf(page + len, " 5. frame count, 0x%x \n", dev->dcam_cxt.dcam_path[DCAM_PATH2].frm_cnt_act);
+ len += sprintf(page + len, " 6. frame type, 0x%x \n", dev->dcam_cxt.dcam_path[DCAM_PATH2].frm_type);
+ for (print_cnt = 0; print_cnt < DCAM_PATH_2_FRM_CNT_MAX; print_cnt ++) {
+ len += sprintf(page + len, "%2d. frame buffer%d, 0x%8x 0x%8x 0x%8x \n",
+ (6 + print_cnt),
+ print_cnt,
+ dev->dcam_cxt.dcam_path[DCAM_PATH2].frm_addr[print_cnt].yaddr,
+ dev->dcam_cxt.dcam_path[DCAM_PATH2].frm_addr[print_cnt].uaddr,
+ dev->dcam_cxt.dcam_path[DCAM_PATH2].frm_addr[print_cnt].vaddr);
+ }
+
+ }
+
+ reg_buf = (uint32_t*)vzalloc(reg_buf_len);
+ ret = dcam_read_registers(reg_buf, &reg_buf_len);
+ if (ret) {
+ vfree(reg_buf);
+ return len;
+ }
+
+ len += sprintf(page + len, "*************************************************************** \n");
+ len += sprintf(page + len, "dcam registers \n");
+ print_cnt = 0;
+ while (print_len < reg_buf_len) {
+ len += sprintf(page + len, "offset 0x%03x: 0x%08x, 0x%08x, 0x%08x, 0x%08x \n",
+ print_len,
+ reg_buf[print_cnt],
+ reg_buf[print_cnt+1],
+ reg_buf[print_cnt+2],
+ reg_buf[print_cnt+3]);
+ print_cnt += 4;
+ print_len += 16;
+ }
+
+ ret = csi_read_registers(reg_buf, &reg_buf_len);
+ if (ret) {
+ vfree(reg_buf);
+ return len;
+ }
+
+ len += sprintf(page + len, "*************************************************************** \n");
+ len += sprintf(page + len, "csi host registers \n");
+ print_cnt = 0;
+ print_len = 0;
+ while (print_len < reg_buf_len) {
+ len += sprintf(page + len, "offset 0x%03x: 0x%08x, 0x%08x, 0x%08x, 0x%08x \n",
+ print_len,
+ reg_buf[print_cnt],
+ reg_buf[print_cnt+1],
+ reg_buf[print_cnt+2],
+ reg_buf[print_cnt+3]);
+ print_cnt += 4;
+ print_len += 16;
+ }
+ len += sprintf(page + len, "*************************************************************** \n");
+ len += sprintf(page + len, "The end of DCAM device \n");
+ msleep(10);
+ vfree(reg_buf);
+
+ return len;
+}
+#endif
+
+static struct file_operations image_fops = {
+ .owner = THIS_MODULE,
+ .open = sprd_img_k_open,
+ .unlocked_ioctl = sprd_img_k_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = sprd_img_k_ioctl,
+#endif
+ .release = sprd_img_k_release,
+ .read = sprd_img_read,
+ .write = sprd_img_write,
+};
+
+static struct miscdevice image_dev = {
+ .minor = IMAGE_MINOR,
+ .name = IMG_DEVICE_NAME,
+ .fops = &image_fops,
+};
+
+
+int sprd_img_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ printk(KERN_ALERT "sprd_img_probe called\n");
+
+ ret = misc_register(&image_dev);
+ if (ret) {
+ printk(KERN_ERR "cannot register miscdev on minor=%d (%d)\n",
+ IMAGE_MINOR, ret);
+ ret = -EACCES;
+ goto exit;
+ }
+ image_dev.this_device->of_node = pdev->dev.of_node;
+ parse_baseaddress(pdev->dev.of_node);
+
+ printk(KERN_ALERT "sprd_img_probe Success\n");
+ goto exit;
+
+exit:
+ return ret;
+}
+
+static int sprd_img_remove(struct platform_device *pdev)
+{
+ misc_deregister(&image_dev);
+ return 0;
+}
+
+static void sprd_img_shutdown(struct platform_device *pdev)
+{
+ sprd_flash_close();
+}
+
+LOCAL const struct of_device_id of_match_table_dcam[] = {
+ { .compatible = "sprd,sprd_dcam", },
+ { },
+};
+LOCAL struct platform_driver sprd_img_driver = {
+ .probe = sprd_img_probe,
+ .remove = sprd_img_remove,
+ .shutdown = sprd_img_shutdown,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = IMG_DEVICE_NAME,
+ .of_match_table = of_match_ptr(of_match_table_dcam),
+ },
+};
+
+int __init sprd_img_k_init(void)
+{
+ if (platform_driver_register(&sprd_img_driver) != 0) {
+ printk("platform device register Failed \n");
+ return -1;
+ }
+
+ if (dcam_scale_coeff_alloc()) {
+ printk("dcam_scale_coeff_alloc Failed \n");
+ return -1;
+ }
+
+ printk(KERN_INFO "Video Technology Magazine Virtual Video "
+ "Capture Board ver %u.%u.%u successfully loaded.\n",
+ (DCAM_VERSION >> 16) & 0xFF, (DCAM_VERSION >> 8) & 0xFF,
+ DCAM_VERSION & 0xFF);
+ return 0;
+}
+
+void sprd_img_k_exit(void)
+{
+ dcam_scale_coeff_free();
+ platform_driver_unregister(&sprd_img_driver);
+}
+
+module_init(sprd_img_k_init);
+module_exit(sprd_img_k_exit);
+MODULE_DESCRIPTION("DCAM Driver");
+MODULE_AUTHOR("Multimedia_Camera@Spreadtrum");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/media/sprd_dcam/common/flash_test.c b/drivers/media/sprd_dcam/common/flash_test.c
new file mode 100644
index 00000000..dc8be3ef
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/flash_test.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (C) 2014 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+/* notes : note location /sys/class/flash_test/flash_test/
+ * echo 0x11>flash_value
+ * cat flash_value
+ */
+#include "flash_test.h"
+#include "parse_hwinfo.h"
+#include <../flash/flash.h>
+
+#define SENSOR_K_SUCCESS 0
+#define SENSOR_K_FAIL (-1)
+#define SENSOR_K_FALSE 0
+#define SENSOR_K_TRUE 1
+
+
+static struct class* flash_test_class = NULL;
+static int g_flash_mode=0;
+
+int setflash(uint32_t flash_mode)
+{
+ switch (flash_mode) {
+ case FLASH_OPEN: /*flash on */
+ case FLASH_TORCH: /*for torch low light */
+ sprd_flash_on();
+ break;
+ case FLASH_HIGH_LIGHT: /*high light */
+ sprd_flash_on();
+ break;
+ case FLASH_CLOSE_AFTER_OPEN: /*close flash */
+ case FLASH_CLOSE_AFTER_AUTOFOCUS:
+ case FLASH_CLOSE:
+ sprd_flash_close();
+ break;
+ default:
+ printk("sprd_v4l2_setflash unknow mode:flash_mode 0x%x \n", flash_mode);
+ break;
+ }
+ return 0;
+}
+
+static ssize_t flash_test_show(struct device* dev,
+ struct device_attribute* attr, char* buf)
+{
+ return snprintf(buf, PAGE_SIZE, "flash_mode is :0x%x\n", g_flash_mode);
+}
+
+static ssize_t flash_test_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,size_t c)
+{
+ int ret;
+ unsigned long flash_mode;
+ printk(KERN_ALERT"flash_test_store buf=%s line %d .\n",buf,__LINE__);
+ ret = kstrtoul(buf, 16, &flash_mode);
+ if (ret)
+ return ret;
+ g_flash_mode=flash_mode;
+ setflash(flash_mode);
+ return c;
+}
+static DEVICE_ATTR(flash_value, 0644, flash_test_show, flash_test_store);
+
+static int __init flash_test_init(void){
+ int err = -1;
+ dev_t dev_num = 0;
+ int flash_test_major = 0;
+ int flash_test_minor = 0;
+ struct device* flash_test_dev = NULL;
+ err = alloc_chrdev_region(&dev_num, 0, 1, FLASH_TEST_DEVICE_NODE_NAME);
+ if (err < 0) {
+ printk(KERN_ALERT"Failed to alloc char dev region.\n");
+ goto fail;
+ }
+ flash_test_major = MAJOR(dev_num);
+ flash_test_minor = MINOR(dev_num);
+ flash_test_class = class_create(THIS_MODULE, FLASH_TEST_DEVICE_CLASS_NAME);
+ if (IS_ERR(flash_test_class)) {
+ err = PTR_ERR(flash_test_class);
+ printk(KERN_ALERT"Failed to create flash_test class.\n");
+ goto destroy_class;
+ }
+ flash_test_dev = device_create(flash_test_class, NULL, dev_num, "%s", FLASH_TEST_DEVICE_FILE_NAME);
+ if (IS_ERR(flash_test_dev)) {
+ err = PTR_ERR(flash_test_dev);
+ printk(KERN_ALERT"Failed to create flash_test device.");
+ goto destroy_class;
+ }
+ err = device_create_file(flash_test_dev, &dev_attr_flash_value);
+ if (err < 0) {
+ printk(KERN_ALERT"Failed to create attribute val.");
+ goto destroy_device;
+ }
+ return 0;
+destroy_device:
+ device_destroy(flash_test_class, dev_num);
+destroy_class:
+ class_destroy(flash_test_class);
+ unregister_chrdev_region(MKDEV(flash_test_major, flash_test_minor), 1);
+fail:
+ return err;
+}
+module_init(flash_test_init);
+MODULE_AUTHOR("freed wang, spreadtrum");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Flash test Interface");
diff --git a/drivers/media/sprd_dcam/common/flash_test.h b/drivers/media/sprd_dcam/common/flash_test.h
new file mode 100644
index 00000000..03011b30
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/flash_test.h
@@ -0,0 +1,38 @@
+#ifndef _FLASH_TEST_H_
+#define _FLASH_TEST_H_
+
+#include <linux/semaphore.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/cdev.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/of_gpio.h>
+#include <linux/proc_fs.h>
+#include <soc/sprd/adi.h>
+#ifndef CONFIG_64BIT
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#endif
+
+#define FLASH_TEST_DEVICE_NODE_NAME "flash_test"
+#define FLASH_TEST_DEVICE_FILE_NAME "flash_test"
+#define FLASH_TEST_DEVICE_PROC_NAME "flash_test"
+#define FLASH_TEST_DEVICE_CLASS_NAME "flash_test"
+
+enum flash_status {
+ FLASH_CLOSE = 0x0,
+ FLASH_OPEN = 0x1,
+ FLASH_TORCH = 0x2, /*user only set flash to close/open/torch state */
+ FLASH_AUTO = 0x3,
+ FLASH_CLOSE_AFTER_OPEN = 0x10, /* following is set to sensor */
+ FLASH_HIGH_LIGHT = 0x11,
+ FLASH_OPEN_ON_RECORDING = 0x22,
+ FLASH_CLOSE_AFTER_AUTOFOCUS = 0x30,
+ FLASH_STATUS_MAX
+};
+
+#endif
diff --git a/drivers/media/sprd_dcam/common/gen_scale_coef.c b/drivers/media/sprd_dcam/common/gen_scale_coef.c
new file mode 100644
index 00000000..1cf6e95d
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/gen_scale_coef.c
@@ -0,0 +1,699 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include "sin_cos.h"
+#include "gen_scale_coef.h"
+#include <linux/mm.h>
+#include <linux/math64.h>
+
+#define GSC_FIX 24
+#define GSC_COUNT 256
+
+#define GSC_ABS(_a) ((_a) < 0 ? -(_a) : (_a))
+#define GSC_SIGN2(input, p) {if (p>=0) input = 1; if (p < 0) input = -1;}
+#define COEF_ARR_ROWS 9
+#define COEF_ARR_COLUMNS 8
+#define COEF_ARR_COL_MAX 16
+#define MIN_POOL_SIZE (6 * 1024)
+#define TRUE 1
+#define FALSE 0
+#define SCI_MEMSET memset
+#define MAX( _x, _y ) ( ((_x) > (_y)) ? (_x) : (_y) )
+
+typedef struct {
+ unsigned long begin_addr;
+ uint32_t total_size;
+ uint32_t used_size;
+} GSC_MEM_POOL;
+
+
+static uint8_t _InitPool(void *buffer_ptr,
+ uint32_t buffer_size, GSC_MEM_POOL * pool_ptr)
+{
+ if (NULL == buffer_ptr || 0 == buffer_size || NULL == pool_ptr) {
+ return FALSE;
+ }
+ if (buffer_size < MIN_POOL_SIZE) {
+ return FALSE;
+ }
+ pool_ptr->begin_addr = (unsigned long) buffer_ptr;
+ pool_ptr->total_size = buffer_size;
+ pool_ptr->used_size = 0;
+ return TRUE;
+}
+
+static void *_Allocate(uint32_t size,
+ uint32_t align_shift, GSC_MEM_POOL * pool_ptr)
+{
+ unsigned long begin_addr = 0;
+ unsigned long temp_addr = 0;
+
+ if (NULL == pool_ptr) {
+ return NULL;
+ }
+ begin_addr = pool_ptr->begin_addr;
+ temp_addr = begin_addr + pool_ptr->used_size;
+ temp_addr =
+ ((temp_addr + (1 << align_shift) -
+ 1) >> align_shift) << align_shift;
+ if (temp_addr + size > begin_addr + pool_ptr->total_size) {
+ return NULL;
+ }
+ pool_ptr->used_size = (temp_addr + size) - begin_addr;
+ SCI_MEMSET((void *)temp_addr, 0, size);
+ return (void *)temp_addr;
+}
+
+static int64_t div64_s64_s64(int64_t dividend, int64_t divisor)
+{
+ int8_t sign = 1;
+ int64_t dividend_tmp = dividend;
+ int64_t divisor_tmp = divisor;
+ int64_t ret = 0;
+ if (0 == divisor) {
+ return 0;
+ }
+ if ((dividend >> 63) & 0x1) {
+ sign *= -1;
+ dividend_tmp = dividend * (-1);
+ }
+ if ((divisor >> 63) & 0x1) {
+ sign *= -1;
+ divisor_tmp = divisor * (-1);
+ }
+ ret = div64_s64(dividend_tmp, divisor_tmp);
+ ret *= sign;
+ return ret;
+}
+
+static void normalize_inter(int64_t * data, int16_t * int_data, uint8_t ilen)
+{
+ uint8_t it;
+ int64_t tmp_d = 0;
+ int64_t *tmp_data = NULL;
+ int64_t tmp_sum_val = 0;
+ tmp_data = data;
+ tmp_sum_val = 0;
+ for (it = 0; it < ilen; it++) {
+ tmp_sum_val += tmp_data[it];
+ }
+ if (0 == tmp_sum_val) {
+ uint8_t value = 256 / ilen;
+ for (it = 0; it < ilen; it++) {
+ tmp_d = value;
+ int_data[it] = (int16_t) tmp_d;
+ }
+ } else {
+ for (it = 0; it < ilen; it++) {
+ tmp_d =
+ div64_s64_s64(tmp_data[it] * (int64_t) 256,
+ tmp_sum_val);
+ int_data[it] = (uint16_t) tmp_d;
+ }
+ }
+}
+
+static int16_t sum_fun(int16_t * data, int8_t ilen)
+{
+ int8_t i;
+ int16_t tmp_sum;
+ tmp_sum = 0;
+
+ for (i = 0; i < ilen; i++)
+ tmp_sum += *data++;
+ return tmp_sum;
+}
+
+static void adjust_filter_inter(int16_t * filter, uint8_t ilen)
+{
+ int32_t i, midi;
+ int32_t tmpi, tmp_S;
+ int32_t tmp_val = 0;
+
+ tmpi = sum_fun(filter, ilen) - 256;
+ midi = ilen >> 1;
+ GSC_SIGN2(tmp_val, tmpi);
+
+ if ((tmpi & 1) == 1) {
+ filter[midi] = filter[midi] - tmp_val;
+ tmpi -= tmp_val;
+ }
+ tmp_S = GSC_ABS(tmpi / 2);
+ if ((ilen & 1) == 1) {
+ for (i = 0; i < tmp_S; i++) {
+ filter[midi - (i + 1)] =
+ filter[midi - (i + 1)] - tmp_val;
+ filter[midi + (i + 1)] =
+ filter[midi + (i + 1)] - tmp_val;
+ }
+ } else {
+ for (i = 0; i < tmp_S; i++) {
+ filter[midi - (i + 1)] =
+ filter[midi - (i + 1)] - tmp_val;
+ filter[midi + i] = filter[midi + i] - tmp_val;
+ }
+ }
+ if (filter[midi] > 255) {
+ tmp_val = filter[midi];
+ filter[midi] = 255;
+ filter[midi - 1] = filter[midi - 1] + tmp_val - 255;
+ }
+}
+
+static int16_t CalYmodelCoef(int16_t coef_lenght,
+ int16_t * coef_data_ptr,
+ int16_t N, int16_t M, GSC_MEM_POOL * pool_ptr)
+{
+ int8_t mount;
+ int16_t i, mid_i, kk, j, sum_val;
+ int64_t *filter = _Allocate(GSC_COUNT * sizeof(int64_t), 3, pool_ptr);
+ int64_t *tmp_filter =
+ _Allocate(GSC_COUNT * sizeof(int64_t), 3, pool_ptr);
+ int16_t *normal_filter =
+ _Allocate(GSC_COUNT * sizeof(int16_t), 2, pool_ptr);
+
+ if (NULL == filter || NULL == tmp_filter || NULL == normal_filter) {
+ return 1;
+ }
+ mid_i = coef_lenght >> 1;
+ filter[mid_i] =
+ div64_s64_s64((int64_t) ((int64_t) N << GSC_FIX),
+ (int64_t) MAX(M, N));
+ for (i = 0; i < mid_i; i++) {
+ int64_t angle_x =
+ div64_s64_s64((int64_t) ARC_32_COEF * (int64_t) (i + 1) *
+ (int64_t) N, (int64_t) MAX(M,
+ N) * (int64_t) 8);
+ int64_t angle_y =
+ div64_s64_s64((int64_t) ARC_32_COEF * (int64_t) (i + 1) *
+ (int64_t) N, (int64_t) (M * N) * (int64_t) 8);
+ int32_t value_x = dcam_sin_32((int32_t) angle_x);
+ int32_t value_y = dcam_sin_32((int32_t) angle_y);
+ filter[mid_i + i + 1] =
+ div64_s64_s64((int64_t)
+ ((int64_t) value_x *
+ (int64_t) (1 << GSC_FIX)),
+ (int64_t) ((int64_t) M * (int64_t) value_y));
+ filter[mid_i - (i + 1)] = filter[mid_i + i + 1];
+ }
+ for (i = -1; i < mid_i; i++) {
+ int32_t angle_32 =
+ (int32_t)
+ div64_s64_s64((int64_t)
+ ((int64_t) 2 * (int64_t) (mid_i - i - 1) *
+ (int64_t) ARC_32_COEF),
+ (int64_t) coef_lenght);
+ int64_t a = (int64_t) 9059697;
+ int64_t b = (int64_t) 7717519;
+ int64_t t = a - ((b * dcam_cos_32(angle_32)) >> 30);
+ filter[mid_i + i + 1] = (t * filter[mid_i + i + 1]) >> GSC_FIX;
+ filter[mid_i - (i + 1)] = filter[mid_i + i + 1];
+ }
+ for (i = 0; i < 8; i++) {
+ mount = 0;
+ for (j = i; j < coef_lenght; j += 8) {
+ tmp_filter[mount] = filter[j];
+ mount++;
+ }
+ normalize_inter(tmp_filter, normal_filter, (int8_t) mount);
+ sum_val = sum_fun(normal_filter, mount);
+ if (256 != sum_val) {
+ adjust_filter_inter(normal_filter, mount);
+ }
+ mount = 0;
+ for (kk = i; kk < coef_lenght; kk += 8) {
+ coef_data_ptr[kk] = normal_filter[mount];
+ mount++;
+ }
+ }
+ return 0;
+}
+
+static int16_t CalY_ScalingCoef(int16_t tap,
+ int16_t D,
+ int16_t I,
+ int16_t * y_coef_data_ptr,
+ int16_t dir, GSC_MEM_POOL * pool_ptr)
+{
+ uint16_t coef_lenght;
+
+ coef_lenght = (uint16_t) (tap * 8);
+ SCI_MEMSET(y_coef_data_ptr, 0, coef_lenght * sizeof(int16_t));
+ CalYmodelCoef(coef_lenght, y_coef_data_ptr, I, D, pool_ptr);
+ return coef_lenght;
+}
+
+static int16_t CalUV_ScalingCoef(int16_t tap,
+ int16_t D,
+ int16_t I,
+ int16_t * uv_coef_data_ptr,
+ int16_t dir, GSC_MEM_POOL * pool_ptr)
+{
+ int16_t uv_coef_lenght;
+
+ if ((dir == 1)) {
+ uv_coef_lenght = (int16_t) (tap * 8);
+ CalYmodelCoef(uv_coef_lenght, uv_coef_data_ptr, I, D, pool_ptr);
+ } else {
+ if (D > I) {
+ uv_coef_lenght = (int16_t) (tap * 8);
+ } else {
+ uv_coef_lenght = (int16_t) (2 * 8);
+ }
+ CalYmodelCoef(uv_coef_lenght, uv_coef_data_ptr, I, D, pool_ptr);
+ }
+ return uv_coef_lenght;
+}
+
+static void GetFilter(int16_t * coef_data_ptr,
+ int16_t * out_filter,
+ int16_t iI_hor, int16_t coef_len, int16_t * filter_len)
+{
+ int16_t i, pos_start;
+
+ pos_start = coef_len / 2;
+ while (pos_start >= iI_hor) {
+ pos_start -= iI_hor;
+ }
+ for (i = 0; i < iI_hor; i++) {
+ int16_t len = 0;
+ int16_t j;
+ int16_t pos = pos_start + i;
+ while (pos >= iI_hor) {
+ pos -= iI_hor;
+ }
+ for (j = 0; j < coef_len; j += iI_hor) {
+ *out_filter++ = coef_data_ptr[j + pos];
+ len++;
+ }
+ *filter_len++ = len;
+ }
+}
+
+static void WriteScalarCoef(int16_t * dst_coef_ptr,
+ int16_t * coef_ptr, int16_t dst_pitch, int16_t src_pitch)
+{
+ int i, j;
+
+ for (i = 0; i < 8; i++) {
+ for (j = 0; j < src_pitch; j++) {
+ *(dst_coef_ptr + j) =
+ *(coef_ptr + i * src_pitch + src_pitch - 1 - j);
+ }
+ dst_coef_ptr += dst_pitch;
+ }
+}
+
+static void SetHorRegisterCoef(uint32_t * reg_coef_ptr, int16_t * y_coef_ptr,
+ int16_t * uv_coef_ptr)
+{
+ int32_t i = 0;
+ int16_t *y_coef_arr[COEF_ARR_ROWS] = { NULL };
+ int16_t *uv_coef_arr[COEF_ARR_ROWS] = { NULL };
+
+ for (i = 0; i < COEF_ARR_ROWS; i++) {
+ y_coef_arr[i] = y_coef_ptr;
+ uv_coef_arr[i] = uv_coef_ptr;
+ y_coef_ptr += COEF_ARR_COLUMNS;
+ uv_coef_ptr += COEF_ARR_COLUMNS;
+ }
+
+ // horizontal Y Scaling Coef Config register
+ for (i = 0; i < 8; i++) {
+ uint16_t p0, p1;
+ uint32_t reg;
+
+ p0 = (uint16_t) y_coef_arr[i][7];
+ p1 = (uint16_t) y_coef_arr[i][6];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ p0 = (uint16_t) y_coef_arr[i][5];
+ p1 = (uint16_t) y_coef_arr[i][4];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ p0 = (uint16_t) y_coef_arr[i][3];
+ p1 = (uint16_t) y_coef_arr[i][2];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ p0 = (uint16_t) y_coef_arr[i][1];
+ p1 = (uint16_t) y_coef_arr[i][0];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ }
+ // horizontal UV Scaling Coef Config register
+ for (i = 0; i < 8; i++) {
+ uint16_t p0, p1;
+ uint32_t reg;
+
+ p0 = (uint16_t) uv_coef_arr[i][3];
+ p1 = (uint16_t) uv_coef_arr[i][2];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ p0 = (uint16_t) uv_coef_arr[i][1];
+ p1 = (uint16_t) uv_coef_arr[i][0];
+ reg = ((p0 & 0x1ff)) | ((p1 & 0x1ff) << 9);
+ *reg_coef_ptr++ = reg;
+ }
+}
+
+static void SetVerRegisterCoef(uint32_t * reg_coef_lum_ptr,
+ uint32_t *reg_coef_ch_ptr,
+ int16_t * y_coef_ptr,
+ int16_t * uv_coef_ptr,
+ int16_t i_h,//decimition at horizontal
+ int16_t o_h,//interpolation at horizontal
+ uint8_t is_scaling2yuv420)
+{
+ uint32_t cnts = 0;
+ uint32_t i = 0, j = 0;
+
+ if(2 * o_h <= i_h)
+ {
+ for(i = 0; i < 9; i++)
+ {
+ for(j = 0; j < 16; j++)
+ {
+ reg_coef_lum_ptr[cnts++] = *(y_coef_ptr +i * 16 + j);
+ if(SCALER_COEF_TAB_LEN_VER == cnts)
+ {
+ break;
+ }
+ }
+ }
+
+ cnts = 0;
+ for(i = 0; i < 9; i++)
+ {
+ for(j = 0; j < 16; j++)
+ {
+ reg_coef_ch_ptr[cnts++] = *(uv_coef_ptr + i * 16 +j);
+ if(SCALER_COEF_TAB_LEN_VER == cnts)
+ {
+ break;
+ }
+ }
+
+ }
+ }
+ else
+ {
+ for(i = 0; i < 8; i++)
+ {
+ for(j = 0; j < 4; j++)
+ {
+ reg_coef_lum_ptr[cnts++] = *(y_coef_ptr +i * 16 + j);
+
+ }
+ }
+
+ cnts = 0;
+ if((o_h <= i_h) && is_scaling2yuv420)
+ {
+ for(i = 0; i < 9; i++)
+ {
+ for(j = 0; j < 16; j++)
+ {
+ reg_coef_ch_ptr[cnts++] = *(uv_coef_ptr +i * 16 + j);
+ if(SCALER_COEF_TAB_LEN_VER == cnts)
+ {
+ break;
+ }
+ }
+
+ }
+ }
+ else
+ {
+ for(i = 0; i < 8; i++)
+ {
+ for(j = 0; j < 4; j++)
+ {
+ reg_coef_ch_ptr[cnts++] = *(uv_coef_ptr +i * 16 + j);
+ }
+ }
+ }
+ }
+}
+
+static void CheckCoefRange(int16_t * coef_ptr, int16_t rows, int16_t columns, int16_t pitch)
+{
+ int16_t i, j;
+ int16_t value, diff, sign;
+ int16_t *coef_arr[COEF_ARR_ROWS] = { NULL };
+
+ for (i = 0; i < COEF_ARR_ROWS; i++) {
+ coef_arr[i] = coef_ptr;
+ coef_ptr += pitch;
+ }
+ for (i = 0; i < rows; i++) {
+ for (j = 0; j < columns; j++) {
+ value = coef_arr[i][j];
+ if (value > 255) {
+ diff = value - 255;
+ coef_arr[i][j] = 255;
+ sign = GSC_ABS(diff);
+ if ((sign & 1) == 1) { // ilen is odd
+ coef_arr[i][j + 1] =
+ coef_arr[i][j + 1] + (diff + 1) / 2;
+ coef_arr[i][j - 1] =
+ coef_arr[i][j - 1] + (diff - 1) / 2;
+ } else { // ilen is even
+ coef_arr[i][j + 1] =
+ coef_arr[i][j + 1] + (diff) / 2;
+ coef_arr[i][j - 1] =
+ coef_arr[i][j - 1] + (diff) / 2;
+ }
+ }
+ }
+ }
+}
+
+static void CalcVerEdgeCoef(int16_t * coeff_ptr, int16_t D, int16_t I,
+ int16_t tap, int16_t pitch)
+{
+ int32_t phase_temp[9];
+ int32_t acc = 0;
+ int32_t i_sample_cnt = 0;
+ uint8_t phase = 0;
+ uint8_t spec_tap = 0;
+ int32_t l;
+ int16_t i, j;
+ int16_t *coeff_arr[COEF_ARR_ROWS];
+
+ for (i = 0; i < COEF_ARR_ROWS; i++) {
+ coeff_arr[i] = coeff_ptr;
+ coeff_ptr += pitch;
+ }
+ for (j = 0; j <= 8; j++)
+ phase_temp[j] = j * I / 8;
+
+ for (i = 0; i < I; i++) {
+ spec_tap = i & 1;
+ while (acc >= I) {
+ acc -= I;
+ i_sample_cnt++;
+ }
+
+ for (j = 0; j < 8; j++) {
+ if (acc >= phase_temp[j] && acc < phase_temp[j + 1]) {
+ phase = (uint8_t) j;
+ break;
+ }
+ }
+
+ {
+ int32_t j;
+ for (j = (1 - tap / 2); j <= (tap / 2); j++) {
+ l = i_sample_cnt + j;
+ if (l <= 0) {
+ coeff_arr[8][spec_tap] +=
+ coeff_arr[phase][j + tap / 2 - 1];
+ } else {
+ if (l >= D - 1) {
+ coeff_arr[8][spec_tap + 2] +=
+ coeff_arr[phase][j +
+ tap / 2 -
+ 1];
+ }
+ }
+ }
+ }
+ acc += D;
+ }
+}
+
+/**---------------------------------------------------------------------------*
+ ** Public Functions *
+ **---------------------------------------------------------------------------*/
+/****************************************************************************/
+/* Purpose: generate scale factor */
+/* Author: */
+/* Input: */
+/* i_w: source image width */
+/* i_h: source image height */
+/* o_w: target image width */
+/* o_h: target image height */
+/* Output: */
+/* coeff_h_ptr: pointer of horizontal coefficient buffer, the size of which must be at */
+/* least SCALER_COEF_TAP_NUM_HOR * 4 bytes */
+/* the output coefficient will be located in coeff_h_ptr[0], ......, */
+/* coeff_h_ptr[SCALER_COEF_TAP_NUM_HOR-1] */
+/* coeff_v_ptr: pointer of vertical coefficient buffer, the size of which must be at */
+/* least (SCALER_COEF_TAP_NUM_VER + 1) * 4 bytes */
+/* the output coefficient will be located in coeff_v_ptr[0], ......, */
+/* coeff_h_ptr[SCALER_COEF_TAP_NUM_VER-1] and the tap number */
+/* will be located in coeff_h_ptr[SCALER_COEF_TAP_NUM_VER] */
+/* temp_buf_ptr: temp buffer used while generate the coefficient */
+/* temp_buf_ptr: temp buffer size, 6k is the suggest size */
+/* Return: */
+/* Note: */
+/****************************************************************************/
+uint8_t Dcam_GenScaleCoeff(int16_t i_w,
+ int16_t i_h,
+ int16_t o_w,
+ int16_t o_h,
+ uint32_t *coeff_h_ptr,
+ uint32_t *coeff_v_lum_ptr,
+ uint32_t *coeff_v_ch_ptr,
+ uint8_t scaling2yuv420,
+ uint8_t *scaler_tap,
+ uint8_t *chrome_tap,
+ void *temp_buf_ptr,
+ uint32_t temp_buf_size
+ )
+{
+ int16_t D_hor = i_w; //decimition at horizontal
+ int16_t D_ver = i_h; //decimition at vertical
+ int16_t I_hor = o_w; //interpolation at horizontal
+ int16_t I_ver = o_h; //interpolation at vertical
+ int16_t I_ver_bak_uv = o_h;
+ int16_t I_ver_bak_y = o_h;
+ int16_t *cong_Ycom_hor = 0;
+ int16_t *cong_UVcom_hor = 0;
+ int16_t *cong_Ycom_ver = 0;
+ int16_t *cong_UVcom_ver = 0;
+
+ uint16_t luma_ver_tap, chrome_ver_tap;
+ uint16_t luma_ver_maxtap = 16, chrome_ver_maxtap = 16;
+
+ uint32_t coef_buf_size = 0;
+ int16_t *temp_filter_ptr = NULL;
+ int16_t *filter_ptr = NULL;
+ uint32_t filter_buf_size = GSC_COUNT * sizeof(int16_t);
+ int16_t filter_len[COEF_ARR_ROWS] = { 0 };
+ int16_t coef_len = 0;
+ GSC_MEM_POOL pool = { 0 };
+
+ if (0 == i_w || 0 == i_h || 0 == o_w || (0 == o_h) \
+ || (NULL == coeff_h_ptr) || (NULL == coeff_v_lum_ptr) \
+ || (NULL == coeff_v_ch_ptr) || (NULL == scaler_tap) \
+ || (NULL == chrome_tap) || (NULL == temp_buf_ptr)) {
+
+ printk("GenScaleCoeff: i_w: %d, i_h: %d, o_w:%d, o_h: %d, coef_h:%p, coef_v_lum:%p, \
+ coef_v_chr: %p, y_tap: %p, ch_tap: %p, tmp_buf:%p",
+ i_w, i_h, o_w, o_h, coeff_h_ptr, coeff_v_lum_ptr, \
+ coeff_v_ch_ptr, scaler_tap, chrome_tap, temp_buf_ptr);
+
+ return FALSE;
+ }
+
+ /* init pool and allocate static array */
+ if (!_InitPool(temp_buf_ptr, temp_buf_size, &pool)) {
+ return FALSE;
+ }
+
+ coef_buf_size = COEF_ARR_ROWS * COEF_ARR_COL_MAX * sizeof(int16_t);
+ cong_Ycom_hor = (int16_t*)_Allocate(coef_buf_size, 2, &pool);
+ cong_UVcom_hor = (int16_t*)_Allocate(coef_buf_size, 2, &pool);
+ cong_Ycom_ver = (int16_t*)_Allocate(coef_buf_size, 2, &pool);
+ cong_UVcom_ver = (int16_t*)_Allocate(coef_buf_size, 2, &pool);
+
+ if (NULL == cong_Ycom_hor
+ || NULL == cong_UVcom_hor
+ ||(NULL == cong_Ycom_ver)
+ ||(NULL == cong_UVcom_ver)) {
+ return FALSE;
+ }
+
+ temp_filter_ptr = _Allocate(filter_buf_size, 2, &pool);
+ filter_ptr = _Allocate(filter_buf_size, 2, &pool);
+ if (NULL == temp_filter_ptr || NULL == filter_ptr) {
+ return FALSE;
+ }
+
+ /* calculate coefficients of Y component in horizontal direction */
+ coef_len = CalY_ScalingCoef(8, D_hor, I_hor, temp_filter_ptr, 1, &pool);
+ GetFilter(temp_filter_ptr, filter_ptr, 8, coef_len, filter_len);
+ WriteScalarCoef(cong_Ycom_hor, filter_ptr, 8, 8);
+ CheckCoefRange(cong_Ycom_hor, 8, 8, 8);
+
+ /* calculate coefficients of UV component in horizontal direction */
+ coef_len = CalUV_ScalingCoef(4, D_hor, I_hor, temp_filter_ptr, 1, &pool);
+ GetFilter(temp_filter_ptr, filter_ptr, 8, coef_len, filter_len);
+ WriteScalarCoef(cong_UVcom_hor, filter_ptr, 8, 4);
+ CheckCoefRange(cong_UVcom_hor, 8, 4, 8);
+ /* write the coefficient to register format */
+ SetHorRegisterCoef(coeff_h_ptr, cong_Ycom_hor, cong_UVcom_hor);
+
+ luma_ver_tap = ((uint8_t)(D_ver / I_ver)) * 2;
+ chrome_ver_tap = luma_ver_tap;
+
+ if ( luma_ver_tap > luma_ver_maxtap)
+ luma_ver_tap = luma_ver_maxtap;//modified by Hongbo, max_tap 8-->16
+ if(luma_ver_tap <= 2)
+ luma_ver_tap = 4;
+
+ *scaler_tap = (uint8_t)luma_ver_tap;
+
+ //------------------------------------------------------//
+ //////////////////////////////////////////////////////////
+ /* calculate coefficients of Y component in vertical direction*/
+ coef_len = CalY_ScalingCoef(luma_ver_tap, D_ver, I_ver, temp_filter_ptr, 0, &pool);
+ GetFilter(temp_filter_ptr, filter_ptr, 8, coef_len, filter_len);
+ WriteScalarCoef(cong_Ycom_ver, filter_ptr, 16, filter_len[0]);
+ CheckCoefRange(cong_Ycom_ver, 8, luma_ver_tap, 16);
+ /* calculate coefficients of UV component in vertical direction */
+ if (scaling2yuv420) {
+ I_ver_bak_uv /= 2;
+ chrome_ver_tap *= 2;
+ chrome_ver_maxtap = 16;
+ }
+
+ if ( chrome_ver_tap > chrome_ver_maxtap)
+ chrome_ver_tap = chrome_ver_maxtap;//modified by Hongbo, max_tap 8-->16
+ if(chrome_ver_tap <= 2)
+ chrome_ver_tap = 4;
+ *chrome_tap = (uint8_t)chrome_ver_tap;
+
+ coef_len = CalUV_ScalingCoef((int16_t) (chrome_ver_tap),
+ D_ver, I_ver_bak_uv, temp_filter_ptr,
+ 0, &pool);
+ GetFilter(temp_filter_ptr, filter_ptr, 8, coef_len, filter_len);
+ WriteScalarCoef(cong_UVcom_ver, filter_ptr, 16, filter_len[0]);
+ CheckCoefRange(cong_UVcom_ver, 8, chrome_ver_tap, 16);
+
+ /* calculate edge coefficients of Y component in vertical direction */
+ if(2 * I_ver_bak_y <= D_ver) { //only scale down
+ CalcVerEdgeCoef(cong_Ycom_ver, D_ver, I_ver_bak_y, luma_ver_tap, 16);
+ }
+ /* calculate edge coefficients of UV component in vertical direction */
+ if(2 * I_ver_bak_uv <= D_ver) { //only scale down
+ CalcVerEdgeCoef(cong_UVcom_ver, D_ver, I_ver_bak_uv, chrome_ver_tap, 16);
+ }
+ /* write the coefficient to register format */
+ SetVerRegisterCoef(coeff_v_lum_ptr, coeff_v_ch_ptr,
+ cong_Ycom_ver, cong_UVcom_ver,
+ D_ver, I_ver, scaling2yuv420);
+
+
+ return TRUE;
+}
diff --git a/drivers/media/sprd_dcam/common/gen_scale_coef.h b/drivers/media/sprd_dcam/common/gen_scale_coef.h
new file mode 100644
index 00000000..549a9475
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/gen_scale_coef.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#ifndef _GEN_SCALE_COEF_H_
+#define _GEN_SCALE_COEF_H_
+
+#include <linux/types.h>
+
+#define SCALER_COEF_TAB_LEN_HOR 48
+#define SCALER_COEF_TAB_LEN_VER 132
+
+uint8_t Dcam_GenScaleCoeff(int16_t i_w,
+ int16_t i_h,
+ int16_t o_w,
+ int16_t o_h,
+ uint32_t *coeff_h_ptr,
+ uint32_t *coeff_v_lum_ptr,
+ uint32_t *coeff_v_ch_ptr,
+ uint8_t scaling2yuv420,
+ uint8_t *scaler_tap,
+ uint8_t *chrome_tap,
+ void *temp_buf_ptr,
+ uint32_t temp_buf_size);
+
+#endif
diff --git a/drivers/media/sprd_dcam/common/parse_hwinfo.c b/drivers/media/sprd_dcam/common/parse_hwinfo.c
new file mode 100755
index 00000000..255f83b7
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/parse_hwinfo.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#ifndef CONFIG_64BIT
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#include <mach/irqs.h>
+#else
+#include <soc/sprd/irqs.h>
+#endif
+#include <soc/sprd/sci.h>
+#include <soc/sprd/sci_glb_regs.h>
+
+#include <linux/sprd_iommu.h>
+#include <linux/delay.h>
+#include <linux/of_gpio.h>
+#include "dcam_drv.h"
+
+//#define PARSE_DEBUG
+
+#ifdef PARSE_DEBUG
+ #define PARSE_TRACE printk
+#else
+ #define PARSE_TRACE pr_debug
+#endif
+
+#ifdef CONFIG_SC_FPGA
+#define CLK_MM_I_IN_CLOCKTREE 0
+#else
+#define CLK_MM_I_IN_CLOCKTREE 1
+#endif
+
+#ifdef CONFIG_OF
+unsigned long dcam_regbase = 0 ;
+unsigned long isp_regbase = 0;
+unsigned long csi_regbase = 0;
+#else
+#endif
+static atomic_t mm_enabe_cnt = ATOMIC_INIT(0);
+
+void parse_baseaddress(struct device_node *dn)
+{
+#ifdef CONFIG_OF
+ struct resource r;
+
+ if (0 == of_address_to_resource(dn, 0, &r)) {
+ PARSE_TRACE("PARSE BASE=0x%x\n", r.start);
+ } else {
+ PARSE_TRACE("PARSE BASE ADDRESS ERROR\n");
+ return;
+ }
+ if (dcam_regbase == 0 && strcmp(dn->name, "sprd_dcam") == 0) {
+ dcam_regbase = ioremap_nocache(r.start, resource_size(&r));
+ PARSE_TRACE("Dcam register base addr: 0x%lx\n", dcam_regbase);
+ } else if (isp_regbase == 0 && strcmp(dn->name, "sprd_isp") == 0) {
+ isp_regbase = ioremap_nocache(r.start, resource_size(&r));
+ PARSE_TRACE("Isp register base addr: 0x%lx\n", isp_regbase);
+ } else if (csi_regbase == 0 && strcmp(dn->name, "sprd_sensor") == 0) {
+ csi_regbase = ioremap_nocache(r.start, resource_size(&r));
+ PARSE_TRACE("Csi register base addr: 0x%lx\n", csi_regbase);
+ }
+#endif
+}
+
+uint32_t parse_irq(struct device_node *dn)
+{
+#ifdef CONFIG_OF
+ return irq_of_parse_and_map(dn, 0);
+#else
+ return DCAM_IRQ;
+#endif
+}
+
+struct clk * parse_clk(struct device_node *dn, char *clkname)
+{
+#ifdef CONFIG_OF
+ PARSE_TRACE("parse_clk %s \n",clkname);
+ return of_clk_get_by_name(dn, clkname);
+#else
+ return clk_get(NULL, clkname);
+#endif
+}
+
+int32_t clk_mm_i_eb(struct device_node *dn, uint32_t enable)
+{
+#ifdef CONFIG_SC_FPGA_CLK
+ return 0;
+#else
+#if CLK_MM_I_IN_CLOCKTREE
+ int ret = 0;
+ struct clk* clk_mm_i = NULL;
+
+ clk_mm_i = parse_clk(dn, "clk_mm_i");
+ if (IS_ERR(clk_mm_i)) {
+ printk("clk_mm_i_eb: get fail.\n");
+ return -1;
+ }
+
+ if(enable){
+ ret = clk_enable(clk_mm_i);
+ if (ret) {
+ printk("clk_mm_i_eb: enable fail.\n");
+ return -1;
+ }
+#if defined(CONFIG_SPRD_IOMMU)
+ {
+ sprd_iommu_module_enable(IOMMU_MM);
+ }
+#endif
+ PARSE_TRACE("clk_mm_i_eb enable ok.\n");
+ atomic_inc(&mm_enabe_cnt);
+ }else{
+#if defined(CONFIG_SPRD_IOMMU)
+ {
+ sprd_iommu_module_disable(IOMMU_MM);
+ }
+#endif
+ clk_disable(clk_mm_i);
+ clk_put(clk_mm_i);
+ clk_mm_i = NULL;
+ udelay(500);
+ atomic_dec(&mm_enabe_cnt);
+ PARSE_TRACE("clk_mm_i_eb disable ok.\n");
+ }
+
+#else
+ if(enable){
+ if(atomic_inc_return(&mm_enabe_cnt) == 1) {
+ REG_OWR(REG_AON_APB_APB_EB0,BIT_MM_EB);
+ REG_AWR(REG_PMU_APB_PD_MM_TOP_CFG,~BIT_PD_MM_TOP_FORCE_SHUTDOWN);
+ REG_OWR(REG_MM_AHB_GEN_CKG_CFG,BIT_SENSOR_CKG_EN|BIT_DCAM_AXI_CKG_EN);
+ PARSE_TRACE("mm enable ok.\n");
+ }
+ }else{
+ if(atomic_dec_return(&mm_enabe_cnt) == 0) {
+ REG_AWR(REG_MM_AHB_GEN_CKG_CFG,~(BIT_SENSOR_CKG_EN|BIT_DCAM_AXI_CKG_EN));
+ REG_OWR(REG_PMU_APB_PD_MM_TOP_CFG,BIT_PD_MM_TOP_FORCE_SHUTDOWN);
+ REG_AWR(REG_AON_APB_APB_EB0,~BIT_MM_EB);
+ udelay(500);
+ PARSE_TRACE("mm disable ok.\n");
+ }
+ }
+#endif
+
+ PARSE_TRACE("mm_enabe_cnt = %d.\n",atomic_read(&mm_enabe_cnt));
+#ifdef PARSE_DEBUG
+ if(enable)
+ mm_clk_register_trace();
+#endif
+ return 0;
+#endif
+}
+
+#ifndef GPIO_SUB_SENSOR_RESET
+#define GPIO_SUB_SENSOR_RESET 0
+#endif
+
+#define GPIO_SENSOR_DEV0_PWN GPIO_MAIN_SENSOR_PWN
+#define GPIO_SENSOR_DEV1_PWN GPIO_SUB_SENSOR_PWN
+#define GPIO_SENSOR_DEV2_PWN 0
+#define GPIO_SENSOR_DEV0_RST GPIO_SENSOR_RESET
+#define GPIO_SENSOR_DEV1_RST GPIO_SUB_SENSOR_RESET
+#define GPIO_SENSOR_DEV2_RST 0
+
+int get_gpio_id(struct device_node *dn, int *pwn, int *reset, uint32_t sensor_id)
+{
+ if (NULL == pwn || NULL == reset)
+ return -1;
+
+#ifdef CONFIG_OF
+ if (0 == sensor_id) {
+ *pwn = of_get_gpio(dn, 1);
+ *reset = of_get_gpio(dn, 0);
+ } else if (1 == sensor_id) {
+ *pwn = of_get_gpio(dn, 3);
+ *reset = of_get_gpio(dn, 2);
+ } else {
+ *pwn = 0;
+ *reset = 0;
+ }
+#else
+ if (0 == sensor_id) {
+ *pwn = GPIO_SENSOR_DEV0_PWN;
+ *reset = GPIO_SENSOR_DEV0_RST;
+ } else if (1 == sensor_id) {
+ *pwn = GPIO_SENSOR_DEV1_PWN;
+ *reset = GPIO_SENSOR_DEV1_RST;
+ } else {
+ *pwn = GPIO_SENSOR_DEV2_PWN;
+ *reset = GPIO_SENSOR_DEV2_RST;
+ }
+#endif
+
+ return 0;
+}
+
+int get_gpio_id_ex(struct device_node *dn, int type, int *id, uint32_t sensor_id)
+{
+ if (NULL == id)
+ return -1;
+
+#ifdef CONFIG_OF
+ switch (type) {
+ case GPIO_CAMDVDD:
+ *id = of_get_gpio(dn, 4);
+ break;
+
+ default:
+ *id = 0;
+ break;
+ }
+#else
+ *id = 0;
+#endif
+
+ return 0;
+}
+
+
+#ifndef REGU_DEV0_CAMAVDD
+#define REGU_DEV0_CAMAVDD "vddcama"
+#endif
+#ifndef REGU_DEV1_CAMAVDD
+#define REGU_DEV1_CAMAVDD "vddcama"
+#endif
+#ifndef REGU_DEV2_CAMAVDD
+#define REGU_DEV2_CAMAVDD "vddcama"
+#endif
+#ifndef REGU_DEV0_CAMDVDD
+#define REGU_DEV0_CAMDVDD "vddcamd"
+#endif
+#ifndef REGU_DEV1_CAMDVDD
+#define REGU_DEV1_CAMDVDD "vddcamd"
+#endif
+#ifndef REGU_DEV2_CAMDVDD
+#define REGU_DEV2_CAMDVDD "vddcamd"
+#endif
+#ifndef REGU_DEV0_CAMIOVDD
+#define REGU_DEV0_CAMIOVDD "vddcamio"
+#endif
+#ifndef REGU_DEV1_CAMIOVDD
+#define REGU_DEV1_CAMIOVDD "vddcamio"
+#endif
+#ifndef REGU_DEV2_CAMIOVDD
+#define REGU_DEV2_CAMIOVDD "vddcamio"
+#endif
+#ifndef REGU_DEV0_CAMMOT
+#define REGU_DEV0_CAMMOT "vddcammot"
+#endif
+#ifndef REGU_DEV1_CAMMOT
+#define REGU_DEV1_CAMMOT "vddcammot"
+#endif
+#ifndef REGU_DEV2_CAMMOT
+#define REGU_DEV2_CAMMOT "vddcammot"
+#endif
+
+const char *c_sensor_avdd_name[] = {
+ REGU_DEV0_CAMAVDD,
+ REGU_DEV1_CAMAVDD,
+ REGU_DEV2_CAMAVDD};
+
+const char *c_sensor_iovdd_name[] = {
+ REGU_DEV0_CAMIOVDD,
+ REGU_DEV1_CAMIOVDD,
+ REGU_DEV2_CAMIOVDD};
+
+const char *c_sensor_dvdd_name[] = {
+ REGU_DEV0_CAMDVDD,
+ REGU_DEV1_CAMDVDD,
+ REGU_DEV2_CAMDVDD};
+
+const char *c_sensor_mot_name[] = {
+ REGU_DEV0_CAMMOT,
+ REGU_DEV1_CAMMOT,
+ REGU_DEV2_CAMMOT};
+
+int get_regulator_name(struct device_node *dn, int *type, uint32_t sensor_id, char **name)
+{
+ const char *ldostr;
+ int ret = 0;
+
+ switch (*type) {
+ case REGU_CAMAVDD:
+ ret = of_property_read_string_index(dn, "vdds", sensor_id*4 + 1, &ldostr);
+ if(!ret) {
+ *name = ldostr;
+ PARSE_TRACE("REGU_CAMAVDD = >%s\n",*name);
+ } else {
+ *name = (char*)c_sensor_avdd_name[sensor_id];
+ }
+ break;
+
+ case REGU_CAMDVDD:
+ ret = of_property_read_string_index(dn, "vdds", sensor_id*4 + 2, &ldostr);
+ if(!ret) {
+ *name = ldostr;
+ PARSE_TRACE("REGU_CAMDVDD = >%s\n",*name);
+ } else {
+ *name = (char*)c_sensor_dvdd_name[sensor_id];
+ }
+ break;
+
+ case REGU_CAMIOVDD:
+ ret = of_property_read_string_index(dn, "vdds", sensor_id*4 + 3, &ldostr);
+ if(!ret) {
+ *name = ldostr;
+ PARSE_TRACE("REGU_CAMIOVDD = >%s\n",*name);
+ } else {
+ *name = (char*)c_sensor_iovdd_name[sensor_id];
+ }
+ break;
+
+ case REGU_CAMMOT:
+ ret = of_property_read_string_index(dn, "vdds", sensor_id*4, &ldostr);
+ if(!ret) {
+ *name = ldostr;
+ PARSE_TRACE("REGU_CAMMOT = >%s\n",*name);
+ } else {
+ *name = (char*)c_sensor_mot_name[sensor_id];
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if(strcmp(name, "vddcammot")==0) {
+ *type = REGU_CAMMOT;
+ } else if(strcmp(name, "vddcama")==0){
+ *type = REGU_CAMAVDD;
+ } else if(strcmp(name, "vddcamd")==0){
+ *type = REGU_CAMDVDD;
+ } else if(strcmp(name, "vddcamio")==0){
+ *type = REGU_CAMIOVDD;
+ }
+ of_node_put(dn);
+ return 0;
+}
diff --git a/drivers/media/sprd_dcam/common/parse_hwinfo.h b/drivers/media/sprd_dcam/common/parse_hwinfo.h
new file mode 100755
index 00000000..9e1e8f39
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/parse_hwinfo.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/types.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/sprd_mm.h>
+
+#ifdef CONFIG_64BIT
+#include <soc/sprd/sci_glb_regs.h>
+#endif
+
+extern unsigned long dcam_regbase;
+extern unsigned long isp_regbase;
+extern unsigned long csi_regbase;
+
+#ifndef CONFIG_OF
+#define DCAM_BASE SPRD_DEV_P2V(dcam_regbase)
+#define ISP_BASE SPRD_DEV_P2V(isp_regbase)
+#define CSI2_BASE SPRD_DEV_P2V(csi_regbase)
+
+#else
+
+#define DCAM_BASE (dcam_regbase)
+#define ISP_BASE (isp_regbase)
+#define CSI2_BASE (csi_regbase)
+#endif
+
+
+enum get_regu_type_e {
+ REGU_CAMAVDD = 0,
+ REGU_CAMDVDD,
+ REGU_CAMIOVDD,
+ REGU_CAMMOT,
+ REGU_MAX
+};
+enum get_gpio_type_e {
+ GPIO_CAMDVDD = 0,
+ GPIO_CAMMAX
+};
+#ifdef CONFIG_64BIT
+//#define SPRD_ISP_SIZE SZ_32K
+//#define SPRD_MMAHB_BASE SPRD_DEV_P2V(REGS_MM_AHB_BASE)
+//#define SPRD_MMCKG_BASE SPRD_DEV_P2V(REGS_MM_CLK_BASE)
+//#define SPRD_PIN_BASE SPRD_DEV_P2V(0x60a00000)
+
+//#define SPRD_ADISLAVE_BASE SPRD_DEV_P2V(REGS_ADI_BASE)
+#define SPRD_FLASH_OFST 0x890
+#define SPRD_FLASH_CTRL_BIT 0x8000
+#define SPRD_FLASH_LOW_VAL 0x3
+#define SPRD_FLASH_HIGH_VAL 0xF
+#define SPRD_FLASH_LOW_CUR 110
+#define SPRD_FLASH_HIGH_CUR 470
+#endif
+#define ZTEHZ_FLASH_HIGH_VAL 0xB
+void parse_baseaddress(struct device_node *dn);
+uint32_t parse_irq(struct device_node *dn);
+struct clk * parse_clk(struct device_node *dn, char *clkname);
+int get_gpio_id(struct device_node *dn, int *pwn, int *reset, uint32_t sensor_id);
+int get_gpio_id_ex(struct device_node *dn, int type, int *id, uint32_t sensor_id);
+int get_regulator_name(struct device_node *dn, int *type, uint32_t sensor_id, char **name);
diff --git a/drivers/media/sprd_dcam/common/parse_hwinfo_tshark2.h b/drivers/media/sprd_dcam/common/parse_hwinfo_tshark2.h
new file mode 100644
index 00000000..e9aa0939
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/parse_hwinfo_tshark2.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/types.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/sprd_mm.h>
+
+#ifdef CONFIG_64BIT
+#include <soc/sprd/sci_glb_regs.h>
+#endif
+
+#ifndef CONFIG_SC_FPGA
+#ifndef CONFIG_OF
+extern unsigned long dcam_regbase;
+extern unsigned long isp_regbase;
+extern unsigned long csi_regbase;
+#define DCAM_BASE SPRD_DEV_P2V(dcam_regbase)
+#define ISP_BASE SPRD_DEV_P2V(isp_regbase)
+#define CSI2_BASE SPRD_DEV_P2V(csi_regbase)
+#else
+extern unsigned long dcam_regbase;
+extern unsigned long isp_regbase;
+extern unsigned long csi_regbase;
+#define DCAM_BASE (dcam_regbase)
+#define ISP_BASE (isp_regbase)
+#define CSI2_BASE (csi_regbase)
+#endif
+#else
+extern unsigned long dcam_regbase;
+extern unsigned long isp_regbase;
+extern unsigned long csi_regbase;
+#define DCAM_BASE (dcam_regbase)
+#define ISP_BASE (isp_regbase)
+#define CSI2_BASE (csi_regbase)
+#endif
diff --git a/drivers/media/sprd_dcam/common/sin_cos.c b/drivers/media/sprd_dcam/common/sin_cos.c
new file mode 100644
index 00000000..909d63c0
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/sin_cos.c
@@ -0,0 +1,270 @@
+/******************************************************************************
+ ** File Name: sin_cos.h *
+ ** Author: shan.he *
+ ** DATE: 2010-11-22 *
+ ** Copyright: 2010 Spreadtrum, Incoporated. All Rights Reserved. *
+ ** Description: *
+ ** Note: *
+ *****************************************************************************/
+/******************************************************************************
+ ** Edit History *
+ **---------------------------------------------------------------------------*
+ ** DATE NAME DESCRIPTION *
+ *****************************************************************************/
+
+/**---------------------------------------------------------------------------*
+ ** Dependencies *
+ **---------------------------------------------------------------------------*/
+#include "sin_cos.h"
+
+/**---------------------------------------------------------------------------*
+ ** Macros *
+ **---------------------------------------------------------------------------*/
+//typedef long long __int64
+#define SINCOS_BIT_31 (1 << 31)
+#define SINCOS_BIT_30 (1 << 30)
+
+//#define SMULL(x, y) ((__int64)(x) * (__int64)(y))
+#define SMULL(x, y) ((int64_t)(x) * (int64_t)(y))
+
+/**---------------------------------------------------------------------------*
+ ** static variable *
+ **---------------------------------------------------------------------------*/
+static const uint32_t cossin_tbl[64] =
+{
+ 0x3ffec42d, 0x00c90e90, 0x3ff4e5e0, 0x025b0caf,
+ 0x3fe12acb, 0x03ecadcf, 0x3fc395f9, 0x057db403,
+ 0x3f9c2bfb, 0x070de172, 0x3f6af2e3, 0x089cf867,
+ 0x3f2ff24a, 0x0a2abb59, 0x3eeb3347, 0x0bb6ecef,
+ 0x3e9cc076, 0x0d415013, 0x3e44a5ef, 0x0ec9a7f3,
+ 0x3de2f148, 0x104fb80e, 0x3d77b192, 0x11d3443f,
+ 0x3d02f757, 0x135410c3, 0x3c84d496, 0x14d1e242,
+ 0x3bfd5cc4, 0x164c7ddd, 0x3b6ca4c4, 0x17c3a931,
+ 0x3ad2c2e8, 0x19372a64, 0x3a2fcee8, 0x1aa6c82b,
+ 0x3983e1e8, 0x1c1249d8, 0x38cf1669, 0x1d79775c,
+ 0x3811884d, 0x1edc1953, 0x374b54ce, 0x2039f90f,
+ 0x367c9a7e, 0x2192e09b, 0x35a5793c, 0x22e69ac8,
+ 0x34c61236, 0x2434f332, 0x33de87de, 0x257db64c,
+ 0x32eefdea, 0x26c0b162, 0x31f79948, 0x27fdb2a7,
+ 0x30f8801f, 0x29348937, 0x2ff1d9c7, 0x2a650525,
+ 0x2ee3cebe, 0x2b8ef77d, 0x2dce88aa, 0x2cb2324c
+};
+
+/**---------------------------------------------------------------------------*
+ ** static Functions *
+ **---------------------------------------------------------------------------*/
+// s(x) = sin(2*PI*x*2^(-32)) =s(a) * cos(PI*(x-a)*2^(-31)) + c(a) * sin(PI*(x-a)*2^(-31))
+// b = x - a, A = PI*a*2^(-31), B = PI*(x-a)*2^(-32)
+// PI / 128 <= A < PI/4, 0 <= B < PI / 128
+// sin(B) = B - B ^ 3 / 6; cos(B)=1 - B ^ 2 / 2;
+// s(x) = sin(A) * cos(B) + cos(A) * sin(B)
+// s(x) = sin(A) - sin(A) * B^2 / 2 + cos(A) * B - cos(A) * B * B^2 / 6
+// s(x) = S1 - S2 + S3 + S4;
+// S1 = sin(A), S2 = sin(A) * B^2 / 2, S3 = cos(A) * B, S4 = - cos(A) * B * B^2 / 6
+// T1 = B^2;
+/*lint --e{647}*/
+static int32_t sin_core(int32_t arc_q33, int32_t sign)
+{
+ int32_t a, b, B;
+ int32_t sin_a, cos_a;
+ int32_t S1, S2, S3, S4, T1;
+ int32_t R = 0;
+
+ int32_t C1 = 0x6487ed51; //round(2 * PI * 2 ^ 28)
+ int32_t C2 = -715827882; //0xd5555556; //round(-2^32/6)
+
+ a = arc_q33 >> 25;
+ cos_a = cossin_tbl[2 * a];
+ sin_a = cossin_tbl[2 * a + 1];
+ cos_a ^= (sign >> 31);
+ sin_a ^= (sign >> 31);
+
+ a = a << 25;
+ b = arc_q33 - a;
+ b -= (1 << 24);
+
+ B = SMULL((b << 3), C1) >> 32; //B at Q32
+
+ T1 = SMULL(B, B) >> 32; //B^2 at Q32
+
+ S1 = sin_a;
+ S2 = SMULL(sin_a, T1 >> 1) >> 32; //S2 at Q30
+ S3 = SMULL(cos_a, B) >> 32; //S3 at Q30
+ S4 = SMULL(T1, C2) >> 32; //-B^2 / 6 at Q32
+ S4 = SMULL(S3, S4) >> 32; //S4 at Q30
+
+ R = S1 - S2 + S3 + S4;
+
+ return R;
+}
+
+// c(x) = cos(2*PI*x*2^(-32)) = c(a) * cos(PI*(x-a)*2^(-31)) + s(a) * sin(PI*(x-a)*2^(-31))
+// b = x - a, A = PI*a*2^(-31), B = PI*(x-a)*2^(-32)
+// PI / 128 <= A < PI/4, 0 <= B < PI / 128
+// sin(B) = B - B ^ 3 / 6; cos(B)=1 - B ^ 2 / 2;
+// s(x) = cos(A) * cos(B) - sin(A) * sin(B)
+// s(x) = cos(A) - cos(A) * B^2 / 2 - sin(A) * B + sin(A) * B * B^2 / 6;
+// s(x) = S1 - S2 - S3 + S4;
+// S1 = cos(A), S2 = cos(A) * B^2 / 2, S3 = sin(A) * B, S4 = sin(A) * B * B^2 / 6
+// T1 = B^2;
+/*lint --e{647}*/
+static int32_t cos_core(int32_t arc_q33, int32_t sign)
+{
+ int32_t a, b, B;
+ int32_t sin_a, cos_a;
+ int32_t S1, S2, S3, S4, T1;
+ int32_t R = 0;
+
+ int32_t C1 = 0x6487ed51; //round(2 * PI * 2 ^ 28)
+ int32_t C2 = 0x2aaaaaab; //round(2^32/6)
+
+ a = arc_q33 >> 25;
+ cos_a = cossin_tbl[a * 2];
+ sin_a = cossin_tbl[a * 2 + 1];
+ cos_a ^= (sign >> 31); //correct the sign
+ sin_a ^= (sign >> 31); //correct the sign
+
+ a = a << 25;
+ b = arc_q33 - a;
+ b -= (1 << 24);
+
+ B = SMULL((b << 3), C1) >> 32; //B at Q32
+
+ T1 = SMULL(B, B) >> 32; //B^2 at Q32
+
+ S1 = cos_a;
+ S2 = SMULL(cos_a, T1 >> 1) >> 32; //S2 at Q30
+ S3 = SMULL(sin_a, B) >> 32; //S3 at Q30
+ S4 = SMULL(T1, C2) >> 32; //B^2 / 6 at Q32
+ S4 = SMULL(S3, S4) >> 32; //S4 at Q30
+
+ R = S1 - S2 - S3 + S4;
+
+ return R;
+}
+
+/**---------------------------------------------------------------------------*
+ ** Public Functions *
+ **---------------------------------------------------------------------------*/
+/****************************************************************************/
+/* Purpose: get the sin value of an arc at Q32 */
+/* Author: */
+/* Input: arc at Q32 */
+/* Output: none */
+/* Return: sin value at Q30 */
+/* Note: arc at Q32 = arc * (2 ^ 32) */
+/* value at Q30 = value * (2 ^ 30) */
+/****************************************************************************/
+/*lint --e{648}*/
+int32_t dcam_sin_32(int32_t n)
+{
+ int32_t s = n & SINCOS_BIT_31; //if s equal to 1, the sin value is negative
+
+ n = n << 1; //angle in revolutions at Q33, the BIT_31 only indicates the sign
+
+ if (0 == n) // == pi, 0
+ {
+ return 0;
+ }
+
+ if (SINCOS_BIT_31 == (n & SINCOS_BIT_31)) // >= pi/2
+ {
+ n &= ~SINCOS_BIT_31; //-= pi/2
+
+ if (n < SINCOS_BIT_30) // < pi/4
+ {
+ return cos_core(n, s);
+ }
+ else if (n == SINCOS_BIT_30) // == pi/4
+ {
+ n -= 1;
+ }
+ else if (n > SINCOS_BIT_30) // > pi/4
+ {
+ n = SINCOS_BIT_31 - n; // pi/2 - n
+ }
+
+ return sin_core(n, s);
+ }
+ else
+ {
+ if (n < SINCOS_BIT_30) // < pi/4
+ {
+ return sin_core(n, s);
+ }
+
+ if (n == SINCOS_BIT_30) // == pi/4
+ {
+ n -= 1;
+ }
+ else if (n > SINCOS_BIT_30) // > pi/4
+ {
+ n = SINCOS_BIT_31 - n; // pi/2 - n
+ }
+
+ return cos_core(n, s);
+ }
+}
+
+
+/****************************************************************************/
+/* Purpose: get the cos value of an arc at Q32 */
+/* Author: */
+/* Input: arc at Q32 */
+/* Output: none */
+/* Return: cos value at Q30 */
+/* Note: arc at Q32 = arc * (2 ^ 32) */
+/* value at Q30 = value * (2 ^ 30) */
+/****************************************************************************/
+/*lint --e{648}*/
+int32_t dcam_cos_32(int32_t n)
+{
+ int32_t s = n & SINCOS_BIT_31; //if s equal to 1, the sin value is negative
+
+ n = n << 1; //angle in revolutions at Q33, the BIT_31 only indicates the sign
+
+ if (n == SINCOS_BIT_31)
+ {
+ return 0;
+ }
+
+ if (SINCOS_BIT_31 == (n & SINCOS_BIT_31)) // >= pi/2
+ {
+ n &= ~SINCOS_BIT_31; //-= pi/2
+
+ if (n < SINCOS_BIT_30) // < pi/4
+ {
+ return -sin_core(n, s);
+ }
+ else if (n == SINCOS_BIT_30) // == pi/4
+ {
+ n -= 1;
+ }
+ else if (n > SINCOS_BIT_30) // > pi/4
+ {
+ n = SINCOS_BIT_31 - n; // pi/2 - n
+ }
+
+ return -cos_core(n, s);
+ }
+ else
+ {
+ if (n < SINCOS_BIT_30) // < pi/4
+ {
+ return cos_core(n, s);
+ }
+
+ if (n == SINCOS_BIT_30) // == pi/4
+ {
+ n -= 1;
+ }
+ else if (n > SINCOS_BIT_30) // > pi/4
+ {
+ n = SINCOS_BIT_31 - n; // pi/2 - n
+ }
+
+ return sin_core(n, s);
+ }
+}
+
+
diff --git a/drivers/media/sprd_dcam/common/sin_cos.h b/drivers/media/sprd_dcam/common/sin_cos.h
new file mode 100644
index 00000000..f8b02ea3
--- /dev/null
+++ b/drivers/media/sprd_dcam/common/sin_cos.h
@@ -0,0 +1,74 @@
+/******************************************************************************
+ ** File Name: sin_cos.h *
+ ** Author: shan.he *
+ ** DATE: 2010-11-22 *
+ ** Copyright: 2010 Spreadtrum, Incoporated. All Rights Reserved. *
+ ** Description: *
+ ** Note: *
+ *****************************************************************************/
+/******************************************************************************
+ ** Edit History *
+ **---------------------------------------------------------------------------*
+ ** DATE NAME DESCRIPTION *
+ *****************************************************************************/
+#ifndef _SIN_COS_H_
+#define _SIN_COS_H_
+
+/**---------------------------------------------------------------------------*
+ ** Dependencies *
+ **---------------------------------------------------------------------------*/
+//#include "sci_types.h"
+#include <linux/types.h>
+
+/**---------------------------------------------------------------------------*
+ ** Macros *
+ **---------------------------------------------------------------------------*/
+#define COSSIN_Q 30
+
+#define pi 3.14159265359
+#define PI_32 0x3243F6A88 //pi * (1 << 32)
+#define ARC_32_COEF 0x80000000
+//convert arc of double type to int32 type
+#define ARC_32(arc) (int32_t)((arc) / (pi) * 2147483648);
+
+/**---------------------------------------------------------------------------*
+ ** Compiler Flag *
+ **---------------------------------------------------------------------------*/
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**---------------------------------------------------------------------------*
+ ** Public Functions *
+ **---------------------------------------------------------------------------*/
+/****************************************************************************/
+/* Purpose: get the sin value of an arc at Q32 */
+/* Author: */
+/* Input: arc at Q32 */
+/* Output: none */
+/* Return: sin value at Q30 */
+/* Note: arc at Q32 = arc * (2 ^ 32) */
+/* value at Q30 = value * (2 ^ 30) */
+/****************************************************************************/
+int32_t dcam_sin_32(int32_t n);
+
+/****************************************************************************/
+/* Purpose: get the cos value of an arc at Q32 */
+/* Author: */
+/* Input: arc at Q32 */
+/* Output: none */
+/* Return: cos value at Q30 */
+/* Note: arc at Q32 = arc * (2 ^ 32) */
+/* value at Q30 = value * (2 ^ 30) */
+/****************************************************************************/
+int32_t dcam_cos_32(int32_t n);
+
+/**---------------------------------------------------------------------------*
+ ** Compiler Flag *
+ **---------------------------------------------------------------------------*/
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/media/sprd_dcam/flash/Makefile b/drivers/media/sprd_dcam/flash/Makefile
new file mode 100755
index 00000000..5c1bbbd8
--- /dev/null
+++ b/drivers/media/sprd_dcam/flash/Makefile
@@ -0,0 +1,82 @@
+
+ifeq ($(CONFIG_MACH_VIVALTO),y)
+obj-y += flash_vivalto.o
+else
+ifeq ($(CONFIG_MACH_KANAS_W),y)
+obj-y += flash_kanas_w.o
+else
+ifeq ($(CONFIG_MACH_SP8730SEA),y)
+obj-y += flash_sgm3140.o
+else
+ifeq ($(CONFIG_MACH_SP9836AEA_4MOD),y)
+obj-y += flash_parallel_connect_bg.o
+else
+ifeq ($(CONFIG_MACH_SP9838AEA_5MOD),y)
+obj-y += flash_gpio.o
+else
+ifeq ($(CONFIG_MACH_SP9838AEA_POWER_DEBUG),y)
+obj-y += flash_gpio.o
+else
+ifeq ($(CONFIG_MACH_SP9838AEA_8CORE_LIGHT_SLEEP),y)
+obj-y += flash_gpio.o
+else
+ifeq ($(CONFIG_MACH_SP9838AEA_FHD),y)
+obj-y += flash_gpio.o
+else
+ifeq ($(CONFIG_MACH_SP9630EA4MN),y)
+obj-y += flash_parallel_connect_bg.o
+else
+ifeq ($(CONFIG_MACH_SP9836AEA_3MOD), y)
+obj-y += flash_parallel_connect_bg.o
+else
+ifeq ($(CONFIG_MACH_SP9830AEA_5M_H100), y)
+obj-y += flash_parallel_connect_bg.o
+else
+ifeq ($(CONFIG_MACH_SP9830IEB_5M_H100), y)
+obj-y += flash_parallel_connect_bg.o
+else
+ifeq ($(CONFIG_MACH_SP7720EA), y)
+obj-y += flash_parallel_connect_bg.o
+else
+ifeq ($(CONFIG_MACH_COREPRIMELITE),y)
+obj-y += flash_sm5701.o
+else
+ifeq ($(CONFIG_MACH_SP8730SEEA),y)
+obj-y += flash_sgm3140.o
+else
+ifeq ($(CONFIG_MACH_SP8730SEEA_QHD),y)
+obj-y += flash_sgm3140.o
+else
+ifeq ($(CONFIG_MACH_SP9830IEA_5M_H100),y)
+obj-y += flash_sprd_sm5701.o
+else
+ifeq ($(CONFIG_MACH_GRANDPRIME3G_VE),y)
+obj-y += flash_sm5701.o
+else
+ifeq ($(CONFIG_MACH_GRANDPRIME_DTV),y)
+obj-y += flash_sm5701.o
+else
+ifeq ($(CONFIG_MACH_COREPRIME3G_VE),y)
+obj-y += flash_sm5701.o
+else
+obj-y += flash_common.o
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
+endif
diff --git a/drivers/media/sprd_dcam/flash/flash.h b/drivers/media/sprd_dcam/flash/flash.h
new file mode 100644
index 00000000..ee686332
--- /dev/null
+++ b/drivers/media/sprd_dcam/flash/flash.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef _DCAM_DRV_FLASH_H_
+#define _DCAM_DRV_FLASH_H_
+
+#include <linux/types.h>
+
+int sprd_flash_on(void);
+int sprd_flash_high_light(void);
+int sprd_flash_close(void);
+#endif
diff --git a/drivers/media/sprd_dcam/flash/flash_common.c b/drivers/media/sprd_dcam/flash/flash_common.c
new file mode 100644
index 00000000..492a823d
--- /dev/null
+++ b/drivers/media/sprd_dcam/flash/flash_common.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#ifndef CONFIG_64BIT
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#endif
+#include <soc/sprd/adi.h>
+#include "../common/parse_hwinfo.h"
+
+int sprd_flash_on(void)
+{
+ printk("sprd_flash_on \n");
+ sci_adi_clr(SPRD_ADISLAVE_BASE + SPRD_FLASH_OFST, SPRD_FLASH_HIGH_VAL);
+ sci_adi_set(SPRD_ADISLAVE_BASE + SPRD_FLASH_OFST, SPRD_FLASH_CTRL_BIT | SPRD_FLASH_LOW_VAL); /*0x3 = 110ma*/
+ return 0;
+}
+
+int sprd_flash_high_light(void)
+{
+ printk("sprd_flash_high_light \n");
+ sci_adi_clr(SPRD_ADISLAVE_BASE + SPRD_FLASH_OFST, SPRD_FLASH_HIGH_VAL);
+ sci_adi_set(SPRD_ADISLAVE_BASE + SPRD_FLASH_OFST, SPRD_FLASH_CTRL_BIT | ZTEHZ_FLASH_HIGH_VAL); /*0xB = 350ma*/
+ return 0;
+}
+
+int sprd_flash_close(void)
+{
+ printk("sprd_flash_close \n");
+ sci_adi_clr(SPRD_ADISLAVE_BASE + SPRD_FLASH_OFST, SPRD_FLASH_CTRL_BIT | SPRD_FLASH_HIGH_VAL);
+ return 0;
+}
diff --git a/drivers/media/sprd_dcam/flash/flash_gpio.c b/drivers/media/sprd_dcam/flash/flash_gpio.c
new file mode 100644
index 00000000..acbfc0f4
--- /dev/null
+++ b/drivers/media/sprd_dcam/flash/flash_gpio.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#ifndef CONFIG_64BIT
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#include <soc/sprd/adi.h>
+#endif
+
+#include <asm/gpio.h>
+
+#define SPRD_FLASH_ON 1
+#define SPRD_FLASH_OFF 0
+
+#undef GPIO_CAM_FLASH_EN
+#define GPIO_CAM_FLASH_EN 131
+
+int sprd_flash_on(void)
+{
+ printk("sprd_flash_on \n");
+ gpio_request(GPIO_CAM_FLASH_EN,"cam_flash_en");
+ gpio_direction_output(GPIO_CAM_FLASH_EN, SPRD_FLASH_ON);
+ gpio_free(GPIO_CAM_FLASH_EN);
+ return 0;
+}
+
+int sprd_flash_high_light(void)
+{
+ printk("sprd_flash_high_light \n");
+ gpio_request(GPIO_CAM_FLASH_EN,"cam_flash_en");
+ gpio_direction_output(GPIO_CAM_FLASH_EN, SPRD_FLASH_ON);
+ gpio_free(GPIO_CAM_FLASH_EN);
+ return 0;
+}
+
+int sprd_flash_close(void)
+{
+ printk("sprd_flash_close \n");
+ gpio_request(GPIO_CAM_FLASH_EN,"cam_flash_en");
+ gpio_direction_output(GPIO_CAM_FLASH_EN, SPRD_FLASH_OFF);
+ gpio_free(GPIO_CAM_FLASH_EN);
+ return 0;
+}
diff --git a/drivers/media/sprd_dcam/flash/flash_kanas_w.c b/drivers/media/sprd_dcam/flash/flash_kanas_w.c
new file mode 100644
index 00000000..de606207
--- /dev/null
+++ b/drivers/media/sprd_dcam/flash/flash_kanas_w.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#ifndef CONFIG_64BIT
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/adi.h>
+#endif
+
+#include <linux/leds/flashlight.h>
+
+struct flashlight_device* sprd_get_flashlight_by_name(void)
+{
+ struct flashlight_device* flash_ptr = NULL;
+
+ flash_ptr = find_flashlight_by_name("rt-flash-led");
+ if (NULL == flash_ptr) {
+ printk("sprd_get_flashlight_by_name: flash_ptr is PNULL \n");
+ return NULL;
+ }
+ flashlight_set_mode(flash_ptr, FLASHLIGHT_MODE_FLASH);
+ return flash_ptr;
+}
+
+int sprd_flash_on(void)
+{
+ struct flashlight_device* flash_ptr = NULL;
+
+ flash_ptr = sprd_get_flashlight_by_name();
+ printk("sprd_flash_on kanas w \n");
+ flashlight_strobe(flash_ptr);
+ return 0;
+}
+
+int sprd_flash_high_light(void)
+{
+ struct flashlight_device* flash_ptr = NULL;
+
+ flash_ptr = sprd_get_flashlight_by_name();
+ printk("sprd_flash_high_light kanas w \n");
+ flashlight_strobe(flash_ptr);
+ return 0;
+}
+
+int sprd_flash_close(void)
+{
+ struct flashlight_device* flash_ptr = NULL;
+
+ flash_ptr = sprd_get_flashlight_by_name();
+ printk("sprd_flash_close kanas w \n");
+ flashlight_set_mode(flash_ptr, FLASHLIGHT_MODE_OFF);
+ return 0;
+}
diff --git a/drivers/media/sprd_dcam/flash/flash_parallel_connect_bg.c b/drivers/media/sprd_dcam/flash/flash_parallel_connect_bg.c
new file mode 100644
index 00000000..340a87c1
--- /dev/null
+++ b/drivers/media/sprd_dcam/flash/flash_parallel_connect_bg.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#ifndef CONFIG_64BIT
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#endif
+#include <soc/sprd/adi.h>
+#include "../common/parse_hwinfo.h"
+
+#define SPRD_PWM0_CTRL_OFST 0xEC
+#define SPRD_PWM0_PATTERN_HIGHT_OFST 0x10
+#define SPRD_PWM0_PATTERT_LOW_OFST 0xC
+#define SPRD_PWM0_TONE_OFST 0x8
+#define SPRD_PWM0_RATION_OFST 0x4
+#define SPRD_WHTLED_CTRL_OFST 0xF0
+
+extern int sci_efuse_ib_trim_get(unsigned int *p_cal_data);
+
+unsigned int ib_trim_cal_data = 0;
+static int init_flag = 1;
+
+int sprd_flash_on(void)
+{
+ if (init_flag && sci_efuse_ib_trim_get(&ib_trim_cal_data)) {
+ /*
+ 1. set ib_trim_cal_data to WHTLED_CTRL的IB_TRIM(0x400388F0 [15:9])
+ 2. set IB_TRIM_EM_SEL of RGB_CTRL to 0(0x400388EC [11])
+ */
+ sci_adi_clr(ANA_CTL_GLB_BASE + SPRD_WHTLED_CTRL_OFST, 0x7F << 9);
+ sci_adi_set(ANA_CTL_GLB_BASE + SPRD_WHTLED_CTRL_OFST, (ib_trim_cal_data & 0x7F) << 9);
+ sci_adi_clr(ANA_CTL_GLB_BASE + SPRD_PWM0_CTRL_OFST, (0x1 << 11));
+ init_flag = 0;
+ printk("parallel sprd_flash_on trim = %d\n", ib_trim_cal_data);
+ }
+
+ printk("parallel sprd_flash_on \n");
+ /*ENABLE THE PWM0 CONTROLLTER: RTC_PWM0_EN=1 & PWM0_EN=1*/
+ sci_adi_clr(ANA_CTL_GLB_BASE + SPRD_PWM0_CTRL_OFST, 0xFFFF);
+ sci_adi_set(ANA_CTL_GLB_BASE + SPRD_PWM0_CTRL_OFST, 0xC805);
+
+ /*SET PWM0 PATTERN HIGH*/
+ sci_adi_set(ANA_PWM_BASE + SPRD_PWM0_PATTERN_HIGHT_OFST, 0xFFFF);
+
+ /*SET PWM0 PATTERN LOW*/
+ sci_adi_set(ANA_PWM_BASE + SPRD_PWM0_PATTERT_LOW_OFST, 0xFFFF);
+
+ /*TONE DIV USE DEFAULT VALUE*/
+ sci_adi_clr(ANA_PWM_BASE + SPRD_PWM0_TONE_OFST, 0x0100);
+
+ /*SET PWM0 DUTY RATIO = 100%: MOD=FF & DUTY=FF*/
+ sci_adi_set(ANA_PWM_BASE + SPRD_PWM0_RATION_OFST, 0x0100);
+
+ /*ENABLE PWM0 OUTPUT: PWM0_EN=1*/
+ sci_adi_set(ANA_PWM_BASE, 0x100);
+
+ /*SET LOW LIGHT */
+ sci_adi_clr(ANA_CTL_GLB_BASE + SPRD_WHTLED_CTRL_OFST, 0xFFFF);
+ sci_adi_set(ANA_CTL_GLB_BASE + SPRD_WHTLED_CTRL_OFST, 0x1e);
+
+ /*ENABLE WHTLED*/
+ sci_adi_clr(ANA_CTL_GLB_BASE + SPRD_WHTLED_CTRL_OFST, 0x1);
+ return 0;
+}
+
+int sprd_flash_high_light(void)
+{
+ printk("parallel sprd_flash_high_light \n");
+ /*SET HIGH LIGHT*/
+ sci_adi_clr(ANA_CTL_GLB_BASE + SPRD_WHTLED_CTRL_OFST, 0xFFFF);
+ sci_adi_set(ANA_CTL_GLB_BASE + SPRD_WHTLED_CTRL_OFST, 0x40);
+ /*ENABLE WHTLED*/
+ sci_adi_clr(ANA_CTL_GLB_BASE + SPRD_WHTLED_CTRL_OFST, 0x1);
+ return 0;
+}
+
+int sprd_flash_close(void)
+{
+ printk("parallel sprd_flash_close \n");
+
+ /*DISABLE WHTLED*/
+ sci_adi_clr(ANA_CTL_GLB_BASE + SPRD_WHTLED_CTRL_OFST, 0xFFFF);
+ sci_adi_set(ANA_CTL_GLB_BASE + SPRD_WHTLED_CTRL_OFST, 0x1);
+
+ /*DISABLE THE PWM0 CONTROLLTER: RTC_PWM0_EN=0 & PWM0_EN=0*/
+ sci_adi_clr(ANA_CTL_GLB_BASE + SPRD_PWM0_CTRL_OFST, 0xC000);
+
+ /*ENABLE PWM0 OUTPUT: PWM0_EN=0*/
+ sci_adi_clr(ANA_PWM_BASE, 0x100);
+ return 0;
+}
diff --git a/drivers/media/sprd_dcam/flash/flash_sgm3140.c b/drivers/media/sprd_dcam/flash/flash_sgm3140.c
new file mode 100644
index 00000000..81490416
--- /dev/null
+++ b/drivers/media/sprd_dcam/flash/flash_sgm3140.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#ifndef CONFIG_64BIT
+#include <soc/sprd/board.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/adi.h>
+#endif
+
+#include <asm/gpio.h>
+
+#define SPRD_FLASH_ON 1
+#define SPRD_FLASH_OFF 0
+
+int sprd_flash_on(void)
+{
+ printk("sprd_flash_on \n");
+ gpio_request(GPIO_CAM_FLASH_EN,"cam_flash_en");
+ gpio_direction_output(GPIO_CAM_FLASH_EN, SPRD_FLASH_ON);
+ gpio_free(GPIO_CAM_FLASH_EN);
+
+ gpio_request(GPIO_CAM_FLASH_MODE,"cam_flash_mode");
+ gpio_direction_output(GPIO_CAM_FLASH_MODE, SPRD_FLASH_OFF);
+ gpio_free(GPIO_CAM_FLASH_MODE);
+ return 0;
+}
+
+int sprd_flash_high_light(void)
+{
+ printk("sprd_flash_high_light \n");
+ gpio_request(GPIO_CAM_FLASH_EN,"cam_flash_en");
+ gpio_direction_output(GPIO_CAM_FLASH_EN, SPRD_FLASH_ON);
+ gpio_free(GPIO_CAM_FLASH_EN);
+
+ gpio_request(GPIO_CAM_FLASH_MODE,"cam_flash_mode");
+ gpio_direction_output(GPIO_CAM_FLASH_MODE, SPRD_FLASH_ON);
+ gpio_free(GPIO_CAM_FLASH_MODE);
+ return 0;
+}
+
+int sprd_flash_close(void)
+{
+ printk("sprd_flash_close \n");
+ gpio_request(GPIO_CAM_FLASH_EN,"cam_flash_en");
+ gpio_direction_output(GPIO_CAM_FLASH_EN, SPRD_FLASH_OFF);
+ gpio_free(GPIO_CAM_FLASH_EN);
+
+ gpio_request(GPIO_CAM_FLASH_MODE,"cam_flash_mode");
+ gpio_direction_output(GPIO_CAM_FLASH_MODE, SPRD_FLASH_OFF);
+ gpio_free(GPIO_CAM_FLASH_MODE);
+ return 0;
+}
diff --git a/drivers/media/sprd_dcam/flash/flash_sm5701.c b/drivers/media/sprd_dcam/flash/flash_sm5701.c
new file mode 100644
index 00000000..81354ec1
--- /dev/null
+++ b/drivers/media/sprd_dcam/flash/flash_sm5701.c
@@ -0,0 +1,48 @@
+/*
+* * Copyright (C) 2012 Spreadtrum Communications Inc.
+* *
+* * This software is licensed under the terms of the GNU General Public
+* * License version 2, as published by the Free Software Foundation, and
+* * may be copied, distributed, and modified under those terms.
+* *
+* * This program is distributed in the hope that 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.
+* */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#include <soc/sprd/adi.h>
+#include <linux/leds.h>
+#include <linux/mfd/sm5701_core.h>
+
+int sprd_flash_on(void)
+{
+ printk("sprd_flash_on\n");
+ sm5701_led_ready(MOVIE_MODE);
+ sm5701_set_fleden(SM5701_FLEDEN_ON_MOVIE);
+
+ return 0;
+}
+
+int sprd_flash_high_light(void)
+{
+ printk("sprd_flash_high_light\n");
+ sm5701_led_ready(FLASH_MODE);
+ sm5701_set_fleden(SM5701_FLEDEN_ON_FLASH);
+
+ return 0;
+}
+
+int sprd_flash_close(void)
+{
+ printk("sprd_flash_close\n");
+ sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
+ sm5701_led_ready(LED_DISABLE);
+
+ return 0;
+}
+
diff --git a/drivers/media/sprd_dcam/flash/flash_sprd_sm5701.c b/drivers/media/sprd_dcam/flash/flash_sprd_sm5701.c
new file mode 100644
index 00000000..746495ab
--- /dev/null
+++ b/drivers/media/sprd_dcam/flash/flash_sprd_sm5701.c
@@ -0,0 +1,48 @@
+/*
+* * Copyright (C) 2012 Spreadtrum Communications Inc.
+* *
+* * This software is licensed under the terms of the GNU General Public
+* * License version 2, as published by the Free Software Foundation, and
+* * may be copied, distributed, and modified under those terms.
+* *
+* * This program is distributed in the hope that 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.
+* */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <soc/sprd/hardware.h>
+#include <soc/sprd/board.h>
+#include <soc/sprd/adi.h>
+#include <linux/leds.h>
+#include <linux/mfd/sprd_sm5701_core.h>
+
+int sprd_flash_on(void)
+{
+
+ sm5701_led_ready(MOVIE_MODE);
+ sm5701_set_fleden(SM5701_FLEDEN_ON_MOVIE);
+
+ return 0;
+}
+
+int sprd_flash_high_light(void)
+{
+
+ sm5701_led_ready(FLASH_MODE);
+ sm5701_set_fleden(SM5701_FLEDEN_ON_FLASH);
+
+ return 0;
+}
+
+int sprd_flash_close(void)
+{
+
+ sm5701_set_fleden(SM5701_FLEDEN_DISABLED);
+ sm5701_led_ready(LED_DISABLE);
+
+ return 0;
+}
+
diff --git a/drivers/media/sprd_dcam/flash/flash_vivalto.c b/drivers/media/sprd_dcam/flash/flash_vivalto.c
new file mode 100644
index 00000000..e020933c
--- /dev/null
+++ b/drivers/media/sprd_dcam/flash/flash_vivalto.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/init.h>
+
+#ifndef CONFIG_64BIT
+#include <mach/hardware.h>
+#include <mach/board.h>
+#include <mach/adi.h>
+#endif
+
+#include <asm/gpio.h>
+
+#define SPRD_FLASH_ON 1
+#define SPRD_FLASH_OFF 0
+
+int sprd_flash_on(void)
+{
+ printk("sprd_flash_on \n");
+ gpio_request(GPIO_CAM_FLASH_EN,"cam_flash_en");
+ gpio_direction_output(GPIO_CAM_FLASH_EN, SPRD_FLASH_ON);
+ gpio_free(GPIO_CAM_FLASH_EN);
+ return 0;
+}
+
+int sprd_flash_high_light(void)
+{
+ printk("sprd_flash_high_light \n");
+ gpio_request(GPIO_CAM_FLASH_EN,"cam_flash_en");
+ gpio_direction_output(GPIO_CAM_FLASH_EN, SPRD_FLASH_ON);
+ gpio_free(GPIO_CAM_FLASH_EN);
+ return 0;
+}
+
+int sprd_flash_close(void)
+{
+ printk("sprd_flash_close \n");
+ gpio_request(GPIO_CAM_FLASH_EN,"cam_flash_en");
+ gpio_direction_output(GPIO_CAM_FLASH_EN, SPRD_FLASH_OFF);
+ gpio_free(GPIO_CAM_FLASH_EN);
+ return 0;
+}
diff --git a/drivers/media/sprd_dcam/pike/dcam_drv.c b/drivers/media/sprd_dcam/pike/dcam_drv.c
new file mode 100644
index 00000000..55fcd4c5
--- /dev/null
+++ b/drivers/media/sprd_dcam/pike/dcam_drv.c
@@ -0,0 +1,4549 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <linux/kthread.h>
+#include <soc/sprd/hardware.h>
+#include <mach/irqs.h>
+#include <soc/sprd/sci.h>
+#include <soc/sprd/sci_glb_regs.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/wakelock.h>
+#include "dcam_drv.h"
+#include "gen_scale_coef.h"
+
+#define LOCAL static
+/*#define LOCAL*/
+
+//#define DCAM_DRV_DEBUG
+#define DCAM_LOWEST_ADDR 0x800
+#define DCAM_ADDR_INVALID(addr) ((uint32_t)(addr) < DCAM_LOWEST_ADDR)
+#define DCAM_YUV_ADDR_INVALID(y,u,v) \
+ (DCAM_ADDR_INVALID(y) && \
+ DCAM_ADDR_INVALID(u) && \
+ DCAM_ADDR_INVALID(v))
+
+#define DCAM_SC1_H_TAB_OFFSET 0x400
+#define DCAM_SC1_V_TAB_OFFSET 0x4F0
+#define DCAM_SC1_V_CHROMA_TAB_OFFSET 0x8F0
+
+#define DCAM_SC2_H_TAB_OFFSET 0x1400
+#define DCAM_SC2_V_TAB_OFFSET 0x14F0
+#define DCAM_SC2_V_CHROMA_TAB_OFFSET 0x18F0
+
+#define DCAM_SC_COEFF_BUF_SIZE (24 << 10)
+#define DCAM_SC_COEFF_COEF_SIZE (1 << 10)
+#define DCAM_SC_COEFF_TMP_SIZE (21 << 10)
+#define DCAM_SC_COEFF_BUF_COUNT 2
+
+
+#define DCAM_SC_H_COEF_SIZE (0xC0)
+#define DCAM_SC_V_COEF_SIZE (0x210)
+#define DCAM_SC_V_CHROM_COEF_SIZE (0x210)
+
+#define DCAM_SC_COEFF_H_NUM (DCAM_SC_H_COEF_SIZE/4)
+#define DCAM_SC_COEFF_V_NUM (DCAM_SC_V_COEF_SIZE/4)
+#define DCAM_SC_COEFF_V_CHROMA_NUM (DCAM_SC_V_CHROM_COEF_SIZE/4)
+
+#define DCAM_AXI_STOP_TIMEOUT 1000
+#define DCAM_CLK_DOMAIN_AHB 1
+#define DCAM_CLK_DOMAIN_DCAM 0
+
+#ifdef CONFIG_SC_FPGA
+#define DCAM_PATH_TIMEOUT msecs_to_jiffies(500*10)
+#else
+#define DCAM_PATH_TIMEOUT msecs_to_jiffies(500)
+#endif
+
+#define DCAM_FRM_QUEUE_LENGTH 4
+
+#define DCAM_STATE_QUICKQUIT 0x01
+
+#define DCAM_CHECK_PARAM_ZERO_POINTER(n) \
+ do { \
+ if (0 == (int)(n)) \
+ return -DCAM_RTN_PARA_ERR; \
+ } while(0)
+
+#define DCAM_CLEAR(a) \
+ do { \
+ memset((void *)(a), 0, sizeof(*(a))); \
+ } while(0)
+
+#define DEBUG_STR "Error L %d, %s \n"
+#define DEBUG_ARGS __LINE__,__FUNCTION__
+#define DCAM_RTN_IF_ERR \
+ do { \
+ if(rtn) { \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return -(rtn); \
+ } \
+ } while(0)
+
+#define DCAM_IRQ_LINE_MASK 0x001FFFFFUL
+
+typedef void (*dcam_isr)(void);
+
+enum {
+ DCAM_FRM_UNLOCK = 0,
+ DCAM_FRM_LOCK_WRITE = 0x10011001,
+ DCAM_FRM_LOCK_READ = 0x01100110
+};
+
+enum {
+ DCAM_ST_STOP = 0,
+ DCAM_ST_START,
+};
+
+#define DCAM_IRQ_ERR_MASK \
+ ((1 << DCAM_PATH0_OV) | (1 << DCAM_PATH1_OV) | (1 << DCAM_PATH2_OV) | \
+ (1 << DCAM_SN_LINE_ERR) | (1 << DCAM_SN_FRAME_ERR) | \
+ (1 << DCAM_ISP_OV) | (1 << DCAM_MIPI_OV))
+
+#define DCAM_IRQ_JPEG_OV_MASK (1 << DCAM_JPEG_BUF_OV)
+
+#define DCAM_CHECK_ZERO(a) \
+ do { \
+ if (DCAM_ADDR_INVALID(a)) { \
+ printk("DCAM, zero pointer \n"); \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return -EFAULT; \
+ } \
+ } while(0)
+
+#define DCAM_CHECK_ZERO_VOID(a) \
+ do { \
+ if (DCAM_ADDR_INVALID(a)) { \
+ printk("DCAM, zero pointer \n"); \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return; \
+ } \
+ } while(0)
+
+struct dcam_cap_desc {
+ uint32_t interface;
+ uint32_t input_format;
+ uint32_t frame_deci_factor;
+ uint32_t img_x_deci_factor;
+ uint32_t img_y_deci_factor;
+};
+
+struct dcam_path_valid {
+ uint32_t input_size :1;
+ uint32_t input_rect :1;
+ uint32_t output_size :1;
+ uint32_t output_format :1;
+ uint32_t src_sel :1;
+ uint32_t data_endian :1;
+ uint32_t frame_deci :1;
+ uint32_t scale_tap :1;
+ uint32_t v_deci :1;
+};
+
+struct dcam_frm_queue {
+ struct dcam_frame frm_array[DCAM_FRM_QUEUE_LENGTH];
+ uint32_t valid_cnt;
+};
+
+struct dcam_buf_queue {
+ struct dcam_frame frame[DCAM_FRM_CNT_MAX];
+ struct dcam_frame *write;
+ struct dcam_frame *read;
+ spinlock_t lock;
+};
+
+struct dcam_path_desc {
+ struct dcam_size input_size;
+ struct dcam_rect input_rect;
+ struct dcam_size sc_input_size;
+ struct dcam_size output_size;
+ struct dcam_frame input_frame;
+ struct dcam_frm_queue frame_queue;
+ struct dcam_buf_queue buf_queue;
+ //struct dcam_frame *output_frame_head;
+ //struct dcam_frame *output_frame_cur;
+ struct dcam_endian_sel data_endian;
+ struct dcam_sc_tap scale_tap;
+ struct dcam_deci deci_val;
+ struct dcam_path_valid valid_param;
+ uint32_t frame_base_id;
+ uint32_t output_frame_count;
+ uint32_t output_format;
+ uint32_t src_sel;
+ uint32_t rot_mode;
+ uint32_t frame_deci;
+ uint32_t valide;
+ uint32_t status;
+ struct semaphore tx_done_sema;
+ struct semaphore sof_sema;
+ uint32_t wait_for_done;
+ uint32_t is_update;
+ uint32_t wait_for_sof;
+ uint32_t need_stop;
+ uint32_t need_wait;
+ int32_t sof_cnt;
+};
+
+struct dcam_module {
+ uint32_t dcam_mode;
+ uint32_t module_addr;
+ struct dcam_cap_desc dcam_cap;
+ struct dcam_path_desc dcam_path0;
+ struct dcam_path_desc dcam_path1;
+ struct dcam_path_desc dcam_path2;
+ struct dcam_frame path0_frame[DCAM_PATH_0_FRM_CNT_MAX];
+ struct dcam_frame path1_frame[DCAM_PATH_1_FRM_CNT_MAX];
+ struct dcam_frame path2_frame[DCAM_PATH_2_FRM_CNT_MAX];
+ struct dcam_frame path0_reserved_frame;
+ struct dcam_frame path1_reserved_frame;
+ struct dcam_frame path2_reserved_frame;
+ struct semaphore stop_sema;
+ uint32_t wait_stop;
+ struct semaphore resize_done_sema;
+ uint32_t wait_resize_done;
+ struct semaphore rotation_done_sema;
+ uint32_t wait_rotation_done;
+ uint32_t err_happened;
+ struct semaphore scale_coeff_mem_sema;
+ uint32_t state;
+};
+
+struct dcam_sc_coeff {
+ uint32_t buf[DCAM_SC_COEFF_BUF_SIZE];
+ uint32_t flag;
+ struct dcam_path_desc dcam_path1;
+};
+
+struct dcam_sc_array {
+ struct dcam_sc_coeff scaling_coeff[DCAM_SC_COEFF_BUF_COUNT];
+ struct dcam_sc_coeff *scaling_coeff_queue[DCAM_SC_COEFF_BUF_COUNT];
+ uint32_t valid_cnt;
+ uint32_t is_smooth_zoom;
+};
+
+LOCAL atomic_t s_dcam_users = ATOMIC_INIT(0);
+LOCAL atomic_t s_resize_flag = ATOMIC_INIT(0);
+LOCAL atomic_t s_rotation_flag = ATOMIC_INIT(0);
+LOCAL struct clk* s_dcam_clk = NULL;
+LOCAL struct dcam_module* s_p_dcam_mod = 0;
+LOCAL uint32_t s_dcam_irq = 0x5A0000A5;
+LOCAL dcam_isr_func s_user_func[DCAM_IRQ_NUMBER];
+LOCAL void* s_user_data[DCAM_IRQ_NUMBER];
+LOCAL struct dcam_sc_array* s_dcam_sc_array = NULL;
+LOCAL struct wake_lock dcam_wakelock;
+
+LOCAL DEFINE_MUTEX(dcam_sem);
+LOCAL DEFINE_MUTEX(dcam_scale_sema);
+LOCAL DEFINE_MUTEX(dcam_rot_sema);
+LOCAL DEFINE_MUTEX(dcam_module_sema);
+LOCAL DEFINE_SPINLOCK(dcam_mod_lock);
+LOCAL DEFINE_SPINLOCK(dcam_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_cfg_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_control_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_mask_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_clr_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_ahbm_sts_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_endian_lock);
+
+LOCAL void _dcam_path0_set(void);
+LOCAL void _dcam_path1_set(struct dcam_path_desc *path);
+LOCAL void _dcam_path2_set(void);
+LOCAL void _dcam_frm_clear(enum dcam_path_index path_index);
+LOCAL void _dcam_link_frm(uint32_t base_id);
+LOCAL int32_t _dcam_path_set_next_frm(enum dcam_path_index path_index, uint32_t is_1st_frm);
+/*LOCAL int32_t _dcam_path_trim(enum dcam_path_index path_index);*/
+LOCAL int32_t _dcam_path_scaler(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_calc_sc_size(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_set_sc_coeff(enum dcam_path_index path_index);
+LOCAL void _dcam_force_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy);
+LOCAL void _dcam_auto_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy);
+LOCAL void _dcam_force_copy(enum dcam_path_index path_index);
+LOCAL void _dcam_auto_copy(enum dcam_path_index path_index);
+LOCAL void _dcam_reg_trace(void);
+/*LOCAL void _dcam_sensor_sof(void);*/
+LOCAL void _dcam_sensor_eof(void);
+LOCAL void _dcam_cap_sof(void);
+LOCAL void _dcam_cap_eof(void);
+LOCAL void _dcam_path0_done(void);
+LOCAL void _dcam_path0_overflow(void);
+LOCAL void _dcam_path1_done(void);
+LOCAL void _dcam_path1_overflow(void);
+LOCAL void _dcam_sensor_line_err(void);
+LOCAL void _dcam_sensor_frame_err(void);
+LOCAL void _dcam_jpeg_buf_ov(void);
+LOCAL void _dcam_path2_done(void);
+LOCAL void _dcam_path2_ov(void);
+LOCAL void _dcam_isp_ov(void);
+LOCAL void _dcam_mipi_ov(void);
+LOCAL void _dcam_path1_slice_done(void);
+LOCAL void _dcam_path2_slice_done(void);
+LOCAL void _dcam_raw_slice_done(void);
+LOCAL void _dcam_path1_sof(void);
+LOCAL void _dcam_path2_sof(void);
+LOCAL irqreturn_t _dcam_isr_root(int irq, void *dev_id);
+LOCAL void _dcam_stopped_notice(void);
+LOCAL void _dcam_stopped(void);
+LOCAL int32_t _dcam_path_check_deci(enum dcam_path_index path_index, uint32_t *is_deci);
+extern void _dcam_isp_root(void);
+LOCAL int _dcam_internal_init(void);
+LOCAL void _dcam_internal_deinit(void);
+LOCAL void _dcam_wait_path_done(enum dcam_path_index path_index, uint32_t *p_flag);
+LOCAL void _dcam_path_done_notice(enum dcam_path_index path_index);
+LOCAL void _dcam_rot_done(void);
+LOCAL int32_t _dcam_err_pre_proc(void);
+LOCAL void _dcam_frm_queue_clear(struct dcam_frm_queue *queue);
+LOCAL int32_t _dcam_frame_enqueue(struct dcam_frm_queue *queue, struct dcam_frame *frame);
+LOCAL int32_t _dcam_frame_dequeue(struct dcam_frm_queue *queue, struct dcam_frame *frame);
+LOCAL void _dcam_buf_queue_init(struct dcam_buf_queue *queue);
+LOCAL int32_t _dcam_buf_queue_write(struct dcam_buf_queue *queue, struct dcam_frame *frame);
+LOCAL int32_t _dcam_buf_queue_read(struct dcam_buf_queue *queue, struct dcam_frame *frame);
+LOCAL void _dcam_wait_update_done(enum dcam_path_index path_index, uint32_t *p_flag);
+LOCAL void _dcam_path_updated_notice(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_get_valid_sc_coeff(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff);
+LOCAL int32_t _dcam_push_sc_buf(struct dcam_sc_array *sc, uint32_t index);
+LOCAL int32_t _dcam_pop_sc_buf(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff);
+LOCAL int32_t _dcam_calc_sc_coeff(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_write_sc_coeff(enum dcam_path_index path_index);
+LOCAL void _dcam_wait_for_quickstop(enum dcam_path_index path_index);
+
+LOCAL const dcam_isr isr_list[DCAM_IRQ_NUMBER] = {
+ NULL,//_dcam_isp_root,
+ _dcam_sensor_eof,
+ _dcam_cap_sof,
+ _dcam_cap_eof,
+ _dcam_path0_done,
+ _dcam_path0_overflow,
+ _dcam_path1_done,
+ _dcam_path1_overflow,
+ _dcam_path2_done,
+ _dcam_path2_ov,
+ _dcam_sensor_line_err,
+ _dcam_sensor_frame_err,
+ _dcam_jpeg_buf_ov,
+ _dcam_isp_ov,
+ _dcam_mipi_ov,
+ _dcam_rot_done,
+ _dcam_path1_slice_done,
+ _dcam_path2_slice_done,
+ _dcam_raw_slice_done,
+ _dcam_path1_sof,
+ _dcam_path2_sof,
+};
+
+void dcam_glb_reg_awr(uint32_t addr, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ REG_WR(addr, REG_RD(addr) & (val));
+ break;
+ }
+}
+
+void dcam_glb_reg_owr(uint32_t addr, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ REG_WR(addr, REG_RD(addr) | (val));
+ break;
+ }
+}
+
+void dcam_glb_reg_mwr(uint32_t addr, uint32_t mask, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+ uint32_t tmp = 0;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ break;
+ }
+}
+
+int32_t dcam_module_init(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ if (if_mode >= DCAM_CAP_IF_MODE_MAX) {
+ rtn = -DCAM_RTN_CAP_IF_MODE_ERR;
+ } else {
+ if (sn_mode >= DCAM_CAP_MODE_MAX) {
+ rtn = -DCAM_RTN_CAP_SENSOR_MODE_ERR;
+ } else {
+ _dcam_internal_init();
+ _dcam_link_frm(0); /* set default base frame index as 0 */
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path0.buf_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path1.buf_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path2.buf_queue);
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ cap_desc->interface = if_mode;
+ cap_desc->input_format = sn_mode;
+ /*REG_OWR(DCAM_EB, BIT_13);//MM_EB*/
+ /*REG_OWR(DCAM_MATRIX_EB, BIT_10|BIT_5);*/
+ if (DCAM_CAP_IF_CSI2 == if_mode) {
+ /* REG_OWR(CSI2_DPHY_EB, MIPI_EB_BIT);*/
+ //ret = _dcam_mipi_clk_en();
+ dcam_glb_reg_owr(DCAM_CFG, BIT_9, DCAM_CFG_REG);
+ REG_MWR(CAP_MIPI_CTRL, BIT_2 | BIT_1, sn_mode << 1);
+ } else {
+ /*REG_OWR(DCAM_EB, CCIR_IN_EB_BIT);
+ REG_OWR(DCAM_EB, CCIR_EB_BIT);*/
+ //ret = _dcam_ccir_clk_en();
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ REG_MWR(CAP_CCIR_CTRL, BIT_2 | BIT_1, sn_mode << 1);
+ }
+ rtn = DCAM_RTN_SUCCESS;
+ }
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_module_deinit(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ if (DCAM_CAP_IF_CSI2 == if_mode) {
+ /*REG_MWR(CSI2_DPHY_EB, MIPI_EB_BIT, 0 << 10);*/
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ //_dcam_mipi_clk_dis();
+ } else {
+ /*REG_MWR(DCAM_EB, CCIR_IN_EB_BIT, 0 << 2);
+ REG_MWR(DCAM_EB, CCIR_EB_BIT, 0 << 9);*/
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ //_dcam_ccir_clk_dis();
+ }
+
+ _dcam_internal_deinit();
+
+ return -rtn;
+}
+
+int dcam_scale_coeff_alloc(void)
+{
+ int ret = 0;
+
+ if (NULL == s_dcam_sc_array) {
+ s_dcam_sc_array = (struct dcam_sc_array*)vzalloc(sizeof(struct dcam_sc_array));
+ if (NULL == s_dcam_sc_array) {
+ printk("DCAM: _dcam_scale_coeff_alloc fail.\n");
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+void dcam_scale_coeff_free(void)
+{
+ if (s_dcam_sc_array) {
+ vfree(s_dcam_sc_array);
+ s_dcam_sc_array = NULL;
+ }
+}
+
+LOCAL uint32_t *dcam_get_scale_coeff_addr(uint32_t *index)
+{
+ uint32_t i;
+
+ if (DCAM_ADDR_INVALID(s_dcam_sc_array)) {
+ printk("DCAM: scale addr, invalid param 0x%x \n",
+ (uint32_t)s_dcam_sc_array);
+ return NULL;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_BUF_COUNT; i++) {
+ if (0 == s_dcam_sc_array->scaling_coeff[i].flag) {
+ *index = i;
+ DCAM_TRACE("dcam: get buf index %d \n", i);
+ return s_dcam_sc_array->scaling_coeff[i].buf;
+ }
+ }
+ printk("dcam: get buf index %d \n", i);
+
+ return NULL;
+}
+
+int32_t dcam_module_en(struct device_node *dn)
+{
+ int ret = 0;
+ unsigned int irq_no = 0;
+
+ DCAM_TRACE("DCAM: dcam_module_en, In %d \n", s_dcam_users.counter);
+
+ mutex_lock(&dcam_module_sema);
+ if (atomic_inc_return(&s_dcam_users) == 1) {
+
+ wake_lock_init(&dcam_wakelock, WAKE_LOCK_SUSPEND,
+ "pm_message_wakelock_dcam");
+
+ wake_lock(&dcam_wakelock);
+
+ ret = clk_mm_i_eb(dn,1);
+ if (ret) {
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+
+ ret = dcam_set_clk(dn,DCAM_CLK_256M);
+ if (ret) {
+ clk_mm_i_eb(dn,0);
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+
+ parse_baseaddress(dn);
+
+ dcam_reset(DCAM_RST_ALL, 0);
+ atomic_set(&s_resize_flag, 0);
+ atomic_set(&s_rotation_flag, 0);
+ memset((void*)s_user_func, 0, sizeof(s_user_func));
+ memset((void*)s_user_data, 0, sizeof(s_user_data));
+ printk("DCAM: register isr, 0x%x \n", REG_RD(DCAM_INT_MASK));
+
+ irq_no = parse_irq(dn);
+ printk("DCAM: irq_no = 0x%x \n", irq_no);
+ ret = request_irq(irq_no,
+ _dcam_isr_root,
+ IRQF_SHARED,
+ "DCAM",
+ (void*)&s_dcam_irq);
+ if (ret) {
+ printk("DCAM: dcam_start, error %d \n", ret);
+ dcam_set_clk(dn,DCAM_CLK_NONE);
+ clk_mm_i_eb(dn,0);
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+
+ DCAM_TRACE("DCAM: dcam_module_en end \n");
+ }
+ DCAM_TRACE("DCAM: dcam_module_en, Out %d \n", s_dcam_users.counter);
+ mutex_unlock(&dcam_module_sema);
+ return 0;
+
+fail_exit:
+ wake_unlock(&dcam_wakelock);
+ wake_lock_destroy(&dcam_wakelock);
+ atomic_dec(&s_dcam_users);
+ mutex_unlock(&dcam_module_sema);
+ return ret;
+}
+
+int32_t dcam_module_dis(struct device_node *dn)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ int ret = 0;
+ unsigned int irq_no = 0;
+
+ DCAM_TRACE("DCAM: dcam_module_dis, In %d \n", s_dcam_users.counter);
+
+ mutex_lock(&dcam_module_sema);
+ if (atomic_dec_return(&s_dcam_users) == 0) {
+
+ sci_glb_clr(DCAM_EB, DCAM_EB_BIT);
+ dcam_set_clk(dn,DCAM_CLK_NONE);
+ printk("DCAM: un register isr \n");
+ irq_no = parse_irq(dn);
+ free_irq(irq_no, (void*)&s_dcam_irq);
+ ret = clk_mm_i_eb(dn,0);
+ if (ret) {
+ rtn = -DCAM_RTN_MAX;
+ }
+ wake_unlock(&dcam_wakelock);
+ wake_lock_destroy(&dcam_wakelock);
+ }
+
+ DCAM_TRACE("DCAM: dcam_module_dis, Out %d \n", s_dcam_users.counter);
+ mutex_unlock(&dcam_module_sema);
+
+ return rtn;
+}
+
+int32_t dcam_reset(enum dcam_rst_mode reset_mode, uint32_t is_isr)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ uint32_t time_out = 0;
+
+ DCAM_TRACE("DCAM: reset: %d \n", reset_mode);
+
+ if (!is_isr) {
+ mutex_lock(&dcam_scale_sema);
+ mutex_lock(&dcam_rot_sema);
+ }
+
+ if (DCAM_RST_ALL == reset_mode) {
+ if (atomic_read(&s_dcam_users)) {
+ /* firstly, stop AXI writing */
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_6, DCAM_AHBM_STS_REG);
+ }
+
+ /* then wait for AHB busy cleared */
+ while (++time_out < DCAM_AXI_STOP_TIMEOUT) {
+ if (0 == (REG_RD(DCAM_AHBM_STS) & BIT_0))
+ break;
+ }
+ if (time_out >= DCAM_AXI_STOP_TIMEOUT) {
+ printk("DCAM: reset TO: %d \n", time_out);
+ return DCAM_RTN_TIMEOUT;
+ }
+ }
+
+ /* do reset action */
+ switch (reset_mode) {
+ case DCAM_RST_PATH0:
+ sci_glb_set(DCAM_RST, PATH0_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH0_RST_BIT);
+ DCAM_TRACE("DCAM: reset path0 \n");
+ break;
+
+ case DCAM_RST_PATH1:
+ sci_glb_set(DCAM_RST, PATH1_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH1_RST_BIT);
+ DCAM_TRACE("DCAM: reset path1 \n");
+ break;
+
+ case DCAM_RST_PATH2:
+ sci_glb_set(DCAM_RST, PATH2_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH2_RST_BIT);
+ DCAM_TRACE("DCAM: reset path2 \n");
+ break;
+
+ case DCAM_RST_ALL:
+ sci_glb_set(DCAM_RST, DCAM_MOD_RST_BIT | CCIR_RST_BIT);
+ sci_glb_clr(DCAM_RST, DCAM_MOD_RST_BIT | CCIR_RST_BIT);
+ dcam_glb_reg_owr(DCAM_INT_CLR,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_CLR_REG);
+ dcam_glb_reg_owr(DCAM_INT_MASK,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_MASK_REG);
+ printk("DCAM: reset all \n");
+ break;
+ default:
+ rtn = DCAM_RTN_PARA_ERR;
+ break;
+ }
+
+ if (DCAM_RST_ALL == reset_mode) {
+ if (atomic_read(&s_dcam_users)) {
+ /* the end, enable AXI writing */
+ dcam_glb_reg_awr(DCAM_AHBM_STS, ~BIT_6, DCAM_AHBM_STS_REG);
+ }
+ }
+
+ if (!is_isr) {
+ mutex_unlock(&dcam_rot_sema);
+ mutex_unlock(&dcam_scale_sema);
+ }
+
+ DCAM_TRACE("DCAM: reset_mode=%x end \n", reset_mode);
+
+ return -rtn;
+}
+
+int32_t dcam_set_clk(struct device_node *dn, enum dcam_clk_sel clk_sel)
+{
+#ifdef CONFIG_SC_FPGA_CLK
+ return 0;
+#else
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct clk *clk_parent;
+ char *parent = "clk_312m";
+ int ret = 0;
+
+ switch (clk_sel) {
+ case DCAM_CLK_312M:
+ parent = "clk_312m";
+ break;
+ case DCAM_CLK_256M:
+ parent = "clk_256m";
+ break;
+ case DCAM_CLK_128M:
+ parent = "clk_128m";
+ break;
+ case DCAM_CLK_76M8:
+ parent = "clk_76p8m";
+ break;
+ case DCAM_CLK_NONE:
+ printk("DCAM close CLK %d \n", (int)clk_get_rate(s_dcam_clk));
+ if (s_dcam_clk) {
+ clk_disable(s_dcam_clk);
+ clk_put(s_dcam_clk);
+ s_dcam_clk = NULL;
+ }
+ return 0;
+ default:
+ parent = "clk_128m";
+ break;
+ }
+
+ if (NULL == s_dcam_clk) {
+ s_dcam_clk = parse_clk(dn,"clk_dcam");
+ if (IS_ERR(s_dcam_clk)) {
+ printk("DCAM: clk_get fail, %d \n", (int)s_dcam_clk);
+ return -1;
+ } else {
+ DCAM_TRACE("DCAM: get clk_parent ok \n");
+ }
+ } else {
+ clk_disable(s_dcam_clk);
+ }
+
+ clk_parent = clk_get(NULL, parent);
+ if (IS_ERR(clk_parent)) {
+ printk("DCAM: dcam_set_clk fail, %d \n", (int)clk_parent);
+ return -1;
+ } else {
+ DCAM_TRACE("DCAM: get clk_parent ok \n");
+ }
+
+ ret = clk_set_parent(s_dcam_clk, clk_parent);
+ if(ret){
+ printk("DCAM: clk_set_parent fail, %d \n", ret);
+ }
+
+ ret = clk_enable(s_dcam_clk);
+ if (ret) {
+ printk("enable dcam clk error.\n");
+ return -1;
+ }
+ return rtn;
+#endif
+}
+
+int32_t dcam_update_path(enum dcam_path_index path_index, struct dcam_size *in_size,
+ struct dcam_rect *in_rect, struct dcam_size *out_size)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flags;
+ uint32_t is_deci = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ rtn = dcam_path1_cfg(DCAM_PATH_INPUT_SIZE, in_size);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path1_cfg(DCAM_PATH_INPUT_RECT, in_rect);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path1_cfg(DCAM_PATH_OUTPUT_SIZE, out_size);
+ DCAM_RTN_IF_ERR;
+ rtn = _dcam_path_check_deci(DCAM_PATH_IDX_1, &is_deci);
+ DCAM_RTN_IF_ERR;
+ DCAM_TRACE("DCAM: To update path1 \n");
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_1);
+ DCAM_RTN_IF_ERR;
+ DCAM_TRACE("DCAM: dcam_update_path 1 \n");
+ if (s_dcam_sc_array->is_smooth_zoom) {
+ spin_lock_irqsave(&dcam_lock, flags);
+ s_p_dcam_mod->dcam_path1.is_update = 1;
+ spin_unlock_irqrestore(&dcam_lock, flags);
+ } else {
+ _dcam_wait_update_done(DCAM_PATH_IDX_1, &s_p_dcam_mod->dcam_path1.is_update);
+ }
+ if (!s_dcam_sc_array->is_smooth_zoom) {
+ _dcam_wait_update_done(DCAM_PATH_IDX_1, NULL);
+ }
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ local_irq_save(flags);
+ if(s_p_dcam_mod->dcam_path2.is_update){
+ local_irq_restore(flags);
+ DCAM_TRACE("DCAM: dcam_update_path 2: updating return \n");
+ return rtn;
+ }
+ local_irq_restore(flags);
+
+ rtn = dcam_path2_cfg(DCAM_PATH_INPUT_SIZE, in_size);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path2_cfg(DCAM_PATH_INPUT_RECT, in_rect);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path2_cfg(DCAM_PATH_OUTPUT_SIZE, out_size);
+ DCAM_RTN_IF_ERR;
+
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_2);
+ DCAM_RTN_IF_ERR;
+
+ local_irq_save(flags);
+ s_p_dcam_mod->dcam_path2.is_update = 1;
+ local_irq_restore(flags);
+ }
+
+ DCAM_TRACE("DCAM: dcam_update_path: done \n");
+
+ return -rtn;
+}
+
+int32_t dcam_start_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ uint32_t cap_en = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: start_path: path %d, mode %x path 0,1,2 {%d %d %d} \n",
+ path_index,
+ s_p_dcam_mod->dcam_mode,
+ s_p_dcam_mod->dcam_path0.valide,
+ s_p_dcam_mod->dcam_path1.valide,
+ s_p_dcam_mod->dcam_path2.valide);
+
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_8, DCAM_AHBM_STS_REG); // aiden add: write arbit mode
+
+ cap_en = REG_RD(DCAM_CONTROL) & BIT_2;
+ DCAM_TRACE("DCAM: cap_eb %d \n", cap_en);
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ _dcam_path0_set();
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, true);
+ DCAM_RTN_IF_ERR;
+ if (cap_en) {
+ /* if cap is already open, the sequence is:
+ cap force copy -> path 0 enable -> cap auto copy */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_0, 1 << 0, DCAM_CONTROL_REG); /* Cap force copy */
+ dcam_glb_reg_owr(DCAM_CFG, BIT_0, DCAM_CFG_REG); /* Enable Path 0 */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_1, 1 << 1, DCAM_CONTROL_REG); /* Cap auto copy, trigger path 0 enable */
+ } else {
+ dcam_glb_reg_owr(DCAM_CFG, BIT_0, DCAM_CFG_REG); /* Enable Path 0 */
+ }
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+
+ //rtn = _dcam_path_trim(DCAM_PATH_IDX_1);
+ //DCAM_RTN_IF_ERR;
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_1);
+ DCAM_RTN_IF_ERR;
+
+ _dcam_path1_set(&s_p_dcam_mod->dcam_path1);
+ DCAM_TRACE("DCAM: start path: path_control=%x \n", REG_RD(DCAM_CONTROL));
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy_ext(DCAM_PATH_IDX_1, true, true);
+ DCAM_TRACE("DCAM: int= %x \n", REG_RD(DCAM_INT_STS));
+ dcam_glb_reg_owr(DCAM_CFG, BIT_1, DCAM_CFG_REG);
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_2);
+ DCAM_RTN_IF_ERR;
+
+ _dcam_path2_set();
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy_ext(DCAM_PATH_IDX_2, true, true);
+ dcam_glb_reg_owr(DCAM_CFG, BIT_2, DCAM_CFG_REG);
+ }
+
+ printk("DCAM PATH S: %d \n", path_index);
+
+ if (0 == cap_en) {
+#ifdef DCAM_DEBUG
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_5 | BIT_4, 1 << 4);
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_5 | BIT_4, 1 << 4);
+#endif
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_0, 1 << 0, DCAM_CONTROL_REG); /* Cap force copy */
+ //REG_MWR(DCAM_CONTROL, BIT_1, 1 << 1); /* Cap auto copy */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 1 << 2, DCAM_CONTROL_REG); /* Cap Enable */
+ }
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, false);
+ DCAM_RTN_IF_ERR;
+ _dcam_auto_copy(DCAM_PATH_IDX_0);
+ s_p_dcam_mod->dcam_path0.status = DCAM_ST_START;
+ }
+
+ _dcam_reg_trace();
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ s_p_dcam_mod->dcam_path1.need_wait = 0;
+ s_p_dcam_mod->dcam_path1.status = DCAM_ST_START;
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ s_p_dcam_mod->dcam_path2.need_wait = 0;
+ s_p_dcam_mod->dcam_path2.status = DCAM_ST_START;
+ }
+
+ if (DCAM_PATH_IDX_ALL != path_index) {
+ if ((DCAM_PATH_IDX_0 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_0, NULL);
+ } else if ((DCAM_PATH_IDX_1 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_1, NULL);
+ } else if ((DCAM_PATH_IDX_2 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_2, NULL);
+ }
+ }
+
+ DCAM_TRACE("DCAM: start_path E\n");
+ return -rtn;
+}
+
+int32_t dcam_start(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ int ret = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: dcam_start %x \n", s_p_dcam_mod->dcam_mode);
+
+ ret = dcam_start_path(DCAM_PATH_IDX_ALL);
+ //ret = dcam_start_path(DCAM_PATH_IDX_1);
+
+ return -rtn;
+}
+
+int32_t dcam_stop_cap(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+#if 0
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ printk("DCAM: stop cap %d \n", s_p_dcam_mod->dcam_mode);
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 0, DCAM_CONTROL_REG); /* Cap Enable */
+ DCAM_TRACE("DCAM: stop cap, s_resize_flag %d \n", atomic_read(&s_resize_flag));
+ if (atomic_read(&s_resize_flag)) {
+ s_p_dcam_mod->wait_resize_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->resize_done_sema, DCAM_PATH_TIMEOUT);
+ }
+ if (atomic_read(&s_rotation_flag)) {
+ s_p_dcam_mod->wait_rotation_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->rotation_done_sema, DCAM_PATH_TIMEOUT);
+ }
+
+ dcam_reset(DCAM_RST_ALL, 0);
+ DCAM_TRACE("DCAM: stop cap, Out \n");
+#endif
+ return -rtn;
+}
+
+int32_t _dcam_stop_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ spin_lock_irqsave(&dcam_lock, flag);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: stop path Wrong index 0x%x \n", path_index);
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ return -rtn;
+ }
+
+ _dcam_wait_for_quickstop(path_index);
+ p_path->status = DCAM_ST_STOP;
+ p_path->valide = 0;
+ _dcam_frm_clear(path_index);
+
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ return rtn;
+}
+
+int32_t dcam_stop_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ printk("DCAM: stop_path 0x%x \n", path_index);
+
+ if (path_index < DCAM_PATH_IDX_0 ||
+ path_index >= DCAM_PATH_IDX_ALL) {
+ printk("DCAM: error path_index \n");
+ return -rtn;
+ }
+
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_0, &s_p_dcam_mod->dcam_path0.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_0);
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_1, &s_p_dcam_mod->dcam_path1.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_1);
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ DCAM_TRACE("DCAM: stop path2 In \n");
+ _dcam_wait_path_done(DCAM_PATH_IDX_2, &s_p_dcam_mod->dcam_path2.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_2);
+ }
+
+ DCAM_TRACE("DCAM dcam_stop_path E: %d \n", path_index);
+
+ return -rtn;
+}
+
+LOCAL void _dcam_wait_for_channel_stop(enum dcam_path_index path_index)
+{
+ int time_out = 5000;
+ uint32_t ret = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ /* wait for AHB path busy cleared */
+ while (time_out) {
+ if (s_p_dcam_mod->dcam_path1.valide && (DCAM_PATH_IDX_1 & path_index)) {
+ ret = REG_RD(DCAM_AHBM_STS) & BIT_17;
+ } else if (s_p_dcam_mod->dcam_path2.valide && (DCAM_PATH_IDX_2 & path_index)) {
+ ret = REG_RD(DCAM_AHBM_STS) & BIT_18;
+ } else {
+ /*nothing*/
+ }
+ if (!ret) {
+ break;
+ }
+ time_out --;
+ }
+
+ DCAM_TRACE("DCAM: wait channel stop %d %d \n", ret, time_out);
+
+ return;
+}
+
+LOCAL void _dcam_quickstop_set(enum dcam_path_index path_index, uint32_t path_rst, uint32_t path_bit,
+ uint32_t cfg_bit, uint32_t ahbm_bit, uint32_t auto_copy_bit)
+{
+ dcam_glb_reg_owr(DCAM_AHBM_STS, ahbm_bit, DCAM_AHBM_STS_REG);
+ udelay(10);
+ dcam_glb_reg_mwr(DCAM_CFG, cfg_bit, ~cfg_bit, DCAM_CFG_REG);
+ _dcam_force_copy(path_index);
+ _dcam_wait_for_channel_stop(path_index);
+ dcam_glb_reg_awr(DCAM_AHBM_STS, ~ahbm_bit, DCAM_AHBM_STS_REG);
+ dcam_reset(path_rst, 0);
+
+ return;
+}
+
+#define DCAM_IRQ_MASK_PATH0 (0x0f|(0x03<<4)|(1<<12)|(1<<21)) //let other module continue
+#define DCAM_IRQ_MASK_PATH1 (0x0f|(0x03<<6)|(1<<16)|(1<<19)|(1<<22))
+#define DCAM_IRQ_MASK_PATH2 (0x0f|(0x03<<8)|(1<<17)|(1<<20)|(1<<23))
+
+LOCAL void _dcam_quickstop_set_all(enum dcam_path_index path_index, uint32_t path_bit, uint32_t cfg_bit, uint32_t ahbm_bit)
+{
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_3 | BIT_4 | BIT_5, DCAM_AHBM_STS_REG);
+ udelay(10);
+ dcam_glb_reg_awr(DCAM_CFG, ~(BIT_0 | BIT_1 | BIT_2), DCAM_CFG_REG);
+ dcam_glb_reg_owr(DCAM_CONTROL, BIT_10 | BIT_12, DCAM_CONTROL_REG);
+ dcam_glb_reg_awr(DCAM_CONTROL, ~(BIT_10 | BIT_12), DCAM_CONTROL_REG);
+ _dcam_wait_for_channel_stop(DCAM_PATH_IDX_1);
+ _dcam_wait_for_channel_stop(DCAM_PATH_IDX_2);
+
+ return;
+}
+
+LOCAL void _dcam_wait_for_quickstop(enum dcam_path_index path_index)
+{
+ int time_out = 5000;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: state before stop 0x%x\n", s_p_dcam_mod->state);
+
+ if (DCAM_PATH_IDX_ALL == path_index) {
+ _dcam_quickstop_set_all(0, 0, 0, 0);
+ } else {
+ if (s_p_dcam_mod->dcam_path0.valide && (DCAM_PATH_IDX_0 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_0, DCAM_RST_PATH0, DCAM_IRQ_MASK_PATH0, BIT_0, BIT_3, BIT_9);
+ }
+ if (s_p_dcam_mod->dcam_path1.valide && (DCAM_PATH_IDX_1 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_1, DCAM_RST_PATH1, DCAM_IRQ_MASK_PATH1, BIT_1, BIT_4, BIT_11);
+ }
+ if (s_p_dcam_mod->dcam_path2.valide && (DCAM_PATH_IDX_2 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_2, DCAM_RST_PATH2, DCAM_IRQ_MASK_PATH2, BIT_2, BIT_5, BIT_13);
+ }
+ }
+
+ DCAM_TRACE("DCAM: exit _dcam_wait_for_quickstop %d state: 0x%x \n ", time_out, s_p_dcam_mod->state);
+
+ return;
+}
+
+int32_t dcam_stop(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ s_p_dcam_mod->state |= DCAM_STATE_QUICKQUIT;
+ printk("DCAM dcam_stop In \n");
+ if (atomic_read(&s_resize_flag)) {
+ s_p_dcam_mod->wait_resize_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->resize_done_sema, DCAM_PATH_TIMEOUT);
+ }
+ if (atomic_read(&s_rotation_flag)) {
+ s_p_dcam_mod->wait_rotation_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->rotation_done_sema, DCAM_PATH_TIMEOUT);
+ }
+
+ //mutex_lock(&dcam_sem);
+ printk("DCAM dcam_stop get dcam_sem\n");
+ spin_lock_irqsave(&dcam_lock, flag);
+
+ dcam_glb_reg_owr(DCAM_INT_MASK,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_MASK_REG);
+
+ _dcam_wait_for_quickstop(DCAM_PATH_IDX_ALL);
+ s_p_dcam_mod->dcam_path0.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path0.valide = 0;
+ s_p_dcam_mod->dcam_path1.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path1.valide = 0;
+ s_p_dcam_mod->dcam_path2.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path2.valide = 0;
+ _dcam_frm_clear(DCAM_PATH_IDX_0);
+ _dcam_frm_clear(DCAM_PATH_IDX_1);
+ _dcam_frm_clear(DCAM_PATH_IDX_2);
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ dcam_reset(DCAM_RST_ALL, 0);
+ s_p_dcam_mod->state &= ~DCAM_STATE_QUICKQUIT;
+ //mutex_unlock(&dcam_sem);
+
+ printk("DCAM: dcam_stop Out, s_resize_flag %d \n", atomic_read(&s_resize_flag));
+
+ return -rtn;
+}
+
+int32_t dcam_resume(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->dcam_path1.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy(DCAM_PATH_IDX_1);
+ _dcam_frm_clear(DCAM_PATH_IDX_1);
+ }
+
+ if (s_p_dcam_mod->dcam_path2.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy(DCAM_PATH_IDX_2);
+ _dcam_frm_clear(DCAM_PATH_IDX_2);
+ }
+
+
+ if (s_p_dcam_mod->dcam_path1.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, false);
+ DCAM_RTN_IF_ERR;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_1, DCAM_CFG_REG);
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_1, true, true);
+ }
+
+ if (s_p_dcam_mod->dcam_path2.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, false);
+ DCAM_RTN_IF_ERR;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_2, DCAM_CFG_REG);
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_2, true, true);
+ }
+
+ printk("DCAM R \n");
+
+ dcam_glb_reg_owr(DCAM_CONTROL, BIT_2, DCAM_CONTROL_REG); /* Enable CAP */
+ return -rtn;
+}
+
+int32_t dcam_pause(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ dcam_glb_reg_awr(DCAM_CONTROL, ~BIT_2, DCAM_CONTROL_REG); /* Disable CAP */
+ printk("DCAM P \n");
+ return -rtn;
+}
+
+int32_t dcam_reg_isr(enum dcam_irq_id id, dcam_isr_func user_func, void* user_data)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ if(id >= DCAM_IRQ_NUMBER) {
+ rtn = DCAM_RTN_ISR_ID_ERR;
+ } else {
+ spin_lock_irqsave(&dcam_lock, flag);
+ s_user_func[id] = user_func;
+ s_user_data[id] = user_data;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ }
+ return -rtn;
+}
+
+int32_t dcam_cap_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ switch (id) {
+ case DCAM_CAP_SYNC_POL:
+ {
+ struct dcam_cap_sync_pol *sync_pol = (struct dcam_cap_sync_pol*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+
+ if (sync_pol->vsync_pol > 1 ||
+ sync_pol->hsync_pol > 1 ||
+ sync_pol->pclk_pol > 1) {
+ rtn = DCAM_RTN_CAP_SYNC_POL_ERR;
+ } else {
+ sci_glb_set(DCAM_CCIR_PCLK_EB, CCIR_PCLK_EB_BIT);
+ REG_MWR(CAP_CCIR_CTRL, BIT_3, sync_pol->hsync_pol << 3);
+ REG_MWR(CAP_CCIR_CTRL, BIT_4, sync_pol->vsync_pol << 4);
+ //REG_MWR(CLK_DLY_CTRL, BIT_19, sync_pol->pclk_pol << 19); // aiden todo
+
+ if (sync_pol->pclk_src == 0x00) {
+ sci_glb_clr(CAP_CCIR_PLCK_SRC, (BIT_25 | BIT_26));
+ DCAM_TRACE("DCAM: set pclk src0\n");
+ } else if (sync_pol->pclk_src == 0x01) {
+ sci_glb_clr(CAP_CCIR_PLCK_SRC, (BIT_25 | BIT_26));
+ sci_glb_set(CAP_CCIR_PLCK_SRC, (BIT_25));
+ DCAM_TRACE("DCAM: set pclk src1\n");
+ } else {
+ DCAM_TRACE("DCAM: set pclk src default\n");
+ }
+ }
+ } else {
+ if (sync_pol->need_href) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_5, 1 << 5);
+ } else {
+ REG_MWR(CAP_MIPI_CTRL, BIT_5, 0 << 5);
+ }
+ }
+ break;
+ }
+
+ case DCAM_CAP_DATA_BITS:
+ {
+ enum dcam_cap_data_bits bits = *(enum dcam_cap_data_bits*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ if (DCAM_CAP_8_BITS == bits || DCAM_CAP_10_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 0 << 9);
+ } else if (DCAM_CAP_4_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 1 << 9);
+ } else if (DCAM_CAP_2_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 2 << 9);
+ } else if (DCAM_CAP_1_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 3 << 9);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_BITS_ERR;
+ }
+
+ } else {
+ if (DCAM_CAP_12_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 2 << 3);
+ } else if (DCAM_CAP_10_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 1 << 3);
+ } else if (DCAM_CAP_8_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 0 << 3);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_BITS_ERR;
+ }
+ }
+ break;
+ }
+
+ case DCAM_CAP_YUV_TYPE:
+ {
+ enum dcam_cap_pattern pat = *(enum dcam_cap_pattern*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (pat < DCAM_PATTERN_MAX) {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_CTRL, BIT_8 | BIT_7, pat << 7);
+ else
+ REG_MWR(CAP_MIPI_CTRL, BIT_8 | BIT_7, pat << 7);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_YUV_ERR;
+ }
+ break;
+ }
+
+ case DCAM_CAP_PRE_SKIP_CNT:
+ {
+ uint32_t skip_num = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (skip_num > DCAM_CAP_SKIP_FRM_MAX) {
+ rtn = DCAM_RTN_CAP_SKIP_FRAME_ERR;
+ } else {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_3 | BIT_2 | BIT_1 | BIT_0, skip_num);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_3 | BIT_2 | BIT_1 | BIT_0, skip_num);
+ }
+ break;
+ }
+
+ case DCAM_CAP_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor < DCAM_FRM_DECI_FAC_MAX) {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_5 | BIT_4, deci_factor << 4);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_5 | BIT_4, deci_factor << 4);
+ } else {
+ rtn = DCAM_RTN_CAP_FRAME_DECI_ERR;
+ }
+ break;
+ }
+
+ case DCAM_CAP_FRM_COUNT_CLR:
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_22, 1 << 22);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_22, 1 << 22);
+ break;
+
+ case DCAM_CAP_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+ uint32_t tmp = 0;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+#if 0
+ if (rect->x > DCAM_CAP_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_CAP_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_CAP_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_CAP_FRAME_HEIGHT_MAX ) {
+ rtn = DCAM_RTN_CAP_FRAME_SIZE_ERR;
+ return -rtn;
+ }
+#endif
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ tmp = rect->x | (rect->y << 16);
+ REG_WR(CAP_CCIR_START, tmp);
+ tmp = (rect->x + rect->w - 1);
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_CCIR_END, tmp);
+ } else {
+ tmp = (rect->x << 1) | (rect->y << 16);
+ REG_WR(CAP_CCIR_START, tmp);
+ tmp = ((rect->x + rect->w) << 1) - 1;
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_CCIR_END, tmp);
+ }
+ } else {
+ tmp = rect->x | (rect->y << 16);
+ REG_WR(CAP_MIPI_START, tmp);
+ tmp = (rect->x + rect->w - 1);
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_MIPI_END, tmp);
+ }
+ break;
+ }
+
+ case DCAM_CAP_IMAGE_XY_DECI:
+ {
+ struct dcam_cap_dec *cap_dec = (struct dcam_cap_dec*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (cap_dec->x_factor > DCAM_CAP_X_DECI_FAC_MAX ||
+ cap_dec->y_factor > DCAM_CAP_Y_DECI_FAC_MAX ) {
+ rtn = DCAM_RTN_CAP_XY_DECI_ERR;
+ } else {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ if (cap_dec->x_factor > 1 ||
+ cap_dec->y_factor > 1) {
+ rtn = DCAM_RTN_CAP_XY_DECI_ERR;
+ }
+ }
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ REG_MWR(CAP_CCIR_IMG_DECI, BIT_1 | BIT_0, cap_dec->x_factor);
+ REG_MWR(CAP_CCIR_IMG_DECI, BIT_3 | BIT_2, cap_dec->y_factor << 2);
+ } else {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ // REG_MWR(CAP_MIPI_IMG_DECI, BIT_0, cap_dec->x_factor); // for camera path
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_1, cap_dec->x_factor << 1);//for ISP
+ } else {
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_1 | BIT_0, cap_dec->x_factor);
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_3 | BIT_2, cap_dec->y_factor << 2);
+ }
+ }
+ }
+
+ break;
+ }
+
+ case DCAM_CAP_JPEG_SET_BUF_LEN:
+ {
+ uint32_t jpg_buf_size = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ jpg_buf_size = jpg_buf_size/DCAM_JPG_BUF_UNIT;
+ if (jpg_buf_size >= DCAM_JPG_UNITS) {
+ rtn = DCAM_RTN_CAP_JPEG_BUF_LEN_ERR;
+ } else {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_WR(CAP_CCIR_JPG_CTRL,jpg_buf_size);
+ else
+ REG_WR(CAP_MIPI_JPG_CTRL,jpg_buf_size);
+ }
+ break;
+ }
+
+ case DCAM_CAP_TO_ISP:
+ {
+ uint32_t need_isp = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (need_isp) {
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_7, 1 << 7, DCAM_CFG_REG);
+ } else {
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_7, 0 << 7, DCAM_CFG_REG);
+ }
+ break;
+ }
+
+ case DCAM_CAP_DATA_PACKET:
+ {
+ uint32_t is_loose = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface &&
+ DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ if (is_loose) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_0, 1);
+ } else {
+ REG_MWR(CAP_MIPI_CTRL, BIT_0, 0);
+ }
+ } else {
+ rtn = DCAM_RTN_MODE_ERR;
+ }
+
+ break;
+ }
+
+ case DCAM_CAP_SAMPLE_MODE:
+ {
+ enum dcam_capture_mode samp_mode = *(enum dcam_capture_mode*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (samp_mode >= DCAM_CAPTURE_MODE_MAX) {
+ rtn = DCAM_RTN_MODE_ERR;
+ } else {
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_6, samp_mode << 6);
+ } else {
+ REG_MWR(CAP_CCIR_CTRL, BIT_6, samp_mode << 6);
+ }
+ s_p_dcam_mod->dcam_mode = samp_mode;
+ }
+ break;
+ }
+
+ case DCAM_CAP_ZOOM_MODE:
+ {
+ uint32_t zoom_mode = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ s_dcam_sc_array->is_smooth_zoom = zoom_mode;
+ break;
+ }
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_cap_get_info(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ switch(id) {
+ case DCAM_CAP_FRM_COUNT_GET:
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ *(uint32_t*)param = REG_RD(CAP_MIPI_FRM_CTRL) >> 16;
+ } else {
+ *(uint32_t*)param = REG_RD(CAP_CCIR_FRM_CTRL) >> 16;
+ }
+ break;
+
+ case DCAM_CAP_JPEG_GET_LENGTH:
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ *(uint32_t*)param = REG_RD(CAP_MIPI_FRM_SIZE);
+ } else {
+ *(uint32_t*)param = REG_RD(CAP_CCIR_FRM_SIZE);
+ }
+ break;
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+ }
+ return -rtn;
+}
+
+int32_t dcam_path0_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH0_INPUT_SIZE {%d %d} \n", size->w, size->h);
+#if 0
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else
+#endif
+ {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_output_mode format = *(enum dcam_output_mode*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if((DCAM_OUTPUT_WORD != format) &&
+ (DCAM_OUTPUT_HALF_WORD != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->output_format = format;
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path0.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path0.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_0_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH0;
+ frame.fid = s_p_dcam_mod->dcam_path0.frame_base_id;
+ DCAM_TRACE("DCAM: Path 0 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path0.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path0_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ path->valide = *(uint32_t*)param;
+ break;
+ }
+
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_path1_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path1;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_INPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_INPUT_RECT {%d %d %d %d} \n",
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+
+ if (rect->x > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_PATH_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_TRIM_SIZE_ERR;
+ } else {
+ memcpy((void*)&path->input_rect,
+ (void*)rect,
+ sizeof(struct dcam_rect));
+ //if (path->input_rect.h >= DCAM_HEIGHT_MIN) {
+ // path->input_rect.h--;
+ //}
+ path->valid_param.input_rect = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_OUTPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->output_size.w = size->w;
+ path->output_size.h = size->h;
+ path->valid_param.output_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_fmt format = *(enum dcam_fmt*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ path->output_format = format;
+
+ if((DCAM_YUV422 != format) &&
+ (DCAM_YUV420 != format) &&
+ (DCAM_YUV420_3FRAME != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH1;
+ frame.fid = s_p_dcam_mod->dcam_path1.frame_base_id;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path1.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path1_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_SRC_SEL:
+ {
+ uint32_t src_sel = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (src_sel >= DCAM_PATH_FROM_NONE) {
+ rtn = DCAM_RTN_PATH_SRC_ERR;
+ } else {
+ path->src_sel = src_sel;
+ path->valid_param.src_sel = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path1.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->data_endian.uv_endian = endian->uv_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ path->valide = *(uint32_t*)param;
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path1.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_1_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_path2_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_INPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+
+ }
+ break;
+ }
+
+ case DCAM_PATH_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_INPUT_RECT {%d %d %d %d} \n",
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+
+ if (rect->x > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_PATH_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_TRIM_SIZE_ERR;
+ } else {
+ memcpy((void*)&path->input_rect,
+ (void*)rect,
+ sizeof(struct dcam_rect));
+#if 0
+ if (path->input_rect.h >= DCAM_HEIGHT_MIN) {
+ path->input_rect.h--;
+ }
+#endif
+ path->valid_param.input_rect = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_OUTPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->output_size.w = size->w;
+ path->output_size.h = size->h;
+ path->valid_param.output_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_fmt format = *(enum dcam_fmt*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if((DCAM_YUV422 != format) &&
+ (DCAM_YUV420 != format) &&
+ (DCAM_YUV420_3FRAME != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->output_format = format;
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH2;
+ frame.fid = s_p_dcam_mod->dcam_path2.frame_base_id;
+ DCAM_TRACE("DCAM: Path 2 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path2.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path2_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_SRC_SEL:
+ {
+ uint32_t src_sel = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (src_sel >= DCAM_PATH_FROM_NONE) {
+ rtn = DCAM_RTN_PATH_SRC_ERR;
+ } else {
+ path->src_sel = src_sel;
+ path->valid_param.src_sel = 1;
+
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path2.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->data_endian.uv_endian = endian->uv_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ path->valide = *(uint32_t*)param;
+
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path2.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_2_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_get_resizer(uint32_t wait_opt)
+{
+ int32_t rtn = 0;
+
+ printk("resizer_get:%d\n",current->pid);
+
+
+ if( 0 == wait_opt) {
+ rtn = mutex_trylock(&dcam_sem) ? 0 : 1;
+ return rtn;
+ } else if (DCAM_WAIT_FOREVER == wait_opt){
+ mutex_lock(&dcam_sem);
+ return rtn;
+ } else {
+ return 0;//mutex_timeout(&dcam_sem, wait_opt);
+ }
+}
+
+int32_t dcam_rel_resizer(void)
+{
+ printk("resizer_put:%d\n",current->pid);
+ mutex_unlock(&dcam_sem);
+ return 0;
+}
+
+int32_t dcam_resize_start(void)
+{
+ atomic_inc(&s_resize_flag);
+ mutex_lock(&dcam_scale_sema);
+ return 0;
+}
+
+int32_t dcam_resize_end(void)
+{
+ unsigned long flag;
+
+ atomic_dec(&s_resize_flag);
+ mutex_unlock(&dcam_scale_sema);
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+ }
+
+ if (s_p_dcam_mod) {
+ if (s_p_dcam_mod->wait_resize_done) {
+ up(&s_p_dcam_mod->resize_done_sema);
+ s_p_dcam_mod->wait_resize_done = 0;
+ }
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+}
+
+int32_t dcam_rotation_start(void)
+{
+ atomic_inc(&s_rotation_flag);
+ mutex_lock(&dcam_rot_sema);
+ return 0;
+}
+
+int32_t dcam_rotation_end(void)
+{
+ unsigned long flag;
+
+ atomic_dec(&s_rotation_flag);
+ mutex_unlock(&dcam_rot_sema);
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+ }
+
+ if (s_p_dcam_mod) {
+ if (s_p_dcam_mod->wait_rotation_done) {
+ up(&s_p_dcam_mod->rotation_done_sema);
+ s_p_dcam_mod->wait_rotation_done = 0;
+ }
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+}
+
+void dcam_int_en(void)
+{
+ if (atomic_read(&s_dcam_users) == 1) {
+ enable_irq(DCAM_IRQ);
+ }
+}
+
+void dcam_int_dis(void)
+{
+ if (atomic_read(&s_dcam_users) == 1) {
+ disable_irq(DCAM_IRQ);
+ }
+}
+
+int32_t dcam_frame_is_locked(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (frame)
+ rtn = frame->lock == DCAM_FRM_LOCK_WRITE ? 1 : 0;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_frame_lock(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: lock %d \n", (uint32_t)(0xF&frame->fid));
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (likely(frame))
+ frame->lock = DCAM_FRM_LOCK_WRITE;
+ else
+ rtn = DCAM_RTN_PARA_ERR;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_frame_unlock(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: unlock %d \n", (uint32_t)(0xF&frame->fid));
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (likely(frame))
+ frame->lock = DCAM_FRM_UNLOCK;
+ else
+ rtn = DCAM_RTN_PARA_ERR;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_read_registers(uint32_t* reg_buf, uint32_t *buf_len)
+{
+ uint32_t *reg_addr = (uint32_t*)DCAM_BASE;
+
+ if (NULL == reg_buf || NULL == buf_len || 0 != (*buf_len % 4)) {
+ return -1;
+ }
+
+ if (atomic_read(&s_dcam_users) == 1) {
+ while (buf_len != 0 && (uint32_t)reg_addr < DCAM_END) {
+ *reg_buf++ = REG_RD(reg_addr);
+ reg_addr++;
+ *buf_len -= 4;
+ }
+ *buf_len = (uint32_t)reg_addr - DCAM_BASE;
+ }
+
+ return 0;
+}
+
+int32_t dcam_get_path_id(struct dcam_get_path_id *path_id, uint32_t *channel_id)
+{
+ int ret = DCAM_RTN_SUCCESS;
+
+ if (NULL == path_id || NULL == channel_id) {
+ return -1;
+ }
+
+ DCAM_TRACE("DCAM: fourcc 0x%x, w %d, h %d, %d %d \n",
+ path_id->fourcc, path_id->input_size.w, path_id->input_size.h,
+ path_id->is_path_work[DCAM_PATH1], path_id->is_path_work[DCAM_PATH2]);
+
+ if (path_id->need_isp_tool) {
+ *channel_id = DCAM_PATH0;
+ } else if (V4L2_PIX_FMT_GREY == path_id->fourcc && !path_id->is_path_work[DCAM_PATH0]) {
+ *channel_id = DCAM_PATH0;
+ } else if (V4L2_PIX_FMT_JPEG == path_id->fourcc && !path_id->is_path_work[DCAM_PATH0]) {
+ *channel_id = DCAM_PATH0;
+ } else if (path_id->output_size.w <= DCAM_PATH1_LINE_BUF_LENGTH && !path_id->is_path_work[DCAM_PATH1]) {
+ *channel_id = DCAM_PATH1;
+ } else if (path_id->output_size.w <= DCAM_PATH2_LINE_BUF_LENGTH && !path_id->is_path_work[DCAM_PATH2]) {
+ *channel_id = DCAM_PATH2;
+ } else {
+ *channel_id = DCAM_PATH0;
+ }
+ printk("DCAM: path id %d \n", *channel_id);
+
+ return ret;
+}
+
+int32_t dcam_get_path_capability(struct dcam_path_capability *capacity)
+{
+ int ret = DCAM_RTN_SUCCESS;
+
+ if (NULL == capacity) {
+ return -1;
+ }
+
+ capacity->count = 3;
+ capacity->path_info[DCAM_PATH0].line_buf = 0;
+ capacity->path_info[DCAM_PATH0].support_yuv = 0;
+ capacity->path_info[DCAM_PATH0].support_raw = 1;
+ capacity->path_info[DCAM_PATH0].support_jpeg = 1;
+ capacity->path_info[DCAM_PATH0].support_scaling = 0;
+ capacity->path_info[DCAM_PATH0].support_trim = 0;
+ capacity->path_info[DCAM_PATH0].is_scaleing_path = 0;
+
+ capacity->path_info[DCAM_PATH1].line_buf = DCAM_PATH1_LINE_BUF_LENGTH;
+ capacity->path_info[DCAM_PATH1].support_yuv = 1;
+ capacity->path_info[DCAM_PATH1].support_raw = 0;
+ capacity->path_info[DCAM_PATH1].support_jpeg = 0;
+ capacity->path_info[DCAM_PATH1].support_scaling = 1;
+ capacity->path_info[DCAM_PATH1].support_trim = 1;
+ capacity->path_info[DCAM_PATH1].is_scaleing_path = 0;
+
+ capacity->path_info[DCAM_PATH2].line_buf = DCAM_PATH2_LINE_BUF_LENGTH;
+ capacity->path_info[DCAM_PATH2].support_yuv = 1;
+ capacity->path_info[DCAM_PATH2].support_raw = 0;
+ capacity->path_info[DCAM_PATH2].support_jpeg = 0;
+ capacity->path_info[DCAM_PATH2].support_scaling = 1;
+ capacity->path_info[DCAM_PATH2].support_trim = 1;
+ capacity->path_info[DCAM_PATH2].is_scaleing_path = 1;
+
+ return ret;
+}
+
+
+LOCAL irqreturn_t _dcam_isr_root(int irq, void *dev_id)
+{
+ uint32_t irq_line, status;
+ unsigned long flag;
+ int32_t i;
+
+ DCAM_TRACE("DCAM: ISR 0x%x \n", REG_RD(DCAM_INT_STS));
+ status = REG_RD(DCAM_INT_STS) & DCAM_IRQ_LINE_MASK;
+ if (unlikely(0 == status)) {
+ return IRQ_NONE;
+ }
+
+ irq_line = status;
+ if (unlikely(DCAM_IRQ_ERR_MASK & status)) {
+ if (_dcam_err_pre_proc()) {
+ return IRQ_NONE;
+ }
+ }
+
+ spin_lock_irqsave(&dcam_lock,flag);
+
+ //for (i = DCAM_IRQ_NUMBER - 1; i >= 0; i--) {
+ for (i = 0; i < DCAM_IRQ_NUMBER; i++) {
+ if (irq_line & (1 << (uint32_t)i)) {
+ if (isr_list[i]) {
+ isr_list[i]();
+ }
+ }
+ irq_line &= ~(uint32_t)(1 << (uint32_t)i); //clear the interrupt flag
+ if(!irq_line) //no interrupt source left
+ break;
+ }
+
+ REG_WR(DCAM_INT_CLR, status);
+ DCAM_TRACE("DCAM: status 0x%x, ISR 0x%x \n", status, REG_RD(DCAM_INT_STS));
+
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ return IRQ_HANDLED;
+}
+
+LOCAL void _dcam_path0_set(void)
+{
+ uint32_t reg_val = 0;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH0_SRC_SIZE, reg_val);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_output_mode format = path->output_format;
+ REG_MWR(DCAM_PATH0_CFG, BIT_2, format << 2);
+ DCAM_TRACE("DCAM: path 0: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_1 | BIT_0, path->frame_deci << 0);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_5 | BIT_4, path->data_endian.y_endian << 4, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM DRV: path 0: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+}
+LOCAL void _dcam_path1_set(struct dcam_path_desc *path)
+{
+ uint32_t reg_val = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ DCAM_CHECK_ZERO_VOID(path);
+
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH1_SRC_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: src {%d %d} \n",path->input_size.w, path->input_size.h);
+ }
+
+ if (path->valid_param.input_rect) {
+ reg_val = path->input_rect.x | (path->input_rect.y << 16);
+ REG_WR(DCAM_PATH1_TRIM_START, reg_val);
+ reg_val = path->input_rect.w | (path->input_rect.h << 16);
+ REG_WR(DCAM_PATH1_TRIM_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: rect {%d %d %d %d} \n",
+ path->input_rect.x,
+ path->input_rect.y,
+ path->input_rect.w,
+ path->input_rect.h);
+ }
+
+ if (path->valid_param.output_size) {
+ reg_val = path->output_size.w | (path->output_size.h << 16);
+ REG_WR(DCAM_PATH1_DST_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: dst {%d %d} \n",path->output_size.w, path->output_size.h);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_fmt format = path->output_format;
+ if (DCAM_YUV422 == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 0 << 6);
+ } else if (DCAM_YUV420 == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 1 << 6);
+ } else if (DCAM_YUV420_3FRAME == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 3 << 6);
+ } else {
+ DCAM_TRACE("DCAM: invalid path 1 output format %d \n", format);
+ }
+ DCAM_TRACE("DCAM: path 1: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.src_sel) {
+ REG_MWR(DCAM_CFG, BIT_12 | BIT_11, path->src_sel << 11);
+ DCAM_TRACE("DCAM: path 1: src_sel=0x%x \n", path->src_sel);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_7 | BIT_6, path->data_endian.y_endian << 6, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_9 | BIT_8, path->data_endian.uv_endian << 8, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM: path 1: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_24 | BIT_23, path->frame_deci << 23);
+ DCAM_TRACE("DCAM: path 1: frame_deci=0x%x \n", path->frame_deci);
+ }
+
+ if (path->valid_param.scale_tap) {
+ path->valid_param.scale_tap = 0;
+ REG_MWR(DCAM_PATH1_CFG, BIT_19 | BIT_18 | BIT_17 | BIT_16, (path->scale_tap.y_tap & 0x0F) << 16);
+ REG_MWR(DCAM_PATH1_CFG, BIT_15 | BIT_14 | BIT_13 | BIT_12 | BIT_11, (path->scale_tap.uv_tap & 0x1F) << 11);
+ DCAM_TRACE("DCAM: path 1: scale_tap, y=0x%x, uv=0x%x \n", path->scale_tap.y_tap, path->scale_tap.uv_tap);
+ }
+
+ if (path->valid_param.v_deci) {
+ path->valid_param.v_deci = 0;
+ REG_MWR(DCAM_PATH1_CFG, BIT_2, path->deci_val.deci_x_en << 2);
+ REG_MWR(DCAM_PATH1_CFG, BIT_1 | BIT_0, path->deci_val.deci_x);
+
+ REG_MWR(DCAM_PATH1_CFG, BIT_5, path->deci_val.deci_y_en << 5);
+ REG_MWR(DCAM_PATH1_CFG, BIT_4 | BIT_3, path->deci_val.deci_y << 3);
+ DCAM_TRACE("DCAM: path 1: deci, x_en=%d, x=%d, y_en=%d, y=%d \n",
+ path->deci_val.deci_x_en, path->deci_val.deci_x, path->deci_val.deci_y_en, path->deci_val.deci_y);
+ }
+}
+
+LOCAL void _dcam_path2_set(void)
+{
+ struct dcam_path_desc *path = NULL;
+ uint32_t reg_val = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH2_SRC_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: src {%d %d} \n",path->input_size.w, path->input_size.h);
+ }
+
+ if (path->valid_param.input_rect) {
+ reg_val = path->input_rect.x | (path->input_rect.y << 16);
+ REG_WR(DCAM_PATH2_TRIM_START, reg_val);
+ reg_val = path->input_rect.w | (path->input_rect.h << 16);
+ REG_WR(DCAM_PATH2_TRIM_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: rect {%d %d %d %d} \n",
+ path->input_rect.x,
+ path->input_rect.y,
+ path->input_rect.w,
+ path->input_rect.h);
+ }
+
+ if(path->valid_param.output_size){
+ reg_val = path->output_size.w | (path->output_size.h << 16);
+ REG_WR(DCAM_PATH2_DST_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: dst {%d %d} \n",path->output_size.w, path->output_size.h);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_fmt format = path->output_format;
+
+ // REG_MWR(DCAM_PATH2_CFG, BIT_8, 0 << 8); // aiden todo
+
+ if (DCAM_YUV422 == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 0 << 6);
+ } else if (DCAM_YUV420 == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 1 << 6);
+ } else if (DCAM_YUV420_3FRAME == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 3 << 6);
+ } else {
+ DCAM_TRACE("DCAM: invalid path 2 output format %d \n", format);
+ }
+ DCAM_TRACE("DCAM: path 2: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.src_sel) {
+ REG_MWR(DCAM_CFG, BIT_14 | BIT_13, path->src_sel << 13);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_11 | BIT_10, path->data_endian.y_endian << 10,DCAM_ENDIAN_REG );
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_13 | BIT_12, path->data_endian.uv_endian << 12, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM: path 2: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_24 | BIT_23, path->frame_deci << 23);
+ DCAM_TRACE("DCAM: path 2: frame_deci=0x%x \n", path->frame_deci);
+ }
+
+ if (path->valid_param.scale_tap) {
+ path->valid_param.scale_tap = 0;
+ REG_MWR(DCAM_PATH2_CFG, BIT_19 | BIT_18 | BIT_17 | BIT_16, (path->scale_tap.y_tap & 0x0F) << 16);
+ REG_MWR(DCAM_PATH2_CFG, BIT_15 | BIT_14 | BIT_13 | BIT_12 | BIT_11, (path->scale_tap.uv_tap & 0x1F) << 11);
+ DCAM_TRACE("DCAM: path 2: scale_tap, y=0x%x, uv=0x%x \n",
+ path->scale_tap.y_tap, path->scale_tap.uv_tap);
+ }
+
+ if (path->valid_param.v_deci) {
+ path->valid_param.v_deci = 0;
+ REG_MWR(DCAM_PATH2_CFG, BIT_2, path->deci_val.deci_x_en << 2);
+ REG_MWR(DCAM_PATH2_CFG, BIT_1 | BIT_0, path->deci_val.deci_x);
+
+ REG_MWR(DCAM_PATH2_CFG, BIT_5, path->deci_val.deci_y_en << 5);
+ REG_MWR(DCAM_PATH2_CFG, BIT_4 | BIT_3, path->deci_val.deci_y << 3);
+ DCAM_TRACE("DCAM: path 2: deci, x_en=%d, x=%d, y_en=%d, y=%d \n",
+ path->deci_val.deci_x_en, path->deci_val.deci_x, path->deci_val.deci_y_en, path->deci_val.deci_y);
+ }
+}
+
+LOCAL void _dcam_buf_queue_init(struct dcam_buf_queue *queue)
+{
+ if (DCAM_ADDR_INVALID(queue)) {
+ printk("DCAM: invalid heap 0x%x \n", (uint32_t)queue);
+ return;
+ }
+
+ memset((void*)queue, 0, sizeof(struct dcam_buf_queue));
+ queue->write = &queue->frame[0];
+ queue->read = &queue->frame[0];
+ spin_lock_init(&queue->lock);
+ return;
+}
+
+LOCAL int32_t _dcam_buf_queue_write(struct dcam_buf_queue *queue, struct dcam_frame *frame)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_frame *ori_frame;
+ unsigned long flag;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: enq, invalid param 0x%x, 0x%x \n",
+ (uint32_t)queue,
+ (uint32_t)frame);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&queue->lock, flag);
+ ori_frame = queue->write;
+ DCAM_TRACE("DCAM: _dcam_buf_queue_write \n");
+ *queue->write++ = *frame;
+ if (queue->write > &queue->frame[DCAM_FRM_CNT_MAX-1]) {
+ queue->write = &queue->frame[0];
+ }
+
+ if (queue->write == queue->read) {
+ queue->write = ori_frame;
+ printk("DCAM: warning, queue is full, cannot write 0x%lx \n", frame->yaddr);
+ }
+ spin_unlock_irqrestore(&queue->lock, flag);
+ DCAM_TRACE("DCAM: _dcam_buf_queue_write type %d \n", frame->type);
+ return ret;
+}
+
+LOCAL int32_t _dcam_buf_queue_read(struct dcam_buf_queue *queue, struct dcam_frame *frame)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: deq, invalid param 0x%x, 0x%x \n",
+ (uint32_t)queue,
+ (uint32_t)frame);
+ return -EINVAL;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_buf_queue_read \n");
+
+ spin_lock_irqsave(&queue->lock, flag);
+ if (queue->read != queue->write) {
+ *frame = *queue->read++;
+ if (queue->read > &queue->frame[DCAM_FRM_CNT_MAX-1]) {
+ queue->read = &queue->frame[0];
+ }
+ } else {
+ ret = EAGAIN;
+ }
+ spin_unlock_irqrestore(&queue->lock, flag);
+ DCAM_TRACE("DCAM: _dcam_buf_queue_read type %d \n", frame->type);
+ return ret;
+}
+
+LOCAL void _dcam_frm_queue_clear(struct dcam_frm_queue *queue)
+{
+ if (DCAM_ADDR_INVALID(queue)) {
+ printk("DCAM: invalid heap 0x%x \n", (uint32_t)queue);
+ return;
+ }
+
+ memset((void*)queue, 0, sizeof(struct dcam_frm_queue));
+ return;
+}
+
+LOCAL int32_t _dcam_frame_enqueue(struct dcam_frm_queue *queue, struct dcam_frame *frame)
+{
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: enq, invalid param 0x%x, 0x%x \n",
+ (uint32_t)queue,
+ (uint32_t)frame);
+ return -1;
+ }
+ if (queue->valid_cnt >= DCAM_FRM_QUEUE_LENGTH) {
+ printk("DCAM: q over flow \n");
+ return -1;
+ }
+ //queue->frm_array[queue->valid_cnt] = frame;
+ memcpy(&queue->frm_array[queue->valid_cnt], frame, sizeof(struct dcam_frame));
+ queue->valid_cnt ++;
+ DCAM_TRACE("DCAM: en queue, %d, %d, 0x%x, 0x%x \n",
+ (0xF & frame->fid),
+ queue->valid_cnt,
+ frame->yaddr,
+ frame->uaddr);
+ return 0;
+}
+
+LOCAL int32_t _dcam_frame_dequeue(struct dcam_frm_queue *queue, struct dcam_frame *frame)
+{
+ uint32_t i = 0;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: deq, invalid param 0x%x, 0x%x \n",
+ (uint32_t)queue,
+ (uint32_t)frame);
+ return -1;
+ }
+ if (queue->valid_cnt == 0) {
+ printk("DCAM: q under flow \n");
+ return -1;
+ }
+
+ //*frame = queue->frm_array[0];
+ memcpy(frame, &queue->frm_array[0], sizeof(struct dcam_frame));
+ queue->valid_cnt--;
+ for (i = 0; i < queue->valid_cnt; i++) {
+ //queue->frm_array[i] = queue->frm_array[i+1];
+ memcpy(&queue->frm_array[i], &queue->frm_array[i+1], sizeof(struct dcam_frame));
+ }
+ DCAM_TRACE("DCAM: de queue, %d, %d \n",
+ (0xF & (frame)->fid),
+ queue->valid_cnt);
+ return 0;
+}
+
+LOCAL void _dcam_frm_clear(enum dcam_path_index path_index)
+{
+ uint32_t i = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path0.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path0.buf_queue);
+ }
+
+ if (DCAM_PATH_IDX_1 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path1.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path1.buf_queue);
+ }
+
+ if (DCAM_PATH_IDX_2 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path2.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path2.buf_queue);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_frm_pop(enum dcam_path_index path_index)
+{
+ uint32_t i = 0;
+ struct dcam_frame *frame = NULL;
+ uint32_t *frame_count;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 & path_index) {
+ frame = &s_p_dcam_mod->path0_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path0.output_frame_count;
+ }
+ if (DCAM_PATH_IDX_1 & path_index) {
+ frame = &s_p_dcam_mod->path1_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path1.output_frame_count;
+ }
+ if (DCAM_PATH_IDX_2 & path_index) {
+ frame = &s_p_dcam_mod->path2_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path2.output_frame_count;
+ }
+ printk("DCAM: frame pop index %d frame_count %d addr 0x%x \n", path_index, *frame_count, frame->yaddr);
+ if (0 == *frame_count) {
+ return;
+ }
+
+ for (i = 0; i < *frame_count - 1; i++) {
+ memcpy(frame+i, frame+i+1, sizeof(struct dcam_frame));
+ }
+ (*frame_count)--;
+ //memset(frame+(*frame_count), 0, sizeof(struct dcam_frame));
+ (frame+(*frame_count))->yaddr = 0;
+ (frame+(*frame_count))->uaddr = 0;
+ (frame+(*frame_count))->vaddr = 0;
+
+ if (0 == *frame_count) {
+ //_dcam_wait_for_quickstop(path_index);
+ }
+ DCAM_TRACE("DCAM: frame pop done \n");
+
+ return;
+}
+
+
+LOCAL void _dcam_link_frm(uint32_t base_id)
+{
+/* uint32_t i = 0;
+ struct dcam_frame *path0_frame = NULL;
+ struct dcam_frame *path1_frame = NULL;
+ struct dcam_frame *path2_frame = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ path0_frame = &s_p_dcam_mod->path0_frame[0];
+ path1_frame = &s_p_dcam_mod->path1_frame[0];
+ path2_frame = &s_p_dcam_mod->path2_frame[0];
+ for (i = 0; i < DCAM_PATH_0_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path0_frame + i);
+ //(path0_frame+i)->next = path0_frame + (i + 1) % DCAM_PATH_0_FRM_CNT_MAX;
+ //(path0_frame+i)->prev = path0_frame + (i - 1 + DCAM_PATH_0_FRM_CNT_MAX) % DCAM_PATH_0_FRM_CNT_MAX;
+ (path0_frame+i)->fid = base_id + i;
+ }
+
+ for (i = 0; i < DCAM_PATH_1_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path1_frame + i);
+ //(path1_frame+i)->next = path1_frame + (i + 1) % DCAM_PATH_1_FRM_CNT_MAX;
+ //(path1_frame+i)->prev = path1_frame + (i - 1 + DCAM_PATH_1_FRM_CNT_MAX) % DCAM_PATH_1_FRM_CNT_MAX;
+ (path1_frame+i)->fid = base_id + i;
+ }
+
+ for (i = 0; i < DCAM_PATH_2_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path2_frame + i);
+ //(path2_frame+i)->next = path2_frame+(i + 1) % DCAM_PATH_2_FRM_CNT_MAX;
+ //(path2_frame+i)->prev = path2_frame+(i - 1 + DCAM_PATH_2_FRM_CNT_MAX) % DCAM_PATH_2_FRM_CNT_MAX;
+ (path2_frame+i)->fid = base_id + i;
+ }
+
+ //s_p_dcam_mod->dcam_path0.output_frame_head = path0_frame;
+ //s_p_dcam_mod->dcam_path1.output_frame_head = path1_frame;
+ //s_p_dcam_mod->dcam_path2.output_frame_head = path2_frame;
+ //s_p_dcam_mod->dcam_path0.output_frame_cur = path0_frame;
+ //s_p_dcam_mod->dcam_path1.output_frame_cur = path1_frame;
+ //s_p_dcam_mod->dcam_path2.output_frame_cur = path2_frame;
+*/
+ return;
+}
+
+LOCAL int32_t _dcam_path_set_next_frm(enum dcam_path_index path_index, uint32_t is_1st_frm)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_frame frame;
+ struct dcam_frame *reserved_frame = NULL;
+ struct dcam_frame *orig_frame = NULL;
+ struct dcam_path_desc *path = NULL;
+ uint32_t yuv_reg[3] = {0};
+ uint32_t path_max_frm_cnt;
+ uint32_t flag = 0;
+ struct dcam_frm_queue *p_heap = NULL;
+ struct dcam_buf_queue *p_buf_queue = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ reserved_frame = &s_p_dcam_mod->path0_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path0;
+ yuv_reg[0] = DCAM_FRM_ADDR0;
+ path_max_frm_cnt = DCAM_PATH_0_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path0.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path0.buf_queue;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ //frame = &s_p_dcam_mod->path1_frame[0];
+ reserved_frame = &s_p_dcam_mod->path1_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path1;
+ yuv_reg[0] = DCAM_FRM_ADDR1;
+ yuv_reg[1] = DCAM_FRM_ADDR2;
+ yuv_reg[2] = DCAM_FRM_ADDR3;
+ path_max_frm_cnt = DCAM_PATH_1_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path1.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path1.buf_queue;
+ } else /*if(DCAM_PATH_IDX_2 == path_index)*/ {
+ //frame = &s_p_dcam_mod->path2_frame[0];
+ reserved_frame = &s_p_dcam_mod->path2_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path2;
+ yuv_reg[0] = DCAM_FRM_ADDR4;
+ yuv_reg[1] = DCAM_FRM_ADDR5;
+ yuv_reg[2] = DCAM_FRM_ADDR6;
+ path_max_frm_cnt = DCAM_PATH_2_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path2.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path2.buf_queue;
+ }
+
+ if (0 != _dcam_buf_queue_read(p_buf_queue, &frame)) {
+ DCAM_TRACE("DCAM: No freed frame id %d \n", frame.fid);
+ memcpy(&frame, reserved_frame, sizeof(struct dcam_frame));
+ }
+
+ DCAM_TRACE("DCAM: next %d y 0x%x uv 0x%x \n", path->output_frame_count, frame.yaddr, frame.uaddr);
+ REG_WR(yuv_reg[0], frame.yaddr);
+ if ((DCAM_YUV400 > path->output_format) && (DCAM_PATH_IDX_0 != path_index)) {
+ REG_WR(yuv_reg[1], frame.uaddr);
+ if (DCAM_YUV420_3FRAME == path->output_format) {
+ REG_WR(yuv_reg[2], frame.vaddr);
+ }
+ }
+ dcam_frame_lock(&frame);
+ if (0 == _dcam_frame_enqueue(p_heap, &frame)) {
+ } else {
+ dcam_frame_unlock(&frame);
+ rtn = DCAM_RTN_PATH_FRAME_LOCKED;
+ }
+
+ return -rtn;
+}
+
+#if 0
+LOCAL int32_t _dcam_path_trim(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path;
+ uint32_t cfg_reg, ctrl_bit;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ ctrl_bit = 8;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ ctrl_bit = 1;
+ } else {
+ printk("DCAM: _dcam_path_trim invalid path_index=%d \n", path_index);
+ return -1;
+ }
+
+ if (path->input_size.w != path->input_rect.w ||
+ path->input_size.h != path->input_rect.h) {
+ /*REG_OWR(cfg_reg, 1 << ctrl_bit);*/
+ } else {
+ /*REG_MWR(cfg_reg, 1 << ctrl_bit, 0 << ctrl_bit);*/
+ }
+
+ return rtn;
+
+}
+#endif
+
+LOCAL int32_t _dcam_path_scaler(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ uint32_t cfg_reg = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index){
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ }
+
+ DCAM_CHECK_ZERO(path);
+ if (DCAM_RAWRGB == path->output_format ||
+ DCAM_JPEG == path->output_format) {
+ DCAM_TRACE("DCAM: _dcam_path_scaler out format is %d, no need scaler \n", path->output_format);
+ return DCAM_RTN_SUCCESS;
+ }
+
+ rtn = _dcam_calc_sc_size(path_index);
+ if (DCAM_RTN_SUCCESS != rtn) {
+ return rtn;
+ }
+
+ if (path->sc_input_size.w == path->output_size.w &&
+ path->sc_input_size.h == path->output_size.h &&
+ DCAM_YUV422 == path->output_format) {
+ REG_MWR(cfg_reg, BIT_20, 1 << 20);// bypass scaler if the output size equals input size for YUV422 format
+ } else {
+ REG_MWR(cfg_reg, BIT_20, 0 << 20);
+ if (s_dcam_sc_array->is_smooth_zoom
+ && DCAM_PATH_IDX_1 == path_index
+ && DCAM_ST_START == path->status) {
+ rtn = _dcam_calc_sc_coeff(path_index);
+ } else {
+ rtn = _dcam_set_sc_coeff(path_index);
+ }
+ }
+
+ return rtn;
+}
+
+LOCAL int32_t _dcam_path_check_deci(enum dcam_path_index path_index, uint32_t *is_deci)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ uint32_t w_deci = 0;
+ uint32_t h_deci = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ goto dcam_path_err;
+ }
+
+ if (path->input_rect.w > (path->output_size.w * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.h > (path->output_size.h * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.w * DCAM_SC_COEFF_UP_MAX < path->output_size.w ||
+ path->input_rect.h * DCAM_SC_COEFF_UP_MAX < path->output_size.h) {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ } else {
+ if (path->input_rect.w > path->output_size.w * DCAM_SC_COEFF_DOWN_MAX)
+ w_deci = 1;
+ if (path->input_rect.h > path->output_size.h * DCAM_SC_COEFF_DOWN_MAX)
+ h_deci = 1;
+
+ if(w_deci || h_deci)
+ *is_deci = 1;
+ else
+ *is_deci = 0;
+ }
+
+dcam_path_err:
+ DCAM_TRACE("DCAM: _dcam_path_check_deci: path_index=%d, is_deci=%d, rtn=%d \n", path_index, *is_deci, rtn);
+
+ return rtn;
+}
+
+LOCAL uint32_t _dcam_get_path_deci_factor(uint32_t src_size, uint32_t dst_size)
+{
+ uint32_t factor = 0;
+
+ if (0 == src_size || 0 == dst_size) {
+ return factor;
+ }
+
+ /* factor: 0 - 1/2, 1 - 1/4, 2 - 1/8, 3 - 1/16 */
+ for (factor = 0; factor < DCAM_PATH_DECI_FAC_MAX; factor ++) {
+ if (src_size < (uint32_t)(dst_size * (1 << (factor + 1)))) {
+ break;
+ }
+ }
+
+ return factor;
+}
+
+LOCAL int32_t _dcam_calc_sc_size(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ uint32_t cfg_reg = 0;
+ uint32_t tmp_dstsize = 0;
+ uint32_t align_size = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index){
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ }
+
+ DCAM_CHECK_ZERO(path);
+ if (path->input_rect.w > (path->output_size.w * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.h > (path->output_size.h * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.w * DCAM_SC_COEFF_UP_MAX < path->output_size.w ||
+ path->input_rect.h * DCAM_SC_COEFF_UP_MAX < path->output_size.h) {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ } else {
+ path->sc_input_size.w = path->input_rect.w;
+ path->sc_input_size.h = path->input_rect.h;
+ if (path->input_rect.w > path->output_size.w * DCAM_SC_COEFF_DOWN_MAX) {
+ tmp_dstsize = path->output_size.w * DCAM_SC_COEFF_DOWN_MAX;
+ path->deci_val.deci_x = _dcam_get_path_deci_factor(path->input_rect.w, tmp_dstsize);
+ path->deci_val.deci_x_en = 1;
+ path->valid_param.v_deci = 1;
+ align_size = (1 << (path->deci_val.deci_x+1))*DCAM_PIXEL_ALIGN_WIDTH;
+ path->input_rect.w = (path->input_rect.w) & ~(align_size-1);
+ path->input_rect.x = (path->input_rect.x) & ~(align_size-1);
+ path->sc_input_size.w = path->input_rect.w >> (path->deci_val.deci_x+1);
+ } else {
+ path->deci_val.deci_x = 0;
+ path->deci_val.deci_x_en = 0;
+ path->valid_param.v_deci = 1;
+ }
+
+ if (path->input_rect.h > path->output_size.h * DCAM_SC_COEFF_DOWN_MAX) {
+ tmp_dstsize = path->output_size.h * DCAM_SC_COEFF_DOWN_MAX;
+ path->deci_val.deci_y = _dcam_get_path_deci_factor(path->input_rect.h, tmp_dstsize);
+ path->deci_val.deci_y_en = 1;
+ path->valid_param.v_deci = 1;
+ align_size = (1 << (path->deci_val.deci_y+1))*DCAM_PIXEL_ALIGN_HEIGHT;
+ path->input_rect.h = (path->input_rect.h) & ~(align_size-1);
+ path->input_rect.y = (path->input_rect.y) & ~(align_size-1);
+ path->sc_input_size.h = path->input_rect.h >> (path->deci_val.deci_y+1);
+ } else {
+ path->deci_val.deci_y = 0;
+ path->deci_val.deci_y_en = 0;
+ path->valid_param.v_deci = 1;
+ }
+
+ }
+
+ DCAM_TRACE("DCAM: _dcam_calc_sc_size, path=%d, x_en=%d, deci_x=%d, y_en=%d, deci_y=%d \n",
+ path_index, path->deci_val.deci_x_en,
+ path->deci_val.deci_x, path->deci_val.deci_y_en,
+ path->deci_val.deci_y);
+
+ return -rtn;
+}
+
+LOCAL int32_t _dcam_set_sc_coeff(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *path = NULL;
+ uint32_t i = 0;
+ uint32_t h_coeff_addr = DCAM_BASE;
+ uint32_t v_coeff_addr = DCAM_BASE;
+ uint32_t v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ uint32_t ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ uint8_t y_tap = 0;
+ uint8_t uv_tap = 0;
+ uint32_t index = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_set_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ down(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ if (!(Dcam_GenScaleCoeff((int16_t)path->sc_input_size.w,
+ (int16_t)path->sc_input_size.h,
+ (int16_t)path->output_size.w,
+ (int16_t)path->output_size.h,
+ h_coeff,
+ v_coeff,
+ v_chroma_coeff,
+ scale2yuv420,
+ &y_tap,
+ &uv_tap,
+ tmp_buf + (DCAM_SC_COEFF_COEF_SIZE*3/4),
+ DCAM_SC_COEFF_TMP_SIZE))) {
+ printk("DCAM: _dcam_set_sc_coeff Dcam_GenScaleCoeff error! \n");
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ return -DCAM_RTN_PATH_GEN_COEFF_ERR;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_H_NUM; i++) {
+ REG_WR(h_coeff_addr, *h_coeff);
+ h_coeff_addr += 4;
+ h_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_NUM; i++) {
+ REG_WR(v_coeff_addr, *v_coeff);
+ v_coeff_addr += 4;
+ v_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_CHROMA_NUM; i++) {
+ REG_WR(v_chroma_coeff_addr, *v_chroma_coeff);
+ v_chroma_coeff_addr += 4;
+ v_chroma_coeff++;
+ }
+
+ path->scale_tap.y_tap = y_tap;
+ path->scale_tap.uv_tap = uv_tap;
+ path->valid_param.scale_tap = 1;
+
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ return DCAM_RTN_SUCCESS;
+}
+
+LOCAL void _dcam_force_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy)
+{
+ uint32_t reg_val = 0;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ if(path_copy)
+ reg_val |= BIT_10;
+ if(coef_copy)
+ reg_val |= BIT_14;
+
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ if(path_copy)
+ reg_val |= BIT_12;
+ if(coef_copy)
+ reg_val |= BIT_16;
+
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_force_copy_ext invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_auto_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy)
+{
+ uint32_t reg_val = 0;
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_9;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_11;
+ if (coef_copy)
+ reg_val |= BIT_15;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_13;
+ if (coef_copy)
+ reg_val |= BIT_17;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_auto_copy_ext invalid path index: %d \n", path_index);
+ }
+
+}
+
+LOCAL void _dcam_force_copy(enum dcam_path_index path_index)
+{
+ if (DCAM_PATH_IDX_1 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_10, 1 << 10, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_12, 1 << 12, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_force_copy invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_auto_copy(enum dcam_path_index path_index)
+{
+ if (DCAM_PATH_IDX_0 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_9, 1 << 9, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_11, 1 << 11, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_13, 1 << 13, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_auto_copy invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_reg_trace(void)
+{
+#ifdef DCAM_DRV_DEBUG
+ uint32_t addr = 0;
+
+ printk("DCAM: Register list");
+ for (addr = DCAM_CFG; addr <= CAP_SENSOR_CTRL; addr += 16) {
+ printk("\n 0x%x: 0x%x 0x%x 0x%x 0x%x",
+ addr,
+ REG_RD(addr),
+ REG_RD(addr + 4),
+ REG_RD(addr + 8),
+ REG_RD(addr + 12));
+ }
+
+ printk("\n");
+#endif
+}
+
+#if 0
+LOCAL void _dcam_sensor_sof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_SOF];
+ void *data = s_user_data[DCAM_SN_SOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _sn_sof \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+#endif
+
+LOCAL void _dcam_sensor_eof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_EOF];
+ void *data = s_user_data[DCAM_SN_EOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _sn_eof \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_cap_sof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_CAP_SOF];
+ void *data = s_user_data[DCAM_CAP_SOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _cap_sof \n");
+
+ _dcam_stopped_notice();
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_cap_eof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_CAP_EOF];
+ void *data = s_user_data[DCAM_CAP_EOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path0_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH0_DONE];
+ void *data = s_user_data[DCAM_PATH0_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ if (0 == path->valide) {
+ printk("DCAM: path0 not valid \n");
+ return;
+ }
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_0, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_0);
+ DCAM_TRACE("DCAM 0 \n");
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, false);
+ if (rtn) {
+ printk("DCAM: 0 w \n");
+ return;
+ }
+ _dcam_auto_copy(DCAM_PATH_IDX_0);
+
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path0_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path0_reserved_frame \n");
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path0_overflow(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH0_OV];
+ void *data = s_user_data[DCAM_PATH0_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path0_overflow \n");
+ path = &s_p_dcam_mod->dcam_path0;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_DONE];
+ void *data = s_user_data[DCAM_PATH1_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path1;
+ if (0 == path->valide) {
+ printk("DCAM: path1 not valid \n");
+ return;
+ }
+
+ DCAM_TRACE("DCAM: 1\n");
+
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_1, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_1);
+
+ if (path->sof_cnt < 1) {
+ printk("DCAM: path1 done cnt %d\n", path->sof_cnt);
+ path->need_wait = 0;
+ return;
+ }
+ path->sof_cnt = 0;
+
+ if (path->need_wait) {
+ path->need_wait = 0;
+ } else {
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path1_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ DCAM_TRACE("DCAM: path1 frame 0x%x, y uv, 0x%x 0x%x \n",
+ (int)&frame, frame.yaddr, frame.uaddr);
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path1_reserved_frame \n");
+ }
+ }
+ return;
+}
+
+LOCAL void _dcam_path1_overflow(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_OV];
+ void *data = s_user_data[DCAM_PATH1_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path1_overflow \n");
+ path = &s_p_dcam_mod->dcam_path1;
+ //frame = path->output_frame_cur->prev->prev;
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_sensor_line_err(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_LINE_ERR];
+ void *data = s_user_data[DCAM_SN_LINE_ERR];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _line_err \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_sensor_frame_err(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_FRAME_ERR];
+ void *data = s_user_data[DCAM_SN_FRAME_ERR];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _frame_err \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_jpeg_buf_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_JPEG_BUF_OV];
+ void *data = s_user_data[DCAM_JPEG_BUF_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _jpeg_overflow \n");
+ path = &s_p_dcam_mod->dcam_path0;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_DONE];
+ void *data = s_user_data[DCAM_PATH2_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ if (atomic_read(&s_resize_flag)) {
+ memset(&frame, 0, sizeof(struct dcam_frame));
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+
+ DCAM_TRACE("DCAM: 2, %d %d \n", path->need_stop, path->need_wait);
+ if (path->status == DCAM_ST_START) {
+
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_2, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_2);
+
+ if (path->sof_cnt < 1) {
+ printk("DCAM: path2 done cnt %d\n", path->sof_cnt);
+ path->need_wait = 0;
+ return;
+ }
+ path->sof_cnt = 0;
+
+ if (path->need_wait) {
+ path->need_wait = 0;
+ } else {
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path2_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ DCAM_TRACE("DCAM: path2 frame 0x%x, y uv, 0x%x 0x%x \n",
+ (int)&frame, frame.yaddr, frame.uaddr);
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path2_reserved_frame \n");
+ }
+ }
+ }
+ }
+}
+
+LOCAL void _dcam_path2_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_OV];
+ void *data = s_user_data[DCAM_PATH2_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path2_overflow \n");
+ path = &s_p_dcam_mod->dcam_path2;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path2_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_isp_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_ISP_OV];
+ void *data = s_user_data[DCAM_ISP_OV];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _isp_overflow \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_mipi_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_MIPI_OV];
+ void *data = s_user_data[DCAM_MIPI_OV];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ printk("DCAM: _mipi_overflow \n");
+ return;
+}
+
+LOCAL void _dcam_rot_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_ROT_DONE];
+ void *data = s_user_data[DCAM_ROT_DONE];
+
+ DCAM_TRACE("DCAM: rot_done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_SLICE_DONE];
+ void *data = s_user_data[DCAM_PATH1_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 1 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_SLICE_DONE];
+ void *data = s_user_data[DCAM_PATH2_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 2 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_raw_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_RAW_SLICE_DONE];
+ void *data = s_user_data[DCAM_RAW_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 0 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_sof(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_SOF];
+ void *data = s_user_data[DCAM_PATH1_SOF];
+ struct dcam_path_desc *path;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_TRACE("DCAM: 1 sof done \n");
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ DCAM_CHECK_ZERO_VOID(s_dcam_sc_array);
+
+ if(s_p_dcam_mod->dcam_path1.status == DCAM_ST_START){
+
+ path = &s_p_dcam_mod->dcam_path1;
+ if (0 == path->valide) {
+ printk("DCAM: path1 not valid \n");
+ return;
+ }
+
+ if (path->sof_cnt > 0) {
+ printk("DCAM: path1 sof %d \n", path->sof_cnt);
+ return;
+ } else {
+ path->sof_cnt++;
+ }
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, false);
+ if (path->is_update) {
+ if (s_dcam_sc_array->is_smooth_zoom) {
+ _dcam_get_valid_sc_coeff(s_dcam_sc_array, &sc_coeff);
+ _dcam_write_sc_coeff(DCAM_PATH_IDX_1);
+ _dcam_path1_set(&sc_coeff->dcam_path1);
+ _dcam_pop_sc_buf(s_dcam_sc_array, &sc_coeff);
+ } else {
+ _dcam_path1_set(path);
+ }
+ path->is_update = 0;
+ DCAM_TRACE("DCAM: path1 updated \n");
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_1, true, true);
+ } else {
+ if (rtn) {
+ DCAM_TRACE("DCAM: path1 updated \n");
+ } else {
+ _dcam_auto_copy(DCAM_PATH_IDX_1);
+ }
+ }
+
+ _dcam_path_updated_notice(DCAM_PATH_IDX_1);
+
+ if (rtn) {
+ path->need_wait = 1;
+ printk("DCAM: 1 w\n");
+ return;
+ }
+ }
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_sof(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_SOF];
+ void *data = s_user_data[DCAM_PATH2_SOF];
+ struct dcam_path_desc *path;
+
+ DCAM_TRACE("DCAM: 2 sof done \n");
+
+ if (atomic_read(&s_resize_flag)) {
+ printk("DCAM: path 2 sof, review now \n");
+ } else {
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ return;
+ }
+
+ if(s_p_dcam_mod->dcam_path2.status == DCAM_ST_START){
+
+ path = &s_p_dcam_mod->dcam_path2;
+ if (0 == path->valide) {
+ printk("DCAM: path2 not valid \n");
+ return;
+ }
+
+ if (path->sof_cnt > 0) {
+ printk("DCAM: path2 sof %d \n", path->sof_cnt);
+ return;
+ } else {
+ path->sof_cnt++;
+ }
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, false);
+ if (path->is_update) {
+ _dcam_path2_set();
+ path->is_update = 0;
+ DCAM_TRACE("DCAM: path2 updated \n");
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_2, true, true);
+ } else {
+ if (rtn) {
+ DCAM_TRACE("DCAM: path2 updated \n");
+ } else {
+ _dcam_auto_copy(DCAM_PATH_IDX_2);
+ }
+ }
+
+ _dcam_path_updated_notice(DCAM_PATH_IDX_2);
+
+ if (rtn) {
+ path->need_wait = 1;
+ printk("DCAM:2 w \n");
+ return;
+ }
+ }
+ }
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL int32_t _dcam_err_pre_proc(void)
+{
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: state in err_pre_proc 0x%x,",s_p_dcam_mod->state);
+ if (s_p_dcam_mod->state & DCAM_STATE_QUICKQUIT)
+ return -1;
+
+ s_p_dcam_mod->err_happened = 1;
+ printk("DCAM: err, 0x%x, ISP int 0x%x \n",
+ REG_RD(DCAM_INT_STS),
+ REG_RD(SPRD_ISP_BASE + 0x2080));
+
+ _dcam_reg_trace();
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 0, DCAM_CONTROL_REG); /* Cap Disable */
+ _dcam_stopped();
+ if (0 == atomic_read(&s_resize_flag) &&
+ 0 == atomic_read(&s_rotation_flag)) {
+ dcam_reset(DCAM_RST_ALL, 1);
+ }
+ return 0;
+}
+
+LOCAL void _dcam_stopped(void)
+{
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: stopped, %d \n", s_p_dcam_mod->wait_stop);
+
+ _dcam_path_done_notice(DCAM_PATH_IDX_0);
+ _dcam_path_done_notice(DCAM_PATH_IDX_1);
+ _dcam_path_done_notice(DCAM_PATH_IDX_2);
+ _dcam_stopped_notice();
+ return;
+}
+
+LOCAL int _dcam_internal_init(void)
+{
+ int ret = 0;
+
+ s_p_dcam_mod = (struct dcam_module*)vzalloc(sizeof(struct dcam_module));
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ sema_init(&s_p_dcam_mod->stop_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path0.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path1.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path2.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path0.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path1.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path2.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->resize_done_sema, 0);
+ sema_init(&s_p_dcam_mod->rotation_done_sema, 0);
+ sema_init(&s_p_dcam_mod->scale_coeff_mem_sema, 1);
+
+ memset((void*)s_dcam_sc_array, 0, sizeof(struct dcam_sc_array));
+ return ret;
+}
+LOCAL void _dcam_internal_deinit(void)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ printk("DCAM: Invalid addr, 0x%x", (uint32_t)s_p_dcam_mod);
+ } else {
+ vfree(s_p_dcam_mod);
+ s_p_dcam_mod = NULL;
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return;
+}
+
+LOCAL void _dcam_wait_path_done(enum dcam_path_index path_index, uint32_t *p_flag)
+{
+ int ret = 0;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->err_happened) {
+ return;
+ }
+ if (DCAM_CAPTURE_MODE_SINGLE == s_p_dcam_mod->dcam_mode) {
+ return;
+ }
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done wait %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+
+ spin_lock_irqsave(&dcam_lock, flag);
+ if (p_flag) {
+ *p_flag = 1;
+ }
+ p_path->wait_for_done = 1;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ ret = down_timeout(&p_path->tx_done_sema, DCAM_PATH_TIMEOUT);
+ if (ret) {
+ _dcam_reg_trace();
+ printk("DCAM: Failed to wait path 0x%x done \n", path_index);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path_done_notice(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *p_path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done notice %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+ if (p_path->wait_for_done) {
+ up(&p_path->tx_done_sema);
+ p_path->wait_for_done = 0;
+ }
+
+ return;
+}
+
+LOCAL void _dcam_wait_update_done(enum dcam_path_index path_index, uint32_t *p_flag)
+{
+ int ret = 0;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->err_happened) {
+ return;
+ }
+ if (DCAM_CAPTURE_MODE_SINGLE == s_p_dcam_mod->dcam_mode) {
+ return;
+ }
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done wait %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+
+ spin_lock_irqsave(&dcam_lock, flag);
+ if (p_flag) {
+ *p_flag = 1;
+ }
+ p_path->wait_for_sof = 1;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ ret = down_timeout(&p_path->sof_sema, DCAM_PATH_TIMEOUT);
+ if (ret) {
+ _dcam_reg_trace();
+ printk("DCAM: Failed to wait update path 0x%x done \n", path_index);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path_updated_notice(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *p_path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done notice %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+ if (p_path->wait_for_sof) {
+ up(&p_path->sof_sema);
+ p_path->wait_for_sof = 0;
+ }
+
+ return;
+}
+
+
+LOCAL void _dcam_stopped_notice(void)
+{
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->wait_stop) {
+ up(&s_p_dcam_mod->stop_sema);
+ s_p_dcam_mod->wait_stop = 0;
+ }
+}
+
+void mm_clk_register_trace(void)
+{
+ uint32_t i = 0;
+ printk("REG_AON_APB_APB_EB0 = 0x%x \n",REG_RD(REG_AON_APB_APB_EB0));
+ printk("REG_PMU_APB_PD_MM_TOP_CFG = 0x%x \n",REG_RD(REG_PMU_APB_PD_MM_TOP_CFG));
+ printk("REG_PMU_APB_CP_SOFT_RST = 0x%x \n",REG_RD(REG_PMU_APB_CP_SOFT_RST));
+ if(!(REG_RD(REG_AON_APB_APB_EB0)&BIT_MM_EB) ) return ;
+ if(REG_RD(REG_PMU_APB_PD_MM_TOP_CFG)&BIT_PD_MM_TOP_FORCE_SHUTDOWN) return ;
+
+ printk("mm_clk_reg, part 1 \n");
+ for (i = 0 ; i <= 0x10; i += 4 ) {
+ printk("MMAHB: %x val:%x \b\n",
+ (SPRD_MMAHB_BASE + i),
+ REG_RD(SPRD_MMAHB_BASE + i));
+ }
+
+ printk("mm_clk_reg, part 2 \n");
+ for (i = 0x20 ; i <= 0x38; i += 4 ) {
+ printk("MMCKG: %x val:%x \b\n",
+ (SPRD_MMCKG_BASE + i),
+ REG_RD(SPRD_MMCKG_BASE + i));
+ }
+}
+
+int32_t dcam_stop_sc_coeff(void)
+{
+ uint32_t zoom_mode;
+
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ zoom_mode = s_dcam_sc_array->is_smooth_zoom;
+ /*memset((void*)s_dcam_sc_array, 0, sizeof(struct dcam_sc_array));*/
+ s_dcam_sc_array->is_smooth_zoom = zoom_mode;
+ s_dcam_sc_array->valid_cnt = 0;
+ memset(&s_dcam_sc_array->scaling_coeff_queue, 0, DCAM_SC_COEFF_BUF_COUNT*sizeof(struct dcam_sc_coeff *));
+
+ return 0;
+}
+
+LOCAL int32_t _dcam_get_valid_sc_coeff(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff)
+{
+ if (DCAM_ADDR_INVALID(sc) || DCAM_ADDR_INVALID(sc_coeff)) {
+ printk("DCAM: get valid sc, invalid param 0x%x, 0x%x \n",
+ (uint32_t)sc,
+ (uint32_t)sc_coeff);
+ return -1;
+ }
+ if (sc->valid_cnt == 0) {
+ printk("DCAM: valid cnt 0 \n");
+ return -1;
+ }
+
+ *sc_coeff = sc->scaling_coeff_queue[0];
+ DCAM_TRACE("DCAM: get valid sc, %d \n", sc->valid_cnt);
+ return 0;
+}
+
+
+LOCAL int32_t _dcam_push_sc_buf(struct dcam_sc_array *sc, uint32_t index)
+{
+ if (DCAM_ADDR_INVALID(sc)) {
+ printk("DCAM: push sc, invalid param 0x%x \n",
+ (uint32_t)sc);
+ return -1;
+ }
+ if (sc->valid_cnt >= DCAM_SC_COEFF_BUF_COUNT) {
+ printk("DCAM: valid cnt %d \n", sc->valid_cnt);
+ return -1;
+ }
+
+ sc->scaling_coeff[index].flag = 1;
+ sc->scaling_coeff_queue[sc->valid_cnt] = &sc->scaling_coeff[index];
+ sc->valid_cnt ++;
+
+ DCAM_TRACE("DCAM: push sc, %d \n", sc->valid_cnt);
+
+ return 0;
+}
+
+LOCAL int32_t _dcam_pop_sc_buf(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff)
+{
+ uint32_t i = 0;
+
+ if (DCAM_ADDR_INVALID(sc) || DCAM_ADDR_INVALID(sc_coeff)) {
+ printk("DCAM: pop sc, invalid param 0x%x, 0x%x \n",
+ (uint32_t)sc,
+ (uint32_t)sc_coeff);
+ return -1;
+ }
+ if (sc->valid_cnt == 0) {
+ printk("DCAM: valid cnt 0 \n");
+ return -1;
+ }
+ sc->scaling_coeff_queue[0]->flag = 0;
+ *sc_coeff = sc->scaling_coeff_queue[0];
+ sc->valid_cnt--;
+ for (i = 0; i < sc->valid_cnt; i++) {
+ sc->scaling_coeff_queue[i] = sc->scaling_coeff_queue[i+1];
+ }
+ DCAM_TRACE("DCAM: pop sc, %d \n", sc->valid_cnt);
+ return 0;
+}
+
+LOCAL int32_t _dcam_write_sc_coeff(enum dcam_path_index path_index)
+{
+ int32_t ret = 0;
+ struct dcam_path_desc *path = NULL;
+ uint32_t i = 0;
+ uint32_t h_coeff_addr = DCAM_BASE;
+ uint32_t v_coeff_addr = DCAM_BASE;
+ uint32_t v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ uint32_t ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ ret = _dcam_get_valid_sc_coeff(s_dcam_sc_array, &sc_coeff);
+ if (ret) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+ tmp_buf = sc_coeff->buf;
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &sc_coeff->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_write_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+ for (i = 0; i < DCAM_SC_COEFF_H_NUM; i++) {
+ REG_WR(h_coeff_addr, *h_coeff);
+ h_coeff_addr += 4;
+ h_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_NUM; i++) {
+ REG_WR(v_coeff_addr, *v_coeff);
+ v_coeff_addr += 4;
+ v_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_CHROMA_NUM; i++) {
+ REG_WR(v_chroma_coeff_addr, *v_chroma_coeff);
+ v_chroma_coeff_addr += 4;
+ v_chroma_coeff++;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_write_sc_coeff E \n");
+
+ return ret;
+}
+
+LOCAL int32_t _dcam_calc_sc_coeff(enum dcam_path_index path_index)
+{
+ unsigned long flag;
+ struct dcam_path_desc *path = NULL;
+ uint32_t h_coeff_addr = DCAM_BASE;
+ uint32_t v_coeff_addr = DCAM_BASE;
+ uint32_t v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ uint32_t ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ uint8_t y_tap = 0;
+ uint8_t uv_tap = 0;
+ uint32_t index = 0;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_calc_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+ down(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ spin_lock_irqsave(&dcam_lock,flag);
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+ if (NULL == tmp_buf) {
+ _dcam_pop_sc_buf(s_dcam_sc_array, &sc_coeff);
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+ }
+ spin_unlock_irqrestore(&dcam_lock,flag);
+
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ if (!(Dcam_GenScaleCoeff((int16_t)path->sc_input_size.w,
+ (int16_t)path->sc_input_size.h,
+ (int16_t)path->output_size.w,
+ (int16_t)path->output_size.h,
+ h_coeff,
+ v_coeff,
+ v_chroma_coeff,
+ scale2yuv420,
+ &y_tap,
+ &uv_tap,
+ tmp_buf + (DCAM_SC_COEFF_COEF_SIZE*3/4),
+ DCAM_SC_COEFF_TMP_SIZE))) {
+ printk("DCAM: _dcam_calc_sc_coeff Dcam_GenScaleCoeff error! \n");
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ return -DCAM_RTN_PATH_GEN_COEFF_ERR;
+ }
+ path->scale_tap.y_tap = y_tap;
+ path->scale_tap.uv_tap = uv_tap;
+ path->valid_param.scale_tap = 1;
+ memcpy(&s_dcam_sc_array->scaling_coeff[index].dcam_path1, path, sizeof(struct dcam_path_desc));
+ spin_lock_irqsave(&dcam_lock,flag);
+ _dcam_push_sc_buf(s_dcam_sc_array, index);
+ spin_unlock_irqrestore(&dcam_lock,flag);
+
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ DCAM_TRACE("DCAM: _dcam_calc_sc_coeff E \n");
+
+ return DCAM_RTN_SUCCESS;
+}
diff --git a/drivers/media/sprd_dcam/pike/dcam_drv.h b/drivers/media/sprd_dcam/pike/dcam_drv.h
new file mode 100755
index 00000000..ea7b11a8
--- /dev/null
+++ b/drivers/media/sprd_dcam/pike/dcam_drv.h
@@ -0,0 +1,448 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef _DCAM_DRV_8830_H_
+#define _DCAM_DRV_8830_H_
+
+#include <linux/types.h>
+#include "dcam_reg.h"
+#include "parse_hwinfo.h"
+
+//#define DCAM_DEBUG
+
+#ifdef DCAM_DEBUG
+ #define DCAM_TRACE printk
+#else
+ #define DCAM_TRACE pr_debug
+#endif
+
+#define DCAM_WAIT_FOREVER 0xFFFFFFFF
+#define DCAM_PATH_1_FRM_CNT_MAX 10
+#define DCAM_PATH_2_FRM_CNT_MAX 10/*4*/
+#define DCAM_PATH_0_FRM_CNT_MAX 10
+#define DCAM_FRM_CNT_MAX 10 /* max between path_1_frm_cnt and path_2_frm_cnt */
+#define DCAM_HEIGHT_MIN 4
+#define DCAM_JPEG_LENGTH_MIN 30720 /*640X480 div 10*/
+
+enum dcam_swtich_status {
+ DCAM_SWITCH_IDLE = 0,
+ DCAM_SWITCH_PAUSE,
+ DCAM_SWITCH_DONE,
+ DCAM_SWITCH_MAX
+};
+
+enum dcam_drv_rtn {
+ DCAM_RTN_SUCCESS = 0,
+ DCAM_RTN_PARA_ERR = 0x10,
+ DCAM_RTN_IO_ID_ERR,
+ DCAM_RTN_ISR_ID_ERR,
+ DCAM_RTN_MASTER_SEL_ERR,
+ DCAM_RTN_MODE_ERR,
+ DCAM_RTN_TIMEOUT,
+
+ DCAM_RTN_CAP_FRAME_SEL_ERR = 0x20,
+ DCAM_RTN_CAP_IN_FORMAT_ERR,
+ DCAM_RTN_CAP_IN_BITS_ERR,
+ DCAM_RTN_CAP_IN_YUV_ERR,
+ DCAM_RTN_CAP_SYNC_POL_ERR,
+ DCAM_RTN_CAP_SKIP_FRAME_ERR,
+ DCAM_RTN_CAP_FRAME_DECI_ERR,
+ DCAM_RTN_CAP_XY_DECI_ERR,
+ DCAM_RTN_CAP_FRAME_SIZE_ERR,
+ DCAM_RTN_CAP_SENSOR_MODE_ERR,
+ DCAM_RTN_CAP_JPEG_BUF_LEN_ERR,
+ DCAM_RTN_CAP_IF_MODE_ERR,
+
+ DCAM_RTN_PATH_SRC_SIZE_ERR = 0x30,
+ DCAM_RTN_PATH_TRIM_SIZE_ERR,
+ DCAM_RTN_PATH_DES_SIZE_ERR,
+ DCAM_RTN_PATH_IN_FMT_ERR,
+ DCAM_RTN_PATH_OUT_FMT_ERR,
+ DCAM_RTN_PATH_SC_ERR,
+ DCAM_RTN_PATH_SUB_SAMPLE_ERR,
+ DCAM_RTN_PATH_ADDR_ERR,
+ DCAM_RTN_PATH_FRAME_TOO_MANY,
+ DCAM_RTN_PATH_FRAME_LOCKED,
+ DCAM_RTN_PATH_NO_MEM,
+ DCAM_RTN_PATH_GEN_COEFF_ERR,
+ DCAM_RTN_PATH_SRC_ERR,
+ DCAM_RTN_PATH_ENDIAN_ERR,
+ DCAM_RTN_PATH_FRM_DECI_ERR,
+ DCAM_RTN_MAX
+};
+
+enum dcam_rst_mode {
+ DCAM_RST_ALL = 0,
+ DCAM_RST_PATH0,
+ DCAM_RST_PATH1,
+ DCAM_RST_PATH2
+};
+
+enum dcam_path_index {
+ DCAM_PATH_IDX_NONE = 0,
+ DCAM_PATH_IDX_0 = 1,
+ DCAM_PATH_IDX_1 = 2,
+ DCAM_PATH_IDX_2 = 4,
+ DCAM_PATH_IDX_ALL = 7,
+};
+
+
+enum dcam_fmt {
+ DCAM_YUV422 = 0,
+ DCAM_YUV420,
+ DCAM_YUV420_3FRAME,
+ DCAM_YUV400,
+ DCAM_RGB565,
+ DCAM_RGB888,
+ DCAM_RAWRGB,
+ DCAM_JPEG,
+ DCAM_FTM_MAX
+};
+
+enum dcam_cap_pattern {
+ DCAM_YUYV = 0,
+ DCAM_YVYU,
+ DCAM_UYVY,
+ DCAM_VYUY,
+ DCAM_PATTERN_MAX
+};
+
+enum dcam_capture_mode {
+ DCAM_CAPTURE_MODE_SINGLE = 0,
+ DCAM_CAPTURE_MODE_MULTIPLE,
+ DCAM_CAPTURE_MODE_MAX
+};
+
+
+enum dcam_irq_id {
+ DCAM_SN_SOF = 0,
+ DCAM_SN_EOF,
+ DCAM_CAP_SOF,
+ DCAM_CAP_EOF,
+ DCAM_PATH0_DONE,
+ DCAM_PATH0_OV,
+ DCAM_PATH1_DONE,
+ DCAM_PATH1_OV,
+ DCAM_PATH2_DONE,
+ DCAM_PATH2_OV,
+ DCAM_SN_LINE_ERR,
+ DCAM_SN_FRAME_ERR,
+ DCAM_JPEG_BUF_OV,
+ DCAM_ISP_OV,
+ DCAM_MIPI_OV,
+ DCAM_ROT_DONE,
+ DCAM_PATH1_SLICE_DONE,
+ DCAM_PATH2_SLICE_DONE,
+ DCAM_RAW_SLICE_DONE,
+ DCAM_PATH1_SOF,
+ DCAM_PATH2_SOF,
+ DCAM_IRQ_NUMBER
+};
+
+enum dcam_cfg_id {
+ DCAM_CAP_SYNC_POL = 0,
+ DCAM_CAP_DATA_BITS,
+ DCAM_CAP_DATA_PACKET,
+ DCAM_CAP_YUV_TYPE,
+ DCAM_CAP_PRE_SKIP_CNT,
+ DCAM_CAP_FRM_DECI,
+ DCAM_CAP_FRM_COUNT_CLR,
+ DCAM_CAP_FRM_COUNT_GET,
+ DCAM_CAP_INPUT_RECT,
+ DCAM_CAP_IMAGE_XY_DECI,
+ DCAM_CAP_JPEG_GET_LENGTH,
+ DCAM_CAP_JPEG_SET_BUF_LEN,
+ DCAM_CAP_TO_ISP,
+ DCAM_CAP_SAMPLE_MODE,
+ DCAM_CAP_ZOOM_MODE,
+
+ DCAM_PATH_INPUT_SIZE,
+ DCAM_PATH_INPUT_RECT,
+ DCAM_PATH_INPUT_ADDR,
+ DCAM_PATH_OUTPUT_SIZE,
+ DCAM_PATH_OUTPUT_FORMAT,
+ DCAM_PATH_OUTPUT_ADDR,
+ DCAM_PATH_OUTPUT_RESERVED_ADDR,
+ DCAM_PATH_FRAME_BASE_ID,
+ DCAM_PATH_SWAP_BUFF,
+ DCAM_PATH_SUB_SAMPLE_EN_X,
+ DCAM_PATH_SUB_SAMPLE_EN_Y,
+ DCAM_PATH_SUB_SAMPLE_MOD,
+ DCAM_PATH_SLICE_SCALE_EN,
+ DCAM_PATH_SLICE_SCALE_HEIGHT,
+ DCAM_PATH_DITHER_EN,
+ DCAM_PATH_IS_IN_SCALE_RANGE,
+ DCAM_PATH_IS_SCALE_EN,
+ DCAM_PATH_SLICE_OUT_HEIGHT,
+ DCAM_PATH_DATA_ENDIAN,
+ DCAM_PATH_SRC_SEL,
+ DCAM_PATH_ENABLE,
+ DCAM_PATH_FRAME_TYPE,
+ DCAM_PATH_ROT_MODE,
+ DCAM_PATH_FRM_DECI,
+ DCAM_PATH_SHRINK,
+ DCAM_CFG_ID_E_MAX
+};
+
+/*
+enum dcam_sub_sample_mode
+{
+ DCAM_SUB_2 = 0,
+ DCAM_SUB_4,
+ DCAM_SUB_8,
+ DCAM_SUB_16,
+ DCAM_SUB_MAX
+};
+
+enum dcam_ahb_frm
+{
+ DCAM_AHB_FRAME_SRC,
+ DCAM_AHB_FRAME_PATH1_DST,
+ DCAM_AHB_FRAME_PATH2_DST,
+ DCAM_AHB_FRAME_SWAP,
+ DCAM_AHB_FRAME_LINE,
+ DCAM_AHB_FRAME_MAX
+};
+*/
+enum iram_owner {
+ IRAM_FOR_DCAM = 0,
+ IRAM_FOR_ARM
+};
+
+enum dcam_clk_sel {
+ DCAM_CLK_312M = 0,
+ DCAM_CLK_256M,
+ DCAM_CLK_128M,
+ DCAM_CLK_76M8,
+ DCAM_CLK_NONE
+};
+
+enum dcam_cap_if_mode {
+ DCAM_CAP_IF_CCIR = 0,
+ DCAM_CAP_IF_CSI2,
+ DCAM_CAP_IF_MODE_MAX
+};
+
+enum dcam_path_src_sel {
+ DCAM_PATH_FROM_CAP = 0,
+ DCAM_PATH_FROM_ISP,
+ DCAM_PATH_FROM_NONE
+};
+
+enum dcam_cap_sensor_mode {
+ DCAM_CAP_MODE_YUV = 0,
+ DCAM_CAP_MODE_SPI,
+ DCAM_CAP_MODE_JPEG,
+ DCAM_CAP_MODE_RAWRGB,
+ DCAM_CAP_MODE_MAX
+};
+
+enum dcam_cap_data_bits {
+ DCAM_CAP_12_BITS = 12,
+ DCAM_CAP_10_BITS = 10,
+ DCAM_CAP_8_BITS = 8,
+ DCAM_CAP_4_BITS = 4,
+ DCAM_CAP_2_BITS = 2,
+ DCAM_CAP_1_BITS = 1,
+ DCAM_CAP_BITS_MAX = 0xFF
+};
+
+enum dcam_data_endian {
+ DCAM_ENDIAN_BIG = 0,
+ DCAM_ENDIAN_LITTLE,
+ DCAM_ENDIAN_HALFBIG,
+ DCAM_ENDIAN_HALFLITTLE,
+ DCAM_ENDIAN_MAX
+};
+
+enum dcam_output_mode {
+ DCAM_OUTPUT_WORD = 0,
+ DCAM_OUTPUT_HALF_WORD,
+ DCAM_OUTPUT_YVYU_1FRAME,
+ DCAM_OUTPUT_YUV420,
+};
+
+enum dcam_glb_reg_id {
+ DCAM_CFG_REG = 0,
+ DCAM_CONTROL_REG,
+ DCAM_INIT_MASK_REG,
+ DCAM_INIT_CLR_REG,
+ DCAM_AHBM_STS_REG,
+ DCAM_ENDIAN_REG,
+ DCAM_REG_MAX
+};
+
+enum dcam_v4l2_wtite_cmd_id {
+ DCAM_V4L2_WRITE_STOP = 0x5AA5,
+ DCAM_V4L2_WRITE_FREE_FRAME = 0xA55A,
+ DCAM_V4L2_WRITE_MAX
+};
+
+struct dcam_cap_sync_pol {
+ uint8_t vsync_pol;
+ uint8_t hsync_pol;
+ uint8_t pclk_pol;
+ uint8_t need_href;
+ uint8_t pclk_src;
+ uint8_t reserved[3];
+};
+
+struct dcam_endian_sel {
+ uint8_t y_endian;
+ uint8_t uv_endian;
+ uint8_t reserved0;
+ uint8_t reserved1;
+};
+
+struct dcam_cap_dec {
+ uint8_t x_factor;
+ uint8_t y_factor;
+ uint8_t x_mode;
+ uint8_t reserved;
+};
+
+struct dcam_path_dec {
+ uint8_t x_factor;
+ uint8_t y_factor;
+ uint8_t reserved[2];
+};
+
+struct dcam_size {
+ uint32_t w;
+ uint32_t h;
+};
+
+struct dcam_rect {
+ uint32_t x;
+ uint32_t y;
+ uint32_t w;
+ uint32_t h;
+};
+
+struct dcam_addr {
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+ uint32_t yaddr_vir;
+ uint32_t uaddr_vir;
+ uint32_t vaddr_vir;
+
+};
+
+struct dcam_sc_tap {
+ uint32_t y_tap;
+ uint32_t uv_tap;
+};
+
+struct dcam_deci {
+ uint32_t deci_x_en;
+ uint32_t deci_x;
+ uint32_t deci_y_en;
+ uint32_t deci_y;
+};
+
+struct dcam_frame {
+ uint32_t type;
+ uint32_t lock;
+ uint32_t flags;
+ uint32_t fid;
+ uint32_t width;
+ uint32_t height;
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+ uint32_t yaddr_vir;
+ uint32_t uaddr_vir;
+ uint32_t vaddr_vir;
+ struct dcam_frame *prev;
+ struct dcam_frame *next;
+};
+
+struct dcam_get_path_id {
+ uint32_t fourcc;
+ uint32_t is_path_work[DCAM_PATH_MAX];
+ uint32_t need_isp_tool;
+ uint32_t need_isp;
+ uint32_t need_shrink;
+ struct dcam_size input_size;
+ struct dcam_rect input_trim;
+ struct dcam_size output_size;
+};
+
+struct dcam_path_info {
+ uint32_t line_buf;
+ uint32_t support_yuv;
+ uint32_t support_raw;
+ uint32_t support_jpeg;
+ uint32_t support_scaling;
+ uint32_t support_trim;
+ uint32_t is_scaleing_path;
+};
+
+struct dcam_path_capability {
+ uint32_t count;
+ struct dcam_path_info path_info[DCAM_PATH_MAX];
+};
+
+
+typedef int (*dcam_isr_func)(struct dcam_frame* frame, void* u_data);
+
+int32_t dcam_module_init(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode);
+int32_t dcam_module_deinit(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode);
+int32_t dcam_module_en(struct device_node *dn);
+int32_t dcam_module_dis(struct device_node *dn);
+int32_t dcam_mipi_clk_en(struct device_node *dn);
+int32_t dcam_mipi_clk_dis(struct device_node *dn);
+int32_t dcam_ccir_clk_en(void);
+int32_t dcam_ccir_clk_dis(void);
+int32_t dcam_reset(enum dcam_rst_mode reset_mode, uint32_t is_isr);
+int32_t dcam_set_clk(struct device_node *dn, enum dcam_clk_sel clk_sel);
+int32_t dcam_update_path(enum dcam_path_index path_index, struct dcam_size *in_size,
+ struct dcam_rect *in_rect, struct dcam_size *out_size);
+int32_t dcam_start_path(enum dcam_path_index path_index);
+int32_t dcam_start(void);
+int32_t dcam_stop_path(enum dcam_path_index path_index);
+int32_t dcam_stop(void);
+int32_t dcam_resume(void);
+int32_t dcam_pause(void);
+int32_t dcam_reg_isr(enum dcam_irq_id id, dcam_isr_func user_func, void* u_data);
+int32_t dcam_cap_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_cap_get_info(enum dcam_cfg_id id, void *param);
+int32_t dcam_path0_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_path1_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_path2_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_get_resizer(uint32_t wait_opt);
+int32_t dcam_rel_resizer(void);
+void dcam_int_en(void);
+void dcam_int_dis(void);
+int32_t dcam_frame_is_locked(struct dcam_frame *frame);
+int32_t dcam_frame_lock(struct dcam_frame *frame);
+int32_t dcam_frame_unlock(struct dcam_frame *frame);
+int32_t dcam_read_registers(uint32_t* reg_buf, uint32_t *buf_len);
+int32_t dcam_resize_start(void);
+int32_t dcam_resize_end(void);
+int32_t dcam_stop_cap(void);
+void dcam_glb_reg_awr(uint32_t addr, uint32_t val, uint32_t reg_id);
+void dcam_glb_reg_owr(uint32_t addr, uint32_t val, uint32_t reg_id);
+void dcam_glb_reg_mwr(uint32_t addr, uint32_t mask, uint32_t val, uint32_t reg_id);
+int dcam_scale_coeff_alloc(void);
+void dcam_scale_coeff_free(void);
+int32_t dcam_rotation_start(void);
+int32_t dcam_rotation_end(void);
+int32_t dcam_get_path_id(struct dcam_get_path_id *path_id, uint32_t *channel_id);
+int32_t dcam_stop_sc_coeff(void);
+int32_t dcam_get_path_capability(struct dcam_path_capability *capacity);
+
+#endif //_DCAM_DRV_8830_H_
diff --git a/drivers/media/sprd_dcam/pike/dcam_reg.h b/drivers/media/sprd_dcam/pike/dcam_reg.h
new file mode 100644
index 00000000..58f41fa6
--- /dev/null
+++ b/drivers/media/sprd_dcam/pike/dcam_reg.h
@@ -0,0 +1,192 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#ifndef _REG_DCAM_TIGER_H_
+#define _REG_DCAM_TIGER_H_
+
+#include <soc/sprd/globalregs.h>
+
+#define BIT_0 0x01
+#define BIT_1 0x02
+#define BIT_2 0x04
+#define BIT_3 0x08
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+#define BIT_8 0x0100
+#define BIT_9 0x0200
+#define BIT_10 0x0400
+#define BIT_11 0x0800
+#define BIT_12 0x1000
+#define BIT_13 0x2000
+#define BIT_14 0x4000
+#define BIT_15 0x8000
+#define BIT_16 0x010000
+#define BIT_17 0x020000
+#define BIT_18 0x040000
+#define BIT_19 0x080000
+#define BIT_20 0x100000
+#define BIT_21 0x200000
+#define BIT_22 0x400000
+#define BIT_23 0x800000
+#define BIT_24 0x01000000
+#define BIT_25 0x02000000
+#define BIT_26 0x04000000
+#define BIT_27 0x08000000
+#define BIT_28 0x10000000
+#define BIT_29 0x20000000
+#define BIT_30 0x40000000
+#define BIT_31 0x80000000
+
+#define GLOBAL_BASE SPRD_GREG_BASE
+#define ARM_GLB_GEN0 (GLOBAL_BASE + 0x008UL)
+#define ARM_GLB_GEN3 (GLOBAL_BASE + 0x01CUL)
+#define ARM_GLB_PLL_SCR (GLOBAL_BASE + 0x070UL)
+//#define GR_CLK_GEN5 (GLOBAL_BASE + 0x07CUL)
+#define CLK_DLY_CTRL (GLOBAL_BASE + 0x05CUL)
+
+#define DCAM_AHB_BASE SPRD_MMAHB_BASE
+#define DCAM_AHB_CTL0 (DCAM_AHB_BASE + 0x0000UL)
+#define DCAM_EB (DCAM_AHB_CTL0 + 0x0000UL)
+#define CSI2_DPHY_EB (DCAM_AHB_CTL0 + 0x0000UL)
+#define DCAM_RST (DCAM_AHB_CTL0 + 0x0004UL)
+#define DCAM_MATRIX_EB (DCAM_AHB_CTL0 + 0x0008UL)
+#define DCAM_CCIR_PCLK_EB (SPRD_MMCKG_BASE + 0x0028UL)
+
+
+#define DCAM_CFG (DCAM_BASE + 0x0000UL)
+#define DCAM_CONTROL (DCAM_BASE + 0x0004UL)
+#define DCAM_PATH0_CFG (DCAM_BASE + 0x0008UL)
+#define DCAM_PATH0_SRC_SIZE (DCAM_BASE + 0x000CUL)
+#define DCAM_PATH1_CFG (DCAM_BASE + 0x0010UL)
+#define DCAM_PATH1_SRC_SIZE (DCAM_BASE + 0x0014UL)
+#define DCAM_PATH1_DST_SIZE (DCAM_BASE + 0x0018UL)
+#define DCAM_PATH1_TRIM_START (DCAM_BASE + 0x001CUL)
+#define DCAM_PATH1_TRIM_SIZE (DCAM_BASE + 0x0020UL)
+#define DCAM_PATH2_CFG (DCAM_BASE + 0x0024UL)
+#define DCAM_PATH2_SRC_SIZE (DCAM_BASE + 0x0028UL)
+#define DCAM_PATH2_DST_SIZE (DCAM_BASE + 0x002CUL)
+#define DCAM_PATH2_TRIM_START (DCAM_BASE + 0x0030UL)
+#define DCAM_PATH2_TRIM_SIZE (DCAM_BASE + 0x0034UL)
+#define REV_SLICE_VER (DCAM_BASE + 0x0038UL)
+#define DCAM_INT_STS (DCAM_BASE + 0x003CUL)
+#define DCAM_INT_MASK (DCAM_BASE + 0x0040UL)
+#define DCAM_INT_CLR (DCAM_BASE + 0x0044UL)
+#define DCAM_INT_RAW (DCAM_BASE + 0x0048UL)
+#define DCAM_FRM_ADDR0 (DCAM_BASE + 0x004CUL)
+#define DCAM_FRM_ADDR1 (DCAM_BASE + 0x0050UL)
+#define DCAM_FRM_ADDR2 (DCAM_BASE + 0x0054UL)
+#define DCAM_FRM_ADDR3 (DCAM_BASE + 0x0058UL)
+#define DCAM_FRM_ADDR4 (DCAM_BASE + 0x005CUL)
+#define DCAM_FRM_ADDR5 (DCAM_BASE + 0x0060UL)
+#define DCAM_FRM_ADDR6 (DCAM_BASE + 0x0064UL)
+#define DCAM_BURST_GAP (DCAM_BASE + 0x0068UL)
+#define DCAM_ENDIAN_SEL (DCAM_BASE + 0x006CUL)
+#define DCAM_AHBM_STS (DCAM_BASE + 0x0070UL)
+#define DCAM_FRM_ADDR7 (DCAM_BASE + 0x0074UL)
+#define DCAM_FRM_ADDR8 (DCAM_BASE + 0x0078UL)
+#define DCAM_FRM_ADDR9 (DCAM_BASE + 0x007CUL)
+#define DCAM_FRM_ADDR10 (DCAM_BASE + 0x0080UL)
+#define DCAM_FRM_ADDR11 (DCAM_BASE + 0x0084UL)
+#define CCIR_PATT_CFG (DCAM_BASE + 0x0088UL)
+#define CCIR_PATT_SIZE (DCAM_BASE + 0x008CUL)
+#define CCIR_PATT_VBLANK (DCAM_BASE + 0x0090UL)
+#define CCIR_PATT_HBLANK (DCAM_BASE + 0x0094UL)
+#define REV_BURST_IN_CFG (DCAM_BASE + 0x0098UL)
+#define REV_BURST_IN_TRIM_START (DCAM_BASE + 0x009CUL)
+#define REV_BURST_IN_TRIM_SIZE (DCAM_BASE + 0x00A0UL)
+#define REV_SLICE_CFG (DCAM_BASE + 0x00A4UL)
+#define PATH1_SLICE_O_VCNT (DCAM_BASE + 0x00A8UL)
+#define PATH2_SLICE_O_VCNT (DCAM_BASE + 0x00ACUL)
+
+#define CAP_CCIR_CTRL (DCAM_BASE + 0x0100UL)
+#define CAP_CCIR_FRM_CTRL (DCAM_BASE + 0x0104UL)
+#define CAP_CCIR_START (DCAM_BASE + 0x0108UL)
+#define CAP_CCIR_END (DCAM_BASE + 0x010CUL)
+#define CAP_CCIR_IMG_DECI (DCAM_BASE + 0x0110UL)
+#define CAP_CCIR_ATV_FIX (DCAM_BASE + 0x0114UL)
+#define CAP_CCIR_OBSERVE (DCAM_BASE + 0x0118UL)
+#define CAP_CCIR_JPG_CTRL (DCAM_BASE + 0x011CUL)
+#define CAP_CCIR_FRM_SIZE (DCAM_BASE + 0x0120UL)
+#define CAP_CCIR_PLCK_SRC (SPRD_PIN_BASE + 0x04)
+#define CAP_SPI_CFG (DCAM_BASE + 0x0124UL)
+
+#define CAP_MIPI_CTRL (DCAM_BASE + 0x0128UL)
+#define CAP_MIPI_FRM_CTRL (DCAM_BASE + 0x012CUL)
+#define CAP_MIPI_START (DCAM_BASE + 0x0130UL)
+#define CAP_MIPI_END (DCAM_BASE + 0x0134UL)
+#define CAP_MIPI_IMG_DECI (DCAM_BASE + 0x0138UL)
+#define CAP_MIPI_JPG_CTRL (DCAM_BASE + 0x013CUL)
+#define CAP_MIPI_FRM_SIZE (DCAM_BASE + 0x0140UL)
+#define CAP_SENSOR_CTRL (DCAM_BASE + 0x0144UL)
+
+#define BLC_CFG (DCAM_BASE + 0x0148UL)
+#define BLC_START (DCAM_BASE + 0x014CUL)
+#define BLC_END (DCAM_BASE + 0x0150UL)
+#define BLC_TARGET (DCAM_BASE + 0x0154UL)
+#define BLC_MANUAL (DCAM_BASE + 0x0158UL)
+#define BLC_VALUE1 (DCAM_BASE + 0x015CUL)
+#define BLC_VALUE2 (DCAM_BASE + 0x0160UL)
+
+#define DCAM_END BLC_VALUE2
+
+
+#define DCAM_EB_BIT BIT_0
+#define CCIR_EB_BIT BIT_1
+#define MIPI_EB_BIT BIT_10 // aiden: todo
+
+#define DCAM_MOD_RST_BIT BIT_0
+#define CCIR_RST_BIT BIT_1
+#define PATH0_RST_BIT BIT_7
+#define PATH1_RST_BIT BIT_8
+#define PATH2_RST_BIT BIT_9
+#define CCIR_PCLK_EB_BIT BIT_16
+
+#define DCAM_PATH_NUM 3
+#define DCAM_CAP_SKIP_FRM_MAX 16
+#define DCAM_FRM_DECI_FAC_MAX 4
+#define DCAM_CAP_FRAME_WIDTH_MAX 4092
+#define DCAM_CAP_FRAME_HEIGHT_MAX 4092
+#define DCAM_PATH_FRAME_WIDTH_MAX 4092
+#define DCAM_PATH_FRAME_HEIGHT_MAX 4092
+#define DCAM_CAP_X_DECI_FAC_MAX 4 // cap deci: 0 - 1/8
+#define DCAM_CAP_Y_DECI_FAC_MAX 4 // cap deci: 0 - 1/8
+#define DCAM_JPG_BUF_UNIT (1 << 15)
+#define DCAM_JPG_UNITS (1 << 10)
+#define DCAM_SC_COEFF_UP_MAX 4 // path scaling: 1/8 - 4
+#define DCAM_SC_COEFF_DOWN_MAX 7 // path scaling: 1/8 - 4
+#define DCAM_PATH_DECI_FAC_MAX 4 // path deci: 1/2 - 1/16
+#define DCAM_PATH1_LINE_BUF_LENGTH 1296
+#define DCAM_PATH2_LINE_BUF_LENGTH 3280
+#define DCAM_ISP_LINE_BUF_LENGTH 3280
+#define DCAM_SCALING_THRESHOLD 2048
+#define DCAM_IRQ IRQ_DCAM_INT
+
+#define DCAM_PIXEL_ALIGN_WIDTH 4
+#define DCAM_PIXEL_ALIGN_HEIGHT 2
+
+#define DCAM_PATH_NUM 3
+enum {
+ DCAM_PATH0 = 0,
+ DCAM_PATH1,
+ DCAM_PATH2,
+ DCAM_PATH_MAX
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_REG_DCAM_TIGER_H_
+
+
diff --git a/drivers/media/sprd_dcam/sc8830/dcam_drv.h b/drivers/media/sprd_dcam/sc8830/dcam_drv.h
new file mode 100755
index 00000000..c510a70f
--- /dev/null
+++ b/drivers/media/sprd_dcam/sc8830/dcam_drv.h
@@ -0,0 +1,420 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef _DCAM_DRV_8830_H_
+#define _DCAM_DRV_8830_H_
+
+#include <linux/types.h>
+#include "dcam_reg.h"
+#include "parse_hwinfo.h"
+
+//#define DCAM_DEBUG
+
+#ifdef DCAM_DEBUG
+ #define DCAM_TRACE printk
+#else
+ #define DCAM_TRACE pr_debug
+#endif
+
+#define DCAM_WAIT_FOREVER 0xFFFFFFFF
+#define DCAM_PATH_1_FRM_CNT_MAX 8
+#define DCAM_PATH_2_FRM_CNT_MAX 8
+#define DCAM_PATH_0_FRM_CNT_MAX 8
+#define DCAM_FRM_CNT_MAX 8 /* max between path_1_frm_cnt and path_2_frm_cnt */
+#define DCAM_HEIGHT_MIN 4
+#define DCAM_JPEG_LENGTH_MIN 30720 /*640X480 div 10*/
+
+enum dcam_swtich_status {
+ DCAM_SWITCH_IDLE = 0,
+ DCAM_SWITCH_PAUSE,
+ DCAM_SWITCH_DONE,
+ DCAM_SWITCH_MAX
+};
+
+enum dcam_drv_rtn {
+ DCAM_RTN_SUCCESS = 0,
+ DCAM_RTN_PARA_ERR = 0x10,
+ DCAM_RTN_IO_ID_ERR,
+ DCAM_RTN_ISR_ID_ERR,
+ DCAM_RTN_MASTER_SEL_ERR,
+ DCAM_RTN_MODE_ERR,
+ DCAM_RTN_TIMEOUT,
+
+ DCAM_RTN_CAP_FRAME_SEL_ERR = 0x20,
+ DCAM_RTN_CAP_IN_FORMAT_ERR,
+ DCAM_RTN_CAP_IN_BITS_ERR,
+ DCAM_RTN_CAP_IN_YUV_ERR,
+ DCAM_RTN_CAP_SYNC_POL_ERR,
+ DCAM_RTN_CAP_SKIP_FRAME_ERR,
+ DCAM_RTN_CAP_FRAME_DECI_ERR,
+ DCAM_RTN_CAP_XY_DECI_ERR,
+ DCAM_RTN_CAP_FRAME_SIZE_ERR,
+ DCAM_RTN_CAP_SENSOR_MODE_ERR,
+ DCAM_RTN_CAP_JPEG_BUF_LEN_ERR,
+ DCAM_RTN_CAP_IF_MODE_ERR,
+
+ DCAM_RTN_PATH_SRC_SIZE_ERR = 0x30,
+ DCAM_RTN_PATH_TRIM_SIZE_ERR,
+ DCAM_RTN_PATH_DES_SIZE_ERR,
+ DCAM_RTN_PATH_IN_FMT_ERR,
+ DCAM_RTN_PATH_OUT_FMT_ERR,
+ DCAM_RTN_PATH_SC_ERR,
+ DCAM_RTN_PATH_SUB_SAMPLE_ERR,
+ DCAM_RTN_PATH_ADDR_ERR,
+ DCAM_RTN_PATH_FRAME_TOO_MANY,
+ DCAM_RTN_PATH_FRAME_LOCKED,
+ DCAM_RTN_PATH_NO_MEM,
+ DCAM_RTN_PATH_GEN_COEFF_ERR,
+ DCAM_RTN_PATH_SRC_ERR,
+ DCAM_RTN_PATH_ENDIAN_ERR,
+ DCAM_RTN_PATH_FRM_DECI_ERR,
+ DCAM_RTN_MAX
+};
+
+enum dcam_rst_mode {
+ DCAM_RST_ALL = 0,
+ DCAM_RST_PATH0,
+ DCAM_RST_PATH1,
+ DCAM_RST_PATH2
+};
+
+enum dcam_path_index {
+ DCAM_PATH_IDX_NONE = 0,
+ DCAM_PATH_IDX_0 = 1,
+ DCAM_PATH_IDX_1 = 2,
+ DCAM_PATH_IDX_2 = 4,
+ DCAM_PATH_IDX_ALL = 7,
+};
+
+
+enum dcam_fmt {
+ DCAM_YUV422 = 0,
+ DCAM_YUV420,
+ DCAM_YUV420_3FRAME,
+ DCAM_YUV400,
+ DCAM_RGB565,
+ DCAM_RGB888,
+ DCAM_RAWRGB,
+ DCAM_JPEG,
+ DCAM_FTM_MAX
+};
+
+enum dcam_cap_pattern {
+ DCAM_YUYV = 0,
+ DCAM_YVYU,
+ DCAM_UYVY,
+ DCAM_VYUY,
+ DCAM_PATTERN_MAX
+};
+
+enum dcam_capture_mode {
+ DCAM_CAPTURE_MODE_SINGLE = 0,
+ DCAM_CAPTURE_MODE_MULTIPLE,
+ DCAM_CAPTURE_MODE_MAX
+};
+
+
+enum dcam_irq_id {
+ DCAM_SN_SOF = 0,
+ DCAM_SN_EOF,
+ DCAM_CAP_SOF,
+ DCAM_CAP_EOF,
+ DCAM_PATH0_DONE,
+ DCAM_PATH0_OV,
+ DCAM_PATH1_DONE,
+ DCAM_PATH1_OV,
+ DCAM_PATH2_DONE,
+ DCAM_PATH2_OV,
+ DCAM_SN_LINE_ERR,
+ DCAM_SN_FRAME_ERR,
+ DCAM_JPEG_BUF_OV,
+ DCAM_ISP_OV,
+ DCAM_MIPI_OV,
+ DCAM_ROT_DONE,
+ DCAM_PATH1_SLICE_DONE,
+ DCAM_PATH2_SLICE_DONE,
+ DCAM_RAW_SLICE_DONE,
+ DCAM_PATH1_SOF,
+ DCAM_PATH2_SOF,
+ DCAM_IRQ_NUMBER
+};
+
+enum dcam_cfg_id {
+ DCAM_CAP_SYNC_POL = 0,
+ DCAM_CAP_DATA_BITS,
+ DCAM_CAP_DATA_PACKET,
+ DCAM_CAP_YUV_TYPE,
+ DCAM_CAP_PRE_SKIP_CNT,
+ DCAM_CAP_FRM_DECI,
+ DCAM_CAP_FRM_COUNT_CLR,
+ DCAM_CAP_FRM_COUNT_GET,
+ DCAM_CAP_INPUT_RECT,
+ DCAM_CAP_IMAGE_XY_DECI,
+ DCAM_CAP_JPEG_GET_LENGTH,
+ DCAM_CAP_JPEG_SET_BUF_LEN,
+ DCAM_CAP_TO_ISP,
+ DCAM_CAP_SAMPLE_MODE,
+ DCAM_CAP_ZOOM_MODE,
+
+ DCAM_PATH_INPUT_SIZE,
+ DCAM_PATH_INPUT_RECT,
+ DCAM_PATH_INPUT_ADDR,
+ DCAM_PATH_OUTPUT_SIZE,
+ DCAM_PATH_OUTPUT_FORMAT,
+ DCAM_PATH_OUTPUT_ADDR,
+ DCAM_PATH_FRAME_BASE_ID,
+ DCAM_PATH_SWAP_BUFF,
+ DCAM_PATH_SUB_SAMPLE_EN_X,
+ DCAM_PATH_SUB_SAMPLE_EN_Y,
+ DCAM_PATH_SUB_SAMPLE_MOD,
+ DCAM_PATH_SLICE_SCALE_EN,
+ DCAM_PATH_SLICE_SCALE_HEIGHT,
+ DCAM_PATH_DITHER_EN,
+ DCAM_PATH_IS_IN_SCALE_RANGE,
+ DCAM_PATH_IS_SCALE_EN,
+ DCAM_PATH_SLICE_OUT_HEIGHT,
+ DCAM_PATH_DATA_ENDIAN,
+ DCAM_PATH_SRC_SEL,
+ DCAM_PATH_ENABLE,
+ DCAM_PATH_FRAME_TYPE,
+ DCAM_PATH_ROT_MODE,
+ DCAM_PATH_FRM_DECI,
+ DCAM_PATH_SHRINK,
+ DCAM_CFG_ID_E_MAX
+};
+
+/*
+enum dcam_sub_sample_mode
+{
+ DCAM_SUB_2 = 0,
+ DCAM_SUB_4,
+ DCAM_SUB_8,
+ DCAM_SUB_16,
+ DCAM_SUB_MAX
+};
+
+enum dcam_ahb_frm
+{
+ DCAM_AHB_FRAME_SRC,
+ DCAM_AHB_FRAME_PATH1_DST,
+ DCAM_AHB_FRAME_PATH2_DST,
+ DCAM_AHB_FRAME_SWAP,
+ DCAM_AHB_FRAME_LINE,
+ DCAM_AHB_FRAME_MAX
+};
+*/
+enum iram_owner {
+ IRAM_FOR_DCAM = 0,
+ IRAM_FOR_ARM
+};
+
+enum dcam_clk_sel {
+ DCAM_CLK_256M = 0,
+ DCAM_CLK_128M,
+ DCAM_CLK_76M8,
+ DCAM_CLK_48M,
+ DCAM_CLK_NONE
+};
+
+enum dcam_cap_if_mode {
+ DCAM_CAP_IF_CCIR = 0,
+ DCAM_CAP_IF_CSI2,
+ DCAM_CAP_IF_MODE_MAX
+};
+
+enum dcam_path_src_sel {
+ DCAM_PATH_FROM_CAP = 0,
+ DCAM_PATH_FROM_ISP,
+ DCAM_PATH_FROM_NONE
+};
+
+enum dcam_cap_sensor_mode {
+ DCAM_CAP_MODE_YUV = 0,
+ DCAM_CAP_MODE_SPI,
+ DCAM_CAP_MODE_JPEG,
+ DCAM_CAP_MODE_RAWRGB,
+ DCAM_CAP_MODE_MAX
+};
+
+enum dcam_cap_data_bits {
+ DCAM_CAP_12_BITS = 12,
+ DCAM_CAP_10_BITS = 10,
+ DCAM_CAP_8_BITS = 8,
+ DCAM_CAP_4_BITS = 4,
+ DCAM_CAP_2_BITS = 2,
+ DCAM_CAP_1_BITS = 1,
+ DCAM_CAP_BITS_MAX = 0xFF
+};
+
+enum dcam_data_endian {
+ DCAM_ENDIAN_BIG = 0,
+ DCAM_ENDIAN_LITTLE,
+ DCAM_ENDIAN_HALFBIG,
+ DCAM_ENDIAN_HALFLITTLE,
+ DCAM_ENDIAN_MAX
+};
+
+enum dcam_output_mode {
+ DCAM_OUTPUT_WORD = 0,
+ DCAM_OUTPUT_HALF_WORD,
+};
+
+enum dcam_glb_reg_id {
+ DCAM_CFG_REG = 0,
+ DCAM_CONTROL_REG,
+ DCAM_INIT_MASK_REG,
+ DCAM_INIT_CLR_REG,
+ DCAM_AHBM_STS_REG,
+ DCAM_ENDIAN_REG,
+ DCAM_REG_MAX
+};
+
+enum dcam_v4l2_wtite_cmd_id {
+ DCAM_V4L2_WRITE_STOP = 0x5AA5,
+ DCAM_V4L2_WRITE_FREE_FRAME = 0xA55A,
+ DCAM_V4L2_WRITE_MAX
+};
+
+struct dcam_cap_sync_pol {
+ uint8_t vsync_pol;
+ uint8_t hsync_pol;
+ uint8_t pclk_pol;
+ uint8_t need_href;
+ uint8_t pclk_src;
+ uint8_t reserved[3];
+};
+
+struct dcam_endian_sel {
+ uint8_t y_endian;
+ uint8_t uv_endian;
+ uint8_t reserved0;
+ uint8_t reserved1;
+};
+
+struct dcam_cap_dec {
+ uint8_t x_factor;
+ uint8_t y_factor;
+ uint8_t x_mode;
+ uint8_t reserved;
+};
+
+struct dcam_path_dec {
+ uint8_t x_factor;
+ uint8_t y_factor;
+ uint8_t reserved[2];
+};
+
+struct dcam_size {
+ uint32_t w;
+ uint32_t h;
+};
+
+struct dcam_rect {
+ uint32_t x;
+ uint32_t y;
+ uint32_t w;
+ uint32_t h;
+};
+
+struct dcam_addr {
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+};
+
+struct dcam_sc_tap {
+ uint32_t y_tap;
+ uint32_t uv_tap;
+};
+
+struct dcam_deci {
+ uint32_t deci_x_en;
+ uint32_t deci_x;
+ uint32_t deci_y_en;
+ uint32_t deci_y;
+};
+
+struct dcam_frame {
+ uint32_t type;
+ uint32_t lock;
+ uint32_t flags;
+ uint32_t fid;
+ uint32_t width;
+ uint32_t height;
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+ struct dcam_frame *prev;
+ struct dcam_frame *next;
+};
+
+struct dcam_get_path_id {
+ uint32_t fourcc;
+ uint32_t is_path_work[DCAM_PATH_MAX];
+ uint32_t need_isp_tool;
+ uint32_t need_isp;
+ uint32_t need_shrink;
+ struct dcam_size input_size;
+ struct dcam_rect input_trim;
+ struct dcam_size output_size;
+};
+
+typedef int (*dcam_isr_func)(struct dcam_frame* frame, void* u_data);
+
+int32_t dcam_module_init(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode);
+int32_t dcam_module_deinit(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode);
+int32_t dcam_module_en(struct device_node *dn);
+int32_t dcam_module_dis(struct device_node *dn);
+int32_t dcam_mipi_clk_en(struct device_node *dn);
+int32_t dcam_mipi_clk_dis(struct device_node *dn);
+int32_t dcam_ccir_clk_en(void);
+int32_t dcam_ccir_clk_dis(void);
+int32_t dcam_reset(enum dcam_rst_mode reset_mode, uint32_t is_isr);
+int32_t dcam_set_clk(struct device_node *dn, enum dcam_clk_sel clk_sel);
+int32_t dcam_update_path(enum dcam_path_index path_index, struct dcam_size *in_size,
+ struct dcam_rect *in_rect, struct dcam_size *out_size);
+int32_t dcam_start_path(enum dcam_path_index path_index);
+int32_t dcam_start(void);
+int32_t dcam_stop_path(enum dcam_path_index path_index);
+int32_t dcam_stop(void);
+int32_t dcam_resume(void);
+int32_t dcam_pause(void);
+int32_t dcam_reg_isr(enum dcam_irq_id id, dcam_isr_func user_func, void* u_data);
+int32_t dcam_cap_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_cap_get_info(enum dcam_cfg_id id, void *param);
+int32_t dcam_path0_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_path1_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_path2_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_get_resizer(uint32_t wait_opt);
+int32_t dcam_rel_resizer(void);
+void dcam_int_en(void);
+void dcam_int_dis(void);
+int32_t dcam_frame_is_locked(struct dcam_frame *frame);
+int32_t dcam_frame_lock(struct dcam_frame *frame);
+int32_t dcam_frame_unlock(struct dcam_frame *frame);
+int32_t dcam_read_registers(uint32_t* reg_buf, uint32_t *buf_len);
+int32_t dcam_resize_start(void);
+int32_t dcam_resize_end(void);
+int32_t dcam_stop_cap(void);
+void dcam_glb_reg_awr(uint32_t addr, uint32_t val, uint32_t reg_id);
+void dcam_glb_reg_owr(uint32_t addr, uint32_t val, uint32_t reg_id);
+void dcam_glb_reg_mwr(uint32_t addr, uint32_t mask, uint32_t val, uint32_t reg_id);
+int dcam_scale_coeff_alloc(void);
+void dcam_scale_coeff_free(void);
+int32_t dcam_rotation_start(void);
+int32_t dcam_rotation_end(void);
+int32_t dcam_get_path_id(struct dcam_get_path_id *path_id, uint32_t *channel_id);
+int32_t dcam_stop_sc_coeff(void);
+#endif //_DCAM_DRV_8830_H_
diff --git a/drivers/media/sprd_dcam/sharkl/dcam_drv.c b/drivers/media/sprd_dcam/sharkl/dcam_drv.c
new file mode 100644
index 00000000..11858913
--- /dev/null
+++ b/drivers/media/sprd_dcam/sharkl/dcam_drv.c
@@ -0,0 +1,4580 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <linux/kthread.h>
+#ifndef CONFIG_64BIT
+#include <soc/sprd/hardware.h>
+#include <mach/irqs.h>
+#else
+#include <soc/sprd/irqs.h>
+#endif
+#include <soc/sprd/sci.h>
+#include <soc/sprd/sci_glb_regs.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/wakelock.h>
+#include "dcam_drv.h"
+#include "gen_scale_coef.h"
+
+#define LOCAL static
+/*#define LOCAL*/
+
+//#define DCAM_DRV_DEBUG
+#define DCAM_LOWEST_ADDR 0x800
+#define DCAM_ADDR_INVALID(addr) ((unsigned long)(addr) < DCAM_LOWEST_ADDR)
+#define DCAM_YUV_ADDR_INVALID(y,u,v) \
+ (DCAM_ADDR_INVALID(y) && \
+ DCAM_ADDR_INVALID(u) && \
+ DCAM_ADDR_INVALID(v))
+
+#define DCAM_SC1_H_TAB_OFFSET 0x400
+#define DCAM_SC1_V_TAB_OFFSET 0x4F0
+#define DCAM_SC1_V_CHROMA_TAB_OFFSET 0x8F0
+
+#define DCAM_SC2_H_TAB_OFFSET 0x1400
+#define DCAM_SC2_V_TAB_OFFSET 0x14F0
+#define DCAM_SC2_V_CHROMA_TAB_OFFSET 0x18F0
+
+#define DCAM_SC_COEFF_BUF_SIZE (24 << 10)
+#define DCAM_SC_COEFF_COEF_SIZE (1 << 10)
+#define DCAM_SC_COEFF_TMP_SIZE (21 << 10)
+#define DCAM_SC_COEFF_BUF_COUNT 2
+
+
+#define DCAM_SC_H_COEF_SIZE (0xC0)
+#define DCAM_SC_V_COEF_SIZE (0x210)
+#define DCAM_SC_V_CHROM_COEF_SIZE (0x210)
+
+#define DCAM_SC_COEFF_H_NUM (DCAM_SC_H_COEF_SIZE/4)
+#define DCAM_SC_COEFF_V_NUM (DCAM_SC_V_COEF_SIZE/4)
+#define DCAM_SC_COEFF_V_CHROMA_NUM (DCAM_SC_V_CHROM_COEF_SIZE/4)
+
+#define DCAM_AXI_STOP_TIMEOUT 1000
+#define DCAM_CLK_DOMAIN_AHB 1
+#define DCAM_CLK_DOMAIN_DCAM 0
+
+#ifdef CONFIG_SC_FPGA
+#define DCAM_PATH_TIMEOUT msecs_to_jiffies(500*10)
+#else
+#define DCAM_PATH_TIMEOUT msecs_to_jiffies(500)
+#endif
+
+#define DCAM_FRM_QUEUE_LENGTH 4
+
+#define DCAM_STATE_QUICKQUIT 0x01
+
+#define DCAM_CHECK_PARAM_ZERO_POINTER(n) \
+ do { \
+ if (0 == (unsigned long)(n)) \
+ return -DCAM_RTN_PARA_ERR; \
+ } while(0)
+
+#define DCAM_CLEAR(a) \
+ do { \
+ memset((void *)(a), 0, sizeof(*(a))); \
+ } while(0)
+
+#define DEBUG_STR "Error L %d, %s \n"
+#define DEBUG_ARGS __LINE__,__FUNCTION__
+#define DCAM_RTN_IF_ERR \
+ do { \
+ if(rtn) { \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return -(rtn); \
+ } \
+ } while(0)
+
+#define DCAM_IRQ_LINE_MASK 0x001FFFFFUL
+
+typedef void (*dcam_isr)(void);
+
+enum {
+ DCAM_FRM_UNLOCK = 0,
+ DCAM_FRM_LOCK_WRITE = 0x10011001,
+ DCAM_FRM_LOCK_READ = 0x01100110
+};
+
+enum {
+ DCAM_ST_STOP = 0,
+ DCAM_ST_START,
+};
+
+#define DCAM_IRQ_ERR_MASK \
+ ((1 << DCAM_PATH0_OV) | (1 << DCAM_PATH1_OV) | (1 << DCAM_PATH2_OV) | \
+ (1 << DCAM_SN_LINE_ERR) | (1 << DCAM_SN_FRAME_ERR) | \
+ (1 << DCAM_ISP_OV) | (1 << DCAM_MIPI_OV))
+
+#define DCAM_IRQ_JPEG_OV_MASK (1 << DCAM_JPEG_BUF_OV)
+
+#define DCAM_CHECK_ZERO(a) \
+ do { \
+ if (DCAM_ADDR_INVALID(a)) { \
+ printk("DCAM, zero pointer \n"); \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return -EFAULT; \
+ } \
+ } while(0)
+
+#define DCAM_CHECK_ZERO_VOID(a) \
+ do { \
+ if (DCAM_ADDR_INVALID(a)) { \
+ printk("DCAM, zero pointer \n"); \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return; \
+ } \
+ } while(0)
+
+struct dcam_cap_desc {
+ uint32_t interface;
+ uint32_t input_format;
+ uint32_t frame_deci_factor;
+ uint32_t img_x_deci_factor;
+ uint32_t img_y_deci_factor;
+};
+
+struct dcam_path_valid {
+ uint32_t input_size :1;
+ uint32_t input_rect :1;
+ uint32_t output_size :1;
+ uint32_t output_format :1;
+ uint32_t src_sel :1;
+ uint32_t data_endian :1;
+ uint32_t frame_deci :1;
+ uint32_t scale_tap :1;
+ uint32_t v_deci :1;
+};
+
+struct dcam_frm_queue {
+ struct dcam_frame frm_array[DCAM_FRM_QUEUE_LENGTH];
+ uint32_t valid_cnt;
+};
+
+struct dcam_buf_queue {
+ struct dcam_frame frame[DCAM_FRM_CNT_MAX];
+ struct dcam_frame *write;
+ struct dcam_frame *read;
+ spinlock_t lock;
+};
+
+struct dcam_path_desc {
+ struct dcam_size input_size;
+ struct dcam_rect input_rect;
+ struct dcam_size sc_input_size;
+ struct dcam_size output_size;
+ struct dcam_frame input_frame;
+ struct dcam_frm_queue frame_queue;
+ struct dcam_buf_queue buf_queue;
+ //struct dcam_frame *output_frame_head;
+ //struct dcam_frame *output_frame_cur;
+ struct dcam_endian_sel data_endian;
+ struct dcam_sc_tap scale_tap;
+ struct dcam_deci deci_val;
+ struct dcam_path_valid valid_param;
+ uint32_t frame_base_id;
+ uint32_t output_frame_count;
+ uint32_t output_format;
+ uint32_t src_sel;
+ uint32_t rot_mode;
+ uint32_t frame_deci;
+ uint32_t valide;
+ uint32_t status;
+ struct semaphore tx_done_sema;
+ struct semaphore sof_sema;
+ uint32_t wait_for_done;
+ uint32_t is_update;
+ uint32_t wait_for_sof;
+ uint32_t need_stop;
+ uint32_t need_wait;
+ int32_t sof_cnt;
+};
+
+struct dcam_module {
+ uint32_t dcam_mode;
+ uint32_t module_addr;
+ struct dcam_cap_desc dcam_cap;
+ struct dcam_path_desc dcam_path0;
+ struct dcam_path_desc dcam_path1;
+ struct dcam_path_desc dcam_path2;
+ struct dcam_frame path0_frame[DCAM_PATH_0_FRM_CNT_MAX];
+ struct dcam_frame path1_frame[DCAM_PATH_1_FRM_CNT_MAX];
+ struct dcam_frame path2_frame[DCAM_PATH_2_FRM_CNT_MAX];
+ struct dcam_frame path0_reserved_frame;
+ struct dcam_frame path1_reserved_frame;
+ struct dcam_frame path2_reserved_frame;
+ struct semaphore stop_sema;
+ uint32_t wait_stop;
+ struct semaphore resize_done_sema;
+ uint32_t wait_resize_done;
+ struct semaphore rotation_done_sema;
+ uint32_t wait_rotation_done;
+ uint32_t err_happened;
+ struct semaphore scale_coeff_mem_sema;
+ uint32_t state;
+};
+
+struct dcam_sc_coeff {
+ uint32_t buf[DCAM_SC_COEFF_BUF_SIZE];
+ uint32_t flag;
+ struct dcam_path_desc dcam_path1;
+};
+
+struct dcam_sc_array {
+ struct dcam_sc_coeff scaling_coeff[DCAM_SC_COEFF_BUF_COUNT];
+ struct dcam_sc_coeff *scaling_coeff_queue[DCAM_SC_COEFF_BUF_COUNT];
+ uint32_t valid_cnt;
+ uint32_t is_smooth_zoom;
+};
+
+LOCAL atomic_t s_dcam_users = ATOMIC_INIT(0);
+LOCAL atomic_t s_resize_flag = ATOMIC_INIT(0);
+LOCAL atomic_t s_rotation_flag = ATOMIC_INIT(0);
+#ifndef CONFIG_SC_FPGA
+LOCAL struct clk* s_dcam_clk = NULL;
+#endif
+LOCAL struct dcam_module* s_p_dcam_mod = 0;
+LOCAL uint32_t s_dcam_irq = 0x5A0000A5;
+LOCAL dcam_isr_func s_user_func[DCAM_IRQ_NUMBER];
+LOCAL void* s_user_data[DCAM_IRQ_NUMBER];
+LOCAL struct dcam_sc_array* s_dcam_sc_array = NULL;
+LOCAL struct wake_lock dcam_wakelock;
+
+LOCAL DEFINE_MUTEX(dcam_sem);
+LOCAL DEFINE_MUTEX(dcam_scale_sema);
+LOCAL DEFINE_MUTEX(dcam_rot_sema);
+LOCAL DEFINE_MUTEX(dcam_module_sema);
+LOCAL DEFINE_SPINLOCK(dcam_mod_lock);
+LOCAL DEFINE_SPINLOCK(dcam_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_cfg_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_control_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_mask_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_clr_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_ahbm_sts_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_endian_lock);
+
+LOCAL void _dcam_path0_set(void);
+LOCAL void _dcam_path1_set(struct dcam_path_desc *path);
+LOCAL void _dcam_path2_set(void);
+LOCAL void _dcam_frm_clear(enum dcam_path_index path_index);
+LOCAL void _dcam_link_frm(uint32_t base_id);
+LOCAL int32_t _dcam_path_set_next_frm(enum dcam_path_index path_index, uint32_t is_1st_frm);
+/*LOCAL int32_t _dcam_path_trim(enum dcam_path_index path_index);*/
+LOCAL int32_t _dcam_path_scaler(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_calc_sc_size(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_set_sc_coeff(enum dcam_path_index path_index);
+LOCAL void _dcam_force_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy);
+LOCAL void _dcam_auto_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy);
+LOCAL void _dcam_force_copy(enum dcam_path_index path_index);
+LOCAL void _dcam_auto_copy(enum dcam_path_index path_index);
+LOCAL void _dcam_reg_trace(void);
+/*LOCAL void _dcam_sensor_sof(void);*/
+LOCAL void _dcam_sensor_eof(void);
+LOCAL void _dcam_cap_sof(void);
+LOCAL void _dcam_cap_eof(void);
+LOCAL void _dcam_path0_done(void);
+LOCAL void _dcam_path0_overflow(void);
+LOCAL void _dcam_path1_done(void);
+LOCAL void _dcam_path1_overflow(void);
+LOCAL void _dcam_sensor_line_err(void);
+LOCAL void _dcam_sensor_frame_err(void);
+LOCAL void _dcam_jpeg_buf_ov(void);
+LOCAL void _dcam_path2_done(void);
+LOCAL void _dcam_path2_ov(void);
+LOCAL void _dcam_isp_ov(void);
+LOCAL void _dcam_mipi_ov(void);
+LOCAL void _dcam_path1_slice_done(void);
+LOCAL void _dcam_path2_slice_done(void);
+LOCAL void _dcam_raw_slice_done(void);
+LOCAL void _dcam_path1_sof(void);
+LOCAL void _dcam_path2_sof(void);
+LOCAL irqreturn_t _dcam_isr_root(int irq, void *dev_id);
+LOCAL void _dcam_stopped_notice(void);
+LOCAL void _dcam_stopped(void);
+LOCAL int32_t _dcam_path_check_deci(enum dcam_path_index path_index, uint32_t *is_deci);
+extern void _dcam_isp_root(void);
+LOCAL int _dcam_internal_init(void);
+LOCAL void _dcam_internal_deinit(void);
+LOCAL void _dcam_wait_path_done(enum dcam_path_index path_index, uint32_t *p_flag);
+LOCAL void _dcam_path_done_notice(enum dcam_path_index path_index);
+LOCAL void _dcam_rot_done(void);
+LOCAL int32_t _dcam_err_pre_proc(void);
+LOCAL void _dcam_frm_queue_clear(struct dcam_frm_queue *queue);
+LOCAL int32_t _dcam_frame_enqueue(struct dcam_frm_queue *queue, struct dcam_frame *frame);
+LOCAL int32_t _dcam_frame_dequeue(struct dcam_frm_queue *queue, struct dcam_frame *frame);
+LOCAL void _dcam_buf_queue_init(struct dcam_buf_queue *queue);
+LOCAL int32_t _dcam_buf_queue_write(struct dcam_buf_queue *queue, struct dcam_frame *frame);
+LOCAL int32_t _dcam_buf_queue_read(struct dcam_buf_queue *queue, struct dcam_frame *frame);
+LOCAL void _dcam_wait_update_done(enum dcam_path_index path_index, uint32_t *p_flag);
+LOCAL void _dcam_path_updated_notice(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_get_valid_sc_coeff(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff);
+LOCAL int32_t _dcam_push_sc_buf(struct dcam_sc_array *sc, uint32_t index);
+LOCAL int32_t _dcam_pop_sc_buf(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff);
+LOCAL int32_t _dcam_calc_sc_coeff(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_write_sc_coeff(enum dcam_path_index path_index);
+LOCAL void _dcam_wait_for_quickstop(enum dcam_path_index path_index);
+
+LOCAL const dcam_isr isr_list[DCAM_IRQ_NUMBER] = {
+ NULL,//_dcam_isp_root,
+ _dcam_sensor_eof,
+ _dcam_cap_sof,
+ _dcam_cap_eof,
+ _dcam_path0_done,
+ _dcam_path0_overflow,
+ _dcam_path1_done,
+ _dcam_path1_overflow,
+ _dcam_path2_done,
+ _dcam_path2_ov,
+ _dcam_sensor_line_err,
+ _dcam_sensor_frame_err,
+ _dcam_jpeg_buf_ov,
+ _dcam_isp_ov,
+ _dcam_mipi_ov,
+ _dcam_rot_done,
+ _dcam_path1_slice_done,
+ _dcam_path2_slice_done,
+ _dcam_raw_slice_done,
+ _dcam_path1_sof,
+ _dcam_path2_sof,
+};
+
+void dcam_glb_reg_awr(unsigned long addr, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ REG_WR(addr, REG_RD(addr) & (val));
+ break;
+ }
+}
+
+void dcam_glb_reg_owr(unsigned long addr, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ REG_WR(addr, REG_RD(addr) | (val));
+ break;
+ }
+}
+
+void dcam_glb_reg_mwr(unsigned long addr, uint32_t mask, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+ uint32_t tmp = 0;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ break;
+ }
+}
+
+int32_t dcam_module_init(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ if (if_mode >= DCAM_CAP_IF_MODE_MAX) {
+ rtn = -DCAM_RTN_CAP_IF_MODE_ERR;
+ } else {
+ if (sn_mode >= DCAM_CAP_MODE_MAX) {
+ rtn = -DCAM_RTN_CAP_SENSOR_MODE_ERR;
+ } else {
+ _dcam_internal_init();
+ _dcam_link_frm(0); /* set default base frame index as 0 */
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path0.buf_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path1.buf_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path2.buf_queue);
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ cap_desc->interface = if_mode;
+ cap_desc->input_format = sn_mode;
+ /*REG_OWR(DCAM_EB, BIT_13);//MM_EB*/
+ /*REG_OWR(DCAM_MATRIX_EB, BIT_10|BIT_5);*/
+ if (DCAM_CAP_IF_CSI2 == if_mode) {
+ /* REG_OWR(CSI2_DPHY_EB, MIPI_EB_BIT);*/
+ //ret = _dcam_mipi_clk_en();
+ dcam_glb_reg_owr(DCAM_CFG, BIT_9, DCAM_CFG_REG);
+ REG_MWR(CAP_MIPI_CTRL, BIT_2 | BIT_1, sn_mode << 1);
+ } else {
+ /*REG_OWR(DCAM_EB, CCIR_IN_EB_BIT);
+ REG_OWR(DCAM_EB, CCIR_EB_BIT);*/
+ //ret = _dcam_ccir_clk_en();
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ REG_MWR(CAP_CCIR_CTRL, BIT_2 | BIT_1, sn_mode << 1);
+ }
+ rtn = DCAM_RTN_SUCCESS;
+ }
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_module_deinit(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ if (DCAM_CAP_IF_CSI2 == if_mode) {
+ /*REG_MWR(CSI2_DPHY_EB, MIPI_EB_BIT, 0 << 10);*/
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ //_dcam_mipi_clk_dis();
+ } else {
+ /*REG_MWR(DCAM_EB, CCIR_IN_EB_BIT, 0 << 2);
+ REG_MWR(DCAM_EB, CCIR_EB_BIT, 0 << 9);*/
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ //_dcam_ccir_clk_dis();
+ }
+
+ _dcam_internal_deinit();
+
+ return -rtn;
+}
+
+int dcam_scale_coeff_alloc(void)
+{
+ int ret = 0;
+
+ if (NULL == s_dcam_sc_array) {
+ s_dcam_sc_array = (struct dcam_sc_array*)vzalloc(sizeof(struct dcam_sc_array));
+ if (NULL == s_dcam_sc_array) {
+ printk("DCAM: _dcam_scale_coeff_alloc fail.\n");
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+void dcam_scale_coeff_free(void)
+{
+ if (s_dcam_sc_array) {
+ vfree(s_dcam_sc_array);
+ s_dcam_sc_array = NULL;
+ }
+}
+
+LOCAL uint32_t *dcam_get_scale_coeff_addr(uint32_t *index)
+{
+ uint32_t i;
+
+ if (DCAM_ADDR_INVALID(s_dcam_sc_array)) {
+ printk("DCAM: scale addr, invalid param %p \n", s_dcam_sc_array);
+ return NULL;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_BUF_COUNT; i++) {
+ if (0 == s_dcam_sc_array->scaling_coeff[i].flag) {
+ *index = i;
+ DCAM_TRACE("dcam: get buf index %d \n", i);
+ return s_dcam_sc_array->scaling_coeff[i].buf;
+ }
+ }
+ printk("dcam: get buf index %d \n", i);
+
+ return NULL;
+}
+
+int32_t dcam_module_en(struct device_node *dn)
+{
+ int ret = 0;
+ unsigned int irq_no = 0;
+
+ DCAM_TRACE("DCAM: dcam_module_en, In %d \n", s_dcam_users.counter);
+
+ mutex_lock(&dcam_module_sema);
+ if (atomic_inc_return(&s_dcam_users) == 1) {
+
+ wake_lock_init(&dcam_wakelock, WAKE_LOCK_SUSPEND,
+ "pm_message_wakelock_dcam");
+
+ wake_lock(&dcam_wakelock);
+
+ ret = clk_mm_i_eb(dn,1);
+ if (ret) {
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+
+ ret = dcam_set_clk(dn,DCAM_CLK_312M);
+ if (ret) {
+ clk_mm_i_eb(dn,0);
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+ //parse_baseaddress(dn);
+
+ dcam_reset(DCAM_RST_ALL, 0);
+ atomic_set(&s_resize_flag, 0);
+ atomic_set(&s_rotation_flag, 0);
+ memset((void*)s_user_func, 0, sizeof(s_user_func));
+ memset((void*)s_user_data, 0, sizeof(s_user_data));
+ printk("DCAM: register isr, 0x%x \n", REG_RD(DCAM_INT_MASK));
+
+ irq_no = parse_irq(dn);
+ printk("DCAM: irq_no = 0x%x \n", irq_no);
+ ret = request_irq(irq_no,
+ _dcam_isr_root,
+ IRQF_SHARED,
+ "DCAM",
+ (void*)&s_dcam_irq);
+ if (ret) {
+ printk("DCAM: dcam_start, error %d \n", ret);
+ dcam_set_clk(dn,DCAM_CLK_NONE);
+ clk_mm_i_eb(dn,0);
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+
+ DCAM_TRACE("DCAM: dcam_module_en end \n");
+ }
+ DCAM_TRACE("DCAM: dcam_module_en, Out %d \n", s_dcam_users.counter);
+ mutex_unlock(&dcam_module_sema);
+ return 0;
+
+fail_exit:
+ wake_unlock(&dcam_wakelock);
+ wake_lock_destroy(&dcam_wakelock);
+ atomic_dec(&s_dcam_users);
+ mutex_unlock(&dcam_module_sema);
+ return ret;
+}
+
+int32_t dcam_module_dis(struct device_node *dn)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ int ret = 0;
+ unsigned int irq_no = 0;
+
+ DCAM_TRACE("DCAM: dcam_module_dis, In %d \n", s_dcam_users.counter);
+
+ mutex_lock(&dcam_module_sema);
+ if (atomic_dec_return(&s_dcam_users) == 0) {
+
+ sci_glb_clr(DCAM_EB, DCAM_EB_BIT);
+ dcam_set_clk(dn,DCAM_CLK_NONE);
+ printk("DCAM: un register isr \n");
+ irq_no = parse_irq(dn);
+ free_irq(irq_no, (void*)&s_dcam_irq);
+ ret = clk_mm_i_eb(dn,0);
+ if (ret) {
+ rtn = -DCAM_RTN_MAX;
+ }
+ wake_unlock(&dcam_wakelock);
+ wake_lock_destroy(&dcam_wakelock);
+ }
+
+ DCAM_TRACE("DCAM: dcam_module_dis, Out %d \n", s_dcam_users.counter);
+ mutex_unlock(&dcam_module_sema);
+
+ return rtn;
+}
+
+int32_t dcam_reset(enum dcam_rst_mode reset_mode, uint32_t is_isr)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ uint32_t time_out = 0;
+
+ DCAM_TRACE("DCAM: reset: %d \n", reset_mode);
+ (void)is_isr;
+ printk("DCAM: reset: %d %d \n", reset_mode, is_isr);
+ if (DCAM_RST_ALL == reset_mode) {
+ /* then wait for AHB busy cleared */
+ while (++time_out < DCAM_AXI_STOP_TIMEOUT) {
+ if (0 == (REG_RD(DCAM_AHBM_STS) & BIT_0))
+ break;
+ }
+ if (time_out >= DCAM_AXI_STOP_TIMEOUT) {
+ printk("DCAM: reset TO: %d \n", time_out);
+ return DCAM_RTN_TIMEOUT;
+ }
+ }
+
+ /* do reset action */
+ switch (reset_mode) {
+ case DCAM_RST_PATH0:
+ sci_glb_set(DCAM_RST, PATH0_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH0_RST_BIT);
+ DCAM_TRACE("DCAM: reset path0 \n");
+ break;
+
+ case DCAM_RST_PATH1:
+ sci_glb_set(DCAM_RST, PATH1_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH1_RST_BIT);
+ DCAM_TRACE("DCAM: reset path1 \n");
+ break;
+
+ case DCAM_RST_PATH2:
+ sci_glb_set(DCAM_RST, PATH2_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH2_RST_BIT);
+ DCAM_TRACE("DCAM: reset path2 \n");
+ break;
+
+ case DCAM_RST_ALL:
+ sci_glb_set(DCAM_RST, DCAM_MOD_RST_BIT | CCIR_RST_BIT);
+ sci_glb_clr(DCAM_RST, DCAM_MOD_RST_BIT | CCIR_RST_BIT);
+ dcam_glb_reg_owr(DCAM_INT_CLR,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_CLR_REG);
+ dcam_glb_reg_owr(DCAM_INT_MASK,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_MASK_REG);
+ printk("DCAM: reset all \n");
+ break;
+ default:
+ rtn = DCAM_RTN_PARA_ERR;
+ break;
+ }
+
+ if (DCAM_RST_ALL == reset_mode) {
+ if (atomic_read(&s_dcam_users)) {
+ /* the end, enable AXI writing */
+ dcam_glb_reg_awr(DCAM_AHBM_STS, ~BIT_6, DCAM_AHBM_STS_REG);
+ }
+ }
+
+ DCAM_TRACE("DCAM: reset_mode=%x end \n", reset_mode);
+
+ return -rtn;
+}
+
+int32_t dcam_set_clk(struct device_node *dn, enum dcam_clk_sel clk_sel)
+{
+#ifdef CONFIG_SC_FPGA
+ return 0;
+#else
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct clk *clk_parent;
+ char *parent = "clk_312m";
+ int ret = 0;
+
+ switch (clk_sel) {
+ case DCAM_CLK_312M:
+ parent = "clk_312m";
+ break;
+ case DCAM_CLK_256M:
+ parent = "clk_256m";
+ break;
+ case DCAM_CLK_128M:
+ parent = "clk_128m";
+ break;
+ case DCAM_CLK_76M8:
+ parent = "clk_76p8m";
+ break;
+ case DCAM_CLK_NONE:
+ printk("DCAM close CLK %d \n", (int)clk_get_rate(s_dcam_clk));
+ if (s_dcam_clk) {
+ clk_disable(s_dcam_clk);
+ clk_put(s_dcam_clk);
+ s_dcam_clk = NULL;
+ }
+ return 0;
+ default:
+ parent = "clk_128m";
+ break;
+ }
+
+ if (NULL == s_dcam_clk) {
+ s_dcam_clk = parse_clk(dn,"clk_dcam");
+ if (IS_ERR(s_dcam_clk)) {
+ printk("DCAM: clk_get fail, %d \n", (int)s_dcam_clk);
+ return -1;
+ } else {
+ DCAM_TRACE("DCAM: get clk_parent ok \n");
+ }
+ } else {
+ clk_disable(s_dcam_clk);
+ }
+
+ clk_parent = clk_get(NULL, parent);
+ if (IS_ERR(clk_parent)) {
+ printk("DCAM: dcam_set_clk fail, %d \n", (int)clk_parent);
+ return -1;
+ } else {
+ DCAM_TRACE("DCAM: get clk_parent ok \n");
+ }
+
+ ret = clk_set_parent(s_dcam_clk, clk_parent);
+ if(ret){
+ printk("DCAM: clk_set_parent fail, %d \n", ret);
+ }
+
+ ret = clk_enable(s_dcam_clk);
+ if (ret) {
+ printk("enable dcam clk error.\n");
+ return -1;
+ }
+ return rtn;
+#endif
+}
+
+int32_t dcam_update_path(enum dcam_path_index path_index, struct dcam_size *in_size,
+ struct dcam_rect *in_rect, struct dcam_size *out_size)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flags;
+ uint32_t is_deci = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ rtn = dcam_path1_cfg(DCAM_PATH_INPUT_SIZE, in_size);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path1_cfg(DCAM_PATH_INPUT_RECT, in_rect);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path1_cfg(DCAM_PATH_OUTPUT_SIZE, out_size);
+ DCAM_RTN_IF_ERR;
+ rtn = _dcam_path_check_deci(DCAM_PATH_IDX_1, &is_deci);
+ DCAM_RTN_IF_ERR;
+ DCAM_TRACE("DCAM: To update path1 \n");
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_1);
+ DCAM_RTN_IF_ERR;
+ DCAM_TRACE("DCAM: dcam_update_path 1 \n");
+ if (s_dcam_sc_array->is_smooth_zoom) {
+ spin_lock_irqsave(&dcam_lock, flags);
+ s_p_dcam_mod->dcam_path1.is_update = 1;
+ spin_unlock_irqrestore(&dcam_lock, flags);
+ } else {
+ _dcam_wait_update_done(DCAM_PATH_IDX_1, &s_p_dcam_mod->dcam_path1.is_update);
+ }
+ if (!s_dcam_sc_array->is_smooth_zoom) {
+ _dcam_wait_update_done(DCAM_PATH_IDX_1, NULL);
+ }
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ local_irq_save(flags);
+ if (s_p_dcam_mod->dcam_path2.is_update) {
+ local_irq_restore(flags);
+ DCAM_TRACE("DCAM: dcam_update_path 2: updating return \n");
+ return rtn;
+ }
+ local_irq_restore(flags);
+
+ rtn = dcam_path2_cfg(DCAM_PATH_INPUT_SIZE, in_size);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path2_cfg(DCAM_PATH_INPUT_RECT, in_rect);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path2_cfg(DCAM_PATH_OUTPUT_SIZE, out_size);
+ DCAM_RTN_IF_ERR;
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_2);
+ DCAM_RTN_IF_ERR;
+
+ local_irq_save(flags);
+ s_p_dcam_mod->dcam_path2.is_update = 1;
+ local_irq_restore(flags);
+ }
+
+ DCAM_TRACE("DCAM: dcam_update_path: done \n");
+
+ return -rtn;
+}
+
+int32_t dcam_start_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ uint32_t cap_en = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: start_path: path %d, mode %x path 0,1,2 {%d %d %d} \n",
+ path_index,
+ s_p_dcam_mod->dcam_mode,
+ s_p_dcam_mod->dcam_path0.valide,
+ s_p_dcam_mod->dcam_path1.valide,
+ s_p_dcam_mod->dcam_path2.valide);
+
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_8, DCAM_AHBM_STS_REG); // aiden add: write arbit mode
+
+ cap_en = REG_RD(DCAM_CONTROL) & BIT_2;
+ DCAM_TRACE("DCAM: cap_eb %d \n", cap_en);
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ _dcam_path0_set();
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy(DCAM_PATH_IDX_0);
+#if 0
+ if (cap_en) {
+ /* if cap is already open, the sequence is:
+ cap force copy -> path 0 enable -> cap auto copy */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_0, 1 << 0, DCAM_CONTROL_REG); /* Cap force copy */
+ dcam_glb_reg_owr(DCAM_CFG, BIT_0, DCAM_CFG_REG); /* Enable Path 0 */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_1, 1 << 1, DCAM_CONTROL_REG); /* Cap auto copy, trigger path 0 enable */
+ } else {
+ dcam_glb_reg_owr(DCAM_CFG, BIT_0, DCAM_CFG_REG); /* Enable Path 0 */
+ }
+#endif
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+
+ //rtn = _dcam_path_trim(DCAM_PATH_IDX_1);
+ //DCAM_RTN_IF_ERR;
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_1);
+ DCAM_RTN_IF_ERR;
+
+ _dcam_path1_set(&s_p_dcam_mod->dcam_path1);
+ DCAM_TRACE("DCAM: start path: path_control=%x \n", REG_RD(DCAM_CONTROL));
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy_ext(DCAM_PATH_IDX_1, true, true);
+ DCAM_TRACE("DCAM: int= %x \n", REG_RD(DCAM_INT_STS));
+ dcam_glb_reg_owr(DCAM_CFG, BIT_1, DCAM_CFG_REG);
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_2);
+ DCAM_RTN_IF_ERR;
+
+ _dcam_path2_set();
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy_ext(DCAM_PATH_IDX_2, true, true);
+ }
+
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, false);
+ DCAM_RTN_IF_ERR;
+ _dcam_auto_copy(DCAM_PATH_IDX_0);
+ s_p_dcam_mod->dcam_path0.status = DCAM_ST_START;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_0, DCAM_CFG_REG); /* Enable Path 0 */
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ s_p_dcam_mod->dcam_path1.need_wait = 0;
+ s_p_dcam_mod->dcam_path1.status = DCAM_ST_START;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_1, DCAM_CFG_REG);
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ s_p_dcam_mod->dcam_path2.need_wait = 0;
+ s_p_dcam_mod->dcam_path2.status = DCAM_ST_START;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_2, DCAM_CFG_REG);
+ }
+
+ if (0 == cap_en) {
+#if 0 //def DCAM_DEBUG
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_5 | BIT_4, 0 << 4);
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_3|BIT_2|BIT_1|BIT_0, 0x07);
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_5 | BIT_4, 1 << 4);
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_3|BIT_2|BIT_1|BIT_0, 0x07);
+#endif
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_0, 1 << 0, DCAM_CONTROL_REG); /* Cap force copy */
+ //REG_MWR(DCAM_CONTROL, BIT_1, 1 << 1); /* Cap auto copy */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 1 << 2, DCAM_CONTROL_REG); /* Cap Enable */
+ }
+
+ if (DCAM_PATH_IDX_ALL != path_index) {
+ if ((DCAM_PATH_IDX_0 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_0, NULL);
+ } else if ((DCAM_PATH_IDX_1 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_1, NULL);
+ } else if ((DCAM_PATH_IDX_2 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_2, NULL);
+ }
+ }
+
+ printk("DCAM PATH S: %d \n", path_index);
+
+ _dcam_reg_trace();
+
+ DCAM_TRACE("DCAM: start_path E\n");
+ return -rtn;
+}
+
+int32_t dcam_start(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ int ret = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: dcam_start %x \n", s_p_dcam_mod->dcam_mode);
+
+ ret = dcam_start_path(DCAM_PATH_IDX_ALL);
+ //ret = dcam_start_path(DCAM_PATH_IDX_1);
+
+ return -rtn;
+}
+
+int32_t dcam_stop_cap(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ return -rtn;
+}
+
+int32_t _dcam_stop_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ spin_lock_irqsave(&dcam_lock, flag);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: stop path Wrong index 0x%x \n", path_index);
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ return -rtn;
+ }
+
+ _dcam_wait_for_quickstop(path_index);
+ p_path->status = DCAM_ST_STOP;
+ p_path->valide = 0;
+ _dcam_frm_clear(path_index);
+
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ return rtn;
+}
+
+int32_t dcam_stop_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ printk("DCAM: stop_path 0x%x \n", path_index);
+
+ if (path_index < DCAM_PATH_IDX_0 ||
+ path_index >= DCAM_PATH_IDX_ALL) {
+ printk("DCAM: error path_index \n");
+ return -rtn;
+ }
+
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_0, &s_p_dcam_mod->dcam_path0.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_0);
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_1, &s_p_dcam_mod->dcam_path1.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_1);
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ DCAM_TRACE("DCAM: stop path2 In \n");
+ _dcam_wait_path_done(DCAM_PATH_IDX_2, &s_p_dcam_mod->dcam_path2.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_2);
+ }
+
+ DCAM_TRACE("DCAM dcam_stop_path E: %d \n", path_index);
+
+ return -rtn;
+}
+
+LOCAL void _dcam_wait_for_channel_stop(enum dcam_path_index path_index)
+{
+ int time_out = 5000;
+ uint32_t ret = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ /* wait for AHB path busy cleared */
+ while (time_out) {
+ if (s_p_dcam_mod->dcam_path1.valide && (DCAM_PATH_IDX_1 & path_index)) {
+ ret = REG_RD(DCAM_AHBM_STS) & BIT_17;
+ } else if (s_p_dcam_mod->dcam_path2.valide && (DCAM_PATH_IDX_2 & path_index)) {
+ ret = REG_RD(DCAM_AHBM_STS) & BIT_18;
+ } else {
+ /*nothing*/
+ }
+ if (!ret) {
+ break;
+ }
+ time_out --;
+ }
+
+ DCAM_TRACE("DCAM: wait channel stop %d %d \n", ret, time_out);
+
+ return;
+}
+
+LOCAL void _dcam_quickstop_set(enum dcam_path_index path_index, uint32_t path_rst, uint32_t path_bit,
+ uint32_t cfg_bit, uint32_t ahbm_bit, uint32_t auto_copy_bit)
+{
+ dcam_glb_reg_owr(DCAM_AHBM_STS, ahbm_bit, DCAM_AHBM_STS_REG);
+ udelay(1000);
+ dcam_glb_reg_mwr(DCAM_CFG, cfg_bit, ~cfg_bit, DCAM_CFG_REG);
+ _dcam_wait_for_channel_stop(path_index);
+ _dcam_force_copy(path_index);
+ dcam_reset(path_rst, 0);
+ dcam_glb_reg_awr(DCAM_AHBM_STS, ~ahbm_bit, DCAM_AHBM_STS_REG);
+
+ return;
+}
+
+#define DCAM_IRQ_MASK_PATH0 (0x0f|(0x03<<4)|(1<<12)|(1<<21)) //let other module continue
+#define DCAM_IRQ_MASK_PATH1 (0x0f|(0x03<<6)|(1<<16)|(1<<19)|(1<<22))
+#define DCAM_IRQ_MASK_PATH2 (0x0f|(0x03<<8)|(1<<17)|(1<<20)|(1<<23))
+
+LOCAL void _dcam_quickstop_set_all(enum dcam_path_index path_index, uint32_t path_bit, uint32_t cfg_bit, uint32_t ahbm_bit)
+{
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_3 | BIT_4 | BIT_5, DCAM_AHBM_STS_REG);
+ udelay(10);
+ dcam_glb_reg_awr(DCAM_CFG, ~(BIT_0 | BIT_1 | BIT_2), DCAM_CFG_REG);
+ dcam_glb_reg_owr(DCAM_CONTROL, BIT_10 | BIT_12, DCAM_CONTROL_REG);
+ dcam_glb_reg_awr(DCAM_CONTROL, ~(BIT_10 | BIT_12), DCAM_CONTROL_REG);
+ _dcam_wait_for_channel_stop(DCAM_PATH_IDX_1);
+ _dcam_wait_for_channel_stop(DCAM_PATH_IDX_2);
+
+ return;
+}
+
+LOCAL void _dcam_wait_for_quickstop(enum dcam_path_index path_index)
+{
+ int time_out = 5000;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: state before stop 0x%x\n", s_p_dcam_mod->state);
+
+ if (DCAM_PATH_IDX_ALL == path_index) {
+ _dcam_quickstop_set_all(0, 0, 0, 0);
+ } else {
+ if (s_p_dcam_mod->dcam_path0.valide && (DCAM_PATH_IDX_0 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_0, DCAM_RST_PATH0, DCAM_IRQ_MASK_PATH0, BIT_0, BIT_3, BIT_9);
+ }
+ if (s_p_dcam_mod->dcam_path1.valide && (DCAM_PATH_IDX_1 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_1, DCAM_RST_PATH1, DCAM_IRQ_MASK_PATH1, BIT_1, BIT_4, BIT_11);
+ }
+ if (s_p_dcam_mod->dcam_path2.valide && (DCAM_PATH_IDX_2 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_2, DCAM_RST_PATH2, DCAM_IRQ_MASK_PATH2, BIT_2, BIT_5, BIT_13);
+ }
+ }
+
+ DCAM_TRACE("DCAM: exit _dcam_wait_for_quickstop %d state: 0x%x \n ", time_out, s_p_dcam_mod->state);
+
+ return;
+}
+
+int32_t dcam_stop(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ s_p_dcam_mod->state |= DCAM_STATE_QUICKQUIT;
+ printk("DCAM dcam_stop In \n");
+ if (atomic_read(&s_resize_flag)) {
+ s_p_dcam_mod->wait_resize_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->resize_done_sema, DCAM_PATH_TIMEOUT);
+ }
+ if (atomic_read(&s_rotation_flag)) {
+ s_p_dcam_mod->wait_rotation_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->rotation_done_sema, DCAM_PATH_TIMEOUT);
+ }
+
+ mutex_lock(&dcam_scale_sema);
+ mutex_lock(&dcam_rot_sema);
+
+ spin_lock_irqsave(&dcam_lock, flag);
+
+ _dcam_wait_for_quickstop(DCAM_PATH_IDX_ALL);
+ s_p_dcam_mod->dcam_path0.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path0.valide = 0;
+ s_p_dcam_mod->dcam_path1.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path1.valide = 0;
+ s_p_dcam_mod->dcam_path2.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path2.valide = 0;
+ _dcam_frm_clear(DCAM_PATH_IDX_0);
+ _dcam_frm_clear(DCAM_PATH_IDX_1);
+ _dcam_frm_clear(DCAM_PATH_IDX_2);
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ dcam_reset(DCAM_RST_ALL, 0);
+ mutex_unlock(&dcam_rot_sema);
+ mutex_unlock(&dcam_scale_sema);
+
+ s_p_dcam_mod->state &= ~DCAM_STATE_QUICKQUIT;
+
+ DCAM_TRACE("DCAM: dcam_stop Out, s_resize_flag %d \n", atomic_read(&s_resize_flag));
+
+ return -rtn;
+}
+
+
+int32_t dcam_reg_isr(enum dcam_irq_id id, dcam_isr_func user_func, void* user_data)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ if(id >= DCAM_IRQ_NUMBER) {
+ rtn = DCAM_RTN_ISR_ID_ERR;
+ } else {
+ spin_lock_irqsave(&dcam_lock, flag);
+ s_user_func[id] = user_func;
+ s_user_data[id] = user_data;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ }
+ return -rtn;
+}
+
+int32_t dcam_cap_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ switch (id) {
+ case DCAM_CAP_SYNC_POL:
+ {
+ struct dcam_cap_sync_pol *sync_pol = (struct dcam_cap_sync_pol*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+
+ if (sync_pol->vsync_pol > 1 ||
+ sync_pol->hsync_pol > 1 ||
+ sync_pol->pclk_pol > 1) {
+ rtn = DCAM_RTN_CAP_SYNC_POL_ERR;
+ } else {
+ #ifndef CONFIG_SC_FPGA
+ sci_glb_set(DCAM_CCIR_PCLK_EB, CCIR_PCLK_EB_BIT);
+ #endif
+ REG_MWR(CAP_CCIR_CTRL, BIT_3, sync_pol->hsync_pol << 3);
+ REG_MWR(CAP_CCIR_CTRL, BIT_4, sync_pol->vsync_pol << 4);
+ //REG_MWR(CLK_DLY_CTRL, BIT_19, sync_pol->pclk_pol << 19); // aiden todo
+
+ if (sync_pol->pclk_src == 0x00) {
+ #ifndef CONFIG_SC_FPGA
+ sci_glb_clr(CAP_CCIR_PLCK_SRC, (BIT_25 | BIT_26));
+ #endif
+ DCAM_TRACE("DCAM: set pclk src0\n");
+ } else if (sync_pol->pclk_src == 0x01) {
+ #ifndef CONFIG_SC_FPGA
+ sci_glb_clr(CAP_CCIR_PLCK_SRC, (BIT_25 | BIT_26));
+ sci_glb_set(CAP_CCIR_PLCK_SRC, (BIT_25));
+ #endif
+ DCAM_TRACE("DCAM: set pclk src1\n");
+ } else {
+ DCAM_TRACE("DCAM: set pclk src default\n");
+ }
+ }
+ } else {
+ if (sync_pol->need_href) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_5, 1 << 5);
+ } else {
+ REG_MWR(CAP_MIPI_CTRL, BIT_5, 0 << 5);
+ }
+ }
+ break;
+ }
+
+ case DCAM_CAP_DATA_BITS:
+ {
+ enum dcam_cap_data_bits bits = *(enum dcam_cap_data_bits*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ if (DCAM_CAP_8_BITS == bits || DCAM_CAP_10_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 0 << 9);
+ } else if (DCAM_CAP_4_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 1 << 9);
+ } else if (DCAM_CAP_2_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 2 << 9);
+ } else if (DCAM_CAP_1_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 3 << 9);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_BITS_ERR;
+ }
+
+ } else {
+ if (DCAM_CAP_12_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 2 << 3);
+ } else if (DCAM_CAP_10_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 1 << 3);
+ } else if (DCAM_CAP_8_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 0 << 3);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_BITS_ERR;
+ }
+ }
+ break;
+ }
+
+ case DCAM_CAP_YUV_TYPE:
+ {
+ enum dcam_cap_pattern pat = *(enum dcam_cap_pattern*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (pat < DCAM_PATTERN_MAX) {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_CTRL, BIT_8 | BIT_7, pat << 7);
+ else
+ REG_MWR(CAP_MIPI_CTRL, BIT_8 | BIT_7, pat << 7);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_YUV_ERR;
+ }
+ break;
+ }
+
+ case DCAM_CAP_PRE_SKIP_CNT:
+ {
+ uint32_t skip_num = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (skip_num > DCAM_CAP_SKIP_FRM_MAX) {
+ rtn = DCAM_RTN_CAP_SKIP_FRAME_ERR;
+ } else {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_3 | BIT_2 | BIT_1 | BIT_0, skip_num);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_3 | BIT_2 | BIT_1 | BIT_0, skip_num);
+ }
+ break;
+ }
+
+ case DCAM_CAP_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor < DCAM_FRM_DECI_FAC_MAX) {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_5 | BIT_4, deci_factor << 4);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_5 | BIT_4, deci_factor << 4);
+ } else {
+ rtn = DCAM_RTN_CAP_FRAME_DECI_ERR;
+ }
+ break;
+ }
+
+ case DCAM_CAP_FRM_COUNT_CLR:
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_22, 1 << 22);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_22, 1 << 22);
+ break;
+
+ case DCAM_CAP_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+ uint32_t tmp = 0;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+#if 0
+ if (rect->x > DCAM_CAP_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_CAP_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_CAP_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_CAP_FRAME_HEIGHT_MAX ) {
+ rtn = DCAM_RTN_CAP_FRAME_SIZE_ERR;
+ return -rtn;
+ }
+#endif
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ tmp = rect->x | (rect->y << 16);
+ REG_WR(CAP_CCIR_START, tmp);
+ tmp = (rect->x + rect->w - 1);
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_CCIR_END, tmp);
+ } else {
+ tmp = (rect->x << 1) | (rect->y << 16);
+ REG_WR(CAP_CCIR_START, tmp);
+ tmp = ((rect->x + rect->w) << 1) - 1;
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_CCIR_END, tmp);
+ }
+ } else {
+ tmp = rect->x | (rect->y << 16);
+ REG_WR(CAP_MIPI_START, tmp);
+ tmp = (rect->x + rect->w - 1);
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_MIPI_END, tmp);
+ }
+ break;
+ }
+
+ case DCAM_CAP_IMAGE_XY_DECI:
+ {
+ struct dcam_cap_dec *cap_dec = (struct dcam_cap_dec*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (cap_dec->x_factor > DCAM_CAP_X_DECI_FAC_MAX ||
+ cap_dec->y_factor > DCAM_CAP_Y_DECI_FAC_MAX ) {
+ rtn = DCAM_RTN_CAP_XY_DECI_ERR;
+ } else {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ if (cap_dec->x_factor > 1 ||
+ cap_dec->y_factor > 1) {
+ rtn = DCAM_RTN_CAP_XY_DECI_ERR;
+ }
+ }
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ REG_MWR(CAP_CCIR_IMG_DECI, BIT_1 | BIT_0, cap_dec->x_factor);
+ REG_MWR(CAP_CCIR_IMG_DECI, BIT_3 | BIT_2, cap_dec->y_factor << 2);
+ } else {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ // REG_MWR(CAP_MIPI_IMG_DECI, BIT_0, cap_dec->x_factor); // for camera path
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_1, cap_dec->x_factor << 1);//for ISP
+ } else {
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_1 | BIT_0, cap_dec->x_factor);
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_3 | BIT_2, cap_dec->y_factor << 2);
+ }
+ }
+ }
+
+ break;
+ }
+
+ case DCAM_CAP_JPEG_SET_BUF_LEN:
+ {
+ uint32_t jpg_buf_size = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ jpg_buf_size = jpg_buf_size/DCAM_JPG_BUF_UNIT;
+ if (jpg_buf_size >= DCAM_JPG_UNITS) {
+ rtn = DCAM_RTN_CAP_JPEG_BUF_LEN_ERR;
+ } else {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_WR(CAP_CCIR_JPG_CTRL,jpg_buf_size);
+ else
+ REG_WR(CAP_MIPI_JPG_CTRL,jpg_buf_size);
+ }
+ break;
+ }
+
+ case DCAM_CAP_TO_ISP:
+ {
+ uint32_t need_isp = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (need_isp) {
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_7, 1 << 7, DCAM_CFG_REG);
+ } else {
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_7, 0 << 7, DCAM_CFG_REG);
+ }
+ break;
+ }
+
+ case DCAM_CAP_DATA_PACKET:
+ {
+ uint32_t is_loose = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface &&
+ DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ if (is_loose) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_0, 1);
+ } else {
+ REG_MWR(CAP_MIPI_CTRL, BIT_0, 0);
+ }
+ } else {
+ rtn = DCAM_RTN_MODE_ERR;
+ }
+
+ break;
+ }
+
+ case DCAM_CAP_SAMPLE_MODE:
+ {
+ enum dcam_capture_mode samp_mode = *(enum dcam_capture_mode*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (samp_mode >= DCAM_CAPTURE_MODE_MAX) {
+ rtn = DCAM_RTN_MODE_ERR;
+ } else {
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_6, samp_mode << 6);
+ } else {
+ REG_MWR(CAP_CCIR_CTRL, BIT_6, samp_mode << 6);
+ }
+ s_p_dcam_mod->dcam_mode = samp_mode;
+ }
+ break;
+ }
+
+ case DCAM_CAP_ZOOM_MODE:
+ {
+ uint32_t zoom_mode = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ s_dcam_sc_array->is_smooth_zoom = zoom_mode;
+ break;
+ }
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_cap_get_info(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ switch(id) {
+ case DCAM_CAP_FRM_COUNT_GET:
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ *(uint32_t*)param = REG_RD(CAP_MIPI_FRM_CTRL) >> 16;
+ } else {
+ *(uint32_t*)param = REG_RD(CAP_CCIR_FRM_CTRL) >> 16;
+ }
+ break;
+
+ case DCAM_CAP_JPEG_GET_LENGTH:
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ *(uint32_t*)param = REG_RD(CAP_MIPI_FRM_SIZE);
+ } else {
+ *(uint32_t*)param = REG_RD(CAP_CCIR_FRM_SIZE);
+ }
+ break;
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+ }
+ return -rtn;
+}
+
+int32_t dcam_path0_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH0_INPUT_SIZE {%d %d} \n", size->w, size->h);
+#if 0
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else
+#endif
+ {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH0_INPUT_RECT {%d %d %d %d} \n",
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+
+ //if (rect->x > DCAM_PATH_FRAME_WIDTH_MAX ||
+ //rect->y > DCAM_PATH_FRAME_HEIGHT_MAX ||
+ //rect->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ //rect->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ // rtn = DCAM_RTN_PATH_TRIM_SIZE_ERR;
+ //} else {
+ memcpy((void*)&path->input_rect,
+ (void*)rect,
+ sizeof(struct dcam_rect));
+ //if (path->input_rect.h >= DCAM_HEIGHT_MIN) {
+ // path->input_rect.h--;
+ //}
+ /* path0 output size is different with other paths */
+ path->output_size.w = rect->w;
+ path->output_size.h = rect->h;
+ path->valid_param.input_rect = 1;
+ //}
+ break;
+ }
+
+ case DCAM_PATH_SRC_SEL:
+ {
+ uint32_t src_sel = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (src_sel >= DCAM_PATH_FROM_NONE) {
+ rtn = DCAM_RTN_PATH_SRC_ERR;
+ } else {
+ path->src_sel = src_sel;
+ path->valid_param.src_sel = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_output_mode format = *(enum dcam_output_mode*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if((DCAM_OUTPUT_WORD != format) &&
+ (DCAM_OUTPUT_HALF_WORD != format) &&
+ (DCAM_OUTPUT_YVYU_1FRAME != format) &&
+ (DCAM_OUTPUT_YUV420 != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->output_format = format;
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path0.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path0.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_0_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH0;
+ frame.fid = s_p_dcam_mod->dcam_path0.frame_base_id;
+ DCAM_TRACE("DCAM: Path 0 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path0.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path0_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->data_endian.uv_endian = endian->uv_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ path->valide = *(uint32_t*)param;
+ break;
+ }
+
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_path1_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path1;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_INPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_INPUT_RECT {%d %d %d %d} \n",
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+
+ if (rect->x > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_PATH_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_TRIM_SIZE_ERR;
+ } else {
+ memcpy((void*)&path->input_rect,
+ (void*)rect,
+ sizeof(struct dcam_rect));
+ //if (path->input_rect.h >= DCAM_HEIGHT_MIN) {
+ // path->input_rect.h--;
+ //}
+ path->valid_param.input_rect = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_OUTPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->output_size.w = size->w;
+ path->output_size.h = size->h;
+ path->valid_param.output_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_fmt format = *(enum dcam_fmt*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ path->output_format = format;
+
+ if((DCAM_YUV422 != format) &&
+ (DCAM_YUV420 != format) &&
+ (DCAM_YUV420_3FRAME != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH1;
+ frame.fid = s_p_dcam_mod->dcam_path1.frame_base_id;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path1.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path1_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_SRC_SEL:
+ {
+ uint32_t src_sel = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (src_sel >= DCAM_PATH_FROM_NONE) {
+ rtn = DCAM_RTN_PATH_SRC_ERR;
+ } else {
+ path->src_sel = src_sel;
+ path->valid_param.src_sel = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path1.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->data_endian.uv_endian = endian->uv_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ path->valide = *(uint32_t*)param;
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path1.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_1_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_path2_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_INPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH2_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH2_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+
+ }
+ break;
+ }
+
+ case DCAM_PATH_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_INPUT_RECT {%d %d %d %d} \n",
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+
+ if (rect->x > DCAM_PATH2_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_PATH2_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_PATH2_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_PATH2_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_TRIM_SIZE_ERR;
+ } else {
+ memcpy((void*)&path->input_rect,
+ (void*)rect,
+ sizeof(struct dcam_rect));
+#if 0
+ if (path->input_rect.h >= DCAM_HEIGHT_MIN) {
+ path->input_rect.h--;
+ }
+#endif
+ path->valid_param.input_rect = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_OUTPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH2_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH2_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->output_size.w = size->w;
+ path->output_size.h = size->h;
+ path->valid_param.output_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_fmt format = *(enum dcam_fmt*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if((DCAM_YUV422 != format) &&
+ (DCAM_YUV420 != format) &&
+ (DCAM_YUV420_3FRAME != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->output_format = format;
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH2;
+ frame.fid = s_p_dcam_mod->dcam_path2.frame_base_id;
+ DCAM_TRACE("DCAM: Path 2 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path2.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path2_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_SRC_SEL:
+ {
+ uint32_t src_sel = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (src_sel >= DCAM_PATH_FROM_NONE) {
+ rtn = DCAM_RTN_PATH_SRC_ERR;
+ } else {
+ path->src_sel = src_sel;
+ path->valid_param.src_sel = 1;
+
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path2.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->data_endian.uv_endian = endian->uv_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ path->valide = *(uint32_t*)param;
+
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path2.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_2_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_get_resizer(uint32_t wait_opt)
+{
+ int32_t rtn = 0;
+
+ printk("resizer_get:%d\n",current->pid);
+
+
+ if( 0 == wait_opt) {
+ rtn = mutex_trylock(&dcam_sem) ? 0 : 1;
+ return rtn;
+ } else if (DCAM_WAIT_FOREVER == wait_opt){
+ mutex_lock(&dcam_sem);
+ return rtn;
+ } else {
+ return 0;//mutex_timeout(&dcam_sem, wait_opt);
+ }
+}
+
+int32_t dcam_rel_resizer(void)
+{
+ printk("resizer_put:%d\n",current->pid);
+ mutex_unlock(&dcam_sem);
+ return 0;
+}
+
+int32_t dcam_resize_start(void)
+{
+ atomic_inc(&s_resize_flag);
+ mutex_lock(&dcam_scale_sema);
+ return 0;
+}
+
+int32_t dcam_resize_end(void)
+{
+ unsigned long flag;
+
+ atomic_dec(&s_resize_flag);
+ mutex_unlock(&dcam_scale_sema);
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+ }
+
+ if (s_p_dcam_mod) {
+ if (s_p_dcam_mod->wait_resize_done) {
+ up(&s_p_dcam_mod->resize_done_sema);
+ s_p_dcam_mod->wait_resize_done = 0;
+ }
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+}
+
+int32_t dcam_rotation_start(void)
+{
+ atomic_inc(&s_rotation_flag);
+ mutex_lock(&dcam_rot_sema);
+ return 0;
+}
+
+int32_t dcam_rotation_end(void)
+{
+ unsigned long flag;
+
+ atomic_dec(&s_rotation_flag);
+ mutex_unlock(&dcam_rot_sema);
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+ }
+
+ if (s_p_dcam_mod) {
+ if (s_p_dcam_mod->wait_rotation_done) {
+ up(&s_p_dcam_mod->rotation_done_sema);
+ s_p_dcam_mod->wait_rotation_done = 0;
+ }
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+}
+
+void dcam_int_en(void)
+{
+ if (atomic_read(&s_dcam_users) == 1) {
+ enable_irq(DCAM_IRQ);
+ }
+}
+
+void dcam_int_dis(void)
+{
+ if (atomic_read(&s_dcam_users) == 1) {
+ disable_irq(DCAM_IRQ);
+ }
+}
+
+int32_t dcam_frame_is_locked(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (frame)
+ rtn = frame->lock == DCAM_FRM_LOCK_WRITE ? 1 : 0;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_frame_lock(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: lock %d \n", (uint32_t)(0xF&frame->fid));
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (likely(frame))
+ frame->lock = DCAM_FRM_LOCK_WRITE;
+ else
+ rtn = DCAM_RTN_PARA_ERR;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_frame_unlock(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: unlock %d \n", (uint32_t)(0xF&frame->fid));
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (likely(frame))
+ frame->lock = DCAM_FRM_UNLOCK;
+ else
+ rtn = DCAM_RTN_PARA_ERR;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_read_registers(uint32_t* reg_buf, uint32_t *buf_len)
+{
+ uint32_t *reg_addr = (uint32_t*)DCAM_BASE;
+
+ if (NULL == reg_buf || NULL == buf_len || 0 != (*buf_len % 4)) {
+ return -1;
+ }
+
+ if (atomic_read(&s_dcam_users) == 1) {
+ while (buf_len != 0 && (unsigned long)reg_addr < DCAM_END) {
+ *reg_buf++ = REG_RD(reg_addr);
+ reg_addr++;
+ *buf_len -= 4;
+ }
+ *buf_len = (unsigned long)reg_addr - DCAM_BASE;
+ }
+
+ return 0;
+}
+
+int32_t dcam_get_path_id(struct dcam_get_path_id *path_id, uint32_t *channel_id)
+{
+ int ret = DCAM_RTN_SUCCESS;
+
+ if (NULL == path_id || NULL == channel_id) {
+ return -1;
+ }
+
+ DCAM_TRACE("DCAM: fourcc 0x%x, w %d, h %d \n", path_id->fourcc, path_id->input_size.w, path_id->input_size.h);
+
+ if (path_id->need_isp_tool) {
+ *channel_id = DCAM_PATH0;
+ } else if (V4L2_PIX_FMT_GREY == path_id->fourcc && !path_id->is_path_work[DCAM_PATH0]) {
+ *channel_id = DCAM_PATH0;
+ } else if (V4L2_PIX_FMT_JPEG == path_id->fourcc && !path_id->is_path_work[DCAM_PATH0]) {
+ *channel_id = DCAM_PATH0;
+ /*} else if (path_id->output_size.w == path_id->input_size.w && path_id->output_size.h == path_id->input_size.h) {
+ *channel_id = DCAM_PATH0;*/
+ } else if (path_id->output_size.w <= DCAM_PATH1_LINE_BUF_LENGTH && !path_id->is_path_work[DCAM_PATH1]) {
+ *channel_id = DCAM_PATH1;
+ } else if (path_id->output_size.w <= DCAM_PATH2_LINE_BUF_LENGTH && !path_id->is_path_work[DCAM_PATH2]) {
+ *channel_id = DCAM_PATH2;
+ } else {
+ *channel_id = DCAM_PATH0;
+ }
+ printk("DCAM: path id %d \n", *channel_id);
+
+ return ret;
+}
+
+int32_t dcam_get_path_capability(struct dcam_path_capability *capacity)
+{
+ int ret = DCAM_RTN_SUCCESS;
+
+ if (NULL == capacity) {
+ return -1;
+ }
+
+ capacity->count = 3;
+ capacity->path_info[DCAM_PATH0].line_buf = 0;
+ capacity->path_info[DCAM_PATH0].support_yuv = 0;
+ capacity->path_info[DCAM_PATH0].support_raw = 1;
+ capacity->path_info[DCAM_PATH0].support_jpeg = 1;
+ capacity->path_info[DCAM_PATH0].support_scaling = 0;
+ capacity->path_info[DCAM_PATH0].support_trim = 0;
+ capacity->path_info[DCAM_PATH0].is_scaleing_path = 0;
+
+ capacity->path_info[DCAM_PATH1].line_buf = DCAM_PATH1_LINE_BUF_LENGTH;
+ capacity->path_info[DCAM_PATH1].support_yuv = 1;
+ capacity->path_info[DCAM_PATH1].support_raw = 0;
+ capacity->path_info[DCAM_PATH1].support_jpeg = 0;
+ capacity->path_info[DCAM_PATH1].support_scaling = 1;
+ capacity->path_info[DCAM_PATH1].support_trim = 1;
+ capacity->path_info[DCAM_PATH1].is_scaleing_path = 0;
+
+ capacity->path_info[DCAM_PATH2].line_buf = DCAM_PATH2_LINE_BUF_LENGTH;
+ capacity->path_info[DCAM_PATH2].support_yuv = 1;
+ capacity->path_info[DCAM_PATH2].support_raw = 0;
+ capacity->path_info[DCAM_PATH2].support_jpeg = 0;
+ capacity->path_info[DCAM_PATH2].support_scaling = 1;
+ capacity->path_info[DCAM_PATH2].support_trim = 1;
+ capacity->path_info[DCAM_PATH2].is_scaleing_path = 1;
+
+ return ret;
+}
+
+
+LOCAL irqreturn_t _dcam_isr_root(int irq, void *dev_id)
+{
+ uint32_t irq_line, status;
+ unsigned long flag;
+ int32_t i;
+
+ DCAM_TRACE("DCAM: ISR 0x%x \n", REG_RD(DCAM_INT_STS));
+ status = REG_RD(DCAM_INT_STS) & DCAM_IRQ_LINE_MASK;
+ if (unlikely(0 == status)) {
+ return IRQ_NONE;
+ }
+
+ irq_line = status;
+ if (unlikely(DCAM_IRQ_ERR_MASK & status)) {
+ if (_dcam_err_pre_proc()) {
+ return IRQ_NONE;
+ }
+ }
+
+ spin_lock_irqsave(&dcam_lock,flag);
+
+ //for (i = DCAM_IRQ_NUMBER - 1; i >= 0; i--) {
+ for (i = 0; i < DCAM_IRQ_NUMBER; i++) {
+ if (irq_line & (1 << (uint32_t)i)) {
+ if (isr_list[i]) {
+ isr_list[i]();
+ }
+ }
+ irq_line &= ~(uint32_t)(1 << (uint32_t)i); //clear the interrupt flag
+ if(!irq_line) //no interrupt source left
+ break;
+ }
+
+ REG_WR(DCAM_INT_CLR, status);
+ DCAM_TRACE("DCAM: status 0x%x, ISR 0x%x \n", status, REG_RD(DCAM_INT_STS));
+
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ return IRQ_HANDLED;
+}
+
+LOCAL void _dcam_path0_set(void)
+{
+ uint32_t reg_val = 0;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH0_SRC_SIZE, reg_val);
+ }
+
+ if (path->valid_param.input_rect) {
+ reg_val = path->input_rect.x | (path->input_rect.y << 16);
+ REG_WR(DCAM_PATH0_TRIM_START, reg_val);
+ reg_val = path->input_rect.w | (path->input_rect.h << 16);
+ REG_WR(DCAM_PATH0_TRIM_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path0 set: rect {%d %d %d %d} \n",
+ path->input_rect.x,
+ path->input_rect.y,
+ path->input_rect.w,
+ path->input_rect.h);
+ }
+
+ if (path->valid_param.src_sel) {
+ REG_MWR(DCAM_CFG, BIT_10 , path->src_sel << 10);
+ DCAM_TRACE("DCAM: path 0: src_sel=0x%x \n", path->src_sel);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_1 | BIT_0, path->frame_deci << 0);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_output_mode format = path->output_format;
+ REG_MWR(DCAM_PATH0_CFG, BIT_2 | BIT_3, format << 2);
+ DCAM_TRACE("DCAM: path 0: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_5 | BIT_4, path->data_endian.y_endian << 4, DCAM_ENDIAN_REG);
+ if (DCAM_ENDIAN_BIG == path->data_endian.y_endian) {
+ if (DCAM_ENDIAN_LITTLE == path->data_endian.uv_endian ||
+ DCAM_ENDIAN_HALFBIG == path->data_endian.uv_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_20, 1 << 20, DCAM_ENDIAN_REG);
+ } else {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_20, 0, DCAM_ENDIAN_REG);
+ }
+ } else if (DCAM_ENDIAN_LITTLE == path->data_endian.y_endian) {
+ if (DCAM_ENDIAN_BIG == path->data_endian.uv_endian ||
+ DCAM_ENDIAN_HALFBIG == path->data_endian.uv_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_20, 1 << 20, DCAM_ENDIAN_REG);
+ } else {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_20, 0, DCAM_ENDIAN_REG);
+ }
+ } else {
+ printk("DCAM DRV: endian, do nothing u %d, v %d \n",
+ path->data_endian.y_endian,
+ path->data_endian.uv_endian);
+ }
+
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM DRV: path 0: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+}
+
+LOCAL void _dcam_path1_set(struct dcam_path_desc *path)
+{
+ uint32_t reg_val = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ DCAM_CHECK_ZERO_VOID(path);
+
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH1_SRC_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: src {%d %d} \n",path->input_size.w, path->input_size.h);
+ }
+
+ if (path->valid_param.input_rect) {
+ reg_val = path->input_rect.x | (path->input_rect.y << 16);
+ REG_WR(DCAM_PATH1_TRIM_START, reg_val);
+ reg_val = path->input_rect.w | (path->input_rect.h << 16);
+ REG_WR(DCAM_PATH1_TRIM_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: rect {%d %d %d %d} \n",
+ path->input_rect.x,
+ path->input_rect.y,
+ path->input_rect.w,
+ path->input_rect.h);
+ }
+
+ if (path->valid_param.output_size) {
+ reg_val = path->output_size.w | (path->output_size.h << 16);
+ REG_WR(DCAM_PATH1_DST_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: dst {%d %d} \n",path->output_size.w, path->output_size.h);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_fmt format = path->output_format;
+ if (DCAM_YUV422 == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 0 << 6);
+ } else if (DCAM_YUV420 == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 1 << 6);
+ } else if (DCAM_YUV420_3FRAME == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 3 << 6);
+ } else {
+ DCAM_TRACE("DCAM: invalid path 1 output format %d \n", format);
+ }
+ DCAM_TRACE("DCAM: path 1: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.src_sel) {
+ REG_MWR(DCAM_CFG, BIT_12 | BIT_11, path->src_sel << 11);
+ DCAM_TRACE("DCAM: path 1: src_sel=0x%x \n", path->src_sel);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_7 | BIT_6, path->data_endian.y_endian << 6, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_9 | BIT_8, path->data_endian.uv_endian << 8, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM: path 1: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_24 | BIT_23, path->frame_deci << 23);
+ DCAM_TRACE("DCAM: path 1: frame_deci=0x%x \n", path->frame_deci);
+ }
+
+ if (path->valid_param.scale_tap) {
+ path->valid_param.scale_tap = 0;
+ REG_MWR(DCAM_PATH1_CFG, BIT_19 | BIT_18 | BIT_17 | BIT_16, (path->scale_tap.y_tap & 0x0F) << 16);
+ REG_MWR(DCAM_PATH1_CFG, BIT_15 | BIT_14 | BIT_13 | BIT_12 | BIT_11, (path->scale_tap.uv_tap & 0x1F) << 11);
+ DCAM_TRACE("DCAM: path 1: scale_tap, y=0x%x, uv=0x%x \n", path->scale_tap.y_tap, path->scale_tap.uv_tap);
+ }
+
+ if (path->valid_param.v_deci) {
+ path->valid_param.v_deci = 0;
+ REG_MWR(DCAM_PATH1_CFG, BIT_2, path->deci_val.deci_x_en << 2);
+ REG_MWR(DCAM_PATH1_CFG, BIT_1 | BIT_0, path->deci_val.deci_x);
+
+ REG_MWR(DCAM_PATH1_CFG, BIT_5, path->deci_val.deci_y_en << 5);
+ REG_MWR(DCAM_PATH1_CFG, BIT_4 | BIT_3, path->deci_val.deci_y << 3);
+ DCAM_TRACE("DCAM: path 1: deci, x_en=%d, x=%d, y_en=%d, y=%d \n",
+ path->deci_val.deci_x_en, path->deci_val.deci_x, path->deci_val.deci_y_en, path->deci_val.deci_y);
+ }
+}
+
+LOCAL void _dcam_path2_set(void)
+{
+ struct dcam_path_desc *path = NULL;
+ uint32_t reg_val = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH2_SRC_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: src {%d %d} \n",path->input_size.w, path->input_size.h);
+ }
+
+ if (path->valid_param.input_rect) {
+ reg_val = path->input_rect.x | (path->input_rect.y << 16);
+ REG_WR(DCAM_PATH2_TRIM_START, reg_val);
+ reg_val = path->input_rect.w | (path->input_rect.h << 16);
+ REG_WR(DCAM_PATH2_TRIM_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: rect {%d %d %d %d} \n",
+ path->input_rect.x,
+ path->input_rect.y,
+ path->input_rect.w,
+ path->input_rect.h);
+ }
+
+ if(path->valid_param.output_size){
+ reg_val = path->output_size.w | (path->output_size.h << 16);
+ REG_WR(DCAM_PATH2_DST_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: dst {%d %d} \n",path->output_size.w, path->output_size.h);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_fmt format = path->output_format;
+
+ // REG_MWR(DCAM_PATH2_CFG, BIT_8, 0 << 8); // aiden todo
+
+ if (DCAM_YUV422 == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 0 << 6);
+ } else if (DCAM_YUV420 == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 1 << 6);
+ } else if (DCAM_YUV420_3FRAME == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 3 << 6);
+ } else {
+ DCAM_TRACE("DCAM: invalid path 2 output format %d \n", format);
+ }
+ DCAM_TRACE("DCAM: path 2: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.src_sel) {
+ REG_MWR(DCAM_CFG, BIT_14 | BIT_13, path->src_sel << 13);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_11 | BIT_10, path->data_endian.y_endian << 10,DCAM_ENDIAN_REG );
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_13 | BIT_12, path->data_endian.uv_endian << 12, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM: path 2: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_24 | BIT_23, path->frame_deci << 23);
+ DCAM_TRACE("DCAM: path 2: frame_deci=0x%x \n", path->frame_deci);
+ }
+
+ if (path->valid_param.scale_tap) {
+ path->valid_param.scale_tap = 0;
+ REG_MWR(DCAM_PATH2_CFG, BIT_19 | BIT_18 | BIT_17 | BIT_16, (path->scale_tap.y_tap & 0x0F) << 16);
+ REG_MWR(DCAM_PATH2_CFG, BIT_15 | BIT_14 | BIT_13 | BIT_12 | BIT_11, (path->scale_tap.uv_tap & 0x1F) << 11);
+ DCAM_TRACE("DCAM: path 2: scale_tap, y=0x%x, uv=0x%x \n",
+ path->scale_tap.y_tap, path->scale_tap.uv_tap);
+ }
+
+ if (path->valid_param.v_deci) {
+ path->valid_param.v_deci = 0;
+ REG_MWR(DCAM_PATH2_CFG, BIT_2, path->deci_val.deci_x_en << 2);
+ REG_MWR(DCAM_PATH2_CFG, BIT_1 | BIT_0, path->deci_val.deci_x);
+
+ REG_MWR(DCAM_PATH2_CFG, BIT_5, path->deci_val.deci_y_en << 5);
+ REG_MWR(DCAM_PATH2_CFG, BIT_4 | BIT_3, path->deci_val.deci_y << 3);
+ DCAM_TRACE("DCAM: path 2: deci, x_en=%d, x=%d, y_en=%d, y=%d \n",
+ path->deci_val.deci_x_en, path->deci_val.deci_x, path->deci_val.deci_y_en, path->deci_val.deci_y);
+ }
+}
+
+LOCAL void _dcam_buf_queue_init(struct dcam_buf_queue *queue)
+{
+ if (DCAM_ADDR_INVALID(queue)) {
+ printk("DCAM: invalid heap %p \n", queue);
+ return;
+ }
+
+ memset((void*)queue, 0, sizeof(struct dcam_buf_queue));
+ queue->write = &queue->frame[0];
+ queue->read = &queue->frame[0];
+ spin_lock_init(&queue->lock);
+ return;
+}
+
+LOCAL int32_t _dcam_buf_queue_write(struct dcam_buf_queue *queue, struct dcam_frame *frame)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_frame *ori_frame;
+ unsigned long flag;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: enq, invalid param %p, %p \n",
+ queue,
+ frame);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&queue->lock, flag);
+ ori_frame = queue->write;
+ DCAM_TRACE("DCAM: _dcam_buf_queue_write \n");
+ *queue->write++ = *frame;
+ if (queue->write > &queue->frame[DCAM_FRM_CNT_MAX-1]) {
+ queue->write = &queue->frame[0];
+ }
+
+ if (queue->write == queue->read) {
+ queue->write = ori_frame;
+ printk("DCAM: warning, queue is full, cannot write 0x%lx \n", frame->yaddr);
+ }
+ spin_unlock_irqrestore(&queue->lock, flag);
+
+ DCAM_TRACE("DCAM: _dcam_buf_queue_write type %d \n", frame->type);
+ return ret;
+}
+
+LOCAL int32_t _dcam_buf_queue_read(struct dcam_buf_queue *queue, struct dcam_frame *frame)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: deq, invalid param %p, %p \n",
+ queue,
+ frame);
+ return -EINVAL;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_buf_queue_read \n");
+
+ spin_lock_irqsave(&queue->lock, flag);
+ if (queue->read != queue->write) {
+ *frame = *queue->read++;
+ if (queue->read > &queue->frame[DCAM_FRM_CNT_MAX-1]) {
+ queue->read = &queue->frame[0];
+ }
+ } else {
+ ret = EAGAIN;
+ }
+ spin_unlock_irqrestore(&queue->lock, flag);
+
+ DCAM_TRACE("DCAM: _dcam_buf_queue_read type %d \n", frame->type);
+ return ret;
+}
+
+LOCAL void _dcam_frm_queue_clear(struct dcam_frm_queue *queue)
+{
+ if (DCAM_ADDR_INVALID(queue)) {
+ printk("DCAM: invalid heap %p \n", queue);
+ return;
+ }
+
+ memset((void*)queue, 0, sizeof(struct dcam_frm_queue));
+ return;
+}
+
+LOCAL int32_t _dcam_frame_enqueue(struct dcam_frm_queue *queue, struct dcam_frame *frame)
+{
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: enq, invalid param %p, %p \n",
+ queue,
+ frame);
+ return -1;
+ }
+ if (queue->valid_cnt >= DCAM_FRM_QUEUE_LENGTH) {
+ printk("DCAM: q over flow \n");
+ return -1;
+ }
+ //queue->frm_array[queue->valid_cnt] = frame;
+ memcpy(&queue->frm_array[queue->valid_cnt], frame, sizeof(struct dcam_frame));
+ queue->valid_cnt ++;
+ DCAM_TRACE("DCAM: en queue, %d, %d, 0x%x, 0x%x \n",
+ (0xF & frame->fid),
+ queue->valid_cnt,
+ frame->yaddr,
+ frame->uaddr);
+ return 0;
+}
+
+LOCAL int32_t _dcam_frame_dequeue(struct dcam_frm_queue *queue, struct dcam_frame *frame)
+{
+ uint32_t i = 0;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: deq, invalid param %p, %p \n",
+ queue,
+ frame);
+ return -1;
+ }
+ if (queue->valid_cnt == 0) {
+ printk("DCAM: q under flow \n");
+ return -1;
+ }
+
+ //*frame = queue->frm_array[0];
+ memcpy(frame, &queue->frm_array[0], sizeof(struct dcam_frame));
+ queue->valid_cnt--;
+ for (i = 0; i < queue->valid_cnt; i++) {
+ //queue->frm_array[i] = queue->frm_array[i+1];
+ memcpy(&queue->frm_array[i], &queue->frm_array[i+1], sizeof(struct dcam_frame));
+ }
+ DCAM_TRACE("DCAM: de queue, %d, %d \n",
+ (0xF & (frame)->fid),
+ queue->valid_cnt);
+ return 0;
+}
+
+LOCAL void _dcam_frm_clear(enum dcam_path_index path_index)
+{
+ uint32_t i = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path0.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path0.buf_queue);
+ }
+
+ if (DCAM_PATH_IDX_1 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path1.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path1.buf_queue);
+ }
+
+ if (DCAM_PATH_IDX_2 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path2.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path2.buf_queue);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_frm_pop(enum dcam_path_index path_index)
+{
+ uint32_t i = 0;
+ struct dcam_frame *frame = NULL;
+ uint32_t *frame_count;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 & path_index) {
+ frame = &s_p_dcam_mod->path0_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path0.output_frame_count;
+ }
+ if (DCAM_PATH_IDX_1 & path_index) {
+ frame = &s_p_dcam_mod->path1_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path1.output_frame_count;
+ }
+ if (DCAM_PATH_IDX_2 & path_index) {
+ frame = &s_p_dcam_mod->path2_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path2.output_frame_count;
+ }
+ printk("DCAM: frame pop index %d frame_count %d addr 0x%x \n", path_index, *frame_count, frame->yaddr);
+ if (0 == *frame_count) {
+ return;
+ }
+
+ for (i = 0; i < *frame_count - 1; i++) {
+ memcpy(frame+i, frame+i+1, sizeof(struct dcam_frame));
+ }
+ (*frame_count)--;
+ //memset(frame+(*frame_count), 0, sizeof(struct dcam_frame));
+ (frame+(*frame_count))->yaddr = 0;
+ (frame+(*frame_count))->uaddr = 0;
+ (frame+(*frame_count))->vaddr = 0;
+
+ if (0 == *frame_count) {
+ //_dcam_wait_for_quickstop(path_index);
+ }
+ DCAM_TRACE("DCAM: frame pop done \n");
+
+ return;
+}
+
+
+LOCAL void _dcam_link_frm(uint32_t base_id)
+{
+/* uint32_t i = 0;
+ struct dcam_frame *path0_frame = NULL;
+ struct dcam_frame *path1_frame = NULL;
+ struct dcam_frame *path2_frame = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ path0_frame = &s_p_dcam_mod->path0_frame[0];
+ path1_frame = &s_p_dcam_mod->path1_frame[0];
+ path2_frame = &s_p_dcam_mod->path2_frame[0];
+ for (i = 0; i < DCAM_PATH_0_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path0_frame + i);
+ //(path0_frame+i)->next = path0_frame + (i + 1) % DCAM_PATH_0_FRM_CNT_MAX;
+ //(path0_frame+i)->prev = path0_frame + (i - 1 + DCAM_PATH_0_FRM_CNT_MAX) % DCAM_PATH_0_FRM_CNT_MAX;
+ (path0_frame+i)->fid = base_id + i;
+ }
+
+ for (i = 0; i < DCAM_PATH_1_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path1_frame + i);
+ //(path1_frame+i)->next = path1_frame + (i + 1) % DCAM_PATH_1_FRM_CNT_MAX;
+ //(path1_frame+i)->prev = path1_frame + (i - 1 + DCAM_PATH_1_FRM_CNT_MAX) % DCAM_PATH_1_FRM_CNT_MAX;
+ (path1_frame+i)->fid = base_id + i;
+ }
+
+ for (i = 0; i < DCAM_PATH_2_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path2_frame + i);
+ //(path2_frame+i)->next = path2_frame+(i + 1) % DCAM_PATH_2_FRM_CNT_MAX;
+ //(path2_frame+i)->prev = path2_frame+(i - 1 + DCAM_PATH_2_FRM_CNT_MAX) % DCAM_PATH_2_FRM_CNT_MAX;
+ (path2_frame+i)->fid = base_id + i;
+ }
+
+ //s_p_dcam_mod->dcam_path0.output_frame_head = path0_frame;
+ //s_p_dcam_mod->dcam_path1.output_frame_head = path1_frame;
+ //s_p_dcam_mod->dcam_path2.output_frame_head = path2_frame;
+ //s_p_dcam_mod->dcam_path0.output_frame_cur = path0_frame;
+ //s_p_dcam_mod->dcam_path1.output_frame_cur = path1_frame;
+ //s_p_dcam_mod->dcam_path2.output_frame_cur = path2_frame;
+*/
+ return;
+}
+
+LOCAL int32_t _dcam_path_set_next_frm(enum dcam_path_index path_index, uint32_t is_1st_frm)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_frame frame;
+ struct dcam_frame *reserved_frame = NULL;
+ struct dcam_frame *orig_frame = NULL;
+ struct dcam_path_desc *path = NULL;
+ unsigned long yuv_reg[3] = {0};
+ uint32_t path_max_frm_cnt;
+ uint32_t flag = 0;
+ struct dcam_frm_queue *p_heap = NULL;
+ struct dcam_buf_queue *p_buf_queue = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ reserved_frame = &s_p_dcam_mod->path0_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path0;
+ yuv_reg[0] = DCAM_FRM_ADDR0;
+ yuv_reg[1] = DCAM_FRM_ADDR12;
+ path_max_frm_cnt = DCAM_PATH_0_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path0.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path0.buf_queue;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ //frame = &s_p_dcam_mod->path1_frame[0];
+ reserved_frame = &s_p_dcam_mod->path1_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path1;
+ yuv_reg[0] = DCAM_FRM_ADDR1;
+ yuv_reg[1] = DCAM_FRM_ADDR2;
+ yuv_reg[2] = DCAM_FRM_ADDR3;
+ path_max_frm_cnt = DCAM_PATH_1_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path1.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path1.buf_queue;
+ } else /*if(DCAM_PATH_IDX_2 == path_index)*/ {
+ //frame = &s_p_dcam_mod->path2_frame[0];
+ reserved_frame = &s_p_dcam_mod->path2_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path2;
+ yuv_reg[0] = DCAM_FRM_ADDR4;
+ yuv_reg[1] = DCAM_FRM_ADDR5;
+ yuv_reg[2] = DCAM_FRM_ADDR6;
+ path_max_frm_cnt = DCAM_PATH_2_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path2.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path2.buf_queue;
+ }
+
+ if (0 != _dcam_buf_queue_read(p_buf_queue, &frame)) {
+ DCAM_TRACE("DCAM: No freed frame id %d \n", frame.fid);
+ memcpy(&frame, reserved_frame, sizeof(struct dcam_frame));
+ }
+
+ DCAM_TRACE("DCAM: next %d y 0x%x uv 0x%x \n", path->output_frame_count, frame.yaddr, frame.uaddr);
+ REG_WR(yuv_reg[0], frame.yaddr);
+ if ((DCAM_YUV400 > path->output_format) && (DCAM_PATH_IDX_0 != path_index)) {
+ REG_WR(yuv_reg[1], frame.uaddr);
+ if (DCAM_YUV420_3FRAME == path->output_format) {
+ REG_WR(yuv_reg[2], frame.vaddr);
+ }
+ }
+ dcam_frame_lock(&frame);
+ if (0 == _dcam_frame_enqueue(p_heap, &frame)) {
+ } else {
+ dcam_frame_unlock(&frame);
+ rtn = DCAM_RTN_PATH_FRAME_LOCKED;
+ }
+
+ return -rtn;
+}
+
+#if 0
+LOCAL int32_t _dcam_path_trim(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path;
+ uint32_t cfg_reg, ctrl_bit;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ ctrl_bit = 8;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ ctrl_bit = 1;
+ } else {
+ printk("DCAM: _dcam_path_trim invalid path_index=%d \n", path_index);
+ return -1;
+ }
+
+ if (path->input_size.w != path->input_rect.w ||
+ path->input_size.h != path->input_rect.h) {
+ /*REG_OWR(cfg_reg, 1 << ctrl_bit);*/
+ } else {
+ /*REG_MWR(cfg_reg, 1 << ctrl_bit, 0 << ctrl_bit);*/
+ }
+
+ return rtn;
+
+}
+#endif
+
+LOCAL int32_t _dcam_path_scaler(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ unsigned long cfg_reg = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index){
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ }
+
+ DCAM_CHECK_ZERO(path);
+ if (DCAM_RAWRGB == path->output_format ||
+ DCAM_JPEG == path->output_format) {
+ DCAM_TRACE("DCAM: _dcam_path_scaler out format is %d, no need scaler \n", path->output_format);
+ return DCAM_RTN_SUCCESS;
+ }
+
+ rtn = _dcam_calc_sc_size(path_index);
+ if (DCAM_RTN_SUCCESS != rtn) {
+ return rtn;
+ }
+
+ if (path->sc_input_size.w == path->output_size.w &&
+ path->sc_input_size.h == path->output_size.h &&
+ DCAM_YUV422 == path->output_format) {
+ REG_MWR(cfg_reg, BIT_20, 1 << 20);// bypass scaler if the output size equals input size for YUV422 format
+ } else {
+ REG_MWR(cfg_reg, BIT_20, 0 << 20);
+ if (s_dcam_sc_array->is_smooth_zoom
+ && DCAM_PATH_IDX_1 == path_index
+ && DCAM_ST_START == path->status) {
+ rtn = _dcam_calc_sc_coeff(path_index);
+ } else {
+ rtn = _dcam_set_sc_coeff(path_index);
+ }
+ }
+
+ return rtn;
+}
+
+LOCAL int32_t _dcam_path_check_deci(enum dcam_path_index path_index, uint32_t *is_deci)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ uint32_t w_deci = 0;
+ uint32_t h_deci = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ goto dcam_path_err;
+ }
+
+ if (path->input_rect.w > (path->output_size.w * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.h > (path->output_size.h * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.w * DCAM_SC_COEFF_UP_MAX < path->output_size.w ||
+ path->input_rect.h * DCAM_SC_COEFF_UP_MAX < path->output_size.h) {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ } else {
+ if (path->input_rect.w > path->output_size.w * DCAM_SC_COEFF_DOWN_MAX)
+ w_deci = 1;
+ if (path->input_rect.h > path->output_size.h * DCAM_SC_COEFF_DOWN_MAX)
+ h_deci = 1;
+
+ if(w_deci || h_deci)
+ *is_deci = 1;
+ else
+ *is_deci = 0;
+ }
+
+dcam_path_err:
+ DCAM_TRACE("DCAM: _dcam_path_check_deci: path_index=%d, is_deci=%d, rtn=%d \n", path_index, *is_deci, rtn);
+
+ return rtn;
+}
+
+LOCAL uint32_t _dcam_get_path_deci_factor(uint32_t src_size, uint32_t dst_size)
+{
+ uint32_t factor = 0;
+
+ if (0 == src_size || 0 == dst_size) {
+ return factor;
+ }
+
+ /* factor: 0 - 1/2, 1 - 1/4, 2 - 1/8, 3 - 1/16 */
+ for (factor = 0; factor < DCAM_PATH_DECI_FAC_MAX; factor ++) {
+ if (src_size < (uint32_t)(dst_size * (1 << (factor + 1)))) {
+ break;
+ }
+ }
+
+ return factor;
+}
+
+LOCAL int32_t _dcam_calc_sc_size(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ unsigned long cfg_reg = 0;
+ uint32_t tmp_dstsize = 0;
+ uint32_t align_size = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index){
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ }
+
+ DCAM_CHECK_ZERO(path);
+ if (path->input_rect.w > (path->output_size.w * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.h > (path->output_size.h * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.w * DCAM_SC_COEFF_UP_MAX < path->output_size.w ||
+ path->input_rect.h * DCAM_SC_COEFF_UP_MAX < path->output_size.h) {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ } else {
+ path->sc_input_size.w = path->input_rect.w;
+ path->sc_input_size.h = path->input_rect.h;
+ if (path->input_rect.w > path->output_size.w * DCAM_SC_COEFF_DOWN_MAX) {
+ tmp_dstsize = path->output_size.w * DCAM_SC_COEFF_DOWN_MAX;
+ path->deci_val.deci_x = _dcam_get_path_deci_factor(path->input_rect.w, tmp_dstsize);
+ path->deci_val.deci_x_en = 1;
+ path->valid_param.v_deci = 1;
+ align_size = (1 << (path->deci_val.deci_x+1))*DCAM_PIXEL_ALIGN_WIDTH;
+ path->input_rect.w = (path->input_rect.w) & ~(align_size-1);
+ path->input_rect.x = (path->input_rect.x) & ~(align_size-1);
+ path->sc_input_size.w = path->input_rect.w >> (path->deci_val.deci_x+1);
+ } else {
+ path->deci_val.deci_x = 0;
+ path->deci_val.deci_x_en = 0;
+ path->valid_param.v_deci = 1;
+ }
+
+ if (path->input_rect.h > path->output_size.h * DCAM_SC_COEFF_DOWN_MAX) {
+ tmp_dstsize = path->output_size.h * DCAM_SC_COEFF_DOWN_MAX;
+ path->deci_val.deci_y = _dcam_get_path_deci_factor(path->input_rect.h, tmp_dstsize);
+ path->deci_val.deci_y_en = 1;
+ path->valid_param.v_deci = 1;
+ align_size = (1 << (path->deci_val.deci_y+1))*DCAM_PIXEL_ALIGN_HEIGHT;
+ path->input_rect.h = (path->input_rect.h) & ~(align_size-1);
+ path->input_rect.y = (path->input_rect.y) & ~(align_size-1);
+ path->sc_input_size.h = path->input_rect.h >> (path->deci_val.deci_y+1);
+ } else {
+ path->deci_val.deci_y = 0;
+ path->deci_val.deci_y_en = 0;
+ path->valid_param.v_deci = 1;
+ }
+
+ }
+
+ DCAM_TRACE("DCAM: _dcam_calc_sc_size, path=%d, x_en=%d, deci_x=%d, y_en=%d, deci_y=%d \n",
+ path_index, path->deci_val.deci_x_en,
+ path->deci_val.deci_x, path->deci_val.deci_y_en,
+ path->deci_val.deci_y);
+
+ return -rtn;
+}
+
+LOCAL int32_t _dcam_set_sc_coeff(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *path = NULL;
+ uint32_t i = 0;
+ unsigned long h_coeff_addr = DCAM_BASE;
+ unsigned long v_coeff_addr = DCAM_BASE;
+ unsigned long v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ unsigned long ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ uint8_t y_tap = 0;
+ uint8_t uv_tap = 0;
+ uint32_t index = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_set_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ down(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ if (!(Dcam_GenScaleCoeff((int16_t)path->sc_input_size.w,
+ (int16_t)path->sc_input_size.h,
+ (int16_t)path->output_size.w,
+ (int16_t)path->output_size.h,
+ h_coeff,
+ v_coeff,
+ v_chroma_coeff,
+ scale2yuv420,
+ &y_tap,
+ &uv_tap,
+ tmp_buf + (DCAM_SC_COEFF_COEF_SIZE*3/4),
+ DCAM_SC_COEFF_TMP_SIZE))) {
+ printk("DCAM: _dcam_set_sc_coeff Dcam_GenScaleCoeff error! \n");
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ return -DCAM_RTN_PATH_GEN_COEFF_ERR;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_H_NUM; i++) {
+ REG_WR(h_coeff_addr, *h_coeff);
+ h_coeff_addr += 4;
+ h_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_NUM; i++) {
+ REG_WR(v_coeff_addr, *v_coeff);
+ v_coeff_addr += 4;
+ v_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_CHROMA_NUM; i++) {
+ REG_WR(v_chroma_coeff_addr, *v_chroma_coeff);
+ v_chroma_coeff_addr += 4;
+ v_chroma_coeff++;
+ }
+
+ path->scale_tap.y_tap = y_tap;
+ path->scale_tap.uv_tap = uv_tap;
+ path->valid_param.scale_tap = 1;
+
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ return DCAM_RTN_SUCCESS;
+}
+
+LOCAL void _dcam_force_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy)
+{
+ uint32_t reg_val = 0;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ if(path_copy)
+ reg_val |= BIT_10;
+ if(coef_copy)
+ reg_val |= BIT_14;
+
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ if(path_copy)
+ reg_val |= BIT_12;
+ if(coef_copy)
+ reg_val |= BIT_16;
+
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_force_copy_ext invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_auto_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy)
+{
+ uint32_t reg_val = 0;
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_9;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_11;
+ if (coef_copy)
+ reg_val |= BIT_15;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_13;
+ if (coef_copy)
+ reg_val |= BIT_17;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_auto_copy_ext invalid path index: %d \n", path_index);
+ }
+
+}
+
+LOCAL void _dcam_force_copy(enum dcam_path_index path_index)
+{
+ if (DCAM_PATH_IDX_0 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_0, 1 << 0, DCAM_CONTROL_REG); /* Cap force copy */
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_10, 1 << 10, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_12, 1 << 12, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_force_copy invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_auto_copy(enum dcam_path_index path_index)
+{
+ if (DCAM_PATH_IDX_0 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_9, 1 << 9, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_11, 1 << 11, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_13, 1 << 13, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_auto_copy invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_reg_trace(void)
+{
+#ifdef DCAM_DRV_DEBUG
+ unsigned long addr = 0;
+
+ printk("DCAM: Register list");
+ for (addr = DCAM_CFG; addr <= CAP_SENSOR_CTRL; addr += 16) {
+ printk("\n 0x%lx: 0x%x 0x%x 0x%x 0x%x",
+ addr,
+ REG_RD(addr),
+ REG_RD(addr + 4),
+ REG_RD(addr + 8),
+ REG_RD(addr + 12));
+ }
+
+ printk("\n");
+#endif
+}
+
+#if 0
+LOCAL void _dcam_sensor_sof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_SOF];
+ void *data = s_user_data[DCAM_SN_SOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _sn_sof \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+#endif
+
+LOCAL void _dcam_sensor_eof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_EOF];
+ void *data = s_user_data[DCAM_SN_EOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _sn_eof \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_cap_sof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_CAP_SOF];
+ void *data = s_user_data[DCAM_CAP_SOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _cap_sof \n");
+
+ _dcam_stopped_notice();
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_cap_eof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_CAP_EOF];
+ void *data = s_user_data[DCAM_CAP_EOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path0_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH0_DONE];
+ void *data = s_user_data[DCAM_PATH0_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ if (0 == path->valide) {
+ printk("DCAM: path0 not valid \n");
+ return;
+ }
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_0, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_0);
+ DCAM_TRACE("DCAM 0 \n");
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, false);
+ if (rtn) {
+ printk("DCAM: 0 w \n");
+ return;
+ }
+ _dcam_auto_copy(DCAM_PATH_IDX_0);
+
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path0_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path0_reserved_frame \n");
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path0_overflow(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH0_OV];
+ void *data = s_user_data[DCAM_PATH0_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path0_overflow \n");
+ path = &s_p_dcam_mod->dcam_path0;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_DONE];
+ void *data = s_user_data[DCAM_PATH1_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path1;
+ if (0 == path->valide) {
+ printk("DCAM: path1 not valid \n");
+ return;
+ }
+
+ DCAM_TRACE("DCAM: 1\n");
+
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_1, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_1);
+
+ if (path->sof_cnt < 1) {
+ printk("DCAM: path1 done cnt %d\n", path->sof_cnt);
+ path->need_wait = 0;
+ return;
+ }
+ path->sof_cnt = 0;
+
+ if (path->need_wait) {
+ path->need_wait = 0;
+ } else {
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path1_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ DCAM_TRACE("DCAM: path1 frame 0x%x, y uv, 0x%x 0x%x \n",
+ (int)&frame, frame.yaddr, frame.uaddr);
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path1_reserved_frame \n");
+ }
+ }
+ return;
+}
+
+LOCAL void _dcam_path1_overflow(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_OV];
+ void *data = s_user_data[DCAM_PATH1_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path1_overflow \n");
+ path = &s_p_dcam_mod->dcam_path1;
+ //frame = path->output_frame_cur->prev->prev;
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_sensor_line_err(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_LINE_ERR];
+ void *data = s_user_data[DCAM_SN_LINE_ERR];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _line_err \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_sensor_frame_err(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_FRAME_ERR];
+ void *data = s_user_data[DCAM_SN_FRAME_ERR];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _frame_err \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_jpeg_buf_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_JPEG_BUF_OV];
+ void *data = s_user_data[DCAM_JPEG_BUF_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _jpeg_overflow \n");
+ path = &s_p_dcam_mod->dcam_path0;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_DONE];
+ void *data = s_user_data[DCAM_PATH2_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ if (atomic_read(&s_resize_flag)) {
+ memset(&frame, 0, sizeof(struct dcam_frame));
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+
+ DCAM_TRACE("DCAM: 2, %d %d \n", path->need_stop, path->need_wait);
+ if (path->status == DCAM_ST_START) {
+
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_2, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_2);
+
+ if (path->sof_cnt < 1) {
+ printk("DCAM: path2 done cnt %d\n", path->sof_cnt);
+ path->need_wait = 0;
+ return;
+ }
+ path->sof_cnt = 0;
+
+ if (path->need_wait) {
+ path->need_wait = 0;
+ } else {
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path2_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ DCAM_TRACE("DCAM: path2 frame 0x%x, y uv, 0x%x 0x%x \n",
+ (int)&frame, frame.yaddr, frame.uaddr);
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path2_reserved_frame \n");
+ }
+ }
+ }
+ }
+}
+
+LOCAL void _dcam_path2_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_OV];
+ void *data = s_user_data[DCAM_PATH2_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path2_overflow \n");
+ path = &s_p_dcam_mod->dcam_path2;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path2_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_isp_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_ISP_OV];
+ void *data = s_user_data[DCAM_ISP_OV];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _isp_overflow \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_mipi_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_MIPI_OV];
+ void *data = s_user_data[DCAM_MIPI_OV];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ printk("DCAM: _mipi_overflow \n");
+ return;
+}
+
+LOCAL void _dcam_rot_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_ROT_DONE];
+ void *data = s_user_data[DCAM_ROT_DONE];
+
+ DCAM_TRACE("DCAM: rot_done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_SLICE_DONE];
+ void *data = s_user_data[DCAM_PATH1_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 1 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_SLICE_DONE];
+ void *data = s_user_data[DCAM_PATH2_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 2 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_raw_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_RAW_SLICE_DONE];
+ void *data = s_user_data[DCAM_RAW_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 0 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_sof(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_SOF];
+ void *data = s_user_data[DCAM_PATH1_SOF];
+ struct dcam_path_desc *path;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_TRACE("DCAM: 1 sof done \n");
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ DCAM_CHECK_ZERO_VOID(s_dcam_sc_array);
+
+ if(s_p_dcam_mod->dcam_path1.status == DCAM_ST_START){
+
+ path = &s_p_dcam_mod->dcam_path1;
+ if (0 == path->valide) {
+ printk("DCAM: path1 not valid \n");
+ return;
+ }
+
+ if (path->sof_cnt > 0) {
+ printk("DCAM: path1 sof %d \n", path->sof_cnt);
+ return;
+ } else {
+ path->sof_cnt++;
+ }
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, false);
+ if (path->is_update) {
+ if (s_dcam_sc_array->is_smooth_zoom) {
+ _dcam_get_valid_sc_coeff(s_dcam_sc_array, &sc_coeff);
+ _dcam_write_sc_coeff(DCAM_PATH_IDX_1);
+ _dcam_path1_set(&sc_coeff->dcam_path1);
+ _dcam_pop_sc_buf(s_dcam_sc_array, &sc_coeff);
+ } else {
+ _dcam_path1_set(path);
+ }
+ path->is_update = 0;
+ DCAM_TRACE("DCAM: path1 updated \n");
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_1, true, true);
+ } else {
+ if (rtn) {
+ DCAM_TRACE("DCAM: path1 updated \n");
+ } else {
+ _dcam_auto_copy(DCAM_PATH_IDX_1);
+ }
+ }
+
+ _dcam_path_updated_notice(DCAM_PATH_IDX_1);
+
+ if (rtn) {
+ path->need_wait = 1;
+ printk("DCAM: 1 w\n");
+ return;
+ }
+ }
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_sof(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_SOF];
+ void *data = s_user_data[DCAM_PATH2_SOF];
+ struct dcam_path_desc *path;
+
+ DCAM_TRACE("DCAM: 2 sof done \n");
+
+ if (atomic_read(&s_resize_flag)) {
+ printk("DCAM: path 2 sof, review now \n");
+ } else {
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ return;
+ }
+
+ if(s_p_dcam_mod->dcam_path2.status == DCAM_ST_START){
+
+ path = &s_p_dcam_mod->dcam_path2;
+ if (0 == path->valide) {
+ printk("DCAM: path2 not valid \n");
+ return;
+ }
+
+ if (path->sof_cnt > 0) {
+ printk("DCAM: path2 sof %d \n", path->sof_cnt);
+ return;
+ } else {
+ path->sof_cnt++;
+ }
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, false);
+ if (path->is_update) {
+ _dcam_path2_set();
+ path->is_update = 0;
+ DCAM_TRACE("DCAM: path2 updated \n");
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_2, true, true);
+ } else {
+ if (rtn) {
+ DCAM_TRACE("DCAM: path2 updated \n");
+ } else {
+ _dcam_auto_copy(DCAM_PATH_IDX_2);
+ }
+ }
+
+ _dcam_path_updated_notice(DCAM_PATH_IDX_2);
+
+ if (rtn) {
+ path->need_wait = 1;
+ printk("DCAM:2 w \n");
+ return;
+ }
+ }
+ }
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL int32_t _dcam_err_pre_proc(void)
+{
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: state in err_pre_proc 0x%x,",s_p_dcam_mod->state);
+ if (s_p_dcam_mod->state & DCAM_STATE_QUICKQUIT)
+ return -1;
+
+ s_p_dcam_mod->err_happened = 1;
+ //printk("DCAM: err, 0x%x, ISP int 0x%x \n",
+ // REG_RD(DCAM_INT_STS),
+ // REG_RD(SPRD_ISP_BASE + 0x2080));
+ printk("DCAM: err, 0x%x \n",
+ REG_RD(DCAM_INT_STS));
+
+ _dcam_reg_trace();
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 0, DCAM_CONTROL_REG); /* Cap Disable */
+ _dcam_stopped();
+ if (0 == atomic_read(&s_resize_flag) &&
+ 0 == atomic_read(&s_rotation_flag)) {
+ dcam_reset(DCAM_RST_ALL, 1);
+ }
+ return 0;
+}
+
+LOCAL void _dcam_stopped(void)
+{
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: stopped, %d \n", s_p_dcam_mod->wait_stop);
+
+ _dcam_path_done_notice(DCAM_PATH_IDX_0);
+ _dcam_path_done_notice(DCAM_PATH_IDX_1);
+ _dcam_path_done_notice(DCAM_PATH_IDX_2);
+ _dcam_stopped_notice();
+ return;
+}
+
+LOCAL int _dcam_internal_init(void)
+{
+ int ret = 0;
+
+ s_p_dcam_mod = (struct dcam_module*)vzalloc(sizeof(struct dcam_module));
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ sema_init(&s_p_dcam_mod->stop_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path0.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path1.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path2.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path0.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path1.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path2.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->resize_done_sema, 0);
+ sema_init(&s_p_dcam_mod->rotation_done_sema, 0);
+ sema_init(&s_p_dcam_mod->scale_coeff_mem_sema, 1);
+
+ memset((void*)s_dcam_sc_array, 0, sizeof(struct dcam_sc_array));
+ return ret;
+}
+LOCAL void _dcam_internal_deinit(void)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ printk("DCAM: Invalid addr, %p", s_p_dcam_mod);
+ } else {
+ vfree(s_p_dcam_mod);
+ s_p_dcam_mod = NULL;
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return;
+}
+
+LOCAL void _dcam_wait_path_done(enum dcam_path_index path_index, uint32_t *p_flag)
+{
+ int ret = 0;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->err_happened) {
+ return;
+ }
+ if (DCAM_CAPTURE_MODE_SINGLE == s_p_dcam_mod->dcam_mode) {
+ return;
+ }
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done wait %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+
+ spin_lock_irqsave(&dcam_lock, flag);
+ if (p_flag) {
+ *p_flag = 1;
+ }
+ p_path->wait_for_done = 1;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ ret = down_timeout(&p_path->tx_done_sema, DCAM_PATH_TIMEOUT);
+ if (ret) {
+ _dcam_reg_trace();
+ printk("DCAM: Failed to wait path 0x%x done \n", path_index);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path_done_notice(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *p_path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done notice %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+ if (p_path->wait_for_done) {
+ up(&p_path->tx_done_sema);
+ p_path->wait_for_done = 0;
+ }
+
+ return;
+}
+
+LOCAL void _dcam_wait_update_done(enum dcam_path_index path_index, uint32_t *p_flag)
+{
+ int ret = 0;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->err_happened) {
+ return;
+ }
+ if (DCAM_CAPTURE_MODE_SINGLE == s_p_dcam_mod->dcam_mode) {
+ return;
+ }
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done wait %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+
+ spin_lock_irqsave(&dcam_lock, flag);
+ if (p_flag) {
+ *p_flag = 1;
+ }
+ p_path->wait_for_sof = 1;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ ret = down_timeout(&p_path->sof_sema, DCAM_PATH_TIMEOUT);
+ if (ret) {
+ _dcam_reg_trace();
+ printk("DCAM: Failed to wait update path 0x%x done \n", path_index);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path_updated_notice(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *p_path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done notice %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+ if (p_path->wait_for_sof) {
+ up(&p_path->sof_sema);
+ p_path->wait_for_sof = 0;
+ }
+
+ return;
+}
+
+
+LOCAL void _dcam_stopped_notice(void)
+{
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->wait_stop) {
+ up(&s_p_dcam_mod->stop_sema);
+ s_p_dcam_mod->wait_stop = 0;
+ }
+}
+
+void mm_clk_register_trace(void)
+{
+ uint32_t i = 0;
+ printk("REG_AON_APB_APB_EB0 = 0x%x \n",REG_RD(REG_AON_APB_APB_EB0));
+ printk("REG_PMU_APB_PD_MM_TOP_CFG = 0x%x \n",REG_RD(REG_PMU_APB_PD_MM_TOP_CFG));
+ printk("REG_PMU_APB_CP_SOFT_RST = 0x%x \n",REG_RD(REG_PMU_APB_CP_SOFT_RST));
+ if(!(REG_RD(REG_AON_APB_APB_EB0)&BIT_MM_EB) ) return ;
+ if(REG_RD(REG_PMU_APB_PD_MM_TOP_CFG)&BIT_PD_MM_TOP_FORCE_SHUTDOWN) return ;
+
+ printk("mm_clk_reg, part 1 \n");
+ for (i = 0 ; i <= 0x10; i += 4 ) {
+ printk("MMAHB: %lx val:%x \b\n",
+ (SPRD_MMAHB_BASE + i),
+ REG_RD(SPRD_MMAHB_BASE + i));
+ }
+
+ printk("mm_clk_reg, part 2 \n");
+ for (i = 0x20 ; i <= 0x38; i += 4 ) {
+ printk("MMCKG: %lx val:%x \b\n",
+ (SPRD_MMCKG_BASE + i),
+ REG_RD(SPRD_MMCKG_BASE + i));
+ }
+}
+
+int32_t dcam_stop_sc_coeff(void)
+{
+ uint32_t zoom_mode;
+
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ zoom_mode = s_dcam_sc_array->is_smooth_zoom;
+ /*memset((void*)s_dcam_sc_array, 0, sizeof(struct dcam_sc_array));*/
+ s_dcam_sc_array->is_smooth_zoom = zoom_mode;
+ s_dcam_sc_array->valid_cnt = 0;
+ memset(&s_dcam_sc_array->scaling_coeff_queue, 0, DCAM_SC_COEFF_BUF_COUNT*sizeof(struct dcam_sc_coeff *));
+
+ return 0;
+}
+
+LOCAL int32_t _dcam_get_valid_sc_coeff(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff)
+{
+ if (DCAM_ADDR_INVALID(sc) || DCAM_ADDR_INVALID(sc_coeff)) {
+ printk("DCAM: get valid sc, invalid param %p, %p \n",
+ sc,
+ sc_coeff);
+ return -1;
+ }
+ if (sc->valid_cnt == 0) {
+ printk("DCAM: valid cnt 0 \n");
+ return -1;
+ }
+
+ *sc_coeff = sc->scaling_coeff_queue[0];
+ DCAM_TRACE("DCAM: get valid sc, %d \n", sc->valid_cnt);
+ return 0;
+}
+
+
+LOCAL int32_t _dcam_push_sc_buf(struct dcam_sc_array *sc, uint32_t index)
+{
+ if (DCAM_ADDR_INVALID(sc)) {
+ printk("DCAM: push sc, invalid param %p \n", sc);
+ return -1;
+ }
+ if (sc->valid_cnt >= DCAM_SC_COEFF_BUF_COUNT) {
+ printk("DCAM: valid cnt %d \n", sc->valid_cnt);
+ return -1;
+ }
+
+ sc->scaling_coeff[index].flag = 1;
+ sc->scaling_coeff_queue[sc->valid_cnt] = &sc->scaling_coeff[index];
+ sc->valid_cnt ++;
+
+ DCAM_TRACE("DCAM: push sc, %d \n", sc->valid_cnt);
+
+ return 0;
+}
+
+LOCAL int32_t _dcam_pop_sc_buf(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff)
+{
+ uint32_t i = 0;
+
+ if (DCAM_ADDR_INVALID(sc) || DCAM_ADDR_INVALID(sc_coeff)) {
+ printk("DCAM: pop sc, invalid param %p, %p \n",
+ sc,
+ sc_coeff);
+ return -1;
+ }
+ if (sc->valid_cnt == 0) {
+ printk("DCAM: valid cnt 0 \n");
+ return -1;
+ }
+ sc->scaling_coeff_queue[0]->flag = 0;
+ *sc_coeff = sc->scaling_coeff_queue[0];
+ sc->valid_cnt--;
+ for (i = 0; i < sc->valid_cnt; i++) {
+ sc->scaling_coeff_queue[i] = sc->scaling_coeff_queue[i+1];
+ }
+ DCAM_TRACE("DCAM: pop sc, %d \n", sc->valid_cnt);
+ return 0;
+}
+
+LOCAL int32_t _dcam_write_sc_coeff(enum dcam_path_index path_index)
+{
+ int32_t ret = 0;
+ struct dcam_path_desc *path = NULL;
+ uint32_t i = 0;
+ unsigned long h_coeff_addr = DCAM_BASE;
+ unsigned long v_coeff_addr = DCAM_BASE;
+ unsigned long v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ unsigned long ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ ret = _dcam_get_valid_sc_coeff(s_dcam_sc_array, &sc_coeff);
+ if (ret) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+ tmp_buf = sc_coeff->buf;
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &sc_coeff->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_write_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+ for (i = 0; i < DCAM_SC_COEFF_H_NUM; i++) {
+ REG_WR(h_coeff_addr, *h_coeff);
+ h_coeff_addr += 4;
+ h_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_NUM; i++) {
+ REG_WR(v_coeff_addr, *v_coeff);
+ v_coeff_addr += 4;
+ v_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_CHROMA_NUM; i++) {
+ REG_WR(v_chroma_coeff_addr, *v_chroma_coeff);
+ v_chroma_coeff_addr += 4;
+ v_chroma_coeff++;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_write_sc_coeff E \n");
+
+ return ret;
+}
+
+LOCAL int32_t _dcam_calc_sc_coeff(enum dcam_path_index path_index)
+{
+ unsigned long flag;
+ struct dcam_path_desc *path = NULL;
+ unsigned long h_coeff_addr = DCAM_BASE;
+ unsigned long v_coeff_addr = DCAM_BASE;
+ unsigned long v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ unsigned long ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ uint8_t y_tap = 0;
+ uint8_t uv_tap = 0;
+ uint32_t index = 0;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_calc_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+ down(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ spin_lock_irqsave(&dcam_lock,flag);
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+ if (NULL == tmp_buf) {
+ _dcam_pop_sc_buf(s_dcam_sc_array, &sc_coeff);
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+ }
+ spin_unlock_irqrestore(&dcam_lock,flag);
+
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ if (!(Dcam_GenScaleCoeff((int16_t)path->sc_input_size.w,
+ (int16_t)path->sc_input_size.h,
+ (int16_t)path->output_size.w,
+ (int16_t)path->output_size.h,
+ h_coeff,
+ v_coeff,
+ v_chroma_coeff,
+ scale2yuv420,
+ &y_tap,
+ &uv_tap,
+ tmp_buf + (DCAM_SC_COEFF_COEF_SIZE*3/4),
+ DCAM_SC_COEFF_TMP_SIZE))) {
+ printk("DCAM: _dcam_calc_sc_coeff Dcam_GenScaleCoeff error! \n");
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ return -DCAM_RTN_PATH_GEN_COEFF_ERR;
+ }
+ path->scale_tap.y_tap = y_tap;
+ path->scale_tap.uv_tap = uv_tap;
+ path->valid_param.scale_tap = 1;
+ memcpy(&s_dcam_sc_array->scaling_coeff[index].dcam_path1, path, sizeof(struct dcam_path_desc));
+ spin_lock_irqsave(&dcam_lock,flag);
+ _dcam_push_sc_buf(s_dcam_sc_array, index);
+ spin_unlock_irqrestore(&dcam_lock,flag);
+
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ DCAM_TRACE("DCAM: _dcam_calc_sc_coeff E \n");
+
+ return DCAM_RTN_SUCCESS;
+}
diff --git a/drivers/media/sprd_dcam/sharkl/dcam_drv.h b/drivers/media/sprd_dcam/sharkl/dcam_drv.h
new file mode 100755
index 00000000..620b404e
--- /dev/null
+++ b/drivers/media/sprd_dcam/sharkl/dcam_drv.h
@@ -0,0 +1,445 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef _DCAM_DRV_8830_H_
+#define _DCAM_DRV_8830_H_
+
+#include <linux/types.h>
+#include "dcam_reg.h"
+#include "parse_hwinfo.h"
+
+//#define DCAM_DEBUG
+
+#ifdef DCAM_DEBUG
+ #define DCAM_TRACE printk
+#else
+ #define DCAM_TRACE pr_debug
+#endif
+
+#define DCAM_WAIT_FOREVER 0xFFFFFFFF
+#define DCAM_PATH_1_FRM_CNT_MAX 10
+#define DCAM_PATH_2_FRM_CNT_MAX 10/*4*/
+#define DCAM_PATH_0_FRM_CNT_MAX 10
+#define DCAM_FRM_CNT_MAX 10 /* max between path_1_frm_cnt and path_2_frm_cnt */
+#define DCAM_HEIGHT_MIN 4
+#define DCAM_JPEG_LENGTH_MIN 30720 /*640X480 div 10*/
+
+enum dcam_swtich_status {
+ DCAM_SWITCH_IDLE = 0,
+ DCAM_SWITCH_PAUSE,
+ DCAM_SWITCH_DONE,
+ DCAM_SWITCH_MAX
+};
+
+enum dcam_drv_rtn {
+ DCAM_RTN_SUCCESS = 0,
+ DCAM_RTN_PARA_ERR = 0x10,
+ DCAM_RTN_IO_ID_ERR,
+ DCAM_RTN_ISR_ID_ERR,
+ DCAM_RTN_MASTER_SEL_ERR,
+ DCAM_RTN_MODE_ERR,
+ DCAM_RTN_TIMEOUT,
+
+ DCAM_RTN_CAP_FRAME_SEL_ERR = 0x20,
+ DCAM_RTN_CAP_IN_FORMAT_ERR,
+ DCAM_RTN_CAP_IN_BITS_ERR,
+ DCAM_RTN_CAP_IN_YUV_ERR,
+ DCAM_RTN_CAP_SYNC_POL_ERR,
+ DCAM_RTN_CAP_SKIP_FRAME_ERR,
+ DCAM_RTN_CAP_FRAME_DECI_ERR,
+ DCAM_RTN_CAP_XY_DECI_ERR,
+ DCAM_RTN_CAP_FRAME_SIZE_ERR,
+ DCAM_RTN_CAP_SENSOR_MODE_ERR,
+ DCAM_RTN_CAP_JPEG_BUF_LEN_ERR,
+ DCAM_RTN_CAP_IF_MODE_ERR,
+
+ DCAM_RTN_PATH_SRC_SIZE_ERR = 0x30,
+ DCAM_RTN_PATH_TRIM_SIZE_ERR,
+ DCAM_RTN_PATH_DES_SIZE_ERR,
+ DCAM_RTN_PATH_IN_FMT_ERR,
+ DCAM_RTN_PATH_OUT_FMT_ERR,
+ DCAM_RTN_PATH_SC_ERR,
+ DCAM_RTN_PATH_SUB_SAMPLE_ERR,
+ DCAM_RTN_PATH_ADDR_ERR,
+ DCAM_RTN_PATH_FRAME_TOO_MANY,
+ DCAM_RTN_PATH_FRAME_LOCKED,
+ DCAM_RTN_PATH_NO_MEM,
+ DCAM_RTN_PATH_GEN_COEFF_ERR,
+ DCAM_RTN_PATH_SRC_ERR,
+ DCAM_RTN_PATH_ENDIAN_ERR,
+ DCAM_RTN_PATH_FRM_DECI_ERR,
+ DCAM_RTN_MAX
+};
+
+enum dcam_rst_mode {
+ DCAM_RST_ALL = 0,
+ DCAM_RST_PATH0,
+ DCAM_RST_PATH1,
+ DCAM_RST_PATH2
+};
+
+enum dcam_path_index {
+ DCAM_PATH_IDX_NONE = 0,
+ DCAM_PATH_IDX_0 = 1,
+ DCAM_PATH_IDX_1 = 2,
+ DCAM_PATH_IDX_2 = 4,
+ DCAM_PATH_IDX_ALL = 7,
+};
+
+
+enum dcam_fmt {
+ DCAM_YUV422 = 0,
+ DCAM_YUV420,
+ DCAM_YUV420_3FRAME,
+ DCAM_YUV400,
+ DCAM_RGB565,
+ DCAM_RGB888,
+ DCAM_RAWRGB,
+ DCAM_JPEG,
+ DCAM_FTM_MAX
+};
+
+enum dcam_cap_pattern {
+ DCAM_YUYV = 0,
+ DCAM_YVYU,
+ DCAM_UYVY,
+ DCAM_VYUY,
+ DCAM_PATTERN_MAX
+};
+
+enum dcam_capture_mode {
+ DCAM_CAPTURE_MODE_SINGLE = 0,
+ DCAM_CAPTURE_MODE_MULTIPLE,
+ DCAM_CAPTURE_MODE_MAX
+};
+
+
+enum dcam_irq_id {
+ DCAM_SN_SOF = 0,
+ DCAM_SN_EOF,
+ DCAM_CAP_SOF,
+ DCAM_CAP_EOF,
+ DCAM_PATH0_DONE,
+ DCAM_PATH0_OV,
+ DCAM_PATH1_DONE,
+ DCAM_PATH1_OV,
+ DCAM_PATH2_DONE,
+ DCAM_PATH2_OV,
+ DCAM_SN_LINE_ERR,
+ DCAM_SN_FRAME_ERR,
+ DCAM_JPEG_BUF_OV,
+ DCAM_ISP_OV,
+ DCAM_MIPI_OV,
+ DCAM_ROT_DONE,
+ DCAM_PATH1_SLICE_DONE,
+ DCAM_PATH2_SLICE_DONE,
+ DCAM_RAW_SLICE_DONE,
+ DCAM_PATH1_SOF,
+ DCAM_PATH2_SOF,
+ DCAM_PATH0_END,
+ DCAM_PATH1_END,
+ DCAM_PATH2_END,
+ DCAM_IRQ_NUMBER
+};
+
+enum dcam_cfg_id {
+ DCAM_CAP_SYNC_POL = 0,
+ DCAM_CAP_DATA_BITS,
+ DCAM_CAP_DATA_PACKET,
+ DCAM_CAP_YUV_TYPE,
+ DCAM_CAP_PRE_SKIP_CNT,
+ DCAM_CAP_FRM_DECI,
+ DCAM_CAP_FRM_COUNT_CLR,
+ DCAM_CAP_FRM_COUNT_GET,
+ DCAM_CAP_INPUT_RECT,
+ DCAM_CAP_IMAGE_XY_DECI,
+ DCAM_CAP_JPEG_GET_LENGTH,
+ DCAM_CAP_JPEG_SET_BUF_LEN,
+ DCAM_CAP_TO_ISP,
+ DCAM_CAP_SAMPLE_MODE,
+ DCAM_CAP_ZOOM_MODE,
+
+ DCAM_PATH_INPUT_SIZE,
+ DCAM_PATH_INPUT_RECT,
+ DCAM_PATH_INPUT_ADDR,
+ DCAM_PATH_OUTPUT_SIZE,
+ DCAM_PATH_OUTPUT_FORMAT,
+ DCAM_PATH_OUTPUT_ADDR,
+ DCAM_PATH_OUTPUT_RESERVED_ADDR,
+ DCAM_PATH_FRAME_BASE_ID,
+ DCAM_PATH_SWAP_BUFF,
+ DCAM_PATH_SUB_SAMPLE_EN_X,
+ DCAM_PATH_SUB_SAMPLE_EN_Y,
+ DCAM_PATH_SUB_SAMPLE_MOD,
+ DCAM_PATH_SLICE_SCALE_EN,
+ DCAM_PATH_SLICE_SCALE_HEIGHT,
+ DCAM_PATH_DITHER_EN,
+ DCAM_PATH_IS_IN_SCALE_RANGE,
+ DCAM_PATH_IS_SCALE_EN,
+ DCAM_PATH_SLICE_OUT_HEIGHT,
+ DCAM_PATH_DATA_ENDIAN,
+ DCAM_PATH_SRC_SEL,
+ DCAM_PATH_ENABLE,
+ DCAM_PATH_FRAME_TYPE,
+ DCAM_PATH_ROT_MODE,
+ DCAM_PATH_FRM_DECI,
+ DCAM_PATH_SHRINK,
+ DCAM_CFG_ID_E_MAX
+};
+
+/*
+enum dcam_sub_sample_mode
+{
+ DCAM_SUB_2 = 0,
+ DCAM_SUB_4,
+ DCAM_SUB_8,
+ DCAM_SUB_16,
+ DCAM_SUB_MAX
+};
+
+enum dcam_ahb_frm
+{
+ DCAM_AHB_FRAME_SRC,
+ DCAM_AHB_FRAME_PATH1_DST,
+ DCAM_AHB_FRAME_PATH2_DST,
+ DCAM_AHB_FRAME_SWAP,
+ DCAM_AHB_FRAME_LINE,
+ DCAM_AHB_FRAME_MAX
+};
+*/
+enum iram_owner {
+ IRAM_FOR_DCAM = 0,
+ IRAM_FOR_ARM
+};
+
+enum dcam_clk_sel {
+ DCAM_CLK_312M = 0,
+ DCAM_CLK_256M,
+ DCAM_CLK_128M,
+ DCAM_CLK_76M8,
+ DCAM_CLK_NONE
+};
+
+enum dcam_cap_if_mode {
+ DCAM_CAP_IF_CCIR = 0,
+ DCAM_CAP_IF_CSI2,
+ DCAM_CAP_IF_MODE_MAX
+};
+
+enum dcam_path_src_sel {
+ DCAM_PATH_FROM_CAP = 0,
+ DCAM_PATH_FROM_ISP,
+ DCAM_PATH_FROM_NONE
+};
+
+enum dcam_cap_sensor_mode {
+ DCAM_CAP_MODE_YUV = 0,
+ DCAM_CAP_MODE_SPI,
+ DCAM_CAP_MODE_JPEG,
+ DCAM_CAP_MODE_RAWRGB,
+ DCAM_CAP_MODE_MAX
+};
+
+enum dcam_cap_data_bits {
+ DCAM_CAP_12_BITS = 12,
+ DCAM_CAP_10_BITS = 10,
+ DCAM_CAP_8_BITS = 8,
+ DCAM_CAP_4_BITS = 4,
+ DCAM_CAP_2_BITS = 2,
+ DCAM_CAP_1_BITS = 1,
+ DCAM_CAP_BITS_MAX = 0xFF
+};
+
+enum dcam_data_endian {
+ DCAM_ENDIAN_BIG = 0,
+ DCAM_ENDIAN_LITTLE,
+ DCAM_ENDIAN_HALFBIG,
+ DCAM_ENDIAN_HALFLITTLE,
+ DCAM_ENDIAN_MAX
+};
+
+enum dcam_output_mode {
+ DCAM_OUTPUT_WORD = 0,
+ DCAM_OUTPUT_HALF_WORD,
+ DCAM_OUTPUT_YVYU_1FRAME,
+ DCAM_OUTPUT_YUV420,
+};
+
+enum dcam_glb_reg_id {
+ DCAM_CFG_REG = 0,
+ DCAM_CONTROL_REG,
+ DCAM_INIT_MASK_REG,
+ DCAM_INIT_CLR_REG,
+ DCAM_AHBM_STS_REG,
+ DCAM_ENDIAN_REG,
+ DCAM_REG_MAX
+};
+
+struct dcam_cap_sync_pol {
+ uint8_t vsync_pol;
+ uint8_t hsync_pol;
+ uint8_t pclk_pol;
+ uint8_t need_href;
+ uint8_t pclk_src;
+ uint8_t reserved[3];
+};
+
+struct dcam_endian_sel {
+ uint8_t y_endian;
+ uint8_t uv_endian;
+ uint8_t reserved0;
+ uint8_t reserved1;
+};
+
+struct dcam_cap_dec {
+ uint8_t x_factor;
+ uint8_t y_factor;
+ uint8_t x_mode;
+ uint8_t reserved;
+};
+
+struct dcam_path_dec {
+ uint8_t x_factor;
+ uint8_t y_factor;
+ uint8_t reserved[2];
+};
+
+struct dcam_size {
+ uint32_t w;
+ uint32_t h;
+};
+
+struct dcam_rect {
+ uint32_t x;
+ uint32_t y;
+ uint32_t w;
+ uint32_t h;
+};
+
+struct dcam_addr {
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+ uint32_t yaddr_vir;
+ uint32_t uaddr_vir;
+ uint32_t vaddr_vir;
+
+};
+
+struct dcam_sc_tap {
+ uint32_t y_tap;
+ uint32_t uv_tap;
+};
+
+struct dcam_deci {
+ uint32_t deci_x_en;
+ uint32_t deci_x;
+ uint32_t deci_y_en;
+ uint32_t deci_y;
+};
+
+struct dcam_frame {
+ uint32_t type;
+ uint32_t lock;
+ uint32_t flags;
+ uint32_t fid;
+ uint32_t width;
+ uint32_t height;
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+ uint32_t yaddr_vir;
+ uint32_t uaddr_vir;
+ uint32_t vaddr_vir;
+ struct dcam_frame *prev;
+ struct dcam_frame *next;
+};
+
+struct dcam_get_path_id {
+ uint32_t fourcc;
+ uint32_t is_path_work[DCAM_PATH_MAX];
+ uint32_t need_isp_tool;
+ uint32_t need_isp;
+ uint32_t need_shrink;
+ struct dcam_size input_size;
+ struct dcam_rect input_trim;
+ struct dcam_size output_size;
+};
+
+struct dcam_path_info {
+ uint32_t line_buf;
+ uint32_t support_yuv;
+ uint32_t support_raw;
+ uint32_t support_jpeg;
+ uint32_t support_scaling;
+ uint32_t support_trim;
+ uint32_t is_scaleing_path;
+};
+
+struct dcam_path_capability {
+ uint32_t count;
+ struct dcam_path_info path_info[DCAM_PATH_MAX];
+};
+
+
+typedef int (*dcam_isr_func)(struct dcam_frame* frame, void* u_data);
+
+int32_t dcam_module_init(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode);
+int32_t dcam_module_deinit(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode);
+int32_t dcam_module_en(struct device_node *dn);
+int32_t dcam_module_dis(struct device_node *dn);
+int32_t dcam_mipi_clk_en(struct device_node *dn);
+int32_t dcam_mipi_clk_dis(struct device_node *dn);
+int32_t dcam_ccir_clk_en(void);
+int32_t dcam_ccir_clk_dis(void);
+int32_t dcam_reset(enum dcam_rst_mode reset_mode, uint32_t is_isr);
+int32_t dcam_set_clk(struct device_node *dn, enum dcam_clk_sel clk_sel);
+int32_t dcam_update_path(enum dcam_path_index path_index, struct dcam_size *in_size,
+ struct dcam_rect *in_rect, struct dcam_size *out_size);
+int32_t dcam_start_path(enum dcam_path_index path_index);
+int32_t dcam_start(void);
+int32_t dcam_stop_path(enum dcam_path_index path_index);
+int32_t dcam_stop(void);
+int32_t dcam_resume(void);
+int32_t dcam_pause(void);
+int32_t dcam_reg_isr(enum dcam_irq_id id, dcam_isr_func user_func, void* u_data);
+int32_t dcam_cap_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_cap_get_info(enum dcam_cfg_id id, void *param);
+int32_t dcam_path0_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_path1_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_path2_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_get_resizer(uint32_t wait_opt);
+int32_t dcam_rel_resizer(void);
+void dcam_int_en(void);
+void dcam_int_dis(void);
+int32_t dcam_frame_is_locked(struct dcam_frame *frame);
+int32_t dcam_frame_lock(struct dcam_frame *frame);
+int32_t dcam_frame_unlock(struct dcam_frame *frame);
+int32_t dcam_read_registers(uint32_t* reg_buf, uint32_t *buf_len);
+int32_t dcam_resize_start(void);
+int32_t dcam_resize_end(void);
+int32_t dcam_stop_cap(void);
+void dcam_glb_reg_awr(unsigned long addr, uint32_t val, uint32_t reg_id);
+void dcam_glb_reg_owr(unsigned long addr, uint32_t val, uint32_t reg_id);
+void dcam_glb_reg_mwr(unsigned long addr, uint32_t mask, uint32_t val, uint32_t reg_id);
+int dcam_scale_coeff_alloc(void);
+void dcam_scale_coeff_free(void);
+int32_t dcam_rotation_start(void);
+int32_t dcam_rotation_end(void);
+int32_t dcam_get_path_id(struct dcam_get_path_id *path_id, uint32_t *channel_id);
+int32_t dcam_stop_sc_coeff(void);
+int32_t dcam_get_path_capability(struct dcam_path_capability *capacity);
+
+#endif //_DCAM_DRV_8830_H_
diff --git a/drivers/media/sprd_dcam/sharkl/dcam_reg.h b/drivers/media/sprd_dcam/sharkl/dcam_reg.h
new file mode 100644
index 00000000..e725c6be
--- /dev/null
+++ b/drivers/media/sprd_dcam/sharkl/dcam_reg.h
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#ifndef _REG_DCAM_TIGER_H_
+#define _REG_DCAM_TIGER_H_
+
+#ifndef CONFIG_64BIT
+#include <soc/sprd/globalregs.h>
+#endif
+
+#define BIT_0 0x01
+#define BIT_1 0x02
+#define BIT_2 0x04
+#define BIT_3 0x08
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+#define BIT_8 0x0100
+#define BIT_9 0x0200
+#define BIT_10 0x0400
+#define BIT_11 0x0800
+#define BIT_12 0x1000
+#define BIT_13 0x2000
+#define BIT_14 0x4000
+#define BIT_15 0x8000
+#define BIT_16 0x010000
+#define BIT_17 0x020000
+#define BIT_18 0x040000
+#define BIT_19 0x080000
+#define BIT_20 0x100000
+#define BIT_21 0x200000
+#define BIT_22 0x400000
+#define BIT_23 0x800000
+#define BIT_24 0x01000000
+#define BIT_25 0x02000000
+#define BIT_26 0x04000000
+#define BIT_27 0x08000000
+#define BIT_28 0x10000000
+#define BIT_29 0x20000000
+#define BIT_30 0x40000000
+#define BIT_31 0x80000000
+
+#define GLOBAL_BASE SPRD_GREG_BASE
+#define ARM_GLB_GEN0 (GLOBAL_BASE + 0x008UL)
+#define ARM_GLB_GEN3 (GLOBAL_BASE + 0x01CUL)
+#define ARM_GLB_PLL_SCR (GLOBAL_BASE + 0x070UL)
+//#define GR_CLK_GEN5 (GLOBAL_BASE + 0x07CUL)
+#define CLK_DLY_CTRL (GLOBAL_BASE + 0x05CUL)
+
+#define DCAM_AHB_BASE SPRD_MMAHB_BASE
+#define DCAM_AHB_CTL0 (DCAM_AHB_BASE + 0x0000UL)
+#define DCAM_EB (DCAM_AHB_CTL0 + 0x0000UL)
+//#define CSI2_DPHY_EB (DCAM_AHB_CTL0 + 0x0000UL)
+#define DCAM_RST (DCAM_AHB_CTL0 + 0x0004UL)
+#define DCAM_MATRIX_EB (DCAM_AHB_CTL0 + 0x0008UL)
+#define DCAM_CCIR_PCLK_EB (SPRD_MMCKG_BASE + 0x0028UL)
+
+
+#define DCAM_CFG (DCAM_BASE + 0x0000UL)
+#define DCAM_CONTROL (DCAM_BASE + 0x0004UL)
+#define DCAM_PATH0_CFG (DCAM_BASE + 0x0008UL)
+#define DCAM_PATH0_SRC_SIZE (DCAM_BASE + 0x000CUL)
+#define DCAM_PATH1_CFG (DCAM_BASE + 0x0010UL)
+#define DCAM_PATH1_SRC_SIZE (DCAM_BASE + 0x0014UL)
+#define DCAM_PATH1_DST_SIZE (DCAM_BASE + 0x0018UL)
+#define DCAM_PATH1_TRIM_START (DCAM_BASE + 0x001CUL)
+#define DCAM_PATH1_TRIM_SIZE (DCAM_BASE + 0x0020UL)
+#define DCAM_PATH2_CFG (DCAM_BASE + 0x0024UL)
+#define DCAM_PATH2_SRC_SIZE (DCAM_BASE + 0x0028UL)
+#define DCAM_PATH2_DST_SIZE (DCAM_BASE + 0x002CUL)
+#define DCAM_PATH2_TRIM_START (DCAM_BASE + 0x0030UL)
+#define DCAM_PATH2_TRIM_SIZE (DCAM_BASE + 0x0034UL)
+#define REV_SLICE_VER (DCAM_BASE + 0x0038UL)
+#define DCAM_INT_STS (DCAM_BASE + 0x003CUL)
+#define DCAM_INT_MASK (DCAM_BASE + 0x0040UL)
+#define DCAM_INT_CLR (DCAM_BASE + 0x0044UL)
+#define DCAM_INT_RAW (DCAM_BASE + 0x0048UL)
+#define DCAM_FRM_ADDR0 (DCAM_BASE + 0x004CUL)
+#define DCAM_FRM_ADDR1 (DCAM_BASE + 0x0050UL)
+#define DCAM_FRM_ADDR2 (DCAM_BASE + 0x0054UL)
+#define DCAM_FRM_ADDR3 (DCAM_BASE + 0x0058UL)
+#define DCAM_FRM_ADDR4 (DCAM_BASE + 0x005CUL)
+#define DCAM_FRM_ADDR5 (DCAM_BASE + 0x0060UL)
+#define DCAM_FRM_ADDR6 (DCAM_BASE + 0x0064UL)
+#define DCAM_BURST_GAP (DCAM_BASE + 0x0068UL)
+#define DCAM_ENDIAN_SEL (DCAM_BASE + 0x006CUL)
+#define DCAM_AHBM_STS (DCAM_BASE + 0x0070UL)
+#define DCAM_FRM_ADDR7 (DCAM_BASE + 0x0074UL)
+#define DCAM_FRM_ADDR8 (DCAM_BASE + 0x0078UL)
+#define DCAM_FRM_ADDR9 (DCAM_BASE + 0x007CUL)
+#define DCAM_FRM_ADDR10 (DCAM_BASE + 0x0080UL)
+#define DCAM_FRM_ADDR11 (DCAM_BASE + 0x0084UL)
+#define CCIR_PATT_CFG (DCAM_BASE + 0x0088UL)
+#define CCIR_PATT_SIZE (DCAM_BASE + 0x008CUL)
+#define CCIR_PATT_VBLANK (DCAM_BASE + 0x0090UL)
+#define CCIR_PATT_HBLANK (DCAM_BASE + 0x0094UL)
+#define REV_BURST_IN_CFG (DCAM_BASE + 0x0098UL)
+#define REV_BURST_IN_TRIM_START (DCAM_BASE + 0x009CUL)
+#define REV_BURST_IN_TRIM_SIZE (DCAM_BASE + 0x00A0UL)
+#define REV_SLICE_CFG (DCAM_BASE + 0x00A4UL)
+#define PATH1_SLICE_O_VCNT (DCAM_BASE + 0x00A8UL)
+#define PATH2_SLICE_O_VCNT (DCAM_BASE + 0x00ACUL)
+
+#define DCAM_PATH0_TRIM_START (DCAM_BASE + 0x00B8UL)
+#define DCAM_PATH0_TRIM_SIZE (DCAM_BASE + 0x00BCUL)
+#define DCAM_FRM_ADDR12 (DCAM_BASE + 0x00C0UL)
+
+#define CAP_CCIR_CTRL (DCAM_BASE + 0x0100UL)
+#define CAP_CCIR_FRM_CTRL (DCAM_BASE + 0x0104UL)
+#define CAP_CCIR_START (DCAM_BASE + 0x0108UL)
+#define CAP_CCIR_END (DCAM_BASE + 0x010CUL)
+#define CAP_CCIR_IMG_DECI (DCAM_BASE + 0x0110UL)
+#define CAP_CCIR_ATV_FIX (DCAM_BASE + 0x0114UL)
+#define CAP_CCIR_OBSERVE (DCAM_BASE + 0x0118UL)
+#define CAP_CCIR_JPG_CTRL (DCAM_BASE + 0x011CUL)
+#define CAP_CCIR_FRM_SIZE (DCAM_BASE + 0x0120UL)
+#define CAP_CCIR_PLCK_SRC (SPRD_PIN_BASE + 0x04)
+#define CAP_SPI_CFG (DCAM_BASE + 0x0124UL)
+
+#define CAP_MIPI_CTRL (DCAM_BASE + 0x0128UL)
+#define CAP_MIPI_FRM_CTRL (DCAM_BASE + 0x012CUL)
+#define CAP_MIPI_START (DCAM_BASE + 0x0130UL)
+#define CAP_MIPI_END (DCAM_BASE + 0x0134UL)
+#define CAP_MIPI_IMG_DECI (DCAM_BASE + 0x0138UL)
+#define CAP_MIPI_JPG_CTRL (DCAM_BASE + 0x013CUL)
+#define CAP_MIPI_FRM_SIZE (DCAM_BASE + 0x0140UL)
+#define CAP_SENSOR_CTRL (DCAM_BASE + 0x0144UL)
+
+#define BLC_CFG (DCAM_BASE + 0x0148UL)
+#define BLC_START (DCAM_BASE + 0x014CUL)
+#define BLC_END (DCAM_BASE + 0x0150UL)
+#define BLC_TARGET (DCAM_BASE + 0x0154UL)
+#define BLC_MANUAL (DCAM_BASE + 0x0158UL)
+#define BLC_VALUE1 (DCAM_BASE + 0x015CUL)
+#define BLC_VALUE2 (DCAM_BASE + 0x0160UL)
+
+#define DCAM_END BLC_VALUE2
+
+
+#define DCAM_EB_BIT BIT_0
+#define CCIR_EB_BIT BIT_1
+#define MIPI_EB_BIT BIT_10 // aiden: todo
+
+#define DCAM_MOD_RST_BIT BIT_0
+#define CCIR_RST_BIT BIT_1
+#define PATH0_RST_BIT BIT_7
+#define PATH1_RST_BIT BIT_8
+#define PATH2_RST_BIT BIT_9
+#define CCIR_PCLK_EB_BIT BIT_16
+
+#define DCAM_PATH_NUM 3
+#define DCAM_CAP_SKIP_FRM_MAX 16
+#define DCAM_FRM_DECI_FAC_MAX 4
+#define DCAM_CAP_FRAME_WIDTH_MAX 4092
+#define DCAM_CAP_FRAME_HEIGHT_MAX 4092
+#define DCAM_PATH_FRAME_WIDTH_MAX 4092
+#define DCAM_PATH_FRAME_HEIGHT_MAX 4092
+#if defined(CONFIG_ARCH_SCX35LT8)
+#define DCAM_PATH2_FRAME_WIDTH_MAX 4416
+#define DCAM_PATH2_FRAME_HEIGHT_MAX 4092
+#else
+#define DCAM_PATH2_FRAME_WIDTH_MAX 4092
+#define DCAM_PATH2_FRAME_HEIGHT_MAX 4092
+#endif
+#define DCAM_CAP_X_DECI_FAC_MAX 4 // cap deci: 0 - 1/8
+#define DCAM_CAP_Y_DECI_FAC_MAX 4 // cap deci: 0 - 1/8
+#define DCAM_JPG_BUF_UNIT (1 << 15)
+#define DCAM_JPG_UNITS (1 << 10)
+#define DCAM_SC_COEFF_UP_MAX 4 // path scaling: 1/8 - 4
+#define DCAM_SC_COEFF_DOWN_MAX 7 // path scaling: 1/8 - 4
+#define DCAM_PATH_DECI_FAC_MAX 4 // path deci: 1/2 - 1/16
+#define DCAM_PATH1_LINE_BUF_LENGTH 2048
+#define DCAM_PATH2_LINE_BUF_LENGTH 4416
+#define DCAM_ISP_LINE_BUF_LENGTH 3280
+#define DCAM_SCALING_THRESHOLD 2600
+#define DCAM_IRQ IRQ_DCAM_INT
+
+#define DCAM_PIXEL_ALIGN_WIDTH 4
+#define DCAM_PIXEL_ALIGN_HEIGHT 2
+
+#define DCAM_PATH_NUM 3
+enum {
+ DCAM_PATH0 = 0,
+ DCAM_PATH1,
+ DCAM_PATH2,
+ DCAM_PATH_MAX
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_REG_DCAM_TIGER_H_
+
+
diff --git a/drivers/media/sprd_dcam/tshark/dcam_drv.c b/drivers/media/sprd_dcam/tshark/dcam_drv.c
new file mode 100644
index 00000000..e1426730
--- /dev/null
+++ b/drivers/media/sprd_dcam/tshark/dcam_drv.c
@@ -0,0 +1,4693 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <linux/kthread.h>
+#include <soc/sprd/hardware.h>
+#include <mach/irqs.h>
+#include <soc/sprd/sci.h>
+#include <soc/sprd/sci_glb_regs.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/wakelock.h>
+#include "dcam_drv.h"
+#include "gen_scale_coef.h"
+#include <linux/sprd_2351.h>
+
+#define LOCAL static
+/*#define LOCAL*/
+
+//#define DCAM_DRV_DEBUG
+#define DCAM_LOWEST_ADDR 0x800
+#define DCAM_ADDR_INVALID(addr) ((uint32_t)(addr) < DCAM_LOWEST_ADDR)
+#define DCAM_YUV_ADDR_INVALID(y,u,v) \
+ (DCAM_ADDR_INVALID(y) && \
+ DCAM_ADDR_INVALID(u) && \
+ DCAM_ADDR_INVALID(v))
+
+#define DCAM_SC1_H_TAB_OFFSET 0x400
+#define DCAM_SC1_V_TAB_OFFSET 0x4F0
+#define DCAM_SC1_V_CHROMA_TAB_OFFSET 0x8F0
+
+#define DCAM_SC2_H_TAB_OFFSET 0x1400
+#define DCAM_SC2_V_TAB_OFFSET 0x14F0
+#define DCAM_SC2_V_CHROMA_TAB_OFFSET 0x18F0
+
+#define DCAM_SC_COEFF_BUF_SIZE (24 << 10)
+#define DCAM_SC_COEFF_COEF_SIZE (1 << 10)
+#define DCAM_SC_COEFF_TMP_SIZE (21 << 10)
+#define DCAM_SC_COEFF_BUF_COUNT 2
+
+
+#define DCAM_SC_H_COEF_SIZE (0xC0)
+#define DCAM_SC_V_COEF_SIZE (0x210)
+#define DCAM_SC_V_CHROM_COEF_SIZE (0x210)
+
+#define DCAM_SC_COEFF_H_NUM (DCAM_SC_H_COEF_SIZE/4)
+#define DCAM_SC_COEFF_V_NUM (DCAM_SC_V_COEF_SIZE/4)
+#define DCAM_SC_COEFF_V_CHROMA_NUM (DCAM_SC_V_CHROM_COEF_SIZE/4)
+
+#define DCAM_AXI_STOP_TIMEOUT 1000
+#define DCAM_CLK_DOMAIN_AHB 1
+#define DCAM_CLK_DOMAIN_DCAM 0
+
+#ifdef CONFIG_SC_FPGA
+#define DCAM_PATH_TIMEOUT msecs_to_jiffies(500*10)
+#else
+#define DCAM_PATH_TIMEOUT msecs_to_jiffies(500)
+#endif
+
+#define DCAM_FRM_QUEUE_LENGTH 4
+
+#define DCAM_STATE_QUICKQUIT 0x01
+
+#define DCAM_CHECK_PARAM_ZERO_POINTER(n) \
+ do { \
+ if (0 == (int)(n)) \
+ return -DCAM_RTN_PARA_ERR; \
+ } while(0)
+
+#define DCAM_CLEAR(a) \
+ do { \
+ memset((void *)(a), 0, sizeof(*(a))); \
+ } while(0)
+
+#define DEBUG_STR "Error L %d, %s \n"
+#define DEBUG_ARGS __LINE__,__FUNCTION__
+#define DCAM_RTN_IF_ERR \
+ do { \
+ if(rtn) { \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return -(rtn); \
+ } \
+ } while(0)
+
+#define DCAM_IRQ_LINE_MASK 0x001FFFFFUL
+
+typedef void (*dcam_isr)(void);
+
+enum {
+ DCAM_FRM_UNLOCK = 0,
+ DCAM_FRM_LOCK_WRITE = 0x10011001,
+ DCAM_FRM_LOCK_READ = 0x01100110
+};
+
+enum {
+ DCAM_ST_STOP = 0,
+ DCAM_ST_START,
+};
+
+#define DCAM_IRQ_ERR_MASK \
+ ((1 << DCAM_PATH0_OV) | (1 << DCAM_PATH1_OV) | (1 << DCAM_PATH2_OV) | \
+ (1 << DCAM_SN_LINE_ERR) | (1 << DCAM_SN_FRAME_ERR) | \
+ (1 << DCAM_ISP_OV) | (1 << DCAM_MIPI_OV))
+
+#define DCAM_IRQ_JPEG_OV_MASK (1 << DCAM_JPEG_BUF_OV)
+
+#define DCAM_CHECK_ZERO(a) \
+ do { \
+ if (DCAM_ADDR_INVALID(a)) { \
+ printk("DCAM, zero pointer \n"); \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return -EFAULT; \
+ } \
+ } while(0)
+
+#define DCAM_CHECK_ZERO_VOID(a) \
+ do { \
+ if (DCAM_ADDR_INVALID(a)) { \
+ printk("DCAM, zero pointer \n"); \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return; \
+ } \
+ } while(0)
+
+struct dcam_cap_desc {
+ uint32_t interface;
+ uint32_t input_format;
+ uint32_t frame_deci_factor;
+ uint32_t img_x_deci_factor;
+ uint32_t img_y_deci_factor;
+};
+
+struct dcam_path_valid {
+ uint32_t input_size :1;
+ uint32_t input_rect :1;
+ uint32_t output_size :1;
+ uint32_t output_format :1;
+ uint32_t src_sel :1;
+ uint32_t data_endian :1;
+ uint32_t frame_deci :1;
+ uint32_t scale_tap :1;
+ uint32_t v_deci :1;
+ uint32_t rot_mode :1;
+ uint32_t shrink :1;
+};
+
+struct dcam_frm_queue {
+ struct dcam_frame frm_array[DCAM_FRM_QUEUE_LENGTH];
+ uint32_t valid_cnt;
+};
+
+struct dcam_buf_queue {
+ struct dcam_frame frame[DCAM_FRM_CNT_MAX];
+ struct dcam_frame *write;
+ struct dcam_frame *read;
+ spinlock_t lock;
+};
+
+struct dcam_path_desc {
+ struct dcam_size input_size;
+ struct dcam_rect input_rect;
+ struct dcam_size sc_input_size;
+ struct dcam_size output_size;
+ struct dcam_frame input_frame;
+ struct dcam_frm_queue frame_queue;
+ struct dcam_buf_queue buf_queue;
+ //struct dcam_frame *output_frame_head;
+ //struct dcam_frame *output_frame_cur;
+ struct dcam_endian_sel data_endian;
+ struct dcam_sc_tap scale_tap;
+ struct dcam_deci deci_val;
+ uint32_t shrink;
+ struct dcam_path_valid valid_param;
+ uint32_t frame_base_id;
+ uint32_t output_frame_count;
+ uint32_t output_format;
+ uint32_t src_sel;
+ uint32_t rot_mode;
+ uint32_t frame_deci;
+ uint32_t valide;
+ uint32_t status;
+ struct semaphore tx_done_sema;
+ struct semaphore sof_sema;
+ uint32_t wait_for_done;
+ uint32_t is_update;
+ uint32_t wait_for_sof;
+ uint32_t need_stop;
+ uint32_t need_wait;
+ int32_t sof_cnt;
+};
+
+struct dcam_module {
+ uint32_t dcam_mode;
+ uint32_t module_addr;
+ struct dcam_cap_desc dcam_cap;
+ struct dcam_path_desc dcam_path0;
+ struct dcam_path_desc dcam_path1;
+ struct dcam_path_desc dcam_path2;
+ struct dcam_frame path0_frame[DCAM_PATH_0_FRM_CNT_MAX];
+ struct dcam_frame path1_frame[DCAM_PATH_1_FRM_CNT_MAX];
+ struct dcam_frame path2_frame[DCAM_PATH_2_FRM_CNT_MAX];
+ struct dcam_frame path0_reserved_frame;
+ struct dcam_frame path1_reserved_frame;
+ struct dcam_frame path2_reserved_frame;
+ struct semaphore stop_sema;
+ uint32_t wait_stop;
+ struct semaphore resize_done_sema;
+ uint32_t wait_resize_done;
+ struct semaphore rotation_done_sema;
+ uint32_t wait_rotation_done;
+ uint32_t err_happened;
+ struct semaphore scale_coeff_mem_sema;
+ uint32_t state;
+};
+
+struct dcam_sc_coeff {
+ uint32_t buf[DCAM_SC_COEFF_BUF_SIZE];
+ uint32_t flag;
+ struct dcam_path_desc dcam_path1;
+};
+
+struct dcam_sc_array {
+ struct dcam_sc_coeff scaling_coeff[DCAM_SC_COEFF_BUF_COUNT];
+ struct dcam_sc_coeff *scaling_coeff_queue[DCAM_SC_COEFF_BUF_COUNT];
+ uint32_t valid_cnt;
+ uint32_t is_smooth_zoom;
+};
+
+LOCAL atomic_t s_dcam_users = ATOMIC_INIT(0);
+LOCAL atomic_t s_resize_flag = ATOMIC_INIT(0);
+LOCAL atomic_t s_rotation_flag = ATOMIC_INIT(0);
+LOCAL struct clk* s_dcam_clk = NULL;
+LOCAL struct dcam_module* s_p_dcam_mod = 0;
+LOCAL uint32_t s_dcam_irq = 0x5A0000A5;
+LOCAL dcam_isr_func s_user_func[DCAM_IRQ_NUMBER];
+LOCAL void* s_user_data[DCAM_IRQ_NUMBER];
+LOCAL struct dcam_sc_array* s_dcam_sc_array = NULL;
+LOCAL struct wake_lock dcam_wakelock;
+LOCAL uint32_t s_need_312m_clk_flag = 0;
+
+LOCAL DEFINE_MUTEX(dcam_sem);
+LOCAL DEFINE_MUTEX(dcam_scale_sema);
+LOCAL DEFINE_MUTEX(dcam_rot_sema);
+LOCAL DEFINE_MUTEX(dcam_module_sema);
+LOCAL DEFINE_SPINLOCK(dcam_mod_lock);
+LOCAL DEFINE_SPINLOCK(dcam_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_cfg_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_control_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_mask_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_clr_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_ahbm_sts_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_endian_lock);
+
+LOCAL void _dcam_path0_set(void);
+LOCAL void _dcam_path1_set(struct dcam_path_desc *path);
+LOCAL void _dcam_path2_set(void);
+LOCAL void _dcam_frm_clear(enum dcam_path_index path_index);
+LOCAL void _dcam_link_frm(uint32_t base_id);
+LOCAL int32_t _dcam_path_set_next_frm(enum dcam_path_index path_index, uint32_t is_1st_frm);
+/*LOCAL int32_t _dcam_path_trim(enum dcam_path_index path_index);*/
+LOCAL int32_t _dcam_path_scaler(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_calc_sc_size(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_set_sc_coeff(enum dcam_path_index path_index);
+LOCAL void _dcam_force_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy);
+LOCAL void _dcam_auto_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy);
+LOCAL void _dcam_force_copy(enum dcam_path_index path_index);
+LOCAL void _dcam_auto_copy(enum dcam_path_index path_index);
+LOCAL void _dcam_reg_trace(void);
+LOCAL void _dcam_sensor_sof(void);
+LOCAL void _dcam_sensor_eof(void);
+LOCAL void _dcam_cap_sof(void);
+LOCAL void _dcam_cap_eof(void);
+LOCAL void _dcam_path0_done(void);
+LOCAL void _dcam_path0_overflow(void);
+LOCAL void _dcam_path1_done(void);
+LOCAL void _dcam_path1_overflow(void);
+LOCAL void _dcam_sensor_line_err(void);
+LOCAL void _dcam_sensor_frame_err(void);
+LOCAL void _dcam_jpeg_buf_ov(void);
+LOCAL void _dcam_path2_done(void);
+LOCAL void _dcam_path2_ov(void);
+LOCAL void _dcam_isp_ov(void);
+LOCAL void _dcam_mipi_ov(void);
+LOCAL void _dcam_path1_slice_done(void);
+LOCAL void _dcam_path2_slice_done(void);
+LOCAL void _dcam_raw_slice_done(void);
+LOCAL void _dcam_path1_sof(void);
+LOCAL void _dcam_path2_sof(void);
+LOCAL irqreturn_t _dcam_isr_root(int irq, void *dev_id);
+LOCAL void _dcam_stopped_notice(void);
+LOCAL void _dcam_stopped(void);
+LOCAL int32_t _dcam_path_check_deci(enum dcam_path_index path_index, uint32_t *is_deci);
+extern void _dcam_isp_root(void);
+LOCAL int _dcam_internal_init(void);
+LOCAL void _dcam_internal_deinit(void);
+LOCAL void _dcam_wait_path_done(enum dcam_path_index path_index, uint32_t *p_flag);
+LOCAL void _dcam_path_done_notice(enum dcam_path_index path_index);
+LOCAL void _dcam_rot_done(void);
+LOCAL int32_t _dcam_err_pre_proc(void);
+LOCAL void _dcam_frm_queue_clear(struct dcam_frm_queue *queue);
+LOCAL int32_t _dcam_frame_enqueue(struct dcam_frm_queue *queue, struct dcam_frame *frame);
+LOCAL int32_t _dcam_frame_dequeue(struct dcam_frm_queue *queue, struct dcam_frame *frame);
+LOCAL void _dcam_buf_queue_init(struct dcam_buf_queue *queue);
+LOCAL int32_t _dcam_buf_queue_write(struct dcam_buf_queue *queue, struct dcam_frame *frame);
+LOCAL int32_t _dcam_buf_queue_read(struct dcam_buf_queue *queue, struct dcam_frame *frame);
+LOCAL void _dcam_wait_update_done(enum dcam_path_index path_index, uint32_t *p_flag);
+LOCAL void _dcam_path_updated_notice(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_get_valid_sc_coeff(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff);
+LOCAL int32_t _dcam_push_sc_buf(struct dcam_sc_array *sc, uint32_t index);
+LOCAL int32_t _dcam_pop_sc_buf(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff);
+LOCAL int32_t _dcam_calc_sc_coeff(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_write_sc_coeff(enum dcam_path_index path_index);
+LOCAL void _dcam_wait_for_quickstop(enum dcam_path_index path_index);
+
+LOCAL const dcam_isr isr_list[DCAM_IRQ_NUMBER] = {
+ NULL,//_dcam_isp_root,
+ _dcam_sensor_eof,
+ _dcam_cap_sof,
+ _dcam_cap_eof,
+ _dcam_path0_done,
+ _dcam_path0_overflow,
+ _dcam_path1_done,
+ _dcam_path1_overflow,
+ _dcam_path2_done,
+ _dcam_path2_ov,
+ _dcam_sensor_line_err,
+ _dcam_sensor_frame_err,
+ _dcam_jpeg_buf_ov,
+ _dcam_isp_ov,
+ _dcam_mipi_ov,
+ _dcam_rot_done,
+ _dcam_path1_slice_done,
+ _dcam_path2_slice_done,
+ _dcam_raw_slice_done,
+ _dcam_path1_sof,
+ _dcam_path2_sof,
+};
+
+void dcam_glb_reg_awr(uint32_t addr, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ REG_WR(addr, REG_RD(addr) & (val));
+ break;
+ }
+}
+
+void dcam_glb_reg_owr(uint32_t addr, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ REG_WR(addr, REG_RD(addr) | (val));
+ break;
+ }
+}
+
+void dcam_glb_reg_mwr(uint32_t addr, uint32_t mask, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+ uint32_t tmp = 0;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ break;
+ }
+}
+
+int32_t dcam_module_init(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ if (if_mode >= DCAM_CAP_IF_MODE_MAX) {
+ rtn = -DCAM_RTN_CAP_IF_MODE_ERR;
+ } else {
+ if (sn_mode >= DCAM_CAP_MODE_MAX) {
+ rtn = -DCAM_RTN_CAP_SENSOR_MODE_ERR;
+ } else {
+ _dcam_internal_init();
+ _dcam_link_frm(0); /* set default base frame index as 0 */
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path0.buf_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path1.buf_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path2.buf_queue);
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ cap_desc->interface = if_mode;
+ cap_desc->input_format = sn_mode;
+ /*REG_OWR(DCAM_EB, BIT_13);//MM_EB*/
+ /*REG_OWR(DCAM_MATRIX_EB, BIT_10|BIT_5);*/
+ if (DCAM_CAP_IF_CSI2 == if_mode) {
+ /* REG_OWR(CSI2_DPHY_EB, MIPI_EB_BIT);*/
+ //ret = _dcam_mipi_clk_en();
+ dcam_glb_reg_owr(DCAM_CFG, BIT_9, DCAM_CFG_REG);
+ REG_MWR(CAP_MIPI_CTRL, BIT_2 | BIT_1, sn_mode << 1);
+ } else {
+ /*REG_OWR(DCAM_EB, CCIR_IN_EB_BIT);
+ REG_OWR(DCAM_EB, CCIR_EB_BIT);*/
+ //ret = _dcam_ccir_clk_en();
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ REG_MWR(CAP_CCIR_CTRL, BIT_2 | BIT_1, sn_mode << 1);
+ }
+ rtn = DCAM_RTN_SUCCESS;
+ }
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_module_deinit(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ if (DCAM_CAP_IF_CSI2 == if_mode) {
+ /*REG_MWR(CSI2_DPHY_EB, MIPI_EB_BIT, 0 << 10);*/
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ //_dcam_mipi_clk_dis();
+ } else {
+ /*REG_MWR(DCAM_EB, CCIR_IN_EB_BIT, 0 << 2);
+ REG_MWR(DCAM_EB, CCIR_EB_BIT, 0 << 9);*/
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ //_dcam_ccir_clk_dis();
+ }
+
+ _dcam_internal_deinit();
+
+ return -rtn;
+}
+
+int dcam_scale_coeff_alloc(void)
+{
+ int ret = 0;
+
+ if (NULL == s_dcam_sc_array) {
+ s_dcam_sc_array = (struct dcam_sc_array*)vzalloc(sizeof(struct dcam_sc_array));
+ if (NULL == s_dcam_sc_array) {
+ printk("DCAM: _dcam_scale_coeff_alloc fail.\n");
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+void dcam_scale_coeff_free(void)
+{
+ if (s_dcam_sc_array) {
+ vfree(s_dcam_sc_array);
+ s_dcam_sc_array = NULL;
+ }
+}
+
+#ifdef CONFIG_CPLL_1024M
+void (*change_clk_notify_gpu)(bool is_change);
+EXPORT_SYMBOL(change_clk_notify_gpu);
+void dcam_set_gpucp2_freq(uint32_t on)
+{
+ struct clk *cpll;
+ cpll = clk_get(NULL, "clk_cpll");
+ if (IS_ERR(cpll )) {
+ printk("DCAM: dcam_set_gpucp2_freq fail, %d \n", (int)cpll);
+ return;
+ }
+ printk("Dcam set gpucp2 freq is %d \n", on);
+ if (on) {
+ if (NULL != change_clk_notify_gpu) {
+ change_clk_notify_gpu(true);
+ }
+#ifndef CONFIG_SPRD_2351
+ clk_set_rate(cpll, 624000000);
+#else
+ if (get_cp2_state()) {
+ sprd_switch_cp2_clk(1);
+ } else {
+ clk_set_rate(cpll, 624000000);
+ }
+#endif
+ udelay(2000);
+ printk("delay 2ms in on.\n");
+ }
+ else {
+#ifndef CONFIG_SPRD_2351
+ clk_set_rate(cpll, 1024000000);
+#else
+ if (get_cp2_state()) {
+ sprd_switch_cp2_clk(0);
+ } else {
+ clk_set_rate(cpll, 1024000000);
+ }
+#endif
+ udelay(2000);
+ printk("delay 2ms in off.\n");
+ if (NULL != change_clk_notify_gpu) {
+ change_clk_notify_gpu(false);
+ }
+ }
+}
+void dcam_set_highclk_flag(uint32_t flag)
+{
+ printk("dcam_set_highclk_flag: flag=%d clk_flag=%d\n", flag, s_need_312m_clk_flag);
+ if ( flag != s_need_312m_clk_flag) {
+ s_need_312m_clk_flag = flag;
+ dcam_set_gpucp2_freq(flag);
+ }
+}
+#endif
+LOCAL uint32_t *dcam_get_scale_coeff_addr(uint32_t *index)
+{
+ uint32_t i;
+
+ if (DCAM_ADDR_INVALID(s_dcam_sc_array)) {
+ printk("DCAM: scale addr, invalid param 0x%x \n",
+ (uint32_t)s_dcam_sc_array);
+ return NULL;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_BUF_COUNT; i++) {
+ if (0 == s_dcam_sc_array->scaling_coeff[i].flag) {
+ *index = i;
+ DCAM_TRACE("dcam: get buf index %d \n", i);
+ return s_dcam_sc_array->scaling_coeff[i].buf;
+ }
+ }
+ printk("dcam: get buf index %d \n", i);
+
+ return NULL;
+}
+
+int32_t dcam_module_en(struct device_node *dn)
+{
+ int ret = 0;
+ unsigned int irq_no = 0;
+
+ DCAM_TRACE("DCAM: dcam_module_en, In %d \n", s_dcam_users.counter);
+ mutex_lock(&dcam_module_sema);
+ if (atomic_inc_return(&s_dcam_users) == 1) {
+
+ wake_lock_init(&dcam_wakelock, WAKE_LOCK_SUSPEND,
+ "pm_message_wakelock_dcam");
+
+ wake_lock(&dcam_wakelock);
+
+ ret = clk_mm_i_eb(dn,1);
+ if (ret) {
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+ ret = dcam_set_clk(dn,DCAM_CLK_312M);
+ if (ret) {
+ clk_mm_i_eb(dn,0);
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+
+ parse_baseaddress(dn);
+
+ dcam_reset(DCAM_RST_ALL, 0);
+ atomic_set(&s_resize_flag, 0);
+ atomic_set(&s_rotation_flag, 0);
+ memset((void*)s_user_func, 0, sizeof(s_user_func));
+ memset((void*)s_user_data, 0, sizeof(s_user_data));
+ printk("DCAM: register isr, 0x%x \n", REG_RD(DCAM_INT_MASK));
+
+ irq_no = parse_irq(dn);
+ printk("DCAM: irq_no = 0x%x \n", irq_no);
+ ret = request_irq(irq_no,
+ _dcam_isr_root,
+ IRQF_SHARED,
+ "DCAM",
+ (void*)&s_dcam_irq);
+ if (ret) {
+ printk("DCAM: dcam_start, error %d \n", ret);
+ dcam_set_clk(dn,DCAM_CLK_NONE);
+ clk_mm_i_eb(dn,0);
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+
+ DCAM_TRACE("DCAM: dcam_module_en end \n");
+ }
+ DCAM_TRACE("DCAM: dcam_module_en, Out %d \n", s_dcam_users.counter);
+ mutex_unlock(&dcam_module_sema);
+ return 0;
+
+fail_exit:
+ wake_unlock(&dcam_wakelock);
+ wake_lock_destroy(&dcam_wakelock);
+ atomic_dec(&s_dcam_users);
+ mutex_unlock(&dcam_module_sema);
+ return ret;
+}
+
+int32_t dcam_module_dis(struct device_node *dn)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ int ret = 0;
+ unsigned int irq_no = 0;
+
+ DCAM_TRACE("DCAM: dcam_module_dis, In %d \n", s_dcam_users.counter);
+
+ mutex_lock(&dcam_module_sema);
+ if (atomic_dec_return(&s_dcam_users) == 0) {
+ sci_glb_clr(DCAM_EB, DCAM_EB_BIT);
+ dcam_set_clk(dn,DCAM_CLK_NONE);
+ printk("DCAM: un register isr \n");
+ irq_no = parse_irq(dn);
+ free_irq(irq_no, (void*)&s_dcam_irq);
+ ret = clk_mm_i_eb(dn,0);
+ if (ret) {
+ rtn = -DCAM_RTN_MAX;
+ }
+ wake_unlock(&dcam_wakelock);
+ wake_lock_destroy(&dcam_wakelock);
+ }
+
+ DCAM_TRACE("DCAM: dcam_module_dis, Out %d \n", s_dcam_users.counter);
+ mutex_unlock(&dcam_module_sema);
+
+ return rtn;
+}
+
+int32_t dcam_reset(enum dcam_rst_mode reset_mode, uint32_t is_isr)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ uint32_t time_out = 0;
+
+ DCAM_TRACE("DCAM: reset: %d \n", reset_mode);
+
+ if (!is_isr) {
+ mutex_lock(&dcam_rot_sema);
+ }
+
+ if (DCAM_RST_ALL == reset_mode) {
+ if (atomic_read(&s_dcam_users)) {
+ /* firstly, stop AXI writing */
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_6, DCAM_AHBM_STS_REG);
+ }
+
+ /* then wait for AHB busy cleared */
+ while (++time_out < DCAM_AXI_STOP_TIMEOUT) {
+ if (0 == (REG_RD(DCAM_AHBM_STS) & BIT_0))
+ break;
+ }
+ if (time_out >= DCAM_AXI_STOP_TIMEOUT) {
+ printk("DCAM: reset TO: %d \n", time_out);
+ return DCAM_RTN_TIMEOUT;
+ }
+ }
+
+ /* do reset action */
+ switch (reset_mode) {
+ case DCAM_RST_PATH0:
+ sci_glb_set(DCAM_RST, PATH0_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH0_RST_BIT);
+ DCAM_TRACE("DCAM: reset path0 \n");
+ break;
+
+ case DCAM_RST_PATH1:
+ sci_glb_set(DCAM_RST, PATH1_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH1_RST_BIT);
+ DCAM_TRACE("DCAM: reset path1 \n");
+ break;
+
+ case DCAM_RST_PATH2:
+ sci_glb_set(DCAM_RST, PATH2_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH2_RST_BIT);
+ DCAM_TRACE("DCAM: reset path2 \n");
+ break;
+
+ case DCAM_RST_ALL:
+ sci_glb_set(DCAM_RST, DCAM_MOD_RST_BIT | CCIR_RST_BIT);
+ sci_glb_clr(DCAM_RST, DCAM_MOD_RST_BIT | CCIR_RST_BIT);
+ dcam_glb_reg_owr(DCAM_INT_CLR,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_CLR_REG);
+ dcam_glb_reg_owr(DCAM_INT_MASK,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_MASK_REG);
+ printk("DCAM: reset all \n");
+ break;
+ default:
+ rtn = DCAM_RTN_PARA_ERR;
+ break;
+ }
+
+ if (DCAM_RST_ALL == reset_mode) {
+ if (atomic_read(&s_dcam_users)) {
+ /* the end, enable AXI writing */
+ dcam_glb_reg_awr(DCAM_AHBM_STS, ~BIT_6, DCAM_AHBM_STS_REG);
+ }
+ }
+
+ if (!is_isr) {
+ mutex_unlock(&dcam_rot_sema);
+ }
+
+ DCAM_TRACE("DCAM: reset_mode=%x end \n", reset_mode);
+
+ return -rtn;
+}
+
+int32_t dcam_set_clk(struct device_node *dn, enum dcam_clk_sel clk_sel)
+{
+#ifdef CONFIG_SC_FPGA_CLK
+ return 0;
+#else
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct clk *clk_parent;
+ char *parent = "clk_312m";
+ int ret = 0;
+
+ switch (clk_sel) {
+ case DCAM_CLK_312M:
+ parent = "clk_312m";
+ break;
+ case DCAM_CLK_256M:
+ parent = "clk_256m";
+ break;
+ case DCAM_CLK_128M:
+ parent = "clk_128m";
+ break;
+ case DCAM_CLK_76M8:
+ parent = "clk_76p8m";
+ break;
+ case DCAM_CLK_NONE:
+ printk("DCAM close CLK %d \n", (int)clk_get_rate(s_dcam_clk));
+ if (s_dcam_clk) {
+ clk_disable(s_dcam_clk);
+ clk_put(s_dcam_clk);
+ s_dcam_clk = NULL;
+ }
+ return 0;
+ default:
+ parent = "clk_128m";
+ break;
+ }
+
+ if (NULL == s_dcam_clk) {
+ s_dcam_clk = parse_clk(dn,"clk_dcam");
+ if (IS_ERR(s_dcam_clk)) {
+ printk("DCAM: clk_get fail, %d \n", (int)s_dcam_clk);
+ return -1;
+ } else {
+ DCAM_TRACE("DCAM: get clk_parent ok \n");
+ }
+ } else {
+ clk_disable(s_dcam_clk);
+ }
+
+ clk_parent = clk_get(NULL, parent);
+ if (IS_ERR(clk_parent)) {
+ printk("DCAM: dcam_set_clk fail, %d \n", (int)clk_parent);
+ return -1;
+ } else {
+ DCAM_TRACE("DCAM: get clk_parent ok \n");
+ }
+
+ ret = clk_set_parent(s_dcam_clk, clk_parent);
+ if(ret){
+ printk("DCAM: clk_set_parent fail, %d \n", ret);
+ }
+
+ ret = clk_enable(s_dcam_clk);
+ if (ret) {
+ printk("enable dcam clk error.\n");
+ return -1;
+ }
+ return rtn;
+#endif
+}
+
+int32_t dcam_update_path(enum dcam_path_index path_index, struct dcam_size *in_size,
+ struct dcam_rect *in_rect, struct dcam_size *out_size)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flags;
+ uint32_t is_deci = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ rtn = dcam_path1_cfg(DCAM_PATH_INPUT_SIZE, in_size);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path1_cfg(DCAM_PATH_INPUT_RECT, in_rect);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path1_cfg(DCAM_PATH_OUTPUT_SIZE, out_size);
+ DCAM_RTN_IF_ERR;
+ rtn = _dcam_path_check_deci(DCAM_PATH_IDX_1, &is_deci);
+ DCAM_RTN_IF_ERR;
+ DCAM_TRACE("DCAM: To update path1 \n");
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_1);
+ DCAM_RTN_IF_ERR;
+ DCAM_TRACE("DCAM: dcam_update_path 1 \n");
+ if (s_dcam_sc_array->is_smooth_zoom) {
+ spin_lock_irqsave(&dcam_lock, flags);
+ s_p_dcam_mod->dcam_path1.is_update = 1;
+ spin_unlock_irqrestore(&dcam_lock, flags);
+ } else {
+ _dcam_wait_update_done(DCAM_PATH_IDX_1, &s_p_dcam_mod->dcam_path1.is_update);
+ }
+ if (!s_dcam_sc_array->is_smooth_zoom) {
+ _dcam_wait_update_done(DCAM_PATH_IDX_1, NULL);
+ }
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ local_irq_save(flags);
+ if(s_p_dcam_mod->dcam_path2.is_update){
+ local_irq_restore(flags);
+ DCAM_TRACE("DCAM: dcam_update_path 2: updating return \n");
+ return rtn;
+ }
+ local_irq_restore(flags);
+
+ rtn = dcam_path2_cfg(DCAM_PATH_INPUT_SIZE, in_size);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path2_cfg(DCAM_PATH_INPUT_RECT, in_rect);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path2_cfg(DCAM_PATH_OUTPUT_SIZE, out_size);
+ DCAM_RTN_IF_ERR;
+
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_2);
+ DCAM_RTN_IF_ERR;
+
+ local_irq_save(flags);
+ s_p_dcam_mod->dcam_path2.is_update = 1;
+ local_irq_restore(flags);
+ }
+
+ DCAM_TRACE("DCAM: dcam_update_path: done \n");
+
+ return -rtn;
+}
+
+int32_t dcam_start_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ uint32_t cap_en = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: start_path: path %d, mode %x path 0,1,2 {%d %d %d} \n",
+ path_index,
+ s_p_dcam_mod->dcam_mode,
+ s_p_dcam_mod->dcam_path0.valide,
+ s_p_dcam_mod->dcam_path1.valide,
+ s_p_dcam_mod->dcam_path2.valide);
+
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_8, DCAM_AHBM_STS_REG); // aiden add: write arbit mode
+
+ cap_en = REG_RD(DCAM_CONTROL) & BIT_2;
+ DCAM_TRACE("DCAM: cap_eb %d \n", cap_en);
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ _dcam_path0_set();
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, true);
+ DCAM_RTN_IF_ERR;
+ if (cap_en) {
+ /* if cap is already open, the sequence is:
+ cap force copy -> path 0 enable -> cap auto copy */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_0, 1 << 0, DCAM_CONTROL_REG); /* Cap force copy */
+ dcam_glb_reg_owr(DCAM_CFG, BIT_0, DCAM_CFG_REG); /* Enable Path 0 */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_1, 1 << 1, DCAM_CONTROL_REG); /* Cap auto copy, trigger path 0 enable */
+ } else {
+ dcam_glb_reg_owr(DCAM_CFG, BIT_0, DCAM_CFG_REG); /* Enable Path 0 */
+ }
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+
+ //rtn = _dcam_path_trim(DCAM_PATH_IDX_1);
+ //DCAM_RTN_IF_ERR;
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_1);
+ DCAM_RTN_IF_ERR;
+
+ _dcam_path1_set(&s_p_dcam_mod->dcam_path1);
+ DCAM_TRACE("DCAM: start path: path_control=%x \n", REG_RD(DCAM_CONTROL));
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy_ext(DCAM_PATH_IDX_1, true, true);
+ DCAM_TRACE("DCAM: int= %x \n", REG_RD(DCAM_INT_STS));
+ dcam_glb_reg_owr(DCAM_CFG, BIT_1, DCAM_CFG_REG);
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_2);
+ DCAM_RTN_IF_ERR;
+
+ _dcam_path2_set();
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy_ext(DCAM_PATH_IDX_2, true, true);
+ dcam_glb_reg_owr(DCAM_CFG, BIT_2, DCAM_CFG_REG);
+ }
+
+ printk("DCAM PATH S: %d \n", path_index);
+
+ if (0 == cap_en) {
+#ifdef DCAM_DEBUG
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_5 | BIT_4, 1 << 4);
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_5 | BIT_4, 1 << 4);
+#endif
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_0, 1 << 0, DCAM_CONTROL_REG); /* Cap force copy */
+ //REG_MWR(DCAM_CONTROL, BIT_1, 1 << 1); /* Cap auto copy */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 1 << 2, DCAM_CONTROL_REG); /* Cap Enable */
+ }
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, false);
+ DCAM_RTN_IF_ERR;
+ _dcam_auto_copy(DCAM_PATH_IDX_0);
+ s_p_dcam_mod->dcam_path0.status = DCAM_ST_START;
+ }
+
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ s_p_dcam_mod->dcam_path1.need_wait = 0;
+ s_p_dcam_mod->dcam_path1.status = DCAM_ST_START;
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ s_p_dcam_mod->dcam_path2.need_wait = 0;
+ s_p_dcam_mod->dcam_path2.status = DCAM_ST_START;
+ }
+
+ if (DCAM_PATH_IDX_ALL != path_index) {
+ if ((DCAM_PATH_IDX_0 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_0, NULL);
+ } else if ((DCAM_PATH_IDX_1 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_1, NULL);
+ } else if ((DCAM_PATH_IDX_2 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_2, NULL);
+ }
+ }
+
+ printk("DCAM PATH S: %d \n", path_index);
+
+ _dcam_reg_trace();
+
+ DCAM_TRACE("DCAM: start_path E\n");
+ return -rtn;
+}
+
+int32_t dcam_start(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ int ret = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: dcam_start %x \n", s_p_dcam_mod->dcam_mode);
+
+ ret = dcam_start_path(DCAM_PATH_IDX_ALL);
+ //ret = dcam_start_path(DCAM_PATH_IDX_1);
+
+ return -rtn;
+}
+
+int32_t dcam_stop_cap(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+#if 0
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ printk("DCAM: stop cap %d \n", s_p_dcam_mod->dcam_mode);
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 0, DCAM_CONTROL_REG); /* Cap Enable */
+ DCAM_TRACE("DCAM: stop cap, s_resize_flag %d \n", atomic_read(&s_resize_flag));
+ if (atomic_read(&s_resize_flag)) {
+ s_p_dcam_mod->wait_resize_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->resize_done_sema, DCAM_PATH_TIMEOUT);
+ }
+ if (atomic_read(&s_rotation_flag)) {
+ s_p_dcam_mod->wait_rotation_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->rotation_done_sema, DCAM_PATH_TIMEOUT);
+ }
+
+ dcam_reset(DCAM_RST_ALL, 0);
+ DCAM_TRACE("DCAM: stop cap, Out \n");
+#endif
+ return -rtn;
+}
+
+int32_t _dcam_stop_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ spin_lock_irqsave(&dcam_lock, flag);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: stop path Wrong index 0x%x \n", path_index);
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ return -rtn;
+ }
+
+ _dcam_wait_for_quickstop(path_index);
+ p_path->status = DCAM_ST_STOP;
+ p_path->valide = 0;
+ _dcam_frm_clear(path_index);
+
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ return rtn;
+}
+
+int32_t dcam_stop_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ printk("DCAM: stop_path 0x%x \n", path_index);
+
+ if (path_index < DCAM_PATH_IDX_0 ||
+ path_index >= DCAM_PATH_IDX_ALL) {
+ printk("DCAM: error path_index \n");
+ return -rtn;
+ }
+
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_0, &s_p_dcam_mod->dcam_path0.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_0);
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_1, &s_p_dcam_mod->dcam_path1.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_1);
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ DCAM_TRACE("DCAM: stop path2 In \n");
+ _dcam_wait_path_done(DCAM_PATH_IDX_2, &s_p_dcam_mod->dcam_path2.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_2);
+ }
+
+ DCAM_TRACE("DCAM dcam_stop_path E: %d \n", path_index);
+
+ return -rtn;
+}
+
+LOCAL void _dcam_wait_for_channel_stop(enum dcam_path_index path_index)
+{
+ int time_out = 5000;
+ uint32_t ret = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ /* wait for AHB path busy cleared */
+ while (time_out) {
+ if (s_p_dcam_mod->dcam_path1.valide && (DCAM_PATH_IDX_1 & path_index)) {
+ ret = REG_RD(DCAM_AHBM_STS) & BIT_17;
+ } else if (s_p_dcam_mod->dcam_path2.valide && (DCAM_PATH_IDX_2 & path_index)) {
+ ret = REG_RD(DCAM_AHBM_STS) & BIT_18;
+ } else {
+ /*nothing*/
+ }
+ if (!ret) {
+ break;
+ }
+ time_out --;
+ }
+
+ DCAM_TRACE("DCAM: wait channel stop %d %d \n", ret, time_out);
+
+ return;
+}
+
+LOCAL void _dcam_quickstop_set(enum dcam_path_index path_index, uint32_t path_rst, uint32_t path_bit,
+ uint32_t cfg_bit, uint32_t ahbm_bit, uint32_t auto_copy_bit)
+{
+ dcam_glb_reg_owr(DCAM_AHBM_STS, ahbm_bit, DCAM_AHBM_STS_REG);
+ udelay(1000);
+ dcam_glb_reg_mwr(DCAM_CFG, cfg_bit, ~cfg_bit, DCAM_CFG_REG);
+ _dcam_wait_for_channel_stop(path_index);
+ _dcam_force_copy(path_index);
+ dcam_reset(path_rst, 0);
+ dcam_glb_reg_awr(DCAM_AHBM_STS, ~ahbm_bit, DCAM_AHBM_STS_REG);
+
+ return;
+}
+
+#define DCAM_IRQ_MASK_PATH0 (0x0f|(0x03<<4)|(1<<12)|(1<<21)) //let other module continue
+#define DCAM_IRQ_MASK_PATH1 (0x0f|(0x03<<6)|(1<<16)|(1<<19)|(1<<22))
+#define DCAM_IRQ_MASK_PATH2 (0x0f|(0x03<<8)|(1<<17)|(1<<20)|(1<<23))
+
+LOCAL void _dcam_quickstop_set_all(enum dcam_path_index path_index, uint32_t path_bit, uint32_t cfg_bit, uint32_t ahbm_bit)
+{
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_3 | BIT_4 | BIT_5, DCAM_AHBM_STS_REG);
+ udelay(10);
+ dcam_glb_reg_awr(DCAM_CFG, ~(BIT_0 | BIT_1 | BIT_2), DCAM_CFG_REG);
+ dcam_glb_reg_owr(DCAM_CONTROL, BIT_10 | BIT_12, DCAM_CONTROL_REG);
+ dcam_glb_reg_awr(DCAM_CONTROL, ~(BIT_10 | BIT_12), DCAM_CONTROL_REG);
+ _dcam_wait_for_channel_stop(DCAM_PATH_IDX_0);
+ _dcam_wait_for_channel_stop(DCAM_PATH_IDX_1);
+ _dcam_wait_for_channel_stop(DCAM_PATH_IDX_2);
+
+ return;
+}
+
+LOCAL void _dcam_wait_for_quickstop(enum dcam_path_index path_index)
+{
+ int time_out = 5000;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: state before stop 0x%x\n", s_p_dcam_mod->state);
+
+ if (DCAM_PATH_IDX_ALL == path_index) {
+ _dcam_quickstop_set_all(0, 0, 0, 0);
+ } else {
+ if (s_p_dcam_mod->dcam_path0.valide && (DCAM_PATH_IDX_0 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_0, DCAM_RST_PATH0, DCAM_IRQ_MASK_PATH0, BIT_0, BIT_3, BIT_9);
+ }
+ if (s_p_dcam_mod->dcam_path1.valide && (DCAM_PATH_IDX_1 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_1, DCAM_RST_PATH1, DCAM_IRQ_MASK_PATH1, BIT_1, BIT_4, BIT_11);
+ }
+ if (s_p_dcam_mod->dcam_path2.valide && (DCAM_PATH_IDX_2 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_2, DCAM_RST_PATH2, DCAM_IRQ_MASK_PATH2, BIT_2, BIT_5, BIT_13);
+ }
+ }
+
+ DCAM_TRACE("DCAM: exit _dcam_wait_for_quickstop %d state: 0x%x \n ", time_out, s_p_dcam_mod->state);
+
+ return;
+}
+
+int32_t dcam_stop(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ s_p_dcam_mod->state |= DCAM_STATE_QUICKQUIT;
+ printk("DCAM dcam_stop In \n");
+ if (atomic_read(&s_resize_flag)) {
+ s_p_dcam_mod->wait_resize_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->resize_done_sema, DCAM_PATH_TIMEOUT);
+ }
+ if (atomic_read(&s_rotation_flag)) {
+ s_p_dcam_mod->wait_rotation_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->rotation_done_sema, DCAM_PATH_TIMEOUT);
+ }
+
+ printk("DCAM dcam_stop get dcam_sem\n");
+ mutex_lock(&dcam_scale_sema);
+ spin_lock_irqsave(&dcam_lock, flag);
+
+ dcam_glb_reg_owr(DCAM_INT_MASK,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_MASK_REG);
+
+ _dcam_wait_for_quickstop(DCAM_PATH_IDX_ALL);
+ s_p_dcam_mod->dcam_path0.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path0.valide = 0;
+ s_p_dcam_mod->dcam_path1.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path1.valide = 0;
+ s_p_dcam_mod->dcam_path2.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path2.valide = 0;
+ _dcam_frm_clear(DCAM_PATH_IDX_0);
+ _dcam_frm_clear(DCAM_PATH_IDX_1);
+ _dcam_frm_clear(DCAM_PATH_IDX_2);
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ dcam_reset(DCAM_RST_ALL, 0);
+ s_p_dcam_mod->state &= ~DCAM_STATE_QUICKQUIT;
+ mutex_unlock(&dcam_scale_sema);
+ printk("DCAM: dcam_stop Out, s_resize_flag %d \n", atomic_read(&s_resize_flag));
+
+ return -rtn;
+}
+
+int32_t dcam_resume(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->dcam_path1.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy(DCAM_PATH_IDX_1);
+ _dcam_frm_clear(DCAM_PATH_IDX_1);
+ }
+
+ if (s_p_dcam_mod->dcam_path2.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy(DCAM_PATH_IDX_2);
+ _dcam_frm_clear(DCAM_PATH_IDX_2);
+ }
+
+
+ if (s_p_dcam_mod->dcam_path1.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, false);
+ DCAM_RTN_IF_ERR;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_1, DCAM_CFG_REG);
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_1, true, true);
+ }
+
+ if (s_p_dcam_mod->dcam_path2.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, false);
+ DCAM_RTN_IF_ERR;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_2, DCAM_CFG_REG);
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_2, true, true);
+ }
+
+ printk("DCAM R \n");
+
+ dcam_glb_reg_owr(DCAM_CONTROL, BIT_2, DCAM_CONTROL_REG); /* Enable CAP */
+ return -rtn;
+}
+
+int32_t dcam_pause(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ dcam_glb_reg_awr(DCAM_CONTROL, ~BIT_2, DCAM_CONTROL_REG); /* Disable CAP */
+ printk("DCAM P \n");
+ return -rtn;
+}
+
+int32_t dcam_reg_isr(enum dcam_irq_id id, dcam_isr_func user_func, void* user_data)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ if(id >= DCAM_IRQ_NUMBER) {
+ rtn = DCAM_RTN_ISR_ID_ERR;
+ } else {
+ spin_lock_irqsave(&dcam_lock, flag);
+ s_user_func[id] = user_func;
+ s_user_data[id] = user_data;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ }
+ return -rtn;
+}
+
+int32_t dcam_cap_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ switch (id) {
+ case DCAM_CAP_SYNC_POL:
+ {
+ struct dcam_cap_sync_pol *sync_pol = (struct dcam_cap_sync_pol*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+
+ if (sync_pol->vsync_pol > 1 ||
+ sync_pol->hsync_pol > 1 ||
+ sync_pol->pclk_pol > 1) {
+ rtn = DCAM_RTN_CAP_SYNC_POL_ERR;
+ } else {
+ sci_glb_set(DCAM_CCIR_PCLK_EB, CCIR_PCLK_EB_BIT);
+ REG_MWR(CAP_CCIR_CTRL, BIT_3, sync_pol->hsync_pol << 3);
+ REG_MWR(CAP_CCIR_CTRL, BIT_4, sync_pol->vsync_pol << 4);
+ //REG_MWR(CLK_DLY_CTRL, BIT_19, sync_pol->pclk_pol << 19); // aiden todo
+
+ if (sync_pol->pclk_src == 0x00) {
+ sci_glb_clr(CAP_CCIR_PLCK_SRC, (BIT_25 | BIT_26));
+ DCAM_TRACE("DCAM: set pclk src0\n");
+ } else if (sync_pol->pclk_src == 0x01) {
+ sci_glb_clr(CAP_CCIR_PLCK_SRC, (BIT_25 | BIT_26));
+ sci_glb_set(CAP_CCIR_PLCK_SRC, (BIT_25));
+ DCAM_TRACE("DCAM: set pclk src1\n");
+ } else {
+ DCAM_TRACE("DCAM: set pclk src default\n");
+ }
+ }
+ } else {
+ if (sync_pol->need_href) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_5, 1 << 5);
+ } else {
+ REG_MWR(CAP_MIPI_CTRL, BIT_5, 0 << 5);
+ }
+ }
+ break;
+ }
+
+ case DCAM_CAP_DATA_BITS:
+ {
+ enum dcam_cap_data_bits bits = *(enum dcam_cap_data_bits*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ if (DCAM_CAP_8_BITS == bits || DCAM_CAP_10_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 0 << 9);
+ } else if (DCAM_CAP_4_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 1 << 9);
+ } else if (DCAM_CAP_2_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 2 << 9);
+ } else if (DCAM_CAP_1_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 3 << 9);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_BITS_ERR;
+ }
+
+ } else {
+ if (DCAM_CAP_12_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 2 << 3);
+ } else if (DCAM_CAP_10_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 1 << 3);
+ } else if (DCAM_CAP_8_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 0 << 3);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_BITS_ERR;
+ }
+ }
+ break;
+ }
+
+ case DCAM_CAP_YUV_TYPE:
+ {
+ enum dcam_cap_pattern pat = *(enum dcam_cap_pattern*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (pat < DCAM_PATTERN_MAX) {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_CTRL, BIT_8 | BIT_7, pat << 7);
+ else
+ REG_MWR(CAP_MIPI_CTRL, BIT_8 | BIT_7, pat << 7);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_YUV_ERR;
+ }
+ break;
+ }
+
+ case DCAM_CAP_PRE_SKIP_CNT:
+ {
+ uint32_t skip_num = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (skip_num > DCAM_CAP_SKIP_FRM_MAX) {
+ rtn = DCAM_RTN_CAP_SKIP_FRAME_ERR;
+ } else {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_3 | BIT_2 | BIT_1 | BIT_0, skip_num);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_3 | BIT_2 | BIT_1 | BIT_0, skip_num);
+ }
+ break;
+ }
+
+ case DCAM_CAP_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor < DCAM_FRM_DECI_FAC_MAX) {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_5 | BIT_4, deci_factor << 4);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_5 | BIT_4, deci_factor << 4);
+ } else {
+ rtn = DCAM_RTN_CAP_FRAME_DECI_ERR;
+ }
+ break;
+ }
+
+ case DCAM_CAP_FRM_COUNT_CLR:
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_22, 1 << 22);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_22, 1 << 22);
+ break;
+
+ case DCAM_CAP_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+ uint32_t tmp = 0;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+#if 0
+ if (rect->x > DCAM_CAP_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_CAP_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_CAP_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_CAP_FRAME_HEIGHT_MAX ) {
+ rtn = DCAM_RTN_CAP_FRAME_SIZE_ERR;
+ return -rtn;
+ }
+#endif
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ tmp = rect->x | (rect->y << 16);
+ REG_WR(CAP_CCIR_START, tmp);
+ tmp = (rect->x + rect->w - 1);
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_CCIR_END, tmp);
+ } else {
+ tmp = (rect->x << 1) | (rect->y << 16);
+ REG_WR(CAP_CCIR_START, tmp);
+ tmp = ((rect->x + rect->w) << 1) - 1;
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_CCIR_END, tmp);
+ }
+ } else {
+ tmp = rect->x | (rect->y << 16);
+ REG_WR(CAP_MIPI_START, tmp);
+ tmp = (rect->x + rect->w - 1);
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_MIPI_END, tmp);
+ }
+ break;
+ }
+
+ case DCAM_CAP_IMAGE_XY_DECI:
+ {
+ struct dcam_cap_dec *cap_dec = (struct dcam_cap_dec*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (cap_dec->x_factor > DCAM_CAP_X_DECI_FAC_MAX ||
+ cap_dec->y_factor > DCAM_CAP_Y_DECI_FAC_MAX ) {
+ rtn = DCAM_RTN_CAP_XY_DECI_ERR;
+ } else {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ if (cap_dec->x_factor > 1 ||
+ cap_dec->y_factor > 1) {
+ rtn = DCAM_RTN_CAP_XY_DECI_ERR;
+ }
+ }
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ REG_MWR(CAP_CCIR_IMG_DECI, BIT_1 | BIT_0, cap_dec->x_factor);
+ REG_MWR(CAP_CCIR_IMG_DECI, BIT_3 | BIT_2, cap_dec->y_factor << 2);
+ } else {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ // REG_MWR(CAP_MIPI_IMG_DECI, BIT_0, cap_dec->x_factor); // for camera path
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_1, cap_dec->x_factor << 1);//for ISP
+ } else {
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_1 | BIT_0, cap_dec->x_factor);
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_3 | BIT_2, cap_dec->y_factor << 2);
+ }
+ }
+ }
+
+ break;
+ }
+
+ case DCAM_CAP_JPEG_SET_BUF_LEN:
+ {
+ uint32_t jpg_buf_size = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ jpg_buf_size = jpg_buf_size/DCAM_JPG_BUF_UNIT;
+ if (jpg_buf_size >= DCAM_JPG_UNITS) {
+ rtn = DCAM_RTN_CAP_JPEG_BUF_LEN_ERR;
+ } else {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_WR(CAP_CCIR_JPG_CTRL,jpg_buf_size);
+ else
+ REG_WR(CAP_MIPI_JPG_CTRL,jpg_buf_size);
+ }
+ break;
+ }
+
+ case DCAM_CAP_TO_ISP:
+ {
+ uint32_t need_isp = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (need_isp) {
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_7, 1 << 7, DCAM_CFG_REG);
+ } else {
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_7, 0 << 7, DCAM_CFG_REG);
+ }
+ break;
+ }
+
+ case DCAM_CAP_DATA_PACKET:
+ {
+ uint32_t is_loose = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface &&
+ DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ if (is_loose) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_0, 1);
+ } else {
+ REG_MWR(CAP_MIPI_CTRL, BIT_0, 0);
+ }
+ } else {
+ rtn = DCAM_RTN_MODE_ERR;
+ }
+
+ break;
+ }
+
+ case DCAM_CAP_SAMPLE_MODE:
+ {
+ enum dcam_capture_mode samp_mode = *(enum dcam_capture_mode*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (samp_mode >= DCAM_CAPTURE_MODE_MAX) {
+ rtn = DCAM_RTN_MODE_ERR;
+ } else {
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_6, samp_mode << 6);
+ } else {
+ REG_MWR(CAP_CCIR_CTRL, BIT_6, samp_mode << 6);
+ }
+ s_p_dcam_mod->dcam_mode = samp_mode;
+ }
+ break;
+ }
+
+ case DCAM_CAP_ZOOM_MODE:
+ {
+ uint32_t zoom_mode = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ s_dcam_sc_array->is_smooth_zoom = zoom_mode;
+ break;
+ }
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_cap_get_info(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ switch(id) {
+ case DCAM_CAP_FRM_COUNT_GET:
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ *(uint32_t*)param = REG_RD(CAP_MIPI_FRM_CTRL) >> 16;
+ } else {
+ *(uint32_t*)param = REG_RD(CAP_CCIR_FRM_CTRL) >> 16;
+ }
+ break;
+
+ case DCAM_CAP_JPEG_GET_LENGTH:
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ *(uint32_t*)param = REG_RD(CAP_MIPI_FRM_SIZE);
+ } else {
+ *(uint32_t*)param = REG_RD(CAP_CCIR_FRM_SIZE);
+ }
+ break;
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+ }
+ return -rtn;
+}
+
+int32_t dcam_path0_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH0_INPUT_SIZE {%d %d} \n", size->w, size->h);
+#if 0
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else
+#endif
+ {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_output_mode format = *(enum dcam_output_mode*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if((DCAM_OUTPUT_WORD != format) &&
+ (DCAM_OUTPUT_HALF_WORD != format) &&
+ (DCAM_OUTPUT_YVYU_1FRAME != format) &&
+ (DCAM_OUTPUT_YUV420 != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->output_format = format;
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path0.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path0.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_0_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH0;
+ frame.fid = s_p_dcam_mod->dcam_path0.frame_base_id;
+ DCAM_TRACE("DCAM: Path 0 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path0.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path0_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+
+ DCAM_TRACE("DCAM: Path 0 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ path->valide = *(uint32_t*)param;
+ break;
+ }
+
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_path1_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path1;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_INPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_INPUT_RECT {%d %d %d %d} \n",
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+
+ if (rect->x > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_PATH_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_TRIM_SIZE_ERR;
+ } else {
+ memcpy((void*)&path->input_rect,
+ (void*)rect,
+ sizeof(struct dcam_rect));
+ //if (path->input_rect.h >= DCAM_HEIGHT_MIN) {
+ // path->input_rect.h--;
+ //}
+ path->valid_param.input_rect = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_OUTPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->output_size.w = size->w;
+ path->output_size.h = size->h;
+ path->valid_param.output_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_fmt format = *(enum dcam_fmt*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ path->output_format = format;
+
+ if((DCAM_YUV422 != format) &&
+ (DCAM_YUV420 != format) &&
+ (DCAM_YUV420_3FRAME != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH1;
+ frame.fid = s_p_dcam_mod->dcam_path1.frame_base_id;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path1.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path1_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_SRC_SEL:
+ {
+ uint32_t src_sel = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (src_sel >= DCAM_PATH_FROM_NONE) {
+ rtn = DCAM_RTN_PATH_SRC_ERR;
+ } else {
+ path->src_sel = src_sel;
+ path->valid_param.src_sel = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path1.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->data_endian.uv_endian = endian->uv_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ path->valide = *(uint32_t*)param;
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path1.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_1_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+ case DCAM_PATH_ROT_MODE:
+ {
+ uint32_t rot_mode = *(uint32_t*)param;
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (rot_mode >= DCAM_PATH_FRAME_ROT_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ }else{
+ path->rot_mode = rot_mode;
+ path->valid_param.rot_mode = 1;
+ printk("zcf dcam_path1_cfg rot:\n",path->rot_mode);
+ }
+ }
+
+ case DCAM_PATH_SHRINK:
+ {
+ uint32_t shrink = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (shrink == 1) {
+ path->shrink = 1;
+ } else {
+ path->shrink = 0;
+ }
+ path->valid_param.shrink = 1;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_path2_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_INPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+
+ }
+ break;
+ }
+
+ case DCAM_PATH_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_INPUT_RECT {%d %d %d %d} \n",
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+
+ if (rect->x > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_PATH_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_TRIM_SIZE_ERR;
+ } else {
+ memcpy((void*)&path->input_rect,
+ (void*)rect,
+ sizeof(struct dcam_rect));
+#if 0
+ if (path->input_rect.h >= DCAM_HEIGHT_MIN) {
+ path->input_rect.h--;
+ }
+#endif
+ path->valid_param.input_rect = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_OUTPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->output_size.w = size->w;
+ path->output_size.h = size->h;
+ path->valid_param.output_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_fmt format = *(enum dcam_fmt*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if((DCAM_YUV422 != format) &&
+ (DCAM_YUV420 != format) &&
+ (DCAM_YUV420_3FRAME != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->output_format = format;
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH2;
+ frame.fid = s_p_dcam_mod->dcam_path2.frame_base_id;
+ DCAM_TRACE("DCAM: Path 2 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path2.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path2_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_SRC_SEL:
+ {
+ uint32_t src_sel = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (src_sel >= DCAM_PATH_FROM_NONE) {
+ rtn = DCAM_RTN_PATH_SRC_ERR;
+ } else {
+ path->src_sel = src_sel;
+ path->valid_param.src_sel = 1;
+
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path2.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->data_endian.uv_endian = endian->uv_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ path->valide = *(uint32_t*)param;
+
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path2.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_2_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_ROT_MODE:
+ {
+ uint32_t rot_mode = *(uint32_t*)param;
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (rot_mode >= DCAM_PATH_FRAME_ROT_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ }else{
+ path->rot_mode = rot_mode;
+ path->valid_param.rot_mode = 1;
+ printk("zcf dcam_path2_cfg rot:\n",path->rot_mode);
+ }
+ }
+
+ case DCAM_PATH_SHRINK:
+ {
+ uint32_t shrink = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (shrink == 1) {
+ path->shrink = 1;
+ } else {
+ path->shrink = 0;
+ }
+ path->valid_param.shrink = 1;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_get_resizer(uint32_t wait_opt)
+{
+ int32_t rtn = 0;
+
+ printk("resizer_get:%d\n",current->pid);
+
+
+ if( 0 == wait_opt) {
+ rtn = mutex_trylock(&dcam_sem) ? 0 : 1;
+ return rtn;
+ } else if (DCAM_WAIT_FOREVER == wait_opt){
+ mutex_lock(&dcam_sem);
+ return rtn;
+ } else {
+ return 0;//mutex_timeout(&dcam_sem, wait_opt);
+ }
+}
+
+int32_t dcam_rel_resizer(void)
+{
+ printk("resizer_put:%d\n",current->pid);
+ mutex_unlock(&dcam_sem);
+ return 0;
+}
+
+int32_t dcam_resize_start(void)
+{
+ atomic_inc(&s_resize_flag);
+ mutex_lock(&dcam_scale_sema);
+ return 0;
+}
+
+int32_t dcam_resize_end(void)
+{
+ unsigned long flag;
+
+ atomic_dec(&s_resize_flag);
+ mutex_unlock(&dcam_scale_sema);
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+ }
+
+ if (s_p_dcam_mod) {
+ if (s_p_dcam_mod->wait_resize_done) {
+ up(&s_p_dcam_mod->resize_done_sema);
+ s_p_dcam_mod->wait_resize_done = 0;
+ }
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+}
+
+int32_t dcam_rotation_start(void)
+{
+ atomic_inc(&s_rotation_flag);
+ mutex_lock(&dcam_rot_sema);
+ return 0;
+}
+
+int32_t dcam_rotation_end(void)
+{
+ unsigned long flag;
+
+ atomic_dec(&s_rotation_flag);
+ mutex_unlock(&dcam_rot_sema);
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+ }
+
+ if (s_p_dcam_mod) {
+ if (s_p_dcam_mod->wait_rotation_done) {
+ up(&s_p_dcam_mod->rotation_done_sema);
+ s_p_dcam_mod->wait_rotation_done = 0;
+ }
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+}
+
+void dcam_int_en(void)
+{
+ if (atomic_read(&s_dcam_users) == 1) {
+ enable_irq(DCAM_IRQ);
+ }
+}
+
+void dcam_int_dis(void)
+{
+ if (atomic_read(&s_dcam_users) == 1) {
+ disable_irq(DCAM_IRQ);
+ }
+}
+
+int32_t dcam_frame_is_locked(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (frame)
+ rtn = frame->lock == DCAM_FRM_LOCK_WRITE ? 1 : 0;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_frame_lock(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: lock %d \n", (uint32_t)(0xF&frame->fid));
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (likely(frame))
+ frame->lock = DCAM_FRM_LOCK_WRITE;
+ else
+ rtn = DCAM_RTN_PARA_ERR;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_frame_unlock(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: unlock %d \n", (uint32_t)(0xF&frame->fid));
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (likely(frame))
+ frame->lock = DCAM_FRM_UNLOCK;
+ else
+ rtn = DCAM_RTN_PARA_ERR;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_read_registers(uint32_t* reg_buf, uint32_t *buf_len)
+{
+ uint32_t *reg_addr = (uint32_t*)DCAM_BASE;
+
+ if (NULL == reg_buf || NULL == buf_len || 0 != (*buf_len % 4)) {
+ return -1;
+ }
+
+ if (atomic_read(&s_dcam_users) == 1) {
+ while (buf_len != 0 && (uint32_t)reg_addr < DCAM_END) {
+ *reg_buf++ = REG_RD(reg_addr);
+ reg_addr++;
+ *buf_len -= 4;
+ }
+ *buf_len = (uint32_t)reg_addr - DCAM_BASE;
+ }
+
+ return 0;
+}
+
+int32_t dcam_get_path_id(struct dcam_get_path_id *path_id, uint32_t *channel_id)
+{
+ int ret = DCAM_RTN_SUCCESS;
+
+ if (NULL == path_id || NULL == channel_id) {
+ return -1;
+ }
+
+ printk("DCAM: fourcc 0x%x, input w %d, h %d output w %d, h %d input_trim %d %d %d %d shrink %d need_isp %d\n", path_id->fourcc,
+ path_id->input_size.w, path_id->input_size.h,
+ path_id->output_size.w, path_id->output_size.h,
+ path_id->input_trim.x, path_id->input_trim.y, path_id->input_trim.w, path_id->input_trim.h,
+ path_id->need_shrink, path_id->need_isp);
+
+ if (path_id->need_isp_tool) {
+ *channel_id = DCAM_PATH0;
+ } else if (V4L2_PIX_FMT_GREY == path_id->fourcc && !path_id->is_path_work[DCAM_PATH0]) {
+ *channel_id = DCAM_PATH0;
+ } else if (V4L2_PIX_FMT_JPEG == path_id->fourcc && !path_id->is_path_work[DCAM_PATH0]) {
+ *channel_id = DCAM_PATH0;
+ } else if (path_id->output_size.w <= DCAM_PATH1_LINE_BUF_LENGTH && !path_id->is_path_work[DCAM_PATH1]) {
+ *channel_id = DCAM_PATH1;
+ } else if (path_id->output_size.w <= DCAM_PATH2_LINE_BUF_LENGTH && !path_id->is_path_work[DCAM_PATH2]) {
+ *channel_id = DCAM_PATH2;
+ } else {
+ *channel_id = DCAM_PATH0;
+ }
+ printk("DCAM: path id %d \n", *channel_id);
+
+ return ret;
+}
+
+int32_t dcam_get_path_capability(struct dcam_path_capability *capacity)
+{
+ int ret = DCAM_RTN_SUCCESS;
+
+ if (NULL == capacity) {
+ return -1;
+ }
+
+ capacity->count = 3;
+ capacity->path_info[DCAM_PATH0].line_buf = 0;
+ capacity->path_info[DCAM_PATH0].support_yuv = 0;
+ capacity->path_info[DCAM_PATH0].support_raw = 1;
+ capacity->path_info[DCAM_PATH0].support_jpeg = 1;
+ capacity->path_info[DCAM_PATH0].support_scaling = 0;
+ capacity->path_info[DCAM_PATH0].support_trim = 0;
+ capacity->path_info[DCAM_PATH0].is_scaleing_path = 0;
+
+ capacity->path_info[DCAM_PATH1].line_buf = DCAM_PATH1_LINE_BUF_LENGTH;
+ capacity->path_info[DCAM_PATH1].support_yuv = 1;
+ capacity->path_info[DCAM_PATH1].support_raw = 0;
+ capacity->path_info[DCAM_PATH1].support_jpeg = 0;
+ capacity->path_info[DCAM_PATH1].support_scaling = 1;
+ capacity->path_info[DCAM_PATH1].support_trim = 1;
+ capacity->path_info[DCAM_PATH1].is_scaleing_path = 0;
+
+ capacity->path_info[DCAM_PATH2].line_buf = DCAM_PATH2_LINE_BUF_LENGTH;
+ capacity->path_info[DCAM_PATH2].support_yuv = 1;
+ capacity->path_info[DCAM_PATH2].support_raw = 0;
+ capacity->path_info[DCAM_PATH2].support_jpeg = 0;
+ capacity->path_info[DCAM_PATH2].support_scaling = 1;
+ capacity->path_info[DCAM_PATH2].support_trim = 1;
+ capacity->path_info[DCAM_PATH2].is_scaleing_path = 1;
+
+ return ret;
+}
+
+
+LOCAL irqreturn_t _dcam_isr_root(int irq, void *dev_id)
+{
+ uint32_t irq_line, status;
+ unsigned long flag;
+ int32_t i;
+
+ DCAM_TRACE("DCAM: ISR 0x%x \n", REG_RD(DCAM_INT_STS));
+ status = REG_RD(DCAM_INT_STS) & DCAM_IRQ_LINE_MASK;
+ if (unlikely(0 == status)) {
+ return IRQ_NONE;
+ }
+
+ irq_line = status;
+ if (unlikely(DCAM_IRQ_ERR_MASK & status)) {
+ if (_dcam_err_pre_proc()) {
+ return IRQ_NONE;
+ }
+ }
+
+ spin_lock_irqsave(&dcam_lock,flag);
+
+ //for (i = DCAM_IRQ_NUMBER - 1; i >= 0; i--) {
+ for (i = 0; i < DCAM_IRQ_NUMBER; i++) {
+ if (irq_line & (1 << (uint32_t)i)) {
+ if (isr_list[i]) {
+ isr_list[i]();
+ }
+ }
+ irq_line &= ~(uint32_t)(1 << (uint32_t)i); //clear the interrupt flag
+ if(!irq_line) //no interrupt source left
+ break;
+ }
+
+ REG_WR(DCAM_INT_CLR, status);
+ DCAM_TRACE("DCAM: status 0x%x, ISR 0x%x \n", status, REG_RD(DCAM_INT_STS));
+
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ return IRQ_HANDLED;
+}
+
+LOCAL void _dcam_path0_set(void)
+{
+ uint32_t reg_val = 0;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH0_SRC_SIZE, reg_val);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_1 | BIT_0, path->frame_deci << 0);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_output_mode format = path->output_format;
+ REG_MWR(DCAM_PATH0_CFG, BIT_2, format << 2);
+ DCAM_TRACE("DCAM: path 0: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_5 | BIT_4, path->data_endian.y_endian << 4, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM DRV: path 0: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+}
+LOCAL void _dcam_path1_set(struct dcam_path_desc *path)
+{
+ uint32_t reg_val = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ DCAM_CHECK_ZERO_VOID(path);
+
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH1_SRC_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: src {%d %d} \n",path->input_size.w, path->input_size.h);
+ }
+
+ if (path->valid_param.input_rect) {
+ reg_val = path->input_rect.x | (path->input_rect.y << 16);
+ REG_WR(DCAM_PATH1_TRIM_START, reg_val);
+ reg_val = path->input_rect.w | (path->input_rect.h << 16);
+ REG_WR(DCAM_PATH1_TRIM_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: rect {%d %d %d %d} \n",
+ path->input_rect.x,
+ path->input_rect.y,
+ path->input_rect.w,
+ path->input_rect.h);
+ }
+
+ if (path->valid_param.output_size) {
+ reg_val = path->output_size.w | (path->output_size.h << 16);
+ REG_WR(DCAM_PATH1_DST_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: dst {%d %d} \n",path->output_size.w, path->output_size.h);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_fmt format = path->output_format;
+ if (DCAM_YUV422 == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 0 << 6);
+ } else if (DCAM_YUV420 == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 1 << 6);
+ } else if (DCAM_YUV420_3FRAME == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 3 << 6);
+ } else {
+ DCAM_TRACE("DCAM: invalid path 1 output format %d \n", format);
+ }
+ DCAM_TRACE("DCAM: path 1: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.src_sel) {
+ REG_MWR(DCAM_CFG, BIT_12 | BIT_11, path->src_sel << 11);
+ DCAM_TRACE("DCAM: path 1: src_sel=0x%x \n", path->src_sel);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_7 | BIT_6, path->data_endian.y_endian << 6, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_9 | BIT_8, path->data_endian.uv_endian << 8, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM: path 1: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_24 | BIT_23, path->frame_deci << 23);
+ DCAM_TRACE("DCAM: path 1: frame_deci=0x%x \n", path->frame_deci);
+ }
+
+ if (path->valid_param.scale_tap) {
+ path->valid_param.scale_tap = 0;
+ REG_MWR(DCAM_PATH1_CFG, BIT_19 | BIT_18 | BIT_17 | BIT_16, (path->scale_tap.y_tap & 0x0F) << 16);
+ REG_MWR(DCAM_PATH1_CFG, BIT_15 | BIT_14 | BIT_13 | BIT_12 | BIT_11, (path->scale_tap.uv_tap & 0x1F) << 11);
+ DCAM_TRACE("DCAM: path 1: scale_tap, y=0x%x, uv=0x%x \n", path->scale_tap.y_tap, path->scale_tap.uv_tap);
+ }
+
+ if (path->valid_param.v_deci) {
+ path->valid_param.v_deci = 0;
+ REG_MWR(DCAM_PATH1_CFG, BIT_2, path->deci_val.deci_x_en << 2);
+ REG_MWR(DCAM_PATH1_CFG, BIT_1 | BIT_0, path->deci_val.deci_x);
+
+ REG_MWR(DCAM_PATH1_CFG, BIT_5, path->deci_val.deci_y_en << 5);
+ REG_MWR(DCAM_PATH1_CFG, BIT_4 | BIT_3, path->deci_val.deci_y << 3);
+ DCAM_TRACE("DCAM: path 1: deci, x_en=%d, x=%d, y_en=%d, y=%d \n",
+ path->deci_val.deci_x_en, path->deci_val.deci_x, path->deci_val.deci_y_en, path->deci_val.deci_y);
+ }
+
+ if(path->valid_param.rot_mode){
+ path->valid_param.rot_mode = 0;
+ printk("zcf dcam_path1_set 1 rot_mod :%d reg:%x\n",path->rot_mode,REG_RD(DCAM_PATH1_CFG));
+ REG_MWR(DCAM_PATH1_CFG, BIT_10 | BIT_9, path->rot_mode << 9);
+ printk("zcf dcam_path1_set 1 rot_mod :%d reg:%x\n",path->rot_mode,REG_RD(DCAM_PATH1_CFG));
+ }
+
+ if (path->valid_param.shrink) {
+ path->valid_param.shrink = 0;
+ REG_MWR(DCAM_PATH1_CFG, BIT_25 | BIT_26, path->shrink << 25);
+ DCAM_TRACE("DCAM: path 1: shrink, %d \n", path->shrink);
+ }
+}
+
+LOCAL void _dcam_path2_set(void)
+{
+ struct dcam_path_desc *path = NULL;
+ uint32_t reg_val = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH2_SRC_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: src {%d %d} \n",path->input_size.w, path->input_size.h);
+ }
+
+ if (path->valid_param.input_rect) {
+ reg_val = path->input_rect.x | (path->input_rect.y << 16);
+ REG_WR(DCAM_PATH2_TRIM_START, reg_val);
+ reg_val = path->input_rect.w | (path->input_rect.h << 16);
+ REG_WR(DCAM_PATH2_TRIM_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: rect {%d %d %d %d} \n",
+ path->input_rect.x,
+ path->input_rect.y,
+ path->input_rect.w,
+ path->input_rect.h);
+ }
+
+ if(path->valid_param.output_size){
+ reg_val = path->output_size.w | (path->output_size.h << 16);
+ REG_WR(DCAM_PATH2_DST_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: dst {%d %d} \n",path->output_size.w, path->output_size.h);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_fmt format = path->output_format;
+
+ // REG_MWR(DCAM_PATH2_CFG, BIT_8, 0 << 8); // aiden todo
+
+ if (DCAM_YUV422 == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 0 << 6);
+ } else if (DCAM_YUV420 == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 1 << 6);
+ } else if (DCAM_YUV420_3FRAME == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 3 << 6);
+ } else {
+ DCAM_TRACE("DCAM: invalid path 2 output format %d \n", format);
+ }
+ DCAM_TRACE("DCAM: path 2: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.src_sel) {
+ REG_MWR(DCAM_CFG, BIT_14 | BIT_13, path->src_sel << 13);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_11 | BIT_10, path->data_endian.y_endian << 10,DCAM_ENDIAN_REG );
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_13 | BIT_12, path->data_endian.uv_endian << 12, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM: path 2: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_24 | BIT_23, path->frame_deci << 23);
+ DCAM_TRACE("DCAM: path 2: frame_deci=0x%x \n", path->frame_deci);
+ }
+
+ if (path->valid_param.scale_tap) {
+ path->valid_param.scale_tap = 0;
+ REG_MWR(DCAM_PATH2_CFG, BIT_19 | BIT_18 | BIT_17 | BIT_16, (path->scale_tap.y_tap & 0x0F) << 16);
+ REG_MWR(DCAM_PATH2_CFG, BIT_15 | BIT_14 | BIT_13 | BIT_12 | BIT_11, (path->scale_tap.uv_tap & 0x1F) << 11);
+ DCAM_TRACE("DCAM: path 2: scale_tap, y=0x%x, uv=0x%x \n",
+ path->scale_tap.y_tap, path->scale_tap.uv_tap);
+ }
+
+ if (path->valid_param.v_deci) {
+ path->valid_param.v_deci = 0;
+ REG_MWR(DCAM_PATH2_CFG, BIT_2, path->deci_val.deci_x_en << 2);
+ REG_MWR(DCAM_PATH2_CFG, BIT_1 | BIT_0, path->deci_val.deci_x);
+
+ REG_MWR(DCAM_PATH2_CFG, BIT_5, path->deci_val.deci_y_en << 5);
+ REG_MWR(DCAM_PATH2_CFG, BIT_4 | BIT_3, path->deci_val.deci_y << 3);
+ DCAM_TRACE("DCAM: path 2: deci, x_en=%d, x=%d, y_en=%d, y=%d \n",
+ path->deci_val.deci_x_en, path->deci_val.deci_x, path->deci_val.deci_y_en, path->deci_val.deci_y);
+ }
+
+ if (path->valid_param.rot_mode){
+ path->valid_param.rot_mode = 0;
+ printk("zcf dcam_path2_set rot_mod :%d reg:%x\n",path->rot_mode,REG_RD(DCAM_PATH2_CFG));
+ REG_MWR(DCAM_PATH2_CFG, BIT_10 | BIT_9, path->rot_mode << 9);
+ printk("zcf dcam_path2_set rot_mod :%d reg:%x\n",path->rot_mode,REG_RD(DCAM_PATH2_CFG));
+ }
+
+ if (path->valid_param.shrink) {
+ path->valid_param.shrink = 0;
+ REG_MWR(DCAM_PATH2_CFG, BIT_25 | BIT_26, path->shrink << 25);
+ DCAM_TRACE("DCAM: path 2: shrink, %d \n", path->shrink);
+ }
+}
+
+LOCAL void _dcam_buf_queue_init(struct dcam_buf_queue *queue)
+{
+ if (DCAM_ADDR_INVALID(queue)) {
+ printk("DCAM: invalid heap 0x%x \n", (uint32_t)queue);
+ return;
+ }
+
+ memset((void*)queue, 0, sizeof(struct dcam_buf_queue));
+ queue->write = &queue->frame[0];
+ queue->read = &queue->frame[0];
+ spin_lock_init(&queue->lock);
+ return;
+}
+
+LOCAL int32_t _dcam_buf_queue_write(struct dcam_buf_queue *queue, struct dcam_frame *frame)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_frame *ori_frame;
+ unsigned long flag;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: enq, invalid param 0x%x, 0x%x \n",
+ (uint32_t)queue,
+ (uint32_t)frame);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&queue->lock, flag);
+ ori_frame = queue->write;
+ DCAM_TRACE("DCAM: _dcam_buf_queue_write \n");
+ *queue->write++ = *frame;
+ if (queue->write > &queue->frame[DCAM_FRM_CNT_MAX-1]) {
+ queue->write = &queue->frame[0];
+ }
+
+ if (queue->write == queue->read) {
+ queue->write = ori_frame;
+ printk("DCAM: warning, queue is full, cannot write 0x%lx \n", frame->yaddr);
+ }
+ spin_unlock_irqrestore(&queue->lock, flag);
+ DCAM_TRACE("DCAM: _dcam_buf_queue_write type %d \n", frame->type);
+ return ret;
+}
+
+LOCAL int32_t _dcam_buf_queue_read(struct dcam_buf_queue *queue, struct dcam_frame *frame)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: deq, invalid param 0x%x, 0x%x \n",
+ (uint32_t)queue,
+ (uint32_t)frame);
+ return -EINVAL;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_buf_queue_read \n");
+
+ spin_lock_irqsave(&queue->lock, flag);
+ if (queue->read != queue->write) {
+ *frame = *queue->read++;
+ if (queue->read > &queue->frame[DCAM_FRM_CNT_MAX-1]) {
+ queue->read = &queue->frame[0];
+ }
+ } else {
+ ret = EAGAIN;
+ }
+ spin_unlock_irqrestore(&queue->lock, flag);
+ DCAM_TRACE("DCAM: _dcam_buf_queue_read type %d \n", frame->type);
+ return ret;
+}
+
+LOCAL void _dcam_frm_queue_clear(struct dcam_frm_queue *queue)
+{
+ if (DCAM_ADDR_INVALID(queue)) {
+ printk("DCAM: invalid heap 0x%x \n", (uint32_t)queue);
+ return;
+ }
+
+ memset((void*)queue, 0, sizeof(struct dcam_frm_queue));
+ return;
+}
+
+LOCAL int32_t _dcam_frame_enqueue(struct dcam_frm_queue *queue, struct dcam_frame *frame)
+{
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: enq, invalid param 0x%x, 0x%x \n",
+ (uint32_t)queue,
+ (uint32_t)frame);
+ return -1;
+ }
+ if (queue->valid_cnt >= DCAM_FRM_QUEUE_LENGTH) {
+ printk("DCAM: q over flow \n");
+ return -1;
+ }
+ //queue->frm_array[queue->valid_cnt] = frame;
+ memcpy(&queue->frm_array[queue->valid_cnt], frame, sizeof(struct dcam_frame));
+ queue->valid_cnt ++;
+ DCAM_TRACE("DCAM: en queue, %d, %d, 0x%x, 0x%x \n",
+ (0xF & frame->fid),
+ queue->valid_cnt,
+ frame->yaddr,
+ frame->uaddr);
+ return 0;
+}
+
+LOCAL int32_t _dcam_frame_dequeue(struct dcam_frm_queue *queue, struct dcam_frame *frame)
+{
+ uint32_t i = 0;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: deq, invalid param 0x%x, 0x%x \n",
+ (uint32_t)queue,
+ (uint32_t)frame);
+ return -1;
+ }
+ if (queue->valid_cnt == 0) {
+ printk("DCAM: q under flow \n");
+ return -1;
+ }
+
+ //*frame = queue->frm_array[0];
+ memcpy(frame, &queue->frm_array[0], sizeof(struct dcam_frame));
+ queue->valid_cnt--;
+ for (i = 0; i < queue->valid_cnt; i++) {
+ //queue->frm_array[i] = queue->frm_array[i+1];
+ memcpy(&queue->frm_array[i], &queue->frm_array[i+1], sizeof(struct dcam_frame));
+ }
+ DCAM_TRACE("DCAM: de queue, %d, %d \n",
+ (0xF & (frame)->fid),
+ queue->valid_cnt);
+ return 0;
+}
+
+LOCAL void _dcam_frm_clear(enum dcam_path_index path_index)
+{
+ uint32_t i = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path0.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path0.buf_queue);
+ }
+
+ if (DCAM_PATH_IDX_1 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path1.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path1.buf_queue);
+ }
+
+ if (DCAM_PATH_IDX_2 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path2.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path2.buf_queue);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_frm_pop(enum dcam_path_index path_index)
+{
+ uint32_t i = 0;
+ struct dcam_frame *frame = NULL;
+ uint32_t *frame_count;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 & path_index) {
+ frame = &s_p_dcam_mod->path0_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path0.output_frame_count;
+ }
+ if (DCAM_PATH_IDX_1 & path_index) {
+ frame = &s_p_dcam_mod->path1_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path1.output_frame_count;
+ }
+ if (DCAM_PATH_IDX_2 & path_index) {
+ frame = &s_p_dcam_mod->path2_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path2.output_frame_count;
+ }
+ printk("DCAM: frame pop index %d frame_count %d addr 0x%x \n", path_index, *frame_count, frame->yaddr);
+ if (0 == *frame_count) {
+ return;
+ }
+
+ for (i = 0; i < *frame_count - 1; i++) {
+ memcpy(frame+i, frame+i+1, sizeof(struct dcam_frame));
+ }
+ (*frame_count)--;
+ //memset(frame+(*frame_count), 0, sizeof(struct dcam_frame));
+ (frame+(*frame_count))->yaddr = 0;
+ (frame+(*frame_count))->uaddr = 0;
+ (frame+(*frame_count))->vaddr = 0;
+
+ if (0 == *frame_count) {
+ //_dcam_wait_for_quickstop(path_index);
+ }
+ DCAM_TRACE("DCAM: frame pop done \n");
+
+ return;
+}
+
+
+LOCAL void _dcam_link_frm(uint32_t base_id)
+{
+/* uint32_t i = 0;
+ struct dcam_frame *path0_frame = NULL;
+ struct dcam_frame *path1_frame = NULL;
+ struct dcam_frame *path2_frame = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ path0_frame = &s_p_dcam_mod->path0_frame[0];
+ path1_frame = &s_p_dcam_mod->path1_frame[0];
+ path2_frame = &s_p_dcam_mod->path2_frame[0];
+ for (i = 0; i < DCAM_PATH_0_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path0_frame + i);
+ //(path0_frame+i)->next = path0_frame + (i + 1) % DCAM_PATH_0_FRM_CNT_MAX;
+ //(path0_frame+i)->prev = path0_frame + (i - 1 + DCAM_PATH_0_FRM_CNT_MAX) % DCAM_PATH_0_FRM_CNT_MAX;
+ (path0_frame+i)->fid = base_id + i;
+ }
+
+ for (i = 0; i < DCAM_PATH_1_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path1_frame + i);
+ //(path1_frame+i)->next = path1_frame + (i + 1) % DCAM_PATH_1_FRM_CNT_MAX;
+ //(path1_frame+i)->prev = path1_frame + (i - 1 + DCAM_PATH_1_FRM_CNT_MAX) % DCAM_PATH_1_FRM_CNT_MAX;
+ (path1_frame+i)->fid = base_id + i;
+ }
+
+ for (i = 0; i < DCAM_PATH_2_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path2_frame + i);
+ //(path2_frame+i)->next = path2_frame+(i + 1) % DCAM_PATH_2_FRM_CNT_MAX;
+ //(path2_frame+i)->prev = path2_frame+(i - 1 + DCAM_PATH_2_FRM_CNT_MAX) % DCAM_PATH_2_FRM_CNT_MAX;
+ (path2_frame+i)->fid = base_id + i;
+ }
+
+ //s_p_dcam_mod->dcam_path0.output_frame_head = path0_frame;
+ //s_p_dcam_mod->dcam_path1.output_frame_head = path1_frame;
+ //s_p_dcam_mod->dcam_path2.output_frame_head = path2_frame;
+ //s_p_dcam_mod->dcam_path0.output_frame_cur = path0_frame;
+ //s_p_dcam_mod->dcam_path1.output_frame_cur = path1_frame;
+ //s_p_dcam_mod->dcam_path2.output_frame_cur = path2_frame;
+*/
+ return;
+}
+
+LOCAL int32_t _dcam_path_set_next_frm(enum dcam_path_index path_index, uint32_t is_1st_frm)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_frame frame;
+ struct dcam_frame *reserved_frame = NULL;
+ struct dcam_frame *orig_frame = NULL;
+ struct dcam_path_desc *path = NULL;
+ uint32_t yuv_reg[3] = {0};
+ uint32_t path_max_frm_cnt;
+ uint32_t flag = 0;
+ struct dcam_frm_queue *p_heap = NULL;
+ struct dcam_buf_queue *p_buf_queue = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ reserved_frame = &s_p_dcam_mod->path0_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path0;
+ yuv_reg[0] = DCAM_FRM_ADDR0;
+ path_max_frm_cnt = DCAM_PATH_0_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path0.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path0.buf_queue;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ //frame = &s_p_dcam_mod->path1_frame[0];
+ reserved_frame = &s_p_dcam_mod->path1_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path1;
+ yuv_reg[0] = DCAM_FRM_ADDR1;
+ yuv_reg[1] = DCAM_FRM_ADDR2;
+ yuv_reg[2] = DCAM_FRM_ADDR3;
+ path_max_frm_cnt = DCAM_PATH_1_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path1.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path1.buf_queue;
+ } else /*if(DCAM_PATH_IDX_2 == path_index)*/ {
+ //frame = &s_p_dcam_mod->path2_frame[0];
+ reserved_frame = &s_p_dcam_mod->path2_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path2;
+ yuv_reg[0] = DCAM_FRM_ADDR4;
+ yuv_reg[1] = DCAM_FRM_ADDR5;
+ yuv_reg[2] = DCAM_FRM_ADDR6;
+ path_max_frm_cnt = DCAM_PATH_2_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path2.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path2.buf_queue;
+ }
+
+ if (0 != _dcam_buf_queue_read(p_buf_queue, &frame)) {
+ DCAM_TRACE("DCAM: No freed frame id %d \n", frame.fid);
+ memcpy(&frame, reserved_frame, sizeof(struct dcam_frame));
+ }
+
+ DCAM_TRACE("DCAM: next %d y 0x%x uv 0x%x \n", path->output_frame_count, frame.yaddr, frame.uaddr);
+ REG_WR(yuv_reg[0], frame.yaddr);
+ if (((DCAM_YUV400 > path->output_format) && (DCAM_PATH_IDX_0 != path_index)) ||
+ ((DCAM_OUTPUT_YUV420 == path->output_format) && (DCAM_PATH_IDX_0 == path_index))) {
+ REG_WR(yuv_reg[1], frame.uaddr);
+ if (DCAM_YUV420_3FRAME == path->output_format) {
+ REG_WR(yuv_reg[2], frame.vaddr);
+ }
+ }
+ dcam_frame_lock(&frame);
+ if (0 == _dcam_frame_enqueue(p_heap, &frame)) {
+ } else {
+ dcam_frame_unlock(&frame);
+ rtn = DCAM_RTN_PATH_FRAME_LOCKED;
+ }
+
+ return -rtn;
+}
+
+#if 0
+LOCAL int32_t _dcam_path_trim(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path;
+ uint32_t cfg_reg, ctrl_bit;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ ctrl_bit = 8;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ ctrl_bit = 1;
+ } else {
+ printk("DCAM: _dcam_path_trim invalid path_index=%d \n", path_index);
+ return -1;
+ }
+
+ if (path->input_size.w != path->input_rect.w ||
+ path->input_size.h != path->input_rect.h) {
+ /*REG_OWR(cfg_reg, 1 << ctrl_bit);*/
+ } else {
+ /*REG_MWR(cfg_reg, 1 << ctrl_bit, 0 << ctrl_bit);*/
+ }
+
+ return rtn;
+
+}
+#endif
+
+LOCAL int32_t _dcam_path_scaler(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ uint32_t cfg_reg = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index){
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ }
+
+ DCAM_CHECK_ZERO(path);
+ if (DCAM_RAWRGB == path->output_format ||
+ DCAM_JPEG == path->output_format) {
+ DCAM_TRACE("DCAM: _dcam_path_scaler out format is %d, no need scaler \n", path->output_format);
+ return DCAM_RTN_SUCCESS;
+ }
+
+ rtn = _dcam_calc_sc_size(path_index);
+ if (DCAM_RTN_SUCCESS != rtn) {
+ return rtn;
+ }
+
+ if (path->sc_input_size.w == path->output_size.w &&
+ path->sc_input_size.h == path->output_size.h &&
+ DCAM_YUV422 == path->output_format) {
+ REG_MWR(cfg_reg, BIT_20, 1 << 20);// bypass scaler if the output size equals input size for YUV422 format
+ } else {
+ REG_MWR(cfg_reg, BIT_20, 0 << 20);
+ if (s_dcam_sc_array->is_smooth_zoom
+ && DCAM_PATH_IDX_1 == path_index
+ && DCAM_ST_START == path->status) {
+ rtn = _dcam_calc_sc_coeff(path_index);
+ } else {
+ rtn = _dcam_set_sc_coeff(path_index);
+ }
+ }
+
+ return rtn;
+}
+
+LOCAL int32_t _dcam_path_check_deci(enum dcam_path_index path_index, uint32_t *is_deci)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ uint32_t w_deci = 0;
+ uint32_t h_deci = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ goto dcam_path_err;
+ }
+
+ if (path->input_rect.w > (path->output_size.w * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.h > (path->output_size.h * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.w * DCAM_SC_COEFF_UP_MAX < path->output_size.w ||
+ path->input_rect.h * DCAM_SC_COEFF_UP_MAX < path->output_size.h) {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ } else {
+ if (path->input_rect.w > path->output_size.w * DCAM_SC_COEFF_DOWN_MAX)
+ w_deci = 1;
+ if (path->input_rect.h > path->output_size.h * DCAM_SC_COEFF_DOWN_MAX)
+ h_deci = 1;
+
+ if(w_deci || h_deci)
+ *is_deci = 1;
+ else
+ *is_deci = 0;
+ }
+
+dcam_path_err:
+ DCAM_TRACE("DCAM: _dcam_path_check_deci: path_index=%d, is_deci=%d, rtn=%d \n", path_index, *is_deci, rtn);
+
+ return rtn;
+}
+
+LOCAL uint32_t _dcam_get_path_deci_factor(uint32_t src_size, uint32_t dst_size)
+{
+ uint32_t factor = 0;
+
+ if (0 == src_size || 0 == dst_size) {
+ return factor;
+ }
+
+ /* factor: 0 - 1/2, 1 - 1/4, 2 - 1/8, 3 - 1/16 */
+ for (factor = 0; factor < DCAM_PATH_DECI_FAC_MAX; factor ++) {
+ if (src_size < (uint32_t)(dst_size * (1 << (factor + 1)))) {
+ break;
+ }
+ }
+
+ return factor;
+}
+
+LOCAL int32_t _dcam_calc_sc_size(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ uint32_t cfg_reg = 0;
+ uint32_t tmp_dstsize = 0;
+ uint32_t align_size = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index){
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ }
+
+ DCAM_CHECK_ZERO(path);
+ if (path->input_rect.w > (path->output_size.w * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.h > (path->output_size.h * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.w * DCAM_SC_COEFF_UP_MAX < path->output_size.w ||
+ path->input_rect.h * DCAM_SC_COEFF_UP_MAX < path->output_size.h) {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ } else {
+ path->sc_input_size.w = path->input_rect.w;
+ path->sc_input_size.h = path->input_rect.h;
+ if (path->input_rect.w > path->output_size.w * DCAM_SC_COEFF_DOWN_MAX) {
+ tmp_dstsize = path->output_size.w * DCAM_SC_COEFF_DOWN_MAX;
+ path->deci_val.deci_x = _dcam_get_path_deci_factor(path->input_rect.w, tmp_dstsize);
+ path->deci_val.deci_x_en = 1;
+ path->valid_param.v_deci = 1;
+ align_size = (1 << (path->deci_val.deci_x+1))*DCAM_PIXEL_ALIGN_WIDTH;
+ path->input_rect.w = (path->input_rect.w) & ~(align_size-1);
+ path->input_rect.x = (path->input_rect.x) & ~(align_size-1);
+ path->sc_input_size.w = path->input_rect.w >> (path->deci_val.deci_x+1);
+ } else {
+ path->deci_val.deci_x = 0;
+ path->deci_val.deci_x_en = 0;
+ path->valid_param.v_deci = 1;
+ }
+
+ if (path->input_rect.h > path->output_size.h * DCAM_SC_COEFF_DOWN_MAX) {
+ tmp_dstsize = path->output_size.h * DCAM_SC_COEFF_DOWN_MAX;
+ path->deci_val.deci_y = _dcam_get_path_deci_factor(path->input_rect.h, tmp_dstsize);
+ path->deci_val.deci_y_en = 1;
+ path->valid_param.v_deci = 1;
+ align_size = (1 << (path->deci_val.deci_y+1))*DCAM_PIXEL_ALIGN_HEIGHT;
+ path->input_rect.h = (path->input_rect.h) & ~(align_size-1);
+ path->input_rect.y = (path->input_rect.y) & ~(align_size-1);
+ path->sc_input_size.h = path->input_rect.h >> (path->deci_val.deci_y+1);
+ } else {
+ path->deci_val.deci_y = 0;
+ path->deci_val.deci_y_en = 0;
+ path->valid_param.v_deci = 1;
+ }
+
+ }
+
+ DCAM_TRACE("DCAM: _dcam_calc_sc_size, path=%d, x_en=%d, deci_x=%d, y_en=%d, deci_y=%d \n",
+ path_index, path->deci_val.deci_x_en,
+ path->deci_val.deci_x, path->deci_val.deci_y_en,
+ path->deci_val.deci_y);
+
+ return -rtn;
+}
+
+LOCAL int32_t _dcam_set_sc_coeff(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *path = NULL;
+ uint32_t i = 0;
+ uint32_t h_coeff_addr = DCAM_BASE;
+ uint32_t v_coeff_addr = DCAM_BASE;
+ uint32_t v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ uint32_t ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ uint8_t y_tap = 0;
+ uint8_t uv_tap = 0;
+ uint32_t index = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_set_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ down(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ if (!(Dcam_GenScaleCoeff((int16_t)path->sc_input_size.w,
+ (int16_t)path->sc_input_size.h,
+ (int16_t)path->output_size.w,
+ (int16_t)path->output_size.h,
+ h_coeff,
+ v_coeff,
+ v_chroma_coeff,
+ scale2yuv420,
+ &y_tap,
+ &uv_tap,
+ tmp_buf + (DCAM_SC_COEFF_COEF_SIZE*3/4),
+ DCAM_SC_COEFF_TMP_SIZE))) {
+ printk("DCAM: _dcam_set_sc_coeff Dcam_GenScaleCoeff error! \n");
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ return -DCAM_RTN_PATH_GEN_COEFF_ERR;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_H_NUM; i++) {
+ REG_WR(h_coeff_addr, *h_coeff);
+ h_coeff_addr += 4;
+ h_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_NUM; i++) {
+ REG_WR(v_coeff_addr, *v_coeff);
+ v_coeff_addr += 4;
+ v_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_CHROMA_NUM; i++) {
+ REG_WR(v_chroma_coeff_addr, *v_chroma_coeff);
+ v_chroma_coeff_addr += 4;
+ v_chroma_coeff++;
+ }
+
+ path->scale_tap.y_tap = y_tap;
+ path->scale_tap.uv_tap = uv_tap;
+ path->valid_param.scale_tap = 1;
+
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ return DCAM_RTN_SUCCESS;
+}
+
+LOCAL void _dcam_force_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy)
+{
+ uint32_t reg_val = 0;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ if(path_copy)
+ reg_val |= BIT_10;
+ if(coef_copy)
+ reg_val |= BIT_14;
+
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ if(path_copy)
+ reg_val |= BIT_12;
+ if(coef_copy)
+ reg_val |= BIT_16;
+
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_force_copy_ext invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_auto_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy)
+{
+ uint32_t reg_val = 0;
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_9;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_11;
+ if (coef_copy)
+ reg_val |= BIT_15;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_13;
+ if (coef_copy)
+ reg_val |= BIT_17;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_auto_copy_ext invalid path index: %d \n", path_index);
+ }
+
+}
+
+LOCAL void _dcam_force_copy(enum dcam_path_index path_index)
+{
+ if (DCAM_PATH_IDX_1 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_10, 1 << 10, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_12, 1 << 12, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_force_copy invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_auto_copy(enum dcam_path_index path_index)
+{
+ if (DCAM_PATH_IDX_0 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_9, 1 << 9, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_11, 1 << 11, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_13, 1 << 13, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_auto_copy invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_reg_trace(void)
+{
+#ifdef DCAM_DRV_DEBUG
+ uint32_t addr = 0;
+
+ printk("DCAM: Register list");
+ for (addr = DCAM_CFG; addr <= CAP_SENSOR_CTRL; addr += 16) {
+ printk("\n 0x%x: 0x%x 0x%x 0x%x 0x%x",
+ addr,
+ REG_RD(addr),
+ REG_RD(addr + 4),
+ REG_RD(addr + 8),
+ REG_RD(addr + 12));
+ }
+
+ printk("\n");
+#endif
+}
+
+#if 0
+LOCAL void _dcam_sensor_sof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_SOF];
+ void *data = s_user_data[DCAM_SN_SOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _sn_sof \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+#endif
+
+LOCAL void _dcam_sensor_eof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_EOF];
+ void *data = s_user_data[DCAM_SN_EOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _sn_eof \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_cap_sof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_CAP_SOF];
+ void *data = s_user_data[DCAM_CAP_SOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _cap_sof \n");
+
+ _dcam_stopped_notice();
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_cap_eof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_CAP_EOF];
+ void *data = s_user_data[DCAM_CAP_EOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path0_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH0_DONE];
+ void *data = s_user_data[DCAM_PATH0_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ if (0 == path->valide) {
+ printk("DCAM: path0 not valid \n");
+ return;
+ }
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_0, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_0);
+ DCAM_TRACE("DCAM 0 \n");
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, false);
+ if (rtn) {
+ printk("DCAM: 0 w \n");
+ return;
+ }
+ _dcam_auto_copy(DCAM_PATH_IDX_0);
+
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path0_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path0_reserved_frame \n");
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path0_overflow(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH0_OV];
+ void *data = s_user_data[DCAM_PATH0_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path0_overflow \n");
+ path = &s_p_dcam_mod->dcam_path0;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_DONE];
+ void *data = s_user_data[DCAM_PATH1_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path1;
+ if (0 == path->valide) {
+ printk("DCAM: path1 not valid \n");
+ return;
+ }
+
+ DCAM_TRACE("DCAM: 1\n");
+
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_1, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_1);
+
+ if (path->sof_cnt < 1) {
+ printk("DCAM: path1 done cnt %d\n", path->sof_cnt);
+ path->need_wait = 0;
+ return;
+ }
+ path->sof_cnt = 0;
+
+ if (path->need_wait) {
+ path->need_wait = 0;
+ } else {
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path1_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ DCAM_TRACE("DCAM: path1 frame 0x%x, y uv, 0x%x 0x%x \n",
+ (int)&frame, frame.yaddr, frame.uaddr);
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path1_reserved_frame \n");
+ }
+ }
+ return;
+}
+
+LOCAL void _dcam_path1_overflow(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_OV];
+ void *data = s_user_data[DCAM_PATH1_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path1_overflow \n");
+ path = &s_p_dcam_mod->dcam_path1;
+ //frame = path->output_frame_cur->prev->prev;
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_sensor_line_err(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_LINE_ERR];
+ void *data = s_user_data[DCAM_SN_LINE_ERR];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _line_err \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_sensor_frame_err(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_FRAME_ERR];
+ void *data = s_user_data[DCAM_SN_FRAME_ERR];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _frame_err \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_jpeg_buf_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_JPEG_BUF_OV];
+ void *data = s_user_data[DCAM_JPEG_BUF_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _jpeg_overflow \n");
+ path = &s_p_dcam_mod->dcam_path0;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_DONE];
+ void *data = s_user_data[DCAM_PATH2_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ if (atomic_read(&s_resize_flag)) {
+ memset(&frame, 0, sizeof(struct dcam_frame));
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+
+ DCAM_TRACE("DCAM: 2, %d %d \n", path->need_stop, path->need_wait);
+ if (path->status == DCAM_ST_START) {
+
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_2, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_2);
+
+ if (path->sof_cnt < 1) {
+ printk("DCAM: path2 done cnt %d\n", path->sof_cnt);
+ path->need_wait = 0;
+ return;
+ }
+ path->sof_cnt = 0;
+
+ if (path->need_wait) {
+ path->need_wait = 0;
+ } else {
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path2_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ DCAM_TRACE("DCAM: path2 frame 0x%x, y uv, 0x%x 0x%x \n",
+ (int)&frame, frame.yaddr, frame.uaddr);
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path2_reserved_frame \n");
+ }
+ }
+ }
+ }
+}
+
+LOCAL void _dcam_path2_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_OV];
+ void *data = s_user_data[DCAM_PATH2_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path2_overflow \n");
+ path = &s_p_dcam_mod->dcam_path2;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path2_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_isp_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_ISP_OV];
+ void *data = s_user_data[DCAM_ISP_OV];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _isp_overflow \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_mipi_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_MIPI_OV];
+ void *data = s_user_data[DCAM_MIPI_OV];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ printk("DCAM: _mipi_overflow \n");
+ return;
+}
+
+LOCAL void _dcam_rot_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_ROT_DONE];
+ void *data = s_user_data[DCAM_ROT_DONE];
+
+ DCAM_TRACE("DCAM: rot_done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_SLICE_DONE];
+ void *data = s_user_data[DCAM_PATH1_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 1 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_SLICE_DONE];
+ void *data = s_user_data[DCAM_PATH2_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 2 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_raw_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_RAW_SLICE_DONE];
+ void *data = s_user_data[DCAM_RAW_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 0 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_sof(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_SOF];
+ void *data = s_user_data[DCAM_PATH1_SOF];
+ struct dcam_path_desc *path;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_TRACE("DCAM: 1 sof done \n");
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ DCAM_CHECK_ZERO_VOID(s_dcam_sc_array);
+
+ if(s_p_dcam_mod->dcam_path1.status == DCAM_ST_START){
+
+ path = &s_p_dcam_mod->dcam_path1;
+ if (0 == path->valide) {
+ printk("DCAM: path1 not valid \n");
+ return;
+ }
+
+ if (path->sof_cnt > 0) {
+ printk("DCAM: path1 sof %d \n", path->sof_cnt);
+ return;
+ } else {
+ path->sof_cnt++;
+ }
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, false);
+ if (path->is_update) {
+ if (s_dcam_sc_array->is_smooth_zoom) {
+ _dcam_get_valid_sc_coeff(s_dcam_sc_array, &sc_coeff);
+ _dcam_write_sc_coeff(DCAM_PATH_IDX_1);
+ _dcam_path1_set(&sc_coeff->dcam_path1);
+ _dcam_pop_sc_buf(s_dcam_sc_array, &sc_coeff);
+ } else {
+ _dcam_path1_set(path);
+ }
+ path->is_update = 0;
+ DCAM_TRACE("DCAM: path1 updated \n");
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_1, true, true);
+ } else {
+ if (rtn) {
+ DCAM_TRACE("DCAM: path1 updated \n");
+ } else {
+ _dcam_auto_copy(DCAM_PATH_IDX_1);
+ }
+ }
+
+ _dcam_path_updated_notice(DCAM_PATH_IDX_1);
+
+ if (rtn) {
+ path->need_wait = 1;
+ printk("DCAM: 1 w\n");
+ return;
+ }
+ }
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_sof(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_SOF];
+ void *data = s_user_data[DCAM_PATH2_SOF];
+ struct dcam_path_desc *path;
+
+ DCAM_TRACE("DCAM: 2 sof done \n");
+
+ if (atomic_read(&s_resize_flag)) {
+ printk("DCAM: path 2 sof, review now \n");
+ } else {
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ return;
+ }
+
+ if(s_p_dcam_mod->dcam_path2.status == DCAM_ST_START){
+
+ path = &s_p_dcam_mod->dcam_path2;
+ if (0 == path->valide) {
+ printk("DCAM: path2 not valid \n");
+ return;
+ }
+
+ if (path->sof_cnt > 0) {
+ printk("DCAM: path2 sof %d \n", path->sof_cnt);
+ return;
+ } else {
+ path->sof_cnt++;
+ }
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, false);
+ if (path->is_update) {
+ _dcam_path2_set();
+ path->is_update = 0;
+ DCAM_TRACE("DCAM: path2 updated \n");
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_2, true, true);
+ } else {
+ if (rtn) {
+ DCAM_TRACE("DCAM: path2 updated \n");
+ } else {
+ _dcam_auto_copy(DCAM_PATH_IDX_2);
+ }
+ }
+
+ _dcam_path_updated_notice(DCAM_PATH_IDX_2);
+
+ if (rtn) {
+ path->need_wait = 1;
+ printk("DCAM:2 w \n");
+ return;
+ }
+ }
+ }
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL int32_t _dcam_err_pre_proc(void)
+{
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: state in err_pre_proc 0x%x,",s_p_dcam_mod->state);
+ if (s_p_dcam_mod->state & DCAM_STATE_QUICKQUIT)
+ return -1;
+
+ s_p_dcam_mod->err_happened = 1;
+ printk("DCAM: err, 0x%x, ISP int 0x%x \n",
+ REG_RD(DCAM_INT_STS),
+ REG_RD(SPRD_ISP_BASE + 0x2080));
+
+ _dcam_reg_trace();
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 0, DCAM_CONTROL_REG); /* Cap Disable */
+ _dcam_stopped();
+ if (0 == atomic_read(&s_resize_flag) &&
+ 0 == atomic_read(&s_rotation_flag)) {
+ dcam_reset(DCAM_RST_ALL, 1);
+ }
+ return 0;
+}
+
+LOCAL void _dcam_stopped(void)
+{
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: stopped, %d \n", s_p_dcam_mod->wait_stop);
+
+ _dcam_path_done_notice(DCAM_PATH_IDX_0);
+ _dcam_path_done_notice(DCAM_PATH_IDX_1);
+ _dcam_path_done_notice(DCAM_PATH_IDX_2);
+ _dcam_stopped_notice();
+ return;
+}
+
+LOCAL int _dcam_internal_init(void)
+{
+ int ret = 0;
+
+ s_p_dcam_mod = (struct dcam_module*)vzalloc(sizeof(struct dcam_module));
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ sema_init(&s_p_dcam_mod->stop_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path0.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path1.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path2.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path0.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path1.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path2.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->resize_done_sema, 0);
+ sema_init(&s_p_dcam_mod->rotation_done_sema, 0);
+ sema_init(&s_p_dcam_mod->scale_coeff_mem_sema, 1);
+
+ memset((void*)s_dcam_sc_array, 0, sizeof(struct dcam_sc_array));
+ return ret;
+}
+LOCAL void _dcam_internal_deinit(void)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ printk("DCAM: Invalid addr, 0x%x", (uint32_t)s_p_dcam_mod);
+ } else {
+ vfree(s_p_dcam_mod);
+ s_p_dcam_mod = NULL;
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return;
+}
+
+LOCAL void _dcam_wait_path_done(enum dcam_path_index path_index, uint32_t *p_flag)
+{
+ int ret = 0;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->err_happened) {
+ return;
+ }
+ if (DCAM_CAPTURE_MODE_SINGLE == s_p_dcam_mod->dcam_mode) {
+ return;
+ }
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done wait %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+
+ spin_lock_irqsave(&dcam_lock, flag);
+ if (p_flag) {
+ *p_flag = 1;
+ }
+ p_path->wait_for_done = 1;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ ret = down_timeout(&p_path->tx_done_sema, DCAM_PATH_TIMEOUT);
+ if (ret) {
+ _dcam_reg_trace();
+ printk("DCAM: Failed to wait path 0x%x done \n", path_index);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path_done_notice(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *p_path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done notice %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+ if (p_path->wait_for_done) {
+ up(&p_path->tx_done_sema);
+ p_path->wait_for_done = 0;
+ }
+
+ return;
+}
+
+LOCAL void _dcam_wait_update_done(enum dcam_path_index path_index, uint32_t *p_flag)
+{
+ int ret = 0;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->err_happened) {
+ return;
+ }
+ if (DCAM_CAPTURE_MODE_SINGLE == s_p_dcam_mod->dcam_mode) {
+ return;
+ }
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done wait %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+
+ spin_lock_irqsave(&dcam_lock, flag);
+ if (p_flag) {
+ *p_flag = 1;
+ }
+ p_path->wait_for_sof = 1;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ ret = down_timeout(&p_path->sof_sema, DCAM_PATH_TIMEOUT);
+ if (ret) {
+ _dcam_reg_trace();
+ printk("DCAM: Failed to wait update path 0x%x done \n", path_index);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path_updated_notice(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *p_path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done notice %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+ if (p_path->wait_for_sof) {
+ up(&p_path->sof_sema);
+ p_path->wait_for_sof = 0;
+ }
+
+ return;
+}
+
+
+LOCAL void _dcam_stopped_notice(void)
+{
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->wait_stop) {
+ up(&s_p_dcam_mod->stop_sema);
+ s_p_dcam_mod->wait_stop = 0;
+ }
+}
+
+void mm_clk_register_trace(void)
+{
+ uint32_t i = 0;
+ printk("REG_AON_APB_APB_EB0 = 0x%x \n",REG_RD(REG_AON_APB_APB_EB0));
+ printk("REG_PMU_APB_PD_MM_TOP_CFG = 0x%x \n",REG_RD(REG_PMU_APB_PD_MM_TOP_CFG));
+ printk("REG_PMU_APB_CP_SOFT_RST = 0x%x \n",REG_RD(REG_PMU_APB_CP_SOFT_RST));
+ if(!(REG_RD(REG_AON_APB_APB_EB0)&BIT_MM_EB) ) return ;
+ if(REG_RD(REG_PMU_APB_PD_MM_TOP_CFG)&BIT_PD_MM_TOP_FORCE_SHUTDOWN) return ;
+
+ printk("mm_clk_reg, part 1 \n");
+ for (i = 0 ; i <= 0x10; i += 4 ) {
+ printk("MMAHB: %x val:%x \b\n",
+ (SPRD_MMAHB_BASE + i),
+ REG_RD(SPRD_MMAHB_BASE + i));
+ }
+
+ printk("mm_clk_reg, part 2 \n");
+ for (i = 0x20 ; i <= 0x38; i += 4 ) {
+ printk("MMCKG: %x val:%x \b\n",
+ (SPRD_MMCKG_BASE + i),
+ REG_RD(SPRD_MMCKG_BASE + i));
+ }
+}
+
+int32_t dcam_stop_sc_coeff(void)
+{
+ uint32_t zoom_mode;
+
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ zoom_mode = s_dcam_sc_array->is_smooth_zoom;
+ /*memset((void*)s_dcam_sc_array, 0, sizeof(struct dcam_sc_array));*/
+ s_dcam_sc_array->is_smooth_zoom = zoom_mode;
+ s_dcam_sc_array->valid_cnt = 0;
+ memset(&s_dcam_sc_array->scaling_coeff_queue, 0, DCAM_SC_COEFF_BUF_COUNT*sizeof(struct dcam_sc_coeff *));
+
+ return 0;
+}
+
+LOCAL int32_t _dcam_get_valid_sc_coeff(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff)
+{
+ if (DCAM_ADDR_INVALID(sc) || DCAM_ADDR_INVALID(sc_coeff)) {
+ printk("DCAM: get valid sc, invalid param 0x%x, 0x%x \n",
+ (uint32_t)sc,
+ (uint32_t)sc_coeff);
+ return -1;
+ }
+ if (sc->valid_cnt == 0) {
+ printk("DCAM: valid cnt 0 \n");
+ return -1;
+ }
+
+ *sc_coeff = sc->scaling_coeff_queue[0];
+ DCAM_TRACE("DCAM: get valid sc, %d \n", sc->valid_cnt);
+ return 0;
+}
+
+
+LOCAL int32_t _dcam_push_sc_buf(struct dcam_sc_array *sc, uint32_t index)
+{
+ if (DCAM_ADDR_INVALID(sc)) {
+ printk("DCAM: push sc, invalid param 0x%x \n",
+ (uint32_t)sc);
+ return -1;
+ }
+ if (sc->valid_cnt >= DCAM_SC_COEFF_BUF_COUNT) {
+ printk("DCAM: valid cnt %d \n", sc->valid_cnt);
+ return -1;
+ }
+
+ sc->scaling_coeff[index].flag = 1;
+ sc->scaling_coeff_queue[sc->valid_cnt] = &sc->scaling_coeff[index];
+ sc->valid_cnt ++;
+
+ DCAM_TRACE("DCAM: push sc, %d \n", sc->valid_cnt);
+
+ return 0;
+}
+
+LOCAL int32_t _dcam_pop_sc_buf(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff)
+{
+ uint32_t i = 0;
+
+ if (DCAM_ADDR_INVALID(sc) || DCAM_ADDR_INVALID(sc_coeff)) {
+ printk("DCAM: pop sc, invalid param 0x%x, 0x%x \n",
+ (uint32_t)sc,
+ (uint32_t)sc_coeff);
+ return -1;
+ }
+ if (sc->valid_cnt == 0) {
+ printk("DCAM: valid cnt 0 \n");
+ return -1;
+ }
+ sc->scaling_coeff_queue[0]->flag = 0;
+ *sc_coeff = sc->scaling_coeff_queue[0];
+ sc->valid_cnt--;
+ for (i = 0; i < sc->valid_cnt; i++) {
+ sc->scaling_coeff_queue[i] = sc->scaling_coeff_queue[i+1];
+ }
+ DCAM_TRACE("DCAM: pop sc, %d \n", sc->valid_cnt);
+ return 0;
+}
+
+LOCAL int32_t _dcam_write_sc_coeff(enum dcam_path_index path_index)
+{
+ int32_t ret = 0;
+ struct dcam_path_desc *path = NULL;
+ uint32_t i = 0;
+ uint32_t h_coeff_addr = DCAM_BASE;
+ uint32_t v_coeff_addr = DCAM_BASE;
+ uint32_t v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ uint32_t ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ ret = _dcam_get_valid_sc_coeff(s_dcam_sc_array, &sc_coeff);
+ if (ret) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+ tmp_buf = sc_coeff->buf;
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &sc_coeff->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_write_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+ for (i = 0; i < DCAM_SC_COEFF_H_NUM; i++) {
+ REG_WR(h_coeff_addr, *h_coeff);
+ h_coeff_addr += 4;
+ h_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_NUM; i++) {
+ REG_WR(v_coeff_addr, *v_coeff);
+ v_coeff_addr += 4;
+ v_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_CHROMA_NUM; i++) {
+ REG_WR(v_chroma_coeff_addr, *v_chroma_coeff);
+ v_chroma_coeff_addr += 4;
+ v_chroma_coeff++;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_write_sc_coeff E \n");
+
+ return ret;
+}
+
+LOCAL int32_t _dcam_calc_sc_coeff(enum dcam_path_index path_index)
+{
+ unsigned long flag;
+ struct dcam_path_desc *path = NULL;
+ uint32_t h_coeff_addr = DCAM_BASE;
+ uint32_t v_coeff_addr = DCAM_BASE;
+ uint32_t v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ uint32_t ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ uint8_t y_tap = 0;
+ uint8_t uv_tap = 0;
+ uint32_t index = 0;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_calc_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+ down(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ spin_lock_irqsave(&dcam_lock,flag);
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+ if (NULL == tmp_buf) {
+ _dcam_pop_sc_buf(s_dcam_sc_array, &sc_coeff);
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+ }
+ spin_unlock_irqrestore(&dcam_lock,flag);
+
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ if (!(Dcam_GenScaleCoeff((int16_t)path->sc_input_size.w,
+ (int16_t)path->sc_input_size.h,
+ (int16_t)path->output_size.w,
+ (int16_t)path->output_size.h,
+ h_coeff,
+ v_coeff,
+ v_chroma_coeff,
+ scale2yuv420,
+ &y_tap,
+ &uv_tap,
+ tmp_buf + (DCAM_SC_COEFF_COEF_SIZE*3/4),
+ DCAM_SC_COEFF_TMP_SIZE))) {
+ printk("DCAM: _dcam_calc_sc_coeff Dcam_GenScaleCoeff error! \n");
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ return -DCAM_RTN_PATH_GEN_COEFF_ERR;
+ }
+ path->scale_tap.y_tap = y_tap;
+ path->scale_tap.uv_tap = uv_tap;
+ path->valid_param.scale_tap = 1;
+ memcpy(&s_dcam_sc_array->scaling_coeff[index].dcam_path1, path, sizeof(struct dcam_path_desc));
+ spin_lock_irqsave(&dcam_lock,flag);
+ _dcam_push_sc_buf(s_dcam_sc_array, index);
+ spin_unlock_irqrestore(&dcam_lock,flag);
+
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ DCAM_TRACE("DCAM: _dcam_calc_sc_coeff E \n");
+
+ return DCAM_RTN_SUCCESS;
+}
diff --git a/drivers/media/sprd_dcam/tshark/dcam_drv.h b/drivers/media/sprd_dcam/tshark/dcam_drv.h
new file mode 100755
index 00000000..bd14be20
--- /dev/null
+++ b/drivers/media/sprd_dcam/tshark/dcam_drv.h
@@ -0,0 +1,449 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef _DCAM_DRV_8830_H_
+#define _DCAM_DRV_8830_H_
+
+#include <linux/types.h>
+#include "dcam_reg.h"
+#include "parse_hwinfo.h"
+
+//#define DCAM_DEBUG
+
+#ifdef DCAM_DEBUG
+ #define DCAM_TRACE printk
+#else
+ #define DCAM_TRACE pr_debug
+#endif
+
+#define DCAM_WAIT_FOREVER 0xFFFFFFFF
+#define DCAM_PATH_1_FRM_CNT_MAX 10
+#define DCAM_PATH_2_FRM_CNT_MAX 10/*4*/
+#define DCAM_PATH_0_FRM_CNT_MAX 10
+#define DCAM_FRM_CNT_MAX 10 /* max between path_1_frm_cnt and path_2_frm_cnt */
+#define DCAM_HEIGHT_MIN 4
+#define DCAM_JPEG_LENGTH_MIN 30720 /*640X480 div 10*/
+
+enum dcam_swtich_status {
+ DCAM_SWITCH_IDLE = 0,
+ DCAM_SWITCH_PAUSE,
+ DCAM_SWITCH_DONE,
+ DCAM_SWITCH_MAX
+};
+
+enum dcam_drv_rtn {
+ DCAM_RTN_SUCCESS = 0,
+ DCAM_RTN_PARA_ERR = 0x10,
+ DCAM_RTN_IO_ID_ERR,
+ DCAM_RTN_ISR_ID_ERR,
+ DCAM_RTN_MASTER_SEL_ERR,
+ DCAM_RTN_MODE_ERR,
+ DCAM_RTN_TIMEOUT,
+
+ DCAM_RTN_CAP_FRAME_SEL_ERR = 0x20,
+ DCAM_RTN_CAP_IN_FORMAT_ERR,
+ DCAM_RTN_CAP_IN_BITS_ERR,
+ DCAM_RTN_CAP_IN_YUV_ERR,
+ DCAM_RTN_CAP_SYNC_POL_ERR,
+ DCAM_RTN_CAP_SKIP_FRAME_ERR,
+ DCAM_RTN_CAP_FRAME_DECI_ERR,
+ DCAM_RTN_CAP_XY_DECI_ERR,
+ DCAM_RTN_CAP_FRAME_SIZE_ERR,
+ DCAM_RTN_CAP_SENSOR_MODE_ERR,
+ DCAM_RTN_CAP_JPEG_BUF_LEN_ERR,
+ DCAM_RTN_CAP_IF_MODE_ERR,
+
+ DCAM_RTN_PATH_SRC_SIZE_ERR = 0x30,
+ DCAM_RTN_PATH_TRIM_SIZE_ERR,
+ DCAM_RTN_PATH_DES_SIZE_ERR,
+ DCAM_RTN_PATH_IN_FMT_ERR,
+ DCAM_RTN_PATH_OUT_FMT_ERR,
+ DCAM_RTN_PATH_SC_ERR,
+ DCAM_RTN_PATH_SUB_SAMPLE_ERR,
+ DCAM_RTN_PATH_ADDR_ERR,
+ DCAM_RTN_PATH_FRAME_TOO_MANY,
+ DCAM_RTN_PATH_FRAME_LOCKED,
+ DCAM_RTN_PATH_NO_MEM,
+ DCAM_RTN_PATH_GEN_COEFF_ERR,
+ DCAM_RTN_PATH_SRC_ERR,
+ DCAM_RTN_PATH_ENDIAN_ERR,
+ DCAM_RTN_PATH_FRM_DECI_ERR,
+ DCAM_RTN_MAX
+};
+
+enum dcam_rst_mode {
+ DCAM_RST_ALL = 0,
+ DCAM_RST_PATH0,
+ DCAM_RST_PATH1,
+ DCAM_RST_PATH2
+};
+
+enum dcam_path_index {
+ DCAM_PATH_IDX_NONE = 0,
+ DCAM_PATH_IDX_0 = 1,
+ DCAM_PATH_IDX_1 = 2,
+ DCAM_PATH_IDX_2 = 4,
+ DCAM_PATH_IDX_ALL = 7,
+};
+
+
+enum dcam_fmt {
+ DCAM_YUV422 = 0,
+ DCAM_YUV420,
+ DCAM_YUV420_3FRAME,
+ DCAM_YUV400,
+ DCAM_RGB565,
+ DCAM_RGB888,
+ DCAM_RAWRGB,
+ DCAM_JPEG,
+ DCAM_FTM_MAX
+};
+
+enum dcam_cap_pattern {
+ DCAM_YUYV = 0,
+ DCAM_YVYU,
+ DCAM_UYVY,
+ DCAM_VYUY,
+ DCAM_PATTERN_MAX
+};
+
+enum dcam_capture_mode {
+ DCAM_CAPTURE_MODE_SINGLE = 0,
+ DCAM_CAPTURE_MODE_MULTIPLE,
+ DCAM_CAPTURE_MODE_MAX
+};
+
+
+enum dcam_irq_id {
+ DCAM_SN_SOF = 0,
+ DCAM_SN_EOF,
+ DCAM_CAP_SOF,
+ DCAM_CAP_EOF,
+ DCAM_PATH0_DONE,
+ DCAM_PATH0_OV,
+ DCAM_PATH1_DONE,
+ DCAM_PATH1_OV,
+ DCAM_PATH2_DONE,
+ DCAM_PATH2_OV,
+ DCAM_SN_LINE_ERR,
+ DCAM_SN_FRAME_ERR,
+ DCAM_JPEG_BUF_OV,
+ DCAM_ISP_OV,
+ DCAM_MIPI_OV,
+ DCAM_ROT_DONE,
+ DCAM_PATH1_SLICE_DONE,
+ DCAM_PATH2_SLICE_DONE,
+ DCAM_RAW_SLICE_DONE,
+ DCAM_PATH1_SOF,
+ DCAM_PATH2_SOF,
+ DCAM_IRQ_NUMBER
+};
+
+enum dcam_cfg_id {
+ DCAM_CAP_SYNC_POL = 0,
+ DCAM_CAP_DATA_BITS,
+ DCAM_CAP_DATA_PACKET,
+ DCAM_CAP_YUV_TYPE,
+ DCAM_CAP_PRE_SKIP_CNT,
+ DCAM_CAP_FRM_DECI,
+ DCAM_CAP_FRM_COUNT_CLR,
+ DCAM_CAP_FRM_COUNT_GET,
+ DCAM_CAP_INPUT_RECT,
+ DCAM_CAP_IMAGE_XY_DECI,
+ DCAM_CAP_JPEG_GET_LENGTH,
+ DCAM_CAP_JPEG_SET_BUF_LEN,
+ DCAM_CAP_TO_ISP,
+ DCAM_CAP_SAMPLE_MODE,
+ DCAM_CAP_ZOOM_MODE,
+
+ DCAM_PATH_INPUT_SIZE,
+ DCAM_PATH_INPUT_RECT,
+ DCAM_PATH_INPUT_ADDR,
+ DCAM_PATH_OUTPUT_SIZE,
+ DCAM_PATH_OUTPUT_FORMAT,
+ DCAM_PATH_OUTPUT_ADDR,
+ DCAM_PATH_OUTPUT_RESERVED_ADDR,
+ DCAM_PATH_FRAME_BASE_ID,
+ DCAM_PATH_SWAP_BUFF,
+ DCAM_PATH_SUB_SAMPLE_EN_X,
+ DCAM_PATH_SUB_SAMPLE_EN_Y,
+ DCAM_PATH_SUB_SAMPLE_MOD,
+ DCAM_PATH_SLICE_SCALE_EN,
+ DCAM_PATH_SLICE_SCALE_HEIGHT,
+ DCAM_PATH_DITHER_EN,
+ DCAM_PATH_IS_IN_SCALE_RANGE,
+ DCAM_PATH_IS_SCALE_EN,
+ DCAM_PATH_SLICE_OUT_HEIGHT,
+ DCAM_PATH_DATA_ENDIAN,
+ DCAM_PATH_SRC_SEL,
+ DCAM_PATH_ENABLE,
+ DCAM_PATH_FRAME_TYPE,
+ DCAM_PATH_ROT_MODE,
+ DCAM_PATH_FRM_DECI,
+ DCAM_PATH_SHRINK,
+ DCAM_CFG_ID_E_MAX
+};
+
+/*
+enum dcam_sub_sample_mode
+{
+ DCAM_SUB_2 = 0,
+ DCAM_SUB_4,
+ DCAM_SUB_8,
+ DCAM_SUB_16,
+ DCAM_SUB_MAX
+};
+
+enum dcam_ahb_frm
+{
+ DCAM_AHB_FRAME_SRC,
+ DCAM_AHB_FRAME_PATH1_DST,
+ DCAM_AHB_FRAME_PATH2_DST,
+ DCAM_AHB_FRAME_SWAP,
+ DCAM_AHB_FRAME_LINE,
+ DCAM_AHB_FRAME_MAX
+};
+*/
+enum iram_owner {
+ IRAM_FOR_DCAM = 0,
+ IRAM_FOR_ARM
+};
+
+enum dcam_clk_sel {
+ DCAM_CLK_312M = 0,
+ DCAM_CLK_256M,
+ DCAM_CLK_128M,
+ DCAM_CLK_76M8,
+ DCAM_CLK_NONE
+};
+
+enum dcam_cap_if_mode {
+ DCAM_CAP_IF_CCIR = 0,
+ DCAM_CAP_IF_CSI2,
+ DCAM_CAP_IF_MODE_MAX
+};
+
+enum dcam_path_src_sel {
+ DCAM_PATH_FROM_CAP = 0,
+ DCAM_PATH_FROM_ISP,
+ DCAM_PATH_FROM_NONE
+};
+
+enum dcam_cap_sensor_mode {
+ DCAM_CAP_MODE_YUV = 0,
+ DCAM_CAP_MODE_SPI,
+ DCAM_CAP_MODE_JPEG,
+ DCAM_CAP_MODE_RAWRGB,
+ DCAM_CAP_MODE_MAX
+};
+
+enum dcam_cap_data_bits {
+ DCAM_CAP_12_BITS = 12,
+ DCAM_CAP_10_BITS = 10,
+ DCAM_CAP_8_BITS = 8,
+ DCAM_CAP_4_BITS = 4,
+ DCAM_CAP_2_BITS = 2,
+ DCAM_CAP_1_BITS = 1,
+ DCAM_CAP_BITS_MAX = 0xFF
+};
+
+enum dcam_data_endian {
+ DCAM_ENDIAN_BIG = 0,
+ DCAM_ENDIAN_LITTLE,
+ DCAM_ENDIAN_HALFBIG,
+ DCAM_ENDIAN_HALFLITTLE,
+ DCAM_ENDIAN_MAX
+};
+
+enum dcam_output_mode {
+ DCAM_OUTPUT_WORD = 0,
+ DCAM_OUTPUT_HALF_WORD,
+ DCAM_OUTPUT_YVYU_1FRAME,
+ DCAM_OUTPUT_YUV420,
+};
+
+enum dcam_glb_reg_id {
+ DCAM_CFG_REG = 0,
+ DCAM_CONTROL_REG,
+ DCAM_INIT_MASK_REG,
+ DCAM_INIT_CLR_REG,
+ DCAM_AHBM_STS_REG,
+ DCAM_ENDIAN_REG,
+ DCAM_REG_MAX
+};
+
+enum dcam_v4l2_wtite_cmd_id {
+ DCAM_V4L2_WRITE_STOP = 0x5AA5,
+ DCAM_V4L2_WRITE_FREE_FRAME = 0xA55A,
+ DCAM_V4L2_WRITE_MAX
+};
+
+struct dcam_cap_sync_pol {
+ uint8_t vsync_pol;
+ uint8_t hsync_pol;
+ uint8_t pclk_pol;
+ uint8_t need_href;
+ uint8_t pclk_src;
+ uint8_t reserved[3];
+};
+
+struct dcam_endian_sel {
+ uint8_t y_endian;
+ uint8_t uv_endian;
+ uint8_t reserved0;
+ uint8_t reserved1;
+};
+
+struct dcam_cap_dec {
+ uint8_t x_factor;
+ uint8_t y_factor;
+ uint8_t x_mode;
+ uint8_t reserved;
+};
+
+struct dcam_path_dec {
+ uint8_t x_factor;
+ uint8_t y_factor;
+ uint8_t reserved[2];
+};
+
+struct dcam_size {
+ uint32_t w;
+ uint32_t h;
+};
+
+struct dcam_rect {
+ uint32_t x;
+ uint32_t y;
+ uint32_t w;
+ uint32_t h;
+};
+
+struct dcam_addr {
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+ uint32_t yaddr_vir;
+ uint32_t uaddr_vir;
+ uint32_t vaddr_vir;
+
+};
+
+struct dcam_sc_tap {
+ uint32_t y_tap;
+ uint32_t uv_tap;
+};
+
+struct dcam_deci {
+ uint32_t deci_x_en;
+ uint32_t deci_x;
+ uint32_t deci_y_en;
+ uint32_t deci_y;
+};
+
+struct dcam_frame {
+ uint32_t type;
+ uint32_t lock;
+ uint32_t flags;
+ uint32_t fid;
+ uint32_t width;
+ uint32_t height;
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+ uint32_t yaddr_vir;
+ uint32_t uaddr_vir;
+ uint32_t vaddr_vir;
+ struct dcam_frame *prev;
+ struct dcam_frame *next;
+};
+
+struct dcam_get_path_id {
+ uint32_t fourcc;
+ uint32_t is_path_work[DCAM_PATH_MAX];
+ uint32_t need_isp_tool;
+ uint32_t need_isp;
+ uint32_t need_shrink;
+ struct dcam_size input_size;
+ struct dcam_rect input_trim;
+ struct dcam_size output_size;
+};
+
+struct dcam_path_info {
+ uint32_t line_buf;
+ uint32_t support_yuv;
+ uint32_t support_raw;
+ uint32_t support_jpeg;
+ uint32_t support_scaling;
+ uint32_t support_trim;
+ uint32_t is_scaleing_path;
+};
+
+struct dcam_path_capability {
+ uint32_t count;
+ struct dcam_path_info path_info[DCAM_PATH_MAX];
+};
+
+
+typedef int (*dcam_isr_func)(struct dcam_frame* frame, void* u_data);
+
+int32_t dcam_module_init(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode);
+int32_t dcam_module_deinit(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode);
+int32_t dcam_module_en(struct device_node *dn);
+int32_t dcam_module_dis(struct device_node *dn);
+int32_t dcam_mipi_clk_en(struct device_node *dn);
+int32_t dcam_mipi_clk_dis(struct device_node *dn);
+int32_t dcam_ccir_clk_en(void);
+int32_t dcam_ccir_clk_dis(void);
+int32_t dcam_reset(enum dcam_rst_mode reset_mode, uint32_t is_isr);
+int32_t dcam_set_clk(struct device_node *dn, enum dcam_clk_sel clk_sel);
+int32_t dcam_update_path(enum dcam_path_index path_index, struct dcam_size *in_size,
+ struct dcam_rect *in_rect, struct dcam_size *out_size);
+int32_t dcam_start_path(enum dcam_path_index path_index);
+int32_t dcam_start(void);
+int32_t dcam_stop_path(enum dcam_path_index path_index);
+int32_t dcam_stop(void);
+int32_t dcam_resume(void);
+int32_t dcam_pause(void);
+int32_t dcam_reg_isr(enum dcam_irq_id id, dcam_isr_func user_func, void* u_data);
+int32_t dcam_cap_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_cap_get_info(enum dcam_cfg_id id, void *param);
+int32_t dcam_path0_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_path1_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_path2_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_get_resizer(uint32_t wait_opt);
+int32_t dcam_rel_resizer(void);
+void dcam_int_en(void);
+void dcam_int_dis(void);
+int32_t dcam_frame_is_locked(struct dcam_frame *frame);
+int32_t dcam_frame_lock(struct dcam_frame *frame);
+int32_t dcam_frame_unlock(struct dcam_frame *frame);
+int32_t dcam_read_registers(uint32_t* reg_buf, uint32_t *buf_len);
+int32_t dcam_resize_start(void);
+int32_t dcam_resize_end(void);
+int32_t dcam_stop_cap(void);
+void dcam_glb_reg_awr(uint32_t addr, uint32_t val, uint32_t reg_id);
+void dcam_glb_reg_owr(uint32_t addr, uint32_t val, uint32_t reg_id);
+void dcam_glb_reg_mwr(uint32_t addr, uint32_t mask, uint32_t val, uint32_t reg_id);
+int dcam_scale_coeff_alloc(void);
+void dcam_scale_coeff_free(void);
+int32_t dcam_rotation_start(void);
+int32_t dcam_rotation_end(void);
+int32_t dcam_get_path_id(struct dcam_get_path_id *path_id, uint32_t *channel_id);
+int32_t dcam_stop_sc_coeff(void);
+int32_t dcam_get_path_capability(struct dcam_path_capability *capacity);
+void dcam_set_highclk_flag(uint32_t flag);
+
+#endif //_DCAM_DRV_8830_H_
diff --git a/drivers/media/sprd_dcam/tshark/dcam_reg.h b/drivers/media/sprd_dcam/tshark/dcam_reg.h
new file mode 100755
index 00000000..0f48831c
--- /dev/null
+++ b/drivers/media/sprd_dcam/tshark/dcam_reg.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#ifndef _REG_DCAM_TIGER_H_
+#define _REG_DCAM_TIGER_H_
+
+#include <soc/sprd/globalregs.h>
+
+#define BIT_0 0x01
+#define BIT_1 0x02
+#define BIT_2 0x04
+#define BIT_3 0x08
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+#define BIT_8 0x0100
+#define BIT_9 0x0200
+#define BIT_10 0x0400
+#define BIT_11 0x0800
+#define BIT_12 0x1000
+#define BIT_13 0x2000
+#define BIT_14 0x4000
+#define BIT_15 0x8000
+#define BIT_16 0x010000
+#define BIT_17 0x020000
+#define BIT_18 0x040000
+#define BIT_19 0x080000
+#define BIT_20 0x100000
+#define BIT_21 0x200000
+#define BIT_22 0x400000
+#define BIT_23 0x800000
+#define BIT_24 0x01000000
+#define BIT_25 0x02000000
+#define BIT_26 0x04000000
+#define BIT_27 0x08000000
+#define BIT_28 0x10000000
+#define BIT_29 0x20000000
+#define BIT_30 0x40000000
+#define BIT_31 0x80000000
+
+#define GLOBAL_BASE SPRD_GREG_BASE
+#define ARM_GLB_GEN0 (GLOBAL_BASE + 0x008UL)
+#define ARM_GLB_GEN3 (GLOBAL_BASE + 0x01CUL)
+#define ARM_GLB_PLL_SCR (GLOBAL_BASE + 0x070UL)
+//#define GR_CLK_GEN5 (GLOBAL_BASE + 0x07CUL)
+#define CLK_DLY_CTRL (GLOBAL_BASE + 0x05CUL)
+
+#define DCAM_AHB_BASE SPRD_MMAHB_BASE
+#define DCAM_AHB_CTL0 (DCAM_AHB_BASE + 0x0000UL)
+#define DCAM_EB (DCAM_AHB_CTL0 + 0x0000UL)
+#define CSI2_DPHY_EB (DCAM_AHB_CTL0 + 0x0000UL)
+#define DCAM_RST (DCAM_AHB_CTL0 + 0x0004UL)
+#define DCAM_MATRIX_EB (DCAM_AHB_CTL0 + 0x0008UL)
+#define DCAM_CCIR_PCLK_EB (SPRD_MMCKG_BASE + 0x0028UL)
+
+
+#define DCAM_CFG (DCAM_BASE + 0x0000UL)
+#define DCAM_CONTROL (DCAM_BASE + 0x0004UL)
+#define DCAM_PATH0_CFG (DCAM_BASE + 0x0008UL)
+#define DCAM_PATH0_SRC_SIZE (DCAM_BASE + 0x000CUL)
+#define DCAM_PATH1_CFG (DCAM_BASE + 0x0010UL)
+#define DCAM_PATH1_SRC_SIZE (DCAM_BASE + 0x0014UL)
+#define DCAM_PATH1_DST_SIZE (DCAM_BASE + 0x0018UL)
+#define DCAM_PATH1_TRIM_START (DCAM_BASE + 0x001CUL)
+#define DCAM_PATH1_TRIM_SIZE (DCAM_BASE + 0x0020UL)
+#define DCAM_PATH2_CFG (DCAM_BASE + 0x0024UL)
+#define DCAM_PATH2_SRC_SIZE (DCAM_BASE + 0x0028UL)
+#define DCAM_PATH2_DST_SIZE (DCAM_BASE + 0x002CUL)
+#define DCAM_PATH2_TRIM_START (DCAM_BASE + 0x0030UL)
+#define DCAM_PATH2_TRIM_SIZE (DCAM_BASE + 0x0034UL)
+#define REV_SLICE_VER (DCAM_BASE + 0x0038UL)
+#define DCAM_INT_STS (DCAM_BASE + 0x003CUL)
+#define DCAM_INT_MASK (DCAM_BASE + 0x0040UL)
+#define DCAM_INT_CLR (DCAM_BASE + 0x0044UL)
+#define DCAM_INT_RAW (DCAM_BASE + 0x0048UL)
+#define DCAM_FRM_ADDR0 (DCAM_BASE + 0x004CUL)
+#define DCAM_FRM_ADDR1 (DCAM_BASE + 0x0050UL)
+#define DCAM_FRM_ADDR2 (DCAM_BASE + 0x0054UL)
+#define DCAM_FRM_ADDR3 (DCAM_BASE + 0x0058UL)
+#define DCAM_FRM_ADDR4 (DCAM_BASE + 0x005CUL)
+#define DCAM_FRM_ADDR5 (DCAM_BASE + 0x0060UL)
+#define DCAM_FRM_ADDR6 (DCAM_BASE + 0x0064UL)
+#define DCAM_BURST_GAP (DCAM_BASE + 0x0068UL)
+#define DCAM_ENDIAN_SEL (DCAM_BASE + 0x006CUL)
+#define DCAM_AHBM_STS (DCAM_BASE + 0x0070UL)
+#define DCAM_FRM_ADDR7 (DCAM_BASE + 0x0074UL)
+#define DCAM_FRM_ADDR8 (DCAM_BASE + 0x0078UL)
+#define DCAM_FRM_ADDR9 (DCAM_BASE + 0x007CUL)
+#define DCAM_FRM_ADDR10 (DCAM_BASE + 0x0080UL)
+#define DCAM_FRM_ADDR11 (DCAM_BASE + 0x0084UL)
+#define CCIR_PATT_CFG (DCAM_BASE + 0x0088UL)
+#define CCIR_PATT_SIZE (DCAM_BASE + 0x008CUL)
+#define CCIR_PATT_VBLANK (DCAM_BASE + 0x0090UL)
+#define CCIR_PATT_HBLANK (DCAM_BASE + 0x0094UL)
+#define REV_BURST_IN_CFG (DCAM_BASE + 0x0098UL)
+#define REV_BURST_IN_TRIM_START (DCAM_BASE + 0x009CUL)
+#define REV_BURST_IN_TRIM_SIZE (DCAM_BASE + 0x00A0UL)
+#define REV_SLICE_CFG (DCAM_BASE + 0x00A4UL)
+#define PATH1_SLICE_O_VCNT (DCAM_BASE + 0x00A8UL)
+#define PATH2_SLICE_O_VCNT (DCAM_BASE + 0x00ACUL)
+
+#define DCAM_PATH0_TRIM_START (DCAM_BASE + 0x00B8UL)
+#define DCAM_PATH0_TRIM_SIZE (DCAM_BASE + 0x00BCUL)
+#define DCAM_FRM_ADDR12 (DCAM_BASE + 0x00C0UL)
+
+#define CAP_CCIR_CTRL (DCAM_BASE + 0x0100UL)
+#define CAP_CCIR_FRM_CTRL (DCAM_BASE + 0x0104UL)
+#define CAP_CCIR_START (DCAM_BASE + 0x0108UL)
+#define CAP_CCIR_END (DCAM_BASE + 0x010CUL)
+#define CAP_CCIR_IMG_DECI (DCAM_BASE + 0x0110UL)
+#define CAP_CCIR_ATV_FIX (DCAM_BASE + 0x0114UL)
+#define CAP_CCIR_OBSERVE (DCAM_BASE + 0x0118UL)
+#define CAP_CCIR_JPG_CTRL (DCAM_BASE + 0x011CUL)
+#define CAP_CCIR_FRM_SIZE (DCAM_BASE + 0x0120UL)
+#define CAP_CCIR_PLCK_SRC (SPRD_PIN_BASE + 0x04)
+#define CAP_SPI_CFG (DCAM_BASE + 0x0124UL)
+
+#define CAP_MIPI_CTRL (DCAM_BASE + 0x0128UL)
+#define CAP_MIPI_FRM_CTRL (DCAM_BASE + 0x012CUL)
+#define CAP_MIPI_START (DCAM_BASE + 0x0130UL)
+#define CAP_MIPI_END (DCAM_BASE + 0x0134UL)
+#define CAP_MIPI_IMG_DECI (DCAM_BASE + 0x0138UL)
+#define CAP_MIPI_JPG_CTRL (DCAM_BASE + 0x013CUL)
+#define CAP_MIPI_FRM_SIZE (DCAM_BASE + 0x0140UL)
+#define CAP_SENSOR_CTRL (DCAM_BASE + 0x0144UL)
+
+#define BLC_CFG (DCAM_BASE + 0x0148UL)
+#define BLC_START (DCAM_BASE + 0x014CUL)
+#define BLC_END (DCAM_BASE + 0x0150UL)
+#define BLC_TARGET (DCAM_BASE + 0x0154UL)
+#define BLC_MANUAL (DCAM_BASE + 0x0158UL)
+#define BLC_VALUE1 (DCAM_BASE + 0x015CUL)
+#define BLC_VALUE2 (DCAM_BASE + 0x0160UL)
+
+#define DCAM_END BLC_VALUE2
+
+
+#define DCAM_EB_BIT BIT_0
+#define CCIR_EB_BIT BIT_1
+#define MIPI_EB_BIT BIT_10 // aiden: todo
+
+#define DCAM_MOD_RST_BIT BIT_0
+#define CCIR_RST_BIT BIT_1
+#define PATH0_RST_BIT BIT_7
+#define PATH1_RST_BIT BIT_8
+#define PATH2_RST_BIT BIT_9
+#define CCIR_PCLK_EB_BIT BIT_16
+
+#define DCAM_PATH_NUM 3
+#define DCAM_CAP_SKIP_FRM_MAX 16
+#define DCAM_FRM_DECI_FAC_MAX 4
+#define DCAM_CAP_FRAME_WIDTH_MAX 4092
+#define DCAM_CAP_FRAME_HEIGHT_MAX 4092
+#define DCAM_PATH_FRAME_WIDTH_MAX 4092
+#define DCAM_PATH_FRAME_HEIGHT_MAX 4092
+#define DCAM_CAP_X_DECI_FAC_MAX 4 // cap deci: 0 - 1/8
+#define DCAM_CAP_Y_DECI_FAC_MAX 4 // cap deci: 0 - 1/8
+#define DCAM_PATH_FRAME_ROT_MAX 4
+#define DCAM_JPG_BUF_UNIT (1 << 15)
+#define DCAM_JPG_UNITS (1 << 10)
+#define DCAM_SC_COEFF_UP_MAX 4 // path scaling: 1/8 - 4
+#define DCAM_SC_COEFF_DOWN_MAX 7 // path scaling: 1/8 - 4
+#define DCAM_PATH_DECI_FAC_MAX 4 // path deci: 1/2 - 1/16
+#define DCAM_PATH1_LINE_BUF_LENGTH 2048
+#define DCAM_PATH2_LINE_BUF_LENGTH 4096
+#define DCAM_ISP_LINE_BUF_LENGTH 3280
+#define DCAM_SCALING_THRESHOLD 2300
+#define DCAM_IRQ IRQ_DCAM_INT
+
+#define DCAM_PIXEL_ALIGN_WIDTH 4
+#define DCAM_PIXEL_ALIGN_HEIGHT 2
+
+#define DCAM_PATH_NUM 3
+enum {
+ DCAM_PATH0 = 0,
+ DCAM_PATH1,
+ DCAM_PATH2,
+ DCAM_PATH_MAX
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_REG_DCAM_TIGER_H_
+
+
diff --git a/drivers/media/sprd_dcam/tshark2/dcam_drv.c b/drivers/media/sprd_dcam/tshark2/dcam_drv.c
new file mode 100755
index 00000000..05aaa87c
--- /dev/null
+++ b/drivers/media/sprd_dcam/tshark2/dcam_drv.c
@@ -0,0 +1,4913 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/bitops.h>
+#include <linux/semaphore.h>
+#include <linux/delay.h>
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <asm/io.h>
+#include <linux/kthread.h>
+#ifndef CONFIG_64BIT
+#include <soc/sprd/hardware.h>
+#include <mach/irqs.h>
+#else
+#include <soc/sprd/irqs.h>
+#endif
+#include <soc/sprd/sci.h>
+#include <soc/sprd/sci_glb_regs.h>
+#include <linux/vmalloc.h>
+#include <linux/videodev2.h>
+#include <linux/wakelock.h>
+#include "dcam_drv.h"
+#include "gen_scale_coef.h"
+#include <linux/sprd_2351.h>
+
+#define LOCAL static
+/*#define LOCAL*/
+
+//#define DCAM_DRV_DEBUG
+#define DCAM_LOWEST_ADDR 0x800
+#define DCAM_ADDR_INVALID(addr) ((unsigned long)(addr) < DCAM_LOWEST_ADDR)
+#define DCAM_YUV_ADDR_INVALID(y,u,v) \
+ (DCAM_ADDR_INVALID(y) && \
+ DCAM_ADDR_INVALID(u) && \
+ DCAM_ADDR_INVALID(v))
+
+#define DCAM_SC1_H_TAB_OFFSET 0x400
+#define DCAM_SC1_V_TAB_OFFSET 0x4F0
+#define DCAM_SC1_V_CHROMA_TAB_OFFSET 0x8F0
+
+#define DCAM_SC2_H_TAB_OFFSET 0x1400
+#define DCAM_SC2_V_TAB_OFFSET 0x14F0
+#define DCAM_SC2_V_CHROMA_TAB_OFFSET 0x18F0
+
+#define DCAM_SC_COEFF_BUF_SIZE (24 << 10)
+#define DCAM_SC_COEFF_COEF_SIZE (1 << 10)
+#define DCAM_SC_COEFF_TMP_SIZE (21 << 10)
+#define DCAM_SC_COEFF_BUF_COUNT 2
+
+
+#define DCAM_SC_H_COEF_SIZE (0xC0)
+#define DCAM_SC_V_COEF_SIZE (0x210)
+#define DCAM_SC_V_CHROM_COEF_SIZE (0x210)
+
+#define DCAM_SC_COEFF_H_NUM (DCAM_SC_H_COEF_SIZE/4)
+#define DCAM_SC_COEFF_V_NUM (DCAM_SC_V_COEF_SIZE/4)
+#define DCAM_SC_COEFF_V_CHROMA_NUM (DCAM_SC_V_CHROM_COEF_SIZE/4)
+
+#define DCAM_AXI_STOP_TIMEOUT 1000
+#define DCAM_CLK_DOMAIN_AHB 1
+#define DCAM_CLK_DOMAIN_DCAM 0
+
+#ifdef CONFIG_SC_FPGA
+#define DCAM_PATH_TIMEOUT msecs_to_jiffies(500*10)
+#else
+#define DCAM_PATH_TIMEOUT msecs_to_jiffies(500)
+#endif
+
+#define DCAM_FRM_QUEUE_LENGTH 4
+
+#define DCAM_STATE_QUICKQUIT 0x01
+
+#define DCAM_CHECK_PARAM_ZERO_POINTER(n) \
+ do { \
+ if (0 == (unsigned long)(n)) \
+ return -DCAM_RTN_PARA_ERR; \
+ } while(0)
+
+#define DCAM_CLEAR(a) \
+ do { \
+ memset((void *)(a), 0, sizeof(*(a))); \
+ } while(0)
+
+#define DEBUG_STR "Error L %d, %s \n"
+#define DEBUG_ARGS __LINE__,__FUNCTION__
+#define DCAM_RTN_IF_ERR \
+ do { \
+ if(rtn) { \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return -(rtn); \
+ } \
+ } while(0)
+
+#define DCAM_IRQ_LINE_MASK 0x011FFFFFUL
+
+typedef void (*dcam_isr)(void);
+
+enum {
+ DCAM_FRM_UNLOCK = 0,
+ DCAM_FRM_LOCK_WRITE = 0x10011001,
+ DCAM_FRM_LOCK_READ = 0x01100110
+};
+
+enum {
+ DCAM_ST_STOP = 0,
+ DCAM_ST_START,
+};
+
+#define DCAM_IRQ_ERR_MASK \
+ ((1 << DCAM_PATH0_OV) | (1 << DCAM_PATH1_OV) | (1 << DCAM_PATH2_OV) | \
+ (1 << DCAM_SN_LINE_ERR) | (1 << DCAM_SN_FRAME_ERR) | \
+ (1 << DCAM_ISP_OV) | (1 << DCAM_MIPI_OV))
+
+#define DCAM_IRQ_JPEG_OV_MASK (1 << DCAM_JPEG_BUF_OV)
+
+#define DCAM_CHECK_ZERO(a) \
+ do { \
+ if (DCAM_ADDR_INVALID(a)) { \
+ printk("DCAM, zero pointer \n"); \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return -EFAULT; \
+ } \
+ } while(0)
+
+#define DCAM_CHECK_ZERO_VOID(a) \
+ do { \
+ if (DCAM_ADDR_INVALID(a)) { \
+ printk("DCAM, zero pointer \n"); \
+ printk(DEBUG_STR, DEBUG_ARGS); \
+ return; \
+ } \
+ } while(0)
+
+struct dcam_cap_desc {
+ uint32_t interface;
+ uint32_t input_format;
+ uint32_t frame_deci_factor;
+ uint32_t img_x_deci_factor;
+ uint32_t img_y_deci_factor;
+};
+
+struct dcam_path_valid {
+ uint32_t input_size :1;
+ uint32_t input_rect :1;
+ uint32_t output_size :1;
+ uint32_t output_format :1;
+ uint32_t src_sel :1;
+ uint32_t data_endian :1;
+ uint32_t frame_deci :1;
+ uint32_t scale_tap :1;
+ uint32_t v_deci :1;
+ uint32_t rot_mode :1;
+ uint32_t shrink :1;
+};
+
+struct dcam_frm_queue {
+ struct dcam_frame frm_array[DCAM_FRM_QUEUE_LENGTH];
+ uint32_t valid_cnt;
+};
+
+struct dcam_buf_queue {
+ struct dcam_frame frame[DCAM_FRM_CNT_MAX];
+ struct dcam_frame *write;
+ struct dcam_frame *read;
+ spinlock_t lock;
+};
+
+struct dcam_path_desc {
+ struct dcam_size input_size;
+ struct dcam_rect input_rect;
+ struct dcam_size sc_input_size;
+ struct dcam_size output_size;
+ struct dcam_frame input_frame;
+ struct dcam_frm_queue frame_queue;
+ struct dcam_buf_queue buf_queue;
+ //struct dcam_frame *output_frame_head;
+ //struct dcam_frame *output_frame_cur;
+ struct dcam_endian_sel data_endian;
+ struct dcam_sc_tap scale_tap;
+ struct dcam_deci deci_val;
+ uint32_t shrink;
+ struct dcam_path_valid valid_param;
+ uint32_t frame_base_id;
+ uint32_t output_frame_count;
+ uint32_t output_format;
+ uint32_t src_sel;
+ uint32_t rot_mode;
+ uint32_t frame_deci;
+ uint32_t valide;
+ uint32_t status;
+ struct semaphore tx_done_sema;
+ struct semaphore sof_sema;
+ uint32_t wait_for_done;
+ uint32_t is_update;
+ uint32_t wait_for_sof;
+ uint32_t need_stop;
+ uint32_t need_wait;
+ int32_t sof_cnt;
+};
+
+struct dcam_module {
+ uint32_t dcam_mode;
+ uint32_t module_addr;
+ struct dcam_cap_desc dcam_cap;
+ struct dcam_path_desc dcam_path0;
+ struct dcam_path_desc dcam_path1;
+ struct dcam_path_desc dcam_path2;
+ struct dcam_frame path0_frame[DCAM_PATH_0_FRM_CNT_MAX];
+ struct dcam_frame path1_frame[DCAM_PATH_1_FRM_CNT_MAX];
+ struct dcam_frame path2_frame[DCAM_PATH_2_FRM_CNT_MAX];
+ struct dcam_frame path0_reserved_frame;
+ struct dcam_frame path1_reserved_frame;
+ struct dcam_frame path2_reserved_frame;
+ struct semaphore stop_sema;
+ uint32_t wait_stop;
+ struct semaphore resize_done_sema;
+ uint32_t wait_resize_done;
+ struct semaphore rotation_done_sema;
+ uint32_t wait_rotation_done;
+ uint32_t err_happened;
+ struct semaphore scale_coeff_mem_sema;
+ uint32_t state;
+};
+
+struct dcam_sc_coeff {
+ uint32_t buf[DCAM_SC_COEFF_BUF_SIZE];
+ uint32_t flag;
+ struct dcam_path_desc dcam_path1;
+};
+
+struct dcam_sc_array {
+ struct dcam_sc_coeff scaling_coeff[DCAM_SC_COEFF_BUF_COUNT];
+ struct dcam_sc_coeff *scaling_coeff_queue[DCAM_SC_COEFF_BUF_COUNT];
+ uint32_t valid_cnt;
+ uint32_t is_smooth_zoom;
+};
+
+LOCAL atomic_t s_dcam_users = ATOMIC_INIT(0);
+LOCAL atomic_t s_resize_flag = ATOMIC_INIT(0);
+LOCAL atomic_t s_rotation_flag = ATOMIC_INIT(0);
+#ifndef CONFIG_SC_FPGA
+LOCAL struct clk* s_dcam_clk = NULL;
+#endif
+LOCAL struct dcam_module* s_p_dcam_mod = 0;
+LOCAL uint32_t s_dcam_irq = 0x5A0000A5;
+LOCAL dcam_isr_func s_user_func[DCAM_IRQ_NUMBER];
+LOCAL void* s_user_data[DCAM_IRQ_NUMBER];
+LOCAL struct dcam_sc_array* s_dcam_sc_array = NULL;
+LOCAL struct wake_lock dcam_wakelock;
+LOCAL uint32_t s_need_312m_clk_flag = 0;
+
+LOCAL DEFINE_MUTEX(dcam_sem);
+LOCAL DEFINE_MUTEX(dcam_scale_sema);
+LOCAL DEFINE_MUTEX(dcam_rot_sema);
+LOCAL DEFINE_MUTEX(dcam_module_sema);
+LOCAL DEFINE_SPINLOCK(dcam_mod_lock);
+LOCAL DEFINE_SPINLOCK(dcam_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_cfg_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_control_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_mask_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_clr_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_ahbm_sts_lock);
+LOCAL DEFINE_SPINLOCK(dcam_glb_reg_endian_lock);
+
+LOCAL void _dcam_path0_set(void);
+LOCAL void _dcam_path1_set(struct dcam_path_desc *path);
+LOCAL void _dcam_path2_set(void);
+LOCAL void _dcam_frm_clear(enum dcam_path_index path_index);
+LOCAL void _dcam_link_frm(uint32_t base_id);
+LOCAL int32_t _dcam_path_set_next_frm(enum dcam_path_index path_index, uint32_t is_1st_frm);
+/*LOCAL int32_t _dcam_path_trim(enum dcam_path_index path_index);*/
+LOCAL int32_t _dcam_path_scaler(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_calc_sc_size(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_set_sc_coeff(enum dcam_path_index path_index);
+LOCAL void _dcam_force_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy);
+LOCAL void _dcam_auto_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy);
+LOCAL void _dcam_force_copy(enum dcam_path_index path_index);
+LOCAL void _dcam_auto_copy(enum dcam_path_index path_index);
+LOCAL void _dcam_reg_trace(void);
+LOCAL void _dcam_sensor_sof(void);
+LOCAL void _dcam_sensor_eof(void);
+LOCAL void _dcam_cap_sof(void);
+LOCAL void _dcam_cap_eof(void);
+LOCAL void _dcam_path0_done(void);
+LOCAL void _dcam_path0_overflow(void);
+LOCAL void _dcam_path1_done(void);
+LOCAL void _dcam_path1_overflow(void);
+LOCAL void _dcam_sensor_line_err(void);
+LOCAL void _dcam_sensor_frame_err(void);
+LOCAL void _dcam_jpeg_buf_ov(void);
+LOCAL void _dcam_path2_done(void);
+LOCAL void _dcam_path2_ov(void);
+LOCAL void _dcam_isp_ov(void);
+LOCAL void _dcam_mipi_ov(void);
+LOCAL void _dcam_path1_slice_done(void);
+LOCAL void _dcam_path2_slice_done(void);
+LOCAL void _dcam_raw_slice_done(void);
+LOCAL void _dcam_path0_sof(void);
+LOCAL void _dcam_path1_sof(void);
+LOCAL void _dcam_path2_sof(void);
+LOCAL irqreturn_t _dcam_isr_root(int irq, void *dev_id);
+LOCAL void _dcam_stopped_notice(void);
+LOCAL void _dcam_stopped(void);
+LOCAL int32_t _dcam_path_check_deci(enum dcam_path_index path_index, uint32_t *is_deci);
+extern void _dcam_isp_root(void);
+LOCAL int _dcam_internal_init(void);
+LOCAL void _dcam_internal_deinit(void);
+LOCAL void _dcam_wait_path_done(enum dcam_path_index path_index, uint32_t *p_flag);
+LOCAL void _dcam_path_done_notice(enum dcam_path_index path_index);
+LOCAL void _dcam_rot_done(void);
+LOCAL int32_t _dcam_err_pre_proc(void);
+LOCAL void _dcam_frm_queue_clear(struct dcam_frm_queue *queue);
+LOCAL int32_t _dcam_frame_enqueue(struct dcam_frm_queue *queue, struct dcam_frame *frame);
+LOCAL int32_t _dcam_frame_dequeue(struct dcam_frm_queue *queue, struct dcam_frame *frame);
+LOCAL void _dcam_buf_queue_init(struct dcam_buf_queue *queue);
+LOCAL int32_t _dcam_buf_queue_write(struct dcam_buf_queue *queue, struct dcam_frame *frame);
+LOCAL int32_t _dcam_buf_queue_read(struct dcam_buf_queue *queue, struct dcam_frame *frame);
+LOCAL void _dcam_wait_update_done(enum dcam_path_index path_index, uint32_t *p_flag);
+LOCAL void _dcam_path_updated_notice(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_get_valid_sc_coeff(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff);
+LOCAL int32_t _dcam_push_sc_buf(struct dcam_sc_array *sc, uint32_t index);
+LOCAL int32_t _dcam_pop_sc_buf(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff);
+LOCAL int32_t _dcam_calc_sc_coeff(enum dcam_path_index path_index);
+LOCAL int32_t _dcam_write_sc_coeff(enum dcam_path_index path_index);
+LOCAL void _dcam_wait_for_quickstop(enum dcam_path_index path_index);
+
+LOCAL const dcam_isr isr_list[DCAM_IRQ_NUMBER] = {
+ NULL,//_dcam_isp_root,
+ _dcam_sensor_eof,
+ _dcam_cap_sof,
+ _dcam_cap_eof,
+ _dcam_path0_done,
+ _dcam_path0_overflow,
+ _dcam_path1_done,
+ _dcam_path1_overflow,
+ _dcam_path2_done,
+ _dcam_path2_ov,
+ _dcam_sensor_line_err,
+ _dcam_sensor_frame_err,
+ _dcam_jpeg_buf_ov,
+ _dcam_isp_ov,
+ _dcam_mipi_ov,
+ _dcam_rot_done,
+ _dcam_path1_slice_done,
+ _dcam_path2_slice_done,
+ _dcam_raw_slice_done,
+ _dcam_path1_sof,
+ _dcam_path2_sof,
+ NULL,
+ NULL,
+ NULL,
+ _dcam_path0_sof,
+};
+
+void dcam_glb_reg_awr(unsigned long addr, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ REG_WR(addr, REG_RD(addr) & (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ REG_WR(addr, REG_RD(addr) & (val));
+ break;
+ }
+}
+
+void dcam_glb_reg_owr(unsigned long addr, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ REG_WR(addr, REG_RD(addr) | (val));
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ REG_WR(addr, REG_RD(addr) | (val));
+ break;
+ }
+}
+
+void dcam_glb_reg_mwr(unsigned long addr, uint32_t mask, uint32_t val, uint32_t reg_id)
+{
+ unsigned long flag;
+ uint32_t tmp = 0;
+
+ switch(reg_id) {
+ case DCAM_CFG_REG:
+ spin_lock_irqsave(&dcam_glb_reg_cfg_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_cfg_lock, flag);
+ break;
+ case DCAM_CONTROL_REG:
+ spin_lock_irqsave(&dcam_glb_reg_control_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_control_lock, flag);
+ break;
+ case DCAM_INIT_MASK_REG:
+ spin_lock_irqsave(&dcam_glb_reg_mask_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_mask_lock, flag);
+ break;
+ case DCAM_INIT_CLR_REG:
+ spin_lock_irqsave(&dcam_glb_reg_clr_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_clr_lock, flag);
+ break;
+ case DCAM_AHBM_STS_REG:
+ spin_lock_irqsave(&dcam_glb_reg_ahbm_sts_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_ahbm_sts_lock, flag);
+ break;
+ case DCAM_ENDIAN_REG:
+ spin_lock_irqsave(&dcam_glb_reg_endian_lock, flag);
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ spin_unlock_irqrestore(&dcam_glb_reg_endian_lock, flag);
+ break;
+ default:
+ {
+ tmp = REG_RD(addr);
+ tmp &= ~(mask);
+ REG_WR(addr, tmp | ((mask) & (val)));
+ }
+ break;
+ }
+}
+
+int32_t dcam_module_init(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ if (if_mode >= DCAM_CAP_IF_MODE_MAX) {
+ rtn = -DCAM_RTN_CAP_IF_MODE_ERR;
+ } else {
+ if (sn_mode >= DCAM_CAP_MODE_MAX) {
+ rtn = -DCAM_RTN_CAP_SENSOR_MODE_ERR;
+ } else {
+ _dcam_internal_init();
+ _dcam_link_frm(0); /* set default base frame index as 0 */
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path0.buf_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path1.buf_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path2.buf_queue);
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ cap_desc->interface = if_mode;
+ cap_desc->input_format = sn_mode;
+ /*REG_OWR(DCAM_EB, BIT_13);//MM_EB*/
+ /*REG_OWR(DCAM_MATRIX_EB, BIT_10|BIT_5);*/
+ if (DCAM_CAP_IF_CSI2 == if_mode) {
+ /* REG_OWR(CSI2_DPHY_EB, MIPI_EB_BIT);*/
+ //ret = _dcam_mipi_clk_en();
+ dcam_glb_reg_owr(DCAM_CFG, BIT_9, DCAM_CFG_REG);
+ REG_MWR(CAP_MIPI_CTRL, BIT_2 | BIT_1, sn_mode << 1);
+ } else {
+ /*REG_OWR(DCAM_EB, CCIR_IN_EB_BIT);
+ REG_OWR(DCAM_EB, CCIR_EB_BIT);*/
+ //ret = _dcam_ccir_clk_en();
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ REG_MWR(CAP_CCIR_CTRL, BIT_2 | BIT_1, sn_mode << 1);
+ }
+ rtn = DCAM_RTN_SUCCESS;
+ }
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_module_deinit(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ if (DCAM_CAP_IF_CSI2 == if_mode) {
+ /*REG_MWR(CSI2_DPHY_EB, MIPI_EB_BIT, 0 << 10);*/
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ //_dcam_mipi_clk_dis();
+ } else {
+ /*REG_MWR(DCAM_EB, CCIR_IN_EB_BIT, 0 << 2);
+ REG_MWR(DCAM_EB, CCIR_EB_BIT, 0 << 9);*/
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_9, 0 << 9, DCAM_CFG_REG);
+ //_dcam_ccir_clk_dis();
+ }
+
+ _dcam_internal_deinit();
+
+ return -rtn;
+}
+
+int dcam_scale_coeff_alloc(void)
+{
+ int ret = 0;
+
+ if (NULL == s_dcam_sc_array) {
+ s_dcam_sc_array = (struct dcam_sc_array*)vzalloc(sizeof(struct dcam_sc_array));
+ if (NULL == s_dcam_sc_array) {
+ printk("DCAM: _dcam_scale_coeff_alloc fail.\n");
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+void dcam_scale_coeff_free(void)
+{
+ if (s_dcam_sc_array) {
+ vfree(s_dcam_sc_array);
+ s_dcam_sc_array = NULL;
+ }
+}
+
+#ifdef CONFIG_CPLL_1024M
+void (*change_clk_notify_gpu)(bool is_change);
+EXPORT_SYMBOL(change_clk_notify_gpu);
+void dcam_set_gpucp2_freq(uint32_t on)
+{
+ struct clk *cpll;
+ cpll = clk_get(NULL, "clk_cpll");
+ if (IS_ERR(cpll )) {
+ printk("DCAM: dcam_set_gpucp2_freq fail, %d \n", (int)cpll);
+ return;
+ }
+ printk("Dcam set gpucp2 freq is %d \n", on);
+ if (on) {
+ if (NULL != change_clk_notify_gpu) {
+ change_clk_notify_gpu(true);
+ }
+#ifndef CONFIG_SPRD_2351
+ clk_set_rate(cpll, 624000000);
+#else
+ if (get_cp2_state()) {
+ sprd_switch_cp2_clk(1);
+ } else {
+ clk_set_rate(cpll, 624000000);
+ }
+#endif
+ }
+ else {
+#ifndef CONFIG_SPRD_2351
+ clk_set_rate(cpll, 1024000000);
+#else
+ if (get_cp2_state()) {
+ sprd_switch_cp2_clk(0);
+ } else {
+ clk_set_rate(cpll, 1024000000);
+ }
+#endif
+ if (NULL != change_clk_notify_gpu) {
+ change_clk_notify_gpu(false);
+ }
+ }
+}
+void dcam_set_highclk_flag(uint32_t flag)
+{
+ printk("dcam_set_highclk_flag: flag=%d clk_flag=%d\n", flag, s_need_312m_clk_flag);
+ if ( flag != s_need_312m_clk_flag) {
+ s_need_312m_clk_flag = flag;
+ dcam_set_gpucp2_freq(flag);
+ }
+}
+#endif
+LOCAL uint32_t *dcam_get_scale_coeff_addr(uint32_t *index)
+{
+ uint32_t i;
+
+ if (DCAM_ADDR_INVALID(s_dcam_sc_array)) {
+ printk("DCAM: scale addr, invalid param %p \n", s_dcam_sc_array);
+ return NULL;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_BUF_COUNT; i++) {
+ if (0 == s_dcam_sc_array->scaling_coeff[i].flag) {
+ *index = i;
+ DCAM_TRACE("dcam: get buf index %d \n", i);
+ return s_dcam_sc_array->scaling_coeff[i].buf;
+ }
+ }
+ printk("dcam: get buf index %d \n", i);
+
+ return NULL;
+}
+
+int32_t dcam_module_en(struct device_node *dn)
+{
+ int ret = 0;
+ unsigned int irq_no = 0;
+
+ DCAM_TRACE("DCAM: dcam_module_en, In %d \n", s_dcam_users.counter);
+ mutex_lock(&dcam_module_sema);
+ if (atomic_inc_return(&s_dcam_users) == 1) {
+
+ wake_lock_init(&dcam_wakelock, WAKE_LOCK_SUSPEND,
+ "pm_message_wakelock_dcam");
+
+ wake_lock(&dcam_wakelock);
+
+ ret = clk_mm_i_eb(dn,1);
+ if (ret) {
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+
+ #if defined (CONFIG_ARCH_SCX35LT8)
+ ret = dcam_set_clk(dn,DCAM_CLK_384M);
+ #else
+ ret = dcam_set_clk(dn,DCAM_CLK_312M);
+ #endif
+ if (ret) {
+ clk_mm_i_eb(dn,0);
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+#ifndef CONFIG_ARCH_SCX35LT8
+ parse_baseaddress(dn);
+#endif
+ dcam_reset(DCAM_RST_ALL, 0);
+ atomic_set(&s_resize_flag, 0);
+ atomic_set(&s_rotation_flag, 0);
+ memset((void*)s_user_func, 0, sizeof(s_user_func));
+ memset((void*)s_user_data, 0, sizeof(s_user_data));
+ printk("DCAM: register isr, 0x%x \n", REG_RD(DCAM_INT_MASK));
+
+ irq_no = parse_irq(dn);
+ printk("DCAM: irq_no = 0x%x \n", irq_no);
+ ret = request_irq(irq_no,
+ _dcam_isr_root,
+ IRQF_SHARED,
+ "DCAM",
+ (void*)&s_dcam_irq);
+ if (ret) {
+ printk("DCAM: dcam_start, error %d \n", ret);
+ dcam_set_clk(dn,DCAM_CLK_NONE);
+ clk_mm_i_eb(dn,0);
+ ret = -DCAM_RTN_MAX;
+ goto fail_exit;
+ }
+
+ DCAM_TRACE("DCAM: dcam_module_en end \n");
+ }
+ DCAM_TRACE("DCAM: dcam_module_en, Out %d \n", s_dcam_users.counter);
+ mutex_unlock(&dcam_module_sema);
+ return 0;
+
+fail_exit:
+ wake_unlock(&dcam_wakelock);
+ wake_lock_destroy(&dcam_wakelock);
+ atomic_dec(&s_dcam_users);
+ mutex_unlock(&dcam_module_sema);
+ return ret;
+}
+
+int32_t dcam_module_dis(struct device_node *dn)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ int ret = 0;
+ unsigned int irq_no = 0;
+
+ DCAM_TRACE("DCAM: dcam_module_dis, In %d \n", s_dcam_users.counter);
+
+ mutex_lock(&dcam_module_sema);
+ if (atomic_dec_return(&s_dcam_users) == 0) {
+ sci_glb_clr(DCAM_EB, DCAM_EB_BIT);
+ dcam_set_clk(dn,DCAM_CLK_NONE);
+ printk("DCAM: un register isr \n");
+ irq_no = parse_irq(dn);
+ free_irq(irq_no, (void*)&s_dcam_irq);
+ ret = clk_mm_i_eb(dn,0);
+ if (ret) {
+ rtn = -DCAM_RTN_MAX;
+ }
+ wake_unlock(&dcam_wakelock);
+ wake_lock_destroy(&dcam_wakelock);
+ }
+
+ DCAM_TRACE("DCAM: dcam_module_dis, Out %d \n", s_dcam_users.counter);
+ mutex_unlock(&dcam_module_sema);
+
+ return rtn;
+}
+
+int32_t dcam_reset(enum dcam_rst_mode reset_mode, uint32_t is_isr)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ uint32_t time_out = 0;
+
+ DCAM_TRACE("DCAM: reset: %d \n", reset_mode);
+
+ if (!is_isr) {
+ mutex_lock(&dcam_rot_sema);
+ }
+
+ if (DCAM_RST_ALL == reset_mode) {
+ if (atomic_read(&s_dcam_users)) {
+ /* firstly, stop AXI writing */
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_6, DCAM_AHBM_STS_REG);
+ }
+
+ /* then wait for AHB busy cleared */
+ while (++time_out < DCAM_AXI_STOP_TIMEOUT) {
+ if (0 == (REG_RD(DCAM_AHBM_STS) & BIT_0))
+ break;
+ }
+ if (time_out >= DCAM_AXI_STOP_TIMEOUT) {
+ printk("DCAM: reset TO: %d \n", time_out);
+ return DCAM_RTN_TIMEOUT;
+ }
+ }
+
+ /* do reset action */
+ switch (reset_mode) {
+ case DCAM_RST_PATH0:
+ sci_glb_set(DCAM_RST, PATH0_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH0_RST_BIT);
+ DCAM_TRACE("DCAM: reset path0 \n");
+ break;
+
+ case DCAM_RST_PATH1:
+ sci_glb_set(DCAM_RST, PATH1_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH1_RST_BIT);
+ DCAM_TRACE("DCAM: reset path1 \n");
+ break;
+
+ case DCAM_RST_PATH2:
+ sci_glb_set(DCAM_RST, PATH2_RST_BIT);
+ sci_glb_clr(DCAM_RST, PATH2_RST_BIT);
+ DCAM_TRACE("DCAM: reset path2 \n");
+ break;
+
+ case DCAM_RST_ALL:
+ sci_glb_set(DCAM_RST, DCAM_MOD_RST_BIT | CCIR_RST_BIT);
+ sci_glb_clr(DCAM_RST, DCAM_MOD_RST_BIT | CCIR_RST_BIT);
+ dcam_glb_reg_owr(DCAM_INT_CLR,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_CLR_REG);
+ dcam_glb_reg_owr(DCAM_INT_MASK,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_MASK_REG);
+ printk("DCAM: reset all \n");
+ break;
+ default:
+ rtn = DCAM_RTN_PARA_ERR;
+ break;
+ }
+
+ if (DCAM_RST_ALL == reset_mode) {
+ if (atomic_read(&s_dcam_users)) {
+ /* the end, enable AXI writing */
+ dcam_glb_reg_awr(DCAM_AHBM_STS, ~BIT_6, DCAM_AHBM_STS_REG);
+ }
+ }
+
+ if (!is_isr) {
+ mutex_unlock(&dcam_rot_sema);
+ }
+
+ DCAM_TRACE("DCAM: reset_mode=%x end \n", reset_mode);
+
+ return -rtn;
+}
+
+int32_t dcam_set_clk(struct device_node *dn, enum dcam_clk_sel clk_sel)
+{
+#ifdef CONFIG_SC_FPGA
+ return 0;
+#else
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct clk *clk_parent;
+ char *parent = "clk_312m";
+ int ret = 0;
+
+ switch (clk_sel) {
+ case DCAM_CLK_384M:
+ parent = "clk_384m";
+ break;
+ case DCAM_CLK_312M:
+ parent = "clk_312m";
+ break;
+ case DCAM_CLK_256M:
+ parent = "clk_256m";
+ break;
+ case DCAM_CLK_128M:
+ parent = "clk_128m";
+ break;
+ case DCAM_CLK_76M8:
+ parent = "clk_76p8m";
+ break;
+ case DCAM_CLK_NONE:
+ printk("DCAM close CLK %d \n", (int)clk_get_rate(s_dcam_clk));
+ if (s_dcam_clk) {
+ clk_disable(s_dcam_clk);
+ clk_put(s_dcam_clk);
+ s_dcam_clk = NULL;
+ }
+ return 0;
+ default:
+ parent = "clk_128m";
+ break;
+ }
+
+ if (NULL == s_dcam_clk) {
+ s_dcam_clk = parse_clk(dn,"clk_dcam");
+ if (IS_ERR(s_dcam_clk)) {
+ printk("DCAM: clk_get fail, %d \n", (int)s_dcam_clk);
+ return -1;
+ } else {
+ DCAM_TRACE("DCAM: get clk_parent ok \n");
+ }
+ } else {
+ clk_disable(s_dcam_clk);
+ }
+
+ clk_parent = clk_get(NULL, parent);
+ if (IS_ERR(clk_parent)) {
+ printk("DCAM: dcam_set_clk fail, %d \n", (int)clk_parent);
+ return -1;
+ } else {
+ DCAM_TRACE("DCAM: get clk_parent ok \n");
+ }
+
+ ret = clk_set_parent(s_dcam_clk, clk_parent);
+ if(ret){
+ printk("DCAM: clk_set_parent fail, %d \n", ret);
+ }
+
+ ret = clk_enable(s_dcam_clk);
+ if (ret) {
+ printk("enable dcam clk error.\n");
+ return -1;
+ }
+ return rtn;
+#endif
+}
+
+int32_t dcam_update_path(enum dcam_path_index path_index, struct dcam_size *in_size,
+ struct dcam_rect *in_rect, struct dcam_size *out_size)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flags;
+ uint32_t is_deci = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ DCAM_TRACE("DCAM:update path \n");
+ DCAM_TRACE("path_index %d s_p_dcam_mod->dcam_path0.valide %d \n", path_index, s_p_dcam_mod->dcam_path0.valide);
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ rtn = dcam_path0_cfg(DCAM_PATH_INPUT_SIZE, in_size);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path0_cfg(DCAM_PATH_INPUT_RECT, in_rect);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path0_cfg(DCAM_PATH_OUTPUT_SIZE, out_size);
+ DCAM_RTN_IF_ERR;
+ printk("DCAM: To update path0 \n");
+ //_dcam_auto_copy(DCAM_PATH_IDX_0);
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ rtn = dcam_path1_cfg(DCAM_PATH_INPUT_SIZE, in_size);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path1_cfg(DCAM_PATH_INPUT_RECT, in_rect);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path1_cfg(DCAM_PATH_OUTPUT_SIZE, out_size);
+ DCAM_RTN_IF_ERR;
+ rtn = _dcam_path_check_deci(DCAM_PATH_IDX_1, &is_deci);
+ DCAM_RTN_IF_ERR;
+ DCAM_TRACE("DCAM: To update path1 \n");
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_1);
+ DCAM_RTN_IF_ERR;
+ DCAM_TRACE("DCAM: dcam_update_path 1 \n");
+ if (s_dcam_sc_array->is_smooth_zoom) {
+ spin_lock_irqsave(&dcam_lock, flags);
+ s_p_dcam_mod->dcam_path1.is_update = 1;
+ spin_unlock_irqrestore(&dcam_lock, flags);
+ } else {
+ _dcam_wait_update_done(DCAM_PATH_IDX_1, &s_p_dcam_mod->dcam_path1.is_update);
+ }
+ if (!s_dcam_sc_array->is_smooth_zoom) {
+ _dcam_wait_update_done(DCAM_PATH_IDX_1, NULL);
+ }
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ local_irq_save(flags);
+ if(s_p_dcam_mod->dcam_path2.is_update){
+ local_irq_restore(flags);
+ DCAM_TRACE("DCAM: dcam_update_path 2: updating return \n");
+ return rtn;
+ }
+ local_irq_restore(flags);
+
+ rtn = dcam_path2_cfg(DCAM_PATH_INPUT_SIZE, in_size);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path2_cfg(DCAM_PATH_INPUT_RECT, in_rect);
+ DCAM_RTN_IF_ERR;
+ rtn = dcam_path2_cfg(DCAM_PATH_OUTPUT_SIZE, out_size);
+ DCAM_RTN_IF_ERR;
+
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_2);
+ DCAM_RTN_IF_ERR;
+
+ local_irq_save(flags);
+ s_p_dcam_mod->dcam_path2.is_update = 1;
+ local_irq_restore(flags);
+ }
+
+ DCAM_TRACE("DCAM: dcam_update_path: done \n");
+
+ return -rtn;
+}
+
+int32_t dcam_start_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ uint32_t cap_en = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: start_path: path %d, mode %x path 0,1,2 {%d %d %d} \n",
+ path_index,
+ s_p_dcam_mod->dcam_mode,
+ s_p_dcam_mod->dcam_path0.valide,
+ s_p_dcam_mod->dcam_path1.valide,
+ s_p_dcam_mod->dcam_path2.valide);
+
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_8, DCAM_AHBM_STS_REG); // aiden add: write arbit mode
+
+ cap_en = REG_RD(DCAM_CONTROL) & BIT_2;
+ DCAM_TRACE("DCAM: cap_eb %d \n", cap_en);
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ _dcam_path0_set();
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, true);
+ DCAM_RTN_IF_ERR;
+ //_dcam_force_copy(DCAM_PATH_IDX_0);
+ _dcam_auto_copy(DCAM_PATH_IDX_0);
+#if 0
+ if (cap_en) {
+ /* if cap is already open, the sequence is:
+ cap force copy -> path 0 enable -> cap auto copy */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_0, 1 << 0, DCAM_CONTROL_REG); /* Cap force copy */
+ dcam_glb_reg_owr(DCAM_CFG, BIT_0, DCAM_CFG_REG); /* Enable Path 0 */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_1, 1 << 1, DCAM_CONTROL_REG); /* Cap auto copy, trigger path 0 enable */
+ } else {
+ dcam_glb_reg_owr(DCAM_CFG, BIT_0, DCAM_CFG_REG); /* Enable Path 0 */
+ }
+#endif
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+
+ //rtn = _dcam_path_trim(DCAM_PATH_IDX_1);
+ //DCAM_RTN_IF_ERR;
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_1);
+ DCAM_RTN_IF_ERR;
+
+ _dcam_path1_set(&s_p_dcam_mod->dcam_path1);
+ DCAM_TRACE("DCAM: start path: path_control=%x \n", REG_RD(DCAM_CONTROL));
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy_ext(DCAM_PATH_IDX_1, true, true);
+ DCAM_TRACE("DCAM: int= %x \n", REG_RD(DCAM_INT_STS));
+ dcam_glb_reg_owr(DCAM_CFG, BIT_1, DCAM_CFG_REG);
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ rtn = _dcam_path_scaler(DCAM_PATH_IDX_2);
+ DCAM_RTN_IF_ERR;
+
+ _dcam_path2_set();
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy_ext(DCAM_PATH_IDX_2, true, true);
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ if ((uint32_t)(s_p_dcam_mod->dcam_path1.output_size.w * s_p_dcam_mod->dcam_path1.output_size.h) >=
+ (uint32_t)(s_p_dcam_mod->dcam_path2.output_size.w * s_p_dcam_mod->dcam_path2.output_size.h)) {
+ REG_WR(DCAM_BURST_GAP, 0x100000);
+ }
+ }
+ }
+
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ //rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, false);
+ //DCAM_RTN_IF_ERR;
+ //_dcam_auto_copy(DCAM_PATH_IDX_0);
+ s_p_dcam_mod->dcam_path0.need_wait = 0;
+ s_p_dcam_mod->dcam_path0.status = DCAM_ST_START;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_0, DCAM_CFG_REG); /* Enable Path 0 */
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ s_p_dcam_mod->dcam_path1.need_wait = 0;
+ s_p_dcam_mod->dcam_path1.status = DCAM_ST_START;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_1, DCAM_CFG_REG);
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ s_p_dcam_mod->dcam_path2.need_wait = 0;
+ s_p_dcam_mod->dcam_path2.status = DCAM_ST_START;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_2, DCAM_CFG_REG);
+ }
+
+ if (0 == cap_en) {
+#if 0 //def DCAM_DEBUG
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_5 | BIT_4, 0 << 4);
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_3|BIT_2|BIT_1|BIT_0, 0x07);
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_5 | BIT_4, 1 << 4);
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_3|BIT_2|BIT_1|BIT_0, 0x07);
+#endif
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_0, 1 << 0, DCAM_CONTROL_REG); /* Cap force copy */
+ //REG_MWR(DCAM_CONTROL, BIT_1, 1 << 1); /* Cap auto copy */
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 1 << 2, DCAM_CONTROL_REG); /* Cap Enable */
+ }
+
+ if (DCAM_PATH_IDX_ALL != path_index) {
+ if ((DCAM_PATH_IDX_0 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_0, NULL);
+ } else if ((DCAM_PATH_IDX_1 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_1, NULL);
+ } else if ((DCAM_PATH_IDX_2 & path_index)) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_2, NULL);
+ }
+ }
+
+ printk("DCAM PATH S: %d \n", path_index);
+
+ _dcam_reg_trace();
+
+ DCAM_TRACE("DCAM: start_path E\n");
+ return -rtn;
+}
+
+int32_t dcam_start(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ int ret = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: dcam_start %x \n", s_p_dcam_mod->dcam_mode);
+
+ ret = dcam_start_path(DCAM_PATH_IDX_ALL);
+ //ret = dcam_start_path(DCAM_PATH_IDX_1);
+
+ return -rtn;
+}
+
+int32_t dcam_stop_cap(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+#if 0
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ printk("DCAM: stop cap %d \n", s_p_dcam_mod->dcam_mode);
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 0, DCAM_CONTROL_REG); /* Cap Enable */
+ DCAM_TRACE("DCAM: stop cap, s_resize_flag %d \n", atomic_read(&s_resize_flag));
+ if (atomic_read(&s_resize_flag)) {
+ s_p_dcam_mod->wait_resize_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->resize_done_sema, DCAM_PATH_TIMEOUT);
+ }
+ if (atomic_read(&s_rotation_flag)) {
+ s_p_dcam_mod->wait_rotation_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->rotation_done_sema, DCAM_PATH_TIMEOUT);
+ }
+
+ dcam_reset(DCAM_RST_ALL, 0);
+ DCAM_TRACE("DCAM: stop cap, Out \n");
+#endif
+ return -rtn;
+}
+
+int32_t _dcam_stop_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ spin_lock_irqsave(&dcam_lock, flag);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: stop path Wrong index 0x%x \n", path_index);
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ return -rtn;
+ }
+
+ _dcam_wait_for_quickstop(path_index);
+ p_path->status = DCAM_ST_STOP;
+ p_path->valide = 0;
+ _dcam_frm_clear(path_index);
+
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ return rtn;
+}
+
+int32_t dcam_stop_path(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ printk("DCAM: stop_path 0x%x \n", path_index);
+
+ if (path_index < DCAM_PATH_IDX_0 ||
+ path_index >= DCAM_PATH_IDX_ALL) {
+ printk("DCAM: error path_index \n");
+ return -rtn;
+ }
+
+ if ((DCAM_PATH_IDX_0 & path_index) && s_p_dcam_mod->dcam_path0.valide) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_0, &s_p_dcam_mod->dcam_path0.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_0);
+ }
+
+ if ((DCAM_PATH_IDX_1 & path_index) && s_p_dcam_mod->dcam_path1.valide) {
+ _dcam_wait_path_done(DCAM_PATH_IDX_1, &s_p_dcam_mod->dcam_path1.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_1);
+ }
+
+ if ((DCAM_PATH_IDX_2 & path_index) && s_p_dcam_mod->dcam_path2.valide) {
+ DCAM_TRACE("DCAM: stop path2 In \n");
+ _dcam_wait_path_done(DCAM_PATH_IDX_2, &s_p_dcam_mod->dcam_path2.need_stop);
+ _dcam_stop_path(DCAM_PATH_IDX_2);
+ }
+
+ DCAM_TRACE("DCAM dcam_stop_path E: %d \n", path_index);
+
+ return -rtn;
+}
+
+LOCAL void _dcam_wait_for_channel_stop(enum dcam_path_index path_index)
+{
+ int time_out = 5000;
+ uint32_t ret = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ /* wait for AHB path busy cleared */
+ while (time_out) {
+ if (s_p_dcam_mod->dcam_path1.valide && (DCAM_PATH_IDX_1 & path_index)) {
+ ret = REG_RD(DCAM_AHBM_STS) & BIT_17;
+ } else if (s_p_dcam_mod->dcam_path2.valide && (DCAM_PATH_IDX_2 & path_index)) {
+ ret = REG_RD(DCAM_AHBM_STS) & BIT_18;
+ } else if (s_p_dcam_mod->dcam_path0.valide && (DCAM_PATH_IDX_0 & path_index)) {
+ ret = REG_RD(DCAM_AHBM_STS) & BIT_19;
+ } else {
+ /*nothing*/
+ }
+ if (!ret) {
+ break;
+ }
+ time_out --;
+ }
+
+ DCAM_TRACE("DCAM: wait channel stop %d %d \n", ret, time_out);
+
+ return;
+}
+
+LOCAL void _dcam_quickstop_set(enum dcam_path_index path_index, uint32_t path_rst, uint32_t path_bit,
+ uint32_t cfg_bit, uint32_t ahbm_bit, uint32_t auto_copy_bit)
+{
+ dcam_glb_reg_owr(DCAM_AHBM_STS, ahbm_bit, DCAM_AHBM_STS_REG);
+ udelay(1000);
+ dcam_glb_reg_mwr(DCAM_CFG, cfg_bit, ~cfg_bit, DCAM_CFG_REG);
+ _dcam_wait_for_channel_stop(path_index);
+ _dcam_force_copy(path_index);
+ dcam_reset(path_rst, 0);
+ dcam_glb_reg_awr(DCAM_AHBM_STS, ~ahbm_bit, DCAM_AHBM_STS_REG);
+
+ return;
+}
+
+#define DCAM_IRQ_MASK_PATH0 (0x0f|(0x03<<4)|(1<<12)|(1<<21)) //let other module continue
+#define DCAM_IRQ_MASK_PATH1 (0x0f|(0x03<<6)|(1<<16)|(1<<19)|(1<<22))
+#define DCAM_IRQ_MASK_PATH2 (0x0f|(0x03<<8)|(1<<17)|(1<<20)|(1<<23))
+
+LOCAL void _dcam_quickstop_set_all(enum dcam_path_index path_index, uint32_t path_bit, uint32_t cfg_bit, uint32_t ahbm_bit)
+{
+ dcam_glb_reg_owr(DCAM_AHBM_STS, BIT_3 | BIT_4 | BIT_5, DCAM_AHBM_STS_REG);
+ udelay(10);
+ dcam_glb_reg_awr(DCAM_CFG, ~(BIT_0 | BIT_1 | BIT_2), DCAM_CFG_REG);
+ dcam_glb_reg_owr(DCAM_CONTROL, BIT_8 | BIT_10 | BIT_12, DCAM_CONTROL_REG);
+ dcam_glb_reg_awr(DCAM_CONTROL, ~(BIT_8 | BIT_10 | BIT_12), DCAM_CONTROL_REG);
+ _dcam_wait_for_channel_stop(DCAM_PATH_IDX_0);
+ _dcam_wait_for_channel_stop(DCAM_PATH_IDX_1);
+ _dcam_wait_for_channel_stop(DCAM_PATH_IDX_2);
+
+ return;
+}
+
+LOCAL void _dcam_wait_for_quickstop(enum dcam_path_index path_index)
+{
+ int time_out = 5000;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: state before stop 0x%x\n", s_p_dcam_mod->state);
+
+ if (DCAM_PATH_IDX_ALL == path_index) {
+ _dcam_quickstop_set_all(0, 0, 0, 0);
+ } else {
+ if (s_p_dcam_mod->dcam_path0.valide && (DCAM_PATH_IDX_0 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_0, DCAM_RST_PATH0, DCAM_IRQ_MASK_PATH0, BIT_0, BIT_3, BIT_9);
+ }
+ if (s_p_dcam_mod->dcam_path1.valide && (DCAM_PATH_IDX_1 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_1, DCAM_RST_PATH1, DCAM_IRQ_MASK_PATH1, BIT_1, BIT_4, BIT_11);
+ }
+ if (s_p_dcam_mod->dcam_path2.valide && (DCAM_PATH_IDX_2 & path_index)) {
+ _dcam_quickstop_set(DCAM_PATH_IDX_2, DCAM_RST_PATH2, DCAM_IRQ_MASK_PATH2, BIT_2, BIT_5, BIT_13);
+ }
+ }
+
+ DCAM_TRACE("DCAM: exit _dcam_wait_for_quickstop %d state: 0x%x \n ", time_out, s_p_dcam_mod->state);
+
+ return;
+}
+
+int32_t dcam_stop(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ s_p_dcam_mod->state |= DCAM_STATE_QUICKQUIT;
+ printk("DCAM dcam_stop In \n");
+ if (atomic_read(&s_resize_flag)) {
+ s_p_dcam_mod->wait_resize_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->resize_done_sema, DCAM_PATH_TIMEOUT);
+ }
+ if (atomic_read(&s_rotation_flag)) {
+ s_p_dcam_mod->wait_rotation_done = 1;
+ rtn = down_timeout(&s_p_dcam_mod->rotation_done_sema, DCAM_PATH_TIMEOUT);
+ }
+
+ dcam_stop_path(DCAM_PATH_IDX_2);
+ printk("DCAM dcam_stop get dcam_sem\n");
+ mutex_lock(&dcam_scale_sema);
+ spin_lock_irqsave(&dcam_lock, flag);
+
+ dcam_glb_reg_owr(DCAM_INT_MASK,
+ DCAM_IRQ_LINE_MASK,
+ DCAM_INIT_MASK_REG);
+
+ _dcam_wait_for_quickstop(DCAM_PATH_IDX_ALL);
+ s_p_dcam_mod->dcam_path0.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path0.valide = 0;
+ s_p_dcam_mod->dcam_path1.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path1.valide = 0;
+ s_p_dcam_mod->dcam_path2.status = DCAM_ST_STOP;
+ s_p_dcam_mod->dcam_path2.valide = 0;
+ _dcam_frm_clear(DCAM_PATH_IDX_0);
+ _dcam_frm_clear(DCAM_PATH_IDX_1);
+ _dcam_frm_clear(DCAM_PATH_IDX_2);
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ dcam_reset(DCAM_RST_ALL, 0);
+ s_p_dcam_mod->state &= ~DCAM_STATE_QUICKQUIT;
+ mutex_unlock(&dcam_scale_sema);
+
+ printk("DCAM: dcam_stop Out, s_resize_flag %d \n", atomic_read(&s_resize_flag));
+
+ return -rtn;
+}
+
+int32_t dcam_resume(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->dcam_path1.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy(DCAM_PATH_IDX_1);
+ _dcam_frm_clear(DCAM_PATH_IDX_1);
+ }
+
+ if (s_p_dcam_mod->dcam_path2.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, true);
+ DCAM_RTN_IF_ERR;
+ _dcam_force_copy(DCAM_PATH_IDX_2);
+ _dcam_frm_clear(DCAM_PATH_IDX_2);
+ }
+
+
+ if (s_p_dcam_mod->dcam_path1.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, false);
+ DCAM_RTN_IF_ERR;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_1, DCAM_CFG_REG);
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_1, true, true);
+ }
+
+ if (s_p_dcam_mod->dcam_path2.valide) {
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, false);
+ DCAM_RTN_IF_ERR;
+ dcam_glb_reg_owr(DCAM_CFG, BIT_2, DCAM_CFG_REG);
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_2, true, true);
+ }
+
+ printk("DCAM R \n");
+
+ dcam_glb_reg_owr(DCAM_CONTROL, BIT_2, DCAM_CONTROL_REG); /* Enable CAP */
+ return -rtn;
+}
+
+int32_t dcam_pause(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+
+ dcam_glb_reg_awr(DCAM_CONTROL, ~BIT_2, DCAM_CONTROL_REG); /* Disable CAP */
+ printk("DCAM P \n");
+ return -rtn;
+}
+
+int32_t dcam_reg_isr(enum dcam_irq_id id, dcam_isr_func user_func, void* user_data)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ if(id >= DCAM_IRQ_NUMBER) {
+ rtn = DCAM_RTN_ISR_ID_ERR;
+ } else {
+ spin_lock_irqsave(&dcam_lock, flag);
+ s_user_func[id] = user_func;
+ s_user_data[id] = user_data;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ }
+ return -rtn;
+}
+
+int32_t dcam_cap_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ switch (id) {
+ case DCAM_CAP_SYNC_POL:
+ {
+ struct dcam_cap_sync_pol *sync_pol = (struct dcam_cap_sync_pol*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+
+ if (sync_pol->vsync_pol > 1 ||
+ sync_pol->hsync_pol > 1 ||
+ sync_pol->pclk_pol > 1) {
+ rtn = DCAM_RTN_CAP_SYNC_POL_ERR;
+ } else {
+ #ifndef CONFIG_SC_FPGA
+ sci_glb_set(DCAM_CCIR_PCLK_EB, CCIR_PCLK_EB_BIT);
+ #endif
+ REG_MWR(CAP_CCIR_CTRL, BIT_3, sync_pol->hsync_pol << 3);
+ REG_MWR(CAP_CCIR_CTRL, BIT_4, sync_pol->vsync_pol << 4);
+ //REG_MWR(CLK_DLY_CTRL, BIT_19, sync_pol->pclk_pol << 19); // aiden todo
+
+ if (sync_pol->pclk_src == 0x00) {
+ #ifndef CONFIG_SC_FPGA
+ sci_glb_clr(CAP_CCIR_PLCK_SRC, (BIT_25 | BIT_26));
+ #endif
+ DCAM_TRACE("DCAM: set pclk src0\n");
+ } else if (sync_pol->pclk_src == 0x01) {
+ #ifndef CONFIG_SC_FPGA
+ sci_glb_clr(CAP_CCIR_PLCK_SRC, (BIT_25 | BIT_26));
+ sci_glb_set(CAP_CCIR_PLCK_SRC, (BIT_25));
+ #endif
+ DCAM_TRACE("DCAM: set pclk src1\n");
+ } else {
+ DCAM_TRACE("DCAM: set pclk src default\n");
+ }
+ }
+ } else {
+ if (sync_pol->need_href) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_5, 1 << 5);
+ } else {
+ REG_MWR(CAP_MIPI_CTRL, BIT_5, 0 << 5);
+ }
+ }
+ break;
+ }
+
+ case DCAM_CAP_DATA_BITS:
+ {
+ enum dcam_cap_data_bits bits = *(enum dcam_cap_data_bits*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ if (DCAM_CAP_8_BITS == bits || DCAM_CAP_10_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 0 << 9);
+ } else if (DCAM_CAP_4_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 1 << 9);
+ } else if (DCAM_CAP_2_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 2 << 9);
+ } else if (DCAM_CAP_1_BITS == bits) {
+ REG_MWR(CAP_CCIR_CTRL, BIT_10 | BIT_9, 3 << 9);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_BITS_ERR;
+ }
+
+ } else {
+ if (DCAM_CAP_12_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 2 << 3);
+ } else if (DCAM_CAP_10_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 1 << 3);
+ } else if (DCAM_CAP_8_BITS == bits) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_4 | BIT_3, 0 << 3);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_BITS_ERR;
+ }
+ }
+ break;
+ }
+
+ case DCAM_CAP_YUV_TYPE:
+ {
+ enum dcam_cap_pattern pat = *(enum dcam_cap_pattern*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (pat < DCAM_PATTERN_MAX) {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_CTRL, BIT_8 | BIT_7, pat << 7);
+ else
+ REG_MWR(CAP_MIPI_CTRL, BIT_8 | BIT_7, pat << 7);
+ } else {
+ rtn = DCAM_RTN_CAP_IN_YUV_ERR;
+ }
+ break;
+ }
+
+ case DCAM_CAP_PRE_SKIP_CNT:
+ {
+ uint32_t skip_num = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (skip_num > DCAM_CAP_SKIP_FRM_MAX) {
+ rtn = DCAM_RTN_CAP_SKIP_FRAME_ERR;
+ } else {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_3 | BIT_2 | BIT_1 | BIT_0, skip_num);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_3 | BIT_2 | BIT_1 | BIT_0, skip_num);
+ }
+ break;
+ }
+
+ case DCAM_CAP_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor < DCAM_FRM_DECI_FAC_MAX) {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_5 | BIT_4, deci_factor << 4);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_5 | BIT_4, deci_factor << 4);
+ } else {
+ rtn = DCAM_RTN_CAP_FRAME_DECI_ERR;
+ }
+ break;
+ }
+
+ case DCAM_CAP_FRM_COUNT_CLR:
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_MWR(CAP_CCIR_FRM_CTRL, BIT_22, 1 << 22);
+ else
+ REG_MWR(CAP_MIPI_FRM_CTRL, BIT_22, 1 << 22);
+ break;
+
+ case DCAM_CAP_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+ uint32_t tmp = 0;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+#if 0
+ if (rect->x > DCAM_CAP_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_CAP_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_CAP_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_CAP_FRAME_HEIGHT_MAX ) {
+ rtn = DCAM_RTN_CAP_FRAME_SIZE_ERR;
+ return -rtn;
+ }
+#endif
+
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ tmp = rect->x | (rect->y << 16);
+ REG_WR(CAP_CCIR_START, tmp);
+ tmp = (rect->x + rect->w - 1);
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_CCIR_END, tmp);
+ } else {
+ tmp = (rect->x << 1) | (rect->y << 16);
+ REG_WR(CAP_CCIR_START, tmp);
+ tmp = ((rect->x + rect->w) << 1) - 1;
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_CCIR_END, tmp);
+ }
+ } else {
+ tmp = rect->x | (rect->y << 16);
+ REG_WR(CAP_MIPI_START, tmp);
+ tmp = (rect->x + rect->w - 1);
+ tmp |= (rect->y + rect->h - 1) << 16;
+ REG_WR(CAP_MIPI_END, tmp);
+ }
+ break;
+ }
+
+ case DCAM_CAP_IMAGE_XY_DECI:
+ {
+ struct dcam_cap_dec *cap_dec = (struct dcam_cap_dec*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (cap_dec->x_factor > DCAM_CAP_X_DECI_FAC_MAX ||
+ cap_dec->y_factor > DCAM_CAP_Y_DECI_FAC_MAX ) {
+ rtn = DCAM_RTN_CAP_XY_DECI_ERR;
+ } else {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ if (cap_dec->x_factor > 1 ||
+ cap_dec->y_factor > 1) {
+ rtn = DCAM_RTN_CAP_XY_DECI_ERR;
+ }
+ }
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface) {
+ REG_MWR(CAP_CCIR_IMG_DECI, BIT_1 | BIT_0, cap_dec->x_factor);
+ REG_MWR(CAP_CCIR_IMG_DECI, BIT_3 | BIT_2, cap_dec->y_factor << 2);
+ } else {
+ if (DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ // REG_MWR(CAP_MIPI_IMG_DECI, BIT_0, cap_dec->x_factor); // for camera path
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_1, cap_dec->x_factor << 1);//for ISP
+ } else {
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_1 | BIT_0, cap_dec->x_factor);
+ REG_MWR(CAP_MIPI_IMG_DECI, BIT_3 | BIT_2, cap_dec->y_factor << 2);
+ }
+ }
+ }
+
+ break;
+ }
+
+ case DCAM_CAP_JPEG_SET_BUF_LEN:
+ {
+ uint32_t jpg_buf_size = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ jpg_buf_size = jpg_buf_size/DCAM_JPG_BUF_UNIT;
+ if (jpg_buf_size >= DCAM_JPG_UNITS) {
+ rtn = DCAM_RTN_CAP_JPEG_BUF_LEN_ERR;
+ } else {
+ if (DCAM_CAP_IF_CCIR == cap_desc->interface)
+ REG_WR(CAP_CCIR_JPG_CTRL,jpg_buf_size);
+ else
+ REG_WR(CAP_MIPI_JPG_CTRL,jpg_buf_size);
+ }
+ break;
+ }
+
+ case DCAM_CAP_TO_ISP:
+ {
+ uint32_t need_isp = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (need_isp) {
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_7, 1 << 7, DCAM_CFG_REG);
+ } else {
+ dcam_glb_reg_mwr(DCAM_CFG, BIT_7, 0 << 7, DCAM_CFG_REG);
+ }
+ break;
+ }
+
+ case DCAM_CAP_DATA_PACKET:
+ {
+ uint32_t is_loose = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface &&
+ DCAM_CAP_MODE_RAWRGB == cap_desc->input_format) {
+ if (is_loose) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_0, 1);
+ } else {
+ REG_MWR(CAP_MIPI_CTRL, BIT_0, 0);
+ }
+ } else {
+ rtn = DCAM_RTN_MODE_ERR;
+ }
+
+ break;
+ }
+
+ case DCAM_CAP_SAMPLE_MODE:
+ {
+ enum dcam_capture_mode samp_mode = *(enum dcam_capture_mode*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (samp_mode >= DCAM_CAPTURE_MODE_MAX) {
+ rtn = DCAM_RTN_MODE_ERR;
+ } else {
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ REG_MWR(CAP_MIPI_CTRL, BIT_6, samp_mode << 6);
+ } else {
+ REG_MWR(CAP_CCIR_CTRL, BIT_6, samp_mode << 6);
+ }
+ s_p_dcam_mod->dcam_mode = samp_mode;
+ }
+ break;
+ }
+
+ case DCAM_CAP_ZOOM_MODE:
+ {
+ uint32_t zoom_mode = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ s_dcam_sc_array->is_smooth_zoom = zoom_mode;
+ break;
+ }
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_cap_get_info(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_cap_desc *cap_desc = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ cap_desc = &s_p_dcam_mod->dcam_cap;
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ switch(id) {
+ case DCAM_CAP_FRM_COUNT_GET:
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ *(uint32_t*)param = REG_RD(CAP_MIPI_FRM_CTRL) >> 16;
+ } else {
+ *(uint32_t*)param = REG_RD(CAP_CCIR_FRM_CTRL) >> 16;
+ }
+ break;
+
+ case DCAM_CAP_JPEG_GET_LENGTH:
+ if (DCAM_CAP_IF_CSI2 == cap_desc->interface) {
+ *(uint32_t*)param = REG_RD(CAP_MIPI_FRM_SIZE);
+ } else {
+ *(uint32_t*)param = REG_RD(CAP_CCIR_FRM_SIZE);
+ }
+ break;
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+ }
+ return -rtn;
+}
+
+int32_t dcam_path0_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH0_INPUT_SIZE {%d %d} \n", size->w, size->h);
+#if 0
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else
+#endif
+ {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH0_INPUT_RECT {%d %d %d %d} \n",
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+
+ //if (rect->x > DCAM_PATH_FRAME_WIDTH_MAX ||
+ //rect->y > DCAM_PATH_FRAME_HEIGHT_MAX ||
+ //rect->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ //rect->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ // rtn = DCAM_RTN_PATH_TRIM_SIZE_ERR;
+ //} else {
+ memcpy((void*)&path->input_rect,
+ (void*)rect,
+ sizeof(struct dcam_rect));
+ //if (path->input_rect.h >= DCAM_HEIGHT_MIN) {
+ // path->input_rect.h--;
+ //}
+ /* path0 output size is different with other paths */
+ path->output_size.w = rect->w;
+ path->output_size.h = rect->h;
+ path->valid_param.input_rect = 1;
+ //}
+ break;
+ }
+ case DCAM_PATH_OUTPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_OUTPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->output_size.w = size->w;
+ path->output_size.h = size->h;
+ path->valid_param.output_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_SRC_SEL:
+ {
+ uint32_t src_sel = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (src_sel >= DCAM_PATH_FROM_NONE) {
+ rtn = DCAM_RTN_PATH_SRC_ERR;
+ } else {
+ path->src_sel = src_sel;
+ path->valid_param.src_sel = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_output_mode format = *(enum dcam_output_mode*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if((DCAM_OUTPUT_WORD != format) &&
+ (DCAM_OUTPUT_HALF_WORD != format) &&
+ (DCAM_OUTPUT_YVYU_1FRAME != format) &&
+ (DCAM_OUTPUT_YUV420 != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->output_format = format;
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path0.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path0.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_0_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH0;
+ frame.fid = s_p_dcam_mod->dcam_path0.frame_base_id;
+ DCAM_TRACE("DCAM: Path 0 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path0.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path0_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+
+ DCAM_TRACE("DCAM: Path 0 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->data_endian.uv_endian = endian->uv_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ path->valide = *(uint32_t*)param;
+ break;
+ }
+
+ default:
+ rtn = DCAM_RTN_IO_ID_ERR;
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_path1_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path1;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_INPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_INPUT_RECT {%d %d %d %d} \n",
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+
+ if (rect->x > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_PATH_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_TRIM_SIZE_ERR;
+ } else {
+ memcpy((void*)&path->input_rect,
+ (void*)rect,
+ sizeof(struct dcam_rect));
+ //if (path->input_rect.h >= DCAM_HEIGHT_MIN) {
+ // path->input_rect.h--;
+ //}
+ path->valid_param.input_rect = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH1_OUTPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->output_size.w = size->w;
+ path->output_size.h = size->h;
+ path->valid_param.output_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_fmt format = *(enum dcam_fmt*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ path->output_format = format;
+
+ if((DCAM_YUV422 != format) &&
+ (DCAM_YUV420 != format) &&
+ (DCAM_YUV420_3FRAME != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH1;
+ frame.fid = s_p_dcam_mod->dcam_path1.frame_base_id;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path1.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path1_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_SRC_SEL:
+ {
+ uint32_t src_sel = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (src_sel >= DCAM_PATH_FROM_NONE) {
+ rtn = DCAM_RTN_PATH_SRC_ERR;
+ } else {
+ path->src_sel = src_sel;
+ path->valid_param.src_sel = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path1.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->data_endian.uv_endian = endian->uv_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ path->valide = *(uint32_t*)param;
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path1.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_1_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+ case DCAM_PATH_ROT_MODE:
+ {
+ uint32_t rot_mode = *(uint32_t*)param;
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (rot_mode >= DCAM_PATH_FRAME_ROT_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ }else{
+ path->rot_mode = rot_mode;
+ path->valid_param.rot_mode = 1;
+ printk("zcf dcam_path1_cfg rot:\n",path->rot_mode);
+ }
+ }
+
+ case DCAM_PATH_SHRINK:
+ {
+ uint32_t shrink = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (shrink == 1) {
+ path->shrink = 1;
+ } else {
+ path->shrink = 0;
+ }
+ path->valid_param.shrink = 1;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_path2_cfg(enum dcam_cfg_id id, void *param)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+ switch (id) {
+
+ case DCAM_PATH_INPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_INPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH2_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH2_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->input_size.w = size->w;
+ path->input_size.h = size->h;
+ path->valid_param.input_size = 1;
+
+ }
+ break;
+ }
+
+ case DCAM_PATH_INPUT_RECT:
+ {
+ struct dcam_rect *rect = (struct dcam_rect*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_INPUT_RECT {%d %d %d %d} \n",
+ rect->x,
+ rect->y,
+ rect->w,
+ rect->h);
+
+ if (rect->x > DCAM_PATH2_FRAME_WIDTH_MAX ||
+ rect->y > DCAM_PATH2_FRAME_HEIGHT_MAX ||
+ rect->w > DCAM_PATH2_FRAME_WIDTH_MAX ||
+ rect->h > DCAM_PATH2_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_TRIM_SIZE_ERR;
+ } else {
+ memcpy((void*)&path->input_rect,
+ (void*)rect,
+ sizeof(struct dcam_rect));
+#if 0
+ if (path->input_rect.h >= DCAM_HEIGHT_MIN) {
+ path->input_rect.h--;
+ }
+#endif
+ path->valid_param.input_rect = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_SIZE:
+ {
+ struct dcam_size *size = (struct dcam_size*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH2_OUTPUT_SIZE {%d %d} \n", size->w, size->h);
+ if (size->w > DCAM_PATH2_FRAME_WIDTH_MAX ||
+ size->h > DCAM_PATH2_FRAME_HEIGHT_MAX) {
+ rtn = DCAM_RTN_PATH_SRC_SIZE_ERR;
+ } else {
+ path->output_size.w = size->w;
+ path->output_size.h = size->h;
+ path->valid_param.output_size = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_FORMAT:
+ {
+ enum dcam_fmt format = *(enum dcam_fmt*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if((DCAM_YUV422 != format) &&
+ (DCAM_YUV420 != format) &&
+ (DCAM_YUV420_3FRAME != format)){
+ rtn = DCAM_RTN_PATH_OUT_FMT_ERR;
+ path->output_format = DCAM_FTM_MAX;
+ }else{
+ path->output_format = format;
+ path->valid_param.output_format = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame frame;
+ memset((void*)&frame, 0, sizeof(struct dcam_frame));
+ frame.yaddr = p_addr->yaddr;
+ frame.uaddr = p_addr->uaddr;
+ frame.vaddr = p_addr->vaddr;
+ frame.yaddr_vir = p_addr->yaddr_vir;
+ frame.uaddr_vir = p_addr->uaddr_vir;
+ frame.vaddr_vir = p_addr->vaddr_vir;
+ frame.type = DCAM_PATH2;
+ frame.fid = s_p_dcam_mod->dcam_path2.frame_base_id;
+ DCAM_TRACE("DCAM: Path 2 DCAM_PATH_OUTPUT_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ _dcam_buf_queue_write(&s_p_dcam_mod->dcam_path2.buf_queue, &frame);
+ }
+ break;
+ }
+
+ case DCAM_PATH_OUTPUT_RESERVED_ADDR:
+ {
+ struct dcam_addr *p_addr = (struct dcam_addr*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (DCAM_YUV_ADDR_INVALID(p_addr->yaddr, p_addr->uaddr, p_addr->vaddr)) {
+ rtn = DCAM_RTN_PATH_ADDR_ERR;
+ } else {
+ struct dcam_frame *frame = &s_p_dcam_mod->path2_reserved_frame;
+ frame->yaddr = p_addr->yaddr;
+ frame->uaddr = p_addr->uaddr;
+ frame->vaddr = p_addr->vaddr;
+ frame->yaddr_vir = p_addr->yaddr_vir;
+ frame->uaddr_vir = p_addr->uaddr_vir;
+ frame->vaddr_vir = p_addr->vaddr_vir;
+ DCAM_TRACE("DCAM: Path 1 DCAM_PATH_OUTPUT_RESERVED_ADDR, i=%d, y=0x%x, u=0x%x, v=0x%x \n",
+ path->output_frame_count, p_addr->yaddr, p_addr->uaddr, p_addr->vaddr);
+ }
+ break;
+ }
+
+ case DCAM_PATH_SRC_SEL:
+ {
+ uint32_t src_sel = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (src_sel >= DCAM_PATH_FROM_NONE) {
+ rtn = DCAM_RTN_PATH_SRC_ERR;
+ } else {
+ path->src_sel = src_sel;
+ path->valid_param.src_sel = 1;
+
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRAME_BASE_ID:
+ {
+ uint32_t base_id = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_BASE_ID 0x%x \n", base_id);
+ s_p_dcam_mod->dcam_path2.frame_base_id = base_id;
+ break;
+ }
+
+ case DCAM_PATH_DATA_ENDIAN:
+ {
+ struct dcam_endian_sel *endian = (struct dcam_endian_sel*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (endian->y_endian >= DCAM_ENDIAN_MAX ||
+ endian->uv_endian >= DCAM_ENDIAN_MAX) {
+ rtn = DCAM_RTN_PATH_ENDIAN_ERR;
+ } else {
+ path->data_endian.y_endian = endian->y_endian;
+ path->data_endian.uv_endian = endian->uv_endian;
+ path->valid_param.data_endian = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_ENABLE:
+ {
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ path->valide = *(uint32_t*)param;
+
+ break;
+ }
+
+ case DCAM_PATH_FRAME_TYPE:
+ {
+ struct dcam_frame *frame = &s_p_dcam_mod->dcam_path2.buf_queue.frame[0];
+ uint32_t frm_type = *(uint32_t*)param, i;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ DCAM_TRACE("DCAM: DCAM_PATH_FRAME_TYPE 0x%x \n", frm_type);
+ for (i = 0; i < DCAM_PATH_2_FRM_CNT_MAX; i++) {
+ (frame+i)->type = frm_type;
+ }
+ break;
+ }
+
+ case DCAM_PATH_FRM_DECI:
+ {
+ uint32_t deci_factor = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (deci_factor >= DCAM_FRM_DECI_FAC_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ } else {
+ path->frame_deci = deci_factor;
+ path->valid_param.frame_deci = 1;
+ }
+ break;
+ }
+
+ case DCAM_PATH_ROT_MODE:
+ {
+ uint32_t rot_mode = *(uint32_t*)param;
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+ if (rot_mode >= DCAM_PATH_FRAME_ROT_MAX) {
+ rtn = DCAM_RTN_PATH_FRM_DECI_ERR;
+ }else{
+ path->rot_mode = rot_mode;
+ path->valid_param.rot_mode = 1;
+ printk("zcf dcam_path2_cfg rot:\n",path->rot_mode);
+ }
+ }
+
+ case DCAM_PATH_SHRINK:
+ {
+ uint32_t shrink = *(uint32_t*)param;
+
+ DCAM_CHECK_PARAM_ZERO_POINTER(param);
+
+ if (shrink == 1) {
+ path->shrink = 1;
+ } else {
+ path->shrink = 0;
+ }
+ path->valid_param.shrink = 1;
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ return -rtn;
+}
+
+int32_t dcam_get_resizer(uint32_t wait_opt)
+{
+ int32_t rtn = 0;
+
+ printk("resizer_get:%d\n",current->pid);
+
+
+ if( 0 == wait_opt) {
+ rtn = mutex_trylock(&dcam_sem) ? 0 : 1;
+ return rtn;
+ } else if (DCAM_WAIT_FOREVER == wait_opt){
+ mutex_lock(&dcam_sem);
+ return rtn;
+ } else {
+ return 0;//mutex_timeout(&dcam_sem, wait_opt);
+ }
+}
+
+int32_t dcam_rel_resizer(void)
+{
+ printk("resizer_put:%d\n",current->pid);
+ mutex_unlock(&dcam_sem);
+ return 0;
+}
+
+int32_t dcam_resize_start(void)
+{
+ atomic_inc(&s_resize_flag);
+ mutex_lock(&dcam_scale_sema);
+ return 0;
+}
+
+int32_t dcam_resize_end(void)
+{
+ unsigned long flag;
+
+ atomic_dec(&s_resize_flag);
+ mutex_unlock(&dcam_scale_sema);
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+ }
+
+ if (s_p_dcam_mod) {
+ if (s_p_dcam_mod->wait_resize_done) {
+ up(&s_p_dcam_mod->resize_done_sema);
+ s_p_dcam_mod->wait_resize_done = 0;
+ }
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+}
+
+int32_t dcam_rotation_start(void)
+{
+ atomic_inc(&s_rotation_flag);
+ mutex_lock(&dcam_rot_sema);
+ return 0;
+}
+
+int32_t dcam_rotation_end(void)
+{
+ unsigned long flag;
+
+ atomic_dec(&s_rotation_flag);
+ mutex_unlock(&dcam_rot_sema);
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+ }
+
+ if (s_p_dcam_mod) {
+ if (s_p_dcam_mod->wait_rotation_done) {
+ up(&s_p_dcam_mod->rotation_done_sema);
+ s_p_dcam_mod->wait_rotation_done = 0;
+ }
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return 0;
+}
+
+void dcam_int_en(void)
+{
+ if (atomic_read(&s_dcam_users) == 1) {
+ enable_irq(DCAM_IRQ);
+ }
+}
+
+void dcam_int_dis(void)
+{
+ if (atomic_read(&s_dcam_users) == 1) {
+ disable_irq(DCAM_IRQ);
+ }
+}
+
+int32_t dcam_frame_is_locked(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (frame)
+ rtn = frame->lock == DCAM_FRM_LOCK_WRITE ? 1 : 0;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_frame_lock(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: lock %d \n", (uint32_t)(0xF&frame->fid));
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (likely(frame))
+ frame->lock = DCAM_FRM_LOCK_WRITE;
+ else
+ rtn = DCAM_RTN_PARA_ERR;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_frame_unlock(struct dcam_frame *frame)
+{
+ uint32_t rtn = 0;
+ unsigned long flags;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: unlock %d \n", (uint32_t)(0xF&frame->fid));
+
+ /*To disable irq*/
+ local_irq_save(flags);
+ if (likely(frame))
+ frame->lock = DCAM_FRM_UNLOCK;
+ else
+ rtn = DCAM_RTN_PARA_ERR;
+ local_irq_restore(flags);
+ /*To enable irq*/
+
+ return -rtn;
+}
+
+int32_t dcam_read_registers(uint32_t* reg_buf, uint32_t *buf_len)
+{
+ uint32_t *reg_addr = (uint32_t*)DCAM_BASE;
+
+ if (NULL == reg_buf || NULL == buf_len || 0 != (*buf_len % 4)) {
+ return -1;
+ }
+
+ if (atomic_read(&s_dcam_users) == 1) {
+ while (buf_len != 0 && (unsigned long)reg_addr < DCAM_END) {
+ *reg_buf++ = REG_RD(reg_addr);
+ reg_addr++;
+ *buf_len -= 4;
+ }
+ *buf_len = (unsigned long)reg_addr - DCAM_BASE;
+ }
+
+ return 0;
+}
+
+int32_t dcam_get_path_id(struct dcam_get_path_id *path_id, uint32_t *channel_id)
+{
+ int ret = DCAM_RTN_SUCCESS;
+
+ if (NULL == path_id || NULL == channel_id) {
+ return -1;
+ }
+
+ printk("DCAM: fourcc 0x%x, input w %d, h %d output w %d, h %d input_trim %d %d %d %d shrink %d need_isp %d\n", path_id->fourcc,
+ path_id->input_size.w, path_id->input_size.h,
+ path_id->output_size.w, path_id->output_size.h,
+ path_id->input_trim.x, path_id->input_trim.y, path_id->input_trim.w, path_id->input_trim.h,
+ path_id->need_shrink, path_id->need_isp);
+
+ if (path_id->need_isp_tool) {
+ *channel_id = DCAM_PATH0;
+ } else if (V4L2_PIX_FMT_GREY == path_id->fourcc && !path_id->is_path_work[DCAM_PATH0]) {
+ *channel_id = DCAM_PATH0;
+ } else if (V4L2_PIX_FMT_JPEG == path_id->fourcc && !path_id->is_path_work[DCAM_PATH0]) {
+ *channel_id = DCAM_PATH0;
+ } else if (path_id->output_size.w <= DCAM_PATH1_LINE_BUF_LENGTH && !path_id->is_path_work[DCAM_PATH1]) {
+ *channel_id = DCAM_PATH1;
+#ifndef CONFIG_ARCH_SCX35LT8
+ } else if (!path_id->need_shrink && path_id->need_isp && !path_id->is_path_work[DCAM_PATH0]
+ && path_id->output_size.w == path_id->input_trim.w && path_id->output_size.h == path_id->input_trim.h) {
+ *channel_id = DCAM_PATH0;
+#endif
+ } else if (path_id->output_size.w <= DCAM_PATH2_LINE_BUF_LENGTH && !path_id->is_path_work[DCAM_PATH2]) {
+ *channel_id = DCAM_PATH2;
+ } else {
+ *channel_id = DCAM_PATH0;
+ }
+ printk("DCAM: path id %d \n", *channel_id);
+
+ return ret;
+}
+
+int32_t dcam_get_path_capability(struct dcam_path_capability *capacity)
+{
+ int ret = DCAM_RTN_SUCCESS;
+
+ if (NULL == capacity) {
+ return -1;
+ }
+
+ capacity->count = 3;
+ capacity->path_info[DCAM_PATH0].line_buf = 0;
+#ifndef CONFIG_ARCH_SCX35LT8
+ capacity->path_info[DCAM_PATH0].support_yuv = 1;
+#else
+ capacity->path_info[DCAM_PATH0].support_yuv = 0;
+#endif
+ capacity->path_info[DCAM_PATH0].support_raw = 1;
+ capacity->path_info[DCAM_PATH0].support_jpeg = 1;
+ capacity->path_info[DCAM_PATH0].support_scaling = 0;
+ capacity->path_info[DCAM_PATH0].support_trim = 0;
+ capacity->path_info[DCAM_PATH0].is_scaleing_path = 0;
+
+ capacity->path_info[DCAM_PATH1].line_buf = DCAM_PATH1_LINE_BUF_LENGTH;
+ capacity->path_info[DCAM_PATH1].support_yuv = 1;
+ capacity->path_info[DCAM_PATH1].support_raw = 0;
+ capacity->path_info[DCAM_PATH1].support_jpeg = 0;
+ capacity->path_info[DCAM_PATH1].support_scaling = 1;
+ capacity->path_info[DCAM_PATH1].support_trim = 1;
+ capacity->path_info[DCAM_PATH1].is_scaleing_path = 0;
+
+ capacity->path_info[DCAM_PATH2].line_buf = DCAM_PATH2_LINE_BUF_LENGTH;
+ capacity->path_info[DCAM_PATH2].support_yuv = 1;
+ capacity->path_info[DCAM_PATH2].support_raw = 0;
+ capacity->path_info[DCAM_PATH2].support_jpeg = 0;
+ capacity->path_info[DCAM_PATH2].support_scaling = 1;
+ capacity->path_info[DCAM_PATH2].support_trim = 1;
+ capacity->path_info[DCAM_PATH2].is_scaleing_path = 1;
+
+ return ret;
+}
+
+
+LOCAL irqreturn_t _dcam_isr_root(int irq, void *dev_id)
+{
+ uint32_t irq_line, status;
+ unsigned long flag;
+ int32_t i;
+
+ DCAM_TRACE("DCAM: ISR 0x%x \n", REG_RD(DCAM_INT_STS));
+ status = REG_RD(DCAM_INT_STS) & DCAM_IRQ_LINE_MASK;
+ if (unlikely(0 == status)) {
+ return IRQ_NONE;
+ }
+
+ irq_line = status;
+ if (unlikely(DCAM_IRQ_ERR_MASK & status)) {
+ if (_dcam_err_pre_proc()) {
+ return IRQ_NONE;
+ }
+ }
+
+ spin_lock_irqsave(&dcam_lock,flag);
+
+ //for (i = DCAM_IRQ_NUMBER - 1; i >= 0; i--) {
+ for (i = 0; i < DCAM_IRQ_NUMBER; i++) {
+ if (irq_line & (1 << (uint32_t)i)) {
+ if (isr_list[i]) {
+ isr_list[i]();
+ }
+ }
+ irq_line &= ~(uint32_t)(1 << (uint32_t)i); //clear the interrupt flag
+ if(!irq_line) //no interrupt source left
+ break;
+ }
+
+ REG_WR(DCAM_INT_CLR, status);
+ DCAM_TRACE("DCAM: status 0x%x, ISR 0x%x \n", status, REG_RD(DCAM_INT_STS));
+
+ spin_unlock_irqrestore(&dcam_lock, flag);
+
+ return IRQ_HANDLED;
+}
+
+LOCAL void _dcam_path0_set(void)
+{
+ uint32_t reg_val = 0;
+ struct dcam_path_desc *path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH0_SRC_SIZE, reg_val);
+ }
+
+ if (path->valid_param.input_rect) {
+ reg_val = path->input_rect.x | (path->input_rect.y << 16);
+ REG_WR(DCAM_PATH0_TRIM_START, reg_val);
+ reg_val = path->input_rect.w | (path->input_rect.h << 16);
+ REG_WR(DCAM_PATH0_TRIM_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path0 set: rect {%d %d %d %d} \n",
+ path->input_rect.x,
+ path->input_rect.y,
+ path->input_rect.w,
+ path->input_rect.h);
+ }
+
+ if (path->valid_param.src_sel) {
+ REG_MWR(DCAM_CFG, BIT_10 , path->src_sel << 10);
+ DCAM_TRACE("DCAM: path 0: src_sel=0x%x \n", path->src_sel);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_1 | BIT_0, path->frame_deci << 0);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_output_mode format = path->output_format;
+ REG_MWR(DCAM_PATH0_CFG, BIT_2 | BIT_3, format << 2);
+ DCAM_TRACE("DCAM: path 0: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_5 | BIT_4, path->data_endian.y_endian << 4, DCAM_ENDIAN_REG);
+ if (DCAM_ENDIAN_BIG == path->data_endian.y_endian) {
+ if (DCAM_ENDIAN_LITTLE == path->data_endian.uv_endian ||
+ DCAM_ENDIAN_HALFBIG == path->data_endian.uv_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_20, 1 << 20, DCAM_ENDIAN_REG);
+ } else {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_20, 0, DCAM_ENDIAN_REG);
+ }
+ } else if (DCAM_ENDIAN_LITTLE == path->data_endian.y_endian) {
+ if (DCAM_ENDIAN_BIG == path->data_endian.uv_endian ||
+ DCAM_ENDIAN_HALFBIG == path->data_endian.uv_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_20, 1 << 20, DCAM_ENDIAN_REG);
+ } else {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_20, 0, DCAM_ENDIAN_REG);
+ }
+ } else {
+ printk("DCAM DRV: endian, do nothing u %d, v %d \n",
+ path->data_endian.y_endian,
+ path->data_endian.uv_endian);
+ }
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM DRV: path 0: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+}
+LOCAL void _dcam_path1_set(struct dcam_path_desc *path)
+{
+ uint32_t reg_val = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ DCAM_CHECK_ZERO_VOID(path);
+
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH1_SRC_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: src {%d %d} \n",path->input_size.w, path->input_size.h);
+ }
+
+ if (path->valid_param.input_rect) {
+ reg_val = path->input_rect.x | (path->input_rect.y << 16);
+ REG_WR(DCAM_PATH1_TRIM_START, reg_val);
+ reg_val = path->input_rect.w | (path->input_rect.h << 16);
+ REG_WR(DCAM_PATH1_TRIM_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: rect {%d %d %d %d} \n",
+ path->input_rect.x,
+ path->input_rect.y,
+ path->input_rect.w,
+ path->input_rect.h);
+ }
+
+ if (path->valid_param.output_size) {
+ reg_val = path->output_size.w | (path->output_size.h << 16);
+ REG_WR(DCAM_PATH1_DST_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path1 set: dst {%d %d} \n",path->output_size.w, path->output_size.h);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_fmt format = path->output_format;
+ if (DCAM_YUV422 == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 0 << 6);
+ } else if (DCAM_YUV420 == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 1 << 6);
+ } else if (DCAM_YUV420_3FRAME == format) {
+ REG_MWR(DCAM_PATH1_CFG, BIT_7 | BIT_6, 3 << 6);
+ } else {
+ DCAM_TRACE("DCAM: invalid path 1 output format %d \n", format);
+ }
+ DCAM_TRACE("DCAM: path 1: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.src_sel) {
+ REG_MWR(DCAM_CFG, BIT_12 | BIT_11, path->src_sel << 11);
+ DCAM_TRACE("DCAM: path 1: src_sel=0x%x \n", path->src_sel);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_7 | BIT_6, path->data_endian.y_endian << 6, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_9 | BIT_8, path->data_endian.uv_endian << 8, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM: path 1: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_24 | BIT_23, path->frame_deci << 23);
+ DCAM_TRACE("DCAM: path 1: frame_deci=0x%x \n", path->frame_deci);
+ }
+
+ if (path->valid_param.scale_tap) {
+ path->valid_param.scale_tap = 0;
+ REG_MWR(DCAM_PATH1_CFG, BIT_19 | BIT_18 | BIT_17 | BIT_16, (path->scale_tap.y_tap & 0x0F) << 16);
+ REG_MWR(DCAM_PATH1_CFG, BIT_15 | BIT_14 | BIT_13 | BIT_12 | BIT_11, (path->scale_tap.uv_tap & 0x1F) << 11);
+ DCAM_TRACE("DCAM: path 1: scale_tap, y=0x%x, uv=0x%x \n", path->scale_tap.y_tap, path->scale_tap.uv_tap);
+ }
+
+ if (path->valid_param.v_deci) {
+ path->valid_param.v_deci = 0;
+ REG_MWR(DCAM_PATH1_CFG, BIT_2, path->deci_val.deci_x_en << 2);
+ REG_MWR(DCAM_PATH1_CFG, BIT_1 | BIT_0, path->deci_val.deci_x);
+
+ REG_MWR(DCAM_PATH1_CFG, BIT_5, path->deci_val.deci_y_en << 5);
+ REG_MWR(DCAM_PATH1_CFG, BIT_4 | BIT_3, path->deci_val.deci_y << 3);
+ DCAM_TRACE("DCAM: path 1: deci, x_en=%d, x=%d, y_en=%d, y=%d \n",
+ path->deci_val.deci_x_en, path->deci_val.deci_x, path->deci_val.deci_y_en, path->deci_val.deci_y);
+ }
+
+ if(path->valid_param.rot_mode){
+ path->valid_param.rot_mode = 0;
+ printk("zcf dcam_path1_set 1 rot_mod :%d reg:%x\n",path->rot_mode,REG_RD(DCAM_PATH1_CFG));
+ REG_MWR(DCAM_PATH1_CFG, BIT_10 | BIT_9, path->rot_mode << 9);
+ printk("zcf dcam_path1_set 1 rot_mod :%d reg:%x\n",path->rot_mode,REG_RD(DCAM_PATH1_CFG));
+ }
+
+ if (path->valid_param.shrink) {
+ path->valid_param.shrink = 0;
+ REG_MWR(DCAM_PATH1_CFG, BIT_25 | BIT_26, path->shrink << 25);
+ DCAM_TRACE("DCAM: path 1: shrink, %d \n", path->shrink);
+ }
+}
+
+LOCAL void _dcam_path2_set(void)
+{
+ struct dcam_path_desc *path = NULL;
+ uint32_t reg_val = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+ if (path->valid_param.input_size) {
+ reg_val = path->input_size.w | (path->input_size.h << 16);
+ REG_WR(DCAM_PATH2_SRC_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: src {%d %d} \n",path->input_size.w, path->input_size.h);
+ }
+
+ if (path->valid_param.input_rect) {
+ reg_val = path->input_rect.x | (path->input_rect.y << 16);
+ REG_WR(DCAM_PATH2_TRIM_START, reg_val);
+ reg_val = path->input_rect.w | (path->input_rect.h << 16);
+ REG_WR(DCAM_PATH2_TRIM_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: rect {%d %d %d %d} \n",
+ path->input_rect.x,
+ path->input_rect.y,
+ path->input_rect.w,
+ path->input_rect.h);
+ }
+
+ if(path->valid_param.output_size){
+ reg_val = path->output_size.w | (path->output_size.h << 16);
+ REG_WR(DCAM_PATH2_DST_SIZE, reg_val);
+ DCAM_TRACE("DCAM: path2 set: dst {%d %d} \n",path->output_size.w, path->output_size.h);
+ }
+
+ if (path->valid_param.output_format) {
+ enum dcam_fmt format = path->output_format;
+
+ // REG_MWR(DCAM_PATH2_CFG, BIT_8, 0 << 8); // aiden todo
+
+ if (DCAM_YUV422 == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 0 << 6);
+ } else if (DCAM_YUV420 == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 1 << 6);
+ } else if (DCAM_YUV420_3FRAME == format) {
+ REG_MWR(DCAM_PATH2_CFG, BIT_7 | BIT_6, 3 << 6);
+ } else {
+ DCAM_TRACE("DCAM: invalid path 2 output format %d \n", format);
+ }
+ DCAM_TRACE("DCAM: path 2: output_format=0x%x \n", format);
+ }
+
+ if (path->valid_param.src_sel) {
+ REG_MWR(DCAM_CFG, BIT_14 | BIT_13, path->src_sel << 13);
+ }
+
+ if (path->valid_param.data_endian) {
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_11 | BIT_10, path->data_endian.y_endian << 10,DCAM_ENDIAN_REG );
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_13 | BIT_12, path->data_endian.uv_endian << 12, DCAM_ENDIAN_REG);
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_18, BIT_18, DCAM_ENDIAN_REG); // axi write
+ dcam_glb_reg_mwr(DCAM_ENDIAN_SEL, BIT_19, BIT_19, DCAM_ENDIAN_REG); // axi read
+ DCAM_TRACE("DCAM: path 2: data_endian y=0x%x, uv=0x%x \n",
+ path->data_endian.y_endian, path->data_endian.uv_endian);
+ }
+
+ if (path->valid_param.frame_deci) {
+ REG_MWR(DCAM_PATH0_CFG, BIT_24 | BIT_23, path->frame_deci << 23);
+ DCAM_TRACE("DCAM: path 2: frame_deci=0x%x \n", path->frame_deci);
+ }
+
+ if (path->valid_param.scale_tap) {
+ path->valid_param.scale_tap = 0;
+ REG_MWR(DCAM_PATH2_CFG, BIT_19 | BIT_18 | BIT_17 | BIT_16, (path->scale_tap.y_tap & 0x0F) << 16);
+ REG_MWR(DCAM_PATH2_CFG, BIT_15 | BIT_14 | BIT_13 | BIT_12 | BIT_11, (path->scale_tap.uv_tap & 0x1F) << 11);
+ DCAM_TRACE("DCAM: path 2: scale_tap, y=0x%x, uv=0x%x \n",
+ path->scale_tap.y_tap, path->scale_tap.uv_tap);
+ }
+
+ if (path->valid_param.v_deci) {
+ path->valid_param.v_deci = 0;
+ REG_MWR(DCAM_PATH2_CFG, BIT_2, path->deci_val.deci_x_en << 2);
+ REG_MWR(DCAM_PATH2_CFG, BIT_1 | BIT_0, path->deci_val.deci_x);
+
+ REG_MWR(DCAM_PATH2_CFG, BIT_5, path->deci_val.deci_y_en << 5);
+ REG_MWR(DCAM_PATH2_CFG, BIT_4 | BIT_3, path->deci_val.deci_y << 3);
+ DCAM_TRACE("DCAM: path 2: deci, x_en=%d, x=%d, y_en=%d, y=%d \n",
+ path->deci_val.deci_x_en, path->deci_val.deci_x, path->deci_val.deci_y_en, path->deci_val.deci_y);
+ }
+
+ if (path->valid_param.rot_mode){
+ path->valid_param.rot_mode = 0;
+ printk("zcf dcam_path2_set rot_mod :%d reg:%x\n",path->rot_mode,REG_RD(DCAM_PATH2_CFG));
+ REG_MWR(DCAM_PATH2_CFG, BIT_10 | BIT_9, path->rot_mode << 9);
+ printk("zcf dcam_path2_set rot_mod :%d reg:%x\n",path->rot_mode,REG_RD(DCAM_PATH2_CFG));
+ }
+
+ if (path->valid_param.shrink) {
+ path->valid_param.shrink = 0;
+ REG_MWR(DCAM_PATH2_CFG, BIT_25 | BIT_26, path->shrink << 25);
+ DCAM_TRACE("DCAM: path 2: shrink, %d \n", path->shrink);
+ }
+}
+
+LOCAL void _dcam_buf_queue_init(struct dcam_buf_queue *queue)
+{
+ if (DCAM_ADDR_INVALID(queue)) {
+ printk("DCAM: invalid heap %p \n", queue);
+ return;
+ }
+
+ memset((void*)queue, 0, sizeof(struct dcam_buf_queue));
+ queue->write = &queue->frame[0];
+ queue->read = &queue->frame[0];
+ spin_lock_init(&queue->lock);
+ return;
+}
+
+LOCAL int32_t _dcam_buf_queue_write(struct dcam_buf_queue *queue, struct dcam_frame *frame)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ struct dcam_frame *ori_frame;
+ unsigned long flag;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: enq, invalid param %p, %p \n",
+ queue,
+ frame);
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&queue->lock, flag);
+ ori_frame = queue->write;
+ DCAM_TRACE("DCAM: _dcam_buf_queue_write \n");
+ *queue->write++ = *frame;
+ if (queue->write > &queue->frame[DCAM_FRM_CNT_MAX-1]) {
+ queue->write = &queue->frame[0];
+ }
+
+ if (queue->write == queue->read) {
+ queue->write = ori_frame;
+ printk("DCAM: warning, queue is full, cannot write 0x%lx \n", frame->yaddr);
+ }
+ spin_unlock_irqrestore(&queue->lock, flag);
+ DCAM_TRACE("DCAM: _dcam_buf_queue_write type %d \n", frame->type);
+ return ret;
+}
+
+LOCAL int32_t _dcam_buf_queue_read(struct dcam_buf_queue *queue, struct dcam_frame *frame)
+{
+ int ret = DCAM_RTN_SUCCESS;
+ unsigned long flag;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: deq, invalid param %p, %p \n",
+ queue,
+ frame);
+ return -EINVAL;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_buf_queue_read \n");
+
+ spin_lock_irqsave(&queue->lock, flag);
+ if (queue->read != queue->write) {
+ *frame = *queue->read++;
+ if (queue->read > &queue->frame[DCAM_FRM_CNT_MAX-1]) {
+ queue->read = &queue->frame[0];
+ }
+ } else {
+ ret = EAGAIN;
+ }
+ spin_unlock_irqrestore(&queue->lock, flag);
+ DCAM_TRACE("DCAM: _dcam_buf_queue_read type %d \n", frame->type);
+ return ret;
+}
+
+LOCAL void _dcam_frm_queue_clear(struct dcam_frm_queue *queue)
+{
+ if (DCAM_ADDR_INVALID(queue)) {
+ printk("DCAM: invalid heap %p \n", queue);
+ return;
+ }
+
+ memset((void*)queue, 0, sizeof(struct dcam_frm_queue));
+ return;
+}
+
+LOCAL int32_t _dcam_frame_enqueue(struct dcam_frm_queue *queue, struct dcam_frame *frame)
+{
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: enq, invalid param %p, %p \n",
+ queue,
+ frame);
+ return -1;
+ }
+ if (queue->valid_cnt >= DCAM_FRM_QUEUE_LENGTH) {
+ printk("DCAM: q over flow \n");
+ return -1;
+ }
+ //queue->frm_array[queue->valid_cnt] = frame;
+ memcpy(&queue->frm_array[queue->valid_cnt], frame, sizeof(struct dcam_frame));
+ queue->valid_cnt ++;
+ DCAM_TRACE("DCAM: en queue, %d, %d, 0x%x, 0x%x \n",
+ (0xF & frame->fid),
+ queue->valid_cnt,
+ frame->yaddr,
+ frame->uaddr);
+ return 0;
+}
+
+LOCAL int32_t _dcam_frame_dequeue(struct dcam_frm_queue *queue, struct dcam_frame *frame)
+{
+ uint32_t i = 0;
+
+ if (DCAM_ADDR_INVALID(queue) || DCAM_ADDR_INVALID(frame)) {
+ printk("DCAM: deq, invalid param %p, %p \n",
+ queue,
+ frame);
+ return -1;
+ }
+ if (queue->valid_cnt == 0) {
+ printk("DCAM: q under flow \n");
+ return -1;
+ }
+
+ //*frame = queue->frm_array[0];
+ memcpy(frame, &queue->frm_array[0], sizeof(struct dcam_frame));
+ queue->valid_cnt--;
+ for (i = 0; i < queue->valid_cnt; i++) {
+ //queue->frm_array[i] = queue->frm_array[i+1];
+ memcpy(&queue->frm_array[i], &queue->frm_array[i+1], sizeof(struct dcam_frame));
+ }
+ DCAM_TRACE("DCAM: de queue, %d, %d \n",
+ (0xF & (frame)->fid),
+ queue->valid_cnt);
+ return 0;
+}
+
+LOCAL void _dcam_frm_clear(enum dcam_path_index path_index)
+{
+ uint32_t i = 0;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path0.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path0.buf_queue);
+ }
+
+ if (DCAM_PATH_IDX_1 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path1.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path1.buf_queue);
+ }
+
+ if (DCAM_PATH_IDX_2 & path_index) {
+ _dcam_frm_queue_clear(&s_p_dcam_mod->dcam_path2.frame_queue);
+ _dcam_buf_queue_init(&s_p_dcam_mod->dcam_path2.buf_queue);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_frm_pop(enum dcam_path_index path_index)
+{
+ uint32_t i = 0;
+ struct dcam_frame *frame = NULL;
+ uint32_t *frame_count;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 & path_index) {
+ frame = &s_p_dcam_mod->path0_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path0.output_frame_count;
+ }
+ if (DCAM_PATH_IDX_1 & path_index) {
+ frame = &s_p_dcam_mod->path1_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path1.output_frame_count;
+ }
+ if (DCAM_PATH_IDX_2 & path_index) {
+ frame = &s_p_dcam_mod->path2_frame[0];
+ frame_count = &s_p_dcam_mod->dcam_path2.output_frame_count;
+ }
+ printk("DCAM: frame pop index %d frame_count %d addr 0x%x \n", path_index, *frame_count, frame->yaddr);
+ if (0 == *frame_count) {
+ return;
+ }
+
+ for (i = 0; i < *frame_count - 1; i++) {
+ memcpy(frame+i, frame+i+1, sizeof(struct dcam_frame));
+ }
+ (*frame_count)--;
+ //memset(frame+(*frame_count), 0, sizeof(struct dcam_frame));
+ (frame+(*frame_count))->yaddr = 0;
+ (frame+(*frame_count))->uaddr = 0;
+ (frame+(*frame_count))->vaddr = 0;
+
+ if (0 == *frame_count) {
+ //_dcam_wait_for_quickstop(path_index);
+ }
+ DCAM_TRACE("DCAM: frame pop done \n");
+
+ return;
+}
+
+
+LOCAL void _dcam_link_frm(uint32_t base_id)
+{
+/* uint32_t i = 0;
+ struct dcam_frame *path0_frame = NULL;
+ struct dcam_frame *path1_frame = NULL;
+ struct dcam_frame *path2_frame = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ path0_frame = &s_p_dcam_mod->path0_frame[0];
+ path1_frame = &s_p_dcam_mod->path1_frame[0];
+ path2_frame = &s_p_dcam_mod->path2_frame[0];
+ for (i = 0; i < DCAM_PATH_0_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path0_frame + i);
+ //(path0_frame+i)->next = path0_frame + (i + 1) % DCAM_PATH_0_FRM_CNT_MAX;
+ //(path0_frame+i)->prev = path0_frame + (i - 1 + DCAM_PATH_0_FRM_CNT_MAX) % DCAM_PATH_0_FRM_CNT_MAX;
+ (path0_frame+i)->fid = base_id + i;
+ }
+
+ for (i = 0; i < DCAM_PATH_1_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path1_frame + i);
+ //(path1_frame+i)->next = path1_frame + (i + 1) % DCAM_PATH_1_FRM_CNT_MAX;
+ //(path1_frame+i)->prev = path1_frame + (i - 1 + DCAM_PATH_1_FRM_CNT_MAX) % DCAM_PATH_1_FRM_CNT_MAX;
+ (path1_frame+i)->fid = base_id + i;
+ }
+
+ for (i = 0; i < DCAM_PATH_2_FRM_CNT_MAX; i++) {
+ DCAM_CLEAR(path2_frame + i);
+ //(path2_frame+i)->next = path2_frame+(i + 1) % DCAM_PATH_2_FRM_CNT_MAX;
+ //(path2_frame+i)->prev = path2_frame+(i - 1 + DCAM_PATH_2_FRM_CNT_MAX) % DCAM_PATH_2_FRM_CNT_MAX;
+ (path2_frame+i)->fid = base_id + i;
+ }
+
+ //s_p_dcam_mod->dcam_path0.output_frame_head = path0_frame;
+ //s_p_dcam_mod->dcam_path1.output_frame_head = path1_frame;
+ //s_p_dcam_mod->dcam_path2.output_frame_head = path2_frame;
+ //s_p_dcam_mod->dcam_path0.output_frame_cur = path0_frame;
+ //s_p_dcam_mod->dcam_path1.output_frame_cur = path1_frame;
+ //s_p_dcam_mod->dcam_path2.output_frame_cur = path2_frame;
+*/
+ return;
+}
+
+LOCAL int32_t _dcam_path_set_next_frm(enum dcam_path_index path_index, uint32_t is_1st_frm)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_frame frame;
+ struct dcam_frame *reserved_frame = NULL;
+ struct dcam_frame *orig_frame = NULL;
+ struct dcam_path_desc *path = NULL;
+ unsigned long yuv_reg[3] = {0};
+ uint32_t path_max_frm_cnt;
+ uint32_t flag = 0;
+ struct dcam_frm_queue *p_heap = NULL;
+ struct dcam_buf_queue *p_buf_queue = NULL;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ reserved_frame = &s_p_dcam_mod->path0_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path0;
+ yuv_reg[0] = DCAM_FRM_ADDR0;
+ yuv_reg[1] = DCAM_FRM_ADDR12;
+ path_max_frm_cnt = DCAM_PATH_0_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path0.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path0.buf_queue;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ //frame = &s_p_dcam_mod->path1_frame[0];
+ reserved_frame = &s_p_dcam_mod->path1_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path1;
+ yuv_reg[0] = DCAM_FRM_ADDR1;
+ yuv_reg[1] = DCAM_FRM_ADDR2;
+ yuv_reg[2] = DCAM_FRM_ADDR3;
+ path_max_frm_cnt = DCAM_PATH_1_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path1.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path1.buf_queue;
+ } else /*if(DCAM_PATH_IDX_2 == path_index)*/ {
+ //frame = &s_p_dcam_mod->path2_frame[0];
+ reserved_frame = &s_p_dcam_mod->path2_reserved_frame;
+ path = &s_p_dcam_mod->dcam_path2;
+ yuv_reg[0] = DCAM_FRM_ADDR4;
+ yuv_reg[1] = DCAM_FRM_ADDR5;
+ yuv_reg[2] = DCAM_FRM_ADDR6;
+ path_max_frm_cnt = DCAM_PATH_2_FRM_CNT_MAX;
+ p_heap = &s_p_dcam_mod->dcam_path2.frame_queue;
+ p_buf_queue = &s_p_dcam_mod->dcam_path2.buf_queue;
+ }
+
+ if (0 != _dcam_buf_queue_read(p_buf_queue, &frame)) {
+ DCAM_TRACE("DCAM: No freed frame id %d \n", frame.fid);
+ memcpy(&frame, reserved_frame, sizeof(struct dcam_frame));
+ }
+
+ DCAM_TRACE("DCAM: next %d y 0x%x uv 0x%x \n", path->output_frame_count, frame.yaddr, frame.uaddr);
+ REG_WR(yuv_reg[0], frame.yaddr);
+ if (((DCAM_YUV400 > path->output_format) && (DCAM_PATH_IDX_0 != path_index)) ||
+ ((DCAM_OUTPUT_YUV420 == path->output_format) && (DCAM_PATH_IDX_0 == path_index))) {
+ REG_WR(yuv_reg[1], frame.uaddr);
+ if (DCAM_YUV420_3FRAME == path->output_format) {
+ REG_WR(yuv_reg[2], frame.vaddr);
+ }
+ }
+ dcam_frame_lock(&frame);
+ if (0 == _dcam_frame_enqueue(p_heap, &frame)) {
+ } else {
+ dcam_frame_unlock(&frame);
+ rtn = DCAM_RTN_PATH_FRAME_LOCKED;
+ }
+
+ return -rtn;
+}
+
+#if 0
+LOCAL int32_t _dcam_path_trim(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path;
+ uint32_t cfg_reg, ctrl_bit;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ ctrl_bit = 8;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ ctrl_bit = 1;
+ } else {
+ printk("DCAM: _dcam_path_trim invalid path_index=%d \n", path_index);
+ return -1;
+ }
+
+ if (path->input_size.w != path->input_rect.w ||
+ path->input_size.h != path->input_rect.h) {
+ /*REG_OWR(cfg_reg, 1 << ctrl_bit);*/
+ } else {
+ /*REG_MWR(cfg_reg, 1 << ctrl_bit, 0 << ctrl_bit);*/
+ }
+
+ return rtn;
+
+}
+#endif
+
+LOCAL int32_t _dcam_path_scaler(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ unsigned long cfg_reg = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index){
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ }
+
+ DCAM_CHECK_ZERO(path);
+ if (DCAM_RAWRGB == path->output_format ||
+ DCAM_JPEG == path->output_format) {
+ DCAM_TRACE("DCAM: _dcam_path_scaler out format is %d, no need scaler \n", path->output_format);
+ return DCAM_RTN_SUCCESS;
+ }
+
+ rtn = _dcam_calc_sc_size(path_index);
+ if (DCAM_RTN_SUCCESS != rtn) {
+ return rtn;
+ }
+
+ if (path->sc_input_size.w == path->output_size.w &&
+ path->sc_input_size.h == path->output_size.h &&
+ DCAM_YUV422 == path->output_format) {
+ REG_MWR(cfg_reg, BIT_20, 1 << 20);// bypass scaler if the output size equals input size for YUV422 format
+ } else {
+ REG_MWR(cfg_reg, BIT_20, 0 << 20);
+ if (s_dcam_sc_array->is_smooth_zoom
+ && DCAM_PATH_IDX_1 == path_index
+ && DCAM_ST_START == path->status) {
+ rtn = _dcam_calc_sc_coeff(path_index);
+ } else {
+ rtn = _dcam_set_sc_coeff(path_index);
+ }
+ }
+
+ return rtn;
+}
+
+LOCAL int32_t _dcam_path_check_deci(enum dcam_path_index path_index, uint32_t *is_deci)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ uint32_t w_deci = 0;
+ uint32_t h_deci = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ goto dcam_path_err;
+ }
+
+ if (path->input_rect.w > (path->output_size.w * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.h > (path->output_size.h * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.w * DCAM_SC_COEFF_UP_MAX < path->output_size.w ||
+ path->input_rect.h * DCAM_SC_COEFF_UP_MAX < path->output_size.h) {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ } else {
+ if (path->input_rect.w > path->output_size.w * DCAM_SC_COEFF_DOWN_MAX)
+ w_deci = 1;
+ if (path->input_rect.h > path->output_size.h * DCAM_SC_COEFF_DOWN_MAX)
+ h_deci = 1;
+
+ if(w_deci || h_deci)
+ *is_deci = 1;
+ else
+ *is_deci = 0;
+ }
+
+dcam_path_err:
+ DCAM_TRACE("DCAM: _dcam_path_check_deci: path_index=%d, is_deci=%d, rtn=%d \n", path_index, *is_deci, rtn);
+
+ return rtn;
+}
+
+LOCAL uint32_t _dcam_get_path_deci_factor(uint32_t src_size, uint32_t dst_size)
+{
+ uint32_t factor = 0;
+
+ if (0 == src_size || 0 == dst_size) {
+ return factor;
+ }
+
+ /* factor: 0 - 1/2, 1 - 1/4, 2 - 1/8, 3 - 1/16 */
+ for (factor = 0; factor < DCAM_PATH_DECI_FAC_MAX; factor ++) {
+ if (src_size < (uint32_t)(dst_size * (1 << (factor + 1)))) {
+ break;
+ }
+ }
+
+ return factor;
+}
+
+LOCAL int32_t _dcam_calc_sc_size(enum dcam_path_index path_index)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ struct dcam_path_desc *path = NULL;
+ unsigned long cfg_reg = 0;
+ uint32_t tmp_dstsize = 0;
+ uint32_t align_size = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ cfg_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index){
+ path = &s_p_dcam_mod->dcam_path2;
+ cfg_reg = DCAM_PATH2_CFG;
+ }
+
+ DCAM_CHECK_ZERO(path);
+ if (path->input_rect.w > (path->output_size.w * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.h > (path->output_size.h * DCAM_SC_COEFF_DOWN_MAX * (1<<DCAM_PATH_DECI_FAC_MAX)) ||
+ path->input_rect.w * DCAM_SC_COEFF_UP_MAX < path->output_size.w ||
+ path->input_rect.h * DCAM_SC_COEFF_UP_MAX < path->output_size.h) {
+ rtn = DCAM_RTN_PATH_SC_ERR;
+ } else {
+ path->sc_input_size.w = path->input_rect.w;
+ path->sc_input_size.h = path->input_rect.h;
+ if (path->input_rect.w > path->output_size.w * DCAM_SC_COEFF_DOWN_MAX) {
+ tmp_dstsize = path->output_size.w * DCAM_SC_COEFF_DOWN_MAX;
+ path->deci_val.deci_x = _dcam_get_path_deci_factor(path->input_rect.w, tmp_dstsize);
+ path->deci_val.deci_x_en = 1;
+ path->valid_param.v_deci = 1;
+ align_size = (1 << (path->deci_val.deci_x+1))*DCAM_PIXEL_ALIGN_WIDTH;
+ path->input_rect.w = (path->input_rect.w) & ~(align_size-1);
+ path->input_rect.x = (path->input_rect.x) & ~(align_size-1);
+ path->sc_input_size.w = path->input_rect.w >> (path->deci_val.deci_x+1);
+ } else {
+ path->deci_val.deci_x = 0;
+ path->deci_val.deci_x_en = 0;
+ path->valid_param.v_deci = 1;
+ }
+
+ if (path->input_rect.h > path->output_size.h * DCAM_SC_COEFF_DOWN_MAX) {
+ tmp_dstsize = path->output_size.h * DCAM_SC_COEFF_DOWN_MAX;
+ path->deci_val.deci_y = _dcam_get_path_deci_factor(path->input_rect.h, tmp_dstsize);
+ path->deci_val.deci_y_en = 1;
+ path->valid_param.v_deci = 1;
+ align_size = (1 << (path->deci_val.deci_y+1))*DCAM_PIXEL_ALIGN_HEIGHT;
+ path->input_rect.h = (path->input_rect.h) & ~(align_size-1);
+ path->input_rect.y = (path->input_rect.y) & ~(align_size-1);
+ path->sc_input_size.h = path->input_rect.h >> (path->deci_val.deci_y+1);
+ } else {
+ path->deci_val.deci_y = 0;
+ path->deci_val.deci_y_en = 0;
+ path->valid_param.v_deci = 1;
+ }
+
+ }
+
+ DCAM_TRACE("DCAM: _dcam_calc_sc_size, path=%d, x_en=%d, deci_x=%d, y_en=%d, deci_y=%d \n",
+ path_index, path->deci_val.deci_x_en,
+ path->deci_val.deci_x, path->deci_val.deci_y_en,
+ path->deci_val.deci_y);
+
+ return -rtn;
+}
+
+LOCAL int32_t _dcam_set_sc_coeff(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *path = NULL;
+ uint32_t i = 0;
+ unsigned long h_coeff_addr = DCAM_BASE;
+ unsigned long v_coeff_addr = DCAM_BASE;
+ unsigned long v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ unsigned long ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ uint8_t y_tap = 0;
+ uint8_t uv_tap = 0;
+ uint32_t index = 0;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_set_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ down(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ if (!(Dcam_GenScaleCoeff((int16_t)path->sc_input_size.w,
+ (int16_t)path->sc_input_size.h,
+ (int16_t)path->output_size.w,
+ (int16_t)path->output_size.h,
+ h_coeff,
+ v_coeff,
+ v_chroma_coeff,
+ scale2yuv420,
+ &y_tap,
+ &uv_tap,
+ tmp_buf + (DCAM_SC_COEFF_COEF_SIZE*3/4),
+ DCAM_SC_COEFF_TMP_SIZE))) {
+ printk("DCAM: _dcam_set_sc_coeff Dcam_GenScaleCoeff error! \n");
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ return -DCAM_RTN_PATH_GEN_COEFF_ERR;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_H_NUM; i++) {
+ REG_WR(h_coeff_addr, *h_coeff);
+ h_coeff_addr += 4;
+ h_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_NUM; i++) {
+ REG_WR(v_coeff_addr, *v_coeff);
+ v_coeff_addr += 4;
+ v_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_CHROMA_NUM; i++) {
+ REG_WR(v_chroma_coeff_addr, *v_chroma_coeff);
+ v_chroma_coeff_addr += 4;
+ v_chroma_coeff++;
+ }
+
+ path->scale_tap.y_tap = y_tap;
+ path->scale_tap.uv_tap = uv_tap;
+ path->valid_param.scale_tap = 1;
+
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ return DCAM_RTN_SUCCESS;
+}
+
+LOCAL void _dcam_force_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy)
+{
+ uint32_t reg_val = 0;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ if(path_copy)
+ reg_val |= BIT_10;
+ if(coef_copy)
+ reg_val |= BIT_14;
+
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ if(path_copy)
+ reg_val |= BIT_12;
+ if(coef_copy)
+ reg_val |= BIT_16;
+
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_force_copy_ext invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_auto_copy_ext(enum dcam_path_index path_index, uint32_t path_copy, uint32_t coef_copy)
+{
+ uint32_t reg_val = 0;
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_9;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_11;
+ if (coef_copy)
+ reg_val |= BIT_15;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ if (path_copy)
+ reg_val |= BIT_13;
+ if (coef_copy)
+ reg_val |= BIT_17;
+ dcam_glb_reg_mwr(DCAM_CONTROL, reg_val, reg_val, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_auto_copy_ext invalid path index: %d \n", path_index);
+ }
+
+}
+
+LOCAL void _dcam_force_copy(enum dcam_path_index path_index)
+{
+ if (DCAM_PATH_IDX_1 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_10, 1 << 10, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_12, 1 << 12, DCAM_CONTROL_REG);
+ } else if (DCAM_PATH_IDX_0 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_8, 1 << 8, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_force_copy invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_auto_copy(enum dcam_path_index path_index)
+{
+ if (DCAM_PATH_IDX_0 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_9, 1 << 9, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_11, 1 << 11, DCAM_CONTROL_REG);
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_13, 1 << 13, DCAM_CONTROL_REG);
+ } else {
+ DCAM_TRACE("DCAM: _dcam_auto_copy invalid path index: %d \n", path_index);
+ }
+}
+
+LOCAL void _dcam_reg_trace(void)
+{
+#ifdef DCAM_DRV_DEBUG
+ unsigned long addr = 0;
+
+ printk("DCAM: Register list");
+ for (addr = DCAM_CFG; addr <= CAP_SENSOR_CTRL; addr += 16) {
+ printk("\n 0x%lx: 0x%x 0x%x 0x%x 0x%x",
+ addr,
+ REG_RD(addr),
+ REG_RD(addr + 4),
+ REG_RD(addr + 8),
+ REG_RD(addr + 12));
+ }
+
+ printk("\n");
+#endif
+}
+
+#if 0
+LOCAL void _dcam_sensor_sof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_SOF];
+ void *data = s_user_data[DCAM_SN_SOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _sn_sof \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+#endif
+
+LOCAL void _dcam_sensor_eof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_EOF];
+ void *data = s_user_data[DCAM_SN_EOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _sn_eof \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_cap_sof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_CAP_SOF];
+ void *data = s_user_data[DCAM_CAP_SOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: _cap_sof \n");
+
+ _dcam_stopped_notice();
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_cap_eof(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_CAP_EOF];
+ void *data = s_user_data[DCAM_CAP_EOF];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path0_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH0_DONE];
+ void *data = s_user_data[DCAM_PATH0_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path0;
+ if (0 == path->valide) {
+ printk("DCAM: path0 not valid \n");
+ return;
+ }
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_0, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_0);
+ DCAM_TRACE("DCAM 0 \n");
+ if (path->sof_cnt < 1) {
+ printk("DCAM: path0 done cnt %d\n", path->sof_cnt);
+ path->need_wait = 0;
+ return;
+ }
+ path->sof_cnt = 0;
+
+ if (path->need_wait) {
+ path->need_wait = 0;
+ } else {
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path0_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ DCAM_TRACE("DCAM: path0 frame 0x%x, y uv, 0x%x 0x%x \n",
+ (int)&frame, frame.yaddr, frame.uaddr);
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path0_reserved_frame \n");
+ }
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path0_overflow(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH0_OV];
+ void *data = s_user_data[DCAM_PATH0_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path0_overflow \n");
+ path = &s_p_dcam_mod->dcam_path0;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_DONE];
+ void *data = s_user_data[DCAM_PATH1_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path1;
+ if (0 == path->valide) {
+ printk("DCAM: path1 not valid \n");
+ return;
+ }
+
+ DCAM_TRACE("DCAM: 1\n");
+
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_1, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_1);
+
+ if (path->sof_cnt < 1) {
+ printk("DCAM: path1 done cnt %d\n", path->sof_cnt);
+ path->need_wait = 0;
+ return;
+ }
+ path->sof_cnt = 0;
+
+ if (path->need_wait) {
+ path->need_wait = 0;
+ } else {
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path1_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ DCAM_TRACE("DCAM: path1 frame 0x%x, y uv, 0x%x 0x%x \n",
+ (int)&frame, frame.yaddr, frame.uaddr);
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path1_reserved_frame \n");
+ }
+ }
+ return;
+}
+
+LOCAL void _dcam_path1_overflow(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_OV];
+ void *data = s_user_data[DCAM_PATH1_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path1_overflow \n");
+ path = &s_p_dcam_mod->dcam_path1;
+ //frame = path->output_frame_cur->prev->prev;
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_sensor_line_err(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_LINE_ERR];
+ void *data = s_user_data[DCAM_SN_LINE_ERR];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _line_err \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_sensor_frame_err(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_SN_FRAME_ERR];
+ void *data = s_user_data[DCAM_SN_FRAME_ERR];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _frame_err \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_jpeg_buf_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_JPEG_BUF_OV];
+ void *data = s_user_data[DCAM_JPEG_BUF_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _jpeg_overflow \n");
+ path = &s_p_dcam_mod->dcam_path0;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path0_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_done(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_DONE];
+ void *data = s_user_data[DCAM_PATH2_DONE];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ if (atomic_read(&s_resize_flag)) {
+ memset(&frame, 0, sizeof(struct dcam_frame));
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ path = &s_p_dcam_mod->dcam_path2;
+
+ DCAM_TRACE("DCAM: 2, %d %d \n", path->need_stop, path->need_wait);
+ if (path->status == DCAM_ST_START) {
+
+ if (path->need_stop) {
+ dcam_glb_reg_awr(DCAM_CFG, ~BIT_2, DCAM_CFG_REG);
+ path->need_stop = 0;
+ }
+ _dcam_path_done_notice(DCAM_PATH_IDX_2);
+
+ if (path->sof_cnt < 1) {
+ printk("DCAM: path2 done cnt %d\n", path->sof_cnt);
+ path->need_wait = 0;
+ return;
+ }
+ path->sof_cnt = 0;
+
+ if (path->need_wait) {
+ path->need_wait = 0;
+ } else {
+ rtn = _dcam_frame_dequeue(&path->frame_queue, &frame);
+ if (0 == rtn && frame.yaddr != s_p_dcam_mod->path2_reserved_frame.yaddr && 0 != dcam_frame_is_locked(&frame)) {
+ DCAM_TRACE("DCAM: path2 frame 0x%x, y uv, 0x%x 0x%x \n",
+ (int)&frame, frame.yaddr, frame.uaddr);
+ frame.width = path->output_size.w;
+ frame.height = path->output_size.h;
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+ } else {
+ DCAM_TRACE("DCAM: path2_reserved_frame \n");
+ }
+ }
+ }
+ }
+}
+
+LOCAL void _dcam_path2_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_OV];
+ void *data = s_user_data[DCAM_PATH2_OV];
+ struct dcam_path_desc *path;
+ struct dcam_frame frame;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _path2_overflow \n");
+ path = &s_p_dcam_mod->dcam_path2;
+ //frame = path->output_frame_cur->prev->prev;
+ //frame = &s_p_dcam_mod->path2_frame[0];
+ _dcam_frame_dequeue(&path->frame_queue, &frame);
+
+ if (user_func) {
+ (*user_func)(&frame, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_isp_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_ISP_OV];
+ void *data = s_user_data[DCAM_ISP_OV];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ printk("DCAM: _isp_overflow \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_mipi_ov(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_MIPI_OV];
+ void *data = s_user_data[DCAM_MIPI_OV];
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ printk("DCAM: _mipi_overflow \n");
+ return;
+}
+
+LOCAL void _dcam_rot_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_ROT_DONE];
+ void *data = s_user_data[DCAM_ROT_DONE];
+
+ DCAM_TRACE("DCAM: rot_done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_SLICE_DONE];
+ void *data = s_user_data[DCAM_PATH1_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 1 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_SLICE_DONE];
+ void *data = s_user_data[DCAM_PATH2_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 2 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_raw_slice_done(void)
+{
+ dcam_isr_func user_func = s_user_func[DCAM_RAW_SLICE_DONE];
+ void *data = s_user_data[DCAM_RAW_SLICE_DONE];
+
+ DCAM_TRACE("DCAM: 0 slice done \n");
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path0_sof(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH0_SOF];
+ void *data = s_user_data[DCAM_PATH0_SOF];
+ struct dcam_path_desc *path;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_TRACE("DCAM: 0 sof 1 \n");
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ DCAM_CHECK_ZERO_VOID(s_dcam_sc_array);
+
+ if(s_p_dcam_mod->dcam_path0.status == DCAM_ST_START){
+ DCAM_TRACE("DCAM: 0 sof 2 \n");
+ path = &s_p_dcam_mod->dcam_path0;
+ if (0 == path->valide) {
+ printk("DCAM: path0 not valid \n");
+ return;
+ }
+
+ if (path->sof_cnt > 0) {
+ printk("DCAM: path0 sof %d \n", path->sof_cnt);
+ return;
+ } else {
+ path->sof_cnt++;
+ }
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_0, false);
+
+ if (rtn) {
+ DCAM_TRACE("DCAM: path0 updated \n");
+ } else {
+ _dcam_auto_copy(DCAM_PATH_IDX_0);
+ }
+
+ _dcam_path_updated_notice(DCAM_PATH_IDX_0);
+
+ if (rtn) {
+ path->need_wait = 1;
+ printk("DCAM: 0 w\n");
+ return;
+ }
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path1_sof(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH1_SOF];
+ void *data = s_user_data[DCAM_PATH1_SOF];
+ struct dcam_path_desc *path;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_TRACE("DCAM: 1 sof done \n");
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+ DCAM_CHECK_ZERO_VOID(s_dcam_sc_array);
+
+ if(s_p_dcam_mod->dcam_path1.status == DCAM_ST_START){
+
+ path = &s_p_dcam_mod->dcam_path1;
+ if (0 == path->valide) {
+ printk("DCAM: path1 not valid \n");
+ return;
+ }
+
+ if (path->sof_cnt > 0) {
+ printk("DCAM: path1 sof %d \n", path->sof_cnt);
+ return;
+ } else {
+ path->sof_cnt++;
+ }
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_1, false);
+ if (path->is_update) {
+ if (s_dcam_sc_array->is_smooth_zoom) {
+ _dcam_get_valid_sc_coeff(s_dcam_sc_array, &sc_coeff);
+ _dcam_write_sc_coeff(DCAM_PATH_IDX_1);
+ _dcam_path1_set(&sc_coeff->dcam_path1);
+ _dcam_pop_sc_buf(s_dcam_sc_array, &sc_coeff);
+ } else {
+ _dcam_path1_set(path);
+ }
+ path->is_update = 0;
+ DCAM_TRACE("DCAM: path1 updated \n");
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_1, true, true);
+ } else {
+ if (rtn) {
+ DCAM_TRACE("DCAM: path1 updated \n");
+ } else {
+ _dcam_auto_copy(DCAM_PATH_IDX_1);
+ }
+ }
+
+ _dcam_path_updated_notice(DCAM_PATH_IDX_1);
+
+ if (rtn) {
+ path->need_wait = 1;
+ printk("DCAM: 1 w\n");
+ return;
+ }
+ }
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path2_sof(void)
+{
+ enum dcam_drv_rtn rtn = DCAM_RTN_SUCCESS;
+ dcam_isr_func user_func = s_user_func[DCAM_PATH2_SOF];
+ void *data = s_user_data[DCAM_PATH2_SOF];
+ struct dcam_path_desc *path;
+
+ DCAM_TRACE("DCAM: 2 sof done \n");
+
+ if (atomic_read(&s_resize_flag)) {
+ printk("DCAM: path 2 sof, review now \n");
+ } else {
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ return;
+ }
+
+ if(s_p_dcam_mod->dcam_path2.status == DCAM_ST_START){
+
+ path = &s_p_dcam_mod->dcam_path2;
+ if (0 == path->valide) {
+ printk("DCAM: path2 not valid \n");
+ return;
+ }
+
+ if (path->sof_cnt > 0) {
+ printk("DCAM: path2 sof %d \n", path->sof_cnt);
+ return;
+ } else {
+ path->sof_cnt++;
+ }
+
+ rtn = _dcam_path_set_next_frm(DCAM_PATH_IDX_2, false);
+ if (path->is_update) {
+ _dcam_path2_set();
+ path->is_update = 0;
+ DCAM_TRACE("DCAM: path2 updated \n");
+ _dcam_auto_copy_ext(DCAM_PATH_IDX_2, true, true);
+ } else {
+ if (rtn) {
+ DCAM_TRACE("DCAM: path2 updated \n");
+ } else {
+ _dcam_auto_copy(DCAM_PATH_IDX_2);
+ }
+ }
+
+ _dcam_path_updated_notice(DCAM_PATH_IDX_2);
+
+ if (rtn) {
+ path->need_wait = 1;
+ printk("DCAM:2 w \n");
+ return;
+ }
+ }
+ }
+
+ if (user_func) {
+ (*user_func)(NULL, data);
+ }
+
+ return;
+}
+
+LOCAL int32_t _dcam_err_pre_proc(void)
+{
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: state in err_pre_proc 0x%x,",s_p_dcam_mod->state);
+ if (s_p_dcam_mod->state & DCAM_STATE_QUICKQUIT)
+ return -1;
+
+ s_p_dcam_mod->err_happened = 1;
+ printk("DCAM: err, 0x%x, ISP int 0x%x \n",
+ REG_RD(DCAM_INT_STS),
+ REG_RD(SPRD_ISP_BASE + 0x2080));
+
+ _dcam_reg_trace();
+ dcam_glb_reg_mwr(DCAM_CONTROL, BIT_2, 0, DCAM_CONTROL_REG); /* Cap Disable */
+ _dcam_stopped();
+ if (0 == atomic_read(&s_resize_flag) &&
+ 0 == atomic_read(&s_rotation_flag)) {
+ dcam_reset(DCAM_RST_ALL, 1);
+ }
+ return 0;
+}
+
+LOCAL void _dcam_stopped(void)
+{
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ DCAM_TRACE("DCAM: stopped, %d \n", s_p_dcam_mod->wait_stop);
+
+ _dcam_path_done_notice(DCAM_PATH_IDX_0);
+ _dcam_path_done_notice(DCAM_PATH_IDX_1);
+ _dcam_path_done_notice(DCAM_PATH_IDX_2);
+ _dcam_stopped_notice();
+ return;
+}
+
+LOCAL int _dcam_internal_init(void)
+{
+ int ret = 0;
+
+ s_p_dcam_mod = (struct dcam_module*)vzalloc(sizeof(struct dcam_module));
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+
+ sema_init(&s_p_dcam_mod->stop_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path0.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path1.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path2.tx_done_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path0.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path1.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->dcam_path2.sof_sema, 0);
+ sema_init(&s_p_dcam_mod->resize_done_sema, 0);
+ sema_init(&s_p_dcam_mod->rotation_done_sema, 0);
+ sema_init(&s_p_dcam_mod->scale_coeff_mem_sema, 1);
+
+ memset((void*)s_dcam_sc_array, 0, sizeof(struct dcam_sc_array));
+ return ret;
+}
+LOCAL void _dcam_internal_deinit(void)
+{
+ unsigned long flag;
+
+ spin_lock_irqsave(&dcam_mod_lock, flag);
+ if (DCAM_ADDR_INVALID(s_p_dcam_mod)) {
+ printk("DCAM: Invalid addr, %p", s_p_dcam_mod);
+ } else {
+ vfree(s_p_dcam_mod);
+ s_p_dcam_mod = NULL;
+ }
+ spin_unlock_irqrestore(&dcam_mod_lock, flag);
+ return;
+}
+
+LOCAL void _dcam_wait_path_done(enum dcam_path_index path_index, uint32_t *p_flag)
+{
+ int ret = 0;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->err_happened) {
+ return;
+ }
+ if (DCAM_CAPTURE_MODE_SINGLE == s_p_dcam_mod->dcam_mode) {
+ return;
+ }
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done wait %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+
+ spin_lock_irqsave(&dcam_lock, flag);
+ if (p_flag) {
+ *p_flag = 1;
+ }
+ p_path->wait_for_done = 1;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ ret = down_timeout(&p_path->tx_done_sema, DCAM_PATH_TIMEOUT);
+ if (ret) {
+ _dcam_reg_trace();
+ printk("DCAM: Failed to wait path 0x%x done \n", path_index);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path_done_notice(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *p_path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done notice %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+ if (p_path->wait_for_done) {
+ up(&p_path->tx_done_sema);
+ p_path->wait_for_done = 0;
+ }
+
+ return;
+}
+
+LOCAL void _dcam_wait_update_done(enum dcam_path_index path_index, uint32_t *p_flag)
+{
+ int ret = 0;
+ struct dcam_path_desc *p_path = NULL;
+ unsigned long flag;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->err_happened) {
+ return;
+ }
+ if (DCAM_CAPTURE_MODE_SINGLE == s_p_dcam_mod->dcam_mode) {
+ return;
+ }
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if (DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done wait %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+
+ spin_lock_irqsave(&dcam_lock, flag);
+ if (p_flag) {
+ *p_flag = 1;
+ }
+ p_path->wait_for_sof = 1;
+ spin_unlock_irqrestore(&dcam_lock, flag);
+ ret = down_timeout(&p_path->sof_sema, DCAM_PATH_TIMEOUT);
+ if (ret) {
+ _dcam_reg_trace();
+ printk("DCAM: Failed to wait update path 0x%x done \n", path_index);
+ }
+
+ return;
+}
+
+LOCAL void _dcam_path_updated_notice(enum dcam_path_index path_index)
+{
+ struct dcam_path_desc *p_path = NULL;
+
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (DCAM_PATH_IDX_0 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path0;
+ } else if(DCAM_PATH_IDX_1 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path1;
+ } else if(DCAM_PATH_IDX_2 == path_index) {
+ p_path = &s_p_dcam_mod->dcam_path2;
+ } else {
+ printk("DCAM: Wrong index 0x%x \n", path_index);
+ return;
+ }
+ DCAM_TRACE("DCAM: path done notice %d, %d \n", p_path->wait_for_done, p_path->tx_done_sema.count);
+ if (p_path->wait_for_sof) {
+ up(&p_path->sof_sema);
+ p_path->wait_for_sof = 0;
+ }
+
+ return;
+}
+
+
+LOCAL void _dcam_stopped_notice(void)
+{
+ DCAM_CHECK_ZERO_VOID(s_p_dcam_mod);
+
+ if (s_p_dcam_mod->wait_stop) {
+ up(&s_p_dcam_mod->stop_sema);
+ s_p_dcam_mod->wait_stop = 0;
+ }
+}
+
+void mm_clk_register_trace(void)
+{
+ uint32_t i = 0;
+ printk("REG_AON_APB_APB_EB0 = 0x%x \n",REG_RD(REG_AON_APB_APB_EB0));
+ printk("REG_PMU_APB_PD_MM_TOP_CFG = 0x%x \n",REG_RD(REG_PMU_APB_PD_MM_TOP_CFG));
+ printk("REG_PMU_APB_CP_SOFT_RST = 0x%x \n",REG_RD(REG_PMU_APB_CP_SOFT_RST));
+ if(!(REG_RD(REG_AON_APB_APB_EB0)&BIT_MM_EB) ) return ;
+ if(REG_RD(REG_PMU_APB_PD_MM_TOP_CFG)&BIT_PD_MM_TOP_FORCE_SHUTDOWN) return ;
+
+ printk("mm_clk_reg, part 1 \n");
+ for (i = 0 ; i <= 0x10; i += 4 ) {
+ printk("MMAHB: %lx val:%x \b\n",
+ (SPRD_MMAHB_BASE + i),
+ REG_RD(SPRD_MMAHB_BASE + i));
+ }
+
+ printk("mm_clk_reg, part 2 \n");
+ for (i = 0x20 ; i <= 0x38; i += 4 ) {
+ printk("MMCKG: %lx val:%x \b\n",
+ (SPRD_MMCKG_BASE + i),
+ REG_RD(SPRD_MMCKG_BASE + i));
+ }
+}
+
+int32_t dcam_stop_sc_coeff(void)
+{
+ uint32_t zoom_mode;
+
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ zoom_mode = s_dcam_sc_array->is_smooth_zoom;
+ /*memset((void*)s_dcam_sc_array, 0, sizeof(struct dcam_sc_array));*/
+ s_dcam_sc_array->is_smooth_zoom = zoom_mode;
+ s_dcam_sc_array->valid_cnt = 0;
+ memset(&s_dcam_sc_array->scaling_coeff_queue, 0, DCAM_SC_COEFF_BUF_COUNT*sizeof(struct dcam_sc_coeff *));
+
+ return 0;
+}
+
+LOCAL int32_t _dcam_get_valid_sc_coeff(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff)
+{
+ if (DCAM_ADDR_INVALID(sc) || DCAM_ADDR_INVALID(sc_coeff)) {
+ printk("DCAM: get valid sc, invalid param %p, %p \n",
+ sc,
+ sc_coeff);
+ return -1;
+ }
+ if (sc->valid_cnt == 0) {
+ printk("DCAM: valid cnt 0 \n");
+ return -1;
+ }
+
+ *sc_coeff = sc->scaling_coeff_queue[0];
+ DCAM_TRACE("DCAM: get valid sc, %d \n", sc->valid_cnt);
+ return 0;
+}
+
+
+LOCAL int32_t _dcam_push_sc_buf(struct dcam_sc_array *sc, uint32_t index)
+{
+ if (DCAM_ADDR_INVALID(sc)) {
+ printk("DCAM: push sc, invalid param %p \n", sc);
+ return -1;
+ }
+ if (sc->valid_cnt >= DCAM_SC_COEFF_BUF_COUNT) {
+ printk("DCAM: valid cnt %d \n", sc->valid_cnt);
+ return -1;
+ }
+
+ sc->scaling_coeff[index].flag = 1;
+ sc->scaling_coeff_queue[sc->valid_cnt] = &sc->scaling_coeff[index];
+ sc->valid_cnt ++;
+
+ DCAM_TRACE("DCAM: push sc, %d \n", sc->valid_cnt);
+
+ return 0;
+}
+
+LOCAL int32_t _dcam_pop_sc_buf(struct dcam_sc_array *sc, struct dcam_sc_coeff **sc_coeff)
+{
+ uint32_t i = 0;
+
+ if (DCAM_ADDR_INVALID(sc) || DCAM_ADDR_INVALID(sc_coeff)) {
+ printk("DCAM: pop sc, invalid param %p, %p \n",
+ sc,
+ sc_coeff);
+ return -1;
+ }
+ if (sc->valid_cnt == 0) {
+ printk("DCAM: valid cnt 0 \n");
+ return -1;
+ }
+ sc->scaling_coeff_queue[0]->flag = 0;
+ *sc_coeff = sc->scaling_coeff_queue[0];
+ sc->valid_cnt--;
+ for (i = 0; i < sc->valid_cnt; i++) {
+ sc->scaling_coeff_queue[i] = sc->scaling_coeff_queue[i+1];
+ }
+ DCAM_TRACE("DCAM: pop sc, %d \n", sc->valid_cnt);
+ return 0;
+}
+
+LOCAL int32_t _dcam_write_sc_coeff(enum dcam_path_index path_index)
+{
+ int32_t ret = 0;
+ struct dcam_path_desc *path = NULL;
+ uint32_t i = 0;
+ unsigned long h_coeff_addr = DCAM_BASE;
+ unsigned long v_coeff_addr = DCAM_BASE;
+ unsigned long v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ unsigned long ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ ret = _dcam_get_valid_sc_coeff(s_dcam_sc_array, &sc_coeff);
+ if (ret) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+ tmp_buf = sc_coeff->buf;
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &sc_coeff->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_write_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+ for (i = 0; i < DCAM_SC_COEFF_H_NUM; i++) {
+ REG_WR(h_coeff_addr, *h_coeff);
+ h_coeff_addr += 4;
+ h_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_NUM; i++) {
+ REG_WR(v_coeff_addr, *v_coeff);
+ v_coeff_addr += 4;
+ v_coeff++;
+ }
+
+ for (i = 0; i < DCAM_SC_COEFF_V_CHROMA_NUM; i++) {
+ REG_WR(v_chroma_coeff_addr, *v_chroma_coeff);
+ v_chroma_coeff_addr += 4;
+ v_chroma_coeff++;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_write_sc_coeff E \n");
+
+ return ret;
+}
+
+LOCAL int32_t _dcam_calc_sc_coeff(enum dcam_path_index path_index)
+{
+ unsigned long flag;
+ struct dcam_path_desc *path = NULL;
+ unsigned long h_coeff_addr = DCAM_BASE;
+ unsigned long v_coeff_addr = DCAM_BASE;
+ unsigned long v_chroma_coeff_addr = DCAM_BASE;
+ uint32_t *tmp_buf = NULL;
+ uint32_t *h_coeff = NULL;
+ uint32_t *v_coeff = NULL;
+ uint32_t *v_chroma_coeff = NULL;
+ uint32_t clk_switch_bit = 0;
+ uint32_t clk_switch_shift_bit = 0;
+ uint32_t clk_status_bit = 0;
+ unsigned long ver_tap_reg = 0;
+ uint32_t scale2yuv420 = 0;
+ uint8_t y_tap = 0;
+ uint8_t uv_tap = 0;
+ uint32_t index = 0;
+ struct dcam_sc_coeff *sc_coeff;
+
+ DCAM_CHECK_ZERO(s_p_dcam_mod);
+ DCAM_CHECK_ZERO(s_dcam_sc_array);
+
+ if (DCAM_PATH_IDX_1 != path_index && DCAM_PATH_IDX_2 != path_index)
+ return -DCAM_RTN_PARA_ERR;
+
+ if (DCAM_PATH_IDX_1 == path_index) {
+ path = &s_p_dcam_mod->dcam_path1;
+ h_coeff_addr += DCAM_SC1_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC1_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC1_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_3;
+ clk_switch_shift_bit = 3;
+ clk_status_bit = BIT_5;
+ ver_tap_reg = DCAM_PATH1_CFG;
+ } else if (DCAM_PATH_IDX_2 == path_index) {
+ path = &s_p_dcam_mod->dcam_path2;
+ h_coeff_addr += DCAM_SC2_H_TAB_OFFSET;
+ v_coeff_addr += DCAM_SC2_V_TAB_OFFSET;
+ v_chroma_coeff_addr += DCAM_SC2_V_CHROMA_TAB_OFFSET;
+ clk_switch_bit = BIT_4;
+ clk_switch_shift_bit = 4;
+ clk_status_bit = BIT_6;
+ ver_tap_reg = DCAM_PATH2_CFG;
+ }
+
+ if (DCAM_YUV420 == path->output_format) {
+ scale2yuv420 = 1;
+ }
+
+ DCAM_TRACE("DCAM: _dcam_calc_sc_coeff {%d %d %d %d}, 420=%d \n",
+ path->sc_input_size.w,
+ path->sc_input_size.h,
+ path->output_size.w,
+ path->output_size.h, scale2yuv420);
+
+ down(&s_p_dcam_mod->scale_coeff_mem_sema);
+
+ spin_lock_irqsave(&dcam_lock,flag);
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+ if (NULL == tmp_buf) {
+ _dcam_pop_sc_buf(s_dcam_sc_array, &sc_coeff);
+ tmp_buf = dcam_get_scale_coeff_addr(&index);
+ }
+ spin_unlock_irqrestore(&dcam_lock,flag);
+
+ if (NULL == tmp_buf) {
+ return -DCAM_RTN_PATH_NO_MEM;
+ }
+
+ h_coeff = tmp_buf;
+ v_coeff = tmp_buf + (DCAM_SC_COEFF_COEF_SIZE/4);
+ v_chroma_coeff = v_coeff + (DCAM_SC_COEFF_COEF_SIZE/4);
+
+ if (!(Dcam_GenScaleCoeff((int16_t)path->sc_input_size.w,
+ (int16_t)path->sc_input_size.h,
+ (int16_t)path->output_size.w,
+ (int16_t)path->output_size.h,
+ h_coeff,
+ v_coeff,
+ v_chroma_coeff,
+ scale2yuv420,
+ &y_tap,
+ &uv_tap,
+ tmp_buf + (DCAM_SC_COEFF_COEF_SIZE*3/4),
+ DCAM_SC_COEFF_TMP_SIZE))) {
+ printk("DCAM: _dcam_calc_sc_coeff Dcam_GenScaleCoeff error! \n");
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ return -DCAM_RTN_PATH_GEN_COEFF_ERR;
+ }
+ path->scale_tap.y_tap = y_tap;
+ path->scale_tap.uv_tap = uv_tap;
+ path->valid_param.scale_tap = 1;
+ memcpy(&s_dcam_sc_array->scaling_coeff[index].dcam_path1, path, sizeof(struct dcam_path_desc));
+ spin_lock_irqsave(&dcam_lock,flag);
+ _dcam_push_sc_buf(s_dcam_sc_array, index);
+ spin_unlock_irqrestore(&dcam_lock,flag);
+
+ up(&s_p_dcam_mod->scale_coeff_mem_sema);
+ DCAM_TRACE("DCAM: _dcam_calc_sc_coeff E \n");
+
+ return DCAM_RTN_SUCCESS;
+}
diff --git a/drivers/media/sprd_dcam/tshark2/dcam_drv.h b/drivers/media/sprd_dcam/tshark2/dcam_drv.h
new file mode 100755
index 00000000..f5c17f2e
--- /dev/null
+++ b/drivers/media/sprd_dcam/tshark2/dcam_drv.h
@@ -0,0 +1,454 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef _DCAM_DRV_8830_H_
+#define _DCAM_DRV_8830_H_
+
+#include <linux/types.h>
+#include "dcam_reg.h"
+#include "parse_hwinfo.h"
+
+//#define DCAM_DEBUG
+
+#ifdef DCAM_DEBUG
+ #define DCAM_TRACE printk
+#else
+ #define DCAM_TRACE pr_debug
+#endif
+
+#define DCAM_WAIT_FOREVER 0xFFFFFFFF
+#define DCAM_PATH_1_FRM_CNT_MAX 10
+#define DCAM_PATH_2_FRM_CNT_MAX 10/*4*/
+#define DCAM_PATH_0_FRM_CNT_MAX 10
+#define DCAM_FRM_CNT_MAX 10 /* max between path_1_frm_cnt and path_2_frm_cnt */
+#define DCAM_HEIGHT_MIN 4
+#define DCAM_JPEG_LENGTH_MIN 30720 /*640X480 div 10*/
+
+enum dcam_swtich_status {
+ DCAM_SWITCH_IDLE = 0,
+ DCAM_SWITCH_PAUSE,
+ DCAM_SWITCH_DONE,
+ DCAM_SWITCH_MAX
+};
+
+enum dcam_drv_rtn {
+ DCAM_RTN_SUCCESS = 0,
+ DCAM_RTN_PARA_ERR = 0x10,
+ DCAM_RTN_IO_ID_ERR,
+ DCAM_RTN_ISR_ID_ERR,
+ DCAM_RTN_MASTER_SEL_ERR,
+ DCAM_RTN_MODE_ERR,
+ DCAM_RTN_TIMEOUT,
+
+ DCAM_RTN_CAP_FRAME_SEL_ERR = 0x20,
+ DCAM_RTN_CAP_IN_FORMAT_ERR,
+ DCAM_RTN_CAP_IN_BITS_ERR,
+ DCAM_RTN_CAP_IN_YUV_ERR,
+ DCAM_RTN_CAP_SYNC_POL_ERR,
+ DCAM_RTN_CAP_SKIP_FRAME_ERR,
+ DCAM_RTN_CAP_FRAME_DECI_ERR,
+ DCAM_RTN_CAP_XY_DECI_ERR,
+ DCAM_RTN_CAP_FRAME_SIZE_ERR,
+ DCAM_RTN_CAP_SENSOR_MODE_ERR,
+ DCAM_RTN_CAP_JPEG_BUF_LEN_ERR,
+ DCAM_RTN_CAP_IF_MODE_ERR,
+
+ DCAM_RTN_PATH_SRC_SIZE_ERR = 0x30,
+ DCAM_RTN_PATH_TRIM_SIZE_ERR,
+ DCAM_RTN_PATH_DES_SIZE_ERR,
+ DCAM_RTN_PATH_IN_FMT_ERR,
+ DCAM_RTN_PATH_OUT_FMT_ERR,
+ DCAM_RTN_PATH_SC_ERR,
+ DCAM_RTN_PATH_SUB_SAMPLE_ERR,
+ DCAM_RTN_PATH_ADDR_ERR,
+ DCAM_RTN_PATH_FRAME_TOO_MANY,
+ DCAM_RTN_PATH_FRAME_LOCKED,
+ DCAM_RTN_PATH_NO_MEM,
+ DCAM_RTN_PATH_GEN_COEFF_ERR,
+ DCAM_RTN_PATH_SRC_ERR,
+ DCAM_RTN_PATH_ENDIAN_ERR,
+ DCAM_RTN_PATH_FRM_DECI_ERR,
+ DCAM_RTN_MAX
+};
+
+enum dcam_rst_mode {
+ DCAM_RST_ALL = 0,
+ DCAM_RST_PATH0,
+ DCAM_RST_PATH1,
+ DCAM_RST_PATH2
+};
+
+enum dcam_path_index {
+ DCAM_PATH_IDX_NONE = 0,
+ DCAM_PATH_IDX_0 = 1,
+ DCAM_PATH_IDX_1 = 2,
+ DCAM_PATH_IDX_2 = 4,
+ DCAM_PATH_IDX_ALL = 7,
+};
+
+
+enum dcam_fmt {
+ DCAM_YUV422 = 0,
+ DCAM_YUV420,
+ DCAM_YUV420_3FRAME,
+ DCAM_YUV400,
+ DCAM_RGB565,
+ DCAM_RGB888,
+ DCAM_RAWRGB,
+ DCAM_JPEG,
+ DCAM_FTM_MAX
+};
+
+enum dcam_cap_pattern {
+ DCAM_YUYV = 0,
+ DCAM_YVYU,
+ DCAM_UYVY,
+ DCAM_VYUY,
+ DCAM_PATTERN_MAX
+};
+
+enum dcam_capture_mode {
+ DCAM_CAPTURE_MODE_SINGLE = 0,
+ DCAM_CAPTURE_MODE_MULTIPLE,
+ DCAM_CAPTURE_MODE_MAX
+};
+
+
+enum dcam_irq_id {
+ DCAM_SN_SOF = 0,
+ DCAM_SN_EOF,
+ DCAM_CAP_SOF,
+ DCAM_CAP_EOF,
+ DCAM_PATH0_DONE,
+ DCAM_PATH0_OV,
+ DCAM_PATH1_DONE,
+ DCAM_PATH1_OV,
+ DCAM_PATH2_DONE,
+ DCAM_PATH2_OV,
+ DCAM_SN_LINE_ERR,
+ DCAM_SN_FRAME_ERR,
+ DCAM_JPEG_BUF_OV,
+ DCAM_ISP_OV,
+ DCAM_MIPI_OV,
+ DCAM_ROT_DONE,
+ DCAM_PATH1_SLICE_DONE,
+ DCAM_PATH2_SLICE_DONE,
+ DCAM_RAW_SLICE_DONE,
+ DCAM_PATH1_SOF,
+ DCAM_PATH2_SOF,
+ DCAM_PATH0_END,
+ DCAM_PATH1_END,
+ DCAM_PATH2_END,
+ DCAM_PATH0_SOF,
+ DCAM_IRQ_NUMBER
+};
+
+enum dcam_cfg_id {
+ DCAM_CAP_SYNC_POL = 0,
+ DCAM_CAP_DATA_BITS,
+ DCAM_CAP_DATA_PACKET,
+ DCAM_CAP_YUV_TYPE,
+ DCAM_CAP_PRE_SKIP_CNT,
+ DCAM_CAP_FRM_DECI,
+ DCAM_CAP_FRM_COUNT_CLR,
+ DCAM_CAP_FRM_COUNT_GET,
+ DCAM_CAP_INPUT_RECT,
+ DCAM_CAP_IMAGE_XY_DECI,
+ DCAM_CAP_JPEG_GET_LENGTH,
+ DCAM_CAP_JPEG_SET_BUF_LEN,
+ DCAM_CAP_TO_ISP,
+ DCAM_CAP_SAMPLE_MODE,
+ DCAM_CAP_ZOOM_MODE,
+
+ DCAM_PATH_INPUT_SIZE,
+ DCAM_PATH_INPUT_RECT,
+ DCAM_PATH_INPUT_ADDR,
+ DCAM_PATH_OUTPUT_SIZE,
+ DCAM_PATH_OUTPUT_FORMAT,
+ DCAM_PATH_OUTPUT_ADDR,
+ DCAM_PATH_OUTPUT_RESERVED_ADDR,
+ DCAM_PATH_FRAME_BASE_ID,
+ DCAM_PATH_SWAP_BUFF,
+ DCAM_PATH_SUB_SAMPLE_EN_X,
+ DCAM_PATH_SUB_SAMPLE_EN_Y,
+ DCAM_PATH_SUB_SAMPLE_MOD,
+ DCAM_PATH_SLICE_SCALE_EN,
+ DCAM_PATH_SLICE_SCALE_HEIGHT,
+ DCAM_PATH_DITHER_EN,
+ DCAM_PATH_IS_IN_SCALE_RANGE,
+ DCAM_PATH_IS_SCALE_EN,
+ DCAM_PATH_SLICE_OUT_HEIGHT,
+ DCAM_PATH_DATA_ENDIAN,
+ DCAM_PATH_SRC_SEL,
+ DCAM_PATH_ENABLE,
+ DCAM_PATH_FRAME_TYPE,
+ DCAM_PATH_ROT_MODE,
+ DCAM_PATH_FRM_DECI,
+ DCAM_PATH_SHRINK,
+ DCAM_CFG_ID_E_MAX
+};
+
+/*
+enum dcam_sub_sample_mode
+{
+ DCAM_SUB_2 = 0,
+ DCAM_SUB_4,
+ DCAM_SUB_8,
+ DCAM_SUB_16,
+ DCAM_SUB_MAX
+};
+
+enum dcam_ahb_frm
+{
+ DCAM_AHB_FRAME_SRC,
+ DCAM_AHB_FRAME_PATH1_DST,
+ DCAM_AHB_FRAME_PATH2_DST,
+ DCAM_AHB_FRAME_SWAP,
+ DCAM_AHB_FRAME_LINE,
+ DCAM_AHB_FRAME_MAX
+};
+*/
+enum iram_owner {
+ IRAM_FOR_DCAM = 0,
+ IRAM_FOR_ARM
+};
+
+enum dcam_clk_sel {
+ DCAM_CLK_384M = 0,
+ DCAM_CLK_312M,
+ DCAM_CLK_256M,
+ DCAM_CLK_128M,
+ DCAM_CLK_76M8,
+ DCAM_CLK_NONE
+};
+
+enum dcam_cap_if_mode {
+ DCAM_CAP_IF_CCIR = 0,
+ DCAM_CAP_IF_CSI2,
+ DCAM_CAP_IF_MODE_MAX
+};
+
+enum dcam_path_src_sel {
+ DCAM_PATH_FROM_CAP = 0,
+ DCAM_PATH_FROM_ISP,
+ DCAM_PATH_FROM_NONE
+};
+
+enum dcam_cap_sensor_mode {
+ DCAM_CAP_MODE_YUV = 0,
+ DCAM_CAP_MODE_SPI,
+ DCAM_CAP_MODE_JPEG,
+ DCAM_CAP_MODE_RAWRGB,
+ DCAM_CAP_MODE_MAX
+};
+
+enum dcam_cap_data_bits {
+ DCAM_CAP_12_BITS = 12,
+ DCAM_CAP_10_BITS = 10,
+ DCAM_CAP_8_BITS = 8,
+ DCAM_CAP_4_BITS = 4,
+ DCAM_CAP_2_BITS = 2,
+ DCAM_CAP_1_BITS = 1,
+ DCAM_CAP_BITS_MAX = 0xFF
+};
+
+enum dcam_data_endian {
+ DCAM_ENDIAN_BIG = 0,
+ DCAM_ENDIAN_LITTLE,
+ DCAM_ENDIAN_HALFBIG,
+ DCAM_ENDIAN_HALFLITTLE,
+ DCAM_ENDIAN_MAX
+};
+
+enum dcam_output_mode {
+ DCAM_OUTPUT_WORD = 0,
+ DCAM_OUTPUT_HALF_WORD,
+ DCAM_OUTPUT_YVYU_1FRAME,
+ DCAM_OUTPUT_YUV420,
+};
+
+enum dcam_glb_reg_id {
+ DCAM_CFG_REG = 0,
+ DCAM_CONTROL_REG,
+ DCAM_INIT_MASK_REG,
+ DCAM_INIT_CLR_REG,
+ DCAM_AHBM_STS_REG,
+ DCAM_ENDIAN_REG,
+ DCAM_REG_MAX
+};
+
+enum dcam_v4l2_wtite_cmd_id {
+ DCAM_V4L2_WRITE_STOP = 0x5AA5,
+ DCAM_V4L2_WRITE_FREE_FRAME = 0xA55A,
+ DCAM_V4L2_WRITE_MAX
+};
+
+struct dcam_cap_sync_pol {
+ uint8_t vsync_pol;
+ uint8_t hsync_pol;
+ uint8_t pclk_pol;
+ uint8_t need_href;
+ uint8_t pclk_src;
+ uint8_t reserved[3];
+};
+
+struct dcam_endian_sel {
+ uint8_t y_endian;
+ uint8_t uv_endian;
+ uint8_t reserved0;
+ uint8_t reserved1;
+};
+
+struct dcam_cap_dec {
+ uint8_t x_factor;
+ uint8_t y_factor;
+ uint8_t x_mode;
+ uint8_t reserved;
+};
+
+struct dcam_path_dec {
+ uint8_t x_factor;
+ uint8_t y_factor;
+ uint8_t reserved[2];
+};
+
+struct dcam_size {
+ uint32_t w;
+ uint32_t h;
+};
+
+struct dcam_rect {
+ uint32_t x;
+ uint32_t y;
+ uint32_t w;
+ uint32_t h;
+};
+
+struct dcam_addr {
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+ uint32_t yaddr_vir;
+ uint32_t uaddr_vir;
+ uint32_t vaddr_vir;
+
+};
+
+struct dcam_sc_tap {
+ uint32_t y_tap;
+ uint32_t uv_tap;
+};
+
+struct dcam_deci {
+ uint32_t deci_x_en;
+ uint32_t deci_x;
+ uint32_t deci_y_en;
+ uint32_t deci_y;
+};
+
+struct dcam_frame {
+ uint32_t type;
+ uint32_t lock;
+ uint32_t flags;
+ uint32_t fid;
+ uint32_t width;
+ uint32_t height;
+ uint32_t yaddr;
+ uint32_t uaddr;
+ uint32_t vaddr;
+ uint32_t yaddr_vir;
+ uint32_t uaddr_vir;
+ uint32_t vaddr_vir;
+ struct dcam_frame *prev;
+ struct dcam_frame *next;
+};
+
+struct dcam_get_path_id {
+ uint32_t fourcc;
+ uint32_t is_path_work[DCAM_PATH_MAX];
+ uint32_t need_isp_tool;
+ uint32_t need_isp;
+ uint32_t need_shrink;
+ struct dcam_size input_size;
+ struct dcam_rect input_trim;
+ struct dcam_size output_size;
+};
+
+struct dcam_path_info {
+ uint32_t line_buf;
+ uint32_t support_yuv;
+ uint32_t support_raw;
+ uint32_t support_jpeg;
+ uint32_t support_scaling;
+ uint32_t support_trim;
+ uint32_t is_scaleing_path;
+};
+
+struct dcam_path_capability {
+ uint32_t count;
+ struct dcam_path_info path_info[DCAM_PATH_MAX];
+};
+
+
+typedef int (*dcam_isr_func)(struct dcam_frame* frame, void* u_data);
+
+int32_t dcam_module_init(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode);
+int32_t dcam_module_deinit(enum dcam_cap_if_mode if_mode,
+ enum dcam_cap_sensor_mode sn_mode);
+int32_t dcam_module_en(struct device_node *dn);
+int32_t dcam_module_dis(struct device_node *dn);
+int32_t dcam_mipi_clk_en(struct device_node *dn);
+int32_t dcam_mipi_clk_dis(struct device_node *dn);
+int32_t dcam_ccir_clk_en(void);
+int32_t dcam_ccir_clk_dis(void);
+int32_t dcam_reset(enum dcam_rst_mode reset_mode, uint32_t is_isr);
+int32_t dcam_set_clk(struct device_node *dn, enum dcam_clk_sel clk_sel);
+int32_t dcam_update_path(enum dcam_path_index path_index, struct dcam_size *in_size,
+ struct dcam_rect *in_rect, struct dcam_size *out_size);
+int32_t dcam_start_path(enum dcam_path_index path_index);
+int32_t dcam_start(void);
+int32_t dcam_stop_path(enum dcam_path_index path_index);
+int32_t dcam_stop(void);
+int32_t dcam_resume(void);
+int32_t dcam_pause(void);
+int32_t dcam_reg_isr(enum dcam_irq_id id, dcam_isr_func user_func, void* u_data);
+int32_t dcam_cap_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_cap_get_info(enum dcam_cfg_id id, void *param);
+int32_t dcam_path0_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_path1_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_path2_cfg(enum dcam_cfg_id id, void *param);
+int32_t dcam_get_resizer(uint32_t wait_opt);
+int32_t dcam_rel_resizer(void);
+void dcam_int_en(void);
+void dcam_int_dis(void);
+int32_t dcam_frame_is_locked(struct dcam_frame *frame);
+int32_t dcam_frame_lock(struct dcam_frame *frame);
+int32_t dcam_frame_unlock(struct dcam_frame *frame);
+int32_t dcam_read_registers(uint32_t* reg_buf, uint32_t *buf_len);
+int32_t dcam_resize_start(void);
+int32_t dcam_resize_end(void);
+int32_t dcam_stop_cap(void);
+void dcam_glb_reg_awr(unsigned long addr, uint32_t val, uint32_t reg_id);
+void dcam_glb_reg_owr(unsigned long addr, uint32_t val, uint32_t reg_id);
+void dcam_glb_reg_mwr(unsigned long addr, uint32_t mask, uint32_t val, uint32_t reg_id);
+int dcam_scale_coeff_alloc(void);
+void dcam_scale_coeff_free(void);
+int32_t dcam_rotation_start(void);
+int32_t dcam_rotation_end(void);
+int32_t dcam_get_path_id(struct dcam_get_path_id *path_id, uint32_t *channel_id);
+int32_t dcam_stop_sc_coeff(void);
+int32_t dcam_get_path_capability(struct dcam_path_capability *capacity);
+void dcam_set_highclk_flag(uint32_t flag);
+
+#endif //_DCAM_DRV_8830_H_
diff --git a/drivers/media/sprd_dcam/tshark2/dcam_reg.h b/drivers/media/sprd_dcam/tshark2/dcam_reg.h
new file mode 100755
index 00000000..87b50015
--- /dev/null
+++ b/drivers/media/sprd_dcam/tshark2/dcam_reg.h
@@ -0,0 +1,216 @@
+/*
+ * Copyright (C) 2012 Spreadtrum Communications Inc.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that 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.
+ */
+#ifndef _REG_DCAM_TIGER_H_
+#define _REG_DCAM_TIGER_H_
+
+#ifndef CONFIG_64BIT
+#include <soc/sprd/globalregs.h>
+#endif
+
+#define BIT_0 0x01
+#define BIT_1 0x02
+#define BIT_2 0x04
+#define BIT_3 0x08
+#define BIT_4 0x10
+#define BIT_5 0x20
+#define BIT_6 0x40
+#define BIT_7 0x80
+#define BIT_8 0x0100
+#define BIT_9 0x0200
+#define BIT_10 0x0400
+#define BIT_11 0x0800
+#define BIT_12 0x1000
+#define BIT_13 0x2000
+#define BIT_14 0x4000
+#define BIT_15 0x8000
+#define BIT_16 0x010000
+#define BIT_17 0x020000
+#define BIT_18 0x040000
+#define BIT_19 0x080000
+#define BIT_20 0x100000
+#define BIT_21 0x200000
+#define BIT_22 0x400000
+#define BIT_23 0x800000
+#define BIT_24 0x01000000
+#define BIT_25 0x02000000
+#define BIT_26 0x04000000
+#define BIT_27 0x08000000
+#define BIT_28 0x10000000
+#define BIT_29 0x20000000
+#define BIT_30 0x40000000
+#define BIT_31 0x80000000
+
+#define GLOBAL_BASE SPRD_GREG_BASE
+#define ARM_GLB_GEN0 (GLOBAL_BASE + 0x008UL)
+#define ARM_GLB_GEN3 (GLOBAL_BASE + 0x01CUL)
+#define ARM_GLB_PLL_SCR (GLOBAL_BASE + 0x070UL)
+//#define GR_CLK_GEN5 (GLOBAL_BASE + 0x07CUL)
+#define CLK_DLY_CTRL (GLOBAL_BASE + 0x05CUL)
+
+#define DCAM_AHB_BASE SPRD_MMAHB_BASE
+#define DCAM_AHB_CTL0 (DCAM_AHB_BASE + 0x0000UL)
+#define DCAM_EB (DCAM_AHB_CTL0 + 0x0000UL)
+#define CSI2_DPHY_EB (DCAM_AHB_CTL0 + 0x0000UL)
+#define DCAM_RST (DCAM_AHB_CTL0 + 0x0004UL)
+#define DCAM_MATRIX_EB (DCAM_AHB_CTL0 + 0x0008UL)
+#define DCAM_CCIR_PCLK_EB (SPRD_MMCKG_BASE + 0x0028UL)
+
+
+#define DCAM_CFG (DCAM_BASE + 0x0000UL)
+#define DCAM_CONTROL (DCAM_BASE + 0x0004UL)
+#define DCAM_PATH0_CFG (DCAM_BASE + 0x0008UL)
+#define DCAM_PATH0_SRC_SIZE (DCAM_BASE + 0x000CUL)
+#define DCAM_PATH1_CFG (DCAM_BASE + 0x0010UL)
+#define DCAM_PATH1_SRC_SIZE (DCAM_BASE + 0x0014UL)
+#define DCAM_PATH1_DST_SIZE (DCAM_BASE + 0x0018UL)
+#define DCAM_PATH1_TRIM_START (DCAM_BASE + 0x001CUL)
+#define DCAM_PATH1_TRIM_SIZE (DCAM_BASE + 0x0020UL)
+#define DCAM_PATH2_CFG (DCAM_BASE + 0x0024UL)
+#define DCAM_PATH2_SRC_SIZE (DCAM_BASE + 0x0028UL)
+#define DCAM_PATH2_DST_SIZE (DCAM_BASE + 0x002CUL)
+#define DCAM_PATH2_TRIM_START (DCAM_BASE + 0x0030UL)
+#define DCAM_PATH2_TRIM_SIZE (DCAM_BASE + 0x0034UL)
+#define REV_SLICE_VER (DCAM_BASE + 0x0038UL)
+#define DCAM_INT_STS (DCAM_BASE + 0x003CUL)
+#define DCAM_INT_MASK (DCAM_BASE + 0x0040UL)
+#define DCAM_INT_CLR (DCAM_BASE + 0x0044UL)
+#define DCAM_INT_RAW (DCAM_BASE + 0x0048UL)
+#define DCAM_FRM_ADDR0 (DCAM_BASE + 0x004CUL)
+#define DCAM_FRM_ADDR1 (DCAM_BASE + 0x0050UL)
+#define DCAM_FRM_ADDR2 (DCAM_BASE + 0x0054UL)
+#define DCAM_FRM_ADDR3 (DCAM_BASE + 0x0058UL)
+#define DCAM_FRM_ADDR4 (DCAM_BASE + 0x005CUL)
+#define DCAM_FRM_ADDR5 (DCAM_BASE + 0x0060UL)
+#define DCAM_FRM_ADDR6 (DCAM_BASE + 0x0064UL)
+#define DCAM_BURST_GAP (DCAM_BASE + 0x0068UL)
+#define DCAM_ENDIAN_SEL (DCAM_BASE + 0x006CUL)
+#define DCAM_AHBM_STS (DCAM_BASE + 0x0070UL)
+#define DCAM_FRM_ADDR7 (DCAM_BASE + 0x0074UL)
+#define DCAM_FRM_ADDR8 (DCAM_BASE + 0x0078UL)
+#define DCAM_FRM_ADDR9 (DCAM_BASE + 0x007CUL)
+#define DCAM_FRM_ADDR10 (DCAM_BASE + 0x0080UL)
+#define DCAM_FRM_ADDR11 (DCAM_BASE + 0x0084UL)
+#define CCIR_PATT_CFG (DCAM_BASE + 0x0088UL)
+#define CCIR_PATT_SIZE (DCAM_BASE + 0x008CUL)
+#define CCIR_PATT_VBLANK (DCAM_BASE + 0x0090UL)
+#define CCIR_PATT_HBLANK (DCAM_BASE + 0x0094UL)
+#define REV_BURST_IN_CFG (DCAM_BASE + 0x0098UL)
+#define REV_BURST_IN_TRIM_START (DCAM_BASE + 0x009CUL)
+#define REV_BURST_IN_TRIM_SIZE (DCAM_BASE + 0x00A0UL)
+#define REV_SLICE_CFG (DCAM_BASE + 0x00A4UL)
+#define PATH1_SLICE_O_VCNT (DCAM_BASE + 0x00A8UL)
+#define PATH2_SLICE_O_VCNT (DCAM_BASE + 0x00ACUL)
+
+#define DCAM_PATH0_TRIM_START (DCAM_BASE + 0x00B8UL)
+#define DCAM_PATH0_TRIM_SIZE (DCAM_BASE + 0x00BCUL)
+#define DCAM_FRM_ADDR12 (DCAM_BASE + 0x00C0UL)
+
+#define CAP_CCIR_CTRL (DCAM_BASE + 0x0100UL)
+#define CAP_CCIR_FRM_CTRL (DCAM_BASE + 0x0104UL)
+#define CAP_CCIR_START (DCAM_BASE + 0x0108UL)
+#define CAP_CCIR_END (DCAM_BASE + 0x010CUL)
+#define CAP_CCIR_IMG_DECI (DCAM_BASE + 0x0110UL)
+#define CAP_CCIR_ATV_FIX (DCAM_BASE + 0x0114UL)
+#define CAP_CCIR_OBSERVE (DCAM_BASE + 0x0118UL)
+#define CAP_CCIR_JPG_CTRL (DCAM_BASE + 0x011CUL)
+#define CAP_CCIR_FRM_SIZE (DCAM_BASE + 0x0120UL)
+#define CAP_CCIR_PLCK_SRC (SPRD_PIN_BASE + 0x04)
+#define CAP_SPI_CFG (DCAM_BASE + 0x0124UL)
+
+#define CAP_MIPI_CTRL (DCAM_BASE + 0x0128UL)
+#define CAP_MIPI_FRM_CTRL (DCAM_BASE + 0x012CUL)
+#define CAP_MIPI_START (DCAM_BASE + 0x0130UL)
+#define CAP_MIPI_END (DCAM_BASE + 0x0134UL)
+#define CAP_MIPI_IMG_DECI (DCAM_BASE + 0x0138UL)
+#define CAP_MIPI_JPG_CTRL (DCAM_BASE + 0x013CUL)
+#define CAP_MIPI_FRM_SIZE (DCAM_BASE + 0x0140UL)
+#define CAP_SENSOR_CTRL (DCAM_BASE + 0x0144UL)
+
+#define BLC_CFG (DCAM_BASE + 0x0148UL)
+#define BLC_START (DCAM_BASE + 0x014CUL)
+#define BLC_END (DCAM_BASE + 0x0150UL)
+#define BLC_TARGET (DCAM_BASE + 0x0154UL)
+#define BLC_MANUAL (DCAM_BASE + 0x0158UL)
+#define BLC_VALUE1 (DCAM_BASE + 0x015CUL)
+#define BLC_VALUE2 (DCAM_BASE + 0x0160UL)
+
+#define DCAM_END BLC_VALUE2
+
+
+#define DCAM_EB_BIT BIT_0
+#define CCIR_EB_BIT BIT_1
+#define MIPI_EB_BIT BIT_10 // aiden: todo
+
+#define DCAM_MOD_RST_BIT BIT_0
+#define CCIR_RST_BIT BIT_1
+#define PATH0_RST_BIT BIT_7
+#define PATH1_RST_BIT BIT_8
+#define PATH2_RST_BIT BIT_9
+#define CCIR_PCLK_EB_BIT BIT_16
+
+#define DCAM_PATH_NUM 3
+#define DCAM_CAP_SKIP_FRM_MAX 16
+#define DCAM_FRM_DECI_FAC_MAX 4
+#define DCAM_CAP_FRAME_WIDTH_MAX 4092
+#define DCAM_CAP_FRAME_HEIGHT_MAX 4092
+#if defined(CONFIG_ARCH_SCX35LT8)
+#define DCAM_PATH_FRAME_WIDTH_MAX 4416
+#define DCAM_PATH_FRAME_HEIGHT_MAX 4092
+#define DCAM_PATH2_FRAME_WIDTH_MAX 4416
+#define DCAM_PATH2_FRAME_HEIGHT_MAX 4092
+#else
+#define DCAM_PATH_FRAME_WIDTH_MAX 4092
+#define DCAM_PATH_FRAME_HEIGHT_MAX 4092
+#define DCAM_PATH2_FRAME_WIDTH_MAX 4092
+#define DCAM_PATH2_FRAME_HEIGHT_MAX 4092
+#endif
+#define DCAM_CAP_X_DECI_FAC_MAX 4 // cap deci: 0 - 1/8
+#define DCAM_CAP_Y_DECI_FAC_MAX 4 // cap deci: 0 - 1/8
+#define DCAM_PATH_FRAME_ROT_MAX 4
+#define DCAM_JPG_BUF_UNIT (1 << 15)
+#define DCAM_JPG_UNITS (1 << 10)
+#define DCAM_SC_COEFF_UP_MAX 4 // path scaling: 1/8 - 4
+#define DCAM_SC_COEFF_DOWN_MAX 7 // path scaling: 1/8 - 4
+#define DCAM_PATH_DECI_FAC_MAX 4 // path deci: 1/2 - 1/16
+#define DCAM_PATH1_LINE_BUF_LENGTH 2048
+
+#if defined(CONFIG_ARCH_SCX35LT8)
+#define DCAM_PATH2_LINE_BUF_LENGTH 4416
+#define DCAM_ISP_LINE_BUF_LENGTH 4416
+#define DCAM_SCALING_THRESHOLD 2600
+#else
+#define DCAM_PATH2_LINE_BUF_LENGTH 4096
+#define DCAM_ISP_LINE_BUF_LENGTH 3280
+#define DCAM_SCALING_THRESHOLD 2300
+#endif
+
+#define DCAM_IRQ IRQ_DCAM_INT
+
+#define DCAM_PIXEL_ALIGN_WIDTH 4
+#define DCAM_PIXEL_ALIGN_HEIGHT 2
+
+#define DCAM_PATH_NUM 3
+enum {
+ DCAM_PATH0 = 0,
+ DCAM_PATH1,
+ DCAM_PATH2,
+ DCAM_PATH_MAX
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif //_REG_DCAM_TIGER_H_
+
+