rk29-ipp: add deinterlace support & fix bugs
authorchenli <chenli@rockchip.com>
Thu, 19 May 2011 11:44:40 +0000 (19:44 +0800)
committerchenli <chenli@rockchip.com>
Thu, 19 May 2011 11:58:34 +0000 (19:58 +0800)
1.Add deinterlace support
2.Check input parameters in ipp_do_blit()
3.Enable or disable all clocks need by IPP in ipp_do_blit() for power saving
4.Sovle the problem of scheduling timeout

arch/arm/mach-rk29/include/mach/rk29-ipp.h [changed mode: 0644->0755]
drivers/staging/rk29/ipp/rk29-ipp.c

old mode 100644 (file)
new mode 100755 (executable)
index ebbc888..f94dc57
@@ -20,6 +20,15 @@ struct rk29_ipp_req {
        uint32_t dst_vir_w;\r
        uint32_t timeout;\r
        uint32_t flag; //rotate\r
+       \r
+       //chenli 0506\r
+       //deinterlace_enable 1:enable 0:disable\r
+       uint8_t deinterlace_enable;\r
+       //the sum of three paras should be 32,and single para should be less than 32\r
+       uint8_t deinterlace_para0;\r
+       uint8_t deinterlace_para1;\r
+       uint8_t deinterlace_para2;\r
+               \r
 };\r
 \r
 //uint32_t format Ã¶¾ÙÀàÐÍ\r
index 5fc6247cc6d1b1a65b13f4a40862f4437a8bee1d..0cd992df0149c18e89b39b363c8d4d1612c10ff4 100755 (executable)
 #include <linux/syscalls.h>\r
 #include <linux/timer.h>\r
 #include <mach/rk29-ipp.h>\r
+#include <linux/time.h>\r
 \r
+//#define IPP_TEST\r
+#ifdef IPP_TEST\r
+#include <asm/cacheflush.h>\r
+struct delayed_work d_work;\r
+\r
+static struct timeval hw_set;\r
+static struct timeval irq_ret;\r
+static struct timeval irq_done;\r
+static struct timeval wait_done;\r
+#endif\r
 \r
 struct ipp_drvdata {\r
        struct miscdevice miscdev;\r
@@ -47,15 +58,24 @@ struct ipp_drvdata {
        void *ipp_base;\r
        struct ipp_regs regs;\r
        int irq0;\r
+\r
+       struct clk *pd_display;\r
+       struct clk *aclk_lcdc;\r
+       struct clk *hclk_lcdc;\r
+       struct clk *aclk_ddr_lcdc;\r
+       struct clk *hclk_cpu_display;\r
+       struct clk *aclk_disp_matrix;\r
+       struct clk *hclk_disp_matrix;\r
        struct clk *axi_clk;\r
        struct clk *ahb_clk;\r
+       \r
        struct mutex    mutex;  // mutex\r
 };\r
 \r
 static struct ipp_drvdata *drvdata = NULL;\r
 \r
 static DECLARE_WAIT_QUEUE_HEAD(wait_queue);\r
-static int wq_condition = 0;\r
+static volatile int wq_condition = 0;\r
 \r
 /* Context data (unique) */\r
 struct ipp_context\r
@@ -79,9 +99,11 @@ struct ipp_context
 #define DRIVER_DESC            "RK29 IPP Device Driver"\r
 #define DRIVER_NAME            "rk29-ipp"\r
 \r
+\r
+\r
 /* Logging */\r
 #define IPP_DEBUG 0\r
-#ifdef IPP_DEBUG\r
+#if IPP_DEBUG\r
 #define DBG(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args)\r
 #define ERR(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args)\r
 #define WARNING(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args)\r
@@ -93,6 +115,11 @@ struct ipp_context
 #define INFO(format, args...)\r
 #endif\r
 \r
+\r
+\r
+\r
+\r
+\r
 static inline void ipp_write( uint32_t b, uint32_t r)\r
 {\r
        __raw_writel(b, drvdata->ipp_base + r);\r
@@ -128,19 +155,64 @@ int ipp_do_blit(struct rk29_ipp_req *req)
        uint32_t rotate;\r
        uint32_t pre_scale      = 0;\r
        uint32_t post_scale = 0;\r
-       uint32_t pre_scale_w, pre_scale_h;\r
+       uint32_t pre_scale_w, pre_scale_h;//pre_scale para\r
        uint32_t post_scale_w = 0x1000;\r
        uint32_t post_scale_h = 0x1000;\r
-       uint32_t pre_scale_target_w=0, pre_scale_target_h=0;\r
-       uint32_t post_scale_target_w, post_scale_target_h;\r
+       uint32_t pre_scale_output_w=0, pre_scale_output_h=0;//pre_scaleµÄÊä³ö¿í¸ß\r
+       uint32_t post_scale_input_w, post_scale_input_h;//post_scaleµÄÊäÈë¿í¸ß\r
        uint32_t dst0_YrgbMst=0,dst0_CbrMst=0;\r
        uint32_t ret = 0;\r
+       uint32_t deinterlace_config = 0;\r
+       int wait_ret;\r
 \r
+       mutex_lock(&drvdata->mutex);\r
+       \r
        if (drvdata == NULL) {                  /* ddl@rock-chips.com : check driver is normal or not */\r
-               printk(KERN_ERR, "%s drvdata is NULL, IPP driver probe is fail!!\n", __FUNCTION__);\r
+               //printk(KERN_ERR, "%s drvdata is NULL, IPP driver probe is fail!!\n", __FUNCTION__);\r
+               printk("%s drvdata is NULL, IPP driver probe is fail!!\n", __FUNCTION__);\r
                return -EPERM;\r
        }\r
 \r
+\r
+       /*IPP can support up to 8191*8191 resolution in RGB format,but we limit the image size to 8190*8190 here*/\r
+       //check src width and height\r
+       if (unlikely((req->src0.w <16) || (req->src0.w > 8190) || (req->src0.h < 16) || (req->src0.h > 8190))) {\r
+               ERR("invalid source resolution\n");\r
+               ret = -EINVAL;\r
+               goto erorr_input;\r
+       }\r
+\r
+       //check dst width and height\r
+       if (unlikely((req->dst0.w <16) || (req->dst0.w > 2047) || (req->dst0.h < 16) || (req->dst0.h > 2047))) {\r
+               ERR("invalid destination resolution\n");\r
+               ret = -EINVAL;\r
+               goto erorr_input;\r
+       }\r
+\r
+       //check src address\r
+       if (unlikely(req->src0.YrgbMst== 0) )\r
+       {\r
+               ERR("could not retrieve src image from memory\n");\r
+               ret = -EINVAL;\r
+               goto erorr_input;\r
+       }\r
+\r
+       //check src address\r
+       if (unlikely(req->dst0.YrgbMst== 0) )\r
+       {\r
+               ERR("could not retrieve dst image from memory\n");\r
+               ret = -EINVAL;\r
+               goto erorr_input;\r
+       }\r
+       //check rotate degree\r
+       if(req->flag >= IPP_ROT_LIMIT)\r
+       {\r
+           ERR("rk29_ipp is not surpport rot degree!!!!\n");\r
+               ret =  -EINVAL;\r
+               goto erorr_input;\r
+       }\r
+\r
+       \r
        rotate = req->flag;\r
        switch (rotate) {\r
        case IPP_ROT_90:\r
@@ -329,6 +401,84 @@ int ipp_do_blit(struct rk29_ipp_req *req)
                break;\r
        }\r
 \r
+       //enable clk\r
+       if(drvdata->pd_display)\r
+       {\r
+               clk_enable(drvdata->pd_display);\r
+       }\r
+       else\r
+       {\r
+               printk("pd_display is null \n");\r
+               ret =  -EINVAL;\r
+               goto error_pd_display;\r
+       }\r
+       \r
+       if(drvdata->aclk_lcdc)\r
+       {\r
+               clk_enable(drvdata->aclk_lcdc);\r
+       }\r
+       else\r
+       {\r
+               printk("aclk_lcdc is null \n");\r
+               ret =  -EINVAL;\r
+               goto error_aclk_lcdc;\r
+       }\r
+\r
+       if(drvdata->hclk_lcdc)\r
+       {\r
+               clk_enable(drvdata->hclk_lcdc);\r
+       }\r
+       else\r
+       {\r
+               printk("hclk_lcdc is null \n");\r
+               ret =  -EINVAL;\r
+               goto error_hclk_lcdc;\r
+       }\r
+\r
+       if(drvdata->aclk_ddr_lcdc)\r
+       {\r
+               clk_enable(drvdata->aclk_ddr_lcdc);\r
+       }\r
+       else\r
+       {\r
+               printk("aclk_ddr_lcdc is null \n");\r
+               ret =  -EINVAL;\r
+               goto error_aclk_ddr_lcdc;\r
+       }\r
+       \r
+       if(drvdata->hclk_cpu_display)\r
+       {\r
+               clk_enable(drvdata->hclk_cpu_display);\r
+       }\r
+       else\r
+       {\r
+               printk("hclk_cpu_display is null \n");\r
+               ret =  -EINVAL;\r
+               goto error_hclk_cpu_display;\r
+       }\r
+       \r
+       if(drvdata->aclk_disp_matrix)\r
+       {\r
+               clk_enable(drvdata->aclk_disp_matrix);\r
+       }\r
+       else\r
+       {\r
+               printk("aclk_disp_matrix is null \n");\r
+               ret =  -EINVAL;\r
+               goto error_aclk_disp_matrix;\r
+       }\r
+\r
+       if(drvdata->hclk_disp_matrix)\r
+       {\r
+               clk_enable(drvdata->hclk_disp_matrix);\r
+       }\r
+       else\r
+       {\r
+               printk("hclk_disp_matrix is null \n");\r
+               ret =  -EINVAL;\r
+               goto error_hclk_disp_matrix;\r
+       }\r
+       \r
        if(drvdata->axi_clk)\r
        {\r
                clk_enable(drvdata->axi_clk);\r
@@ -350,6 +500,15 @@ int ipp_do_blit(struct rk29_ipp_req *req)
                ret = -EINVAL;\r
                goto error_ahb_clk;\r
        }\r
+       //enable clk end\r
+\r
+       //check if IPP is idle\r
+       if(((ipp_read(IPP_INT)>>6)&0x3) !=0)// idle\r
+       {\r
+               printk("IPP staus is not idle,can noe set register\n");\r
+               goto error_status;\r
+       }\r
+\r
 \r
        /* Configure source image */\r
        DBG("src YrgbMst 0x%x , CbrMst0x%x,  %dx%d, fmt = %d\n", req->src0.YrgbMst,req->src0.CbrMst,\r
@@ -373,6 +532,7 @@ int ipp_do_blit(struct rk29_ipp_req *req)
        {\r
                ipp_write(dst0_CbrMst, IPP_DST0_CBR_MST);\r
        }\r
+\r
        ipp_write(req->dst0.h<<16|req->dst0.w, IPP_DST_IMG_INFO);\r
 \r
        /*Configure Pre_scale*/\r
@@ -408,30 +568,6 @@ int ipp_do_blit(struct rk29_ipp_req *req)
                        }\r
 \r
                        DBG("!!!!!pre_scale_h %d,pre_scale_w %d \n",pre_scale_h,pre_scale_w);\r
-\r
-                       ipp_write((ipp_read(IPP_CONFIG)&0xffffffef)|PRE_SCALE, IPP_CONFIG);             //enable pre_scale\r
-                       ipp_write((pre_scale_h-1)<<3|(pre_scale_w-1),IPP_PRE_SCL_PARA);\r
-\r
-                       if((req->src0.w%pre_scale_w)!=0) //ÏòÉÏÈ¡Õû ceil\r
-                       {\r
-                               pre_scale_target_w = req->src0.w/pre_scale_w+1;\r
-                       }\r
-                       else\r
-                       {\r
-                               pre_scale_target_w = req->src0.w/pre_scale_w;\r
-                       }\r
-\r
-                       if((req->src0.h%pre_scale_h)!=0)//ÏòÉÏÈ¡Õû ceil\r
-                       {\r
-                               pre_scale_target_h  = req->src0.h/pre_scale_h +1;\r
-                       }\r
-                       else\r
-                       {\r
-                               pre_scale_target_h = req->src0.h/pre_scale_h;\r
-                       }\r
-\r
-                       ipp_write(((pre_scale_target_h)<<16)|(pre_scale_target_w), IPP_PRE_IMG_INFO);\r
-\r
                }\r
                else//0 180 x ,y\r
                {\r
@@ -453,31 +589,56 @@ int ipp_do_blit(struct rk29_ipp_req *req)
                        {\r
                                pre_scale_h = 1;\r
                        }\r
-\r
                        DBG("!!!!!pre_scale_h %d,pre_scale_w %d \n",pre_scale_h,pre_scale_w);\r
+               }\r
 \r
-                       ipp_write((ipp_read(IPP_CONFIG)&0xffffffef)|PRE_SCALE, IPP_CONFIG);             //enable pre_scale\r
-                       ipp_write((pre_scale_h-1)<<3|(pre_scale_w-1),IPP_PRE_SCL_PARA);\r
-\r
-                       if((req->src0.w%pre_scale_w)!=0) //ÏòÉÏÈ¡Õû ceil\r
+               //pre_scale only support 1/2 to 1/8 time\r
+               if(pre_scale_w > 8)\r
+               {\r
+                       if(pre_scale_w < 16)\r
                        {\r
-                               pre_scale_target_w = req->src0.w/pre_scale_w+1;\r
+                               pre_scale_w = 8;\r
                        }\r
                        else\r
                        {\r
-                               pre_scale_target_w = req->src0.w/pre_scale_w;\r
+                               printk("invalid pre_scale operation! pre_scale_w should not be more than 8!\n");\r
+                               goto error_scale;\r
                        }\r
-\r
-                       if((req->src0.h%pre_scale_h)!=0)//ÏòÉÏÈ¡Õû ceil\r
+               }\r
+               if(pre_scale_h > 8)\r
+               {\r
+                       if(pre_scale_h < 16)\r
                        {\r
-                               pre_scale_target_h  = req->src0.h/pre_scale_h +1;\r
+                               pre_scale_h = 8;\r
                        }\r
                        else\r
                        {\r
-                               pre_scale_target_h = req->src0.h/pre_scale_h;\r
+                               printk("invalid pre_scale operation! pre_scale_h should not be more than 8!\n");\r
+                               goto error_scale;\r
                        }\r
                }\r
-               ipp_write(((pre_scale_target_h)<<16)|(pre_scale_target_w), IPP_PRE_IMG_INFO);\r
+                       \r
+               if((req->src0.w%pre_scale_w)!=0) //ÏòÉÏÈ¡Õû ceil\r
+               {\r
+                       pre_scale_output_w = req->src0.w/pre_scale_w+1;\r
+               }\r
+               else\r
+               {\r
+                       pre_scale_output_w = req->src0.w/pre_scale_w;\r
+               }\r
+\r
+               if((req->src0.h%pre_scale_h)!=0)//ÏòÉÏÈ¡Õû ceil\r
+               {\r
+                       pre_scale_output_h  = req->src0.h/pre_scale_h +1;\r
+               }\r
+               else\r
+               {\r
+                       pre_scale_output_h = req->src0.h/pre_scale_h;\r
+               }\r
+                       \r
+               ipp_write((ipp_read(IPP_CONFIG)&0xffffffef)|PRE_SCALE, IPP_CONFIG);             //enable pre_scale\r
+               ipp_write((pre_scale_h-1)<<3|(pre_scale_w-1),IPP_PRE_SCL_PARA);\r
+               ipp_write(((pre_scale_output_h)<<16)|(pre_scale_output_w), IPP_PRE_IMG_INFO);\r
 \r
        }\r
        else//no pre_scale\r
@@ -490,7 +651,9 @@ int ipp_do_blit(struct rk29_ipp_req *req)
        if((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate))\r
        {\r
                if (( (req->src0.h%req->dst0.w)!=0)||( (req->src0.w%req->dst0.h)!= 0)//СÊý±¶ËõС\r
-                       ||(req->dst0.w > req->src0.h) ||(req->dst0.h > req->src0.w))\r
+                       ||((req->src0.h/req->dst0.w)>8)||((req->src0.h%req->dst0.w)>8)   //ËõСϵÊý´óÓÚ8\r
+                       ||(req->dst0.w > req->src0.h)  ||(req->dst0.h > req->src0.w))    //·Å´ó\r
+                                                       \r
                {\r
                        post_scale = 1;\r
                }\r
@@ -502,7 +665,8 @@ int ipp_do_blit(struct rk29_ipp_req *req)
        else  //0 180 x-flip y-flip\r
        {\r
                if (( (req->src0.w%req->dst0.w)!=0)||( (req->src0.h%req->dst0.h)!= 0)//СÊý±¶ËõС\r
-                       ||(req->dst0.w > req->src0.w) ||(req->dst0.h > req->src0.h))\r
+                   ||((req->src0.w/req->dst0.w)>8)||((req->src0.h%req->dst0.h)>8)       //ËõСϵÊý´óÓÚ8\r
+                       ||(req->dst0.w > req->src0.w)  ||(req->dst0.h > req->src0.h))    //·Å´ó\r
                {\r
                        post_scale = 1;\r
                }\r
@@ -514,74 +678,104 @@ int ipp_do_blit(struct rk29_ipp_req *req)
 \r
        if(post_scale)\r
        {\r
+               if(pre_scale)\r
+               {\r
+                       post_scale_input_w = pre_scale_output_w;\r
+                       post_scale_input_h = pre_scale_output_h;\r
+               }\r
+               else\r
+               {\r
+                       post_scale_input_w = req->src0.w;\r
+                       post_scale_input_h = req->src0.h;\r
+               }\r
+                       \r
                if((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate))\r
                {\r
-                       if(pre_scale)\r
-                       {\r
-                               post_scale_target_w = pre_scale_target_w;\r
-                               post_scale_target_h = pre_scale_target_h;\r
-                       }\r
-                       else\r
-                       {\r
-                               post_scale_target_w = req->src0.w;\r
-                               post_scale_target_h = req->src0.h;\r
-                       }\r
-\r
-                       DBG("post_scale_target_w %d ,post_scale_target_h %d !!!\n",post_scale_target_w,post_scale_target_h);\r
+                       DBG("post_scale_input_w %d ,post_scale_input_h %d !!!\n",post_scale_input_w,post_scale_input_h);\r
 \r
                        switch(req->src0.fmt)\r
                        {\r
                        case IPP_XRGB_8888:\r
                        case IPP_RGB_565:\r
                        case IPP_Y_CBCR_H1V1:\r
-                                post_scale_w = (uint32_t)(4096*(post_scale_target_w-1)/(req->dst0.h-1));\r
+                               //In horiaontial scale case, the factor must be minus 1 if the result of the factor is integer\r
+                                if(((4096*(post_scale_input_w-1))%(req->dst0.h-1))==0)\r
+                                {\r
+                                       post_scale_w = (uint32_t)(4096*(post_scale_input_w-1)/(req->dst0.h-1))-1;\r
+                                }\r
+                                else\r
+                                {\r
+                                        post_scale_w = (uint32_t)(4096*(post_scale_input_w-1)/(req->dst0.h-1));\r
+                                }\r
                     break;\r
 \r
                        case IPP_Y_CBCR_H2V1:\r
                        case IPP_Y_CBCR_H2V2:\r
-                                post_scale_w = (uint32_t)(4096*(post_scale_target_w/2-1)/(req->dst0.h/2-1));\r
+                               //In horiaontial scale case, the factor must be minus 1 if the result of the factor is integer\r
+                                if(((4096*(post_scale_input_w/2-1))%(req->dst0.h/2-1))==0)\r
+                                {\r
+                                       post_scale_w = (uint32_t)(4096*(post_scale_input_w/2-1)/(req->dst0.h/2-1))-1;\r
+                                }\r
+                                else\r
+                                {\r
+                                        post_scale_w = (uint32_t)(4096*(post_scale_input_w/2-1)/(req->dst0.h/2-1));\r
+                                }\r
                         break;\r
 \r
                        default:\r
                                break;\r
                }\r
-                       post_scale_h = (uint32_t)(4096*(post_scale_target_h -1)/(req->dst0.w-1));\r
+                       post_scale_h = (uint32_t)(4096*(post_scale_input_h -1)/(req->dst0.w-1));\r
 \r
                        DBG("1111 post_scale_w %x,post_scale_h %x!!! \n",post_scale_w,post_scale_h);\r
                }\r
                else// 0 180 x-flip y-flip\r
                {\r
-\r
-                       if(pre_scale)\r
-                       {\r
-                               post_scale_target_w = pre_scale_target_w;\r
-                               post_scale_target_h = pre_scale_target_h;\r
-                       }\r
-                       else\r
-                       {\r
-                               post_scale_target_w = req->src0.w;\r
-                               post_scale_target_h = req->src0.h;\r
-                       }\r
-\r
                        switch(req->src0.fmt)\r
                        {\r
                        case IPP_XRGB_8888:\r
                        case IPP_RGB_565:\r
                        case IPP_Y_CBCR_H1V1:\r
-                                post_scale_w = (uint32_t)(4096*(post_scale_target_w-1)/(req->dst0.w-1));\r
+                               //In horiaontial scale case, the factor must be minus 1 if the result of the factor is integer\r
+                                if(((4096*(post_scale_input_w-1))%(req->dst0.w-1))==0)\r
+                                {\r
+                                       post_scale_w = (uint32_t)(4096*(post_scale_input_w-1)/(req->dst0.w-1))-1;\r
+                                }\r
+                                else\r
+                                {\r
+                                        post_scale_w = (uint32_t)(4096*(post_scale_input_w-1)/(req->dst0.w-1));\r
+                                }\r
                     break;\r
 \r
                        case IPP_Y_CBCR_H2V1:\r
                        case IPP_Y_CBCR_H2V2:\r
-                                post_scale_w = (uint32_t)(4096*(post_scale_target_w/2-1)/(req->dst0.w/2-1));\r
+                               ////In horiaontial scale case, the factor must be minus 1 if the result of the factor is integer\r
+                                if(((4096*(post_scale_input_w/2-1))%(req->dst0.w/2-1))==0)\r
+                                {\r
+                                       post_scale_w = (uint32_t)(4096*(post_scale_input_w/2-1)/(req->dst0.w/2-1))-1;\r
+                                }\r
+                                else\r
+                                {\r
+                                        post_scale_w = (uint32_t)(4096*(post_scale_input_w/2-1)/(req->dst0.w/2-1));\r
+                                }\r
                         break;\r
 \r
                        default:\r
                                break;\r
                }\r
-                       post_scale_h = (uint32_t)(4096*(post_scale_target_h -1)/(req->dst0.h-1));\r
+                       post_scale_h = (uint32_t)(4096*(post_scale_input_h -1)/(req->dst0.h-1));\r
 \r
                }\r
+\r
+               if(!((req->src0.fmt != IPP_Y_CBCR_H2V1)&&(req->src0.w == 176)&&(req->src0.h == 144)&&(req->dst0.w == 480)&&(req->src0.h == 800)))\r
+               {       \r
+                       //only support 1/2 to 4 times scaling,but 176*144->480*800 can pass\r
+                       if(post_scale_w<0x3ff || post_scale_w>0x1fff || post_scale_h<0x400 || post_scale_h>0x2000 )\r
+                       {\r
+                               printk("invalid post_scale para!\n");\r
+                               goto error_scale;\r
+                       }\r
+               }\r
                ipp_write((ipp_read(IPP_CONFIG)&0xfffffff7)|POST_SCALE, IPP_CONFIG); //enable post_scale\r
                ipp_write((post_scale_h<<16)|post_scale_w, IPP_POST_SCL_PARA);\r
        }\r
@@ -598,18 +792,43 @@ int ipp_do_blit(struct rk29_ipp_req *req)
        {\r
                ipp_write(ipp_read(IPP_CONFIG)&(~ROT_ENABLE), IPP_CONFIG);\r
        }\r
-       else if(req->flag > IPP_ROT_LIMIT)\r
-       {\r
-           printk("rk29_ipp is not surpport rot degree!!!!\n");\r
-               ret = -1;\r
-               goto error_rot_limit;\r
-       }\r
        else\r
        {\r
                ipp_write(ipp_read(IPP_CONFIG)|ROT_ENABLE, IPP_CONFIG);\r
                ipp_write(ipp_read(IPP_CONFIG)|rotate<<5, IPP_CONFIG);\r
        }\r
 \r
+       /*Configure deinterlace*/\r
+       if(req->deinterlace_enable == 1)\r
+       {\r
+               //only support YUV format\r
+               if(IS_YCRCB(req->src0.fmt))\r
+               {\r
+                       //If pre_scale is enable, Deinterlace is done by scale filter\r
+                       if(!pre_scale)\r
+                       {\r
+                               //check the deinterlace parameters\r
+                               if((req->deinterlace_para0 < 32) && (req->deinterlace_para1 < 32) && (req->deinterlace_para2 < 32) \r
+                                       && ((req->deinterlace_para0 + req->deinterlace_para1 + req->deinterlace_para2) == 32))\r
+                               {\r
+                                       deinterlace_config = (req->deinterlace_enable<<24) | (req->deinterlace_para0<<19) | (req->deinterlace_para1<<14) | (req->deinterlace_para2<<9);\r
+                                       DBG("para0 %d, para1 %d, para2 %d,deinterlace_config  %x\n",req->deinterlace_para0,req->deinterlace_para1,req->deinterlace_para2,deinterlace_config);\r
+                                       ipp_write((ipp_read(IPP_CONFIG)&0xFE0001FF)|deinterlace_config, IPP_CONFIG);\r
+\r
+                                       printk("IPP_CONFIG2 = 0x%x\n",ipp_read(IPP_CONFIG));\r
+                               }\r
+                               else\r
+                               {\r
+                                       ERR("invalid deinterlace parameters!\n");\r
+                               }\r
+                       }\r
+               }\r
+               else\r
+               {\r
+                       ERR("only support YUV format!\n");\r
+               }\r
+       }\r
+\r
        /*Configure other*/\r
        ipp_write((req->dst_vir_w<<16)|req->src_vir_w, IPP_IMG_VIR);\r
 \r
@@ -622,11 +841,68 @@ int ipp_do_blit(struct rk29_ipp_req *req)
 \r
        //msleep(5000);//debug use\r
 \r
+       wq_condition = 0;\r
+       dsb();\r
+#ifdef IPP_TEST\r
+       memset(&hw_set,0,sizeof(struct timeval));\r
+       memset(&irq_ret,0,sizeof(struct timeval));\r
+       memset(&irq_done,0,sizeof(struct timeval));\r
+       memset(&wait_done,0,sizeof(struct timeval));\r
+       do_gettimeofday(&hw_set);\r
+#endif\r
+\r
        ipp_write(1, IPP_PROCESS_ST);\r
+       //Important!Without msleep,ipp driver may occupy too much CPU,this can lead the ipp interrupt to timeout\r
+       msleep(1);\r
+\r
+       wait_ret = wait_event_interruptible_timeout(wait_queue, wq_condition, msecs_to_jiffies(req->timeout));\r
+\r
+#ifdef IPP_TEST\r
+       do_gettimeofday(&wait_done);\r
+       if ((((irq_ret.tv_sec - hw_set.tv_sec) * 1000 + (irq_ret.tv_usec - hw_set.tv_usec) / 1000) > 10) ||\r
+               (((wait_done.tv_sec - irq_done.tv_sec) * 1000 + (wait_done.tv_usec - irq_done.tv_usec) / 1000) > 10)) {\r
+               printk("hw time: %8d irq time %8d\n",\r
+                       ((irq_ret.tv_sec - hw_set.tv_sec) * 1000 + (irq_ret.tv_usec - hw_set.tv_usec) / 1000),\r
+                       ((wait_done.tv_sec - irq_done.tv_sec) * 1000 + (wait_done.tv_usec - irq_done.tv_usec) / 1000));\r
+       }\r
+#endif\r
+       \r
 \r
-       if(!wait_event_timeout(wait_queue, wq_condition, msecs_to_jiffies(req->timeout)))\r
+       if (wait_ret <= 0)\r
        {\r
                printk("%s wait_event_timeout \n",__FUNCTION__);\r
+\r
+#ifdef IPP_TEST\r
+               //print all register's value\r
+               printk("wait_ret: %d\n", wait_ret);\r
+               printk("wq_condition: %d\n", wq_condition);\r
+               printk("IPP_CONFIG: %x\n",ipp_read(IPP_CONFIG));\r
+               printk("IPP_SRC_IMG_INFO: %x\n",ipp_read(IPP_SRC_IMG_INFO));\r
+               printk("IPP_DST_IMG_INFO: %x\n",ipp_read(IPP_DST_IMG_INFO));\r
+               printk("IPP_IMG_VIR: %x\n",ipp_read(IPP_IMG_VIR));\r
+               printk("IPP_INT: %x\n",ipp_read(IPP_INT));\r
+               printk("IPP_SRC0_Y_MST: %x\n",ipp_read(IPP_SRC0_Y_MST));\r
+               printk("IPP_SRC0_CBR_MST: %x\n",ipp_read(IPP_SRC0_CBR_MST));\r
+               printk("IPP_SRC1_Y_MST: %x\n",ipp_read(IPP_SRC1_Y_MST));\r
+               printk("IPP_SRC1_CBR_MST: %x\n",ipp_read(IPP_SRC1_CBR_MST));\r
+               printk("IPP_DST0_Y_MST: %x\n",ipp_read(IPP_DST0_Y_MST));\r
+               printk("IPP_DST0_CBR_MST: %x\n",ipp_read(IPP_DST0_CBR_MST));\r
+               printk("IPP_DST1_Y_MST: %x\n",ipp_read(IPP_DST1_Y_MST));\r
+               printk("IPP_DST1_CBR_MST: %x\n",ipp_read(IPP_DST1_CBR_MST));\r
+               printk("IPP_PRE_SCL_PARA: %x\n",ipp_read(IPP_PRE_SCL_PARA));\r
+               printk("IPP_POST_SCL_PARA: %x\n",ipp_read(IPP_POST_SCL_PARA));\r
+               printk("IPP_SWAP_CTRL: %x\n",ipp_read(IPP_SWAP_CTRL));\r
+               printk("IPP_PRE_IMG_INFO: %x\n",ipp_read(IPP_PRE_IMG_INFO));\r
+               printk("IPP_AXI_ID: %x\n",ipp_read(IPP_AXI_ID));\r
+               printk("IPP_SRESET: %x\n",ipp_read(IPP_SRESET));\r
+               printk("IPP_PROCESS_ST: %x\n",ipp_read(IPP_PROCESS_ST));\r
+\r
+               while(1)\r
+               {\r
+\r
+               }\r
+#endif\r
+               \r
                wq_condition = 0;\r
                if(!drvdata)\r
                {\r
@@ -635,10 +911,9 @@ int ipp_do_blit(struct rk29_ipp_req *req)
                        goto error_null;\r
            }\r
                ret =  -EAGAIN;\r
-               goto errot_timeout;\r
+               goto error_timeout;\r
        }\r
 \r
-       wq_condition = 0;\r
 \r
        if(!drvdata)\r
        {\r
@@ -649,24 +924,42 @@ int ipp_do_blit(struct rk29_ipp_req *req)
 \r
        if(((ipp_read(IPP_INT)>>6)&0x3) ==0)// idle\r
        {\r
-               clk_disable(drvdata->axi_clk);\r
-               clk_disable(drvdata->ahb_clk);\r
+               goto error_noerror;\r
        }\r
        else\r
        {\r
                printk("rk29 ipp status is error!!!\n");\r
                ret =  -EINVAL;\r
-               goto errot_timeout;\r
+               goto error_timeout;\r
        }\r
-       return 0;\r
-\r
+       \r
+error_status:\r
+error_scale:\r
 error_null:\r
-errot_timeout:\r
-error_rot_limit:\r
-error_ahb_clk:\r
+error_timeout:\r
+       //soft rest\r
+       ipp_soft_reset();\r
+error_noerror:\r
        clk_disable(drvdata->ahb_clk);\r
-error_axi_clk:\r
+error_ahb_clk:\r
        clk_disable(drvdata->axi_clk);\r
+error_axi_clk: \r
+       clk_disable(drvdata->hclk_disp_matrix);\r
+error_hclk_disp_matrix:\r
+       clk_disable(drvdata->aclk_disp_matrix);\r
+error_aclk_disp_matrix:\r
+       clk_disable(drvdata->hclk_cpu_display);\r
+error_hclk_cpu_display:\r
+    clk_disable(drvdata->aclk_ddr_lcdc);\r
+error_aclk_ddr_lcdc:\r
+       clk_disable(drvdata->hclk_lcdc);\r
+error_hclk_lcdc:\r
+       clk_disable(drvdata->aclk_lcdc);\r
+error_aclk_lcdc:       \r
+       clk_disable(drvdata->pd_display);\r
+error_pd_display:\r
+erorr_input:\r
+       mutex_unlock(&drvdata->mutex);\r
        return ret;\r
 }\r
 \r
@@ -685,36 +978,9 @@ static int stretch_blit(struct ipp_context *ctx,  unsigned long arg )
                goto err_noput;\r
        }\r
 \r
-       if (unlikely((req.src0.w <= 1) || (req.src0.h <= 1))) {\r
-               ERR("invalid source resolution\n");\r
-               ret = -EINVAL;\r
-               goto err_noput;\r
-       }\r
-\r
-       if (unlikely((req.dst0.w <= 1) || (req.dst0.h <= 1))) {\r
-               ERR("invalid destination resolution\n");\r
-               ret = -EINVAL;\r
-               goto err_noput;\r
-       }\r
-\r
-       if (unlikely(req.src0.YrgbMst== 0) )\r
-       {\r
-               ERR("could not retrieve src image from memory\n");\r
-               ret = -EINVAL;\r
-               goto err_noput;\r
-       }\r
-\r
-       if (unlikely(req.dst0.YrgbMst== 0) )\r
-       {\r
-               ERR("could not retrieve dst image from memory\n");\r
-               ret = -EINVAL;\r
-               goto err_noput;\r
-       }\r
-\r
        ret = ipp_do_blit(&req);\r
        if(ret != 0) {\r
                ERR("Failed to start IPP operation (%d)\n", ret);\r
-               ipp_soft_reset();\r
                goto err_noput;\r
        }\r
 \r
@@ -775,20 +1041,21 @@ static int ipp_release(struct inode *inode, struct file *file)
 \r
 static irqreturn_t rk29_ipp_irq(int irq,  void *dev_id)\r
 {\r
-       uint32_t stat;\r
+#ifdef IPP_TEST\r
+       do_gettimeofday(&irq_ret);\r
+#endif\r
+       ipp_write(ipp_read(IPP_INT)|0x3c, IPP_INT);\r
 \r
        DBG("rk29_ipp_irq %d \n",irq);\r
-       stat = ipp_read(IPP_INT);\r
 \r
-       while(!(stat & 0x1))\r
-       {\r
-               DBG("stat %d \n",stat);\r
-       }\r
        wq_condition = 1;\r
-       wake_up(&wait_queue);\r
+       dsb();\r
+       \r
+#ifdef IPP_TEST\r
+       do_gettimeofday(&irq_done);\r
+#endif\r
+       wake_up_interruptible_sync(&wait_queue);\r
 \r
-       ipp_write(ipp_read(IPP_INT)|0xc, IPP_INT);\r
-       ipp_write(ipp_read(IPP_INT)|0x30, IPP_INT);\r
        return IRQ_HANDLED;\r
 }\r
 \r
@@ -805,11 +1072,205 @@ static struct miscdevice ipp_dev ={
     .fops  = &ipp_fops,\r
 };\r
 \r
+#ifdef IPP_TEST\r
+\r
+static void ipp_test_work_handler(struct work_struct *work)\r
+{\r
+\r
+                struct rk29_ipp_req ipp_req;\r
+         int i=0,j;\r
+                int ret = 0;\r
+\r
+                uint8_t *srcY ;\r
+                uint8_t *dstY;\r
+                uint8_t *srcUV ;\r
+                uint8_t *dstUV;\r
+                 uint32_t src_addr;\r
+                uint32_t dst_addr;\r
+                uint8_t *p;\r
+#if 0\r
+//test lzg's bug\r
+uint32_t size = 8*1024*1024;\r
+\r
+#define PMEM_VPU_BASE 0x76000000\r
+#define PMEM_VPU_SIZE  0x4000000\r
+       //      srcY = ioremap_cached(PMEM_VPU_BASE, PMEM_VPU_SIZE);\r
+\r
+\r
+       //      srcUV = srcY + size;\r
+       //      dstY = srcUV + size;\r
+       //      dstUV = dstY + size;\r
+               //src_addr = virt_to_phys(srcY);\r
+               //dst_addr = virt_to_phys(dstY);\r
+               src_addr = PMEM_VPU_BASE;\r
+               dst_addr = PMEM_VPU_BASE + size*2;\r
+               printk("src_addr: %x-%x, dst_addr: %x-%x\n",srcY,src_addr,dstY,dst_addr);\r
+\r
+               ipp_req.src0.YrgbMst = src_addr;\r
+               ipp_req.src0.CbrMst = src_addr + size;\r
+               ipp_req.src0.w = 2048;\r
+               ipp_req.src0.h = 1440;\r
+               ipp_req.src0.fmt = IPP_Y_CBCR_H2V2;\r
+               \r
+               ipp_req.dst0.YrgbMst = dst_addr;\r
+               ipp_req.dst0.CbrMst = dst_addr + size;\r
+               ipp_req.dst0.w = 2048;\r
+               ipp_req.dst0.h = 1440;\r
+       \r
+               ipp_req.src_vir_w = 2048;\r
+               ipp_req.dst_vir_w = 2048;\r
+               ipp_req.timeout = 500;\r
+               ipp_req.flag = IPP_ROT_0;\r
+               \r
+               ret = ipp_do_blit(&ipp_req);\r
+#undef PMEM_VPU_BASE\r
+#undef PMEM_VPU_SIZE\r
+\r
+#endif\r
+\r
+//test zyc's bug                \r
+\r
+               uint32_t size = 800*480;\r
+               srcY = (uint32_t)__get_free_pages(GFP_KERNEL, 9); //320*240*2*2bytes=300k < 128 pages\r
+               srcUV = srcY + size;\r
+               dstY = srcUV + size;\r
+               dstUV = dstY + size;\r
+               src_addr = virt_to_phys(srcY);\r
+               dst_addr = virt_to_phys(dstY);\r
+               printk("src_addr: %x-%x, dst_addr: %x-%x\n",srcY,srcUV,dstY,dstUV);\r
+\r
+               \r
+               ipp_req.src0.YrgbMst = src_addr;\r
+               ipp_req.src0.CbrMst = src_addr + size;\r
+               ipp_req.src0.w = 800;\r
+               ipp_req.src0.h = 480;\r
+               ipp_req.src0.fmt = IPP_Y_CBCR_H2V2;\r
+               \r
+               ipp_req.dst0.YrgbMst = dst_addr;\r
+               ipp_req.dst0.CbrMst = dst_addr + size;\r
+               ipp_req.dst0.w = 800;\r
+               ipp_req.dst0.h = 480;\r
+       \r
+               ipp_req.src_vir_w = 800;\r
+               ipp_req.dst_vir_w = 800;\r
+               ipp_req.timeout = 50;\r
+               ipp_req.flag = IPP_ROT_0;\r
+\r
+               \r
+               while(!ret)\r
+               {\r
+                       ipp_req.timeout = 50;\r
+                       ret = ipp_do_blit(&ipp_req);\r
+               }\r
+               \r
+               free_pages(srcY, 9);\r
+\r
+\r
+//test deinterlace\r
+#if 0\r
+               uint32_t size = 16*16;\r
+               srcY = (uint32_t*)kmalloc(size*2*2,GFP_KERNEL);\r
+               memset(srcY,0,size*2*2);\r
+               srcUV = srcY + size;\r
+               dstY = srcY + size*2;\r
+               dstUV = dstY + size;\r
+               src_addr = virt_to_phys(srcY);\r
+               dst_addr = virt_to_phys(dstY);\r
+               printk("src_addr: %x-%x, dst_addr: %x-%x\n",srcY,srcUV,dstY,dstUV);\r
+\r
+               //set srcY\r
+               p=srcY;\r
+               for(i=0;i<256; i++)\r
+               {\r
+                       *p++ = i;\r
+               }\r
+               \r
+               //set srcUV\r
+               p=srcUV;\r
+               for(i=0;i<128; i++)\r
+               {\r
+                       *p++ = 2*i;\r
+               }\r
+               \r
+               dmac_clean_range(srcY,srcY+size*2);\r
+               \r
+               ipp_req.src0.YrgbMst = src_addr;\r
+               ipp_req.src0.CbrMst = src_addr + size;\r
+               ipp_req.src0.w = 16;\r
+               ipp_req.src0.h = 16;\r
+               ipp_req.src0.fmt = IPP_Y_CBCR_H2V2;\r
+               \r
+               ipp_req.dst0.YrgbMst = dst_addr;\r
+               ipp_req.dst0.CbrMst = dst_addr + size;\r
+               ipp_req.dst0.w = 16;\r
+               ipp_req.dst0.h = 16;\r
+       \r
+               ipp_req.src_vir_w = 16;\r
+               ipp_req.dst_vir_w = 16;\r
+               ipp_req.timeout = 1000;\r
+               ipp_req.flag = IPP_ROT_0;\r
+\r
+               ipp_req.deinterlace_enable =1;\r
+               ipp_req.deinterlace_para0 = 16;\r
+               ipp_req.deinterlace_para1 = 16;\r
+               ipp_req.deinterlace_para2 = 0;\r
+               \r
+               ipp_do_blit(&ipp_req);\r
+\r
+               \r
+/*\r
+               for(i=0;i<8;i++)\r
+               {\r
+                       for(j=0;j<32;j++)\r
+                       {\r
+                               printk("%4x ",*(srcY+j+i*32));\r
+                       }\r
+                       printk("\n");\r
+               }\r
+\r
+               \r
+               printk("\n\n");\r
+               dmac_inv_range(dstY,dstY+size*2);\r
+               for(i=0;i<8;i++)\r
+               {\r
+                       for(j=0;j<32;j++)\r
+                       {\r
+                               printk("%4x ",*(dstY+j+i*32));\r
+                       }\r
+                       printk("\n");\r
+               }\r
+\r
+               printk("\n\n");\r
+               for(i=0;i<8;i++)\r
+               {\r
+                       for(j=0;j<16;j++)\r
+                       {\r
+                               printk("%4x ",*(srcUV+j+i*16));\r
+                       }\r
+                       printk("\n");\r
+               }\r
+               printk("\n\n");\r
+               for(i=0;i<8;i++)\r
+               {\r
+                       for(j=0;j<16;j++)\r
+                       {\r
+                               printk("%4x ",*(dstUV+j+i*16));\r
+                       }\r
+                       printk("\n");\r
+               }\r
+*/             \r
+               kfree(srcY);\r
+#endif\r
+\r
+}\r
+#endif\r
+\r
 static int __init ipp_drv_probe(struct platform_device *pdev)\r
 {\r
        struct ipp_drvdata *data;\r
        int ret = 0;\r
 \r
+\r
        data = kmalloc(sizeof(struct ipp_drvdata), GFP_KERNEL);\r
        if(NULL==data)\r
        {\r
@@ -818,6 +1279,62 @@ static int __init ipp_drv_probe(struct platform_device *pdev)
        }\r
 \r
        /* get the clock */\r
+       data->pd_display = clk_get(&pdev->dev, "pd_display");\r
+       if (IS_ERR(data->pd_display))\r
+       {\r
+               ERR("failed to find ipp pd_display source\n");\r
+               ret = -ENOENT;\r
+               goto err_clock;\r
+       }\r
+\r
+       data->aclk_lcdc = clk_get(&pdev->dev, "aclk_lcdc");\r
+       if (IS_ERR(data->aclk_lcdc))\r
+       {\r
+               ERR("failed to find ipp aclk_lcdc source\n");\r
+               ret = -ENOENT;\r
+               goto err_clock;\r
+       }\r
+       \r
+       data->hclk_lcdc = clk_get(&pdev->dev, "hclk_lcdc");\r
+       if (IS_ERR(data->hclk_lcdc))\r
+       {\r
+               ERR("failed to find ipp hclk_lcdc source\n");\r
+               ret = -ENOENT;\r
+               goto err_clock;\r
+       }\r
+\r
+       data->aclk_ddr_lcdc = clk_get(&pdev->dev, "aclk_ddr_lcdc");\r
+       if (IS_ERR(data->aclk_ddr_lcdc))\r
+       {\r
+               ERR("failed to find ipp aclk_ddr_lcdc source\n");\r
+               ret = -ENOENT;\r
+               goto err_clock;\r
+       }\r
+\r
+       data->hclk_cpu_display = clk_get(&pdev->dev, "hclk_cpu_display");\r
+       if (IS_ERR(data->hclk_cpu_display))\r
+       {\r
+               ERR("failed to find ipp hclk_cpu_display source\n");\r
+               ret = -ENOENT;\r
+               goto err_clock;\r
+       }\r
+\r
+       data->aclk_disp_matrix = clk_get(&pdev->dev, "aclk_disp_matrix");\r
+       if (IS_ERR(data->aclk_disp_matrix))\r
+       {\r
+               ERR("failed to find ipp aclk_disp_matrix source\n");\r
+               ret = -ENOENT;\r
+               goto err_clock;\r
+       }\r
+\r
+       data->hclk_disp_matrix = clk_get(&pdev->dev, "hclk_disp_matrix");\r
+       if (IS_ERR(data->hclk_disp_matrix))\r
+       {\r
+               ERR("failed to find ipp hclk_disp_matrix source\n");\r
+               ret = -ENOENT;\r
+               goto err_clock;\r
+       }\r
+       \r
        data->axi_clk = clk_get(&pdev->dev, "aclk_ipp");\r
        if (IS_ERR(data->axi_clk))\r
        {\r
@@ -835,7 +1352,7 @@ static int __init ipp_drv_probe(struct platform_device *pdev)
        }\r
 \r
        /* map the memory */\r
-       data->ipp_base = (void*)ioremap( RK29_IPP_PHYS, SZ_16K);//ipp size 16k\r
+       data->ipp_base = (void*)ioremap_nocache( RK29_IPP_PHYS, SZ_16K);//ipp size 16k\r
        if (data->ipp_base == NULL)\r
        {\r
                ERR("ioremap failed\n");\r
@@ -854,7 +1371,8 @@ static int __init ipp_drv_probe(struct platform_device *pdev)
        }\r
 \r
        /* request the IRQ */\r
-       ret = request_irq(data->irq0, rk29_ipp_irq, IRQF_SHARED, "rk29-ipp", pdev);\r
+       //ret = request_irq(data->irq0, rk29_ipp_irq, IRQF_SHARED, "rk29-ipp", pdev);\r
+       ret = request_irq(data->irq0, rk29_ipp_irq, 0/*IRQF_DISABLED*/, "rk29-ipp", pdev);\r
        if (ret)\r
        {\r
                ERR("request_irq failed (%d).\n", ret);\r
@@ -874,6 +1392,11 @@ static int __init ipp_drv_probe(struct platform_device *pdev)
        }\r
        DBG("Driver loaded succesfully\n");\r
 \r
+#ifdef IPP_TEST\r
+       INIT_DELAYED_WORK(&d_work, ipp_test_work_handler);\r
+       schedule_delayed_work(&d_work, msecs_to_jiffies(5000));\r
+#endif\r
+\r
        return 0;\r
 \r
 err_misc_register:\r
@@ -902,6 +1425,33 @@ static int ipp_drv_remove(struct platform_device *pdev)
        if(data->ahb_clk) {\r
                clk_put(data->ahb_clk);\r
        }\r
+       if(data->aclk_disp_matrix) {\r
+               clk_put(data->aclk_disp_matrix);\r
+       }\r
+\r
+       if(data->hclk_disp_matrix) {\r
+               clk_put(data->hclk_disp_matrix);\r
+       }\r
+       \r
+       if(data->aclk_ddr_lcdc) {\r
+               clk_put(data->aclk_ddr_lcdc);\r
+       }\r
+       \r
+       if(data->hclk_lcdc) {\r
+               clk_put(data->hclk_lcdc);\r
+       }\r
+\r
+       if(data->aclk_lcdc) {\r
+               clk_put(data->aclk_lcdc);\r
+       }\r
+       \r
+       if(data->hclk_cpu_display) {\r
+               clk_put(data->hclk_cpu_display);\r
+       }\r
+\r
+       if(data->pd_display){\r
+               clk_put(data->pd_display);\r
+       }\r
 \r
     kfree(data);\r
     return 0;\r