162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright 2019 NXP.
462306a36Sopenharmony_ci */
562306a36Sopenharmony_ci
662306a36Sopenharmony_ci#include <linux/clk.h>
762306a36Sopenharmony_ci#include <linux/delay.h>
862306a36Sopenharmony_ci#include <linux/interrupt.h>
962306a36Sopenharmony_ci#include <linux/of.h>
1062306a36Sopenharmony_ci#include <linux/platform_device.h>
1162306a36Sopenharmony_ci#include <linux/slab.h>
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_ci#include "dcss-dev.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define DCSS_DTG_TC_CONTROL_STATUS			0x00
1662306a36Sopenharmony_ci#define   CH3_EN					BIT(0)
1762306a36Sopenharmony_ci#define   CH2_EN					BIT(1)
1862306a36Sopenharmony_ci#define   CH1_EN					BIT(2)
1962306a36Sopenharmony_ci#define   OVL_DATA_MODE					BIT(3)
2062306a36Sopenharmony_ci#define   BLENDER_VIDEO_ALPHA_SEL			BIT(7)
2162306a36Sopenharmony_ci#define   DTG_START					BIT(8)
2262306a36Sopenharmony_ci#define   DBY_MODE_EN					BIT(9)
2362306a36Sopenharmony_ci#define   CH1_ALPHA_SEL					BIT(10)
2462306a36Sopenharmony_ci#define   CSS_PIX_COMP_SWAP_POS				12
2562306a36Sopenharmony_ci#define   CSS_PIX_COMP_SWAP_MASK			GENMASK(14, 12)
2662306a36Sopenharmony_ci#define   DEFAULT_FG_ALPHA_POS				24
2762306a36Sopenharmony_ci#define   DEFAULT_FG_ALPHA_MASK				GENMASK(31, 24)
2862306a36Sopenharmony_ci#define DCSS_DTG_TC_DTG					0x04
2962306a36Sopenharmony_ci#define DCSS_DTG_TC_DISP_TOP				0x08
3062306a36Sopenharmony_ci#define DCSS_DTG_TC_DISP_BOT				0x0C
3162306a36Sopenharmony_ci#define DCSS_DTG_TC_CH1_TOP				0x10
3262306a36Sopenharmony_ci#define DCSS_DTG_TC_CH1_BOT				0x14
3362306a36Sopenharmony_ci#define DCSS_DTG_TC_CH2_TOP				0x18
3462306a36Sopenharmony_ci#define DCSS_DTG_TC_CH2_BOT				0x1C
3562306a36Sopenharmony_ci#define DCSS_DTG_TC_CH3_TOP				0x20
3662306a36Sopenharmony_ci#define DCSS_DTG_TC_CH3_BOT				0x24
3762306a36Sopenharmony_ci#define   TC_X_POS					0
3862306a36Sopenharmony_ci#define   TC_X_MASK					GENMASK(12, 0)
3962306a36Sopenharmony_ci#define   TC_Y_POS					16
4062306a36Sopenharmony_ci#define   TC_Y_MASK					GENMASK(28, 16)
4162306a36Sopenharmony_ci#define DCSS_DTG_TC_CTXLD				0x28
4262306a36Sopenharmony_ci#define   TC_CTXLD_DB_Y_POS				0
4362306a36Sopenharmony_ci#define   TC_CTXLD_DB_Y_MASK				GENMASK(12, 0)
4462306a36Sopenharmony_ci#define   TC_CTXLD_SB_Y_POS				16
4562306a36Sopenharmony_ci#define   TC_CTXLD_SB_Y_MASK				GENMASK(28, 16)
4662306a36Sopenharmony_ci#define DCSS_DTG_TC_CH1_BKRND				0x2C
4762306a36Sopenharmony_ci#define DCSS_DTG_TC_CH2_BKRND				0x30
4862306a36Sopenharmony_ci#define   BKRND_R_Y_COMP_POS				20
4962306a36Sopenharmony_ci#define   BKRND_R_Y_COMP_MASK				GENMASK(29, 20)
5062306a36Sopenharmony_ci#define   BKRND_G_U_COMP_POS				10
5162306a36Sopenharmony_ci#define   BKRND_G_U_COMP_MASK				GENMASK(19, 10)
5262306a36Sopenharmony_ci#define   BKRND_B_V_COMP_POS				0
5362306a36Sopenharmony_ci#define   BKRND_B_V_COMP_MASK				GENMASK(9, 0)
5462306a36Sopenharmony_ci#define DCSS_DTG_BLENDER_DBY_RANGEINV			0x38
5562306a36Sopenharmony_ci#define DCSS_DTG_BLENDER_DBY_RANGEMIN			0x3C
5662306a36Sopenharmony_ci#define DCSS_DTG_BLENDER_DBY_BDP			0x40
5762306a36Sopenharmony_ci#define DCSS_DTG_BLENDER_BKRND_I			0x44
5862306a36Sopenharmony_ci#define DCSS_DTG_BLENDER_BKRND_P			0x48
5962306a36Sopenharmony_ci#define DCSS_DTG_BLENDER_BKRND_T			0x4C
6062306a36Sopenharmony_ci#define DCSS_DTG_LINE0_INT				0x50
6162306a36Sopenharmony_ci#define DCSS_DTG_LINE1_INT				0x54
6262306a36Sopenharmony_ci#define DCSS_DTG_BG_ALPHA_DEFAULT			0x58
6362306a36Sopenharmony_ci#define DCSS_DTG_INT_STATUS				0x5C
6462306a36Sopenharmony_ci#define DCSS_DTG_INT_CONTROL				0x60
6562306a36Sopenharmony_ci#define DCSS_DTG_TC_CH3_BKRND				0x64
6662306a36Sopenharmony_ci#define DCSS_DTG_INT_MASK				0x68
6762306a36Sopenharmony_ci#define   LINE0_IRQ					BIT(0)
6862306a36Sopenharmony_ci#define   LINE1_IRQ					BIT(1)
6962306a36Sopenharmony_ci#define   LINE2_IRQ					BIT(2)
7062306a36Sopenharmony_ci#define   LINE3_IRQ					BIT(3)
7162306a36Sopenharmony_ci#define DCSS_DTG_LINE2_INT				0x6C
7262306a36Sopenharmony_ci#define DCSS_DTG_LINE3_INT				0x70
7362306a36Sopenharmony_ci#define DCSS_DTG_DBY_OL					0x74
7462306a36Sopenharmony_ci#define DCSS_DTG_DBY_BL					0x78
7562306a36Sopenharmony_ci#define DCSS_DTG_DBY_EL					0x7C
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_cistruct dcss_dtg {
7862306a36Sopenharmony_ci	struct device *dev;
7962306a36Sopenharmony_ci	struct dcss_ctxld *ctxld;
8062306a36Sopenharmony_ci	void __iomem *base_reg;
8162306a36Sopenharmony_ci	u32 base_ofs;
8262306a36Sopenharmony_ci
8362306a36Sopenharmony_ci	u32 ctx_id;
8462306a36Sopenharmony_ci
8562306a36Sopenharmony_ci	bool in_use;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	u32 dis_ulc_x;
8862306a36Sopenharmony_ci	u32 dis_ulc_y;
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	u32 control_status;
9162306a36Sopenharmony_ci	u32 alpha;
9262306a36Sopenharmony_ci	u32 alpha_cfg;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	int ctxld_kick_irq;
9562306a36Sopenharmony_ci	bool ctxld_kick_irq_en;
9662306a36Sopenharmony_ci};
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_cistatic void dcss_dtg_write(struct dcss_dtg *dtg, u32 val, u32 ofs)
9962306a36Sopenharmony_ci{
10062306a36Sopenharmony_ci	if (!dtg->in_use)
10162306a36Sopenharmony_ci		dcss_writel(val, dtg->base_reg + ofs);
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	dcss_ctxld_write(dtg->ctxld, dtg->ctx_id,
10462306a36Sopenharmony_ci			 val, dtg->base_ofs + ofs);
10562306a36Sopenharmony_ci}
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_cistatic irqreturn_t dcss_dtg_irq_handler(int irq, void *data)
10862306a36Sopenharmony_ci{
10962306a36Sopenharmony_ci	struct dcss_dtg *dtg = data;
11062306a36Sopenharmony_ci	u32 status;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	if (!(status & LINE0_IRQ))
11562306a36Sopenharmony_ci		return IRQ_NONE;
11662306a36Sopenharmony_ci
11762306a36Sopenharmony_ci	dcss_ctxld_kick(dtg->ctxld);
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_ci	dcss_writel(status & LINE0_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci	return IRQ_HANDLED;
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic int dcss_dtg_irq_config(struct dcss_dtg *dtg,
12562306a36Sopenharmony_ci			       struct platform_device *pdev)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	int ret;
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci	dtg->ctxld_kick_irq = platform_get_irq_byname(pdev, "ctxld_kick");
13062306a36Sopenharmony_ci	if (dtg->ctxld_kick_irq < 0)
13162306a36Sopenharmony_ci		return dtg->ctxld_kick_irq;
13262306a36Sopenharmony_ci
13362306a36Sopenharmony_ci	dcss_update(0, LINE0_IRQ | LINE1_IRQ,
13462306a36Sopenharmony_ci		    dtg->base_reg + DCSS_DTG_INT_MASK);
13562306a36Sopenharmony_ci
13662306a36Sopenharmony_ci	ret = request_irq(dtg->ctxld_kick_irq, dcss_dtg_irq_handler,
13762306a36Sopenharmony_ci			  0, "dcss_ctxld_kick", dtg);
13862306a36Sopenharmony_ci	if (ret) {
13962306a36Sopenharmony_ci		dev_err(dtg->dev, "dtg: irq request failed.\n");
14062306a36Sopenharmony_ci		return ret;
14162306a36Sopenharmony_ci	}
14262306a36Sopenharmony_ci
14362306a36Sopenharmony_ci	disable_irq(dtg->ctxld_kick_irq);
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	dtg->ctxld_kick_irq_en = false;
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return 0;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ciint dcss_dtg_init(struct dcss_dev *dcss, unsigned long dtg_base)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	int ret = 0;
15362306a36Sopenharmony_ci	struct dcss_dtg *dtg;
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	dtg = kzalloc(sizeof(*dtg), GFP_KERNEL);
15662306a36Sopenharmony_ci	if (!dtg)
15762306a36Sopenharmony_ci		return -ENOMEM;
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	dcss->dtg = dtg;
16062306a36Sopenharmony_ci	dtg->dev = dcss->dev;
16162306a36Sopenharmony_ci	dtg->ctxld = dcss->ctxld;
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_ci	dtg->base_reg = ioremap(dtg_base, SZ_4K);
16462306a36Sopenharmony_ci	if (!dtg->base_reg) {
16562306a36Sopenharmony_ci		dev_err(dcss->dev, "dtg: unable to remap dtg base\n");
16662306a36Sopenharmony_ci		ret = -ENOMEM;
16762306a36Sopenharmony_ci		goto err_ioremap;
16862306a36Sopenharmony_ci	}
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci	dtg->base_ofs = dtg_base;
17162306a36Sopenharmony_ci	dtg->ctx_id = CTX_DB;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	dtg->alpha = 255;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	dtg->control_status |= OVL_DATA_MODE | BLENDER_VIDEO_ALPHA_SEL |
17662306a36Sopenharmony_ci		((dtg->alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK);
17762306a36Sopenharmony_ci
17862306a36Sopenharmony_ci	ret = dcss_dtg_irq_config(dtg, to_platform_device(dcss->dev));
17962306a36Sopenharmony_ci	if (ret)
18062306a36Sopenharmony_ci		goto err_irq;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	return 0;
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_cierr_irq:
18562306a36Sopenharmony_ci	iounmap(dtg->base_reg);
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_cierr_ioremap:
18862306a36Sopenharmony_ci	kfree(dtg);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	return ret;
19162306a36Sopenharmony_ci}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_civoid dcss_dtg_exit(struct dcss_dtg *dtg)
19462306a36Sopenharmony_ci{
19562306a36Sopenharmony_ci	free_irq(dtg->ctxld_kick_irq, dtg);
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	if (dtg->base_reg)
19862306a36Sopenharmony_ci		iounmap(dtg->base_reg);
19962306a36Sopenharmony_ci
20062306a36Sopenharmony_ci	kfree(dtg);
20162306a36Sopenharmony_ci}
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_civoid dcss_dtg_sync_set(struct dcss_dtg *dtg, struct videomode *vm)
20462306a36Sopenharmony_ci{
20562306a36Sopenharmony_ci	struct dcss_dev *dcss = dcss_drv_dev_to_dcss(dtg->dev);
20662306a36Sopenharmony_ci	u16 dtg_lrc_x, dtg_lrc_y;
20762306a36Sopenharmony_ci	u16 dis_ulc_x, dis_ulc_y;
20862306a36Sopenharmony_ci	u16 dis_lrc_x, dis_lrc_y;
20962306a36Sopenharmony_ci	u32 sb_ctxld_trig, db_ctxld_trig;
21062306a36Sopenharmony_ci	u32 pixclock = vm->pixelclock;
21162306a36Sopenharmony_ci	u32 actual_clk;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	dtg_lrc_x = vm->hfront_porch + vm->hback_porch + vm->hsync_len +
21462306a36Sopenharmony_ci		    vm->hactive - 1;
21562306a36Sopenharmony_ci	dtg_lrc_y = vm->vfront_porch + vm->vback_porch + vm->vsync_len +
21662306a36Sopenharmony_ci		    vm->vactive - 1;
21762306a36Sopenharmony_ci	dis_ulc_x = vm->hsync_len + vm->hback_porch - 1;
21862306a36Sopenharmony_ci	dis_ulc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch - 1;
21962306a36Sopenharmony_ci	dis_lrc_x = vm->hsync_len + vm->hback_porch + vm->hactive - 1;
22062306a36Sopenharmony_ci	dis_lrc_y = vm->vsync_len + vm->vfront_porch + vm->vback_porch +
22162306a36Sopenharmony_ci		    vm->vactive - 1;
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	clk_disable_unprepare(dcss->pix_clk);
22462306a36Sopenharmony_ci	clk_set_rate(dcss->pix_clk, vm->pixelclock);
22562306a36Sopenharmony_ci	clk_prepare_enable(dcss->pix_clk);
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_ci	actual_clk = clk_get_rate(dcss->pix_clk);
22862306a36Sopenharmony_ci	if (pixclock != actual_clk) {
22962306a36Sopenharmony_ci		dev_info(dtg->dev,
23062306a36Sopenharmony_ci			 "Pixel clock set to %u kHz instead of %u kHz.\n",
23162306a36Sopenharmony_ci			 (actual_clk / 1000), (pixclock / 1000));
23262306a36Sopenharmony_ci	}
23362306a36Sopenharmony_ci
23462306a36Sopenharmony_ci	dcss_dtg_write(dtg, ((dtg_lrc_y << TC_Y_POS) | dtg_lrc_x),
23562306a36Sopenharmony_ci		       DCSS_DTG_TC_DTG);
23662306a36Sopenharmony_ci	dcss_dtg_write(dtg, ((dis_ulc_y << TC_Y_POS) | dis_ulc_x),
23762306a36Sopenharmony_ci		       DCSS_DTG_TC_DISP_TOP);
23862306a36Sopenharmony_ci	dcss_dtg_write(dtg, ((dis_lrc_y << TC_Y_POS) | dis_lrc_x),
23962306a36Sopenharmony_ci		       DCSS_DTG_TC_DISP_BOT);
24062306a36Sopenharmony_ci
24162306a36Sopenharmony_ci	dtg->dis_ulc_x = dis_ulc_x;
24262306a36Sopenharmony_ci	dtg->dis_ulc_y = dis_ulc_y;
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	sb_ctxld_trig = ((0 * dis_lrc_y / 100) << TC_CTXLD_SB_Y_POS) &
24562306a36Sopenharmony_ci							TC_CTXLD_SB_Y_MASK;
24662306a36Sopenharmony_ci	db_ctxld_trig = ((99 * dis_lrc_y / 100) << TC_CTXLD_DB_Y_POS) &
24762306a36Sopenharmony_ci							TC_CTXLD_DB_Y_MASK;
24862306a36Sopenharmony_ci
24962306a36Sopenharmony_ci	dcss_dtg_write(dtg, sb_ctxld_trig | db_ctxld_trig, DCSS_DTG_TC_CTXLD);
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	/* vblank trigger */
25262306a36Sopenharmony_ci	dcss_dtg_write(dtg, 0, DCSS_DTG_LINE1_INT);
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	/* CTXLD trigger */
25562306a36Sopenharmony_ci	dcss_dtg_write(dtg, ((90 * dis_lrc_y) / 100) << 16, DCSS_DTG_LINE0_INT);
25662306a36Sopenharmony_ci}
25762306a36Sopenharmony_ci
25862306a36Sopenharmony_civoid dcss_dtg_plane_pos_set(struct dcss_dtg *dtg, int ch_num,
25962306a36Sopenharmony_ci			    int px, int py, int pw, int ph)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	u16 p_ulc_x, p_ulc_y;
26262306a36Sopenharmony_ci	u16 p_lrc_x, p_lrc_y;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	p_ulc_x = dtg->dis_ulc_x + px;
26562306a36Sopenharmony_ci	p_ulc_y = dtg->dis_ulc_y + py;
26662306a36Sopenharmony_ci	p_lrc_x = p_ulc_x + pw;
26762306a36Sopenharmony_ci	p_lrc_y = p_ulc_y + ph;
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci	if (!px && !py && !pw && !ph) {
27062306a36Sopenharmony_ci		dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
27162306a36Sopenharmony_ci		dcss_dtg_write(dtg, 0, DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
27262306a36Sopenharmony_ci	} else {
27362306a36Sopenharmony_ci		dcss_dtg_write(dtg, ((p_ulc_y << TC_Y_POS) | p_ulc_x),
27462306a36Sopenharmony_ci			       DCSS_DTG_TC_CH1_TOP + 0x8 * ch_num);
27562306a36Sopenharmony_ci		dcss_dtg_write(dtg, ((p_lrc_y << TC_Y_POS) | p_lrc_x),
27662306a36Sopenharmony_ci			       DCSS_DTG_TC_CH1_BOT + 0x8 * ch_num);
27762306a36Sopenharmony_ci	}
27862306a36Sopenharmony_ci}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_cibool dcss_dtg_global_alpha_changed(struct dcss_dtg *dtg, int ch_num, int alpha)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci	if (ch_num)
28362306a36Sopenharmony_ci		return false;
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	return alpha != dtg->alpha;
28662306a36Sopenharmony_ci}
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_civoid dcss_dtg_plane_alpha_set(struct dcss_dtg *dtg, int ch_num,
28962306a36Sopenharmony_ci			      const struct drm_format_info *format, int alpha)
29062306a36Sopenharmony_ci{
29162306a36Sopenharmony_ci	/* we care about alpha only when channel 0 is concerned */
29262306a36Sopenharmony_ci	if (ch_num)
29362306a36Sopenharmony_ci		return;
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci	/*
29662306a36Sopenharmony_ci	 * Use global alpha if pixel format does not have alpha channel or the
29762306a36Sopenharmony_ci	 * user explicitly chose to use global alpha (i.e. alpha is not OPAQUE).
29862306a36Sopenharmony_ci	 */
29962306a36Sopenharmony_ci	if (!format->has_alpha || alpha != 255)
30062306a36Sopenharmony_ci		dtg->alpha_cfg = (alpha << DEFAULT_FG_ALPHA_POS) & DEFAULT_FG_ALPHA_MASK;
30162306a36Sopenharmony_ci	else /* use per-pixel alpha otherwise */
30262306a36Sopenharmony_ci		dtg->alpha_cfg = CH1_ALPHA_SEL;
30362306a36Sopenharmony_ci
30462306a36Sopenharmony_ci	dtg->alpha = alpha;
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_civoid dcss_dtg_css_set(struct dcss_dtg *dtg)
30862306a36Sopenharmony_ci{
30962306a36Sopenharmony_ci	dtg->control_status |=
31062306a36Sopenharmony_ci			(0x5 << CSS_PIX_COMP_SWAP_POS) & CSS_PIX_COMP_SWAP_MASK;
31162306a36Sopenharmony_ci}
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_civoid dcss_dtg_enable(struct dcss_dtg *dtg)
31462306a36Sopenharmony_ci{
31562306a36Sopenharmony_ci	dtg->control_status |= DTG_START;
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	dtg->control_status &= ~(CH1_ALPHA_SEL | DEFAULT_FG_ALPHA_MASK);
31862306a36Sopenharmony_ci	dtg->control_status |= dtg->alpha_cfg;
31962306a36Sopenharmony_ci
32062306a36Sopenharmony_ci	dcss_dtg_write(dtg, dtg->control_status, DCSS_DTG_TC_CONTROL_STATUS);
32162306a36Sopenharmony_ci
32262306a36Sopenharmony_ci	dtg->in_use = true;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_civoid dcss_dtg_shutoff(struct dcss_dtg *dtg)
32662306a36Sopenharmony_ci{
32762306a36Sopenharmony_ci	dtg->control_status &= ~DTG_START;
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	dcss_writel(dtg->control_status,
33062306a36Sopenharmony_ci		    dtg->base_reg + DCSS_DTG_TC_CONTROL_STATUS);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	dtg->in_use = false;
33362306a36Sopenharmony_ci}
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_cibool dcss_dtg_is_enabled(struct dcss_dtg *dtg)
33662306a36Sopenharmony_ci{
33762306a36Sopenharmony_ci	return dtg->in_use;
33862306a36Sopenharmony_ci}
33962306a36Sopenharmony_ci
34062306a36Sopenharmony_civoid dcss_dtg_ch_enable(struct dcss_dtg *dtg, int ch_num, bool en)
34162306a36Sopenharmony_ci{
34262306a36Sopenharmony_ci	u32 ch_en_map[] = {CH1_EN, CH2_EN, CH3_EN};
34362306a36Sopenharmony_ci	u32 control_status;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	control_status = dtg->control_status & ~ch_en_map[ch_num];
34662306a36Sopenharmony_ci	control_status |= en ? ch_en_map[ch_num] : 0;
34762306a36Sopenharmony_ci
34862306a36Sopenharmony_ci	control_status &= ~(CH1_ALPHA_SEL | DEFAULT_FG_ALPHA_MASK);
34962306a36Sopenharmony_ci	control_status |= dtg->alpha_cfg;
35062306a36Sopenharmony_ci
35162306a36Sopenharmony_ci	if (dtg->control_status != control_status)
35262306a36Sopenharmony_ci		dcss_dtg_write(dtg, control_status, DCSS_DTG_TC_CONTROL_STATUS);
35362306a36Sopenharmony_ci
35462306a36Sopenharmony_ci	dtg->control_status = control_status;
35562306a36Sopenharmony_ci}
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_civoid dcss_dtg_vblank_irq_enable(struct dcss_dtg *dtg, bool en)
35862306a36Sopenharmony_ci{
35962306a36Sopenharmony_ci	u32 status;
36062306a36Sopenharmony_ci	u32 mask = en ? LINE1_IRQ : 0;
36162306a36Sopenharmony_ci
36262306a36Sopenharmony_ci	if (en) {
36362306a36Sopenharmony_ci		status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
36462306a36Sopenharmony_ci		dcss_writel(status & LINE1_IRQ,
36562306a36Sopenharmony_ci			    dtg->base_reg + DCSS_DTG_INT_CONTROL);
36662306a36Sopenharmony_ci	}
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	dcss_update(mask, LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_MASK);
36962306a36Sopenharmony_ci}
37062306a36Sopenharmony_ci
37162306a36Sopenharmony_civoid dcss_dtg_ctxld_kick_irq_enable(struct dcss_dtg *dtg, bool en)
37262306a36Sopenharmony_ci{
37362306a36Sopenharmony_ci	u32 status;
37462306a36Sopenharmony_ci	u32 mask = en ? LINE0_IRQ : 0;
37562306a36Sopenharmony_ci
37662306a36Sopenharmony_ci	if (en) {
37762306a36Sopenharmony_ci		status = dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS);
37862306a36Sopenharmony_ci
37962306a36Sopenharmony_ci		if (!dtg->ctxld_kick_irq_en) {
38062306a36Sopenharmony_ci			dcss_writel(status & LINE0_IRQ,
38162306a36Sopenharmony_ci				    dtg->base_reg + DCSS_DTG_INT_CONTROL);
38262306a36Sopenharmony_ci			enable_irq(dtg->ctxld_kick_irq);
38362306a36Sopenharmony_ci			dtg->ctxld_kick_irq_en = true;
38462306a36Sopenharmony_ci			dcss_update(mask, LINE0_IRQ,
38562306a36Sopenharmony_ci				    dtg->base_reg + DCSS_DTG_INT_MASK);
38662306a36Sopenharmony_ci		}
38762306a36Sopenharmony_ci
38862306a36Sopenharmony_ci		return;
38962306a36Sopenharmony_ci	}
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	if (!dtg->ctxld_kick_irq_en)
39262306a36Sopenharmony_ci		return;
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	disable_irq_nosync(dtg->ctxld_kick_irq);
39562306a36Sopenharmony_ci	dtg->ctxld_kick_irq_en = false;
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	dcss_update(mask, LINE0_IRQ, dtg->base_reg + DCSS_DTG_INT_MASK);
39862306a36Sopenharmony_ci}
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_civoid dcss_dtg_vblank_irq_clear(struct dcss_dtg *dtg)
40162306a36Sopenharmony_ci{
40262306a36Sopenharmony_ci	dcss_update(LINE1_IRQ, LINE1_IRQ, dtg->base_reg + DCSS_DTG_INT_CONTROL);
40362306a36Sopenharmony_ci}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cibool dcss_dtg_vblank_irq_valid(struct dcss_dtg *dtg)
40662306a36Sopenharmony_ci{
40762306a36Sopenharmony_ci	return !!(dcss_readl(dtg->base_reg + DCSS_DTG_INT_STATUS) & LINE1_IRQ);
40862306a36Sopenharmony_ci}
40962306a36Sopenharmony_ci
410