diff options
Diffstat (limited to 'drivers/media/sprd_dcam')
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(×tamp); + 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, ¶m); + 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, ¶m); + /*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, ¶m); + +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, ¶m); + 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, ¶m); + +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, ¶m); + 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, ®_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, ®_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, ®_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, ®_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, ®_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_ + + |
