camera : support arm and rga to do digital zoom.
authorzyc <zyc@rock-chips.com>
Fri, 17 Aug 2012 10:01:02 +0000 (18:01 +0800)
committerzyc <zyc@rock-chips.com>
Fri, 17 Aug 2012 10:01:02 +0000 (18:01 +0800)
arch/arm/mach-rk2928/board-rk2928-sdk-camera.c
arch/arm/mach-rk2928/include/mach/rk2928_camera.h
arch/arm/plat-rk/include/plat/rk_camera.h
drivers/media/video/rk2928_camera.c
drivers/media/video/rk30_camera_oneframe.c

index 02f98b8b3f47145d7d78a63c0a67cdd1664b896b..ad549249f5c2b491f7f7d8cc09057ce61e9da6a9 100644 (file)
@@ -2,8 +2,8 @@
 /*---------------- Camera Sensor Macro Define Begin  ------------------------*/
 /*---------------- Camera Sensor Configuration Macro Begin ------------------------*/
 #define CONFIG_SENSOR_0 RK29_CAM_SENSOR_OV5642                                         /* back camera sensor */
-#define CONFIG_SENSOR_IIC_ADDR_0               0
-#define CONFIG_SENSOR_IIC_ADAPTER_ID_0   4
+#define CONFIG_SENSOR_IIC_ADDR_0               0x78//  0
+#define CONFIG_SENSOR_IIC_ADAPTER_ID_0   0
 #define CONFIG_SENSOR_CIF_INDEX_0                    0
 #define CONFIG_SENSOR_ORIENTATION_0      90
 #define CONFIG_SENSOR_POWER_PIN_0                INVALID_GPIO
@@ -71,7 +71,7 @@
 #define CONFIG_SENSOR_720P_FPS_FIXED_02      30000
 
 #define CONFIG_SENSOR_1 RK29_CAM_SENSOR_OV2659                      /* front camera sensor 0 */
-#define CONFIG_SENSOR_IIC_ADDR_1           0x60
+#define CONFIG_SENSOR_IIC_ADDR_1          0// 0x60
 #define CONFIG_SENSOR_IIC_ADAPTER_ID_1   3
 #define CONFIG_SENSOR_CIF_INDEX_1                                0
 #define CONFIG_SENSOR_ORIENTATION_1       270
index 733a95f5e726b78d33a5f40a263c03622ee78bc1..bb0239343d2963138bac4954f29b0590ac345b5c 100644 (file)
 #define RK_SUPPORT_CIF1   0
 #include <plat/rk_camera.h>
 
+#define CONFIG_CAMERA_SCALE_CROP_MACHINE    RK_CAM_SCALE_CROP_ARM
+
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_ARM)
+    #define CAMERA_SCALE_CROP_MACHINE  "arm"
+#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_IPP)
+    #define CAMERA_SCALE_CROP_MACHINE  "ipp"
+#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_RGA)
+    #define CAMERA_SCALE_CROP_MACHINE  "rga"
+#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE==RK_CAM_SCALE_CROP_PP)
+    #define CAMERA_SCALE_CROP_MACHINE  "pp"
+#endif
+
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM)
+    #define CAMERA_VIDEOBUF_ARM_ACCESS   1
+#else
+    #define CAMERA_VIDEOBUF_ARM_ACCESS   0
+#endif
+
+
 #endif
 
index 8c3780322eb46a8972784e810f9ea7d55666a31a..05dad8a225128a4dcd4cf777479313b0c779ccff 100755 (executable)
 #define RK29_CAM_FLASHACTIVE_H (0x01<<RK29_CAM_FLASHACTIVE_BITPOS)
 #define RK29_CAM_FLASHACTIVE_L  (0x00<<RK29_CAM_FLASHACTIVE_BITPOS)
 
+#define RK_CAM_SCALE_CROP_ARM      0
+#define RK_CAM_SCALE_CROP_IPP      1
+#define RK_CAM_SCALE_CROP_RGA      2
+#define RK_CAM_SCALE_CROP_PP       3
+
+
 /* v4l2_subdev_core_ops.ioctl  ioctl_cmd macro */
 #define RK29_CAM_SUBDEV_ACTIVATE            0x00
 #define RK29_CAM_SUBDEV_DEACTIVATE          0x01
@@ -233,6 +239,7 @@ struct rk29camera_platform_ioctl_cb {
 
 typedef struct rk29_camera_sensor_cb {
     int (*sensor_cb)(void *arg); 
+       int (*scale_crop_cb)(struct work_struct *work);
 }rk29_camera_sensor_cb_s;
 #endif /* __ASM_ARCH_CAMERA_H_ */
 
index 4c6e923a2037ef513b03c5c2c2090ffe0c7e3e04..c4ed001d9c37308ef7803b2fcc41b05e894e009a 100644 (file)
@@ -91,7 +91,7 @@ static void rk_init_camera_plateform_data(void)
 static void rk30_camera_request_reserve_mem(void)\r
 {\r
 #ifdef CONFIG_VIDEO_RK29_WORK_IPP\r
-    #ifdef VIDEO_RKCIF_WORK_SIMUL_OFF\r
+    #ifdef CONFIG_VIDEO_RKCIF_WORK_SIMUL_OFF\r
         rk_camera_platform_data.meminfo.name = "camera_ipp_mem";\r
         rk_camera_platform_data.meminfo.start = board_mem_reserve_add("camera_ipp_mem",PMEM_CAMIPP_NECESSARY);\r
         rk_camera_platform_data.meminfo.size= PMEM_CAMIPP_NECESSARY;\r
index b77d345e94ce3b3acb3f15e8187ab43b8a6eab75..c779cde27b5bda245aa4bb490ebb66d2b06cd24a 100755 (executable)
@@ -47,8 +47,9 @@
 
 #if defined(CONFIG_ARCH_RK2928)
 #include <mach/rk2928_camera.h>
+#include "../../video/rockchip/rga/rga.h"
 #endif
-
+#include <asm/cacheflush.h>
 static int debug ;
 module_param(debug, int, S_IRUGO|S_IWUSR);
 
@@ -253,6 +254,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
 #define RK_CAM_FRAME_INVAL_INIT 3
 #define RK_CAM_FRAME_INVAL_DC 3          /* ddl@rock-chips.com :  */
 #define RK30_CAM_FRAME_MEASURE  5
+
 extern void videobuf_dma_contig_free(struct videobuf_queue *q, struct videobuf_buffer *buf);
 extern dma_addr_t videobuf_to_dma_contig(struct videobuf_buffer *buf);
 
@@ -305,8 +307,17 @@ struct rk_camera_zoominfo
     struct semaphore sem;
     struct v4l2_crop a;
     int vir_width;
+   int vir_height;
     int zoom_rate;
 };
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+struct rk29_camera_vbinfo
+{
+    unsigned int phy_addr;
+    void __iomem *vir_addr;
+    unsigned int size;
+};
+#endif
 struct rk_camera_timer{
        struct rk_camera_dev *pcdev;
        struct hrtimer timer;
@@ -337,10 +348,14 @@ struct rk_camera_dev
        unsigned int pixfmt;
        //for ipp       
        unsigned int vipmem_phybase;
+    void __iomem *vipmem_virbase;
        unsigned int vipmem_size;
        unsigned int vipmem_bsize;
-
-       int host_width; //croped size
+#if CAMERA_VIDEOBUF_ARM_ACCESS    
+    struct rk29_camera_vbinfo *vbinfo;
+    unsigned int vbinfo_count;
+#endif    
+       int host_width;
        int host_height;
        int host_left;  //sensor output size ?
        int host_top;
@@ -406,22 +421,32 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
     struct soc_camera_device *icd = vq->priv_data;
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk_camera_dev *pcdev = ici->priv;
-       int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
-                                               icd->current_fmt->host_fmt);
-       int bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width,
-                                               icd->current_fmt->host_fmt);
-    unsigned int i;
+       unsigned int i;
     struct rk_camera_work *wk;
 
+        struct soc_mbus_pixelfmt fmt;
+       int bytes_per_line;
+       int bytes_per_line_host;
+       fmt.packing = SOC_MBUS_PACKING_1_5X8;
+
+               bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+                                               icd->current_fmt->host_fmt);
+       if(icd->current_fmt->host_fmt->fourcc ==  V4L2_PIX_FMT_RGB565)
+                bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width,
+                                               &fmt);
+       else if(icd->current_fmt->host_fmt->fourcc ==  V4L2_PIX_FMT_RGB24)
+               bytes_per_line_host = pcdev->host_width*3;
+       else
+               bytes_per_line_host = soc_mbus_bytes_per_line(pcdev->host_width,
+                                          icd->current_fmt->host_fmt);
+       printk("user code = %d,packing = %d",icd->current_fmt->code,fmt.packing);
     dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
 
        if (bytes_per_line_host < 0)
                return bytes_per_line_host;
-
        /* planar capture requires Y, U and V buffers to be page aligned */
        *size = PAGE_ALIGN(bytes_per_line*icd->user_height);       /* Y pages UV pages, yuv422*/
        pcdev->vipmem_bsize = PAGE_ALIGN(bytes_per_line_host * pcdev->host_height);
-
        if (CAM_WORKQUEUE_IS_EN()) {
         #ifdef CONFIG_VIDEO_RK29_DIGITALZOOM_IPP_OFF
         if (CAM_IPPWORK_IS_EN()) 
@@ -453,7 +478,22 @@ static int rk_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
             }
                        pcdev->camera_work_count = (*count);
                }
-       
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+        if (pcdev->vbinfo && (pcdev->vbinfo_count != *count)) {
+            kfree(pcdev->vbinfo);
+            pcdev->vbinfo = NULL;
+            pcdev->vbinfo_count = 0x00;
+        }
+
+        if (pcdev->vbinfo == NULL) {
+            pcdev->vbinfo = kzalloc(sizeof(struct rk29_camera_vbinfo)*(*count), GFP_KERNEL);
+            if (pcdev->vbinfo == NULL) {
+                               RKCAMERA_TR("\n %s vbinfo kmalloc fail\n", __FUNCTION__);
+                               BUG();
+                       }
+                       pcdev->vbinfo_count = *count;
+        }
+#endif        
        }
     pcdev->video_vq = vq;
     RKCAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d, count:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_size, *count);
@@ -567,6 +607,7 @@ static void rk_videobuf_queue(struct videobuf_queue *vq,
     struct soc_camera_device *icd = vq->priv_data;
     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk_camera_dev *pcdev = ici->priv;
+    struct rk29_camera_vbinfo *vb_info;
 
     dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %zd\n", __func__,
             vb, vb->baddr, vb->bsize);
@@ -580,6 +621,31 @@ static void rk_videobuf_queue(struct videobuf_queue *vq,
                else
                        BUG();    /* ddl@rock-chips.com : The same videobuffer queue again */
        }
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+    if (pcdev->vbinfo) {
+        vb_info = pcdev->vbinfo+vb->i;
+        if ((vb_info->phy_addr != vb->boff) || (vb_info->size != vb->bsize)) {
+            if (vb_info->vir_addr) {
+                iounmap(vb_info->vir_addr);
+                release_mem_region(vb_info->phy_addr, vb_info->size);
+                vb_info->vir_addr = NULL;
+                vb_info->phy_addr = 0x00;
+                vb_info->size = 0x00;
+            }
+
+            if (request_mem_region(vb->boff,vb->bsize,"rk_camera_vb")) {
+                vb_info->vir_addr = ioremap_cached(vb->boff,vb->bsize); 
+            }
+            
+            if (vb_info->vir_addr) {
+                vb_info->size = vb->bsize;
+                vb_info->phy_addr = vb->boff;
+            } else {
+                RKCAMERA_TR("%s..%d:ioremap videobuf %d failed\n",__FUNCTION__,__LINE__, vb->i);
+            }
+        }
+    }
+#endif    
     if (!pcdev->active) {
         pcdev->active = vb;
         rk_videobuf_capture(vb,pcdev);
@@ -609,16 +675,181 @@ static int rk_pixfmt2ippfmt(unsigned int pixfmt, int *ippfmt)
 rk_pixfmt2ippfmt_err:
        return -1;
 }
-static void rk_camera_capture_process(struct work_struct *work)
+
+static int rk_pixfmt2rgafmt(unsigned int pixfmt, int *ippfmt)
 {
+       switch (pixfmt)
+       {
+               case V4L2_PIX_FMT_YUV420:
+               case V4L2_PIX_FMT_UYVY: // yuv 422, but sensor has defined this format(in fact ,should be defined yuv 420), treat this as yuv 420.
+               case V4L2_PIX_FMT_YUYV: 
+                       {
+                               *ippfmt = RK_FORMAT_YCbCr_420_SP;
+                               break;
+                       }
+               case V4L2_PIX_FMT_YVU420:
+               case V4L2_PIX_FMT_VYUY:
+               case V4L2_PIX_FMT_YVYU:
+                       {
+                               *ippfmt = RK_FORMAT_YCrCb_420_SP;
+                               break;
+                       }
+               case V4L2_PIX_FMT_RGB565:
+                       {
+                               *ippfmt = RK_FORMAT_RGB_565;
+                               break;
+                       }
+               case V4L2_PIX_FMT_RGB24:
+                       {
+                               *ippfmt = RK_FORMAT_RGB_888;
+                               break;
+                       }
+               default:
+                       goto rk_pixfmt2rgafmt_err;
+       }
+
+       return 0;
+rk_pixfmt2rgafmt_err:
+       return -1;
+}
+
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_RGA)
+extern rga_service_info rga_service;
+extern int rga_blit_sync(rga_session *session, struct rga_req *req);
+extern  void rga_service_session_clear(rga_session *session);
+static int rk_camera_scale_crop_rga(struct work_struct *work){
        struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work);
        struct videobuf_buffer *vb = camera_work->vb;
        struct rk_camera_dev *pcdev = camera_work->pcdev;
-       struct rk29_ipp_req ipp_req;
+       int vipdata_base;
        unsigned long int flags;
-    int src_y_offset,src_uv_offset,dst_y_offset,dst_uv_offset,src_y_size,dst_y_size;
-    int scale_times,w,h,vipdata_base;
+       int scale_times,w,h;
+       int src_y_offset;
+       struct rga_req req;
+       rga_session session;
+       int rga_times = 3;
+       const struct soc_mbus_pixelfmt *fmt;
+       int ret = 0;
+       fmt = soc_mbus_get_fmtdesc(pcdev->icd->current_fmt->code);
+       vipdata_base = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
+       if((pcdev->icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_RGB565)
+               && (pcdev->icd->current_fmt->host_fmt->fourcc != V4L2_PIX_FMT_RGB24)){
+               RKCAMERA_TR("RGA not support this format !\n");
+               goto do_ipp_err;
+               }
+       if ((pcdev->icd->user_width > 0x800) || (pcdev->icd->user_height > 0x800)) {
+               scale_times = MAX((pcdev->icd->user_width/0x800),(pcdev->icd->user_height/0x800));                
+               scale_times++;
+       } else {
+               scale_times = 1;
+       }
+       session.pid = current->pid;
+       INIT_LIST_HEAD(&session.waiting);
+       INIT_LIST_HEAD(&session.running);
+       INIT_LIST_HEAD(&session.list_session);
+       init_waitqueue_head(&session.wait);
+       /* no need to protect */
+       list_add_tail(&session.list_session, &rga_service.session);
+       atomic_set(&session.task_running, 0);
+       atomic_set(&session.num_done, 0);
+       
+       memset(&req,0,sizeof(struct rga_req));
+       req.src.act_w = pcdev->zoominfo.a.c.width/scale_times;
+       req.src.act_h = pcdev->zoominfo.a.c.height/scale_times;
+
+       req.src.vir_w = pcdev->zoominfo.vir_width;
+       req.src.vir_h =pcdev->zoominfo.vir_height;
+       req.src.yrgb_addr = vipdata_base;
+       req.src.uv_addr =vipdata_base + req.src.vir_w*req.src.vir_h;
+       req.src.v_addr = req.src.uv_addr ;
+       req.src.format =fmt->fourcc;
+       rk_pixfmt2rgafmt(fmt->fourcc,&req.src.format);
+       req.src.x_offset = pcdev->zoominfo.a.c.left;
+       req.src.y_offset = pcdev->zoominfo.a.c.top;
+
+       req.dst.act_w = pcdev->icd->user_width/scale_times;
+       req.dst.act_h = pcdev->icd->user_height/scale_times;
+
+       req.dst.vir_w = pcdev->icd->user_width;
+       req.dst.vir_h = pcdev->icd->user_height;
+       req.dst.x_offset = 0;
+       req.dst.y_offset = 0;
+       req.dst.yrgb_addr = vb->boff;
+       rk_pixfmt2rgafmt(pcdev->icd->current_fmt->host_fmt->fourcc,&req.dst.format);
+       req.clip.xmin = 0;
+       req.clip.xmax = req.dst.vir_w-1;
+       req.clip.ymin = 0;
+       req.clip.ymax = req.dst.vir_h -1;
+
+       req.rotate_mode = 1;
+       req.scale_mode = 2;
+
+       req.sina = 0;
+       req.cosa = 65536;
+       req.mmu_info.mmu_en = 0;
+
+       for (h=0; h<scale_times; h++) {
+               for (w=0; w<scale_times; w++) {
+                       rga_times = 3;
        
+                       req.src.yrgb_addr = vipdata_base;
+                       req.src.uv_addr =vipdata_base +req.src.vir_w *req.src.vir_h ;
+                       req.src.x_offset = pcdev->zoominfo.a.c.left+w*pcdev->zoominfo.a.c.width/scale_times;
+                       req.src.y_offset = pcdev->zoominfo.a.c.top+h*pcdev->zoominfo.a.c.height/scale_times;
+                       req.dst.x_offset =  pcdev->icd->user_width*w/scale_times;
+                       req.dst.y_offset = pcdev->icd->user_height*h/scale_times;
+                       req.dst.yrgb_addr = vb->boff ;
+               //      RKCAMERA_TR("src.act_w = %d , src.act_h  = %d! vir_w = %d , vir_h = %d,off_x = %d,off_y = %d\n",req.src.act_w,req.src.act_h ,req.src.vir_w,req.src.vir_h,req.src.x_offset,req.src.y_offset);
+               //      RKCAMERA_TR("dst.act_w = %d , dst.act_h  = %d! vir_w = %d , vir_h = %d,off_x = %d,off_y = %d\n",req.dst.act_w,req.dst.act_h ,req.dst.vir_w,req.dst.vir_h,req.dst.x_offset,req.dst.y_offset);
+               //      RKCAMERA_TR("req.src.yrgb_addr = 0x%x,req.dst.yrgb_addr = 0x%x\n",req.src.yrgb_addr,req.dst.yrgb_addr);
+
+                       while(rga_times-- > 0) {
+                               if (rga_blit_sync(&session, &req)){
+                                       RKCAMERA_TR("rga do erro,do again,rga_times = %d!\n",rga_times);
+                                } else {
+                                       break;
+                                }
+                       }
+               
+                       if (rga_times <= 0) {
+                               spin_lock_irqsave(&pcdev->lock, flags);
+                               vb->state = VIDEOBUF_NEEDS_INIT;
+                               spin_unlock_irqrestore(&pcdev->lock, flags);
+                               mutex_lock(&rga_service.lock);
+                               list_del(&session.list_session);
+                               rga_service_session_clear(&session);
+                               mutex_unlock(&rga_service.lock);
+                               goto session_done;
+                       }
+                       }
+       }
+       session_done:
+       mutex_lock(&rga_service.lock);
+       list_del(&session.list_session);
+       rga_service_session_clear(&session);
+       mutex_unlock(&rga_service.lock);
+
+       do_ipp_err:
+
+               return ret;
+       
+}
+
+#endif
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP)
+
+static int rk_camera_scale_crop_ipp(struct work_struct *work)
+{
+       struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work);
+       struct videobuf_buffer *vb = camera_work->vb;
+       struct rk_camera_dev *pcdev = camera_work->pcdev;
+       int vipdata_base;
+       unsigned long int flags;
+
+       struct rk29_ipp_req ipp_req;
+       int src_y_offset,src_uv_offset,dst_y_offset,dst_uv_offset,src_y_size,dst_y_size;
+       int scale_times,w,h;
+        int ret = 0;
     /*
     *ddl@rock-chips.com: 
     * IPP Dest image resolution is 2047x1088, so scale operation break up some times
@@ -632,7 +863,6 @@ static void rk_camera_capture_process(struct work_struct *work)
     memset(&ipp_req, 0, sizeof(struct rk29_ipp_req));
 
 
-    down(&pcdev->zoominfo.sem);
     ipp_req.timeout = 3000;
     ipp_req.flag = IPP_ROT_0; 
     ipp_req.store_clip_mode =1;
@@ -691,15 +921,166 @@ static void rk_camera_capture_process(struct work_struct *work)
         }
     }
 
-    if (pcdev->icd_cb.sensor_cb)
-        (pcdev->icd_cb.sensor_cb)(vb);
 do_ipp_err:
-    up(&pcdev->zoominfo.sem);
-    wake_up(&(camera_work->vb->done)); 
-    spin_lock_irqsave(&pcdev->camera_work_lock, flags);
-    list_add_tail(&camera_work->queue, &pcdev->camera_work_queue);
-    spin_unlock_irqrestore(&pcdev->camera_work_lock, flags);
-       return;
+       return ret;    
+}
+#endif
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM)
+static int rk_camera_scale_crop_arm(struct work_struct *work)
+{
+    struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work);      
+    struct videobuf_buffer *vb = camera_work->vb;      
+    struct rk_camera_dev *pcdev = camera_work->pcdev;  
+    struct rk29_camera_vbinfo *vb_info;        
+    unsigned char *psY,*pdY,*psUV,*pdUV; 
+    unsigned char *src,*dst;
+    unsigned long src_phy,dst_phy;
+    int srcW,srcH,cropW,cropH,dstW,dstH;
+    long zoomindstxIntInv,zoomindstyIntInv;
+    long x,y;
+    long yCoeff00,yCoeff01,xCoeff00,xCoeff01;
+    long sX,sY;
+    long r0,r1,a,b,c,d;
+    int ret = 0;
+
+    src_phy = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;    
+    src = psY = (unsigned char*)(pcdev->vipmem_virbase + vb->i*pcdev->vipmem_bsize);
+    psUV = psY + pcdev->host_width*pcdev->host_height;
+       
+    srcW = pcdev->zoominfo.vir_width;
+    srcH = pcdev->zoominfo.vir_height;
+    cropW = pcdev->zoominfo.a.c.width;
+    cropH = pcdev->zoominfo.a.c.height;
+       
+    psY = psY + (srcW-cropW);
+    psUV = psUV + (srcW-cropW); 
+    
+    vb_info = pcdev->vbinfo+vb->i; 
+    dst_phy = vb_info->phy_addr;
+    dst = pdY = (unsigned char*)vb_info->vir_addr; 
+    pdUV = pdY + pcdev->icd->user_width*pcdev->icd->user_height;
+    dstW = pcdev->icd->user_width;
+    dstH = pcdev->icd->user_height;
+
+    zoomindstxIntInv = ((unsigned long)cropW<<16)/dstW + 1;
+    zoomindstyIntInv = ((unsigned long)cropH<<16)/dstH + 1;
+    //y
+    //for(y = 0; y<dstH - 1 ; y++ ) {   
+    for(y = 0; y<dstH; y++ ) {   
+        yCoeff00 = (y*zoomindstyIntInv)&0xffff;
+        yCoeff01 = 0xffff - yCoeff00; 
+        sY = (y*zoomindstyIntInv >> 16);
+
+        for(x = 0; x<dstW; x++ ) {
+            xCoeff00 = (x*zoomindstxIntInv)&0xffff;
+            xCoeff01 = 0xffff - xCoeff00;      
+            sX = (x*zoomindstxIntInv >> 16);
+
+            a = psY[sY*srcW + sX];
+            b = psY[sY*srcW + sX + 1];
+            c = psY[(sY+1)*srcW + sX];
+            d = psY[(sY+1)*srcW + sX + 1];
+
+            r0 = (a * xCoeff01 + b * xCoeff00)>>16 ;
+            r1 = (c * xCoeff01 + d * xCoeff00)>>16 ;
+            r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16;
+
+            pdY[x] = r0;
+        }
+        pdY += dstW;
+    }
+
+    dstW /= 2;
+    dstH /= 2;
+    srcW /= 2;
+    srcH /= 2;
+
+    //UV
+    //for(y = 0; y<dstH - 1 ; y++ ) {
+    for(y = 0; y<dstH; y++ ) {
+        yCoeff00 = (y*zoomindstyIntInv)&0xffff;
+        yCoeff01 = 0xffff - yCoeff00; 
+        sY = (y*zoomindstyIntInv >> 16);
+
+        for(x = 0; x<dstW; x++ ) {
+            xCoeff00 = (x*zoomindstxIntInv)&0xffff;
+            xCoeff01 = 0xffff - xCoeff00;      
+            sX = (x*zoomindstxIntInv >> 16);
+
+            //U
+            a = psUV[(sY*srcW + sX)*2];
+            b = psUV[(sY*srcW + sX + 1)*2];
+            c = psUV[((sY+1)*srcW + sX)*2];
+            d = psUV[((sY+1)*srcW + sX + 1)*2];
+
+            r0 = (a * xCoeff01 + b * xCoeff00)>>16 ;
+            r1 = (c * xCoeff01 + d * xCoeff00)>>16 ;
+            r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16;
+
+            pdUV[x*2] = r0;
+
+            //V
+            a = psUV[(sY*srcW + sX)*2 + 1];
+            b = psUV[(sY*srcW + sX + 1)*2 + 1];
+            c = psUV[((sY+1)*srcW + sX)*2 + 1];
+            d = psUV[((sY+1)*srcW + sX + 1)*2 + 1];
+
+            r0 = (a * xCoeff01 + b * xCoeff00)>>16 ;
+            r1 = (c * xCoeff01 + d * xCoeff00)>>16 ;
+            r0 = (r0 * yCoeff01 + r1 * yCoeff00)>>16;
+
+            pdUV[x*2 + 1] = r0;
+        }
+        pdUV += dstW*2;
+    }
+
+rk_camera_scale_crop_arm_end:
+
+    dmac_flush_range((void*)src,(void*)(src+pcdev->vipmem_bsize));
+    outer_flush_range((phys_addr_t)src_phy,(phys_addr_t)(src_phy+pcdev->vipmem_bsize));
+    
+    dmac_flush_range((void*)dst,(void*)(dst+vb_info->size));
+    outer_flush_range((phys_addr_t)dst_phy,(phys_addr_t)(dst_phy+vb_info->size));
+
+       return ret;    
+}
+#endif
+static void rk_camera_capture_process(struct work_struct *work)
+{
+    struct rk_camera_work *camera_work = container_of(work, struct rk_camera_work, work);    
+    struct videobuf_buffer *vb = camera_work->vb;    
+    struct rk_camera_dev *pcdev = camera_work->pcdev;    
+    //enum v4l2_mbus_pixelcode icd_code = pcdev->icd->current_fmt->code;    
+    unsigned long flags = 0;    
+    int err = 0;    
+
+    if (!CAM_WORKQUEUE_IS_EN())        
+        goto rk_camera_capture_process_end; 
+    
+    down(&pcdev->zoominfo.sem);
+    if (pcdev->icd_cb.scale_crop_cb){
+        err = (pcdev->icd_cb.scale_crop_cb)(work);
+       }
+    up(&pcdev->zoominfo.sem); 
+    
+    if (pcdev->icd_cb.sensor_cb)        
+        (pcdev->icd_cb.sensor_cb)(vb);    
+
+rk_camera_capture_process_end:    
+    if (err) {        
+        vb->state = VIDEOBUF_ERROR;    
+    } else {
+        if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
+               vb->state = VIDEOBUF_DONE;
+               vb->field_count++;
+               }
+    }    
+    wake_up(&(camera_work->vb->done));     
+    spin_lock_irqsave(&pcdev->camera_work_lock, flags);    
+    list_add_tail(&camera_work->queue, &pcdev->camera_work_queue);    
+    spin_unlock_irqrestore(&pcdev->camera_work_lock, flags);    
+    return;
 }
 static irqreturn_t rk_camera_irq(int irq, void *data)
 {
@@ -751,7 +1132,7 @@ static irqreturn_t rk_camera_irq(int irq, void *data)
         if(!vb){
             printk("no acticve buffer!!!\n");
             goto RK_CAMERA_IRQ_END;
-            }
+        }
                /* ddl@rock-chips.com : this vb may be deleted from queue */
                if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
                list_del_init(&vb->queue);
@@ -768,11 +1149,7 @@ static irqreturn_t rk_camera_irq(int irq, void *data)
                        RKCAMERA_DG("%s video_buf queue is empty!\n",__FUNCTION__);
                }
 
-               if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
-               vb->state = VIDEOBUF_DONE;
-               do_gettimeofday(&vb->ts);
-               vb->field_count++;
-               }
+        do_gettimeofday(&vb->ts);
                if (CAM_WORKQUEUE_IS_EN()) {
             if (!list_empty(&pcdev->camera_work_queue)) {
                 wk = list_entry(pcdev->camera_work_queue.next, struct rk_camera_work, queue);
@@ -783,6 +1160,10 @@ static irqreturn_t rk_camera_irq(int irq, void *data)
                        queue_work(pcdev->camera_wq, &(wk->work));
             }                                  
                } else {
+                   if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
+               vb->state = VIDEOBUF_DONE;              
+               vb->field_count++;
+               }
                        wake_up(&vb->done);
                }
                
@@ -802,6 +1183,7 @@ static void rk_videobuf_release(struct videobuf_queue *vq,
     struct soc_camera_device *icd = vq->priv_data;
     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk_camera_dev *pcdev = ici->priv;
+    struct rk29_camera_vbinfo *vb_info =NULL;
 #ifdef DEBUG
     dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
             vb, vb->baddr, vb->bsize);
@@ -822,16 +1204,25 @@ static void rk_videobuf_release(struct videobuf_queue *vq,
             break;
     }
 #endif
-    if (vb->i == 0) {
-        flush_workqueue(pcdev->camera_wq);
-    }
-    
        if (vb == pcdev->active) {
                RKCAMERA_DG("%s Wait for this video buf(0x%x) write finished!\n ",__FUNCTION__,(unsigned int)vb);
                interruptible_sleep_on_timeout(&vb->done, msecs_to_jiffies(500));
-        flush_workqueue(pcdev->camera_wq);
                RKCAMERA_DG("%s This video buf(0x%x) write finished, release now!!\n",__FUNCTION__,(unsigned int)vb);
        }
+
+    flush_workqueue(pcdev->camera_wq); 
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+    if (pcdev->vbinfo) {
+        vb_info = pcdev->vbinfo + vb->i;
+        
+        if (vb_info->vir_addr) {
+            iounmap(vb_info->vir_addr);
+            release_mem_region(vb_info->phy_addr, vb_info->size);
+            memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo));
+        }       
+               
+       }
+#endif    
     rk_videobuf_free(vq, buf);
 }
 
@@ -925,12 +1316,11 @@ RK_CAMERA_ACTIVE_ERR:
 }
 
 static void rk_camera_deactivate(struct rk_camera_dev *pcdev)
-{
+{      
        clk_disable(pcdev->aclk_cif);
 
        clk_disable(pcdev->hclk_cif);
        clk_disable(pcdev->cif_clk_in);
-       
        clk_disable(pcdev->cif_clk_out);
        clk_enable(pcdev->cif_clk_out);
     clk_set_rate(pcdev->cif_clk_out,48*1000*1000);
@@ -1020,6 +1410,8 @@ static void rk_camera_remove_device(struct soc_camera_device *icd)
     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk_camera_dev *pcdev = ici->priv;
        struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+    struct rk29_camera_vbinfo *vb_info;
+    unsigned int i;
 
        mutex_lock(&camera_lock);
     BUG_ON(icd != pcdev->icd);
@@ -1059,6 +1451,22 @@ static void rk_camera_remove_device(struct soc_camera_device *icd)
         INIT_LIST_HEAD(&pcdev->camera_work_queue);
        }
        rk_camera_deactivate(pcdev);
+#if CAMERA_VIDEOBUF_ARM_ACCESS
+    if (pcdev->vbinfo) {
+        vb_info = pcdev->vbinfo;
+        for (i=0; i<pcdev->vbinfo_count; i++) {
+            if (vb_info->vir_addr) {
+                iounmap(vb_info->vir_addr);
+                release_mem_region(vb_info->phy_addr, vb_info->size);
+                memset(vb_info, 0x00, sizeof(struct rk29_camera_vbinfo));
+            }
+            vb_info++;
+        }
+               kfree(pcdev->vbinfo);
+               pcdev->vbinfo = NULL;
+               pcdev->vbinfo_count = 0;
+       }
+#endif
        pcdev->active = NULL;
     pcdev->icd = NULL;
     pcdev->icd_cb.sensor_cb = NULL;
@@ -1207,6 +1615,18 @@ static const struct soc_mbus_pixelfmt rk_camera_formats[] = {
                .bits_per_sample        = 8,
                .packing                = SOC_MBUS_PACKING_2X8_PADHI,
                .order                  = SOC_MBUS_ORDER_LE,
+       },{
+               .fourcc                 = V4L2_PIX_FMT_RGB565,
+               .name                   = "RGB565",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_LE,
+       },{
+               .fourcc                 = V4L2_PIX_FMT_RGB24,
+               .name                   = "RGB888",
+               .bits_per_sample        = 8,
+               .packing                = SOC_MBUS_PACKING_2X8_PADHI,
+               .order                  = SOC_MBUS_ORDER_LE,
        }
 };
 
@@ -1216,37 +1636,47 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix
     struct rk_camera_dev *pcdev = ici->priv;
     unsigned int cif_fs = 0,cif_crop = 0;
     unsigned int cif_fmt_val = read_cif_reg(pcdev->base,CIF_CIF_FOR) | INPUT_MODE_YUV|YUV_INPUT_422|INPUT_420_ORDER_EVEN|OUTPUT_420_ORDER_EVEN;
+       
+       const struct soc_mbus_pixelfmt *fmt;
+       fmt = soc_mbus_get_fmtdesc(icd_code);
+
+       if((host_pixfmt == V4L2_PIX_FMT_RGB565) || (host_pixfmt == V4L2_PIX_FMT_RGB24)){
+               if(fmt->fourcc == V4L2_PIX_FMT_NV12)
+                       host_pixfmt = V4L2_PIX_FMT_NV12;
+               else if(fmt->fourcc == V4L2_PIX_FMT_NV21)
+                       host_pixfmt = V4L2_PIX_FMT_NV21;
+       }
     switch (host_pixfmt)
     {
         case V4L2_PIX_FMT_NV16:
             cif_fmt_val &= ~YUV_OUTPUT_422;
-                   cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV;
-                   pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC;
-                   pcdev->pixfmt = host_pixfmt;
+               cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV;
+               pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC;
+               pcdev->pixfmt = host_pixfmt;
             break;
-       case V4L2_PIX_FMT_NV61:
-               cif_fmt_val &= ~YUV_OUTPUT_422;
-               cif_fmt_val |= UV_STORAGE_ORDER_VUVU;
-               pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC;
-               pcdev->pixfmt = host_pixfmt;
-               break;
+       case V4L2_PIX_FMT_NV61:
+               cif_fmt_val &= ~YUV_OUTPUT_422;
+               cif_fmt_val |= UV_STORAGE_ORDER_VUVU;
+               pcdev->frame_inval = RK_CAM_FRAME_INVAL_DC;
+               pcdev->pixfmt = host_pixfmt;
+               break;
         case V4L2_PIX_FMT_NV12:
             cif_fmt_val |= YUV_OUTPUT_420;
-               cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV;
+               cif_fmt_val &= ~UV_STORAGE_ORDER_UVUV;
                        if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT)
                                pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT;
                        pcdev->pixfmt = host_pixfmt;
             break;
-       case V4L2_PIX_FMT_NV21:
-               cif_fmt_val |= YUV_OUTPUT_420;
-               cif_fmt_val |= UV_STORAGE_ORDER_VUVU;
-               if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT)
-                       pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT;
-               pcdev->pixfmt = host_pixfmt;
-               break;
-            default:                                                                                /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */
-                       cif_fmt_val |= YUV_OUTPUT_422;
-                break;
+       case V4L2_PIX_FMT_NV21:
+               cif_fmt_val |= YUV_OUTPUT_420;
+               cif_fmt_val |= UV_STORAGE_ORDER_VUVU;
+               if (pcdev->frame_inval != RK_CAM_FRAME_INVAL_INIT)
+                       pcdev->frame_inval = RK_CAM_FRAME_INVAL_INIT;
+               pcdev->pixfmt = host_pixfmt;
+               break;
+        default:                                                                                /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */
+                       cif_fmt_val |= YUV_OUTPUT_422;
+            break;
     }
     switch (icd_code)
     {
@@ -1306,8 +1736,7 @@ static void rk_camera_setup_format(struct soc_camera_device *icd, __u32 host_pix
        write_cif_reg(pcdev->base,CIF_CIF_SET_SIZE, cif_fs);
        write_cif_reg(pcdev->base,CIF_CIF_VIR_LINE_WIDTH, rect->width);
        write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS,  0x00000003);
-
-    //MUST bypass scale 
+       //MUST bypass scale 
        write_cif_reg(pcdev->base,CIF_CIF_SCL_CTRL,0x10);
     RKCAMERA_DG("%s.. crop:0x%x fs:0x%x cif_fmt_val:0x%x CIF_CIF_FOR:0x%x\n",__FUNCTION__,cif_crop,cif_fs,cif_fmt_val,read_cif_reg(pcdev->base,CIF_CIF_FOR));
        return;
@@ -1377,6 +1806,22 @@ static int rk_camera_get_formats(struct soc_camera_device *icd, unsigned int idx
                 dev_dbg(dev, "Providing format %s using code %d\n",
                        rk_camera_formats[3].name,code);
             }
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = &rk_camera_formats[4];
+                       xlate->code = code;
+                       xlate++;
+                       dev_dbg(dev, "Providing format %s using code %d\n",
+                               rk_camera_formats[4].name,code);
+               }
+               formats++;
+               if (xlate) {
+                       xlate->host_fmt = &rk_camera_formats[5];
+                       xlate->code = code;
+                       xlate++;
+                       dev_dbg(dev, "Providing format %s using code %d\n",
+                               rk_camera_formats[5].name,code);
+               }
                        break;          
         default:
             break;
@@ -1538,6 +1983,7 @@ static int rk_camera_set_fmt(struct soc_camera_device *icd,
                pcdev->zoominfo.a.c.top = 0;
             }
                pcdev->zoominfo.vir_width = pcdev->host_width;
+               pcdev->zoominfo.vir_height = pcdev->host_height;
         up(&pcdev->zoominfo.sem);
 
         /* ddl@rock-chips.com: IPP work limit check */
@@ -2171,6 +2617,7 @@ static int rk_camera_set_digit_zoom(struct soc_camera_device *icd,
        pcdev->zoominfo.a.c.top = a.c.top;
        pcdev->zoominfo.a.c.left = a.c.left;
        pcdev->zoominfo.vir_width = pcdev->host_width;
+       pcdev->zoominfo.vir_height= pcdev->host_height;
     up(&pcdev->zoominfo.sem);
        RKCAMERA_DG("%s..zoom_rate:%d (%dx%d at (%d,%d)-> %dx%d)\n",__FUNCTION__, zoom_rate,a.c.width, a.c.height, a.c.left, a.c.top, icd->user_width, icd->user_height );
 
@@ -2326,6 +2773,7 @@ static int rk_camera_probe(struct platform_device *pdev)
 
        pcdev->zoominfo.zoom_rate = 100;
        pcdev->hostid = pdev->id;
+    
     /*config output clk*/ // must modify start
     if(IS_CIF0()){
         pcdev->pd_cif = clk_get(NULL, "pd_cif0");
@@ -2361,15 +2809,38 @@ static int rk_camera_probe(struct platform_device *pdev)
        if (pcdev->pdata && IS_CIF0()) {
                pcdev->vipmem_phybase = pcdev->pdata->meminfo.start;
                pcdev->vipmem_size = pcdev->pdata->meminfo.size;
+
+        if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) {
+            err = -EBUSY;
+            goto exit_ioremap_vipmem;
+        }
+        pcdev->vipmem_virbase = ioremap_cached(pcdev->vipmem_phybase,pcdev->vipmem_size);
+        if (pcdev->vipmem_virbase == NULL) {
+            dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n");
+            err = -ENXIO;
+            goto exit_ioremap_vipmem;
+        }              
                RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size);
        } else if (pcdev->pdata) {
                pcdev->vipmem_phybase = pcdev->pdata->meminfo_cif1.start;
                pcdev->vipmem_size = pcdev->pdata->meminfo_cif1.size;
+
+        if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) {
+            err = -EBUSY;
+            goto exit_ioremap_vipmem;
+        }
+        pcdev->vipmem_virbase = ioremap_cached(pcdev->vipmem_phybase,pcdev->vipmem_size);
+        if (pcdev->vipmem_virbase == NULL) {
+            dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n");
+            err = -ENXIO;
+            goto exit_ioremap_vipmem;
+        }              
                RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size);
        } else {
                RKCAMERA_TR("\n%s Memory for IPP have not obtain! IPP Function is fail\n",__FUNCTION__);
                pcdev->vipmem_phybase = 0;
                pcdev->vipmem_size = 0;
+        pcdev->vipmem_virbase = 0;
        }
        #endif
     INIT_LIST_HEAD(&pcdev->capture);
@@ -2441,6 +2912,13 @@ static int rk_camera_probe(struct platform_device *pdev)
        pcdev->fps_timer.timer.function = rk_camera_fps_func;
     pcdev->icd_cb.sensor_cb = NULL;
 
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP)
+    pcdev->icd_cb.scale_crop_cb = rk_camera_scale_crop_ipp;
+#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM)
+    pcdev->icd_cb.scale_crop_cb = rk_camera_scale_crop_arm;
+#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_RGA)
+    pcdev->icd_cb.scale_crop_cb = rk_camera_scale_crop_rga;    
+#endif
     RKCAMERA_DG("%s(%d) Exit  \n",__FUNCTION__,__LINE__);
     return 0;
 
@@ -2465,7 +2943,10 @@ exit_reqirq:
     iounmap(pcdev->base);
 exit_ioremap_vip:
     release_mem_region(res->start, res->end - res->start + 1);
-
+exit_ioremap_vipmem:
+    if (pcdev->vipmem_virbase)
+        iounmap(pcdev->vipmem_virbase);
+    release_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size);
 exit_reqmem_vip:
     if(pcdev->aclk_cif)
         pcdev->aclk_cif = NULL;