162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * i.MX8QXP/i.MX8QM JPEG encoder/decoder v4l2 driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright 2018-2019 NXP
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/delay.h>
962306a36Sopenharmony_ci#include <media/videobuf2-core.h>
1062306a36Sopenharmony_ci#include "mxc-jpeg-hw.h"
1162306a36Sopenharmony_ci
1262306a36Sopenharmony_ci#define print_wrapper_reg(dev, base_address, reg_offset)\
1362306a36Sopenharmony_ci		internal_print_wrapper_reg(dev, (base_address), #reg_offset,\
1462306a36Sopenharmony_ci					   (reg_offset))
1562306a36Sopenharmony_ci#define internal_print_wrapper_reg(dev, base_address, reg_name, reg_offset) {\
1662306a36Sopenharmony_ci		int val;\
1762306a36Sopenharmony_ci		val = readl((base_address) + (reg_offset));\
1862306a36Sopenharmony_ci		dev_dbg(dev, "Wrapper reg %s = 0x%x\n", reg_name, val);\
1962306a36Sopenharmony_ci}
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_civoid print_descriptor_info(struct device *dev, struct mxc_jpeg_desc *desc)
2262306a36Sopenharmony_ci{
2362306a36Sopenharmony_ci	dev_dbg(dev, " MXC JPEG NEXT_DESCPT_PTR 0x%x\n",
2462306a36Sopenharmony_ci		desc->next_descpt_ptr);
2562306a36Sopenharmony_ci	dev_dbg(dev, " MXC JPEG BUF_BASE0 0x%x\n", desc->buf_base0);
2662306a36Sopenharmony_ci	dev_dbg(dev, " MXC JPEG BUF_BASE1 0x%x\n", desc->buf_base1);
2762306a36Sopenharmony_ci	dev_dbg(dev, " MXC JPEG LINE_PITCH %d\n", desc->line_pitch);
2862306a36Sopenharmony_ci	dev_dbg(dev, " MXC JPEG STM_BUFBASE 0x%x\n", desc->stm_bufbase);
2962306a36Sopenharmony_ci	dev_dbg(dev, " MXC JPEG STM_BUFSIZE %d\n", desc->stm_bufsize);
3062306a36Sopenharmony_ci	dev_dbg(dev, " MXC JPEG IMGSIZE %x (%d x %d)\n", desc->imgsize,
3162306a36Sopenharmony_ci		desc->imgsize >> 16, desc->imgsize & 0xFFFF);
3262306a36Sopenharmony_ci	dev_dbg(dev, " MXC JPEG STM_CTRL 0x%x\n", desc->stm_ctrl);
3362306a36Sopenharmony_ci}
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_civoid print_cast_status(struct device *dev, void __iomem *reg,
3662306a36Sopenharmony_ci		       unsigned int mode)
3762306a36Sopenharmony_ci{
3862306a36Sopenharmony_ci	dev_dbg(dev, "CAST IP status regs:\n");
3962306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS0);
4062306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS1);
4162306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS2);
4262306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS3);
4362306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS4);
4462306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS5);
4562306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS6);
4662306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS7);
4762306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS8);
4862306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS9);
4962306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS10);
5062306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS11);
5162306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS12);
5262306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS13);
5362306a36Sopenharmony_ci	if (mode == MXC_JPEG_DECODE)
5462306a36Sopenharmony_ci		return;
5562306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS14);
5662306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS15);
5762306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS16);
5862306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS17);
5962306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS18);
6062306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, CAST_STATUS19);
6162306a36Sopenharmony_ci}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_civoid print_wrapper_info(struct device *dev, void __iomem *reg)
6462306a36Sopenharmony_ci{
6562306a36Sopenharmony_ci	dev_dbg(dev, "Wrapper regs:\n");
6662306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, GLB_CTRL);
6762306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, COM_STATUS);
6862306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, BUF_BASE0);
6962306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, BUF_BASE1);
7062306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, LINE_PITCH);
7162306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, STM_BUFBASE);
7262306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, STM_BUFSIZE);
7362306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, IMGSIZE);
7462306a36Sopenharmony_ci	print_wrapper_reg(dev, reg, STM_CTRL);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_civoid mxc_jpeg_enable_irq(void __iomem *reg, int slot)
7862306a36Sopenharmony_ci{
7962306a36Sopenharmony_ci	writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS));
8062306a36Sopenharmony_ci	writel(0xF0C, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN));
8162306a36Sopenharmony_ci}
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_civoid mxc_jpeg_disable_irq(void __iomem *reg, int slot)
8462306a36Sopenharmony_ci{
8562306a36Sopenharmony_ci	writel(0x0, reg + MXC_SLOT_OFFSET(slot, SLOT_IRQ_EN));
8662306a36Sopenharmony_ci	writel(0xFFFFFFFF, reg + MXC_SLOT_OFFSET(slot, SLOT_STATUS));
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_civoid mxc_jpeg_sw_reset(void __iomem *reg)
9062306a36Sopenharmony_ci{
9162306a36Sopenharmony_ci	/*
9262306a36Sopenharmony_ci	 * engine soft reset, internal state machine reset
9362306a36Sopenharmony_ci	 * this will not reset registers, however, it seems
9462306a36Sopenharmony_ci	 * the registers may remain inconsistent with the internal state
9562306a36Sopenharmony_ci	 * so, on purpose, at least let GLB_CTRL bits clear after this reset
9662306a36Sopenharmony_ci	 */
9762306a36Sopenharmony_ci	writel(GLB_CTRL_SFT_RST, reg + GLB_CTRL);
9862306a36Sopenharmony_ci}
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_civoid mxc_jpeg_enc_mode_conf(struct device *dev, void __iomem *reg, u8 extseq)
10162306a36Sopenharmony_ci{
10262306a36Sopenharmony_ci	dev_dbg(dev, "CAST Encoder CONFIG...\n");
10362306a36Sopenharmony_ci	/*
10462306a36Sopenharmony_ci	 * "Config_Mode" enabled, "Config_Mode auto clear enabled",
10562306a36Sopenharmony_ci	 */
10662306a36Sopenharmony_ci	if (extseq)
10762306a36Sopenharmony_ci		writel(0xb0, reg + CAST_MODE);
10862306a36Sopenharmony_ci	else
10962306a36Sopenharmony_ci		writel(0xa0, reg + CAST_MODE);
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	/* all markers and segments */
11262306a36Sopenharmony_ci	writel(0x3ff, reg + CAST_CFG_MODE);
11362306a36Sopenharmony_ci}
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_civoid mxc_jpeg_enc_mode_go(struct device *dev, void __iomem *reg, u8 extseq)
11662306a36Sopenharmony_ci{
11762306a36Sopenharmony_ci	dev_dbg(dev, "CAST Encoder GO...\n");
11862306a36Sopenharmony_ci	/*
11962306a36Sopenharmony_ci	 * "GO" enabled, "GO bit auto clear" enabled
12062306a36Sopenharmony_ci	 */
12162306a36Sopenharmony_ci	if (extseq)
12262306a36Sopenharmony_ci		writel(0x150, reg + CAST_MODE);
12362306a36Sopenharmony_ci	else
12462306a36Sopenharmony_ci		writel(0x140, reg + CAST_MODE);
12562306a36Sopenharmony_ci}
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_civoid mxc_jpeg_enc_set_quality(struct device *dev, void __iomem *reg, u8 quality)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	dev_dbg(dev, "CAST Encoder Quality %d...\n", quality);
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	/* quality factor */
13262306a36Sopenharmony_ci	writel(quality, reg + CAST_QUALITY);
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_civoid mxc_jpeg_dec_mode_go(struct device *dev, void __iomem *reg)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	dev_dbg(dev, "CAST Decoder GO...\n");
13862306a36Sopenharmony_ci	writel(MXC_DEC_EXIT_IDLE_MODE, reg + CAST_CTRL);
13962306a36Sopenharmony_ci}
14062306a36Sopenharmony_ci
14162306a36Sopenharmony_ciint mxc_jpeg_enable(void __iomem *reg)
14262306a36Sopenharmony_ci{
14362306a36Sopenharmony_ci	u32 regval;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	writel(GLB_CTRL_JPG_EN, reg + GLB_CTRL);
14662306a36Sopenharmony_ci	regval = readl(reg);
14762306a36Sopenharmony_ci	return regval;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_civoid mxc_jpeg_enable_slot(void __iomem *reg, int slot)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	u32 regval;
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ci	regval = readl(reg + GLB_CTRL);
15562306a36Sopenharmony_ci	writel(GLB_CTRL_SLOT_EN(slot) | regval, reg + GLB_CTRL);
15662306a36Sopenharmony_ci}
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_civoid mxc_jpeg_set_l_endian(void __iomem *reg, int le)
15962306a36Sopenharmony_ci{
16062306a36Sopenharmony_ci	u32 regval;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	regval = readl(reg + GLB_CTRL);
16362306a36Sopenharmony_ci	regval &= ~GLB_CTRL_L_ENDIAN(1); /* clear */
16462306a36Sopenharmony_ci	writel(GLB_CTRL_L_ENDIAN(le) | regval, reg + GLB_CTRL); /* set */
16562306a36Sopenharmony_ci}
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_civoid mxc_jpeg_set_bufsize(struct mxc_jpeg_desc *desc,  u32 bufsize)
16862306a36Sopenharmony_ci{
16962306a36Sopenharmony_ci	desc->stm_bufsize = bufsize;
17062306a36Sopenharmony_ci}
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_civoid mxc_jpeg_set_res(struct mxc_jpeg_desc *desc, u16 w, u16 h)
17362306a36Sopenharmony_ci{
17462306a36Sopenharmony_ci	desc->imgsize = w << 16 | h;
17562306a36Sopenharmony_ci}
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_civoid mxc_jpeg_set_line_pitch(struct mxc_jpeg_desc *desc, u32 line_pitch)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	desc->line_pitch = line_pitch;
18062306a36Sopenharmony_ci}
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_civoid mxc_jpeg_set_desc(u32 desc, void __iomem *reg, int slot)
18362306a36Sopenharmony_ci{
18462306a36Sopenharmony_ci	writel(desc | MXC_NXT_DESCPT_EN,
18562306a36Sopenharmony_ci	       reg + MXC_SLOT_OFFSET(slot, SLOT_NXT_DESCPT_PTR));
18662306a36Sopenharmony_ci}
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_civoid mxc_jpeg_clr_desc(void __iomem *reg, int slot)
18962306a36Sopenharmony_ci{
19062306a36Sopenharmony_ci	writel(0, reg + MXC_SLOT_OFFSET(slot, SLOT_NXT_DESCPT_PTR));
19162306a36Sopenharmony_ci}
192