diff options
Diffstat (limited to 'drivers/media/platform/chips-media')
-rw-r--r-- | drivers/media/platform/chips-media/coda-bit.c | 4 | ||||
-rw-r--r-- | drivers/media/platform/chips-media/coda-common.c | 155 | ||||
-rw-r--r-- | drivers/media/platform/chips-media/coda-jpeg.c | 24 | ||||
-rw-r--r-- | drivers/media/platform/chips-media/coda.h | 7 |
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); |