Merge branches 'work.misc' and 'work.dcache' of git://git.kernel.org/pub/scm/linux...
[sfrench/cifs-2.6.git] / drivers / gpu / drm / arm / malidp_hw.c
1 /*
2  * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3  * Author: Liviu Dudau <Liviu.Dudau@arm.com>
4  *
5  * This program is free software and is provided to you under the terms of the
6  * GNU General Public License version 2 as published by the Free Software
7  * Foundation, and any use by you of this program is subject to the terms
8  * of such GNU licence.
9  *
10  * ARM Mali DP500/DP550/DP650 hardware manipulation routines. This is where
11  * the difference between various versions of the hardware is being dealt with
12  * in an attempt to provide to the rest of the driver code a unified view
13  */
14
15 #include <linux/clk.h>
16 #include <linux/types.h>
17 #include <linux/io.h>
18 #include <drm/drmP.h>
19 #include <video/videomode.h>
20 #include <video/display_timing.h>
21
22 #include "malidp_drv.h"
23 #include "malidp_hw.h"
24
25 static const struct malidp_format_id malidp500_de_formats[] = {
26         /*    fourcc,   layers supporting the format,     internal id  */
27         { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  0 },
28         { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  1 },
29         { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  2 },
30         { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  3 },
31         { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  4 },
32         { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  5 },
33         { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  6 },
34         { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  7 },
35         { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  8 },
36         { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2,  9 },
37         { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
38         { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
39         { DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
40         { DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
41         { DRM_FORMAT_NV12, DE_VIDEO1, 14 },
42         { DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
43 };
44
45 #define MALIDP_ID(__group, __format) \
46         ((((__group) & 0x7) << 3) | ((__format) & 0x7))
47
48 #define MALIDP_COMMON_FORMATS \
49         /*    fourcc,   layers supporting the format,      internal id   */ \
50         { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 0) }, \
51         { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 1) }, \
52         { DRM_FORMAT_RGBA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 2) }, \
53         { DRM_FORMAT_BGRA1010102, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(0, 3) }, \
54         { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 0) }, \
55         { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 1) }, \
56         { DRM_FORMAT_RGBA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 2) }, \
57         { DRM_FORMAT_BGRA8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(1, 3) }, \
58         { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 0) }, \
59         { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 1) }, \
60         { DRM_FORMAT_RGBX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 2) }, \
61         { DRM_FORMAT_BGRX8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2 | DE_SMART, MALIDP_ID(2, 3) }, \
62         { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 0) }, \
63         { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(3, 1) }, \
64         { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 0) }, \
65         { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 1) }, \
66         { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 2) }, \
67         { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_VIDEO2, MALIDP_ID(4, 3) }, \
68         { DRM_FORMAT_YUYV, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 2) },    \
69         { DRM_FORMAT_UYVY, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 3) },    \
70         { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 6) },    \
71         { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
72
73 static const struct malidp_format_id malidp550_de_formats[] = {
74         MALIDP_COMMON_FORMATS,
75 };
76
77 static const struct malidp_layer malidp500_layers[] = {
78         { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB },
79         { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
80         { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
81 };
82
83 static const struct malidp_layer malidp550_layers[] = {
84         { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB },
85         { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
86         { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB },
87         { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE, 0 },
88 };
89
90 #define SE_N_SCALING_COEFFS     96
91 static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
92         [MALIDP_UPSCALING_COEFFS - 1] = {
93                 0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
94                 0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
95                 0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
96                 0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
97                 0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
98                 0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
99                 0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
100                 0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
101                 0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
102                 0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
103                 0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
104                 0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
105         },
106         [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
107                 0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
108                 0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
109                 0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
110                 0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
111                 0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
112                 0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
113                 0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
114                 0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
115                 0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
116                 0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
117                 0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
118                 0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
119         },
120         [MALIDP_DOWNSCALING_2_COEFFS - 1] = {
121                 0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
122                 0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
123                 0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
124                 0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
125                 0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
126                 0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
127                 0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
128                 0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
129                 0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
130                 0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
131                 0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
132                 0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
133         },
134         [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
135                 0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
136                 0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
137                 0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
138                 0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
139                 0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
140                 0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
141                 0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
142                 0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
143                 0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
144                 0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
145                 0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
146                 0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
147         },
148         [MALIDP_DOWNSCALING_4_COEFFS - 1] = {
149                 0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
150                 0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
151                 0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
152                 0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
153                 0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
154                 0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
155                 0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
156                 0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
157                 0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
158                 0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
159                 0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
160                 0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
161         },
162 };
163
164 #define MALIDP_DE_DEFAULT_PREFETCH_START        5
165
166 static int malidp500_query_hw(struct malidp_hw_device *hwdev)
167 {
168         u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
169         /* bit 4 of the CONFIG_ID register holds the line size multiplier */
170         u8 ln_size_mult = conf & 0x10 ? 2 : 1;
171
172         hwdev->min_line_size = 2;
173         hwdev->max_line_size = SZ_2K * ln_size_mult;
174         hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
175         hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
176
177         return 0;
178 }
179
180 static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
181 {
182         u32 status, count = 100;
183
184         malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
185         while (count) {
186                 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
187                 if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
188                         break;
189                 /*
190                  * entering config mode can take as long as the rendering
191                  * of a full frame, hence the long sleep here
192                  */
193                 usleep_range(1000, 10000);
194                 count--;
195         }
196         WARN(count == 0, "timeout while entering config mode");
197 }
198
199 static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
200 {
201         u32 status, count = 100;
202
203         malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
204         malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
205         while (count) {
206                 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
207                 if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
208                         break;
209                 usleep_range(100, 1000);
210                 count--;
211         }
212         WARN(count == 0, "timeout while leaving config mode");
213 }
214
215 static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
216 {
217         u32 status;
218
219         status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
220         if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
221                 return true;
222
223         return false;
224 }
225
226 static void malidp500_set_config_valid(struct malidp_hw_device *hwdev)
227 {
228         malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
229 }
230
231 static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
232 {
233         u32 val = 0;
234
235         malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
236         if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
237                 val |= MALIDP500_HSYNCPOL;
238         if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
239                 val |= MALIDP500_VSYNCPOL;
240         val |= MALIDP_DE_DEFAULT_PREFETCH_START;
241         malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
242
243         /*
244          * Mali-DP500 encodes the background color like this:
245          *    - red   @ MALIDP500_BGND_COLOR[12:0]
246          *    - green @ MALIDP500_BGND_COLOR[27:16]
247          *    - blue  @ (MALIDP500_BGND_COLOR + 4)[12:0]
248          */
249         val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
250               (MALIDP_BGND_COLOR_R & 0xfff);
251         malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
252         malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
253
254         val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
255                 MALIDP_DE_H_BACKPORCH(mode->hback_porch);
256         malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
257
258         val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
259                 MALIDP_DE_V_BACKPORCH(mode->vback_porch);
260         malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
261
262         val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
263                 MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
264         malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
265
266         val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
267         malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
268
269         if (mode->flags & DISPLAY_FLAGS_INTERLACED)
270                 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
271         else
272                 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
273 }
274
275 static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
276 {
277         /* RGB888 or BGR888 can't be rotated */
278         if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
279                 return -EINVAL;
280
281         /*
282          * Each layer needs enough rotation memory to fit 8 lines
283          * worth of pixel data. Required size is then:
284          *    size = rotated_width * (bpp / 8) * 8;
285          */
286         return w * drm_format_plane_cpp(fmt, 0) * 8;
287 }
288
289 static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
290                                            u32 direction,
291                                            u16 addr,
292                                            u8 coeffs_id)
293 {
294         int i;
295         u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
296
297         malidp_hw_write(hwdev,
298                         direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
299                         scaling_control + MALIDP_SE_COEFFTAB_ADDR);
300         for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
301                 malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
302                                 dp500_se_scaling_coeffs[coeffs_id][i]),
303                                 scaling_control + MALIDP_SE_COEFFTAB_DATA);
304 }
305
306 static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
307                                            struct malidp_se_config *se_config,
308                                            struct malidp_se_config *old_config)
309 {
310         /* Get array indices into dp500_se_scaling_coeffs. */
311         u8 h = (u8)se_config->hcoeff - 1;
312         u8 v = (u8)se_config->vcoeff - 1;
313
314         if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
315                     v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
316                 return -EINVAL;
317
318         if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
319                          se_config->vcoeff != old_config->vcoeff)) {
320                 malidp500_se_write_pp_coefftab(hwdev,
321                                                (MALIDP_SE_V_COEFFTAB |
322                                                 MALIDP_SE_H_COEFFTAB),
323                                                0, v);
324         } else {
325                 if (se_config->vcoeff != old_config->vcoeff)
326                         malidp500_se_write_pp_coefftab(hwdev,
327                                                        MALIDP_SE_V_COEFFTAB,
328                                                        0, v);
329                 if (se_config->hcoeff != old_config->hcoeff)
330                         malidp500_se_write_pp_coefftab(hwdev,
331                                                        MALIDP_SE_H_COEFFTAB,
332                                                        0, h);
333         }
334
335         return 0;
336 }
337
338 static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
339                                    struct malidp_se_config *se_config,
340                                    struct videomode *vm)
341 {
342         unsigned long mclk;
343         unsigned long pxlclk = vm->pixelclock; /* Hz */
344         unsigned long htotal = vm->hactive + vm->hfront_porch +
345                                vm->hback_porch + vm->hsync_len;
346         unsigned long input_size = se_config->input_w * se_config->input_h;
347         unsigned long a = 10;
348         long ret;
349
350         /*
351          * mclk = max(a, 1.5) * pxlclk
352          *
353          * To avoid float calculaiton, using 15 instead of 1.5 and div by
354          * 10 to get mclk.
355          */
356         if (se_config->scale_enable) {
357                 a = 15 * input_size / (htotal * se_config->output_h);
358                 if (a < 15)
359                         a = 15;
360         }
361         mclk = a * pxlclk / 10;
362         ret = clk_get_rate(hwdev->mclk);
363         if (ret < mclk) {
364                 DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
365                                  mclk / 1000);
366                 return -EINVAL;
367         }
368         return ret;
369 }
370
371 static int malidp550_query_hw(struct malidp_hw_device *hwdev)
372 {
373         u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
374         u8 ln_size = (conf >> 4) & 0x3, rsize;
375
376         hwdev->min_line_size = 2;
377
378         switch (ln_size) {
379         case 0:
380                 hwdev->max_line_size = SZ_2K;
381                 /* two banks of 64KB for rotation memory */
382                 rsize = 64;
383                 break;
384         case 1:
385                 hwdev->max_line_size = SZ_4K;
386                 /* two banks of 128KB for rotation memory */
387                 rsize = 128;
388                 break;
389         case 2:
390                 hwdev->max_line_size = 1280;
391                 /* two banks of 40KB for rotation memory */
392                 rsize = 40;
393                 break;
394         case 3:
395                 /* reserved value */
396                 hwdev->max_line_size = 0;
397                 return -EINVAL;
398         }
399
400         hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
401         return 0;
402 }
403
404 static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
405 {
406         u32 status, count = 100;
407
408         malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
409         while (count) {
410                 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
411                 if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
412                         break;
413                 /*
414                  * entering config mode can take as long as the rendering
415                  * of a full frame, hence the long sleep here
416                  */
417                 usleep_range(1000, 10000);
418                 count--;
419         }
420         WARN(count == 0, "timeout while entering config mode");
421 }
422
423 static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
424 {
425         u32 status, count = 100;
426
427         malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
428         malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
429         while (count) {
430                 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
431                 if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
432                         break;
433                 usleep_range(100, 1000);
434                 count--;
435         }
436         WARN(count == 0, "timeout while leaving config mode");
437 }
438
439 static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
440 {
441         u32 status;
442
443         status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
444         if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
445                 return true;
446
447         return false;
448 }
449
450 static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
451 {
452         malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
453 }
454
455 static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
456 {
457         u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
458
459         malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
460         /*
461          * Mali-DP550 and Mali-DP650 encode the background color like this:
462          *   - red   @ MALIDP550_DE_BGND_COLOR[23:16]
463          *   - green @ MALIDP550_DE_BGND_COLOR[15:8]
464          *   - blue  @ MALIDP550_DE_BGND_COLOR[7:0]
465          *
466          * We need to truncate the least significant 4 bits from the default
467          * MALIDP_BGND_COLOR_x values
468          */
469         val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
470               (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
471               ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
472         malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
473
474         val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
475                 MALIDP_DE_H_BACKPORCH(mode->hback_porch);
476         malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
477
478         val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
479                 MALIDP_DE_V_BACKPORCH(mode->vback_porch);
480         malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
481
482         val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
483                 MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
484         if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
485                 val |= MALIDP550_HSYNCPOL;
486         if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
487                 val |= MALIDP550_VSYNCPOL;
488         malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
489
490         val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
491         malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
492
493         if (mode->flags & DISPLAY_FLAGS_INTERLACED)
494                 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
495         else
496                 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
497 }
498
499 static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
500 {
501         u32 bytes_per_col;
502
503         /* raw RGB888 or BGR888 can't be rotated */
504         if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
505                 return -EINVAL;
506
507         switch (fmt) {
508         /* 8 lines at 4 bytes per pixel */
509         case DRM_FORMAT_ARGB2101010:
510         case DRM_FORMAT_ABGR2101010:
511         case DRM_FORMAT_RGBA1010102:
512         case DRM_FORMAT_BGRA1010102:
513         case DRM_FORMAT_ARGB8888:
514         case DRM_FORMAT_ABGR8888:
515         case DRM_FORMAT_RGBA8888:
516         case DRM_FORMAT_BGRA8888:
517         case DRM_FORMAT_XRGB8888:
518         case DRM_FORMAT_XBGR8888:
519         case DRM_FORMAT_RGBX8888:
520         case DRM_FORMAT_BGRX8888:
521         case DRM_FORMAT_RGB888:
522         case DRM_FORMAT_BGR888:
523         /* 16 lines at 2 bytes per pixel */
524         case DRM_FORMAT_RGBA5551:
525         case DRM_FORMAT_ABGR1555:
526         case DRM_FORMAT_RGB565:
527         case DRM_FORMAT_BGR565:
528         case DRM_FORMAT_UYVY:
529         case DRM_FORMAT_YUYV:
530                 bytes_per_col = 32;
531                 break;
532         /* 16 lines at 1.5 bytes per pixel */
533         case DRM_FORMAT_NV12:
534         case DRM_FORMAT_YUV420:
535                 bytes_per_col = 24;
536                 break;
537         default:
538                 return -EINVAL;
539         }
540
541         return w * bytes_per_col;
542 }
543
544 static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
545                                            struct malidp_se_config *se_config,
546                                            struct malidp_se_config *old_config)
547 {
548         u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
549                    MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
550         u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
551                         MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
552
553         malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
554         malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
555         return 0;
556 }
557
558 static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
559                                    struct malidp_se_config *se_config,
560                                    struct videomode *vm)
561 {
562         unsigned long mclk;
563         unsigned long pxlclk = vm->pixelclock;
564         unsigned long htotal = vm->hactive + vm->hfront_porch +
565                                vm->hback_porch + vm->hsync_len;
566         unsigned long numerator = 1, denominator = 1;
567         long ret;
568
569         if (se_config->scale_enable) {
570                 numerator = max(se_config->input_w, se_config->output_w) *
571                             se_config->input_h;
572                 numerator += se_config->output_w *
573                              (se_config->output_h -
574                               min(se_config->input_h, se_config->output_h));
575                 denominator = (htotal - 2) * se_config->output_h;
576         }
577
578         /* mclk can't be slower than pxlclk. */
579         if (numerator < denominator)
580                 numerator = denominator = 1;
581         mclk = (pxlclk * numerator) / denominator;
582         ret = clk_get_rate(hwdev->mclk);
583         if (ret < mclk) {
584                 DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
585                                  mclk / 1000);
586                 return -EINVAL;
587         }
588         return ret;
589 }
590
591 static int malidp650_query_hw(struct malidp_hw_device *hwdev)
592 {
593         u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
594         u8 ln_size = (conf >> 4) & 0x3, rsize;
595
596         hwdev->min_line_size = 4;
597
598         switch (ln_size) {
599         case 0:
600         case 2:
601                 /* reserved values */
602                 hwdev->max_line_size = 0;
603                 return -EINVAL;
604         case 1:
605                 hwdev->max_line_size = SZ_4K;
606                 /* two banks of 128KB for rotation memory */
607                 rsize = 128;
608                 break;
609         case 3:
610                 hwdev->max_line_size = 2560;
611                 /* two banks of 80KB for rotation memory */
612                 rsize = 80;
613         }
614
615         hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
616         return 0;
617 }
618
619 const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
620         [MALIDP_500] = {
621                 .map = {
622                         .coeffs_base = MALIDP500_COEFFS_BASE,
623                         .se_base = MALIDP500_SE_BASE,
624                         .dc_base = MALIDP500_DC_BASE,
625                         .out_depth_base = MALIDP500_OUTPUT_DEPTH,
626                         .features = 0,  /* no CLEARIRQ register */
627                         .n_layers = ARRAY_SIZE(malidp500_layers),
628                         .layers = malidp500_layers,
629                         .de_irq_map = {
630                                 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
631                                             MALIDP500_DE_IRQ_AXI_ERR |
632                                             MALIDP500_DE_IRQ_VSYNC |
633                                             MALIDP500_DE_IRQ_GLOBAL,
634                                 .vsync_irq = MALIDP500_DE_IRQ_VSYNC,
635                         },
636                         .se_irq_map = {
637                                 .irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
638                                             MALIDP500_SE_IRQ_GLOBAL,
639                                 .vsync_irq = 0,
640                         },
641                         .dc_irq_map = {
642                                 .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
643                                 .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
644                         },
645                         .pixel_formats = malidp500_de_formats,
646                         .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
647                         .bus_align_bytes = 8,
648                 },
649                 .query_hw = malidp500_query_hw,
650                 .enter_config_mode = malidp500_enter_config_mode,
651                 .leave_config_mode = malidp500_leave_config_mode,
652                 .in_config_mode = malidp500_in_config_mode,
653                 .set_config_valid = malidp500_set_config_valid,
654                 .modeset = malidp500_modeset,
655                 .rotmem_required = malidp500_rotmem_required,
656                 .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
657                 .se_calc_mclk = malidp500_se_calc_mclk,
658                 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
659         },
660         [MALIDP_550] = {
661                 .map = {
662                         .coeffs_base = MALIDP550_COEFFS_BASE,
663                         .se_base = MALIDP550_SE_BASE,
664                         .dc_base = MALIDP550_DC_BASE,
665                         .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
666                         .features = MALIDP_REGMAP_HAS_CLEARIRQ,
667                         .n_layers = ARRAY_SIZE(malidp550_layers),
668                         .layers = malidp550_layers,
669                         .de_irq_map = {
670                                 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
671                                             MALIDP550_DE_IRQ_VSYNC,
672                                 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
673                         },
674                         .se_irq_map = {
675                                 .irq_mask = MALIDP550_SE_IRQ_EOW |
676                                             MALIDP550_SE_IRQ_AXI_ERR,
677                         },
678                         .dc_irq_map = {
679                                 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
680                                 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
681                         },
682                         .pixel_formats = malidp550_de_formats,
683                         .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
684                         .bus_align_bytes = 8,
685                 },
686                 .query_hw = malidp550_query_hw,
687                 .enter_config_mode = malidp550_enter_config_mode,
688                 .leave_config_mode = malidp550_leave_config_mode,
689                 .in_config_mode = malidp550_in_config_mode,
690                 .set_config_valid = malidp550_set_config_valid,
691                 .modeset = malidp550_modeset,
692                 .rotmem_required = malidp550_rotmem_required,
693                 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
694                 .se_calc_mclk = malidp550_se_calc_mclk,
695                 .features = 0,
696         },
697         [MALIDP_650] = {
698                 .map = {
699                         .coeffs_base = MALIDP550_COEFFS_BASE,
700                         .se_base = MALIDP550_SE_BASE,
701                         .dc_base = MALIDP550_DC_BASE,
702                         .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
703                         .features = MALIDP_REGMAP_HAS_CLEARIRQ,
704                         .n_layers = ARRAY_SIZE(malidp550_layers),
705                         .layers = malidp550_layers,
706                         .de_irq_map = {
707                                 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
708                                             MALIDP650_DE_IRQ_DRIFT |
709                                             MALIDP550_DE_IRQ_VSYNC,
710                                 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
711                         },
712                         .se_irq_map = {
713                                 .irq_mask = MALIDP550_SE_IRQ_EOW |
714                                             MALIDP550_SE_IRQ_AXI_ERR,
715                         },
716                         .dc_irq_map = {
717                                 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
718                                 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
719                         },
720                         .pixel_formats = malidp550_de_formats,
721                         .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
722                         .bus_align_bytes = 16,
723                 },
724                 .query_hw = malidp650_query_hw,
725                 .enter_config_mode = malidp550_enter_config_mode,
726                 .leave_config_mode = malidp550_leave_config_mode,
727                 .in_config_mode = malidp550_in_config_mode,
728                 .set_config_valid = malidp550_set_config_valid,
729                 .modeset = malidp550_modeset,
730                 .rotmem_required = malidp550_rotmem_required,
731                 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
732                 .se_calc_mclk = malidp550_se_calc_mclk,
733                 .features = 0,
734         },
735 };
736
737 u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
738                            u8 layer_id, u32 format)
739 {
740         unsigned int i;
741
742         for (i = 0; i < map->n_pixel_formats; i++) {
743                 if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
744                     (map->pixel_formats[i].format == format))
745                         return map->pixel_formats[i].id;
746         }
747
748         return MALIDP_INVALID_FORMAT_ID;
749 }
750
751 static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
752 {
753         u32 base = malidp_get_block_base(hwdev, block);
754
755         if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
756                 malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
757         else
758                 malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
759 }
760
761 static irqreturn_t malidp_de_irq(int irq, void *arg)
762 {
763         struct drm_device *drm = arg;
764         struct malidp_drm *malidp = drm->dev_private;
765         struct malidp_hw_device *hwdev;
766         struct malidp_hw *hw;
767         const struct malidp_irq_map *de;
768         u32 status, mask, dc_status;
769         irqreturn_t ret = IRQ_NONE;
770
771         hwdev = malidp->dev;
772         hw = hwdev->hw;
773         de = &hw->map.de_irq_map;
774
775         /*
776          * if we are suspended it is likely that we were invoked because
777          * we share an interrupt line with some other driver, don't try
778          * to read the hardware registers
779          */
780         if (hwdev->pm_suspended)
781                 return IRQ_NONE;
782
783         /* first handle the config valid IRQ */
784         dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
785         if (dc_status & hw->map.dc_irq_map.vsync_irq) {
786                 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
787                 /* do we have a page flip event? */
788                 if (malidp->event != NULL) {
789                         spin_lock(&drm->event_lock);
790                         drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
791                         malidp->event = NULL;
792                         spin_unlock(&drm->event_lock);
793                 }
794                 atomic_set(&malidp->config_valid, 1);
795                 ret = IRQ_WAKE_THREAD;
796         }
797
798         status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
799         if (!(status & de->irq_mask))
800                 return ret;
801
802         mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
803         status &= mask;
804         if ((status & de->vsync_irq) && malidp->crtc.enabled)
805                 drm_crtc_handle_vblank(&malidp->crtc);
806
807         malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
808
809         return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
810 }
811
812 static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
813 {
814         struct drm_device *drm = arg;
815         struct malidp_drm *malidp = drm->dev_private;
816
817         wake_up(&malidp->wq);
818
819         return IRQ_HANDLED;
820 }
821
822 int malidp_de_irq_init(struct drm_device *drm, int irq)
823 {
824         struct malidp_drm *malidp = drm->dev_private;
825         struct malidp_hw_device *hwdev = malidp->dev;
826         int ret;
827
828         /* ensure interrupts are disabled */
829         malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
830         malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
831         malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
832         malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
833
834         ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
835                                         malidp_de_irq_thread_handler,
836                                         IRQF_SHARED, "malidp-de", drm);
837         if (ret < 0) {
838                 DRM_ERROR("failed to install DE IRQ handler\n");
839                 return ret;
840         }
841
842         /* first enable the DC block IRQs */
843         malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
844                              hwdev->hw->map.dc_irq_map.irq_mask);
845
846         /* now enable the DE block IRQs */
847         malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
848                              hwdev->hw->map.de_irq_map.irq_mask);
849
850         return 0;
851 }
852
853 void malidp_de_irq_fini(struct drm_device *drm)
854 {
855         struct malidp_drm *malidp = drm->dev_private;
856         struct malidp_hw_device *hwdev = malidp->dev;
857
858         malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
859                               hwdev->hw->map.de_irq_map.irq_mask);
860         malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
861                               hwdev->hw->map.dc_irq_map.irq_mask);
862 }
863
864 static irqreturn_t malidp_se_irq(int irq, void *arg)
865 {
866         struct drm_device *drm = arg;
867         struct malidp_drm *malidp = drm->dev_private;
868         struct malidp_hw_device *hwdev = malidp->dev;
869         struct malidp_hw *hw = hwdev->hw;
870         const struct malidp_irq_map *se = &hw->map.se_irq_map;
871         u32 status, mask;
872
873         /*
874          * if we are suspended it is likely that we were invoked because
875          * we share an interrupt line with some other driver, don't try
876          * to read the hardware registers
877          */
878         if (hwdev->pm_suspended)
879                 return IRQ_NONE;
880
881         status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
882         if (!(status & se->irq_mask))
883                 return IRQ_NONE;
884
885         mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
886         status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
887         status &= mask;
888         /* ToDo: status decoding and firing up of VSYNC and page flip events */
889
890         malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
891
892         return IRQ_HANDLED;
893 }
894
895 static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
896 {
897         return IRQ_HANDLED;
898 }
899
900 int malidp_se_irq_init(struct drm_device *drm, int irq)
901 {
902         struct malidp_drm *malidp = drm->dev_private;
903         struct malidp_hw_device *hwdev = malidp->dev;
904         int ret;
905
906         /* ensure interrupts are disabled */
907         malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
908         malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
909
910         ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
911                                         malidp_se_irq_thread_handler,
912                                         IRQF_SHARED, "malidp-se", drm);
913         if (ret < 0) {
914                 DRM_ERROR("failed to install SE IRQ handler\n");
915                 return ret;
916         }
917
918         malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
919                              hwdev->hw->map.se_irq_map.irq_mask);
920
921         return 0;
922 }
923
924 void malidp_se_irq_fini(struct drm_device *drm)
925 {
926         struct malidp_drm *malidp = drm->dev_private;
927         struct malidp_hw_device *hwdev = malidp->dev;
928
929         malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
930                               hwdev->hw->map.se_irq_map.irq_mask);
931 }