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