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