rk29 IPP:IPP driver provides synchronous and asynchronous call interfaces.
authorchenli <chenli@rockchip.com>
Tue, 28 Jun 2011 01:58:29 +0000 (09:58 +0800)
committerchenli <chenli@rockchip.com>
Tue, 28 Jun 2011 02:14:00 +0000 (10:14 +0800)
1.In case of synchronous call please use ipp_blit_sync function.
  In case of asynchronous call please use ipp_blit_async function.
  The old interface ipp_do_blit is not recommended from now on.
2.Use ipp_blit_sync instead of ipp_do_blit in rk29_fb.c

arch/arm/mach-rk29/include/mach/rk29-ipp.h
drivers/staging/rk29/ipp/rk29-ipp.c
drivers/video/rk29_fb.c

index f94dc57c2f065f1c0c10a4bee38261140ac2febb..2256576afbb6eb2bf154618bb38bee0fd2d4e917 100755 (executable)
@@ -1,6 +1,12 @@
 #ifndef _RK29_IPP_DRIVER_H_\r
 #define _RK29_IPP_DRIVER_H_\r
 \r
+\r
+#define IPP_BLIT_SYNC  0x5017\r
+#define IPP_BLIT_ASYNC  0x5018\r
+#define IPP_GET_RESULT  0x5019\r
+\r
+\r
 /* Image data */\r
 struct rk29_ipp_image\r
 {\r
@@ -28,6 +34,9 @@ struct rk29_ipp_req {
        uint8_t deinterlace_para0;\r
        uint8_t deinterlace_para1;\r
        uint8_t deinterlace_para2;\r
+       \r
+       /* completion is reported through a callback */\r
+       void                    (*complete)(int retval);\r
                \r
 };\r
 \r
@@ -76,31 +85,32 @@ typedef enum
 };\r
 \r
 #define IPP_CONFIG                             (0x00)\r
-#define IPP_SRC_IMG_INFO                       (0x04)\r
-#define IPP_DST_IMG_INFO                       (0x08)\r
+#define IPP_SRC_IMG_INFO               (0x04)\r
+#define IPP_DST_IMG_INFO               (0x08)\r
 #define IPP_IMG_VIR                            (0x0c)\r
 #define IPP_INT                                        (0x10)\r
 #define IPP_SRC0_Y_MST                 (0x14)\r
-#define IPP_SRC0_CBR_MST                       (0x18)\r
+#define IPP_SRC0_CBR_MST               (0x18)\r
 #define IPP_SRC1_Y_MST                 (0x1c)\r
-#define IPP_SRC1_CBR_MST                       (0x20)\r
+#define IPP_SRC1_CBR_MST               (0x20)\r
 #define IPP_DST0_Y_MST                 (0x24)\r
-#define IPP_DST0_CBR_MST                       (0x28)\r
+#define IPP_DST0_CBR_MST               (0x28)\r
 #define IPP_DST1_Y_MST                 (0x2c)\r
-#define IPP_DST1_CBR_MST                       (0x30)\r
-#define IPP_PRE_SCL_PARA                       (0x34)\r
-#define IPP_POST_SCL_PARA                      (0x38)\r
-#define IPP_SWAP_CTRL                          (0x3c)\r
-#define IPP_PRE_IMG_INFO                       (0x40)\r
+#define IPP_DST1_CBR_MST               (0x30)\r
+#define IPP_PRE_SCL_PARA               (0x34)\r
+#define IPP_POST_SCL_PARA              (0x38)\r
+#define IPP_SWAP_CTRL                  (0x3c)\r
+#define IPP_PRE_IMG_INFO               (0x40)\r
 #define IPP_AXI_ID                             (0x44)\r
 #define IPP_SRESET                             (0x48)\r
 #define IPP_PROCESS_ST                 (0x50)\r
 \r
 /*ipp config*/\r
 #define ROT_ENABLE                             (1<<8)\r
-#define PRE_SCALE                                      (1<<4)\r
+#define PRE_SCALE                              (1<<4)\r
 #define POST_SCALE                             (1<<3)\r
 \r
+#define IPP_BLIT_COMPLETE_EVENT BIT(1)\r
 \r
 #define IS_YCRCB(img) ((img == IPP_Y_CBCR_H2V1) | (img == IPP_Y_CBCR_H2V2) | \\r
                       (img == IPP_Y_CBCR_H1V1) )\r
@@ -109,4 +119,6 @@ typedef enum
 #define HAS_ALPHA(img) (img == IPP_ARGB_8888)\r
 \r
 int ipp_do_blit(struct rk29_ipp_req *req);\r
+int ipp_blit_async(const struct rk29_ipp_req *req);\r
+int ipp_blit_sync(const struct rk29_ipp_req *req);\r
 #endif /*_RK29_IPP_DRIVER_H_*/
\ No newline at end of file
index 0cd992df0149c18e89b39b363c8d4d1612c10ff4..4c2816cb0550e9696d257052d219f59a84499326 100755 (executable)
 #include <linux/timer.h>\r
 #include <mach/rk29-ipp.h>\r
 #include <linux/time.h>\r
+#include <asm/cacheflush.h>\r
 \r
 //#define IPP_TEST\r
 #ifdef IPP_TEST\r
-#include <asm/cacheflush.h>\r
-struct delayed_work d_work;\r
 \r
+struct delayed_work d_work;\r
+static DECLARE_WAIT_QUEUE_HEAD(test_queue);\r
+int test_condition;\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
+\r
+ktime_t hw_start; \r
+ktime_t hw_end;\r
+ktime_t irq_start; \r
+ktime_t irq_end;\r
+\r
 #endif\r
 \r
+\r
 struct ipp_drvdata {\r
        struct miscdevice miscdev;\r
        struct device dev;\r
-       void *ipp_base;\r
        struct ipp_regs regs;\r
+       void *ipp_base;\r
        int irq0;\r
 \r
        struct clk *pd_display;\r
@@ -70,14 +79,25 @@ struct ipp_drvdata {
        struct clk *ahb_clk;\r
        \r
        struct mutex    mutex;  // mutex\r
+       \r
+       struct delayed_work power_off_work;\r
+       wait_queue_head_t ipp_wait;                 //pollʱµÄµÈ´ý¶ÓÁÐ\r
+       atomic_t ipp_event;\r
+       bool issync;                                                    //ÊÇͬ²½µ÷Óû¹ÊÇÒì²½µ÷ÓÃ\r
+       bool enable;                                                    //IPPÊÇ·ñʹÄÜÁËclk\r
+       int ipp_result;                                                 //´æ·Åµ±Ç°IPP²Ù×÷µÄ½á¹û£¬0´ú±í³É¹¦\r
+       void (*ipp_irq_callback)(int ipp_retval);   //Òì²½µ÷ÓõĻص÷º¯Êý\r
 };\r
 \r
 static struct ipp_drvdata *drvdata = NULL;\r
 \r
-static DECLARE_WAIT_QUEUE_HEAD(wait_queue);\r
-static volatile int wq_condition = 0;\r
+static DECLARE_WAIT_QUEUE_HEAD(hw_wait_queue);\r
+static volatile int wq_condition = 1;                //ͬӲ¼þ½»»¥Ê±1£¬Í¬Ó²¼þ½»»¥Íê³É0\r
+static DECLARE_WAIT_QUEUE_HEAD(blit_wait_queue);     \r
+static volatile int idle_condition = 1;              //ÔÊÐíÖ´ÐÐÏÂÒ»¸öÇëÇó1£¬µ±Ç°ÇëÇóÕýÔÚÖ´ÐÐ0\r
 \r
 /* Context data (unique) */\r
+\r
 struct ipp_context\r
 {\r
        struct ipp_drvdata      *data;  // driver data\r
@@ -87,67 +107,875 @@ struct ipp_context
        struct file                     *dstf;  // destination file (for PMEM)\r
 };\r
 \r
-#define IPP_MAJOR              232\r
-#define RK_IPP_BLIT    0x5017\r
-#define RK_IPP_SYNC    0x5018\r
+#define IPP_MAJOR              232\r
+\r
+\r
+#define RK29_IPP_PHYS  0x10110000\r
+#define RK29_IPP_SIZE  SZ_16K\r
+#define IPP_RESET_TIMEOUT      1000\r
+\r
+/* Driver information */\r
+#define DRIVER_DESC            "RK29 IPP Device Driver"\r
+#define DRIVER_NAME            "rk29-ipp"\r
+\r
+\r
+\r
+/* Logging */\r
+#define IPP_DEBUG 0\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
+#define INFO(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args)\r
+#else\r
+#define DBG(format, args...)\r
+#define ERR(format, args...)\r
+#define WARNING(format, args...)\r
+#define INFO(format, args...)\r
+#endif\r
+\r
+\r
+static inline void ipp_write( uint32_t b, uint32_t r)\r
+{\r
+       __raw_writel(b, drvdata->ipp_base + r);\r
+}\r
+\r
+static inline uint32_t ipp_read( uint32_t r)\r
+{\r
+       return __raw_readl(drvdata->ipp_base + r);\r
+}\r
+\r
+static void ipp_soft_reset(void)\r
+{\r
+       uint32_t i;\r
+       uint32_t reg;\r
+\r
+       ipp_write(1, IPP_SRESET);\r
+\r
+       for(i = 0; i < IPP_RESET_TIMEOUT; i++) {\r
+               reg = ipp_read( IPP_SRESET) & 1;\r
+\r
+               if(reg == 0)\r
+                       break;\r
+\r
+               udelay(1);\r
+       }\r
+\r
+       if(i == IPP_RESET_TIMEOUT)\r
+               ERR("soft reset timeout.\n");\r
+}\r
+\r
+static void ipp_power_on(void)\r
+{\r
+       //printk("ipp_power_on\n");\r
+       cancel_delayed_work_sync(&drvdata->power_off_work);\r
+       if (drvdata->enable)\r
+               return;\r
+       clk_enable(drvdata->pd_display);\r
+       clk_enable(drvdata->aclk_lcdc);\r
+       clk_enable(drvdata->hclk_lcdc);\r
+       clk_enable(drvdata->aclk_ddr_lcdc);\r
+       clk_enable(drvdata->hclk_cpu_display);\r
+       clk_enable(drvdata->aclk_disp_matrix);\r
+       clk_enable(drvdata->hclk_disp_matrix);\r
+       clk_enable(drvdata->axi_clk);\r
+       clk_enable(drvdata->ahb_clk);\r
+\r
+       drvdata->enable = true;\r
+}\r
+\r
+\r
+static void ipp_power_off(struct work_struct *work)\r
+{\r
+       //printk("ipp_power_off\n");\r
+       if(!drvdata->enable)\r
+               return;\r
+       clk_disable(drvdata->pd_display);\r
+       clk_disable(drvdata->aclk_lcdc);\r
+       clk_disable(drvdata->hclk_lcdc);\r
+       clk_disable(drvdata->aclk_ddr_lcdc);\r
+       clk_disable(drvdata->hclk_cpu_display);\r
+       clk_disable(drvdata->aclk_disp_matrix);\r
+       clk_disable(drvdata->hclk_disp_matrix);\r
+       clk_disable(drvdata->axi_clk);\r
+       clk_disable(drvdata->ahb_clk);\r
+\r
+       drvdata->enable = false;\r
+}\r
+\r
+static unsigned int ipp_poll(struct file *filep, poll_table *wait)\r
+{\r
+       //printk("ipp_poll\n");\r
+       \r
+       poll_wait(filep, &drvdata->ipp_wait, wait);\r
+\r
+       if (atomic_read(&drvdata->ipp_event))\r
+       {\r
+               atomic_set(&drvdata->ipp_event, 0);\r
+               return POLLIN | POLLRDNORM;\r
+       }\r
+       return 0;\r
+}\r
+\r
+static void ipp_blit_complete(int retval)\r
+{\r
+\r
+       uint32_t event = IPP_BLIT_COMPLETE_EVENT;\r
+       //printk("ipp_blit_complete\n");\r
+\r
+       atomic_set(&drvdata->ipp_event, event);\r
+       wake_up_interruptible(&drvdata->ipp_wait);\r
+}\r
+\r
+static int ipp_get_result(unsigned long arg)\r
+{\r
+       //printk("ipp_get_result %d\n",drvdata->ipp_result);\r
+       int ret =0;\r
+       \r
+       if (unlikely(copy_to_user((void __user *)arg, &drvdata->ipp_result, sizeof(int)))) {\r
+                       printk("copy_to_user failed\n");\r
+                       ERR("copy_to_user failed\n");\r
+                       ret =  -EFAULT; \r
+               }\r
+       idle_condition = 1;\r
+       //dmac_clean_range((const void*)&idle_condition,(const void*)&idle_condition+4);\r
+       wake_up_interruptible_sync(&blit_wait_queue);\r
+       return ret;\r
+}\r
+\r
+int ipp_check_param(const struct rk29_ipp_req *req)\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
+               return  -EINVAL;\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
+               return  -EINVAL;\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
+               return  -EINVAL;\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
+               return  -EINVAL;\r
+       }\r
+       \r
+       //check rotate degree\r
+       if(req->flag >= IPP_ROT_LIMIT)\r
+       {\r
+               ERR("rk29_ipp is not surpport rot degree!!!!\n");\r
+               return  -EINVAL;\r
+       }\r
+       return 0;\r
+}\r
+\r
+int ipp_blit(const struct rk29_ipp_req *req)\r
+{\r
+       \r
+       uint32_t rotate;\r
+       uint32_t pre_scale      = 0;\r
+       uint32_t post_scale = 0;\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_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
+\r
+       //printk("ipp_blit\n");\r
+       if (drvdata == NULL) {                  /* ddl@rock-chips.com : check driver is normal or not */\r
+               printk("%s drvdata is NULL, IPP driver probe is fail!!\n", __FUNCTION__);\r
+               return -EPERM;\r
+       }\r
+\r
+       drvdata->ipp_result = -1;\r
+\r
+       //ͬ²½µÄÇé¿öÏÂreq->complete¶¼Ó¦¸ÃΪNULL£¬¶øÒì²½µÄÇé¿öÏÂÓû§Ì¬µ÷ÓõÄreq->completeҲΪNULL£¬ÄÚºË̬µ÷ÓõÄreq->completeÓ¦·Ç¿Õ\r
+       if(req->complete)\r
+       {\r
+               drvdata->ipp_irq_callback = req->complete;\r
+       }\r
+       else\r
+       {\r
+               drvdata->ipp_irq_callback = ipp_blit_complete;\r
+       }\r
+\r
+       ret = ipp_check_param(req);\r
+       if(ret ==  -EINVAL)\r
+       {\r
+               goto erorr_input;\r
+       }\r
+       \r
+       rotate = req->flag;\r
+       switch (rotate) {\r
+       case IPP_ROT_90:\r
+               //for rotation 90 degree\r
+               DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt);\r
+               switch(req->src0.fmt)\r
+               {\r
+               case IPP_XRGB_8888:\r
+                       dst0_YrgbMst  =  req->dst0.YrgbMst + req->dst0.w*4;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_RGB_565:\r
+                       dst0_YrgbMst  =  req->dst0.YrgbMst +  req->dst0.w*2;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H1V1:\r
+                       dst0_YrgbMst  =  req->dst0.YrgbMst + req->dst0.w;\r
+                       dst0_CbrMst   =  req->dst0.CbrMst + req->dst0.w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst + req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst + req->dst0.w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V2:\r
+                       dst0_YrgbMst = req->dst0.YrgbMst+ req->dst0.w;\r
+                       dst0_CbrMst  = req->dst0.CbrMst + req->dst0.w;\r
+                       break;\r
+\r
+               default:\r
+\r
+                       break;\r
+               }\r
+       break;\r
+\r
+       case IPP_ROT_180:\r
+               //for rotation 180 degree\r
+               DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt);\r
+               switch(req->src0.fmt)\r
+               {\r
+               case IPP_XRGB_8888:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*4+req->dst0.w*4;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_RGB_565:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*2+req->dst0.w*2;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H1V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2+req->dst0.w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V2:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+((req->dst0.h/2)-1)*req->dst_vir_w+req->dst0.w;\r
+                       break;\r
+\r
+               default:\r
+                       break;\r
+               }\r
+                       break;\r
+\r
+       case IPP_ROT_270:\r
+               DBG("rotate %d, src0.fmt %d \n",rotate,req->src0.fmt);\r
+               switch(req->src0.fmt)\r
+               {\r
+               case IPP_XRGB_8888:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*4;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_RGB_565:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst +(req->dst0.h-1)*req->dst_vir_w*2;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H1V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V2:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+((req->dst0.h/2)-1)*req->dst_vir_w;\r
+                       break;\r
+\r
+               default:\r
+                       break;\r
+               }\r
+               break;\r
+\r
+       case IPP_ROT_X_FLIP:\r
+               DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt);\r
+               switch(req->src0.fmt)\r
+               {\r
+               case IPP_XRGB_8888:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+req->dst0.w*4;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_RGB_565:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+req->dst0.w*2;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H1V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+req->dst0.w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+req->dst0.w;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V2:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+req->dst0.w;\r
+                       dst0_CbrMst  =  req->dst0.CbrMst+req->dst0.w;\r
+                       break;\r
+\r
+               default:\r
+                       break;\r
+               }\r
+\r
+       break;\r
+\r
+       case IPP_ROT_Y_FLIP:\r
+               DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt);\r
+               switch(req->src0.fmt)\r
+               {\r
+               case IPP_XRGB_8888:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*4;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_RGB_565:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w*2;\r
+                       dst0_CbrMst  = req->dst0.CbrMst;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H1V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst = req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w*2;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V1:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst = req->dst0.CbrMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       break;\r
+\r
+               case IPP_Y_CBCR_H2V2:\r
+                       dst0_YrgbMst =  req->dst0.YrgbMst+(req->dst0.h-1)*req->dst_vir_w;\r
+                       dst0_CbrMst = req->dst0.CbrMst+((req->dst0.h/2)-1)*req->dst_vir_w;\r
+                       break;\r
+\r
+       default:\r
+               break;\r
+       }\r
+\r
+       break;\r
+       case IPP_ROT_0:\r
+               //for  0 degree\r
+               DBG("rotate %d, src0.fmt %d",rotate,req->src0.fmt);\r
+               dst0_YrgbMst =  req->dst0.YrgbMst;\r
+               dst0_CbrMst  = req->dst0.CbrMst;\r
+       break;\r
+\r
+       default:\r
+               ERR("ipp is not surpport degree!!\n" );\r
+               break;\r
+       }\r
+       \r
+       //ÏÖÔÚ¿ªÊ¼Ó²¼þ¿ªÊ¼¹¤×÷\r
+       wq_condition = 0;\r
+\r
+       ipp_power_on();\r
+       \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 not 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
+                                       req->src0.w, req->src0.h, req->src0.fmt);\r
+\r
+       ipp_write(req->src0.YrgbMst, IPP_SRC0_Y_MST);\r
+       if(IS_YCRCB(req->src0.fmt))\r
+       {\r
+               ipp_write(req->src0.CbrMst, IPP_SRC0_CBR_MST);\r
+       }\r
+       ipp_write(req->src0.h<<16|req->src0.w, IPP_SRC_IMG_INFO);\r
+       ipp_write((ipp_read(IPP_CONFIG)&(~0x7))|req->src0.fmt, IPP_CONFIG);\r
+\r
+       /* Configure destination image */\r
+       DBG("dst YrgbMst 0x%x , CbrMst0x%x, %dx%d\n", dst0_YrgbMst,dst0_CbrMst,\r
+                                       req->dst0.w, req->dst0.h);\r
+\r
+       ipp_write(dst0_YrgbMst, IPP_DST0_Y_MST);\r
+\r
+       if(IS_YCRCB(req->src0.fmt))\r
+       {\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
+       if((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate))\r
+       {\r
+               pre_scale = ((req->dst0.w < req->src0.h) ? 1 : 0)||((req->dst0.h < req->src0.w) ? 1 : 0);\r
+       }\r
+       else //other degree\r
+       {\r
+               pre_scale = ((req->dst0.w < req->src0.w) ? 1 : 0)||((req->dst0.h < req->src0.h) ? 1 : 0);\r
+       }\r
+\r
+       if(pre_scale)\r
+       {\r
+               if(((IPP_ROT_90 == rotate) || (IPP_ROT_270 == rotate)))\r
+               {\r
+\r
+                       if((req->src0.w>req->dst0.h))\r
+                       {\r
+                               pre_scale_w = (uint32_t)( req->src0.w/req->dst0.h);//floor\r
+                       }\r
+                       else\r
+                       {\r
+                          pre_scale_w = 1;\r
+                       }\r
+                       if((req->src0.h>req->dst0.w))\r
+                       {\r
+                               pre_scale_h = (uint32_t)( req->src0.h/req->dst0.w);//floor\r
+                       }\r
+                       else\r
+                       {\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
+               else//0 180 x ,y\r
+               {\r
+\r
+                       if((req->src0.w>req->dst0.w))\r
+                       {\r
+                               pre_scale_w = (uint32_t)( req->src0.w/req->dst0.w);//floor\r
+                       }\r
+                       else\r
+                       {\r
+                          pre_scale_w = 1;\r
+                       }\r
+\r
+                       if((req->src0.h>req->dst0.h))\r
+                       {\r
+                               pre_scale_h = (uint32_t)( req->src0.h/req->dst0.h);//floor\r
+                       }\r
+                       else\r
+                       {\r
+                               pre_scale_h = 1;\r
+                       }\r
+                       DBG("!!!!!pre_scale_h %d,pre_scale_w %d \n",pre_scale_h,pre_scale_w);\r
+               }\r
+\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_w = 8;\r
+                       }\r
+                       else\r
+                       {\r
+                               printk("invalid pre_scale operation! pre_scale_w should not be more than 8!\n");\r
+                               goto error_scale;\r
+                       }\r
+               }\r
+               if(pre_scale_h > 8)\r
+               {\r
+                       if(pre_scale_h < 16)\r
+                       {\r
+                               pre_scale_h = 8;\r
+                       }\r
+                       else\r
+                       {\r
+                               printk("invalid pre_scale operation! pre_scale_h should not be more than 8!\n");\r
+                               goto error_scale;\r
+                       }\r
+               }\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
+       {\r
+               ipp_write(0,IPP_PRE_SCL_PARA);\r
+               ipp_write((req->src0.h<<16)|req->src0.w, IPP_PRE_IMG_INFO);\r
+       }\r
+\r
+       /*Configure Post_scale*/\r
+       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->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
+               else\r
+               {\r
+                       post_scale = 0;\r
+               }\r
+       }\r
+       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->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
+               else\r
+               {\r
+                       post_scale = 0;\r
+               }\r
+       }\r
+\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
+                       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
+                               //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
+                               //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_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
+                       switch(req->src0.fmt)\r
+                       {\r
+                       case IPP_XRGB_8888:\r
+                       case IPP_RGB_565:\r
+                       case IPP_Y_CBCR_H1V1:\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
+                               ////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_input_h -1)/(req->dst0.h-1));\r
 \r
-#define RK29_IPP_PHYS  0x10110000\r
-#define RK29_IPP_SIZE  SZ_16K\r
-#define IPP_RESET_TIMEOUT      1000\r
+               }\r
 \r
-/* Driver information */\r
-#define DRIVER_DESC            "RK29 IPP Device Driver"\r
-#define DRIVER_NAME            "rk29-ipp"\r
+               if(!((req->src0.fmt != IPP_Y_CBCR_H2V1)&&(req->src0.w == 176)&&(req->src0.h == 144)&&(req->dst0.w == 480)&&(req->dst0.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
+       else //no post_scale\r
+       {\r
+               DBG("no post_scale !!!!!! \n");\r
+               ipp_write(ipp_read(IPP_CONFIG)&(~POST_SCALE), IPP_CONFIG); //disable post_scale\r
+               ipp_write((post_scale_h<<16)|post_scale_w, IPP_POST_SCL_PARA);\r
+       }\r
 \r
+       /* Configure rotation */\r
 \r
+       if(IPP_ROT_0 == req->flag)\r
+       {\r
+               ipp_write(ipp_read(IPP_CONFIG)&(~ROT_ENABLE), IPP_CONFIG);\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
-/* Logging */\r
-#define IPP_DEBUG 0\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
-#define INFO(format, args...) printk(KERN_DEBUG "%s: " format, DRIVER_NAME, ## args)\r
-#else\r
-#define DBG(format, args...)\r
-#define ERR(format, args...)\r
-#define WARNING(format, args...)\r
-#define INFO(format, args...)\r
-#endif\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
+                                       //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
+       if((req->src0.w%4) !=0)\r
+       ipp_write(ipp_read(IPP_CONFIG)|(1<<26), IPP_CONFIG);//store clip mode\r
 \r
+       /* Start the operation */\r
+       ipp_write(8, IPP_INT);//\r
+       \r
+       dsb();\r
+       ipp_write(1, IPP_PROCESS_ST);\r
+       \r
+#ifdef IPP_TEST\r
+       hw_start = ktime_get(); \r
+#endif \r
 \r
+    goto error_noerror;\r
 \r
 \r
-static inline void ipp_write( uint32_t b, uint32_t r)\r
-{\r
-       __raw_writel(b, drvdata->ipp_base + r);\r
+error_status:\r
+error_scale:\r
+       ipp_soft_reset();\r
+       ipp_power_off(NULL);\r
+erorr_input:\r
+error_noerror:\r
+       drvdata->ipp_result = ret;\r
+       return ret;\r
 }\r
 \r
-static inline uint32_t ipp_read( uint32_t r)\r
+int ipp_blit_async(const struct rk29_ipp_req *req)\r
 {\r
-       return __raw_readl(drvdata->ipp_base + r);\r
+       int ret = -1;\r
+       //printk("ipp_blit_async *******************\n");\r
+       \r
+       //Èç¹û´ËʱIPPÔÚÖ´ÐÐÒ»¸öÇëÇ󣬵ȴýIPP¿ÕÏÐ\r
+       mutex_lock(&drvdata->mutex);\r
+       {\r
+               dmac_inv_range((const void*)&idle_condition,(const void*)&idle_condition+4);\r
+               //printk("idle_condition = %d\n",idle_condition);\r
+               wait_event_interruptible(blit_wait_queue, idle_condition);\r
+               idle_condition = 0;\r
+               dmac_clean_range((const void*)&idle_condition,(const void*)&idle_condition+4);\r
+       }\r
+       mutex_unlock(&drvdata->mutex);\r
+\r
+       drvdata->issync = false;        \r
+       ret = ipp_blit(req);\r
+       \r
+       //printk("ipp_blit_async done******************\n");\r
+       return ret;\r
 }\r
 \r
-static void ipp_soft_reset(void)\r
+int ipp_blit_sync(const struct rk29_ipp_req *req)\r
 {\r
-       uint32_t i;\r
-       uint32_t reg;\r
+       int status;\r
+       int wait_ret;\r
 \r
-       ipp_write(1, IPP_SRESET);\r
+       //printk("ipp_blit_sync -------------------\n");\r
 \r
-       for(i = 0; i < IPP_RESET_TIMEOUT; i++) {\r
-               reg = ipp_read( IPP_SRESET) & 1;\r
 \r
-               if(reg == 0)\r
-                       break;\r
+       //Èç¹û´ËʱIPPÔÚÖ´ÐÐÒ»¸öÇëÇ󣬵ȴýIPP¿ÕÏÐ\r
+       mutex_lock(&drvdata->mutex);\r
+       {\r
+               dmac_inv_range((const void*)&idle_condition,(const void*)&idle_condition+4);\r
+               //printk("idle_condition = %d\n",idle_condition);\r
+               wait_event_interruptible(blit_wait_queue, idle_condition);\r
+               idle_condition = 0;\r
+               dmac_clean_range((const void*)&idle_condition,(const void*)&idle_condition+4);\r
+       }\r
+       mutex_unlock(&drvdata->mutex);\r
 \r
-               udelay(1);\r
+       \r
+       drvdata->issync = true;\r
+       drvdata->ipp_result = ipp_blit(req);\r
+   \r
+       if(drvdata->ipp_result == 0)\r
+       {\r
+               wait_ret = wait_event_interruptible_timeout(hw_wait_queue, wq_condition, msecs_to_jiffies(req->timeout));\r
+#ifdef IPP_TEST\r
+               irq_end = ktime_get(); \r
+               irq_end = ktime_sub(irq_end,irq_start);\r
+               hw_end = ktime_sub(hw_end,hw_start);\r
+               if((((int)ktime_to_us(hw_end)/1000)>10)||(((int)ktime_to_us(irq_end)/1000)>10))\r
+               {\r
+                       printk("hw time: %d ms, irq time: %d ms\n",(int)ktime_to_us(hw_end)/1000,(int)ktime_to_us(irq_end)/1000);\r
+               }\r
+#endif                         \r
+               if (wait_ret <= 0)\r
+               {\r
+                       printk("%s wait_ret=%d,wait_event_timeout \n",__FUNCTION__,wait_ret);\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
+                       ipp_soft_reset();\r
+               }\r
+\r
+               ipp_power_off(NULL);\r
        }\r
+       drvdata->issync = false;\r
 \r
-       if(i == IPP_RESET_TIMEOUT)\r
-               ERR("soft reset timeout.\n");\r
+       //ͬ²½µ÷ÓÃÔÚ´ËÈÏΪIPPÒѾ­¿ÕÏУ¬»½Ðѵȴý¶ÓÁР    \r
+       //printk("ipp_blit_sync done ----------------\n");\r
+       status = drvdata->ipp_result;\r
+       idle_condition = 1;\r
+       wake_up_interruptible_sync(&blit_wait_queue);\r
+       \r
+       return status;\r
 }\r
 \r
 int ipp_do_blit(struct rk29_ipp_req *req)\r
@@ -767,7 +1595,7 @@ int ipp_do_blit(struct rk29_ipp_req *req)
 \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
+               if(!((req->src0.fmt != IPP_Y_CBCR_H2V1)&&(req->src0.w == 176)&&(req->src0.h == 144)&&(req->dst0.w == 480)&&(req->dst0.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
@@ -815,7 +1643,7 @@ int ipp_do_blit(struct rk29_ipp_req *req)
                                        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
+                                       //printk("IPP_CONFIG2 = 0x%x\n",ipp_read(IPP_CONFIG));\r
                                }\r
                                else\r
                                {\r
@@ -855,7 +1683,7 @@ int ipp_do_blit(struct rk29_ipp_req *req)
        //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
+       wait_ret = wait_event_interruptible_timeout(hw_wait_queue, wq_condition, msecs_to_jiffies(req->timeout));\r
 \r
 #ifdef IPP_TEST\r
        do_gettimeofday(&wait_done);\r
@@ -963,22 +1791,28 @@ erorr_input:
        return ret;\r
 }\r
 \r
-static int stretch_blit(struct ipp_context *ctx,  unsigned long arg )\r
+static int stretch_blit(/*struct ipp_context *ctx,*/  unsigned long arg ,unsigned int cmd)\r
 {\r
-       struct ipp_drvdata *data = ctx->data;\r
-       int ret = 0;\r
        struct rk29_ipp_req req;\r
-\r
-       mutex_lock(&data->mutex);\r
-\r
+       int ret = 0;\r
+       \r
        if (unlikely(copy_from_user(&req, (struct rk29_ipp_req*)arg,\r
                                        sizeof(struct rk29_ipp_req)))) {\r
                ERR("copy_from_user failed\n");\r
                ret = -EFAULT;\r
                goto err_noput;\r
        }\r
-\r
-       ret = ipp_do_blit(&req);\r
+       \r
+       \r
+       if(cmd == IPP_BLIT_SYNC)\r
+       {\r
+               ret = ipp_blit_sync(&req);\r
+       }\r
+       else\r
+       {\r
+               ret = ipp_blit_async(&req);\r
+       }\r
+       \r
        if(ret != 0) {\r
                ERR("Failed to start IPP operation (%d)\n", ret);\r
                goto err_noput;\r
@@ -986,22 +1820,23 @@ static int stretch_blit(struct ipp_context *ctx,  unsigned long arg )
 \r
 err_noput:\r
 \r
-       mutex_unlock(&data->mutex);\r
-\r
        return ret;\r
 }\r
 \r
-static int ipp_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)\r
+static long ipp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)\r
 {\r
 \r
-       struct ipp_context *ctx = (struct ipp_context *)file->private_data;\r
+       //struct ipp_context *ctx = (struct ipp_context *)file->private_data;\r
        int ret = 0;\r
        switch (cmd)\r
        {\r
-               case RK_IPP_BLIT:\r
-                       ret = stretch_blit(ctx, arg);\r
+               case IPP_BLIT_SYNC:\r
+               case IPP_BLIT_ASYNC:\r
+                       ret = stretch_blit(/*ctx, */arg, cmd);\r
+                       break;\r
+               case IPP_GET_RESULT:\r
+                       ret = ipp_get_result(arg);\r
                        break;\r
-\r
                default:\r
                        ERR("unknown ioctl cmd!\n");\r
                        ret = -EINVAL;\r
@@ -1033,6 +1868,20 @@ static int rk29_ipp_open(struct inode *inode, struct file *file)
 static int ipp_release(struct inode *inode, struct file *file)\r
 {\r
     struct ipp_context *ctx = (struct ipp_context *)file->private_data;\r
+       //printk("ipp_release\n");\r
+\r
+       //clear event\r
+       if(atomic_read(&drvdata->ipp_event))\r
+       {\r
+               atomic_set(&drvdata->ipp_event, 0);\r
+       }\r
+       //Èç¹ûÓ¦ÓòãÏ·¢ÇëÇóºóûÓÐÀ´get result£¬idle_conditionΪ0»áµ¼ÖÂÒÔºóµÄÇëÇóÎÞ·¨Ö´ÐÐ\r
+       idle_condition = 1;\r
+       wq_condition = 0;\r
+       \r
+       //delay 20ms to wait HW completed\r
+       schedule_delayed_work(&drvdata->power_off_work, msecs_to_jiffies(20));\r
+       \r
        kfree(ctx);\r
 \r
        DBG("device released\n");\r
@@ -1041,45 +1890,96 @@ static int ipp_release(struct inode *inode, struct file *file)
 \r
 static irqreturn_t rk29_ipp_irq(int irq,  void *dev_id)\r
 {\r
+       //static int temp =0;\r
+       DBG("rk29_ipp_irq %d \n",irq);\r
+       //printk("rk29_ipp_irq %d \n",irq);\r
+\r
 #ifdef IPP_TEST\r
-       do_gettimeofday(&irq_ret);\r
+       hw_end = ktime_get();\r
 #endif\r
-       ipp_write(ipp_read(IPP_INT)|0x3c, IPP_INT);\r
-\r
-       DBG("rk29_ipp_irq %d \n",irq);\r
 \r
+       ipp_write(ipp_read(IPP_INT)|0x3c, IPP_INT);\r
+       if(((ipp_read(IPP_INT)>>6)&0x3) !=0)// idle\r
+       {       \r
+               printk("IPP is not idle!\n");\r
+               ipp_soft_reset();\r
+               drvdata->ipp_result =  -EAGAIN;\r
+       }\r
+       \r
+       //´ú±íÓ²¼þͬӲ¼þ½»»¥Íê³É\r
        wq_condition = 1;\r
-       dsb();\r
+       \r
        \r
 #ifdef IPP_TEST\r
-       do_gettimeofday(&irq_done);\r
+       irq_start = ktime_get();\r
 #endif\r
-       wake_up_interruptible_sync(&wait_queue);\r
 \r
+       if(drvdata->issync)//sync\r
+       {\r
+               wake_up_interruptible_sync(&hw_wait_queue);\r
+       }\r
+       else//async\r
+       {\r
+               //power off\r
+               schedule_delayed_work(&drvdata->power_off_work, msecs_to_jiffies(1000));\r
+                       \r
+               drvdata->ipp_irq_callback(drvdata->ipp_result);\r
+               //drvdata->ipp_irq_callback(temp);\r
+               \r
+               //Èç¹ûÊÇÄÚºË̬µÄÒì²½µ÷Óã¬ÔòÔڴ˾ͻ½Ðѵȴý¶ÓÁУ»Èç¹ûÊÇÓû§Ì¬µÄÒì²½µ÷Óã¬Òªµ½get_resultÍê³Éºó²ÅÄÜ»½ÐÑ\r
+               if(drvdata->ipp_irq_callback != ipp_blit_complete)\r
+               {\r
+                       idle_condition = 1;\r
+                       wake_up_interruptible_sync(&blit_wait_queue);\r
+               }\r
+               //temp++;\r
+       }\r
+       \r
+       \r
        return IRQ_HANDLED;\r
 }\r
 \r
-struct file_operations ipp_fops = {\r
-       .owner          = THIS_MODULE,\r
-       .open           = rk29_ipp_open,\r
-       .release        = ipp_release,\r
-       .ioctl          = ipp_ioctl,\r
-};\r
+static int ipp_suspend(struct platform_device *pdev, pm_message_t state)\r
+{\r
+       //printk("ipp_suspend\n");\r
+       //ÑÓʱ20msÈ·±£Ó²¼þ¹¤×÷Íê³É\r
+       mdelay(20);\r
+       //È¡Ïûpower_offµÄ¹¤×÷¶ÓÁУ¬Á¢¼´poweroff\r
+       cancel_delayed_work_sync(&drvdata->power_off_work);\r
+       ipp_power_off(NULL);\r
 \r
-static struct miscdevice ipp_dev ={\r
-    .minor = IPP_MAJOR,\r
-    .name  = "rk29-ipp",\r
-    .fops  = &ipp_fops,\r
-};\r
+       return 0;\r
+}\r
+\r
+static int ipp_resume(struct platform_device *pdev)\r
+{\r
+       //printk("ipp_resume\n");\r
+       //Èç¹ûsuspandǰ´¦ÓÚ¹¤×÷״̬£¬Ôòresumeºópower on\r
+       if (!wq_condition) \r
+       {\r
+               drvdata->enable = false;\r
+               ipp_power_on();\r
+       }\r
+       return 0;\r
+}\r
 \r
 #ifdef IPP_TEST\r
+void ipp_test_complete(int retval)\r
+{\r
+       printk("ipp_test_complete retval=%d\n",retval);\r
+       if(retval==0)\r
+       {\r
+               test_condition = 1;\r
+               wake_up_interruptible_sync(&test_queue);\r
+       }\r
+}\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
+                int ret = 0,ret1=0,ret2=0;\r
 \r
                 uint8_t *srcY ;\r
                 uint8_t *dstY;\r
@@ -1088,6 +1988,7 @@ static void ipp_test_work_handler(struct work_struct *work)
                  uint32_t src_addr;\r
                 uint32_t dst_addr;\r
                 uint8_t *p;\r
+                pm_message_t pm;\r
 #if 0\r
 //test lzg's bug\r
 uint32_t size = 8*1024*1024;\r
@@ -1142,8 +2043,8 @@ uint32_t size = 8*1024*1024;
                \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.w = 480;\r
+               ipp_req.src0.h = 320;\r
                ipp_req.src0.fmt = IPP_Y_CBCR_H2V2;\r
                \r
                ipp_req.dst0.YrgbMst = dst_addr;\r
@@ -1151,21 +2052,121 @@ uint32_t size = 8*1024*1024;
                ipp_req.dst0.w = 800;\r
                ipp_req.dst0.h = 480;\r
        \r
-               ipp_req.src_vir_w = 800;\r
+               ipp_req.src_vir_w = 480;\r
                ipp_req.dst_vir_w = 800;\r
-               ipp_req.timeout = 50;\r
+               ipp_req.timeout = 100;\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_req.complete = ipp_test_complete;\r
                \r
+               /*1 test ipp_blit_sync*/\r
+               /*\r
                while(!ret)\r
                {\r
                        ipp_req.timeout = 50;\r
-                       ret = ipp_do_blit(&ipp_req);\r
-               }\r
+                       //ret = ipp_do_blit(&ipp_req);\r
+                       ret = ipp_blit_sync(&ipp_req);\r
+               }*/\r
                \r
-               free_pages(srcY, 9);\r
 \r
+               /*2.test ipp_blit_async*/\r
+               /*\r
+               do\r
+               {\r
+                       test_condition = 0;\r
+                       ret = ipp_blit_async(&ipp_req);\r
+                       if(ret == 0)\r
+                               ret = wait_event_interruptible_timeout(test_queue, test_condition, msecs_to_jiffies(ipp_req.timeout));\r
+                       \r
+                       irq_end = ktime_get(); \r
+                       irq_end = ktime_sub(irq_end,irq_start);\r
+                       hw_end = ktime_sub(hw_end,hw_start);\r
+                       if((((int)ktime_to_us(hw_end)/1000)>10)||(((int)ktime_to_us(irq_end)/1000)>10))\r
+                       {\r
+                               printk("hw time: %d ms, irq time: %d ms\n",(int)ktime_to_us(hw_end)/1000,(int)ktime_to_us(irq_end)/1000);\r
+                       }\r
+               }while(ret>0);\r
+               printk("test ipp_blit_async over!!!\n");\r
+               */\r
+\r
+               /*3.Á¬ÐøÏ·¢Á½¸öÒì²½ÇëÇ󣬵ڶþ´ÎµÄÇëÇóÒªÔÚµÚÒ»´Î·µ»Øºó²Å»áÖ´ÐС£²¢ÇÒÁ½´ÎÇëÇóÈ¡»ØµÄÊǸ÷×ԵĽá¹û*/\r
+               /*\r
+       [   10.253532] ipp_blit_async\r
+       [   10.256210] ipp_blit_async2\r
+       [   10.259000] ipp_blit_async\r
+       [   10.261700] ipp_test_complete retval=0\r
+       [   10.282832] ipp_blit_async2\r
+       [   10.284304] ipp_test_complete retval=1        Á½´ÎÇëÇó·Ö±ðÈ¡»ØÁ˲»Í¬µÄ½á¹û£¬ÄÚºËÖÐÁ½¸öÓ¦ÓÃͬʱÒì²½µ÷ÓÃok\r
+               */\r
+               /*\r
+               ret1 = ipp_blit_async(&ipp_req);\r
+               ret2 = ipp_blit_async(&ipp_req);\r
+               */\r
+\r
+               /*4 Á¬ÐøÏ·¢Á½¸öͬ²½ÇëÇó,µÚ¶þ´ÎµÄÇëÇóÔÚµÚÒ»´Î½áÊøºó²ÅÖ´ÐÐ,²¢ÇÒÁ½´ÎÇëÇóÈ¡»ØÁ˸÷×ԵĽá¹û*/\r
+               /*\r
+               [   10.703628] ipp_blit_async\r
+               [   10.711211] wait_event_interruptible waitret= 0\r
+               [   10.712878] ipp_blit_async2\r
+               [   10.720036] ipp_blit_sync done\r
+               [   10.720229] ipp_blit_async\r
+               [   10.722920] wait_event_interruptible waitret= 0\r
+               [   10.727422] ipp_blit_async2\r
+               [   10.790052] hw time: 1 ms, irq time: 48 ms\r
+               [   10.791294] ipp_blit_sync wait_ret=0,wait_event_timeout \r
+               */\r
+               /*\r
+               ret1 = ipp_blit_sync(&ipp_req);\r
+               ret2 = ipp_blit_sync(&ipp_req);*/\r
+\r
+               /*5.ÏÈÒì²½ºóͬ²½*/\r
+               /*\r
+               ret1 = ipp_blit_async(&ipp_req);\r
+               ret2 = ipp_blit_sync(&ipp_req); \r
+               ret1 = ipp_blit_sync(&ipp_req);\r
+               ret2 = ipp_blit_async(&ipp_req);\r
+               */\r
+\r
+               /*6.ÄÚºËͬ²½µ÷Óã¬ÅäºÏÓû§Ì¬Òì²½µ÷ÓÃ*/\r
+               \r
+               do\r
+               {\r
+                        ret = ipp_blit_sync(&ipp_req);\r
+                        msleep(40);\r
+               }\r
+               while(ret==0);\r
+\r
+               printk("error! ret =%d\n",ret);\r
+\r
+               /*7.suspand and resume*/\r
+               /*\r
+               //do\r
+               {\r
+                        ret = ipp_blit_async(&ipp_req);\r
+                        ipp_suspend(NULL,pm);\r
+                        msleep(1000);\r
+                        ipp_resume(NULL);\r
+               }\r
+               //while(ret==0);*/\r
+       /*      \r
+               do\r
+               {\r
+                        ret = ipp_blit_async(&ipp_req);\r
+                        if(ret == 0)\r
+                               ret = wait_event_interruptible_timeout(test_queue, test_condition, msecs_to_jiffies(ipp_req.timeout));\r
+                        msleep(100);\r
+\r
+               }\r
+               while(ret>0);\r
+*/\r
 \r
+               \r
+               free_pages(srcY, 9);\r
 //test deinterlace\r
 #if 0\r
                uint32_t size = 16*16;\r
@@ -1265,6 +2266,20 @@ uint32_t size = 8*1024*1024;
 }\r
 #endif\r
 \r
+struct file_operations ipp_fops = {\r
+       .owner          = THIS_MODULE,\r
+       .open           = rk29_ipp_open,\r
+       .release        = ipp_release,\r
+       .unlocked_ioctl         = ipp_ioctl,\r
+       .poll           = ipp_poll,\r
+};\r
+\r
+static struct miscdevice ipp_dev ={\r
+    .minor = IPP_MAJOR,\r
+    .name  = "rk29-ipp",\r
+    .fops  = &ipp_fops,\r
+};\r
+\r
 static int __init ipp_drv_probe(struct platform_device *pdev)\r
 {\r
        struct ipp_drvdata *data;\r
@@ -1380,7 +2395,18 @@ static int __init ipp_drv_probe(struct platform_device *pdev)
        }\r
 \r
        mutex_init(&data->mutex);\r
+       data->enable = false;\r
+\r
 \r
+       atomic_set(&data->ipp_event, 0);\r
+       init_waitqueue_head(&data->ipp_wait);\r
+       INIT_DELAYED_WORK(&data->power_off_work, ipp_power_off);\r
+       data->ipp_result = -1;\r
+       data->ipp_irq_callback = NULL;\r
+\r
+\r
+\r
+       \r
        platform_set_drvdata(pdev, data);\r
        drvdata = data;\r
 \r
@@ -1394,7 +2420,7 @@ static int __init ipp_drv_probe(struct platform_device *pdev)
 \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
+       schedule_delayed_work(&d_work, msecs_to_jiffies(35000));\r
 #endif\r
 \r
        return 0;\r
@@ -1457,9 +2483,13 @@ static int ipp_drv_remove(struct platform_device *pdev)
     return 0;\r
 }\r
 \r
+\r
+\r
 static struct platform_driver rk29_ipp_driver = {\r
        .probe          = ipp_drv_probe,\r
        .remove         = ipp_drv_remove,\r
+       .suspend    = ipp_suspend,\r
+       .resume     = ipp_resume,\r
        .driver         = {\r
                .owner  = THIS_MODULE,\r
                .name   = "rk29-ipp",\r
@@ -1484,6 +2514,8 @@ static void __exit rk29_ipp_exit(void)
        platform_driver_unregister(&rk29_ipp_driver);\r
 }\r
 \r
+\r
+\r
 device_initcall_sync(rk29_ipp_init);\r
 module_exit(rk29_ipp_exit);\r
 \r
index aa8b9e0c06e66285ea338172f9f0c347559126be..78589e1ac9fd9c70efc75c98b8a818b8bad47886 100755 (executable)
@@ -1384,7 +1384,8 @@ static int fb0_set_par(struct fb_info *info)
             ipp_req.dst_vir_w = ipp_req.dst0.w;
             ipp_req.timeout = 100;
             ipp_req.flag = IPP_ROT_0;
-            ipp_do_blit(&ipp_req);
+            //ipp_do_blit(&ipp_req);
+            ipp_blit_sync(&ipp_req);
         }else
         #endif
         {
@@ -1477,7 +1478,8 @@ static int fb0_pan_display(struct fb_var_screeninfo *var, struct fb_info *info)
             ipp_req.dst_vir_w = ipp_req.dst0.w;
             ipp_req.timeout = 100;
             ipp_req.flag = IPP_ROT_0;
-            ipp_do_blit(&ipp_req);
+            //ipp_do_blit(&ipp_req);
+            ipp_blit_sync(&ipp_req);
             win1_pan(info);
             return 0;
         }else
@@ -1904,7 +1906,8 @@ static int fb1_set_par(struct fb_info *info)
                                else if(var->rotate == 270)
                                        ipp_req.flag = IPP_ROT_270;
 
-                               ipp_do_blit(&ipp_req);
+                               //ipp_do_blit(&ipp_req);
+                               ipp_blit_sync(&ipp_req);
                                fbprintk("yaddr=0x%x,uvaddr=0x%x\n",ipp_req.dst0.YrgbMst,ipp_req.dst0.CbrMst);
                                yuv_phy[0] = ipp_req.dst0.YrgbMst;
                                yuv_phy[1] = ipp_req.dst0.CbrMst;        
@@ -2096,7 +2099,8 @@ static int fb1_ioctl(struct fb_info *info, unsigned int cmd, unsigned long arg)
                     ipp_req.flag = IPP_ROT_90;
                 else if(var->rotate == 270)
                     ipp_req.flag = IPP_ROT_270;
-                ipp_do_blit(&ipp_req);
+                //ipp_do_blit(&ipp_req);
+                ipp_blit_sync(&ipp_req);
                 fbprintk("yaddr=0x%x,uvaddr=0x%x\n",ipp_req.dst0.YrgbMst,ipp_req.dst0.CbrMst);
                 yuv_phy[0] = ipp_req.dst0.YrgbMst;
                 yuv_phy[1] = ipp_req.dst0.CbrMst;