Commit 2db16c6e authored by Mirela Rabulea's avatar Mirela Rabulea Committed by Mauro Carvalho Chehab

media: imx-jpeg: Add V4L2 driver for i.MX8 JPEG Encoder/Decoder

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: default avatarMirela Rabulea <mirela.rabulea@nxp.com>
Signed-off-by: default avatarHans Verkuil <hverkuil-cisco@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab+huawei@kernel.org>
parent 819f3ea5
......@@ -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
......
......@@ -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
......
# 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.
# 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
// 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));
}
/* 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
This diff is collapsed.
/* SPDX-License-Identifier: GPL-2.0 */
/*
* i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver
*
* Copyright 2018-2019 NXP
*/
#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#ifndef _MXC_JPEG_CORE_H
#define _MXC_JPEG_CORE_H
#define MXC_JPEG_NAME "mxc-jpeg"
#define MXC_JPEG_FMT_TYPE_ENC 0
#define MXC_JPEG_FMT_TYPE_RAW 1
#define MXC_JPEG_DEFAULT_WIDTH 1280
#define MXC_JPEG_DEFAULT_HEIGHT 720
#define MXC_JPEG_DEFAULT_PFMT V4L2_PIX_FMT_RGB24
#define MXC_JPEG_MIN_WIDTH 64
#define MXC_JPEG_MIN_HEIGHT 64
#define MXC_JPEG_MAX_WIDTH 0x2000
#define MXC_JPEG_MAX_HEIGHT 0x2000
#define MXC_JPEG_MAX_CFG_STREAM 0x1000
#define MXC_JPEG_H_ALIGN 3
#define MXC_JPEG_W_ALIGN 3
#define MXC_JPEG_MAX_SIZEIMAGE 0xFFFFFC00
#define MXC_JPEG_MAX_PLANES 2
enum mxc_jpeg_enc_state {
MXC_JPEG_ENCODING = 0, /* jpeg encode phase */
MXC_JPEG_ENC_CONF = 1, /* jpeg encoder config phase */
};
enum mxc_jpeg_mode {
MXC_JPEG_DECODE = 0, /* jpeg decode mode */
MXC_JPEG_ENCODE = 1, /* jpeg encode mode */
};
/**
* struct mxc_jpeg_fmt - driver's internal color format data
* @name: format description
* @fourcc: fourcc code, 0 if not applicable
* @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)
* @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
*/
struct mxc_jpeg_fmt {
char *name;
u32 fourcc;
enum v4l2_jpeg_chroma_subsampling subsampling;
int nc;
int depth;
int colplanes;
int h_align;
int v_align;
u32 flags;
};
struct mxc_jpeg_desc {
u32 next_descpt_ptr;
u32 buf_base0;
u32 buf_base1;
u32 line_pitch;
u32 stm_bufbase;
u32 stm_bufsize;
u32 imgsize;
u32 stm_ctrl;
} __packed;
struct mxc_jpeg_q_data {
struct mxc_jpeg_fmt *fmt;
u32 sizeimage[MXC_JPEG_MAX_PLANES];
u32 bytesperline[MXC_JPEG_MAX_PLANES];
int w;
int w_adjusted;
int h;
int h_adjusted;
unsigned int sequence;
};
struct mxc_jpeg_ctx {
struct mxc_jpeg_dev *mxc_jpeg;
struct mxc_jpeg_q_data out_q;
struct mxc_jpeg_q_data cap_q;
struct v4l2_fh fh;
enum mxc_jpeg_enc_state enc_state;
unsigned int stopping;
unsigned int slot;
};
struct mxc_jpeg_slot_data {
bool used;
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;
dma_addr_t desc_handle;
dma_addr_t cfg_desc_handle; // configuration descriptor dma address
dma_addr_t cfg_stream_handle; // configuration bitstream dma address
};
struct mxc_jpeg_dev {
spinlock_t hw_lock; /* hardware access lock */
unsigned int mode;
struct mutex lock; /* v4l2 ioctls serialization */
struct platform_device *pdev;
struct device *dev;
void __iomem *base_reg;
struct v4l2_device v4l2_dev;
struct v4l2_m2m_dev *m2m_dev;
struct video_device *dec_vdev;
struct mxc_jpeg_slot_data slot_data[MXC_MAX_SLOTS];
int num_domains;
struct device **pd_dev;
struct device_link **pd_link;
};
/**
* struct mxc_jpeg_sof_comp - JPEG Start Of Frame component fields
* @id: component id
* @v: vertical sampling
* @h: horizontal sampling
* @quantization_table_no: id of quantization table
*/
struct mxc_jpeg_sof_comp {
u8 id;
u8 v :4;
u8 h :4;
u8 quantization_table_no;
} __packed;
#define MXC_JPEG_MAX_COMPONENTS 4
/**
* struct mxc_jpeg_sof - JPEG Start Of Frame marker fields
* @length: Start of Frame length
* @precision: precision (bits per pixel per color component)
* @height: image height
* @width: image width
* @components_no: number of color components
* @comp: component fields for each color component
*/
struct mxc_jpeg_sof {
u16 length;
u8 precision;
u16 height, width;
u8 components_no;
struct mxc_jpeg_sof_comp comp[MXC_JPEG_MAX_COMPONENTS];
} __packed;
/**
* struct mxc_jpeg_sos_comp - JPEG Start Of Scan component fields
* @id: component id
* @huffman_table_no: id of the Huffman table
*/
struct mxc_jpeg_sos_comp {
u8 id; /*component id*/
u8 huffman_table_no;
} __packed;
/**
* struct mxc_jpeg_sos - JPEG Start Of Scan marker fields
* @length: Start of Frame length
* @components_no: number of color components
* @comp: SOS component fields for each color component
* @ignorable_bytes: ignorable bytes
*/
struct mxc_jpeg_sos {
u16 length;
u8 components_no;
struct mxc_jpeg_sos_comp comp[MXC_JPEG_MAX_COMPONENTS];
u8 ignorable_bytes[3];
} __packed;
#endif
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment