From: Sergio Aguirre <saaguirre@xxxxxx> OMAP: CAM: Add MMS Kernel changes This adds MMS changes to the OMAP34xx camera driver. Including: - HQ capture NOTE: Credits to MMS crew for all this. Signed-off-by: Sergio Aguirre <saaguirre@xxxxxx> --- drivers/media/video/isp/omap_previewer.c | 392 +++++++++++++++++++++++-------- drivers/media/video/isp/omap_previewer.h | 22 + 2 files changed, 309 insertions(+), 105 deletions(-) Index: omapkernel/drivers/media/video/isp/omap_previewer.c =================================================================== --- omapkernel.orig/drivers/media/video/isp/omap_previewer.c 2008-10-15 19:25:00.000000000 -0500 +++ omapkernel/drivers/media/video/isp/omap_previewer.c 2008-10-15 19:53:07.000000000 -0500 @@ -38,6 +38,24 @@ #define OMAP_PREV_NAME "omap-previewer" +#define BIT_SET(var, shift, mask, val) \ + do { \ + var = (var & ~(mask << shift)) \ + | (val << shift); \ + } while (0) + +/* +#define OMAP_ISP_PREVIEWER_DEBUG +*/ +#undef OMAP_ISP_PREVIEWER_DEBUG + +#ifdef OMAP_ISP_PREVIEWER_DEBUG +#define DPRINTK_PREVIEWER(format, ...) \ + printk(KERN_DEBUG "PREV: " format, ## __VA_ARGS__) +#else +#define DPRINTK_PREVIEWER(format, ...) +#endif + static int prev_major = -1; static struct device *prev_dev; static struct class *prev_class; @@ -45,6 +63,7 @@ static struct platform_driver omap_previewer_driver; static u32 prev_bufsize; +static u32 lsc_bufsize; /** * prev_calculate_crop - Calculate crop size according to device parameters @@ -119,6 +138,10 @@ isppreview_enable_hmed(0); if (config->features & PREV_DARK_FRAME_SUBTRACT) { + DPRINTK_PREVIEWER("[%s] darkaddr %08x, darklineoffset %d\n", + __func__, + config->drkf_params.addr, + config->drkf_params.offset); isppreview_set_darkaddr(config->drkf_params.addr); isppreview_config_darklineoffset(config->drkf_params.offset); isppreview_enable_drkframe(1); @@ -200,28 +223,11 @@ goto err_einval; } - if (params->features & PREV_DARK_FRAME_SUBTRACT) - if (!params->drkf_params.addr - || (params->drkf_params.offset % 32)) { - dev_err(prev_dev, "validate_params: dark frame " - "address\n"); - goto err_einval; - } - - if (params->features & PREV_LENS_SHADING) - if ((params->lens_shading_shift > 7) - || !params->drkf_params.addr - || (params->drkf_params.offset % 32)) { - dev_err(prev_dev, "validate_params: lens shading " - "shift\n"); - goto err_einval; - } - if ((params->size_params.in_pitch <= 0) || (params->size_params.in_pitch % 32)) { params->size_params.in_pitch = (params->size_params.hsize * 2) & 0xFFE0; - dev_err(prev_dev, "\nError in in_pitch; new value = %d", + dev_err(prev_dev, "Error in in_pitch; new value = %d", params->size_params.in_pitch); } @@ -248,6 +254,40 @@ complete(&device->wfc); } +#define ISP_CTRL_SBL_SHARED_RPORTB (1 << 28) +#define ISP_CTRL_SBL_SHARED_RPORTA (1 << 27) +#define SBL_SHARED_RPORTB 28 +#define CBUFF1_BCF_CTRL 24 +#define CBUFF0_BCF_CTRL 22 +#define SBL_RD_RAM_EN 18 +#define SHIFT 6 + +static void previewer_set_isp_ctrl(void) +{ + u32 val; + + val = omap_readl(ISP_CTRL); + + /* Read port used by preview module data read */ + val &= ~ISP_CTRL_SBL_SHARED_RPORTA; + + /* Read port used by preview module dark frame read */ + val &= ~ISP_CTRL_SBL_SHARED_RPORTB; + + BIT_SET(val, CBUFF1_BCF_CTRL, 0x3, 0x01); + BIT_SET(val, CBUFF0_BCF_CTRL, 0x3, 0x01); + BIT_SET(val, SBL_RD_RAM_EN, 0x1, 0x1); + BIT_SET(val, SHIFT, 0x3, 0x00); + + /* write ISP CTRL register */ + omap_writel(val, ISP_CTRL); + +#define TCTRL_CTRL 0x480BC050 +#define TCTRL_FRAME 0x480BC054 + omap_writel(0x00000004, TCTRL_CTRL); + omap_writel(0x000C0000, TCTRL_FRAME); +} + /** * prev_do_preview - Performs the Preview process * @device: Structure containing ISP preview wrapper global information @@ -268,25 +308,23 @@ return -EINVAL; } + previewer_set_isp_ctrl(); + if (device->params->size_params.pixsize == PREV_INWIDTH_8BIT) bpp = 1; else bpp = 2; size = device->params->size_params.hsize * - device->params->size_params.vsize * bpp; + device->params->size_params.vsize * bpp; - ret = isppreview_set_inaddr(device->isp_addr_read); - if (ret) - goto out; - - ret = isppreview_set_outaddr(device->isp_addr_read); - if (ret) - goto out; + isppreview_config_datapath(PRV_RAW_MEM, PREVIEW_MEM); isppreview_try_size(device->params->size_params.hsize, device->params->size_params.vsize, - &out_hsize, &out_vsize); + &out_hsize, + &out_vsize); + ret = isppreview_config_inlineoffset(device->params->size_params.hsize * bpp); @@ -302,10 +340,18 @@ ret = isppreview_config_size(device->params->size_params.hsize, device->params->size_params.vsize, out_hsize, out_vsize); + + device->params->drkf_params.addr = device->isp_addr_lsc; + + prev_hw_setup(device->params); + + ret = isppreview_set_inaddr(device->isp_addr_read); if (ret) goto out; - isppreview_config_datapath(PRV_RAW_MEM, PREVIEW_MEM); + ret = isppreview_set_outaddr(device->isp_addr_read); + if (ret) + goto out; ret = isp_set_callback(CBK_PREV_DONE, preview_isr, (void *)device, (void *)NULL); @@ -317,11 +363,6 @@ wait_for_completion_interruptible(&device->wfc); - if (device->isp_addr_read) { - ispmmu_unmap(device->isp_addr_read); - device->isp_addr_read = 0; - } - ret = isp_unset_callback(CBK_PREV_DONE); dev_dbg(prev_dev, "prev_do_preview L\n"); @@ -340,11 +381,25 @@ struct prev_fh *fh = q->priv_data; struct prev_device *device = fh->device; - ispmmu_unmap(device->isp_addr_read); - device->isp_addr_read = 0; - spin_lock(&device->vbq_lock); - vb->state = VIDEOBUF_NEEDS_INIT; - spin_unlock(&device->vbq_lock); + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + ispmmu_unmap(device->isp_addr_read); + device->isp_addr_read = 0; + spin_lock(&device->inout_vbq_lock); + vb->state = VIDEOBUF_NEEDS_INIT; + spin_unlock(&device->inout_vbq_lock); + } else if (q->type == V4L2_BUF_TYPE_PRIVATE) { + ispmmu_unmap(device->isp_addr_lsc); + device->isp_addr_lsc = 0; + spin_lock(&device->lsc_vbq_lock); + vb->state = VIDEOBUF_NEEDS_INIT; + spin_unlock(&device->lsc_vbq_lock); + } + + if (vb->memory != V4L2_MEMORY_MMAP) { + videobuf_dma_unmap(q, videobuf_to_dma(vb)); + videobuf_dma_free(videobuf_to_dma(vb)); + } + dev_dbg(prev_dev, "previewer_vbq_release\n"); } @@ -364,25 +419,52 @@ struct prev_device *device = fh->device; u32 bpp = 1; - spin_lock(&device->vbq_lock); - if (*cnt <= 0) - *cnt = VIDEO_MAX_FRAME; - - if (*cnt > VIDEO_MAX_FRAME) - *cnt = VIDEO_MAX_FRAME; - - if (!device->params->size_params.hsize || - !device->params->size_params.vsize) { - dev_err(prev_dev, "Can't setup buffer size\n"); - spin_unlock(&device->vbq_lock); + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + spin_lock(&device->inout_vbq_lock); + + if (*cnt <= 0) + *cnt = 1; + + if (*cnt > VIDEO_MAX_FRAME) + *cnt = VIDEO_MAX_FRAME; + + if (!device->params->size_params.hsize || + !device->params->size_params.vsize) { + dev_err(prev_dev, "Can't setup buffer size\n"); + spin_unlock(&device->inout_vbq_lock); + return -EINVAL; + } + + if (device->params->size_params.pixsize == PREV_INWIDTH_10BIT) + bpp = 2; + *size = prev_bufsize = bpp * device->params->size_params.hsize + * device->params->size_params.vsize; + spin_unlock(&device->inout_vbq_lock); + } else if (q->type == V4L2_BUF_TYPE_PRIVATE) { + spin_lock(&device->lsc_vbq_lock); + if (*cnt <= 0) + *cnt = 1; + + if (*cnt > 1) + *cnt = 1; + + if (!device->params->size_params.hsize || + !device->params->size_params.vsize) { + dev_err(prev_dev, "Can't setup lsc buffer size\n"); + spin_unlock(&device->lsc_vbq_lock); + return -EINVAL; + } + + /* upsampled lsc table size - for now bpp = 2 */ + bpp = 2; + *size = lsc_bufsize = bpp * device->params->size_params.hsize + * device->params->size_params.vsize; + + spin_unlock(&device->lsc_vbq_lock); + } else { return -EINVAL; } - if (device->params->size_params.pixsize == PREV_INWIDTH_10BIT) - bpp = 2; - *size = prev_bufsize = bpp * device->params->size_params.hsize - * device->params->size_params.vsize; - spin_unlock(&device->vbq_lock); dev_dbg(prev_dev, "previewer_vbq_setup\n"); return 0; } @@ -407,38 +489,103 @@ struct videobuf_dmabuf *dma = videobuf_to_dma(vb); dev_dbg(prev_dev, "previewer_vbq_prepare E\n"); - spin_lock(&device->vbq_lock); - if (vb->baddr) { - vb->size = prev_bufsize; - vb->bsize = prev_bufsize; - } else { - spin_unlock(&device->vbq_lock); - dev_err(prev_dev, "No user buffer allocated\n"); - goto out; - } - vb->width = device->params->size_params.hsize; - vb->height = device->params->size_params.vsize; - vb->field = field; - spin_unlock(&device->vbq_lock); + if (q->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) { + spin_lock(&device->inout_vbq_lock); + + if (vb->baddr) { + vb->size = prev_bufsize; + vb->bsize = prev_bufsize; + DPRINTK_PREVIEWER("[%s] bsize = %d\n", __func__, + vb->bsize); + } else { + spin_unlock(&device->inout_vbq_lock); + dev_err(prev_dev, "No user buffer allocated\n"); + goto out; + } + + vb->width = device->params->size_params.hsize; + vb->height = device->params->size_params.vsize; + vb->field = field; + spin_unlock(&device->inout_vbq_lock); + + if (vb->state == VIDEOBUF_NEEDS_INIT) { + DPRINTK_PREVIEWER("[%s] baddr = %08x\n", __func__, + (int)vb->baddr); + err = videobuf_iolock(q, vb, NULL); + if (!err) { + isp_addr = ispmmu_map_sg(dma->sglist, + dma->sglen); + + if (!isp_addr) { + err = -EIO; + } else { + device->isp_addr_read = isp_addr; + DPRINTK_PREVIEWER("[%s] " + "isp_addr_read = %08x\n", + __func__, isp_addr); + } + } + } - if (vb->state == VIDEOBUF_NEEDS_INIT) { - err = videobuf_iolock(q, vb, NULL); if (!err) { - isp_addr = ispmmu_map_sg(dma->sglist, dma->sglen); - if (!isp_addr) - err = -EIO; - else - device->isp_addr_read = isp_addr; + vb->state = VIDEOBUF_PREPARED; + flush_cache_user_range(NULL, vb->baddr, (vb->baddr + + vb->bsize)); + } else { + previewer_vbq_release(q, vb); } - } - if (!err) { - vb->state = VIDEOBUF_PREPARED; - flush_cache_user_range(NULL, vb->baddr, - (vb->baddr + vb->bsize)); - } else - previewer_vbq_release(q, vb); + } else if (q->type == V4L2_BUF_TYPE_PRIVATE) { + + spin_lock(&device->lsc_vbq_lock); + + if (vb->baddr) { + vb->size = lsc_bufsize; + vb->bsize = lsc_bufsize; + DPRINTK_PREVIEWER("[%s] bsize = %d\n", __func__, + vb->bsize); + } else { + spin_unlock(&device->lsc_vbq_lock); + dev_err(prev_dev, "No user buffer allocated\n"); + goto out; + } + + vb->width = device->params->size_params.hsize; + vb->height = device->params->size_params.vsize; + vb->field = field; + spin_unlock(&device->lsc_vbq_lock); + + if (vb->state == VIDEOBUF_NEEDS_INIT) { + DPRINTK_PREVIEWER("[%s] baddr = %08x\n", __func__, + (int)vb->baddr); + err = videobuf_iolock(q, vb, NULL); + if (!err) { + isp_addr = ispmmu_map_sg(dma->sglist, + dma->sglen); + if (!isp_addr) { + err = -EIO; + } else { + device->isp_addr_lsc = isp_addr; + DPRINTK_PREVIEWER("[%s] isp_addr_lsc =" + " %08x\n", + __func__, + isp_addr); + } + } + } + + if (!err) { + vb->state = VIDEOBUF_PREPARED; + flush_cache_user_range(NULL, vb->baddr, (vb->baddr + + vb->bsize)); + } else { + previewer_vbq_release(q, vb); + } + + } else { + return -EINVAL; + } dev_dbg(prev_dev, "previewer_vbq_prepare L\n"); out: @@ -495,11 +642,17 @@ device->opened = 1; filp->private_data = fh; - fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fh->inout_type = V4L2_BUF_TYPE_VIDEO_CAPTURE; + fh->lsc_type = V4L2_BUF_TYPE_PRIVATE; fh->device = device; - videobuf_queue_sg_init(&fh->vbq, &device->vbq_ops, NULL, - &device->vbq_lock, fh->type, + videobuf_queue_sg_init(&fh->inout_vbq, &device->vbq_ops, NULL, + &device->inout_vbq_lock, fh->inout_type, + V4L2_FIELD_NONE, + sizeof(struct videobuf_buffer), fh); + + videobuf_queue_sg_init(&fh->lsc_vbq, &device->vbq_ops, NULL, + &device->lsc_vbq_lock, fh->lsc_type, V4L2_FIELD_NONE, sizeof(struct videobuf_buffer), fh); @@ -521,14 +674,17 @@ { struct prev_fh *fh = filp->private_data; struct prev_device *device = fh->device; - struct videobuf_queue *q = &fh->vbq; + struct videobuf_queue *q1 = &fh->inout_vbq; + struct videobuf_queue *q2 = &fh->lsc_vbq; device->opened = 0; device->params = NULL; isppreview_free(); isp_put(); - videobuf_mmap_free(q); + videobuf_mmap_free(q1); + videobuf_mmap_free(q2); prev_bufsize = 0; + lsc_bufsize = 0; filp->private_data = NULL; kfree(fh); @@ -546,10 +702,7 @@ **/ static int previewer_mmap(struct file *file, struct vm_area_struct *vma) { - struct prev_fh *fh = file->private_data; - dev_dbg(prev_dev, "previewer_mmap\n"); - - return videobuf_mmap_mapper(&fh->vbq, vma); + return -EINVAL; } /** @@ -590,40 +743,83 @@ switch (cmd) { case PREV_REQBUF: + { + struct v4l2_requestbuffers *req; + if (mutex_lock_interruptible(&device->prevwrap_mutex)) goto err_eintr; - ret = videobuf_reqbufs(&fh->vbq, (void *)arg); + + req = (struct v4l2_requestbuffers *) arg; + + if (req->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + ret = videobuf_reqbufs(&fh->inout_vbq, (void *) arg); + else if (req->type == V4L2_BUF_TYPE_PRIVATE) + ret = videobuf_reqbufs(&fh->lsc_vbq, (void *) arg); + else + ret = -EINVAL; + mutex_unlock(&device->prevwrap_mutex); break; + } case PREV_QUERYBUF: + { + struct v4l2_buffer *b; + if (mutex_lock_interruptible(&device->prevwrap_mutex)) goto err_eintr; - ret = videobuf_querybuf(&fh->vbq, (void *)arg); + b = (struct v4l2_buffer *) arg; + + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + ret = videobuf_querybuf(&fh->inout_vbq, (void *) arg); + else if (b->type == V4L2_BUF_TYPE_PRIVATE) + ret = videobuf_querybuf(&fh->lsc_vbq, (void *) arg); + else + ret = -EINVAL; + mutex_unlock(&device->prevwrap_mutex); break; + } case PREV_QUEUEBUF: + { + struct v4l2_buffer *b; + if (mutex_lock_interruptible(&device->prevwrap_mutex)) goto err_eintr; - ret = videobuf_qbuf(&fh->vbq, (void *)arg); + + b = (struct v4l2_buffer *) arg; + if (b->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) + ret = videobuf_qbuf(&fh->inout_vbq, (void *) arg); + else if (b->type == V4L2_BUF_TYPE_PRIVATE) + ret = videobuf_qbuf(&fh->lsc_vbq, (void *) arg); + else + ret = -EINVAL; + mutex_unlock(&device->prevwrap_mutex); break; + } case PREV_SET_PARAM: if (mutex_lock_interruptible(&device->prevwrap_mutex)) goto err_eintr; + DPRINTK_PREVIEWER("%s PREV_SET_PARAMS before copy from user:\n", + __func__); if (copy_from_user(¶ms, (struct prev_params *)arg, sizeof(struct prev_params))) { mutex_unlock(&device->prevwrap_mutex); return -EFAULT; } + DPRINTK_PREVIEWER("%s PREV_SET_PARAMS before prev validate " + "params:\n", __func__); ret = prev_validate_params(¶ms); if (ret < 0) { dev_err(prev_dev, "Error validating parameters!\n"); mutex_unlock(&device->prevwrap_mutex); goto out; } + DPRINTK_PREVIEWER("%s PREV_SET_PARAMSbefore memcopy:\n", + __func__); if (device->params) memcpy(device->params, ¶ms, sizeof(struct prev_params)); @@ -632,7 +828,7 @@ return -EINVAL; } - ret = prev_hw_setup(device->params); + /* ret = prev_hw_setup(device->params); */ mutex_unlock(&device->prevwrap_mutex); break; @@ -654,13 +850,13 @@ break; case PREV_GET_CROPSIZE: - { + { struct prev_cropsize outputsize; prev_calculate_crop(device, &outputsize); if (copy_to_user((struct prev_cropsize *)arg, &outputsize, sizeof(struct prev_cropsize))) ret = -EFAULT; - } + } break; default: @@ -792,8 +988,8 @@ device->vbq_ops.buf_prepare = previewer_vbq_prepare; device->vbq_ops.buf_release = previewer_vbq_release; device->vbq_ops.buf_queue = previewer_vbq_queue; - spin_lock_init(&device->vbq_lock); - + spin_lock_init(&device->inout_vbq_lock); + spin_lock_init(&device->lsc_vbq_lock); prevdevice = device; return 0; Index: omapkernel/drivers/media/video/isp/omap_previewer.h =================================================================== --- omapkernel.orig/drivers/media/video/isp/omap_previewer.h 2008-10-15 19:25:00.000000000 -0500 +++ omapkernel/drivers/media/video/isp/omap_previewer.h 2008-10-15 19:54:02.000000000 -0500 @@ -134,29 +134,37 @@ * @opened: State of the device. * @wfc: Wait for completion. Used for locking operations. * @prevwrap_mutex: Mutex for preview wrapper use. - * @vbq_lock: Spinlock for videobuf queues. + * @inout_vbq_lock: Spinlock for in/out videobuf queues. + * @lsc_vbq_lock: Spinlock for LSC videobuf queues. * @vbq_ops: Videobuf queue operations * @isp_addr_read: Input/Output address + * @isp_addr_read: LSC address */ struct prev_device { struct prev_params *params; unsigned char opened; struct completion wfc; - struct mutex prevwrap_mutex; /* For generic internal use */ - spinlock_t vbq_lock; /* For videobuffer queue handling */ + struct mutex prevwrap_mutex; + spinlock_t inout_vbq_lock; /* Spinlock for in/out videobuf queues. */ + spinlock_t lsc_vbq_lock; /* Spinlock for LSC videobuf queues. */ struct videobuf_queue_ops vbq_ops; dma_addr_t isp_addr_read; + dma_addr_t isp_addr_lsc; }; /** * struct prev_fh - Per-filehandle data structure - * @type: Used buffer type. - * @vbq: Videobuffer queue. + * @inout_type: Used buffer type for I/O. + * @inout_vbq: I/O Videobuffer queue. + * @lsc_type: Used buffer type for LSC. + * @lsc_vbq: LSC Videobuffer queue. * @device: Pointer to device information structure. */ struct prev_fh { - enum v4l2_buf_type type; - struct videobuf_queue vbq; + enum v4l2_buf_type inout_type; + struct videobuf_queue inout_vbq; + enum v4l2_buf_type lsc_type; + struct videobuf_queue lsc_vbq; struct prev_device *device; }; #endif -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html