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