drm/arm/malidp: Modified the prototype of malidp irq de-initializers
[linux-2.6-block.git] / drivers / gpu / drm / arm / malidp_hw.c
CommitLineData
ad49f860
LD
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
c2e7f82d 15#include <linux/clk.h>
ad49f860
LD
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"
8cbc5caf 24#include "malidp_mw.h"
ad49f860 25
1cb3cbe7
LD
26enum {
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 */
0735cfdf
LD
30 MW_RESTART, /* SE will start another writeback after this one */
31 MW_STOP, /* SE needs to stop after this writeback */
1cb3cbe7
LD
32};
33
6211b486 34static const struct malidp_format_id malidp500_de_formats[] = {
ad49f860 35 /* fourcc, layers supporting the format, internal id */
09368e32
LD
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 },
ad49f860
LD
38 { DRM_FORMAT_ARGB8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 2 },
39 { DRM_FORMAT_ABGR8888, DE_VIDEO1 | DE_GRAPHICS1 | DE_GRAPHICS2, 3 },
09368e32
LD
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 },
ad49f860
LD
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 },
09368e32 50 { DRM_FORMAT_NV12, DE_VIDEO1 | SE_MEMWRITE, 14 },
ad49f860
LD
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 */ \
a67bbbe2
BS
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) }, \
ad49f860
LD
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) }, \
a67bbbe2
BS
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) }, \
ad49f860
LD
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) }, \
a67bbbe2 79 { DRM_FORMAT_NV12, DE_VIDEO1 | DE_VIDEO2 | SE_MEMWRITE, MALIDP_ID(5, 6) }, \
ad49f860
LD
80 { DRM_FORMAT_YUV420, DE_VIDEO1 | DE_VIDEO2, MALIDP_ID(5, 7) }
81
6211b486 82static const struct malidp_format_id malidp550_de_formats[] = {
ad49f860
LD
83 MALIDP_COMMON_FORMATS,
84};
85
86static const struct malidp_layer malidp500_layers[] = {
6e810eb5
MA
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 },
ad49f860
LD
90};
91
92static const struct malidp_layer malidp550_layers[] = {
6e810eb5
MA
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 },
ad49f860
LD
97};
98
28ce675b
MA
99#define SE_N_SCALING_COEFFS 96
100static 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
ad49f860
LD
173#define MALIDP_DE_DEFAULT_PREFETCH_START 5
174
175static 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
189static 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) {
a6993b21 195 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
ad49f860
LD
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
208static void malidp500_leave_config_mode(struct malidp_hw_device *hwdev)
209{
210 u32 status, count = 100;
211
e64053f0 212 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP500_CONFIG_VALID);
ad49f860
LD
213 malidp_hw_clearbits(hwdev, MALIDP500_DC_CONFIG_REQ, MALIDP500_DC_CONTROL);
214 while (count) {
a6993b21 215 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
ad49f860
LD
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
224static bool malidp500_in_config_mode(struct malidp_hw_device *hwdev)
225{
226 u32 status;
227
a6993b21 228 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
ad49f860
LD
229 if ((status & MALIDP500_DC_CONFIG_REQ) == MALIDP500_DC_CONFIG_REQ)
230 return true;
231
232 return false;
233}
234
0735cfdf 235static void malidp500_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
ad49f860 236{
0735cfdf
LD
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);
ad49f860
LD
241}
242
243static void malidp500_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
244{
245 u32 val = 0;
246
247 malidp_hw_clearbits(hwdev, MALIDP500_DC_CLEAR_MASK, MALIDP500_DC_CONTROL);
248 if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
249 val |= MALIDP500_HSYNCPOL;
250 if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
251 val |= MALIDP500_VSYNCPOL;
252 val |= MALIDP_DE_DEFAULT_PREFETCH_START;
253 malidp_hw_setbits(hwdev, val, MALIDP500_DC_CONTROL);
254
255 /*
256 * Mali-DP500 encodes the background color like this:
257 * - red @ MALIDP500_BGND_COLOR[12:0]
258 * - green @ MALIDP500_BGND_COLOR[27:16]
259 * - blue @ (MALIDP500_BGND_COLOR + 4)[12:0]
260 */
261 val = ((MALIDP_BGND_COLOR_G & 0xfff) << 16) |
262 (MALIDP_BGND_COLOR_R & 0xfff);
263 malidp_hw_write(hwdev, val, MALIDP500_BGND_COLOR);
264 malidp_hw_write(hwdev, MALIDP_BGND_COLOR_B, MALIDP500_BGND_COLOR + 4);
265
266 val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
267 MALIDP_DE_H_BACKPORCH(mode->hback_porch);
268 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
269
270 val = MALIDP500_DE_V_FRONTPORCH(mode->vfront_porch) |
271 MALIDP_DE_V_BACKPORCH(mode->vback_porch);
272 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
273
274 val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
275 MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
276 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
277
278 val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
279 malidp_hw_write(hwdev, val, MALIDP500_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
280
281 if (mode->flags & DISPLAY_FLAGS_INTERLACED)
282 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
283 else
284 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
285}
286
287static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
288{
ad49f860
LD
289 /* RGB888 or BGR888 can't be rotated */
290 if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
291 return -EINVAL;
292
293 /*
294 * Each layer needs enough rotation memory to fit 8 lines
295 * worth of pixel data. Required size is then:
296 * size = rotated_width * (bpp / 8) * 8;
297 */
7ccf281f 298 return w * drm_format_plane_cpp(fmt, 0) * 8;
ad49f860
LD
299}
300
28ce675b
MA
301static void malidp500_se_write_pp_coefftab(struct malidp_hw_device *hwdev,
302 u32 direction,
303 u16 addr,
304 u8 coeffs_id)
305{
306 int i;
307 u16 scaling_control = MALIDP500_SE_CONTROL + MALIDP_SE_SCALING_CONTROL;
308
309 malidp_hw_write(hwdev,
310 direction | (addr & MALIDP_SE_COEFFTAB_ADDR_MASK),
311 scaling_control + MALIDP_SE_COEFFTAB_ADDR);
312 for (i = 0; i < ARRAY_SIZE(dp500_se_scaling_coeffs); ++i)
313 malidp_hw_write(hwdev, MALIDP_SE_SET_COEFFTAB_DATA(
314 dp500_se_scaling_coeffs[coeffs_id][i]),
315 scaling_control + MALIDP_SE_COEFFTAB_DATA);
316}
317
318static int malidp500_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
319 struct malidp_se_config *se_config,
320 struct malidp_se_config *old_config)
321{
322 /* Get array indices into dp500_se_scaling_coeffs. */
323 u8 h = (u8)se_config->hcoeff - 1;
324 u8 v = (u8)se_config->vcoeff - 1;
325
326 if (WARN_ON(h >= ARRAY_SIZE(dp500_se_scaling_coeffs) ||
327 v >= ARRAY_SIZE(dp500_se_scaling_coeffs)))
328 return -EINVAL;
329
330 if ((h == v) && (se_config->hcoeff != old_config->hcoeff ||
331 se_config->vcoeff != old_config->vcoeff)) {
332 malidp500_se_write_pp_coefftab(hwdev,
333 (MALIDP_SE_V_COEFFTAB |
334 MALIDP_SE_H_COEFFTAB),
335 0, v);
336 } else {
337 if (se_config->vcoeff != old_config->vcoeff)
338 malidp500_se_write_pp_coefftab(hwdev,
339 MALIDP_SE_V_COEFFTAB,
340 0, v);
341 if (se_config->hcoeff != old_config->hcoeff)
342 malidp500_se_write_pp_coefftab(hwdev,
343 MALIDP_SE_H_COEFFTAB,
344 0, h);
345 }
346
347 return 0;
348}
349
c2e7f82d
MA
350static long malidp500_se_calc_mclk(struct malidp_hw_device *hwdev,
351 struct malidp_se_config *se_config,
352 struct videomode *vm)
353{
354 unsigned long mclk;
355 unsigned long pxlclk = vm->pixelclock; /* Hz */
356 unsigned long htotal = vm->hactive + vm->hfront_porch +
357 vm->hback_porch + vm->hsync_len;
358 unsigned long input_size = se_config->input_w * se_config->input_h;
359 unsigned long a = 10;
360 long ret;
361
362 /*
363 * mclk = max(a, 1.5) * pxlclk
364 *
365 * To avoid float calculaiton, using 15 instead of 1.5 and div by
366 * 10 to get mclk.
367 */
368 if (se_config->scale_enable) {
369 a = 15 * input_size / (htotal * se_config->output_h);
370 if (a < 15)
371 a = 15;
372 }
373 mclk = a * pxlclk / 10;
374 ret = clk_get_rate(hwdev->mclk);
375 if (ret < mclk) {
376 DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
377 mclk / 1000);
378 return -EINVAL;
379 }
380 return ret;
381}
382
1cb3cbe7
LD
383static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
384 dma_addr_t *addrs, s32 *pitches,
385 int num_planes, u16 w, u16 h, u32 fmt_id)
386{
387 u32 base = MALIDP500_SE_MEMWRITE_BASE;
388 u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
389
390 /* enable the scaling engine block */
391 malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
392
0735cfdf
LD
393 /* restart the writeback if already enabled */
394 if (hwdev->mw_state != MW_NOT_ENABLED)
395 hwdev->mw_state = MW_RESTART;
396 else
397 hwdev->mw_state = MW_START;
1cb3cbe7
LD
398
399 malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
400 switch (num_planes) {
401 case 2:
402 malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
403 malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
404 malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
405 /* fall through */
406 case 1:
407 malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
408 malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
409 malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
410 break;
411 default:
412 WARN(1, "Invalid number of planes");
413 }
414
415 malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
416 MALIDP500_SE_MEMWRITE_OUT_SIZE);
417 malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
418
419 return 0;
420}
421
422static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
423{
424 u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
425
0735cfdf 426 if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART)
1cb3cbe7
LD
427 hwdev->mw_state = MW_STOP;
428 malidp_hw_clearbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
429 malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
430}
431
ad49f860
LD
432static int malidp550_query_hw(struct malidp_hw_device *hwdev)
433{
434 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
435 u8 ln_size = (conf >> 4) & 0x3, rsize;
436
437 hwdev->min_line_size = 2;
438
439 switch (ln_size) {
440 case 0:
441 hwdev->max_line_size = SZ_2K;
442 /* two banks of 64KB for rotation memory */
443 rsize = 64;
444 break;
445 case 1:
446 hwdev->max_line_size = SZ_4K;
447 /* two banks of 128KB for rotation memory */
448 rsize = 128;
449 break;
450 case 2:
451 hwdev->max_line_size = 1280;
452 /* two banks of 40KB for rotation memory */
453 rsize = 40;
454 break;
455 case 3:
456 /* reserved value */
457 hwdev->max_line_size = 0;
458 return -EINVAL;
459 }
460
461 hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
462 return 0;
463}
464
465static void malidp550_enter_config_mode(struct malidp_hw_device *hwdev)
466{
467 u32 status, count = 100;
468
469 malidp_hw_setbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
470 while (count) {
a6993b21 471 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
ad49f860
LD
472 if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
473 break;
474 /*
475 * entering config mode can take as long as the rendering
476 * of a full frame, hence the long sleep here
477 */
478 usleep_range(1000, 10000);
479 count--;
480 }
481 WARN(count == 0, "timeout while entering config mode");
482}
483
484static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
485{
486 u32 status, count = 100;
487
e64053f0 488 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
ad49f860
LD
489 malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
490 while (count) {
a6993b21 491 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
ad49f860
LD
492 if ((status & MALIDP550_DC_CONFIG_REQ) == 0)
493 break;
494 usleep_range(100, 1000);
495 count--;
496 }
497 WARN(count == 0, "timeout while leaving config mode");
498}
499
500static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
501{
502 u32 status;
503
a6993b21 504 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
ad49f860
LD
505 if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
506 return true;
507
508 return false;
509}
510
0735cfdf 511static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
ad49f860 512{
0735cfdf
LD
513 if (value)
514 malidp_hw_setbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
515 else
516 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
ad49f860
LD
517}
518
519static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
520{
521 u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
522
523 malidp_hw_write(hwdev, val, MALIDP550_DE_CONTROL);
524 /*
525 * Mali-DP550 and Mali-DP650 encode the background color like this:
526 * - red @ MALIDP550_DE_BGND_COLOR[23:16]
527 * - green @ MALIDP550_DE_BGND_COLOR[15:8]
528 * - blue @ MALIDP550_DE_BGND_COLOR[7:0]
529 *
530 * We need to truncate the least significant 4 bits from the default
531 * MALIDP_BGND_COLOR_x values
532 */
533 val = (((MALIDP_BGND_COLOR_R >> 4) & 0xff) << 16) |
534 (((MALIDP_BGND_COLOR_G >> 4) & 0xff) << 8) |
535 ((MALIDP_BGND_COLOR_B >> 4) & 0xff);
536 malidp_hw_write(hwdev, val, MALIDP550_DE_BGND_COLOR);
537
538 val = MALIDP_DE_H_FRONTPORCH(mode->hfront_porch) |
539 MALIDP_DE_H_BACKPORCH(mode->hback_porch);
540 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_H_TIMINGS);
541
542 val = MALIDP550_DE_V_FRONTPORCH(mode->vfront_porch) |
543 MALIDP_DE_V_BACKPORCH(mode->vback_porch);
544 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_V_TIMINGS);
545
546 val = MALIDP_DE_H_SYNCWIDTH(mode->hsync_len) |
547 MALIDP_DE_V_SYNCWIDTH(mode->vsync_len);
548 if (mode->flags & DISPLAY_FLAGS_HSYNC_HIGH)
549 val |= MALIDP550_HSYNCPOL;
550 if (mode->flags & DISPLAY_FLAGS_VSYNC_HIGH)
551 val |= MALIDP550_VSYNCPOL;
552 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_SYNC_WIDTH);
553
554 val = MALIDP_DE_H_ACTIVE(mode->hactive) | MALIDP_DE_V_ACTIVE(mode->vactive);
555 malidp_hw_write(hwdev, val, MALIDP550_TIMINGS_BASE + MALIDP_DE_HV_ACTIVE);
556
557 if (mode->flags & DISPLAY_FLAGS_INTERLACED)
558 malidp_hw_setbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
559 else
560 malidp_hw_clearbits(hwdev, MALIDP_DISP_FUNC_ILACED, MALIDP_DE_DISPLAY_FUNC);
561}
562
563static int malidp550_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
564{
565 u32 bytes_per_col;
566
567 /* raw RGB888 or BGR888 can't be rotated */
568 if ((fmt == DRM_FORMAT_RGB888) || (fmt == DRM_FORMAT_BGR888))
569 return -EINVAL;
570
571 switch (fmt) {
572 /* 8 lines at 4 bytes per pixel */
573 case DRM_FORMAT_ARGB2101010:
574 case DRM_FORMAT_ABGR2101010:
575 case DRM_FORMAT_RGBA1010102:
576 case DRM_FORMAT_BGRA1010102:
577 case DRM_FORMAT_ARGB8888:
578 case DRM_FORMAT_ABGR8888:
579 case DRM_FORMAT_RGBA8888:
580 case DRM_FORMAT_BGRA8888:
581 case DRM_FORMAT_XRGB8888:
582 case DRM_FORMAT_XBGR8888:
583 case DRM_FORMAT_RGBX8888:
584 case DRM_FORMAT_BGRX8888:
585 case DRM_FORMAT_RGB888:
586 case DRM_FORMAT_BGR888:
587 /* 16 lines at 2 bytes per pixel */
588 case DRM_FORMAT_RGBA5551:
589 case DRM_FORMAT_ABGR1555:
590 case DRM_FORMAT_RGB565:
591 case DRM_FORMAT_BGR565:
592 case DRM_FORMAT_UYVY:
593 case DRM_FORMAT_YUYV:
594 bytes_per_col = 32;
595 break;
596 /* 16 lines at 1.5 bytes per pixel */
597 case DRM_FORMAT_NV12:
598 case DRM_FORMAT_YUV420:
599 bytes_per_col = 24;
600 break;
601 default:
602 return -EINVAL;
603 }
604
605 return w * bytes_per_col;
606}
607
28ce675b
MA
608static int malidp550_se_set_scaling_coeffs(struct malidp_hw_device *hwdev,
609 struct malidp_se_config *se_config,
610 struct malidp_se_config *old_config)
611{
612 u32 mask = MALIDP550_SE_CTL_VCSEL(MALIDP550_SE_CTL_SEL_MASK) |
613 MALIDP550_SE_CTL_HCSEL(MALIDP550_SE_CTL_SEL_MASK);
614 u32 new_value = MALIDP550_SE_CTL_VCSEL(se_config->vcoeff) |
615 MALIDP550_SE_CTL_HCSEL(se_config->hcoeff);
616
617 malidp_hw_clearbits(hwdev, mask, MALIDP550_SE_CONTROL);
618 malidp_hw_setbits(hwdev, new_value, MALIDP550_SE_CONTROL);
619 return 0;
620}
621
c2e7f82d
MA
622static long malidp550_se_calc_mclk(struct malidp_hw_device *hwdev,
623 struct malidp_se_config *se_config,
624 struct videomode *vm)
625{
626 unsigned long mclk;
627 unsigned long pxlclk = vm->pixelclock;
628 unsigned long htotal = vm->hactive + vm->hfront_porch +
629 vm->hback_porch + vm->hsync_len;
630 unsigned long numerator = 1, denominator = 1;
631 long ret;
632
633 if (se_config->scale_enable) {
634 numerator = max(se_config->input_w, se_config->output_w) *
635 se_config->input_h;
636 numerator += se_config->output_w *
637 (se_config->output_h -
638 min(se_config->input_h, se_config->output_h));
639 denominator = (htotal - 2) * se_config->output_h;
640 }
641
642 /* mclk can't be slower than pxlclk. */
643 if (numerator < denominator)
644 numerator = denominator = 1;
645 mclk = (pxlclk * numerator) / denominator;
646 ret = clk_get_rate(hwdev->mclk);
647 if (ret < mclk) {
648 DRM_DEBUG_DRIVER("mclk requirement of %lu kHz can't be met.\n",
649 mclk / 1000);
650 return -EINVAL;
651 }
652 return ret;
653}
654
846c87a0
LD
655static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
656 dma_addr_t *addrs, s32 *pitches,
657 int num_planes, u16 w, u16 h, u32 fmt_id)
658{
659 u32 base = MALIDP550_SE_MEMWRITE_BASE;
660 u32 de_base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
661
662 /* enable the scaling engine block */
663 malidp_hw_setbits(hwdev, MALIDP_SCALE_ENGINE_EN, de_base + MALIDP_DE_DISPLAY_FUNC);
664
1cb3cbe7
LD
665 hwdev->mw_state = MW_ONESHOT;
666
846c87a0
LD
667 malidp_hw_write(hwdev, fmt_id, base + MALIDP_MW_FORMAT);
668 switch (num_planes) {
669 case 2:
670 malidp_hw_write(hwdev, lower_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_LOW);
671 malidp_hw_write(hwdev, upper_32_bits(addrs[1]), base + MALIDP_MW_P2_PTR_HIGH);
672 malidp_hw_write(hwdev, pitches[1], base + MALIDP_MW_P2_STRIDE);
673 /* fall through */
674 case 1:
675 malidp_hw_write(hwdev, lower_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_LOW);
676 malidp_hw_write(hwdev, upper_32_bits(addrs[0]), base + MALIDP_MW_P1_PTR_HIGH);
677 malidp_hw_write(hwdev, pitches[0], base + MALIDP_MW_P1_STRIDE);
678 break;
679 default:
680 WARN(1, "Invalid number of planes");
681 }
682
683 malidp_hw_write(hwdev, MALIDP_DE_H_ACTIVE(w) | MALIDP_DE_V_ACTIVE(h),
684 MALIDP550_SE_MEMWRITE_OUT_SIZE);
685 malidp_hw_setbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
686 MALIDP550_SE_CONTROL);
687
688 return 0;
689}
690
691static void malidp550_disable_memwrite(struct malidp_hw_device *hwdev)
692{
693 u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
694
695 malidp_hw_clearbits(hwdev, MALIDP550_SE_MEMWRITE_ONESHOT | MALIDP_SE_MEMWRITE_EN,
696 MALIDP550_SE_CONTROL);
697 malidp_hw_clearbits(hwdev, MALIDP_SCALE_ENGINE_EN, base + MALIDP_DE_DISPLAY_FUNC);
698}
699
ad49f860
LD
700static int malidp650_query_hw(struct malidp_hw_device *hwdev)
701{
702 u32 conf = malidp_hw_read(hwdev, MALIDP550_CONFIG_ID);
703 u8 ln_size = (conf >> 4) & 0x3, rsize;
704
705 hwdev->min_line_size = 4;
706
707 switch (ln_size) {
708 case 0:
709 case 2:
710 /* reserved values */
711 hwdev->max_line_size = 0;
712 return -EINVAL;
713 case 1:
714 hwdev->max_line_size = SZ_4K;
715 /* two banks of 128KB for rotation memory */
716 rsize = 128;
717 break;
718 case 3:
719 hwdev->max_line_size = 2560;
720 /* two banks of 80KB for rotation memory */
721 rsize = 80;
722 }
723
724 hwdev->rotation_memory[0] = hwdev->rotation_memory[1] = rsize * SZ_1K;
725 return 0;
726}
727
a6993b21 728const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
ad49f860
LD
729 [MALIDP_500] = {
730 .map = {
02725d31 731 .coeffs_base = MALIDP500_COEFFS_BASE,
ad49f860
LD
732 .se_base = MALIDP500_SE_BASE,
733 .dc_base = MALIDP500_DC_BASE,
734 .out_depth_base = MALIDP500_OUTPUT_DEPTH,
735 .features = 0, /* no CLEARIRQ register */
736 .n_layers = ARRAY_SIZE(malidp500_layers),
737 .layers = malidp500_layers,
738 .de_irq_map = {
739 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
740 MALIDP500_DE_IRQ_AXI_ERR |
741 MALIDP500_DE_IRQ_VSYNC |
742 MALIDP500_DE_IRQ_GLOBAL,
743 .vsync_irq = MALIDP500_DE_IRQ_VSYNC,
613c5c7f
AG
744 .err_mask = MALIDP_DE_IRQ_UNDERRUN |
745 MALIDP500_DE_IRQ_AXI_ERR |
746 MALIDP500_DE_IRQ_SATURATION,
ad49f860
LD
747 },
748 .se_irq_map = {
89610dc2 749 .irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
1cb3cbe7 750 MALIDP500_SE_IRQ_CONF_VALID |
89610dc2 751 MALIDP500_SE_IRQ_GLOBAL,
1cb3cbe7 752 .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID,
613c5c7f
AG
753 .err_mask = MALIDP500_SE_IRQ_INIT_BUSY |
754 MALIDP500_SE_IRQ_AXI_ERROR |
755 MALIDP500_SE_IRQ_OVERRUN,
ad49f860
LD
756 },
757 .dc_irq_map = {
758 .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
759 .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
760 },
6211b486
BS
761 .pixel_formats = malidp500_de_formats,
762 .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
a228062c 763 .bus_align_bytes = 8,
ad49f860
LD
764 },
765 .query_hw = malidp500_query_hw,
766 .enter_config_mode = malidp500_enter_config_mode,
767 .leave_config_mode = malidp500_leave_config_mode,
768 .in_config_mode = malidp500_in_config_mode,
769 .set_config_valid = malidp500_set_config_valid,
770 .modeset = malidp500_modeset,
771 .rotmem_required = malidp500_rotmem_required,
28ce675b 772 .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
c2e7f82d 773 .se_calc_mclk = malidp500_se_calc_mclk,
1cb3cbe7
LD
774 .enable_memwrite = malidp500_enable_memwrite,
775 .disable_memwrite = malidp500_disable_memwrite,
83d642ee 776 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
ad49f860
LD
777 },
778 [MALIDP_550] = {
779 .map = {
02725d31 780 .coeffs_base = MALIDP550_COEFFS_BASE,
ad49f860
LD
781 .se_base = MALIDP550_SE_BASE,
782 .dc_base = MALIDP550_DC_BASE,
783 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
784 .features = MALIDP_REGMAP_HAS_CLEARIRQ,
785 .n_layers = ARRAY_SIZE(malidp550_layers),
786 .layers = malidp550_layers,
787 .de_irq_map = {
788 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
789 MALIDP550_DE_IRQ_VSYNC,
790 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
613c5c7f
AG
791 .err_mask = MALIDP_DE_IRQ_UNDERRUN |
792 MALIDP550_DE_IRQ_SATURATION |
793 MALIDP550_DE_IRQ_AXI_ERR,
ad49f860
LD
794 },
795 .se_irq_map = {
613c5c7f 796 .irq_mask = MALIDP550_SE_IRQ_EOW,
846c87a0 797 .vsync_irq = MALIDP550_SE_IRQ_EOW,
613c5c7f
AG
798 .err_mask = MALIDP550_SE_IRQ_AXI_ERR |
799 MALIDP550_SE_IRQ_OVR |
800 MALIDP550_SE_IRQ_IBSY,
ad49f860
LD
801 },
802 .dc_irq_map = {
846c87a0
LD
803 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
804 MALIDP550_DC_IRQ_SE,
ad49f860
LD
805 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
806 },
6211b486
BS
807 .pixel_formats = malidp550_de_formats,
808 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
a228062c 809 .bus_align_bytes = 8,
ad49f860
LD
810 },
811 .query_hw = malidp550_query_hw,
812 .enter_config_mode = malidp550_enter_config_mode,
813 .leave_config_mode = malidp550_leave_config_mode,
814 .in_config_mode = malidp550_in_config_mode,
815 .set_config_valid = malidp550_set_config_valid,
816 .modeset = malidp550_modeset,
817 .rotmem_required = malidp550_rotmem_required,
28ce675b 818 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
c2e7f82d 819 .se_calc_mclk = malidp550_se_calc_mclk,
846c87a0
LD
820 .enable_memwrite = malidp550_enable_memwrite,
821 .disable_memwrite = malidp550_disable_memwrite,
83d642ee 822 .features = 0,
ad49f860
LD
823 },
824 [MALIDP_650] = {
825 .map = {
02725d31 826 .coeffs_base = MALIDP550_COEFFS_BASE,
ad49f860
LD
827 .se_base = MALIDP550_SE_BASE,
828 .dc_base = MALIDP550_DC_BASE,
829 .out_depth_base = MALIDP550_DE_OUTPUT_DEPTH,
830 .features = MALIDP_REGMAP_HAS_CLEARIRQ,
831 .n_layers = ARRAY_SIZE(malidp550_layers),
832 .layers = malidp550_layers,
833 .de_irq_map = {
834 .irq_mask = MALIDP_DE_IRQ_UNDERRUN |
835 MALIDP650_DE_IRQ_DRIFT |
836 MALIDP550_DE_IRQ_VSYNC,
837 .vsync_irq = MALIDP550_DE_IRQ_VSYNC,
613c5c7f
AG
838 .err_mask = MALIDP_DE_IRQ_UNDERRUN |
839 MALIDP650_DE_IRQ_DRIFT |
840 MALIDP550_DE_IRQ_SATURATION |
841 MALIDP550_DE_IRQ_AXI_ERR |
842 MALIDP650_DE_IRQ_ACEV1 |
843 MALIDP650_DE_IRQ_ACEV2 |
844 MALIDP650_DE_IRQ_ACEG |
845 MALIDP650_DE_IRQ_AXIEP,
ad49f860
LD
846 },
847 .se_irq_map = {
613c5c7f 848 .irq_mask = MALIDP550_SE_IRQ_EOW,
846c87a0 849 .vsync_irq = MALIDP550_SE_IRQ_EOW,
613c5c7f
AG
850 .err_mask = MALIDP550_SE_IRQ_AXI_ERR |
851 MALIDP550_SE_IRQ_OVR |
852 MALIDP550_SE_IRQ_IBSY,
ad49f860
LD
853 },
854 .dc_irq_map = {
846c87a0
LD
855 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
856 MALIDP550_DC_IRQ_SE,
ad49f860
LD
857 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
858 },
6211b486
BS
859 .pixel_formats = malidp550_de_formats,
860 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
a228062c 861 .bus_align_bytes = 16,
ad49f860
LD
862 },
863 .query_hw = malidp650_query_hw,
864 .enter_config_mode = malidp550_enter_config_mode,
865 .leave_config_mode = malidp550_leave_config_mode,
866 .in_config_mode = malidp550_in_config_mode,
867 .set_config_valid = malidp550_set_config_valid,
868 .modeset = malidp550_modeset,
869 .rotmem_required = malidp550_rotmem_required,
28ce675b 870 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
c2e7f82d 871 .se_calc_mclk = malidp550_se_calc_mclk,
846c87a0
LD
872 .enable_memwrite = malidp550_enable_memwrite,
873 .disable_memwrite = malidp550_disable_memwrite,
83d642ee 874 .features = 0,
ad49f860
LD
875 },
876};
877
878u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
879 u8 layer_id, u32 format)
880{
881 unsigned int i;
882
6211b486
BS
883 for (i = 0; i < map->n_pixel_formats; i++) {
884 if (((map->pixel_formats[i].layer & layer_id) == layer_id) &&
885 (map->pixel_formats[i].format == format))
886 return map->pixel_formats[i].id;
ad49f860
LD
887 }
888
889 return MALIDP_INVALID_FORMAT_ID;
890}
891
892static void malidp_hw_clear_irq(struct malidp_hw_device *hwdev, u8 block, u32 irq)
893{
894 u32 base = malidp_get_block_base(hwdev, block);
895
a6993b21 896 if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
ad49f860
LD
897 malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
898 else
899 malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
900}
901
902static irqreturn_t malidp_de_irq(int irq, void *arg)
903{
904 struct drm_device *drm = arg;
905 struct malidp_drm *malidp = drm->dev_private;
906 struct malidp_hw_device *hwdev;
a6993b21 907 struct malidp_hw *hw;
ad49f860
LD
908 const struct malidp_irq_map *de;
909 u32 status, mask, dc_status;
910 irqreturn_t ret = IRQ_NONE;
911
ad49f860 912 hwdev = malidp->dev;
a6993b21
LD
913 hw = hwdev->hw;
914 de = &hw->map.de_irq_map;
ad49f860 915
0df34a80
LD
916 /*
917 * if we are suspended it is likely that we were invoked because
918 * we share an interrupt line with some other driver, don't try
919 * to read the hardware registers
920 */
921 if (hwdev->pm_suspended)
922 return IRQ_NONE;
923
ad49f860 924 /* first handle the config valid IRQ */
a6993b21
LD
925 dc_status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
926 if (dc_status & hw->map.dc_irq_map.vsync_irq) {
ad49f860 927 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
d862b2d6
LD
928 /* do we have a page flip event? */
929 if (malidp->event != NULL) {
930 spin_lock(&drm->event_lock);
931 drm_crtc_send_vblank_event(&malidp->crtc, malidp->event);
932 malidp->event = NULL;
933 spin_unlock(&drm->event_lock);
934 }
1cb3cbe7 935 atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
ad49f860
LD
936 ret = IRQ_WAKE_THREAD;
937 }
938
939 status = malidp_hw_read(hwdev, MALIDP_REG_STATUS);
940 if (!(status & de->irq_mask))
941 return ret;
942
943 mask = malidp_hw_read(hwdev, MALIDP_REG_MASKIRQ);
613c5c7f
AG
944 /* keep the status of the enabled interrupts, plus the error bits */
945 status &= (mask | de->err_mask);
d862b2d6 946 if ((status & de->vsync_irq) && malidp->crtc.enabled)
ad49f860
LD
947 drm_crtc_handle_vblank(&malidp->crtc);
948
613c5c7f
AG
949#ifdef CONFIG_DEBUG_FS
950 if (status & de->err_mask) {
951 malidp_error(malidp, &malidp->de_errors, status,
952 drm_crtc_vblank_count(&malidp->crtc));
953 }
954#endif
ad49f860
LD
955 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
956
957 return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
958}
959
960static irqreturn_t malidp_de_irq_thread_handler(int irq, void *arg)
961{
962 struct drm_device *drm = arg;
963 struct malidp_drm *malidp = drm->dev_private;
964
965 wake_up(&malidp->wq);
966
967 return IRQ_HANDLED;
968}
969
970int malidp_de_irq_init(struct drm_device *drm, int irq)
971{
972 struct malidp_drm *malidp = drm->dev_private;
973 struct malidp_hw_device *hwdev = malidp->dev;
974 int ret;
975
976 /* ensure interrupts are disabled */
977 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
978 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, 0xffffffff);
979 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
980 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, 0xffffffff);
981
982 ret = devm_request_threaded_irq(drm->dev, irq, malidp_de_irq,
983 malidp_de_irq_thread_handler,
984 IRQF_SHARED, "malidp-de", drm);
985 if (ret < 0) {
986 DRM_ERROR("failed to install DE IRQ handler\n");
987 return ret;
988 }
989
990 /* first enable the DC block IRQs */
991 malidp_hw_enable_irq(hwdev, MALIDP_DC_BLOCK,
a6993b21 992 hwdev->hw->map.dc_irq_map.irq_mask);
ad49f860
LD
993
994 /* now enable the DE block IRQs */
995 malidp_hw_enable_irq(hwdev, MALIDP_DE_BLOCK,
a6993b21 996 hwdev->hw->map.de_irq_map.irq_mask);
ad49f860
LD
997
998 return 0;
999}
1000
62862cfb 1001void malidp_de_irq_fini(struct malidp_hw_device *hwdev)
ad49f860 1002{
ad49f860 1003 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
a6993b21 1004 hwdev->hw->map.de_irq_map.irq_mask);
ad49f860 1005 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
a6993b21 1006 hwdev->hw->map.dc_irq_map.irq_mask);
ad49f860
LD
1007}
1008
1009static irqreturn_t malidp_se_irq(int irq, void *arg)
1010{
1011 struct drm_device *drm = arg;
1012 struct malidp_drm *malidp = drm->dev_private;
1013 struct malidp_hw_device *hwdev = malidp->dev;
a6993b21
LD
1014 struct malidp_hw *hw = hwdev->hw;
1015 const struct malidp_irq_map *se = &hw->map.se_irq_map;
ad49f860
LD
1016 u32 status, mask;
1017
0df34a80
LD
1018 /*
1019 * if we are suspended it is likely that we were invoked because
1020 * we share an interrupt line with some other driver, don't try
1021 * to read the hardware registers
1022 */
1023 if (hwdev->pm_suspended)
1024 return IRQ_NONE;
1025
a6993b21 1026 status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
613c5c7f 1027 if (!(status & (se->irq_mask | se->err_mask)))
ad49f860
LD
1028 return IRQ_NONE;
1029
613c5c7f
AG
1030#ifdef CONFIG_DEBUG_FS
1031 if (status & se->err_mask)
1032 malidp_error(malidp, &malidp->se_errors, status,
1033 drm_crtc_vblank_count(&malidp->crtc));
1034#endif
a6993b21 1035 mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
ad49f860 1036 status &= mask;
1cb3cbe7
LD
1037
1038 if (status & se->vsync_irq) {
1039 switch (hwdev->mw_state) {
8cbc5caf
BS
1040 case MW_ONESHOT:
1041 drm_writeback_signal_completion(&malidp->mw_connector, 0);
1042 break;
1cb3cbe7 1043 case MW_STOP:
8cbc5caf 1044 drm_writeback_signal_completion(&malidp->mw_connector, 0);
1cb3cbe7
LD
1045 /* disable writeback after stop */
1046 hwdev->mw_state = MW_NOT_ENABLED;
1047 break;
0735cfdf
LD
1048 case MW_RESTART:
1049 drm_writeback_signal_completion(&malidp->mw_connector, 0);
1050 /* fall through to a new start */
1cb3cbe7
LD
1051 case MW_START:
1052 /* writeback started, need to emulate one-shot mode */
1053 hw->disable_memwrite(hwdev);
1054 /*
0735cfdf
LD
1055 * only set config_valid HW bit if there is no other update
1056 * in progress or if we raced ahead of the DE IRQ handler
1057 * and config_valid flag will not be update until later
1cb3cbe7 1058 */
0735cfdf
LD
1059 status = malidp_hw_read(hwdev, hw->map.dc_base + MALIDP_REG_STATUS);
1060 if ((atomic_read(&malidp->config_valid) != MALIDP_CONFIG_START) ||
1061 (status & hw->map.dc_irq_map.vsync_irq))
1062 hw->set_config_valid(hwdev, 1);
1cb3cbe7
LD
1063 break;
1064 }
1065 }
ad49f860
LD
1066
1067 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
1068
1069 return IRQ_HANDLED;
1070}
1071
1072static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1073{
1074 return IRQ_HANDLED;
1075}
1076
1077int malidp_se_irq_init(struct drm_device *drm, int irq)
1078{
1079 struct malidp_drm *malidp = drm->dev_private;
1080 struct malidp_hw_device *hwdev = malidp->dev;
1081 int ret;
1082
1083 /* ensure interrupts are disabled */
1084 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1085 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, 0xffffffff);
1086
1087 ret = devm_request_threaded_irq(drm->dev, irq, malidp_se_irq,
1088 malidp_se_irq_thread_handler,
1089 IRQF_SHARED, "malidp-se", drm);
1090 if (ret < 0) {
1091 DRM_ERROR("failed to install SE IRQ handler\n");
1092 return ret;
1093 }
1094
1cb3cbe7 1095 hwdev->mw_state = MW_NOT_ENABLED;
ad49f860 1096 malidp_hw_enable_irq(hwdev, MALIDP_SE_BLOCK,
a6993b21 1097 hwdev->hw->map.se_irq_map.irq_mask);
ad49f860
LD
1098
1099 return 0;
1100}
1101
62862cfb 1102void malidp_se_irq_fini(struct malidp_hw_device *hwdev)
ad49f860 1103{
ad49f860 1104 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
a6993b21 1105 hwdev->hw->map.se_irq_map.irq_mask);
ad49f860 1106}