diff options
-rw-r--r-- | drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c | 226 | ||||
-rw-r--r-- | drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h | 8 |
2 files changed, 186 insertions, 48 deletions
diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c index 8db29f763818..d262a563844f 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.c @@ -69,7 +69,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .fourcc = V4L2_PIX_FMT_JPEG, .subsampling = -1, .nc = -1, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .flags = MXC_JPEG_FMT_TYPE_ENC, }, { @@ -78,11 +79,13 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, .nc = 3, .depth = 24, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, .precision = 8, + .is_rgb = 1, }, { .name = "ABGR", /* ABGR packed format */ @@ -90,11 +93,13 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, .nc = 4, .depth = 32, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, .precision = 8, + .is_rgb = 1, }, { .name = "YUV420", /* 1st plane = Y, 2nd plane = UV */ @@ -102,7 +107,21 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, .nc = 3, .depth = 12, /* 6 bytes (4Y + UV) for 4 pixels */ - .colplanes = 2, /* 1 plane Y, 1 plane UV interleaved */ + .mem_planes = 2, + .comp_planes = 2, /* 1 plane Y, 1 plane UV interleaved */ + .h_align = 4, + .v_align = 4, + .flags = MXC_JPEG_FMT_TYPE_RAW, + .precision = 8, + }, + { + .name = "YUV420", /* 1st plane = Y, 2nd plane = UV */ + .fourcc = V4L2_PIX_FMT_NV12, + .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_420, + .nc = 3, + .depth = 12, /* 6 bytes (4Y + UV) for 4 pixels */ + .mem_planes = 1, + .comp_planes = 2, /* 1 plane Y, 1 plane UV interleaved */ .h_align = 4, .v_align = 4, .flags = MXC_JPEG_FMT_TYPE_RAW, @@ -114,7 +133,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_422, .nc = 3, .depth = 16, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .h_align = 4, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, @@ -126,7 +146,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_444, .nc = 3, .depth = 24, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, @@ -138,7 +159,8 @@ static const struct mxc_jpeg_fmt mxc_formats[] = { .subsampling = V4L2_JPEG_CHROMA_SUBSAMPLING_GRAY, .nc = 1, .depth = 8, - .colplanes = 1, + .mem_planes = 1, + .comp_planes = 1, .h_align = 3, .v_align = 3, .flags = MXC_JPEG_FMT_TYPE_RAW, @@ -419,6 +441,7 @@ static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(u32 fourcc) return MXC_JPEG_GRAY; case V4L2_PIX_FMT_YUYV: return MXC_JPEG_YUV422; + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12M: return MXC_JPEG_YUV420; case V4L2_PIX_FMT_YUV24: @@ -445,12 +468,17 @@ static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc, struct vb2_buffer *jpeg_buf, int offset) { int img_fmt = desc->stm_ctrl & STM_CTRL_IMAGE_FORMAT_MASK; + struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(raw_buf->vb2_queue); + struct mxc_jpeg_q_data *q_data; + q_data = mxc_jpeg_get_q_data(ctx, raw_buf->type); desc->buf_base0 = vb2_dma_contig_plane_dma_addr(raw_buf, 0); desc->buf_base1 = 0; if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) { - WARN_ON(raw_buf->num_planes < 2); - desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1); + if (raw_buf->num_planes == 2) + desc->buf_base1 = vb2_dma_contig_plane_dma_addr(raw_buf, 1); + else + desc->buf_base1 = desc->buf_base0 + q_data->sizeimage[0]; } desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(jpeg_buf, 0) + offset; @@ -593,6 +621,28 @@ static void mxc_jpeg_job_finish(struct mxc_jpeg_ctx *ctx, enum vb2_buffer_state mxc_jpeg_sw_reset(reg); } +static u32 mxc_jpeg_get_plane_size(struct mxc_jpeg_q_data *q_data, u32 plane_no) +{ + const struct mxc_jpeg_fmt *fmt = q_data->fmt; + u32 size; + int i; + + if (plane_no >= fmt->mem_planes) + return 0; + + if (fmt->mem_planes == fmt->comp_planes) + return q_data->sizeimage[plane_no]; + + if (plane_no < fmt->mem_planes - 1) + return q_data->sizeimage[plane_no]; + + size = q_data->sizeimage[fmt->mem_planes - 1]; + for (i = fmt->mem_planes; i < fmt->comp_planes; i++) + size += q_data->sizeimage[i]; + + return size; +} + static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) { struct mxc_jpeg_dev *jpeg = priv; @@ -672,11 +722,11 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv) payload); } else { q_data = mxc_jpeg_get_q_data(ctx, cap_type); - payload = q_data->sizeimage[0]; + payload = mxc_jpeg_get_plane_size(q_data, 0); vb2_set_plane_payload(&dst_buf->vb2_buf, 0, payload); vb2_set_plane_payload(&dst_buf->vb2_buf, 1, 0); - if (q_data->fmt->colplanes == 2) { - payload = q_data->sizeimage[1]; + if (q_data->fmt->mem_planes == 2) { + payload = mxc_jpeg_get_plane_size(q_data, 1); vb2_set_plane_payload(&dst_buf->vb2_buf, 1, payload); } dev_dbg(dev, "Decoding finished, payload size: %ld + %ld\n", @@ -715,6 +765,7 @@ static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof, _bswap16(&sof->width); switch (fourcc) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12M: sof->components_no = 3; sof->comp[0].v = 0x2; @@ -751,6 +802,7 @@ static int mxc_jpeg_fixup_sos(struct mxc_jpeg_sos *sos, u8 *sof_u8 = (u8 *)sos; switch (fourcc) { + case V4L2_PIX_FMT_NV12: case V4L2_PIX_FMT_NV12M: sos->components_no = 3; break; @@ -966,6 +1018,32 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf, mxc_jpeg_set_desc(cfg_desc_handle, reg, slot); } +static const struct mxc_jpeg_fmt *mxc_jpeg_get_sibling_format(const struct mxc_jpeg_fmt *fmt) +{ + int i; + + for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) { + if (mxc_formats[i].subsampling == fmt->subsampling && + mxc_formats[i].nc == fmt->nc && + mxc_formats[i].precision == fmt->precision && + mxc_formats[i].is_rgb == fmt->is_rgb && + mxc_formats[i].fourcc != fmt->fourcc) + return &mxc_formats[i]; + } + + return NULL; +} + +static bool mxc_jpeg_compare_format(const struct mxc_jpeg_fmt *fmt1, + const struct mxc_jpeg_fmt *fmt2) +{ + if (fmt1 == fmt2) + return true; + if (mxc_jpeg_get_sibling_format(fmt1) == fmt2) + return true; + return false; +} + static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, struct mxc_jpeg_src_buf *jpeg_src_buf) { @@ -976,6 +1054,8 @@ static bool mxc_jpeg_source_change(struct mxc_jpeg_ctx *ctx, return false; q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE); + if (mxc_jpeg_compare_format(q_data_cap->fmt, jpeg_src_buf->fmt)) + jpeg_src_buf->fmt = q_data_cap->fmt; if (q_data_cap->fmt != jpeg_src_buf->fmt || q_data_cap->w != jpeg_src_buf->w || q_data_cap->h != jpeg_src_buf->h) { @@ -1080,9 +1160,9 @@ static void mxc_jpeg_device_run(void *priv) v4l2_m2m_buf_copy_metadata(src_buf, dst_buf, true); jpeg_src_buf = vb2_to_mxc_buf(&src_buf->vb2_buf); - if (q_data_cap->fmt->colplanes != dst_buf->vb2_buf.num_planes) { + if (q_data_cap->fmt->mem_planes != dst_buf->vb2_buf.num_planes) { dev_err(dev, "Capture format %s has %d planes, but capture buffer has %d planes\n", - q_data_cap->fmt->name, q_data_cap->fmt->colplanes, + q_data_cap->fmt->name, q_data_cap->fmt->mem_planes, dst_buf->vb2_buf.num_planes); jpeg_src_buf->jpeg_parse_error = true; } @@ -1215,19 +1295,19 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q, /* Handle CREATE_BUFS situation - *nplanes != 0 */ if (*nplanes) { - if (*nplanes != q_data->fmt->colplanes) + if (*nplanes != q_data->fmt->mem_planes) return -EINVAL; for (i = 0; i < *nplanes; i++) { - if (sizes[i] < q_data->sizeimage[i]) + if (sizes[i] < mxc_jpeg_get_plane_size(q_data, i)) return -EINVAL; } return 0; } /* Handle REQBUFS situation */ - *nplanes = q_data->fmt->colplanes; + *nplanes = q_data->fmt->mem_planes; for (i = 0; i < *nplanes; i++) - sizes[i] = q_data->sizeimage[i]; + sizes[i] = mxc_jpeg_get_plane_size(q_data, i); return 0; } @@ -1312,19 +1392,40 @@ static int mxc_jpeg_valid_comp_id(struct device *dev, return valid; } +static bool mxc_jpeg_match_image_format(const struct mxc_jpeg_fmt *fmt, + const struct v4l2_jpeg_header *header) +{ + if (fmt->subsampling != header->frame.subsampling || + fmt->nc != header->frame.num_components || + fmt->precision != header->frame.precision) + return false; + + /* + * If the transform flag from APP14 marker is 0, images that are + * encoded with 3 components have RGB colorspace, see Recommendation + * ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding + */ + if (header->frame.subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_444) { + u8 is_rgb = header->app14_tf == V4L2_JPEG_APP14_TF_CMYK_RGB ? 1 : 0; + + if (is_rgb != fmt->is_rgb) + return false; + } + return true; +} + static u32 mxc_jpeg_get_image_format(struct device *dev, const struct v4l2_jpeg_header *header) { int i; u32 fourcc = 0; - for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) - if (mxc_formats[i].subsampling == header->frame.subsampling && - mxc_formats[i].nc == header->frame.num_components && - mxc_formats[i].precision == header->frame.precision) { + for (i = 0; i < MXC_JPEG_NUM_FORMATS; i++) { + if (mxc_jpeg_match_image_format(&mxc_formats[i], header)) { fourcc = mxc_formats[i].fourcc; break; } + } if (fourcc == 0) { dev_err(dev, "Could not identify image format nc=%d, subsampling=%d, precision=%d\n", @@ -1333,17 +1434,6 @@ static u32 mxc_jpeg_get_image_format(struct device *dev, header->frame.precision); return fourcc; } - /* - * If the transform flag from APP14 marker is 0, images that are - * encoded with 3 components have RGB colorspace, see Recommendation - * ITU-T T.872 chapter 6.5.3 APP14 marker segment for colour encoding - */ - if (fourcc == V4L2_PIX_FMT_YUV24 || fourcc == V4L2_PIX_FMT_BGR24) { - if (header->app14_tf == V4L2_JPEG_APP14_TF_CMYK_RGB) - fourcc = V4L2_PIX_FMT_BGR24; - else - fourcc = V4L2_PIX_FMT_YUV24; - } return fourcc; } @@ -1391,7 +1481,7 @@ static void mxc_jpeg_sizeimage(struct mxc_jpeg_q_data *q) } else { q->sizeimage[0] = q->bytesperline[0] * q->h_adjusted; q->sizeimage[1] = 0; - if (q->fmt->fourcc == V4L2_PIX_FMT_NV12M) + if (q->fmt->subsampling == V4L2_JPEG_CHROMA_SUBSAMPLING_420) q->sizeimage[1] = q->sizeimage[0] / 2; } } @@ -1400,6 +1490,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) { struct device *dev = ctx->mxc_jpeg->dev; struct mxc_jpeg_q_data *q_data_out; + struct mxc_jpeg_q_data *q_data_cap; u32 fourcc; struct v4l2_jpeg_header header; struct mxc_jpeg_sof *psof = NULL; @@ -1457,7 +1548,11 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx, struct vb2_buffer *vb) if (!mxc_jpeg_valid_comp_id(dev, psof, psos)) dev_warn(dev, "JPEG component ids should be 0-3 or 1-4"); - fourcc = mxc_jpeg_get_image_format(dev, &header); + q_data_cap = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE); + if (q_data_cap->fmt && mxc_jpeg_match_image_format(q_data_cap->fmt, &header)) + fourcc = q_data_cap->fmt->fourcc; + else + fourcc = mxc_jpeg_get_image_format(dev, &header); if (fourcc == 0) return -EINVAL; @@ -1533,8 +1628,8 @@ static int mxc_jpeg_buf_prepare(struct vb2_buffer *vb) q_data = mxc_jpeg_get_q_data(ctx, vb->vb2_queue->type); if (!q_data) return -EINVAL; - for (i = 0; i < q_data->fmt->colplanes; i++) { - sizeimage = q_data->sizeimage[i]; + for (i = 0; i < q_data->fmt->mem_planes; i++) { + sizeimage = mxc_jpeg_get_plane_size(q_data, i); if (vb2_plane_size(vb, i) < sizeimage) { dev_err(dev, "plane %d too small (%lu < %lu)", i, vb2_plane_size(vb, i), sizeimage); @@ -1761,10 +1856,25 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv, * (more precisely what was propagated on capture queue * after jpeg parse on the output buffer) */ - if (f->index) - return -EINVAL; - f->pixelformat = q_data->fmt->fourcc; - return 0; + int ret = -EINVAL; + const struct mxc_jpeg_fmt *sibling; + + switch (f->index) { + case 0: + f->pixelformat = q_data->fmt->fourcc; + ret = 0; + break; + case 1: + sibling = mxc_jpeg_get_sibling_format(q_data->fmt); + if (sibling) { + f->pixelformat = sibling->fourcc; + ret = 0; + } + break; + default: + break; + } + return ret; } } @@ -1800,6 +1910,27 @@ static u32 mxc_jpeg_get_default_fourcc(struct mxc_jpeg_ctx *ctx, u32 type) return V4L2_TYPE_IS_CAPTURE(type) ? V4L2_PIX_FMT_JPEG : MXC_JPEG_DEFAULT_PFMT; } +static u32 mxc_jpeg_try_fourcc(struct mxc_jpeg_ctx *ctx, u32 fourcc) +{ + const struct mxc_jpeg_fmt *sibling; + struct mxc_jpeg_q_data *q_data_cap; + + if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE) + return fourcc; + if (!ctx->header_parsed) + return fourcc; + + q_data_cap = &ctx->cap_q; + if (q_data_cap->fmt->fourcc == fourcc) + return fourcc; + + sibling = mxc_jpeg_get_sibling_format(q_data_cap->fmt); + if (sibling && sibling->fourcc == fourcc) + return sibling->fourcc; + + return q_data_cap->fmt->fourcc; +} + static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_ctx *ctx, struct mxc_jpeg_q_data *q_data) { @@ -1830,7 +1961,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved)); pix_mp->field = V4L2_FIELD_NONE; - pix_mp->num_planes = fmt->colplanes; + pix_mp->num_planes = fmt->mem_planes; pix_mp->pixelformat = fmt->fourcc; q_data->w = w; @@ -1861,7 +1992,7 @@ static int mxc_jpeg_try_fmt(struct v4l2_format *f, pfmt = &pix_mp->plane_fmt[i]; memset(pfmt->reserved, 0, sizeof(pfmt->reserved)); pfmt->bytesperline = q_data->bytesperline[i]; - pfmt->sizeimage = q_data->sizeimage[i]; + pfmt->sizeimage = mxc_jpeg_get_plane_size(q_data, i); } /* fix colorspace information to sRGB for both output & capture */ @@ -1901,6 +2032,9 @@ static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv, return -EINVAL; } + if (ctx->mxc_jpeg->mode != MXC_JPEG_DECODE && V4L2_TYPE_IS_CAPTURE(f->type)) + f->fmt.pix_mp.pixelformat = mxc_jpeg_try_fourcc(ctx, f->fmt.pix_mp.pixelformat); + return mxc_jpeg_try_fmt(f, ctx, &tmp_q); } @@ -1931,7 +2065,7 @@ static void mxc_jpeg_s_parsed_fmt(struct mxc_jpeg_ctx *ctx, struct v4l2_format * return; q_data_cap = mxc_jpeg_get_q_data(ctx, f->type); - pix_mp->pixelformat = q_data_cap->fmt->fourcc; + pix_mp->pixelformat = mxc_jpeg_try_fourcc(ctx, pix_mp->pixelformat); pix_mp->width = q_data_cap->w; pix_mp->height = q_data_cap->h; } @@ -2028,10 +2162,10 @@ static int mxc_jpeg_g_fmt_vid(struct file *file, void *priv, pix_mp->xfer_func = V4L2_XFER_FUNC_SRGB; pix_mp->quantization = V4L2_QUANTIZATION_FULL_RANGE; - pix_mp->num_planes = q_data->fmt->colplanes; + pix_mp->num_planes = q_data->fmt->mem_planes; for (i = 0; i < pix_mp->num_planes; i++) { pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i]; - pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i]; + pix_mp->plane_fmt[i].sizeimage = mxc_jpeg_get_plane_size(q_data, i); } return 0; diff --git a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h index f75dfc89ff6d..8fa8c0aec5a2 100644 --- a/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h +++ b/drivers/media/platform/nxp/imx-jpeg/mxc-jpeg.h @@ -45,11 +45,13 @@ enum mxc_jpeg_mode { * @subsampling: subsampling of jpeg components * @nc: number of color components * @depth: number of bits per pixel - * @colplanes: number of color planes (1 for packed formats) + * @mem_planes: number of memory planes (1 for packed formats) + * @comp_planes:number of component planes, which includes the alpha plane (1 to 4). * @h_align: horizontal alignment order (align to 2^h_align) * @v_align: vertical alignment order (align to 2^v_align) * @flags: flags describing format applicability * @precision: jpeg sample precision + * @is_rgb: is an RGB pixel format */ struct mxc_jpeg_fmt { const char *name; @@ -57,11 +59,13 @@ struct mxc_jpeg_fmt { enum v4l2_jpeg_chroma_subsampling subsampling; int nc; int depth; - int colplanes; + int mem_planes; + int comp_planes; int h_align; int v_align; u32 flags; u8 precision; + u8 is_rgb; }; struct mxc_jpeg_desc { |