xref: /openbmc/linux/drivers/gpu/drm/arm/malidp_hw.c (revision fed8b7e366e7c8f81e957ef91aa8f0a38e038c66)
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 #include "malidp_mw.h"
25 
26 enum {
27 	MW_NOT_ENABLED = 0,	/* SE writeback not enabled */
28 	MW_ONESHOT,		/* SE in one-shot mode for writeback */
29 	MW_START,		/* SE started writeback */
30 	MW_RESTART,		/* SE will start another writeback after this one */
31 	MW_STOP,		/* SE needs to stop after this writeback */
32 };
33 
34 static const struct malidp_format_id malidp500_de_formats[] = {
35 	/*    fourcc,   layers supporting the format,     internal id  */
36 	{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  0 },
37 	{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  1 },
38 	{ DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  2 },
39 	{ DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  3 },
40 	{ DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  4 },
41 	{ DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2 | SE_MEMWRITE,  5 },
42 	{ DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  6 },
43 	{ DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  7 },
44 	{ DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  8 },
45 	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  9 },
46 	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
47 	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
48 	{ DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
49 	{ DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
50 	{ DRM_FORMAT_NV12, DE_VIDEO1 | SE_MEMWRITE, 14 },
51 	{ DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
52 };
53 
54 #define MALIDP_ID(__group, __format) \
55 	((((__group) & 0x7) << 3) | ((__format) & 0x7))
56 
57 #define MALIDP_COMMON_FORMATS \
58 	/*    fourcc,   layers supporting the format,      internal id   */ \
59 	{ DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 0) }, \
60 	{ DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 1) }, \
61 	{ DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 2) }, \
62 	{ DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(0, 3) }, \
63 	{ DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
64 	{ DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
65 	{ DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
66 	{ DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
67 	{ DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 0) }, \
68 	{ DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 1) }, \
69 	{ DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 2) }, \
70 	{ DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART | SE_MEMWRITE, MALIDP_ID(2, 3) }, \
71 	{ DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 0) }, \
72 	{ DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(3, 1) }, \
73 	{ DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
74 	{ DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
75 	{ DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
76 	{ DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
77 	{ DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },	\
78 	{ DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },	\
79 	{ DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) },	\
80 	{ DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
81 
82 static const struct malidp_format_id malidp550_de_formats[] = {
83 	MALIDP_COMMON_FORMATS,
84 };
85 
86 static const struct malidp_layer malidp500_layers[] = {
87 	/* id, base address, fb pointer address base, stride offset,
88 	 *	yuv2rgb matrix offset, mmu control register offset, rotation_features
89 	 */
90 	{ DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE,
91 		MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY },
92 	{ DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE,
93 		MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
94 	{ DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE,
95 		MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
96 };
97 
98 static const struct malidp_layer malidp550_layers[] = {
99 	/* id, base address, fb pointer address base, stride offset,
100 	 *	yuv2rgb matrix offset, mmu control register offset, rotation_features
101 	 */
102 	{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
103 		MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
104 	{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
105 		MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
106 	{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
107 		MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
108 	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
109 		MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE },
110 };
111 
112 static const struct malidp_layer malidp650_layers[] = {
113 	/* id, base address, fb pointer address base, stride offset,
114 	 *	yuv2rgb matrix offset, mmu control register offset,
115 	 *	rotation_features
116 	 */
117 	{ DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
118 		MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
119 		MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
120 	{ DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
121 		MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL,
122 		ROTATE_COMPRESSED },
123 	{ DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
124 		MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
125 		MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
126 	{ DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
127 		MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL,
128 		ROTATE_NONE },
129 };
130 
131 #define SE_N_SCALING_COEFFS	96
132 static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
133 	[MALIDP_UPSCALING_COEFFS - 1] = {
134 		0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
135 		0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
136 		0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
137 		0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
138 		0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
139 		0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
140 		0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
141 		0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
142 		0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
143 		0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
144 		0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
145 		0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
146 	},
147 	[MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
148 		0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
149 		0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
150 		0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
151 		0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
152 		0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
153 		0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
154 		0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
155 		0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
156 		0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
157 		0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
158 		0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
159 		0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
160 	},
161 	[MALIDP_DOWNSCALING_2_COEFFS - 1] = {
162 		0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
163 		0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
164 		0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
165 		0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
166 		0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
167 		0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
168 		0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
169 		0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
170 		0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
171 		0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
172 		0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
173 		0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
174 	},
175 	[MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
176 		0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
177 		0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
178 		0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
179 		0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
180 		0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
181 		0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
182 		0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
183 		0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
184 		0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
185 		0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
186 		0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
187 		0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
188 	},
189 	[MALIDP_DOWNSCALING_4_COEFFS - 1] = {
190 		0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
191 		0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
192 		0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
193 		0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
194 		0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
195 		0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
196 		0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
197 		0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
198 		0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
199 		0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
200 		0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
201 		0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
202 	},
203 };
204 
205 #define MALIDP_DE_DEFAULT_PREFETCH_START	5
206 
207 static int malidp500_query_hw(struct malidp_hw_device *hwdev)
208 {
209 	u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
210 	/* bit 4 of the CONFIG_ID register holds the line size multiplier */
211 	u8 ln_size_mult = conf & 0x10 ? 2 : 1;
212 
213 	hwdev->min_line_size = 2;
214 	hwdev->max_line_size = SZ_2K * ln_size_mult;
215 	hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
216 	hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
217 
218 	return 0;
219 }
220 
221 static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
222 {
223 	u32 status, count = 100;
224 
225 	malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
226 	while (count) {
227 		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
228 		if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
229 			break;
230 		/*
231 		 * entering config mode can take as long as the rendering
232 		 * of a full frame, hence the long sleep here
233 		 */
234 		usleep_range(1000, 10000);
235 		count--;
236 	}
237 	WARN(count == 0, "timeout while entering config mode");
238 }
239 
240 static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
241 {
242 	u32 status, count = 100;
243 
244 	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
245 	malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
246 	while (count) {
247 		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
248 		if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
249 			break;
250 		usleep_range(100, 1000);
251 		count--;
252 	}
253 	WARN(count == 0, "timeout while leaving config mode");
254 }
255 
256 static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
257 {
258 	u32 status;
259 
260 	status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
261 	if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
262 		return true;
263 
264 	return false;
265 }
266 
267 static void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
268 {
269 	if (value)
270 		malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
271 	else
272 		malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
273 }
274 
275 static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
276 {
277 	u32 val = 0;
278 
279 	malidp_hw_write(hwdev, hwdev->output_color_depth,
280 		hwdev->hw->map.out_depth_base);
281 	malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
282 	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
283 		val |= MALIDP500_HSYNCPOL;
284 	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
285 		val |= MALIDP500_VSYNCPOL;
286 	val |= MALIDP_DE_DEFAULT_PREFETCH_START;
287 	malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
288 
289 	/*
290 	 * Mali-DP500 encodes the background color like this:
291 	 *    - red   @ MALIDP500_BGND_COLOR[12:0]
292 	 *    - green @ MALIDP500_BGND_COLOR[27:16]
293 	 *    - blue  @ (MALIDP500_BGND_COLOR + 4)[12:0]
294 	 */
295 	val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
296 	      (MALIDP_BGND_COLOR_R & 0xfff);
297 	malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
298 	malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
299 
300 	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
301 		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
302 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
303 
304 	val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
305 		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
306 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
307 
308 	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
309 		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
310 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
311 
312 	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
313 	malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
314 
315 	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
316 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
317 	else
318 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
319 }
320 
321 static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
322 {
323 	/*
324 	 * Each layer needs enough rotation memory to fit 8 lines
325 	 * worth of pixel data. Required size is then:
326 	 *    size = rotated_width * (bpp / 8) * 8;
327 	 */
328 	return w * drm_format_plane_cpp(fmt, 0) * 8;
329 }
330 
331 static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
332 					   u32 direction,
333 					   u16 addr,
334 					   u8 coeffs_id)
335 {
336 	int i;
337 	u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
338 
339 	malidp_hw_write(hwdev,
340 			direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
341 			scaling_control + MALIDP_SE_COEFFTAB_ADDR);
342 	for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
343 		malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
344 				dp500_se_scaling_coeffs[coeffs_id][i]),
345 				scaling_control + MALIDP_SE_COEFFTAB_DATA);
346 }
347 
348 static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
349 					   struct malidp_se_config *se_config,
350 					   struct malidp_se_config *old_config)
351 {
352 	/* Get array indices into dp500_se_scaling_coeffs. */
353 	u8 h = (u8)se_config->hcoeff - 1;
354 	u8 v = (u8)se_config->vcoeff - 1;
355 
356 	if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
357 		    v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
358 		return -EINVAL;
359 
360 	if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
361 			 se_config->vcoeff != old_config->vcoeff)) {
362 		malidp500_se_write_pp_coefftab(hwdev,
363 					       (MALIDP_SE_V_COEFFTAB |
364 						MALIDP_SE_H_COEFFTAB),
365 					       0, v);
366 	} else {
367 		if (se_config->vcoeff != old_config->vcoeff)
368 			malidp500_se_write_pp_coefftab(hwdev,
369 						       MALIDP_SE_V_COEFFTAB,
370 						       0, v);
371 		if (se_config->hcoeff != old_config->hcoeff)
372 			malidp500_se_write_pp_coefftab(hwdev,
373 						       MALIDP_SE_H_COEFFTAB,
374 						       0, h);
375 	}
376 
377 	return 0;
378 }
379 
380 static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
381 				   struct malidp_se_config *se_config,
382 				   struct videomode *vm)
383 {
384 	unsigned long mclk;
385 	unsigned long pxlclk = vm->pixelclock; /* Hz */
386 	unsigned long htotal = vm->hactive + vm->hfront_porch +
387 			       vm->hback_porch + vm->hsync_len;
388 	unsigned long input_size = se_config->input_w * se_config->input_h;
389 	unsigned long a = 10;
390 	long ret;
391 
392 	/*
393 	 * mclk = max(a, 1.5) * pxlclk
394 	 *
395 	 * To avoid float calculaiton, using 15 instead of 1.5 and div by
396 	 * 10 to get mclk.
397 	 */
398 	if (se_config->scale_enable) {
399 		a = 15 * input_size / (htotal * se_config->output_h);
400 		if (a < 15)
401 			a = 15;
402 	}
403 	mclk = a * pxlclk / 10;
404 	ret = clk_get_rate(hwdev->mclk);
405 	if (ret < mclk) {
406 		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
407 				 mclk / 1000);
408 		return -EINVAL;
409 	}
410 	return ret;
411 }
412 
413 static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
414 				     dma_addr_t *addrs, s32 *pitches,
415 				     int num_planes, u16 w, u16 h, u32 fmt_id,
416 				     const s16 *rgb2yuv_coeffs)
417 {
418 	u32 base = MALIDP500_SE_MEMWRITE_BASE;
419 	u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
420 
421 	/* enable the scaling engine block */
422 	malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
423 
424 	/* restart the writeback if already enabled */
425 	if (hwdev->mw_state != MW_NOT_ENABLED)
426 		hwdev->mw_state = MW_RESTART;
427 	else
428 		hwdev->mw_state = MW_START;
429 
430 	malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
431 	switch (num_planes) {
432 	case 2:
433 		malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
434 		malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
435 		malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
436 		/* fall through */
437 	case 1:
438 		malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
439 		malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
440 		malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
441 		break;
442 	default:
443 		WARN(1, "Invalid number of planes");
444 	}
445 
446 	malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
447 			MALIDP500_SE_MEMWRITE_OUT_SIZE);
448 
449 	if (rgb2yuv_coeffs) {
450 		int i;
451 
452 		for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
453 			malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
454 					MALIDP500_SE_RGB_YUV_COEFFS + i * 4);
455 		}
456 	}
457 
458 	malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
459 
460 	return 0;
461 }
462 
463 static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
464 {
465 	u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
466 
467 	if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART)
468 		hwdev->mw_state = MW_STOP;
469 	malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
470 	malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
471 }
472 
473 static int malidp550_query_hw(struct malidp_hw_device *hwdev)
474 {
475 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
476 	u8 ln_size = (conf >> 4) & 0x3, rsize;
477 
478 	hwdev->min_line_size = 2;
479 
480 	switch (ln_size) {
481 	case 0:
482 		hwdev->max_line_size = SZ_2K;
483 		/* two banks of 64KB for rotation memory */
484 		rsize = 64;
485 		break;
486 	case 1:
487 		hwdev->max_line_size = SZ_4K;
488 		/* two banks of 128KB for rotation memory */
489 		rsize = 128;
490 		break;
491 	case 2:
492 		hwdev->max_line_size = 1280;
493 		/* two banks of 40KB for rotation memory */
494 		rsize = 40;
495 		break;
496 	case 3:
497 		/* reserved value */
498 		hwdev->max_line_size = 0;
499 		return -EINVAL;
500 	}
501 
502 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
503 	return 0;
504 }
505 
506 static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
507 {
508 	u32 status, count = 100;
509 
510 	malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
511 	while (count) {
512 		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
513 		if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
514 			break;
515 		/*
516 		 * entering config mode can take as long as the rendering
517 		 * of a full frame, hence the long sleep here
518 		 */
519 		usleep_range(1000, 10000);
520 		count--;
521 	}
522 	WARN(count == 0, "timeout while entering config mode");
523 }
524 
525 static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
526 {
527 	u32 status, count = 100;
528 
529 	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
530 	malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
531 	while (count) {
532 		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
533 		if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
534 			break;
535 		usleep_range(100, 1000);
536 		count--;
537 	}
538 	WARN(count == 0, "timeout while leaving config mode");
539 }
540 
541 static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
542 {
543 	u32 status;
544 
545 	status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
546 	if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
547 		return true;
548 
549 	return false;
550 }
551 
552 static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
553 {
554 	if (value)
555 		malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
556 	else
557 		malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
558 }
559 
560 static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
561 {
562 	u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
563 
564 	malidp_hw_write(hwdev, hwdev->output_color_depth,
565 		hwdev->hw->map.out_depth_base);
566 	malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
567 	/*
568 	 * Mali-DP550 and Mali-DP650 encode the background color like this:
569 	 *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
570 	 *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
571 	 *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
572 	 *
573 	 * We need to truncate the least significant 4 bits from the default
574 	 * MALIDP_BGND_COLOR_x values
575 	 */
576 	val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
577 	      (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
578 	      ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
579 	malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
580 
581 	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
582 		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
583 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
584 
585 	val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
586 		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
587 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
588 
589 	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
590 		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
591 	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
592 		val |= MALIDP550_HSYNCPOL;
593 	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
594 		val |= MALIDP550_VSYNCPOL;
595 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
596 
597 	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
598 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
599 
600 	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
601 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
602 	else
603 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
604 }
605 
606 static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
607 {
608 	u32 bytes_per_col;
609 
610 	switch (fmt) {
611 	/* 8 lines at 4 bytes per pixel */
612 	case DRM_FORMAT_ARGB2101010:
613 	case DRM_FORMAT_ABGR2101010:
614 	case DRM_FORMAT_RGBA1010102:
615 	case DRM_FORMAT_BGRA1010102:
616 	case DRM_FORMAT_ARGB8888:
617 	case DRM_FORMAT_ABGR8888:
618 	case DRM_FORMAT_RGBA8888:
619 	case DRM_FORMAT_BGRA8888:
620 	case DRM_FORMAT_XRGB8888:
621 	case DRM_FORMAT_XBGR8888:
622 	case DRM_FORMAT_RGBX8888:
623 	case DRM_FORMAT_BGRX8888:
624 	case DRM_FORMAT_RGB888:
625 	case DRM_FORMAT_BGR888:
626 	/* 16 lines at 2 bytes per pixel */
627 	case DRM_FORMAT_RGBA5551:
628 	case DRM_FORMAT_ABGR1555:
629 	case DRM_FORMAT_RGB565:
630 	case DRM_FORMAT_BGR565:
631 	case DRM_FORMAT_UYVY:
632 	case DRM_FORMAT_YUYV:
633 		bytes_per_col = 32;
634 		break;
635 	/* 16 lines at 1.5 bytes per pixel */
636 	case DRM_FORMAT_NV12:
637 	case DRM_FORMAT_YUV420:
638 		bytes_per_col = 24;
639 		break;
640 	default:
641 		return -EINVAL;
642 	}
643 
644 	return w * bytes_per_col;
645 }
646 
647 static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
648 					   struct malidp_se_config *se_config,
649 					   struct malidp_se_config *old_config)
650 {
651 	u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
652 		   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
653 	u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
654 			MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
655 
656 	malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
657 	malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
658 	return 0;
659 }
660 
661 static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
662 				   struct malidp_se_config *se_config,
663 				   struct videomode *vm)
664 {
665 	unsigned long mclk;
666 	unsigned long pxlclk = vm->pixelclock;
667 	unsigned long htotal = vm->hactive + vm->hfront_porch +
668 			       vm->hback_porch + vm->hsync_len;
669 	unsigned long numerator = 1, denominator = 1;
670 	long ret;
671 
672 	if (se_config->scale_enable) {
673 		numerator = max(se_config->input_w, se_config->output_w) *
674 			    se_config->input_h;
675 		numerator += se_config->output_w *
676 			     (se_config->output_h -
677 			      min(se_config->input_h, se_config->output_h));
678 		denominator = (htotal - 2) * se_config->output_h;
679 	}
680 
681 	/* mclk can't be slower than pxlclk. */
682 	if (numerator < denominator)
683 		numerator = denominator = 1;
684 	mclk = (pxlclk * numerator) / denominator;
685 	ret = clk_get_rate(hwdev->mclk);
686 	if (ret < mclk) {
687 		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
688 				 mclk / 1000);
689 		return -EINVAL;
690 	}
691 	return ret;
692 }
693 
694 static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
695 				     dma_addr_t *addrs, s32 *pitches,
696 				     int num_planes, u16 w, u16 h, u32 fmt_id,
697 				     const s16 *rgb2yuv_coeffs)
698 {
699 	u32 base = MALIDP550_SE_MEMWRITE_BASE;
700 	u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
701 
702 	/* enable the scaling engine block */
703 	malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
704 
705 	hwdev->mw_state = MW_ONESHOT;
706 
707 	malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
708 	switch (num_planes) {
709 	case 2:
710 		malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
711 		malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
712 		malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
713 		/* fall through */
714 	case 1:
715 		malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
716 		malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
717 		malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
718 		break;
719 	default:
720 		WARN(1, "Invalid number of planes");
721 	}
722 
723 	malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
724 			MALIDP550_SE_MEMWRITE_OUT_SIZE);
725 	malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
726 			  MALIDP550_SE_CONTROL);
727 
728 	if (rgb2yuv_coeffs) {
729 		int i;
730 
731 		for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
732 			malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
733 					MALIDP550_SE_RGB_YUV_COEFFS + i * 4);
734 		}
735 	}
736 
737 	return 0;
738 }
739 
740 static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
741 {
742 	u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
743 
744 	malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
745 			    MALIDP550_SE_CONTROL);
746 	malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
747 }
748 
749 static int malidp650_query_hw(struct malidp_hw_device *hwdev)
750 {
751 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
752 	u8 ln_size = (conf >> 4) & 0x3, rsize;
753 
754 	hwdev->min_line_size = 4;
755 
756 	switch (ln_size) {
757 	case 0:
758 	case 2:
759 		/* reserved values */
760 		hwdev->max_line_size = 0;
761 		return -EINVAL;
762 	case 1:
763 		hwdev->max_line_size = SZ_4K;
764 		/* two banks of 128KB for rotation memory */
765 		rsize = 128;
766 		break;
767 	case 3:
768 		hwdev->max_line_size = 2560;
769 		/* two banks of 80KB for rotation memory */
770 		rsize = 80;
771 	}
772 
773 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
774 	return 0;
775 }
776 
777 const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
778 	[MALIDP_500] = {
779 		.map = {
780 			.coeffs_base = MALIDP500_COEFFS_BASE,
781 			.se_base = MALIDP500_SE_BASE,
782 			.dc_base = MALIDP500_DC_BASE,
783 			.out_depth_base = MALIDP500_OUTPUT_DEPTH,
784 			.features = 0,	/* no CLEARIRQ register */
785 			.n_layers = ARRAY_SIZE(malidp500_layers),
786 			.layers = malidp500_layers,
787 			.de_irq_map = {
788 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
789 					    MALIDP500_DE_IRQ_AXI_ERR |
790 					    MALIDP500_DE_IRQ_VSYNC |
791 					    MALIDP500_DE_IRQ_GLOBAL,
792 				.vsync_irq = MALIDP500_DE_IRQ_VSYNC,
793 				.err_mask = MALIDP_DE_IRQ_UNDERRUN |
794 					    MALIDP500_DE_IRQ_AXI_ERR |
795 					    MALIDP500_DE_IRQ_SATURATION,
796 			},
797 			.se_irq_map = {
798 				.irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
799 					    MALIDP500_SE_IRQ_CONF_VALID |
800 					    MALIDP500_SE_IRQ_GLOBAL,
801 				.vsync_irq = MALIDP500_SE_IRQ_CONF_VALID,
802 				.err_mask = MALIDP500_SE_IRQ_INIT_BUSY |
803 					    MALIDP500_SE_IRQ_AXI_ERROR |
804 					    MALIDP500_SE_IRQ_OVERRUN,
805 			},
806 			.dc_irq_map = {
807 				.irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
808 				.vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
809 			},
810 			.pixel_formats = malidp500_de_formats,
811 			.n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
812 			.bus_align_bytes = 8,
813 		},
814 		.query_hw = malidp500_query_hw,
815 		.enter_config_mode = malidp500_enter_config_mode,
816 		.leave_config_mode = malidp500_leave_config_mode,
817 		.in_config_mode = malidp500_in_config_mode,
818 		.set_config_valid = malidp500_set_config_valid,
819 		.modeset = malidp500_modeset,
820 		.rotmem_required = malidp500_rotmem_required,
821 		.se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
822 		.se_calc_mclk = malidp500_se_calc_mclk,
823 		.enable_memwrite = malidp500_enable_memwrite,
824 		.disable_memwrite = malidp500_disable_memwrite,
825 		.features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
826 	},
827 	[MALIDP_550] = {
828 		.map = {
829 			.coeffs_base = MALIDP550_COEFFS_BASE,
830 			.se_base = MALIDP550_SE_BASE,
831 			.dc_base = MALIDP550_DC_BASE,
832 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
833 			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
834 			.n_layers = ARRAY_SIZE(malidp550_layers),
835 			.layers = malidp550_layers,
836 			.de_irq_map = {
837 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
838 					    MALIDP550_DE_IRQ_VSYNC,
839 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
840 				.err_mask = MALIDP_DE_IRQ_UNDERRUN |
841 					    MALIDP550_DE_IRQ_SATURATION |
842 					    MALIDP550_DE_IRQ_AXI_ERR,
843 			},
844 			.se_irq_map = {
845 				.irq_mask = MALIDP550_SE_IRQ_EOW,
846 				.vsync_irq = MALIDP550_SE_IRQ_EOW,
847 				.err_mask  = MALIDP550_SE_IRQ_AXI_ERR |
848 					     MALIDP550_SE_IRQ_OVR |
849 					     MALIDP550_SE_IRQ_IBSY,
850 			},
851 			.dc_irq_map = {
852 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
853 					    MALIDP550_DC_IRQ_SE,
854 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
855 			},
856 			.pixel_formats = malidp550_de_formats,
857 			.n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
858 			.bus_align_bytes = 8,
859 		},
860 		.query_hw = malidp550_query_hw,
861 		.enter_config_mode = malidp550_enter_config_mode,
862 		.leave_config_mode = malidp550_leave_config_mode,
863 		.in_config_mode = malidp550_in_config_mode,
864 		.set_config_valid = malidp550_set_config_valid,
865 		.modeset = malidp550_modeset,
866 		.rotmem_required = malidp550_rotmem_required,
867 		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
868 		.se_calc_mclk = malidp550_se_calc_mclk,
869 		.enable_memwrite = malidp550_enable_memwrite,
870 		.disable_memwrite = malidp550_disable_memwrite,
871 		.features = 0,
872 	},
873 	[MALIDP_650] = {
874 		.map = {
875 			.coeffs_base = MALIDP550_COEFFS_BASE,
876 			.se_base = MALIDP550_SE_BASE,
877 			.dc_base = MALIDP550_DC_BASE,
878 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
879 			.features = MALIDP_REGMAP_HAS_CLEARIRQ,
880 			.n_layers = ARRAY_SIZE(malidp650_layers),
881 			.layers = malidp650_layers,
882 			.de_irq_map = {
883 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
884 					    MALIDP650_DE_IRQ_DRIFT |
885 					    MALIDP550_DE_IRQ_VSYNC,
886 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
887 				.err_mask = MALIDP_DE_IRQ_UNDERRUN |
888 					    MALIDP650_DE_IRQ_DRIFT |
889 					    MALIDP550_DE_IRQ_SATURATION |
890 					    MALIDP550_DE_IRQ_AXI_ERR |
891 					    MALIDP650_DE_IRQ_ACEV1 |
892 					    MALIDP650_DE_IRQ_ACEV2 |
893 					    MALIDP650_DE_IRQ_ACEG |
894 					    MALIDP650_DE_IRQ_AXIEP,
895 			},
896 			.se_irq_map = {
897 				.irq_mask = MALIDP550_SE_IRQ_EOW,
898 				.vsync_irq = MALIDP550_SE_IRQ_EOW,
899 				.err_mask = MALIDP550_SE_IRQ_AXI_ERR |
900 					    MALIDP550_SE_IRQ_OVR |
901 					    MALIDP550_SE_IRQ_IBSY,
902 			},
903 			.dc_irq_map = {
904 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
905 					    MALIDP550_DC_IRQ_SE,
906 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
907 			},
908 			.pixel_formats = malidp550_de_formats,
909 			.n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
910 			.bus_align_bytes = 16,
911 		},
912 		.query_hw = malidp650_query_hw,
913 		.enter_config_mode = malidp550_enter_config_mode,
914 		.leave_config_mode = malidp550_leave_config_mode,
915 		.in_config_mode = malidp550_in_config_mode,
916 		.set_config_valid = malidp550_set_config_valid,
917 		.modeset = malidp550_modeset,
918 		.rotmem_required = malidp550_rotmem_required,
919 		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
920 		.se_calc_mclk = malidp550_se_calc_mclk,
921 		.enable_memwrite = malidp550_enable_memwrite,
922 		.disable_memwrite = malidp550_disable_memwrite,
923 		.features = 0,
924 	},
925 };
926 
927 u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
928 			   u8 layer_id, u32 format)
929 {
930 	unsigned int i;
931 
932 	for (i = 0; i < map->n_pixel_formats; i++) {
933 		if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
934 		    (map->pixel_formats[i].format == format))
935 			return map->pixel_formats[i].id;
936 	}
937 
938 	return MALIDP_INVALID_FORMAT_ID;
939 }
940 
941 static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
942 {
943 	u32 base = malidp_get_block_base(hwdev, block);
944 
945 	if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
946 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
947 	else
948 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
949 }
950 
951 static irqreturn_t malidp_de_irq(int irq, void *arg)
952 {
953 	struct drm_device *drm = arg;
954 	struct malidp_drm *malidp = drm->dev_private;
955 	struct malidp_hw_device *hwdev;
956 	struct malidp_hw *hw;
957 	const struct malidp_irq_map *de;
958 	u32 status, mask, dc_status;
959 	irqreturn_t ret = IRQ_NONE;
960 
961 	hwdev = malidp->dev;
962 	hw = hwdev->hw;
963 	de = &hw->map.de_irq_map;
964 
965 	/*
966 	 * if we are suspended it is likely that we were invoked because
967 	 * we share an interrupt line with some other driver, don't try
968 	 * to read the hardware registers
969 	 */
970 	if (hwdev->pm_suspended)
971 		return IRQ_NONE;
972 
973 	/* first handle the config valid IRQ */
974 	dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
975 	if (dc_status & hw->map.dc_irq_map.vsync_irq) {
976 		malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
977 		/* do we have a page flip event? */
978 		if (malidp->event != NULL) {
979 			spin_lock(&drm->event_lock);
980 			drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
981 			malidp->event = NULL;
982 			spin_unlock(&drm->event_lock);
983 		}
984 		atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
985 		ret = IRQ_WAKE_THREAD;
986 	}
987 
988 	status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
989 	if (!(status & de->irq_mask))
990 		return ret;
991 
992 	mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
993 	/* keep the status of the enabled interrupts, plus the error bits */
994 	status &= (mask | de->err_mask);
995 	if ((status & de->vsync_irq) && malidp->crtc.enabled)
996 		drm_crtc_handle_vblank(&malidp->crtc);
997 
998 #ifdef CONFIG_DEBUG_FS
999 	if (status & de->err_mask) {
1000 		malidp_error(malidp, &malidp->de_errors, status,
1001 			     drm_crtc_vblank_count(&malidp->crtc));
1002 	}
1003 #endif
1004 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
1005 
1006 	return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
1007 }
1008 
1009 static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
1010 {
1011 	struct drm_device *drm = arg;
1012 	struct malidp_drm *malidp = drm->dev_private;
1013 
1014 	wake_up(&malidp->wq);
1015 
1016 	return IRQ_HANDLED;
1017 }
1018 
1019 void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev)
1020 {
1021 	/* ensure interrupts are disabled */
1022 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1023 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1024 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1025 	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1026 
1027 	/* first enable the DC block IRQs */
1028 	malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
1029 			     hwdev->hw->map.dc_irq_map.irq_mask);
1030 
1031 	/* now enable the DE block IRQs */
1032 	malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
1033 			     hwdev->hw->map.de_irq_map.irq_mask);
1034 }
1035 
1036 int malidp_de_irq_init(struct drm_device *drm, int irq)
1037 {
1038 	struct malidp_drm *malidp = drm->dev_private;
1039 	struct malidp_hw_device *hwdev = malidp->dev;
1040 	int ret;
1041 
1042 	/* ensure interrupts are disabled */
1043 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1044 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1045 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1046 	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1047 
1048 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
1049 					malidp_de_irq_thread_handler,
1050 					IRQF_SHARED, "malidp-de", drm);
1051 	if (ret < 0) {
1052 		DRM_ERROR("failed to install DE IRQ handler\n");
1053 		return ret;
1054 	}
1055 
1056 	malidp_de_irq_hw_init(hwdev);
1057 
1058 	return 0;
1059 }
1060 
1061 void malidp_de_irq_fini(struct malidp_hw_device *hwdev)
1062 {
1063 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
1064 			      hwdev->hw->map.de_irq_map.irq_mask);
1065 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
1066 			      hwdev->hw->map.dc_irq_map.irq_mask);
1067 }
1068 
1069 static irqreturn_t malidp_se_irq(int irq, void *arg)
1070 {
1071 	struct drm_device *drm = arg;
1072 	struct malidp_drm *malidp = drm->dev_private;
1073 	struct malidp_hw_device *hwdev = malidp->dev;
1074 	struct malidp_hw *hw = hwdev->hw;
1075 	const struct malidp_irq_map *se = &hw->map.se_irq_map;
1076 	u32 status, mask;
1077 
1078 	/*
1079 	 * if we are suspended it is likely that we were invoked because
1080 	 * we share an interrupt line with some other driver, don't try
1081 	 * to read the hardware registers
1082 	 */
1083 	if (hwdev->pm_suspended)
1084 		return IRQ_NONE;
1085 
1086 	status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
1087 	if (!(status & (se->irq_mask | se->err_mask)))
1088 		return IRQ_NONE;
1089 
1090 #ifdef CONFIG_DEBUG_FS
1091 	if (status & se->err_mask)
1092 		malidp_error(malidp, &malidp->se_errors, status,
1093 			     drm_crtc_vblank_count(&malidp->crtc));
1094 #endif
1095 	mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
1096 	status &= mask;
1097 
1098 	if (status & se->vsync_irq) {
1099 		switch (hwdev->mw_state) {
1100 		case MW_ONESHOT:
1101 			drm_writeback_signal_completion(&malidp->mw_connector, 0);
1102 			break;
1103 		case MW_STOP:
1104 			drm_writeback_signal_completion(&malidp->mw_connector, 0);
1105 			/* disable writeback after stop */
1106 			hwdev->mw_state = MW_NOT_ENABLED;
1107 			break;
1108 		case MW_RESTART:
1109 			drm_writeback_signal_completion(&malidp->mw_connector, 0);
1110 			/* fall through to a new start */
1111 		case MW_START:
1112 			/* writeback started, need to emulate one-shot mode */
1113 			hw->disable_memwrite(hwdev);
1114 			/*
1115 			 * only set config_valid HW bit if there is no other update
1116 			 * in progress or if we raced ahead of the DE IRQ handler
1117 			 * and config_valid flag will not be update until later
1118 			 */
1119 			status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
1120 			if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) ||
1121 			    (status & hw->map.dc_irq_map.vsync_irq))
1122 				hw->set_config_valid(hwdev, 1);
1123 			break;
1124 		}
1125 	}
1126 
1127 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
1128 
1129 	return IRQ_HANDLED;
1130 }
1131 
1132 void malidp_se_irq_hw_init(struct malidp_hw_device *hwdev)
1133 {
1134 	/* ensure interrupts are disabled */
1135 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1136 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1137 
1138 	malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
1139 			     hwdev->hw->map.se_irq_map.irq_mask);
1140 }
1141 
1142 static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1143 {
1144 	return IRQ_HANDLED;
1145 }
1146 
1147 int malidp_se_irq_init(struct drm_device *drm, int irq)
1148 {
1149 	struct malidp_drm *malidp = drm->dev_private;
1150 	struct malidp_hw_device *hwdev = malidp->dev;
1151 	int ret;
1152 
1153 	/* ensure interrupts are disabled */
1154 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1155 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1156 
1157 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
1158 					malidp_se_irq_thread_handler,
1159 					IRQF_SHARED, "malidp-se", drm);
1160 	if (ret < 0) {
1161 		DRM_ERROR("failed to install SE IRQ handler\n");
1162 		return ret;
1163 	}
1164 
1165 	hwdev->mw_state = MW_NOT_ENABLED;
1166 	malidp_se_irq_hw_init(hwdev);
1167 
1168 	return 0;
1169 }
1170 
1171 void malidp_se_irq_fini(struct malidp_hw_device *hwdev)
1172 {
1173 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
1174 			      hwdev->hw->map.se_irq_map.irq_mask);
1175 }
1176