summaryrefslogtreecommitdiff
path: root/drivers/media/platform/imx8/mxc-jpeg-hw.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/platform/imx8/mxc-jpeg-hw.c')
-rw-r--r--drivers/media/platform/imx8/mxc-jpeg-hw.c244
1 files changed, 244 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..2263ec426790
--- /dev/null
+++ b/drivers/media/platform/imx8/mxc-jpeg-hw.c
@@ -0,0 +1,244 @@
+/*
+ * Copyright 2018 NXP
+ */
+/*
+ * The code contained herein is licensed under the GNU General Public
+ * License. You may obtain a copy of the GNU General Public License
+ * Version 2 or later at the following locations:
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#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_go_enc(struct device *dev, void __iomem *reg)
+{
+ dev_dbg(dev, "CAST Encoder GO...\n");
+ /*
+ * "Config_Mode" enabled, "Config_Mode auto clear enabled",
+ * "GO" enabled, "GO bit auto clear" enabled
+ */
+ writel(0x1e0, reg + CAST_MODE);
+
+ /* all markers and segments */
+ writel(0x3ff, reg + CAST_CFG_MODE);
+
+ /* quality factor */
+ writel(0x4b, reg + CAST_QUALITY);
+}
+
+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_go_dec(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);
+}