diff options
Diffstat (limited to 'drivers/media/platform/imx8/mxc-jpeg-hw.c')
-rw-r--r-- | drivers/media/platform/imx8/mxc-jpeg-hw.c | 248 |
1 files changed, 248 insertions, 0 deletions
diff --git a/drivers/media/platform/imx8/mxc-jpeg-hw.c b/drivers/media/platform/imx8/mxc-jpeg-hw.c new file mode 100644 index 000000000000..6ff1bf792be4 --- /dev/null +++ b/drivers/media/platform/imx8/mxc-jpeg-hw.c @@ -0,0 +1,248 @@ +// 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); +} + +u32 mxc_jpeg_get_offset(void __iomem *reg, int slot) +{ + return readl(reg + MXC_SLOT_OFFSET(slot, SLOT_BUF_PTR)); +} + +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 wait_frmdone(struct device *dev, void __iomem *reg) +{ + u32 regval = 0; + + do { + regval = readl(reg + MXC_SLOT_OFFSET(0, SLOT_STATUS)); + } while (!(regval & SLOTa_STATUS_FRMDONE)); + + writel(regval, reg + MXC_SLOT_OFFSET(0, SLOT_STATUS)); /* w1c */ + + dev_dbg(dev, "Received FRMDONE\n"); + if (regval & SLOTa_STATUS_ENC_CONFIG_ERR) + dev_info(dev, "SLOTa_STATUS_ENC_CONFIG_ERR\n"); +} + +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_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_get_slot(void __iomem *reg) +{ + int slot_val; + int i = 0; + int tmp = GLB_CTRL_SLOT_EN(0); + + /* currently enabled slots */ + slot_val = readl(reg + GLB_CTRL) & 0xF0; + + for (; tmp != tmp << 4; tmp = tmp << 1) { + if ((slot_val & tmp) == 0) + /* first free slot */ + return i; + ++i; + } + return -EINVAL; +} + +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_config_mode(void __iomem *reg, int config_mode) +{ + u32 regval; + + regval = readl(reg + STM_CTRL); + regval &= ~STM_CTRL_CONFIG_MOD(1); + writel(STM_CTRL_CONFIG_MOD(config_mode) | regval, reg + STM_CTRL); +} + +int mxc_jpeg_set_params(struct mxc_jpeg_desc *desc, u32 bufsize, + u16 out_pitch, u32 format) +{ + desc->line_pitch = out_pitch; + desc->stm_bufsize = bufsize; + switch (format) { + case V4L2_PIX_FMT_YUV32: + desc->stm_ctrl |= MXC_JPEG_YUV444 << 3; + break; + case V4L2_PIX_FMT_YUYV: + desc->stm_ctrl |= MXC_JPEG_YUV422 << 3; + break; + case V4L2_PIX_FMT_RGB32: + desc->stm_ctrl |= MXC_JPEG_RGB << 3; + break; + default: + return -1; + } + return 0; +} + +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)); +} + +void mxc_jpeg_set_regs_from_desc(struct mxc_jpeg_desc *desc, void __iomem *reg) +{ + writel(desc->buf_base0, reg + BUF_BASE0); + writel(desc->buf_base1, reg + BUF_BASE1); + writel(desc->line_pitch, reg + LINE_PITCH); + writel(desc->stm_bufbase, reg + STM_BUFBASE); + writel(desc->stm_bufsize, reg + STM_BUFSIZE); + writel(desc->imgsize, reg + IMGSIZE); + writel(desc->stm_ctrl, reg + STM_CTRL); +} |