162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2019 NXP.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/device.h>
762306a36Sopenharmony_ci#include <linux/slab.h>
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include "dcss-dev.h"
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#define DCSS_DPR_SYSTEM_CTRL0			0x000
1262306a36Sopenharmony_ci#define   RUN_EN				BIT(0)
1362306a36Sopenharmony_ci#define   SOFT_RESET				BIT(1)
1462306a36Sopenharmony_ci#define   REPEAT_EN				BIT(2)
1562306a36Sopenharmony_ci#define   SHADOW_LOAD_EN			BIT(3)
1662306a36Sopenharmony_ci#define   SW_SHADOW_LOAD_SEL			BIT(4)
1762306a36Sopenharmony_ci#define   BCMD2AXI_MSTR_ID_CTRL			BIT(16)
1862306a36Sopenharmony_ci#define DCSS_DPR_IRQ_MASK			0x020
1962306a36Sopenharmony_ci#define DCSS_DPR_IRQ_MASK_STATUS		0x030
2062306a36Sopenharmony_ci#define DCSS_DPR_IRQ_NONMASK_STATUS		0x040
2162306a36Sopenharmony_ci#define   IRQ_DPR_CTRL_DONE			BIT(0)
2262306a36Sopenharmony_ci#define   IRQ_DPR_RUN				BIT(1)
2362306a36Sopenharmony_ci#define   IRQ_DPR_SHADOW_LOADED			BIT(2)
2462306a36Sopenharmony_ci#define   IRQ_AXI_READ_ERR			BIT(3)
2562306a36Sopenharmony_ci#define   DPR2RTR_YRGB_FIFO_OVFL		BIT(4)
2662306a36Sopenharmony_ci#define   DPR2RTR_UV_FIFO_OVFL			BIT(5)
2762306a36Sopenharmony_ci#define   DPR2RTR_FIFO_LD_BUF_RDY_YRGB_ERR	BIT(6)
2862306a36Sopenharmony_ci#define   DPR2RTR_FIFO_LD_BUF_RDY_UV_ERR	BIT(7)
2962306a36Sopenharmony_ci#define DCSS_DPR_MODE_CTRL0			0x050
3062306a36Sopenharmony_ci#define   RTR_3BUF_EN				BIT(0)
3162306a36Sopenharmony_ci#define   RTR_4LINE_BUF_EN			BIT(1)
3262306a36Sopenharmony_ci#define   TILE_TYPE_POS				2
3362306a36Sopenharmony_ci#define   TILE_TYPE_MASK			GENMASK(4, 2)
3462306a36Sopenharmony_ci#define   YUV_EN				BIT(6)
3562306a36Sopenharmony_ci#define   COMP_2PLANE_EN			BIT(7)
3662306a36Sopenharmony_ci#define   PIX_SIZE_POS				8
3762306a36Sopenharmony_ci#define   PIX_SIZE_MASK				GENMASK(9, 8)
3862306a36Sopenharmony_ci#define   PIX_LUMA_UV_SWAP			BIT(10)
3962306a36Sopenharmony_ci#define   PIX_UV_SWAP				BIT(11)
4062306a36Sopenharmony_ci#define   B_COMP_SEL_POS			12
4162306a36Sopenharmony_ci#define   B_COMP_SEL_MASK			GENMASK(13, 12)
4262306a36Sopenharmony_ci#define   G_COMP_SEL_POS			14
4362306a36Sopenharmony_ci#define   G_COMP_SEL_MASK			GENMASK(15, 14)
4462306a36Sopenharmony_ci#define   R_COMP_SEL_POS			16
4562306a36Sopenharmony_ci#define   R_COMP_SEL_MASK			GENMASK(17, 16)
4662306a36Sopenharmony_ci#define   A_COMP_SEL_POS			18
4762306a36Sopenharmony_ci#define   A_COMP_SEL_MASK			GENMASK(19, 18)
4862306a36Sopenharmony_ci#define DCSS_DPR_FRAME_CTRL0			0x070
4962306a36Sopenharmony_ci#define   HFLIP_EN				BIT(0)
5062306a36Sopenharmony_ci#define   VFLIP_EN				BIT(1)
5162306a36Sopenharmony_ci#define   ROT_ENC_POS				2
5262306a36Sopenharmony_ci#define   ROT_ENC_MASK				GENMASK(3, 2)
5362306a36Sopenharmony_ci#define   ROT_FLIP_ORDER_EN			BIT(4)
5462306a36Sopenharmony_ci#define   PITCH_POS				16
5562306a36Sopenharmony_ci#define   PITCH_MASK				GENMASK(31, 16)
5662306a36Sopenharmony_ci#define DCSS_DPR_FRAME_1P_CTRL0			0x090
5762306a36Sopenharmony_ci#define DCSS_DPR_FRAME_1P_PIX_X_CTRL		0x0A0
5862306a36Sopenharmony_ci#define DCSS_DPR_FRAME_1P_PIX_Y_CTRL		0x0B0
5962306a36Sopenharmony_ci#define DCSS_DPR_FRAME_1P_BASE_ADDR		0x0C0
6062306a36Sopenharmony_ci#define DCSS_DPR_FRAME_2P_CTRL0			0x0E0
6162306a36Sopenharmony_ci#define DCSS_DPR_FRAME_2P_PIX_X_CTRL		0x0F0
6262306a36Sopenharmony_ci#define DCSS_DPR_FRAME_2P_PIX_Y_CTRL		0x100
6362306a36Sopenharmony_ci#define DCSS_DPR_FRAME_2P_BASE_ADDR		0x110
6462306a36Sopenharmony_ci#define DCSS_DPR_STATUS_CTRL0			0x130
6562306a36Sopenharmony_ci#define   STATUS_MUX_SEL_MASK			GENMASK(2, 0)
6662306a36Sopenharmony_ci#define   STATUS_SRC_SEL_POS			16
6762306a36Sopenharmony_ci#define   STATUS_SRC_SEL_MASK			GENMASK(18, 16)
6862306a36Sopenharmony_ci#define DCSS_DPR_STATUS_CTRL1			0x140
6962306a36Sopenharmony_ci#define DCSS_DPR_RTRAM_CTRL0			0x200
7062306a36Sopenharmony_ci#define   NUM_ROWS_ACTIVE			BIT(0)
7162306a36Sopenharmony_ci#define   THRES_HIGH_POS			1
7262306a36Sopenharmony_ci#define   THRES_HIGH_MASK			GENMASK(3, 1)
7362306a36Sopenharmony_ci#define   THRES_LOW_POS				4
7462306a36Sopenharmony_ci#define   THRES_LOW_MASK			GENMASK(6, 4)
7562306a36Sopenharmony_ci#define   ABORT_SEL				BIT(7)
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cienum dcss_tile_type {
7862306a36Sopenharmony_ci	TILE_LINEAR = 0,
7962306a36Sopenharmony_ci	TILE_GPU_STANDARD,
8062306a36Sopenharmony_ci	TILE_GPU_SUPER,
8162306a36Sopenharmony_ci	TILE_VPU_YUV420,
8262306a36Sopenharmony_ci	TILE_VPU_VP9,
8362306a36Sopenharmony_ci};
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_cienum dcss_pix_size {
8662306a36Sopenharmony_ci	PIX_SIZE_8,
8762306a36Sopenharmony_ci	PIX_SIZE_16,
8862306a36Sopenharmony_ci	PIX_SIZE_32,
8962306a36Sopenharmony_ci};
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistruct dcss_dpr_ch {
9262306a36Sopenharmony_ci	struct dcss_dpr *dpr;
9362306a36Sopenharmony_ci	void __iomem *base_reg;
9462306a36Sopenharmony_ci	u32 base_ofs;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	struct drm_format_info format;
9762306a36Sopenharmony_ci	enum dcss_pix_size pix_size;
9862306a36Sopenharmony_ci	enum dcss_tile_type tile;
9962306a36Sopenharmony_ci	bool rtram_4line_en;
10062306a36Sopenharmony_ci	bool rtram_3buf_en;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	u32 frame_ctrl;
10362306a36Sopenharmony_ci	u32 mode_ctrl;
10462306a36Sopenharmony_ci	u32 sys_ctrl;
10562306a36Sopenharmony_ci	u32 rtram_ctrl;
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	bool sys_ctrl_chgd;
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	int ch_num;
11062306a36Sopenharmony_ci	int irq;
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistruct dcss_dpr {
11462306a36Sopenharmony_ci	struct device *dev;
11562306a36Sopenharmony_ci	struct dcss_ctxld *ctxld;
11662306a36Sopenharmony_ci	u32  ctx_id;
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci	struct dcss_dpr_ch ch[3];
11962306a36Sopenharmony_ci};
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_cistatic void dcss_dpr_write(struct dcss_dpr_ch *ch, u32 val, u32 ofs)
12262306a36Sopenharmony_ci{
12362306a36Sopenharmony_ci	struct dcss_dpr *dpr = ch->dpr;
12462306a36Sopenharmony_ci
12562306a36Sopenharmony_ci	dcss_ctxld_write(dpr->ctxld, dpr->ctx_id, val, ch->base_ofs + ofs);
12662306a36Sopenharmony_ci}
12762306a36Sopenharmony_ci
12862306a36Sopenharmony_cistatic int dcss_dpr_ch_init_all(struct dcss_dpr *dpr, unsigned long dpr_base)
12962306a36Sopenharmony_ci{
13062306a36Sopenharmony_ci	struct dcss_dpr_ch *ch;
13162306a36Sopenharmony_ci	int i;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	for (i = 0; i < 3; i++) {
13462306a36Sopenharmony_ci		ch = &dpr->ch[i];
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci		ch->base_ofs = dpr_base + i * 0x1000;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci		ch->base_reg = ioremap(ch->base_ofs, SZ_4K);
13962306a36Sopenharmony_ci		if (!ch->base_reg) {
14062306a36Sopenharmony_ci			dev_err(dpr->dev, "dpr: unable to remap ch %d base\n",
14162306a36Sopenharmony_ci				i);
14262306a36Sopenharmony_ci			return -ENOMEM;
14362306a36Sopenharmony_ci		}
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci		ch->dpr = dpr;
14662306a36Sopenharmony_ci		ch->ch_num = i;
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci		dcss_writel(0xff, ch->base_reg + DCSS_DPR_IRQ_MASK);
14962306a36Sopenharmony_ci	}
15062306a36Sopenharmony_ci
15162306a36Sopenharmony_ci	return 0;
15262306a36Sopenharmony_ci}
15362306a36Sopenharmony_ci
15462306a36Sopenharmony_ciint dcss_dpr_init(struct dcss_dev *dcss, unsigned long dpr_base)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	struct dcss_dpr *dpr;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	dpr = kzalloc(sizeof(*dpr), GFP_KERNEL);
15962306a36Sopenharmony_ci	if (!dpr)
16062306a36Sopenharmony_ci		return -ENOMEM;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	dcss->dpr = dpr;
16362306a36Sopenharmony_ci	dpr->dev = dcss->dev;
16462306a36Sopenharmony_ci	dpr->ctxld = dcss->ctxld;
16562306a36Sopenharmony_ci	dpr->ctx_id = CTX_SB_HP;
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_ci	if (dcss_dpr_ch_init_all(dpr, dpr_base)) {
16862306a36Sopenharmony_ci		int i;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		for (i = 0; i < 3; i++) {
17162306a36Sopenharmony_ci			if (dpr->ch[i].base_reg)
17262306a36Sopenharmony_ci				iounmap(dpr->ch[i].base_reg);
17362306a36Sopenharmony_ci		}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		kfree(dpr);
17662306a36Sopenharmony_ci
17762306a36Sopenharmony_ci		return -ENOMEM;
17862306a36Sopenharmony_ci	}
17962306a36Sopenharmony_ci
18062306a36Sopenharmony_ci	return 0;
18162306a36Sopenharmony_ci}
18262306a36Sopenharmony_ci
18362306a36Sopenharmony_civoid dcss_dpr_exit(struct dcss_dpr *dpr)
18462306a36Sopenharmony_ci{
18562306a36Sopenharmony_ci	int ch_no;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci	/* stop DPR on all channels */
18862306a36Sopenharmony_ci	for (ch_no = 0; ch_no < 3; ch_no++) {
18962306a36Sopenharmony_ci		struct dcss_dpr_ch *ch = &dpr->ch[ch_no];
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		dcss_writel(0, ch->base_reg + DCSS_DPR_SYSTEM_CTRL0);
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci		if (ch->base_reg)
19462306a36Sopenharmony_ci			iounmap(ch->base_reg);
19562306a36Sopenharmony_ci	}
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	kfree(dpr);
19862306a36Sopenharmony_ci}
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_cistatic u32 dcss_dpr_x_pix_wide_adjust(struct dcss_dpr_ch *ch, u32 pix_wide,
20162306a36Sopenharmony_ci				      u32 pix_format)
20262306a36Sopenharmony_ci{
20362306a36Sopenharmony_ci	u8 pix_in_64byte_map[3][5] = {
20462306a36Sopenharmony_ci		/* LIN, GPU_STD, GPU_SUP, VPU_YUV420, VPU_VP9 */
20562306a36Sopenharmony_ci		{   64,       8,       8,          8,     16}, /* PIX_SIZE_8  */
20662306a36Sopenharmony_ci		{   32,       8,       8,          8,      8}, /* PIX_SIZE_16 */
20762306a36Sopenharmony_ci		{   16,       4,       4,          8,      8}, /* PIX_SIZE_32 */
20862306a36Sopenharmony_ci	};
20962306a36Sopenharmony_ci	u32 offset;
21062306a36Sopenharmony_ci	u32 div_64byte_mod, pix_in_64byte;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	pix_in_64byte = pix_in_64byte_map[ch->pix_size][ch->tile];
21362306a36Sopenharmony_ci
21462306a36Sopenharmony_ci	div_64byte_mod = pix_wide % pix_in_64byte;
21562306a36Sopenharmony_ci	offset = (div_64byte_mod == 0) ? 0 : (pix_in_64byte - div_64byte_mod);
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	return pix_wide + offset;
21862306a36Sopenharmony_ci}
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic u32 dcss_dpr_y_pix_high_adjust(struct dcss_dpr_ch *ch, u32 pix_high,
22162306a36Sopenharmony_ci				      u32 pix_format)
22262306a36Sopenharmony_ci{
22362306a36Sopenharmony_ci	u8 num_rows_buf = ch->rtram_4line_en ? 4 : 8;
22462306a36Sopenharmony_ci	u32 offset, pix_y_mod;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	pix_y_mod = pix_high % num_rows_buf;
22762306a36Sopenharmony_ci	offset = pix_y_mod ? (num_rows_buf - pix_y_mod) : 0;
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci	return pix_high + offset;
23062306a36Sopenharmony_ci}
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_civoid dcss_dpr_set_res(struct dcss_dpr *dpr, int ch_num, u32 xres, u32 yres)
23362306a36Sopenharmony_ci{
23462306a36Sopenharmony_ci	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
23562306a36Sopenharmony_ci	u32 pix_format = ch->format.format;
23662306a36Sopenharmony_ci	u32 gap = DCSS_DPR_FRAME_2P_BASE_ADDR - DCSS_DPR_FRAME_1P_BASE_ADDR;
23762306a36Sopenharmony_ci	int plane, max_planes = 1;
23862306a36Sopenharmony_ci	u32 pix_x_wide, pix_y_high;
23962306a36Sopenharmony_ci
24062306a36Sopenharmony_ci	if (pix_format == DRM_FORMAT_NV12 ||
24162306a36Sopenharmony_ci	    pix_format == DRM_FORMAT_NV21)
24262306a36Sopenharmony_ci		max_planes = 2;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	for (plane = 0; plane < max_planes; plane++) {
24562306a36Sopenharmony_ci		yres = plane == 1 ? yres >> 1 : yres;
24662306a36Sopenharmony_ci
24762306a36Sopenharmony_ci		pix_x_wide = dcss_dpr_x_pix_wide_adjust(ch, xres, pix_format);
24862306a36Sopenharmony_ci		pix_y_high = dcss_dpr_y_pix_high_adjust(ch, yres, pix_format);
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		dcss_dpr_write(ch, pix_x_wide,
25162306a36Sopenharmony_ci			       DCSS_DPR_FRAME_1P_PIX_X_CTRL + plane * gap);
25262306a36Sopenharmony_ci		dcss_dpr_write(ch, pix_y_high,
25362306a36Sopenharmony_ci			       DCSS_DPR_FRAME_1P_PIX_Y_CTRL + plane * gap);
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci		dcss_dpr_write(ch, 2, DCSS_DPR_FRAME_1P_CTRL0 + plane * gap);
25662306a36Sopenharmony_ci	}
25762306a36Sopenharmony_ci}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_civoid dcss_dpr_addr_set(struct dcss_dpr *dpr, int ch_num, u32 luma_base_addr,
26062306a36Sopenharmony_ci		       u32 chroma_base_addr, u16 pitch)
26162306a36Sopenharmony_ci{
26262306a36Sopenharmony_ci	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	dcss_dpr_write(ch, luma_base_addr, DCSS_DPR_FRAME_1P_BASE_ADDR);
26562306a36Sopenharmony_ci
26662306a36Sopenharmony_ci	dcss_dpr_write(ch, chroma_base_addr, DCSS_DPR_FRAME_2P_BASE_ADDR);
26762306a36Sopenharmony_ci
26862306a36Sopenharmony_ci	ch->frame_ctrl &= ~PITCH_MASK;
26962306a36Sopenharmony_ci	ch->frame_ctrl |= (((u32)pitch << PITCH_POS) & PITCH_MASK);
27062306a36Sopenharmony_ci}
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_cistatic void dcss_dpr_argb_comp_sel(struct dcss_dpr_ch *ch, int a_sel, int r_sel,
27362306a36Sopenharmony_ci				   int g_sel, int b_sel)
27462306a36Sopenharmony_ci{
27562306a36Sopenharmony_ci	u32 sel;
27662306a36Sopenharmony_ci
27762306a36Sopenharmony_ci	sel = ((a_sel << A_COMP_SEL_POS) & A_COMP_SEL_MASK) |
27862306a36Sopenharmony_ci	      ((r_sel << R_COMP_SEL_POS) & R_COMP_SEL_MASK) |
27962306a36Sopenharmony_ci	      ((g_sel << G_COMP_SEL_POS) & G_COMP_SEL_MASK) |
28062306a36Sopenharmony_ci	      ((b_sel << B_COMP_SEL_POS) & B_COMP_SEL_MASK);
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci	ch->mode_ctrl &= ~(A_COMP_SEL_MASK | R_COMP_SEL_MASK |
28362306a36Sopenharmony_ci			   G_COMP_SEL_MASK | B_COMP_SEL_MASK);
28462306a36Sopenharmony_ci	ch->mode_ctrl |= sel;
28562306a36Sopenharmony_ci}
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_cistatic void dcss_dpr_pix_size_set(struct dcss_dpr_ch *ch,
28862306a36Sopenharmony_ci				  const struct drm_format_info *format)
28962306a36Sopenharmony_ci{
29062306a36Sopenharmony_ci	u32 val;
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci	switch (format->format) {
29362306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
29462306a36Sopenharmony_ci	case DRM_FORMAT_NV21:
29562306a36Sopenharmony_ci		val = PIX_SIZE_8;
29662306a36Sopenharmony_ci		break;
29762306a36Sopenharmony_ci
29862306a36Sopenharmony_ci	case DRM_FORMAT_UYVY:
29962306a36Sopenharmony_ci	case DRM_FORMAT_VYUY:
30062306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
30162306a36Sopenharmony_ci	case DRM_FORMAT_YVYU:
30262306a36Sopenharmony_ci		val = PIX_SIZE_16;
30362306a36Sopenharmony_ci		break;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	default:
30662306a36Sopenharmony_ci		val = PIX_SIZE_32;
30762306a36Sopenharmony_ci		break;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci
31062306a36Sopenharmony_ci	ch->pix_size = val;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	ch->mode_ctrl &= ~PIX_SIZE_MASK;
31362306a36Sopenharmony_ci	ch->mode_ctrl |= ((val << PIX_SIZE_POS) & PIX_SIZE_MASK);
31462306a36Sopenharmony_ci}
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_cistatic void dcss_dpr_uv_swap(struct dcss_dpr_ch *ch, bool swap)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	ch->mode_ctrl &= ~PIX_UV_SWAP;
31962306a36Sopenharmony_ci	ch->mode_ctrl |= (swap ? PIX_UV_SWAP : 0);
32062306a36Sopenharmony_ci}
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_cistatic void dcss_dpr_y_uv_swap(struct dcss_dpr_ch *ch, bool swap)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	ch->mode_ctrl &= ~PIX_LUMA_UV_SWAP;
32562306a36Sopenharmony_ci	ch->mode_ctrl |= (swap ? PIX_LUMA_UV_SWAP : 0);
32662306a36Sopenharmony_ci}
32762306a36Sopenharmony_ci
32862306a36Sopenharmony_cistatic void dcss_dpr_2plane_en(struct dcss_dpr_ch *ch, bool en)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	ch->mode_ctrl &= ~COMP_2PLANE_EN;
33162306a36Sopenharmony_ci	ch->mode_ctrl |= (en ? COMP_2PLANE_EN : 0);
33262306a36Sopenharmony_ci}
33362306a36Sopenharmony_ci
33462306a36Sopenharmony_cistatic void dcss_dpr_yuv_en(struct dcss_dpr_ch *ch, bool en)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	ch->mode_ctrl &= ~YUV_EN;
33762306a36Sopenharmony_ci	ch->mode_ctrl |= (en ? YUV_EN : 0);
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_civoid dcss_dpr_enable(struct dcss_dpr *dpr, int ch_num, bool en)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
34362306a36Sopenharmony_ci	u32 sys_ctrl;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	sys_ctrl = (en ? REPEAT_EN | RUN_EN : 0);
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	if (en) {
34862306a36Sopenharmony_ci		dcss_dpr_write(ch, ch->mode_ctrl, DCSS_DPR_MODE_CTRL0);
34962306a36Sopenharmony_ci		dcss_dpr_write(ch, ch->frame_ctrl, DCSS_DPR_FRAME_CTRL0);
35062306a36Sopenharmony_ci		dcss_dpr_write(ch, ch->rtram_ctrl, DCSS_DPR_RTRAM_CTRL0);
35162306a36Sopenharmony_ci	}
35262306a36Sopenharmony_ci
35362306a36Sopenharmony_ci	if (ch->sys_ctrl != sys_ctrl)
35462306a36Sopenharmony_ci		ch->sys_ctrl_chgd = true;
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	ch->sys_ctrl = sys_ctrl;
35762306a36Sopenharmony_ci}
35862306a36Sopenharmony_ci
35962306a36Sopenharmony_cistruct rgb_comp_sel {
36062306a36Sopenharmony_ci	u32 drm_format;
36162306a36Sopenharmony_ci	int a_sel;
36262306a36Sopenharmony_ci	int r_sel;
36362306a36Sopenharmony_ci	int g_sel;
36462306a36Sopenharmony_ci	int b_sel;
36562306a36Sopenharmony_ci};
36662306a36Sopenharmony_ci
36762306a36Sopenharmony_cistatic struct rgb_comp_sel comp_sel_map[] = {
36862306a36Sopenharmony_ci	{DRM_FORMAT_ARGB8888, 3, 2, 1, 0},
36962306a36Sopenharmony_ci	{DRM_FORMAT_XRGB8888, 3, 2, 1, 0},
37062306a36Sopenharmony_ci	{DRM_FORMAT_ABGR8888, 3, 0, 1, 2},
37162306a36Sopenharmony_ci	{DRM_FORMAT_XBGR8888, 3, 0, 1, 2},
37262306a36Sopenharmony_ci	{DRM_FORMAT_RGBA8888, 0, 3, 2, 1},
37362306a36Sopenharmony_ci	{DRM_FORMAT_RGBX8888, 0, 3, 2, 1},
37462306a36Sopenharmony_ci	{DRM_FORMAT_BGRA8888, 0, 1, 2, 3},
37562306a36Sopenharmony_ci	{DRM_FORMAT_BGRX8888, 0, 1, 2, 3},
37662306a36Sopenharmony_ci};
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_cistatic int to_comp_sel(u32 pix_fmt, int *a_sel, int *r_sel, int *g_sel,
37962306a36Sopenharmony_ci		       int *b_sel)
38062306a36Sopenharmony_ci{
38162306a36Sopenharmony_ci	int i;
38262306a36Sopenharmony_ci
38362306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(comp_sel_map); i++) {
38462306a36Sopenharmony_ci		if (comp_sel_map[i].drm_format == pix_fmt) {
38562306a36Sopenharmony_ci			*a_sel = comp_sel_map[i].a_sel;
38662306a36Sopenharmony_ci			*r_sel = comp_sel_map[i].r_sel;
38762306a36Sopenharmony_ci			*g_sel = comp_sel_map[i].g_sel;
38862306a36Sopenharmony_ci			*b_sel = comp_sel_map[i].b_sel;
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_ci			return 0;
39162306a36Sopenharmony_ci		}
39262306a36Sopenharmony_ci	}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	return -1;
39562306a36Sopenharmony_ci}
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_cistatic void dcss_dpr_rtram_set(struct dcss_dpr_ch *ch, u32 pix_format)
39862306a36Sopenharmony_ci{
39962306a36Sopenharmony_ci	u32 val, mask;
40062306a36Sopenharmony_ci
40162306a36Sopenharmony_ci	switch (pix_format) {
40262306a36Sopenharmony_ci	case DRM_FORMAT_NV21:
40362306a36Sopenharmony_ci	case DRM_FORMAT_NV12:
40462306a36Sopenharmony_ci		ch->rtram_3buf_en = true;
40562306a36Sopenharmony_ci		ch->rtram_4line_en = false;
40662306a36Sopenharmony_ci		break;
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci	default:
40962306a36Sopenharmony_ci		ch->rtram_3buf_en = true;
41062306a36Sopenharmony_ci		ch->rtram_4line_en = true;
41162306a36Sopenharmony_ci		break;
41262306a36Sopenharmony_ci	}
41362306a36Sopenharmony_ci
41462306a36Sopenharmony_ci	val = (ch->rtram_4line_en ? RTR_4LINE_BUF_EN : 0);
41562306a36Sopenharmony_ci	val |= (ch->rtram_3buf_en ? RTR_3BUF_EN : 0);
41662306a36Sopenharmony_ci	mask = RTR_4LINE_BUF_EN | RTR_3BUF_EN;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	ch->mode_ctrl &= ~mask;
41962306a36Sopenharmony_ci	ch->mode_ctrl |= (val & mask);
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	val = (ch->rtram_4line_en ? 0 : NUM_ROWS_ACTIVE);
42262306a36Sopenharmony_ci	val |= (3 << THRES_LOW_POS) & THRES_LOW_MASK;
42362306a36Sopenharmony_ci	val |= (4 << THRES_HIGH_POS) & THRES_HIGH_MASK;
42462306a36Sopenharmony_ci	mask = THRES_LOW_MASK | THRES_HIGH_MASK | NUM_ROWS_ACTIVE;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	ch->rtram_ctrl &= ~mask;
42762306a36Sopenharmony_ci	ch->rtram_ctrl |= (val & mask);
42862306a36Sopenharmony_ci}
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_cistatic void dcss_dpr_setup_components(struct dcss_dpr_ch *ch,
43162306a36Sopenharmony_ci				      const struct drm_format_info *format)
43262306a36Sopenharmony_ci{
43362306a36Sopenharmony_ci	int a_sel, r_sel, g_sel, b_sel;
43462306a36Sopenharmony_ci	bool uv_swap, y_uv_swap;
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_ci	switch (format->format) {
43762306a36Sopenharmony_ci	case DRM_FORMAT_YVYU:
43862306a36Sopenharmony_ci		uv_swap = true;
43962306a36Sopenharmony_ci		y_uv_swap = true;
44062306a36Sopenharmony_ci		break;
44162306a36Sopenharmony_ci
44262306a36Sopenharmony_ci	case DRM_FORMAT_VYUY:
44362306a36Sopenharmony_ci	case DRM_FORMAT_NV21:
44462306a36Sopenharmony_ci		uv_swap = true;
44562306a36Sopenharmony_ci		y_uv_swap = false;
44662306a36Sopenharmony_ci		break;
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	case DRM_FORMAT_YUYV:
44962306a36Sopenharmony_ci		uv_swap = false;
45062306a36Sopenharmony_ci		y_uv_swap = true;
45162306a36Sopenharmony_ci		break;
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_ci	default:
45462306a36Sopenharmony_ci		uv_swap = false;
45562306a36Sopenharmony_ci		y_uv_swap = false;
45662306a36Sopenharmony_ci		break;
45762306a36Sopenharmony_ci	}
45862306a36Sopenharmony_ci
45962306a36Sopenharmony_ci	dcss_dpr_uv_swap(ch, uv_swap);
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	dcss_dpr_y_uv_swap(ch, y_uv_swap);
46262306a36Sopenharmony_ci
46362306a36Sopenharmony_ci	if (!format->is_yuv) {
46462306a36Sopenharmony_ci		if (!to_comp_sel(format->format, &a_sel, &r_sel,
46562306a36Sopenharmony_ci				 &g_sel, &b_sel)) {
46662306a36Sopenharmony_ci			dcss_dpr_argb_comp_sel(ch, a_sel, r_sel, g_sel, b_sel);
46762306a36Sopenharmony_ci		} else {
46862306a36Sopenharmony_ci			dcss_dpr_argb_comp_sel(ch, 3, 2, 1, 0);
46962306a36Sopenharmony_ci		}
47062306a36Sopenharmony_ci	} else {
47162306a36Sopenharmony_ci		dcss_dpr_argb_comp_sel(ch, 0, 0, 0, 0);
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci}
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_cistatic void dcss_dpr_tile_set(struct dcss_dpr_ch *ch, uint64_t modifier)
47662306a36Sopenharmony_ci{
47762306a36Sopenharmony_ci	switch (ch->ch_num) {
47862306a36Sopenharmony_ci	case 0:
47962306a36Sopenharmony_ci		switch (modifier) {
48062306a36Sopenharmony_ci		case DRM_FORMAT_MOD_LINEAR:
48162306a36Sopenharmony_ci			ch->tile = TILE_LINEAR;
48262306a36Sopenharmony_ci			break;
48362306a36Sopenharmony_ci		case DRM_FORMAT_MOD_VIVANTE_TILED:
48462306a36Sopenharmony_ci			ch->tile = TILE_GPU_STANDARD;
48562306a36Sopenharmony_ci			break;
48662306a36Sopenharmony_ci		case DRM_FORMAT_MOD_VIVANTE_SUPER_TILED:
48762306a36Sopenharmony_ci			ch->tile = TILE_GPU_SUPER;
48862306a36Sopenharmony_ci			break;
48962306a36Sopenharmony_ci		default:
49062306a36Sopenharmony_ci			WARN_ON(1);
49162306a36Sopenharmony_ci			break;
49262306a36Sopenharmony_ci		}
49362306a36Sopenharmony_ci		break;
49462306a36Sopenharmony_ci	case 1:
49562306a36Sopenharmony_ci	case 2:
49662306a36Sopenharmony_ci		ch->tile = TILE_LINEAR;
49762306a36Sopenharmony_ci		break;
49862306a36Sopenharmony_ci	default:
49962306a36Sopenharmony_ci		WARN_ON(1);
50062306a36Sopenharmony_ci		return;
50162306a36Sopenharmony_ci	}
50262306a36Sopenharmony_ci
50362306a36Sopenharmony_ci	ch->mode_ctrl &= ~TILE_TYPE_MASK;
50462306a36Sopenharmony_ci	ch->mode_ctrl |= ((ch->tile << TILE_TYPE_POS) & TILE_TYPE_MASK);
50562306a36Sopenharmony_ci}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_civoid dcss_dpr_format_set(struct dcss_dpr *dpr, int ch_num,
50862306a36Sopenharmony_ci			 const struct drm_format_info *format, u64 modifier)
50962306a36Sopenharmony_ci{
51062306a36Sopenharmony_ci	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
51162306a36Sopenharmony_ci
51262306a36Sopenharmony_ci	ch->format = *format;
51362306a36Sopenharmony_ci
51462306a36Sopenharmony_ci	dcss_dpr_yuv_en(ch, format->is_yuv);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	dcss_dpr_pix_size_set(ch, format);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	dcss_dpr_setup_components(ch, format);
51962306a36Sopenharmony_ci
52062306a36Sopenharmony_ci	dcss_dpr_2plane_en(ch, format->num_planes == 2);
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_ci	dcss_dpr_rtram_set(ch, format->format);
52362306a36Sopenharmony_ci
52462306a36Sopenharmony_ci	dcss_dpr_tile_set(ch, modifier);
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_ci/* This function will be called from interrupt context. */
52862306a36Sopenharmony_civoid dcss_dpr_write_sysctrl(struct dcss_dpr *dpr)
52962306a36Sopenharmony_ci{
53062306a36Sopenharmony_ci	int chnum;
53162306a36Sopenharmony_ci
53262306a36Sopenharmony_ci	dcss_ctxld_assert_locked(dpr->ctxld);
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	for (chnum = 0; chnum < 3; chnum++) {
53562306a36Sopenharmony_ci		struct dcss_dpr_ch *ch = &dpr->ch[chnum];
53662306a36Sopenharmony_ci
53762306a36Sopenharmony_ci		if (ch->sys_ctrl_chgd) {
53862306a36Sopenharmony_ci			dcss_ctxld_write_irqsafe(dpr->ctxld, dpr->ctx_id,
53962306a36Sopenharmony_ci						 ch->sys_ctrl,
54062306a36Sopenharmony_ci						 ch->base_ofs +
54162306a36Sopenharmony_ci						 DCSS_DPR_SYSTEM_CTRL0);
54262306a36Sopenharmony_ci			ch->sys_ctrl_chgd = false;
54362306a36Sopenharmony_ci		}
54462306a36Sopenharmony_ci	}
54562306a36Sopenharmony_ci}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_civoid dcss_dpr_set_rotation(struct dcss_dpr *dpr, int ch_num, u32 rotation)
54862306a36Sopenharmony_ci{
54962306a36Sopenharmony_ci	struct dcss_dpr_ch *ch = &dpr->ch[ch_num];
55062306a36Sopenharmony_ci
55162306a36Sopenharmony_ci	ch->frame_ctrl &= ~(HFLIP_EN | VFLIP_EN | ROT_ENC_MASK);
55262306a36Sopenharmony_ci
55362306a36Sopenharmony_ci	ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_X ? HFLIP_EN : 0;
55462306a36Sopenharmony_ci	ch->frame_ctrl |= rotation & DRM_MODE_REFLECT_Y ? VFLIP_EN : 0;
55562306a36Sopenharmony_ci
55662306a36Sopenharmony_ci	if (rotation & DRM_MODE_ROTATE_90)
55762306a36Sopenharmony_ci		ch->frame_ctrl |= 1 << ROT_ENC_POS;
55862306a36Sopenharmony_ci	else if (rotation & DRM_MODE_ROTATE_180)
55962306a36Sopenharmony_ci		ch->frame_ctrl |= 2 << ROT_ENC_POS;
56062306a36Sopenharmony_ci	else if (rotation & DRM_MODE_ROTATE_270)
56162306a36Sopenharmony_ci		ch->frame_ctrl |= 3 << ROT_ENC_POS;
56262306a36Sopenharmony_ci}
563