Skip to content

Commit

Permalink
media: imx-jpeg: Add V4L2 driver for i.MX8 JPEG Encoder/Decoder
Browse files Browse the repository at this point in the history
V4L2 driver for the JPEG encoder/decoder from i.MX8QXP/i.MX8QM application
processors.
The multi-planar buffers API is used.

Baseline and extended sequential jpeg decoding is supported.
Progressive jpeg decoding is not supported by the IP.
Supports encode and decode of various formats:
     YUV444, YUV422, YUV420, RGB, ARGB, Gray
YUV420 is the only multi-planar format supported.
Minimum resolution is 64 x 64, maximum 8192 x 8192.
The alignment requirements for the resolution depend on the format,
multiple of 16 resolutions should work for all formats.

v4l2-compliance tests are passing, including the
streaming tests, "v4l2-compliance -s"

[hverkuil: fix kernel-doc typos]

Signed-off-by: Mirela Rabulea <[email protected]>
Signed-off-by: Hans Verkuil <[email protected]>
Signed-off-by: Mauro Carvalho Chehab <[email protected]>
  • Loading branch information
mrabule1 authored and mchehab committed Mar 22, 2021
1 parent 819f3ea commit 2db16c6
Show file tree
Hide file tree
Showing 8 changed files with 2,630 additions and 0 deletions.
2 changes: 2 additions & 0 deletions drivers/media/platform/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,8 @@ config VIDEO_IMX_PXP
The i.MX Pixel Pipeline is a memory-to-memory engine for scaling,
color space conversion, and rotation.

source "drivers/media/platform/imx-jpeg/Kconfig"

config VIDEO_MEDIATEK_JPEG
tristate "Mediatek JPEG Codec driver"
depends on MTK_IOMMU_V1 || MTK_IOMMU || COMPILE_TEST
Expand Down
1 change: 1 addition & 0 deletions drivers/media/platform/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ obj-$(CONFIG_VIDEO_MX2_EMMAPRP) += mx2_emmaprp.o
obj-$(CONFIG_VIDEO_CODA) += coda/

obj-$(CONFIG_VIDEO_IMX_PXP) += imx-pxp.o
obj-$(CONFIG_VIDEO_IMX8_JPEG) += imx-jpeg/

obj-$(CONFIG_VIDEO_MEM2MEM_DEINTERLACE) += m2m-deinterlace.o

Expand Down
11 changes: 11 additions & 0 deletions drivers/media/platform/imx-jpeg/Kconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# SPDX-License-Identifier: GPL-2.0
config VIDEO_IMX8_JPEG
tristate "IMX8 JPEG Encoder/Decoder"
depends on VIDEO_DEV && VIDEO_V4L2
select VIDEOBUF2_DMA_CONTIG
select V4L2_MEM2MEM_DEV
select V4L2_JPEG_HELPER
default m
help
This is a video4linux2 driver for the i.MX8 QXP/QM integrated
JPEG encoder/decoder.
3 changes: 3 additions & 0 deletions drivers/media/platform/imx-jpeg/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# SPDX-License-Identifier: GPL-2.0
mxc-jpeg-encdec-objs := mxc-jpeg-hw.o mxc-jpeg.o
obj-$(CONFIG_VIDEO_IMX8_JPEG) += mxc-jpeg-encdec.o
168 changes: 168 additions & 0 deletions drivers/media/platform/imx-jpeg/mxc-jpeg-hw.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
// SPDX-License-Identifier: GPL-2.0
/*
* i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver
*
* Copyright 2018-2019 NXP
*/

#include <linux/delay.h>
#include <media/videobuf2-core.h>
#include "mxc-jpeg-hw.h"

#define print_wrapper_reg(dev, base_address, reg_offset)\
internal_print_wrapper_reg(dev, (base_address), #reg_offset,\
(reg_offset))
#define internal_print_wrapper_reg(dev, base_address, reg_name, reg_offset) {\
int val;\
val = readl((base_address) + (reg_offset));\
dev_dbg(dev, "Wrapper reg %s = 0x%x\n", reg_name, val);\
}

void print_descriptor_info(struct device *dev, struct mxc_jpeg_desc *desc)
{
dev_dbg(dev, " MXC JPEG NEXT_DESCPT_PTR 0x%x\n",
desc->next_descpt_ptr);
dev_dbg(dev, " MXC JPEG BUF_BASE0 0x%x\n", desc->buf_base0);
dev_dbg(dev, " MXC JPEG BUF_BASE1 0x%x\n", desc->buf_base1);
dev_dbg(dev, " MXC JPEG LINE_PITCH %d\n", desc->line_pitch);
dev_dbg(dev, " MXC JPEG STM_BUFBASE 0x%x\n", desc->stm_bufbase);
dev_dbg(dev, " MXC JPEG STM_BUFSIZE %d\n", desc->stm_bufsize);
dev_dbg(dev, " MXC JPEG IMGSIZE %x (%d x %d)\n", desc->imgsize,
desc->imgsize >> 16, desc->imgsize & 0xFFFF);
dev_dbg(dev, " MXC JPEG STM_CTRL 0x%x\n", desc->stm_ctrl);
}

void print_cast_status(struct device *dev, void __iomem *reg,
unsigned int mode)
{
dev_dbg(dev, "CAST IP status regs:\n");
print_wrapper_reg(dev, reg, CAST_STATUS0);
print_wrapper_reg(dev, reg, CAST_STATUS1);
print_wrapper_reg(dev, reg, CAST_STATUS2);
print_wrapper_reg(dev, reg, CAST_STATUS3);
print_wrapper_reg(dev, reg, CAST_STATUS4);
print_wrapper_reg(dev, reg, CAST_STATUS5);
print_wrapper_reg(dev, reg, CAST_STATUS6);
print_wrapper_reg(dev, reg, CAST_STATUS7);
print_wrapper_reg(dev, reg, CAST_STATUS8);
print_wrapper_reg(dev, reg, CAST_STATUS9);
print_wrapper_reg(dev, reg, CAST_STATUS10);
print_wrapper_reg(dev, reg, CAST_STATUS11);
print_wrapper_reg(dev, reg, CAST_STATUS12);
print_wrapper_reg(dev, reg, CAST_STATUS13);
if (mode == MXC_JPEG_DECODE)
return;
print_wrapper_reg(dev, reg, CAST_STATUS14);
print_wrapper_reg(dev, reg, CAST_STATUS15);
print_wrapper_reg(dev, reg, CAST_STATUS16);
print_wrapper_reg(dev, reg, CAST_STATUS17);
print_wrapper_reg(dev, reg, CAST_STATUS18);
print_wrapper_reg(dev, reg, CAST_STATUS19);
}

void print_wrapper_info(struct device *dev, void __iomem *reg)
{
dev_dbg(dev, "Wrapper regs:\n");
print_wrapper_reg(dev, reg, GLB_CTRL);
print_wrapper_reg(dev, reg, COM_STATUS);
print_wrapper_reg(dev, reg, BUF_BASE0);
print_wrapper_reg(dev, reg, BUF_BASE1);
print_wrapper_reg(dev, reg, LINE_PITCH);
print_wrapper_reg(dev, reg, STM_BUFBASE);
print_wrapper_reg(dev, reg, STM_BUFSIZE);
print_wrapper_reg(dev, reg, IMGSIZE);
print_wrapper_reg(dev, reg, STM_CTRL);
}

void mxc_jpeg_enable_irq(void __iomem *reg, int slot)
{
writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN));
}

void mxc_jpeg_sw_reset(void __iomem *reg)
{
/*
* engine soft reset, internal state machine reset
* this will not reset registers, however, it seems
* the registers may remain inconsistent with the internal state
* so, on purpose, at least let GLB_CTRL bits clear after this reset
*/
writel(GLB_CTRL_SFT_RST, reg + GLB_CTRL);
}

void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg)
{
dev_dbg(dev, "CAST Encoder CONFIG...\n");
/*
* "Config_Mode" enabled, "Config_Mode auto clear enabled",
*/
writel(0xa0, reg + CAST_MODE);

/* all markers and segments */
writel(0x3ff, reg + CAST_CFG_MODE);

/* quality factor */
writel(0x4b, reg + CAST_QUALITY);
}

void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg)
{
dev_dbg(dev, "CAST Encoder GO...\n");
/*
* "GO" enabled, "GO bit auto clear" enabled
*/
writel(0x140, reg + CAST_MODE);
}

void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg)
{
dev_dbg(dev, "CAST Decoder GO...\n");
writel(MXC_DEC_EXIT_IDLE_MODE, reg + CAST_CTRL);
}

int mxc_jpeg_enable(void __iomem *reg)
{
u32 regval;

writel(GLB_CTRL_JPG_EN, reg + GLB_CTRL);
regval = readl(reg);
return regval;
}

void mxc_jpeg_enable_slot(void __iomem *reg, int slot)
{
u32 regval;

regval = readl(reg + GLB_CTRL);
writel(GLB_CTRL_SLOT_EN(slot) | regval, reg + GLB_CTRL);
}

void mxc_jpeg_set_l_endian(void __iomem *reg, int le)
{
u32 regval;

regval = readl(reg + GLB_CTRL);
regval &= ~GLB_CTRL_L_ENDIAN(1); /* clear */
writel(GLB_CTRL_L_ENDIAN(le) | regval, reg + GLB_CTRL); /* set */
}

void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc, u32 bufsize)
{
desc->stm_bufsize = bufsize;
}

void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h)
{
desc->imgsize = w << 16 | h;
}

void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch)
{
desc->line_pitch = line_pitch;
}

void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot)
{
writel(desc | MXC_NXT_DESCPT_EN,
reg + MXC_SLOT_OFFSET(slot, SLOT_NXT_DESCPT_PTR));
}
140 changes: 140 additions & 0 deletions drivers/media/platform/imx-jpeg/mxc-jpeg-hw.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/* SPDX-License-Identifier: GPL-2.0 */
/*
* i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver
*
* Copyright 2018-2019 NXP
*/

#ifndef _MXC_JPEG_HW_H
#define _MXC_JPEG_HW_H

/* JPEG Decoder/Encoder Wrapper Register Map */
#define GLB_CTRL 0x0
#define COM_STATUS 0x4
#define BUF_BASE0 0x14
#define BUF_BASE1 0x18
#define LINE_PITCH 0x1C
#define STM_BUFBASE 0x20
#define STM_BUFSIZE 0x24
#define IMGSIZE 0x28
#define STM_CTRL 0x2C

/* CAST JPEG-Decoder/Encoder Status Register Map (read-only)*/
#define CAST_STATUS0 0x100
#define CAST_STATUS1 0x104
#define CAST_STATUS2 0x108
#define CAST_STATUS3 0x10c
#define CAST_STATUS4 0x110
#define CAST_STATUS5 0x114
#define CAST_STATUS6 0x118
#define CAST_STATUS7 0x11c
#define CAST_STATUS8 0x120
#define CAST_STATUS9 0x124
#define CAST_STATUS10 0x128
#define CAST_STATUS11 0x12c
#define CAST_STATUS12 0x130
#define CAST_STATUS13 0x134
/* the following are for encoder only */
#define CAST_STATUS14 0x138
#define CAST_STATUS15 0x13c
#define CAST_STATUS16 0x140
#define CAST_STATUS17 0x144
#define CAST_STATUS18 0x148
#define CAST_STATUS19 0x14c

/* CAST JPEG-Decoder Control Register Map (write-only) */
#define CAST_CTRL CAST_STATUS13

/* CAST JPEG-Encoder Control Register Map (write-only) */
#define CAST_MODE CAST_STATUS0
#define CAST_CFG_MODE CAST_STATUS1
#define CAST_QUALITY CAST_STATUS2
#define CAST_RSVD CAST_STATUS3
#define CAST_REC_REGS_SEL CAST_STATUS4
#define CAST_LUMTH CAST_STATUS5
#define CAST_CHRTH CAST_STATUS6
#define CAST_NOMFRSIZE_LO CAST_STATUS7
#define CAST_NOMFRSIZE_HI CAST_STATUS8
#define CAST_OFBSIZE_LO CAST_STATUS9
#define CAST_OFBSIZE_HI CAST_STATUS10

#define MXC_MAX_SLOTS 1 /* TODO use all 4 slots*/
/* JPEG-Decoder Wrapper Slot Registers 0..3 */
#define SLOT_BASE 0x10000
#define SLOT_STATUS 0x0
#define SLOT_IRQ_EN 0x4
#define SLOT_BUF_PTR 0x8
#define SLOT_CUR_DESCPT_PTR 0xC
#define SLOT_NXT_DESCPT_PTR 0x10
#define MXC_SLOT_OFFSET(slot, offset) ((SLOT_BASE * ((slot) + 1)) + (offset))

/* GLB_CTRL fields */
#define GLB_CTRL_JPG_EN 0x1
#define GLB_CTRL_SFT_RST (0x1 << 1)
#define GLB_CTRL_DEC_GO (0x1 << 2)
#define GLB_CTRL_L_ENDIAN(le) ((le) << 3)
#define GLB_CTRL_SLOT_EN(slot) (0x1 << ((slot) + 4))

/* COM_STAUS fields */
#define COM_STATUS_DEC_ONGOING(r) (((r) & (1 << 31)) >> 31)
#define COM_STATUS_CUR_SLOT(r) (((r) & (0x3 << 29)) >> 29)

/* 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)

/* SLOT_STATUS fields for slots 0..3 */
#define SLOT_STATUS_FRMDONE (0x1 << 3)
#define SLOT_STATUS_ENC_CONFIG_ERR (0x1 << 8)

/* SLOT_IRQ_EN fields TBD */

#define MXC_NXT_DESCPT_EN 0x1
#define MXC_DEC_EXIT_IDLE_MODE 0x4

/* 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 */
MXC_JPEG_YUV444 = 0x3, /* 1 Plannar, YUVYUV sequence */
MXC_JPEG_GRAY = 0x4, /* Y8 or Y12 or Single Component */
MXC_JPEG_RESERVED = 0x5,
MXC_JPEG_ARGB = 0x6,
};

#include "mxc-jpeg.h"
void print_descriptor_info(struct device *dev, struct mxc_jpeg_desc *desc);
void print_cast_status(struct device *dev, void __iomem *reg,
unsigned int mode);
void print_wrapper_info(struct device *dev, void __iomem *reg);
void mxc_jpeg_sw_reset(void __iomem *reg);
int mxc_jpeg_enable(void __iomem *reg);
void wait_frmdone(struct device *dev, void __iomem *reg);
void mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg);
void mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg);
void mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg);
int mxc_jpeg_get_slot(void __iomem *reg);
u32 mxc_jpeg_get_offset(void __iomem *reg, int slot);
void mxc_jpeg_enable_slot(void __iomem *reg, int slot);
void mxc_jpeg_set_l_endian(void __iomem *reg, int le);
void mxc_jpeg_enable_irq(void __iomem *reg, int slot);
int mxc_jpeg_set_input(void __iomem *reg, u32 in_buf, u32 bufsize);
int mxc_jpeg_set_output(void __iomem *reg, u16 out_pitch, u32 out_buf,
u16 w, u16 h);
void mxc_jpeg_set_config_mode(void __iomem *reg, int config_mode);
int mxc_jpeg_set_params(struct mxc_jpeg_desc *desc, u32 bufsize, u16
out_pitch, u32 format);
void mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc, u32 bufsize);
void mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h);
void mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch);
void mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot);
void mxc_jpeg_set_regs_from_desc(struct mxc_jpeg_desc *desc,
void __iomem *reg);
#endif
Loading

0 comments on commit 2db16c6

Please sign in to comment.