summaryrefslogtreecommitdiff
path: root/drivers/media/platform/chips-media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/chips-media')
-rw-r--r--drivers/media/platform/chips-media/coda-bit.c4
-rw-r--r--drivers/media/platform/chips-media/coda-common.c155
-rw-r--r--drivers/media/platform/chips-media/coda-jpeg.c24
-rw-r--r--drivers/media/platform/chips-media/coda.h7
4 files changed, 110 insertions, 80 deletions
diff --git a/drivers/media/platform/chips-media/coda-bit.c b/drivers/media/platform/chips-media/coda-bit.c
index c484c008ab02..2736a902e3df 100644
--- a/drivers/media/platform/chips-media/coda-bit.c
+++ b/drivers/media/platform/chips-media/coda-bit.c
@@ -326,6 +326,8 @@ void coda_fill_bitstream(struct coda_ctx *ctx, struct list_head *buffer_list)
struct coda_buffer_meta *meta;
u32 start;
+ lockdep_assert_held(&ctx->bitstream_mutex);
+
if (ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG)
return;
@@ -2174,7 +2176,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
(!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
coda_dbg(1, ctx, "bitstream payload: %d, skipping\n",
coda_get_bitstream_payload(ctx));
- v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
return -EAGAIN;
}
@@ -2184,7 +2185,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to start decoding\n");
- v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
return -EAGAIN;
} else {
ctx->initialized = 1;
diff --git a/drivers/media/platform/chips-media/coda-common.c b/drivers/media/platform/chips-media/coda-common.c
index a57822b05070..af71eea04dbd 100644
--- a/drivers/media/platform/chips-media/coda-common.c
+++ b/drivers/media/platform/chips-media/coda-common.c
@@ -657,6 +657,8 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
const struct coda_q_data *q_data_src;
const struct coda_codec *codec;
struct vb2_queue *src_vq;
+ int hscale = 0;
+ int vscale = 0;
int ret;
bool use_vdoa;
@@ -673,8 +675,13 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
*/
src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (vb2_is_streaming(src_vq)) {
- f->fmt.pix.width = q_data_src->width;
- f->fmt.pix.height = q_data_src->height;
+ if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG &&
+ ctx->dev->devtype->product == CODA_960) {
+ hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width);
+ vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height);
+ }
+ f->fmt.pix.width = q_data_src->width >> hscale;
+ f->fmt.pix.height = q_data_src->height >> vscale;
if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) {
if (ctx->params.jpeg_chroma_subsampling ==
@@ -704,8 +711,8 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
/* The decoders always write complete macroblocks or MCUs */
if (ctx->inst_type == CODA_INST_DECODER) {
- f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
- f->fmt.pix.height = round_up(f->fmt.pix.height, 16);
+ f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16 >> hscale);
+ f->fmt.pix.height = round_up(f->fmt.pix.height, 16 >> vscale);
if (codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
f->fmt.pix.pixelformat == V4L2_PIX_FMT_YUV422P) {
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
@@ -850,17 +857,26 @@ static int coda_s_fmt_vid_cap(struct file *file, void *priv,
struct coda_q_data *q_data_src;
const struct coda_codec *codec;
struct v4l2_rect r;
+ int hscale = 0;
+ int vscale = 0;
int ret;
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
+ if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG &&
+ ctx->dev->devtype->product == CODA_960) {
+ hscale = coda_jpeg_scale(q_data_src->width, f->fmt.pix.width);
+ vscale = coda_jpeg_scale(q_data_src->height, f->fmt.pix.height);
+ }
+
ret = coda_try_fmt_vid_cap(file, priv, f);
if (ret)
return ret;
- q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
r.left = 0;
r.top = 0;
- r.width = q_data_src->width;
- r.height = q_data_src->height;
+ r.width = q_data_src->width >> hscale;
+ r.height = q_data_src->height >> vscale;
ret = coda_s_fmt(ctx, f, &r);
if (ret)
@@ -1091,17 +1107,6 @@ static int coda_s_selection(struct file *file, void *fh,
}
}
-static int coda_try_encoder_cmd(struct file *file, void *fh,
- struct v4l2_encoder_cmd *ec)
-{
- struct coda_ctx *ctx = fh_to_ctx(fh);
-
- if (ctx->inst_type != CODA_INST_ENCODER)
- return -ENOTTY;
-
- return v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
-}
-
static void coda_wake_up_capture_queue(struct coda_ctx *ctx)
{
struct vb2_queue *dst_vq;
@@ -1120,7 +1125,7 @@ static int coda_encoder_cmd(struct file *file, void *fh,
struct vb2_v4l2_buffer *buf;
int ret;
- ret = coda_try_encoder_cmd(file, fh, ec);
+ ret = v4l2_m2m_ioctl_try_encoder_cmd(file, fh, ec);
if (ret < 0)
return ret;
@@ -1149,17 +1154,6 @@ static int coda_encoder_cmd(struct file *file, void *fh,
return 0;
}
-static int coda_try_decoder_cmd(struct file *file, void *fh,
- struct v4l2_decoder_cmd *dc)
-{
- struct coda_ctx *ctx = fh_to_ctx(fh);
-
- if (ctx->inst_type != CODA_INST_DECODER)
- return -ENOTTY;
-
- return v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
-}
-
static bool coda_mark_last_meta(struct coda_ctx *ctx)
{
struct coda_buffer_meta *meta;
@@ -1216,7 +1210,7 @@ static int coda_decoder_cmd(struct file *file, void *fh,
bool wakeup;
int ret;
- ret = coda_try_decoder_cmd(file, fh, dc);
+ ret = v4l2_m2m_ioctl_try_decoder_cmd(file, fh, dc);
if (ret < 0)
return ret;
@@ -1291,9 +1285,6 @@ static int coda_enum_framesizes(struct file *file, void *fh,
struct coda_q_data *q_data_dst;
const struct coda_codec *codec;
- if (ctx->inst_type != CODA_INST_ENCODER)
- return -ENOTTY;
-
if (fsize->index)
return -EINVAL;
@@ -1324,7 +1315,8 @@ static int coda_enum_frameintervals(struct file *file, void *fh,
struct v4l2_frmivalenum *f)
{
struct coda_ctx *ctx = fh_to_ctx(fh);
- int i;
+ struct coda_q_data *q_data;
+ const struct coda_codec *codec;
if (f->index)
return -EINVAL;
@@ -1333,12 +1325,19 @@ static int coda_enum_frameintervals(struct file *file, void *fh,
if (!ctx->vdoa && f->pixel_format == V4L2_PIX_FMT_YUYV)
return -EINVAL;
- for (i = 0; i < CODA_MAX_FORMATS; i++) {
- if (f->pixel_format == ctx->cvd->src_formats[i] ||
- f->pixel_format == ctx->cvd->dst_formats[i])
- break;
+ if (coda_format_normalize_yuv(f->pixel_format) == V4L2_PIX_FMT_YUV420) {
+ q_data = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ codec = coda_find_codec(ctx->dev, f->pixel_format,
+ q_data->fourcc);
+ } else {
+ codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
+ f->pixel_format);
}
- if (i == CODA_MAX_FORMATS)
+ if (!codec)
+ return -EINVAL;
+
+ if (f->width < MIN_W || f->width > codec->max_w ||
+ f->height < MIN_H || f->height > codec->max_h)
return -EINVAL;
f->type = V4L2_FRMIVAL_TYPE_CONTINUOUS;
@@ -1498,9 +1497,9 @@ static const struct v4l2_ioctl_ops coda_ioctl_ops = {
.vidioc_g_selection = coda_g_selection,
.vidioc_s_selection = coda_s_selection,
- .vidioc_try_encoder_cmd = coda_try_encoder_cmd,
+ .vidioc_try_encoder_cmd = v4l2_m2m_ioctl_try_encoder_cmd,
.vidioc_encoder_cmd = coda_encoder_cmd,
- .vidioc_try_decoder_cmd = coda_try_decoder_cmd,
+ .vidioc_try_decoder_cmd = v4l2_m2m_ioctl_try_decoder_cmd,
.vidioc_decoder_cmd = coda_decoder_cmd,
.vidioc_g_parm = coda_g_parm,
@@ -1535,12 +1534,8 @@ static void coda_pic_run_work(struct work_struct *work)
mutex_lock(&dev->coda_mutex);
ret = ctx->ops->prepare_run(ctx);
- if (ret < 0 && ctx->inst_type == CODA_INST_DECODER) {
- mutex_unlock(&dev->coda_mutex);
- mutex_unlock(&ctx->buffer_mutex);
- /* job_finish scheduled by prepare_decode */
- return;
- }
+ if (ret < 0 && ctx->inst_type == CODA_INST_DECODER)
+ goto out;
if (!wait_for_completion_timeout(&ctx->completion,
msecs_to_jiffies(1000))) {
@@ -1562,6 +1557,7 @@ static void coda_pic_run_work(struct work_struct *work)
ctx->ops->seq_end_work)
queue_work(dev->workqueue, &ctx->seq_end_work);
+out:
mutex_unlock(&dev->coda_mutex);
mutex_unlock(&ctx->buffer_mutex);
@@ -1665,13 +1661,18 @@ static void set_default_params(struct coda_ctx *ctx)
csize = coda_estimate_sizeimage(ctx, usize, max_w, max_h);
ctx->params.codec_mode = ctx->codec->mode;
- if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG)
- ctx->colorspace = V4L2_COLORSPACE_JPEG;
- else
+ if (ctx->cvd->src_formats[0] == V4L2_PIX_FMT_JPEG ||
+ ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG) {
+ ctx->colorspace = V4L2_COLORSPACE_SRGB;
+ ctx->xfer_func = V4L2_XFER_FUNC_SRGB;
+ ctx->ycbcr_enc = V4L2_YCBCR_ENC_601;
+ ctx->quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ } else {
ctx->colorspace = V4L2_COLORSPACE_REC709;
- ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
- ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
- ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
+ ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+ ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
+ }
ctx->params.framerate = 30;
/* Default formats for output and input queues */
@@ -2011,13 +2012,13 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
*/
if (q_data_src->fourcc == V4L2_PIX_FMT_JPEG) {
buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
- ret = coda_jpeg_decode_header(ctx, &buf->vb2_buf);
- if (ret < 0) {
- v4l2_err(v4l2_dev,
- "failed to decode JPEG header: %d\n",
- ret);
- goto err;
- }
+ coda_jpeg_decode_header(ctx, &buf->vb2_buf);
+ /*
+ * We have to start streaming even if the first buffer
+ * does not contain a valid JPEG image. The error will
+ * be caught during device run and will be signalled
+ * via the capture buffer error flag.
+ */
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
q_data_dst->width = round_up(q_data_src->width, 16);
@@ -2344,8 +2345,8 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
V4L2_CID_MPEG_VIDEO_H264_CHROMA_QP_INDEX_OFFSET, -12, 12, 1, 0);
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_PROFILE,
- V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE, 0x0,
- V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE);
+ V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE, 0x0,
+ V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE);
if (ctx->dev->devtype->product == CODA_HX4 ||
ctx->dev->devtype->product == CODA_7541) {
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
@@ -2359,12 +2360,15 @@ static void coda_encode_ctrls(struct coda_ctx *ctx)
if (ctx->dev->devtype->product == CODA_960) {
v4l2_ctrl_new_std_menu(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_H264_LEVEL,
- V4L2_MPEG_VIDEO_H264_LEVEL_4_0,
- ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
+ V4L2_MPEG_VIDEO_H264_LEVEL_4_2,
+ ~((1 << V4L2_MPEG_VIDEO_H264_LEVEL_1_0) |
+ (1 << V4L2_MPEG_VIDEO_H264_LEVEL_2_0) |
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_0) |
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_1) |
(1 << V4L2_MPEG_VIDEO_H264_LEVEL_3_2) |
- (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0)),
+ (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_0) |
+ (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_1) |
+ (1 << V4L2_MPEG_VIDEO_H264_LEVEL_4_2)),
V4L2_MPEG_VIDEO_H264_LEVEL_4_0);
}
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
@@ -2426,7 +2430,7 @@ static void coda_decode_ctrls(struct coda_ctx *ctx)
ctx->h264_profile_ctrl = v4l2_ctrl_new_std_menu(&ctx->ctrls,
&coda_ctrl_ops, V4L2_CID_MPEG_VIDEO_H264_PROFILE,
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH,
- ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_BASELINE) |
+ ~((1 << V4L2_MPEG_VIDEO_H264_PROFILE_CONSTRAINED_BASELINE) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_MAIN) |
(1 << V4L2_MPEG_VIDEO_H264_PROFILE_HIGH)),
V4L2_MPEG_VIDEO_H264_PROFILE_HIGH);
@@ -2901,6 +2905,23 @@ static int coda_register_device(struct coda_dev *dev, int i)
v4l2_disable_ioctl(vfd, VIDIOC_G_CROP);
v4l2_disable_ioctl(vfd, VIDIOC_S_CROP);
+ if (dev->devtype->vdevs[i]->type == CODA_INST_ENCODER) {
+ v4l2_disable_ioctl(vfd, VIDIOC_DECODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_DECODER_CMD);
+ if (dev->devtype->vdevs[i]->dst_formats[0] == V4L2_PIX_FMT_JPEG) {
+ v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
+ }
+ } else {
+ v4l2_disable_ioctl(vfd, VIDIOC_ENCODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_TRY_ENCODER_CMD);
+ v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMESIZES);
+ v4l2_disable_ioctl(vfd, VIDIOC_ENUM_FRAMEINTERVALS);
+ v4l2_disable_ioctl(vfd, VIDIOC_G_PARM);
+ v4l2_disable_ioctl(vfd, VIDIOC_S_PARM);
+ }
+
ret = video_register_device(vfd, VFL_TYPE_VIDEO, 0);
if (!ret)
v4l2_info(&dev->v4l2_dev, "%s registered as %s\n",
diff --git a/drivers/media/platform/chips-media/coda-jpeg.c b/drivers/media/platform/chips-media/coda-jpeg.c
index a72f4655e5ad..a0b22b07f69a 100644
--- a/drivers/media/platform/chips-media/coda-jpeg.c
+++ b/drivers/media/platform/chips-media/coda-jpeg.c
@@ -283,7 +283,8 @@ int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb)
ret = v4l2_jpeg_parse_header(buf, len, &header);
if (ret < 0) {
- v4l2_err(&dev->v4l2_dev, "failed to parse header\n");
+ v4l2_err(&dev->v4l2_dev, "failed to parse JPEG header: %pe\n",
+ ERR_PTR(ret));
return ret;
}
@@ -1328,6 +1329,7 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx)
struct coda_q_data *q_data_src, *q_data_dst;
struct vb2_v4l2_buffer *src_buf, *dst_buf;
int chroma_interleave;
+ int scl_hor_mode, scl_ver_mode;
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@@ -1335,27 +1337,24 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx)
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
dst_fourcc = q_data_dst->fourcc;
+ scl_hor_mode = coda_jpeg_scale(q_data_src->width, q_data_dst->width);
+ scl_ver_mode = coda_jpeg_scale(q_data_src->height, q_data_dst->height);
+
if (vb2_get_plane_payload(&src_buf->vb2_buf, 0) == 0)
vb2_set_plane_payload(&src_buf->vb2_buf, 0,
vb2_plane_size(&src_buf->vb2_buf, 0));
chroma_format = coda9_jpeg_chroma_format(q_data_dst->fourcc);
- if (chroma_format < 0) {
- v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
+ if (chroma_format < 0)
return chroma_format;
- }
ret = coda_jpeg_decode_header(ctx, &src_buf->vb2_buf);
if (ret < 0) {
- v4l2_err(&dev->v4l2_dev, "failed to decode JPEG header: %d\n",
- ret);
-
src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
- v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_DONE);
+ v4l2_m2m_buf_done(dst_buf, VB2_BUF_STATE_ERROR);
- v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
return ret;
}
@@ -1386,7 +1385,11 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx)
coda_write(dev, 0, CODA9_REG_JPEG_ROT_INFO);
coda_write(dev, bus_req_num[chroma_format], CODA9_REG_JPEG_OP_INFO);
coda_write(dev, mcu_info[chroma_format], CODA9_REG_JPEG_MCU_INFO);
- coda_write(dev, 0, CODA9_REG_JPEG_SCL_INFO);
+ if (scl_hor_mode || scl_ver_mode)
+ val = CODA9_JPEG_SCL_ENABLE | (scl_hor_mode << 2) | scl_ver_mode;
+ else
+ val = 0;
+ coda_write(dev, val, CODA9_REG_JPEG_SCL_INFO);
coda_write(dev, chroma_interleave, CODA9_REG_JPEG_DPB_CONFIG);
coda_write(dev, ctx->params.jpeg_restart_interval,
CODA9_REG_JPEG_RST_INTVAL);
@@ -1396,7 +1399,6 @@ static int coda9_jpeg_prepare_decode(struct coda_ctx *ctx)
if (ret < 0) {
v4l2_err(&dev->v4l2_dev,
"failed to set up Huffman tables: %d\n", ret);
- v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx);
return ret;
}
}
diff --git a/drivers/media/platform/chips-media/coda.h b/drivers/media/platform/chips-media/coda.h
index dcf35641c603..ddfd0a32c653 100644
--- a/drivers/media/platform/chips-media/coda.h
+++ b/drivers/media/platform/chips-media/coda.h
@@ -380,6 +380,13 @@ u32 coda_mpeg4_parse_headers(struct coda_ctx *ctx, u8 *buf, u32 size);
void coda_update_profile_level_ctrls(struct coda_ctx *ctx, u8 profile_idc,
u8 level_idc);
+static inline int coda_jpeg_scale(int src, int dst)
+{
+ return (dst <= src / 8) ? 3 :
+ (dst <= src / 4) ? 2 :
+ (dst <= src / 2) ? 1 : 0;
+}
+
bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb);
int coda_jpeg_decode_header(struct coda_ctx *ctx, struct vb2_buffer *vb);
int coda_jpeg_write_tables(struct coda_ctx *ctx);