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