From d31235fb8c15b11a37bc1612f3bfb53e0b2ecfc6 Mon Sep 17 00:00:00 2001 From: chenli Date: Thu, 19 May 2011 19:44:40 +0800 Subject: [PATCH] rk29-ipp: add deinterlace support & fix bugs 1.Add deinterlace support 2.Check input parameters in ipp_do_blit() 3.Enable or disable all clocks need by IPP in ipp_do_blit() for power saving 4.Sovle the problem of scheduling timeout --- arch/arm/mach-rk29/include/mach/rk29-ipp.h | 9 + drivers/staging/rk29/ipp/rk29-ipp.c | 810 +++++++++++++++++---- 2 files changed, 689 insertions(+), 130 deletions(-) mode change 100644 => 100755 arch/arm/mach-rk29/include/mach/rk29-ipp.h diff --git a/arch/arm/mach-rk29/include/mach/rk29-ipp.h b/arch/arm/mach-rk29/include/mach/rk29-ipp.h old mode 100644 new mode 100755 index ebbc888d6eee..f94dc57c2f06 --- a/arch/arm/mach-rk29/include/mach/rk29-ipp.h +++ b/arch/arm/mach-rk29/include/mach/rk29-ipp.h @@ -20,6 +20,15 @@ struct rk29_ipp_req { uint32_t dst_vir_w; uint32_t timeout; uint32_t flag; //rotate + + //chenli 0506 + //deinterlace_enable 1:enable 0:disable + uint8_t deinterlace_enable; + //the sum of three paras should be 32,and single para should be less than 32 + uint8_t deinterlace_para0; + uint8_t deinterlace_para1; + uint8_t deinterlace_para2; + }; //uint32_t format ö¾ÙÀàÐÍ diff --git a/drivers/staging/rk29/ipp/rk29-ipp.c b/drivers/staging/rk29/ipp/rk29-ipp.c index 5fc6247cc6d1..0cd992df0149 100755 --- a/drivers/staging/rk29/ipp/rk29-ipp.c +++ b/drivers/staging/rk29/ipp/rk29-ipp.c @@ -39,7 +39,18 @@ #include #include #include +#include +//#define IPP_TEST +#ifdef IPP_TEST +#include +struct delayed_work d_work; + +static struct timeval hw_set; +static struct timeval irq_ret; +static struct timeval irq_done; +static struct timeval wait_done; +#endif struct ipp_drvdata { struct miscdevice miscdev; @@ -47,15 +58,24 @@ struct ipp_drvdata { void *ipp_base; struct ipp_regs regs; int irq0; + + struct clk *pd_display; + struct clk *aclk_lcdc; + struct clk *hclk_lcdc; + struct clk *aclk_ddr_lcdc; + struct clk *hclk_cpu_display; + struct clk *aclk_disp_matrix; + struct clk *hclk_disp_matrix; struct clk *axi_clk; struct clk *ahb_clk; + struct mutex mutex; // mutex }; static struct ipp_drvdata *drvdata = NULL; static DECLARE_WAIT_QUEUE_HEAD(wait_queue); -static int wq_condition = 0; +static volatile int wq_condition = 0; /* Context data (unique) */ struct ipp_context @@ -79,9 +99,11 @@ struct ipp_context #define DRIVER_DESC "RK29 IPP Device Driver" #define DRIVER_NAME "rk29-ipp" + + /* Logging */ #define IPP_DEBUG 0 -#ifdef IPP_DEBUG +#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) @@ -93,6 +115,11 @@ struct ipp_context #define INFO(format, args...) #endif + + + + + static inline void ipp_write( uint32_t b, uint32_t r) { __raw_writel(b, drvdata->ipp_base + r); @@ -128,19 +155,64 @@ int ipp_do_blit(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; + 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_target_w=0, pre_scale_target_h=0; - uint32_t post_scale_target_w, post_scale_target_h; + 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; + int wait_ret; + mutex_lock(&drvdata->mutex); + if (drvdata == NULL) { /* ddl@rock-chips.com : check driver is normal or not */ - printk(KERN_ERR, "%s drvdata is NULL, IPP driver probe is fail!!\n", __FUNCTION__); + //printk(KERN_ERR, "%s drvdata is NULL, IPP driver probe is fail!!\n", __FUNCTION__); + printk("%s drvdata is NULL, IPP driver probe is fail!!\n", __FUNCTION__); return -EPERM; } + + /*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"); + ret = -EINVAL; + goto erorr_input; + } + + //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"); + ret = -EINVAL; + goto erorr_input; + } + + //check src address + if (unlikely(req->src0.YrgbMst== 0) ) + { + ERR("could not retrieve src image from memory\n"); + ret = -EINVAL; + goto erorr_input; + } + + //check src address + if (unlikely(req->dst0.YrgbMst== 0) ) + { + ERR("could not retrieve dst image from memory\n"); + ret = -EINVAL; + goto erorr_input; + } + //check rotate degree + if(req->flag >= IPP_ROT_LIMIT) + { + ERR("rk29_ipp is not surpport rot degree!!!!\n"); + ret = -EINVAL; + goto erorr_input; + } + + rotate = req->flag; switch (rotate) { case IPP_ROT_90: @@ -329,6 +401,84 @@ int ipp_do_blit(struct rk29_ipp_req *req) break; } + //enable clk + if(drvdata->pd_display) + { + clk_enable(drvdata->pd_display); + } + else + { + printk("pd_display is null \n"); + ret = -EINVAL; + goto error_pd_display; + } + + if(drvdata->aclk_lcdc) + { + clk_enable(drvdata->aclk_lcdc); + } + else + { + printk("aclk_lcdc is null \n"); + ret = -EINVAL; + goto error_aclk_lcdc; + } + + if(drvdata->hclk_lcdc) + { + clk_enable(drvdata->hclk_lcdc); + } + else + { + printk("hclk_lcdc is null \n"); + ret = -EINVAL; + goto error_hclk_lcdc; + } + + if(drvdata->aclk_ddr_lcdc) + { + clk_enable(drvdata->aclk_ddr_lcdc); + } + else + { + printk("aclk_ddr_lcdc is null \n"); + ret = -EINVAL; + goto error_aclk_ddr_lcdc; + } + + if(drvdata->hclk_cpu_display) + { + clk_enable(drvdata->hclk_cpu_display); + } + else + { + printk("hclk_cpu_display is null \n"); + ret = -EINVAL; + goto error_hclk_cpu_display; + } + + if(drvdata->aclk_disp_matrix) + { + clk_enable(drvdata->aclk_disp_matrix); + } + else + { + printk("aclk_disp_matrix is null \n"); + ret = -EINVAL; + goto error_aclk_disp_matrix; + } + + if(drvdata->hclk_disp_matrix) + { + clk_enable(drvdata->hclk_disp_matrix); + } + else + { + printk("hclk_disp_matrix is null \n"); + ret = -EINVAL; + goto error_hclk_disp_matrix; + } + if(drvdata->axi_clk) { clk_enable(drvdata->axi_clk); @@ -350,6 +500,15 @@ int ipp_do_blit(struct rk29_ipp_req *req) ret = -EINVAL; goto error_ahb_clk; } + //enable clk end + + //check if IPP is idle + if(((ipp_read(IPP_INT)>>6)&0x3) !=0)// idle + { + printk("IPP staus is not idle,can noe 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, @@ -373,6 +532,7 @@ int ipp_do_blit(struct rk29_ipp_req *req) { ipp_write(dst0_CbrMst, IPP_DST0_CBR_MST); } + ipp_write(req->dst0.h<<16|req->dst0.w, IPP_DST_IMG_INFO); /*Configure Pre_scale*/ @@ -408,30 +568,6 @@ int ipp_do_blit(struct rk29_ipp_req *req) } DBG("!!!!!pre_scale_h %d,pre_scale_w %d \n",pre_scale_h,pre_scale_w); - - 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); - - if((req->src0.w%pre_scale_w)!=0) //ÏòÉÏÈ¡Õû ceil - { - pre_scale_target_w = req->src0.w/pre_scale_w+1; - } - else - { - pre_scale_target_w = req->src0.w/pre_scale_w; - } - - if((req->src0.h%pre_scale_h)!=0)//ÏòÉÏÈ¡Õû ceil - { - pre_scale_target_h = req->src0.h/pre_scale_h +1; - } - else - { - pre_scale_target_h = req->src0.h/pre_scale_h; - } - - ipp_write(((pre_scale_target_h)<<16)|(pre_scale_target_w), IPP_PRE_IMG_INFO); - } else//0 180 x ,y { @@ -453,31 +589,56 @@ int ipp_do_blit(struct rk29_ipp_req *req) { pre_scale_h = 1; } - DBG("!!!!!pre_scale_h %d,pre_scale_w %d \n",pre_scale_h,pre_scale_w); + } - 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); - - if((req->src0.w%pre_scale_w)!=0) //ÏòÉÏÈ¡Õû ceil + //pre_scale only support 1/2 to 1/8 time + if(pre_scale_w > 8) + { + if(pre_scale_w < 16) { - pre_scale_target_w = req->src0.w/pre_scale_w+1; + pre_scale_w = 8; } else { - pre_scale_target_w = req->src0.w/pre_scale_w; + printk("invalid pre_scale operation! pre_scale_w should not be more than 8!\n"); + goto error_scale; } - - if((req->src0.h%pre_scale_h)!=0)//ÏòÉÏÈ¡Õû ceil + } + if(pre_scale_h > 8) + { + if(pre_scale_h < 16) { - pre_scale_target_h = req->src0.h/pre_scale_h +1; + pre_scale_h = 8; } else { - pre_scale_target_h = req->src0.h/pre_scale_h; + printk("invalid pre_scale operation! pre_scale_h should not be more than 8!\n"); + goto error_scale; } } - ipp_write(((pre_scale_target_h)<<16)|(pre_scale_target_w), IPP_PRE_IMG_INFO); + + 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 @@ -490,7 +651,9 @@ int ipp_do_blit(struct rk29_ipp_req *req) 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->dst0.w > req->src0.h) ||(req->dst0.h > req->src0.w)) + ||((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; } @@ -502,7 +665,8 @@ int ipp_do_blit(struct rk29_ipp_req *req) else //0 180 x-flip y-flip { if (( (req->src0.w%req->dst0.w)!=0)||( (req->src0.h%req->dst0.h)!= 0)//СÊý±¶ËõС - ||(req->dst0.w > req->src0.w) ||(req->dst0.h > req->src0.h)) + ||((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; } @@ -514,74 +678,104 @@ int ipp_do_blit(struct rk29_ipp_req *req) 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)) { - if(pre_scale) - { - post_scale_target_w = pre_scale_target_w; - post_scale_target_h = pre_scale_target_h; - } - else - { - post_scale_target_w = req->src0.w; - post_scale_target_h = req->src0.h; - } - - DBG("post_scale_target_w %d ,post_scale_target_h %d !!!\n",post_scale_target_w,post_scale_target_h); + 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: - post_scale_w = (uint32_t)(4096*(post_scale_target_w-1)/(req->dst0.h-1)); + //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: - post_scale_w = (uint32_t)(4096*(post_scale_target_w/2-1)/(req->dst0.h/2-1)); + //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_target_h -1)/(req->dst0.w-1)); + 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 { - - if(pre_scale) - { - post_scale_target_w = pre_scale_target_w; - post_scale_target_h = pre_scale_target_h; - } - else - { - post_scale_target_w = req->src0.w; - post_scale_target_h = req->src0.h; - } - switch(req->src0.fmt) { case IPP_XRGB_8888: case IPP_RGB_565: case IPP_Y_CBCR_H1V1: - post_scale_w = (uint32_t)(4096*(post_scale_target_w-1)/(req->dst0.w-1)); + //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: - post_scale_w = (uint32_t)(4096*(post_scale_target_w/2-1)/(req->dst0.w/2-1)); + ////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_target_h -1)/(req->dst0.h-1)); + post_scale_h = (uint32_t)(4096*(post_scale_input_h -1)/(req->dst0.h-1)); } + + if(!((req->src0.fmt != IPP_Y_CBCR_H2V1)&&(req->src0.w == 176)&&(req->src0.h == 144)&&(req->dst0.w == 480)&&(req->src0.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); } @@ -598,18 +792,43 @@ int ipp_do_blit(struct rk29_ipp_req *req) { ipp_write(ipp_read(IPP_CONFIG)&(~ROT_ENABLE), IPP_CONFIG); } - else if(req->flag > IPP_ROT_LIMIT) - { - printk("rk29_ipp is not surpport rot degree!!!!\n"); - ret = -1; - goto error_rot_limit; - } else { ipp_write(ipp_read(IPP_CONFIG)|ROT_ENABLE, IPP_CONFIG); ipp_write(ipp_read(IPP_CONFIG)|rotate<<5, IPP_CONFIG); } + /*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); @@ -622,11 +841,68 @@ int ipp_do_blit(struct rk29_ipp_req *req) //msleep(5000);//debug use + wq_condition = 0; + dsb(); +#ifdef IPP_TEST + memset(&hw_set,0,sizeof(struct timeval)); + memset(&irq_ret,0,sizeof(struct timeval)); + memset(&irq_done,0,sizeof(struct timeval)); + memset(&wait_done,0,sizeof(struct timeval)); + do_gettimeofday(&hw_set); +#endif + ipp_write(1, IPP_PROCESS_ST); + //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)); + +#ifdef IPP_TEST + do_gettimeofday(&wait_done); + if ((((irq_ret.tv_sec - hw_set.tv_sec) * 1000 + (irq_ret.tv_usec - hw_set.tv_usec) / 1000) > 10) || + (((wait_done.tv_sec - irq_done.tv_sec) * 1000 + (wait_done.tv_usec - irq_done.tv_usec) / 1000) > 10)) { + printk("hw time: %8d irq time %8d\n", + ((irq_ret.tv_sec - hw_set.tv_sec) * 1000 + (irq_ret.tv_usec - hw_set.tv_usec) / 1000), + ((wait_done.tv_sec - irq_done.tv_sec) * 1000 + (wait_done.tv_usec - irq_done.tv_usec) / 1000)); + } +#endif + - if(!wait_event_timeout(wait_queue, wq_condition, msecs_to_jiffies(req->timeout))) + if (wait_ret <= 0) { printk("%s wait_event_timeout \n",__FUNCTION__); + +#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 + wq_condition = 0; if(!drvdata) { @@ -635,10 +911,9 @@ int ipp_do_blit(struct rk29_ipp_req *req) goto error_null; } ret = -EAGAIN; - goto errot_timeout; + goto error_timeout; } - wq_condition = 0; if(!drvdata) { @@ -649,24 +924,42 @@ int ipp_do_blit(struct rk29_ipp_req *req) if(((ipp_read(IPP_INT)>>6)&0x3) ==0)// idle { - clk_disable(drvdata->axi_clk); - clk_disable(drvdata->ahb_clk); + goto error_noerror; } else { printk("rk29 ipp status is error!!!\n"); ret = -EINVAL; - goto errot_timeout; + goto error_timeout; } - return 0; - + +error_status: +error_scale: error_null: -errot_timeout: -error_rot_limit: -error_ahb_clk: +error_timeout: + //soft rest + ipp_soft_reset(); +error_noerror: clk_disable(drvdata->ahb_clk); -error_axi_clk: +error_ahb_clk: clk_disable(drvdata->axi_clk); +error_axi_clk: + clk_disable(drvdata->hclk_disp_matrix); +error_hclk_disp_matrix: + clk_disable(drvdata->aclk_disp_matrix); +error_aclk_disp_matrix: + clk_disable(drvdata->hclk_cpu_display); +error_hclk_cpu_display: + clk_disable(drvdata->aclk_ddr_lcdc); +error_aclk_ddr_lcdc: + clk_disable(drvdata->hclk_lcdc); +error_hclk_lcdc: + clk_disable(drvdata->aclk_lcdc); +error_aclk_lcdc: + clk_disable(drvdata->pd_display); +error_pd_display: +erorr_input: + mutex_unlock(&drvdata->mutex); return ret; } @@ -685,36 +978,9 @@ static int stretch_blit(struct ipp_context *ctx, unsigned long arg ) goto err_noput; } - if (unlikely((req.src0.w <= 1) || (req.src0.h <= 1))) { - ERR("invalid source resolution\n"); - ret = -EINVAL; - goto err_noput; - } - - if (unlikely((req.dst0.w <= 1) || (req.dst0.h <= 1))) { - ERR("invalid destination resolution\n"); - ret = -EINVAL; - goto err_noput; - } - - if (unlikely(req.src0.YrgbMst== 0) ) - { - ERR("could not retrieve src image from memory\n"); - ret = -EINVAL; - goto err_noput; - } - - if (unlikely(req.dst0.YrgbMst== 0) ) - { - ERR("could not retrieve dst image from memory\n"); - ret = -EINVAL; - goto err_noput; - } - ret = ipp_do_blit(&req); if(ret != 0) { ERR("Failed to start IPP operation (%d)\n", ret); - ipp_soft_reset(); goto err_noput; } @@ -775,20 +1041,21 @@ static int ipp_release(struct inode *inode, struct file *file) static irqreturn_t rk29_ipp_irq(int irq, void *dev_id) { - uint32_t stat; +#ifdef IPP_TEST + do_gettimeofday(&irq_ret); +#endif + ipp_write(ipp_read(IPP_INT)|0x3c, IPP_INT); DBG("rk29_ipp_irq %d \n",irq); - stat = ipp_read(IPP_INT); - while(!(stat & 0x1)) - { - DBG("stat %d \n",stat); - } wq_condition = 1; - wake_up(&wait_queue); + dsb(); + +#ifdef IPP_TEST + do_gettimeofday(&irq_done); +#endif + wake_up_interruptible_sync(&wait_queue); - ipp_write(ipp_read(IPP_INT)|0xc, IPP_INT); - ipp_write(ipp_read(IPP_INT)|0x30, IPP_INT); return IRQ_HANDLED; } @@ -805,11 +1072,205 @@ static struct miscdevice ipp_dev ={ .fops = &ipp_fops, }; +#ifdef IPP_TEST + +static void ipp_test_work_handler(struct work_struct *work) +{ + + struct rk29_ipp_req ipp_req; + int i=0,j; + int ret = 0; + + uint8_t *srcY ; + uint8_t *dstY; + uint8_t *srcUV ; + uint8_t *dstUV; + uint32_t src_addr; + uint32_t dst_addr; + uint8_t *p; +#if 0 +//test lzg's bug +uint32_t size = 8*1024*1024; + +#define PMEM_VPU_BASE 0x76000000 +#define PMEM_VPU_SIZE 0x4000000 + // srcY = ioremap_cached(PMEM_VPU_BASE, PMEM_VPU_SIZE); + + + // srcUV = srcY + size; + // dstY = srcUV + size; + // dstUV = dstY + size; + //src_addr = virt_to_phys(srcY); + //dst_addr = virt_to_phys(dstY); + src_addr = PMEM_VPU_BASE; + dst_addr = PMEM_VPU_BASE + size*2; + printk("src_addr: %x-%x, dst_addr: %x-%x\n",srcY,src_addr,dstY,dst_addr); + + ipp_req.src0.YrgbMst = src_addr; + ipp_req.src0.CbrMst = src_addr + size; + ipp_req.src0.w = 2048; + ipp_req.src0.h = 1440; + ipp_req.src0.fmt = IPP_Y_CBCR_H2V2; + + ipp_req.dst0.YrgbMst = dst_addr; + ipp_req.dst0.CbrMst = dst_addr + size; + ipp_req.dst0.w = 2048; + ipp_req.dst0.h = 1440; + + ipp_req.src_vir_w = 2048; + ipp_req.dst_vir_w = 2048; + ipp_req.timeout = 500; + ipp_req.flag = IPP_ROT_0; + + ret = ipp_do_blit(&ipp_req); +#undef PMEM_VPU_BASE +#undef PMEM_VPU_SIZE + +#endif + +//test zyc's bug + + uint32_t size = 800*480; + srcY = (uint32_t)__get_free_pages(GFP_KERNEL, 9); //320*240*2*2bytes=300k < 128 pages + srcUV = srcY + size; + dstY = srcUV + size; + dstUV = dstY + size; + src_addr = virt_to_phys(srcY); + dst_addr = virt_to_phys(dstY); + printk("src_addr: %x-%x, dst_addr: %x-%x\n",srcY,srcUV,dstY,dstUV); + + + 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.fmt = IPP_Y_CBCR_H2V2; + + ipp_req.dst0.YrgbMst = dst_addr; + ipp_req.dst0.CbrMst = dst_addr + size; + ipp_req.dst0.w = 800; + ipp_req.dst0.h = 480; + + ipp_req.src_vir_w = 800; + ipp_req.dst_vir_w = 800; + ipp_req.timeout = 50; + ipp_req.flag = IPP_ROT_0; + + + while(!ret) + { + ipp_req.timeout = 50; + ret = ipp_do_blit(&ipp_req); + } + + free_pages(srcY, 9); + + +//test deinterlace +#if 0 + uint32_t size = 16*16; + srcY = (uint32_t*)kmalloc(size*2*2,GFP_KERNEL); + memset(srcY,0,size*2*2); + srcUV = srcY + size; + dstY = srcY + size*2; + dstUV = dstY + size; + src_addr = virt_to_phys(srcY); + dst_addr = virt_to_phys(dstY); + printk("src_addr: %x-%x, dst_addr: %x-%x\n",srcY,srcUV,dstY,dstUV); + + //set srcY + p=srcY; + for(i=0;i<256; i++) + { + *p++ = i; + } + + //set srcUV + p=srcUV; + for(i=0;i<128; i++) + { + *p++ = 2*i; + } + + dmac_clean_range(srcY,srcY+size*2); + + ipp_req.src0.YrgbMst = src_addr; + ipp_req.src0.CbrMst = src_addr + size; + ipp_req.src0.w = 16; + ipp_req.src0.h = 16; + ipp_req.src0.fmt = IPP_Y_CBCR_H2V2; + + ipp_req.dst0.YrgbMst = dst_addr; + ipp_req.dst0.CbrMst = dst_addr + size; + ipp_req.dst0.w = 16; + ipp_req.dst0.h = 16; + + ipp_req.src_vir_w = 16; + ipp_req.dst_vir_w = 16; + ipp_req.timeout = 1000; + 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_do_blit(&ipp_req); + + +/* + for(i=0;i<8;i++) + { + for(j=0;j<32;j++) + { + printk("%4x ",*(srcY+j+i*32)); + } + printk("\n"); + } + + + printk("\n\n"); + dmac_inv_range(dstY,dstY+size*2); + for(i=0;i<8;i++) + { + for(j=0;j<32;j++) + { + printk("%4x ",*(dstY+j+i*32)); + } + printk("\n"); + } + + printk("\n\n"); + for(i=0;i<8;i++) + { + for(j=0;j<16;j++) + { + printk("%4x ",*(srcUV+j+i*16)); + } + printk("\n"); + } + printk("\n\n"); + for(i=0;i<8;i++) + { + for(j=0;j<16;j++) + { + printk("%4x ",*(dstUV+j+i*16)); + } + printk("\n"); + } +*/ + kfree(srcY); +#endif + +} +#endif + static int __init ipp_drv_probe(struct platform_device *pdev) { struct ipp_drvdata *data; int ret = 0; + data = kmalloc(sizeof(struct ipp_drvdata), GFP_KERNEL); if(NULL==data) { @@ -818,6 +1279,62 @@ static int __init ipp_drv_probe(struct platform_device *pdev) } /* get the clock */ + data->pd_display = clk_get(&pdev->dev, "pd_display"); + if (IS_ERR(data->pd_display)) + { + ERR("failed to find ipp pd_display source\n"); + ret = -ENOENT; + goto err_clock; + } + + data->aclk_lcdc = clk_get(&pdev->dev, "aclk_lcdc"); + if (IS_ERR(data->aclk_lcdc)) + { + ERR("failed to find ipp aclk_lcdc source\n"); + ret = -ENOENT; + goto err_clock; + } + + data->hclk_lcdc = clk_get(&pdev->dev, "hclk_lcdc"); + if (IS_ERR(data->hclk_lcdc)) + { + ERR("failed to find ipp hclk_lcdc source\n"); + ret = -ENOENT; + goto err_clock; + } + + data->aclk_ddr_lcdc = clk_get(&pdev->dev, "aclk_ddr_lcdc"); + if (IS_ERR(data->aclk_ddr_lcdc)) + { + ERR("failed to find ipp aclk_ddr_lcdc source\n"); + ret = -ENOENT; + goto err_clock; + } + + data->hclk_cpu_display = clk_get(&pdev->dev, "hclk_cpu_display"); + if (IS_ERR(data->hclk_cpu_display)) + { + ERR("failed to find ipp hclk_cpu_display source\n"); + ret = -ENOENT; + goto err_clock; + } + + data->aclk_disp_matrix = clk_get(&pdev->dev, "aclk_disp_matrix"); + if (IS_ERR(data->aclk_disp_matrix)) + { + ERR("failed to find ipp aclk_disp_matrix source\n"); + ret = -ENOENT; + goto err_clock; + } + + data->hclk_disp_matrix = clk_get(&pdev->dev, "hclk_disp_matrix"); + if (IS_ERR(data->hclk_disp_matrix)) + { + ERR("failed to find ipp hclk_disp_matrix source\n"); + ret = -ENOENT; + goto err_clock; + } + data->axi_clk = clk_get(&pdev->dev, "aclk_ipp"); if (IS_ERR(data->axi_clk)) { @@ -835,7 +1352,7 @@ static int __init ipp_drv_probe(struct platform_device *pdev) } /* map the memory */ - data->ipp_base = (void*)ioremap( RK29_IPP_PHYS, SZ_16K);//ipp size 16k + data->ipp_base = (void*)ioremap_nocache( RK29_IPP_PHYS, SZ_16K);//ipp size 16k if (data->ipp_base == NULL) { ERR("ioremap failed\n"); @@ -854,7 +1371,8 @@ static int __init ipp_drv_probe(struct platform_device *pdev) } /* request the IRQ */ - ret = request_irq(data->irq0, rk29_ipp_irq, IRQF_SHARED, "rk29-ipp", pdev); + //ret = request_irq(data->irq0, rk29_ipp_irq, IRQF_SHARED, "rk29-ipp", pdev); + ret = request_irq(data->irq0, rk29_ipp_irq, 0/*IRQF_DISABLED*/, "rk29-ipp", pdev); if (ret) { ERR("request_irq failed (%d).\n", ret); @@ -874,6 +1392,11 @@ static int __init ipp_drv_probe(struct platform_device *pdev) } DBG("Driver loaded succesfully\n"); +#ifdef IPP_TEST + INIT_DELAYED_WORK(&d_work, ipp_test_work_handler); + schedule_delayed_work(&d_work, msecs_to_jiffies(5000)); +#endif + return 0; err_misc_register: @@ -902,6 +1425,33 @@ static int ipp_drv_remove(struct platform_device *pdev) if(data->ahb_clk) { clk_put(data->ahb_clk); } + if(data->aclk_disp_matrix) { + clk_put(data->aclk_disp_matrix); + } + + if(data->hclk_disp_matrix) { + clk_put(data->hclk_disp_matrix); + } + + if(data->aclk_ddr_lcdc) { + clk_put(data->aclk_ddr_lcdc); + } + + if(data->hclk_lcdc) { + clk_put(data->hclk_lcdc); + } + + if(data->aclk_lcdc) { + clk_put(data->aclk_lcdc); + } + + if(data->hclk_cpu_display) { + clk_put(data->hclk_cpu_display); + } + + if(data->pd_display){ + clk_put(data->pd_display); + } kfree(data); return 0; -- 2.34.1