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