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