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