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