blob: 28360b8542f724de1d049884ae1b5dfa4a7b9b0e [file] [log] [blame]
Liviu Dudauad49f862016-03-07 10:00:53 +00001/*
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
Mihail Atanassovc2e7f822017-02-13 15:09:01 +000015#include <linux/clk.h>
Liviu Dudauad49f862016-03-07 10:00:53 +000016#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
Brian Starkey6211b482016-10-03 15:08:12 +010025static const struct malidp_format_id malidp500_de_formats[] = {
Liviu Dudauad49f862016-03-07 10:00:53 +000026 /* 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
Brian Starkey6211b482016-10-03 15:08:12 +010073static const struct malidp_format_id malidp550_de_formats[] = {
Liviu Dudauad49f862016-03-07 10:00:53 +000074 MALIDP_COMMON_FORMATS,
75};
76
77static const struct malidp_layer malidp500_layers[] = {
Mihail Atanassov83d642e2017-01-23 15:24:35 +000078 { 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 },
Liviu Dudauad49f862016-03-07 10:00:53 +000081};
82
83static const struct malidp_layer malidp550_layers[] = {
Mihail Atanassov83d642e2017-01-23 15:24:35 +000084 { 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 },
Mihail Atanassovd1479f62017-02-09 11:32:00 +000087 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE },
Liviu Dudauad49f862016-03-07 10:00:53 +000088};
89
Mihail Atanassov28ce6752017-02-13 15:14:05 +000090#define SE_N_SCALING_COEFFS 96
91static 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
Liviu Dudauad49f862016-03-07 10:00:53 +0000164#define MALIDP_DE_DEFAULT_PREFETCH_START 5
165
166static 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
180static 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->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
199static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
200{
201 u32 status, count = 100;
202
Brian Starkeye64053f2016-11-08 11:36:14 +0000203 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
Liviu Dudauad49f862016-03-07 10:00:53 +0000204 malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
205 while (count) {
206 status = malidp_hw_read(hwdev, hwdev->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
215static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
216{
217 u32 status;
218
219 status = malidp_hw_read(hwdev, hwdev->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
226static void malidp500_set_config_valid(struct malidp_hw_device *hwdev)
227{
228 malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
229}
230
231static 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
275static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
276{
Liviu Dudauad49f862016-03-07 10:00:53 +0000277 /* 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 */
Laurent Pinchart7ccf2812016-10-18 01:41:20 +0300286 return w * drm_format_plane_cpp(fmt, 0) * 8;
Liviu Dudauad49f862016-03-07 10:00:53 +0000287}
288
Mihail Atanassov28ce6752017-02-13 15:14:05 +0000289static 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
306static 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
Mihail Atanassovc2e7f822017-02-13 15:09:01 +0000338static 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
Liviu Dudauad49f862016-03-07 10:00:53 +0000371static 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
404static 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->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
423static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
424{
425 u32 status, count = 100;
426
Brian Starkeye64053f2016-11-08 11:36:14 +0000427 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
Liviu Dudauad49f862016-03-07 10:00:53 +0000428 malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
429 while (count) {
430 status = malidp_hw_read(hwdev, hwdev->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
439static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
440{
441 u32 status;
442
443 status = malidp_hw_read(hwdev, hwdev->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
450static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
451{
452 malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
453}
454
455static 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
499static 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
Mihail Atanassov28ce6752017-02-13 15:14:05 +0000544static 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
Mihail Atanassovc2e7f822017-02-13 15:09:01 +0000558static 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
Liviu Dudauad49f862016-03-07 10:00:53 +0000591static 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
619const struct malidp_hw_device malidp_device[MALIDP_MAX_DEVICES] = {
620 [MALIDP_500] = {
621 .map = {
Mihail Atanassov02725d32017-02-01 14:48:50 +0000622 .coeffs_base = MALIDP500_COEFFS_BASE,
Liviu Dudauad49f862016-03-07 10:00:53 +0000623 .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 },
Brian Starkey6211b482016-10-03 15:08:12 +0100644 .pixel_formats = malidp500_de_formats,
645 .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
Brian Starkeya2280622016-10-11 15:26:04 +0100646 .bus_align_bytes = 8,
Liviu Dudauad49f862016-03-07 10:00:53 +0000647 },
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,
Mihail Atanassov28ce6752017-02-13 15:14:05 +0000655 .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
Mihail Atanassovc2e7f822017-02-13 15:09:01 +0000656 .se_calc_mclk = malidp500_se_calc_mclk,
Mihail Atanassov83d642e2017-01-23 15:24:35 +0000657 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
Liviu Dudauad49f862016-03-07 10:00:53 +0000658 },
659 [MALIDP_550] = {
660 .map = {
Mihail Atanassov02725d32017-02-01 14:48:50 +0000661 .coeffs_base = MALIDP550_COEFFS_BASE,
Liviu Dudauad49f862016-03-07 10:00:53 +0000662 .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 },
Brian Starkey6211b482016-10-03 15:08:12 +0100681 .pixel_formats = malidp550_de_formats,
682 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
Brian Starkeya2280622016-10-11 15:26:04 +0100683 .bus_align_bytes = 8,
Liviu Dudauad49f862016-03-07 10:00:53 +0000684 },
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,
Mihail Atanassov28ce6752017-02-13 15:14:05 +0000692 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
Mihail Atanassovc2e7f822017-02-13 15:09:01 +0000693 .se_calc_mclk = malidp550_se_calc_mclk,
Mihail Atanassov83d642e2017-01-23 15:24:35 +0000694 .features = 0,
Liviu Dudauad49f862016-03-07 10:00:53 +0000695 },
696 [MALIDP_650] = {
697 .map = {
Mihail Atanassov02725d32017-02-01 14:48:50 +0000698 .coeffs_base = MALIDP550_COEFFS_BASE,
Liviu Dudauad49f862016-03-07 10:00:53 +0000699 .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 },
Brian Starkey6211b482016-10-03 15:08:12 +0100719 .pixel_formats = malidp550_de_formats,
720 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
Brian Starkeya2280622016-10-11 15:26:04 +0100721 .bus_align_bytes = 16,
Liviu Dudauad49f862016-03-07 10:00:53 +0000722 },
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,
Mihail Atanassov28ce6752017-02-13 15:14:05 +0000730 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
Mihail Atanassovc2e7f822017-02-13 15:09:01 +0000731 .se_calc_mclk = malidp550_se_calc_mclk,
Mihail Atanassov83d642e2017-01-23 15:24:35 +0000732 .features = 0,
Liviu Dudauad49f862016-03-07 10:00:53 +0000733 },
734};
735
736u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
737 u8 layer_id, u32 format)
738{
739 unsigned int i;
740
Brian Starkey6211b482016-10-03 15:08:12 +0100741 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;
Liviu Dudauad49f862016-03-07 10:00:53 +0000745 }
746
747 return MALIDP_INVALID_FORMAT_ID;
748}
749
750static 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->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
760static 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 const struct malidp_irq_map *de;
766 u32 status, mask, dc_status;
767 irqreturn_t ret = IRQ_NONE;
768
769 if (!drm->dev_private)
770 return IRQ_HANDLED;
771
772 hwdev = malidp->dev;
773 de = &hwdev->map.de_irq_map;
774
775 /* first handle the config valid IRQ */
776 dc_status = malidp_hw_read(hwdev, hwdev->map.dc_base + MALIDP_REG_STATUS);
777 if (dc_status & hwdev->map.dc_irq_map.vsync_irq) {
778 /* we have a page flip event */
779 atomic_set(&malidp->config_valid, 1);
780 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
781 ret = IRQ_WAKE_THREAD;
782 }
783
784 status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
785 if (!(status & de->irq_mask))
786 return ret;
787
788 mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
789 status &= mask;
790 if (status & de->vsync_irq)
791 drm_crtc_handle_vblank(&malidp->crtc);
792
793 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
794
795 return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
796}
797
798static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
799{
800 struct drm_device *drm = arg;
801 struct malidp_drm *malidp = drm->dev_private;
802
803 wake_up(&malidp->wq);
804
805 return IRQ_HANDLED;
806}
807
808int malidp_de_irq_init(struct drm_device *drm, int irq)
809{
810 struct malidp_drm *malidp = drm->dev_private;
811 struct malidp_hw_device *hwdev = malidp->dev;
812 int ret;
813
814 /* ensure interrupts are disabled */
815 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
816 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
817 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
818 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
819
820 ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
821 malidp_de_irq_thread_handler,
822 IRQF_SHARED, "malidp-de", drm);
823 if (ret < 0) {
824 DRM_ERROR("failed to install DE IRQ handler\n");
825 return ret;
826 }
827
828 /* first enable the DC block IRQs */
829 malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
830 hwdev->map.dc_irq_map.irq_mask);
831
832 /* now enable the DE block IRQs */
833 malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
834 hwdev->map.de_irq_map.irq_mask);
835
836 return 0;
837}
838
839void malidp_de_irq_fini(struct drm_device *drm)
840{
841 struct malidp_drm *malidp = drm->dev_private;
842 struct malidp_hw_device *hwdev = malidp->dev;
843
844 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
845 hwdev->map.de_irq_map.irq_mask);
846 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
847 hwdev->map.dc_irq_map.irq_mask);
848}
849
850static irqreturn_t malidp_se_irq(int irq, void *arg)
851{
852 struct drm_device *drm = arg;
853 struct malidp_drm *malidp = drm->dev_private;
854 struct malidp_hw_device *hwdev = malidp->dev;
855 u32 status, mask;
856
857 status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
858 if (!(status & hwdev->map.se_irq_map.irq_mask))
859 return IRQ_NONE;
860
861 mask = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_MASKIRQ);
862 status = malidp_hw_read(hwdev, hwdev->map.se_base + MALIDP_REG_STATUS);
863 status &= mask;
864 /* ToDo: status decoding and firing up of VSYNC and page flip events */
865
866 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
867
868 return IRQ_HANDLED;
869}
870
871static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
872{
873 return IRQ_HANDLED;
874}
875
876int malidp_se_irq_init(struct drm_device *drm, int irq)
877{
878 struct malidp_drm *malidp = drm->dev_private;
879 struct malidp_hw_device *hwdev = malidp->dev;
880 int ret;
881
882 /* ensure interrupts are disabled */
883 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
884 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
885
886 ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
887 malidp_se_irq_thread_handler,
888 IRQF_SHARED, "malidp-se", drm);
889 if (ret < 0) {
890 DRM_ERROR("failed to install SE IRQ handler\n");
891 return ret;
892 }
893
894 malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
895 hwdev->map.se_irq_map.irq_mask);
896
897 return 0;
898}
899
900void malidp_se_irq_fini(struct drm_device *drm)
901{
902 struct malidp_drm *malidp = drm->dev_private;
903 struct malidp_hw_device *hwdev = malidp->dev;
904
905 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
906 hwdev->map.se_irq_map.irq_mask);
907}