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