xref: /openbmc/linux/drivers/gpu/drm/arm/malidp_hw.c (revision aa1d19f1)
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 	int bpp = drm_format_plane_cpp(fmt, 0) * 8;
382 
383 	if (bpp == 0) {
384 		switch (fmt) {
385 		case DRM_FORMAT_VUY101010:
386 			bpp = 30;
387 		case DRM_FORMAT_YUV420_10BIT:
388 			bpp = 15;
389 			break;
390 		case DRM_FORMAT_YUV420_8BIT:
391 			bpp = 12;
392 			break;
393 		default:
394 			bpp = 0;
395 		}
396 	}
397 
398 	return bpp;
399 }
400 
401 static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
402 				     u16 h, u32 fmt, bool has_modifier)
403 {
404 	/*
405 	 * Each layer needs enough rotation memory to fit 8 lines
406 	 * worth of pixel data. Required size is then:
407 	 *    size = rotated_width * (bpp / 8) * 8;
408 	 */
409 	int bpp = malidp_format_get_bpp(fmt);
410 
411 	return w * bpp;
412 }
413 
414 static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
415 					   u32 direction,
416 					   u16 addr,
417 					   u8 coeffs_id)
418 {
419 	int i;
420 	u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
421 
422 	malidp_hw_write(hwdev,
423 			direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
424 			scaling_control + MALIDP_SE_COEFFTAB_ADDR);
425 	for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
426 		malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
427 				dp500_se_scaling_coeffs[coeffs_id][i]),
428 				scaling_control + MALIDP_SE_COEFFTAB_DATA);
429 }
430 
431 static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
432 					   struct malidp_se_config *se_config,
433 					   struct malidp_se_config *old_config)
434 {
435 	/* Get array indices into dp500_se_scaling_coeffs. */
436 	u8 h = (u8)se_config->hcoeff - 1;
437 	u8 v = (u8)se_config->vcoeff - 1;
438 
439 	if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
440 		    v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
441 		return -EINVAL;
442 
443 	if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
444 			 se_config->vcoeff != old_config->vcoeff)) {
445 		malidp500_se_write_pp_coefftab(hwdev,
446 					       (MALIDP_SE_V_COEFFTAB |
447 						MALIDP_SE_H_COEFFTAB),
448 					       0, v);
449 	} else {
450 		if (se_config->vcoeff != old_config->vcoeff)
451 			malidp500_se_write_pp_coefftab(hwdev,
452 						       MALIDP_SE_V_COEFFTAB,
453 						       0, v);
454 		if (se_config->hcoeff != old_config->hcoeff)
455 			malidp500_se_write_pp_coefftab(hwdev,
456 						       MALIDP_SE_H_COEFFTAB,
457 						       0, h);
458 	}
459 
460 	return 0;
461 }
462 
463 static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
464 				   struct malidp_se_config *se_config,
465 				   struct videomode *vm)
466 {
467 	unsigned long mclk;
468 	unsigned long pxlclk = vm->pixelclock; /* Hz */
469 	unsigned long htotal = vm->hactive + vm->hfront_porch +
470 			       vm->hback_porch + vm->hsync_len;
471 	unsigned long input_size = se_config->input_w * se_config->input_h;
472 	unsigned long a = 10;
473 	long ret;
474 
475 	/*
476 	 * mclk = max(a, 1.5) * pxlclk
477 	 *
478 	 * To avoid float calculaiton, using 15 instead of 1.5 and div by
479 	 * 10 to get mclk.
480 	 */
481 	if (se_config->scale_enable) {
482 		a = 15 * input_size / (htotal * se_config->output_h);
483 		if (a < 15)
484 			a = 15;
485 	}
486 	mclk = a * pxlclk / 10;
487 	ret = clk_get_rate(hwdev->mclk);
488 	if (ret < mclk) {
489 		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
490 				 mclk / 1000);
491 		return -EINVAL;
492 	}
493 	return ret;
494 }
495 
496 static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
497 				     dma_addr_t *addrs, s32 *pitches,
498 				     int num_planes, u16 w, u16 h, u32 fmt_id,
499 				     const s16 *rgb2yuv_coeffs)
500 {
501 	u32 base = MALIDP500_SE_MEMWRITE_BASE;
502 	u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
503 
504 	/* enable the scaling engine block */
505 	malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
506 
507 	/* restart the writeback if already enabled */
508 	if (hwdev->mw_state != MW_NOT_ENABLED)
509 		hwdev->mw_state = MW_RESTART;
510 	else
511 		hwdev->mw_state = MW_START;
512 
513 	malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
514 	switch (num_planes) {
515 	case 2:
516 		malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
517 		malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
518 		malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
519 		/* fall through */
520 	case 1:
521 		malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
522 		malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
523 		malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
524 		break;
525 	default:
526 		WARN(1, "Invalid number of planes");
527 	}
528 
529 	malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
530 			MALIDP500_SE_MEMWRITE_OUT_SIZE);
531 
532 	if (rgb2yuv_coeffs) {
533 		int i;
534 
535 		for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
536 			malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
537 					MALIDP500_SE_RGB_YUV_COEFFS + i * 4);
538 		}
539 	}
540 
541 	malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
542 
543 	return 0;
544 }
545 
546 static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
547 {
548 	u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
549 
550 	if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART)
551 		hwdev->mw_state = MW_STOP;
552 	malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
553 	malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
554 }
555 
556 static int malidp550_query_hw(struct malidp_hw_device *hwdev)
557 {
558 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
559 	u8 ln_size = (conf >> 4) & 0x3, rsize;
560 
561 	hwdev->min_line_size = 2;
562 
563 	switch (ln_size) {
564 	case 0:
565 		hwdev->max_line_size = SZ_2K;
566 		/* two banks of 64KB for rotation memory */
567 		rsize = 64;
568 		break;
569 	case 1:
570 		hwdev->max_line_size = SZ_4K;
571 		/* two banks of 128KB for rotation memory */
572 		rsize = 128;
573 		break;
574 	case 2:
575 		hwdev->max_line_size = 1280;
576 		/* two banks of 40KB for rotation memory */
577 		rsize = 40;
578 		break;
579 	case 3:
580 		/* reserved value */
581 		hwdev->max_line_size = 0;
582 		return -EINVAL;
583 	}
584 
585 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
586 	return 0;
587 }
588 
589 static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
590 {
591 	u32 status, count = 100;
592 
593 	malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
594 	while (count) {
595 		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
596 		if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
597 			break;
598 		/*
599 		 * entering config mode can take as long as the rendering
600 		 * of a full frame, hence the long sleep here
601 		 */
602 		usleep_range(1000, 10000);
603 		count--;
604 	}
605 	WARN(count == 0, "timeout while entering config mode");
606 }
607 
608 static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
609 {
610 	u32 status, count = 100;
611 
612 	malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
613 	malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
614 	while (count) {
615 		status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
616 		if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
617 			break;
618 		usleep_range(100, 1000);
619 		count--;
620 	}
621 	WARN(count == 0, "timeout while leaving config mode");
622 }
623 
624 static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
625 {
626 	u32 status;
627 
628 	status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
629 	if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
630 		return true;
631 
632 	return false;
633 }
634 
635 static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
636 {
637 	if (value)
638 		malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
639 	else
640 		malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
641 }
642 
643 static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
644 {
645 	u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
646 
647 	malidp_hw_write(hwdev, hwdev->output_color_depth,
648 		hwdev->hw->map.out_depth_base);
649 	malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
650 	/*
651 	 * Mali-DP550 and Mali-DP650 encode the background color like this:
652 	 *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
653 	 *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
654 	 *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
655 	 *
656 	 * We need to truncate the least significant 4 bits from the default
657 	 * MALIDP_BGND_COLOR_x values
658 	 */
659 	val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
660 	      (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
661 	      ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
662 	malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
663 
664 	val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
665 		MALIDP_DE_H_BACKPORCH(mode->hback_porch);
666 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
667 
668 	val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
669 		MALIDP_DE_V_BACKPORCH(mode->vback_porch);
670 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
671 
672 	val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
673 		MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
674 	if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
675 		val |= MALIDP550_HSYNCPOL;
676 	if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
677 		val |= MALIDP550_VSYNCPOL;
678 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
679 
680 	val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
681 	malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
682 
683 	if (mode->flags & DISPLAY_FLAGS_INTERLACED)
684 		malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
685 	else
686 		malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
687 }
688 
689 static int malidpx50_get_bytes_per_column(u32 fmt)
690 {
691 	u32 bytes_per_column;
692 
693 	switch (fmt) {
694 	/* 8 lines at 4 bytes per pixel */
695 	case DRM_FORMAT_ARGB2101010:
696 	case DRM_FORMAT_ABGR2101010:
697 	case DRM_FORMAT_RGBA1010102:
698 	case DRM_FORMAT_BGRA1010102:
699 	case DRM_FORMAT_ARGB8888:
700 	case DRM_FORMAT_ABGR8888:
701 	case DRM_FORMAT_RGBA8888:
702 	case DRM_FORMAT_BGRA8888:
703 	case DRM_FORMAT_XRGB8888:
704 	case DRM_FORMAT_XBGR8888:
705 	case DRM_FORMAT_RGBX8888:
706 	case DRM_FORMAT_BGRX8888:
707 	case DRM_FORMAT_RGB888:
708 	case DRM_FORMAT_BGR888:
709 	/* 16 lines at 2 bytes per pixel */
710 	case DRM_FORMAT_RGBA5551:
711 	case DRM_FORMAT_ABGR1555:
712 	case DRM_FORMAT_RGB565:
713 	case DRM_FORMAT_BGR565:
714 	case DRM_FORMAT_UYVY:
715 	case DRM_FORMAT_YUYV:
716 	case DRM_FORMAT_X0L0:
717 		bytes_per_column = 32;
718 		break;
719 	/* 16 lines at 1.5 bytes per pixel */
720 	case DRM_FORMAT_NV12:
721 	case DRM_FORMAT_YUV420:
722 	/* 8 lines at 3 bytes per pixel */
723 	case DRM_FORMAT_VUY888:
724 	/* 16 lines at 12 bits per pixel */
725 	case DRM_FORMAT_YUV420_8BIT:
726 	/* 8 lines at 3 bytes per pixel */
727 	case DRM_FORMAT_P010:
728 		bytes_per_column = 24;
729 		break;
730 	/* 8 lines at 30 bits per pixel */
731 	case DRM_FORMAT_VUY101010:
732 	/* 16 lines at 15 bits per pixel */
733 	case DRM_FORMAT_YUV420_10BIT:
734 		bytes_per_column = 30;
735 		break;
736 	default:
737 		return -EINVAL;
738 	}
739 
740 	return bytes_per_column;
741 }
742 
743 static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
744 				     u16 h, u32 fmt, bool has_modifier)
745 {
746 	int bytes_per_column = 0;
747 
748 	switch (fmt) {
749 	/* 8 lines at 15 bits per pixel */
750 	case DRM_FORMAT_YUV420_10BIT:
751 		bytes_per_column = 15;
752 		break;
753 	/* Uncompressed YUV 420 10 bit single plane cannot be rotated */
754 	case DRM_FORMAT_X0L2:
755 		if (has_modifier)
756 			bytes_per_column = 8;
757 		else
758 			return -EINVAL;
759 		break;
760 	default:
761 		bytes_per_column = malidpx50_get_bytes_per_column(fmt);
762 	}
763 
764 	if (bytes_per_column == -EINVAL)
765 		return bytes_per_column;
766 
767 	return w * bytes_per_column;
768 }
769 
770 static int malidp650_rotmem_required(struct malidp_hw_device *hwdev, u16 w,
771 				     u16 h, u32 fmt, bool has_modifier)
772 {
773 	int bytes_per_column = 0;
774 
775 	switch (fmt) {
776 	/* 16 lines at 2 bytes per pixel */
777 	case DRM_FORMAT_X0L2:
778 		bytes_per_column = 32;
779 		break;
780 	default:
781 		bytes_per_column = malidpx50_get_bytes_per_column(fmt);
782 	}
783 
784 	if (bytes_per_column == -EINVAL)
785 		return bytes_per_column;
786 
787 	return w * bytes_per_column;
788 }
789 
790 static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
791 					   struct malidp_se_config *se_config,
792 					   struct malidp_se_config *old_config)
793 {
794 	u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
795 		   MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
796 	u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
797 			MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
798 
799 	malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
800 	malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
801 	return 0;
802 }
803 
804 static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
805 				   struct malidp_se_config *se_config,
806 				   struct videomode *vm)
807 {
808 	unsigned long mclk;
809 	unsigned long pxlclk = vm->pixelclock;
810 	unsigned long htotal = vm->hactive + vm->hfront_porch +
811 			       vm->hback_porch + vm->hsync_len;
812 	unsigned long numerator = 1, denominator = 1;
813 	long ret;
814 
815 	if (se_config->scale_enable) {
816 		numerator = max(se_config->input_w, se_config->output_w) *
817 			    se_config->input_h;
818 		numerator += se_config->output_w *
819 			     (se_config->output_h -
820 			      min(se_config->input_h, se_config->output_h));
821 		denominator = (htotal - 2) * se_config->output_h;
822 	}
823 
824 	/* mclk can't be slower than pxlclk. */
825 	if (numerator < denominator)
826 		numerator = denominator = 1;
827 	mclk = (pxlclk * numerator) / denominator;
828 	ret = clk_get_rate(hwdev->mclk);
829 	if (ret < mclk) {
830 		DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
831 				 mclk / 1000);
832 		return -EINVAL;
833 	}
834 	return ret;
835 }
836 
837 static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
838 				     dma_addr_t *addrs, s32 *pitches,
839 				     int num_planes, u16 w, u16 h, u32 fmt_id,
840 				     const s16 *rgb2yuv_coeffs)
841 {
842 	u32 base = MALIDP550_SE_MEMWRITE_BASE;
843 	u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
844 
845 	/* enable the scaling engine block */
846 	malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
847 
848 	hwdev->mw_state = MW_ONESHOT;
849 
850 	malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
851 	switch (num_planes) {
852 	case 2:
853 		malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
854 		malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
855 		malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
856 		/* fall through */
857 	case 1:
858 		malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
859 		malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
860 		malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
861 		break;
862 	default:
863 		WARN(1, "Invalid number of planes");
864 	}
865 
866 	malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
867 			MALIDP550_SE_MEMWRITE_OUT_SIZE);
868 	malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
869 			  MALIDP550_SE_CONTROL);
870 
871 	if (rgb2yuv_coeffs) {
872 		int i;
873 
874 		for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
875 			malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
876 					MALIDP550_SE_RGB_YUV_COEFFS + i * 4);
877 		}
878 	}
879 
880 	return 0;
881 }
882 
883 static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
884 {
885 	u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
886 
887 	malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
888 			    MALIDP550_SE_CONTROL);
889 	malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
890 }
891 
892 static int malidp650_query_hw(struct malidp_hw_device *hwdev)
893 {
894 	u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
895 	u8 ln_size = (conf >> 4) & 0x3, rsize;
896 
897 	hwdev->min_line_size = 4;
898 
899 	switch (ln_size) {
900 	case 0:
901 	case 2:
902 		/* reserved values */
903 		hwdev->max_line_size = 0;
904 		return -EINVAL;
905 	case 1:
906 		hwdev->max_line_size = SZ_4K;
907 		/* two banks of 128KB for rotation memory */
908 		rsize = 128;
909 		break;
910 	case 3:
911 		hwdev->max_line_size = 2560;
912 		/* two banks of 80KB for rotation memory */
913 		rsize = 80;
914 	}
915 
916 	hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
917 	return 0;
918 }
919 
920 const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
921 	[MALIDP_500] = {
922 		.map = {
923 			.coeffs_base = MALIDP500_COEFFS_BASE,
924 			.se_base = MALIDP500_SE_BASE,
925 			.dc_base = MALIDP500_DC_BASE,
926 			.out_depth_base = MALIDP500_OUTPUT_DEPTH,
927 			.features = 0,	/* no CLEARIRQ register */
928 			.n_layers = ARRAY_SIZE(malidp500_layers),
929 			.layers = malidp500_layers,
930 			.de_irq_map = {
931 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
932 					    MALIDP500_DE_IRQ_AXI_ERR |
933 					    MALIDP500_DE_IRQ_VSYNC |
934 					    MALIDP500_DE_IRQ_GLOBAL,
935 				.vsync_irq = MALIDP500_DE_IRQ_VSYNC,
936 				.err_mask = MALIDP_DE_IRQ_UNDERRUN |
937 					    MALIDP500_DE_IRQ_AXI_ERR |
938 					    MALIDP500_DE_IRQ_SATURATION,
939 			},
940 			.se_irq_map = {
941 				.irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
942 					    MALIDP500_SE_IRQ_CONF_VALID |
943 					    MALIDP500_SE_IRQ_GLOBAL,
944 				.vsync_irq = MALIDP500_SE_IRQ_CONF_VALID,
945 				.err_mask = MALIDP500_SE_IRQ_INIT_BUSY |
946 					    MALIDP500_SE_IRQ_AXI_ERROR |
947 					    MALIDP500_SE_IRQ_OVERRUN,
948 			},
949 			.dc_irq_map = {
950 				.irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
951 				.vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
952 			},
953 			.pixel_formats = malidp500_de_formats,
954 			.n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
955 			.bus_align_bytes = 8,
956 		},
957 		.query_hw = malidp500_query_hw,
958 		.enter_config_mode = malidp500_enter_config_mode,
959 		.leave_config_mode = malidp500_leave_config_mode,
960 		.in_config_mode = malidp500_in_config_mode,
961 		.set_config_valid = malidp500_set_config_valid,
962 		.modeset = malidp500_modeset,
963 		.rotmem_required = malidp500_rotmem_required,
964 		.se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
965 		.se_calc_mclk = malidp500_se_calc_mclk,
966 		.enable_memwrite = malidp500_enable_memwrite,
967 		.disable_memwrite = malidp500_disable_memwrite,
968 		.features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
969 	},
970 	[MALIDP_550] = {
971 		.map = {
972 			.coeffs_base = MALIDP550_COEFFS_BASE,
973 			.se_base = MALIDP550_SE_BASE,
974 			.dc_base = MALIDP550_DC_BASE,
975 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
976 			.features = MALIDP_REGMAP_HAS_CLEARIRQ |
977 				    MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
978 				    MALIDP_DEVICE_AFBC_YUV_420_10_SUPPORT_SPLIT |
979 				    MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
980 			.n_layers = ARRAY_SIZE(malidp550_layers),
981 			.layers = malidp550_layers,
982 			.de_irq_map = {
983 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
984 					    MALIDP550_DE_IRQ_VSYNC,
985 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
986 				.err_mask = MALIDP_DE_IRQ_UNDERRUN |
987 					    MALIDP550_DE_IRQ_SATURATION |
988 					    MALIDP550_DE_IRQ_AXI_ERR,
989 			},
990 			.se_irq_map = {
991 				.irq_mask = MALIDP550_SE_IRQ_EOW,
992 				.vsync_irq = MALIDP550_SE_IRQ_EOW,
993 				.err_mask  = MALIDP550_SE_IRQ_AXI_ERR |
994 					     MALIDP550_SE_IRQ_OVR |
995 					     MALIDP550_SE_IRQ_IBSY,
996 			},
997 			.dc_irq_map = {
998 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
999 					    MALIDP550_DC_IRQ_SE,
1000 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
1001 			},
1002 			.pixel_formats = malidp550_de_formats,
1003 			.n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
1004 			.bus_align_bytes = 8,
1005 		},
1006 		.query_hw = malidp550_query_hw,
1007 		.enter_config_mode = malidp550_enter_config_mode,
1008 		.leave_config_mode = malidp550_leave_config_mode,
1009 		.in_config_mode = malidp550_in_config_mode,
1010 		.set_config_valid = malidp550_set_config_valid,
1011 		.modeset = malidp550_modeset,
1012 		.rotmem_required = malidp550_rotmem_required,
1013 		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
1014 		.se_calc_mclk = malidp550_se_calc_mclk,
1015 		.enable_memwrite = malidp550_enable_memwrite,
1016 		.disable_memwrite = malidp550_disable_memwrite,
1017 		.features = 0,
1018 	},
1019 	[MALIDP_650] = {
1020 		.map = {
1021 			.coeffs_base = MALIDP550_COEFFS_BASE,
1022 			.se_base = MALIDP550_SE_BASE,
1023 			.dc_base = MALIDP550_DC_BASE,
1024 			.out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
1025 			.features = MALIDP_REGMAP_HAS_CLEARIRQ |
1026 				    MALIDP_DEVICE_AFBC_SUPPORT_SPLIT |
1027 				    MALIDP_DEVICE_AFBC_YUYV_USE_422_P2,
1028 			.n_layers = ARRAY_SIZE(malidp650_layers),
1029 			.layers = malidp650_layers,
1030 			.de_irq_map = {
1031 				.irq_mask = MALIDP_DE_IRQ_UNDERRUN |
1032 					    MALIDP650_DE_IRQ_DRIFT |
1033 					    MALIDP550_DE_IRQ_VSYNC,
1034 				.vsync_irq = MALIDP550_DE_IRQ_VSYNC,
1035 				.err_mask = MALIDP_DE_IRQ_UNDERRUN |
1036 					    MALIDP650_DE_IRQ_DRIFT |
1037 					    MALIDP550_DE_IRQ_SATURATION |
1038 					    MALIDP550_DE_IRQ_AXI_ERR |
1039 					    MALIDP650_DE_IRQ_ACEV1 |
1040 					    MALIDP650_DE_IRQ_ACEV2 |
1041 					    MALIDP650_DE_IRQ_ACEG |
1042 					    MALIDP650_DE_IRQ_AXIEP,
1043 			},
1044 			.se_irq_map = {
1045 				.irq_mask = MALIDP550_SE_IRQ_EOW,
1046 				.vsync_irq = MALIDP550_SE_IRQ_EOW,
1047 				.err_mask = MALIDP550_SE_IRQ_AXI_ERR |
1048 					    MALIDP550_SE_IRQ_OVR |
1049 					    MALIDP550_SE_IRQ_IBSY,
1050 			},
1051 			.dc_irq_map = {
1052 				.irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
1053 					    MALIDP550_DC_IRQ_SE,
1054 				.vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
1055 			},
1056 			.pixel_formats = malidp650_de_formats,
1057 			.n_pixel_formats = ARRAY_SIZE(malidp650_de_formats),
1058 			.bus_align_bytes = 16,
1059 		},
1060 		.query_hw = malidp650_query_hw,
1061 		.enter_config_mode = malidp550_enter_config_mode,
1062 		.leave_config_mode = malidp550_leave_config_mode,
1063 		.in_config_mode = malidp550_in_config_mode,
1064 		.set_config_valid = malidp550_set_config_valid,
1065 		.modeset = malidp550_modeset,
1066 		.rotmem_required = malidp650_rotmem_required,
1067 		.se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
1068 		.se_calc_mclk = malidp550_se_calc_mclk,
1069 		.enable_memwrite = malidp550_enable_memwrite,
1070 		.disable_memwrite = malidp550_disable_memwrite,
1071 		.features = 0,
1072 	},
1073 };
1074 
1075 u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
1076 			   u8 layer_id, u32 format, bool has_modifier)
1077 {
1078 	unsigned int i;
1079 
1080 	for (i = 0; i < map->n_pixel_formats; i++) {
1081 		if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
1082 		    (map->pixel_formats[i].format == format)) {
1083 			/*
1084 			 * In some DP550 and DP650, DRM_FORMAT_YUYV + AFBC modifier
1085 			 * is supported by a different h/w format id than
1086 			 * DRM_FORMAT_YUYV (only).
1087 			 */
1088 			if (format == DRM_FORMAT_YUYV &&
1089 			    (has_modifier) &&
1090 			    (map->features & MALIDP_DEVICE_AFBC_YUYV_USE_422_P2))
1091 				return AFBC_YUV_422_FORMAT_ID;
1092 			else
1093 				return map->pixel_formats[i].id;
1094 		}
1095 	}
1096 
1097 	return MALIDP_INVALID_FORMAT_ID;
1098 }
1099 
1100 bool malidp_hw_format_is_linear_only(u32 format)
1101 {
1102 	switch (format) {
1103 	case DRM_FORMAT_ARGB2101010:
1104 	case DRM_FORMAT_RGBA1010102:
1105 	case DRM_FORMAT_BGRA1010102:
1106 	case DRM_FORMAT_ARGB8888:
1107 	case DRM_FORMAT_RGBA8888:
1108 	case DRM_FORMAT_BGRA8888:
1109 	case DRM_FORMAT_XBGR8888:
1110 	case DRM_FORMAT_XRGB8888:
1111 	case DRM_FORMAT_RGBX8888:
1112 	case DRM_FORMAT_BGRX8888:
1113 	case DRM_FORMAT_RGB888:
1114 	case DRM_FORMAT_RGB565:
1115 	case DRM_FORMAT_ARGB1555:
1116 	case DRM_FORMAT_RGBA5551:
1117 	case DRM_FORMAT_BGRA5551:
1118 	case DRM_FORMAT_UYVY:
1119 	case DRM_FORMAT_XYUV8888:
1120 	case DRM_FORMAT_XVYU2101010:
1121 	case DRM_FORMAT_X0L2:
1122 	case DRM_FORMAT_X0L0:
1123 		return true;
1124 	default:
1125 		return false;
1126 	}
1127 }
1128 
1129 bool malidp_hw_format_is_afbc_only(u32 format)
1130 {
1131 	switch (format) {
1132 	case DRM_FORMAT_VUY888:
1133 	case DRM_FORMAT_VUY101010:
1134 	case DRM_FORMAT_YUV420_8BIT:
1135 	case DRM_FORMAT_YUV420_10BIT:
1136 		return true;
1137 	default:
1138 		return false;
1139 	}
1140 }
1141 
1142 static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
1143 {
1144 	u32 base = malidp_get_block_base(hwdev, block);
1145 
1146 	if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
1147 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
1148 	else
1149 		malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
1150 }
1151 
1152 static irqreturn_t malidp_de_irq(int irq, void *arg)
1153 {
1154 	struct drm_device *drm = arg;
1155 	struct malidp_drm *malidp = drm->dev_private;
1156 	struct malidp_hw_device *hwdev;
1157 	struct malidp_hw *hw;
1158 	const struct malidp_irq_map *de;
1159 	u32 status, mask, dc_status;
1160 	irqreturn_t ret = IRQ_NONE;
1161 
1162 	hwdev = malidp->dev;
1163 	hw = hwdev->hw;
1164 	de = &hw->map.de_irq_map;
1165 
1166 	/*
1167 	 * if we are suspended it is likely that we were invoked because
1168 	 * we share an interrupt line with some other driver, don't try
1169 	 * to read the hardware registers
1170 	 */
1171 	if (hwdev->pm_suspended)
1172 		return IRQ_NONE;
1173 
1174 	/* first handle the config valid IRQ */
1175 	dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
1176 	if (dc_status & hw->map.dc_irq_map.vsync_irq) {
1177 		malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
1178 		/* do we have a page flip event? */
1179 		if (malidp->event != NULL) {
1180 			spin_lock(&drm->event_lock);
1181 			drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
1182 			malidp->event = NULL;
1183 			spin_unlock(&drm->event_lock);
1184 		}
1185 		atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
1186 		ret = IRQ_WAKE_THREAD;
1187 	}
1188 
1189 	status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
1190 	if (!(status & de->irq_mask))
1191 		return ret;
1192 
1193 	mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
1194 	/* keep the status of the enabled interrupts, plus the error bits */
1195 	status &= (mask | de->err_mask);
1196 	if ((status & de->vsync_irq) && malidp->crtc.enabled)
1197 		drm_crtc_handle_vblank(&malidp->crtc);
1198 
1199 #ifdef CONFIG_DEBUG_FS
1200 	if (status & de->err_mask) {
1201 		malidp_error(malidp, &malidp->de_errors, status,
1202 			     drm_crtc_vblank_count(&malidp->crtc));
1203 	}
1204 #endif
1205 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
1206 
1207 	return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
1208 }
1209 
1210 static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
1211 {
1212 	struct drm_device *drm = arg;
1213 	struct malidp_drm *malidp = drm->dev_private;
1214 
1215 	wake_up(&malidp->wq);
1216 
1217 	return IRQ_HANDLED;
1218 }
1219 
1220 void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev)
1221 {
1222 	/* ensure interrupts are disabled */
1223 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1224 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1225 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1226 	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1227 
1228 	/* first enable the DC block IRQs */
1229 	malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
1230 			     hwdev->hw->map.dc_irq_map.irq_mask);
1231 
1232 	/* now enable the DE block IRQs */
1233 	malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
1234 			     hwdev->hw->map.de_irq_map.irq_mask);
1235 }
1236 
1237 int malidp_de_irq_init(struct drm_device *drm, int irq)
1238 {
1239 	struct malidp_drm *malidp = drm->dev_private;
1240 	struct malidp_hw_device *hwdev = malidp->dev;
1241 	int ret;
1242 
1243 	/* ensure interrupts are disabled */
1244 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1245 	malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1246 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1247 	malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1248 
1249 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
1250 					malidp_de_irq_thread_handler,
1251 					IRQF_SHARED, "malidp-de", drm);
1252 	if (ret < 0) {
1253 		DRM_ERROR("failed to install DE IRQ handler\n");
1254 		return ret;
1255 	}
1256 
1257 	malidp_de_irq_hw_init(hwdev);
1258 
1259 	return 0;
1260 }
1261 
1262 void malidp_de_irq_fini(struct malidp_hw_device *hwdev)
1263 {
1264 	malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
1265 			      hwdev->hw->map.de_irq_map.irq_mask);
1266 	malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
1267 			      hwdev->hw->map.dc_irq_map.irq_mask);
1268 }
1269 
1270 static irqreturn_t malidp_se_irq(int irq, void *arg)
1271 {
1272 	struct drm_device *drm = arg;
1273 	struct malidp_drm *malidp = drm->dev_private;
1274 	struct malidp_hw_device *hwdev = malidp->dev;
1275 	struct malidp_hw *hw = hwdev->hw;
1276 	const struct malidp_irq_map *se = &hw->map.se_irq_map;
1277 	u32 status, mask;
1278 
1279 	/*
1280 	 * if we are suspended it is likely that we were invoked because
1281 	 * we share an interrupt line with some other driver, don't try
1282 	 * to read the hardware registers
1283 	 */
1284 	if (hwdev->pm_suspended)
1285 		return IRQ_NONE;
1286 
1287 	status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
1288 	if (!(status & (se->irq_mask | se->err_mask)))
1289 		return IRQ_NONE;
1290 
1291 #ifdef CONFIG_DEBUG_FS
1292 	if (status & se->err_mask)
1293 		malidp_error(malidp, &malidp->se_errors, status,
1294 			     drm_crtc_vblank_count(&malidp->crtc));
1295 #endif
1296 	mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
1297 	status &= mask;
1298 
1299 	if (status & se->vsync_irq) {
1300 		switch (hwdev->mw_state) {
1301 		case MW_ONESHOT:
1302 			drm_writeback_signal_completion(&malidp->mw_connector, 0);
1303 			break;
1304 		case MW_STOP:
1305 			drm_writeback_signal_completion(&malidp->mw_connector, 0);
1306 			/* disable writeback after stop */
1307 			hwdev->mw_state = MW_NOT_ENABLED;
1308 			break;
1309 		case MW_RESTART:
1310 			drm_writeback_signal_completion(&malidp->mw_connector, 0);
1311 			/* fall through to a new start */
1312 		case MW_START:
1313 			/* writeback started, need to emulate one-shot mode */
1314 			hw->disable_memwrite(hwdev);
1315 			/*
1316 			 * only set config_valid HW bit if there is no other update
1317 			 * in progress or if we raced ahead of the DE IRQ handler
1318 			 * and config_valid flag will not be update until later
1319 			 */
1320 			status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
1321 			if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) ||
1322 			    (status & hw->map.dc_irq_map.vsync_irq))
1323 				hw->set_config_valid(hwdev, 1);
1324 			break;
1325 		}
1326 	}
1327 
1328 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
1329 
1330 	return IRQ_HANDLED;
1331 }
1332 
1333 void malidp_se_irq_hw_init(struct malidp_hw_device *hwdev)
1334 {
1335 	/* ensure interrupts are disabled */
1336 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1337 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1338 
1339 	malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
1340 			     hwdev->hw->map.se_irq_map.irq_mask);
1341 }
1342 
1343 static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1344 {
1345 	return IRQ_HANDLED;
1346 }
1347 
1348 int malidp_se_irq_init(struct drm_device *drm, int irq)
1349 {
1350 	struct malidp_drm *malidp = drm->dev_private;
1351 	struct malidp_hw_device *hwdev = malidp->dev;
1352 	int ret;
1353 
1354 	/* ensure interrupts are disabled */
1355 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1356 	malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1357 
1358 	ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
1359 					malidp_se_irq_thread_handler,
1360 					IRQF_SHARED, "malidp-se", drm);
1361 	if (ret < 0) {
1362 		DRM_ERROR("failed to install SE IRQ handler\n");
1363 		return ret;
1364 	}
1365 
1366 	hwdev->mw_state = MW_NOT_ENABLED;
1367 	malidp_se_irq_hw_init(hwdev);
1368 
1369 	return 0;
1370 }
1371 
1372 void malidp_se_irq_fini(struct malidp_hw_device *hwdev)
1373 {
1374 	malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
1375 			      hwdev->hw->map.se_irq_map.irq_mask);
1376 }
1377