MLK-19247: mxc-jpeg: Remove jpeg-encoder hardcoding to 64x64 yuv422
authorMirela Rabulea <mirela.rabulea@nxp.com>
Tue, 25 Sep 2018 12:49:38 +0000 (15:49 +0300)
committerLeonard Crestez <leonard.crestez@nxp.com>
Wed, 17 Apr 2019 23:51:34 +0000 (02:51 +0300)
Remove hardcodings for encoder (configuration stream especially).
This fix also requires a fixed version of the test applications,
encoder_test.out/decoder_test.out (linux-test repo).

Also fixed MLK-19453: Add support for YUV420 format in jpeg decoder
YUV420 is generally working on encoder/decoder,
but for some particular small files the decoder enters infinite error:
"Instance released before the end of transaction".
RGB24 is working, but the colors are strange in jpeg.
Since YUV444 and RGB24 have the same subsampling,
a RGB24 raw file can be encoded/decoded as YUV444 with the same results.
Fixes for invalid pixel formats.
Full battery of tests run.

Signed-off-by: Mirela Rabulea <mirela.rabulea@nxp.com>
drivers/media/platform/imx8/mxc-jpeg-hw.h
drivers/media/platform/imx8/mxc-jpeg.c
drivers/media/platform/imx8/mxc-jpeg.h

index ce158c8..2094d93 100644 (file)
@@ -85,6 +85,7 @@
 /* STM_CTRL fields */
 #define STM_CTRL_PIXEL_PRECISION               (0x1 << 2)
 #define STM_CTRL_IMAGE_FORMAT(img_fmt)         ((img_fmt) << 3)
+#define STM_CTRL_IMAGE_FORMAT_MASK             (0xF << 3)
 #define STM_CTRL_BITBUF_PTR_CLR(clr)           ((clr) << 7)
 #define STM_CTRL_AUTO_START(go)                        ((go) << 8)
 #define STM_CTRL_CONFIG_MOD(mod)               ((mod) << 9)
 /* JPEG-Decoder Wrapper - STM_CTRL Register Fields */
 #define MXC_PIXEL_PRECISION(precision) ((precision)/8 << 2)
 enum mxc_jpeg_image_format {
+       MXC_JPEG_INVALID = -1,
        MXC_JPEG_YUV420 = 0x0, /* 2 Plannar, Y=1st plane UV=2nd plane */
        MXC_JPEG_YUV422 = 0x1, /* 1 Plannar, YUYV sequence */
        MXC_JPEG_RGB    = 0x2, /* RGBRGB packed format */
index 4d203a6..ab0f817 100644 (file)
@@ -38,8 +38,17 @@ static struct mxc_jpeg_fmt mxc_formats[] = {
                .flags          = MXC_JPEG_FMT_TYPE_ENC,
        },
        {
-               .name           = "RGB32",
-               .fourcc         = V4L2_PIX_FMT_RGB32,
+               .name           = "RGB", /*RGBRGB packed format*/
+               .fourcc         = V4L2_PIX_FMT_RGB24,
+               .depth          = 24,
+               .colplanes      = 1,
+               .h_align        = 0,
+               .v_align        = 0,
+               .flags          = MXC_JPEG_FMT_TYPE_RAW,
+       },
+       {
+               .name           = "ARGB", /* ARGBARGB packed format */
+               .fourcc         = V4L2_PIX_FMT_ARGB32,
                .depth          = 32,
                .colplanes      = 1,
                .h_align        = 0,
@@ -47,7 +56,16 @@ static struct mxc_jpeg_fmt mxc_formats[] = {
                .flags          = MXC_JPEG_FMT_TYPE_RAW,
        },
        {
-               .name           = "YUV422",
+               .name           = "YUV420", /* 1st plane = Y, 2nd plane = UV */
+               .fourcc         = V4L2_PIX_FMT_NV12,
+               .depth          = 12, /* 6 bytes (4Y + UV) for 4 pixels */
+               .colplanes      = 2, /* 1 plane Y, 1 plane UV interleaved */
+               .h_align        = 2,
+               .v_align        = 0,
+               .flags          = MXC_JPEG_FMT_TYPE_RAW,
+       },
+       {
+               .name           = "YUV422", /* YUYV */
                .fourcc         = V4L2_PIX_FMT_YUYV,
                .depth          = 16,
                .colplanes      = 1,
@@ -56,15 +74,25 @@ static struct mxc_jpeg_fmt mxc_formats[] = {
                .flags          = MXC_JPEG_FMT_TYPE_RAW,
        },
        {
-               .name           = "YUV444",
+               .name           = "YUV444", /* YUVYUV */
                .fourcc         = V4L2_PIX_FMT_YUV32,
-               .depth          = 32,
+               .depth          = 24,
+               .colplanes      = 1,
+               .h_align        = 0,
+               .v_align        = 0,
+               .flags          = MXC_JPEG_FMT_TYPE_RAW,
+       },
+       {
+               .name           = "Gray", /* Gray (Y8/Y12) or Single Comp */
+               .fourcc         = V4L2_PIX_FMT_GREY,
+               .depth          = 8,
                .colplanes      = 1,
                .h_align        = 0,
                .v_align        = 0,
                .flags          = MXC_JPEG_FMT_TYPE_RAW,
        },
 };
+#define MXC_JPEG_NUM_FORMATS ARRAY_SIZE(mxc_formats)
 
 static const struct of_device_id mxc_jpeg_match[] = {
        {
@@ -168,6 +196,25 @@ static const unsigned char hactbl[615] = {
 0x0C, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03,
 0x11, 0x00, 0x3F, 0x00, 0xFF, 0xD9
 };
+#define HACTBL_H_OFFSET 159
+#define HACTBL_W_OFFSET 161
+#define HACTBL_COMP1_SUBSAMPLING 165
+#define HACTBL_COMP2_SUBSAMPLING 168
+#define HACTBL_COMP3_SUBSAMPLING 171
+
+/*  Print Four-character-code (FOURCC) */
+static char *fourcc_to_str(u32 format)
+{
+       char *buf = kmalloc(32, GFP_KERNEL);
+
+       snprintf(buf, 32,
+                "%c%c%c%c",
+                format & 0xff,
+                (format >> 8) & 0xff,
+                (format >> 16) & 0xff,
+                (format >> 24) & 0x7f);
+       return buf;
+}
 
 static void print_buf(struct device *dev, struct vb2_buffer *buf)
 {
@@ -185,7 +232,6 @@ static void print_buf(struct device *dev, struct vb2_buffer *buf)
                data[0], data[1], data[2], data[3]);
 }
 
-#define MXC_NUM_FORMATS ARRAY_SIZE(mxc_formats)
 static inline u32 mxc_jpeg_align(u32 val, u32 align)
 {
        return (val + align - 1) & ~(align - 1);
@@ -225,12 +271,91 @@ static int enum_fmt(struct mxc_jpeg_fmt *mxc_formats, int n,
        return 0;
 }
 
+static struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
+                                                u32 pixelformat)
+{
+       unsigned int k;
+
+       for (k = 0; k < MXC_JPEG_NUM_FORMATS; k++) {
+               struct mxc_jpeg_fmt *fmt = &mxc_formats[k];
+
+               if (fmt->fourcc == pixelformat)
+                       return fmt;
+       }
+       return NULL;
+}
+
+static enum mxc_jpeg_image_format mxc_jpeg_fourcc_to_imgfmt(
+       u32     fourcc)
+{
+       switch (fourcc) {
+       case V4L2_PIX_FMT_GREY:
+               return MXC_JPEG_GRAY;
+       case V4L2_PIX_FMT_YUYV:
+               return MXC_JPEG_YUV422;
+       case V4L2_PIX_FMT_NV12:
+               return MXC_JPEG_YUV420;
+       case V4L2_PIX_FMT_YUV32:
+               return MXC_JPEG_YUV444;
+       case V4L2_PIX_FMT_RGB24:
+               return MXC_JPEG_RGB;
+       case V4L2_PIX_FMT_ARGB32:
+               return MXC_JPEG_ARGB;
+       default:
+               return MXC_JPEG_INVALID;
+       }
+}
+
+static int mxc_jpeg_imgfmt_to_fourcc(enum mxc_jpeg_image_format imgfmt,
+                                 u32 *fourcc)
+{
+       switch (imgfmt) {
+       case MXC_JPEG_GRAY:
+               *fourcc = V4L2_PIX_FMT_GREY;
+               return 0;
+       case MXC_JPEG_YUV422:
+               *fourcc = V4L2_PIX_FMT_YUYV;
+               return 0;
+       case MXC_JPEG_YUV420:
+               *fourcc =  V4L2_PIX_FMT_NV12;
+               return 0;
+       case MXC_JPEG_YUV444:
+               *fourcc =  V4L2_PIX_FMT_YUV32;
+               return 0;
+       case MXC_JPEG_RGB:
+               *fourcc =  V4L2_PIX_FMT_RGB24;
+               return 0;
+       case MXC_JPEG_ARGB:
+               *fourcc =  V4L2_PIX_FMT_ARGB32;
+               return 0;
+       default:
+               return 1;
+       }
+}
+
+static struct mxc_jpeg_q_data *mxc_jpeg_get_q_data(struct mxc_jpeg_ctx *ctx,
+                                                  enum v4l2_buf_type type)
+{
+       if (V4L2_TYPE_IS_OUTPUT(type))
+               return &ctx->out_q;
+       return &ctx->cap_q;
+}
+
 static void mxc_jpeg_addrs(struct mxc_jpeg_desc *desc,
                           struct vb2_buffer *b_base0_buf,
                           struct vb2_buffer *bufbase_buf, int offset)
 {
+       int img_fmt = desc->stm_ctrl & STM_CTRL_IMAGE_FORMAT_MASK;
+
        desc->buf_base0 = vb2_dma_contig_plane_dma_addr(b_base0_buf, 0);
-       desc->buf_base1 = 0; /* TODO for YUV420*/
+       desc->buf_base1 = 0;
+       if (img_fmt == STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV420)) {
+               u32 h = desc->imgsize & 0xFFFF;
+               u32 w = (desc->imgsize >> 16) & 0xFFFF;
+               u32 luma_plane_size =  w * h;
+
+               desc->buf_base1 = desc->buf_base0 + luma_plane_size;
+       }
        desc->stm_bufbase = vb2_dma_contig_plane_dma_addr(bufbase_buf, 0) +
                offset;
 }
@@ -243,6 +368,8 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
        struct device *dev = jpeg->dev;
        struct vb2_buffer *src_buf, *dst_buf;
        u32 dec_ret;
+       unsigned long payload_size;
+       struct mxc_jpeg_q_data *q_data;
        int slot = 0; /* TODO remove hardcoded slot 0 */
 
        spin_lock(&jpeg->hw_lock);
@@ -254,7 +381,7 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
                goto job_unlock;
        }
        if (ctx->aborting) {
-               dev_dbg(dev, "Aborting current job\n");
+               dev_warn(dev, "Aborting current job\n");
                mxc_jpeg_sw_reset(reg);
                goto job_finish;
        }
@@ -278,10 +405,18 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
                dev_dbg(dev, "Encoder config finished. Start encoding...\n");
                goto job_unlock;
        }
-       if (ctx->mode == MXC_JPEG_ENCODE)
-               dev_dbg(dev, "Encoding finished\n");
-       else
-               dev_dbg(dev, "Decoding finished\n");
+       if (ctx->mode == MXC_JPEG_ENCODE) {
+               payload_size = readl(reg + MXC_SLOT_OFFSET(slot, SLOT_BUF_PTR));
+               vb2_set_plane_payload(dst_buf, 0, payload_size);
+               dev_dbg(dev, "Encoding finished, payload_size: %ld\n",
+                       payload_size);
+       } else {
+               q_data = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+               payload_size = q_data->sizeimage[0];
+               vb2_set_plane_payload(dst_buf, 0, payload_size);
+               dev_dbg(dev, "Decoding finished, payload_size: %ld\n",
+                       payload_size);
+       }
 
        /* short preview of the results */
        dev_dbg(dev, "src_buf preview: ");
@@ -318,17 +453,62 @@ static void mxc_jpeg_config_dec_desc(struct vb2_buffer *out_buf,
        mxc_jpeg_set_desc(desc_handle, reg, slot);
 }
 
+static void mxc_jpeg_fixup_cfg_stream(void *cfg_stream_vaddr,
+                            enum mxc_jpeg_image_format img_fmt,
+                            u16 w, u16 h)
+{
+       u8 *hactbl = (u8 *)cfg_stream_vaddr;
+
+       hactbl[HACTBL_W_OFFSET] = w >> 8;
+       hactbl[HACTBL_W_OFFSET+1] = (u8)w;
+       hactbl[HACTBL_H_OFFSET] = h >> 8;
+       hactbl[HACTBL_H_OFFSET+1] = (u8)h;
+       switch (img_fmt) {
+       case MXC_JPEG_YUV420:
+               hactbl[HACTBL_COMP1_SUBSAMPLING] = 0x22;
+               hactbl[HACTBL_COMP2_SUBSAMPLING] = 0x11;
+               hactbl[HACTBL_COMP3_SUBSAMPLING] = 0x11;
+               break;
+       case MXC_JPEG_YUV422:
+               hactbl[HACTBL_COMP1_SUBSAMPLING] = 0x21;
+               hactbl[HACTBL_COMP2_SUBSAMPLING] = 0x11;
+               hactbl[HACTBL_COMP3_SUBSAMPLING] = 0x11;
+               break;
+       case MXC_JPEG_YUV444:
+       case MXC_JPEG_RGB:
+       default:
+               hactbl[HACTBL_COMP1_SUBSAMPLING] = 0x11;
+               hactbl[HACTBL_COMP2_SUBSAMPLING] = 0x11;
+               hactbl[HACTBL_COMP3_SUBSAMPLING] = 0x11;
+               break;
+       case MXC_JPEG_ARGB:
+               /* TODO: should be 4 componennts, SOF0 length should change*/
+               hactbl[HACTBL_COMP1_SUBSAMPLING] = 0x11;
+               hactbl[HACTBL_COMP2_SUBSAMPLING] = 0x11;
+               hactbl[HACTBL_COMP3_SUBSAMPLING] = 0x11;
+               break;
+       case MXC_JPEG_GRAY:
+               /* TODO: should be 1 comp only, SOF0 length should change*/
+               hactbl[HACTBL_COMP1_SUBSAMPLING] = 0x11;
+               break;
+       }
+}
+
 static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
                         int slot,
-                        struct mxc_jpeg_dev *jpeg,
+                        struct mxc_jpeg_ctx *ctx,
                         struct vb2_buffer *src_buf, struct vb2_buffer *dst_buf)
 {
+       struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
        void __iomem *reg = jpeg->base_reg;
        struct mxc_jpeg_desc *desc = jpeg->slot_data[slot].desc;
        struct mxc_jpeg_desc *cfg_desc = jpeg->slot_data[slot].cfg_desc;
        dma_addr_t desc_handle = jpeg->slot_data[slot].desc_handle;
        dma_addr_t cfg_desc_handle = jpeg->slot_data[slot].cfg_desc_handle;
+       struct mxc_jpeg_q_data *q_data;
+       enum mxc_jpeg_image_format img_fmt;
 
+       q_data = mxc_jpeg_get_q_data(ctx, src_buf->vb2_queue->type);
 
        /* chain the config descriptor with the encoding descriptor */
        cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN;
@@ -342,14 +522,17 @@ static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
        cfg_desc->stm_ctrl = STM_CTRL_CONFIG_MOD(1);
 
        desc->next_descpt_ptr = 0; /* end of chain */
-       mxc_jpeg_addrs(desc, src_buf, dst_buf, 0);
-       /* TODO remove hardcodings*/
-       mxc_jpeg_set_bufsize(desc, 0x1000);
-       mxc_jpeg_set_res(desc, 64, 64);
-       mxc_jpeg_set_line_pitch(desc, 64 * 2);
+       mxc_jpeg_set_res(desc, q_data->w, q_data->h);
+       mxc_jpeg_set_line_pitch(desc, q_data->w * (q_data->fmt->depth / 8));
+       mxc_jpeg_set_bufsize(desc, desc->line_pitch * q_data->h);
+       img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data->fmt->fourcc);
+       if (img_fmt == MXC_JPEG_INVALID)
+               dev_err(jpeg->dev, "No valid image format detected\n");
        desc->stm_ctrl = STM_CTRL_CONFIG_MOD(0) |
-                        STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV422);
-
+                        STM_CTRL_IMAGE_FORMAT(img_fmt);
+       mxc_jpeg_fixup_cfg_stream(jpeg->slot_data[slot].cfg_stream_vaddr,
+                       img_fmt, q_data->w, q_data->h);
+       mxc_jpeg_addrs(desc, src_buf, dst_buf, 0);
        dev_dbg(jpeg->dev, "cfg_desc - 0x%llx:\n", cfg_desc_handle);
        print_descriptor_info(jpeg->dev, cfg_desc);
        dev_dbg(jpeg->dev, "enc desc - 0x%llx:\n", desc_handle);
@@ -390,7 +573,7 @@ static void mxc_jpeg_device_run(void *priv)
        if (ctx->mode == MXC_JPEG_ENCODE) {
                dev_dbg(dev, "Encoding on slot %d\n", slot);
                ctx->enc_state = MXC_JPEG_ENC_CONF;
-               mxc_jpeg_config_enc_desc(dst_buf, slot, jpeg, src_buf, dst_buf);
+               mxc_jpeg_config_enc_desc(dst_buf, slot, ctx, src_buf, dst_buf);
                mxc_jpeg_go_enc(dev, reg);
        } else {
                dev_dbg(dev, "Decoding on slot %d\n", slot);
@@ -427,14 +610,6 @@ static void mxc_jpeg_job_abort(void *priv)
        dev_dbg(ctx->mxc_jpeg->dev, "Abort requested\n");
 }
 
-static struct mxc_jpeg_q_data *mxc_jpeg_get_q_data(struct mxc_jpeg_ctx *ctx,
-                                                  enum v4l2_buf_type type)
-{
-       if (V4L2_TYPE_IS_OUTPUT(type))
-               return &ctx->out_q;
-       return &ctx->cap_q;
-}
-
 static int mxc_jpeg_queue_setup(struct vb2_queue *q,
                                unsigned int *num_buffers,
                                unsigned int *num_planes,
@@ -448,7 +623,9 @@ static int mxc_jpeg_queue_setup(struct vb2_queue *q,
        if (!q_data)
                return -EINVAL;
        *num_planes = 1;
-       sizes[0] = 10;
+
+       /* assuming worst case jpeg compression: 6 x raw file size */
+       sizes[0] = q_data->w * q_data->h * 6;
 
        if (q_data->sizeimage[0] > 0)
                sizes[0] = q_data->sizeimage[0];
@@ -505,11 +682,11 @@ static u8 get_sof(struct device *dev,
        _bswap16(&sof->length);
        _bswap16(&sof->height);
        _bswap16(&sof->width);
-       dev_info(dev, "JPEG SOF: precision=%d\n", sof->precision);
-       dev_info(dev, "JPEG SOF: height=%d, width=%d\n",
+       dev_dbg(dev, "JPEG SOF: precision=%d\n", sof->precision);
+       dev_dbg(dev, "JPEG SOF: height=%d, width=%d\n",
                sof->height, sof->width);
        for (i = 0; i < sof->components_no; i++) {
-               dev_info(dev, "JPEG SOF: comp_id=%d, H=0x%x, V=0x%x\n",
+               dev_dbg(dev, "JPEG SOF: comp_id=%d, H=0x%x, V=0x%x\n",
                        sof->comp[i].id, sof->comp[i].v, sof->comp[i].h);
        }
        return 0;
@@ -520,31 +697,41 @@ static enum mxc_jpeg_image_format mxc_jpeg_get_image_format(
        const struct mxc_jpeg_sof *sof)
 {
        if (sof->components_no == 1) {
-               dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_GRAY\n");
+               dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_GRAY\n");
                return MXC_JPEG_GRAY;
        }
        if (sof->components_no == 3) {
                if (sof->comp[0].h == 2 && sof->comp[0].v == 2 &&
                    sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
                    sof->comp[2].h == 1 && sof->comp[2].v == 1){
-                       dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV420\n");
+                       dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV420\n");
                        return MXC_JPEG_YUV420;
                }
                if (sof->comp[0].h == 2 && sof->comp[0].v == 1 &&
                    sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
                    sof->comp[2].h == 1 && sof->comp[2].v == 1){
-                       dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV422\n");
+                       dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV422\n");
                        return MXC_JPEG_YUV422;
                }
                if (sof->comp[0].h == 1 && sof->comp[0].v == 1 &&
                    sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
                    sof->comp[2].h == 1 && sof->comp[2].v == 1){
-                       dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV444\n");
+                       dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_YUV444\n");
                        return MXC_JPEG_YUV444;
                }
        }
-       dev_info(dev, "IMAGE_FORMAT is: MXC_JPEG_RESERVED\n");
-       return MXC_JPEG_RESERVED;
+       if (sof->components_no == 4) {
+               if (sof->comp[0].h == 1 && sof->comp[0].v == 1 &&
+                   sof->comp[1].h == 1 && sof->comp[1].v == 1 &&
+                   sof->comp[2].h == 1 && sof->comp[2].v == 1 &&
+                   sof->comp[3].h == 1 && sof->comp[3].v == 1){
+                       /* this is not tested */
+                       dev_dbg(dev, "IMAGE_FORMAT is: MXC_JPEG_ARGB\n");
+                       return MXC_JPEG_ARGB;
+               }
+       }
+       dev_err(dev, "Could not identify image format\n");
+       return MXC_JPEG_INVALID;
 }
 
 static u32 mxc_jpeg_get_line_pitch(
@@ -564,6 +751,9 @@ static u32 mxc_jpeg_get_line_pitch(
        case  MXC_JPEG_RGB:
                line_pitch = sof->width * (sof->precision/8) * 3;
                break;
+       case  MXC_JPEG_ARGB:
+               line_pitch = sof->width * (sof->precision/8) * 4;
+               break;
        case  MXC_JPEG_YUV444:
                line_pitch = sof->width * (sof->precision/8) * 3;
                break;
@@ -574,18 +764,21 @@ static u32 mxc_jpeg_get_line_pitch(
                line_pitch = sof->width * (sof->precision/8) * 3;
                break;
        }
-       dev_info(dev, "line_pitch = %d\n", line_pitch);
+       dev_dbg(dev, "line_pitch = %d\n", line_pitch);
        return line_pitch;
 }
 
-static int mxc_jpeg_parse(struct device *dev,
+static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
        struct mxc_jpeg_desc *desc, u8 *src_addr, u32 size)
 {
+       struct device *dev = ctx->mxc_jpeg->dev;
+       struct mxc_jpeg_q_data *q_data;
        struct mxc_jpeg_stream stream;
        bool notfound = true;
        struct mxc_jpeg_sof sof;
        int byte;
        enum mxc_jpeg_image_format img_fmt;
+       u32 fourcc;
 
        memset(&sof, 0, sizeof(struct mxc_jpeg_sof));
        stream.addr = src_addr;
@@ -615,22 +808,51 @@ static int mxc_jpeg_parse(struct device *dev,
                        notfound = true;
                }
        }
+       q_data = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       if (sof.width != q_data->w || sof.height != q_data->h) {
+               dev_err(dev,
+                       "Resolution mismatch: %dx%d (JPEG) versus %dx%d(user)",
+                       sof.width, sof.height, q_data->w, q_data->h);
+               return -EINVAL;
+       }
        if (sof.width % 8 != 0 || sof.height % 8 != 0) {
-               dev_info(dev, "JPEG width or height not multiple of 8: %dx%d\n",
+               dev_err(dev, "JPEG width or height not multiple of 8: %dx%d\n",
                        sof.width, sof.height);
                return -EINVAL;
        }
        if (sof.width > 0x2000 || sof.height > 0x2000) {
-               dev_info(dev, "JPEG width or height should be <= 8192: %dx%d\n",
+               dev_err(dev, "JPEG width or height should be <= 8192: %dx%d\n",
                        sof.width, sof.height);
                return -EINVAL;
        }
        desc->imgsize = sof.width << 16 | sof.height;
-       dev_info(dev, "JPEG imgsize = 0x%x (%dx%d)\n", desc->imgsize,
+       dev_dbg(dev, "JPEG imgsize = 0x%x (%dx%d)\n", desc->imgsize,
                sof.width, sof.height);
        img_fmt = mxc_jpeg_get_image_format(dev, &sof);
+       if (img_fmt == MXC_JPEG_INVALID)
+               return -EINVAL;
+       if (mxc_jpeg_imgfmt_to_fourcc(img_fmt, &fourcc)) {
+               dev_err(dev, "Fourcc not found for %d", img_fmt);
+               return -EINVAL;
+       }
+
+       if (fourcc != q_data->fmt->fourcc) {
+               char *jpeg_format_name = fourcc_to_str(fourcc);
+               char *user_format_name = fourcc_to_str(q_data->fmt->fourcc);
+
+               dev_warn(dev,
+                        "Pixel format mismatch: jpeg(%s) versus user (%s)",
+                        jpeg_format_name, user_format_name);
+               dev_warn(dev, "Keeping user settings\n");
+               kfree(jpeg_format_name);
+               kfree(user_format_name);
+               img_fmt = mxc_jpeg_fourcc_to_imgfmt(q_data->fmt->fourcc);
+       }
        desc->stm_ctrl |= STM_CTRL_IMAGE_FORMAT(img_fmt);
        desc->line_pitch = mxc_jpeg_get_line_pitch(dev, &sof, img_fmt);
+       q_data->stride = desc->line_pitch;
+       q_data->sizeimage[0] = sof.width * sof.height;
+
        return 0;
 }
 
@@ -640,23 +862,30 @@ static void mxc_jpeg_buf_queue(struct vb2_buffer *vb)
        struct vb2_v4l2_buffer *vbuf = to_vb2_v4l2_buffer(vb);
        struct mxc_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
        int slot = 0; /* TODO get slot*/
+       struct mxc_jpeg_q_data *q_data;
+       int decoded_jpeg_size;
 
        if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
                goto end;
 
        if (ctx->mode != MXC_JPEG_DECODE)
                goto end;
-       ret = mxc_jpeg_parse(ctx->mxc_jpeg->dev,
+       ret = mxc_jpeg_parse(ctx,
                        ctx->mxc_jpeg->slot_data[slot].desc,
                        (u8 *)vb2_plane_vaddr(vb, 0),
                        vb2_get_plane_payload(vb, 0));
        if (ret) {
                v4l2_err(&ctx->mxc_jpeg->v4l2_dev,
-                        "driver does not support this resolution\n");
+                        "driver does not support this resolution/format\n");
                vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
                return;
        }
 
+       q_data = mxc_jpeg_get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+       decoded_jpeg_size = q_data->w * q_data->h * q_data->fmt->depth / 8;
+       if (q_data->sizeimage[0] != decoded_jpeg_size)
+               q_data->sizeimage[0] = decoded_jpeg_size;
+
        if (ctx->state == MXC_JPEG_INIT) {
                struct vb2_queue *dst_vq = v4l2_m2m_get_vq(
                        ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
@@ -736,28 +965,6 @@ static int mxc_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
        return ret;
 }
 
-static struct mxc_jpeg_fmt *mxc_jpeg_find_format(struct mxc_jpeg_ctx *ctx,
-                                                u32 pixelformat,
-                                                unsigned int fmt_type)
-{
-       unsigned int k, fmt_flag;
-
-       fmt_flag = fmt_type;
-
-       if (ctx->mode == MXC_JPEG_ENCODE)
-               fmt_flag = (fmt_type == MXC_JPEG_FMT_TYPE_RAW) ?
-                       MXC_JPEG_FMT_TYPE_ENC :
-                       MXC_JPEG_FMT_TYPE_RAW;
-
-       for (k = 0; k < MXC_JPEG_NUM_FORMATS; k++) {
-               struct mxc_jpeg_fmt *fmt = &mxc_formats[k];
-
-               if (fmt->fourcc == pixelformat && fmt->flags == fmt_flag)
-                       return fmt;
-       }
-       return NULL;
-}
-
 static int mxc_jpeg_alloc_slot_data(struct mxc_jpeg_dev *jpeg)
 {
        int slot;
@@ -855,16 +1062,12 @@ static int mxc_jpeg_open(struct file *file)
        ctx->mxc_jpeg = mxc_jpeg;
        if (mxc_jpeg->mode == MXC_JPEG_ENCODE) {
                ctx->mode = MXC_JPEG_ENCODE;
-               cap_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB24,
-                                                       MXC_JPEG_FMT_TYPE_ENC);
-               out_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
-                                                       MXC_JPEG_FMT_TYPE_RAW);
+               out_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB24);
+               cap_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG);
        } else {
                ctx->mode = MXC_JPEG_DECODE;
-               out_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB24,
-                                                       MXC_JPEG_FMT_TYPE_RAW);
-               cap_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
-                                                       MXC_JPEG_FMT_TYPE_ENC);
+               out_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG);
+               cap_fmt = mxc_jpeg_find_format(ctx, V4L2_PIX_FMT_RGB24);
        }
        ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(mxc_jpeg->m2m_dev, ctx,
                                            mxc_jpeg_queue_init);
@@ -910,10 +1113,10 @@ static int mxc_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
        struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
 
        if (ctx->mode == MXC_JPEG_ENCODE)
-               return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
+               return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
                        MXC_IN_FORMAT);
        else
-               return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
+               return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
                        MXC_OUT_FORMAT);
 }
 
@@ -923,14 +1126,14 @@ static int mxc_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
        struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
 
        if (ctx->mode == MXC_JPEG_DECODE)
-               return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
+               return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
                                MXC_IN_FORMAT);
        else
-               return enum_fmt(mxc_formats, MXC_NUM_FORMATS, f,
+               return enum_fmt(mxc_formats, MXC_JPEG_NUM_FORMATS, f,
                                MXC_OUT_FORMAT);
 }
 
-static void mxc_jpeg_bound_align_image(u32 *w, unsigned int wmin,
+static int mxc_jpeg_bound_align_image(u32 *w, unsigned int wmin,
                                       unsigned int wmax, unsigned int walign,
                                       u32 *h, unsigned int hmin,
                                       unsigned int hmax, unsigned int halign)
@@ -947,74 +1150,101 @@ static void mxc_jpeg_bound_align_image(u32 *w, unsigned int wmin,
                *w += w_step;
        if (*h < height && (*h + h_step) <= hmax)
                *h += h_step;
+
+       return (width != *w || height != *h);
 }
 static int mxc_jpeg_try_fmt(struct v4l2_format *f, struct mxc_jpeg_fmt *fmt,
                            struct mxc_jpeg_ctx *ctx, int q_type)
 {
+       struct device *dev = ctx->mxc_jpeg->dev;
        struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
        struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
-       u32 stride, h;
+       u32 w = pix_mp->width;
+       u32 h = pix_mp->height;
+       unsigned int mode = ctx->mode;
 
        memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
        pix_mp->field = V4L2_FIELD_NONE;
        pix_mp->num_planes = fmt->colplanes;
        pix_mp->pixelformat = fmt->fourcc;
+       if (mxc_jpeg_bound_align_image(&w,
+                                       MXC_JPEG_MIN_WIDTH,
+                                       MXC_JPEG_MAX_WIDTH,
+                                       MXC_JPEG_W_ALIGN,
+                                       &h,
+                                       MXC_JPEG_MIN_HEIGHT,
+                                       MXC_JPEG_MAX_HEIGHT,
+                                       MXC_JPEG_H_ALIGN))
+               dev_warn(dev, "Image was aligned to %dx%d", w, h);
 
-       if (q_type == MXC_JPEG_FMT_TYPE_ENC && ctx->mode == MXC_JPEG_DECODE) {
-               struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
-
-               mxc_jpeg_bound_align_image(&pix_mp->width,
-                                          MXC_JPEG_MIN_WIDTH,
-                                          MXC_JPEG_MAX_WIDTH,
-                                          MXC_JPEG_MIN_WIDTH,
-                                          &pix_mp->height,
-                                          MXC_JPEG_MIN_HEIGHT,
-                                          MXC_JPEG_MAX_HEIGHT,
-                                          MXC_JPEG_MIN_WIDTH);
+       memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
 
-               memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+       /* TODO try_fmt should not modify the state, move to s_fmt */
+       if (q_type == MXC_JPEG_FMT_TYPE_ENC && mode == MXC_JPEG_DECODE) {
                pfmt->bytesperline = 0;
                /* Source size must be aligned to 128 */
                pfmt->sizeimage = mxc_jpeg_align(pfmt->sizeimage, 128);
                if (pfmt->sizeimage == 0)
                        pfmt->sizeimage = MXC_JPEG_DEFAULT_SIZEIMAGE;
-               return 0;
+       } else if (q_type == MXC_JPEG_FMT_TYPE_RAW && mode == MXC_JPEG_DECODE) {
+               pfmt->bytesperline = w * (fmt->depth / 8);
+               pfmt->sizeimage = w * h * fmt->depth / 8;
+       } else if (q_type == MXC_JPEG_FMT_TYPE_ENC && mode == MXC_JPEG_ENCODE) {
+               pfmt->bytesperline = 0;
+               /* assuming worst jpeg compression */
+               pfmt->sizeimage = w * h * 6;
+       } else { /* MXC_JPEG_FMT_TYPE_RAW && MXC_JPEG_ENCODE */
+               pfmt->bytesperline = w * (fmt->depth / 8);
+               pfmt->sizeimage = w * h * fmt->depth / 8;
        }
 
-       /* type is MXC_JPEG_FMT_TYPE_RAW */
-       mxc_jpeg_bound_align_image(&pix_mp->width, MXC_JPEG_MIN_WIDTH,
-                                  MXC_JPEG_MAX_WIDTH, MXC_JPEG_MIN_WIDTH,
-                                  &pix_mp->height, MXC_JPEG_MIN_HEIGHT,
-                                  MXC_JPEG_MAX_HEIGHT, MXC_JPEG_MIN_WIDTH);
-
-       pfmt = &pix_mp->plane_fmt[0];
-       stride = pix_mp->width * 3;
-       h = pix_mp->height;
-       memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
-       pfmt->bytesperline = stride;
-       pfmt->sizeimage = stride * h;
-
        return 0;
 }
 static int mxc_jpeg_try_fmt_vid_cap(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
        struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+       struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+       struct device *dev = jpeg->dev;
        struct mxc_jpeg_fmt *fmt;
+       u32 fourcc = f->fmt.pix_mp.pixelformat;
+
+       int q_type = (ctx->mode == MXC_JPEG_DECODE) ?
+                    MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC;
 
-       fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
-                                  MXC_JPEG_FMT_TYPE_RAW);
-       return mxc_jpeg_try_fmt(f, fmt, ctx, MXC_JPEG_FMT_TYPE_RAW);
+       fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat);
+       if (!fmt || (fmt->flags != q_type)) {
+               char *format_name = fourcc_to_str(fourcc);
+
+               dev_err(dev, "Format not supported: %s.\n",
+                       format_name);
+               kfree(format_name);
+               return -1;
+       }
+       return mxc_jpeg_try_fmt(f, fmt, ctx, q_type);
 }
 static int mxc_jpeg_try_fmt_vid_out(struct file *file, void *priv,
                                struct v4l2_format *f)
 {
        struct mxc_jpeg_ctx *ctx = mxc_jpeg_fh_to_ctx(priv);
+       struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
+       struct device *dev = jpeg->dev;
        struct mxc_jpeg_fmt *fmt;
+       u32 fourcc = f->fmt.pix_mp.pixelformat;
+
+       int q_type = (ctx->mode == MXC_JPEG_ENCODE) ?
+                    MXC_JPEG_FMT_TYPE_RAW : MXC_JPEG_FMT_TYPE_ENC;
 
-       fmt = mxc_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
-                                  MXC_JPEG_FMT_TYPE_ENC);
-       return mxc_jpeg_try_fmt(f, fmt, ctx, MXC_JPEG_FMT_TYPE_ENC);
+       fmt = mxc_jpeg_find_format(ctx, fourcc);
+       if (!fmt || (fmt->flags != q_type)) {
+               char *format_name = fourcc_to_str(fourcc);
+
+               dev_err(dev, "Format not supported: %s.\n",
+                       format_name);
+               kfree(format_name);
+               return -1;
+       }
+       return mxc_jpeg_try_fmt(f, fmt, ctx, q_type);
 }
 static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
                          struct v4l2_format *f)
@@ -1023,7 +1253,6 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
        struct mxc_jpeg_q_data *q_data = NULL;
        struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
        struct mxc_jpeg_dev *jpeg = ctx->mxc_jpeg;
-       unsigned int f_type;
 
        vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
        if (!vq)
@@ -1036,9 +1265,7 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
                return -EBUSY;
        }
 
-       f_type = f->type;
-
-       q_data->fmt = mxc_jpeg_find_format(ctx, pix_mp->pixelformat, f_type);
+       q_data->fmt = mxc_jpeg_find_format(ctx, pix_mp->pixelformat);
        q_data->w = pix_mp->width;
        q_data->h = pix_mp->height;
        q_data->bytesperline[0] = pix_mp->plane_fmt[0].bytesperline;
index d2eb052..f3e987e 100644 (file)
 #define MXC_JPEG_RUNNING               1
 #define MXC_JPEG_FMT_TYPE_ENC          0
 #define MXC_JPEG_FMT_TYPE_RAW          1
-#define MXC_JPEG_NUM_FORMATS           4
 #define MXC_JPEG_MIN_HEIGHT            0x8
 #define MXC_JPEG_MIN_WIDTH             0x8
 #define MXC_JPEG_MAX_HEIGHT            0x2000
 #define MXC_JPEG_MAX_WIDTH             0x2000
+#define MXC_JPEG_H_ALIGN               3
+#define MXC_JPEG_W_ALIGN               3
 #define MXC_JPEG_DEFAULT_SIZEIMAGE     10000
 #define MXC_JPEG_ENC_CONF              1
 #define MXC_JPEG_ENC_DONE              0
@@ -135,7 +136,7 @@ struct mxc_jpeg_sof {
        u8 precision;
        u16 height, width;
        u8 components_no;
-       struct mxc_jpeg_sof_comp comp[3];
+       struct mxc_jpeg_sof_comp comp[4];
 } __packed;
 
 #endif