rk312x camera : oneframe v0.1.9,pingpong v0.1.9
[firefly-linux-kernel-4.4.55.git] / drivers / media / video / rk29_camera_oneframe.c
index 14eddd0af8f71679f1f440875531ffc4146e31bb..8470b12681ae3b6f93e7834385c0aefa63893408 100755 (executable)
@@ -9,7 +9,7 @@
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  */
-
+#ifdef CONFIG_ARCH_RK29
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/io.h>
 #include <media/soc_camera.h>
 #include <media/soc_mediabus.h>
 #include <mach/rk29-ipp.h>
-
+#include <asm/cacheflush.h>
 
 static int debug;
-module_param(debug, int, S_IRUGO|S_IWUSR);
+module_param(debug, int, S_IRUGO|S_IWUSR|S_IWGRP);
 
 #define dprintk(level, fmt, arg...) do {                       \
        if (debug >= level)                                     \
@@ -137,13 +137,32 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
 //Configure Macro
 /*
 *            Driver Version Note
-*v0.0.1 : this driver first support rk2918;
-*v0.0.2 : fix this driver support v4l2 format is V4L2_PIX_FMT_NV12 and V4L2_PIX_FMT_NV16,is not V4L2_PIX_FMT_YUV420 
+*
+*v0.0.x : this driver is 2.6.32 kernel driver;
+*v0.1.x : this driver is 3.0.8 kernel driver;
+*v0.2.x : this driver is rk30 3.0.8 kernel driver;
+*v0.3.x : this driver is camera-isp driver;
+*
+*v0.x.1 : this driver first support rk2918;
+*v0.x.2 : fix this driver support v4l2 format is V4L2_PIX_FMT_NV12 and V4L2_PIX_FMT_NV16,is not V4L2_PIX_FMT_YUV420 
 *         and V4L2_PIX_FMT_YUV422P;
-*v0.0.3 : this driver support VIDIOC_ENUM_FRAMEINTERVALS;
-*v0.0.4 : this driver support digital zoom;
+*v0.x.3 : this driver support VIDIOC_ENUM_FRAMEINTERVALS;
+*v0.x.4 : this driver support digital zoom;
+*v0.x.5 : this driver support test framerate and query framerate from board file configuration;
+*v0.x.6 : this driver improve test framerate method;
+*v0.x.7 : this driver product resolution by IPP crop and scale, which user request but sensor can't support;
+*         note: this version is only provide yifang client, which is not official version;
+*v0.x.8 : this driver and rk29_camera.c support upto 3 back-sensors and upto 3 front-sensors;
+*v0.x.9 : camera io code is compatible for rk29xx and rk30xx
+*v0.x.a : fix error when calculate crop left-top point coordinate;
+*         note: this version provided as patch camera_patch_v1.1
+*v0.x.b : fix sensor autofocus thread may in running when reinit sensor if sensor haven't stream on in first init;
+*v0.x.c : fix work queue havn't been finished after close device;
+*v0.x.d : fix error when calculate crop left-top point coordinate;
+*v0.x.f : fix struct rk29_camera_work may be reentrant.
+*v0.x.11: add support zoom by arm;
 */
-#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 1, 3)
+#define RK29_CAM_VERSION_CODE KERNEL_VERSION(0, 1, 0x11)
 
 /* limit to rk29 hardware capabilities */
 #define RK29_CAM_BUS_PARAM   (SOCAM_MASTER |\
@@ -164,6 +183,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
 #define RK29_CAM_H_MAX        2764
 #define RK29_CAM_FRAME_INVAL_INIT 3
 #define RK29_CAM_FRAME_INVAL_DC 3          /* ddl@rock-chips.com :  */
+#define RK29_CAM_FRAME_MEASURE  5
 
 #define RK29_CAM_AXI   0
 #define RK29_CAM_AHB   1
@@ -200,6 +220,8 @@ struct rk29_camera_work
        struct videobuf_buffer *vb;
        struct rk29_camera_dev *pcdev;
        struct work_struct work;
+    struct list_head queue;
+    unsigned int index;
 };
 struct rk29_camera_frmivalenum
 {
@@ -217,6 +239,14 @@ struct rk29_camera_zoominfo
     struct v4l2_crop a;
     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 rk29_camera_dev
 {
     struct soc_camera_host     soc_host;
@@ -246,12 +276,20 @@ struct rk29_camera_dev
     int frame_inval;           /* ddl@rock-chips.com : The first frames is invalidate  */
     unsigned int irq;
        unsigned int fps;
+    unsigned long frame_interval;
        unsigned int pixfmt;
        unsigned int vipmem_phybase;
+    void __iomem *vipmem_virbase;
        unsigned int vipmem_size;
        unsigned int vipmem_bsize;
+#if CAMERA_VIDEOBUF_ARM_ACCESS    
+    struct rk29_camera_vbinfo *vbinfo;
+    unsigned int vbinfo_count;
+#endif    
        int host_width;
        int host_height;
+    int icd_width;
+    int icd_height;
 
     struct rk29camera_platform_data *pdata;
     struct resource            *res;
@@ -265,6 +303,8 @@ struct rk29_camera_dev
        struct rk29_camera_reg reginfo_suspend;
        struct workqueue_struct *camera_wq;
        struct rk29_camera_work *camera_work;
+    struct list_head camera_work_queue;
+    spinlock_t camera_work_lock;
        unsigned int camera_work_count;
        struct hrtimer fps_timer;
        struct work_struct camera_reinit_work;
@@ -306,6 +346,10 @@ static int rk29_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
     struct rk29_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);
+    int i;
+    struct rk29_camera_work *wk;
 
     dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
 
@@ -314,7 +358,7 @@ static int rk29_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
 
        /* 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 * pcdev->host_height);
+       pcdev->vipmem_bsize = PAGE_ALIGN(bytes_per_line_host * pcdev->host_height);
 
 
        if (CAM_WORKQUEUE_IS_EN()) {
@@ -330,17 +374,40 @@ static int rk29_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
                if ((pcdev->camera_work_count != *count) && pcdev->camera_work) {
                        kfree(pcdev->camera_work);
                        pcdev->camera_work = NULL;
-                       pcdev->camera_work_count = 0;
+                       pcdev->camera_work_count = 0;            
                }
 
                if (pcdev->camera_work == NULL) {
-                       pcdev->camera_work = kmalloc(sizeof(struct rk29_camera_work)*(*count), GFP_KERNEL);
+                       pcdev->camera_work = wk = kzalloc(sizeof(struct rk29_camera_work)*(*count), GFP_KERNEL);
                        if (pcdev->camera_work == NULL) {
                                RK29CAMERA_TR("\n %s kmalloc fail\n", __FUNCTION__);
                                BUG();
                        }
-                       pcdev->camera_work_count = *count;
+            INIT_LIST_HEAD(&pcdev->camera_work_queue);
+
+            for (i=0; i<(*count); i++) {
+                wk->index = i;                
+                list_add_tail(&wk->queue, &pcdev->camera_work_queue);
+                wk++; 
+            }
+                       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) {
+                               RK29CAMERA_TR("\n %s vbinfo kmalloc fail\n", __FUNCTION__);
+                               BUG();
+                       }
+                       pcdev->vbinfo_count = *count;
+        }
+#endif        
        }
 
     RK29CAMERA_DG("%s..%d.. videobuf size:%d, vipmem_buf size:%d, count:%d \n",__FUNCTION__,__LINE__, *size,pcdev->vipmem_size, *count);
@@ -461,7 +528,8 @@ static void rk29_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 rk29_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);
 
@@ -475,6 +543,31 @@ static void rk29_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,"rk29_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 {
+                RK29CAMERA_TR("%s..%d:ioremap videobuf %d failed\n",__FUNCTION__,__LINE__, vb->i);
+            }
+        }
+    }
+#endif    
     if (!pcdev->active) {
         pcdev->active = vb;
         rk29_videobuf_capture(vb);
@@ -504,7 +597,8 @@ static int rk29_pixfmt2ippfmt(unsigned int pixfmt, int *ippfmt)
 rk29_pixfmt2ippfmt_err:
        return -1;
 }
-static void rk29_camera_capture_process(struct work_struct *work)
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP)
+static int rk29_camera_scale_crop_ipp(struct work_struct *work)
 {
        struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work);
        struct videobuf_buffer *vb = camera_work->vb;
@@ -513,7 +607,8 @@ static void rk29_camera_capture_process(struct work_struct *work)
        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 ret = 0;
+    
     /*
     *ddl@rock-chips.com: 
     * IPP Dest image resolution is 2047x1088, so scale operation break up some times
@@ -527,8 +622,6 @@ static void rk29_camera_capture_process(struct work_struct *work)
     
     memset(&ipp_req, 0, sizeof(struct rk29_ipp_req));
     
-    down(&pcdev->zoominfo.sem);
-    
     ipp_req.timeout = 100;
     ipp_req.flag = IPP_ROT_0;    
     ipp_req.src0.w = pcdev->zoominfo.a.c.width/scale_times;
@@ -577,33 +670,190 @@ static void rk29_camera_capture_process(struct work_struct *work)
                RK29CAMERA_TR("ipp_req.src_vir_w:0x%x ipp_req.dst_vir_w :0x%x\n",ipp_req.src_vir_w ,ipp_req.dst_vir_w);
                RK29CAMERA_TR("ipp_req.timeout:0x%x ipp_req.flag :0x%x\n",ipp_req.timeout,ipp_req.flag);
                 
-                       goto do_ipp_err;
+                       goto rk29_camera_scale_crop_ipp_end;
                }
         }
     }
+    
+rk29_camera_scale_crop_ipp_end:        
+       return ret;    
+}
+#endif
+#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM)
+static int rk29_camera_scale_crop_arm(struct work_struct *work)
+{
+    struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work);  
+    struct videobuf_buffer *vb = camera_work->vb;      
+    struct rk29_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;
+    
 
-    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)); 
-       return;
+    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->host_width;
+    srcH = pcdev->host_height;
+    cropW = pcdev->zoominfo.a.c.width;
+    cropH = pcdev->zoominfo.a.c.height;
+    psY = psY + pcdev->host_width - pcdev->zoominfo.a.c.width;
+    psUV = psUV + pcdev->host_width - pcdev->zoominfo.a.c.width; 
+    
+    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;
+    }
+
+rk29_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 rk29_camera_capture_process(struct work_struct *work)
+{
+    struct rk29_camera_work *camera_work = container_of(work, struct rk29_camera_work, work);    
+    struct videobuf_buffer *vb = camera_work->vb;    
+    struct rk29_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 rk29_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);    
+
+rk29_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 rk29_camera_irq(int irq, void *data)
 {
     struct rk29_camera_dev *pcdev = data;
     struct videobuf_buffer *vb;
        struct rk29_camera_work *wk;
+    static struct timeval first_tv;
+    struct timeval tv;
 
     read_vip_reg(RK29_VIP_INT_STS);    /* clear vip interrupte single  */
     /* ddl@rock-chps.com : Current VIP is run in One Frame Mode, Frame 1 is validate */
     if (read_vip_reg(RK29_VIP_FB_SR) & 0x01) {
+        if (!pcdev->fps) {
+            do_gettimeofday(&first_tv);            
+        }
                pcdev->fps++;
                if (!pcdev->active)
                        goto RK29_CAMERA_IRQ_END;
 
-        if (pcdev->frame_inval>0) {
+        if (pcdev->frame_inval>0) {            
             pcdev->frame_inval--;
             rk29_videobuf_capture(pcdev->active);
             goto RK29_CAMERA_IRQ_END;
@@ -612,6 +862,12 @@ static irqreturn_t rk29_camera_irq(int irq, void *data)
             pcdev->frame_inval = 0;
         }
 
+        if(pcdev->fps == RK29_CAM_FRAME_MEASURE) {
+            do_gettimeofday(&tv);            
+            pcdev->frame_interval = ((tv.tv_sec*1000000 + tv.tv_usec) - (first_tv.tv_sec*1000000 + first_tv.tv_usec))
+                                    /(RK29_CAM_FRAME_MEASURE-1);
+        }
+
         vb = pcdev->active;
                /* ddl@rock-chips.com : this vb may be deleted from queue */
                if ((vb->state == VIDEOBUF_QUEUED) || (vb->state == VIDEOBUF_ACTIVE)) {
@@ -629,20 +885,22 @@ static irqreturn_t rk29_camera_irq(int irq, void *data)
         if (pcdev->active == NULL) {
                        RK29CAMERA_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()) {
-                       wk = pcdev->camera_work + vb->i;
-                       INIT_WORK(&(wk->work), rk29_camera_capture_process);
-                       wk->vb = vb;
-                       wk->pcdev = pcdev;
-                       queue_work(pcdev->camera_wq, &(wk->work));
+            if (!list_empty(&pcdev->camera_work_queue)) {
+                wk = list_entry(pcdev->camera_work_queue.next, struct rk29_camera_work, queue);
+                list_del_init(&wk->queue);
+                INIT_WORK(&(wk->work), rk29_camera_capture_process);
+                       wk->vb = vb;
+                       wk->pcdev = pcdev;
+                       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);
                }
     }
@@ -659,6 +917,8 @@ static void rk29_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 rk29_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);
@@ -678,12 +938,26 @@ static void rk29_videobuf_release(struct videobuf_queue *vq,
             dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
             break;
     }
-#endif 
+#endif
        if (vb == pcdev->active) {
                RK29CAMERA_DG("%s Wait for this video buf(0x%x) write finished!\n ",__FUNCTION__,(unsigned int)vb);
-               interruptible_sleep_on_timeout(&vb->done, 100);
+               interruptible_sleep_on_timeout(&vb->done, msecs_to_jiffies(500));
                RK29CAMERA_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    
     rk29_videobuf_free(vq, buf);
 }
 
@@ -839,9 +1113,8 @@ static int rk29_camera_add_device(struct soc_camera_device *icd)
         goto ebusy;
     }
 
-    dev_info(&icd->dev, "RK29 Camera driver attached to camera%d(%s)\n",
-             icd->devnum,dev_name(icd->pdev));
-
+    RK29CAMERA_DG("RK29 Camera driver attached to %s\n",dev_name(icd->pdev));
+    
        pcdev->frame_inval = RK29_CAM_FRAME_INVAL_INIT;
     pcdev->active = NULL;
     pcdev->icd = NULL;
@@ -903,12 +1176,13 @@ static void rk29_camera_remove_device(struct soc_camera_device *icd)
     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk29_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);
 
-    dev_info(&icd->dev, "RK29 Camera driver detached from camera%d(%s)\n",
-             icd->devnum,dev_name(icd->pdev));
+    RK29CAMERA_DG("RK29 Camera driver detached from %s\n",dev_name(icd->pdev));
 
        /* ddl@rock-chips.com: Application will call VIDIOC_STREAMOFF before close device, but
           stream may be turn on again before close device, if suspend and resume happened. */
@@ -923,8 +1197,24 @@ static void rk29_camera_remove_device(struct soc_camera_device *icd)
                kfree(pcdev->camera_work);
                pcdev->camera_work = NULL;
                pcdev->camera_work_count = 0;
+        INIT_LIST_HEAD(&pcdev->camera_work_queue);
        }
-
+#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;
@@ -1087,17 +1377,19 @@ static void rk29_camera_setup_format(struct soc_camera_device *icd, __u32 host_p
                        pcdev->pixfmt = host_pixfmt;
             break;
         default:                                                                                /* ddl@rock-chips.com : vip output format is hold when pixfmt is invalidate */
-            vip_ctrl_val |= (read_vip_reg(RK29_VIP_CTRL) & VIPREGYUV422);
+            if (pcdev->frame_inval != RK29_CAM_FRAME_INVAL_INIT)
+                               pcdev->frame_inval = RK29_CAM_FRAME_INVAL_INIT;
+            pcdev->pixfmt = host_pixfmt;
             break;
     }
 
     switch (icd_code)
     {
         case V4L2_MBUS_FMT_UYVY8_2X8:
-            vip_ctrl_val |= SENSOR_UYVY;
+            vip_ctrl_val |= (SENSOR_UYVY|VIP_YUV);
             break;
         case V4L2_MBUS_FMT_YUYV8_2X8:
-            vip_ctrl_val |= SENSOR_YUYV;
+            vip_ctrl_val |= (SENSOR_YUYV|VIP_YUV);
             break;
         default :
             vip_ctrl_val |= (read_vip_reg(RK29_VIP_CTRL) & SENSOR_YUYV);
@@ -1247,7 +1539,7 @@ static int rk29_camera_set_fmt(struct soc_camera_device *icd,
     struct v4l2_pix_format *pix = &f->fmt.pix;
     struct v4l2_mbus_framefmt mf;
     struct v4l2_rect rect;
-    int ret,usr_w,usr_h;
+    int ret,usr_w,usr_h,icd_width,icd_height;
     int stream_on = 0;
 
        usr_w = pix->width;
@@ -1281,7 +1573,9 @@ static int rk29_camera_set_fmt(struct soc_camera_device *icd,
 
        if (mf.code != xlate->code)
                return -EINVAL;
-
+    
+    icd_width = mf.width;
+    icd_height = mf.height;
        #ifdef CONFIG_VIDEO_RK29_WORK_IPP
        if ((mf.width != usr_w) || (mf.height != usr_h)) {
         if (unlikely((mf.width <16) || (mf.width > 8190) || (mf.height < 16) || (mf.height > 8190))) {
@@ -1294,25 +1588,50 @@ static int rk29_camera_set_fmt(struct soc_camera_device *icd,
                ret = -EINVAL;
             goto RK29_CAMERA_SET_FMT_END;
        }
-               mf.width = usr_w;
-               mf.height = usr_h;
        }
        #endif
     icd->sense = NULL;
 
     if (!ret) {
-        rect.left = 0;
-        rect.top = 0;
-        rect.width = mf.width;
-        rect.height = mf.height;
+
+        if (mf.width*usr_h == mf.height*usr_w) {
+            rect.width = mf.width;
+            rect.height = mf.height;
+        } else {
+            int ratio;
+            if (usr_w > usr_h) {
+                if (mf.width > usr_w) {
+                    ratio = MIN((mf.width*10/usr_w),(mf.height*10/usr_h))-1;
+                    rect.width = usr_w*ratio/10;
+                    rect.height = usr_h*ratio/10;                    
+                } else {
+                    ratio = MAX((usr_w*10/mf.width),(usr_h*10/mf.height))+1;
+                    rect.width = usr_w*10/ratio;
+                    rect.height = usr_h*10/ratio;
+                }                
+            } else {
+                if (mf.height > usr_h) {
+                    ratio = MIN((mf.width*10/usr_w),(mf.height*10/usr_h))-1;
+                    rect.width = usr_w*ratio/10;
+                    rect.height = usr_h*ratio/10;                     
+                } else {
+                    ratio = MAX((usr_w*10/mf.width),(usr_h*10/mf.height))+1;
+                    rect.width = usr_w*10/ratio;
+                    rect.height = usr_h*10/ratio;
+                }
+            }
+        }
+
+        rect.left = (mf.width - rect.width)/2;
+        rect.top = (mf.height - rect.height)/2;
 
         down(&pcdev->zoominfo.sem);        
         pcdev->zoominfo.a.c.width = rect.width*100/pcdev->zoominfo.zoom_rate;
                pcdev->zoominfo.a.c.width &= ~0x03;
                pcdev->zoominfo.a.c.height = rect.height*100/pcdev->zoominfo.zoom_rate;
                pcdev->zoominfo.a.c.height &= ~0x03;
-               pcdev->zoominfo.a.c.left = ((rect.width - pcdev->zoominfo.a.c.width)>>1)&(~0x01);
-               pcdev->zoominfo.a.c.top = ((rect.height - pcdev->zoominfo.a.c.height)>>1)&(~0x01);
+               pcdev->zoominfo.a.c.left = ((rect.width - pcdev->zoominfo.a.c.width)/2 + rect.left)&(~0x01);
+               pcdev->zoominfo.a.c.top = ((rect.height - pcdev->zoominfo.a.c.height)/2 + rect.top)&(~0x01);
         up(&pcdev->zoominfo.sem);
 
         /* ddl@rock-chips.com: IPP work limit check */
@@ -1332,17 +1651,27 @@ static int rk29_camera_set_fmt(struct soc_camera_device *icd,
             }
         }
         
-        RK29CAMERA_DG("%s..%s icd width:%d  host width:%d (zoom: %dx%d@(%d,%d)->%dx%d)\n",__FUNCTION__,xlate->host_fmt->name,
-                                  rect.width, pix->width, pcdev->zoominfo.a.c.width,pcdev->zoominfo.a.c.height, pcdev->zoominfo.a.c.left,pcdev->zoominfo.a.c.top,
+        /* ddl@rock-chips.com: Crop is doing by IPP, not by VIP in rk2918 */
+        rect.left = 0;
+        rect.top = 0;
+        rect.width = mf.width;
+        rect.height = mf.height;
+        
+        RK29CAMERA_DG("%s..%s Sensor output:%dx%d  VIP output:%dx%d (zoom: %dx%d@(%d,%d)->%dx%d)\n",__FUNCTION__,xlate->host_fmt->name,
+                                  mf.width, mf.height,rect.width,rect.height, pcdev->zoominfo.a.c.width,pcdev->zoominfo.a.c.height, pcdev->zoominfo.a.c.left,pcdev->zoominfo.a.c.top,
                                   pix->width, pix->height);
+
+                
         rk29_camera_setup_format(icd, pix->pixelformat, mf.code, &rect); 
         
                if (CAM_IPPWORK_IS_EN()) {
                        BUG_ON(pcdev->vipmem_phybase == 0);
                }
+        pcdev->icd_width = icd_width;
+        pcdev->icd_height = icd_height;
 
-        pix->width = mf.width;
-       pix->height = mf.height;
+        pix->width = usr_w;
+       pix->height = usr_h;
        pix->field = mf.field;
        pix->colorspace = mf.colorspace;
        icd->current_fmt = xlate;        
@@ -1352,7 +1681,7 @@ RK29_CAMERA_SET_FMT_END:
     if (stream_on & ENABLE_CAPTURE)
         write_vip_reg(RK29_VIP_CTRL, (read_vip_reg(RK29_VIP_CTRL) | ENABLE_CAPTURE));
        if (ret)
-       RK29CAMERA_TR("\n%s..%d.. ret = %d  \n",__FUNCTION__,__LINE__, ret);
+       RK29CAMERA_TR("\n%s: Driver isn't support %dx%d resolution which user request!\n",__FUNCTION__,usr_w,usr_h);
     return ret;
 }
 static bool rk29_camera_fmt_capturechk(struct v4l2_format *f)
@@ -1388,7 +1717,8 @@ static int rk29_camera_try_fmt(struct soc_camera_device *icd,
        bool is_capture = rk29_camera_fmt_capturechk(f);
        bool vipmem_is_overflow = false;
     struct v4l2_mbus_framefmt mf;
-
+    int bytes_per_line_host;
+    
        usr_w = pix->width;
        usr_h = pix->height;
        RK29CAMERA_DG("%s enter width:%d  height:%d\n",__FUNCTION__,usr_w,usr_h);
@@ -1429,13 +1759,14 @@ static int rk29_camera_try_fmt(struct soc_camera_device *icd,
                goto RK29_CAMERA_TRY_FMT_END;
     RK29CAMERA_DG("%s mf.width:%d  mf.height:%d\n",__FUNCTION__,mf.width,mf.height);
        #ifdef CONFIG_VIDEO_RK29_WORK_IPP       
-       if ((mf.width > usr_w) && (mf.height > usr_h)) {
+       if ((mf.width != usr_w) || (mf.height != usr_h)) {
+        bytes_per_line_host = soc_mbus_bytes_per_line(mf.width,icd->current_fmt->host_fmt); 
                if (is_capture) {
-                       vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height) > pcdev->vipmem_size);
+                       vipmem_is_overflow = (PAGE_ALIGN(bytes_per_line_host*mf.height) > pcdev->vipmem_size);
                } else {
                        /* Assume preview buffer minimum is 4 */
-                       vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height)*4 > pcdev->vipmem_size);
-               }
+                       vipmem_is_overflow = (PAGE_ALIGN(bytes_per_line_host*mf.height)*4 > pcdev->vipmem_size);
+               }        
                if (vipmem_is_overflow == false) {
                        pix->width = usr_w;
                        pix->height = usr_h;
@@ -1444,26 +1775,14 @@ static int rk29_camera_try_fmt(struct soc_camera_device *icd,
             pix->width = mf.width;
             pix->height = mf.height;            
                }
-       } else if ((mf.width < usr_w) && (mf.height < usr_h)) {
-               if (((usr_w>>1) < mf.width) && ((usr_h>>1) < mf.height)) {
-                       if (is_capture) {
-                               vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height) > pcdev->vipmem_size);
-                       } else {
-                               vipmem_is_overflow = (PAGE_ALIGN(pix->bytesperline*pix->height)*4 > pcdev->vipmem_size);
-                       }
-                       if (vipmem_is_overflow == false) {
-                               pix->width = usr_w;
-                               pix->height = usr_h;
-                       } else {
-                               RK29CAMERA_TR("vipmem for IPP is overflow, This resolution(%dx%d -> %dx%d) is invalidate!\n",mf.width,mf.height,usr_w,usr_h);
+        
+        if ((mf.width < usr_w) || (mf.height < usr_h)) {
+            if (((usr_w>>1) > mf.width) || ((usr_h>>1) > mf.height)) {
+                RK29CAMERA_TR("The aspect ratio(%dx%d/%dx%d) is bigger than 2 !\n",mf.width,mf.height,usr_w,usr_h);
                 pix->width = mf.width;
                 pix->height = mf.height;
-                       }
-               } else {
-                       RK29CAMERA_TR("The aspect ratio(%dx%d/%dx%d) is bigger than 2 !\n",mf.width,mf.height,usr_w,usr_h);
-            pix->width = mf.width;
-            pix->height = mf.height;
-               }
+            }
+        }        
        }
        #else
     pix->width = mf.width;
@@ -1472,15 +1791,15 @@ static int rk29_camera_try_fmt(struct soc_camera_device *icd,
     pix->colorspace    = mf.colorspace;    
 
     switch (mf.field) {
-       case V4L2_FIELD_ANY:
-       case V4L2_FIELD_NONE:
-               pix->field      = V4L2_FIELD_NONE;
-               break;
-       default:
-               /* TODO: support interlaced at least in pass-through mode */
-               dev_err(icd->dev.parent, "Field type %d unsupported.\n",
-                       mf.field);
-               goto RK29_CAMERA_TRY_FMT_END;
+       case V4L2_FIELD_ANY:
+       case V4L2_FIELD_NONE:
+               pix->field      = V4L2_FIELD_NONE;
+               break;
+       default:
+               /* TODO: support interlaced at least in pass-through mode */
+               dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+                       mf.field);
+               goto RK29_CAMERA_TRY_FMT_END;
        }
 
 RK29_CAMERA_TRY_FMT_END:
@@ -1530,14 +1849,27 @@ static int rk29_camera_querycap(struct soc_camera_host *ici,
 {
     struct rk29_camera_dev *pcdev = ici->priv;
     char orientation[5];
+    int i;
+
+    strlcpy(cap->card, dev_name(pcdev->icd->pdev), sizeof(cap->card));
 
-    strlcpy(cap->card, dev_name(pcdev->icd->pdev), sizeof(cap->card));    
-    if (strcmp(dev_name(pcdev->icd->pdev), pcdev->pdata->gpio_res[0].dev_name) == 0) {
-        sprintf(orientation,"-%d",pcdev->pdata->gpio_res[0].orientation);
+    memset(orientation,0x00,sizeof(orientation));
+    for (i=0; i<RK29_CAM_SUPPORT_NUMS;i++) {
+        if ((pcdev->pdata->info[i].dev_name!=NULL) && (strcmp(dev_name(pcdev->icd->pdev), pcdev->pdata->info[i].dev_name) == 0)) {
+            sprintf(orientation,"-%d",pcdev->pdata->info[i].orientation);
+        }
+    }
+    
+    if (orientation[0] != '-') {
+        RK29CAMERA_TR("%s: %s is not registered in rk29_camera_platform_data, orientation apply default value",__FUNCTION__,dev_name(pcdev->icd->pdev));
+        if (strstr(dev_name(pcdev->icd->pdev),"front")) 
+            strcat(cap->card,"-270");
+        else 
+            strcat(cap->card,"-90");
     } else {
-        sprintf(orientation,"-%d",pcdev->pdata->gpio_res[1].orientation);
+        strcat(cap->card,orientation); 
     }
-    strcat(cap->card,orientation); 
+    
     cap->version = RK29_CAM_VERSION_CODE;
     cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
 
@@ -1632,6 +1964,7 @@ static void rk29_camera_reinit_work(struct work_struct *work)
 
        control = to_soc_camera_control(rk29_camdev_info_ptr->icd);
        sd = dev_get_drvdata(control);
+    v4l2_subdev_call(sd, video, s_stream, 0);  /* ddl@rock-chips.com: Avoid sensor autofocus thread is running */
        ret = v4l2_subdev_call(sd,core, init, 1);
 
        mf.width = rk29_camdev_info_ptr->icd->user_width;
@@ -1640,7 +1973,7 @@ static void rk29_camera_reinit_work(struct work_struct *work)
        mf.code = xlate->code;
 
        ret |= v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
-
+    v4l2_subdev_call(sd, video, s_stream, 1);
        write_vip_reg(RK29_VIP_CTRL, (read_vip_reg(RK29_VIP_CTRL)|ENABLE_CAPTURE));
 
        RK29CAMERA_TR("Camera host haven't recevie data from sensor,Reinit sensor now! ret:0x%x\n",ret);
@@ -1676,22 +2009,17 @@ static enum hrtimer_restart rk29_camera_fps_func(struct hrtimer *timer)
                 && (fival_nxt->fival.height == rk29_camdev_info_ptr->icd->user_height)
                 && (fival_nxt->fival.width == rk29_camdev_info_ptr->icd->user_width))
                 || (fival_nxt->fival.discrete.denominator == 0)) {
-
-                if (fival_nxt->fival.discrete.denominator == 0) {
-                    fival_nxt->fival.index = 0;
-                    fival_nxt->fival.width = rk29_camdev_info_ptr->icd->user_width;
-                    fival_nxt->fival.height= rk29_camdev_info_ptr->icd->user_height;
-                    fival_nxt->fival.pixel_format = rk29_camdev_info_ptr->pixfmt;
-                    fival_nxt->fival.discrete.denominator = rk29_camdev_info_ptr->fps+2;
-                    fival_nxt->fival.discrete.numerator = 1;
-                    fival_nxt->fival.type = V4L2_FRMIVAL_TYPE_DISCRETE;
-                } else {                
-                    if (abs(rk29_camdev_info_ptr->fps + 2 - fival_nxt->fival.discrete.numerator) > 2) {
-                        fival_nxt->fival.discrete.denominator = rk29_camdev_info_ptr->fps+2;
-                        fival_nxt->fival.discrete.numerator = 1;
-                        fival_nxt->fival.type = V4L2_FRMIVAL_TYPE_DISCRETE;
-                    }
-                }
+                
+                fival_nxt->fival.index = 0;
+                fival_nxt->fival.width = rk29_camdev_info_ptr->icd->user_width;
+                fival_nxt->fival.height= rk29_camdev_info_ptr->icd->user_height;
+                fival_nxt->fival.pixel_format = rk29_camdev_info_ptr->pixfmt;
+                fival_nxt->fival.discrete.denominator = rk29_camdev_info_ptr->frame_interval;                
+                fival_nxt->fival.reserved[1] = (rk29_camdev_info_ptr->icd_width<<16)
+                                                    |(rk29_camdev_info_ptr->icd_height);
+                fival_nxt->fival.discrete.numerator = 1000000;
+                fival_nxt->fival.type = V4L2_FRMIVAL_TYPE_DISCRETE;
+                
                 rec_flag = 1;
                 fival_rec = fival_nxt;
             }
@@ -1707,8 +2035,12 @@ static enum hrtimer_restart rk29_camera_fps_func(struct hrtimer *timer)
                 fival_pre->nxt->fival.height= rk29_camdev_info_ptr->icd->user_height;
                 fival_pre->nxt->fival.pixel_format = rk29_camdev_info_ptr->pixfmt;
 
-                fival_pre->nxt->fival.discrete.denominator = rk29_camdev_info_ptr->fps+2;
-                fival_pre->nxt->fival.discrete.numerator = 1;
+                fival_pre->nxt->fival.discrete.denominator = rk29_camdev_info_ptr->frame_interval;
+                
+                fival_pre->nxt->fival.reserved[1] = (rk29_camdev_info_ptr->icd_width<<16)
+                                                    |(rk29_camdev_info_ptr->icd_height);
+                
+                fival_pre->nxt->fival.discrete.numerator = 1000000;
                 fival_pre->nxt->fival.type = V4L2_FRMIVAL_TYPE_DISCRETE;
                 rec_flag = 1;
                 fival_rec = fival_pre->nxt;
@@ -1726,7 +2058,7 @@ static int rk29_camera_s_stream(struct soc_camera_device *icd, int enable)
        int ret;
 
        WARN_ON(pcdev->icd != icd);
-
+    pcdev->frame_interval = 0;
        vip_ctrl_val = read_vip_reg(RK29_VIP_CTRL);
        if (enable) {
                pcdev->fps = 0;
@@ -1749,37 +2081,90 @@ int rk29_camera_enum_frameintervals(struct soc_camera_device *icd, struct v4l2_f
     struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
     struct rk29_camera_dev *pcdev = ici->priv;
     struct rk29_camera_frmivalenum *fival_list = NULL;
-    int i,ret = 0;
+    struct v4l2_frmivalenum *fival_head=NULL;
+    int i,ret = 0,index;
     
-    for (i=0; i<2; i++) {
-        if (pcdev->icd_frmival[i].icd == icd) {
-            fival_list = pcdev->icd_frmival[i].fival_list;            
+    index = fival->index & 0x00ffffff;
+    if ((fival->index & 0xff000000) == 0xff000000) {   /* ddl@rock-chips.com: detect framerate */ 
+        for (i=0; i<2; i++) {
+            if (pcdev->icd_frmival[i].icd == icd) {
+                fival_list = pcdev->icd_frmival[i].fival_list;            
+            }
         }
-    }
-    
-    if (fival_list != NULL) {
+        
+        if (fival_list != NULL) {
+            i = 0;
+            while (fival_list != NULL) {
+                if ((fival->pixel_format == fival_list->fival.pixel_format)
+                    && (fival->height == fival_list->fival.height) 
+                    && (fival->width == fival_list->fival.width)) {
+                    if (i == index)
+                        break;
+                    i++;
+                }                
+                fival_list = fival_list->nxt;                
+            }
+            
+            if ((i==index) && (fival_list != NULL)) {
+                memcpy(fival, &fival_list->fival, sizeof(struct v4l2_frmivalenum));
+            } else {
+                ret = -EINVAL;
+            }
+        } else {
+            RK29CAMERA_TR("%s: fival_list is NULL\n",__FUNCTION__);
+            ret = -EINVAL;
+        }
+    } else {  
+
+        for (i=0; i<RK29_CAM_SUPPORT_NUMS; i++) {
+            if (pcdev->pdata->info[i].dev_name && (strcmp(dev_name(pcdev->icd->pdev),pcdev->pdata->info[i].dev_name) == 0)) {
+                fival_head = pcdev->pdata->info[i].fival;
+            }
+        }
+        
+        if (fival_head == NULL) {
+            RK29CAMERA_TR("%s: %s is not registered in rk29_camera_platform_data!!",__FUNCTION__,dev_name(pcdev->icd->pdev));
+            ret = -EINVAL;
+            goto rk29_camera_enum_frameintervals_end;
+        }
+        
         i = 0;
-        while (fival_list != NULL) {
-            if ((fival->pixel_format == fival_list->fival.pixel_format)
-                && (fival->height == fival_list->fival.height) 
-                && (fival->width == fival_list->fival.width)) {
-                if (i == fival->index)
+        while (fival_head->width && fival_head->height) {
+            if ((fival->pixel_format == fival_head->pixel_format)
+                && (fival->height == fival_head->height) 
+                && (fival->width == fival_head->width)) {
+                if (i == index) {
                     break;
+                }
                 i++;
-            }                
-            fival_list = fival_list->nxt;                
+            }
+            fival_head++;  
         }
-        
-        if ((i==fival->index) && (fival_list != NULL)) {
-            memcpy(fival, &fival_list->fival, sizeof(struct v4l2_frmivalenum));
+
+        if ((i == index) && (fival->height == fival_head->height) && (fival->width == fival_head->width)) {
+            memcpy(fival, fival_head, sizeof(struct v4l2_frmivalenum));
+            RK29CAMERA_DG("%s %dx%d@%c%c%c%c framerate : %d/%d\n", dev_name(rk29_camdev_info_ptr->icd->pdev),
+                fival->width, fival->height,
+                fival->pixel_format & 0xFF, (fival->pixel_format >> 8) & 0xFF,
+                           (fival->pixel_format >> 16) & 0xFF, (fival->pixel_format >> 24),
+                            fival->discrete.denominator,fival->discrete.numerator);                        
         } else {
+            if (index == 0)
+                RK29CAMERA_TR("%s have not catch %dx%d@%c%c%c%c index(%d) framerate\n",dev_name(rk29_camdev_info_ptr->icd->pdev),
+                    fival->width,fival->height, 
+                    fival->pixel_format & 0xFF, (fival->pixel_format >> 8) & 0xFF,
+                           (fival->pixel_format >> 16) & 0xFF, (fival->pixel_format >> 24),
+                           index);
+            else
+                RK29CAMERA_DG("%s have not catch %dx%d@%c%c%c%c index(%d) framerate\n",dev_name(rk29_camdev_info_ptr->icd->pdev),
+                    fival->width,fival->height, 
+                    fival->pixel_format & 0xFF, (fival->pixel_format >> 8) & 0xFF,
+                           (fival->pixel_format >> 16) & 0xFF, (fival->pixel_format >> 24),
+                           index);
             ret = -EINVAL;
         }
-    } else {
-        RK29CAMERA_TR("%s: fival_list is NULL\n",__FUNCTION__);
-        ret = -EINVAL;
     }
-
+rk29_camera_enum_frameintervals_end:
     return ret;
 }
 
@@ -1900,7 +2285,9 @@ static int rk29_camera_probe(struct platform_device *pdev)
     int irq,i;
     int err = 0;
 
-    RK29CAMERA_DG("%s..%s..%d  \n",__FUNCTION__,__FILE__,__LINE__);
+    RK29CAMERA_TR("RK29 Camera driver version: v%d.%d.%d  Zoom by %s\n",(RK29_CAM_VERSION_CODE&0xff0000)>>16,
+        (RK29_CAM_VERSION_CODE&0xff00)>>8,RK29_CAM_VERSION_CODE&0xff,CAMERA_SCALE_CROP_MACHINE);
+    
     res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
     irq = platform_get_irq(pdev, 0);
     if (!res || irq < 0) {
@@ -1962,15 +2349,30 @@ static int rk29_camera_probe(struct platform_device *pdev)
        if (pcdev->pdata && (strcmp(pcdev->pdata->meminfo.name,"camera_ipp_mem")==0)) {
                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;
+        } 
+               
                RK29CAMERA_DG("\n%s Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size);
        } else {
                RK29CAMERA_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);
+    INIT_LIST_HEAD(&pcdev->camera_work_queue);
     spin_lock_init(&pcdev->lock);
+    spin_lock_init(&pcdev->camera_work_lock);
     sema_init(&pcdev->zoominfo.sem,1);
 
     /*
@@ -2026,6 +2428,11 @@ static int rk29_camera_probe(struct platform_device *pdev)
        pcdev->fps_timer.function = rk29_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 = rk29_camera_scale_crop_ipp;
+#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM)
+    pcdev->icd_cb.scale_crop_cb = rk29_camera_scale_crop_arm;
+#endif
     RK29CAMERA_DG("%s..%s..%d  \n",__FUNCTION__,__FILE__,__LINE__);
     return 0;
 
@@ -2050,6 +2457,10 @@ exit_reqirq:
     iounmap(pcdev->base);
 exit_ioremap:
     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:
     if (pcdev->aclk_ddr_lcdc) {
                clk_put(pcdev->aclk_ddr_lcdc);
@@ -2120,6 +2531,9 @@ static int __devexit rk29_camera_remove(struct platform_device *pdev)
 
     soc_camera_host_unregister(&pcdev->soc_host);
 
+    iounmap((void __iomem*)pcdev->vipmem_phybase);
+    release_mem_region(pcdev->vipmem_phybase, pcdev->vipmem_size);
+
     res = pcdev->res;
     release_mem_region(res->start, res->end - res->start + 1);
 
@@ -2162,3 +2576,4 @@ module_exit(rk29_camera_exit);
 MODULE_DESCRIPTION("RK29 Soc Camera Host driver");
 MODULE_AUTHOR("ddl <ddl@rock-chips>");
 MODULE_LICENSE("GPL");
+#endif