camera rk30 : do crop by cif when digital zoom,fix bug of request_mem_region twice.

This commit is contained in:
root
2012-08-22 15:50:07 +08:00
parent 519499b58a
commit 6fd2ddf13a

155
drivers/media/video/rk30_camera_oneframe.c Executable file → Normal file
View File

@@ -48,7 +48,6 @@
#if defined(CONFIG_ARCH_RK2928)
#include <mach/rk2928_camera.h>
#include "../../video/rockchip/rga/rga.h"
#endif
#include <asm/cacheflush.h>
static int debug ;
@@ -60,7 +59,7 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
#define RKCAMERA_TR(format, ...) printk(KERN_ERR format, ## __VA_ARGS__)
#define RKCAMERA_DG(format, ...) dprintk(1, format, ## __VA_ARGS__)
#define CIF_DO_CROP 1
// CIF Reg Offset
#define CIF_CIF_CTRL 0x00
#define CIF_CIF_INTEN 0x04
@@ -202,6 +201,15 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
#endif
#define IS_CIF0() (pcdev->hostid == RK_CAM_PLATFORM_DEV_ID_0)
#if (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_IPP)
#define CROP_ALIGN_BYTES (0x03)
#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_ARM)
#define CROP_ALIGN_BYTES (0x03)
#elif (CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_RGA)
#define CROP_ALIGN_BYTES (0x03)
#elif(CONFIG_CAMERA_SCALE_CROP_MACHINE == RK_CAM_SCALE_CROP_PP)
#define CROP_ALIGN_BYTES (0x0F)
#endif
//Configure Macro
/*
* Driver Version Note
@@ -232,9 +240,12 @@ module_param(debug, int, S_IRUGO|S_IWUSR);
*v0.x.e: fix bugs of early suspend when display_pd is closed.
*v0.x.f: fix calculate ipp memory size is enough or not in try_fmt function;
*v0.x.11: fix struct rk_camera_work may be reentrant
*v0.x.13: add scale by arm,rga and pp.
*v0.x.13: 1.add scale by arm,rga and pp.
2.CIF do the crop when digital zoom.
3.fix bug in prob func:request mem twice.
*/
#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0x11)
#define RK_CAM_VERSION_CODE KERNEL_VERSION(0, 2, 0x13)
/* limit to rk29 hardware capabilities */
#define RK_CAM_BUS_PARAM (SOCAM_MASTER |\
@@ -586,7 +597,7 @@ static inline void rk_videobuf_capture(struct videobuf_buffer *vb,struct rk_came
if (vb) {
if (CAM_WORKQUEUE_IS_EN()) {
y_addr = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
uv_addr = y_addr + pcdev->host_width*pcdev->host_height;
uv_addr = y_addr + pcdev->zoominfo.vir_width*pcdev->zoominfo.vir_height;
if (y_addr > (pcdev->vipmem_phybase + pcdev->vipmem_size - pcdev->vipmem_bsize)) {
RKCAMERA_TR("vipmem for IPP is overflow! %dx%d -> %dx%d vb_index:%d\n",pcdev->host_width,pcdev->host_height,
pcdev->icd->user_width,pcdev->icd->user_height, vb->i);
@@ -801,7 +812,7 @@ static int rk_camera_scale_crop_rga(struct work_struct *work){
req.src.vir_w = pcdev->zoominfo.vir_width;
req.src.vir_h =pcdev->zoominfo.vir_height;
req.src.yrgb_addr = vipdata_base;
req.src.uv_addr =vipdata_base + req.src.vir_w*req.src.vir_h;
req.src.uv_addr =vipdata_base + pcdev->zoominfo.vir_width*pcdev->zoominfo.vir_height;;
req.src.v_addr = req.src.uv_addr ;
req.src.format =fmt->fourcc;
rk_pixfmt2rgafmt(fmt->fourcc,&req.src.format);
@@ -834,7 +845,7 @@ static int rk_camera_scale_crop_rga(struct work_struct *work){
rga_times = 3;
req.src.yrgb_addr = vipdata_base;
req.src.uv_addr =vipdata_base +req.src.vir_w *req.src.vir_h ;
req.src.uv_addr =vipdata_base + pcdev->zoominfo.vir_width*pcdev->zoominfo.vir_height;;
req.src.x_offset = pcdev->zoominfo.a.c.left+w*pcdev->zoominfo.a.c.width/scale_times;
req.src.y_offset = pcdev->zoominfo.a.c.top+h*pcdev->zoominfo.a.c.height/scale_times;
req.dst.x_offset = pcdev->icd->user_width*w/scale_times;
@@ -916,14 +927,14 @@ static int rk_camera_scale_crop_ipp(struct work_struct *work)
ipp_req.dst_vir_w = pcdev->icd->user_width;
rk_pixfmt2ippfmt(pcdev->pixfmt, &ipp_req.dst0.fmt);
vipdata_base = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
src_y_size = pcdev->host_width*pcdev->host_height; //vipmem
src_y_size = pcdev->zoominfo.vir_width*pcdev->zoominfo.vir_height; //vipmem
dst_y_size = pcdev->icd->user_width*pcdev->icd->user_height;
for (h=0; h<scale_times; h++) {
for (w=0; w<scale_times; w++) {
int ipp_times = 3;
src_y_offset = (pcdev->zoominfo.a.c.top + h*pcdev->zoominfo.a.c.height/scale_times)* pcdev->host_width
src_y_offset = (pcdev->zoominfo.a.c.top + h*pcdev->zoominfo.a.c.height/scale_times)* pcdev->zoominfo.vir_width
+ pcdev->zoominfo.a.c.left + w*pcdev->zoominfo.a.c.width/scale_times;
src_uv_offset = (pcdev->zoominfo.a.c.top + h*pcdev->zoominfo.a.c.height/scale_times)* pcdev->host_width/2
src_uv_offset = (pcdev->zoominfo.a.c.top + h*pcdev->zoominfo.a.c.height/scale_times)* pcdev->zoominfo.vir_width/2
+ pcdev->zoominfo.a.c.left + w*pcdev->zoominfo.a.c.width/scale_times;
dst_y_offset = pcdev->icd->user_width*pcdev->icd->user_height*h/scale_times + pcdev->icd->user_width*w/scale_times;
@@ -986,7 +997,7 @@ static int rk_camera_scale_crop_arm(struct work_struct *work)
src_phy = pcdev->vipmem_phybase + vb->i*pcdev->vipmem_bsize;
src = psY = (unsigned char*)(pcdev->vipmem_virbase + vb->i*pcdev->vipmem_bsize);
psUV = psY + pcdev->host_width*pcdev->host_height;
psUV = psY + pcdev->zoominfo.vir_width*pcdev->zoominfo.vir_height;;
srcW = pcdev->zoominfo.vir_width;
srcH = pcdev->zoominfo.vir_height;
@@ -1976,8 +1987,8 @@ static int rk_camera_set_fmt(struct soc_camera_device *icd,
pcdev->host_width = ratio*usr_w/10;
pcdev->host_height = ratio*usr_h/10;
//for ipp ,need 4 bit alligned.
pcdev->host_width &= ~0x03;
pcdev->host_height &= ~0x03;
pcdev->host_width &= ~CROP_ALIGN_BYTES;
pcdev->host_height &= ~CROP_ALIGN_BYTES;
RKCAMERA_DG("ratio = %d ,host:%d*%d\n",ratio,pcdev->host_width,pcdev->host_height);
}
else{ // needn't crop ,just scaled by ipp
@@ -2015,21 +2026,38 @@ static int rk_camera_set_fmt(struct soc_camera_device *icd,
pcdev->host_left = rect.left;
pcdev->host_top = rect.top;
down(&pcdev->zoominfo.sem);
pcdev->zoominfo.a.c.width = pcdev->host_width*100/pcdev->zoominfo.zoom_rate;
pcdev->zoominfo.a.c.width &= ~0x03;
pcdev->zoominfo.a.c.height = pcdev->host_height*100/pcdev->zoominfo.zoom_rate;
pcdev->zoominfo.a.c.height &= ~0x03;
//now digital zoom use ipp to do crop and scale
if(pcdev->zoominfo.zoom_rate != 100){
pcdev->zoominfo.a.c.left = ((pcdev->host_width - pcdev->zoominfo.a.c.width)>>1)&(~0x01);
pcdev->zoominfo.a.c.top = ((pcdev->host_height - pcdev->zoominfo.a.c.height)>>1)&(~0x01);
}
else{
pcdev->zoominfo.a.c.left = 0;
pcdev->zoominfo.a.c.top = 0;
}
pcdev->zoominfo.vir_width = pcdev->host_width;
down(&pcdev->zoominfo.sem);
#if CIF_DO_CROP
pcdev->zoominfo.a.c.left = 0;
pcdev->zoominfo.a.c.top = 0;
pcdev->zoominfo.a.c.width = pcdev->host_width*100/pcdev->zoominfo.zoom_rate;
pcdev->zoominfo.a.c.width &= ~CROP_ALIGN_BYTES;
pcdev->zoominfo.a.c.height = pcdev->host_height*100/pcdev->zoominfo.zoom_rate;
pcdev->zoominfo.a.c.height &= ~CROP_ALIGN_BYTES;
pcdev->zoominfo.vir_width = pcdev->zoominfo.a.c.width;
pcdev->zoominfo.vir_height = pcdev->zoominfo.a.c.height;
//recalculate the CIF width & height
rect.width = pcdev->zoominfo.a.c.width ;
rect.height = pcdev->zoominfo.a.c.height;
rect.left = (((pcdev->host_width - pcdev->zoominfo.a.c.width)>>1)&(~0x01))+pcdev->host_left;
rect.top = (((pcdev->host_height - pcdev->zoominfo.a.c.height)>>1)&(~0x01))+pcdev->host_top;
#else
pcdev->zoominfo.a.c.width = pcdev->host_width*100/pcdev->zoominfo.zoom_rate;
pcdev->zoominfo.a.c.width &= ~CROP_ALIGN_BYTES;
pcdev->zoominfo.a.c.height = pcdev->host_height*100/pcdev->zoominfo.zoom_rate;
pcdev->zoominfo.a.c.height &= ~CROP_ALIGN_BYTES;
//now digital zoom use ipp to do crop and scale
if(pcdev->zoominfo.zoom_rate != 100){
pcdev->zoominfo.a.c.left = ((pcdev->host_width - pcdev->zoominfo.a.c.width)>>1)&(~0x01);
pcdev->zoominfo.a.c.top = ((pcdev->host_height - pcdev->zoominfo.a.c.height)>>1)&(~0x01);
}
else{
pcdev->zoominfo.a.c.left = 0;
pcdev->zoominfo.a.c.top = 0;
}
pcdev->zoominfo.vir_width = pcdev->host_width;
pcdev->zoominfo.vir_height = pcdev->host_height;
#endif
up(&pcdev->zoominfo.sem);
/* ddl@rock-chips.com: IPP work limit check */
@@ -2647,24 +2675,63 @@ static int rk_camera_set_digit_zoom(struct soc_camera_device *icd,
struct v4l2_crop a;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct rk_camera_dev *pcdev = ici->priv;
unsigned long tmp_cifctrl;
int flags;
//change the crop and scale parameters
a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
#if CIF_DO_CROP
a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
//a.c.width = pcdev->host_width*100/zoom_rate;
a.c.width = pcdev->host_width*100/zoom_rate;
a.c.width &= ~0x03;
a.c.width &= ~CROP_ALIGN_BYTES;
a.c.height = pcdev->host_height*100/zoom_rate;
a.c.height &= ~0x03;
a.c.height &= ~CROP_ALIGN_BYTES;
a.c.left = ((pcdev->host_width - a.c.width)>>1)+pcdev->host_left;
a.c.top = ((pcdev->host_height - a.c.height)>>1)+pcdev->host_top;
pcdev->stop_cif = true;
tmp_cifctrl = read_cif_reg(pcdev->base,CIF_CIF_CTRL);
write_cif_reg(pcdev->base,CIF_CIF_CTRL, (tmp_cifctrl & ~ENABLE_CAPTURE));
hrtimer_cancel(&(pcdev->fps_timer.timer));
flush_workqueue((pcdev->camera_wq));
down(&pcdev->zoominfo.sem);
pcdev->zoominfo.a.c.left = 0;
pcdev->zoominfo.a.c.top = 0;
pcdev->zoominfo.a.c.width = a.c.width;
pcdev->zoominfo.a.c.height = a.c.height;
pcdev->zoominfo.vir_width = pcdev->zoominfo.a.c.width;
pcdev->zoominfo.vir_height = pcdev->zoominfo.a.c.height;
pcdev->frame_inval = 1;
write_cif_reg(pcdev->base,CIF_CIF_CROP, (a.c.left + (a.c.top<<16)));
write_cif_reg(pcdev->base,CIF_CIF_SET_SIZE, ((a.c.width ) + (a.c.height<<16)));
write_cif_reg(pcdev->base,CIF_CIF_VIR_LINE_WIDTH, a.c.width);
write_cif_reg(pcdev->base,CIF_CIF_FRAME_STATUS, 0x00000002);//frame1 has been ready to receive data,frame 2 is not used
if(pcdev->active)
rk_videobuf_capture(pcdev->active,pcdev);
if((tmp_cifctrl & ENABLE_CAPTURE) == 0)
write_cif_reg(pcdev->base,CIF_CIF_CTRL, (tmp_cifctrl | ENABLE_CAPTURE));
up(&pcdev->zoominfo.sem);
pcdev->stop_cif = false;
hrtimer_start(&(pcdev->fps_timer.timer),ktime_set(3, 0),HRTIMER_MODE_REL);
RKCAMERA_DG("%s..zoom_rate:%d (%dx%d at (%d,%d)-> %dx%d)\n",__FUNCTION__, zoom_rate,a.c.width, a.c.height, a.c.left, a.c.top, icd->user_width, icd->user_height );
#else
a.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
a.c.width = pcdev->host_width*100/zoom_rate;
a.c.width &= ~CROP_ALIGN_BYTES;
a.c.height = pcdev->host_height*100/zoom_rate;
a.c.height &= ~CROP_ALIGN_BYTES;
a.c.left = (pcdev->host_width - a.c.width)>>1;
a.c.top = (pcdev->host_height - a.c.height)>>1;
down(&pcdev->zoominfo.sem);
down(&pcdev->zoominfo.sem);
pcdev->zoominfo.a.c.height = a.c.height;
pcdev->zoominfo.a.c.width = a.c.width;
pcdev->zoominfo.a.c.top = a.c.top;
pcdev->zoominfo.a.c.left = a.c.left;
pcdev->zoominfo.vir_width = pcdev->host_width;
up(&pcdev->zoominfo.sem);
pcdev->zoominfo.vir_height= pcdev->host_height;
up(&pcdev->zoominfo.sem);
RKCAMERA_DG("%s..zoom_rate:%d (%dx%d at (%d,%d)-> %dx%d)\n",__FUNCTION__, zoom_rate,a.c.width, a.c.height, a.c.left, a.c.top, icd->user_width, icd->user_height );
#endif
return 0;
}
@@ -2790,6 +2857,7 @@ static int rk_camera_probe(struct platform_device *pdev)
struct rk_camera_frmivalenum *fival_list,*fival_nxt;
int irq,i;
int err = 0;
static int ipp_mem = 0;
RKCAMERA_DG("%s(%d) Enter..\n",__FUNCTION__,__LINE__);
@@ -2853,8 +2921,11 @@ static int rk_camera_probe(struct platform_device *pdev)
if (pcdev->pdata && IS_CIF0()) {
pcdev->vipmem_phybase = pcdev->pdata->meminfo.start;
pcdev->vipmem_size = pcdev->pdata->meminfo.size;
if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) {
if(ipp_mem > 0 && (pcdev->pdata->meminfo.start == pcdev->pdata->meminfo_cif1.start)){
RKCAMERA_TR("%s(%d): IPP Mem has been obtained \n",__FUNCTION__,__LINE__);
}
else if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) {
err = -EBUSY;
goto exit_ioremap_vipmem;
}
@@ -2863,13 +2934,16 @@ static int rk_camera_probe(struct platform_device *pdev)
dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n");
err = -ENXIO;
goto exit_ioremap_vipmem;
}
}
ipp_mem++;
RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size);
} else if (pcdev->pdata) {
pcdev->vipmem_phybase = pcdev->pdata->meminfo_cif1.start;
pcdev->vipmem_size = pcdev->pdata->meminfo_cif1.size;
if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) {
if(ipp_mem > 0 && (pcdev->pdata->meminfo.start == pcdev->pdata->meminfo_cif1.start)){
RKCAMERA_TR("%s(%d): IPP Mem has been obtained \n",__FUNCTION__,__LINE__);
}
else if (!request_mem_region(pcdev->vipmem_phybase,pcdev->vipmem_size,"rk29_vipmem")) {
err = -EBUSY;
goto exit_ioremap_vipmem;
}
@@ -2878,7 +2952,8 @@ static int rk_camera_probe(struct platform_device *pdev)
dev_err(pcdev->dev, "ioremap() of vip internal memory(Ex:IPP process/raw process) failed\n");
err = -ENXIO;
goto exit_ioremap_vipmem;
}
}
ipp_mem++;
RKCAMERA_TR("%s(%d): Memory(start:0x%x size:0x%x) for IPP obtain \n",__FUNCTION__,__LINE__, pcdev->pdata->meminfo.start,pcdev->pdata->meminfo.size);
} else {
RKCAMERA_TR("\n%s Memory for IPP have not obtain! IPP Function is fail\n",__FUNCTION__);