aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/video/samsung/fimc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video/samsung/fimc')
-rw-r--r--drivers/media/video/samsung/fimc/fimc.h1
-rw-r--r--drivers/media/video/samsung/fimc/fimc_capture.c64
-rw-r--r--drivers/media/video/samsung/fimc/fimc_dev.c54
-rw-r--r--drivers/media/video/samsung/fimc/fimc_dev_u1.c54
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.