static void blit_convert(struct mdp_blit_req *req, struct ppp_regs *regs) { if (req->src.format == req->dst.format) return; if (IS_RGB(req->src.format) && IS_YCRCB(req->dst.format)) { regs->op |= PPP_OP_CONVERT_RGB2YCBCR | PPP_OP_CONVERT_ON; #ifdef CONFIG_MSM_MDP31 /* primary really means set1 */ regs->op |= PPP_OP_CONVERT_MATRIX_PRIMARY; regs->csc_cfg = 0x1e; #endif } else if (IS_YCRCB(req->src.format) && IS_RGB(req->dst.format)) { regs->op |= PPP_OP_CONVERT_YCBCR2RGB | PPP_OP_CONVERT_ON; #ifdef CONFIG_MSM_MDP31 /* secondary really means set2 */ regs->op |= PPP_OP_CONVERT_MATRIX_SECONDARY; regs->csc_cfg = 0; #endif } }
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 output with&height uint32_t post_scale_input_w, post_scale_input_h;//post_scale input width&height uint32_t dst0_YrgbMst=0,dst0_CbrMst=0; uint32_t ret = 0; uint32_t deinterlace_config = 0; uint32_t src0_w = req->src0.w; uint32_t src0_h = req->src0.h; //printk("ipp_blit\n"); if (drvdata == NULL) { /* [email protected] : check driver is normal or not */ printk("%s drvdata is NULL, IPP driver probe is fail!!\n", __FUNCTION__); return -EPERM; } drvdata->ipp_result = -1; //When ipp_blit_async is called in kernel space req->complete should NOT be NULL, otherwise req->complete should be NULL 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) { printk("IPP invalid input!\n"); 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; } //we start to interact with hw now 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/2) ? 1 : 0)||((req->dst0.h <= req->src0.w/2) ? 1 : 0); } else //other degree { pre_scale = ((req->dst0.w <= req->src0.w/2) ? 1 : 0)||((req->dst0.h <= req->src0.h/2) ? 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! Down scaling ratio should not be more than 16!\n"); goto error_scale; } } if(pre_scale_h > 8) { if(pre_scale_h < 16) { pre_scale_h = 8; } else { printk("invalid pre_scale operation! Down scaling ratio should not be more than 16!\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; } //when fmt is YUV,make sure pre_scale_output_w and pre_scale_output_h are even if(IS_YCRCB(req->src0.fmt)) { if((pre_scale_output_w & 0x1) != 0) { pre_scale_output_w -=1; src0_w = pre_scale_output_w * pre_scale_w; } if((pre_scale_output_h & 0x1) != 0) { pre_scale_output_h -=1; src0_h = pre_scale_output_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(ipp_read(IPP_CONFIG)&(~PRE_SCALE), IPP_CONFIG); //disable pre_scale ipp_write(0,IPP_PRE_SCL_PARA); ipp_write((req->src0.h<<16)|req->src0.w, IPP_PRE_IMG_INFO); } ipp_write(src0_h<<16|src0_w, IPP_SRC_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)//non-interger down-scaling ||((req->src0.h/req->dst0.w)>8)||((req->src0.h/req->dst0.w)>8) //down-scaling ratio > 8 ||(req->dst0.w > req->src0.h) ||(req->dst0.h > req->src0.w)) //up-scaling { 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)//non-interger down-scaling ||((req->src0.w/req->dst0.w)>8)||((req->src0.h/req->dst0.h)>8) //down-scaling ratio > 8 ||(req->dst0.w > req->src0.w) ||(req->dst0.h > req->src0.h)) //up-scaling { 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)); } /*only support 1/2 to 4 times scaling,but two cases can pass 1.176*144->480*800, YUV420 2.128*128->480*800, YUV420 */ if(!((req->src0.fmt == IPP_Y_CBCR_H2V2)&& (((req->src0.w == 176)&&(req->src0.h == 144))||((req->src0.w == 128)&&(req->src0.h == 128)))&& ((req->dst0.w == 480)&&(req->dst0.h == 800)))) { 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)&0xffffff1f)|(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); #ifdef CONFIG_DEINTERLACE ipp_write((ipp_read(IPP_CONFIG)&0xFE0001FF)|deinterlace_config, IPP_CONFIG); #else printk("does not support deinterlacing!\n"); ipp_write(ipp_read(IPP_CONFIG)&(~DEINTERLACE_ENABLE), IPP_CONFIG); //disable deinterlace #endif } else { ERR("invalid deinterlace parameters!\n"); } } } else { ERR("only support YUV format!\n"); } } else { ipp_write(ipp_read(IPP_CONFIG)&(~DEINTERLACE_ENABLE), IPP_CONFIG); //disable deinterlace } /*Configure other*/ ipp_write((req->dst_vir_w<<16)|req->src_vir_w, IPP_IMG_VIR); //store clip mode if(req->store_clip_mode == 1) { ipp_write(ipp_read(IPP_CONFIG)|STORE_CLIP_MODE, IPP_CONFIG); } else { ipp_write(ipp_read(IPP_CONFIG)&(~STORE_CLIP_MODE), IPP_CONFIG); } /* Start the operation */ ipp_write(8, IPP_INT); ipp_write(1, IPP_PROCESS_ST); dsb(); dmac_clean_range(drvdata->ipp_base,drvdata->ipp_base+0x54); #ifdef IPP_TEST hw_start = ktime_get(); #endif goto error_noerror; error_status: error_scale: ret = -EINVAL; ipp_soft_reset(); ipp_power_off(NULL); erorr_input: error_noerror: drvdata->ipp_result = ret; //printk("ipp_blit done\n"); return ret; }