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