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