summaryrefslogtreecommitdiff
path: root/drivers/staging/media/ipu3
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/media/ipu3')
-rw-r--r--drivers/staging/media/ipu3/Kconfig2
-rw-r--r--drivers/staging/media/ipu3/ipu3-css.c40
-rw-r--r--drivers/staging/media/ipu3/ipu3-v4l2.c126
-rw-r--r--drivers/staging/media/ipu3/ipu3.c32
4 files changed, 116 insertions, 84 deletions
diff --git a/drivers/staging/media/ipu3/Kconfig b/drivers/staging/media/ipu3/Kconfig
index f80f3e35f431..4b51c67eac88 100644
--- a/drivers/staging/media/ipu3/Kconfig
+++ b/drivers/staging/media/ipu3/Kconfig
@@ -6,7 +6,7 @@ config VIDEO_IPU3_IMGU
depends on X86
select IOMMU_IOVA
select VIDEOBUF2_DMA_SG
- ---help---
+ help
This is the Video4Linux2 driver for Intel IPU3 image processing unit,
found in Intel Skylake and Kaby Lake SoCs and used for processing
images and video.
diff --git a/drivers/staging/media/ipu3/ipu3-css.c b/drivers/staging/media/ipu3/ipu3-css.c
index 15ab77e4b766..23cf5b2cfe8b 100644
--- a/drivers/staging/media/ipu3/ipu3-css.c
+++ b/drivers/staging/media/ipu3/ipu3-css.c
@@ -3,6 +3,7 @@
#include <linux/device.h>
#include <linux/iopoll.h>
+#include <linux/slab.h>
#include "ipu3-css.h"
#include "ipu3-css-fw.h"
@@ -1744,15 +1745,18 @@ int imgu_css_fmt_try(struct imgu_css *css,
struct v4l2_rect *const bds = &r[IPU3_CSS_RECT_BDS];
struct v4l2_rect *const env = &r[IPU3_CSS_RECT_ENVELOPE];
struct v4l2_rect *const gdc = &r[IPU3_CSS_RECT_GDC];
- struct imgu_css_queue q[IPU3_CSS_QUEUES];
- struct v4l2_pix_format_mplane *const in =
- &q[IPU3_CSS_QUEUE_IN].fmt.mpix;
- struct v4l2_pix_format_mplane *const out =
- &q[IPU3_CSS_QUEUE_OUT].fmt.mpix;
- struct v4l2_pix_format_mplane *const vf =
- &q[IPU3_CSS_QUEUE_VF].fmt.mpix;
+ struct imgu_css_queue *q;
+ struct v4l2_pix_format_mplane *in, *out, *vf;
int i, s, ret;
+ q = kcalloc(IPU3_CSS_QUEUES, sizeof(struct imgu_css_queue), GFP_KERNEL);
+ if (!q)
+ return -ENOMEM;
+
+ in = &q[IPU3_CSS_QUEUE_IN].fmt.mpix;
+ out = &q[IPU3_CSS_QUEUE_OUT].fmt.mpix;
+ vf = &q[IPU3_CSS_QUEUE_VF].fmt.mpix;
+
/* Adjust all formats, get statistics buffer sizes and formats */
for (i = 0; i < IPU3_CSS_QUEUES; i++) {
if (fmts[i])
@@ -1766,7 +1770,8 @@ int imgu_css_fmt_try(struct imgu_css *css,
IPU3_CSS_QUEUE_TO_FLAGS(i))) {
dev_notice(css->dev, "can not initialize queue %s\n",
qnames[i]);
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
}
for (i = 0; i < IPU3_CSS_RECTS; i++) {
@@ -1788,7 +1793,8 @@ int imgu_css_fmt_try(struct imgu_css *css,
if (!imgu_css_queue_enabled(&q[IPU3_CSS_QUEUE_IN]) ||
!imgu_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT])) {
dev_warn(css->dev, "required queues are disabled\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
if (!imgu_css_queue_enabled(&q[IPU3_CSS_QUEUE_OUT])) {
@@ -1829,7 +1835,8 @@ int imgu_css_fmt_try(struct imgu_css *css,
ret = imgu_css_find_binary(css, pipe, q, r);
if (ret < 0) {
dev_err(css->dev, "failed to find suitable binary\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
css->pipes[pipe].bindex = ret;
@@ -1843,7 +1850,8 @@ int imgu_css_fmt_try(struct imgu_css *css,
IPU3_CSS_QUEUE_TO_FLAGS(i))) {
dev_err(css->dev,
"final resolution adjustment failed\n");
- return -EINVAL;
+ ret = -EINVAL;
+ goto out;
}
*fmts[i] = q[i].fmt.mpix;
}
@@ -1859,7 +1867,10 @@ int imgu_css_fmt_try(struct imgu_css *css,
bds->width, bds->height, gdc->width, gdc->height,
out->width, out->height, vf->width, vf->height);
- return 0;
+ ret = 0;
+out:
+ kfree(q);
+ return ret;
}
int imgu_css_fmt_set(struct imgu_css *css,
@@ -2160,11 +2171,6 @@ int imgu_css_set_parameters(struct imgu_css *css, unsigned int pipe,
obgrid_size = imgu_css_fw_obgrid_size(bi);
stripes = bi->info.isp.sp.iterator.num_stripes ? : 1;
- /*
- * TODO(b/118782861): If userspace queues more than 4 buffers, the
- * parameters from previous buffers will be overwritten. Fix the driver
- * not to allow this.
- */
imgu_css_pool_get(&css_pipe->pool.parameter_set_info);
param_set = imgu_css_pool_last(&css_pipe->pool.parameter_set_info,
0)->vaddr;
diff --git a/drivers/staging/media/ipu3/ipu3-v4l2.c b/drivers/staging/media/ipu3/ipu3-v4l2.c
index 9c0352b193a7..a7bc22040ed8 100644
--- a/drivers/staging/media/ipu3/ipu3-v4l2.c
+++ b/drivers/staging/media/ipu3/ipu3-v4l2.c
@@ -66,7 +66,7 @@ static int imgu_subdev_s_stream(struct v4l2_subdev *sd, int enable)
struct imgu_css_pipe *css_pipe = &imgu->css.pipes[pipe];
struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
- dev_dbg(dev, "%s %d for pipe %d", __func__, enable, pipe);
+ dev_dbg(dev, "%s %d for pipe %u", __func__, enable, pipe);
/* grab ctrl after streamon and return after off */
v4l2_ctrl_grab(imgu_sd->ctrl, enable);
@@ -101,7 +101,7 @@ static int imgu_subdev_s_stream(struct v4l2_subdev *sd, int enable)
else
css_pipe->pipe_id = IPU3_CSS_PIPE_ID_CAPTURE;
- dev_dbg(dev, "IPU3 pipe %d pipe_id %d", pipe, css_pipe->pipe_id);
+ dev_dbg(dev, "IPU3 pipe %u pipe_id %u", pipe, css_pipe->pipe_id);
rects[IPU3_CSS_RECT_EFFECTIVE] = &imgu_sd->rect.eff;
rects[IPU3_CSS_RECT_BDS] = &imgu_sd->rect.bds;
@@ -109,7 +109,7 @@ static int imgu_subdev_s_stream(struct v4l2_subdev *sd, int enable)
r = imgu_css_fmt_set(&imgu->css, fmts, rects, pipe);
if (r) {
- dev_err(dev, "failed to set initial formats pipe %d with (%d)",
+ dev_err(dev, "failed to set initial formats pipe %u with (%d)",
pipe, r);
return r;
}
@@ -157,7 +157,7 @@ static int imgu_subdev_set_fmt(struct v4l2_subdev *sd,
u32 pad = fmt->pad;
unsigned int pipe = imgu_sd->pipe;
- dev_dbg(&imgu->pci_dev->dev, "set subdev %d pad %d fmt to [%dx%d]",
+ dev_dbg(&imgu->pci_dev->dev, "set subdev %u pad %u fmt to [%ux%u]",
pipe, pad, fmt->format.width, fmt->format.height);
imgu_pipe = &imgu->imgu_pipe[pipe];
@@ -233,7 +233,7 @@ static int imgu_subdev_set_selection(struct v4l2_subdev *sd,
struct v4l2_rect *rect, *try_sel;
dev_dbg(&imgu->pci_dev->dev,
- "set subdev %d sel which %d target 0x%4x rect [%dx%d]",
+ "set subdev %u sel which %u target 0x%4x rect [%ux%u]",
imgu_sd->pipe, sel->which, sel->target,
sel->r.width, sel->r.height);
@@ -279,7 +279,7 @@ static int imgu_link_setup(struct media_entity *entity,
WARN_ON(pad >= IMGU_NODE_NUM);
- dev_dbg(&imgu->pci_dev->dev, "pipe %d pad %d is %s", pipe, pad,
+ dev_dbg(&imgu->pci_dev->dev, "pipe %u pad %u is %s", pipe, pad,
flags & MEDIA_LNK_FL_ENABLED ? "enabled" : "disabled");
imgu_pipe = &imgu->imgu_pipe[pipe];
@@ -294,7 +294,7 @@ static int imgu_link_setup(struct media_entity *entity,
else
__clear_bit(pipe, imgu->css.enabled_pipes);
- dev_dbg(&imgu->pci_dev->dev, "pipe %d is %s", pipe,
+ dev_dbg(&imgu->pci_dev->dev, "pipe %u is %s", pipe,
flags & MEDIA_LNK_FL_ENABLED ? "enabled" : "disabled");
return 0;
@@ -341,8 +341,10 @@ static void imgu_vb2_buf_queue(struct vb2_buffer *vb)
struct imgu_video_device *node =
container_of(vb->vb2_queue, struct imgu_video_device, vbq);
unsigned int queue = imgu_node_to_queue(node->id);
+ struct imgu_buffer *buf = container_of(vb, struct imgu_buffer,
+ vid_buf.vbb.vb2_buf);
unsigned long need_bytes;
- unsigned int pipe = node->pipe;
+ unsigned long payload = vb2_get_plane_payload(vb, 0);
if (vb->vb2_queue->type == V4L2_BUF_TYPE_META_CAPTURE ||
vb->vb2_queue->type == V4L2_BUF_TYPE_META_OUTPUT)
@@ -350,42 +352,26 @@ static void imgu_vb2_buf_queue(struct vb2_buffer *vb)
else
need_bytes = node->vdev_fmt.fmt.pix_mp.plane_fmt[0].sizeimage;
- if (queue == IPU3_CSS_QUEUE_PARAMS) {
- unsigned long payload = vb2_get_plane_payload(vb, 0);
- struct vb2_v4l2_buffer *buf =
- container_of(vb, struct vb2_v4l2_buffer, vb2_buf);
- int r = -EINVAL;
-
- if (payload == 0) {
- payload = need_bytes;
- vb2_set_plane_payload(vb, 0, payload);
- }
- if (payload >= need_bytes)
- r = imgu_css_set_parameters(&imgu->css, pipe,
- vb2_plane_vaddr(vb, 0));
- buf->flags = V4L2_BUF_FLAG_DONE;
- vb2_buffer_done(vb, r == 0 ? VB2_BUF_STATE_DONE
- : VB2_BUF_STATE_ERROR);
-
- } else {
- struct imgu_buffer *buf = container_of(vb, struct imgu_buffer,
- vid_buf.vbb.vb2_buf);
+ if (queue == IPU3_CSS_QUEUE_PARAMS && payload && payload < need_bytes) {
+ dev_err(&imgu->pci_dev->dev, "invalid data size for params.");
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ return;
+ }
- mutex_lock(&imgu->lock);
+ mutex_lock(&imgu->lock);
+ if (queue != IPU3_CSS_QUEUE_PARAMS)
imgu_css_buf_init(&buf->css_buf, queue, buf->map.daddr);
- list_add_tail(&buf->vid_buf.list,
- &node->buffers);
- mutex_unlock(&imgu->lock);
- vb2_set_plane_payload(&buf->vid_buf.vbb.vb2_buf, 0, need_bytes);
+ list_add_tail(&buf->vid_buf.list, &node->buffers);
+ mutex_unlock(&imgu->lock);
- if (imgu->streaming)
- imgu_queue_buffers(imgu, false, pipe);
- }
+ vb2_set_plane_payload(vb, 0, need_bytes);
- dev_dbg(&imgu->pci_dev->dev, "%s for pipe %d node %d", __func__,
- node->pipe, node->id);
+ if (imgu->streaming)
+ imgu_queue_buffers(imgu, false, node->pipe);
+ dev_dbg(&imgu->pci_dev->dev, "%s for pipe %u node %u", __func__,
+ node->pipe, node->id);
}
static int imgu_vb2_queue_setup(struct vb2_queue *vq,
@@ -435,7 +421,7 @@ static bool imgu_all_nodes_streaming(struct imgu_device *imgu,
pipe = except->pipe;
if (!test_bit(pipe, imgu->css.enabled_pipes)) {
dev_warn(&imgu->pci_dev->dev,
- "pipe %d link is not ready yet", pipe);
+ "pipe %u link is not ready yet", pipe);
return false;
}
@@ -479,7 +465,7 @@ static int imgu_vb2_start_streaming(struct vb2_queue *vq, unsigned int count)
int r;
unsigned int pipe;
- dev_dbg(dev, "%s node name %s pipe %d id %u", __func__,
+ dev_dbg(dev, "%s node name %s pipe %u id %u", __func__,
node->name, node->pipe, node->id);
if (imgu->streaming) {
@@ -539,7 +525,7 @@ static void imgu_vb2_stop_streaming(struct vb2_queue *vq)
WARN_ON(!node->enabled);
pipe = node->pipe;
- dev_dbg(dev, "Try to stream off node [%d][%d]", pipe, node->id);
+ dev_dbg(dev, "Try to stream off node [%u][%u]", pipe, node->id);
imgu_pipe = &imgu->imgu_pipe[pipe];
r = v4l2_subdev_call(&imgu_pipe->imgu_sd.subdev, video, s_stream, 0);
if (r)
@@ -664,20 +650,19 @@ static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node,
struct v4l2_format *f, bool try)
{
struct device *dev = &imgu->pci_dev->dev;
- struct v4l2_pix_format_mplane try_fmts[IPU3_CSS_QUEUES];
struct v4l2_pix_format_mplane *fmts[IPU3_CSS_QUEUES] = { NULL };
struct v4l2_rect *rects[IPU3_CSS_RECTS] = { NULL };
struct v4l2_mbus_framefmt pad_fmt;
unsigned int i, css_q;
- int r;
+ int ret;
struct imgu_css_pipe *css_pipe = &imgu->css.pipes[pipe];
struct imgu_media_pipe *imgu_pipe = &imgu->imgu_pipe[pipe];
struct imgu_v4l2_subdev *imgu_sd = &imgu_pipe->imgu_sd;
- dev_dbg(dev, "set fmt node [%u][%u](try = %d)", pipe, node, try);
+ dev_dbg(dev, "set fmt node [%u][%u](try = %u)", pipe, node, try);
for (i = 0; i < IMGU_NODE_NUM; i++)
- dev_dbg(dev, "IMGU pipe %d node %d enabled = %d",
+ dev_dbg(dev, "IMGU pipe %u node %u enabled = %u",
pipe, i, imgu_pipe->nodes[i].enabled);
if (imgu_pipe->nodes[IMGU_NODE_VF].enabled)
@@ -688,7 +673,7 @@ static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node,
else
css_pipe->pipe_id = IPU3_CSS_PIPE_ID_CAPTURE;
- dev_dbg(dev, "IPU3 pipe %d pipe_id = %d", pipe, css_pipe->pipe_id);
+ dev_dbg(dev, "IPU3 pipe %u pipe_id = %u", pipe, css_pipe->pipe_id);
for (i = 0; i < IPU3_CSS_QUEUES; i++) {
unsigned int inode = imgu_map_node(imgu, i);
@@ -698,9 +683,13 @@ static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node,
continue;
if (try) {
- try_fmts[i] =
- imgu_pipe->nodes[inode].vdev_fmt.fmt.pix_mp;
- fmts[i] = &try_fmts[i];
+ fmts[i] = kmemdup(&imgu_pipe->nodes[inode].vdev_fmt.fmt.pix_mp,
+ sizeof(struct v4l2_pix_format_mplane),
+ GFP_KERNEL);
+ if (!fmts[i]) {
+ ret = -ENOMEM;
+ goto out;
+ }
} else {
fmts[i] = &imgu_pipe->nodes[inode].vdev_fmt.fmt.pix_mp;
}
@@ -730,26 +719,33 @@ static int imgu_fmt(struct imgu_device *imgu, unsigned int pipe, int node,
* before we return success from this function, so set it here.
*/
css_q = imgu_node_to_queue(node);
- if (fmts[css_q])
- *fmts[css_q] = f->fmt.pix_mp;
- else
- return -EINVAL;
+ if (!fmts[css_q]) {
+ ret = -EINVAL;
+ goto out;
+ }
+ *fmts[css_q] = f->fmt.pix_mp;
if (try)
- r = imgu_css_fmt_try(&imgu->css, fmts, rects, pipe);
+ ret = imgu_css_fmt_try(&imgu->css, fmts, rects, pipe);
else
- r = imgu_css_fmt_set(&imgu->css, fmts, rects, pipe);
+ ret = imgu_css_fmt_set(&imgu->css, fmts, rects, pipe);
- /* r is the binary number in the firmware blob */
- if (r < 0)
- return r;
+ /* ret is the binary number in the firmware blob */
+ if (ret < 0)
+ goto out;
if (try)
f->fmt.pix_mp = *fmts[css_q];
else
f->fmt = imgu_pipe->nodes[node].vdev_fmt.fmt;
- return 0;
+out:
+ if (try) {
+ for (i = 0; i < IPU3_CSS_QUEUES; i++)
+ kfree(fmts[i]);
+ }
+
+ return ret;
}
static int imgu_try_fmt(struct file *file, void *fh, struct v4l2_format *f)
@@ -781,7 +777,7 @@ static int imgu_vidioc_try_fmt(struct file *file, void *fh,
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
int r;
- dev_dbg(dev, "%s [%ux%u] for node %d\n", __func__,
+ dev_dbg(dev, "%s [%ux%u] for node %u\n", __func__,
pix_mp->width, pix_mp->height, node->id);
r = imgu_try_fmt(file, fh, f);
@@ -799,7 +795,7 @@ static int imgu_vidioc_s_fmt(struct file *file, void *fh, struct v4l2_format *f)
struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
int r;
- dev_dbg(dev, "%s [%ux%u] for node %d\n", __func__,
+ dev_dbg(dev, "%s [%ux%u] for node %u\n", __func__,
pix_mp->width, pix_mp->height, node->id);
r = imgu_try_fmt(file, fh, f);
@@ -1022,7 +1018,7 @@ static int imgu_sd_s_ctrl(struct v4l2_ctrl *ctrl)
struct imgu_device *imgu = v4l2_get_subdevdata(&imgu_sd->subdev);
struct device *dev = &imgu->pci_dev->dev;
- dev_dbg(dev, "set val %d to ctrl 0x%8x for subdev %d",
+ dev_dbg(dev, "set val %d to ctrl 0x%8x for subdev %u",
ctrl->val, ctrl->id, imgu_sd->pipe);
switch (ctrl->id) {
@@ -1122,7 +1118,7 @@ static int imgu_v4l2_subdev_register(struct imgu_device *imgu,
imgu_sd->subdev.flags = V4L2_SUBDEV_FL_HAS_DEVNODE |
V4L2_SUBDEV_FL_HAS_EVENTS;
snprintf(imgu_sd->subdev.name, sizeof(imgu_sd->subdev.name),
- "%s %d", IMGU_NAME, pipe);
+ "%s %u", IMGU_NAME, pipe);
v4l2_set_subdevdata(&imgu_sd->subdev, imgu);
atomic_set(&imgu_sd->running_mode, IPU3_RUNNING_MODE_VIDEO);
v4l2_ctrl_handler_init(hdl, 1);
@@ -1240,7 +1236,7 @@ static int imgu_v4l2_node_setup(struct imgu_device *imgu, unsigned int pipe,
}
/* Initialize vdev */
- snprintf(vdev->name, sizeof(vdev->name), "%s %d %s",
+ snprintf(vdev->name, sizeof(vdev->name), "%s %u %s",
IMGU_NAME, pipe, node->name);
vdev->release = video_device_release_empty;
vdev->fops = &imgu_v4l2_fops;
@@ -1335,7 +1331,7 @@ static int imgu_v4l2_register_pipes(struct imgu_device *imgu)
r = imgu_v4l2_subdev_register(imgu, &imgu_pipe->imgu_sd, i);
if (r) {
dev_err(&imgu->pci_dev->dev,
- "failed to register subdev%d ret (%d)\n", i, r);
+ "failed to register subdev%u ret (%d)\n", i, r);
goto pipes_cleanup;
}
r = imgu_v4l2_nodes_setup_pipe(imgu, i);
diff --git a/drivers/staging/media/ipu3/ipu3.c b/drivers/staging/media/ipu3/ipu3.c
index e0bbdad7cf5b..a7372395a101 100644
--- a/drivers/staging/media/ipu3/ipu3.c
+++ b/drivers/staging/media/ipu3/ipu3.c
@@ -236,6 +236,11 @@ int imgu_queue_buffers(struct imgu_device *imgu, bool initial, unsigned int pipe
dev_dbg(&imgu->pci_dev->dev, "Queue buffers to pipe %d", pipe);
mutex_lock(&imgu->lock);
+ if (!imgu_css_pipe_queue_empty(&imgu->css, pipe)) {
+ mutex_unlock(&imgu->lock);
+ return 0;
+ }
+
/* Buffer set is queued to FW only when input buffer is ready */
for (node = IMGU_NODE_NUM - 1;
imgu_queue_getbuf(imgu, IMGU_NODE_IN, pipe);
@@ -245,6 +250,31 @@ int imgu_queue_buffers(struct imgu_device *imgu, bool initial, unsigned int pipe
dev_warn(&imgu->pci_dev->dev,
"Vf not enabled, ignore queue");
continue;
+ } else if (node == IMGU_NODE_PARAMS &&
+ imgu_pipe->nodes[node].enabled) {
+ struct vb2_buffer *vb;
+ struct imgu_vb2_buffer *ivb;
+
+ /* No parameters for this frame */
+ if (list_empty(&imgu_pipe->nodes[node].buffers))
+ continue;
+
+ ivb = list_first_entry(&imgu_pipe->nodes[node].buffers,
+ struct imgu_vb2_buffer, list);
+ vb = &ivb->vbb.vb2_buf;
+ r = imgu_css_set_parameters(&imgu->css, pipe,
+ vb2_plane_vaddr(vb, 0));
+ if (r) {
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ dev_warn(&imgu->pci_dev->dev,
+ "set parameters failed.");
+ continue;
+ }
+
+ vb2_buffer_done(vb, VB2_BUF_STATE_DONE);
+ dev_dbg(&imgu->pci_dev->dev,
+ "queue user parameters %d to css.", vb->index);
+ list_del(&ivb->list);
} else if (imgu_pipe->queue_enabled[node]) {
struct imgu_css_buffer *buf =
imgu_queue_getbuf(imgu, node, pipe);
@@ -790,7 +820,7 @@ out:
* PCI rpm framework checks the existence of driver rpm callbacks.
* Place a dummy callback here to avoid rpm going into error state.
*/
-static int imgu_rpm_dummy_cb(struct device *dev)
+static __maybe_unused int imgu_rpm_dummy_cb(struct device *dev)
{
return 0;
}