media: atomisp: Convert to videobuf2

Convert atomisp to use videobuf2.

This fixes mmap not working and in general moving over to
the more modern videobuf2 is a good plan.

Reviewed-by: Andy Shevchenko <andy@kernel.org>
Signed-off-by: Hans de Goede <hdegoede@redhat.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
This commit is contained in:
Hans de Goede
2022-10-08 17:39:32 +01:00
committed by Mauro Carvalho Chehab
parent 9a29f5fc34
commit cb48ae89be
12 changed files with 304 additions and 792 deletions

View File

@@ -30,7 +30,6 @@
#include <asm/iosf_mbi.h> #include <asm/iosf_mbi.h>
#include <media/v4l2-event.h> #include <media/v4l2-event.h>
#include <media/videobuf-vmalloc.h>
#define CREATE_TRACE_POINTS #define CREATE_TRACE_POINTS
#include "atomisp_trace_event.h" #include "atomisp_trace_event.h"
@@ -662,23 +661,6 @@ void dump_sp_dmem(struct atomisp_device *isp, unsigned int addr,
} while (--size32); } while (--size32);
} }
static struct videobuf_buffer *atomisp_css_frame_to_vbuf(
struct atomisp_video_pipe *pipe, struct ia_css_frame *frame)
{
struct videobuf_vmalloc_memory *vm_mem;
struct ia_css_frame *handle;
int i;
for (i = 0; pipe->capq.bufs[i]; i++) {
vm_mem = pipe->capq.bufs[i]->priv;
handle = vm_mem->vaddr;
if (handle && handle->data == frame->data)
return pipe->capq.bufs[i];
}
return NULL;
}
int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe) int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe)
{ {
unsigned long irqflags; unsigned long irqflags;
@@ -695,37 +677,40 @@ int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe)
return buffers_in_css; return buffers_in_css;
} }
void atomisp_buffer_done(struct atomisp_video_pipe *pipe, struct videobuf_buffer *vb, void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state)
int state)
{ {
struct atomisp_video_pipe *pipe = vb_to_pipe(&frame->vb.vb2_buf);
lockdep_assert_held(&pipe->irq_lock); lockdep_assert_held(&pipe->irq_lock);
vb->ts = ktime_get_ns(); frame->vb.vb2_buf.timestamp = ktime_get_ns();
vb->field_count = atomic_read(&pipe->asd->sequence) << 1; frame->vb.field = pipe->pix.field;
vb->state = state; frame->vb.sequence = atomic_read(&pipe->asd->sequence);
list_del(&vb->queue); list_del(&frame->queue);
wake_up(&vb->done); if (state == VB2_BUF_STATE_DONE)
vb2_set_plane_payload(&frame->vb.vb2_buf, 0, pipe->pix.sizeimage);
vb2_buffer_done(&frame->vb.vb2_buf, state);
} }
void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames) void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames)
{ {
struct videobuf_buffer *_vb, *vb; struct ia_css_frame *frame, *_frame;
unsigned long irqflags; unsigned long irqflags;
spin_lock_irqsave(&pipe->irq_lock, irqflags); spin_lock_irqsave(&pipe->irq_lock, irqflags);
list_for_each_entry_safe(vb, _vb, &pipe->buffers_in_css, queue) { list_for_each_entry_safe(frame, _frame, &pipe->buffers_in_css, queue) {
if (warn_on_css_frames) if (warn_on_css_frames)
dev_warn(pipe->isp->dev, "Warning: CSS frames queued on flush\n"); dev_warn(pipe->isp->dev, "Warning: CSS frames queued on flush\n");
atomisp_buffer_done(pipe, vb, VIDEOBUF_ERROR); atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
} }
list_for_each_entry_safe(vb, _vb, &pipe->activeq, queue) list_for_each_entry_safe(frame, _frame, &pipe->activeq, queue)
atomisp_buffer_done(pipe, vb, VIDEOBUF_ERROR); atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
list_for_each_entry_safe(vb, _vb, &pipe->buffers_waiting_for_param, queue) { list_for_each_entry_safe(frame, _frame, &pipe->buffers_waiting_for_param, queue) {
pipe->frame_request_config_id[vb->i] = 0; pipe->frame_request_config_id[frame->vb.vb2_buf.index] = 0;
atomisp_buffer_done(pipe, vb, VIDEOBUF_ERROR); atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
} }
spin_unlock_irqrestore(&pipe->irq_lock, irqflags); spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
@@ -874,7 +859,6 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
enum ia_css_pipe_id css_pipe_id, enum ia_css_pipe_id css_pipe_id,
bool q_buffers, enum atomisp_input_stream_id stream_id) bool q_buffers, enum atomisp_input_stream_id stream_id)
{ {
struct videobuf_buffer *vb = NULL;
struct atomisp_video_pipe *pipe = NULL; struct atomisp_video_pipe *pipe = NULL;
struct atomisp_css_buffer buffer; struct atomisp_css_buffer buffer;
bool requeue = false; bool requeue = false;
@@ -1027,10 +1011,7 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
dev_dbg(isp->dev, "%s thumb no flash in this frame\n", dev_dbg(isp->dev, "%s thumb no flash in this frame\n",
__func__); __func__);
} }
vb = atomisp_css_frame_to_vbuf(pipe, frame); pipe->frame_config_id[frame->vb.vb2_buf.index] = frame->isp_config_id;
WARN_ON(!vb);
if (vb)
pipe->frame_config_id[vb->i] = frame->isp_config_id;
if (css_pipe_id == IA_CSS_PIPE_ID_CAPTURE && if (css_pipe_id == IA_CSS_PIPE_ID_CAPTURE &&
asd->pending_capture_request > 0) { asd->pending_capture_request > 0) {
err = atomisp_css_offline_capture_configure(asd, err = atomisp_css_offline_capture_configure(asd,
@@ -1066,13 +1047,8 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
dev_dbg(isp->dev, "%s: main frame with exp_id %d is ready\n", dev_dbg(isp->dev, "%s: main frame with exp_id %d is ready\n",
__func__, frame->exp_id); __func__, frame->exp_id);
vb = atomisp_css_frame_to_vbuf(pipe, frame);
if (!vb) {
WARN_ON(1);
break;
}
i = vb->i; i = frame->vb.vb2_buf.index;
/* free the parameters */ /* free the parameters */
if (pipe->frame_params[i]) { if (pipe->frame_params[i]) {
@@ -1183,9 +1159,9 @@ void atomisp_buf_done(struct atomisp_sub_device *asd, int error,
default: default:
break; break;
} }
if (vb) { if (frame) {
spin_lock_irqsave(&pipe->irq_lock, irqflags); spin_lock_irqsave(&pipe->irq_lock, irqflags);
atomisp_buffer_done(pipe, vb, error ? VIDEOBUF_ERROR : VIDEOBUF_DONE); atomisp_buffer_done(frame, error ? VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
spin_unlock_irqrestore(&pipe->irq_lock, irqflags); spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
} }
@@ -3656,6 +3632,18 @@ void atomisp_free_css_parameters(struct atomisp_css_params *css_param)
} }
} }
static void atomisp_move_frame_to_activeq(struct ia_css_frame *frame,
struct atomisp_css_params_with_list *param)
{
struct atomisp_video_pipe *pipe = vb_to_pipe(&frame->vb.vb2_buf);
unsigned long irqflags;
pipe->frame_params[frame->vb.vb2_buf.index] = param;
spin_lock_irqsave(&pipe->irq_lock, irqflags);
list_move_tail(&frame->queue, &pipe->activeq);
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
}
/* /*
* Check parameter queue list and buffer queue list to find out if matched items * Check parameter queue list and buffer queue list to find out if matched items
* and then set parameter to CSS and enqueue buffer to CSS. * and then set parameter to CSS and enqueue buffer to CSS.
@@ -3666,11 +3654,10 @@ void atomisp_free_css_parameters(struct atomisp_css_params *css_param)
void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe) void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe)
{ {
struct atomisp_sub_device *asd = pipe->asd; struct atomisp_sub_device *asd = pipe->asd;
struct videobuf_buffer *vb = NULL, *vb_tmp; struct ia_css_frame *frame = NULL, *frame_tmp;
struct atomisp_css_params_with_list *param = NULL, *param_tmp; struct atomisp_css_params_with_list *param = NULL, *param_tmp;
struct videobuf_vmalloc_memory *vm_mem = NULL;
unsigned long irqflags;
bool need_to_enqueue_buffer = false; bool need_to_enqueue_buffer = false;
int i;
if (!asd) { if (!asd) {
dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n", dev_err(pipe->isp->dev, "%s(): asd is NULL, device is %s\n",
@@ -3694,44 +3681,32 @@ void atomisp_handle_parameter_and_buffer(struct atomisp_video_pipe *pipe)
list_empty(&pipe->buffers_waiting_for_param)) list_empty(&pipe->buffers_waiting_for_param))
return; return;
list_for_each_entry_safe(vb, vb_tmp, list_for_each_entry_safe(frame, frame_tmp,
&pipe->buffers_waiting_for_param, queue) { &pipe->buffers_waiting_for_param, queue) {
if (pipe->frame_request_config_id[vb->i]) { i = frame->vb.vb2_buf.index;
if (pipe->frame_request_config_id[i]) {
list_for_each_entry_safe(param, param_tmp, list_for_each_entry_safe(param, param_tmp,
&pipe->per_frame_params, list) { &pipe->per_frame_params, list) {
if (pipe->frame_request_config_id[vb->i] != if (pipe->frame_request_config_id[i] != param->params.isp_config_id)
param->params.isp_config_id)
continue; continue;
list_del(&param->list); list_del(&param->list);
list_del(&vb->queue);
/* /*
* clear the request config id as the buffer * clear the request config id as the buffer
* will be handled and enqueued into CSS soon * will be handled and enqueued into CSS soon
*/ */
pipe->frame_request_config_id[vb->i] = 0; pipe->frame_request_config_id[i] = 0;
pipe->frame_params[vb->i] = param; atomisp_move_frame_to_activeq(frame, param);
vm_mem = vb->priv; need_to_enqueue_buffer = true;
BUG_ON(!vm_mem);
break; break;
} }
if (vm_mem) { /* If this is the end, stop further loop */
spin_lock_irqsave(&pipe->irq_lock, irqflags); if (list_entry_is_head(param, &pipe->per_frame_params, list))
list_add_tail(&vb->queue, &pipe->activeq);
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
vm_mem = NULL;
need_to_enqueue_buffer = true;
} else {
/* The is the end, stop further loop */
break; break;
}
} else { } else {
list_del(&vb->queue); atomisp_move_frame_to_activeq(frame, NULL);
pipe->frame_params[vb->i] = NULL;
spin_lock_irqsave(&pipe->irq_lock, irqflags);
list_add_tail(&vb->queue, &pipe->activeq);
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
need_to_enqueue_buffer = true; need_to_enqueue_buffer = true;
} }
} }
@@ -5538,8 +5513,6 @@ done:
f->fmt.pix.priv = PAGE_ALIGN(pipe->pix.width * f->fmt.pix.priv = PAGE_ALIGN(pipe->pix.width *
pipe->pix.height * 2); pipe->pix.height * 2);
pipe->capq.field = f->fmt.pix.field;
/* /*
* If in video 480P case, no GFX throttle * If in video 480P case, no GFX throttle
*/ */

View File

@@ -56,8 +56,7 @@ struct camera_mipi_info *atomisp_to_sensor_mipi_info(struct v4l2_subdev *sd);
struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev); struct atomisp_video_pipe *atomisp_to_video_pipe(struct video_device *dev);
int atomisp_reset(struct atomisp_device *isp); int atomisp_reset(struct atomisp_device *isp);
int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe); int atomisp_buffers_in_css(struct atomisp_video_pipe *pipe);
void atomisp_buffer_done(struct atomisp_video_pipe *pipe, struct videobuf_buffer *buf, void atomisp_buffer_done(struct ia_css_frame *frame, enum vb2_buffer_state state);
int state);
void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames); void atomisp_flush_video_pipe(struct atomisp_video_pipe *pipe, bool warn_on_css_frames);
void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd); void atomisp_flush_bufs_and_wakeup(struct atomisp_sub_device *asd);
void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd); void atomisp_clear_css_buffer_counters(struct atomisp_sub_device *asd);

View File

@@ -25,7 +25,7 @@
#include <linux/v4l2-mediabus.h> #include <linux/v4l2-mediabus.h>
#include <media/videobuf-core.h> #include <media/videobuf2-v4l2.h>
#include "atomisp_compat.h" #include "atomisp_compat.h"
@@ -64,8 +64,4 @@ struct atomisp_fmt {
u32 bayer_order; u32 bayer_order;
}; };
struct atomisp_buffer {
struct videobuf_buffer vb;
};
#endif #endif

View File

@@ -22,7 +22,6 @@
#include "atomisp_compat_css20.h" #include "atomisp_compat_css20.h"
#include "../../include/linux/atomisp.h" #include "../../include/linux/atomisp.h"
#include <media/videobuf-vmalloc.h>
struct atomisp_device; struct atomisp_device;
struct atomisp_sub_device; struct atomisp_sub_device;
@@ -61,7 +60,7 @@ int atomisp_css_irq_enable(struct atomisp_device *isp,
enum ia_css_irq_info info, bool enable); enum ia_css_irq_info info, bool enable);
int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd, int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd,
struct videobuf_vmalloc_memory *vm_mem, struct ia_css_frame *frame,
enum atomisp_input_stream_id stream_id, enum atomisp_input_stream_id stream_id,
enum ia_css_buffer_type css_buf_type, enum ia_css_buffer_type css_buf_type,
enum ia_css_pipe_id css_pipe_id); enum ia_css_pipe_id css_pipe_id);

View File

@@ -996,7 +996,7 @@ void atomisp_css_init_struct(struct atomisp_sub_device *asd)
} }
int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd, int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd,
struct videobuf_vmalloc_memory *vm_mem, struct ia_css_frame *frame,
enum atomisp_input_stream_id stream_id, enum atomisp_input_stream_id stream_id,
enum ia_css_buffer_type css_buf_type, enum ia_css_buffer_type css_buf_type,
enum ia_css_pipe_id css_pipe_id) enum ia_css_pipe_id css_pipe_id)
@@ -1006,7 +1006,7 @@ int atomisp_q_video_buffer_to_css(struct atomisp_sub_device *asd,
int err; int err;
css_buf.type = css_buf_type; css_buf.type = css_buf_type;
css_buf.data.frame = vm_mem->vaddr; css_buf.data.frame = frame;
err = ia_css_pipe_enqueue_buffer( err = ia_css_pipe_enqueue_buffer(
stream_env->pipes[css_pipe_id], &css_buf); stream_env->pipes[css_pipe_id], &css_buf);

View File

@@ -22,7 +22,7 @@
#include <linux/pm_runtime.h> #include <linux/pm_runtime.h>
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/videobuf-vmalloc.h> #include <media/videobuf2-vmalloc.h>
#include "atomisp_cmd.h" #include "atomisp_cmd.h"
#include "atomisp_common.h" #include "atomisp_common.h"
@@ -35,49 +35,53 @@
#include "atomisp-regs.h" #include "atomisp-regs.h"
#include "hmm/hmm.h" #include "hmm/hmm.h"
#include "ia_css_frame.h"
#include "type_support.h" #include "type_support.h"
#include "device_access/device_access.h" #include "device_access/device_access.h"
#define ISP_LEFT_PAD 128 /* equal to 2*NWAY */
/* /*
* input image data, and current frame resolution for test * Videobuf2 ops
*/ */
#define ISP_PARAM_MMAP_OFFSET 0xfffff000 static int atomisp_queue_setup(struct vb2_queue *vq,
unsigned int *nbuffers, unsigned int *nplanes,
#define MAGIC_CHECK(is, should) \ unsigned int sizes[], struct device *alloc_devs[])
do { \
if (unlikely((is) != (should))) { \
pr_err("magic mismatch: %x (expected %x)\n", \
is, should); \
BUG(); \
} \
} while (0)
/*
* Videobuf ops
*/
static int atomisp_buf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{ {
struct atomisp_video_pipe *pipe = vq->priv_data; struct atomisp_video_pipe *pipe = container_of(vq, struct atomisp_video_pipe, vb_queue);
u16 source_pad = atomisp_subdev_source_pad(&pipe->vdev);
int ret;
*size = pipe->pix.sizeimage; ret = atomisp_get_css_frame_info(pipe->asd, source_pad, &pipe->frame_info);
if (ret)
return ret;
atomisp_alloc_css_stat_bufs(pipe->asd, ATOMISP_INPUT_STREAM_GENERAL);
*nplanes = 1;
sizes[0] = PAGE_ALIGN(pipe->pix.sizeimage);
return 0; return 0;
} }
static int atomisp_buf_prepare(struct videobuf_queue *vq, static int atomisp_buf_init(struct vb2_buffer *vb)
struct videobuf_buffer *vb,
enum v4l2_field field)
{ {
struct atomisp_video_pipe *pipe = vq->priv_data; struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
struct ia_css_frame *frame = vb_to_frame(vb);
int ret;
vb->size = pipe->pix.sizeimage; ret = ia_css_frame_init_from_info(frame, &pipe->frame_info);
vb->width = pipe->pix.width; if (ret)
vb->height = pipe->pix.height; return ret;
vb->field = field;
vb->state = VIDEOBUF_PREPARED; if (frame->data_bytes > vb2_plane_size(vb, 0)) {
dev_err(pipe->asd->isp->dev, "Internal error frame.data_bytes(%u) > vb.length(%lu)\n",
frame->data_bytes, vb2_plane_size(vb, 0));
return -EIO;
}
frame->data = hmm_create_from_vmalloc_buf(vb2_plane_size(vb, 0),
vb2_plane_vaddr(vb, 0));
if (frame->data == mmgr_NULL)
return -ENOMEM;
return 0; return 0;
} }
@@ -212,7 +216,6 @@ static int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
enum ia_css_buffer_type css_buf_type, enum ia_css_buffer_type css_buf_type,
enum ia_css_pipe_id css_pipe_id) enum ia_css_pipe_id css_pipe_id)
{ {
struct videobuf_vmalloc_memory *vm_mem;
struct atomisp_css_params_with_list *param; struct atomisp_css_params_with_list *param;
struct ia_css_dvs_grid_info *dvs_grid = struct ia_css_dvs_grid_info *dvs_grid =
atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info); atomisp_css_get_dvs_grid_info(&asd->params.curr_grid_info);
@@ -229,26 +232,22 @@ static int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
space = ATOMISP_CSS_Q_DEPTH - atomisp_buffers_in_css(pipe); space = ATOMISP_CSS_Q_DEPTH - atomisp_buffers_in_css(pipe);
while (space--) { while (space--) {
struct videobuf_buffer *vb; struct ia_css_frame *frame;
spin_lock_irqsave(&pipe->irq_lock, irqflags); spin_lock_irqsave(&pipe->irq_lock, irqflags);
vb = list_first_entry_or_null(&pipe->activeq, struct videobuf_buffer, queue); frame = list_first_entry_or_null(&pipe->activeq, struct ia_css_frame, queue);
if (vb) { if (frame)
list_move_tail(&vb->queue, &pipe->buffers_in_css); list_move_tail(&frame->queue, &pipe->buffers_in_css);
vb->state = VIDEOBUF_ACTIVE;
}
spin_unlock_irqrestore(&pipe->irq_lock, irqflags); spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
if (!vb) if (!frame)
return -EINVAL; return -EINVAL;
/* /*
* If there is a per_frame setting to apply on the buffer, * If there is a per_frame setting to apply on the buffer,
* do it before buffer en-queueing. * do it before buffer en-queueing.
*/ */
vm_mem = vb->priv; param = pipe->frame_params[frame->vb.vb2_buf.index];
param = pipe->frame_params[vb->i];
if (param) { if (param) {
atomisp_makeup_css_parameters(asd, atomisp_makeup_css_parameters(asd,
&asd->params.css_param.update_flag, &asd->params.css_param.update_flag,
@@ -262,8 +261,7 @@ static int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
if (!err) if (!err)
asd->params.config.dz_config = &param->params.dz_config; asd->params.config.dz_config = &param->params.dz_config;
} }
atomisp_css_set_isp_config_applied_frame(asd, atomisp_css_set_isp_config_applied_frame(asd, frame);
vm_mem->vaddr);
atomisp_css_update_isp_params_on_pipe(asd, atomisp_css_update_isp_params_on_pipe(asd,
asd->stream_env[stream_id].pipes[css_pipe_id]); asd->stream_env[stream_id].pipes[css_pipe_id]);
asd->params.dvs_6axis = (struct ia_css_dvs_6axis_config *) asd->params.dvs_6axis = (struct ia_css_dvs_6axis_config *)
@@ -288,14 +286,14 @@ static int atomisp_q_video_buffers_to_css(struct atomisp_sub_device *asd,
&asd->params.css_param.dz_config; &asd->params.css_param.dz_config;
asd->params.css_update_params_needed = true; asd->params.css_update_params_needed = true;
} }
pipe->frame_params[frame->vb.vb2_buf.index] = NULL;
} }
/* Enqueue buffer */ /* Enqueue buffer */
err = atomisp_q_video_buffer_to_css(asd, vm_mem, stream_id, err = atomisp_q_video_buffer_to_css(asd, frame, stream_id,
css_buf_type, css_pipe_id); css_buf_type, css_pipe_id);
if (err) { if (err) {
spin_lock_irqsave(&pipe->irq_lock, irqflags); spin_lock_irqsave(&pipe->irq_lock, irqflags);
list_move_tail(&vb->queue, &pipe->activeq); list_move_tail(&frame->queue, &pipe->activeq);
vb->state = VIDEOBUF_QUEUED;
spin_unlock_irqrestore(&pipe->irq_lock, irqflags); spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
dev_err(asd->isp->dev, "%s, css q fails: %d\n", dev_err(asd->isp->dev, "%s, css q fails: %d\n",
__func__, err); __func__, err);
@@ -522,11 +520,32 @@ int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd)
return 0; return 0;
} }
static void atomisp_buf_queue(struct videobuf_queue *vq, static void atomisp_buf_queue(struct vb2_buffer *vb)
struct videobuf_buffer *vb)
{ {
struct atomisp_video_pipe *pipe = vq->priv_data; struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
struct ia_css_frame *frame = vb_to_frame(vb);
struct atomisp_sub_device *asd = pipe->asd;
u16 source_pad = atomisp_subdev_source_pad(&pipe->vdev);
unsigned long irqflags;
int ret;
mutex_lock(&asd->isp->mutex);
ret = atomisp_pipe_check(pipe, false);
if (ret || pipe->stopping) {
spin_lock_irqsave(&pipe->irq_lock, irqflags);
atomisp_buffer_done(frame, VB2_BUF_STATE_ERROR);
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
goto out_unlock;
}
/* FIXME this ugliness comes from the original atomisp buffer handling */
if (!(vb->skip_cache_sync_on_finish && vb->skip_cache_sync_on_prepare))
wbinvd();
pipe->frame_params[vb->index] = NULL;
spin_lock_irqsave(&pipe->irq_lock, irqflags);
/* /*
* when a frame buffer meets following conditions, it should be put into * when a frame buffer meets following conditions, it should be put into
* the waiting list: * the waiting list:
@@ -538,40 +557,83 @@ static void atomisp_buf_queue(struct videobuf_queue *vq,
* get enqueued. * get enqueued.
*/ */
if (!atomisp_is_vf_pipe(pipe) && if (!atomisp_is_vf_pipe(pipe) &&
(pipe->frame_request_config_id[vb->i] || (pipe->frame_request_config_id[vb->index] ||
!list_empty(&pipe->buffers_waiting_for_param))) !list_empty(&pipe->buffers_waiting_for_param)))
list_add_tail(&vb->queue, &pipe->buffers_waiting_for_param); list_add_tail(&frame->queue, &pipe->buffers_waiting_for_param);
else else
list_add_tail(&vb->queue, &pipe->activeq); list_add_tail(&frame->queue, &pipe->activeq);
vb->state = VIDEOBUF_QUEUED; spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
/* TODO: do this better, not best way to queue to css */
if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) {
if (!list_empty(&pipe->buffers_waiting_for_param))
atomisp_handle_parameter_and_buffer(pipe);
else
atomisp_qbuffers_to_css(asd);
}
/*
* Workaround: Due to the design of HALv3,
* sometimes in ZSL or SDV mode HAL needs to
* capture multiple images within one streaming cycle.
* But the capture number cannot be determined by HAL.
* So HAL only sets the capture number to be 1 and queue multiple
* buffers. Atomisp driver needs to check this case and re-trigger
* CSS to do capture when new buffer is queued.
*/
if (asd->continuous_mode->val && source_pad == ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE &&
!asd->enable_raw_buffer_lock->val && asd->params.offline_parm.num_captures == 1) {
asd->pending_capture_request++;
dev_dbg(asd->isp->dev, "Add one pending capture request.\n");
}
out_unlock:
mutex_unlock(&asd->isp->mutex);
} }
static void atomisp_buf_release(struct videobuf_queue *vq, static void atomisp_buf_cleanup(struct vb2_buffer *vb)
struct videobuf_buffer *vb)
{ {
vb->state = VIDEOBUF_NEEDS_INIT; struct atomisp_video_pipe *pipe = vb_to_pipe(vb);
atomisp_videobuf_free_buf(vb); struct ia_css_frame *frame = vb_to_frame(vb);
int index = frame->vb.vb2_buf.index;
pipe->frame_request_config_id[index] = 0;
pipe->frame_params[index] = NULL;
hmm_free(frame->data);
} }
static const struct videobuf_queue_ops videobuf_qops = { static const struct vb2_ops atomisp_vb2_ops = {
.buf_setup = atomisp_buf_setup, .queue_setup = atomisp_queue_setup,
.buf_prepare = atomisp_buf_prepare, .buf_init = atomisp_buf_init,
.buf_cleanup = atomisp_buf_cleanup,
.buf_queue = atomisp_buf_queue, .buf_queue = atomisp_buf_queue,
.buf_release = atomisp_buf_release, .start_streaming = atomisp_start_streaming,
.stop_streaming = atomisp_stop_streaming,
}; };
static int atomisp_init_pipe(struct atomisp_video_pipe *pipe) static int atomisp_init_pipe(struct atomisp_video_pipe *pipe)
{ {
int ret;
/* init locks */ /* init locks */
spin_lock_init(&pipe->irq_lock); spin_lock_init(&pipe->irq_lock);
mutex_init(&pipe->vb_queue_mutex);
videobuf_queue_vmalloc_init(&pipe->capq, &videobuf_qops, NULL, /* Init videobuf2 queue structure */
&pipe->irq_lock, pipe->vb_queue.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
V4L2_BUF_TYPE_VIDEO_CAPTURE, pipe->vb_queue.io_modes = VB2_MMAP | VB2_USERPTR;
V4L2_FIELD_NONE, pipe->vb_queue.buf_struct_size = sizeof(struct ia_css_frame);
sizeof(struct atomisp_buffer), pipe, pipe->vb_queue.ops = &atomisp_vb2_ops;
NULL); /* ext_lock: NULL */ pipe->vb_queue.mem_ops = &vb2_vmalloc_memops;
pipe->vb_queue.timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
ret = vb2_queue_init(&pipe->vb_queue);
if (ret)
return ret;
pipe->vdev.queue = &pipe->vb_queue;
pipe->vdev.queue->lock = &pipe->vb_queue_mutex;
INIT_LIST_HEAD(&pipe->activeq); INIT_LIST_HEAD(&pipe->activeq);
INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);
@@ -771,45 +833,35 @@ static int atomisp_release(struct file *file)
struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
struct atomisp_sub_device *asd = pipe->asd; struct atomisp_sub_device *asd = pipe->asd;
struct v4l2_requestbuffers req;
struct v4l2_subdev_fh fh; struct v4l2_subdev_fh fh;
struct v4l2_rect clear_compose = {0}; struct v4l2_rect clear_compose = {0};
unsigned long flags; unsigned long flags;
int ret = 0; int ret;
v4l2_fh_init(&fh.vfh, vdev); v4l2_fh_init(&fh.vfh, vdev);
req.count = 0; mutex_lock(&pipe->vb_queue_mutex);
if (!isp)
return -EBADF;
mutex_lock(&isp->mutex); mutex_lock(&isp->mutex);
dev_dbg(isp->dev, "release device %s\n", vdev->name); dev_dbg(isp->dev, "release device %s\n", vdev->name);
asd->subdev.devnode = vdev; asd->subdev.devnode = vdev;
pipe->users--; /*
* FIXME This if is copied from _vb2_fop_release, this cannot use that
if (pipe->capq.streaming) * because that calls v4l2_fh_release() earlier then this function.
dev_warn(isp->dev, * Maybe we can release the fh earlier though, it does not look like
"%s: ISP still streaming while closing!", * anything needs it after this.
__func__); */
if (file->private_data == vdev->queue->owner) {
if (pipe->capq.streaming && vb2_queue_release(vdev->queue);
atomisp_streamoff(file, NULL, V4L2_BUF_TYPE_VIDEO_CAPTURE)) { vdev->queue->owner = NULL;
dev_err(isp->dev, "atomisp_streamoff failed on release, driver bug");
goto done;
} }
pipe->users--;
if (pipe->users) if (pipe->users)
goto done; goto done;
if (atomisp_reqbufs(file, NULL, &req)) {
dev_err(isp->dev, "atomisp_reqbufs failed on release, driver bug");
goto done;
}
/* /*
* A little trick here: * A little trick here:
* file injection input resolution is recorded in the sink pad, * file injection input resolution is recorded in the sink pad,
@@ -867,260 +919,17 @@ done:
V4L2_SEL_TGT_COMPOSE, 0, V4L2_SEL_TGT_COMPOSE, 0,
&clear_compose); &clear_compose);
mutex_unlock(&isp->mutex); mutex_unlock(&isp->mutex);
mutex_unlock(&pipe->vb_queue_mutex);
return v4l2_fh_release(file); return v4l2_fh_release(file);
} }
/*
* Memory help functions for image frame and private parameters
*/
static int do_isp_mm_remap(struct atomisp_device *isp,
struct vm_area_struct *vma,
ia_css_ptr isp_virt, u32 host_virt, u32 pgnr)
{
u32 pfn;
while (pgnr) {
pfn = hmm_virt_to_phys(isp_virt) >> PAGE_SHIFT;
if (remap_pfn_range(vma, host_virt, pfn,
PAGE_SIZE, PAGE_SHARED)) {
dev_err(isp->dev, "remap_pfn_range err.\n");
return -EAGAIN;
}
isp_virt += PAGE_SIZE;
host_virt += PAGE_SIZE;
pgnr--;
}
return 0;
}
static int frame_mmap(struct atomisp_device *isp,
const struct ia_css_frame *frame, struct vm_area_struct *vma)
{
ia_css_ptr isp_virt;
u32 host_virt;
u32 pgnr;
if (!frame) {
dev_err(isp->dev, "%s: NULL frame pointer.\n", __func__);
return -EINVAL;
}
host_virt = vma->vm_start;
isp_virt = frame->data;
pgnr = DIV_ROUND_UP(frame->data_bytes, PAGE_SIZE);
if (do_isp_mm_remap(isp, vma, isp_virt, host_virt, pgnr))
return -EAGAIN;
return 0;
}
int atomisp_videobuf_mmap_mapper(struct videobuf_queue *q,
struct vm_area_struct *vma)
{
u32 offset = vma->vm_pgoff << PAGE_SHIFT;
int ret = -EINVAL, i;
struct atomisp_device *isp =
((struct atomisp_video_pipe *)(q->priv_data))->isp;
struct videobuf_vmalloc_memory *vm_mem;
struct videobuf_mapping *map;
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED)) {
dev_err(isp->dev, "map appl bug: PROT_WRITE and MAP_SHARED are required\n");
return -EINVAL;
}
mutex_lock(&q->vb_lock);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
struct videobuf_buffer *buf = q->bufs[i];
if (!buf)
continue;
map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
if (!map) {
mutex_unlock(&q->vb_lock);
return -ENOMEM;
}
buf->map = map;
map->q = q;
buf->baddr = vma->vm_start;
if (buf && buf->memory == V4L2_MEMORY_MMAP &&
buf->boff == offset) {
vm_mem = buf->priv;
ret = frame_mmap(isp, vm_mem->vaddr, vma);
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
break;
}
}
mutex_unlock(&q->vb_lock);
return ret;
}
/* The input frame contains left and right padding that need to be removed.
* There is always ISP_LEFT_PAD padding on the left side.
* There is also padding on the right (padded_width - width).
*/
static int remove_pad_from_frame(struct atomisp_device *isp,
struct ia_css_frame *in_frame, __u32 width, __u32 height)
{
unsigned int i;
unsigned short *buffer;
int ret = 0;
ia_css_ptr load = in_frame->data;
ia_css_ptr store = load;
buffer = kmalloc_array(width, sizeof(load), GFP_KERNEL);
if (!buffer)
return -ENOMEM;
load += ISP_LEFT_PAD;
for (i = 0; i < height; i++) {
ret = hmm_load(load, buffer, width * sizeof(load));
if (ret < 0)
goto remove_pad_error;
ret = hmm_store(store, buffer, width * sizeof(store));
if (ret < 0)
goto remove_pad_error;
load += in_frame->frame_info.padded_width;
store += width;
}
remove_pad_error:
kfree(buffer);
return ret;
}
static int atomisp_mmap(struct file *file, struct vm_area_struct *vma)
{
struct video_device *vdev = video_devdata(file);
struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
struct atomisp_sub_device *asd = pipe->asd;
struct ia_css_frame *raw_virt_addr;
u32 start = vma->vm_start;
u32 end = vma->vm_end;
u32 size = end - start;
u32 origin_size, new_size;
int ret;
if (!asd) {
dev_err(isp->dev, "%s(): asd is NULL, device is %s\n",
__func__, vdev->name);
return -EINVAL;
}
if (!(vma->vm_flags & (VM_WRITE | VM_READ)))
return -EACCES;
mutex_lock(&isp->mutex);
if (!(vma->vm_flags & VM_SHARED)) {
/* Map private buffer.
* Set VM_SHARED to the flags since we need
* to map the buffer page by page.
* Without VM_SHARED, remap_pfn_range() treats
* this kind of mapping as invalid.
*/
vma->vm_flags |= VM_SHARED;
ret = hmm_mmap(vma, vma->vm_pgoff << PAGE_SHIFT);
mutex_unlock(&isp->mutex);
return ret;
}
/* mmap for ISP offline raw data */
if (atomisp_subdev_source_pad(vdev)
== ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE &&
vma->vm_pgoff == (ISP_PARAM_MMAP_OFFSET >> PAGE_SHIFT)) {
new_size = pipe->pix.width * pipe->pix.height * 2;
if (asd->params.online_process != 0) {
ret = -EINVAL;
goto error;
}
raw_virt_addr = asd->raw_output_frame;
if (!raw_virt_addr) {
dev_err(isp->dev, "Failed to request RAW frame\n");
ret = -EINVAL;
goto error;
}
ret = remove_pad_from_frame(isp, raw_virt_addr,
pipe->pix.width, pipe->pix.height);
if (ret < 0) {
dev_err(isp->dev, "remove pad failed.\n");
goto error;
}
origin_size = raw_virt_addr->data_bytes;
raw_virt_addr->data_bytes = new_size;
if (size != PAGE_ALIGN(new_size)) {
dev_err(isp->dev, "incorrect size for mmap ISP Raw Frame\n");
ret = -EINVAL;
goto error;
}
if (frame_mmap(isp, raw_virt_addr, vma)) {
dev_err(isp->dev, "frame_mmap failed.\n");
raw_virt_addr->data_bytes = origin_size;
ret = -EAGAIN;
goto error;
}
raw_virt_addr->data_bytes = origin_size;
vma->vm_flags |= VM_IO | VM_DONTEXPAND | VM_DONTDUMP;
mutex_unlock(&isp->mutex);
return 0;
}
/*
* mmap for normal frames
*/
if (size != pipe->pix.sizeimage) {
dev_err(isp->dev, "incorrect size for mmap ISP frames\n");
ret = -EINVAL;
goto error;
}
mutex_unlock(&isp->mutex);
return atomisp_videobuf_mmap_mapper(&pipe->capq, vma);
error:
mutex_unlock(&isp->mutex);
return ret;
}
static __poll_t atomisp_poll(struct file *file,
struct poll_table_struct *pt)
{
struct video_device *vdev = video_devdata(file);
struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
mutex_lock(&isp->mutex);
if (pipe->capq.streaming != 1) {
mutex_unlock(&isp->mutex);
return EPOLLERR;
}
mutex_unlock(&isp->mutex);
return videobuf_poll_stream(file, &pipe->capq, pt);
}
const struct v4l2_file_operations atomisp_fops = { const struct v4l2_file_operations atomisp_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.open = atomisp_open, .open = atomisp_open,
.release = atomisp_release, .release = atomisp_release,
.mmap = atomisp_mmap, .mmap = vb2_fop_mmap,
.poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2, .unlocked_ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT #ifdef CONFIG_COMPAT
/* /*
@@ -1129,5 +938,4 @@ const struct v4l2_file_operations atomisp_fops = {
.compat_ioctl32 = atomisp_compat_ioctl32, .compat_ioctl32 = atomisp_compat_ioctl32,
*/ */
#endif #endif
.poll = atomisp_poll,
}; };

View File

@@ -29,13 +29,6 @@ unsigned int atomisp_sub_dev_users(struct atomisp_sub_device *asd);
* Memory help functions for image frame and private parameters * Memory help functions for image frame and private parameters
*/ */
int atomisp_videobuf_mmap_mapper(struct videobuf_queue *q,
struct vm_area_struct *vma);
int atomisp_qbuf_to_css(struct atomisp_device *isp,
struct atomisp_video_pipe *pipe,
struct videobuf_buffer *vb);
int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd); int atomisp_qbuffers_to_css(struct atomisp_sub_device *asd);
extern const struct v4l2_file_operations atomisp_fops; extern const struct v4l2_file_operations atomisp_fops;

View File

@@ -23,7 +23,6 @@
#include <media/v4l2-ioctl.h> #include <media/v4l2-ioctl.h>
#include <media/v4l2-event.h> #include <media/v4l2-event.h>
#include <media/videobuf-vmalloc.h>
#include "atomisp_cmd.h" #include "atomisp_cmd.h"
#include "atomisp_common.h" #include "atomisp_common.h"
@@ -542,6 +541,11 @@ int atomisp_pipe_check(struct atomisp_video_pipe *pipe, bool settings_change)
if (pipe->isp->isp_fatal_error) if (pipe->isp->isp_fatal_error)
return -EIO; return -EIO;
if (settings_change && vb2_is_busy(&pipe->vb_queue)) {
dev_err(pipe->isp->dev, "Set fmt/input IOCTL while streaming\n");
return -EBUSY;
}
switch (pipe->asd->streaming) { switch (pipe->asd->streaming) {
case ATOMISP_DEVICE_STREAMING_DISABLED: case ATOMISP_DEVICE_STREAMING_DISABLED:
break; break;
@@ -632,10 +636,10 @@ static int atomisp_enum_input(struct file *file, void *fh,
static unsigned int static unsigned int
atomisp_subdev_streaming_count(struct atomisp_sub_device *asd) atomisp_subdev_streaming_count(struct atomisp_sub_device *asd)
{ {
return asd->video_out_preview.capq.streaming return asd->video_out_preview.vb_queue.start_streaming_called
+ asd->video_out_capture.capq.streaming + asd->video_out_capture.vb_queue.start_streaming_called
+ asd->video_out_video_capture.capq.streaming + asd->video_out_video_capture.vb_queue.start_streaming_called
+ asd->video_out_vf.capq.streaming; + asd->video_out_vf.vb_queue.start_streaming_called;
} }
unsigned int atomisp_streaming_count(struct atomisp_device *isp) unsigned int atomisp_streaming_count(struct atomisp_device *isp)
@@ -968,37 +972,6 @@ static int atomisp_g_fmt_cap(struct file *file, void *fh,
return atomisp_try_fmt_cap(file, fh, f); return atomisp_try_fmt_cap(file, fh, f);
} }
/*
* Free videobuffer buffer priv data
*/
void atomisp_videobuf_free_buf(struct videobuf_buffer *vb)
{
struct videobuf_vmalloc_memory *vm_mem;
if (!vb)
return;
vm_mem = vb->priv;
if (vm_mem && vm_mem->vaddr) {
ia_css_frame_free(vm_mem->vaddr);
vm_mem->vaddr = NULL;
}
}
/*
* this function is used to free video buffer queue
*/
static void atomisp_videobuf_free_queue(struct videobuf_queue *q)
{
int i;
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
atomisp_videobuf_free_buf(q->bufs[i]);
kfree(q->bufs[i]);
q->bufs[i] = NULL;
}
}
int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd, int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd,
uint16_t stream_id) uint16_t stream_id)
{ {
@@ -1100,178 +1073,13 @@ error:
return -ENOMEM; return -ENOMEM;
} }
/* static int atomisp_qbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer *buf)
* Initiate Memory Mapping or User Pointer I/O
*/
int atomisp_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
struct atomisp_sub_device *asd = pipe->asd;
struct ia_css_frame_info frame_info;
struct ia_css_frame *frame;
struct videobuf_vmalloc_memory *vm_mem;
u16 source_pad = atomisp_subdev_source_pad(vdev);
int ret = 0, i = 0;
if (req->count == 0) {
mutex_lock(&pipe->capq.vb_lock);
if (!list_empty(&pipe->capq.stream))
videobuf_queue_cancel(&pipe->capq);
atomisp_videobuf_free_queue(&pipe->capq);
mutex_unlock(&pipe->capq.vb_lock);
/* clear request config id */
memset(pipe->frame_request_config_id, 0,
VIDEO_MAX_FRAME * sizeof(unsigned int));
memset(pipe->frame_params, 0,
VIDEO_MAX_FRAME *
sizeof(struct atomisp_css_params_with_list *));
return 0;
}
ret = videobuf_reqbufs(&pipe->capq, req);
if (ret)
return ret;
atomisp_alloc_css_stat_bufs(asd, ATOMISP_INPUT_STREAM_GENERAL);
/*
* for user pointer type, buffers are not really allocated here,
* buffers are setup in QBUF operation through v4l2_buffer structure
*/
if (req->memory == V4L2_MEMORY_USERPTR)
return 0;
ret = atomisp_get_css_frame_info(asd, source_pad, &frame_info);
if (ret)
return ret;
/*
* Allocate the real frame here for selected node using our
* memory management function
*/
for (i = 0; i < req->count; i++) {
if (ia_css_frame_allocate_from_info(&frame, &frame_info))
goto error;
vm_mem = pipe->capq.bufs[i]->priv;
vm_mem->vaddr = frame;
}
return ret;
error:
while (i--) {
vm_mem = pipe->capq.bufs[i]->priv;
ia_css_frame_free(vm_mem->vaddr);
}
if (asd->vf_frame)
ia_css_frame_free(asd->vf_frame);
return -ENOMEM;
}
/* application query the status of a buffer */
static int atomisp_querybuf(struct file *file, void *fh,
struct v4l2_buffer *buf)
{
struct video_device *vdev = video_devdata(file);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
return videobuf_querybuf(&pipe->capq, buf);
}
/*
* Applications call the VIDIOC_QBUF ioctl to enqueue an empty (capturing) or
* filled (output) buffer in the drivers incoming queue.
*/
static int atomisp_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{
static const int NOFLUSH_FLAGS = V4L2_BUF_FLAG_NO_CACHE_INVALIDATE |
V4L2_BUF_FLAG_NO_CACHE_CLEAN;
struct video_device *vdev = video_devdata(file);
struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_device *isp = video_get_drvdata(vdev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
struct atomisp_sub_device *asd = pipe->asd;
struct videobuf_buffer *vb;
struct videobuf_vmalloc_memory *vm_mem;
struct ia_css_frame_info frame_info;
struct ia_css_frame *handle = NULL;
u32 length;
u32 pgnr;
int ret;
ret = atomisp_pipe_check(pipe, false);
if (ret)
return ret;
if (!buf || buf->index >= VIDEO_MAX_FRAME ||
!pipe->capq.bufs[buf->index]) {
dev_err(isp->dev, "Invalid index for qbuf.\n");
return -EINVAL;
}
/*
* For userptr type frame, we convert user space address to physic
* address and reprograme out page table properly
*/
if (buf->memory == V4L2_MEMORY_USERPTR) {
if (offset_in_page(buf->m.userptr)) {
dev_err(isp->dev, "Error userptr is not page aligned.\n");
return -EINVAL;
}
vb = pipe->capq.bufs[buf->index];
vm_mem = vb->priv;
if (!vm_mem)
return -EINVAL;
length = vb->bsize;
pgnr = (length + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
if (vb->baddr == buf->m.userptr && vm_mem->vaddr)
goto done;
if (atomisp_get_css_frame_info(asd,
atomisp_subdev_source_pad(vdev), &frame_info))
return -EIO;
ret = ia_css_frame_map(&handle, &frame_info,
(void __user *)buf->m.userptr,
pgnr);
if (ret) {
dev_err(isp->dev, "Failed to map user buffer\n");
return ret;
}
if (vm_mem->vaddr) {
mutex_lock(&pipe->capq.vb_lock);
ia_css_frame_free(vm_mem->vaddr);
vm_mem->vaddr = NULL;
vb->state = VIDEOBUF_NEEDS_INIT;
mutex_unlock(&pipe->capq.vb_lock);
}
vm_mem->vaddr = handle;
buf->flags &= ~V4L2_BUF_FLAG_MAPPED;
buf->flags |= V4L2_BUF_FLAG_QUEUED;
buf->flags &= ~V4L2_BUF_FLAG_DONE;
} else if (buf->memory == V4L2_MEMORY_MMAP) {
buf->flags |= V4L2_BUF_FLAG_MAPPED;
buf->flags |= V4L2_BUF_FLAG_QUEUED;
buf->flags &= ~V4L2_BUF_FLAG_DONE;
/*
* For mmap, frames were allocated at request buffers
*/
}
done:
if (!((buf->flags & NOFLUSH_FLAGS) == NOFLUSH_FLAGS))
wbinvd();
/* FIXME this abuse of buf->reserved2 comes from the original atomisp buffer handling */
if (!atomisp_is_vf_pipe(pipe) && if (!atomisp_is_vf_pipe(pipe) &&
(buf->reserved2 & ATOMISP_BUFFER_HAS_PER_FRAME_SETTING)) { (buf->reserved2 & ATOMISP_BUFFER_HAS_PER_FRAME_SETTING)) {
/* this buffer will have a per-frame parameter */ /* this buffer will have a per-frame parameter */
@@ -1284,90 +1092,27 @@ done:
pipe->frame_request_config_id[buf->index] = 0; pipe->frame_request_config_id[buf->index] = 0;
} }
pipe->frame_params[buf->index] = NULL; return vb2_ioctl_qbuf(file, fh, buf);
mutex_unlock(&isp->mutex);
ret = videobuf_qbuf(&pipe->capq, buf);
mutex_lock(&isp->mutex);
if (ret)
return ret;
/* TODO: do this better, not best way to queue to css */
if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) {
if (!list_empty(&pipe->buffers_waiting_for_param)) {
atomisp_handle_parameter_and_buffer(pipe);
} else {
atomisp_qbuffers_to_css(asd);
}
}
/*
* Workaround: Due to the design of HALv3,
* sometimes in ZSL or SDV mode HAL needs to
* capture multiple images within one streaming cycle.
* But the capture number cannot be determined by HAL.
* So HAL only sets the capture number to be 1 and queue multiple
* buffers. Atomisp driver needs to check this case and re-trigger
* CSS to do capture when new buffer is queued.
*/
if (asd->continuous_mode->val &&
atomisp_subdev_source_pad(vdev)
== ATOMISP_SUBDEV_PAD_SOURCE_CAPTURE &&
pipe->capq.streaming &&
!asd->enable_raw_buffer_lock->val &&
asd->params.offline_parm.num_captures == 1) {
asd->pending_capture_request++;
dev_dbg(isp->dev, "Add one pending capture request.\n");
}
dev_dbg(isp->dev, "qbuf buffer %d (%s) for asd%d\n", buf->index,
vdev->name, asd->index);
return 0;
} }
static int __get_frame_exp_id(struct atomisp_video_pipe *pipe, static int atomisp_dqbuf_wrapper(struct file *file, void *fh, struct v4l2_buffer *buf)
struct v4l2_buffer *buf)
{
struct videobuf_vmalloc_memory *vm_mem;
struct ia_css_frame *handle;
int i;
for (i = 0; pipe->capq.bufs[i]; i++) {
vm_mem = pipe->capq.bufs[i]->priv;
handle = vm_mem->vaddr;
if (buf->index == pipe->capq.bufs[i]->i && handle)
return handle->exp_id;
}
return -EINVAL;
}
/*
* Applications call the VIDIOC_DQBUF ioctl to dequeue a filled (capturing) or
* displayed (output buffer)from the driver's outgoing queue
*/
static int atomisp_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
{ {
struct video_device *vdev = video_devdata(file); struct video_device *vdev = video_devdata(file);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev); struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
struct atomisp_sub_device *asd = pipe->asd; struct atomisp_sub_device *asd = pipe->asd;
struct atomisp_device *isp = video_get_drvdata(vdev); struct atomisp_device *isp = video_get_drvdata(vdev);
struct ia_css_frame *frame;
struct vb2_buffer *vb;
int ret; int ret;
ret = atomisp_pipe_check(pipe, false); ret = vb2_ioctl_dqbuf(file, fh, buf);
if (ret) if (ret)
return ret; return ret;
mutex_unlock(&isp->mutex); vb = pipe->vb_queue.bufs[buf->index];
ret = videobuf_dqbuf(&pipe->capq, buf, file->f_flags & O_NONBLOCK); frame = vb_to_frame(vb);
mutex_lock(&isp->mutex);
if (ret) {
if (ret != -EAGAIN)
dev_dbg(isp->dev, "<%s: %d\n", __func__, ret);
return ret;
}
buf->bytesused = pipe->pix.sizeimage; /* FIXME this abuse of buf->reserved* comes from the original atomisp buffer handling */
buf->reserved = asd->frame_status[buf->index]; buf->reserved = asd->frame_status[buf->index];
/* /*
@@ -1378,7 +1123,7 @@ static int atomisp_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
*/ */
buf->reserved &= 0x0000ffff; buf->reserved &= 0x0000ffff;
if (!(buf->flags & V4L2_BUF_FLAG_ERROR)) if (!(buf->flags & V4L2_BUF_FLAG_ERROR))
buf->reserved |= __get_frame_exp_id(pipe, buf) << 16; buf->reserved |= frame->exp_id;
buf->reserved2 = pipe->frame_config_id[buf->index]; buf->reserved2 = pipe->frame_config_id[buf->index];
dev_dbg(isp->dev, dev_dbg(isp->dev,
@@ -1506,36 +1251,26 @@ static void atomisp_dma_burst_len_cfg(struct atomisp_sub_device *asd)
atomisp_css2_hw_store_32(DMA_BURST_SIZE_REG, 0x00); atomisp_css2_hw_store_32(DMA_BURST_SIZE_REG, 0x00);
} }
/* int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count)
* This ioctl start the capture during streaming I/O.
*/
static int atomisp_streamon(struct file *file, void *fh,
enum v4l2_buf_type type)
{ {
struct video_device *vdev = video_devdata(file); struct atomisp_video_pipe *pipe = vq_to_pipe(vq);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
struct atomisp_sub_device *asd = pipe->asd; struct atomisp_sub_device *asd = pipe->asd;
struct atomisp_device *isp = video_get_drvdata(vdev); struct video_device *vdev = &pipe->vdev;
struct atomisp_device *isp = asd->isp;
struct pci_dev *pdev = to_pci_dev(isp->dev); struct pci_dev *pdev = to_pci_dev(isp->dev);
enum ia_css_pipe_id css_pipe_id; enum ia_css_pipe_id css_pipe_id;
unsigned int sensor_start_stream; unsigned int sensor_start_stream;
unsigned long irqflags; unsigned long irqflags;
int ret; int ret;
mutex_lock(&isp->mutex);
dev_dbg(isp->dev, "Start stream on pad %d for asd%d\n", dev_dbg(isp->dev, "Start stream on pad %d for asd%d\n",
atomisp_subdev_source_pad(vdev), asd->index); atomisp_subdev_source_pad(vdev), asd->index);
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
dev_dbg(isp->dev, "unsupported v4l2 buf type\n");
return -EINVAL;
}
ret = atomisp_pipe_check(pipe, false); ret = atomisp_pipe_check(pipe, false);
if (ret) if (ret)
return ret; goto out_unlock;
if (pipe->capq.streaming)
return 0;
/* Input system HW workaround */ /* Input system HW workaround */
atomisp_dma_burst_len_cfg(asd); atomisp_dma_burst_len_cfg(asd);
@@ -1546,18 +1281,6 @@ static int atomisp_streamon(struct file *file, void *fh,
*/ */
sensor_start_stream = atomisp_sensor_start_stream(asd); sensor_start_stream = atomisp_sensor_start_stream(asd);
spin_lock_irqsave(&pipe->irq_lock, irqflags);
if (list_empty(&pipe->capq.stream)) {
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
dev_dbg(isp->dev, "no buffer in the queue\n");
return -EINVAL;
}
spin_unlock_irqrestore(&pipe->irq_lock, irqflags);
ret = videobuf_streamon(&pipe->capq);
if (ret)
return ret;
/* Reset pending capture request count. */ /* Reset pending capture request count. */
asd->pending_capture_request = 0; asd->pending_capture_request = 0;
@@ -1578,8 +1301,10 @@ static int atomisp_streamon(struct file *file, void *fh,
mutex_unlock(&isp->mutex); mutex_unlock(&isp->mutex);
ret = wait_for_completion_interruptible(&asd->init_done); ret = wait_for_completion_interruptible(&asd->init_done);
mutex_lock(&isp->mutex); mutex_lock(&isp->mutex);
if (ret != 0) if (ret) {
return -ERESTARTSYS; ret = -ERESTARTSYS;
goto out_unlock;
}
} }
/* handle per_frame_setting parameter and buffers */ /* handle per_frame_setting parameter and buffers */
@@ -1601,12 +1326,15 @@ static int atomisp_streamon(struct file *file, void *fh,
asd->params.offline_parm.num_captures, asd->params.offline_parm.num_captures,
asd->params.offline_parm.skip_frames, asd->params.offline_parm.skip_frames,
asd->params.offline_parm.offset); asd->params.offline_parm.offset);
if (ret) if (ret) {
return -EINVAL; ret = -EINVAL;
goto out_unlock;
}
} }
} }
atomisp_qbuffers_to_css(asd); atomisp_qbuffers_to_css(asd);
return 0; ret = 0;
goto out_unlock;
} }
if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) { if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) {
@@ -1632,7 +1360,7 @@ static int atomisp_streamon(struct file *file, void *fh,
ret = atomisp_css_start(asd, css_pipe_id, false); ret = atomisp_css_start(asd, css_pipe_id, false);
if (ret) if (ret)
return ret; goto out_unlock;
spin_lock_irqsave(&isp->lock, irqflags); spin_lock_irqsave(&isp->lock, irqflags);
asd->streaming = ATOMISP_DEVICE_STREAMING_ENABLED; asd->streaming = ATOMISP_DEVICE_STREAMING_ENABLED;
@@ -1652,8 +1380,10 @@ static int atomisp_streamon(struct file *file, void *fh,
atomisp_qbuffers_to_css(asd); atomisp_qbuffers_to_css(asd);
/* Only start sensor when the last streaming instance started */ /* Only start sensor when the last streaming instance started */
if (atomisp_subdev_streaming_count(asd) < sensor_start_stream) if (atomisp_subdev_streaming_count(asd) < sensor_start_stream) {
return 0; ret = 0;
goto out_unlock;
}
start_sensor: start_sensor:
if (isp->flash) { if (isp->flash) {
@@ -1684,7 +1414,7 @@ start_sensor:
ret = atomisp_stream_on_master_slave_sensor(isp, false); ret = atomisp_stream_on_master_slave_sensor(isp, false);
if (ret) { if (ret) {
dev_err(isp->dev, "master slave sensor stream on failed!\n"); dev_err(isp->dev, "master slave sensor stream on failed!\n");
return ret; goto out_unlock;
} }
goto start_delay_wq; goto start_delay_wq;
} else if (asd->depth_mode->val && (atomisp_streaming_count(isp) < } else if (asd->depth_mode->val && (atomisp_streaming_count(isp) <
@@ -1706,7 +1436,8 @@ start_sensor:
spin_lock_irqsave(&isp->lock, irqflags); spin_lock_irqsave(&isp->lock, irqflags);
asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED; asd->streaming = ATOMISP_DEVICE_STREAMING_DISABLED;
spin_unlock_irqrestore(&isp->lock, irqflags); spin_unlock_irqrestore(&isp->lock, irqflags);
return -EINVAL; ret = -EINVAL;
goto out_unlock;
} }
start_delay_wq: start_delay_wq:
@@ -1722,31 +1453,28 @@ start_delay_wq:
asd->delayed_init = ATOMISP_DELAYED_INIT_NOT_QUEUED; asd->delayed_init = ATOMISP_DELAYED_INIT_NOT_QUEUED;
} }
return 0; out_unlock:
mutex_unlock(&isp->mutex);
return ret;
} }
int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type) void atomisp_stop_streaming(struct vb2_queue *vq)
{ {
struct video_device *vdev = video_devdata(file); struct atomisp_video_pipe *pipe = vq_to_pipe(vq);
struct atomisp_device *isp = video_get_drvdata(vdev);
struct pci_dev *pdev = to_pci_dev(isp->dev);
struct atomisp_video_pipe *pipe = atomisp_to_video_pipe(vdev);
struct atomisp_sub_device *asd = pipe->asd; struct atomisp_sub_device *asd = pipe->asd;
struct video_device *vdev = &pipe->vdev;
struct atomisp_device *isp = asd->isp;
struct pci_dev *pdev = to_pci_dev(isp->dev);
enum ia_css_pipe_id css_pipe_id; enum ia_css_pipe_id css_pipe_id;
int ret; int ret;
unsigned long flags; unsigned long flags;
bool first_streamoff = false; bool first_streamoff = false;
mutex_lock(&isp->mutex);
dev_dbg(isp->dev, "Stop stream on pad %d for asd%d\n", dev_dbg(isp->dev, "Stop stream on pad %d for asd%d\n",
atomisp_subdev_source_pad(vdev), asd->index); atomisp_subdev_source_pad(vdev), asd->index);
lockdep_assert_held(&isp->mutex);
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
dev_dbg(isp->dev, "unsupported v4l2 buf type\n");
return -EINVAL;
}
/* /*
* There is no guarantee that the buffers queued to / owned by the ISP * There is no guarantee that the buffers queued to / owned by the ISP
* will properly be returned to the queue when stopping. Set a flag to * will properly be returned to the queue when stopping. Set a flag to
@@ -1756,12 +1484,12 @@ int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
pipe->stopping = true; pipe->stopping = true;
mutex_unlock(&isp->mutex); mutex_unlock(&isp->mutex);
/* wait max 1 second */ /* wait max 1 second */
ret = wait_event_interruptible_timeout(pipe->capq.wait, ret = wait_event_timeout(pipe->vb_queue.done_wq,
atomisp_buffers_in_css(pipe) == 0, HZ); atomisp_buffers_in_css(pipe) == 0, HZ);
mutex_lock(&isp->mutex); mutex_lock(&isp->mutex);
pipe->stopping = false; pipe->stopping = false;
if (ret <= 0) if (ret == 0)
return ret ?: -ETIMEDOUT; dev_warn(isp->dev, "Warning timeout waiting for CSS to return buffers\n");
/* /*
* do only videobuf_streamoff for capture & vf pipes in * do only videobuf_streamoff for capture & vf pipes in
@@ -1778,12 +1506,9 @@ int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_AUTO, false); atomisp_freq_scaling(isp, ATOMISP_DFS_MODE_AUTO, false);
} }
return videobuf_streamoff(&pipe->capq); goto out_unlock;
} }
if (!pipe->capq.streaming)
return 0;
if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED) if (asd->streaming == ATOMISP_DEVICE_STREAMING_ENABLED)
first_streamoff = true; first_streamoff = true;
@@ -1794,12 +1519,8 @@ int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
asd->streaming = ATOMISP_DEVICE_STREAMING_STOPPING; asd->streaming = ATOMISP_DEVICE_STREAMING_STOPPING;
spin_unlock_irqrestore(&isp->lock, flags); spin_unlock_irqrestore(&isp->lock, flags);
if (!first_streamoff) { if (!first_streamoff)
ret = videobuf_streamoff(&pipe->capq);
if (ret)
return ret;
goto stopsensor; goto stopsensor;
}
atomisp_clear_css_buffer_counters(asd); atomisp_clear_css_buffer_counters(asd);
atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false); atomisp_css_irq_enable(isp, IA_CSS_IRQ_INFO_CSS_RECEIVER_SOF, false);
@@ -1814,15 +1535,10 @@ int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type)
atomisp_flush_video_pipe(pipe, true); atomisp_flush_video_pipe(pipe, true);
ret = videobuf_streamoff(&pipe->capq);
if (ret)
return ret;
atomisp_subdev_cleanup_pending_events(asd); atomisp_subdev_cleanup_pending_events(asd);
stopsensor: stopsensor:
if (atomisp_subdev_streaming_count(asd) + 1 if (atomisp_subdev_streaming_count(asd) != atomisp_sensor_start_stream(asd))
!= atomisp_sensor_start_stream(asd)) goto out_unlock;
return 0;
ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera, ret = v4l2_subdev_call(isp->inputs[asd->input_curr].camera,
video, s_stream, 0); video, s_stream, 0);
@@ -1835,7 +1551,7 @@ stopsensor:
/* if other streams are running, isp should not be powered off */ /* if other streams are running, isp should not be powered off */
if (atomisp_streaming_count(isp)) { if (atomisp_streaming_count(isp)) {
atomisp_css_flush(isp); atomisp_css_flush(isp);
return 0; goto out_unlock;
} }
/* Disable the CSI interface on ANN B0/K0 */ /* Disable the CSI interface on ANN B0/K0 */
@@ -1894,7 +1610,8 @@ stopsensor:
} }
isp->isp_timeout = false; isp->isp_timeout = false;
} }
return ret; out_unlock:
mutex_unlock(&isp->mutex);
} }
/* /*
@@ -2683,12 +2400,12 @@ const struct v4l2_ioctl_ops atomisp_ioctl_ops = {
.vidioc_try_fmt_vid_cap = atomisp_try_fmt_cap, .vidioc_try_fmt_vid_cap = atomisp_try_fmt_cap,
.vidioc_g_fmt_vid_cap = atomisp_g_fmt_cap, .vidioc_g_fmt_vid_cap = atomisp_g_fmt_cap,
.vidioc_s_fmt_vid_cap = atomisp_set_fmt, .vidioc_s_fmt_vid_cap = atomisp_set_fmt,
.vidioc_reqbufs = atomisp_reqbufs, .vidioc_reqbufs = vb2_ioctl_reqbufs,
.vidioc_querybuf = atomisp_querybuf, .vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = atomisp_qbuf, .vidioc_qbuf = atomisp_qbuf_wrapper,
.vidioc_dqbuf = atomisp_dqbuf, .vidioc_dqbuf = atomisp_dqbuf_wrapper,
.vidioc_streamon = atomisp_streamon, .vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = atomisp_streamoff, .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_default = atomisp_vidioc_default, .vidioc_default = atomisp_vidioc_default,
.vidioc_s_parm = atomisp_s_parm, .vidioc_s_parm = atomisp_s_parm,
.vidioc_g_parm = atomisp_g_parm, .vidioc_g_parm = atomisp_g_parm,

View File

@@ -39,14 +39,12 @@ int atomisp_pipe_check(struct atomisp_video_pipe *pipe, bool streaming_ok);
int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd, int atomisp_alloc_css_stat_bufs(struct atomisp_sub_device *asd,
uint16_t stream_id); uint16_t stream_id);
int atomisp_streamoff(struct file *file, void *fh, enum v4l2_buf_type type); int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count);
int atomisp_reqbufs(struct file *file, void *fh, struct v4l2_requestbuffers *req); void atomisp_stop_streaming(struct vb2_queue *vq);
enum ia_css_pipe_id atomisp_get_css_pipe_id(struct atomisp_sub_device enum ia_css_pipe_id atomisp_get_css_pipe_id(struct atomisp_sub_device
*asd); *asd);
void atomisp_videobuf_free_buf(struct videobuf_buffer *vb);
extern const struct v4l2_ioctl_ops atomisp_ioctl_ops; extern const struct v4l2_ioctl_ops atomisp_ioctl_ops;
unsigned int atomisp_streaming_count(struct atomisp_device *isp); unsigned int atomisp_streaming_count(struct atomisp_device *isp);
@@ -57,4 +55,8 @@ long atomisp_compat_ioctl32(struct file *file,
int atomisp_stream_on_master_slave_sensor(struct atomisp_device *isp, int atomisp_stream_on_master_slave_sensor(struct atomisp_device *isp,
bool isp_timeout); bool isp_timeout);
int atomisp_start_streaming(struct vb2_queue *vq, unsigned int count);
void atomisp_stop_streaming(struct vb2_queue *vq);
#endif /* __ATOMISP_IOCTL_H__ */ #endif /* __ATOMISP_IOCTL_H__ */

View File

@@ -1064,6 +1064,7 @@ static void atomisp_init_subdev_pipe(struct atomisp_sub_device *asd,
pipe->asd = asd; pipe->asd = asd;
pipe->isp = asd->isp; pipe->isp = asd->isp;
spin_lock_init(&pipe->irq_lock); spin_lock_init(&pipe->irq_lock);
mutex_init(&pipe->vb_queue_mutex);
INIT_LIST_HEAD(&pipe->buffers_in_css); INIT_LIST_HEAD(&pipe->buffers_in_css);
INIT_LIST_HEAD(&pipe->activeq); INIT_LIST_HEAD(&pipe->activeq);
INIT_LIST_HEAD(&pipe->buffers_waiting_for_param); INIT_LIST_HEAD(&pipe->buffers_waiting_for_param);

View File

@@ -21,8 +21,7 @@
#include <media/v4l2-ctrls.h> #include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h> #include <media/v4l2-device.h>
#include <media/v4l2-subdev.h> #include <media/v4l2-subdev.h>
#include <media/videobuf-core.h> #include <media/videobuf2-v4l2.h>
#include "atomisp_common.h" #include "atomisp_common.h"
#include "atomisp_compat.h" #include "atomisp_compat.h"
#include "atomisp_v4l2.h" #include "atomisp_v4l2.h"
@@ -69,7 +68,9 @@ struct atomisp_video_pipe {
struct video_device vdev; struct video_device vdev;
enum v4l2_buf_type type; enum v4l2_buf_type type;
struct media_pad pad; struct media_pad pad;
struct videobuf_queue capq; struct vb2_queue vb_queue;
/* Lock for vb_queue, when also taking isp->mutex this must be taken first! */
struct mutex vb_queue_mutex;
/* List of video-buffers handed over to the CSS */ /* List of video-buffers handed over to the CSS */
struct list_head buffers_in_css; struct list_head buffers_in_css;
/* List of video-buffers handed over to the driver, but not yet to the CSS */ /* List of video-buffers handed over to the driver, but not yet to the CSS */
@@ -82,6 +83,9 @@ struct atomisp_video_pipe {
/* the link list to store per_frame parameters */ /* the link list to store per_frame parameters */
struct list_head per_frame_params; struct list_head per_frame_params;
/* Filled through atomisp_get_css_frame_info() on queue setup */
struct ia_css_frame_info frame_info;
/* Store here the initial run mode */ /* Store here the initial run mode */
unsigned int default_run_mode; unsigned int default_run_mode;
/* Set from streamoff to disallow queuing further buffers in CSS */ /* Set from streamoff to disallow queuing further buffers in CSS */
@@ -113,6 +117,11 @@ struct atomisp_video_pipe {
struct atomisp_css_params_with_list *frame_params[VIDEO_MAX_FRAME]; struct atomisp_css_params_with_list *frame_params[VIDEO_MAX_FRAME];
}; };
#define vq_to_pipe(queue) \
container_of(queue, struct atomisp_video_pipe, vb_queue)
#define vb_to_pipe(vb) vq_to_pipe((vb)->vb2_queue)
struct atomisp_pad_format { struct atomisp_pad_format {
struct v4l2_mbus_framefmt fmt; struct v4l2_mbus_framefmt fmt;
struct v4l2_rect crop; struct v4l2_rect crop;

View File

@@ -20,6 +20,7 @@
* This file contains structs to describe various frame-formats supported by the ISP. * This file contains structs to describe various frame-formats supported by the ISP.
*/ */
#include <media/videobuf2-v4l2.h>
#include <type_support.h> #include <type_support.h>
#include "ia_css_err.h" #include "ia_css_err.h"
#include "ia_css_types.h" #include "ia_css_types.h"
@@ -146,6 +147,17 @@ enum ia_css_frame_flash_state {
* This is the main structure used for all input and output images. * This is the main structure used for all input and output images.
*/ */
struct ia_css_frame { struct ia_css_frame {
/*
* The videobuf2 core will allocate buffers including room for private
* data (the rest of struct ia_css_frame). The vb2_v4l2_buffer must
* be the first member for this to work!
* Note the atomisp code also uses ia_css_frame-s which are not used
* as v4l2-buffers in some places. In this case the vb2 member will
* be unused.
*/
struct vb2_v4l2_buffer vb;
/* List-head for linking into the activeq or buffers_waiting_for_param list */
struct list_head queue;
struct ia_css_frame_info frame_info; /** info struct describing the frame */ struct ia_css_frame_info frame_info; /** info struct describing the frame */
ia_css_ptr data; /** pointer to start of image data */ ia_css_ptr data; /** pointer to start of image data */
unsigned int data_bytes; /** size of image data in bytes */ unsigned int data_bytes; /** size of image data in bytes */
@@ -183,6 +195,9 @@ struct ia_css_frame {
info.format */ info.format */
}; };
#define vb_to_frame(vb2) \
container_of(to_vb2_v4l2_buffer(vb2), struct ia_css_frame, vb)
#define DEFAULT_FRAME { \ #define DEFAULT_FRAME { \
.frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \ .frame_info = IA_CSS_BINARY_DEFAULT_FRAME_INFO, \
.dynamic_queue_id = SH_CSS_INVALID_QUEUE_ID, \ .dynamic_queue_id = SH_CSS_INVALID_QUEUE_ID, \