xref: /openbmc/linux/drivers/gpu/drm/arm/malidp_hw.c (revision 7ccf281f)
1ad49f860SLiviu Dudau /*
2ad49f860SLiviu Dudau  * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3ad49f860SLiviu Dudau  * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4ad49f860SLiviu Dudau  *
5ad49f860SLiviu Dudau  * This program is free software and is provided to you under the terms of the
6ad49f860SLiviu Dudau  * GNU General Public License version 2 as published by the Free Software
7ad49f860SLiviu Dudau  * Foundation, and any use by you of this program is subject to the terms
8ad49f860SLiviu Dudau  * of such GNU licence.
9ad49f860SLiviu Dudau  *
10ad49f860SLiviu Dudau  * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where
11ad49f860SLiviu Dudau  * the difference between various versions of the hardware is being dealt with
12ad49f860SLiviu Dudau  * in an attempt to provide to the rest of the driver code a unified view
13ad49f860SLiviu Dudau  */
14ad49f860SLiviu Dudau 
15ad49f860SLiviu Dudau #include <linux/types.h>
16ad49f860SLiviu Dudau #include <linux/io.h>
17ad49f860SLiviu Dudau #include <drm/drmP.h>
18ad49f860SLiviu Dudau #include <video/videomode.h>
19ad49f860SLiviu Dudau #include <video/display_timing.h>
20ad49f860SLiviu Dudau 
21ad49f860SLiviu Dudau #include "malidp_drv.h"
22ad49f860SLiviu Dudau #include "malidp_hw.h"
23ad49f860SLiviu Dudau 
24ad49f860SLiviu Dudau static const struct malidp_input_format malidp500_de_formats[] = {
25ad49f860SLiviu Dudau 	/*    fourcc,   layers supporting the format,     internal id  */
26ad49f860SLiviu Dudau 	{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  0 },
27ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  1 },
28ad49f860SLiviu Dudau 	{ DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  2 },
29ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  3 },
30ad49f860SLiviu Dudau 	{ DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  4 },
31ad49f860SLiviu Dudau 	{ DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  5 },
32ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  6 },
33ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  7 },
34ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  8 },
35ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  9 },
36ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
37ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
38ad49f860SLiviu Dudau 	{ DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
39ad49f860SLiviu Dudau 	{ DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
40ad49f860SLiviu Dudau 	{ DRM_FORMAT_NV12, DE_VIDEO1, 14 },
41ad49f860SLiviu Dudau 	{ DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
42ad49f860SLiviu Dudau };
43ad49f860SLiviu Dudau 
44ad49f860SLiviu Dudau #define MALIDP_ID(__group, __format) \
45ad49f860SLiviu Dudau 	((((__group) & 0x7) << 3) | ((__format) & 0x7))
46ad49f860SLiviu Dudau 
47ad49f860SLiviu Dudau #define MALIDP_COMMON_FORMATS \
48ad49f860SLiviu Dudau 	/*    fourcc,   layers supporting the format,      internal id   */ \
49ad49f860SLiviu Dudau 	{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 0) }, \
50ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 1) }, \
51ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 2) }, \
52ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 3) }, \
53ad49f860SLiviu Dudau 	{ DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
54ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
55ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
56ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
57ad49f860SLiviu Dudau 	{ DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 0) }, \
58ad49f860SLiviu Dudau 	{ DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 1) }, \
59ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 2) }, \
60ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 3) }, \
61ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 0) }, \
62ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 1) }, \
63ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
64ad49f860SLiviu Dudau 	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
65ad49f860SLiviu Dudau 	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
66ad49f860SLiviu Dudau 	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
67ad49f860SLiviu Dudau 	{ DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },	\
68ad49f860SLiviu Dudau 	{ DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },	\
69ad49f860SLiviu Dudau 	{ DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) },	\
70ad49f860SLiviu Dudau 	{ DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
71ad49f860SLiviu Dudau 
72ad49f860SLiviu Dudau static const struct malidp_input_format malidp550_de_formats[] = {
73ad49f860SLiviu Dudau 	MALIDP_COMMON_FORMATS,
74ad49f860SLiviu Dudau };
75ad49f860SLiviu Dudau 
76ad49f860SLiviu Dudau static const struct malidp_layer malidp500_layers[] = {
77ad49f860SLiviu Dudau 	{ DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE },
78ad49f860SLiviu Dudau 	{ DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE },
79ad49f860SLiviu Dudau 	{ DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE },
80ad49f860SLiviu Dudau };
81ad49f860SLiviu Dudau 
82ad49f860SLiviu Dudau static const struct malidp_layer malidp550_layers[] = {
83ad49f860SLiviu Dudau 	{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE },
84ad49f860SLiviu Dudau 	{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE },
85ad49f860SLiviu Dudau 	{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE },
86ad49f860SLiviu Dudau 	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE },
87ad49f860SLiviu Dudau };
88ad49f860SLiviu Dudau 
89ad49f860SLiviu Dudau #define MALIDP_DE_DEFAULT_PREFETCH_START	5
90ad49f860SLiviu Dudau 
91ad49f860SLiviu Dudau static int malidp500_query_hw(struct malidp_hw_device *hwdev)
92ad49f860SLiviu Dudau {
93ad49f860SLiviu Dudau 	u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
94ad49f860SLiviu Dudau 	/* bit 4 of the CONFIG_ID register holds the line size multiplier */
95ad49f860SLiviu Dudau 	u8 ln_size_mult = conf & 0x10 ? 2 : 1;
96ad49f860SLiviu Dudau 
97ad49f860SLiviu Dudau 	hwdev->min_line_size = 2;
98ad49f860SLiviu Dudau 	hwdev->max_line_size = SZ_2K * ln_size_mult;
99ad49f860SLiviu Dudau 	hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
100ad49f860SLiviu Dudau 	hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
101ad49f860SLiviu Dudau 
102ad49f860SLiviu Dudau 	return 0;
103ad49f860SLiviu Dudau }
104ad49f860SLiviu Dudau 
105ad49f860SLiviu Dudau static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
106ad49f860SLiviu Dudau {
107ad49f860SLiviu Dudau 	u32 status, count = 100;
108ad49f860SLiviu Dudau 
109ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
110ad49f860SLiviu Dudau 	while (count) {
111ad49f860SLiviu Dudau 		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
112ad49f860SLiviu Dudau 		if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
113ad49f860SLiviu Dudau 			break;
114ad49f860SLiviu Dudau 		/*
115ad49f860SLiviu Dudau 		 * entering config mode can take as long as the rendering
116ad49f860SLiviu Dudau 		 * of a full frame, hence the long sleep here
117ad49f860SLiviu Dudau 		 */
118ad49f860SLiviu Dudau 		usleep_range(1000, 10000);
119ad49f860SLiviu Dudau 		count--;
120ad49f860SLiviu Dudau 	}
121ad49f860SLiviu Dudau 	WARN(count == 0, "timeout while entering config mode");
122ad49f860SLiviu Dudau }
123ad49f860SLiviu Dudau 
124ad49f860SLiviu Dudau static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
125ad49f860SLiviu Dudau {
126ad49f860SLiviu Dudau 	u32 status, count = 100;
127ad49f860SLiviu Dudau 
128ad49f860SLiviu Dudau 	malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
129ad49f860SLiviu Dudau 	while (count) {
130ad49f860SLiviu Dudau 		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
131ad49f860SLiviu Dudau 		if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
132ad49f860SLiviu Dudau 			break;
133ad49f860SLiviu Dudau 		usleep_range(100, 1000);
134ad49f860SLiviu Dudau 		count--;
135ad49f860SLiviu Dudau 	}
136ad49f860SLiviu Dudau 	WARN(count == 0, "timeout while leaving config mode");
137ad49f860SLiviu Dudau }
138ad49f860SLiviu Dudau 
139ad49f860SLiviu Dudau static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
140ad49f860SLiviu Dudau {
141ad49f860SLiviu Dudau 	u32 status;
142ad49f860SLiviu Dudau 
143ad49f860SLiviu Dudau 	status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
144ad49f860SLiviu Dudau 	if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
145ad49f860SLiviu Dudau 		return true;
146ad49f860SLiviu Dudau 
147ad49f860SLiviu Dudau 	return false;
148ad49f860SLiviu Dudau }
149ad49f860SLiviu Dudau 
150ad49f860SLiviu Dudau static void malidp500_set_config_valid(struct malidp_hw_device *hwdev)
151ad49f860SLiviu Dudau {
152ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
153ad49f860SLiviu Dudau }
154ad49f860SLiviu Dudau 
155ad49f860SLiviu Dudau static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
156ad49f860SLiviu Dudau {
157ad49f860SLiviu Dudau 	u32 val = 0;
158ad49f860SLiviu Dudau 
159ad49f860SLiviu Dudau 	malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
160ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
161ad49f860SLiviu Dudau 		val |= MALIDP500_HSYNCPOL;
162ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
163ad49f860SLiviu Dudau 		val |= MALIDP500_VSYNCPOL;
164ad49f860SLiviu Dudau 	val |= MALIDP_DE_DEFAULT_PREFETCH_START;
165ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
166ad49f860SLiviu Dudau 
167ad49f860SLiviu Dudau 	/*
168ad49f860SLiviu Dudau 	 * Mali-DP500 encodes the background color like this:
169ad49f860SLiviu Dudau 	 *    - red   @ MALIDP500_BGND_COLOR[12:0]
170ad49f860SLiviu Dudau 	 *    - green @ MALIDP500_BGND_COLOR[27:16]
171ad49f860SLiviu Dudau 	 *    - blue  @ (MALIDP500_BGND_COLOR + 4)[12:0]
172ad49f860SLiviu Dudau 	 */
173ad49f860SLiviu Dudau 	val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
174ad49f860SLiviu Dudau 	      (MALIDP_BGND_COLOR_R & 0xfff);
175ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
176ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
177ad49f860SLiviu Dudau 
178ad49f860SLiviu Dudau 	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
179ad49f860SLiviu Dudau 		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
180ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
181ad49f860SLiviu Dudau 
182ad49f860SLiviu Dudau 	val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
183ad49f860SLiviu Dudau 		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
184ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
185ad49f860SLiviu Dudau 
186ad49f860SLiviu Dudau 	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
187ad49f860SLiviu Dudau 		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
188ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
189ad49f860SLiviu Dudau 
190ad49f860SLiviu Dudau 	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
191ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
192ad49f860SLiviu Dudau 
193ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
194ad49f860SLiviu Dudau 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
195ad49f860SLiviu Dudau 	else
196ad49f860SLiviu Dudau 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
197ad49f860SLiviu Dudau }
198ad49f860SLiviu Dudau 
199ad49f860SLiviu Dudau static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
200ad49f860SLiviu Dudau {
201ad49f860SLiviu Dudau 	/* RGB888 or BGR888 can't be rotated */
202ad49f860SLiviu Dudau 	if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
203ad49f860SLiviu Dudau 		return -EINVAL;
204ad49f860SLiviu Dudau 
205ad49f860SLiviu Dudau 	/*
206ad49f860SLiviu Dudau 	 * Each layer needs enough rotation memory to fit 8 lines
207ad49f860SLiviu Dudau 	 * worth of pixel data. Required size is then:
208ad49f860SLiviu Dudau 	 *    size = rotated_width * (bpp / 8) * 8;
209ad49f860SLiviu Dudau 	 */
2107ccf281fSLaurent Pinchart 	return w * drm_format_plane_cpp(fmt, 0) * 8;
211ad49f860SLiviu Dudau }
212ad49f860SLiviu Dudau 
213ad49f860SLiviu Dudau static int malidp550_query_hw(struct malidp_hw_device *hwdev)
214ad49f860SLiviu Dudau {
215ad49f860SLiviu Dudau 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
216ad49f860SLiviu Dudau 	u8 ln_size = (conf >> 4) & 0x3, rsize;
217ad49f860SLiviu Dudau 
218ad49f860SLiviu Dudau 	hwdev->min_line_size = 2;
219ad49f860SLiviu Dudau 
220ad49f860SLiviu Dudau 	switch (ln_size) {
221ad49f860SLiviu Dudau 	case 0:
222ad49f860SLiviu Dudau 		hwdev->max_line_size = SZ_2K;
223ad49f860SLiviu Dudau 		/* two banks of 64KB for rotation memory */
224ad49f860SLiviu Dudau 		rsize = 64;
225ad49f860SLiviu Dudau 		break;
226ad49f860SLiviu Dudau 	case 1:
227ad49f860SLiviu Dudau 		hwdev->max_line_size = SZ_4K;
228ad49f860SLiviu Dudau 		/* two banks of 128KB for rotation memory */
229ad49f860SLiviu Dudau 		rsize = 128;
230ad49f860SLiviu Dudau 		break;
231ad49f860SLiviu Dudau 	case 2:
232ad49f860SLiviu Dudau 		hwdev->max_line_size = 1280;
233ad49f860SLiviu Dudau 		/* two banks of 40KB for rotation memory */
234ad49f860SLiviu Dudau 		rsize = 40;
235ad49f860SLiviu Dudau 		break;
236ad49f860SLiviu Dudau 	case 3:
237ad49f860SLiviu Dudau 		/* reserved value */
238ad49f860SLiviu Dudau 		hwdev->max_line_size = 0;
239ad49f860SLiviu Dudau 		return -EINVAL;
240ad49f860SLiviu Dudau 	}
241ad49f860SLiviu Dudau 
242ad49f860SLiviu Dudau 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
243ad49f860SLiviu Dudau 	return 0;
244ad49f860SLiviu Dudau }
245ad49f860SLiviu Dudau 
246ad49f860SLiviu Dudau static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
247ad49f860SLiviu Dudau {
248ad49f860SLiviu Dudau 	u32 status, count = 100;
249ad49f860SLiviu Dudau 
250ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
251ad49f860SLiviu Dudau 	while (count) {
252ad49f860SLiviu Dudau 		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
253ad49f860SLiviu Dudau 		if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
254ad49f860SLiviu Dudau 			break;
255ad49f860SLiviu Dudau 		/*
256ad49f860SLiviu Dudau 		 * entering config mode can take as long as the rendering
257ad49f860SLiviu Dudau 		 * of a full frame, hence the long sleep here
258ad49f860SLiviu Dudau 		 */
259ad49f860SLiviu Dudau 		usleep_range(1000, 10000);
260ad49f860SLiviu Dudau 		count--;
261ad49f860SLiviu Dudau 	}
262ad49f860SLiviu Dudau 	WARN(count == 0, "timeout while entering config mode");
263ad49f860SLiviu Dudau }
264ad49f860SLiviu Dudau 
265ad49f860SLiviu Dudau static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
266ad49f860SLiviu Dudau {
267ad49f860SLiviu Dudau 	u32 status, count = 100;
268ad49f860SLiviu Dudau 
269ad49f860SLiviu Dudau 	malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
270ad49f860SLiviu Dudau 	while (count) {
271ad49f860SLiviu Dudau 		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
272ad49f860SLiviu Dudau 		if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
273ad49f860SLiviu Dudau 			break;
274ad49f860SLiviu Dudau 		usleep_range(100, 1000);
275ad49f860SLiviu Dudau 		count--;
276ad49f860SLiviu Dudau 	}
277ad49f860SLiviu Dudau 	WARN(count == 0, "timeout while leaving config mode");
278ad49f860SLiviu Dudau }
279ad49f860SLiviu Dudau 
280ad49f860SLiviu Dudau static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
281ad49f860SLiviu Dudau {
282ad49f860SLiviu Dudau 	u32 status;
283ad49f860SLiviu Dudau 
284ad49f860SLiviu Dudau 	status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
285ad49f860SLiviu Dudau 	if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
286ad49f860SLiviu Dudau 		return true;
287ad49f860SLiviu Dudau 
288ad49f860SLiviu Dudau 	return false;
289ad49f860SLiviu Dudau }
290ad49f860SLiviu Dudau 
291ad49f860SLiviu Dudau static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
292ad49f860SLiviu Dudau {
293ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
294ad49f860SLiviu Dudau }
295ad49f860SLiviu Dudau 
296ad49f860SLiviu Dudau static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
297ad49f860SLiviu Dudau {
298ad49f860SLiviu Dudau 	u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
299ad49f860SLiviu Dudau 
300ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
301ad49f860SLiviu Dudau 	/*
302ad49f860SLiviu Dudau 	 * Mali-DP550 and Mali-DP650 encode the background color like this:
303ad49f860SLiviu Dudau 	 *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
304ad49f860SLiviu Dudau 	 *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
305ad49f860SLiviu Dudau 	 *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
306ad49f860SLiviu Dudau 	 *
307ad49f860SLiviu Dudau 	 * We need to truncate the least significant 4 bits from the default
308ad49f860SLiviu Dudau 	 * MALIDP_BGND_COLOR_x values
309ad49f860SLiviu Dudau 	 */
310ad49f860SLiviu Dudau 	val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
311ad49f860SLiviu Dudau 	      (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
312ad49f860SLiviu Dudau 	      ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
313ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
314ad49f860SLiviu Dudau 
315ad49f860SLiviu Dudau 	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
316ad49f860SLiviu Dudau 		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
317ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
318ad49f860SLiviu Dudau 
319ad49f860SLiviu Dudau 	val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
320ad49f860SLiviu Dudau 		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
321ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
322ad49f860SLiviu Dudau 
323ad49f860SLiviu Dudau 	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
324ad49f860SLiviu Dudau 		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
325ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
326ad49f860SLiviu Dudau 		val |= MALIDP550_HSYNCPOL;
327ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
328ad49f860SLiviu Dudau 		val |= MALIDP550_VSYNCPOL;
329ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
330ad49f860SLiviu Dudau 
331ad49f860SLiviu Dudau 	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
332ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
333ad49f860SLiviu Dudau 
334ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
335ad49f860SLiviu Dudau 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
336ad49f860SLiviu Dudau 	else
337ad49f860SLiviu Dudau 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
338ad49f860SLiviu Dudau }
339ad49f860SLiviu Dudau 
340ad49f860SLiviu Dudau static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
341ad49f860SLiviu Dudau {
342ad49f860SLiviu Dudau 	u32 bytes_per_col;
343ad49f860SLiviu Dudau 
344ad49f860SLiviu Dudau 	/* raw RGB888 or BGR888 can't be rotated */
345ad49f860SLiviu Dudau 	if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
346ad49f860SLiviu Dudau 		return -EINVAL;
347ad49f860SLiviu Dudau 
348ad49f860SLiviu Dudau 	switch (fmt) {
349ad49f860SLiviu Dudau 	/* 8 lines at 4 bytes per pixel */
350ad49f860SLiviu Dudau 	case DRM_FORMAT_ARGB2101010:
351ad49f860SLiviu Dudau 	case DRM_FORMAT_ABGR2101010:
352ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBA1010102:
353ad49f860SLiviu Dudau 	case DRM_FORMAT_BGRA1010102:
354ad49f860SLiviu Dudau 	case DRM_FORMAT_ARGB8888:
355ad49f860SLiviu Dudau 	case DRM_FORMAT_ABGR8888:
356ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBA8888:
357ad49f860SLiviu Dudau 	case DRM_FORMAT_BGRA8888:
358ad49f860SLiviu Dudau 	case DRM_FORMAT_XRGB8888:
359ad49f860SLiviu Dudau 	case DRM_FORMAT_XBGR8888:
360ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBX8888:
361ad49f860SLiviu Dudau 	case DRM_FORMAT_BGRX8888:
362ad49f860SLiviu Dudau 	case DRM_FORMAT_RGB888:
363ad49f860SLiviu Dudau 	case DRM_FORMAT_BGR888:
364ad49f860SLiviu Dudau 	/* 16 lines at 2 bytes per pixel */
365ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBA5551:
366ad49f860SLiviu Dudau 	case DRM_FORMAT_ABGR1555:
367ad49f860SLiviu Dudau 	case DRM_FORMAT_RGB565:
368ad49f860SLiviu Dudau 	case DRM_FORMAT_BGR565:
369ad49f860SLiviu Dudau 	case DRM_FORMAT_UYVY:
370ad49f860SLiviu Dudau 	case DRM_FORMAT_YUYV:
371ad49f860SLiviu Dudau 		bytes_per_col = 32;
372ad49f860SLiviu Dudau 		break;
373ad49f860SLiviu Dudau 	/* 16 lines at 1.5 bytes per pixel */
374ad49f860SLiviu Dudau 	case DRM_FORMAT_NV12:
375ad49f860SLiviu Dudau 	case DRM_FORMAT_YUV420:
376ad49f860SLiviu Dudau 		bytes_per_col = 24;
377ad49f860SLiviu Dudau 		break;
378ad49f860SLiviu Dudau 	default:
379ad49f860SLiviu Dudau 		return -EINVAL;
380ad49f860SLiviu Dudau 	}
381ad49f860SLiviu Dudau 
382ad49f860SLiviu Dudau 	return w * bytes_per_col;
383ad49f860SLiviu Dudau }
384ad49f860SLiviu Dudau 
385ad49f860SLiviu Dudau static int malidp650_query_hw(struct malidp_hw_device *hwdev)
386ad49f860SLiviu Dudau {
387ad49f860SLiviu Dudau 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
388ad49f860SLiviu Dudau 	u8 ln_size = (conf >> 4) & 0x3, rsize;
389ad49f860SLiviu Dudau 
390ad49f860SLiviu Dudau 	hwdev->min_line_size = 4;
391ad49f860SLiviu Dudau 
392ad49f860SLiviu Dudau 	switch (ln_size) {
393ad49f860SLiviu Dudau 	case 0:
394ad49f860SLiviu Dudau 	case 2:
395ad49f860SLiviu Dudau 		/* reserved values */
396ad49f860SLiviu Dudau 		hwdev->max_line_size = 0;
397ad49f860SLiviu Dudau 		return -EINVAL;
398ad49f860SLiviu Dudau 	case 1:
399ad49f860SLiviu Dudau 		hwdev->max_line_size = SZ_4K;
400ad49f860SLiviu Dudau 		/* two banks of 128KB for rotation memory */
401ad49f860SLiviu Dudau 		rsize = 128;
402ad49f860SLiviu Dudau 		break;
403ad49f860SLiviu Dudau 	case 3:
404ad49f860SLiviu Dudau 		hwdev->max_line_size = 2560;
405ad49f860SLiviu Dudau 		/* two banks of 80KB for rotation memory */
406ad49f860SLiviu Dudau 		rsize = 80;
407ad49f860SLiviu Dudau 	}
408ad49f860SLiviu Dudau 
409ad49f860SLiviu Dudau 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
410ad49f860SLiviu Dudau 	return 0;
411ad49f860SLiviu Dudau }
412ad49f860SLiviu Dudau 
413ad49f860SLiviu Dudau const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
414ad49f860SLiviu Dudau 	[MALIDP_500] = {
415ad49f860SLiviu Dudau 		.map = {
416ad49f860SLiviu Dudau 			.se_base = MALIDP500_SE_BASE,
417ad49f860SLiviu Dudau 			.dc_base = MALIDP500_DC_BASE,
418ad49f860SLiviu Dudau 			.out_depth_base = MALIDP500_OUTPUT_DEPTH,
419ad49f860SLiviu Dudau 			.features = 0,	/* no CLEARIRQ register */
420ad49f860SLiviu Dudau 			.n_layers = ARRAY_SIZE(malidp500_layers),
421ad49f860SLiviu Dudau 			.layers = malidp500_layers,
422ad49f860SLiviu Dudau 			.de_irq_map = {
423ad49f860SLiviu Dudau 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
424ad49f860SLiviu Dudau 					    MALIDP500_DE_IRQ_AXI_ERR |
425ad49f860SLiviu Dudau 					    MALIDP500_DE_IRQ_VSYNC |
426ad49f860SLiviu Dudau 					    MALIDP500_DE_IRQ_GLOBAL,
427ad49f860SLiviu Dudau 				.vsync_irq = MALIDP500_DE_IRQ_VSYNC,
428ad49f860SLiviu Dudau 			},
429ad49f860SLiviu Dudau 			.se_irq_map = {
430ad49f860SLiviu Dudau 				.irq_mask = MALIDP500_SE_IRQ_CONF_MODE,
431ad49f860SLiviu Dudau 				.vsync_irq = 0,
432ad49f860SLiviu Dudau 			},
433ad49f860SLiviu Dudau 			.dc_irq_map = {
434ad49f860SLiviu Dudau 				.irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
435ad49f860SLiviu Dudau 				.vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
436ad49f860SLiviu Dudau 			},
437ad49f860SLiviu Dudau 			.input_formats = malidp500_de_formats,
438ad49f860SLiviu Dudau 			.n_input_formats = ARRAY_SIZE(malidp500_de_formats),
439ad49f860SLiviu Dudau 		},
440ad49f860SLiviu Dudau 		.query_hw = malidp500_query_hw,
441ad49f860SLiviu Dudau 		.enter_config_mode = malidp500_enter_config_mode,
442ad49f860SLiviu Dudau 		.leave_config_mode = malidp500_leave_config_mode,
443ad49f860SLiviu Dudau 		.in_config_mode = malidp500_in_config_mode,
444ad49f860SLiviu Dudau 		.set_config_valid = malidp500_set_config_valid,
445ad49f860SLiviu Dudau 		.modeset = malidp500_modeset,
446ad49f860SLiviu Dudau 		.rotmem_required = malidp500_rotmem_required,
447ad49f860SLiviu Dudau 	},
448ad49f860SLiviu Dudau 	[MALIDP_550] = {
449ad49f860SLiviu Dudau 		.map = {
450ad49f860SLiviu Dudau 			.se_base = MALIDP550_SE_BASE,
451ad49f860SLiviu Dudau 			.dc_base = MALIDP550_DC_BASE,
452ad49f860SLiviu Dudau 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
453ad49f860SLiviu Dudau 			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
454ad49f860SLiviu Dudau 			.n_layers = ARRAY_SIZE(malidp550_layers),
455ad49f860SLiviu Dudau 			.layers = malidp550_layers,
456ad49f860SLiviu Dudau 			.de_irq_map = {
457ad49f860SLiviu Dudau 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
458ad49f860SLiviu Dudau 					    MALIDP550_DE_IRQ_VSYNC,
459ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
460ad49f860SLiviu Dudau 			},
461ad49f860SLiviu Dudau 			.se_irq_map = {
462ad49f860SLiviu Dudau 				.irq_mask = MALIDP550_SE_IRQ_EOW |
463ad49f860SLiviu Dudau 					    MALIDP550_SE_IRQ_AXI_ERR,
464ad49f860SLiviu Dudau 			},
465ad49f860SLiviu Dudau 			.dc_irq_map = {
466ad49f860SLiviu Dudau 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
467ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
468ad49f860SLiviu Dudau 			},
469ad49f860SLiviu Dudau 			.input_formats = malidp550_de_formats,
470ad49f860SLiviu Dudau 			.n_input_formats = ARRAY_SIZE(malidp550_de_formats),
471ad49f860SLiviu Dudau 		},
472ad49f860SLiviu Dudau 		.query_hw = malidp550_query_hw,
473ad49f860SLiviu Dudau 		.enter_config_mode = malidp550_enter_config_mode,
474ad49f860SLiviu Dudau 		.leave_config_mode = malidp550_leave_config_mode,
475ad49f860SLiviu Dudau 		.in_config_mode = malidp550_in_config_mode,
476ad49f860SLiviu Dudau 		.set_config_valid = malidp550_set_config_valid,
477ad49f860SLiviu Dudau 		.modeset = malidp550_modeset,
478ad49f860SLiviu Dudau 		.rotmem_required = malidp550_rotmem_required,
479ad49f860SLiviu Dudau 	},
480ad49f860SLiviu Dudau 	[MALIDP_650] = {
481ad49f860SLiviu Dudau 		.map = {
482ad49f860SLiviu Dudau 			.se_base = MALIDP550_SE_BASE,
483ad49f860SLiviu Dudau 			.dc_base = MALIDP550_DC_BASE,
484ad49f860SLiviu Dudau 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
485ad49f860SLiviu Dudau 			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
486ad49f860SLiviu Dudau 			.n_layers = ARRAY_SIZE(malidp550_layers),
487ad49f860SLiviu Dudau 			.layers = malidp550_layers,
488ad49f860SLiviu Dudau 			.de_irq_map = {
489ad49f860SLiviu Dudau 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
490ad49f860SLiviu Dudau 					    MALIDP650_DE_IRQ_DRIFT |
491ad49f860SLiviu Dudau 					    MALIDP550_DE_IRQ_VSYNC,
492ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
493ad49f860SLiviu Dudau 			},
494ad49f860SLiviu Dudau 			.se_irq_map = {
495ad49f860SLiviu Dudau 				.irq_mask = MALIDP550_SE_IRQ_EOW |
496ad49f860SLiviu Dudau 					    MALIDP550_SE_IRQ_AXI_ERR,
497ad49f860SLiviu Dudau 			},
498ad49f860SLiviu Dudau 			.dc_irq_map = {
499ad49f860SLiviu Dudau 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
500ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
501ad49f860SLiviu Dudau 			},
502ad49f860SLiviu Dudau 			.input_formats = malidp550_de_formats,
503ad49f860SLiviu Dudau 			.n_input_formats = ARRAY_SIZE(malidp550_de_formats),
504ad49f860SLiviu Dudau 		},
505ad49f860SLiviu Dudau 		.query_hw = malidp650_query_hw,
506ad49f860SLiviu Dudau 		.enter_config_mode = malidp550_enter_config_mode,
507ad49f860SLiviu Dudau 		.leave_config_mode = malidp550_leave_config_mode,
508ad49f860SLiviu Dudau 		.in_config_mode = malidp550_in_config_mode,
509ad49f860SLiviu Dudau 		.set_config_valid = malidp550_set_config_valid,
510ad49f860SLiviu Dudau 		.modeset = malidp550_modeset,
511ad49f860SLiviu Dudau 		.rotmem_required = malidp550_rotmem_required,
512ad49f860SLiviu Dudau 	},
513ad49f860SLiviu Dudau };
514ad49f860SLiviu Dudau 
515ad49f860SLiviu Dudau u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
516ad49f860SLiviu Dudau 			   u8 layer_id, u32 format)
517ad49f860SLiviu Dudau {
518ad49f860SLiviu Dudau 	unsigned int i;
519ad49f860SLiviu Dudau 
520ad49f860SLiviu Dudau 	for (i = 0; i < map->n_input_formats; i++) {
521ad49f860SLiviu Dudau 		if (((map->input_formats[i].layer & layer_id) == layer_id) &&
522ad49f860SLiviu Dudau 		    (map->input_formats[i].format == format))
523ad49f860SLiviu Dudau 			return map->input_formats[i].id;
524ad49f860SLiviu Dudau 	}
525ad49f860SLiviu Dudau 
526ad49f860SLiviu Dudau 	return MALIDP_INVALID_FORMAT_ID;
527ad49f860SLiviu Dudau }
528ad49f860SLiviu Dudau 
529ad49f860SLiviu Dudau static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
530ad49f860SLiviu Dudau {
531ad49f860SLiviu Dudau 	u32 base = malidp_get_block_base(hwdev, block);
532ad49f860SLiviu Dudau 
533ad49f860SLiviu Dudau 	if (hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
534ad49f860SLiviu Dudau 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
535ad49f860SLiviu Dudau 	else
536ad49f860SLiviu Dudau 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
537ad49f860SLiviu Dudau }
538ad49f860SLiviu Dudau 
539ad49f860SLiviu Dudau static irqreturn_t malidp_de_irq(int irq, void *arg)
540ad49f860SLiviu Dudau {
541ad49f860SLiviu Dudau 	struct drm_device *drm = arg;
542ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
543ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev;
544ad49f860SLiviu Dudau 	const struct malidp_irq_map *de;
545ad49f860SLiviu Dudau 	u32 status, mask, dc_status;
546ad49f860SLiviu Dudau 	irqreturn_t ret = IRQ_NONE;
547ad49f860SLiviu Dudau 
548ad49f860SLiviu Dudau 	if (!drm->dev_private)
549ad49f860SLiviu Dudau 		return IRQ_HANDLED;
550ad49f860SLiviu Dudau 
551ad49f860SLiviu Dudau 	hwdev = malidp->dev;
552ad49f860SLiviu Dudau 	de = &hwdev->map.de_irq_map;
553ad49f860SLiviu Dudau 
554ad49f860SLiviu Dudau 	/* first handle the config valid IRQ */
555ad49f860SLiviu Dudau 	dc_status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
556ad49f860SLiviu Dudau 	if (dc_status & hwdev->map.dc_irq_map.vsync_irq) {
557ad49f860SLiviu Dudau 		/* we have a page flip event */
558ad49f860SLiviu Dudau 		atomic_set(&malidp->config_valid, 1);
559ad49f860SLiviu Dudau 		malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
560ad49f860SLiviu Dudau 		ret = IRQ_WAKE_THREAD;
561ad49f860SLiviu Dudau 	}
562ad49f860SLiviu Dudau 
563ad49f860SLiviu Dudau 	status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
564ad49f860SLiviu Dudau 	if (!(status & de->irq_mask))
565ad49f860SLiviu Dudau 		return ret;
566ad49f860SLiviu Dudau 
567ad49f860SLiviu Dudau 	mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
568ad49f860SLiviu Dudau 	status &= mask;
569ad49f860SLiviu Dudau 	if (status & de->vsync_irq)
570ad49f860SLiviu Dudau 		drm_crtc_handle_vblank(&malidp->crtc);
571ad49f860SLiviu Dudau 
572ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
573ad49f860SLiviu Dudau 
574ad49f860SLiviu Dudau 	return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
575ad49f860SLiviu Dudau }
576ad49f860SLiviu Dudau 
577ad49f860SLiviu Dudau static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
578ad49f860SLiviu Dudau {
579ad49f860SLiviu Dudau 	struct drm_device *drm = arg;
580ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
581ad49f860SLiviu Dudau 
582ad49f860SLiviu Dudau 	wake_up(&malidp->wq);
583ad49f860SLiviu Dudau 
584ad49f860SLiviu Dudau 	return IRQ_HANDLED;
585ad49f860SLiviu Dudau }
586ad49f860SLiviu Dudau 
587ad49f860SLiviu Dudau int malidp_de_irq_init(struct drm_device *drm, int irq)
588ad49f860SLiviu Dudau {
589ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
590ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
591ad49f860SLiviu Dudau 	int ret;
592ad49f860SLiviu Dudau 
593ad49f860SLiviu Dudau 	/* ensure interrupts are disabled */
594ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
595ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
596ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
597ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
598ad49f860SLiviu Dudau 
599ad49f860SLiviu Dudau 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
600ad49f860SLiviu Dudau 					malidp_de_irq_thread_handler,
601ad49f860SLiviu Dudau 					IRQF_SHARED, "malidp-de", drm);
602ad49f860SLiviu Dudau 	if (ret < 0) {
603ad49f860SLiviu Dudau 		DRM_ERROR("failed to install DE IRQ handler\n");
604ad49f860SLiviu Dudau 		return ret;
605ad49f860SLiviu Dudau 	}
606ad49f860SLiviu Dudau 
607ad49f860SLiviu Dudau 	/* first enable the DC block IRQs */
608ad49f860SLiviu Dudau 	malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
609ad49f860SLiviu Dudau 			     hwdev->map.dc_irq_map.irq_mask);
610ad49f860SLiviu Dudau 
611ad49f860SLiviu Dudau 	/* now enable the DE block IRQs */
612ad49f860SLiviu Dudau 	malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
613ad49f860SLiviu Dudau 			     hwdev->map.de_irq_map.irq_mask);
614ad49f860SLiviu Dudau 
615ad49f860SLiviu Dudau 	return 0;
616ad49f860SLiviu Dudau }
617ad49f860SLiviu Dudau 
618ad49f860SLiviu Dudau void malidp_de_irq_fini(struct drm_device *drm)
619ad49f860SLiviu Dudau {
620ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
621ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
622ad49f860SLiviu Dudau 
623ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
624ad49f860SLiviu Dudau 			      hwdev->map.de_irq_map.irq_mask);
625ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
626ad49f860SLiviu Dudau 			      hwdev->map.dc_irq_map.irq_mask);
627ad49f860SLiviu Dudau }
628ad49f860SLiviu Dudau 
629ad49f860SLiviu Dudau static irqreturn_t malidp_se_irq(int irq, void *arg)
630ad49f860SLiviu Dudau {
631ad49f860SLiviu Dudau 	struct drm_device *drm = arg;
632ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
633ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
634ad49f860SLiviu Dudau 	u32 status, mask;
635ad49f860SLiviu Dudau 
636ad49f860SLiviu Dudau 	status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
637ad49f860SLiviu Dudau 	if (!(status & hwdev->map.se_irq_map.irq_mask))
638ad49f860SLiviu Dudau 		return IRQ_NONE;
639ad49f860SLiviu Dudau 
640ad49f860SLiviu Dudau 	mask = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_MASKIRQ);
641ad49f860SLiviu Dudau 	status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
642ad49f860SLiviu Dudau 	status &= mask;
643ad49f860SLiviu Dudau 	/* ToDo: status decoding and firing up of VSYNC and page flip events */
644ad49f860SLiviu Dudau 
645ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
646ad49f860SLiviu Dudau 
647ad49f860SLiviu Dudau 	return IRQ_HANDLED;
648ad49f860SLiviu Dudau }
649ad49f860SLiviu Dudau 
650ad49f860SLiviu Dudau static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
651ad49f860SLiviu Dudau {
652ad49f860SLiviu Dudau 	return IRQ_HANDLED;
653ad49f860SLiviu Dudau }
654ad49f860SLiviu Dudau 
655ad49f860SLiviu Dudau int malidp_se_irq_init(struct drm_device *drm, int irq)
656ad49f860SLiviu Dudau {
657ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
658ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
659ad49f860SLiviu Dudau 	int ret;
660ad49f860SLiviu Dudau 
661ad49f860SLiviu Dudau 	/* ensure interrupts are disabled */
662ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
663ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
664ad49f860SLiviu Dudau 
665ad49f860SLiviu Dudau 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
666ad49f860SLiviu Dudau 					malidp_se_irq_thread_handler,
667ad49f860SLiviu Dudau 					IRQF_SHARED, "malidp-se", drm);
668ad49f860SLiviu Dudau 	if (ret < 0) {
669ad49f860SLiviu Dudau 		DRM_ERROR("failed to install SE IRQ handler\n");
670ad49f860SLiviu Dudau 		return ret;
671ad49f860SLiviu Dudau 	}
672ad49f860SLiviu Dudau 
673ad49f860SLiviu Dudau 	malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
674ad49f860SLiviu Dudau 			     hwdev->map.se_irq_map.irq_mask);
675ad49f860SLiviu Dudau 
676ad49f860SLiviu Dudau 	return 0;
677ad49f860SLiviu Dudau }
678ad49f860SLiviu Dudau 
679ad49f860SLiviu Dudau void malidp_se_irq_fini(struct drm_device *drm)
680ad49f860SLiviu Dudau {
681ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
682ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
683ad49f860SLiviu Dudau 
684ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
685ad49f860SLiviu Dudau 			      hwdev->map.se_irq_map.irq_mask);
686ad49f860SLiviu Dudau }
687