2 * (C) COPYRIGHT 2016 ARM Limited. All rights reserved.
3 * Author: Liviu Dudau <Liviu.Dudau@arm.com>
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"
25 static const struct malidp_format_id malidp500_de_formats[] = {
26 /* fourcc, layers supporting the format, internal id */
27 { DRM_FORMAT_ARGB2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 0 },
28 { DRM_FORMAT_ABGR2101010, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 1 },
29 { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 2 },
30 { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 3 },
31 { DRM_FORMAT_XRGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 4 },
32 { DRM_FORMAT_XBGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 5 },
33 { DRM_FORMAT_RGB888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 6 },
34 { DRM_FORMAT_BGR888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 7 },
35 { DRM_FORMAT_RGBA5551, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 8 },
36 { DRM_FORMAT_ABGR1555, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 9 },
37 { DRM_FORMAT_RGB565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 10 },
38 { DRM_FORMAT_BGR565, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 11 },
39 { DRM_FORMAT_UYVY, DE_VIDEO1, 12 },
40 { DRM_FORMAT_YUYV, DE_VIDEO1, 13 },
41 { DRM_FORMAT_NV12, DE_VIDEO1, 14 },
42 { DRM_FORMAT_YUV420, DE_VIDEO1, 15 },
45 #define MALIDP_ID(__group, __format) \
46 ((((__group) & 0x7) << 3) | ((__format) & 0x7))
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) }
73 static const struct malidp_format_id malidp550_de_formats[] = {
74 MALIDP_COMMON_FORMATS,
77 static const struct malidp_layer malidp500_layers[] = {
78 { DE_VIDEO1, MALIDP500_DE_LV_BASE, MALIDP500_DE_LV_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP500_LV_YUV2RGB },
79 { DE_GRAPHICS1, MALIDP500_DE_LG1_BASE, MALIDP500_DE_LG1_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
80 { DE_GRAPHICS2, MALIDP500_DE_LG2_BASE, MALIDP500_DE_LG2_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
83 static const struct malidp_layer malidp550_layers[] = {
84 { DE_VIDEO1, MALIDP550_DE_LV1_BASE, MALIDP550_DE_LV1_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB },
85 { DE_GRAPHICS1, MALIDP550_DE_LG_BASE, MALIDP550_DE_LG_PTR_BASE, MALIDP_DE_LG_STRIDE, 0 },
86 { DE_VIDEO2, MALIDP550_DE_LV2_BASE, MALIDP550_DE_LV2_PTR_BASE, MALIDP_DE_LV_STRIDE0, MALIDP550_LV_YUV2RGB },
87 { DE_SMART, MALIDP550_DE_LS_BASE, MALIDP550_DE_LS_PTR_BASE, MALIDP550_DE_LS_R1_STRIDE, 0 },
90 #define SE_N_SCALING_COEFFS 96
91 static const u16 dp500_se_scaling_coeffs[][SE_N_SCALING_COEFFS] = {
92 [MALIDP_UPSCALING_COEFFS - 1] = {
93 0x0000, 0x0001, 0x0007, 0x0011, 0x001e, 0x002e, 0x003f, 0x0052,
94 0x0064, 0x0073, 0x007d, 0x0080, 0x007a, 0x006c, 0x0053, 0x002f,
95 0x0000, 0x3fc6, 0x3f83, 0x3f39, 0x3eea, 0x3e9b, 0x3e4f, 0x3e0a,
96 0x3dd4, 0x3db0, 0x3da2, 0x3db1, 0x3dde, 0x3e2f, 0x3ea5, 0x3f40,
97 0x0000, 0x00e5, 0x01ee, 0x0315, 0x0456, 0x05aa, 0x0709, 0x086c,
98 0x09c9, 0x0b15, 0x0c4a, 0x0d5d, 0x0e4a, 0x0f06, 0x0f91, 0x0fe5,
99 0x1000, 0x0fe5, 0x0f91, 0x0f06, 0x0e4a, 0x0d5d, 0x0c4a, 0x0b15,
100 0x09c9, 0x086c, 0x0709, 0x05aa, 0x0456, 0x0315, 0x01ee, 0x00e5,
101 0x0000, 0x3f40, 0x3ea5, 0x3e2f, 0x3dde, 0x3db1, 0x3da2, 0x3db0,
102 0x3dd4, 0x3e0a, 0x3e4f, 0x3e9b, 0x3eea, 0x3f39, 0x3f83, 0x3fc6,
103 0x0000, 0x002f, 0x0053, 0x006c, 0x007a, 0x0080, 0x007d, 0x0073,
104 0x0064, 0x0052, 0x003f, 0x002e, 0x001e, 0x0011, 0x0007, 0x0001
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
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
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
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
164 #define MALIDP_DE_DEFAULT_PREFETCH_START 5
166 static int malidp500_query_hw(struct malidp_hw_device *hwdev)
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;
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 */
180 static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
182 u32 status, count = 100;
184 malidp_hw_setbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
186 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
187 if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
190 * entering config mode can take as long as the rendering
191 * of a full frame, hence the long sleep here
193 usleep_range(1000, 10000);
196 WARN(count == 0, "timeout while entering config mode");
199 static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
201 u32 status, count = 100;
203 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
204 malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
206 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
207 if ((status & MALIDP500_DC_CONFIG_REQ) == 0)
209 usleep_range(100, 1000);
212 WARN(count == 0, "timeout while leaving config mode");
215 static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
219 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
220 if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
226 static void malidp500_set_config_valid(struct malidp_hw_device *hwdev)
228 malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
231 static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
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);
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]
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);
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);
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);
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);
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);
269 if (mode->flags & DISPLAY_FLAGS_INTERLACED)
270 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
272 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
275 static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
277 /* RGB888 or BGR888 can't be rotated */
278 if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
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;
286 return w * drm_format_plane_cpp(fmt, 0) * 8;
289 static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
295 u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
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);
306 static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
307 struct malidp_se_config *se_config,
308 struct malidp_se_config *old_config)
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;
314 if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
315 v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
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),
325 if (se_config->vcoeff != old_config->vcoeff)
326 malidp500_se_write_pp_coefftab(hwdev,
327 MALIDP_SE_V_COEFFTAB,
329 if (se_config->hcoeff != old_config->hcoeff)
330 malidp500_se_write_pp_coefftab(hwdev,
331 MALIDP_SE_H_COEFFTAB,
338 static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
339 struct malidp_se_config *se_config,
340 struct videomode *vm)
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;
351 * mclk = max(a, 1.5) * pxlclk
353 * To avoid float calculaiton, using 15 instead of 1.5 and div by
356 if (se_config->scale_enable) {
357 a = 15 * input_size / (htotal * se_config->output_h);
361 mclk = a * pxlclk / 10;
362 ret = clk_get_rate(hwdev->mclk);
364 DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
371 static int malidp550_query_hw(struct malidp_hw_device *hwdev)
373 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
374 u8 ln_size = (conf >> 4) & 0x3, rsize;
376 hwdev->min_line_size = 2;
380 hwdev->max_line_size = SZ_2K;
381 /* two banks of 64KB for rotation memory */
385 hwdev->max_line_size = SZ_4K;
386 /* two banks of 128KB for rotation memory */
390 hwdev->max_line_size = 1280;
391 /* two banks of 40KB for rotation memory */
396 hwdev->max_line_size = 0;
400 hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
404 static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
406 u32 status, count = 100;
408 malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
410 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
411 if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
414 * entering config mode can take as long as the rendering
415 * of a full frame, hence the long sleep here
417 usleep_range(1000, 10000);
420 WARN(count == 0, "timeout while entering config mode");
423 static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
425 u32 status, count = 100;
427 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
428 malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
430 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
431 if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
433 usleep_range(100, 1000);
436 WARN(count == 0, "timeout while leaving config mode");
439 static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
443 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
444 if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
450 static void malidp550_set_config_valid(struct malidp_hw_device *hwdev)
452 malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
455 static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
457 u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
459 malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
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]
466 * We need to truncate the least significant 4 bits from the default
467 * MALIDP_BGND_COLOR_x values
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);
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);
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);
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);
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);
493 if (mode->flags & DISPLAY_FLAGS_INTERLACED)
494 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
496 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
499 static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
503 /* raw RGB888 or BGR888 can't be rotated */
504 if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
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:
532 /* 16 lines at 1.5 bytes per pixel */
533 case DRM_FORMAT_NV12:
534 case DRM_FORMAT_YUV420:
541 return w * bytes_per_col;
544 static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
545 struct malidp_se_config *se_config,
546 struct malidp_se_config *old_config)
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);
553 malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
554 malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
558 static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
559 struct malidp_se_config *se_config,
560 struct videomode *vm)
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;
569 if (se_config->scale_enable) {
570 numerator = max(se_config->input_w, se_config->output_w) *
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;
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);
584 DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
591 static int malidp650_query_hw(struct malidp_hw_device *hwdev)
593 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
594 u8 ln_size = (conf >> 4) & 0x3, rsize;
596 hwdev->min_line_size = 4;
601 /* reserved values */
602 hwdev->max_line_size = 0;
605 hwdev->max_line_size = SZ_4K;
606 /* two banks of 128KB for rotation memory */
610 hwdev->max_line_size = 2560;
611 /* two banks of 80KB for rotation memory */
615 hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
619 const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
622 .coeffs_base = MALIDP500_COEFFS_BASE,
623 .se_base = MALIDP500_SE_BASE,
624 .dc_base = MALIDP500_DC_BASE,
625 .out_depth_base = MALIDP500_OUTPUT_DEPTH,
626 .features = 0, /* no CLEARIRQ register */
627 .n_layers = ARRAY_SIZE(malidp500_layers),
628 .layers = malidp500_layers,
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,
637 .irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
638 MALIDP500_SE_IRQ_GLOBAL,
642 .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
643 .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
645 .pixel_formats = malidp500_de_formats,
646 .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
647 .bus_align_bytes = 8,
649 .query_hw = malidp500_query_hw,
650 .enter_config_mode = malidp500_enter_config_mode,
651 .leave_config_mode = malidp500_leave_config_mode,
652 .in_config_mode = malidp500_in_config_mode,
653 .set_config_valid = malidp500_set_config_valid,
654 .modeset = malidp500_modeset,
655 .rotmem_required = malidp500_rotmem_required,
656 .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
657 .se_calc_mclk = malidp500_se_calc_mclk,
658 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
662 .coeffs_base = MALIDP550_COEFFS_BASE,
663 .se_base = MALIDP550_SE_BASE,
664 .dc_base = MALIDP550_DC_BASE,
665 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
666 .features = MALIDP_REGMAP_HAS_CLEARIRQ,
667 .n_layers = ARRAY_SIZE(malidp550_layers),
668 .layers = malidp550_layers,
670 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
671 MALIDP550_DE_IRQ_VSYNC,
672 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
675 .irq_mask = MALIDP550_SE_IRQ_EOW |
676 MALIDP550_SE_IRQ_AXI_ERR,
679 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
680 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
682 .pixel_formats = malidp550_de_formats,
683 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
684 .bus_align_bytes = 8,
686 .query_hw = malidp550_query_hw,
687 .enter_config_mode = malidp550_enter_config_mode,
688 .leave_config_mode = malidp550_leave_config_mode,
689 .in_config_mode = malidp550_in_config_mode,
690 .set_config_valid = malidp550_set_config_valid,
691 .modeset = malidp550_modeset,
692 .rotmem_required = malidp550_rotmem_required,
693 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
694 .se_calc_mclk = malidp550_se_calc_mclk,
699 .coeffs_base = MALIDP550_COEFFS_BASE,
700 .se_base = MALIDP550_SE_BASE,
701 .dc_base = MALIDP550_DC_BASE,
702 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
703 .features = MALIDP_REGMAP_HAS_CLEARIRQ,
704 .n_layers = ARRAY_SIZE(malidp550_layers),
705 .layers = malidp550_layers,
707 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
708 MALIDP650_DE_IRQ_DRIFT |
709 MALIDP550_DE_IRQ_VSYNC,
710 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
713 .irq_mask = MALIDP550_SE_IRQ_EOW |
714 MALIDP550_SE_IRQ_AXI_ERR,
717 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID,
718 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
720 .pixel_formats = malidp550_de_formats,
721 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
722 .bus_align_bytes = 16,
724 .query_hw = malidp650_query_hw,
725 .enter_config_mode = malidp550_enter_config_mode,
726 .leave_config_mode = malidp550_leave_config_mode,
727 .in_config_mode = malidp550_in_config_mode,
728 .set_config_valid = malidp550_set_config_valid,
729 .modeset = malidp550_modeset,
730 .rotmem_required = malidp550_rotmem_required,
731 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
732 .se_calc_mclk = malidp550_se_calc_mclk,
737 u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
738 u8 layer_id, u32 format)
742 for (i = 0; i < map->n_pixel_formats; i++) {
743 if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
744 (map->pixel_formats[i].format == format))
745 return map->pixel_formats[i].id;
748 return MALIDP_INVALID_FORMAT_ID;
751 static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
753 u32 base = malidp_get_block_base(hwdev, block);
755 if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
756 malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
758 malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
761 static irqreturn_t malidp_de_irq(int irq, void *arg)
763 struct drm_device *drm = arg;
764 struct malidp_drm *malidp = drm->dev_private;
765 struct malidp_hw_device *hwdev;
766 struct malidp_hw *hw;
767 const struct malidp_irq_map *de;
768 u32 status, mask, dc_status;
769 irqreturn_t ret = IRQ_NONE;
773 de = &hw->map.de_irq_map;
776 * if we are suspended it is likely that we were invoked because
777 * we share an interrupt line with some other driver, don't try
778 * to read the hardware registers
780 if (hwdev->pm_suspended)
783 /* first handle the config valid IRQ */
784 dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
785 if (dc_status & hw->map.dc_irq_map.vsync_irq) {
786 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
787 /* do we have a page flip event? */
788 if (malidp->event != NULL) {
789 spin_lock(&drm->event_lock);
790 drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
791 malidp->event = NULL;
792 spin_unlock(&drm->event_lock);
794 atomic_set(&malidp->config_valid, 1);
795 ret = IRQ_WAKE_THREAD;
798 status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
799 if (!(status & de->irq_mask))
802 mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
804 if ((status & de->vsync_irq) && malidp->crtc.enabled)
805 drm_crtc_handle_vblank(&malidp->crtc);
807 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
809 return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
812 static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
814 struct drm_device *drm = arg;
815 struct malidp_drm *malidp = drm->dev_private;
817 wake_up(&malidp->wq);
822 int malidp_de_irq_init(struct drm_device *drm, int irq)
824 struct malidp_drm *malidp = drm->dev_private;
825 struct malidp_hw_device *hwdev = malidp->dev;
828 /* ensure interrupts are disabled */
829 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
830 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
831 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
832 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
834 ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
835 malidp_de_irq_thread_handler,
836 IRQF_SHARED, "malidp-de", drm);
838 DRM_ERROR("failed to install DE IRQ handler\n");
842 /* first enable the DC block IRQs */
843 malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
844 hwdev->hw->map.dc_irq_map.irq_mask);
846 /* now enable the DE block IRQs */
847 malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
848 hwdev->hw->map.de_irq_map.irq_mask);
853 void malidp_de_irq_fini(struct drm_device *drm)
855 struct malidp_drm *malidp = drm->dev_private;
856 struct malidp_hw_device *hwdev = malidp->dev;
858 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
859 hwdev->hw->map.de_irq_map.irq_mask);
860 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
861 hwdev->hw->map.dc_irq_map.irq_mask);
864 static irqreturn_t malidp_se_irq(int irq, void *arg)
866 struct drm_device *drm = arg;
867 struct malidp_drm *malidp = drm->dev_private;
868 struct malidp_hw_device *hwdev = malidp->dev;
869 struct malidp_hw *hw = hwdev->hw;
870 const struct malidp_irq_map *se = &hw->map.se_irq_map;
874 * if we are suspended it is likely that we were invoked because
875 * we share an interrupt line with some other driver, don't try
876 * to read the hardware registers
878 if (hwdev->pm_suspended)
881 status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
882 if (!(status & se->irq_mask))
885 mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
886 status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
888 /* ToDo: status decoding and firing up of VSYNC and page flip events */
890 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
895 static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
900 int malidp_se_irq_init(struct drm_device *drm, int irq)
902 struct malidp_drm *malidp = drm->dev_private;
903 struct malidp_hw_device *hwdev = malidp->dev;
906 /* ensure interrupts are disabled */
907 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
908 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
910 ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
911 malidp_se_irq_thread_handler,
912 IRQF_SHARED, "malidp-se", drm);
914 DRM_ERROR("failed to install SE IRQ handler\n");
918 malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
919 hwdev->hw->map.se_irq_map.irq_mask);
924 void malidp_se_irq_fini(struct drm_device *drm)
926 struct malidp_drm *malidp = drm->dev_private;
927 struct malidp_hw_device *hwdev = malidp->dev;
929 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
930 hwdev->hw->map.se_irq_map.irq_mask);