From 192a7e76141e2eec7a69bdd4ea55aee03cf063a0 Mon Sep 17 00:00:00 2001 From: Rajakumar Govindaram Date: Sun, 17 Mar 2013 00:21:07 -0700 Subject: [PATCH] msm: camera2: Enhance cpp driver The cpp driver is enhanced to store the buffer mapping info. This helps to get vb2 buffers directly from vb2 queue in kernel space. The redundant queues in cpp kernel driver is removed as because the userspace streamlines the priority based queue. Change-Id: I304c1b929f73331f89b7ac666222156b9f3e9063 Signed-off-by: Rajakumar Govindaram --- .../msm/camera_v2/pproc/cpp/msm_cpp.c | 652 ++++++++++++------ .../msm/camera_v2/pproc/cpp/msm_cpp.h | 28 +- include/media/msmb_pproc.h | 28 + 3 files changed, 507 insertions(+), 201 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c index 7d18513a647..c06b009adc9 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.c @@ -22,7 +22,6 @@ #include #include #include -#include #include #include #include @@ -33,11 +32,14 @@ #include #include #include +#include #include "msm_cpp.h" #include "msm_camera_io_util.h" #define MSM_CPP_DRV_NAME "msm_cpp" +#define MSM_CPP_MAX_BUFF_QUEUE 16 + #define CONFIG_MSM_CPP_DBG 0 #if CONFIG_MSM_CPP_DBG @@ -126,6 +128,278 @@ static uint32_t msm_cpp_read(void __iomem *cpp_base) return tmp; } +static struct msm_cpp_buff_queue_info_t *msm_cpp_get_buff_queue_entry( + struct cpp_device *cpp_dev, uint32_t session_id, uint32_t stream_id) +{ + uint32_t i = 0; + struct msm_cpp_buff_queue_info_t *buff_queue_info = NULL; + + for (i = 0; i < cpp_dev->num_buffq; i++) { + if ((cpp_dev->buff_queue[i].used == 1) && + (cpp_dev->buff_queue[i].session_id == session_id) && + (cpp_dev->buff_queue[i].stream_id == stream_id)) { + buff_queue_info = &cpp_dev->buff_queue[i]; + break; + } + } + + if (buff_queue_info == NULL) { + pr_err("error buffer queue entry for sess:%d strm:%d not found\n", + session_id, stream_id); + } + return buff_queue_info; +} + +static unsigned long msm_cpp_get_phy_addr(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue_info, uint32_t buff_index, + uint8_t native_buff) +{ + unsigned long phy_add = 0; + struct list_head *buff_head; + struct msm_cpp_buffer_map_list_t *buff, *save; + + if (native_buff) + buff_head = &buff_queue_info->native_buff_head; + else + buff_head = &buff_queue_info->vb2_buff_head; + + list_for_each_entry_safe(buff, save, buff_head, entry) { + if (buff->map_info.buff_info.index == buff_index) { + phy_add = buff->map_info.phy_addr; + break; + } + } + + return phy_add; +} + +static unsigned long msm_cpp_queue_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue, + struct msm_cpp_buffer_info_t *buffer_info) +{ + struct list_head *buff_head; + struct msm_cpp_buffer_map_list_t *buff, *save; + int rc = 0; + + if (buffer_info->native_buff) + buff_head = &buff_queue->native_buff_head; + else + buff_head = &buff_queue->vb2_buff_head; + + list_for_each_entry_safe(buff, save, buff_head, entry) { + if (buff->map_info.buff_info.index == buffer_info->index) { + pr_err("error buffer index already queued\n"); + return -EINVAL; + } + } + + buff = kzalloc( + sizeof(struct msm_cpp_buffer_map_list_t), GFP_KERNEL); + if (!buff) { + pr_err("error allocating memory\n"); + return -EINVAL; + } + + buff->map_info.buff_info = *buffer_info; + buff->map_info.ion_handle = ion_import_dma_buf(cpp_dev->client, + buffer_info->fd); + if (IS_ERR_OR_NULL(buff->map_info.ion_handle)) { + pr_err("ION import failed\n"); + goto QUEUE_BUFF_ERROR1; + } + + rc = ion_map_iommu(cpp_dev->client, buff->map_info.ion_handle, + cpp_dev->domain_num, 0, SZ_4K, 0, + (unsigned long *)&buff->map_info.phy_addr, + &buff->map_info.len, 0, 0); + if (rc < 0) { + pr_err("ION mmap failed\n"); + goto QUEUE_BUFF_ERROR2; + } + + INIT_LIST_HEAD(&buff->entry); + list_add_tail(&buff->entry, buff_head); + + return buff->map_info.phy_addr; + +QUEUE_BUFF_ERROR2: + ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle, + cpp_dev->domain_num, 0); +QUEUE_BUFF_ERROR1: + ion_free(cpp_dev->client, buff->map_info.ion_handle); + buff->map_info.ion_handle = NULL; + kzfree(buff); + + return 0; +} + +static void msm_cpp_dequeue_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buffer_map_list_t *buff) +{ + ion_unmap_iommu(cpp_dev->client, buff->map_info.ion_handle, + cpp_dev->domain_num, 0); + ion_free(cpp_dev->client, buff->map_info.ion_handle); + buff->map_info.ion_handle = NULL; + + list_del_init(&buff->entry); + kzfree(buff); + + return; +} + +static unsigned long msm_cpp_fetch_buffer_info(struct cpp_device *cpp_dev, + struct msm_cpp_buffer_info_t *buffer_info, uint32_t session_id, + uint32_t stream_id) +{ + unsigned long phy_addr = 0; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + uint8_t native_buff = buffer_info->native_buff; + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id, + stream_id); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + session_id, stream_id); + return phy_addr; + } + + phy_addr = msm_cpp_get_phy_addr(cpp_dev, buff_queue_info, + buffer_info->index, native_buff); + if ((phy_addr == 0) && (native_buff)) { + phy_addr = msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info, + buffer_info); + } + return phy_addr; +} + +static int32_t msm_cpp_enqueue_buff_info_list(struct cpp_device *cpp_dev, + struct msm_cpp_stream_buff_info_t *stream_buff_info) +{ + uint32_t j; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, + (stream_buff_info->identity >> 16) & 0xFFFF, + stream_buff_info->identity & 0xFFFF); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + (stream_buff_info->identity >> 16) & 0xFFFF, + stream_buff_info->identity & 0xFFFF); + return -EINVAL; + } + + for (j = 0; j < stream_buff_info->num_buffs; j++) { + msm_cpp_queue_buffer_info(cpp_dev, buff_queue_info, + &stream_buff_info->buffer_info[j]); + } + return 0; +} + +static int32_t msm_cpp_dequeue_buff_info_list(struct cpp_device *cpp_dev, + struct msm_cpp_buff_queue_info_t *buff_queue_info) +{ + struct msm_cpp_buffer_map_list_t *buff, *save; + struct list_head *buff_head; + + buff_head = &buff_queue_info->native_buff_head; + list_for_each_entry_safe(buff, save, buff_head, entry) { + msm_cpp_dequeue_buffer_info(cpp_dev, buff); + } + + buff_head = &buff_queue_info->vb2_buff_head; + list_for_each_entry_safe(buff, save, buff_head, entry) { + msm_cpp_dequeue_buffer_info(cpp_dev, buff); + } + + return 0; +} + +static int32_t msm_cpp_add_buff_queue_entry(struct cpp_device *cpp_dev, + uint16_t session_id, uint16_t stream_id) +{ + uint32_t i; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + + for (i = 0; i < cpp_dev->num_buffq; i++) { + if (cpp_dev->buff_queue[i].used == 0) { + buff_queue_info = &cpp_dev->buff_queue[i]; + buff_queue_info->used = 1; + buff_queue_info->session_id = session_id; + buff_queue_info->stream_id = stream_id; + INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); + INIT_LIST_HEAD(&buff_queue_info->native_buff_head); + return 0; + } + } + pr_err("buffer queue full. error for sessionid: %d streamid: %d\n", + session_id, stream_id); + return -EINVAL; +} + +static int32_t msm_cpp_free_buff_queue_entry(struct cpp_device *cpp_dev, + uint32_t session_id, uint32_t stream_id) +{ + struct msm_cpp_buff_queue_info_t *buff_queue_info; + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, session_id, + stream_id); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for sessid:%d strmid:%d\n", + session_id, stream_id); + return -EINVAL; + } + + buff_queue_info->used = 0; + buff_queue_info->session_id = 0; + buff_queue_info->stream_id = 0; + INIT_LIST_HEAD(&buff_queue_info->vb2_buff_head); + INIT_LIST_HEAD(&buff_queue_info->native_buff_head); + return 0; +} + +static int32_t msm_cpp_create_buff_queue(struct cpp_device *cpp_dev, + uint32_t num_buffq) +{ + struct msm_cpp_buff_queue_info_t *buff_queue; + buff_queue = kzalloc( + sizeof(struct msm_cpp_buff_queue_info_t) * num_buffq, + GFP_KERNEL); + if (!buff_queue) { + pr_err("Buff queue allocation failure\n"); + return -ENOMEM; + } + + if (cpp_dev->buff_queue) { + pr_err("Buff queue not empty\n"); + kzfree(buff_queue); + return -EINVAL; + } else { + cpp_dev->buff_queue = buff_queue; + cpp_dev->num_buffq = num_buffq; + } + return 0; +} + +static void msm_cpp_delete_buff_queue(struct cpp_device *cpp_dev) +{ + uint32_t i; + + for (i = 0; i < cpp_dev->num_buffq; i++) { + if (cpp_dev->buff_queue[i].used == 1) { + pr_err("Queue not free sessionid: %d, streamid: %d\n", + cpp_dev->buff_queue[i].session_id, + cpp_dev->buff_queue[i].stream_id); + msm_cpp_free_buff_queue_entry(cpp_dev, + cpp_dev->buff_queue[i].session_id, + cpp_dev->buff_queue[i].stream_id); + } + } + kzfree(cpp_dev->buff_queue); + cpp_dev->buff_queue = NULL; + cpp_dev->num_buffq = 0; + return; +} + static void msm_cpp_poll(void __iomem *cpp_base, u32 val) { uint32_t tmp, retry = 0; @@ -364,6 +638,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) rc = -EBUSY; goto req_irq_fail; } + cpp_dev->buf_mgr_subdev = msm_buf_mngr_get_subdev(); } cpp_dev->hw_info.cpp_hw_version = @@ -375,6 +650,7 @@ static int cpp_init_hardware(struct cpp_device *cpp_dev) msm_camera_io_w(0x1, cpp_dev->vbif_base + 0x4); cpp_dev->taskletq_idx = 0; atomic_set(&cpp_dev->irq_cnt, 0); + msm_cpp_create_buff_queue(cpp_dev, MSM_CPP_MAX_BUFF_QUEUE); if (cpp_dev->is_firmware_loaded == 1) msm_cpp_boot_hw(cpp_dev); return rc; @@ -401,7 +677,7 @@ static void cpp_release_hardware(struct cpp_device *cpp_dev) tasklet_kill(&cpp_dev->cpp_tasklet); atomic_set(&cpp_dev->irq_cnt, 0); } - + msm_cpp_delete_buff_queue(cpp_dev); iounmap(cpp_dev->base); iounmap(cpp_dev->vbif_base); iounmap(cpp_dev->cpp_hw_base); @@ -564,6 +840,18 @@ static const struct v4l2_subdev_internal_ops msm_cpp_internal_ops = { .close = cpp_close_node, }; +static int msm_cpp_buffer_ops(struct cpp_device *cpp_dev, + uint32_t buff_mgr_ops, struct msm_buf_mngr_info *buff_mgr_info) +{ + int rc = -EINVAL; + + rc = v4l2_subdev_call(cpp_dev->buf_mgr_subdev, core, ioctl, + buff_mgr_ops, buff_mgr_info); + if (rc < 0) + pr_err("%s: line %d rc = %d\n", __func__, __LINE__, rc); + return rc; +} + static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev) { struct v4l2_event v4l2_evt; @@ -571,10 +859,13 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev) struct msm_queue_cmd *event_qcmd; struct msm_cpp_frame_info_t *processed_frame; struct msm_device_queue *queue = &cpp_dev->processing_q; + struct msm_buf_mngr_info buff_mgr_info; + int rc = 0; if (queue->len > 0) { frame_qcmd = msm_dequeue(queue, list_frame); processed_frame = frame_qcmd->command; + do_gettimeofday(&(processed_frame->out_time)); kfree(frame_qcmd); event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC); if (!event_qcmd) { @@ -586,78 +877,55 @@ static int msm_cpp_notify_frame_done(struct cpp_device *cpp_dev) CPP_DBG("fid %d\n", processed_frame->frame_id); msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata); + if (!processed_frame->output_buffer_info.processed_divert) { + memset(&buff_mgr_info, 0 , + sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = + ((processed_frame->identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = + (processed_frame->identity & 0xFFFF); + buff_mgr_info.frame_id = processed_frame->frame_id; + buff_mgr_info.timestamp = processed_frame->timestamp; + buff_mgr_info.index = + processed_frame->output_buffer_info.index; + rc = msm_cpp_buffer_ops(cpp_dev, + VIDIOC_MSM_BUF_MNGR_BUF_DONE, + &buff_mgr_info); + if (rc < 0) { + pr_err("error putting buffer\n"); + rc = -EINVAL; + } + } v4l2_evt.id = processed_frame->inst_id; v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE; v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt); } - return 0; + return rc; } -static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev) +static int msm_cpp_send_frame_to_hardware(struct cpp_device *cpp_dev, + struct msm_queue_cmd *frame_qcmd) { uint32_t i; - struct msm_queue_cmd *frame_qcmd; + int32_t rc = -EINVAL; struct msm_cpp_frame_info_t *process_frame; - struct msm_device_queue *queue; if (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) { - while (cpp_dev->processing_q.len < MAX_CPP_PROCESSING_FRAME) { - if (cpp_dev->realtime_q.len != 0) { - queue = &cpp_dev->realtime_q; - } else if (cpp_dev->offline_q.len != 0) { - queue = &cpp_dev->offline_q; - } else { - pr_debug("All frames queued\n"); - break; - } - frame_qcmd = msm_dequeue(queue, list_frame); - process_frame = frame_qcmd->command; - msm_enqueue(&cpp_dev->processing_q, - &frame_qcmd->list_frame); - msm_cpp_write(0x6, cpp_dev->base); - for (i = 0; i < process_frame->msg_len; i++) - msm_cpp_write(process_frame->cpp_cmd_msg[i], - cpp_dev->base); - } + process_frame = frame_qcmd->command; + msm_enqueue(&cpp_dev->processing_q, + &frame_qcmd->list_frame); + msm_cpp_write(0x6, cpp_dev->base); + for (i = 0; i < process_frame->msg_len; i++) + msm_cpp_write(process_frame->cpp_cmd_msg[i], + cpp_dev->base); + do_gettimeofday(&(process_frame->in_time)); + rc = 0; } - return 0; + return rc; } static int msm_cpp_flush_frames(struct cpp_device *cpp_dev) { - struct v4l2_event v4l2_evt; - struct msm_queue_cmd *frame_qcmd; - struct msm_cpp_frame_info_t *process_frame; - struct msm_device_queue *queue; - struct msm_queue_cmd *event_qcmd; - - do { - if (cpp_dev->realtime_q.len != 0) { - queue = &cpp_dev->realtime_q; - } else if (cpp_dev->offline_q.len != 0) { - queue = &cpp_dev->offline_q; - } else { - pr_debug("All frames flushed\n"); - break; - } - frame_qcmd = msm_dequeue(queue, list_frame); - process_frame = frame_qcmd->command; - kfree(frame_qcmd); - event_qcmd = kzalloc(sizeof(struct msm_queue_cmd), GFP_ATOMIC); - if (!event_qcmd) { - pr_err("Insufficient memory. return"); - return -ENOMEM; - } - atomic_set(&event_qcmd->on_heap, 1); - event_qcmd->command = process_frame; - CPP_DBG("fid %d\n", process_frame->frame_id); - msm_enqueue(&cpp_dev->eventData_q, &event_qcmd->list_eventdata); - - v4l2_evt.id = process_frame->inst_id; - v4l2_evt.type = V4L2_EVENT_CPP_FRAME_DONE; - v4l2_event_queue(cpp_dev->msm_sd.sd.devnode, &v4l2_evt); - } while ((cpp_dev->realtime_q.len != 0) || - (cpp_dev->offline_q.len != 0)); return 0; } @@ -669,9 +937,9 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev, struct msm_cpp_frame_info_t *new_frame = kzalloc(sizeof(struct msm_cpp_frame_info_t), GFP_KERNEL); uint32_t *cpp_frame_msg; - unsigned long len; unsigned long in_phyaddr, out_phyaddr; uint16_t num_stripes = 0; + struct msm_buf_mngr_info buff_mgr_info; int i = 0; if (!new_frame) { @@ -706,44 +974,40 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev, new_frame->cpp_cmd_msg = cpp_frame_msg; - CPP_DBG("CPP in_fd: %d out_fd: %d\n", new_frame->src_fd, - new_frame->dst_fd); - - new_frame->src_ion_handle = ion_import_dma_buf(cpp_dev->client, - new_frame->src_fd); - if (IS_ERR_OR_NULL(new_frame->src_ion_handle)) { - pr_err("ION import failed\n"); - rc = PTR_ERR(new_frame->src_ion_handle); + in_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev, + &new_frame->input_buffer_info, + ((new_frame->identity >> 16) & 0xFFFF), + (new_frame->identity & 0xFFFF)); + if (!in_phyaddr) { + pr_err("error gettting input physical address\n"); + rc = -EINVAL; goto ERROR2; } - rc = ion_map_iommu(cpp_dev->client, new_frame->src_ion_handle, - cpp_dev->domain_num, 0, SZ_4K, 0, - (unsigned long *)&in_phyaddr, &len, 0, 0); + memset(&new_frame->output_buffer_info, 0, + sizeof(struct msm_cpp_buffer_info_t)); + memset(&buff_mgr_info, 0, sizeof(struct msm_buf_mngr_info)); + buff_mgr_info.session_id = ((new_frame->identity >> 16) & 0xFFFF); + buff_mgr_info.stream_id = (new_frame->identity & 0xFFFF); + rc = msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_GET_BUF, + &buff_mgr_info); if (rc < 0) { - pr_err("ION import failed\n"); - rc = PTR_ERR(new_frame->src_ion_handle); + pr_err("error getting buffer\n"); + rc = -EINVAL; + goto ERROR2; + } + + new_frame->output_buffer_info.index = buff_mgr_info.index; + out_phyaddr = msm_cpp_fetch_buffer_info(cpp_dev, + &new_frame->output_buffer_info, + ((new_frame->identity >> 16) & 0xFFFF), + (new_frame->identity & 0xFFFF)); + if (!out_phyaddr) { + pr_err("error gettting output physical address\n"); + rc = -EINVAL; goto ERROR3; } - CPP_DBG("in phy addr: 0x%x len: %ld\n", (uint32_t) in_phyaddr, len); - new_frame->dest_ion_handle = ion_import_dma_buf(cpp_dev->client, - new_frame->dst_fd); - if (IS_ERR_OR_NULL(new_frame->dest_ion_handle)) { - pr_err("ION import failed\n"); - rc = PTR_ERR(new_frame->dest_ion_handle); - goto ERROR4; - } - - rc = ion_map_iommu(cpp_dev->client, new_frame->dest_ion_handle, - cpp_dev->domain_num, 0, SZ_4K, 0, - (unsigned long *)&out_phyaddr, &len, 0, 0); - if (rc < 0) { - rc = PTR_ERR(new_frame->dest_ion_handle); - goto ERROR5; - } - - CPP_DBG("out phy addr: 0x%x len: %ld\n", (uint32_t)out_phyaddr, len); num_stripes = ((cpp_frame_msg[12] >> 20) & 0x3FF) + ((cpp_frame_msg[12] >> 10) & 0x3FF) + (cpp_frame_msg[12] & 0x3FF); @@ -760,44 +1024,29 @@ static int msm_cpp_cfg(struct cpp_device *cpp_dev, if (!frame_qcmd) { pr_err("Insufficient memory. return\n"); rc = -ENOMEM; - goto ERROR6; + goto ERROR3; } atomic_set(&frame_qcmd->on_heap, 1); frame_qcmd->command = new_frame; - if (new_frame->frame_type == MSM_CPP_REALTIME_FRAME) { - msm_enqueue(&cpp_dev->realtime_q, - &frame_qcmd->list_frame); - } else if (new_frame->frame_type == MSM_CPP_OFFLINE_FRAME) { - msm_enqueue(&cpp_dev->offline_q, - &frame_qcmd->list_frame); - } else { - pr_err("Invalid frame type\n"); + rc = msm_cpp_send_frame_to_hardware(cpp_dev, frame_qcmd); + if (rc < 0) { + pr_err("error cannot send frame to hardware\n"); rc = -EINVAL; - goto ERROR7; + goto ERROR4; } - msm_cpp_send_frame_to_hardware(cpp_dev); + return rc; -ERROR7: - kfree(frame_qcmd); -ERROR6: - ion_unmap_iommu(cpp_dev->client, new_frame->dest_ion_handle, - cpp_dev->domain_num, 0); -ERROR5: - ion_free(cpp_dev->client, new_frame->dest_ion_handle); - new_frame->dest_ion_handle = NULL; ERROR4: - ion_unmap_iommu(cpp_dev->client, new_frame->src_ion_handle, - cpp_dev->domain_num, 0); + kfree(frame_qcmd); ERROR3: - ion_free(cpp_dev->client, new_frame->src_ion_handle); - new_frame->src_ion_handle = NULL; + msm_cpp_buffer_ops(cpp_dev, VIDIOC_MSM_BUF_MNGR_PUT_BUF, + &buff_mgr_info); ERROR2: kfree(cpp_frame_msg); ERROR1: kfree(new_frame); return rc; - } long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, @@ -855,6 +1104,97 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, case VIDIOC_MSM_CPP_FLUSH_QUEUE: rc = msm_cpp_flush_frames(cpp_dev); break; + case VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO: { + struct msm_cpp_stream_buff_info_t *u_stream_buff_info; + struct msm_cpp_stream_buff_info_t k_stream_buff_info; + if (sizeof(struct msm_cpp_stream_buff_info_t) != + ioctl_ptr->len) { + pr_err("%s:%d: invalid length\n", __func__, __LINE__); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + u_stream_buff_info = kzalloc(ioctl_ptr->len, GFP_KERNEL); + if (!u_stream_buff_info) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(u_stream_buff_info, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + k_stream_buff_info.num_buffs = u_stream_buff_info->num_buffs; + k_stream_buff_info.identity = u_stream_buff_info->identity; + k_stream_buff_info.buffer_info = + kzalloc(k_stream_buff_info.num_buffs * + sizeof(struct msm_cpp_buffer_info_t), GFP_KERNEL); + if (!k_stream_buff_info.buffer_info) { + pr_err("%s:%d: malloc error\n", __func__, __LINE__); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + rc = (copy_from_user(k_stream_buff_info.buffer_info, + (void __user *)u_stream_buff_info->buffer_info, + k_stream_buff_info.num_buffs * + sizeof(struct msm_cpp_buffer_info_t)) ? + -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + kfree(k_stream_buff_info.buffer_info); + kfree(u_stream_buff_info); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + rc = msm_cpp_add_buff_queue_entry(cpp_dev, + ((k_stream_buff_info.identity >> 16) & 0xFFFF), + (k_stream_buff_info.identity & 0xFFFF)); + if (!rc) + rc = msm_cpp_enqueue_buff_info_list(cpp_dev, + &k_stream_buff_info); + + kfree(k_stream_buff_info.buffer_info); + kfree(u_stream_buff_info); + break; + } + case VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO: { + uint32_t identity; + struct msm_cpp_buff_queue_info_t *buff_queue_info; + + rc = (copy_from_user(&identity, + (void __user *)ioctl_ptr->ioctl_ptr, + ioctl_ptr->len) ? -EFAULT : 0); + if (rc) { + ERR_COPY_FROM_USER(); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + buff_queue_info = msm_cpp_get_buff_queue_entry(cpp_dev, + ((identity >> 16) & 0xFFFF), (identity & 0xFFFF)); + if (buff_queue_info == NULL) { + pr_err("error finding buffer queue entry for identity:%d\n", + identity); + mutex_unlock(&cpp_dev->mutex); + return -EINVAL; + } + + msm_cpp_dequeue_buff_info_list(cpp_dev, buff_queue_info); + rc = msm_cpp_free_buff_queue_entry(cpp_dev, + buff_queue_info->session_id, + buff_queue_info->stream_id); + break; + } case VIDIOC_MSM_CPP_GET_EVENTPAYLOAD: { struct msm_device_queue *queue = &cpp_dev->eventData_q; struct msm_queue_cmd *event_qcmd; @@ -868,23 +1208,6 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, mutex_unlock(&cpp_dev->mutex); return -EINVAL; } - if (process_frame->dest_ion_handle) { - ion_unmap_iommu(cpp_dev->client, - process_frame->dest_ion_handle, - cpp_dev->domain_num, 0); - ion_free(cpp_dev->client, - process_frame->dest_ion_handle); - process_frame->dest_ion_handle = NULL; - } - - if (process_frame->src_ion_handle) { - ion_unmap_iommu(cpp_dev->client, - process_frame->src_ion_handle, - cpp_dev->domain_num, 0); - ion_free(cpp_dev->client, - process_frame->src_ion_handle); - process_frame->src_ion_handle = NULL; - } kfree(process_frame->cpp_cmd_msg); kfree(process_frame); @@ -894,7 +1217,7 @@ long msm_cpp_subdev_ioctl(struct v4l2_subdev *sd, } mutex_unlock(&cpp_dev->mutex); CPP_DBG("X\n"); - return 0; + return rc; } int msm_cpp_subscribe_event(struct v4l2_subdev *sd, struct v4l2_fh *fh, @@ -921,8 +1244,6 @@ static const struct v4l2_subdev_ops msm_cpp_subdev_ops = { .core = &msm_cpp_subdev_core_ops, }; -static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev); - static struct v4l2_file_operations msm_cpp_v4l2_subdev_fops; static long msm_cpp_subdev_do_ioctl( @@ -1115,17 +1436,13 @@ static int __devinit cpp_probe(struct platform_device *pdev) cpp_release_hardware(cpp_dev); cpp_dev->state = CPP_STATE_OFF; - msm_cpp_enable_debugfs(cpp_dev); msm_queue_init(&cpp_dev->eventData_q, "eventdata"); - msm_queue_init(&cpp_dev->offline_q, "frame"); - msm_queue_init(&cpp_dev->realtime_q, "frame"); msm_queue_init(&cpp_dev->processing_q, "frame"); INIT_LIST_HEAD(&cpp_dev->tasklet_q); tasklet_init(&cpp_dev->cpp_tasklet, msm_cpp_do_tasklet, (unsigned long)cpp_dev); cpp_dev->cpp_open_cnt = 0; cpp_dev->is_firmware_loaded = 0; - return rc; ERROR3: @@ -1190,65 +1507,6 @@ static void __exit msm_cpp_exit_module(void) platform_driver_unregister(&cpp_driver); } -static int msm_cpp_debugfs_stream_s(void *data, u64 val) -{ - struct cpp_device *cpp_dev = data; - CPP_DBG("CPP processing frame E\n"); - while (1) { - mutex_lock(&cpp_dev->mutex); - msm_cpp_notify_frame_done(cpp_dev); - msm_cpp_send_frame_to_hardware(cpp_dev); - mutex_unlock(&cpp_dev->mutex); - msleep(20); - } - CPP_DBG("CPP processing frame X\n"); - return 0; -} - -static int msm_cpp_debugfs_load_fw(void *data, u64 val) -{ - const struct firmware *fw = NULL; - struct cpp_device *cpp_dev = data; - int rc = 0; - CPP_DBG("%s\n", __func__); - rc = request_firmware(&fw, "FIRMWARE.bin", &cpp_dev->pdev->dev); - if (rc) { - pr_err("request_fw failed\n"); - } else { - CPP_DBG("request ok\n"); - release_firmware(fw); - } - return 0; -} - -DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_stream, NULL, - msm_cpp_debugfs_stream_s, "%llu\n"); -DEFINE_SIMPLE_ATTRIBUTE(cpp_debugfs_fw, NULL, - msm_cpp_debugfs_load_fw, "%llu\n"); - -static int msm_cpp_enable_debugfs(struct cpp_device *cpp_dev) -{ - struct dentry *debugfs_base, *debugfs_test; - debugfs_base = debugfs_create_dir("msm_camera", NULL); - if (!debugfs_base) - return -ENOMEM; - - debugfs_test = debugfs_create_file("test", S_IRUGO | S_IWUSR, - debugfs_base, (void *)cpp_dev, &cpp_debugfs_stream); - if (!debugfs_test) { - debugfs_remove(debugfs_base); - return -ENOMEM; - } - - if (!debugfs_create_file("fw", S_IRUGO | S_IWUSR, debugfs_base, - (void *)cpp_dev, &cpp_debugfs_fw)) { - debugfs_remove(debugfs_test); - debugfs_remove(debugfs_base); - return -ENOMEM; - } - return 0; -} - module_init(msm_cpp_init_module); module_exit(msm_cpp_exit_module); MODULE_DESCRIPTION("MSM CPP driver"); diff --git a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h index b78bfae24fa..36a5fa51c56 100644 --- a/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h +++ b/drivers/media/platform/msm/camera_v2/pproc/cpp/msm_cpp.h @@ -127,6 +127,26 @@ struct msm_cpp_tasklet_queue_cmd { uint8_t cmd_used; }; +struct msm_cpp_buffer_map_info_t { + unsigned long len; + unsigned long phy_addr; + struct ion_handle *ion_handle; + struct msm_cpp_buffer_info_t buff_info; +}; + +struct msm_cpp_buffer_map_list_t { + struct msm_cpp_buffer_map_info_t map_info; + struct list_head entry; +}; + +struct msm_cpp_buff_queue_info_t { + uint32_t used; + uint16_t session_id; + uint16_t stream_id; + struct list_head vb2_buff_head; + struct list_head native_buff_head; +}; + struct cpp_device { struct platform_device *pdev; struct msm_sd_subdev msm_sd; @@ -167,13 +187,13 @@ struct cpp_device { struct msm_device_queue eventData_q; /* V4L2 Event Payload Queue */ - /* Offline Frame Queue process when realtime queue is empty */ - struct msm_device_queue offline_q; - /* Realtime Frame Queue process with highest priority */ - struct msm_device_queue realtime_q; /* Processing Queue * store frame info for frames sent to microcontroller */ struct msm_device_queue processing_q; + + struct msm_cpp_buff_queue_info_t *buff_queue; + uint32_t num_buffq; + struct v4l2_subdev *buf_mgr_subdev; }; #endif /* __MSM_CPP_H__ */ diff --git a/include/media/msmb_pproc.h b/include/media/msmb_pproc.h index 6f8e865ea49..9000774d1ba 100644 --- a/include/media/msmb_pproc.h +++ b/include/media/msmb_pproc.h @@ -11,6 +11,7 @@ #define MAX_PLANES VIDEO_MAX_PLANES #define MAX_NUM_CPP_STRIPS 8 +#define MSM_CPP_MAX_NUM_PLANES 3 enum msm_cpp_frame_type { MSM_CPP_OFFLINE_FRAME, @@ -74,9 +75,25 @@ struct msm_cpp_frame_strip_info { int postscale_crop_en; }; +struct msm_cpp_buffer_info_t { + int fd; + uint32_t index; + uint32_t offset; + uint8_t native_buff; + uint8_t processed_divert; +}; + +struct msm_cpp_stream_buff_info_t { + uint32_t identity; + uint32_t num_buffs; + struct msm_cpp_buffer_info_t *buffer_info; +}; + struct msm_cpp_frame_info_t { int32_t frame_id; + struct timeval timestamp; uint32_t inst_id; + uint32_t identity; uint32_t client_id; enum msm_cpp_frame_type frame_type; uint32_t num_strips; @@ -87,6 +104,11 @@ struct msm_cpp_frame_info_t { int dst_fd; struct ion_handle *src_ion_handle; struct ion_handle *dest_ion_handle; + struct timeval in_time, out_time; + void *cookie; + + struct msm_cpp_buffer_info_t input_buffer_info; + struct msm_cpp_buffer_info_t output_buffer_info; }; struct cpp_hw_info { @@ -112,6 +134,12 @@ struct cpp_hw_info { #define VIDIOC_MSM_CPP_FLUSH_QUEUE \ _IOWR('V', BASE_VIDIOC_PRIVATE + 5, struct msm_camera_v4l2_ioctl_t) +#define VIDIOC_MSM_CPP_ENQUEUE_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 6, struct msm_camera_v4l2_ioctl_t) + +#define VIDIOC_MSM_CPP_DEQUEUE_STREAM_BUFF_INFO \ + _IOWR('V', BASE_VIDIOC_PRIVATE + 7, struct msm_camera_v4l2_ioctl_t) + #define V4L2_EVENT_CPP_FRAME_DONE (V4L2_EVENT_PRIVATE_START + 0) struct msm_camera_v4l2_ioctl_t {