1d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2783ad972SXinliang Liu /*
3783ad972SXinliang Liu  * Hisilicon Hi6220 SoC ADE(Advanced Display Engine)'s crtc&plane driver
4783ad972SXinliang Liu  *
5783ad972SXinliang Liu  * Copyright (c) 2016 Linaro Limited.
66616125bSHao Fang  * Copyright (c) 2014-2016 HiSilicon Limited.
7783ad972SXinliang Liu  *
8783ad972SXinliang Liu  * Author:
9783ad972SXinliang Liu  *	Xinliang Liu <z.liuxinliang@hisilicon.com>
10783ad972SXinliang Liu  *	Xinliang Liu <xinliang.liu@linaro.org>
11783ad972SXinliang Liu  *	Xinwei Kong <kong.kongxinwei@hisilicon.com>
12783ad972SXinliang Liu  */
13783ad972SXinliang Liu 
14783ad972SXinliang Liu #include <linux/bitops.h>
15783ad972SXinliang Liu #include <linux/clk.h>
16783ad972SXinliang Liu #include <linux/mfd/syscon.h>
1740b4db43SSam Ravnborg #include <linux/platform_device.h>
18783ad972SXinliang Liu #include <linux/regmap.h>
19783ad972SXinliang Liu #include <linux/reset.h>
20783ad972SXinliang Liu 
2140b4db43SSam Ravnborg #include <video/display_timing.h>
2240b4db43SSam Ravnborg 
23783ad972SXinliang Liu #include <drm/drm_atomic.h>
24783ad972SXinliang Liu #include <drm/drm_atomic_helper.h>
25fcd70cd3SDaniel Vetter #include <drm/drm_crtc.h>
2640b4db43SSam Ravnborg #include <drm/drm_drv.h>
276bcfe8eaSDanilo Krummrich #include <drm/drm_fb_dma_helper.h>
2840b4db43SSam Ravnborg #include <drm/drm_fourcc.h>
29720cf96dSVille Syrjälä #include <drm/drm_framebuffer.h>
304a83c26aSDanilo Krummrich #include <drm/drm_gem_dma_helper.h>
31fcd70cd3SDaniel Vetter #include <drm/drm_probe_helper.h>
3240b4db43SSam Ravnborg #include <drm/drm_vblank.h>
33bdaf419eSXu YiPing #include <drm/drm_gem_framebuffer_helper.h>
34783ad972SXinliang Liu 
35783ad972SXinliang Liu #include "kirin_drm_drv.h"
36783ad972SXinliang Liu #include "kirin_ade_reg.h"
37783ad972SXinliang Liu 
38d3c9a738SXinliang Liu #define OUT_OVLY	ADE_OVLY2 /* output overlay compositor */
39d3c9a738SXinliang Liu #define ADE_DEBUG	1
40d3c9a738SXinliang Liu 
41d3c9a738SXinliang Liu 
42783ad972SXinliang Liu struct ade_hw_ctx {
43783ad972SXinliang Liu 	void __iomem  *base;
44783ad972SXinliang Liu 	struct regmap *noc_regmap;
45783ad972SXinliang Liu 	struct clk *ade_core_clk;
46783ad972SXinliang Liu 	struct clk *media_noc_clk;
47783ad972SXinliang Liu 	struct clk *ade_pix_clk;
48783ad972SXinliang Liu 	struct reset_control *reset;
49783ad972SXinliang Liu 	bool power_on;
50783ad972SXinliang Liu 	int irq;
5136f8d22dSXu YiPing 
5236f8d22dSXu YiPing 	struct drm_crtc *crtc;
53783ad972SXinliang Liu };
54783ad972SXinliang Liu 
55c11a03f6SXu YiPing static const struct kirin_format ade_formats[] = {
56d3c9a738SXinliang Liu 	/* 16bpp RGB: */
57d3c9a738SXinliang Liu 	{ DRM_FORMAT_RGB565, ADE_RGB_565 },
58d3c9a738SXinliang Liu 	{ DRM_FORMAT_BGR565, ADE_BGR_565 },
59d3c9a738SXinliang Liu 	/* 24bpp RGB: */
60d3c9a738SXinliang Liu 	{ DRM_FORMAT_RGB888, ADE_RGB_888 },
61d3c9a738SXinliang Liu 	{ DRM_FORMAT_BGR888, ADE_BGR_888 },
62d3c9a738SXinliang Liu 	/* 32bpp [A]RGB: */
63d3c9a738SXinliang Liu 	{ DRM_FORMAT_XRGB8888, ADE_XRGB_8888 },
64d3c9a738SXinliang Liu 	{ DRM_FORMAT_XBGR8888, ADE_XBGR_8888 },
65d3c9a738SXinliang Liu 	{ DRM_FORMAT_RGBA8888, ADE_RGBA_8888 },
66d3c9a738SXinliang Liu 	{ DRM_FORMAT_BGRA8888, ADE_BGRA_8888 },
67d3c9a738SXinliang Liu 	{ DRM_FORMAT_ARGB8888, ADE_ARGB_8888 },
68d3c9a738SXinliang Liu 	{ DRM_FORMAT_ABGR8888, ADE_ABGR_8888 },
69d3c9a738SXinliang Liu };
70d3c9a738SXinliang Liu 
71e200d8ebSXu YiPing static const u32 channel_formats[] = {
72d3c9a738SXinliang Liu 	/* channel 1,2,3,4 */
73d3c9a738SXinliang Liu 	DRM_FORMAT_RGB565, DRM_FORMAT_BGR565, DRM_FORMAT_RGB888,
74d3c9a738SXinliang Liu 	DRM_FORMAT_BGR888, DRM_FORMAT_XRGB8888, DRM_FORMAT_XBGR8888,
75d3c9a738SXinliang Liu 	DRM_FORMAT_RGBA8888, DRM_FORMAT_BGRA8888, DRM_FORMAT_ARGB8888,
76d3c9a738SXinliang Liu 	DRM_FORMAT_ABGR8888
77d3c9a738SXinliang Liu };
78d3c9a738SXinliang Liu 
79d3c9a738SXinliang Liu /* convert from fourcc format to ade format */
ade_get_format(u32 pixel_format)80d3c9a738SXinliang Liu static u32 ade_get_format(u32 pixel_format)
81d3c9a738SXinliang Liu {
82d3c9a738SXinliang Liu 	int i;
83d3c9a738SXinliang Liu 
84d3c9a738SXinliang Liu 	for (i = 0; i < ARRAY_SIZE(ade_formats); i++)
85d3c9a738SXinliang Liu 		if (ade_formats[i].pixel_format == pixel_format)
86c11a03f6SXu YiPing 			return ade_formats[i].hw_format;
87d3c9a738SXinliang Liu 
88d3c9a738SXinliang Liu 	/* not found */
89d3c9a738SXinliang Liu 	DRM_ERROR("Not found pixel format!!fourcc_format= %d\n",
90d3c9a738SXinliang Liu 		  pixel_format);
91d3c9a738SXinliang Liu 	return ADE_FORMAT_UNSUPPORT;
92d3c9a738SXinliang Liu }
93d3c9a738SXinliang Liu 
ade_update_reload_bit(void __iomem * base,u32 bit_num,u32 val)94783ad972SXinliang Liu static void ade_update_reload_bit(void __iomem *base, u32 bit_num, u32 val)
95783ad972SXinliang Liu {
96783ad972SXinliang Liu 	u32 bit_ofst, reg_num;
97783ad972SXinliang Liu 
98783ad972SXinliang Liu 	bit_ofst = bit_num % 32;
99783ad972SXinliang Liu 	reg_num = bit_num / 32;
100783ad972SXinliang Liu 
101783ad972SXinliang Liu 	ade_update_bits(base + ADE_RELOAD_DIS(reg_num), bit_ofst,
102783ad972SXinliang Liu 			MASK(1), !!val);
103783ad972SXinliang Liu }
104783ad972SXinliang Liu 
ade_read_reload_bit(void __iomem * base,u32 bit_num)105783ad972SXinliang Liu static u32 ade_read_reload_bit(void __iomem *base, u32 bit_num)
106783ad972SXinliang Liu {
107783ad972SXinliang Liu 	u32 tmp, bit_ofst, reg_num;
108783ad972SXinliang Liu 
109783ad972SXinliang Liu 	bit_ofst = bit_num % 32;
110783ad972SXinliang Liu 	reg_num = bit_num / 32;
111783ad972SXinliang Liu 
112783ad972SXinliang Liu 	tmp = readl(base + ADE_RELOAD_DIS(reg_num));
113783ad972SXinliang Liu 	return !!(BIT(bit_ofst) & tmp);
114783ad972SXinliang Liu }
115783ad972SXinliang Liu 
ade_init(struct ade_hw_ctx * ctx)116783ad972SXinliang Liu static void ade_init(struct ade_hw_ctx *ctx)
117783ad972SXinliang Liu {
118783ad972SXinliang Liu 	void __iomem *base = ctx->base;
119783ad972SXinliang Liu 
120783ad972SXinliang Liu 	/* enable clk gate */
121783ad972SXinliang Liu 	ade_update_bits(base + ADE_CTRL1, AUTO_CLK_GATE_EN_OFST,
122783ad972SXinliang Liu 			AUTO_CLK_GATE_EN, ADE_ENABLE);
123783ad972SXinliang Liu 	/* clear overlay */
124783ad972SXinliang Liu 	writel(0, base + ADE_OVLY1_TRANS_CFG);
125783ad972SXinliang Liu 	writel(0, base + ADE_OVLY_CTL);
126d3c9a738SXinliang Liu 	writel(0, base + ADE_OVLYX_CTL(OUT_OVLY));
127783ad972SXinliang Liu 	/* clear reset and reload regs */
128783ad972SXinliang Liu 	writel(MASK(32), base + ADE_SOFT_RST_SEL(0));
129783ad972SXinliang Liu 	writel(MASK(32), base + ADE_SOFT_RST_SEL(1));
130783ad972SXinliang Liu 	writel(MASK(32), base + ADE_RELOAD_DIS(0));
131783ad972SXinliang Liu 	writel(MASK(32), base + ADE_RELOAD_DIS(1));
132783ad972SXinliang Liu 	/*
133783ad972SXinliang Liu 	 * for video mode, all the ade registers should
134783ad972SXinliang Liu 	 * become effective at frame end.
135783ad972SXinliang Liu 	 */
136783ad972SXinliang Liu 	ade_update_bits(base + ADE_CTRL, FRM_END_START_OFST,
137783ad972SXinliang Liu 			FRM_END_START_MASK, REG_EFFECTIVE_IN_ADEEN_FRMEND);
138783ad972SXinliang Liu }
139783ad972SXinliang Liu 
ade_crtc_mode_fixup(struct drm_crtc * crtc,const struct drm_display_mode * mode,struct drm_display_mode * adjusted_mode)14071f23543SJohn Stultz static bool ade_crtc_mode_fixup(struct drm_crtc *crtc,
14171f23543SJohn Stultz 				const struct drm_display_mode *mode,
14271f23543SJohn Stultz 				struct drm_display_mode *adjusted_mode)
14371f23543SJohn Stultz {
144ada7f67dSXu YiPing 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
145ada7f67dSXu YiPing 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
14671f23543SJohn Stultz 
14771f23543SJohn Stultz 	adjusted_mode->clock =
14871f23543SJohn Stultz 		clk_round_rate(ctx->ade_pix_clk, mode->clock * 1000) / 1000;
14971f23543SJohn Stultz 	return true;
15071f23543SJohn Stultz }
15171f23543SJohn Stultz 
15271f23543SJohn Stultz 
ade_set_pix_clk(struct ade_hw_ctx * ctx,struct drm_display_mode * mode,struct drm_display_mode * adj_mode)153783ad972SXinliang Liu static void ade_set_pix_clk(struct ade_hw_ctx *ctx,
154783ad972SXinliang Liu 			    struct drm_display_mode *mode,
155783ad972SXinliang Liu 			    struct drm_display_mode *adj_mode)
156783ad972SXinliang Liu {
157783ad972SXinliang Liu 	u32 clk_Hz = mode->clock * 1000;
158783ad972SXinliang Liu 	int ret;
159783ad972SXinliang Liu 
160783ad972SXinliang Liu 	/*
161783ad972SXinliang Liu 	 * Success should be guaranteed in mode_valid call back,
162783ad972SXinliang Liu 	 * so failure shouldn't happen here
163783ad972SXinliang Liu 	 */
164783ad972SXinliang Liu 	ret = clk_set_rate(ctx->ade_pix_clk, clk_Hz);
165783ad972SXinliang Liu 	if (ret)
166783ad972SXinliang Liu 		DRM_ERROR("failed to set pixel clk %dHz (%d)\n", clk_Hz, ret);
167783ad972SXinliang Liu 	adj_mode->clock = clk_get_rate(ctx->ade_pix_clk) / 1000;
168783ad972SXinliang Liu }
169783ad972SXinliang Liu 
ade_ldi_set_mode(struct ade_hw_ctx * ctx,struct drm_display_mode * mode,struct drm_display_mode * adj_mode)170e0d8eba5SXu YiPing static void ade_ldi_set_mode(struct ade_hw_ctx *ctx,
171783ad972SXinliang Liu 			     struct drm_display_mode *mode,
172783ad972SXinliang Liu 			     struct drm_display_mode *adj_mode)
173783ad972SXinliang Liu {
174783ad972SXinliang Liu 	void __iomem *base = ctx->base;
175783ad972SXinliang Liu 	u32 width = mode->hdisplay;
176783ad972SXinliang Liu 	u32 height = mode->vdisplay;
177783ad972SXinliang Liu 	u32 hfp, hbp, hsw, vfp, vbp, vsw;
178783ad972SXinliang Liu 	u32 plr_flags;
179783ad972SXinliang Liu 
180783ad972SXinliang Liu 	plr_flags = (mode->flags & DRM_MODE_FLAG_NVSYNC) ? FLAG_NVSYNC : 0;
181783ad972SXinliang Liu 	plr_flags |= (mode->flags & DRM_MODE_FLAG_NHSYNC) ? FLAG_NHSYNC : 0;
182783ad972SXinliang Liu 	hfp = mode->hsync_start - mode->hdisplay;
183783ad972SXinliang Liu 	hbp = mode->htotal - mode->hsync_end;
184783ad972SXinliang Liu 	hsw = mode->hsync_end - mode->hsync_start;
185783ad972SXinliang Liu 	vfp = mode->vsync_start - mode->vdisplay;
186783ad972SXinliang Liu 	vbp = mode->vtotal - mode->vsync_end;
187783ad972SXinliang Liu 	vsw = mode->vsync_end - mode->vsync_start;
188783ad972SXinliang Liu 	if (vsw > 15) {
189783ad972SXinliang Liu 		DRM_DEBUG_DRIVER("vsw exceeded 15\n");
190783ad972SXinliang Liu 		vsw = 15;
191783ad972SXinliang Liu 	}
192783ad972SXinliang Liu 
193783ad972SXinliang Liu 	writel((hbp << HBP_OFST) | hfp, base + LDI_HRZ_CTRL0);
194783ad972SXinliang Liu 	 /* the configured value is actual value - 1 */
195783ad972SXinliang Liu 	writel(hsw - 1, base + LDI_HRZ_CTRL1);
196783ad972SXinliang Liu 	writel((vbp << VBP_OFST) | vfp, base + LDI_VRT_CTRL0);
197783ad972SXinliang Liu 	 /* the configured value is actual value - 1 */
198783ad972SXinliang Liu 	writel(vsw - 1, base + LDI_VRT_CTRL1);
199783ad972SXinliang Liu 	 /* the configured value is actual value - 1 */
200783ad972SXinliang Liu 	writel(((height - 1) << VSIZE_OFST) | (width - 1),
201783ad972SXinliang Liu 	       base + LDI_DSP_SIZE);
202783ad972SXinliang Liu 	writel(plr_flags, base + LDI_PLR_CTRL);
203783ad972SXinliang Liu 
204d3c9a738SXinliang Liu 	/* set overlay compositor output size */
205d3c9a738SXinliang Liu 	writel(((width - 1) << OUTPUT_XSIZE_OFST) | (height - 1),
206d3c9a738SXinliang Liu 	       base + ADE_OVLY_OUTPUT_SIZE(OUT_OVLY));
207d3c9a738SXinliang Liu 
208783ad972SXinliang Liu 	/* ctran6 setting */
209783ad972SXinliang Liu 	writel(CTRAN_BYPASS_ON, base + ADE_CTRAN_DIS(ADE_CTRAN6));
210783ad972SXinliang Liu 	 /* the configured value is actual value - 1 */
211783ad972SXinliang Liu 	writel(width * height - 1, base + ADE_CTRAN_IMAGE_SIZE(ADE_CTRAN6));
212783ad972SXinliang Liu 	ade_update_reload_bit(base, CTRAN_OFST + ADE_CTRAN6, 0);
213783ad972SXinliang Liu 
214783ad972SXinliang Liu 	ade_set_pix_clk(ctx, mode, adj_mode);
215783ad972SXinliang Liu 
216783ad972SXinliang Liu 	DRM_DEBUG_DRIVER("set mode: %dx%d\n", width, height);
217783ad972SXinliang Liu }
218783ad972SXinliang Liu 
ade_power_up(struct ade_hw_ctx * ctx)219783ad972SXinliang Liu static int ade_power_up(struct ade_hw_ctx *ctx)
220783ad972SXinliang Liu {
221783ad972SXinliang Liu 	int ret;
222783ad972SXinliang Liu 
223783ad972SXinliang Liu 	ret = clk_prepare_enable(ctx->media_noc_clk);
224783ad972SXinliang Liu 	if (ret) {
225783ad972SXinliang Liu 		DRM_ERROR("failed to enable media_noc_clk (%d)\n", ret);
226783ad972SXinliang Liu 		return ret;
227783ad972SXinliang Liu 	}
228783ad972SXinliang Liu 
229783ad972SXinliang Liu 	ret = reset_control_deassert(ctx->reset);
230783ad972SXinliang Liu 	if (ret) {
231783ad972SXinliang Liu 		DRM_ERROR("failed to deassert reset\n");
232783ad972SXinliang Liu 		return ret;
233783ad972SXinliang Liu 	}
234783ad972SXinliang Liu 
235783ad972SXinliang Liu 	ret = clk_prepare_enable(ctx->ade_core_clk);
236783ad972SXinliang Liu 	if (ret) {
237783ad972SXinliang Liu 		DRM_ERROR("failed to enable ade_core_clk (%d)\n", ret);
238783ad972SXinliang Liu 		return ret;
239783ad972SXinliang Liu 	}
240783ad972SXinliang Liu 
241783ad972SXinliang Liu 	ade_init(ctx);
242783ad972SXinliang Liu 	ctx->power_on = true;
243783ad972SXinliang Liu 	return 0;
244783ad972SXinliang Liu }
245783ad972SXinliang Liu 
ade_power_down(struct ade_hw_ctx * ctx)246783ad972SXinliang Liu static void ade_power_down(struct ade_hw_ctx *ctx)
247783ad972SXinliang Liu {
248783ad972SXinliang Liu 	void __iomem *base = ctx->base;
249783ad972SXinliang Liu 
250783ad972SXinliang Liu 	writel(ADE_DISABLE, base + LDI_CTRL);
251783ad972SXinliang Liu 	/* dsi pixel off */
252783ad972SXinliang Liu 	writel(DSI_PCLK_OFF, base + LDI_HDMI_DSI_GT);
253783ad972SXinliang Liu 
254783ad972SXinliang Liu 	clk_disable_unprepare(ctx->ade_core_clk);
255783ad972SXinliang Liu 	reset_control_assert(ctx->reset);
256783ad972SXinliang Liu 	clk_disable_unprepare(ctx->media_noc_clk);
257783ad972SXinliang Liu 	ctx->power_on = false;
258783ad972SXinliang Liu }
259783ad972SXinliang Liu 
ade_set_medianoc_qos(struct ade_hw_ctx * ctx)260e0d8eba5SXu YiPing static void ade_set_medianoc_qos(struct ade_hw_ctx *ctx)
261783ad972SXinliang Liu {
262783ad972SXinliang Liu 	struct regmap *map = ctx->noc_regmap;
263783ad972SXinliang Liu 
264783ad972SXinliang Liu 	regmap_update_bits(map, ADE0_QOSGENERATOR_MODE,
265783ad972SXinliang Liu 			   QOSGENERATOR_MODE_MASK, BYPASS_MODE);
266783ad972SXinliang Liu 	regmap_update_bits(map, ADE0_QOSGENERATOR_EXTCONTROL,
267783ad972SXinliang Liu 			   SOCKET_QOS_EN, SOCKET_QOS_EN);
268783ad972SXinliang Liu 
269783ad972SXinliang Liu 	regmap_update_bits(map, ADE1_QOSGENERATOR_MODE,
270783ad972SXinliang Liu 			   QOSGENERATOR_MODE_MASK, BYPASS_MODE);
271783ad972SXinliang Liu 	regmap_update_bits(map, ADE1_QOSGENERATOR_EXTCONTROL,
272783ad972SXinliang Liu 			   SOCKET_QOS_EN, SOCKET_QOS_EN);
273783ad972SXinliang Liu }
274783ad972SXinliang Liu 
ade_crtc_enable_vblank(struct drm_crtc * crtc)275d4f6750fSShawn Guo static int ade_crtc_enable_vblank(struct drm_crtc *crtc)
276bc4611e8SXinliang Liu {
277ada7f67dSXu YiPing 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
278ada7f67dSXu YiPing 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
279bc4611e8SXinliang Liu 	void __iomem *base = ctx->base;
280bc4611e8SXinliang Liu 
281bc4611e8SXinliang Liu 	if (!ctx->power_on)
282bc4611e8SXinliang Liu 		(void)ade_power_up(ctx);
283bc4611e8SXinliang Liu 
284bc4611e8SXinliang Liu 	ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST,
285bc4611e8SXinliang Liu 			MASK(1), 1);
286bc4611e8SXinliang Liu 
287bc4611e8SXinliang Liu 	return 0;
288bc4611e8SXinliang Liu }
289bc4611e8SXinliang Liu 
ade_crtc_disable_vblank(struct drm_crtc * crtc)290d4f6750fSShawn Guo static void ade_crtc_disable_vblank(struct drm_crtc *crtc)
291bc4611e8SXinliang Liu {
292ada7f67dSXu YiPing 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
293ada7f67dSXu YiPing 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
294bc4611e8SXinliang Liu 	void __iomem *base = ctx->base;
295bc4611e8SXinliang Liu 
296bc4611e8SXinliang Liu 	if (!ctx->power_on) {
297bc4611e8SXinliang Liu 		DRM_ERROR("power is down! vblank disable fail\n");
298bc4611e8SXinliang Liu 		return;
299bc4611e8SXinliang Liu 	}
300bc4611e8SXinliang Liu 
301bc4611e8SXinliang Liu 	ade_update_bits(base + LDI_INT_EN, FRAME_END_INT_EN_OFST,
302bc4611e8SXinliang Liu 			MASK(1), 0);
303bc4611e8SXinliang Liu }
304bc4611e8SXinliang Liu 
ade_irq_handler(int irq,void * data)305bc4611e8SXinliang Liu static irqreturn_t ade_irq_handler(int irq, void *data)
306bc4611e8SXinliang Liu {
30736f8d22dSXu YiPing 	struct ade_hw_ctx *ctx = data;
30836f8d22dSXu YiPing 	struct drm_crtc *crtc = ctx->crtc;
309bc4611e8SXinliang Liu 	void __iomem *base = ctx->base;
310bc4611e8SXinliang Liu 	u32 status;
311bc4611e8SXinliang Liu 
312bc4611e8SXinliang Liu 	status = readl(base + LDI_MSK_INT);
313bc4611e8SXinliang Liu 	DRM_DEBUG_VBL("LDI IRQ: status=0x%X\n", status);
314bc4611e8SXinliang Liu 
315bc4611e8SXinliang Liu 	/* vblank irq */
316bc4611e8SXinliang Liu 	if (status & BIT(FRAME_END_INT_EN_OFST)) {
317bc4611e8SXinliang Liu 		ade_update_bits(base + LDI_INT_CLR, FRAME_END_INT_EN_OFST,
318bc4611e8SXinliang Liu 				MASK(1), 1);
319bc4611e8SXinliang Liu 		drm_crtc_handle_vblank(crtc);
320bc4611e8SXinliang Liu 	}
321bc4611e8SXinliang Liu 
322bc4611e8SXinliang Liu 	return IRQ_HANDLED;
323bc4611e8SXinliang Liu }
324bc4611e8SXinliang Liu 
ade_display_enable(struct ade_hw_ctx * ctx)325a202da16SXu YiPing static void ade_display_enable(struct ade_hw_ctx *ctx)
326783ad972SXinliang Liu {
327783ad972SXinliang Liu 	void __iomem *base = ctx->base;
328a202da16SXu YiPing 	u32 out_fmt = LDI_OUT_RGB_888;
329783ad972SXinliang Liu 
330d3c9a738SXinliang Liu 	/* enable output overlay compositor */
331d3c9a738SXinliang Liu 	writel(ADE_ENABLE, base + ADE_OVLYX_CTL(OUT_OVLY));
332d3c9a738SXinliang Liu 	ade_update_reload_bit(base, OVLY_OFST + OUT_OVLY, 0);
333d3c9a738SXinliang Liu 
334783ad972SXinliang Liu 	/* display source setting */
335783ad972SXinliang Liu 	writel(DISP_SRC_OVLY2, base + ADE_DISP_SRC_CFG);
336783ad972SXinliang Liu 
337783ad972SXinliang Liu 	/* enable ade */
338783ad972SXinliang Liu 	writel(ADE_ENABLE, base + ADE_EN);
339783ad972SXinliang Liu 	/* enable ldi */
340783ad972SXinliang Liu 	writel(NORMAL_MODE, base + LDI_WORK_MODE);
341783ad972SXinliang Liu 	writel((out_fmt << BPP_OFST) | DATA_GATE_EN | LDI_EN,
342783ad972SXinliang Liu 	       base + LDI_CTRL);
343783ad972SXinliang Liu 	/* dsi pixel on */
344783ad972SXinliang Liu 	writel(DSI_PCLK_ON, base + LDI_HDMI_DSI_GT);
345783ad972SXinliang Liu }
346783ad972SXinliang Liu 
347d3c9a738SXinliang Liu #if ADE_DEBUG
ade_rdma_dump_regs(void __iomem * base,u32 ch)348d3c9a738SXinliang Liu static void ade_rdma_dump_regs(void __iomem *base, u32 ch)
349d3c9a738SXinliang Liu {
350d3c9a738SXinliang Liu 	u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
351d3c9a738SXinliang Liu 	u32 val;
352d3c9a738SXinliang Liu 
353d3c9a738SXinliang Liu 	reg_ctrl = RD_CH_CTRL(ch);
354d3c9a738SXinliang Liu 	reg_addr = RD_CH_ADDR(ch);
355d3c9a738SXinliang Liu 	reg_size = RD_CH_SIZE(ch);
356d3c9a738SXinliang Liu 	reg_stride = RD_CH_STRIDE(ch);
357d3c9a738SXinliang Liu 	reg_space = RD_CH_SPACE(ch);
358d3c9a738SXinliang Liu 	reg_en = RD_CH_EN(ch);
359d3c9a738SXinliang Liu 
360d3c9a738SXinliang Liu 	val = ade_read_reload_bit(base, RDMA_OFST + ch);
361d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[rdma%d]: reload(%d)\n", ch + 1, val);
362d3c9a738SXinliang Liu 	val = readl(base + reg_ctrl);
363d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[rdma%d]: reg_ctrl(0x%08x)\n", ch + 1, val);
364d3c9a738SXinliang Liu 	val = readl(base + reg_addr);
365d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[rdma%d]: reg_addr(0x%08x)\n", ch + 1, val);
366d3c9a738SXinliang Liu 	val = readl(base + reg_size);
367d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[rdma%d]: reg_size(0x%08x)\n", ch + 1, val);
368d3c9a738SXinliang Liu 	val = readl(base + reg_stride);
369d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[rdma%d]: reg_stride(0x%08x)\n", ch + 1, val);
370d3c9a738SXinliang Liu 	val = readl(base + reg_space);
371d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[rdma%d]: reg_space(0x%08x)\n", ch + 1, val);
372d3c9a738SXinliang Liu 	val = readl(base + reg_en);
373d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[rdma%d]: reg_en(0x%08x)\n", ch + 1, val);
374d3c9a738SXinliang Liu }
375d3c9a738SXinliang Liu 
ade_clip_dump_regs(void __iomem * base,u32 ch)376d3c9a738SXinliang Liu static void ade_clip_dump_regs(void __iomem *base, u32 ch)
377d3c9a738SXinliang Liu {
378d3c9a738SXinliang Liu 	u32 val;
379d3c9a738SXinliang Liu 
380d3c9a738SXinliang Liu 	val = ade_read_reload_bit(base, CLIP_OFST + ch);
381d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[clip%d]: reload(%d)\n", ch + 1, val);
382d3c9a738SXinliang Liu 	val = readl(base + ADE_CLIP_DISABLE(ch));
383d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[clip%d]: reg_clip_disable(0x%08x)\n", ch + 1, val);
384d3c9a738SXinliang Liu 	val = readl(base + ADE_CLIP_SIZE0(ch));
385d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size0(0x%08x)\n", ch + 1, val);
386d3c9a738SXinliang Liu 	val = readl(base + ADE_CLIP_SIZE1(ch));
387d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[clip%d]: reg_clip_size1(0x%08x)\n", ch + 1, val);
388d3c9a738SXinliang Liu }
389d3c9a738SXinliang Liu 
ade_compositor_routing_dump_regs(void __iomem * base,u32 ch)390d3c9a738SXinliang Liu static void ade_compositor_routing_dump_regs(void __iomem *base, u32 ch)
391d3c9a738SXinliang Liu {
392d3c9a738SXinliang Liu 	u8 ovly_ch = 0; /* TODO: Only primary plane now */
393d3c9a738SXinliang Liu 	u32 val;
394d3c9a738SXinliang Liu 
395d3c9a738SXinliang Liu 	val = readl(base + ADE_OVLY_CH_XY0(ovly_ch));
396d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy0(0x%08x)\n", ovly_ch, val);
397d3c9a738SXinliang Liu 	val = readl(base + ADE_OVLY_CH_XY1(ovly_ch));
398d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_xy1(0x%08x)\n", ovly_ch, val);
399d3c9a738SXinliang Liu 	val = readl(base + ADE_OVLY_CH_CTL(ovly_ch));
400d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[overlay ch%d]: reg_ch_ctl(0x%08x)\n", ovly_ch, val);
401d3c9a738SXinliang Liu }
402d3c9a738SXinliang Liu 
ade_dump_overlay_compositor_regs(void __iomem * base,u32 comp)403d3c9a738SXinliang Liu static void ade_dump_overlay_compositor_regs(void __iomem *base, u32 comp)
404d3c9a738SXinliang Liu {
405d3c9a738SXinliang Liu 	u32 val;
406d3c9a738SXinliang Liu 
407d3c9a738SXinliang Liu 	val = ade_read_reload_bit(base, OVLY_OFST + comp);
408d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[overlay%d]: reload(%d)\n", comp + 1, val);
409d3c9a738SXinliang Liu 	writel(ADE_ENABLE, base + ADE_OVLYX_CTL(comp));
410d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("[overlay%d]: reg_ctl(0x%08x)\n", comp + 1, val);
411d3c9a738SXinliang Liu 	val = readl(base + ADE_OVLY_CTL);
412d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("ovly_ctl(0x%08x)\n", val);
413d3c9a738SXinliang Liu }
414d3c9a738SXinliang Liu 
ade_dump_regs(void __iomem * base)415d3c9a738SXinliang Liu static void ade_dump_regs(void __iomem *base)
416d3c9a738SXinliang Liu {
417d3c9a738SXinliang Liu 	u32 i;
418d3c9a738SXinliang Liu 
419d3c9a738SXinliang Liu 	/* dump channel regs */
420d3c9a738SXinliang Liu 	for (i = 0; i < ADE_CH_NUM; i++) {
421d3c9a738SXinliang Liu 		/* dump rdma regs */
422d3c9a738SXinliang Liu 		ade_rdma_dump_regs(base, i);
423d3c9a738SXinliang Liu 
424d3c9a738SXinliang Liu 		/* dump clip regs */
425d3c9a738SXinliang Liu 		ade_clip_dump_regs(base, i);
426d3c9a738SXinliang Liu 
427d3c9a738SXinliang Liu 		/* dump compositor routing regs */
428d3c9a738SXinliang Liu 		ade_compositor_routing_dump_regs(base, i);
429d3c9a738SXinliang Liu 	}
430d3c9a738SXinliang Liu 
431d3c9a738SXinliang Liu 	/* dump overlay compositor regs */
432d3c9a738SXinliang Liu 	ade_dump_overlay_compositor_regs(base, OUT_OVLY);
433d3c9a738SXinliang Liu }
434d3c9a738SXinliang Liu #else
ade_dump_regs(void __iomem * base)435d3c9a738SXinliang Liu static void ade_dump_regs(void __iomem *base) { }
436d3c9a738SXinliang Liu #endif
437d3c9a738SXinliang Liu 
ade_crtc_atomic_enable(struct drm_crtc * crtc,struct drm_atomic_state * state)4380b20a0f8SLaurent Pinchart static void ade_crtc_atomic_enable(struct drm_crtc *crtc,
439351f950dSMaxime Ripard 				   struct drm_atomic_state *state)
440783ad972SXinliang Liu {
441ada7f67dSXu YiPing 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
442ada7f67dSXu YiPing 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
443783ad972SXinliang Liu 	int ret;
444783ad972SXinliang Liu 
445ada7f67dSXu YiPing 	if (kcrtc->enable)
446783ad972SXinliang Liu 		return;
447783ad972SXinliang Liu 
448783ad972SXinliang Liu 	if (!ctx->power_on) {
449783ad972SXinliang Liu 		ret = ade_power_up(ctx);
450783ad972SXinliang Liu 		if (ret)
451783ad972SXinliang Liu 			return;
452783ad972SXinliang Liu 	}
453783ad972SXinliang Liu 
454e0d8eba5SXu YiPing 	ade_set_medianoc_qos(ctx);
455a202da16SXu YiPing 	ade_display_enable(ctx);
456d3c9a738SXinliang Liu 	ade_dump_regs(ctx->base);
45785d8747dSXinliang Liu 	drm_crtc_vblank_on(crtc);
458ada7f67dSXu YiPing 	kcrtc->enable = true;
459783ad972SXinliang Liu }
460783ad972SXinliang Liu 
ade_crtc_atomic_disable(struct drm_crtc * crtc,struct drm_atomic_state * state)46164581714SLaurent Pinchart static void ade_crtc_atomic_disable(struct drm_crtc *crtc,
462351f950dSMaxime Ripard 				    struct drm_atomic_state *state)
463783ad972SXinliang Liu {
464ada7f67dSXu YiPing 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
465ada7f67dSXu YiPing 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
466783ad972SXinliang Liu 
467ada7f67dSXu YiPing 	if (!kcrtc->enable)
468783ad972SXinliang Liu 		return;
469783ad972SXinliang Liu 
47085d8747dSXinliang Liu 	drm_crtc_vblank_off(crtc);
471783ad972SXinliang Liu 	ade_power_down(ctx);
472ada7f67dSXu YiPing 	kcrtc->enable = false;
473783ad972SXinliang Liu }
474783ad972SXinliang Liu 
ade_crtc_mode_set_nofb(struct drm_crtc * crtc)475783ad972SXinliang Liu static void ade_crtc_mode_set_nofb(struct drm_crtc *crtc)
476783ad972SXinliang Liu {
477ada7f67dSXu YiPing 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
478ada7f67dSXu YiPing 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
479783ad972SXinliang Liu 	struct drm_display_mode *mode = &crtc->state->mode;
480783ad972SXinliang Liu 	struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode;
481783ad972SXinliang Liu 
482783ad972SXinliang Liu 	if (!ctx->power_on)
483783ad972SXinliang Liu 		(void)ade_power_up(ctx);
484e0d8eba5SXu YiPing 	ade_ldi_set_mode(ctx, mode, adj_mode);
485783ad972SXinliang Liu }
486783ad972SXinliang Liu 
ade_crtc_atomic_begin(struct drm_crtc * crtc,struct drm_atomic_state * state)487783ad972SXinliang Liu static void ade_crtc_atomic_begin(struct drm_crtc *crtc,
488f6ebe9f9SMaxime Ripard 				  struct drm_atomic_state *state)
489783ad972SXinliang Liu {
490ada7f67dSXu YiPing 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
491ada7f67dSXu YiPing 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
492a2f04243SPeter Griffin 	struct drm_display_mode *mode = &crtc->state->mode;
493a2f04243SPeter Griffin 	struct drm_display_mode *adj_mode = &crtc->state->adjusted_mode;
494783ad972SXinliang Liu 
495783ad972SXinliang Liu 	if (!ctx->power_on)
496783ad972SXinliang Liu 		(void)ade_power_up(ctx);
497e0d8eba5SXu YiPing 	ade_ldi_set_mode(ctx, mode, adj_mode);
498783ad972SXinliang Liu }
499783ad972SXinliang Liu 
ade_crtc_atomic_flush(struct drm_crtc * crtc,struct drm_atomic_state * state)500783ad972SXinliang Liu static void ade_crtc_atomic_flush(struct drm_crtc *crtc,
501f6ebe9f9SMaxime Ripard 				  struct drm_atomic_state *state)
502783ad972SXinliang Liu 
503783ad972SXinliang Liu {
504ada7f67dSXu YiPing 	struct kirin_crtc *kcrtc = to_kirin_crtc(crtc);
505ada7f67dSXu YiPing 	struct ade_hw_ctx *ctx = kcrtc->hw_ctx;
50630bb70eeSDaniel Vetter 	struct drm_pending_vblank_event *event = crtc->state->event;
507783ad972SXinliang Liu 	void __iomem *base = ctx->base;
508783ad972SXinliang Liu 
509783ad972SXinliang Liu 	/* only crtc is enabled regs take effect */
510ada7f67dSXu YiPing 	if (kcrtc->enable) {
511d3c9a738SXinliang Liu 		ade_dump_regs(base);
512783ad972SXinliang Liu 		/* flush ade registers */
513783ad972SXinliang Liu 		writel(ADE_ENABLE, base + ADE_EN);
514783ad972SXinliang Liu 	}
51530bb70eeSDaniel Vetter 
51630bb70eeSDaniel Vetter 	if (event) {
51730bb70eeSDaniel Vetter 		crtc->state->event = NULL;
51830bb70eeSDaniel Vetter 
51930bb70eeSDaniel Vetter 		spin_lock_irq(&crtc->dev->event_lock);
52030bb70eeSDaniel Vetter 		if (drm_crtc_vblank_get(crtc) == 0)
52130bb70eeSDaniel Vetter 			drm_crtc_arm_vblank_event(crtc, event);
52230bb70eeSDaniel Vetter 		else
52330bb70eeSDaniel Vetter 			drm_crtc_send_vblank_event(crtc, event);
52430bb70eeSDaniel Vetter 		spin_unlock_irq(&crtc->dev->event_lock);
52530bb70eeSDaniel Vetter 	}
526783ad972SXinliang Liu }
527783ad972SXinliang Liu 
528783ad972SXinliang Liu static const struct drm_crtc_helper_funcs ade_crtc_helper_funcs = {
52971f23543SJohn Stultz 	.mode_fixup	= ade_crtc_mode_fixup,
530783ad972SXinliang Liu 	.mode_set_nofb	= ade_crtc_mode_set_nofb,
531783ad972SXinliang Liu 	.atomic_begin	= ade_crtc_atomic_begin,
532783ad972SXinliang Liu 	.atomic_flush	= ade_crtc_atomic_flush,
5330b20a0f8SLaurent Pinchart 	.atomic_enable	= ade_crtc_atomic_enable,
53464581714SLaurent Pinchart 	.atomic_disable	= ade_crtc_atomic_disable,
535783ad972SXinliang Liu };
536783ad972SXinliang Liu 
537783ad972SXinliang Liu static const struct drm_crtc_funcs ade_crtc_funcs = {
538783ad972SXinliang Liu 	.destroy	= drm_crtc_cleanup,
539783ad972SXinliang Liu 	.set_config	= drm_atomic_helper_set_config,
540783ad972SXinliang Liu 	.page_flip	= drm_atomic_helper_page_flip,
541783ad972SXinliang Liu 	.reset		= drm_atomic_helper_crtc_reset,
542783ad972SXinliang Liu 	.atomic_duplicate_state	= drm_atomic_helper_crtc_duplicate_state,
543783ad972SXinliang Liu 	.atomic_destroy_state	= drm_atomic_helper_crtc_destroy_state,
544d4f6750fSShawn Guo 	.enable_vblank	= ade_crtc_enable_vblank,
545d4f6750fSShawn Guo 	.disable_vblank	= ade_crtc_disable_vblank,
546783ad972SXinliang Liu };
547783ad972SXinliang Liu 
ade_rdma_set(void __iomem * base,struct drm_framebuffer * fb,u32 ch,u32 y,u32 in_h,u32 fmt)548d3c9a738SXinliang Liu static void ade_rdma_set(void __iomem *base, struct drm_framebuffer *fb,
549d3c9a738SXinliang Liu 			 u32 ch, u32 y, u32 in_h, u32 fmt)
550d3c9a738SXinliang Liu {
5514a83c26aSDanilo Krummrich 	struct drm_gem_dma_object *obj = drm_fb_dma_get_gem_obj(fb, 0);
552d3c9a738SXinliang Liu 	u32 reg_ctrl, reg_addr, reg_size, reg_stride, reg_space, reg_en;
553d3c9a738SXinliang Liu 	u32 stride = fb->pitches[0];
554*8c30eeccSDanilo Krummrich 	u32 addr = (u32) obj->dma_addr + y * stride;
555d3c9a738SXinliang Liu 
556d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("rdma%d: (y=%d, height=%d), stride=%d, paddr=0x%x\n",
557*8c30eeccSDanilo Krummrich 			 ch + 1, y, in_h, stride, (u32) obj->dma_addr);
55892f1d09cSSakari Ailus 	DRM_DEBUG_DRIVER("addr=0x%x, fb:%dx%d, pixel_format=%d(%p4cc)\n",
559b3c11ac2SEric Engestrom 			 addr, fb->width, fb->height, fmt,
56092f1d09cSSakari Ailus 			 &fb->format->format);
561d3c9a738SXinliang Liu 
562d3c9a738SXinliang Liu 	/* get reg offset */
563d3c9a738SXinliang Liu 	reg_ctrl = RD_CH_CTRL(ch);
564d3c9a738SXinliang Liu 	reg_addr = RD_CH_ADDR(ch);
565d3c9a738SXinliang Liu 	reg_size = RD_CH_SIZE(ch);
566d3c9a738SXinliang Liu 	reg_stride = RD_CH_STRIDE(ch);
567d3c9a738SXinliang Liu 	reg_space = RD_CH_SPACE(ch);
568d3c9a738SXinliang Liu 	reg_en = RD_CH_EN(ch);
569d3c9a738SXinliang Liu 
570d3c9a738SXinliang Liu 	/*
571d3c9a738SXinliang Liu 	 * TODO: set rotation
572d3c9a738SXinliang Liu 	 */
573d3c9a738SXinliang Liu 	writel((fmt << 16) & 0x1f0000, base + reg_ctrl);
574d3c9a738SXinliang Liu 	writel(addr, base + reg_addr);
575d3c9a738SXinliang Liu 	writel((in_h << 16) | stride, base + reg_size);
576d3c9a738SXinliang Liu 	writel(stride, base + reg_stride);
577d3c9a738SXinliang Liu 	writel(in_h * stride, base + reg_space);
578d3c9a738SXinliang Liu 	writel(ADE_ENABLE, base + reg_en);
579d3c9a738SXinliang Liu 	ade_update_reload_bit(base, RDMA_OFST + ch, 0);
580d3c9a738SXinliang Liu }
581d3c9a738SXinliang Liu 
ade_rdma_disable(void __iomem * base,u32 ch)582d3c9a738SXinliang Liu static void ade_rdma_disable(void __iomem *base, u32 ch)
583d3c9a738SXinliang Liu {
584d3c9a738SXinliang Liu 	u32 reg_en;
585d3c9a738SXinliang Liu 
586d3c9a738SXinliang Liu 	/* get reg offset */
587d3c9a738SXinliang Liu 	reg_en = RD_CH_EN(ch);
588d3c9a738SXinliang Liu 	writel(0, base + reg_en);
589d3c9a738SXinliang Liu 	ade_update_reload_bit(base, RDMA_OFST + ch, 1);
590d3c9a738SXinliang Liu }
591d3c9a738SXinliang Liu 
ade_clip_set(void __iomem * base,u32 ch,u32 fb_w,u32 x,u32 in_w,u32 in_h)592d3c9a738SXinliang Liu static void ade_clip_set(void __iomem *base, u32 ch, u32 fb_w, u32 x,
593d3c9a738SXinliang Liu 			 u32 in_w, u32 in_h)
594d3c9a738SXinliang Liu {
595d3c9a738SXinliang Liu 	u32 disable_val;
596d3c9a738SXinliang Liu 	u32 clip_left;
597d3c9a738SXinliang Liu 	u32 clip_right;
598d3c9a738SXinliang Liu 
599d3c9a738SXinliang Liu 	/*
600d3c9a738SXinliang Liu 	 * clip width, no need to clip height
601d3c9a738SXinliang Liu 	 */
602d3c9a738SXinliang Liu 	if (fb_w == in_w) { /* bypass */
603d3c9a738SXinliang Liu 		disable_val = 1;
604d3c9a738SXinliang Liu 		clip_left = 0;
605d3c9a738SXinliang Liu 		clip_right = 0;
606d3c9a738SXinliang Liu 	} else {
607d3c9a738SXinliang Liu 		disable_val = 0;
608d3c9a738SXinliang Liu 		clip_left = x;
609d3c9a738SXinliang Liu 		clip_right = fb_w - (x + in_w) - 1;
610d3c9a738SXinliang Liu 	}
611d3c9a738SXinliang Liu 
612d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("clip%d: clip_left=%d, clip_right=%d\n",
613d3c9a738SXinliang Liu 			 ch + 1, clip_left, clip_right);
614d3c9a738SXinliang Liu 
615d3c9a738SXinliang Liu 	writel(disable_val, base + ADE_CLIP_DISABLE(ch));
616d3c9a738SXinliang Liu 	writel((fb_w - 1) << 16 | (in_h - 1), base + ADE_CLIP_SIZE0(ch));
617d3c9a738SXinliang Liu 	writel(clip_left << 16 | clip_right, base + ADE_CLIP_SIZE1(ch));
618d3c9a738SXinliang Liu 	ade_update_reload_bit(base, CLIP_OFST + ch, 0);
619d3c9a738SXinliang Liu }
620d3c9a738SXinliang Liu 
ade_clip_disable(void __iomem * base,u32 ch)621d3c9a738SXinliang Liu static void ade_clip_disable(void __iomem *base, u32 ch)
622d3c9a738SXinliang Liu {
623d3c9a738SXinliang Liu 	writel(1, base + ADE_CLIP_DISABLE(ch));
624d3c9a738SXinliang Liu 	ade_update_reload_bit(base, CLIP_OFST + ch, 1);
625d3c9a738SXinliang Liu }
626d3c9a738SXinliang Liu 
has_Alpha_channel(int format)627d3c9a738SXinliang Liu static bool has_Alpha_channel(int format)
628d3c9a738SXinliang Liu {
629d3c9a738SXinliang Liu 	switch (format) {
630d3c9a738SXinliang Liu 	case ADE_ARGB_8888:
631d3c9a738SXinliang Liu 	case ADE_ABGR_8888:
632d3c9a738SXinliang Liu 	case ADE_RGBA_8888:
633d3c9a738SXinliang Liu 	case ADE_BGRA_8888:
634d3c9a738SXinliang Liu 		return true;
635d3c9a738SXinliang Liu 	default:
636d3c9a738SXinliang Liu 		return false;
637d3c9a738SXinliang Liu 	}
638d3c9a738SXinliang Liu }
639d3c9a738SXinliang Liu 
ade_get_blending_params(u32 fmt,u8 glb_alpha,u8 * alp_mode,u8 * alp_sel,u8 * under_alp_sel)640d3c9a738SXinliang Liu static void ade_get_blending_params(u32 fmt, u8 glb_alpha, u8 *alp_mode,
641d3c9a738SXinliang Liu 				    u8 *alp_sel, u8 *under_alp_sel)
642d3c9a738SXinliang Liu {
643d3c9a738SXinliang Liu 	bool has_alpha = has_Alpha_channel(fmt);
644d3c9a738SXinliang Liu 
645d3c9a738SXinliang Liu 	/*
646d3c9a738SXinliang Liu 	 * get alp_mode
647d3c9a738SXinliang Liu 	 */
648d3c9a738SXinliang Liu 	if (has_alpha && glb_alpha < 255)
649d3c9a738SXinliang Liu 		*alp_mode = ADE_ALP_PIXEL_AND_GLB;
650d3c9a738SXinliang Liu 	else if (has_alpha)
651d3c9a738SXinliang Liu 		*alp_mode = ADE_ALP_PIXEL;
652d3c9a738SXinliang Liu 	else
653d3c9a738SXinliang Liu 		*alp_mode = ADE_ALP_GLOBAL;
654d3c9a738SXinliang Liu 
655d3c9a738SXinliang Liu 	/*
656d3c9a738SXinliang Liu 	 * get alp sel
657d3c9a738SXinliang Liu 	 */
658d3c9a738SXinliang Liu 	*alp_sel = ADE_ALP_MUL_COEFF_3; /* 1 */
659d3c9a738SXinliang Liu 	*under_alp_sel = ADE_ALP_MUL_COEFF_2; /* 0 */
660d3c9a738SXinliang Liu }
661d3c9a738SXinliang Liu 
ade_compositor_routing_set(void __iomem * base,u8 ch,u32 x0,u32 y0,u32 in_w,u32 in_h,u32 fmt)662d3c9a738SXinliang Liu static void ade_compositor_routing_set(void __iomem *base, u8 ch,
663d3c9a738SXinliang Liu 				       u32 x0, u32 y0,
664d3c9a738SXinliang Liu 				       u32 in_w, u32 in_h, u32 fmt)
665d3c9a738SXinliang Liu {
666d3c9a738SXinliang Liu 	u8 ovly_ch = 0; /* TODO: This is the zpos, only one plane now */
667d3c9a738SXinliang Liu 	u8 glb_alpha = 255;
668d3c9a738SXinliang Liu 	u32 x1 = x0 + in_w - 1;
669d3c9a738SXinliang Liu 	u32 y1 = y0 + in_h - 1;
670d3c9a738SXinliang Liu 	u32 val;
671d3c9a738SXinliang Liu 	u8 alp_sel;
672d3c9a738SXinliang Liu 	u8 under_alp_sel;
673d3c9a738SXinliang Liu 	u8 alp_mode;
674d3c9a738SXinliang Liu 
675d3c9a738SXinliang Liu 	ade_get_blending_params(fmt, glb_alpha, &alp_mode, &alp_sel,
676d3c9a738SXinliang Liu 				&under_alp_sel);
677d3c9a738SXinliang Liu 
678d3c9a738SXinliang Liu 	/* overlay routing setting
679d3c9a738SXinliang Liu 	 */
680d3c9a738SXinliang Liu 	writel(x0 << 16 | y0, base + ADE_OVLY_CH_XY0(ovly_ch));
681d3c9a738SXinliang Liu 	writel(x1 << 16 | y1, base + ADE_OVLY_CH_XY1(ovly_ch));
682d3c9a738SXinliang Liu 	val = (ch + 1) << CH_SEL_OFST | BIT(CH_EN_OFST) |
683d3c9a738SXinliang Liu 		alp_sel << CH_ALP_SEL_OFST |
684d3c9a738SXinliang Liu 		under_alp_sel << CH_UNDER_ALP_SEL_OFST |
685d3c9a738SXinliang Liu 		glb_alpha << CH_ALP_GBL_OFST |
686d3c9a738SXinliang Liu 		alp_mode << CH_ALP_MODE_OFST;
687d3c9a738SXinliang Liu 	writel(val, base + ADE_OVLY_CH_CTL(ovly_ch));
688d3c9a738SXinliang Liu 	/* connect this plane/channel to overlay2 compositor */
689d3c9a738SXinliang Liu 	ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch),
690d3c9a738SXinliang Liu 			CH_OVLY_SEL_MASK, CH_OVLY_SEL_VAL(OUT_OVLY));
691d3c9a738SXinliang Liu }
692d3c9a738SXinliang Liu 
ade_compositor_routing_disable(void __iomem * base,u32 ch)693d3c9a738SXinliang Liu static void ade_compositor_routing_disable(void __iomem *base, u32 ch)
694d3c9a738SXinliang Liu {
695d3c9a738SXinliang Liu 	u8 ovly_ch = 0; /* TODO: Only primary plane now */
696d3c9a738SXinliang Liu 
697d3c9a738SXinliang Liu 	/* disable this plane/channel */
698d3c9a738SXinliang Liu 	ade_update_bits(base + ADE_OVLY_CH_CTL(ovly_ch), CH_EN_OFST,
699d3c9a738SXinliang Liu 			MASK(1), 0);
700d3c9a738SXinliang Liu 	/* dis-connect this plane/channel of overlay2 compositor */
701d3c9a738SXinliang Liu 	ade_update_bits(base + ADE_OVLY_CTL, CH_OVLY_SEL_OFST(ovly_ch),
702d3c9a738SXinliang Liu 			CH_OVLY_SEL_MASK, 0);
703d3c9a738SXinliang Liu }
704d3c9a738SXinliang Liu 
705d3c9a738SXinliang Liu /*
706d3c9a738SXinliang Liu  * Typicaly, a channel looks like: DMA-->clip-->scale-->ctrans-->compositor
707d3c9a738SXinliang Liu  */
ade_update_channel(struct kirin_plane * kplane,struct drm_framebuffer * fb,int crtc_x,int crtc_y,unsigned int crtc_w,unsigned int crtc_h,u32 src_x,u32 src_y,u32 src_w,u32 src_h)7080ae622c5SXu YiPing static void ade_update_channel(struct kirin_plane *kplane,
709d3c9a738SXinliang Liu 			       struct drm_framebuffer *fb, int crtc_x,
710d3c9a738SXinliang Liu 			       int crtc_y, unsigned int crtc_w,
711d3c9a738SXinliang Liu 			       unsigned int crtc_h, u32 src_x,
712d3c9a738SXinliang Liu 			       u32 src_y, u32 src_w, u32 src_h)
713d3c9a738SXinliang Liu {
7140ae622c5SXu YiPing 	struct ade_hw_ctx *ctx = kplane->hw_ctx;
715d3c9a738SXinliang Liu 	void __iomem *base = ctx->base;
716438b74a5SVille Syrjälä 	u32 fmt = ade_get_format(fb->format->format);
7170ae622c5SXu YiPing 	u32 ch = kplane->ch;
718d3c9a738SXinliang Liu 	u32 in_w;
719d3c9a738SXinliang Liu 	u32 in_h;
720d3c9a738SXinliang Liu 
721d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("channel%d: src:(%d, %d)-%dx%d, crtc:(%d, %d)-%dx%d",
722d3c9a738SXinliang Liu 			 ch + 1, src_x, src_y, src_w, src_h,
723d3c9a738SXinliang Liu 			 crtc_x, crtc_y, crtc_w, crtc_h);
724d3c9a738SXinliang Liu 
725d3c9a738SXinliang Liu 	/* 1) DMA setting */
726d3c9a738SXinliang Liu 	in_w = src_w;
727d3c9a738SXinliang Liu 	in_h = src_h;
728d3c9a738SXinliang Liu 	ade_rdma_set(base, fb, ch, src_y, in_h, fmt);
729d3c9a738SXinliang Liu 
730d3c9a738SXinliang Liu 	/* 2) clip setting */
731d3c9a738SXinliang Liu 	ade_clip_set(base, ch, fb->width, src_x, in_w, in_h);
732d3c9a738SXinliang Liu 
733d3c9a738SXinliang Liu 	/* 3) TODO: scale setting for overlay planes */
734d3c9a738SXinliang Liu 
735d3c9a738SXinliang Liu 	/* 4) TODO: ctran/csc setting for overlay planes */
736d3c9a738SXinliang Liu 
737d3c9a738SXinliang Liu 	/* 5) compositor routing setting */
738d3c9a738SXinliang Liu 	ade_compositor_routing_set(base, ch, crtc_x, crtc_y, in_w, in_h, fmt);
739d3c9a738SXinliang Liu }
740d3c9a738SXinliang Liu 
ade_disable_channel(struct kirin_plane * kplane)7410ae622c5SXu YiPing static void ade_disable_channel(struct kirin_plane *kplane)
742d3c9a738SXinliang Liu {
7430ae622c5SXu YiPing 	struct ade_hw_ctx *ctx = kplane->hw_ctx;
744d3c9a738SXinliang Liu 	void __iomem *base = ctx->base;
7450ae622c5SXu YiPing 	u32 ch = kplane->ch;
746d3c9a738SXinliang Liu 
747d3c9a738SXinliang Liu 	DRM_DEBUG_DRIVER("disable channel%d\n", ch + 1);
748d3c9a738SXinliang Liu 
749d3c9a738SXinliang Liu 	/* disable read DMA */
750d3c9a738SXinliang Liu 	ade_rdma_disable(base, ch);
751d3c9a738SXinliang Liu 
752d3c9a738SXinliang Liu 	/* disable clip */
753d3c9a738SXinliang Liu 	ade_clip_disable(base, ch);
754d3c9a738SXinliang Liu 
755d3c9a738SXinliang Liu 	/* disable compositor routing */
756d3c9a738SXinliang Liu 	ade_compositor_routing_disable(base, ch);
757d3c9a738SXinliang Liu }
758d3c9a738SXinliang Liu 
ade_plane_atomic_check(struct drm_plane * plane,struct drm_atomic_state * state)759d3c9a738SXinliang Liu static int ade_plane_atomic_check(struct drm_plane *plane,
7607c11b99aSMaxime Ripard 				  struct drm_atomic_state *state)
761d3c9a738SXinliang Liu {
7627c11b99aSMaxime Ripard 	struct drm_plane_state *new_plane_state = drm_atomic_get_new_plane_state(state,
7637c11b99aSMaxime Ripard 										 plane);
764ba5c1649SMaxime Ripard 	struct drm_framebuffer *fb = new_plane_state->fb;
765ba5c1649SMaxime Ripard 	struct drm_crtc *crtc = new_plane_state->crtc;
766d3c9a738SXinliang Liu 	struct drm_crtc_state *crtc_state;
767ba5c1649SMaxime Ripard 	u32 src_x = new_plane_state->src_x >> 16;
768ba5c1649SMaxime Ripard 	u32 src_y = new_plane_state->src_y >> 16;
769ba5c1649SMaxime Ripard 	u32 src_w = new_plane_state->src_w >> 16;
770ba5c1649SMaxime Ripard 	u32 src_h = new_plane_state->src_h >> 16;
771ba5c1649SMaxime Ripard 	int crtc_x = new_plane_state->crtc_x;
772ba5c1649SMaxime Ripard 	int crtc_y = new_plane_state->crtc_y;
773ba5c1649SMaxime Ripard 	u32 crtc_w = new_plane_state->crtc_w;
774ba5c1649SMaxime Ripard 	u32 crtc_h = new_plane_state->crtc_h;
775d3c9a738SXinliang Liu 	u32 fmt;
776d3c9a738SXinliang Liu 
777d3c9a738SXinliang Liu 	if (!crtc || !fb)
778d3c9a738SXinliang Liu 		return 0;
779d3c9a738SXinliang Liu 
780438b74a5SVille Syrjälä 	fmt = ade_get_format(fb->format->format);
781d3c9a738SXinliang Liu 	if (fmt == ADE_FORMAT_UNSUPPORT)
782d3c9a738SXinliang Liu 		return -EINVAL;
783d3c9a738SXinliang Liu 
784dec92020SMaxime Ripard 	crtc_state = drm_atomic_get_crtc_state(state, crtc);
785d3c9a738SXinliang Liu 	if (IS_ERR(crtc_state))
786d3c9a738SXinliang Liu 		return PTR_ERR(crtc_state);
787d3c9a738SXinliang Liu 
788d3c9a738SXinliang Liu 	if (src_w != crtc_w || src_h != crtc_h) {
789d3c9a738SXinliang Liu 		return -EINVAL;
790d3c9a738SXinliang Liu 	}
791d3c9a738SXinliang Liu 
792d3c9a738SXinliang Liu 	if (src_x + src_w > fb->width ||
793d3c9a738SXinliang Liu 	    src_y + src_h > fb->height)
794d3c9a738SXinliang Liu 		return -EINVAL;
795d3c9a738SXinliang Liu 
796d3c9a738SXinliang Liu 	if (crtc_x < 0 || crtc_y < 0)
797d3c9a738SXinliang Liu 		return -EINVAL;
798d3c9a738SXinliang Liu 
799d3c9a738SXinliang Liu 	if (crtc_x + crtc_w > crtc_state->adjusted_mode.hdisplay ||
800d3c9a738SXinliang Liu 	    crtc_y + crtc_h > crtc_state->adjusted_mode.vdisplay)
801d3c9a738SXinliang Liu 		return -EINVAL;
802d3c9a738SXinliang Liu 
803d3c9a738SXinliang Liu 	return 0;
804d3c9a738SXinliang Liu }
805d3c9a738SXinliang Liu 
ade_plane_atomic_update(struct drm_plane * plane,struct drm_atomic_state * state)806d3c9a738SXinliang Liu static void ade_plane_atomic_update(struct drm_plane *plane,
807977697e2SMaxime Ripard 				    struct drm_atomic_state *state)
808d3c9a738SXinliang Liu {
80937418bf1SMaxime Ripard 	struct drm_plane_state *new_state = drm_atomic_get_new_plane_state(state,
81037418bf1SMaxime Ripard 									   plane);
8110ae622c5SXu YiPing 	struct kirin_plane *kplane = to_kirin_plane(plane);
812d3c9a738SXinliang Liu 
81341016fe1SMaxime Ripard 	ade_update_channel(kplane, new_state->fb, new_state->crtc_x,
81441016fe1SMaxime Ripard 			   new_state->crtc_y,
81541016fe1SMaxime Ripard 			   new_state->crtc_w, new_state->crtc_h,
81641016fe1SMaxime Ripard 			   new_state->src_x >> 16, new_state->src_y >> 16,
81741016fe1SMaxime Ripard 			   new_state->src_w >> 16, new_state->src_h >> 16);
818d3c9a738SXinliang Liu }
819d3c9a738SXinliang Liu 
ade_plane_atomic_disable(struct drm_plane * plane,struct drm_atomic_state * state)820d3c9a738SXinliang Liu static void ade_plane_atomic_disable(struct drm_plane *plane,
821977697e2SMaxime Ripard 				     struct drm_atomic_state *state)
822d3c9a738SXinliang Liu {
8230ae622c5SXu YiPing 	struct kirin_plane *kplane = to_kirin_plane(plane);
824d3c9a738SXinliang Liu 
8250ae622c5SXu YiPing 	ade_disable_channel(kplane);
826d3c9a738SXinliang Liu }
827d3c9a738SXinliang Liu 
828d3c9a738SXinliang Liu static const struct drm_plane_helper_funcs ade_plane_helper_funcs = {
829d3c9a738SXinliang Liu 	.atomic_check = ade_plane_atomic_check,
830d3c9a738SXinliang Liu 	.atomic_update = ade_plane_atomic_update,
831d3c9a738SXinliang Liu 	.atomic_disable = ade_plane_atomic_disable,
832d3c9a738SXinliang Liu };
833d3c9a738SXinliang Liu 
834d3c9a738SXinliang Liu static struct drm_plane_funcs ade_plane_funcs = {
835d3c9a738SXinliang Liu 	.update_plane	= drm_atomic_helper_update_plane,
836d3c9a738SXinliang Liu 	.disable_plane	= drm_atomic_helper_disable_plane,
837d3c9a738SXinliang Liu 	.destroy = drm_plane_cleanup,
838d3c9a738SXinliang Liu 	.reset = drm_atomic_helper_plane_reset,
839d3c9a738SXinliang Liu 	.atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
840d3c9a738SXinliang Liu 	.atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
841d3c9a738SXinliang Liu };
842d3c9a738SXinliang Liu 
ade_hw_ctx_alloc(struct platform_device * pdev,struct drm_crtc * crtc)84336f8d22dSXu YiPing static void *ade_hw_ctx_alloc(struct platform_device *pdev,
84436f8d22dSXu YiPing 			      struct drm_crtc *crtc)
845783ad972SXinliang Liu {
846783ad972SXinliang Liu 	struct resource *res;
847783ad972SXinliang Liu 	struct device *dev = &pdev->dev;
848783ad972SXinliang Liu 	struct device_node *np = pdev->dev.of_node;
84943774b0eSXu YiPing 	struct ade_hw_ctx *ctx = NULL;
85036f8d22dSXu YiPing 	int ret;
85143774b0eSXu YiPing 
85243774b0eSXu YiPing 	ctx = devm_kzalloc(dev, sizeof(*ctx), GFP_KERNEL);
85343774b0eSXu YiPing 	if (!ctx) {
85443774b0eSXu YiPing 		DRM_ERROR("failed to alloc ade_hw_ctx\n");
85543774b0eSXu YiPing 		return ERR_PTR(-ENOMEM);
85643774b0eSXu YiPing 	}
857783ad972SXinliang Liu 
858783ad972SXinliang Liu 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
859783ad972SXinliang Liu 	ctx->base = devm_ioremap_resource(dev, res);
860783ad972SXinliang Liu 	if (IS_ERR(ctx->base)) {
861783ad972SXinliang Liu 		DRM_ERROR("failed to remap ade io base\n");
86243774b0eSXu YiPing 		return ERR_PTR(-EIO);
863783ad972SXinliang Liu 	}
864783ad972SXinliang Liu 
865783ad972SXinliang Liu 	ctx->reset = devm_reset_control_get(dev, NULL);
866783ad972SXinliang Liu 	if (IS_ERR(ctx->reset))
86743774b0eSXu YiPing 		return ERR_PTR(-ENODEV);
868783ad972SXinliang Liu 
869783ad972SXinliang Liu 	ctx->noc_regmap =
870783ad972SXinliang Liu 		syscon_regmap_lookup_by_phandle(np, "hisilicon,noc-syscon");
871783ad972SXinliang Liu 	if (IS_ERR(ctx->noc_regmap)) {
872783ad972SXinliang Liu 		DRM_ERROR("failed to get noc regmap\n");
87343774b0eSXu YiPing 		return ERR_PTR(-ENODEV);
874783ad972SXinliang Liu 	}
875783ad972SXinliang Liu 
876783ad972SXinliang Liu 	ctx->irq = platform_get_irq(pdev, 0);
877783ad972SXinliang Liu 	if (ctx->irq < 0) {
878783ad972SXinliang Liu 		DRM_ERROR("failed to get irq\n");
87943774b0eSXu YiPing 		return ERR_PTR(-ENODEV);
880783ad972SXinliang Liu 	}
881783ad972SXinliang Liu 
882783ad972SXinliang Liu 	ctx->ade_core_clk = devm_clk_get(dev, "clk_ade_core");
88343fd0d92SWei Yongjun 	if (IS_ERR(ctx->ade_core_clk)) {
884783ad972SXinliang Liu 		DRM_ERROR("failed to parse clk ADE_CORE\n");
88543774b0eSXu YiPing 		return ERR_PTR(-ENODEV);
886783ad972SXinliang Liu 	}
887783ad972SXinliang Liu 
888783ad972SXinliang Liu 	ctx->media_noc_clk = devm_clk_get(dev, "clk_codec_jpeg");
88943fd0d92SWei Yongjun 	if (IS_ERR(ctx->media_noc_clk)) {
890783ad972SXinliang Liu 		DRM_ERROR("failed to parse clk CODEC_JPEG\n");
89143774b0eSXu YiPing 		return ERR_PTR(-ENODEV);
892783ad972SXinliang Liu 	}
893783ad972SXinliang Liu 
894783ad972SXinliang Liu 	ctx->ade_pix_clk = devm_clk_get(dev, "clk_ade_pix");
89543fd0d92SWei Yongjun 	if (IS_ERR(ctx->ade_pix_clk)) {
896783ad972SXinliang Liu 		DRM_ERROR("failed to parse clk ADE_PIX\n");
89743774b0eSXu YiPing 		return ERR_PTR(-ENODEV);
898783ad972SXinliang Liu 	}
899783ad972SXinliang Liu 
90036f8d22dSXu YiPing 	/* vblank irq init */
90136f8d22dSXu YiPing 	ret = devm_request_irq(dev, ctx->irq, ade_irq_handler,
90236f8d22dSXu YiPing 			       IRQF_SHARED, dev->driver->name, ctx);
90336f8d22dSXu YiPing 	if (ret)
90436f8d22dSXu YiPing 		return ERR_PTR(-EIO);
90536f8d22dSXu YiPing 
90636f8d22dSXu YiPing 	ctx->crtc = crtc;
90736f8d22dSXu YiPing 
90843774b0eSXu YiPing 	return ctx;
909783ad972SXinliang Liu }
910783ad972SXinliang Liu 
ade_hw_ctx_cleanup(void * hw_ctx)9112e89b4fbSXu YiPing static void ade_hw_ctx_cleanup(void *hw_ctx)
9122e89b4fbSXu YiPing {
9132e89b4fbSXu YiPing }
9142e89b4fbSXu YiPing 
915bdaf419eSXu YiPing static const struct drm_mode_config_funcs ade_mode_config_funcs = {
916bdaf419eSXu YiPing 	.fb_create = drm_gem_fb_create,
917bdaf419eSXu YiPing 	.atomic_check = drm_atomic_helper_check,
918bdaf419eSXu YiPing 	.atomic_commit = drm_atomic_helper_commit,
919bdaf419eSXu YiPing 
920bdaf419eSXu YiPing };
921bdaf419eSXu YiPing 
9224a83c26aSDanilo Krummrich DEFINE_DRM_GEM_DMA_FOPS(ade_fops);
9231053d018SXu YiPing 
92470a59dd8SDaniel Vetter static const struct drm_driver ade_driver = {
9251053d018SXu YiPing 	.driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_ATOMIC,
9261053d018SXu YiPing 	.fops = &ade_fops,
9274a83c26aSDanilo Krummrich 	DRM_GEM_DMA_DRIVER_OPS,
9281053d018SXu YiPing 	.name = "kirin",
9291053d018SXu YiPing 	.desc = "Hisilicon Kirin620 SoC DRM Driver",
9301053d018SXu YiPing 	.date = "20150718",
9311053d018SXu YiPing 	.major = 1,
9321053d018SXu YiPing 	.minor = 0,
9331053d018SXu YiPing };
9341053d018SXu YiPing 
9357903ba41SXu YiPing struct kirin_drm_data ade_driver_data = {
93648fa7c17SXu YiPing 	.num_planes = ADE_CH_NUM,
93748fa7c17SXu YiPing 	.prim_plane = ADE_CH1,
938e200d8ebSXu YiPing 	.channel_formats = channel_formats,
939e200d8ebSXu YiPing 	.channel_formats_cnt = ARRAY_SIZE(channel_formats),
94049af4611SXu YiPing 	.config_max_width = 2048,
94149af4611SXu YiPing 	.config_max_height = 2048,
9421053d018SXu YiPing 	.driver = &ade_driver,
9435fb2e411SXu YiPing 	.crtc_helper_funcs = &ade_crtc_helper_funcs,
9445fb2e411SXu YiPing 	.crtc_funcs = &ade_crtc_funcs,
9455fb2e411SXu YiPing 	.plane_helper_funcs = &ade_plane_helper_funcs,
9465fb2e411SXu YiPing 	.plane_funcs = &ade_plane_funcs,
947bdaf419eSXu YiPing 	.mode_config_funcs = &ade_mode_config_funcs,
948bdaf419eSXu YiPing 
9492e89b4fbSXu YiPing 	.alloc_hw_ctx = ade_hw_ctx_alloc,
9502e89b4fbSXu YiPing 	.cleanup_hw_ctx = ade_hw_ctx_cleanup,
9519cd2e854SDaniel Vetter };
952