#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
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
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
\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
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
//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
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
\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
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
\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
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
\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
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
}\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
}\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
\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
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
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