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