Linux Audio

Check our new training course

Loading...
Note: File does not exist in v3.1.
  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
 24static const struct malidp_input_format 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
 72static const struct malidp_input_format malidp550_de_formats[] = {
 73	MALIDP_COMMON_FORMATS,
 74};
 75
 76static const struct malidp_layer malidp500_layers[] = {
 77	{ DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE },
 78	{ DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE },
 79	{ DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE },
 80};
 81
 82static const struct malidp_layer malidp550_layers[] = {
 83	{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE },
 84	{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE },
 85	{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE },
 86	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE },
 87};
 88
 89#define MALIDP_DE_DEFAULT_PREFETCH_START	5
 90
 91static 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
105static 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
124static 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
140static 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
151static void malidp500_set_config_valid(struct malidp_hw_device *hwdev)
152{
153	malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
154}
155
156static 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
200static 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
214static 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
247static 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
266static 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
282static 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
293static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
294{
295	malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
296}
297
298static 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
342static 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
387static 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
415const 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			.input_formats = malidp500_de_formats,
440			.n_input_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	},
451	[MALIDP_550] = {
452		.map = {
453			.se_base = MALIDP550_SE_BASE,
454			.dc_base = MALIDP550_DC_BASE,
455			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
456			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
457			.n_layers = ARRAY_SIZE(malidp550_layers),
458			.layers = malidp550_layers,
459			.de_irq_map = {
460				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
461					    MALIDP550_DE_IRQ_VSYNC,
462				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
463			},
464			.se_irq_map = {
465				.irq_mask = MALIDP550_SE_IRQ_EOW |
466					    MALIDP550_SE_IRQ_AXI_ERR,
467			},
468			.dc_irq_map = {
469				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
470				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
471			},
472			.input_formats = malidp550_de_formats,
473			.n_input_formats = ARRAY_SIZE(malidp550_de_formats),
474			.bus_align_bytes = 8,
475		},
476		.query_hw = malidp550_query_hw,
477		.enter_config_mode = malidp550_enter_config_mode,
478		.leave_config_mode = malidp550_leave_config_mode,
479		.in_config_mode = malidp550_in_config_mode,
480		.set_config_valid = malidp550_set_config_valid,
481		.modeset = malidp550_modeset,
482		.rotmem_required = malidp550_rotmem_required,
483	},
484	[MALIDP_650] = {
485		.map = {
486			.se_base = MALIDP550_SE_BASE,
487			.dc_base = MALIDP550_DC_BASE,
488			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
489			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
490			.n_layers = ARRAY_SIZE(malidp550_layers),
491			.layers = malidp550_layers,
492			.de_irq_map = {
493				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
494					    MALIDP650_DE_IRQ_DRIFT |
495					    MALIDP550_DE_IRQ_VSYNC,
496				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
497			},
498			.se_irq_map = {
499				.irq_mask = MALIDP550_SE_IRQ_EOW |
500					    MALIDP550_SE_IRQ_AXI_ERR,
501			},
502			.dc_irq_map = {
503				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
504				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
505			},
506			.input_formats = malidp550_de_formats,
507			.n_input_formats = ARRAY_SIZE(malidp550_de_formats),
508			.bus_align_bytes = 16,
509		},
510		.query_hw = malidp650_query_hw,
511		.enter_config_mode = malidp550_enter_config_mode,
512		.leave_config_mode = malidp550_leave_config_mode,
513		.in_config_mode = malidp550_in_config_mode,
514		.set_config_valid = malidp550_set_config_valid,
515		.modeset = malidp550_modeset,
516		.rotmem_required = malidp550_rotmem_required,
517	},
518};
519
520u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
521			   u8 layer_id, u32 format)
522{
523	unsigned int i;
524
525	for (i = 0; i < map->n_input_formats; i++) {
526		if (((map->input_formats[i].layer & layer_id) == layer_id) &&
527		    (map->input_formats[i].format == format))
528			return map->input_formats[i].id;
529	}
530
531	return MALIDP_INVALID_FORMAT_ID;
532}
533
534static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
535{
536	u32 base = malidp_get_block_base(hwdev, block);
537
538	if (hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
539		malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
540	else
541		malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
542}
543
544static irqreturn_t malidp_de_irq(int irq, void *arg)
545{
546	struct drm_device *drm = arg;
547	struct malidp_drm *malidp = drm->dev_private;
548	struct malidp_hw_device *hwdev;
549	const struct malidp_irq_map *de;
550	u32 status, mask, dc_status;
551	irqreturn_t ret = IRQ_NONE;
552
553	if (!drm->dev_private)
554		return IRQ_HANDLED;
555
556	hwdev = malidp->dev;
557	de = &hwdev->map.de_irq_map;
558
559	/* first handle the config valid IRQ */
560	dc_status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
561	if (dc_status & hwdev->map.dc_irq_map.vsync_irq) {
562		/* we have a page flip event */
563		atomic_set(&malidp->config_valid, 1);
564		malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
565		ret = IRQ_WAKE_THREAD;
566	}
567
568	status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
569	if (!(status & de->irq_mask))
570		return ret;
571
572	mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
573	status &= mask;
574	if (status & de->vsync_irq)
575		drm_crtc_handle_vblank(&malidp->crtc);
576
577	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
578
579	return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
580}
581
582static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
583{
584	struct drm_device *drm = arg;
585	struct malidp_drm *malidp = drm->dev_private;
586
587	wake_up(&malidp->wq);
588
589	return IRQ_HANDLED;
590}
591
592int malidp_de_irq_init(struct drm_device *drm, int irq)
593{
594	struct malidp_drm *malidp = drm->dev_private;
595	struct malidp_hw_device *hwdev = malidp->dev;
596	int ret;
597
598	/* ensure interrupts are disabled */
599	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
600	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
601	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
602	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
603
604	ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
605					malidp_de_irq_thread_handler,
606					IRQF_SHARED, "malidp-de", drm);
607	if (ret < 0) {
608		DRM_ERROR("failed to install DE IRQ handler\n");
609		return ret;
610	}
611
612	/* first enable the DC block IRQs */
613	malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
614			     hwdev->map.dc_irq_map.irq_mask);
615
616	/* now enable the DE block IRQs */
617	malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
618			     hwdev->map.de_irq_map.irq_mask);
619
620	return 0;
621}
622
623void malidp_de_irq_fini(struct drm_device *drm)
624{
625	struct malidp_drm *malidp = drm->dev_private;
626	struct malidp_hw_device *hwdev = malidp->dev;
627
628	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
629			      hwdev->map.de_irq_map.irq_mask);
630	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
631			      hwdev->map.dc_irq_map.irq_mask);
632}
633
634static irqreturn_t malidp_se_irq(int irq, void *arg)
635{
636	struct drm_device *drm = arg;
637	struct malidp_drm *malidp = drm->dev_private;
638	struct malidp_hw_device *hwdev = malidp->dev;
639	u32 status, mask;
640
641	status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
642	if (!(status & hwdev->map.se_irq_map.irq_mask))
643		return IRQ_NONE;
644
645	mask = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_MASKIRQ);
646	status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
647	status &= mask;
648	/* ToDo: status decoding and firing up of VSYNC and page flip events */
649
650	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
651
652	return IRQ_HANDLED;
653}
654
655static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
656{
657	return IRQ_HANDLED;
658}
659
660int malidp_se_irq_init(struct drm_device *drm, int irq)
661{
662	struct malidp_drm *malidp = drm->dev_private;
663	struct malidp_hw_device *hwdev = malidp->dev;
664	int ret;
665
666	/* ensure interrupts are disabled */
667	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
668	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
669
670	ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
671					malidp_se_irq_thread_handler,
672					IRQF_SHARED, "malidp-se", drm);
673	if (ret < 0) {
674		DRM_ERROR("failed to install SE IRQ handler\n");
675		return ret;
676	}
677
678	malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
679			     hwdev->map.se_irq_map.irq_mask);
680
681	return 0;
682}
683
684void malidp_se_irq_fini(struct drm_device *drm)
685{
686	struct malidp_drm *malidp = drm->dev_private;
687	struct malidp_hw_device *hwdev = malidp->dev;
688
689	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
690			      hwdev->map.se_irq_map.irq_mask);
691}