index 2cd0f87da8e29785ad38a87b05b219893024e720..ab0b961dd1dcaec00ab06e6a76e10dac9949df43 100644 (file)
static struct vip_fmt vip_formats[] = {
{
- .name = "YUV 444 co-planar",
+ .name = "NV24 YUV 444 co-planar",
.fourcc = V4L2_PIX_FMT_NV24,
- .code = V4L2_MBUS_FMT_YDYUYDYV8_1X16,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.coplanar = 1,
.vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y444],
},
},
{
- .name = "YUV 422 co-planar",
+ .name = "NV16 YUV 422 co-planar",
.fourcc = V4L2_PIX_FMT_NV16,
- .code = V4L2_MBUS_FMT_YDYUYDYV8_1X16,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.coplanar = 1,
.vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y422],
},
},
{
- .name = "YUV 420 co-planar",
+ .name = "NV12 YUV 420 co-planar",
.fourcc = V4L2_PIX_FMT_NV12,
- .code = V4L2_MBUS_FMT_YDYUYDYV8_1X16,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.coplanar = 1,
.vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_Y420],
.code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.coplanar = 0,
- .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CY422],
+ .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CBY422],
},
},
{
.name = "YUYV 422 packed",
.fourcc = V4L2_PIX_FMT_YUYV,
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.coplanar = 0,
- .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YC422],
+ .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YCB422],
},
},
{
.name = "VYUY 422 packed",
.fourcc = V4L2_PIX_FMT_VYUY,
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .colorspace = V4L2_COLORSPACE_SMPTE170M,
+ .coplanar = 0,
+ .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_CRY422],
+ },
+ },
+ {
+ .name = "YVYU 422 packed",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.coplanar = 0,
- .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YC422],
+ .vpdma_fmt = { &vpdma_yuv_fmts[VPDMA_DATA_FMT_YCR422],
},
},
{
/*
* Find our format description corresponding to the passed v4l2_format
*/
-#ifdef DISABLED_FOR_NOW
-static struct vip_fmt *find_format_by_pix(u32 pixelformat)
-{
- struct vip_fmt *fmt;
- unsigned int k;
-
- for (k = 0; k < ARRAY_SIZE(vip_formats); k++) {
- fmt = &vip_formats[k];
- if (fmt->fourcc == pixelformat)
- return fmt;
- }
- return NULL;
-}
-#endif
-
-static struct vip_fmt *find_format_by_code(u32 code)
-{
- struct vip_fmt *fmt;
- unsigned int k;
-
- for (k = 0; k < ARRAY_SIZE(vip_formats); k++) {
- fmt = &vip_formats[k];
- if (fmt->code == code)
- return fmt;
- }
-
- return NULL;
-}
-
-static struct vip_fmt *find_active_format_by_pix(struct vip_dev *dev,
- u32 pixelformat)
+static struct vip_fmt *find_port_format_by_pix(struct vip_port *port,
+ u32 pixelformat)
{
+ struct vip_dev *dev = port->dev;
struct vip_fmt *fmt;
unsigned int k;
return NULL;
}
-static struct vip_fmt *find_active_format_by_code(struct vip_dev *dev,
- u32 code)
-{
- struct vip_fmt *fmt;
- unsigned int k;
-
- for (k = 0; k < dev->num_active_fmt; k++) {
- fmt = dev->active_fmt[k];
- if (fmt->code == code)
- return fmt;
- }
-
- return NULL;
-}
-
static LIST_HEAD(vip_shared_list);
static inline struct vip_dev *notifier_to_vip_dev(struct v4l2_async_notifier *n)
@@ -304,6 +270,7 @@ static inline struct vip_dev *notifier_to_vip_dev(struct v4l2_async_notifier *n)
static int alloc_port(struct vip_dev *, int);
static void free_port(struct vip_port *);
static int vip_setup_parser(struct vip_port *port);
+static void stop_dma(struct vip_stream *stream);
static inline u32 read_sreg(struct vip_shared *shared, int offset)
{
{
u32 val, ret, offset;
- if (polarity == 0 && port->dev->syscon) {
+ if (polarity == 1 && port->dev->syscon) {
/*
* When the VIP parser is configured to so that the pixel clock
* This will make sure that an abort descriptor for this channel
* would be submitted to VPDMA causing any ongoing transaction to be
* aborted and cleanup the VPDMA FSM for this channel */
- dev->vpdma_channels[channel] = 1;
+ stream->vpdma_channels[channel] = 1;
- vpdma_rawchan_add_out_dtd(&dev->desc_list, c_rect->width, c_rect,
+ vpdma_rawchan_add_out_dtd(&stream->desc_list, c_rect->width, c_rect,
fmt->vpdma_fmt[plane], dma_addr, max_width, max_height,
channel, flags);
add_out_dtd(stream, VIP_SRCE_CHROMA);
}
-static void enable_irqs(struct vip_dev *dev, int irq_num)
+static void enable_irqs(struct vip_dev *dev, int irq_num, int list_num)
{
u32 reg_addr = VIP_INT0_ENABLE0_SET +
VIP_INTC_INTX_OFFSET * irq_num;
- int list_num = dev->slice_id;
write_sreg(dev->shared, reg_addr, 1 << (list_num * 2));
irq_num, list_num, true);
}
-static void disable_irqs(struct vip_dev *dev, int irq_num)
+static void disable_irqs(struct vip_dev *dev, int irq_num, int list_num)
{
u32 reg_addr = VIP_INT0_ENABLE0_CLR +
VIP_INTC_INTX_OFFSET * irq_num;
- int list_num = dev->slice_id;
- write_sreg(dev->shared, reg_addr, 0xffffffff);
+ write_sreg(dev->shared, reg_addr, 1 << (list_num * 2));
vpdma_enable_list_complete_irq(dev->shared->vpdma,
irq_num, list_num, false);
}
-static void clear_irqs(struct vip_dev *dev, int irq_num)
+static void clear_irqs(struct vip_dev *dev, int irq_num, int list_num)
{
u32 reg_addr = VIP_INT0_STATUS0_CLR +
VIP_INTC_INTX_OFFSET * irq_num;
- write_sreg(dev->shared, reg_addr, 0xffffffff);
+ write_sreg(dev->shared, reg_addr, 1 << (list_num * 2));
vpdma_clear_list_stat(dev->shared->vpdma, irq_num, dev->slice_id);
}
struct vip_dev *dev = port->dev;
unsigned int list_length;
- dev->desc_next = dev->desc_list.buf.addr;
+ stream->desc_next = stream->desc_list.buf.addr;
add_stream_dtds(stream);
- list_length = dev->desc_next - dev->desc_list.buf.addr;
- vpdma_map_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
+ list_length = stream->desc_next - stream->desc_list.buf.addr;
+ vpdma_map_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
}
/*
* Should be called after a new vb is queued and on a vpdma list
* completion interrupt.
*/
-static void start_dma(struct vip_dev *dev, struct vip_buffer *buf)
+static void start_dma(struct vip_stream *stream, struct vip_buffer *buf)
{
+ struct vip_dev *dev = stream->port->dev;
struct vpdma_data *vpdma = dev->shared->vpdma;
+ int list_num = stream->list_num;
dma_addr_t dma_addr;
int drop_data;
- if (vpdma_list_busy(vpdma, dev->slice_id)) {
+ if (vpdma_list_busy(vpdma, list_num)) {
vip_err(dev, "vpdma list busy, cannot post");
return; /* nothing to do */
}
vip_dbg(4, dev, "start_dma: dropped\n");
}
- vpdma_update_dma_addr(dev->shared->vpdma, &dev->desc_list,
- dma_addr, dev->write_desc, drop_data);
- vpdma_submit_descs(dev->shared->vpdma, &dev->desc_list, dev->slice_id);
+ vpdma_update_dma_addr(dev->shared->vpdma, &stream->desc_list,
+ dma_addr, stream->write_desc, drop_data, 0);
+
+ if (stream->port->fmt->coplanar) {
+ dma_addr += stream->width * stream->height;
+ vpdma_update_dma_addr(dev->shared->vpdma, &stream->desc_list,
+ dma_addr, stream->write_desc + 1, drop_data, 1);
+ }
+
+ vpdma_submit_descs(dev->shared->vpdma,
+ &stream->desc_list, stream->list_num);
}
static void vip_schedule_next_buffer(struct vip_stream *stream)
struct vip_buffer, list);
buf->drop = true;
- list_move_tail(&buf->list, &dev->vip_bufs);
+ list_move_tail(&buf->list, &stream->post_bufs);
buf = NULL;
} else if (vb2_is_streaming(&stream->vb_vidq)) {
buf = list_entry(stream->vidq.next,
struct vip_buffer, list);
buf->drop = false;
- list_move_tail(&buf->list, &dev->vip_bufs);
+ list_move_tail(&buf->list, &stream->post_bufs);
vip_dbg(4, dev, "added next buffer\n");
} else {
vip_err(dev, "IRQ occurred when not streaming\n");
buf = list_entry(stream->dropq.next,
struct vip_buffer, list);
buf->drop = true;
- list_move_tail(&buf->list, &dev->vip_bufs);
+ list_move_tail(&buf->list, &stream->post_bufs);
buf = NULL;
}
spin_unlock_irqrestore(&dev->slock, flags);
- start_dma(dev, buf);
+ start_dma(stream, buf);
}
static void vip_process_buffer_complete(struct vip_stream *stream)
struct vb2_buffer *vb = NULL;
unsigned long flags, fld;
- buf = list_first_entry(&dev->vip_bufs, struct vip_buffer, list);
+ buf = list_first_entry(&stream->post_bufs, struct vip_buffer, list);
if (stream->port->flags & FLAG_INTERLACED) {
- vpdma_unmap_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
+ vpdma_unmap_desc_buf(dev->shared->vpdma,
+ &stream->desc_list.buf);
- fld = dtd_get_field(dev->write_desc);
+ fld = dtd_get_field(stream->write_desc);
stream->field = fld ? V4L2_FIELD_BOTTOM : V4L2_FIELD_TOP;
- vpdma_map_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
+ vpdma_map_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
}
if (buf) {
static irqreturn_t vip_irq(int irq_vip, void *data)
{
struct vip_dev *dev = (struct vip_dev *)data;
+ struct vpdma_data *vpdma = dev->shared->vpdma;
struct vip_stream *stream;
- int list_num = dev->slice_id;
+ int list_num;
int irq_num = dev->slice_id;
u32 irqst, reg_addr;
vip_dbg(8, dev, "IRQ %d VIP_INT%d_STATUS0 0x%x\n",
irq_vip, irq_num, irqst);
if (irqst) {
- vpdma_clear_list_stat(dev->shared->vpdma, irq_num, list_num);
-
reg_addr = VIP_INT0_STATUS0_CLR +
VIP_INTC_INTX_OFFSET * irq_num;
write_sreg(dev->shared, reg_addr, irqst);
- }
- stream = dev->ports[0]->cap_streams[0];
- if (dev->num_skip_irq)
- dev->num_skip_irq--;
- else
- vip_process_buffer_complete(stream);
+ for (list_num = 0; list_num < 8; list_num++) {
+ /* Check for LIST_COMPLETE IRQ */
+ if (!(irqst & (1 << list_num * 2)))
+ continue;
- vip_schedule_next_buffer(stream);
+ vip_dbg(8, dev, "IRQ %d: handling LIST%d_COMPLETE\n",
+ irq_num, list_num);
- return IRQ_HANDLED;
-}
+ stream = vpdma_hwlist_get_priv(vpdma, list_num);
+ if (!stream || stream->list_num != list_num) {
+ vip_err(dev, "IRQ occured for unused list");
+ continue;
+ }
-/*
- * video ioctls
- */
-static struct v4l2_mbus_framefmt *
-vip_video_pix_to_mbus(const struct v4l2_pix_format *pix,
- struct v4l2_mbus_framefmt *mbus)
-{
- unsigned int i;
+ vpdma_clear_list_stat(vpdma, irq_num, list_num);
- memset(mbus, 0, sizeof(*mbus));
- mbus->width = pix->width;
- mbus->height = pix->height;
+ if (dev->num_skip_irq)
+ dev->num_skip_irq--;
+ else
+ vip_process_buffer_complete(stream);
- mbus->code = V4L2_MBUS_FMT_YUYV8_2X8;
- for (i = 0; i < ARRAY_SIZE(vip_formats) - 1; ++i) {
- if (vip_formats[i].fourcc == pix->pixelformat) {
- mbus->code = vip_formats[i].code;
- break;
+ vip_schedule_next_buffer(stream);
+ irqst &= ~((1 << list_num * 2));
}
}
- mbus->colorspace = pix->colorspace;
- mbus->field = pix->field;
-
- return mbus;
+ return IRQ_HANDLED;
}
+/*
+ * video ioctls
+ */
static int vip_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
strncpy(cap->card, VIP_MODULE_NAME, sizeof(cap->card) - 1);
snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
VIP_MODULE_NAME);
- cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
+ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
return -EINVAL;
inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = stream->vfd->tvnorms;
sprintf(inp->name, "camera %u", stream->vfd->num);
return 0;
struct vip_stream *stream = file2stream(file);
struct vip_dev *dev = stream->port->dev;
+ *std = stream->vfd->tvnorms;
v4l2_subdev_call(dev->sensor, video, querystd, std);
+ vip_dbg(1, dev, "querystd: 0x%lx\n", (unsigned long)*std);
return 0;
}
struct vip_stream *stream = file2stream(file);
struct vip_dev *dev = stream->port->dev;
- *std = 0;
+ *std = stream->vfd->tvnorms;
v4l2_subdev_call(dev->sensor, video, g_std_output, std);
+ vip_dbg(1, dev, "g_std: 0x%lx\n", (unsigned long)*std);
+
return 0;
}
struct vip_stream *stream = file2stream(file);
struct vip_dev *dev = stream->port->dev;
+ vip_dbg(1, dev, "s_std: 0x%lx\n", (unsigned long)std);
+
+ if (!(std & stream->vfd->tvnorms)) {
+ vip_dbg(1, dev, "s_std after check: 0x%lx\n",
+ (unsigned long)std);
+ return -EINVAL;
+ }
+
v4l2_subdev_call(dev->sensor, video, s_std_output, std);
return 0;
}
{
struct vip_stream *stream = file2stream(file);
struct vip_dev *dev = stream->port->dev;
- struct vip_fmt *fmt;
+ struct vip_fmt *fmt = NULL;
vip_dbg(3, dev, "enum_fmt index:%d\n", f->index);
+
if (f->index >= dev->num_active_fmt)
return -EINVAL;
{
struct vip_stream *stream = file2stream(file);
struct vip_dev *dev = stream->port->dev;
+ struct vip_port *port = stream->port;
struct vip_fmt *fmt;
- int ret;
- fmt = find_active_format_by_pix(dev, f->pixel_format);
+ fmt = find_port_format_by_pix(port, f->pixel_format);
if (!fmt)
return -EINVAL;
- ret = v4l2_subdev_call(dev->sensor, video, enum_framesizes, f);
- if (ret)
- vip_dbg(1, dev, "enum_framesizes failed in subdev\n");
-
- return ret;
+ return v4l2_subdev_call(dev->sensor, video, enum_framesizes, f);
}
static int vip_enum_frameintervals(struct file *file, void *priv,
{
struct vip_stream *stream = file2stream(file);
struct vip_dev *dev = stream->port->dev;
+ struct vip_port *port = stream->port;
struct v4l2_frmsizeenum fsize;
struct vip_fmt *fmt;
int ret;
if (f->index)
return -EINVAL;
- fmt = find_active_format_by_pix(dev, f->pixel_format);
+ fmt = find_port_format_by_pix(port, f->pixel_format);
if (!fmt)
return -EINVAL;
ret = v4l2_subdev_call(dev->sensor, video,
enum_framesizes, &fsize);
if (ret) {
- if (fsize.index == 0)
- vip_dbg(1, dev, "enum_frameinterval failed on the first enum_framesize\n");
return -EINVAL;
}
(f->height >= fsize.stepwise.min_height) &&
(f->height <= fsize.stepwise.max_height))
break;
- } else
+ } else {
return -EINVAL;
+ }
}
f->type = V4L2_FRMIVAL_TYPE_DISCRETE;
return 0;
}
+static int vip_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ if (parm->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ parm->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
+ parm->parm.capture.timeperframe.numerator = 1;
+ parm->parm.capture.timeperframe.denominator = 30;
+ parm->parm.capture.readbuffers = 4;
+ return 0;
+}
+
static int vip_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *parm)
{
parm->parm.capture.timeperframe.numerator = 1;
parm->parm.capture.timeperframe.denominator = 30;
+ parm->parm.capture.readbuffers = 4;
return 0;
}
-static int vip_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+static int vip_calc_format_size(struct vip_port *port,
+ struct vip_fmt *fmt,
+ struct v4l2_format *f)
{
- struct vip_stream *stream = file2stream(file);
- struct vip_dev *dev = stream->port->dev;
- struct vip_fmt *fmt = find_active_format_by_pix(dev,
- f->fmt.pix.pixelformat);
- enum v4l2_field field;
+ struct vip_dev *dev = port->dev;
+ enum v4l2_field *field;
if (!fmt) {
- vip_err(dev,
- "Fourcc format (0x%08x) invalid.\n",
- f->fmt.pix.pixelformat);
+ vip_dbg(2, dev,
+ "no vip_fmt format provided!\n");
return -EINVAL;
}
- field = f->fmt.pix.field;
-
- if (field == V4L2_FIELD_ANY)
- field = V4L2_FIELD_NONE;
- else if (V4L2_FIELD_NONE != field && V4L2_FIELD_ALTERNATE != field)
+ field = &f->fmt.pix.field;
+ if (*field == V4L2_FIELD_ANY)
+ *field = V4L2_FIELD_NONE;
+ else if (V4L2_FIELD_NONE != *field && V4L2_FIELD_ALTERNATE != *field)
return -EINVAL;
- f->fmt.pix.field = field;
-
v4l_bound_align_image(&f->fmt.pix.width, MIN_W, MAX_W, W_ALIGN,
&f->fmt.pix.height, MIN_H, MAX_H, H_ALIGN,
S_ALIGN);
f->fmt.pix.colorspace = fmt->colorspace;
f->fmt.pix.priv = 0;
- vip_dbg(3, dev, "try_fmt fourcc:%s size: %dx%d bpl:%d img_size:%d\n",
+ vip_dbg(3, dev, "calc_format_size: fourcc:%s size: %dx%d bpl:%d img_size:%d\n",
fourcc_to_str(f->fmt.pix.pixelformat),
f->fmt.pix.width, f->fmt.pix.height,
f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
return 0;
}
+static int vip_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vip_stream *stream = file2stream(file);
+ struct vip_port *port = stream->port;
+ struct vip_dev *dev = port->dev;
+ struct v4l2_frmsizeenum fsize;
+ struct vip_fmt *fmt;
+ int ret, found;
+
+ vip_dbg(3, dev, "try_fmt fourcc:%s size: %dx%d\n",
+ fourcc_to_str(f->fmt.pix.pixelformat),
+ f->fmt.pix.width, f->fmt.pix.height);
+
+ fmt = find_port_format_by_pix(port, f->fmt.pix.pixelformat);
+ if (!fmt) {
+ vip_dbg(2, dev,
+ "Fourcc format (0x%08x) not found.\n",
+ f->fmt.pix.pixelformat);
+
+ /* Just get the first one enumerated */
+ fmt = dev->active_fmt[0];
+ f->fmt.pix.pixelformat = fmt->fourcc;
+ }
+
+ /* check for/find a valid width/height */
+ ret = 0;
+ found = false;
+ for (fsize.index = 0; ; fsize.index++) {
+ ret = v4l2_subdev_call(dev->sensor, video,
+ enum_framesizes, &fsize);
+ if (ret)
+ break;
+
+ if (fsize.type == V4L2_FRMSIZE_TYPE_DISCRETE) {
+ if ((f->fmt.pix.width == fsize.discrete.width) &&
+ (((f->fmt.pix.field == V4L2_FIELD_ALTERNATE) ?
+ f->fmt.pix.height * 2 : f->fmt.pix.height) ==
+ fsize.discrete.height)) {
+ found = true;
+ break;
+ }
+ } else if ((fsize.type == V4L2_FRMSIZE_TYPE_CONTINUOUS) ||
+ (fsize.type == V4L2_FRMSIZE_TYPE_STEPWISE)) {
+ if ((f->fmt.pix.width >= fsize.stepwise.min_width) &&
+ (f->fmt.pix.width <= fsize.stepwise.max_width) &&
+ (f->fmt.pix.height >= fsize.stepwise.min_height) &&
+ (f->fmt.pix.height <= fsize.stepwise.max_height)) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ /* use existing values as default */
+ f->fmt.pix.width = port->mbus_framefmt.width;
+ f->fmt.pix.height = port->mbus_framefmt.height;
+ }
+
+ /* That we have a fmt calculate imagesize and bytesperline */
+ return vip_calc_format_size(port, fmt, f);
+}
+
static int vip_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vip_stream *stream = file2stream(file);
struct vip_port *port = stream->port;
struct vip_dev *dev = stream->port->dev;
- struct v4l2_mbus_framefmt mbus_fmt;
- struct vip_fmt *fmt;
- struct v4l2_format try_f;
- int ret;
+ struct vip_fmt *fmt = port->fmt;
/* Use last known values or defaults */
f->fmt.pix.width = stream->width;
f->fmt.pix.bytesperline = stream->bytesperline;
f->fmt.pix.sizeimage = stream->sizeimage;
- /* Check with the subdevice */
- ret = v4l2_subdev_call(dev->sensor, video, g_mbus_fmt, &mbus_fmt);
- if (ret)
- vip_dbg(1, dev, "g_mbus_fmt failed in subdev\n");
-
- fmt = find_active_format_by_code(dev, mbus_fmt.code);
- if (!fmt) {
- vip_err(dev,
- "mbus_code (0x%08x) invalid.\n",
- mbus_fmt.code);
- return -EINVAL;
- }
-
- vip_dbg(3, dev, "g_fmt subdev mbus_code: %04X fourcc:%s size: %dx%d\n",
- fmt->code,
- fourcc_to_str(fmt->fourcc),
- mbus_fmt.width, mbus_fmt.height);
-
- /*
- * Run a try_fmt call to properly calculate
- * the sizeimage and bytesperline values
- * in case the defaults were not accurate.
- */
- try_f = *f;
- try_f.fmt.pix.pixelformat = fmt->fourcc;
- try_f.fmt.pix.width = mbus_fmt.width;
- try_f.fmt.pix.height = mbus_fmt.height;
- try_f.fmt.pix.field = mbus_fmt.field;
- try_f.fmt.pix.colorspace = mbus_fmt.colorspace;
-
- ret = vip_try_fmt_vid_cap(file, priv, &try_f);
- if (ret)
- return ret;
-
- if (port->fmt != fmt) {
- vip_dbg(1, dev, "g_fmt fmt mismatch port->fmt:%p fmt:%p\n",
- port->fmt, fmt);
- vip_dbg(1, dev, "g_fmt port->fmt->fourcc:%s\n",
- fourcc_to_str(port->fmt->fourcc));
- vip_dbg(1, dev, "fmt->fourcc:%s\n",
- fourcc_to_str(fmt->fourcc));
- vip_dbg(1, dev, "g_fmt port->fmt->name:%s fmt->name:%s\n",
- port->fmt->name, fmt->name);
- port->fmt = fmt;
- }
- /*
- * Since everything looks correct update
- * the local copy as well to make sure we are consistent
- */
- *f = try_f;
- stream->width = f->fmt.pix.width;
- stream->height = f->fmt.pix.height;
- stream->sup_field = f->fmt.pix.field;
- if (stream->sup_field == V4L2_FIELD_ALTERNATE)
- port->flags |= FLAG_INTERLACED;
- else
- port->flags &= ~FLAG_INTERLACED;
- stream->bytesperline = f->fmt.pix.bytesperline;
- stream->sizeimage = f->fmt.pix.sizeimage;
- port->c_rect.left = 0;
- port->c_rect.top = 0;
- port->c_rect.width = stream->width;
- port->c_rect.height = stream->height;
-
- vip_dbg(3, dev, "g_fmt fourcc:%s size: %dx%d bpl:%d img_size:%d\n",
+ vip_dbg(3, dev,
+ "g_fmt fourcc:%s code: %04x size: %dx%d bpl:%d img_size:%d\n",
fourcc_to_str(f->fmt.pix.pixelformat),
+ fmt->code,
f->fmt.pix.width, f->fmt.pix.height,
f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
+ vip_dbg(3, dev, "g_fmt vpdma data type: 0x%02X\n",
+ port->fmt->vpdma_fmt[0]->data_type);
return 0;
}
-/*
- * Set the registers that are modified when the video format changes.
- */
-static void set_fmt_params(struct vip_stream *stream)
-{
- struct vip_dev *dev = stream->port->dev;
-
- stream->sequence = 0;
- stream->field = V4L2_FIELD_TOP;
-
- if (stream->port->fmt->colorspace == V4L2_COLORSPACE_SRGB) {
- vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT);
- /* Set alpha component in background color */
- vpdma_set_bg_color(dev->shared->vpdma,
- (struct vpdma_data_format *)
- stream->port->fmt->vpdma_fmt[0],
- 0xff);
- }
-}
-
-int vip_s_fmt_vid_cap(struct file *file, void *priv,
+static int vip_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vip_stream *stream = file2stream(file);
return -EBUSY;
}
- port->fmt = find_active_format_by_pix(dev,
- f->fmt.pix.pixelformat);
+ port->fmt = find_port_format_by_pix(port,
+ f->fmt.pix.pixelformat);
stream->width = f->fmt.pix.width;
stream->height = f->fmt.pix.height;
- if (port->fmt->colorspace != f->fmt.pix.colorspace)
- vip_dbg(1, dev, "s_fmt colorspace mismatch port->fmt %d f->fmt %d\n",
- port->fmt->colorspace, f->fmt.pix.colorspace);
-
stream->bytesperline = f->fmt.pix.bytesperline;
stream->sizeimage = f->fmt.pix.sizeimage;
stream->sup_field = f->fmt.pix.field;
else
port->flags &= ~FLAG_INTERLACED;
- vip_dbg(1, dev,
- "Setting format for type %d, wxh: %dx%d, fourcc:%s\n",
- f->type, stream->width, stream->height,
- fourcc_to_str(port->fmt->fourcc));
-
vip_dbg(3, dev, "s_fmt fourcc:%s size: %dx%d bpl:%d img_size:%d\n",
fourcc_to_str(f->fmt.pix.pixelformat),
f->fmt.pix.width, f->fmt.pix.height,
f->fmt.pix.bytesperline, f->fmt.pix.sizeimage);
- mf = vip_video_pix_to_mbus(&f->fmt.pix, &sfmt.format);
+ mf = &sfmt.format;
+ v4l2_fill_mbus_format(mf, &f->fmt.pix, port->fmt->code);
+
+ /* Save it */
+ port->mbus_framefmt = *mf;
vip_dbg(3, dev, "s_fmt pix_to_mbus mbus_code: %04X size: %dx%d\n",
mf->code,
vip_dbg(3, dev, "s_fmt subdev s_fmt mbus_code: %04X size: %dx%d\n",
mf->code,
mf->width, mf->height);
+ vip_dbg(3, dev, "s_fmt vpdma data type: 0x%02X\n",
+ port->fmt->vpdma_fmt[0]->data_type);
return 0;
}
-EXPORT_SYMBOL(vip_s_fmt_vid_cap);
+
+/*
+ * Set the registers that are modified when the video format changes.
+ */
+static void set_fmt_params(struct vip_stream *stream)
+{
+ struct vip_dev *dev = stream->port->dev;
+ int data_path_reg;
+
+ stream->sequence = 0;
+ stream->field = V4L2_FIELD_TOP;
+
+ if (stream->port->fmt->colorspace == V4L2_COLORSPACE_SRGB) {
+ vip_set_slice_path(dev, VIP_RGB_OUT_LO_DATA_SELECT);
+ /* Set alpha component in background color */
+ vpdma_set_bg_color(dev->shared->vpdma,
+ (struct vpdma_data_format *)
+ stream->port->fmt->vpdma_fmt[0],
+ 0xff);
+ }
+
+ data_path_reg = VIP_VIP1_DATA_PATH_SELECT + 4 * dev->slice_id;
+ if (stream->port->fmt->coplanar) {
+ stream->port->flags &= ~FLAG_MULT_PORT;
+ write_vreg(dev, data_path_reg, 0x600);
+ } else {
+ stream->port->flags |= FLAG_MULT_PORT;
+ write_vreg(dev, data_path_reg, 0x8000);
+ }
+}
static int vip_g_selection(struct file *file, void *fh,
struct v4l2_selection *s)
.vidioc_enum_frameintervals = vip_enum_frameintervals,
.vidioc_enum_framesizes = vip_enum_framesizes,
.vidioc_s_parm = vip_s_parm,
-
+ .vidioc_g_parm = vip_g_parm,
.vidioc_g_selection = vip_g_selection,
.vidioc_s_selection = vip_s_selection,
.vidioc_reqbufs = vb2_ioctl_reqbufs,
dev->num_skip_irq = VIP_VPDMA_FIFO_SIZE;
spin_lock_irqsave(&dev->slock, flags);
- if (vpdma_list_busy(dev->shared->vpdma, dev->slice_id)) {
+ if (vpdma_list_busy(dev->shared->vpdma, stream->list_num)) {
spin_unlock_irqrestore(&dev->slock, flags);
- vpdma_unmap_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
- vpdma_reset_desc_list(&dev->desc_list);
+ vpdma_unmap_desc_buf(dev->shared->vpdma,
+ &stream->desc_list.buf);
+ vpdma_reset_desc_list(&stream->desc_list);
return -EBUSY;
}
- list_move_tail(&buf->list, &dev->vip_bufs);
+ list_move_tail(&buf->list, &stream->post_bufs);
spin_unlock_irqrestore(&dev->slock, flags);
vip_dbg(2, dev, "start_streaming: start_dma buf 0x%x\n",
(unsigned int)buf);
- start_dma(dev, buf);
+ start_dma(stream, buf);
/* We enable the irq after posting the vpdma descriptor
* to prevent sprurious interrupt coming in before the
* vb2 layer is completely ready to handle them
* otherwise the vb2_streaming test would fail early on
*/
- enable_irqs(dev, dev->slice_id);
+ enable_irqs(dev, dev->slice_id, stream->list_num);
+
return 0;
}
vip_dbg(1, dev, "stream on failed in subdev\n");
}
- disable_irqs(dev, dev->slice_id);
- clear_irqs(dev, dev->slice_id);
+ disable_irqs(dev, dev->slice_id, stream->list_num);
+ clear_irqs(dev, dev->slice_id, stream->list_num);
+ stop_dma(stream);
/* release all active buffers */
- while (!list_empty(&dev->vip_bufs)) {
- buf = list_entry(dev->vip_bufs.next, struct vip_buffer, list);
+ while (!list_empty(&stream->post_bufs)) {
+ buf = list_entry(stream->post_bufs.next,
+ struct vip_buffer, list);
list_del(&buf->list);
if (buf->drop == 1)
list_add_tail(&buf->list, &stream->dropq);
if (!vb2_is_streaming(vq))
return 0;
- vpdma_unmap_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
- vpdma_reset_desc_list(&dev->desc_list);
+ vpdma_unmap_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
+ vpdma_reset_desc_list(&stream->desc_list);
return 0;
}
*/
static int vip_init_dev(struct vip_dev *dev)
+{
+ if (dev->num_ports != 0)
+ goto done;
+
+ vip_set_clock_enable(dev, 1);
+done:
+ dev->num_ports++;
+
+ return 0;
+}
+
+static int vip_init_port(struct vip_port *port)
{
int ret;
+ struct vip_dev *dev = port->dev;
+ struct vip_fmt *fmt;
+ struct v4l2_mbus_framefmt *mbus_fmt = &port->mbus_framefmt;
- if (dev->num_ports != 0)
+ if (port->num_streams != 0)
goto done;
- ret = vpdma_create_desc_list(&dev->desc_list, VIP_DESC_LIST_SIZE,
+ ret = vip_init_dev(port->dev);
+ if (ret)
+ goto done;
+
+ /* Get subdevice current frame format */
+ ret = v4l2_subdev_call(dev->sensor, video, g_mbus_fmt, mbus_fmt);
+ if (ret)
+ vip_dbg(1, dev, "init_port g_mbus_fmt failed in subdev\n");
+
+ /* try to find one that matches */
+ fmt = find_port_format_by_pix(port, mbus_fmt->code);
+ if (!fmt) {
+ vip_dbg(1, dev, "subdev default mbus_fmt %04x is not matched.\n",
+ mbus_fmt->code);
+ /* if all else fails just pick the first one */
+ fmt = dev->active_fmt[0];
+
+ mbus_fmt->code = fmt->code;
+ ret = v4l2_subdev_call(dev->sensor, video,
+ s_mbus_fmt, mbus_fmt);
+ if (ret)
+ vip_dbg(1, dev, "init_port s_mbus_fmt failed in subdev\n");
+ }
+
+ /* Assign current format */
+ port->fmt = fmt;
+
+ vip_dbg(3, dev, "vip_init_port: g_mbus_fmt subdev mbus_code: %04X fourcc:%s size: %dx%d\n",
+ fmt->code,
+ fourcc_to_str(fmt->fourcc),
+ mbus_fmt->width, mbus_fmt->height);
+
+ if (mbus_fmt->field == V4L2_FIELD_ALTERNATE)
+ port->flags |= FLAG_INTERLACED;
+ else
+ port->flags &= ~FLAG_INTERLACED;
+
+ port->c_rect.left = 0;
+ port->c_rect.top = 0;
+ port->c_rect.width = mbus_fmt->width;
+ port->c_rect.height = mbus_fmt->height;
+
+done:
+ port->num_streams++;
+ return 0;
+}
+
+static int vip_init_stream(struct vip_stream *stream)
+{
+ struct vip_port *port = stream->port;
+ struct vip_dev *dev = port->dev;
+ struct vip_fmt *fmt;
+ struct v4l2_mbus_framefmt *mbus_fmt;
+ struct v4l2_format f;
+ int ret;
+
+ ret = vip_init_port(port);
+ if (ret != 0)
+ return ret;
+
+ fmt = port->fmt;
+ mbus_fmt = &port->mbus_framefmt;
+
+ /* Properly calculate the sizeimage and bytesperline values. */
+ v4l2_fill_pix_format(&f.fmt.pix, mbus_fmt);
+ f.fmt.pix.pixelformat = fmt->fourcc;
+ ret = vip_calc_format_size(port, fmt, &f);
+ if (ret)
+ return ret;
+
+ stream->width = f.fmt.pix.width;
+ stream->height = f.fmt.pix.height;
+ stream->sup_field = f.fmt.pix.field;
+ stream->bytesperline = f.fmt.pix.bytesperline;
+ stream->sizeimage = f.fmt.pix.sizeimage;
+
+ vip_dbg(3, dev, "init_stream fourcc:%s size: %dx%d bpl:%d img_size:%d\n",
+ fourcc_to_str(f.fmt.pix.pixelformat),
+ f.fmt.pix.width, f.fmt.pix.height,
+ f.fmt.pix.bytesperline, f.fmt.pix.sizeimage);
+ vip_dbg(3, dev, "init_stream vpdma data type: 0x%02X\n",
+ port->fmt->vpdma_fmt[0]->data_type);
+
+ ret = vpdma_create_desc_list(&stream->desc_list, VIP_DESC_LIST_SIZE,
VPDMA_LIST_TYPE_NORMAL);
if (ret != 0)
return ret;
- dev->write_desc = (struct vpdma_dtd *)dev->desc_list.buf.addr
+ stream->write_desc = (struct vpdma_dtd *)stream->desc_list.buf.addr
+ 15;
- vip_set_clock_enable(dev, 1);
-done:
- dev->num_ports++;
-
return 0;
}
static void vip_release_dev(struct vip_dev *dev)
{
- vpdma_unmap_desc_buf(dev->shared->vpdma, &dev->desc_list.buf);
- vpdma_free_desc_buf(&dev->desc_list.buf);
- vpdma_free_desc_list(&dev->desc_list);
-
/*
* On last close, disable clocks to conserve power
*/
struct vip_dev *dev = port->dev;
struct v4l2_of_endpoint *endpoint = dev->endpoint;
int iface = DUAL_8B_INTERFACE;
- int sync_type;
+ int sync_type, pclk_type;
unsigned int flags;
+ flags = endpoint->bus.parallel.flags;
vip_reset_port(port);
vip_set_port_enable(port, 1);
break;
case 1:
default:
- sync_type = EMBEDDED_SYNC_SINGLE_YUV422;
+ sync_type =
+ EMBEDDED_SYNC_LINE_MULTIPLEXED_YUV422;
}
}
else
sync_type = DISCRETE_SYNC_SINGLE_YUV422;
- flags = endpoint->bus.parallel.flags;
if (flags & (V4L2_MBUS_HSYNC_ACTIVE_HIGH |
V4L2_MBUS_HSYNC_ACTIVE_LOW))
vip_set_vsync_polarity(port,
vip_set_hsync_polarity(port,
flags & V4L2_MBUS_VSYNC_ACTIVE_HIGH ? 1 : 0);
- if (flags & (V4L2_MBUS_PCLK_SAMPLE_RISING |
- V4L2_MBUS_PCLK_SAMPLE_FALLING))
- vip_set_pclk_polarity(port,
- flags & V4L2_MBUS_PCLK_SAMPLE_RISING ? 1 : 0);
-
vip_xtra_set_repack_sel(port, 0);
vip_set_actvid_hsync_n(port, 0);
vip_set_actvid_polarity(port, 1);
return -EINVAL;
}
+ pclk_type = flags & V4L2_MBUS_PCLK_SAMPLE_RISING ? 0 : 1;
+ vip_set_pclk_polarity(port, pclk_type);
vip_set_data_interface(port, iface);
vip_sync_type(port, sync_type);
return 0;
}
-static int vip_init_port(struct vip_port *port)
+static void vip_release_stream(struct vip_stream *stream)
{
- int ret;
-
- if (port->num_streams != 0)
- goto done;
-
- ret = vip_init_dev(port->dev);
- if (ret)
- goto done;
-
- port->fmt = port->dev->active_fmt[0];
- port->src_colorspace = port->fmt->colorspace;
- port->c_rect.left = 0;
- port->c_rect.top = 0;
+ struct vip_dev *dev = stream->port->dev;
-done:
- port->num_streams++;
- return 0;
+ vpdma_unmap_desc_buf(dev->shared->vpdma, &stream->desc_list.buf);
+ vpdma_free_desc_buf(&stream->desc_list.buf);
+ vpdma_free_desc_list(&stream->desc_list);
}
-static void vip_release_port(struct vip_port *port)
+static void stop_dma(struct vip_stream *stream)
{
- struct vip_dev *dev = port->dev;
+ struct vip_dev *dev = stream->port->dev;
int ch, size = 0;
/* Create a list of channels to be cleared */
for (ch = 0; ch < VPDMA_MAX_CHANNELS; ch++) {
- if (dev->vpdma_channels[ch] == 1) {
- dev->vpdma_channels[size++] = ch;
+ if (stream->vpdma_channels[ch] == 1) {
+ stream->vpdma_channels[size++] = ch;
vip_dbg(2, dev, "Clear channel no: %d\n", ch);
}
}
/* Clear all the used channels for the list */
- vpdma_list_cleanup(dev->shared->vpdma, dev->slice_id,
- dev->vpdma_channels, size);
+ vpdma_list_cleanup(dev->shared->vpdma, stream->list_num,
+ stream->vpdma_channels, size);
for (ch = 0; ch < VPDMA_MAX_CHANNELS; ch++)
- dev->vpdma_channels[ch] = 0;
-
- if (--port->num_streams == 0)
- vip_release_dev(port->dev);
+ stream->vpdma_channels[ch] = 0;
}
-int vip_open(struct file *file)
+static int vip_open(struct file *file)
{
struct vip_stream *stream = video_drvdata(file);
struct vip_port *port = stream->port;
* Then initialize hw module.
*/
if (v4l2_fh_is_singular_file(file)) {
- if (vip_init_port(port)) {
- goto free_fh;
+ if (vip_init_stream(stream)) {
ret = -ENODEV;
+ goto free_fh;
}
- stream->width = 1280;
- stream->height = 720;
- stream->sizeimage = stream->width * stream->height *
- (port->fmt->vpdma_fmt[0]->depth +
- (port->fmt->coplanar ?
- port->fmt->vpdma_fmt[1]->depth : 0)) >> 3;
- stream->bytesperline = round_up((stream->width *
- port->fmt->vpdma_fmt[0]->depth) >> 3,
- 1 << L_ALIGN);
- stream->sup_field = V4L2_FIELD_NONE;
- port->c_rect.width = stream->width;
- port->c_rect.height = stream->height;
vip_dbg(1, dev, "Created stream instance %p\n", stream);
}
}
return ret;
}
-EXPORT_SYMBOL(vip_open);
-int vip_release(struct file *file)
+static int vip_release(struct file *file)
{
struct vip_stream *stream = video_drvdata(file);
struct vip_port *port = stream->port;
mutex_lock(&dev->mutex);
vip_stop_streaming(q);
- vip_release_port(stream->port);
+ vip_release_stream(stream);
+
+ if (--port->num_streams == 0)
+ vip_release_dev(port->dev);
mutex_unlock(&dev->mutex);
vip_dbg(1, dev, "Releasing stream instance %p\n", stream);
return vb2_fop_release(file);
}
-EXPORT_SYMBOL(vip_release);
static const struct v4l2_file_operations vip_fops = {
.owner = THIS_MODULE,
.open = vip_open,
.release = vip_release,
+ .read = vb2_fop_read,
.poll = vb2_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = vb2_fop_mmap,
.ioctl_ops = &vip_ioctl_ops,
.minor = -1,
.release = video_device_release,
+ .tvnorms = V4L2_STD_NTSC | V4L2_STD_PAL | V4L2_STD_SECAM,
};
static int alloc_stream(struct vip_port *port, int stream_id, int vfl_type)
stream->stream_id = stream_id;
stream->vfl_type = vfl_type;
+ stream->list_num = vpdma_hwlist_alloc(dev->shared->vpdma, stream);
+ if (stream->list_num < 0) {
+ vip_err(dev, "Could not get VPDMA hwlist");
+ ret = -ENODEV;
+ goto do_free_stream;
+ }
+
+ INIT_LIST_HEAD(&stream->post_bufs);
+
if (vfl_type == VFL_TYPE_GRABBER)
port->cap_streams[stream_id] = stream;
else
*/
q = &stream->vb_vidq;
q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- q->io_modes = VB2_MMAP | VB2_DMABUF;
+ q->io_modes = VB2_MMAP | VB2_DMABUF | VB2_READ;
q->drv_priv = stream;
q->buf_struct_size = sizeof(struct vip_buffer);
q->ops = &vip_video_qops;
video_unregister_device(stream->vfd);
video_device_release(stream->vfd);
+ vpdma_hwlist_release(dev->shared->vpdma, stream->list_num);
kfree(stream);
}
+static int get_subdev_active_format(struct vip_port *port,
+ struct v4l2_subdev *subdev)
+{
+ struct vip_dev *dev = port->dev;
+ struct vip_fmt *fmt;
+ enum v4l2_mbus_pixelcode code;
+ int ret = 0;
+ unsigned int k, i, j;
+
+ /* Enumerate sub device formats and enable all matching local formats */
+ dev->num_active_fmt = 0;
+ for (k = 0, i = 0;
+ (ret != -EINVAL);
+ k++) {
+ ret = v4l2_subdev_call(subdev, video, enum_mbus_fmt, k, &code);
+ if (ret == 0) {
+ vip_dbg(2, dev,
+ "subdev %s: code: %04x idx: %d\n",
+ subdev->name, code, k);
+
+ for (j = 0; j < ARRAY_SIZE(vip_formats); j++) {
+ fmt = &vip_formats[j];
+ if (code == fmt->code) {
+ dev->active_fmt[i] = fmt;
+ dev->num_active_fmt = i++;
+ vip_dbg(2, dev,
+ "matched fourcc: %s: code: %04x idx: %d\n",
+ fourcc_to_str(fmt->fourcc),
+ fmt->code,
+ dev->num_active_fmt);
+ }
+ }
+ }
+ }
+
+ if (i == 0) {
+ vip_err(dev, "No suitable format reported by subdev %s\n",
+ subdev->name);
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int alloc_port(struct vip_dev *dev, int id)
{
struct vip_port *port;
port->dev = dev;
port->port_id = id;
port->num_streams = 0;
+ port->flags |= FLAG_MULT_PORT;
ret = alloc_stream(port, 0, VFL_TYPE_GRABBER);
- return 0;
+ if (dev->endpoint->bus_type == V4L2_MBUS_BT656) {
+ /* Allocate streams for 4 channels */
+ ret = alloc_stream(port, 2, VFL_TYPE_GRABBER);
+ ret = alloc_stream(port, 4, VFL_TYPE_GRABBER);
+ ret = alloc_stream(port, 6, VFL_TYPE_GRABBER);
+ }
+
+ return get_subdev_active_format(port, dev->sensor);
}
static void free_port(struct vip_port *port)
return r < 0 ? r : 0;
}
-static int get_subdev_active_format(struct vip_dev *dev,
- struct v4l2_subdev *subdev)
-{
- struct vip_fmt *fmt;
- enum v4l2_mbus_pixelcode code;
- int ret = 0;
- unsigned int k;
-
- /* first find how many formats to allocate the correct size */
- dev->num_active_fmt = 0;
- for (k = 0;
- (ret != -EINVAL) && (dev->num_active_fmt < VIP_MAX_ACTIVE_FMT);
- k++) {
- ret = v4l2_subdev_call(subdev, video, enum_mbus_fmt, k, &code);
- if (ret == 0) {
- fmt = find_format_by_code(code);
- if (fmt) {
- dev->active_fmt[dev->num_active_fmt] = fmt;
- dev->num_active_fmt++;
- }
- }
- }
-
- if (dev->num_active_fmt == 0) {
-
- vip_err(dev, "No suitable format reported by subdev %s\n",
- subdev->name);
- return -EINVAL;
- }
-
- return 0;
-}
static int vip_async_bound(struct v4l2_async_notifier *notifier,
struct v4l2_subdev *subdev,
{
struct vip_dev *dev = notifier_to_vip_dev(notifier);
unsigned int idx = asd - &dev->config->asd[0];
+ int ret;
vip_dbg(1, dev, "vip_async_bound\n");
if (idx > dev->config->asd_sizes)
return -EINVAL;
- if (get_subdev_active_format(dev, subdev))
- return 0;
-
if (dev->sensor) {
if (asd < dev->sensor->asd) {
/* Notified of a subdev earlier in the array */
+ dev->sensor = subdev;
+ dev->endpoint = &dev->config->endpoints[idx];
vip_info(dev, "Switching to subdev %s (High priority)",
subdev->name);
- } else {
+
+ } else
vip_info(dev, "Rejecting subdev %s (Low priority)",
subdev->name);
- return 0;
- }
- } else
- alloc_port(dev, 0);
+ return 0;
+ }
dev->sensor = subdev;
dev->endpoint = &dev->config->endpoints[idx];
- vip_info(dev, "Using sensor %s for capture\n",
- subdev->name);
+ ret = alloc_port(dev, 0);
+ if (!ret)
+ vip_info(dev, "Using sensor %s for capture\n", subdev->name);
- return 0;
+ return ret;
}
static int vip_async_complete(struct v4l2_async_notifier *notifier)
vip_shared_set_clock_enable(shared, 1);
vip_top_vpdma_reset(shared);
- shared->vpdma = vpdma_create(pdev, vip_vpdma_fw_cb);
- if (!shared->vpdma) {
- dev_err(&pdev->dev, "Creating VPDMA failed");
- goto do_iounmap;
- }
-
list_add_tail(&shared->list, &vip_shared_list);
platform_set_drvdata(pdev, shared);
atomic_set(&shared->devs_allocated, 0);
if (!dev)
return -ENOMEM;
+ dev->instance_id = (int)of_dev_id->data;
+ snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
+ "%s%d-s%d", VIP_MODULE_NAME, dev->instance_id, slice);
+
dev->irq = platform_get_irq(pdev, slice);
if (!dev->irq) {
dev_err(&pdev->dev, "Could not get IRQ");
}
if (devm_request_irq(&pdev->dev, dev->irq, vip_irq,
- 0, VIP_MODULE_NAME, dev) < 0) {
+ 0, dev->v4l2_dev.name, dev) < 0) {
ret = -ENOMEM;
goto dev_unreg;
}
spin_lock_init(&dev->slock);
spin_lock_init(&dev->lock);
- INIT_LIST_HEAD(&dev->vip_bufs);
-
- dev->instance_id = (int)of_dev_id->data;
-
- snprintf(dev->v4l2_dev.name, sizeof(dev->v4l2_dev.name),
- "%s%d-%d", VIP_MODULE_NAME, dev->instance_id, slice);
ret = v4l2_device_register(&pdev->dev, &dev->v4l2_dev);
if (ret)
goto err_runtime_get;
vip_set_slice_path(dev, VIP_MULTI_CHANNEL_DATA_SELECT);
}
+ shared->vpdma = &shared->vpdma_data;
+ ret = vpdma_create(pdev, shared->vpdma, vip_vpdma_fw_cb);
+ if (ret) {
+ dev_err(&pdev->dev, "Creating VPDMA failed");
+ goto dev_unreg;
+ }
+
return 0;
dev_unreg:
},
{},
};
+MODULE_DEVICE_TABLE(of, vip_of_match);
#else
#define vip_of_match NULL
#endif