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
27enum {
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
35static 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
106static const struct malidp_format_id malidp550_de_formats[] = {
107	MALIDP_COMMON_FORMATS,
108};
109
110static 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
115static 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
130static 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
147static 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
168const 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
195static 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
270static 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
284static 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
303static 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
319static 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
330static 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
338static 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
393int 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
417static 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
430static 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
447static 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
479static 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
512static 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
562static 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
572static 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
605static 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
624static 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
640static 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
651static 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
659static 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
705static 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
759static 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
786static 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
806static 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
820static 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
853static 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
899static 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
908static 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
936const 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
1091u8 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
1116bool 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
1145bool 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
1158static 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
1168static irqreturn_t malidp_de_irq(int irq, void *arg)
1169{
1170	struct drm_device *drm = arg;
1171	struct malidp_drm *malidp = drm_to_malidp(drm);
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
1226static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
1227{
1228	struct drm_device *drm = arg;
1229	struct malidp_drm *malidp = drm_to_malidp(drm);
1230
1231	wake_up(&malidp->wq);
1232
1233	return IRQ_HANDLED;
1234}
1235
1236void 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
1253int malidp_de_irq_init(struct drm_device *drm, int irq)
1254{
1255	struct malidp_drm *malidp = drm_to_malidp(drm);
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
1278void 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
1286static irqreturn_t malidp_se_irq(int irq, void *arg)
1287{
1288	struct drm_device *drm = arg;
1289	struct malidp_drm *malidp = drm_to_malidp(drm);
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
1349void 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
1359static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1360{
1361	return IRQ_HANDLED;
1362}
1363
1364int malidp_se_irq_init(struct drm_device *drm, int irq)
1365{
1366	struct malidp_drm *malidp = drm_to_malidp(drm);
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
1388void 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