Merge tag 'mtd/for-4.16' of git://git.infradead.org/linux-mtd
[linux-2.6-microblaze.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 },
79         { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE },
80         { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE },
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 },
85         { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE },
86         { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0 },
87         { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE },
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                                 .vsync_irq = 0,
639                         },
640                         .dc_irq_map = {
641                                 .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
642                                 .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
643                         },
644                         .pixel_formats = malidp500_de_formats,
645                         .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
646                         .bus_align_bytes = 8,
647                 },
648                 .query_hw = malidp500_query_hw,
649                 .enter_config_mode = malidp500_enter_config_mode,
650                 .leave_config_mode = malidp500_leave_config_mode,
651                 .in_config_mode = malidp500_in_config_mode,
652                 .set_config_valid = malidp500_set_config_valid,
653                 .modeset = malidp500_modeset,
654                 .rotmem_required = malidp500_rotmem_required,
655                 .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
656                 .se_calc_mclk = malidp500_se_calc_mclk,
657                 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
658         },
659         [MALIDP_550] = {
660                 .map = {
661                         .coeffs_base = MALIDP550_COEFFS_BASE,
662                         .se_base = MALIDP550_SE_BASE,
663                         .dc_base = MALIDP550_DC_BASE,
664                         .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
665                         .features = MALIDP_REGMAP_HAS_CLEARIRQ,
666                         .n_layers = ARRAY_SIZE(malidp550_layers),
667                         .layers = malidp550_layers,
668                         .de_irq_map = {
669                                 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
670                                             MALIDP550_DE_IRQ_VSYNC,
671                                 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
672                         },
673                         .se_irq_map = {
674                                 .irq_mask = MALIDP550_SE_IRQ_EOW |
675                                             MALIDP550_SE_IRQ_AXI_ERR,
676                         },
677                         .dc_irq_map = {
678                                 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
679                                 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
680                         },
681                         .pixel_formats = malidp550_de_formats,
682                         .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
683                         .bus_align_bytes = 8,
684                 },
685                 .query_hw = malidp550_query_hw,
686                 .enter_config_mode = malidp550_enter_config_mode,
687                 .leave_config_mode = malidp550_leave_config_mode,
688                 .in_config_mode = malidp550_in_config_mode,
689                 .set_config_valid = malidp550_set_config_valid,
690                 .modeset = malidp550_modeset,
691                 .rotmem_required = malidp550_rotmem_required,
692                 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
693                 .se_calc_mclk = malidp550_se_calc_mclk,
694                 .features = 0,
695         },
696         [MALIDP_650] = {
697                 .map = {
698                         .coeffs_base = MALIDP550_COEFFS_BASE,
699                         .se_base = MALIDP550_SE_BASE,
700                         .dc_base = MALIDP550_DC_BASE,
701                         .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
702                         .features = MALIDP_REGMAP_HAS_CLEARIRQ,
703                         .n_layers = ARRAY_SIZE(malidp550_layers),
704                         .layers = malidp550_layers,
705                         .de_irq_map = {
706                                 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
707                                             MALIDP650_DE_IRQ_DRIFT |
708                                             MALIDP550_DE_IRQ_VSYNC,
709                                 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
710                         },
711                         .se_irq_map = {
712                                 .irq_mask = MALIDP550_SE_IRQ_EOW |
713                                             MALIDP550_SE_IRQ_AXI_ERR,
714                         },
715                         .dc_irq_map = {
716                                 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
717                                 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
718                         },
719                         .pixel_formats = malidp550_de_formats,
720                         .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
721                         .bus_align_bytes = 16,
722                 },
723                 .query_hw = malidp650_query_hw,
724                 .enter_config_mode = malidp550_enter_config_mode,
725                 .leave_config_mode = malidp550_leave_config_mode,
726                 .in_config_mode = malidp550_in_config_mode,
727                 .set_config_valid = malidp550_set_config_valid,
728                 .modeset = malidp550_modeset,
729                 .rotmem_required = malidp550_rotmem_required,
730                 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
731                 .se_calc_mclk = malidp550_se_calc_mclk,
732                 .features = 0,
733         },
734 };
735
736 u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
737                            u8 layer_id, u32 format)
738 {
739         unsigned int i;
740
741         for (i = 0; i < map->n_pixel_formats; i++) {
742                 if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
743                     (map->pixel_formats[i].format == format))
744                         return map->pixel_formats[i].id;
745         }
746
747         return MALIDP_INVALID_FORMAT_ID;
748 }
749
750 static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
751 {
752         u32 base = malidp_get_block_base(hwdev, block);
753
754         if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
755                 malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
756         else
757                 malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
758 }
759
760 static irqreturn_t malidp_de_irq(int irq, void *arg)
761 {
762         struct drm_device *drm = arg;
763         struct malidp_drm *malidp = drm->dev_private;
764         struct malidp_hw_device *hwdev;
765         struct malidp_hw *hw;
766         const struct malidp_irq_map *de;
767         u32 status, mask, dc_status;
768         irqreturn_t ret = IRQ_NONE;
769
770         hwdev = malidp->dev;
771         hw = hwdev->hw;
772         de = &hw->map.de_irq_map;
773
774         /*
775          * if we are suspended it is likely that we were invoked because
776          * we share an interrupt line with some other driver, don't try
777          * to read the hardware registers
778          */
779         if (hwdev->pm_suspended)
780                 return IRQ_NONE;
781
782         /* first handle the config valid IRQ */
783         dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
784         if (dc_status & hw->map.dc_irq_map.vsync_irq) {
785                 /* we have a page flip event */
786                 atomic_set(&malidp->config_valid, 1);
787                 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
788                 ret = IRQ_WAKE_THREAD;
789         }
790
791         status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
792         if (!(status & de->irq_mask))
793                 return ret;
794
795         mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
796         status &= mask;
797         if (status & de->vsync_irq)
798                 drm_crtc_handle_vblank(&malidp->crtc);
799
800         malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
801
802         return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
803 }
804
805 static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
806 {
807         struct drm_device *drm = arg;
808         struct malidp_drm *malidp = drm->dev_private;
809
810         wake_up(&malidp->wq);
811
812         return IRQ_HANDLED;
813 }
814
815 int malidp_de_irq_init(struct drm_device *drm, int irq)
816 {
817         struct malidp_drm *malidp = drm->dev_private;
818         struct malidp_hw_device *hwdev = malidp->dev;
819         int ret;
820
821         /* ensure interrupts are disabled */
822         malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
823         malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
824         malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
825         malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
826
827         ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
828                                         malidp_de_irq_thread_handler,
829                                         IRQF_SHARED, "malidp-de", drm);
830         if (ret < 0) {
831                 DRM_ERROR("failed to install DE IRQ handler\n");
832                 return ret;
833         }
834
835         /* first enable the DC block IRQs */
836         malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
837                              hwdev->hw->map.dc_irq_map.irq_mask);
838
839         /* now enable the DE block IRQs */
840         malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
841                              hwdev->hw->map.de_irq_map.irq_mask);
842
843         return 0;
844 }
845
846 void malidp_de_irq_fini(struct drm_device *drm)
847 {
848         struct malidp_drm *malidp = drm->dev_private;
849         struct malidp_hw_device *hwdev = malidp->dev;
850
851         malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
852                               hwdev->hw->map.de_irq_map.irq_mask);
853         malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
854                               hwdev->hw->map.dc_irq_map.irq_mask);
855 }
856
857 static irqreturn_t malidp_se_irq(int irq, void *arg)
858 {
859         struct drm_device *drm = arg;
860         struct malidp_drm *malidp = drm->dev_private;
861         struct malidp_hw_device *hwdev = malidp->dev;
862         struct malidp_hw *hw = hwdev->hw;
863         const struct malidp_irq_map *se = &hw->map.se_irq_map;
864         u32 status, mask;
865
866         /*
867          * if we are suspended it is likely that we were invoked because
868          * we share an interrupt line with some other driver, don't try
869          * to read the hardware registers
870          */
871         if (hwdev->pm_suspended)
872                 return IRQ_NONE;
873
874         status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
875         if (!(status & se->irq_mask))
876                 return IRQ_NONE;
877
878         mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
879         status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
880         status &= mask;
881         /* ToDo: status decoding and firing up of VSYNC and page flip events */
882
883         malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
884
885         return IRQ_HANDLED;
886 }
887
888 static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
889 {
890         return IRQ_HANDLED;
891 }
892
893 int malidp_se_irq_init(struct drm_device *drm, int irq)
894 {
895         struct malidp_drm *malidp = drm->dev_private;
896         struct malidp_hw_device *hwdev = malidp->dev;
897         int ret;
898
899         /* ensure interrupts are disabled */
900         malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
901         malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
902
903         ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
904                                         malidp_se_irq_thread_handler,
905                                         IRQF_SHARED, "malidp-se", drm);
906         if (ret < 0) {
907                 DRM_ERROR("failed to install SE IRQ handler\n");
908                 return ret;
909         }
910
911         malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
912                              hwdev->hw->map.se_irq_map.irq_mask);
913
914         return 0;
915 }
916
917 void malidp_se_irq_fini(struct drm_device *drm)
918 {
919         struct malidp_drm *malidp = drm->dev_private;
920         struct malidp_hw_device *hwdev = malidp->dev;
921
922         malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
923                               hwdev->hw->map.se_irq_map.irq_mask);
924 }