diff options
Diffstat (limited to 'drivers/media/video/samsung/fimc')
-rw-r--r-- | drivers/media/video/samsung/fimc/fimc.h | 1 | ||||
-rw-r--r-- | drivers/media/video/samsung/fimc/fimc_capture.c | 64 | ||||
-rw-r--r-- | drivers/media/video/samsung/fimc/fimc_dev.c | 54 | ||||
-rw-r--r-- | drivers/media/video/samsung/fimc/fimc_dev_u1.c | 54 |
4 files changed, 161 insertions, 12 deletions
diff --git a/drivers/media/video/samsung/fimc/fimc.h b/drivers/media/video/samsung/fimc/fimc.h index b648965..228a1c4 100644 --- a/drivers/media/video/samsung/fimc/fimc.h +++ b/drivers/media/video/samsung/fimc/fimc.h @@ -469,6 +469,7 @@ struct fimc_control { struct mutex lock; /* controller lock */ struct mutex v4l2_lock; spinlock_t outq_lock; + spinlock_t inq_lock; wait_queue_head_t wq; struct device *dev; #if defined(CONFIG_BUSFREQ_OPP) || defined(CONFIG_BUSFREQ_LOCK_WRAPPER) diff --git a/drivers/media/video/samsung/fimc/fimc_capture.c b/drivers/media/video/samsung/fimc/fimc_capture.c index 7d00c8b..f76345c 100644 --- a/drivers/media/video/samsung/fimc/fimc_capture.c +++ b/drivers/media/video/samsung/fimc/fimc_capture.c @@ -32,6 +32,10 @@ #include "fimc.h" +#ifdef CONFIG_MACH_KONA +extern fimc_is; +#endif + static struct pm_qos_request_list bus_qos_pm_qos_req; static const struct v4l2_fmtdesc capture_fmts[] = { @@ -816,6 +820,7 @@ static int fimc_configure_subdev(struct fimc_control *ctrl) if (!sd) { fimc_err("%s: v4l2 subdev board registering failed\n", __func__); + return -ENODEV; } /* Assign subdev to proper camera device pointer */ ctrl->cam->sd = sd; @@ -1435,7 +1440,7 @@ int fimc_s_fmt_vid_private(struct file *file, void *fh, struct v4l2_format *f) mbus_fmt = &ctrl->cap->mbus_fmt; mbus_fmt->width = pix->width; mbus_fmt->height = pix->height; -#ifdef CONFIG_MACH_P4NOTE +#if defined(CONFIG_MACH_P4NOTE) /* Unfortuntely, we have to use pix->field (not pix->priv) since * pix.field is already used in the below else condtion statement * (in case that sub-devices are not registered) @@ -1445,6 +1450,11 @@ int fimc_s_fmt_vid_private(struct file *file, void *fh, struct v4l2_format *f) #if defined(CONFIG_MACH_GC1) mbus_fmt->field = pix->priv; #endif + +#if defined(CONFIG_MACH_KONA) + if(!fimc_is) + mbus_fmt->field = pix->field; +#endif printk(KERN_INFO "%s mbus_fmt->width = %d, height = %d,\n", __func__,mbus_fmt->width ,mbus_fmt->height); @@ -1927,6 +1937,8 @@ int fimc_reqbufs_capture_mmap(void *fh, struct v4l2_requestbuffers *b) case V4L2_PIX_FMT_YVYU: /* fall through */ case V4L2_PIX_FMT_NV16: /* fall through */ case V4L2_PIX_FMT_NV61: /* fall through */ + fimc_err("%s : w %d h %d \n",__func__, + cap->fmt.width, cap->fmt.height); fimc_info1("%s : 1plane\n", __func__); ret = fimc_alloc_buffers(ctrl, 1, cap->fmt.width * cap->fmt.height, SZ_4K, bpp, cap->pktdata_enable, cap->pktdata_size); @@ -1940,6 +1952,7 @@ int fimc_reqbufs_capture_mmap(void *fh, struct v4l2_requestbuffers *b) break; case V4L2_PIX_FMT_NV12: + fimc_info1("%s : 2plane for NV12\n", __func__); ret = fimc_alloc_buffers(ctrl, 2, cap->fmt.width * cap->fmt.height, SZ_64K, bpp, cap->pktdata_enable, cap->pktdata_size); @@ -2143,6 +2156,7 @@ int fimc_querybuf_capture(void *fh, struct v4l2_buffer *b) int fimc_g_ctrl_capture(void *fh, struct v4l2_control *c) { struct fimc_control *ctrl = fh; + struct v4l2_frmsizeenum cam_frmsize; int ret = 0; fimc_dbg("%s\n", __func__); @@ -2164,6 +2178,24 @@ int fimc_g_ctrl_capture(void *fh, struct v4l2_control *c) c->value = ctrl->cap->cacheable; break; + case V4L2_CID_CAMERA_SENSOR_OUTPUT_SIZE: + cam_frmsize.index = -1; + cam_frmsize.discrete.width = 0; + cam_frmsize.discrete.height = 0; + + ret = v4l2_subdev_call(ctrl->cam->sd, video, enum_framesizes, + &cam_frmsize); + if (ret < 0) { + dev_err(ctrl->dev, "%s: enum_framesizes failed\n", + __func__); + if (ret != -ENOIOCTLCMD) + return ret; + } else { + c->value = (cam_frmsize.discrete.width << 16)|(cam_frmsize.discrete.height&0xFFFF); + dev_err(ctrl->dev,"sensor_output (%d, %d)\n", cam_frmsize.discrete.width, cam_frmsize.discrete.height); + } + break; + default: /* get ctrl supported by subdev */ /* WriteBack doesn't have subdev_call */ @@ -2248,7 +2280,7 @@ int fimc_s_ctrl_capture(void *fh, struct v4l2_control *c) clk_disable(ctrl->cam->clk); fimc->mclk_status = CAM_MCLK_OFF; ctrl->cam->initialized = 0; -#ifdef CONFIG_MACH_P4NOTE +#if defined(CONFIG_MACH_P4NOTE) || defined(CONFIG_MACH_KONA) /* 100ms: increase delay. * There are cases that sensor doesn't get revived * inspite of doing power reset.*/ @@ -2723,7 +2755,7 @@ int fimc_streamon_capture(void *fh) } } -#ifdef CONFIG_MACH_P4NOTE +#if defined(CONFIG_MACH_P4NOTE) || defined(CONFIG_MACH_KONA) #ifdef CONFIG_VIDEO_IMPROVE_STREAMOFF v4l2_subdev_call(cam->sd, video, s_stream, STREAM_MODE_WAIT_OFF); @@ -2753,7 +2785,7 @@ int fimc_streamon_capture(void *fh) cap->fmt.pixelformat); } } -#ifdef CONFIG_MACH_P4NOTE +#if defined(CONFIG_MACH_P4NOTE) || defined(CONFIG_MACH_KONA) if (1) { #else if (cap->fmt.priv != V4L2_PIX_FMT_MODE_CAPTURE) { @@ -2930,9 +2962,20 @@ int fimc_streamon_capture(void *fh) fimc_start_capture(ctrl); ctrl->status = FIMC_STREAMON; - if (ctrl->is.sd && fimc_cam_use) + if (ctrl->is.sd && fimc_cam_use) { ret = v4l2_subdev_call(ctrl->is.sd, video, s_stream, 1); - printk(KERN_INFO "%s-- fimc%d\n", __func__, ctrl->id); + if (ret < 0) { + dev_err(ctrl->dev, "%s: s_stream failed\n", + __func__); + if (cam->type == CAM_TYPE_MIPI) { + if (cam->id == CAMERA_CSI_C) + s3c_csis_stop(CSI_CH_0); + else + s3c_csis_stop(CSI_CH_1); + } + return ret; + } + } /* if available buffer did not remained */ return 0; @@ -3135,17 +3178,16 @@ int fimc_qbuf_capture(void *fh, struct v4l2_buffer *b) int available_bufnum; size_t length = 0; int i; + unsigned long spin_flags; if (!cap || !ctrl->cam) { fimc_err("%s: No capture device.\n", __func__); return -ENODEV; } - mutex_lock(&ctrl->v4l2_lock); if (pdata->hw_ver >= 0x51) { if (cap->bufs[idx].state != VIDEOBUF_IDLE) { fimc_err("%s: invalid state idx : %d\n", __func__, idx); - mutex_unlock(&ctrl->v4l2_lock); return -EINVAL; } else { if (b->memory == V4L2_MEMORY_USERPTR) { @@ -3167,7 +3209,6 @@ int fimc_qbuf_capture(void *fh, struct v4l2_buffer *b) if (ret < 0) { fimc_err("%s: _qbuf_dmabuf error.\n", __func__); - mutex_unlock(&ctrl->v4l2_lock); return -ENODEV; } for (i = 0; i < vb->num_planes; i++) { @@ -3181,7 +3222,6 @@ int fimc_qbuf_capture(void *fh, struct v4l2_buffer *b) } else { fimc_err("%s: Wrong sg value.\n", __func__); - mutex_unlock(&ctrl->v4l2_lock); return -ENODEV; } } @@ -3203,6 +3243,7 @@ int fimc_qbuf_capture(void *fh, struct v4l2_buffer *b) #endif } + spin_lock_irqsave(&ctrl->inq_lock, spin_flags); fimc_hwset_output_buf_sequence(ctrl, idx, FIMC_FRAMECNT_SEQ_ENABLE); cap->bufs[idx].state = VIDEOBUF_QUEUED; if (ctrl->status == FIMC_BUFFER_STOP) { @@ -3217,13 +3258,12 @@ int fimc_qbuf_capture(void *fh, struct v4l2_buffer *b) ctrl->restart = true; } } + spin_unlock_irqrestore(&ctrl->inq_lock, spin_flags); } } else { fimc_add_inqueue(ctrl, b->index); } - mutex_unlock(&ctrl->v4l2_lock); - if (!cap->cacheable) return 0; diff --git a/drivers/media/video/samsung/fimc/fimc_dev.c b/drivers/media/video/samsung/fimc/fimc_dev.c index 1ed79dd..4822587 100644 --- a/drivers/media/video/samsung/fimc/fimc_dev.c +++ b/drivers/media/video/samsung/fimc/fimc_dev.c @@ -898,6 +898,50 @@ static struct vm_operations_struct fimc_mmap_ops = { }; static inline +int fimc_mmap_own_mem(struct file *filp, struct vm_area_struct *vma) +{ + struct fimc_prv_data *prv_data = + (struct fimc_prv_data *)filp->private_data; + struct fimc_control *ctrl = prv_data->ctrl; + u32 start_phy_addr = 0; + u32 size = vma->vm_end - vma->vm_start; + u32 pfn, idx = vma->vm_pgoff; + u32 buf_length = 0; + + buf_length = ctrl->mem.size; + if (size > PAGE_ALIGN(buf_length)) { + fimc_err("Requested mmap size is too big\n"); + return -EINVAL; + } + + start_phy_addr = ctrl->mem.base + (vma->vm_pgoff << PAGE_SHIFT); + + if (!cma_is_registered_region(start_phy_addr, size)) { + pr_err("[%s] handling non-cma region (%#x@%#x)is prohibited\n", + __func__, buf_length, start_phy_addr); + return -EINVAL; + } + + /* only supports non-cached mmap */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_RESERVED; + + if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) { + fimc_err("writable mapping must be shared\n"); + return -EINVAL; + } + + pfn = __phys_to_pfn(start_phy_addr); + + if (remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot)) { + fimc_err("mmap fail\n"); + return -EINVAL; + } + + return 0; +} + +static inline int fimc_mmap_out_src(struct file *filp, struct vm_area_struct *vma) { struct fimc_prv_data *prv_data = @@ -981,10 +1025,14 @@ static inline int fimc_mmap_out(struct file *filp, struct vm_area_struct *vma) int idx = ctrl->out->ctx[ctx_id].overlay.req_idx; int ret = -1; +#if 0 if (idx >= 0) ret = fimc_mmap_out_dst(filp, vma, idx); else if (idx == FIMC_MMAP_IDX) ret = fimc_mmap_out_src(filp, vma); +#else + ret = fimc_mmap_own_mem(filp, vma); +#endif return ret; } @@ -1002,6 +1050,12 @@ static inline int fimc_mmap_cap(struct file *filp, struct vm_area_struct *vma) vma->vm_flags |= VM_RESERVED; + if (!cma_is_registered_region(ctrl->cap->bufs[idx].base[0], size)) { + pr_err("[%s] handling non-cma region (%#x@%#x)is prohibited\n", + __func__, size, ctrl->cap->bufs[idx].base[0]); + return -EINVAL; + } + /* * page frame number of the address for a source frame * to be stored at. diff --git a/drivers/media/video/samsung/fimc/fimc_dev_u1.c b/drivers/media/video/samsung/fimc/fimc_dev_u1.c index 811ac96..52246a1 100644 --- a/drivers/media/video/samsung/fimc/fimc_dev_u1.c +++ b/drivers/media/video/samsung/fimc/fimc_dev_u1.c @@ -745,6 +745,50 @@ static struct vm_operations_struct fimc_mmap_ops = { }; static inline +int fimc_mmap_own_mem(struct file *filp, struct vm_area_struct *vma) +{ + struct fimc_prv_data *prv_data = + (struct fimc_prv_data *)filp->private_data; + struct fimc_control *ctrl = prv_data->ctrl; + u32 start_phy_addr = 0; + u32 size = vma->vm_end - vma->vm_start; + u32 pfn, idx = vma->vm_pgoff; + u32 buf_length = 0; + + buf_length = ctrl->mem.size; + if (size > PAGE_ALIGN(buf_length)) { + fimc_err("Requested mmap size is too big\n"); + return -EINVAL; + } + + start_phy_addr = ctrl->mem.base + (vma->vm_pgoff << PAGE_SHIFT); + + if (!cma_is_registered_region(start_phy_addr, size)) { + pr_err("[%s] handling non-cma region (%#x@%#x)is prohibited\n", + __func__, buf_length, start_phy_addr); + return -EINVAL; + } + + /* only supports non-cached mmap */ + vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); + vma->vm_flags |= VM_RESERVED; + + if ((vma->vm_flags & VM_WRITE) && !(vma->vm_flags & VM_SHARED)) { + fimc_err("writable mapping must be shared\n"); + return -EINVAL; + } + + pfn = __phys_to_pfn(start_phy_addr); + + if (remap_pfn_range(vma, vma->vm_start, pfn, size, vma->vm_page_prot)) { + fimc_err("mmap fail\n"); + return -EINVAL; + } + + return 0; +} + +static inline int fimc_mmap_out_src(struct file *filp, struct vm_area_struct *vma) { struct fimc_prv_data *prv_data = @@ -829,10 +873,14 @@ static inline int fimc_mmap_out(struct file *filp, struct vm_area_struct *vma) int idx = ctrl->out->ctx[ctx_id].overlay.req_idx; int ret = -1; +#if 0 if (idx >= 0) ret = fimc_mmap_out_dst(filp, vma, idx); else if (idx == FIMC_MMAP_IDX) ret = fimc_mmap_out_src(filp, vma); +#else + ret = fimc_mmap_own_mem(filp, vma); +#endif return ret; } @@ -849,6 +897,12 @@ static inline int fimc_mmap_cap(struct file *filp, struct vm_area_struct *vma) vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); vma->vm_flags |= VM_RESERVED; + if (!cma_is_registered_region(ctrl->cap->bufs[idx].base[0], size)) { + pr_err("[%s] handling non-cma region (%#x@%#x)is prohibited\n", + __func__, size, ctrl->cap->bufs[idx].base[0]); + return -EINVAL; + } + /* * page frame number of the address for a source frame * to be stored at. |