camera: Store the data offsets for each planes.

- When the user queues a buffer, store the data offset
  along with the address offset which is already stored.
  data offset indicates the offset of the data in the
  buffer.
- Use this offset when the physical address of the
  buffer is configured to VFE.
- Depending on the number of planes present in the
  buffer, store either the y, cbr offset or the
  offset of each plane.

Signed-off-by: Kiran Kumar H N <hurlisal@codeaurora.org>
diff --git a/drivers/media/video/msm/msm.c b/drivers/media/video/msm/msm.c
index e3b97c9..2f83234 100644
--- a/drivers/media/video/msm/msm.c
+++ b/drivers/media/video/msm/msm.c
@@ -770,25 +770,26 @@
 	}
 	if (!pb->count) {
 		/* Deallocation. free buf_offset array */
-		D("%s freeing buf_offset information ", __func__);
+		D("%s freeing buffer offsets array ", __func__);
 		for (j = 0 ; j < pcam_inst->buf_count ; j++)
 			kfree(pcam_inst->buf_offset[j]);
 		kfree(pcam_inst->buf_offset);
 	} else {
 		/* Allocation. allocate buf_offset array */
-		pcam_inst->buf_offset = (uint32_t **)
-			kzalloc(pb->count * sizeof(uint32_t *),
+		pcam_inst->buf_offset = (struct msm_cam_buf_offset **)
+			kzalloc(pb->count * sizeof(struct msm_cam_buf_offset *),
 							GFP_KERNEL);
 		if (!pcam_inst->buf_offset) {
 			pr_err("%s out of memory ", __func__);
 			return -ENOMEM;
 		}
 		for (i = 0; i < pb->count; i++) {
-			pcam_inst->buf_offset[i] = kzalloc(sizeof(uint32_t) *
+			pcam_inst->buf_offset[i] =
+				kzalloc(sizeof(struct msm_cam_buf_offset) *
 				pcam_inst->plane_info.num_planes, GFP_KERNEL);
 			if (!pcam_inst->buf_offset[i]) {
 				pr_err("%s out of memory ", __func__);
-				for (j = i ; j >= 0; j--)
+				for (j = i-1 ; j >= 0; j--)
 					kfree(pcam_inst->buf_offset[j]);
 				kfree(pcam_inst->buf_offset);
 				return -ENOMEM;
@@ -825,14 +826,18 @@
 	WARN_ON(pctx != f->private_data);
 	if (pb->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
 		for (i = 0; i < pcam_inst->plane_info.num_planes; i++) {
-			D("%s storing buf_offset for plane %d as %d",
-				__func__, i, pb->m.planes[i].reserved[0]);
-			pcam_inst->buf_offset[pb->index][i] =
+			D("%s stored offsets for plane %d as"
+				"addr offset %d, data offset %d",
+				__func__, i, pb->m.planes[i].reserved[0],
+				pb->m.planes[i].data_offset);
+			pcam_inst->buf_offset[pb->index][i].data_offset =
+				pb->m.planes[i].data_offset;
+			pcam_inst->buf_offset[pb->index][i].addr_offset =
 				pb->m.planes[i].reserved[0];
 		}
 	} else {
 		D("%s stored reserved info %d", __func__, pb->reserved);
-		pcam_inst->buf_offset[pb->index][0] = pb->reserved;
+		pcam_inst->buf_offset[pb->index][0].addr_offset = pb->reserved;
 	}
 
 	rc = vb2_qbuf(&pcam_inst->vid_bufq, pb);
diff --git a/drivers/media/video/msm/msm.h b/drivers/media/video/msm/msm.h
index 001ca4b..01ca3e0 100644
--- a/drivers/media/video/msm/msm.h
+++ b/drivers/media/video/msm/msm.h
@@ -240,6 +240,10 @@
 	unsigned long buffer;
 	int fd;
 };
+struct msm_cam_buf_offset {
+	uint32_t addr_offset;
+	uint32_t data_offset;
+};
 
 #define MSM_DEV_INST_MAX                    16
 struct msm_cam_v4l2_dev_inst {
@@ -255,8 +259,8 @@
 	int image_mode;
 	int path;
 	int buf_count;
-	/* buffer offset, if any */
-	uint32_t **buf_offset;
+	/* buffer offsets, if any */
+	struct msm_cam_buf_offset **buf_offset;
 	struct v4l2_crop crop;
 	int streamon;
 	struct msm_mem_map_info mem_map;
diff --git a/drivers/media/video/msm/msm_mctl_buf.c b/drivers/media/video/msm/msm_mctl_buf.c
index 617c8b4..a83fa00 100644
--- a/drivers/media/video/msm/msm_mctl_buf.c
+++ b/drivers/media/video/msm/msm_mctl_buf.c
@@ -77,9 +77,11 @@
 	struct msm_cam_v4l2_device *pcam;
 	struct videobuf2_contig_pmem *mem;
 	struct vb2_queue	*vq;
-	uint32_t offset;
+	uint32_t buf_idx;
 	struct msm_frame_buffer *buf;
 	int rc = 0, i;
+	enum videobuf2_buffer_type buf_type;
+	struct videobuf2_msm_offset offset;
 	vq = vb->vb2_queue;
 	pcam_inst = vb2_get_drv_priv(vq);
 	pcam = pcam_inst->pcam;
@@ -95,17 +97,28 @@
 	if (buf->state == MSM_BUFFER_STATE_INITIALIZED)
 		return rc;
 
+	buf_type = (vb->num_planes == 1) ? VIDEOBUF2_SINGLE_PLANE
+					: VIDEOBUF2_MULTIPLE_PLANES;
+	if (buf_type == VIDEOBUF2_SINGLE_PLANE) {
+		offset.sp_off.y_off = 0;
+		offset.sp_off.cbcr_off =
+			pcam_inst->plane_info.plane[0].offset;
+	}
+	buf_idx = vb->v4l2_buf.index;
 	for (i = 0; i < vb->num_planes; i++) {
 		mem = vb2_plane_cookie(vb, i);
-		offset = pcam_inst->plane_info.plane[i].offset;
+		if (buf_type == VIDEOBUF2_MULTIPLE_PLANES)
+			offset.data_offset =
+				pcam_inst->plane_info.plane[i].offset;
 
 		if (vb->v4l2_buf.memory == V4L2_MEMORY_USERPTR)
-			rc = videobuf2_pmem_contig_user_get(mem, offset,
-				pcam_inst->buf_offset[vb->v4l2_buf.index][i],
+			rc = videobuf2_pmem_contig_user_get(mem, &offset,
+				buf_type,
+				pcam_inst->buf_offset[buf_idx][i].addr_offset,
 				pcam_inst->path);
 		else
-			rc = videobuf2_pmem_contig_mmap_get(mem, offset,
-				pcam_inst->path);
+			rc = videobuf2_pmem_contig_mmap_get(mem, &offset,
+				buf_type, pcam_inst->path);
 		if (rc < 0) {
 			pr_err("%s error initializing buffer ",
 				__func__);
@@ -393,13 +406,23 @@
 	struct msm_frame_buffer *buf = NULL, *tmp;
 	uint32_t buf_phyaddr = 0;
 	unsigned long flags = 0;
+	uint32_t buf_idx, offset = 0;
+	struct videobuf2_contig_pmem *mem;
 
 	/* we actually need a list, not a queue */
 	spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
 	list_for_each_entry_safe(buf, tmp,
 			&pcam_inst->free_vq, list) {
+		buf_idx = buf->vidbuf.v4l2_buf.index;
+		mem = vb2_plane_cookie(&buf->vidbuf, 0);
+		if (mem->buffer_type ==	VIDEOBUF2_MULTIPLE_PLANES)
+			offset = mem->offset.data_offset +
+				pcam_inst->buf_offset[buf_idx][0].data_offset;
+		else
+			offset = mem->offset.sp_off.y_off;
 		buf_phyaddr = (unsigned long)
-				videobuf2_to_pmem_contig(&buf->vidbuf, 0);
+				videobuf2_to_pmem_contig(&buf->vidbuf, 0) +
+				offset;
 		D("%s vb_idx=%d,vb_paddr=0x%x ch0=0x%x\n",
 			__func__, buf->vidbuf.v4l2_buf.index,
 			buf_phyaddr, fbuf->ch_paddr[0]);
@@ -483,6 +506,7 @@
 	struct videobuf2_contig_pmem *mem;
 	struct msm_frame_buffer *buf = NULL;
 	int rc = -EINVAL, idx, i;
+	uint32_t buf_idx, plane_offset = 0;
 
 	if (!free_buf) {
 		pr_err("%s: free_buf= null\n", __func__);
@@ -498,33 +522,45 @@
 	}
 	spin_lock_irqsave(&pcam_inst->vq_irqlock, flags);
 	list_for_each_entry(buf, &pcam_inst->free_vq, list) {
-		if (buf->state == MSM_BUFFER_STATE_QUEUED) {
-			if (pcam_inst->vid_fmt.type ==
+		if (buf->state != MSM_BUFFER_STATE_QUEUED)
+			continue;
+
+		buf_idx = buf->vidbuf.v4l2_buf.index;
+		if (pcam_inst->vid_fmt.type ==
 				V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
-				free_buf->num_planes =
-					pcam_inst->plane_info.num_planes;
-				for (i = 0; i < free_buf->num_planes; i++)
-					free_buf->ch_paddr[i] =	(uint32_t)
-					videobuf2_to_pmem_contig(
-						&buf->vidbuf, i);
-			} else {
-				mem = vb2_plane_cookie(&buf->vidbuf, 0);
-				free_buf->ch_paddr[0] = (uint32_t)
-				videobuf2_to_pmem_contig(&buf->vidbuf, 0);
-				free_buf->ch_paddr[1] =
-					free_buf->ch_paddr[0] + mem->offset;
+			free_buf->num_planes =
+				pcam_inst->plane_info.num_planes;
+			for (i = 0; i < free_buf->num_planes; i++) {
+				mem = vb2_plane_cookie(&buf->vidbuf, i);
+				if (mem->buffer_type ==
+						VIDEOBUF2_MULTIPLE_PLANES)
+					plane_offset =
+					mem->offset.data_offset;
+				else
+					plane_offset =
+					mem->offset.sp_off.cbcr_off;
+
+				free_buf->ch_paddr[i] =	(uint32_t)
+				videobuf2_to_pmem_contig(&buf->vidbuf, i) +
+				pcam_inst->buf_offset[buf_idx][i].data_offset +
+				plane_offset;
 			}
-			free_buf->vb = (uint32_t)buf;
-			buf->state = MSM_BUFFER_STATE_RESERVED;
-			D("%s idx=%d,inst=0x%p,idx=%d,paddr=0x%x, "
-				"ch1 addr=0x%x\n", __func__,
-				idx, pcam_inst,
-				buf->vidbuf.v4l2_buf.index,
-				free_buf->ch_paddr[0],
-				free_buf->ch_paddr[1]);
-			rc = 0;
-			break;
+		} else {
+			mem = vb2_plane_cookie(&buf->vidbuf, 0);
+			free_buf->ch_paddr[0] = (uint32_t)
+				videobuf2_to_pmem_contig(&buf->vidbuf, 0) +
+				mem->offset.sp_off.y_off;
+			free_buf->ch_paddr[1] =	free_buf->ch_paddr[0] +
+				mem->offset.sp_off.cbcr_off;
 		}
+		free_buf->vb = (uint32_t)buf;
+		buf->state = MSM_BUFFER_STATE_RESERVED;
+		D("%s idx=%d,inst=0x%p,idx=%d,paddr=0x%x, "
+			"ch1 addr=0x%x\n", __func__,
+			idx, pcam_inst,	buf->vidbuf.v4l2_buf.index,
+			free_buf->ch_paddr[0], free_buf->ch_paddr[1]);
+		rc = 0;
+		break;
 	}
 	if (rc != 0)
 		D("%s:No free buffer available: inst = 0x%p ",
diff --git a/drivers/media/video/msm/msm_mctl_pp.c b/drivers/media/video/msm/msm_mctl_pp.c
index 167e721..f0c1bfa 100644
--- a/drivers/media/video/msm/msm_mctl_pp.c
+++ b/drivers/media/video/msm/msm_mctl_pp.c
@@ -134,7 +134,7 @@
 		videobuf2_to_pmem_contig(&vb->vidbuf, 0);
 	div.phy_offset = mem->addr_offset;
 	div.y_off      = 0;
-	div.cbcr_off   = mem->offset;
+	div.cbcr_off   = mem->offset.sp_off.cbcr_off;
 	div.fd         = (int)mem->vaddr;
 	div.vb = (uint32_t)vb;
 	p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode]++;
@@ -142,7 +142,7 @@
 		p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode]++;
 	div.frame_id   =
 		p_mctl->pp_info.cur_frame_id[pcam_inst->image_mode];
-	div.path       = mem->buffer_type;
+	div.path       = mem->path;
 	div.length     = mem->size;
 	msm_mctl_gettimeofday(&div.timestamp);
 	vb->vidbuf.v4l2_buf.timestamp = div.timestamp;
@@ -167,14 +167,14 @@
 	memset(pp_frame, 0, sizeof(struct msm_pp_frame));
 	pp_frame->handle = (uint32_t)vb;
 	pp_frame->frame_id = vb->vidbuf.v4l2_buf.sequence;
-	pp_frame->image_type = (unsigned short)mem->buffer_type;
+	pp_frame->image_type = (unsigned short)mem->path;
 	pp_frame->timestamp = vb->vidbuf.v4l2_buf.timestamp;
 	/* hard coded for now. Will need to expand to MP case */
 	pp_frame->num_planes = 1;
 	pp_frame->sp.addr_offset = mem->addr_offset;
 	pp_frame->sp.phy_addr = videobuf2_to_pmem_contig(&vb->vidbuf, 0);
 	pp_frame->sp.y_off = 0;
-	pp_frame->sp.cbcr_off = mem->offset;
+	pp_frame->sp.cbcr_off = mem->offset.sp_off.cbcr_off;
 	pp_frame->sp.length = mem->size;
 	pp_frame->sp.fd = (int)mem->vaddr;
 	return 0;
diff --git a/drivers/media/video/videobuf2-msm-mem.c b/drivers/media/video/videobuf2-msm-mem.c
index 74debe1..d765244 100644
--- a/drivers/media/video/videobuf2-msm-mem.c
+++ b/drivers/media/video/videobuf2-msm-mem.c
@@ -124,10 +124,16 @@
 	kfree(mem);
 }
 int videobuf2_pmem_contig_mmap_get(struct videobuf2_contig_pmem *mem,
-					uint32_t offset, int path)
+				struct videobuf2_msm_offset *offset,
+				enum videobuf2_buffer_type buffer_type,
+				int path)
 {
-	mem->offset = offset;
-	mem->buffer_type = path;
+	if (offset)
+		mem->offset = *offset;
+	else
+		memset(&mem->offset, 0, sizeof(struct videobuf2_msm_offset));
+	mem->buffer_type = buffer_type;
+	mem->path = path;
 	return 0;
 }
 EXPORT_SYMBOL_GPL(videobuf2_pmem_contig_mmap_get);
@@ -143,7 +149,8 @@
  * Returns 0 if successful.
  */
 int videobuf2_pmem_contig_user_get(struct videobuf2_contig_pmem *mem,
-					uint32_t offset,
+					struct videobuf2_msm_offset *offset,
+					enum videobuf2_buffer_type buffer_type,
 					uint32_t addr_offset, int path)
 {
 	unsigned long kvstart;
@@ -161,8 +168,12 @@
 					__func__, (int)mem->vaddr, rc);
 		return rc;
 	}
-	mem->offset = offset;
-	mem->buffer_type = path;
+	if (offset)
+		mem->offset = *offset;
+	else
+		memset(&mem->offset, 0, sizeof(struct videobuf2_msm_offset));
+	mem->path = path;
+	mem->buffer_type = buffer_type;
 	flags = MSM_SUBSYSTEM_MAP_IOVA;
 	mem->subsys_id = MSM_SUBSYSTEM_CAMERA;
 	mem->msm_buffer = msm_subsystem_map_buffer(mem->phyaddr, len,
diff --git a/include/media/videobuf2-msm-mem.h b/include/media/videobuf2-msm-mem.h
index 1cb2fbc..ac1575b 100644
--- a/include/media/videobuf2-msm-mem.h
+++ b/include/media/videobuf2-msm-mem.h
@@ -22,18 +22,35 @@
 	unsigned int count;
 };
 
+enum videobuf2_buffer_type {
+	VIDEOBUF2_SINGLE_PLANE,
+	VIDEOBUF2_MULTIPLE_PLANES
+};
+
+struct videobuf2_sp_offset {
+	uint32_t y_off;
+	uint32_t cbcr_off;
+};
+
+struct videobuf2_msm_offset {
+	union {
+		struct videobuf2_sp_offset sp_off;
+		uint32_t data_offset;
+	};
+};
+
 struct videobuf2_contig_pmem {
 	u32 magic;
 	void *vaddr;
 	int phyaddr;
 	unsigned long size;
 	int is_userptr;
-	/* Single plane - CbCr offset
-	 * Multi plane - plane offset
-	 */
-	uint32_t offset;
-	int buffer_type;
+	/* Offset of the plane inside the buffer */
+	struct videobuf2_msm_offset offset;
+	enum videobuf2_buffer_type buffer_type;
+	int path;
 	struct file *file;
+	/* Offset of the buffer */
 	uint32_t addr_offset;
 	int dirty;
 	unsigned int count;
@@ -48,9 +65,11 @@
 					unsigned int size,
 					void *priv);
 int videobuf2_pmem_contig_mmap_get(struct videobuf2_contig_pmem *mem,
-					uint32_t offset, int path);
+					struct videobuf2_msm_offset *offset,
+					enum videobuf2_buffer_type, int path);
 int videobuf2_pmem_contig_user_get(struct videobuf2_contig_pmem *mem,
-					uint32_t offset,
+					struct videobuf2_msm_offset *offset,
+					enum videobuf2_buffer_type,
 					uint32_t addr_offset, int path);
 void videobuf2_pmem_contig_user_put(struct videobuf2_contig_pmem *mem);
 unsigned long videobuf2_to_pmem_contig(struct vb2_buffer *buf,