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