xref: /openbmc/linux/drivers/gpu/drm/arm/malidp_hw.c (revision ad49f860)
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 	unsigned int depth;
202ad49f860SLiviu Dudau 	int bpp;
203ad49f860SLiviu Dudau 
204ad49f860SLiviu Dudau 	/* RGB888 or BGR888 can't be rotated */
205ad49f860SLiviu Dudau 	if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
206ad49f860SLiviu Dudau 		return -EINVAL;
207ad49f860SLiviu Dudau 
208ad49f860SLiviu Dudau 	/*
209ad49f860SLiviu Dudau 	 * Each layer needs enough rotation memory to fit 8 lines
210ad49f860SLiviu Dudau 	 * worth of pixel data. Required size is then:
211ad49f860SLiviu Dudau 	 *    size = rotated_width * (bpp / 8) * 8;
212ad49f860SLiviu Dudau 	 */
213ad49f860SLiviu Dudau 	drm_fb_get_bpp_depth(fmt, &depth, &bpp);
214ad49f860SLiviu Dudau 
215ad49f860SLiviu Dudau 	return w * bpp;
216ad49f860SLiviu Dudau }
217ad49f860SLiviu Dudau 
218ad49f860SLiviu Dudau static int malidp550_query_hw(struct malidp_hw_device *hwdev)
219ad49f860SLiviu Dudau {
220ad49f860SLiviu Dudau 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
221ad49f860SLiviu Dudau 	u8 ln_size = (conf >> 4) & 0x3, rsize;
222ad49f860SLiviu Dudau 
223ad49f860SLiviu Dudau 	hwdev->min_line_size = 2;
224ad49f860SLiviu Dudau 
225ad49f860SLiviu Dudau 	switch (ln_size) {
226ad49f860SLiviu Dudau 	case 0:
227ad49f860SLiviu Dudau 		hwdev->max_line_size = SZ_2K;
228ad49f860SLiviu Dudau 		/* two banks of 64KB for rotation memory */
229ad49f860SLiviu Dudau 		rsize = 64;
230ad49f860SLiviu Dudau 		break;
231ad49f860SLiviu Dudau 	case 1:
232ad49f860SLiviu Dudau 		hwdev->max_line_size = SZ_4K;
233ad49f860SLiviu Dudau 		/* two banks of 128KB for rotation memory */
234ad49f860SLiviu Dudau 		rsize = 128;
235ad49f860SLiviu Dudau 		break;
236ad49f860SLiviu Dudau 	case 2:
237ad49f860SLiviu Dudau 		hwdev->max_line_size = 1280;
238ad49f860SLiviu Dudau 		/* two banks of 40KB for rotation memory */
239ad49f860SLiviu Dudau 		rsize = 40;
240ad49f860SLiviu Dudau 		break;
241ad49f860SLiviu Dudau 	case 3:
242ad49f860SLiviu Dudau 		/* reserved value */
243ad49f860SLiviu Dudau 		hwdev->max_line_size = 0;
244ad49f860SLiviu Dudau 		return -EINVAL;
245ad49f860SLiviu Dudau 	}
246ad49f860SLiviu Dudau 
247ad49f860SLiviu Dudau 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
248ad49f860SLiviu Dudau 	return 0;
249ad49f860SLiviu Dudau }
250ad49f860SLiviu Dudau 
251ad49f860SLiviu Dudau static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
252ad49f860SLiviu Dudau {
253ad49f860SLiviu Dudau 	u32 status, count = 100;
254ad49f860SLiviu Dudau 
255ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
256ad49f860SLiviu Dudau 	while (count) {
257ad49f860SLiviu Dudau 		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
258ad49f860SLiviu Dudau 		if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
259ad49f860SLiviu Dudau 			break;
260ad49f860SLiviu Dudau 		/*
261ad49f860SLiviu Dudau 		 * entering config mode can take as long as the rendering
262ad49f860SLiviu Dudau 		 * of a full frame, hence the long sleep here
263ad49f860SLiviu Dudau 		 */
264ad49f860SLiviu Dudau 		usleep_range(1000, 10000);
265ad49f860SLiviu Dudau 		count--;
266ad49f860SLiviu Dudau 	}
267ad49f860SLiviu Dudau 	WARN(count == 0, "timeout while entering config mode");
268ad49f860SLiviu Dudau }
269ad49f860SLiviu Dudau 
270ad49f860SLiviu Dudau static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
271ad49f860SLiviu Dudau {
272ad49f860SLiviu Dudau 	u32 status, count = 100;
273ad49f860SLiviu Dudau 
274ad49f860SLiviu Dudau 	malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
275ad49f860SLiviu Dudau 	while (count) {
276ad49f860SLiviu Dudau 		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
277ad49f860SLiviu Dudau 		if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
278ad49f860SLiviu Dudau 			break;
279ad49f860SLiviu Dudau 		usleep_range(100, 1000);
280ad49f860SLiviu Dudau 		count--;
281ad49f860SLiviu Dudau 	}
282ad49f860SLiviu Dudau 	WARN(count == 0, "timeout while leaving config mode");
283ad49f860SLiviu Dudau }
284ad49f860SLiviu Dudau 
285ad49f860SLiviu Dudau static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
286ad49f860SLiviu Dudau {
287ad49f860SLiviu Dudau 	u32 status;
288ad49f860SLiviu Dudau 
289ad49f860SLiviu Dudau 	status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
290ad49f860SLiviu Dudau 	if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
291ad49f860SLiviu Dudau 		return true;
292ad49f860SLiviu Dudau 
293ad49f860SLiviu Dudau 	return false;
294ad49f860SLiviu Dudau }
295ad49f860SLiviu Dudau 
296ad49f860SLiviu Dudau static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
297ad49f860SLiviu Dudau {
298ad49f860SLiviu Dudau 	malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
299ad49f860SLiviu Dudau }
300ad49f860SLiviu Dudau 
301ad49f860SLiviu Dudau static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
302ad49f860SLiviu Dudau {
303ad49f860SLiviu Dudau 	u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
304ad49f860SLiviu Dudau 
305ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
306ad49f860SLiviu Dudau 	/*
307ad49f860SLiviu Dudau 	 * Mali-DP550 and Mali-DP650 encode the background color like this:
308ad49f860SLiviu Dudau 	 *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
309ad49f860SLiviu Dudau 	 *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
310ad49f860SLiviu Dudau 	 *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
311ad49f860SLiviu Dudau 	 *
312ad49f860SLiviu Dudau 	 * We need to truncate the least significant 4 bits from the default
313ad49f860SLiviu Dudau 	 * MALIDP_BGND_COLOR_x values
314ad49f860SLiviu Dudau 	 */
315ad49f860SLiviu Dudau 	val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
316ad49f860SLiviu Dudau 	      (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
317ad49f860SLiviu Dudau 	      ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
318ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
319ad49f860SLiviu Dudau 
320ad49f860SLiviu Dudau 	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
321ad49f860SLiviu Dudau 		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
322ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
323ad49f860SLiviu Dudau 
324ad49f860SLiviu Dudau 	val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
325ad49f860SLiviu Dudau 		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
326ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
327ad49f860SLiviu Dudau 
328ad49f860SLiviu Dudau 	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
329ad49f860SLiviu Dudau 		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
330ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
331ad49f860SLiviu Dudau 		val |= MALIDP550_HSYNCPOL;
332ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
333ad49f860SLiviu Dudau 		val |= MALIDP550_VSYNCPOL;
334ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
335ad49f860SLiviu Dudau 
336ad49f860SLiviu Dudau 	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
337ad49f860SLiviu Dudau 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
338ad49f860SLiviu Dudau 
339ad49f860SLiviu Dudau 	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
340ad49f860SLiviu Dudau 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
341ad49f860SLiviu Dudau 	else
342ad49f860SLiviu Dudau 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
343ad49f860SLiviu Dudau }
344ad49f860SLiviu Dudau 
345ad49f860SLiviu Dudau static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
346ad49f860SLiviu Dudau {
347ad49f860SLiviu Dudau 	u32 bytes_per_col;
348ad49f860SLiviu Dudau 
349ad49f860SLiviu Dudau 	/* raw RGB888 or BGR888 can't be rotated */
350ad49f860SLiviu Dudau 	if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
351ad49f860SLiviu Dudau 		return -EINVAL;
352ad49f860SLiviu Dudau 
353ad49f860SLiviu Dudau 	switch (fmt) {
354ad49f860SLiviu Dudau 	/* 8 lines at 4 bytes per pixel */
355ad49f860SLiviu Dudau 	case DRM_FORMAT_ARGB2101010:
356ad49f860SLiviu Dudau 	case DRM_FORMAT_ABGR2101010:
357ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBA1010102:
358ad49f860SLiviu Dudau 	case DRM_FORMAT_BGRA1010102:
359ad49f860SLiviu Dudau 	case DRM_FORMAT_ARGB8888:
360ad49f860SLiviu Dudau 	case DRM_FORMAT_ABGR8888:
361ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBA8888:
362ad49f860SLiviu Dudau 	case DRM_FORMAT_BGRA8888:
363ad49f860SLiviu Dudau 	case DRM_FORMAT_XRGB8888:
364ad49f860SLiviu Dudau 	case DRM_FORMAT_XBGR8888:
365ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBX8888:
366ad49f860SLiviu Dudau 	case DRM_FORMAT_BGRX8888:
367ad49f860SLiviu Dudau 	case DRM_FORMAT_RGB888:
368ad49f860SLiviu Dudau 	case DRM_FORMAT_BGR888:
369ad49f860SLiviu Dudau 	/* 16 lines at 2 bytes per pixel */
370ad49f860SLiviu Dudau 	case DRM_FORMAT_RGBA5551:
371ad49f860SLiviu Dudau 	case DRM_FORMAT_ABGR1555:
372ad49f860SLiviu Dudau 	case DRM_FORMAT_RGB565:
373ad49f860SLiviu Dudau 	case DRM_FORMAT_BGR565:
374ad49f860SLiviu Dudau 	case DRM_FORMAT_UYVY:
375ad49f860SLiviu Dudau 	case DRM_FORMAT_YUYV:
376ad49f860SLiviu Dudau 		bytes_per_col = 32;
377ad49f860SLiviu Dudau 		break;
378ad49f860SLiviu Dudau 	/* 16 lines at 1.5 bytes per pixel */
379ad49f860SLiviu Dudau 	case DRM_FORMAT_NV12:
380ad49f860SLiviu Dudau 	case DRM_FORMAT_YUV420:
381ad49f860SLiviu Dudau 		bytes_per_col = 24;
382ad49f860SLiviu Dudau 		break;
383ad49f860SLiviu Dudau 	default:
384ad49f860SLiviu Dudau 		return -EINVAL;
385ad49f860SLiviu Dudau 	}
386ad49f860SLiviu Dudau 
387ad49f860SLiviu Dudau 	return w * bytes_per_col;
388ad49f860SLiviu Dudau }
389ad49f860SLiviu Dudau 
390ad49f860SLiviu Dudau static int malidp650_query_hw(struct malidp_hw_device *hwdev)
391ad49f860SLiviu Dudau {
392ad49f860SLiviu Dudau 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
393ad49f860SLiviu Dudau 	u8 ln_size = (conf >> 4) & 0x3, rsize;
394ad49f860SLiviu Dudau 
395ad49f860SLiviu Dudau 	hwdev->min_line_size = 4;
396ad49f860SLiviu Dudau 
397ad49f860SLiviu Dudau 	switch (ln_size) {
398ad49f860SLiviu Dudau 	case 0:
399ad49f860SLiviu Dudau 	case 2:
400ad49f860SLiviu Dudau 		/* reserved values */
401ad49f860SLiviu Dudau 		hwdev->max_line_size = 0;
402ad49f860SLiviu Dudau 		return -EINVAL;
403ad49f860SLiviu Dudau 	case 1:
404ad49f860SLiviu Dudau 		hwdev->max_line_size = SZ_4K;
405ad49f860SLiviu Dudau 		/* two banks of 128KB for rotation memory */
406ad49f860SLiviu Dudau 		rsize = 128;
407ad49f860SLiviu Dudau 		break;
408ad49f860SLiviu Dudau 	case 3:
409ad49f860SLiviu Dudau 		hwdev->max_line_size = 2560;
410ad49f860SLiviu Dudau 		/* two banks of 80KB for rotation memory */
411ad49f860SLiviu Dudau 		rsize = 80;
412ad49f860SLiviu Dudau 	}
413ad49f860SLiviu Dudau 
414ad49f860SLiviu Dudau 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
415ad49f860SLiviu Dudau 	return 0;
416ad49f860SLiviu Dudau }
417ad49f860SLiviu Dudau 
418ad49f860SLiviu Dudau const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
419ad49f860SLiviu Dudau 	[MALIDP_500] = {
420ad49f860SLiviu Dudau 		.map = {
421ad49f860SLiviu Dudau 			.se_base = MALIDP500_SE_BASE,
422ad49f860SLiviu Dudau 			.dc_base = MALIDP500_DC_BASE,
423ad49f860SLiviu Dudau 			.out_depth_base = MALIDP500_OUTPUT_DEPTH,
424ad49f860SLiviu Dudau 			.features = 0,	/* no CLEARIRQ register */
425ad49f860SLiviu Dudau 			.n_layers = ARRAY_SIZE(malidp500_layers),
426ad49f860SLiviu Dudau 			.layers = malidp500_layers,
427ad49f860SLiviu Dudau 			.de_irq_map = {
428ad49f860SLiviu Dudau 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
429ad49f860SLiviu Dudau 					    MALIDP500_DE_IRQ_AXI_ERR |
430ad49f860SLiviu Dudau 					    MALIDP500_DE_IRQ_VSYNC |
431ad49f860SLiviu Dudau 					    MALIDP500_DE_IRQ_GLOBAL,
432ad49f860SLiviu Dudau 				.vsync_irq = MALIDP500_DE_IRQ_VSYNC,
433ad49f860SLiviu Dudau 			},
434ad49f860SLiviu Dudau 			.se_irq_map = {
435ad49f860SLiviu Dudau 				.irq_mask = MALIDP500_SE_IRQ_CONF_MODE,
436ad49f860SLiviu Dudau 				.vsync_irq = 0,
437ad49f860SLiviu Dudau 			},
438ad49f860SLiviu Dudau 			.dc_irq_map = {
439ad49f860SLiviu Dudau 				.irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
440ad49f860SLiviu Dudau 				.vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
441ad49f860SLiviu Dudau 			},
442ad49f860SLiviu Dudau 			.input_formats = malidp500_de_formats,
443ad49f860SLiviu Dudau 			.n_input_formats = ARRAY_SIZE(malidp500_de_formats),
444ad49f860SLiviu Dudau 		},
445ad49f860SLiviu Dudau 		.query_hw = malidp500_query_hw,
446ad49f860SLiviu Dudau 		.enter_config_mode = malidp500_enter_config_mode,
447ad49f860SLiviu Dudau 		.leave_config_mode = malidp500_leave_config_mode,
448ad49f860SLiviu Dudau 		.in_config_mode = malidp500_in_config_mode,
449ad49f860SLiviu Dudau 		.set_config_valid = malidp500_set_config_valid,
450ad49f860SLiviu Dudau 		.modeset = malidp500_modeset,
451ad49f860SLiviu Dudau 		.rotmem_required = malidp500_rotmem_required,
452ad49f860SLiviu Dudau 	},
453ad49f860SLiviu Dudau 	[MALIDP_550] = {
454ad49f860SLiviu Dudau 		.map = {
455ad49f860SLiviu Dudau 			.se_base = MALIDP550_SE_BASE,
456ad49f860SLiviu Dudau 			.dc_base = MALIDP550_DC_BASE,
457ad49f860SLiviu Dudau 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
458ad49f860SLiviu Dudau 			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
459ad49f860SLiviu Dudau 			.n_layers = ARRAY_SIZE(malidp550_layers),
460ad49f860SLiviu Dudau 			.layers = malidp550_layers,
461ad49f860SLiviu Dudau 			.de_irq_map = {
462ad49f860SLiviu Dudau 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
463ad49f860SLiviu Dudau 					    MALIDP550_DE_IRQ_VSYNC,
464ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
465ad49f860SLiviu Dudau 			},
466ad49f860SLiviu Dudau 			.se_irq_map = {
467ad49f860SLiviu Dudau 				.irq_mask = MALIDP550_SE_IRQ_EOW |
468ad49f860SLiviu Dudau 					    MALIDP550_SE_IRQ_AXI_ERR,
469ad49f860SLiviu Dudau 			},
470ad49f860SLiviu Dudau 			.dc_irq_map = {
471ad49f860SLiviu Dudau 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
472ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
473ad49f860SLiviu Dudau 			},
474ad49f860SLiviu Dudau 			.input_formats = malidp550_de_formats,
475ad49f860SLiviu Dudau 			.n_input_formats = ARRAY_SIZE(malidp550_de_formats),
476ad49f860SLiviu Dudau 		},
477ad49f860SLiviu Dudau 		.query_hw = malidp550_query_hw,
478ad49f860SLiviu Dudau 		.enter_config_mode = malidp550_enter_config_mode,
479ad49f860SLiviu Dudau 		.leave_config_mode = malidp550_leave_config_mode,
480ad49f860SLiviu Dudau 		.in_config_mode = malidp550_in_config_mode,
481ad49f860SLiviu Dudau 		.set_config_valid = malidp550_set_config_valid,
482ad49f860SLiviu Dudau 		.modeset = malidp550_modeset,
483ad49f860SLiviu Dudau 		.rotmem_required = malidp550_rotmem_required,
484ad49f860SLiviu Dudau 	},
485ad49f860SLiviu Dudau 	[MALIDP_650] = {
486ad49f860SLiviu Dudau 		.map = {
487ad49f860SLiviu Dudau 			.se_base = MALIDP550_SE_BASE,
488ad49f860SLiviu Dudau 			.dc_base = MALIDP550_DC_BASE,
489ad49f860SLiviu Dudau 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
490ad49f860SLiviu Dudau 			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
491ad49f860SLiviu Dudau 			.n_layers = ARRAY_SIZE(malidp550_layers),
492ad49f860SLiviu Dudau 			.layers = malidp550_layers,
493ad49f860SLiviu Dudau 			.de_irq_map = {
494ad49f860SLiviu Dudau 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
495ad49f860SLiviu Dudau 					    MALIDP650_DE_IRQ_DRIFT |
496ad49f860SLiviu Dudau 					    MALIDP550_DE_IRQ_VSYNC,
497ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
498ad49f860SLiviu Dudau 			},
499ad49f860SLiviu Dudau 			.se_irq_map = {
500ad49f860SLiviu Dudau 				.irq_mask = MALIDP550_SE_IRQ_EOW |
501ad49f860SLiviu Dudau 					    MALIDP550_SE_IRQ_AXI_ERR,
502ad49f860SLiviu Dudau 			},
503ad49f860SLiviu Dudau 			.dc_irq_map = {
504ad49f860SLiviu Dudau 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
505ad49f860SLiviu Dudau 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
506ad49f860SLiviu Dudau 			},
507ad49f860SLiviu Dudau 			.input_formats = malidp550_de_formats,
508ad49f860SLiviu Dudau 			.n_input_formats = ARRAY_SIZE(malidp550_de_formats),
509ad49f860SLiviu Dudau 		},
510ad49f860SLiviu Dudau 		.query_hw = malidp650_query_hw,
511ad49f860SLiviu Dudau 		.enter_config_mode = malidp550_enter_config_mode,
512ad49f860SLiviu Dudau 		.leave_config_mode = malidp550_leave_config_mode,
513ad49f860SLiviu Dudau 		.in_config_mode = malidp550_in_config_mode,
514ad49f860SLiviu Dudau 		.set_config_valid = malidp550_set_config_valid,
515ad49f860SLiviu Dudau 		.modeset = malidp550_modeset,
516ad49f860SLiviu Dudau 		.rotmem_required = malidp550_rotmem_required,
517ad49f860SLiviu Dudau 	},
518ad49f860SLiviu Dudau };
519ad49f860SLiviu Dudau 
520ad49f860SLiviu Dudau u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
521ad49f860SLiviu Dudau 			   u8 layer_id, u32 format)
522ad49f860SLiviu Dudau {
523ad49f860SLiviu Dudau 	unsigned int i;
524ad49f860SLiviu Dudau 
525ad49f860SLiviu Dudau 	for (i = 0; i < map->n_input_formats; i++) {
526ad49f860SLiviu Dudau 		if (((map->input_formats[i].layer & layer_id) == layer_id) &&
527ad49f860SLiviu Dudau 		    (map->input_formats[i].format == format))
528ad49f860SLiviu Dudau 			return map->input_formats[i].id;
529ad49f860SLiviu Dudau 	}
530ad49f860SLiviu Dudau 
531ad49f860SLiviu Dudau 	return MALIDP_INVALID_FORMAT_ID;
532ad49f860SLiviu Dudau }
533ad49f860SLiviu Dudau 
534ad49f860SLiviu Dudau static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
535ad49f860SLiviu Dudau {
536ad49f860SLiviu Dudau 	u32 base = malidp_get_block_base(hwdev, block);
537ad49f860SLiviu Dudau 
538ad49f860SLiviu Dudau 	if (hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
539ad49f860SLiviu Dudau 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
540ad49f860SLiviu Dudau 	else
541ad49f860SLiviu Dudau 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
542ad49f860SLiviu Dudau }
543ad49f860SLiviu Dudau 
544ad49f860SLiviu Dudau static irqreturn_t malidp_de_irq(int irq, void *arg)
545ad49f860SLiviu Dudau {
546ad49f860SLiviu Dudau 	struct drm_device *drm = arg;
547ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
548ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev;
549ad49f860SLiviu Dudau 	const struct malidp_irq_map *de;
550ad49f860SLiviu Dudau 	u32 status, mask, dc_status;
551ad49f860SLiviu Dudau 	irqreturn_t ret = IRQ_NONE;
552ad49f860SLiviu Dudau 
553ad49f860SLiviu Dudau 	if (!drm->dev_private)
554ad49f860SLiviu Dudau 		return IRQ_HANDLED;
555ad49f860SLiviu Dudau 
556ad49f860SLiviu Dudau 	hwdev = malidp->dev;
557ad49f860SLiviu Dudau 	de = &hwdev->map.de_irq_map;
558ad49f860SLiviu Dudau 
559ad49f860SLiviu Dudau 	/* first handle the config valid IRQ */
560ad49f860SLiviu Dudau 	dc_status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
561ad49f860SLiviu Dudau 	if (dc_status & hwdev->map.dc_irq_map.vsync_irq) {
562ad49f860SLiviu Dudau 		/* we have a page flip event */
563ad49f860SLiviu Dudau 		atomic_set(&malidp->config_valid, 1);
564ad49f860SLiviu Dudau 		malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
565ad49f860SLiviu Dudau 		ret = IRQ_WAKE_THREAD;
566ad49f860SLiviu Dudau 	}
567ad49f860SLiviu Dudau 
568ad49f860SLiviu Dudau 	status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
569ad49f860SLiviu Dudau 	if (!(status & de->irq_mask))
570ad49f860SLiviu Dudau 		return ret;
571ad49f860SLiviu Dudau 
572ad49f860SLiviu Dudau 	mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
573ad49f860SLiviu Dudau 	status &= mask;
574ad49f860SLiviu Dudau 	if (status & de->vsync_irq)
575ad49f860SLiviu Dudau 		drm_crtc_handle_vblank(&malidp->crtc);
576ad49f860SLiviu Dudau 
577ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
578ad49f860SLiviu Dudau 
579ad49f860SLiviu Dudau 	return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
580ad49f860SLiviu Dudau }
581ad49f860SLiviu Dudau 
582ad49f860SLiviu Dudau static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
583ad49f860SLiviu Dudau {
584ad49f860SLiviu Dudau 	struct drm_device *drm = arg;
585ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
586ad49f860SLiviu Dudau 
587ad49f860SLiviu Dudau 	wake_up(&malidp->wq);
588ad49f860SLiviu Dudau 
589ad49f860SLiviu Dudau 	return IRQ_HANDLED;
590ad49f860SLiviu Dudau }
591ad49f860SLiviu Dudau 
592ad49f860SLiviu Dudau int malidp_de_irq_init(struct drm_device *drm, int irq)
593ad49f860SLiviu Dudau {
594ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
595ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
596ad49f860SLiviu Dudau 	int ret;
597ad49f860SLiviu Dudau 
598ad49f860SLiviu Dudau 	/* ensure interrupts are disabled */
599ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
600ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
601ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
602ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
603ad49f860SLiviu Dudau 
604ad49f860SLiviu Dudau 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
605ad49f860SLiviu Dudau 					malidp_de_irq_thread_handler,
606ad49f860SLiviu Dudau 					IRQF_SHARED, "malidp-de", drm);
607ad49f860SLiviu Dudau 	if (ret < 0) {
608ad49f860SLiviu Dudau 		DRM_ERROR("failed to install DE IRQ handler\n");
609ad49f860SLiviu Dudau 		return ret;
610ad49f860SLiviu Dudau 	}
611ad49f860SLiviu Dudau 
612ad49f860SLiviu Dudau 	/* first enable the DC block IRQs */
613ad49f860SLiviu Dudau 	malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
614ad49f860SLiviu Dudau 			     hwdev->map.dc_irq_map.irq_mask);
615ad49f860SLiviu Dudau 
616ad49f860SLiviu Dudau 	/* now enable the DE block IRQs */
617ad49f860SLiviu Dudau 	malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
618ad49f860SLiviu Dudau 			     hwdev->map.de_irq_map.irq_mask);
619ad49f860SLiviu Dudau 
620ad49f860SLiviu Dudau 	return 0;
621ad49f860SLiviu Dudau }
622ad49f860SLiviu Dudau 
623ad49f860SLiviu Dudau void malidp_de_irq_fini(struct drm_device *drm)
624ad49f860SLiviu Dudau {
625ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
626ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
627ad49f860SLiviu Dudau 
628ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
629ad49f860SLiviu Dudau 			      hwdev->map.de_irq_map.irq_mask);
630ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
631ad49f860SLiviu Dudau 			      hwdev->map.dc_irq_map.irq_mask);
632ad49f860SLiviu Dudau }
633ad49f860SLiviu Dudau 
634ad49f860SLiviu Dudau static irqreturn_t malidp_se_irq(int irq, void *arg)
635ad49f860SLiviu Dudau {
636ad49f860SLiviu Dudau 	struct drm_device *drm = arg;
637ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
638ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
639ad49f860SLiviu Dudau 	u32 status, mask;
640ad49f860SLiviu Dudau 
641ad49f860SLiviu Dudau 	status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
642ad49f860SLiviu Dudau 	if (!(status & hwdev->map.se_irq_map.irq_mask))
643ad49f860SLiviu Dudau 		return IRQ_NONE;
644ad49f860SLiviu Dudau 
645ad49f860SLiviu Dudau 	mask = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_MASKIRQ);
646ad49f860SLiviu Dudau 	status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
647ad49f860SLiviu Dudau 	status &= mask;
648ad49f860SLiviu Dudau 	/* ToDo: status decoding and firing up of VSYNC and page flip events */
649ad49f860SLiviu Dudau 
650ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
651ad49f860SLiviu Dudau 
652ad49f860SLiviu Dudau 	return IRQ_HANDLED;
653ad49f860SLiviu Dudau }
654ad49f860SLiviu Dudau 
655ad49f860SLiviu Dudau static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
656ad49f860SLiviu Dudau {
657ad49f860SLiviu Dudau 	return IRQ_HANDLED;
658ad49f860SLiviu Dudau }
659ad49f860SLiviu Dudau 
660ad49f860SLiviu Dudau int malidp_se_irq_init(struct drm_device *drm, int irq)
661ad49f860SLiviu Dudau {
662ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
663ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
664ad49f860SLiviu Dudau 	int ret;
665ad49f860SLiviu Dudau 
666ad49f860SLiviu Dudau 	/* ensure interrupts are disabled */
667ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
668ad49f860SLiviu Dudau 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
669ad49f860SLiviu Dudau 
670ad49f860SLiviu Dudau 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
671ad49f860SLiviu Dudau 					malidp_se_irq_thread_handler,
672ad49f860SLiviu Dudau 					IRQF_SHARED, "malidp-se", drm);
673ad49f860SLiviu Dudau 	if (ret < 0) {
674ad49f860SLiviu Dudau 		DRM_ERROR("failed to install SE IRQ handler\n");
675ad49f860SLiviu Dudau 		return ret;
676ad49f860SLiviu Dudau 	}
677ad49f860SLiviu Dudau 
678ad49f860SLiviu Dudau 	malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
679ad49f860SLiviu Dudau 			     hwdev->map.se_irq_map.irq_mask);
680ad49f860SLiviu Dudau 
681ad49f860SLiviu Dudau 	return 0;
682ad49f860SLiviu Dudau }
683ad49f860SLiviu Dudau 
684ad49f860SLiviu Dudau void malidp_se_irq_fini(struct drm_device *drm)
685ad49f860SLiviu Dudau {
686ad49f860SLiviu Dudau 	struct malidp_drm *malidp = drm->dev_private;
687ad49f860SLiviu Dudau 	struct malidp_hw_device *hwdev = malidp->dev;
688ad49f860SLiviu Dudau 
689ad49f860SLiviu Dudau 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
690ad49f860SLiviu Dudau 			      hwdev->map.se_irq_map.irq_mask);
691ad49f860SLiviu Dudau }
692