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