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