forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 407
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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: Mirela Rabulea <[email protected]> Signed-off-by: Hans Verkuil <[email protected]> Signed-off-by: Mauro Carvalho Chehab <[email protected]>
- Loading branch information
Showing
8 changed files
with
2,630 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.