• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/clk.h>
16 #include <linux/types.h>
17 #include <linux/io.h>
18 #include <drm/drmP.h>
19 #include <video/videomode.h>
20 #include <video/display_timing.h>
21 
22 #include "malidp_drv.h"
23 #include "malidp_hw.h"
24 
25 static const struct malidp_format_id malidp500_de_formats[] = {
26 	/*    fourcc,   layers supporting the format,     internal id  */
27 	{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  0 },
28 	{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  1 },
29 	{ DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  2 },
30 	{ DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  3 },
31 	{ DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  4 },
32 	{ DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  5 },
33 	{ DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  6 },
34 	{ DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  7 },
35 	{ DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  8 },
36 	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  9 },
37 	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
38 	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
39 	{ DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
40 	{ DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
41 	{ DRM_FORMAT_NV12, DE_VIDEO1, 14 },
42 	{ DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
43 };
44 
45 #define MALIDP_ID(__group, __format) \
46 	((((__group) & 0x7) << 3) | ((__format) & 0x7))
47 
48 #define MALIDP_COMMON_FORMATS \
49 	/*    fourcc,   layers supporting the format,      internal id   */ \
50 	{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 0) }, \
51 	{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 1) }, \
52 	{ DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 2) }, \
53 	{ DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 3) }, \
54 	{ DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
55 	{ DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
56 	{ DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
57 	{ DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
58 	{ DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 0) }, \
59 	{ DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 1) }, \
60 	{ DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 2) }, \
61 	{ DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 3) }, \
62 	{ DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 0) }, \
63 	{ DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 1) }, \
64 	{ DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
65 	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
66 	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
67 	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
68 	{ DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },	\
69 	{ DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },	\
70 	{ DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) },	\
71 	{ DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
72 
73 static const struct malidp_format_id malidp550_de_formats[] = {
74 	MALIDP_COMMON_FORMATS,
75 };
76 
77 static const struct malidp_layer malidp500_layers[] = {
78 	{ DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0 },
79 	{ DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE },
80 	{ DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE },
81 };
82 
83 static const struct malidp_layer malidp550_layers[] = {
84 	{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0 },
85 	{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE },
86 	{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0 },
87 	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE },
88 };
89 
90 #define SE_N_SCALING_COEFFS	96
91 static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
92 	[MALIDP_UPSCALING_COEFFS - 1] = {
93 		0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
94 		0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
95 		0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
96 		0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
97 		0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
98 		0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
99 		0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
100 		0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
101 		0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
102 		0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
103 		0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
104 		0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
105 	},
106 	[MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
107 		0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
108 		0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
109 		0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
110 		0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
111 		0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
112 		0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
113 		0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
114 		0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
115 		0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
116 		0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
117 		0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
118 		0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
119 	},
120 	[MALIDP_DOWNSCALING_2_COEFFS - 1] = {
121 		0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
122 		0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
123 		0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
124 		0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
125 		0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
126 		0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
127 		0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
128 		0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
129 		0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
130 		0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
131 		0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
132 		0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
133 	},
134 	[MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
135 		0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
136 		0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
137 		0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
138 		0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
139 		0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
140 		0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
141 		0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
142 		0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
143 		0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
144 		0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
145 		0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
146 		0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
147 	},
148 	[MALIDP_DOWNSCALING_4_COEFFS - 1] = {
149 		0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
150 		0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
151 		0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
152 		0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
153 		0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
154 		0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
155 		0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
156 		0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
157 		0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
158 		0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
159 		0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
160 		0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
161 	},
162 };
163 
164 #define MALIDP_DE_DEFAULT_PREFETCH_START	5
165 
malidp500_query_hw(struct malidp_hw_device * hwdev)166 static int malidp500_query_hw(struct malidp_hw_device *hwdev)
167 {
168 	u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
169 	/* bit 4 of the CONFIG_ID register holds the line size multiplier */
170 	u8 ln_size_mult = conf & 0x10 ? 2 : 1;
171 
172 	hwdev->min_line_size = 2;
173 	hwdev->max_line_size = SZ_2K * ln_size_mult;
174 	hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
175 	hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
176 
177 	return 0;
178 }
179 
malidp500_enter_config_mode(struct malidp_hw_device * hwdev)180 static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
181 {
182 	u32 status, count = 100;
183 
184 	malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
185 	while (count) {
186 		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
187 		if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
188 			break;
189 		/*
190 		 * entering config mode can take as long as the rendering
191 		 * of a full frame, hence the long sleep here
192 		 */
193 		usleep_range(1000, 10000);
194 		count--;
195 	}
196 	WARN(count == 0, "timeout while entering config mode");
197 }
198 
malidp500_leave_config_mode(struct malidp_hw_device * hwdev)199 static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
200 {
201 	u32 status, count = 100;
202 
203 	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
204 	malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
205 	while (count) {
206 		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
207 		if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
208 			break;
209 		usleep_range(100, 1000);
210 		count--;
211 	}
212 	WARN(count == 0, "timeout while leaving config mode");
213 }
214 
malidp500_in_config_mode(struct malidp_hw_device * hwdev)215 static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
216 {
217 	u32 status;
218 
219 	status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
220 	if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
221 		return true;
222 
223 	return false;
224 }
225 
malidp500_set_config_valid(struct malidp_hw_device * hwdev)226 static void malidp500_set_config_valid(struct malidp_hw_device *hwdev)
227 {
228 	malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
229 }
230 
malidp500_modeset(struct malidp_hw_device * hwdev,struct videomode * mode)231 static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
232 {
233 	u32 val = 0;
234 
235 	malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
236 	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
237 		val |= MALIDP500_HSYNCPOL;
238 	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
239 		val |= MALIDP500_VSYNCPOL;
240 	val |= MALIDP_DE_DEFAULT_PREFETCH_START;
241 	malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
242 
243 	/*
244 	 * Mali-DP500 encodes the background color like this:
245 	 *    - red   @ MALIDP500_BGND_COLOR[12:0]
246 	 *    - green @ MALIDP500_BGND_COLOR[27:16]
247 	 *    - blue  @ (MALIDP500_BGND_COLOR + 4)[12:0]
248 	 */
249 	val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
250 	      (MALIDP_BGND_COLOR_R & 0xfff);
251 	malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
252 	malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
253 
254 	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
255 		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
256 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
257 
258 	val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
259 		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
260 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
261 
262 	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
263 		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
264 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
265 
266 	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
267 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
268 
269 	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
270 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
271 	else
272 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
273 }
274 
malidp500_rotmem_required(struct malidp_hw_device * hwdev,u16 w,u16 h,u32 fmt)275 static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
276 {
277 	/* RGB888 or BGR888 can't be rotated */
278 	if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
279 		return -EINVAL;
280 
281 	/*
282 	 * Each layer needs enough rotation memory to fit 8 lines
283 	 * worth of pixel data. Required size is then:
284 	 *    size = rotated_width * (bpp / 8) * 8;
285 	 */
286 	return w * drm_format_plane_cpp(fmt, 0) * 8;
287 }
288 
malidp500_se_write_pp_coefftab(struct malidp_hw_device * hwdev,u32 direction,u16 addr,u8 coeffs_id)289 static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
290 					   u32 direction,
291 					   u16 addr,
292 					   u8 coeffs_id)
293 {
294 	int i;
295 	u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
296 
297 	malidp_hw_write(hwdev,
298 			direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
299 			scaling_control + MALIDP_SE_COEFFTAB_ADDR);
300 	for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
301 		malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
302 				dp500_se_scaling_coeffs[coeffs_id][i]),
303 				scaling_control + MALIDP_SE_COEFFTAB_DATA);
304 }
305 
malidp500_se_set_scaling_coeffs(struct malidp_hw_device * hwdev,struct malidp_se_config * se_config,struct malidp_se_config * old_config)306 static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
307 					   struct malidp_se_config *se_config,
308 					   struct malidp_se_config *old_config)
309 {
310 	/* Get array indices into dp500_se_scaling_coeffs. */
311 	u8 h = (u8)se_config->hcoeff - 1;
312 	u8 v = (u8)se_config->vcoeff - 1;
313 
314 	if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
315 		    v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
316 		return -EINVAL;
317 
318 	if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
319 			 se_config->vcoeff != old_config->vcoeff)) {
320 		malidp500_se_write_pp_coefftab(hwdev,
321 					       (MALIDP_SE_V_COEFFTAB |
322 						MALIDP_SE_H_COEFFTAB),
323 					       0, v);
324 	} else {
325 		if (se_config->vcoeff != old_config->vcoeff)
326 			malidp500_se_write_pp_coefftab(hwdev,
327 						       MALIDP_SE_V_COEFFTAB,
328 						       0, v);
329 		if (se_config->hcoeff != old_config->hcoeff)
330 			malidp500_se_write_pp_coefftab(hwdev,
331 						       MALIDP_SE_H_COEFFTAB,
332 						       0, h);
333 	}
334 
335 	return 0;
336 }
337 
malidp500_se_calc_mclk(struct malidp_hw_device * hwdev,struct malidp_se_config * se_config,struct videomode * vm)338 static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
339 				   struct malidp_se_config *se_config,
340 				   struct videomode *vm)
341 {
342 	unsigned long mclk;
343 	unsigned long pxlclk = vm->pixelclock; /* Hz */
344 	unsigned long htotal = vm->hactive + vm->hfront_porch +
345 			       vm->hback_porch + vm->hsync_len;
346 	unsigned long input_size = se_config->input_w * se_config->input_h;
347 	unsigned long a = 10;
348 	long ret;
349 
350 	/*
351 	 * mclk = max(a, 1.5) * pxlclk
352 	 *
353 	 * To avoid float calculaiton, using 15 instead of 1.5 and div by
354 	 * 10 to get mclk.
355 	 */
356 	if (se_config->scale_enable) {
357 		a = 15 * input_size / (htotal * se_config->output_h);
358 		if (a < 15)
359 			a = 15;
360 	}
361 	mclk = a * pxlclk / 10;
362 	ret = clk_get_rate(hwdev->mclk);
363 	if (ret < mclk) {
364 		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
365 				 mclk / 1000);
366 		return -EINVAL;
367 	}
368 	return ret;
369 }
370 
malidp550_query_hw(struct malidp_hw_device * hwdev)371 static int malidp550_query_hw(struct malidp_hw_device *hwdev)
372 {
373 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
374 	u8 ln_size = (conf >> 4) & 0x3, rsize;
375 
376 	hwdev->min_line_size = 2;
377 
378 	switch (ln_size) {
379 	case 0:
380 		hwdev->max_line_size = SZ_2K;
381 		/* two banks of 64KB for rotation memory */
382 		rsize = 64;
383 		break;
384 	case 1:
385 		hwdev->max_line_size = SZ_4K;
386 		/* two banks of 128KB for rotation memory */
387 		rsize = 128;
388 		break;
389 	case 2:
390 		hwdev->max_line_size = 1280;
391 		/* two banks of 40KB for rotation memory */
392 		rsize = 40;
393 		break;
394 	case 3:
395 		/* reserved value */
396 		hwdev->max_line_size = 0;
397 		return -EINVAL;
398 	}
399 
400 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
401 	return 0;
402 }
403 
malidp550_enter_config_mode(struct malidp_hw_device * hwdev)404 static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
405 {
406 	u32 status, count = 100;
407 
408 	malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
409 	while (count) {
410 		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
411 		if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
412 			break;
413 		/*
414 		 * entering config mode can take as long as the rendering
415 		 * of a full frame, hence the long sleep here
416 		 */
417 		usleep_range(1000, 10000);
418 		count--;
419 	}
420 	WARN(count == 0, "timeout while entering config mode");
421 }
422 
malidp550_leave_config_mode(struct malidp_hw_device * hwdev)423 static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
424 {
425 	u32 status, count = 100;
426 
427 	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
428 	malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
429 	while (count) {
430 		status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
431 		if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
432 			break;
433 		usleep_range(100, 1000);
434 		count--;
435 	}
436 	WARN(count == 0, "timeout while leaving config mode");
437 }
438 
malidp550_in_config_mode(struct malidp_hw_device * hwdev)439 static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
440 {
441 	u32 status;
442 
443 	status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
444 	if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
445 		return true;
446 
447 	return false;
448 }
449 
malidp550_set_config_valid(struct malidp_hw_device * hwdev)450 static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
451 {
452 	malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
453 }
454 
malidp550_modeset(struct malidp_hw_device * hwdev,struct videomode * mode)455 static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
456 {
457 	u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
458 
459 	malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
460 	/*
461 	 * Mali-DP550 and Mali-DP650 encode the background color like this:
462 	 *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
463 	 *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
464 	 *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
465 	 *
466 	 * We need to truncate the least significant 4 bits from the default
467 	 * MALIDP_BGND_COLOR_x values
468 	 */
469 	val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
470 	      (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
471 	      ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
472 	malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
473 
474 	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
475 		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
476 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
477 
478 	val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
479 		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
480 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
481 
482 	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
483 		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
484 	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
485 		val |= MALIDP550_HSYNCPOL;
486 	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
487 		val |= MALIDP550_VSYNCPOL;
488 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
489 
490 	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
491 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
492 
493 	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
494 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
495 	else
496 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
497 }
498 
malidp550_rotmem_required(struct malidp_hw_device * hwdev,u16 w,u16 h,u32 fmt)499 static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
500 {
501 	u32 bytes_per_col;
502 
503 	/* raw RGB888 or BGR888 can't be rotated */
504 	if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
505 		return -EINVAL;
506 
507 	switch (fmt) {
508 	/* 8 lines at 4 bytes per pixel */
509 	case DRM_FORMAT_ARGB2101010:
510 	case DRM_FORMAT_ABGR2101010:
511 	case DRM_FORMAT_RGBA1010102:
512 	case DRM_FORMAT_BGRA1010102:
513 	case DRM_FORMAT_ARGB8888:
514 	case DRM_FORMAT_ABGR8888:
515 	case DRM_FORMAT_RGBA8888:
516 	case DRM_FORMAT_BGRA8888:
517 	case DRM_FORMAT_XRGB8888:
518 	case DRM_FORMAT_XBGR8888:
519 	case DRM_FORMAT_RGBX8888:
520 	case DRM_FORMAT_BGRX8888:
521 	case DRM_FORMAT_RGB888:
522 	case DRM_FORMAT_BGR888:
523 	/* 16 lines at 2 bytes per pixel */
524 	case DRM_FORMAT_RGBA5551:
525 	case DRM_FORMAT_ABGR1555:
526 	case DRM_FORMAT_RGB565:
527 	case DRM_FORMAT_BGR565:
528 	case DRM_FORMAT_UYVY:
529 	case DRM_FORMAT_YUYV:
530 		bytes_per_col = 32;
531 		break;
532 	/* 16 lines at 1.5 bytes per pixel */
533 	case DRM_FORMAT_NV12:
534 	case DRM_FORMAT_YUV420:
535 		bytes_per_col = 24;
536 		break;
537 	default:
538 		return -EINVAL;
539 	}
540 
541 	return w * bytes_per_col;
542 }
543 
malidp550_se_set_scaling_coeffs(struct malidp_hw_device * hwdev,struct malidp_se_config * se_config,struct malidp_se_config * old_config)544 static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
545 					   struct malidp_se_config *se_config,
546 					   struct malidp_se_config *old_config)
547 {
548 	u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
549 		   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
550 	u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
551 			MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
552 
553 	malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
554 	malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
555 	return 0;
556 }
557 
malidp550_se_calc_mclk(struct malidp_hw_device * hwdev,struct malidp_se_config * se_config,struct videomode * vm)558 static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
559 				   struct malidp_se_config *se_config,
560 				   struct videomode *vm)
561 {
562 	unsigned long mclk;
563 	unsigned long pxlclk = vm->pixelclock;
564 	unsigned long htotal = vm->hactive + vm->hfront_porch +
565 			       vm->hback_porch + vm->hsync_len;
566 	unsigned long numerator = 1, denominator = 1;
567 	long ret;
568 
569 	if (se_config->scale_enable) {
570 		numerator = max(se_config->input_w, se_config->output_w) *
571 			    se_config->input_h;
572 		numerator += se_config->output_w *
573 			     (se_config->output_h -
574 			      min(se_config->input_h, se_config->output_h));
575 		denominator = (htotal - 2) * se_config->output_h;
576 	}
577 
578 	/* mclk can't be slower than pxlclk. */
579 	if (numerator < denominator)
580 		numerator = denominator = 1;
581 	mclk = (pxlclk * numerator) / denominator;
582 	ret = clk_get_rate(hwdev->mclk);
583 	if (ret < mclk) {
584 		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
585 				 mclk / 1000);
586 		return -EINVAL;
587 	}
588 	return ret;
589 }
590 
malidp650_query_hw(struct malidp_hw_device * hwdev)591 static int malidp650_query_hw(struct malidp_hw_device *hwdev)
592 {
593 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
594 	u8 ln_size = (conf >> 4) & 0x3, rsize;
595 
596 	hwdev->min_line_size = 4;
597 
598 	switch (ln_size) {
599 	case 0:
600 	case 2:
601 		/* reserved values */
602 		hwdev->max_line_size = 0;
603 		return -EINVAL;
604 	case 1:
605 		hwdev->max_line_size = SZ_4K;
606 		/* two banks of 128KB for rotation memory */
607 		rsize = 128;
608 		break;
609 	case 3:
610 		hwdev->max_line_size = 2560;
611 		/* two banks of 80KB for rotation memory */
612 		rsize = 80;
613 	}
614 
615 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
616 	return 0;
617 }
618 
619 const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
620 	[MALIDP_500] = {
621 		.map = {
622 			.coeffs_base = MALIDP500_COEFFS_BASE,
623 			.se_base = MALIDP500_SE_BASE,
624 			.dc_base = MALIDP500_DC_BASE,
625 			.out_depth_base = MALIDP500_OUTPUT_DEPTH,
626 			.features = 0,	/* no CLEARIRQ register */
627 			.n_layers = ARRAY_SIZE(malidp500_layers),
628 			.layers = malidp500_layers,
629 			.de_irq_map = {
630 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
631 					    MALIDP500_DE_IRQ_AXI_ERR |
632 					    MALIDP500_DE_IRQ_VSYNC |
633 					    MALIDP500_DE_IRQ_GLOBAL,
634 				.vsync_irq = MALIDP500_DE_IRQ_VSYNC,
635 			},
636 			.se_irq_map = {
637 				.irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
638 					    MALIDP500_SE_IRQ_GLOBAL,
639 				.vsync_irq = 0,
640 			},
641 			.dc_irq_map = {
642 				.irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
643 				.vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
644 			},
645 			.pixel_formats = malidp500_de_formats,
646 			.n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
647 			.bus_align_bytes = 8,
648 		},
649 		.query_hw = malidp500_query_hw,
650 		.enter_config_mode = malidp500_enter_config_mode,
651 		.leave_config_mode = malidp500_leave_config_mode,
652 		.in_config_mode = malidp500_in_config_mode,
653 		.set_config_valid = malidp500_set_config_valid,
654 		.modeset = malidp500_modeset,
655 		.rotmem_required = malidp500_rotmem_required,
656 		.se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
657 		.se_calc_mclk = malidp500_se_calc_mclk,
658 		.features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
659 	},
660 	[MALIDP_550] = {
661 		.map = {
662 			.coeffs_base = MALIDP550_COEFFS_BASE,
663 			.se_base = MALIDP550_SE_BASE,
664 			.dc_base = MALIDP550_DC_BASE,
665 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
666 			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
667 			.n_layers = ARRAY_SIZE(malidp550_layers),
668 			.layers = malidp550_layers,
669 			.de_irq_map = {
670 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
671 					    MALIDP550_DE_IRQ_VSYNC,
672 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
673 			},
674 			.se_irq_map = {
675 				.irq_mask = MALIDP550_SE_IRQ_EOW |
676 					    MALIDP550_SE_IRQ_AXI_ERR,
677 			},
678 			.dc_irq_map = {
679 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
680 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
681 			},
682 			.pixel_formats = malidp550_de_formats,
683 			.n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
684 			.bus_align_bytes = 8,
685 		},
686 		.query_hw = malidp550_query_hw,
687 		.enter_config_mode = malidp550_enter_config_mode,
688 		.leave_config_mode = malidp550_leave_config_mode,
689 		.in_config_mode = malidp550_in_config_mode,
690 		.set_config_valid = malidp550_set_config_valid,
691 		.modeset = malidp550_modeset,
692 		.rotmem_required = malidp550_rotmem_required,
693 		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
694 		.se_calc_mclk = malidp550_se_calc_mclk,
695 		.features = 0,
696 	},
697 	[MALIDP_650] = {
698 		.map = {
699 			.coeffs_base = MALIDP550_COEFFS_BASE,
700 			.se_base = MALIDP550_SE_BASE,
701 			.dc_base = MALIDP550_DC_BASE,
702 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
703 			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
704 			.n_layers = ARRAY_SIZE(malidp550_layers),
705 			.layers = malidp550_layers,
706 			.de_irq_map = {
707 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
708 					    MALIDP650_DE_IRQ_DRIFT |
709 					    MALIDP550_DE_IRQ_VSYNC,
710 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
711 			},
712 			.se_irq_map = {
713 				.irq_mask = MALIDP550_SE_IRQ_EOW |
714 					    MALIDP550_SE_IRQ_AXI_ERR,
715 			},
716 			.dc_irq_map = {
717 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
718 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
719 			},
720 			.pixel_formats = malidp550_de_formats,
721 			.n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
722 			.bus_align_bytes = 16,
723 		},
724 		.query_hw = malidp650_query_hw,
725 		.enter_config_mode = malidp550_enter_config_mode,
726 		.leave_config_mode = malidp550_leave_config_mode,
727 		.in_config_mode = malidp550_in_config_mode,
728 		.set_config_valid = malidp550_set_config_valid,
729 		.modeset = malidp550_modeset,
730 		.rotmem_required = malidp550_rotmem_required,
731 		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
732 		.se_calc_mclk = malidp550_se_calc_mclk,
733 		.features = 0,
734 	},
735 };
736 
malidp_hw_get_format_id(const struct malidp_hw_regmap * map,u8 layer_id,u32 format)737 u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
738 			   u8 layer_id, u32 format)
739 {
740 	unsigned int i;
741 
742 	for (i = 0; i < map->n_pixel_formats; i++) {
743 		if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
744 		    (map->pixel_formats[i].format == format))
745 			return map->pixel_formats[i].id;
746 	}
747 
748 	return MALIDP_INVALID_FORMAT_ID;
749 }
750 
malidp_hw_clear_irq(struct malidp_hw_device * hwdev,u8 block,u32 irq)751 static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
752 {
753 	u32 base = malidp_get_block_base(hwdev, block);
754 
755 	if (hwdev->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
756 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
757 	else
758 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
759 }
760 
malidp_de_irq(int irq,void * arg)761 static irqreturn_t malidp_de_irq(int irq, void *arg)
762 {
763 	struct drm_device *drm = arg;
764 	struct malidp_drm *malidp = drm->dev_private;
765 	struct malidp_hw_device *hwdev;
766 	const struct malidp_irq_map *de;
767 	u32 status, mask, dc_status;
768 	irqreturn_t ret = IRQ_NONE;
769 
770 	hwdev = malidp->dev;
771 	de = &hwdev->map.de_irq_map;
772 
773 	/*
774 	 * if we are suspended it is likely that we were invoked because
775 	 * we share an interrupt line with some other driver, don't try
776 	 * to read the hardware registers
777 	 */
778 	if (hwdev->pm_suspended)
779 		return IRQ_NONE;
780 
781 	/* first handle the config valid IRQ */
782 	dc_status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
783 	if (dc_status & hwdev->map.dc_irq_map.vsync_irq) {
784 		/* we have a page flip event */
785 		atomic_set(&malidp->config_valid, 1);
786 		malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
787 		ret = IRQ_WAKE_THREAD;
788 	}
789 
790 	status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
791 	if (!(status & de->irq_mask))
792 		return ret;
793 
794 	mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
795 	status &= mask;
796 	if (status & de->vsync_irq)
797 		drm_crtc_handle_vblank(&malidp->crtc);
798 
799 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
800 
801 	return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
802 }
803 
malidp_de_irq_thread_handler(int irq,void * arg)804 static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
805 {
806 	struct drm_device *drm = arg;
807 	struct malidp_drm *malidp = drm->dev_private;
808 
809 	wake_up(&malidp->wq);
810 
811 	return IRQ_HANDLED;
812 }
813 
malidp_de_irq_init(struct drm_device * drm,int irq)814 int malidp_de_irq_init(struct drm_device *drm, int irq)
815 {
816 	struct malidp_drm *malidp = drm->dev_private;
817 	struct malidp_hw_device *hwdev = malidp->dev;
818 	int ret;
819 
820 	/* ensure interrupts are disabled */
821 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
822 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
823 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
824 	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
825 
826 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
827 					malidp_de_irq_thread_handler,
828 					IRQF_SHARED, "malidp-de", drm);
829 	if (ret < 0) {
830 		DRM_ERROR("failed to install DE IRQ handler\n");
831 		return ret;
832 	}
833 
834 	/* first enable the DC block IRQs */
835 	malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
836 			     hwdev->map.dc_irq_map.irq_mask);
837 
838 	/* now enable the DE block IRQs */
839 	malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
840 			     hwdev->map.de_irq_map.irq_mask);
841 
842 	return 0;
843 }
844 
malidp_de_irq_fini(struct drm_device * drm)845 void malidp_de_irq_fini(struct drm_device *drm)
846 {
847 	struct malidp_drm *malidp = drm->dev_private;
848 	struct malidp_hw_device *hwdev = malidp->dev;
849 
850 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
851 			      hwdev->map.de_irq_map.irq_mask);
852 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
853 			      hwdev->map.dc_irq_map.irq_mask);
854 }
855 
malidp_se_irq(int irq,void * arg)856 static irqreturn_t malidp_se_irq(int irq, void *arg)
857 {
858 	struct drm_device *drm = arg;
859 	struct malidp_drm *malidp = drm->dev_private;
860 	struct malidp_hw_device *hwdev = malidp->dev;
861 	u32 status, mask;
862 
863 	/*
864 	 * if we are suspended it is likely that we were invoked because
865 	 * we share an interrupt line with some other driver, don't try
866 	 * to read the hardware registers
867 	 */
868 	if (hwdev->pm_suspended)
869 		return IRQ_NONE;
870 
871 	status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
872 	if (!(status & hwdev->map.se_irq_map.irq_mask))
873 		return IRQ_NONE;
874 
875 	mask = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_MASKIRQ);
876 	status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
877 	status &= mask;
878 	/* ToDo: status decoding and firing up of VSYNC and page flip events */
879 
880 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
881 
882 	return IRQ_HANDLED;
883 }
884 
malidp_se_irq_thread_handler(int irq,void * arg)885 static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
886 {
887 	return IRQ_HANDLED;
888 }
889 
malidp_se_irq_init(struct drm_device * drm,int irq)890 int malidp_se_irq_init(struct drm_device *drm, int irq)
891 {
892 	struct malidp_drm *malidp = drm->dev_private;
893 	struct malidp_hw_device *hwdev = malidp->dev;
894 	int ret;
895 
896 	/* ensure interrupts are disabled */
897 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
898 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
899 
900 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
901 					malidp_se_irq_thread_handler,
902 					IRQF_SHARED, "malidp-se", drm);
903 	if (ret < 0) {
904 		DRM_ERROR("failed to install SE IRQ handler\n");
905 		return ret;
906 	}
907 
908 	malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
909 			     hwdev->map.se_irq_map.irq_mask);
910 
911 	return 0;
912 }
913 
malidp_se_irq_fini(struct drm_device * drm)914 void malidp_se_irq_fini(struct drm_device *drm)
915 {
916 	struct malidp_drm *malidp = drm->dev_private;
917 	struct malidp_hw_device *hwdev = malidp->dev;
918 
919 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
920 			      hwdev->map.se_irq_map.irq_mask);
921 }
922