media: coda: add JPEG downscale support
authorPhilipp Zabel <p.zabel@pengutronix.de>
Wed, 6 Apr 2022 08:51:45 +0000 (09:51 +0100)
committerMauro Carvalho Chehab <mchehab@kernel.org>
Sun, 24 Apr 2022 07:46:27 +0000 (08:46 +0100)
The JPEG decoder in the CODA960 VPU can downscale images while decoding,
with a factor of 1/2, 1/4, or 1/8.

Signed-off-by: Philipp Zabel <p.zabel@pengutronix.de>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@kernel.org>
drivers/media/platform/chips-media/coda-common.c
drivers/media/platform/chips-media/coda-jpeg.c
drivers/media/platform/chips-media/coda.h

index a5c20d5..93ac519 100644 (file)
@@ -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)
index 21d14f9..6b19efc 100644 (file)
@@ -1328,6 +1328,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,6 +1336,9 @@ 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));
@@ -1383,7 +1387,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);
index dcf3564..ddfd0a3 100644 (file)
@@ -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);