2 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
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
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
15 #include <linux/clk.h>
16 #include <linux/types.h>
19 #include <video/videomode.h>
20 #include <video/display_timing.h>
22 #include "malidp_drv.h"
23 #include "malidp_hw.h"
24 #include "malidp_mw.h"
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 */
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 },
54 #define MALIDP_ID(__group, __format) \
55 ((((__group) & 0x7) << 3) | ((__format) & 0x7))
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 { DRM_FORMAT_X0L2, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(6, 6)}
83 static const struct malidp_format_id malidp550_de_formats[] = {
84 MALIDP_COMMON_FORMATS,
87 static const struct malidp_format_id malidp650_de_formats[] = {
88 MALIDP_COMMON_FORMATS,
89 { DRM_FORMAT_X0L0, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 4)},
92 static const struct malidp_layer malidp500_layers[] = {
93 /* id, base address, fb pointer address base, stride offset,
94 * yuv2rgb matrix offset, mmu control register offset, rotation_features
96 { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE,
97 MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB, 0, ROTATE_ANY },
98 { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE,
99 MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
100 { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE,
101 MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
104 static const struct malidp_layer malidp550_layers[] = {
105 /* id, base address, fb pointer address base, stride offset,
106 * yuv2rgb matrix offset, mmu control register offset, rotation_features
108 { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
109 MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
110 { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
111 MALIDP_DE_LG_STRIDE, 0, 0, ROTATE_ANY },
112 { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
113 MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB, 0, ROTATE_ANY },
114 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
115 MALIDP550_DE_LS_R1_STRIDE, 0, 0, ROTATE_NONE },
118 static const struct malidp_layer malidp650_layers[] = {
119 /* id, base address, fb pointer address base, stride offset,
120 * yuv2rgb matrix offset, mmu control register offset,
123 { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE,
124 MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
125 MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
126 { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE,
127 MALIDP_DE_LG_STRIDE, 0, MALIDP650_DE_LG_MMU_CTRL,
129 { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE,
130 MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB,
131 MALIDP650_DE_LV_MMU_CTRL, ROTATE_ANY },
132 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE,
133 MALIDP550_DE_LS_R1_STRIDE, 0, MALIDP650_DE_LS_MMU_CTRL,
137 #define SE_N_SCALING_COEFFS 96
138 static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
139 [MALIDP_UPSCALING_COEFFS - 1] = {
140 0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
141 0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
142 0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
143 0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
144 0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
145 0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
146 0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
147 0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
148 0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
149 0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
150 0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
151 0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
153 [MALIDP_DOWNSCALING_1_5_COEFFS - 1] = {
154 0x0059, 0x004f, 0x0041, 0x002e, 0x0016, 0x3ffb, 0x3fd9, 0x3fb4,
155 0x3f8c, 0x3f62, 0x3f36, 0x3f09, 0x3edd, 0x3eb3, 0x3e8d, 0x3e6c,
156 0x3e52, 0x3e3f, 0x3e35, 0x3e37, 0x3e46, 0x3e61, 0x3e8c, 0x3ec5,
157 0x3f0f, 0x3f68, 0x3fd1, 0x004a, 0x00d3, 0x0169, 0x020b, 0x02b8,
158 0x036e, 0x042d, 0x04f2, 0x05b9, 0x0681, 0x0745, 0x0803, 0x08ba,
159 0x0965, 0x0a03, 0x0a91, 0x0b0d, 0x0b75, 0x0bc6, 0x0c00, 0x0c20,
160 0x0c28, 0x0c20, 0x0c00, 0x0bc6, 0x0b75, 0x0b0d, 0x0a91, 0x0a03,
161 0x0965, 0x08ba, 0x0803, 0x0745, 0x0681, 0x05b9, 0x04f2, 0x042d,
162 0x036e, 0x02b8, 0x020b, 0x0169, 0x00d3, 0x004a, 0x3fd1, 0x3f68,
163 0x3f0f, 0x3ec5, 0x3e8c, 0x3e61, 0x3e46, 0x3e37, 0x3e35, 0x3e3f,
164 0x3e52, 0x3e6c, 0x3e8d, 0x3eb3, 0x3edd, 0x3f09, 0x3f36, 0x3f62,
165 0x3f8c, 0x3fb4, 0x3fd9, 0x3ffb, 0x0016, 0x002e, 0x0041, 0x004f
167 [MALIDP_DOWNSCALING_2_COEFFS - 1] = {
168 0x3f19, 0x3f03, 0x3ef0, 0x3edf, 0x3ed0, 0x3ec5, 0x3ebd, 0x3eb9,
169 0x3eb9, 0x3ebf, 0x3eca, 0x3ed9, 0x3eef, 0x3f0a, 0x3f2c, 0x3f52,
170 0x3f7f, 0x3fb0, 0x3fe8, 0x0026, 0x006a, 0x00b4, 0x0103, 0x0158,
171 0x01b1, 0x020d, 0x026c, 0x02cd, 0x032f, 0x0392, 0x03f4, 0x0455,
172 0x04b4, 0x051e, 0x0585, 0x05eb, 0x064c, 0x06a8, 0x06fe, 0x074e,
173 0x0796, 0x07d5, 0x080c, 0x0839, 0x085c, 0x0875, 0x0882, 0x0887,
174 0x0881, 0x0887, 0x0882, 0x0875, 0x085c, 0x0839, 0x080c, 0x07d5,
175 0x0796, 0x074e, 0x06fe, 0x06a8, 0x064c, 0x05eb, 0x0585, 0x051e,
176 0x04b4, 0x0455, 0x03f4, 0x0392, 0x032f, 0x02cd, 0x026c, 0x020d,
177 0x01b1, 0x0158, 0x0103, 0x00b4, 0x006a, 0x0026, 0x3fe8, 0x3fb0,
178 0x3f7f, 0x3f52, 0x3f2c, 0x3f0a, 0x3eef, 0x3ed9, 0x3eca, 0x3ebf,
179 0x3eb9, 0x3eb9, 0x3ebd, 0x3ec5, 0x3ed0, 0x3edf, 0x3ef0, 0x3f03
181 [MALIDP_DOWNSCALING_2_75_COEFFS - 1] = {
182 0x3f51, 0x3f60, 0x3f71, 0x3f84, 0x3f98, 0x3faf, 0x3fc8, 0x3fe3,
183 0x0000, 0x001f, 0x0040, 0x0064, 0x008a, 0x00b1, 0x00da, 0x0106,
184 0x0133, 0x0160, 0x018e, 0x01bd, 0x01ec, 0x021d, 0x024e, 0x0280,
185 0x02b2, 0x02e4, 0x0317, 0x0349, 0x037c, 0x03ad, 0x03df, 0x0410,
186 0x0440, 0x0468, 0x048f, 0x04b3, 0x04d6, 0x04f8, 0x0516, 0x0533,
187 0x054e, 0x0566, 0x057c, 0x0590, 0x05a0, 0x05ae, 0x05ba, 0x05c3,
188 0x05c9, 0x05c3, 0x05ba, 0x05ae, 0x05a0, 0x0590, 0x057c, 0x0566,
189 0x054e, 0x0533, 0x0516, 0x04f8, 0x04d6, 0x04b3, 0x048f, 0x0468,
190 0x0440, 0x0410, 0x03df, 0x03ad, 0x037c, 0x0349, 0x0317, 0x02e4,
191 0x02b2, 0x0280, 0x024e, 0x021d, 0x01ec, 0x01bd, 0x018e, 0x0160,
192 0x0133, 0x0106, 0x00da, 0x00b1, 0x008a, 0x0064, 0x0040, 0x001f,
193 0x0000, 0x3fe3, 0x3fc8, 0x3faf, 0x3f98, 0x3f84, 0x3f71, 0x3f60
195 [MALIDP_DOWNSCALING_4_COEFFS - 1] = {
196 0x0094, 0x00a9, 0x00be, 0x00d4, 0x00ea, 0x0101, 0x0118, 0x012f,
197 0x0148, 0x0160, 0x017a, 0x0193, 0x01ae, 0x01c8, 0x01e4, 0x01ff,
198 0x021c, 0x0233, 0x024a, 0x0261, 0x0278, 0x028f, 0x02a6, 0x02bd,
199 0x02d4, 0x02eb, 0x0302, 0x0319, 0x032f, 0x0346, 0x035d, 0x0374,
200 0x038a, 0x0397, 0x03a3, 0x03af, 0x03bb, 0x03c6, 0x03d1, 0x03db,
201 0x03e4, 0x03ed, 0x03f6, 0x03fe, 0x0406, 0x040d, 0x0414, 0x041a,
202 0x0420, 0x041a, 0x0414, 0x040d, 0x0406, 0x03fe, 0x03f6, 0x03ed,
203 0x03e4, 0x03db, 0x03d1, 0x03c6, 0x03bb, 0x03af, 0x03a3, 0x0397,
204 0x038a, 0x0374, 0x035d, 0x0346, 0x032f, 0x0319, 0x0302, 0x02eb,
205 0x02d4, 0x02bd, 0x02a6, 0x028f, 0x0278, 0x0261, 0x024a, 0x0233,
206 0x021c, 0x01ff, 0x01e4, 0x01c8, 0x01ae, 0x0193, 0x017a, 0x0160,
207 0x0148, 0x012f, 0x0118, 0x0101, 0x00ea, 0x00d4, 0x00be, 0x00a9
211 #define MALIDP_DE_DEFAULT_PREFETCH_START 5
213 static int malidp500_query_hw(struct malidp_hw_device *hwdev)
215 u32 conf = malidp_hw_read(hwdev, MALIDP500_CONFIG_ID);
216 /* bit 4 of the CONFIG_ID register holds the line size multiplier */
217 u8 ln_size_mult = conf & 0x10 ? 2 : 1;
219 hwdev->min_line_size = 2;
220 hwdev->max_line_size = SZ_2K * ln_size_mult;
221 hwdev->rotation_memory[0] = SZ_1K * 64 * ln_size_mult;
222 hwdev->rotation_memory[1] = 0; /* no second rotation memory bank */
227 static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
229 u32 status, count = 100;
231 malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
233 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
234 if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
237 * entering config mode can take as long as the rendering
238 * of a full frame, hence the long sleep here
240 usleep_range(1000, 10000);
243 WARN(count == 0, "timeout while entering config mode");
246 static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
248 u32 status, count = 100;
250 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
251 malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
253 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
254 if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
256 usleep_range(100, 1000);
259 WARN(count == 0, "timeout while leaving config mode");
262 static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
266 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
267 if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
273 static void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
276 malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
278 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
281 static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
285 malidp_hw_write(hwdev, hwdev->output_color_depth,
286 hwdev->hw->map.out_depth_base);
287 malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
288 if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
289 val |= MALIDP500_HSYNCPOL;
290 if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
291 val |= MALIDP500_VSYNCPOL;
292 val |= MALIDP_DE_DEFAULT_PREFETCH_START;
293 malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
296 * Mali-DP500 encodes the background color like this:
297 * - red @ MALIDP500_BGND_COLOR[12:0]
298 * - green @ MALIDP500_BGND_COLOR[27:16]
299 * - blue @ (MALIDP500_BGND_COLOR + 4)[12:0]
301 val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
302 (MALIDP_BGND_COLOR_R & 0xfff);
303 malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
304 malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
306 val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
307 MALIDP_DE_H_BACKPORCH(mode->hback_porch);
308 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
310 val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
311 MALIDP_DE_V_BACKPORCH(mode->vback_porch);
312 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
314 val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
315 MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
316 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
318 val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
319 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
321 if (mode->flags & DISPLAY_FLAGS_INTERLACED)
322 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
324 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
327 static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
330 * Each layer needs enough rotation memory to fit 8 lines
331 * worth of pixel data. Required size is then:
332 * size = rotated_width * (bpp / 8) * 8;
334 return w * drm_format_plane_cpp(fmt, 0) * 8;
337 static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
343 u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
345 malidp_hw_write(hwdev,
346 direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
347 scaling_control + MALIDP_SE_COEFFTAB_ADDR);
348 for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
349 malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
350 dp500_se_scaling_coeffs[coeffs_id][i]),
351 scaling_control + MALIDP_SE_COEFFTAB_DATA);
354 static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
355 struct malidp_se_config *se_config,
356 struct malidp_se_config *old_config)
358 /* Get array indices into dp500_se_scaling_coeffs. */
359 u8 h = (u8)se_config->hcoeff - 1;
360 u8 v = (u8)se_config->vcoeff - 1;
362 if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
363 v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
366 if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
367 se_config->vcoeff != old_config->vcoeff)) {
368 malidp500_se_write_pp_coefftab(hwdev,
369 (MALIDP_SE_V_COEFFTAB |
370 MALIDP_SE_H_COEFFTAB),
373 if (se_config->vcoeff != old_config->vcoeff)
374 malidp500_se_write_pp_coefftab(hwdev,
375 MALIDP_SE_V_COEFFTAB,
377 if (se_config->hcoeff != old_config->hcoeff)
378 malidp500_se_write_pp_coefftab(hwdev,
379 MALIDP_SE_H_COEFFTAB,
386 static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
387 struct malidp_se_config *se_config,
388 struct videomode *vm)
391 unsigned long pxlclk = vm->pixelclock; /* Hz */
392 unsigned long htotal = vm->hactive + vm->hfront_porch +
393 vm->hback_porch + vm->hsync_len;
394 unsigned long input_size = se_config->input_w * se_config->input_h;
395 unsigned long a = 10;
399 * mclk = max(a, 1.5) * pxlclk
401 * To avoid float calculaiton, using 15 instead of 1.5 and div by
404 if (se_config->scale_enable) {
405 a = 15 * input_size / (htotal * se_config->output_h);
409 mclk = a * pxlclk / 10;
410 ret = clk_get_rate(hwdev->mclk);
412 DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
419 static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
420 dma_addr_t *addrs, s32 *pitches,
421 int num_planes, u16 w, u16 h, u32 fmt_id,
422 const s16 *rgb2yuv_coeffs)
424 u32 base = MALIDP500_SE_MEMWRITE_BASE;
425 u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
427 /* enable the scaling engine block */
428 malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
430 /* restart the writeback if already enabled */
431 if (hwdev->mw_state != MW_NOT_ENABLED)
432 hwdev->mw_state = MW_RESTART;
434 hwdev->mw_state = MW_START;
436 malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
437 switch (num_planes) {
439 malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
440 malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
441 malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
444 malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
445 malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
446 malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
449 WARN(1, "Invalid number of planes");
452 malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
453 MALIDP500_SE_MEMWRITE_OUT_SIZE);
455 if (rgb2yuv_coeffs) {
458 for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
459 malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
460 MALIDP500_SE_RGB_YUV_COEFFS + i * 4);
464 malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
469 static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
471 u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
473 if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART)
474 hwdev->mw_state = MW_STOP;
475 malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
476 malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
479 static int malidp550_query_hw(struct malidp_hw_device *hwdev)
481 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
482 u8 ln_size = (conf >> 4) & 0x3, rsize;
484 hwdev->min_line_size = 2;
488 hwdev->max_line_size = SZ_2K;
489 /* two banks of 64KB for rotation memory */
493 hwdev->max_line_size = SZ_4K;
494 /* two banks of 128KB for rotation memory */
498 hwdev->max_line_size = 1280;
499 /* two banks of 40KB for rotation memory */
504 hwdev->max_line_size = 0;
508 hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
512 static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
514 u32 status, count = 100;
516 malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
518 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
519 if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
522 * entering config mode can take as long as the rendering
523 * of a full frame, hence the long sleep here
525 usleep_range(1000, 10000);
528 WARN(count == 0, "timeout while entering config mode");
531 static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
533 u32 status, count = 100;
535 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
536 malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
538 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
539 if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
541 usleep_range(100, 1000);
544 WARN(count == 0, "timeout while leaving config mode");
547 static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
551 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
552 if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
558 static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
561 malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
563 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
566 static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
568 u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
570 malidp_hw_write(hwdev, hwdev->output_color_depth,
571 hwdev->hw->map.out_depth_base);
572 malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
574 * Mali-DP550 and Mali-DP650 encode the background color like this:
575 * - red @ MALIDP550_DE_BGND_COLOR[23:16]
576 * - green @ MALIDP550_DE_BGND_COLOR[15:8]
577 * - blue @ MALIDP550_DE_BGND_COLOR[7:0]
579 * We need to truncate the least significant 4 bits from the default
580 * MALIDP_BGND_COLOR_x values
582 val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
583 (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
584 ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
585 malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
587 val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
588 MALIDP_DE_H_BACKPORCH(mode->hback_porch);
589 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
591 val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
592 MALIDP_DE_V_BACKPORCH(mode->vback_porch);
593 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
595 val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
596 MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
597 if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
598 val |= MALIDP550_HSYNCPOL;
599 if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
600 val |= MALIDP550_VSYNCPOL;
601 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
603 val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
604 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
606 if (mode->flags & DISPLAY_FLAGS_INTERLACED)
607 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
609 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
612 static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
617 /* 8 lines at 4 bytes per pixel */
618 case DRM_FORMAT_ARGB2101010:
619 case DRM_FORMAT_ABGR2101010:
620 case DRM_FORMAT_RGBA1010102:
621 case DRM_FORMAT_BGRA1010102:
622 case DRM_FORMAT_ARGB8888:
623 case DRM_FORMAT_ABGR8888:
624 case DRM_FORMAT_RGBA8888:
625 case DRM_FORMAT_BGRA8888:
626 case DRM_FORMAT_XRGB8888:
627 case DRM_FORMAT_XBGR8888:
628 case DRM_FORMAT_RGBX8888:
629 case DRM_FORMAT_BGRX8888:
630 case DRM_FORMAT_RGB888:
631 case DRM_FORMAT_BGR888:
632 /* 16 lines at 2 bytes per pixel */
633 case DRM_FORMAT_RGBA5551:
634 case DRM_FORMAT_ABGR1555:
635 case DRM_FORMAT_RGB565:
636 case DRM_FORMAT_BGR565:
637 case DRM_FORMAT_UYVY:
638 case DRM_FORMAT_YUYV:
639 case DRM_FORMAT_X0L0:
640 case DRM_FORMAT_X0L2:
643 /* 16 lines at 1.5 bytes per pixel */
644 case DRM_FORMAT_NV12:
645 case DRM_FORMAT_YUV420:
652 return w * bytes_per_col;
655 static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
656 struct malidp_se_config *se_config,
657 struct malidp_se_config *old_config)
659 u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
660 MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
661 u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
662 MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
664 malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
665 malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
669 static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
670 struct malidp_se_config *se_config,
671 struct videomode *vm)
674 unsigned long pxlclk = vm->pixelclock;
675 unsigned long htotal = vm->hactive + vm->hfront_porch +
676 vm->hback_porch + vm->hsync_len;
677 unsigned long numerator = 1, denominator = 1;
680 if (se_config->scale_enable) {
681 numerator = max(se_config->input_w, se_config->output_w) *
683 numerator += se_config->output_w *
684 (se_config->output_h -
685 min(se_config->input_h, se_config->output_h));
686 denominator = (htotal - 2) * se_config->output_h;
689 /* mclk can't be slower than pxlclk. */
690 if (numerator < denominator)
691 numerator = denominator = 1;
692 mclk = (pxlclk * numerator) / denominator;
693 ret = clk_get_rate(hwdev->mclk);
695 DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
702 static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
703 dma_addr_t *addrs, s32 *pitches,
704 int num_planes, u16 w, u16 h, u32 fmt_id,
705 const s16 *rgb2yuv_coeffs)
707 u32 base = MALIDP550_SE_MEMWRITE_BASE;
708 u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
710 /* enable the scaling engine block */
711 malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
713 hwdev->mw_state = MW_ONESHOT;
715 malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
716 switch (num_planes) {
718 malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
719 malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
720 malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
723 malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
724 malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
725 malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
728 WARN(1, "Invalid number of planes");
731 malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
732 MALIDP550_SE_MEMWRITE_OUT_SIZE);
733 malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
734 MALIDP550_SE_CONTROL);
736 if (rgb2yuv_coeffs) {
739 for (i = 0; i < MALIDP_COLORADJ_NUM_COEFFS; i++) {
740 malidp_hw_write(hwdev, rgb2yuv_coeffs[i],
741 MALIDP550_SE_RGB_YUV_COEFFS + i * 4);
748 static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
750 u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
752 malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
753 MALIDP550_SE_CONTROL);
754 malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
757 static int malidp650_query_hw(struct malidp_hw_device *hwdev)
759 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
760 u8 ln_size = (conf >> 4) & 0x3, rsize;
762 hwdev->min_line_size = 4;
767 /* reserved values */
768 hwdev->max_line_size = 0;
771 hwdev->max_line_size = SZ_4K;
772 /* two banks of 128KB for rotation memory */
776 hwdev->max_line_size = 2560;
777 /* two banks of 80KB for rotation memory */
781 hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
785 const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
788 .coeffs_base = MALIDP500_COEFFS_BASE,
789 .se_base = MALIDP500_SE_BASE,
790 .dc_base = MALIDP500_DC_BASE,
791 .out_depth_base = MALIDP500_OUTPUT_DEPTH,
792 .features = 0, /* no CLEARIRQ register */
793 .n_layers = ARRAY_SIZE(malidp500_layers),
794 .layers = malidp500_layers,
796 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
797 MALIDP500_DE_IRQ_AXI_ERR |
798 MALIDP500_DE_IRQ_VSYNC |
799 MALIDP500_DE_IRQ_GLOBAL,
800 .vsync_irq = MALIDP500_DE_IRQ_VSYNC,
801 .err_mask = MALIDP_DE_IRQ_UNDERRUN |
802 MALIDP500_DE_IRQ_AXI_ERR |
803 MALIDP500_DE_IRQ_SATURATION,
806 .irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
807 MALIDP500_SE_IRQ_CONF_VALID |
808 MALIDP500_SE_IRQ_GLOBAL,
809 .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID,
810 .err_mask = MALIDP500_SE_IRQ_INIT_BUSY |
811 MALIDP500_SE_IRQ_AXI_ERROR |
812 MALIDP500_SE_IRQ_OVERRUN,
815 .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
816 .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
818 .pixel_formats = malidp500_de_formats,
819 .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
820 .bus_align_bytes = 8,
822 .query_hw = malidp500_query_hw,
823 .enter_config_mode = malidp500_enter_config_mode,
824 .leave_config_mode = malidp500_leave_config_mode,
825 .in_config_mode = malidp500_in_config_mode,
826 .set_config_valid = malidp500_set_config_valid,
827 .modeset = malidp500_modeset,
828 .rotmem_required = malidp500_rotmem_required,
829 .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
830 .se_calc_mclk = malidp500_se_calc_mclk,
831 .enable_memwrite = malidp500_enable_memwrite,
832 .disable_memwrite = malidp500_disable_memwrite,
833 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
837 .coeffs_base = MALIDP550_COEFFS_BASE,
838 .se_base = MALIDP550_SE_BASE,
839 .dc_base = MALIDP550_DC_BASE,
840 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
841 .features = MALIDP_REGMAP_HAS_CLEARIRQ,
842 .n_layers = ARRAY_SIZE(malidp550_layers),
843 .layers = malidp550_layers,
845 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
846 MALIDP550_DE_IRQ_VSYNC,
847 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
848 .err_mask = MALIDP_DE_IRQ_UNDERRUN |
849 MALIDP550_DE_IRQ_SATURATION |
850 MALIDP550_DE_IRQ_AXI_ERR,
853 .irq_mask = MALIDP550_SE_IRQ_EOW,
854 .vsync_irq = MALIDP550_SE_IRQ_EOW,
855 .err_mask = MALIDP550_SE_IRQ_AXI_ERR |
856 MALIDP550_SE_IRQ_OVR |
857 MALIDP550_SE_IRQ_IBSY,
860 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
862 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
864 .pixel_formats = malidp550_de_formats,
865 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
866 .bus_align_bytes = 8,
868 .query_hw = malidp550_query_hw,
869 .enter_config_mode = malidp550_enter_config_mode,
870 .leave_config_mode = malidp550_leave_config_mode,
871 .in_config_mode = malidp550_in_config_mode,
872 .set_config_valid = malidp550_set_config_valid,
873 .modeset = malidp550_modeset,
874 .rotmem_required = malidp550_rotmem_required,
875 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
876 .se_calc_mclk = malidp550_se_calc_mclk,
877 .enable_memwrite = malidp550_enable_memwrite,
878 .disable_memwrite = malidp550_disable_memwrite,
883 .coeffs_base = MALIDP550_COEFFS_BASE,
884 .se_base = MALIDP550_SE_BASE,
885 .dc_base = MALIDP550_DC_BASE,
886 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
887 .features = MALIDP_REGMAP_HAS_CLEARIRQ,
888 .n_layers = ARRAY_SIZE(malidp650_layers),
889 .layers = malidp650_layers,
891 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
892 MALIDP650_DE_IRQ_DRIFT |
893 MALIDP550_DE_IRQ_VSYNC,
894 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
895 .err_mask = MALIDP_DE_IRQ_UNDERRUN |
896 MALIDP650_DE_IRQ_DRIFT |
897 MALIDP550_DE_IRQ_SATURATION |
898 MALIDP550_DE_IRQ_AXI_ERR |
899 MALIDP650_DE_IRQ_ACEV1 |
900 MALIDP650_DE_IRQ_ACEV2 |
901 MALIDP650_DE_IRQ_ACEG |
902 MALIDP650_DE_IRQ_AXIEP,
905 .irq_mask = MALIDP550_SE_IRQ_EOW,
906 .vsync_irq = MALIDP550_SE_IRQ_EOW,
907 .err_mask = MALIDP550_SE_IRQ_AXI_ERR |
908 MALIDP550_SE_IRQ_OVR |
909 MALIDP550_SE_IRQ_IBSY,
912 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
914 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
916 .pixel_formats = malidp650_de_formats,
917 .n_pixel_formats = ARRAY_SIZE(malidp650_de_formats),
918 .bus_align_bytes = 16,
920 .query_hw = malidp650_query_hw,
921 .enter_config_mode = malidp550_enter_config_mode,
922 .leave_config_mode = malidp550_leave_config_mode,
923 .in_config_mode = malidp550_in_config_mode,
924 .set_config_valid = malidp550_set_config_valid,
925 .modeset = malidp550_modeset,
926 .rotmem_required = malidp550_rotmem_required,
927 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
928 .se_calc_mclk = malidp550_se_calc_mclk,
929 .enable_memwrite = malidp550_enable_memwrite,
930 .disable_memwrite = malidp550_disable_memwrite,
935 u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
936 u8 layer_id, u32 format)
940 for (i = 0; i < map->n_pixel_formats; i++) {
941 if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
942 (map->pixel_formats[i].format == format))
943 return map->pixel_formats[i].id;
946 return MALIDP_INVALID_FORMAT_ID;
949 static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
951 u32 base = malidp_get_block_base(hwdev, block);
953 if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
954 malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
956 malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
959 static irqreturn_t malidp_de_irq(int irq, void *arg)
961 struct drm_device *drm = arg;
962 struct malidp_drm *malidp = drm->dev_private;
963 struct malidp_hw_device *hwdev;
964 struct malidp_hw *hw;
965 const struct malidp_irq_map *de;
966 u32 status, mask, dc_status;
967 irqreturn_t ret = IRQ_NONE;
971 de = &hw->map.de_irq_map;
974 * if we are suspended it is likely that we were invoked because
975 * we share an interrupt line with some other driver, don't try
976 * to read the hardware registers
978 if (hwdev->pm_suspended)
981 /* first handle the config valid IRQ */
982 dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
983 if (dc_status & hw->map.dc_irq_map.vsync_irq) {
984 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
985 /* do we have a page flip event? */
986 if (malidp->event != NULL) {
987 spin_lock(&drm->event_lock);
988 drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
989 malidp->event = NULL;
990 spin_unlock(&drm->event_lock);
992 atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
993 ret = IRQ_WAKE_THREAD;
996 status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
997 if (!(status & de->irq_mask))
1000 mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
1001 /* keep the status of the enabled interrupts, plus the error bits */
1002 status &= (mask | de->err_mask);
1003 if ((status & de->vsync_irq) && malidp->crtc.enabled)
1004 drm_crtc_handle_vblank(&malidp->crtc);
1006 #ifdef CONFIG_DEBUG_FS
1007 if (status & de->err_mask) {
1008 malidp_error(malidp, &malidp->de_errors, status,
1009 drm_crtc_vblank_count(&malidp->crtc));
1012 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
1014 return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
1017 static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
1019 struct drm_device *drm = arg;
1020 struct malidp_drm *malidp = drm->dev_private;
1022 wake_up(&malidp->wq);
1027 void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev)
1029 /* ensure interrupts are disabled */
1030 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1031 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1032 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1033 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1035 /* first enable the DC block IRQs */
1036 malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
1037 hwdev->hw->map.dc_irq_map.irq_mask);
1039 /* now enable the DE block IRQs */
1040 malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
1041 hwdev->hw->map.de_irq_map.irq_mask);
1044 int malidp_de_irq_init(struct drm_device *drm, int irq)
1046 struct malidp_drm *malidp = drm->dev_private;
1047 struct malidp_hw_device *hwdev = malidp->dev;
1050 /* ensure interrupts are disabled */
1051 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1052 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
1053 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1054 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
1056 ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
1057 malidp_de_irq_thread_handler,
1058 IRQF_SHARED, "malidp-de", drm);
1060 DRM_ERROR("failed to install DE IRQ handler\n");
1064 malidp_de_irq_hw_init(hwdev);
1069 void malidp_de_irq_fini(struct malidp_hw_device *hwdev)
1071 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
1072 hwdev->hw->map.de_irq_map.irq_mask);
1073 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
1074 hwdev->hw->map.dc_irq_map.irq_mask);
1077 static irqreturn_t malidp_se_irq(int irq, void *arg)
1079 struct drm_device *drm = arg;
1080 struct malidp_drm *malidp = drm->dev_private;
1081 struct malidp_hw_device *hwdev = malidp->dev;
1082 struct malidp_hw *hw = hwdev->hw;
1083 const struct malidp_irq_map *se = &hw->map.se_irq_map;
1087 * if we are suspended it is likely that we were invoked because
1088 * we share an interrupt line with some other driver, don't try
1089 * to read the hardware registers
1091 if (hwdev->pm_suspended)
1094 status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
1095 if (!(status & (se->irq_mask | se->err_mask)))
1098 #ifdef CONFIG_DEBUG_FS
1099 if (status & se->err_mask)
1100 malidp_error(malidp, &malidp->se_errors, status,
1101 drm_crtc_vblank_count(&malidp->crtc));
1103 mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
1106 if (status & se->vsync_irq) {
1107 switch (hwdev->mw_state) {
1109 drm_writeback_signal_completion(&malidp->mw_connector, 0);
1112 drm_writeback_signal_completion(&malidp->mw_connector, 0);
1113 /* disable writeback after stop */
1114 hwdev->mw_state = MW_NOT_ENABLED;
1117 drm_writeback_signal_completion(&malidp->mw_connector, 0);
1118 /* fall through to a new start */
1120 /* writeback started, need to emulate one-shot mode */
1121 hw->disable_memwrite(hwdev);
1123 * only set config_valid HW bit if there is no other update
1124 * in progress or if we raced ahead of the DE IRQ handler
1125 * and config_valid flag will not be update until later
1127 status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
1128 if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) ||
1129 (status & hw->map.dc_irq_map.vsync_irq))
1130 hw->set_config_valid(hwdev, 1);
1135 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
1140 void malidp_se_irq_hw_init(struct malidp_hw_device *hwdev)
1142 /* ensure interrupts are disabled */
1143 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1144 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1146 malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
1147 hwdev->hw->map.se_irq_map.irq_mask);
1150 static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1155 int malidp_se_irq_init(struct drm_device *drm, int irq)
1157 struct malidp_drm *malidp = drm->dev_private;
1158 struct malidp_hw_device *hwdev = malidp->dev;
1161 /* ensure interrupts are disabled */
1162 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1163 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1165 ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
1166 malidp_se_irq_thread_handler,
1167 IRQF_SHARED, "malidp-se", drm);
1169 DRM_ERROR("failed to install SE IRQ handler\n");
1173 hwdev->mw_state = MW_NOT_ENABLED;
1174 malidp_se_irq_hw_init(hwdev);
1179 void malidp_se_irq_fini(struct malidp_hw_device *hwdev)
1181 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
1182 hwdev->hw->map.se_irq_map.irq_mask);