MLK-20290: mxc-jpeg: Inject a default Huffman table for the decoder
authorMirela Rabulea <mirela.rabulea@nxp.com>
Wed, 26 Jun 2019 13:38:29 +0000 (16:38 +0300)
committerMirela Rabulea <mirela.rabulea@nxp.com>
Fri, 28 Jun 2019 12:41:11 +0000 (15:41 +0300)
So far, the configuration stream was used only for the encoder, but
it is actually possible to use it for the decoder too, in order to inject
a default Huffman table, because the CAST IP decoder gets stuck for jpegs
that do not contain any Huffman table.
Add dht_needed member in the context structure, and set it true when a
jpeg without any DHT marker is detected. In such case, the decoder will
also operate in 2 phases: first DHT injection, then user buffer decode;
this is done by chaining a configuration  descriptor before the decoding
descriptor. The configuration stream is set-up in the s_fmt ioctl with
the minimum resolution.

Also print an error when a jpeg smaller than the minimum size, 64x64
according to imx8qxp errata ERR050135, is detected.

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

index adf1058..d64a21d 100644 (file)
@@ -106,6 +106,7 @@ static const struct of_device_id mxc_jpeg_match[] = {
        { },
 };
 
+/* default configuration stream 64x64 yuv422 */
 static const unsigned char jpeg_soi[] = {0xFF, 0xD8};
 static const unsigned char jpeg_app0[] = {0xFF, 0xE0, 0x00, 0x10, 0x4A,
 0x46, 0x49, 0x46, 0x00, 0x01, 0x01, 0x00,
@@ -480,6 +481,11 @@ static irqreturn_t mxc_jpeg_dec_irq(int irq, void *priv)
                mxc_jpeg_enc_mode_go(dev, reg);
                goto job_unlock;
        }
+       if (ctx->mode == MXC_JPEG_DECODE && ctx->dht_needed) {
+               ctx->dht_needed = false;
+               dev_dbg(dev, "Decoder DHT cfg finished. Start decoding...\n");
+               goto job_unlock;
+       }
        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);
@@ -521,20 +527,47 @@ job_unlock:
 
 static void mxc_jpeg_config_dec_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;
+       dma_addr_t cfg_stream_handle = jpeg->slot_data[slot].cfg_stream_handle;
+       unsigned int cfg_stream_size = jpeg->slot_data[slot].cfg_stream_size;
 
+       if (ctx->dht_needed) {
+               /*
+                * use the config descriptor to inject a default huffman table
+                * by chaining it before the decoding descriptor
+                */
+               cfg_desc->next_descpt_ptr = desc_handle | MXC_NXT_DESCPT_EN;
+               cfg_desc->buf_base0 = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
+               cfg_desc->buf_base1 = 0;
+               cfg_desc->imgsize = MXC_JPEG_MIN_WIDTH << 16;
+               cfg_desc->imgsize |= MXC_JPEG_MIN_HEIGHT;
+               cfg_desc->line_pitch = MXC_JPEG_MIN_WIDTH * 2;
+               cfg_desc->stm_ctrl = STM_CTRL_IMAGE_FORMAT(MXC_JPEG_YUV422);
+               cfg_desc->stm_bufbase = cfg_stream_handle;
+               cfg_desc->stm_bufsize = mxc_jpeg_align(cfg_stream_size, 1024);
+               print_descriptor_info(jpeg->dev, cfg_desc);
+       }
+
+       desc->next_descpt_ptr = 0; /* end of chain */
        mxc_jpeg_addrs(desc, dst_buf, src_buf, 0);
        mxc_jpeg_set_bufsize(desc,
                        mxc_jpeg_align(vb2_plane_size(src_buf, 0), 1024));
        print_descriptor_info(jpeg->dev, desc);
-
-       /* validate the decoding descriptor */
-       mxc_jpeg_set_desc(desc_handle, reg, slot);
+       if (ctx->dht_needed) {
+               /* validate the configuration descriptor */
+               mxc_jpeg_set_desc(cfg_desc_handle, reg, slot);
+       } else {
+               /* validate the decoding descriptor */
+               mxc_jpeg_set_desc(desc_handle, reg, slot);
+       }
 }
 
 static int mxc_jpeg_fixup_sof(struct mxc_jpeg_sof *sof,
@@ -614,11 +647,11 @@ static int mxc_jpeg_fixup_sos(struct mxc_jpeg_sos *sos,
        return sos_length; /* not swaped */
 }
 
-static void mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr,
-                                     u32 fourcc,
-                                     u16 w, u16 h)
+static unsigned int mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr,
+                                             u32 fourcc,
+                                             u16 w, u16 h)
 {
-       int offset = 0;
+       unsigned int offset = 0;
        u8 *cfg = (u8 *)cfg_stream_vaddr;
        struct mxc_jpeg_sof *sof;
        struct mxc_jpeg_sos *sos;
@@ -656,6 +689,8 @@ static void mxc_jpeg_setup_cfg_stream(void *cfg_stream_vaddr,
 
        memcpy(cfg + offset, jpeg_eoi, sizeof(jpeg_eoi));
        offset += sizeof(jpeg_eoi);
+
+       return offset;
 }
 
 static void mxc_jpeg_config_enc_desc(struct vb2_buffer *out_buf,
@@ -729,6 +764,10 @@ static void mxc_jpeg_device_run(void *priv)
                goto end;
        }
 
+       /*
+        * TODO: this reset should be removed, once we figure out
+        * how to overcome hardware issues both on encoder and decoder
+        */
        mxc_jpeg_sw_reset(reg);
        mxc_jpeg_enable(reg);
        mxc_jpeg_set_l_endian(reg, 1);
@@ -745,7 +784,7 @@ static void mxc_jpeg_device_run(void *priv)
        } else {
                dev_dbg(dev, "Decoding on slot %d\n", slot);
                print_nbuf_to_eoi(dev, src_buf, 0);
-               mxc_jpeg_config_dec_desc(dst_buf, slot, jpeg, src_buf, dst_buf);
+               mxc_jpeg_config_dec_desc(dst_buf, slot, ctx, src_buf, dst_buf);
                mxc_jpeg_dec_mode_go(dev, reg);
        }
 end:
@@ -1059,6 +1098,7 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
        stream.addr = src_addr;
        stream.end = size;
        stream.loc = 0;
+       ctx->dht_needed = true;
        while (notfound) {
                byte = get_byte(&stream);
                if (byte == -1)
@@ -1073,6 +1113,10 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
                if (byte == 0)
                        continue;
                switch (byte) {
+               case DHT:
+                       /* DHT marker present, no need to inject default one */
+                       ctx->dht_needed = false;
+                       break;
                case SOF2: /* Progressive DCF frame definition */
                        dev_err(dev,
                                "Progressive JPEG isn't supported by hardware");
@@ -1112,11 +1156,18 @@ static int mxc_jpeg_parse(struct mxc_jpeg_ctx *ctx,
                        sof.width, sof.height);
                return -EINVAL;
        }
-       if (sof.width > 0x2000 || sof.height > 0x2000) {
+       if (sof.width > MXC_JPEG_MAX_WIDTH ||
+           sof.height > MXC_JPEG_MAX_HEIGHT) {
                dev_err(dev, "JPEG width or height should be <= 8192: %dx%d\n",
                        sof.width, sof.height);
                return -EINVAL;
        }
+       if (sof.width < MXC_JPEG_MIN_WIDTH ||
+           sof.height < MXC_JPEG_MIN_HEIGHT) {
+               dev_err(dev, "JPEG width or height should be > 64: %dx%d\n",
+                       sof.width, sof.height);
+               return -EINVAL;
+       }
        if (sof.components_no > MXC_JPEG_MAX_COMPONENTS) {
                dev_err(dev, "JPEG number of components should be <=%d",
                        MXC_JPEG_MAX_COMPONENTS);
@@ -1651,6 +1702,17 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
                                      MXC_JPEG_MAX_HEIGHT,
                                      q_data->fmt->v_align,
                                      0);
+               /*
+                * the config stream contains a huffman table, use it
+                * to inject a default huffman table for decoder
+                */
+               if (q_data->fmt->flags == MXC_JPEG_FMT_TYPE_ENC) {
+                       jpeg->slot_data[ctx->slot].cfg_stream_size =
+                       mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr,
+                                                 V4L2_PIX_FMT_YUYV,
+                                                 MXC_JPEG_MIN_WIDTH,
+                                                 MXC_JPEG_MIN_HEIGHT);
+               }
        } else {
                /*
                 * align down the resolution for CAST IP,
@@ -1666,6 +1728,7 @@ static int mxc_jpeg_s_fmt(struct mxc_jpeg_ctx *ctx,
                                      q_data->fmt->v_align,
                                      0);
                if (q_data->fmt->flags == MXC_JPEG_FMT_TYPE_RAW)
+                       jpeg->slot_data[ctx->slot].cfg_stream_size =
                        mxc_jpeg_setup_cfg_stream(cfg_stream_vaddr,
                                                  q_data->fmt->fourcc,
                                                  q_data->w_adjusted,
index e01f6ec..8bfc62e 100644 (file)
@@ -25,8 +25,8 @@
 #define MXC_JPEG_RUNNING               1
 #define MXC_JPEG_FMT_TYPE_ENC          0
 #define MXC_JPEG_FMT_TYPE_RAW          1
-#define MXC_JPEG_MIN_HEIGHT            0x8
-#define MXC_JPEG_MIN_WIDTH             0x8
+#define MXC_JPEG_MIN_HEIGHT            64
+#define MXC_JPEG_MIN_WIDTH             64
 #define MXC_JPEG_MAX_HEIGHT            0x2000
 #define MXC_JPEG_MAX_WIDTH             0x2000
 #define MXC_JPEG_MAX_CFG_STREAM                0x1000
@@ -39,6 +39,7 @@
 #define SOF1                           0xC1
 #define SOF2                           0xC2
 #define SOS                            0xDA
+#define DHT                            0xC4
 #define MXC_JPEG_ENC_CONF_DONE         1
 #define MXC_JPEG_MAX_PLANES            2
 
@@ -96,6 +97,7 @@ struct mxc_jpeg_ctx {
        unsigned int                    enc_state;
        unsigned int                    aborting;
        unsigned int                    stopping;
+       unsigned int                    dht_needed;
        unsigned int                    slot;
 };
 
@@ -104,6 +106,7 @@ struct mxc_jpeg_slot_data {
        struct mxc_jpeg_desc *desc; // enc/dec descriptor
        struct mxc_jpeg_desc *cfg_desc; // configuration descriptor
        void *cfg_stream_vaddr; // configuration bitstream virtual address
+       unsigned int cfg_stream_size;
        int flags;
        dma_addr_t desc_handle;
        dma_addr_t cfg_desc_handle; // configuration descriptor dma address