vt: vt_ioctl: fix VT_DISALLOCATE freeing in-use virtual console
[linux/fpc-iii.git] / drivers / gpu / drm / arm / malidp_hw.c
blob2781e462c1ed5dd7b275ad0d9b9cccc1cc258a1f
1 /*
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
8 * of such GNU licence.
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>
17 #include <linux/io.h>
18 #include <drm/drmP.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"
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 */
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) }
82 static const struct malidp_format_id malidp550_de_formats[] = {
83 MALIDP_COMMON_FORMATS,
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 },
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 },
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
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
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
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
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
173 #define MALIDP_DE_DEFAULT_PREFETCH_START 5
175 static int malidp500_query_hw(struct malidp_hw_device *hwdev)
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;
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 */
186 return 0;
189 static void malidp500_enter_config_mode(struct malidp_hw_device *hwdev)
191 u32 status, count = 100;
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;
199 * entering config mode can take as long as the rendering
200 * of a full frame, hence the long sleep here
202 usleep_range(1000, 10000);
203 count--;
205 WARN(count == 0, "timeout while entering config mode");
208 static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
210 u32 status, count = 100;
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--;
221 WARN(count == 0, "timeout while leaving config mode");
224 static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
226 u32 status;
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;
232 return false;
235 static void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
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);
243 static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
245 u32 val = 0;
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);
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]
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);
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);
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);
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);
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);
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);
289 static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
291 /* RGB888 or BGR888 can't be rotated */
292 if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
293 return -EINVAL;
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;
300 return w * drm_format_plane_cpp(fmt, 0) * 8;
303 static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
304 u32 direction,
305 u16 addr,
306 u8 coeffs_id)
308 int i;
309 u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
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);
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)
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;
328 if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
329 v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
330 return -EINVAL;
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);
349 return 0;
352 static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
353 struct malidp_se_config *se_config,
354 struct videomode *vm)
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;
365 * mclk = max(a, 1.5) * pxlclk
367 * To avoid float calculaiton, using 15 instead of 1.5 and div by
368 * 10 to get mclk.
370 if (se_config->scale_enable) {
371 a = 15 * input_size / (htotal * se_config->output_h);
372 if (a < 15)
373 a = 15;
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;
382 return ret;
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)
390 u32 base = MALIDP500_SE_MEMWRITE_BASE;
391 u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
393 /* enable the scaling engine block */
394 malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
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;
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");
418 malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
419 MALIDP500_SE_MEMWRITE_OUT_SIZE);
421 if (rgb2yuv_coeffs) {
422 int i;
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);
430 malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
432 return 0;
435 static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
437 u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
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);
445 static int malidp550_query_hw(struct malidp_hw_device *hwdev)
447 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
448 u8 ln_size = (conf >> 4) & 0x3, rsize;
450 hwdev->min_line_size = 2;
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;
474 hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
475 return 0;
478 static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
480 u32 status, count = 100;
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;
488 * entering config mode can take as long as the rendering
489 * of a full frame, hence the long sleep here
491 usleep_range(1000, 10000);
492 count--;
494 WARN(count == 0, "timeout while entering config mode");
497 static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
499 u32 status, count = 100;
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--;
510 WARN(count == 0, "timeout while leaving config mode");
513 static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
515 u32 status;
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;
521 return false;
524 static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
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);
532 static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
534 u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
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);
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]
545 * We need to truncate the least significant 4 bits from the default
546 * MALIDP_BGND_COLOR_x values
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);
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);
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);
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);
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);
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);
578 static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
580 u32 bytes_per_col;
582 /* raw RGB888 or BGR888 can't be rotated */
583 if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
584 return -EINVAL;
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;
620 return w * bytes_per_col;
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)
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);
632 malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
633 malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
634 return 0;
637 static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
638 struct malidp_se_config *se_config,
639 struct videomode *vm)
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;
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;
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;
667 return ret;
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)
675 u32 base = MALIDP550_SE_MEMWRITE_BASE;
676 u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
678 /* enable the scaling engine block */
679 malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
681 hwdev->mw_state = MW_ONESHOT;
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");
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);
704 if (rgb2yuv_coeffs) {
705 int i;
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);
713 return 0;
716 static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
718 u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
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);
725 static int malidp650_query_hw(struct malidp_hw_device *hwdev)
727 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
728 u8 ln_size = (conf >> 4) & 0x3, rsize;
730 hwdev->min_line_size = 4;
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;
749 hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
750 return 0;
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,
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,
782 .dc_irq_map = {
783 .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
784 .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
786 .pixel_formats = malidp500_de_formats,
787 .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
788 .bus_align_bytes = 8,
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,
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,
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,
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,
832 .pixel_formats = malidp550_de_formats,
833 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
834 .bus_align_bytes = 8,
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,
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,
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,
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,
884 .pixel_formats = malidp550_de_formats,
885 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
886 .bus_align_bytes = 16,
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,
903 u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
904 u8 layer_id, u32 format)
906 unsigned int i;
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;
914 return MALIDP_INVALID_FORMAT_ID;
917 static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
919 u32 base = malidp_get_block_base(hwdev, block);
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);
927 static irqreturn_t malidp_de_irq(int irq, void *arg)
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;
937 hwdev = malidp->dev;
938 hw = hwdev->hw;
939 de = &hw->map.de_irq_map;
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
946 if (hwdev->pm_suspended)
947 return IRQ_NONE;
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);
960 atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
961 ret = IRQ_WAKE_THREAD;
964 status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
965 if (!(status & de->irq_mask))
966 return ret;
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);
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));
979 #endif
980 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
982 return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
985 static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
987 struct drm_device *drm = arg;
988 struct malidp_drm *malidp = drm->dev_private;
990 wake_up(&malidp->wq);
992 return IRQ_HANDLED;
995 void malidp_de_irq_hw_init(struct malidp_hw_device *hwdev)
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);
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);
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);
1012 int malidp_de_irq_init(struct drm_device *drm, int irq)
1014 struct malidp_drm *malidp = drm->dev_private;
1015 struct malidp_hw_device *hwdev = malidp->dev;
1016 int ret;
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);
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;
1032 malidp_de_irq_hw_init(hwdev);
1034 return 0;
1037 void malidp_de_irq_fini(struct malidp_hw_device *hwdev)
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);
1045 static irqreturn_t malidp_se_irq(int irq, void *arg)
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;
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
1059 if (hwdev->pm_suspended)
1060 return IRQ_NONE;
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;
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;
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);
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
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;
1103 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
1105 return IRQ_HANDLED;
1108 void malidp_se_irq_hw_init(struct malidp_hw_device *hwdev)
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);
1114 malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
1115 hwdev->hw->map.se_irq_map.irq_mask);
1118 static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1120 return IRQ_HANDLED;
1123 int malidp_se_irq_init(struct drm_device *drm, int irq)
1125 struct malidp_drm *malidp = drm->dev_private;
1126 struct malidp_hw_device *hwdev = malidp->dev;
1127 int ret;
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);
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;
1141 hwdev->mw_state = MW_NOT_ENABLED;
1142 malidp_se_irq_hw_init(hwdev);
1144 return 0;
1147 void malidp_se_irq_fini(struct malidp_hw_device *hwdev)
1149 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
1150 hwdev->hw->map.se_irq_map.irq_mask);