Merge branch 'work.lookup' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[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
f877006d
AKH
247 malidp_hw_write(hwdev, hwdev->output_color_depth,
248 hwdev->hw->map.out_depth_base);
ad49f860
LD
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
289static int malidp500_rotmem_required(struct malidp_hw_device *hwdev, u16 w, u16 h, u32 fmt)
290{
ad49f860
LD
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 */
7ccf281f 300 return w * drm_format_plane_cpp(fmt, 0) * 8;
ad49f860
LD
301}
302
28ce675b
MA
303static 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
320static 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
c2e7f82d
MA
352static 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
1cb3cbe7
LD
385static int malidp500_enable_memwrite(struct malidp_hw_device *hwdev,
386 dma_addr_t *addrs, s32 *pitches,
89578d04
AG
387 int num_planes, u16 w, u16 h, u32 fmt_id,
388 const s16 *rgb2yuv_coeffs)
1cb3cbe7
LD
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
0735cfdf
LD
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;
1cb3cbe7
LD
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);
89578d04
AG
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
1cb3cbe7
LD
430 malidp_hw_setbits(hwdev, MALIDP_SE_MEMWRITE_EN, MALIDP500_SE_CONTROL);
431
432 return 0;
433}
434
435static void malidp500_disable_memwrite(struct malidp_hw_device *hwdev)
436{
437 u32 base = malidp_get_block_base(hwdev, MALIDP_DE_BLOCK);
438
0735cfdf 439 if (hwdev->mw_state == MW_START || hwdev->mw_state == MW_RESTART)
1cb3cbe7
LD
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
ad49f860
LD
445static 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
478static 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) {
a6993b21 484 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
ad49f860
LD
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
497static void malidp550_leave_config_mode(struct malidp_hw_device *hwdev)
498{
499 u32 status, count = 100;
500
e64053f0 501 malidp_hw_clearbits(hwdev, MALIDP_CFG_VALID, MALIDP550_CONFIG_VALID);
ad49f860
LD
502 malidp_hw_clearbits(hwdev, MALIDP550_DC_CONFIG_REQ, MALIDP550_DC_CONTROL);
503 while (count) {
a6993b21 504 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
ad49f860
LD
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
513static bool malidp550_in_config_mode(struct malidp_hw_device *hwdev)
514{
515 u32 status;
516
a6993b21 517 status = malidp_hw_read(hwdev, hwdev->hw->map.dc_base + MALIDP_REG_STATUS);
ad49f860
LD
518 if ((status & MALIDP550_DC_CONFIG_REQ) == MALIDP550_DC_CONFIG_REQ)
519 return true;
520
521 return false;
522}
523
0735cfdf 524static void malidp550_set_config_valid(struct malidp_hw_device *hwdev, u8 value)
ad49f860 525{
0735cfdf
LD
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);
ad49f860
LD
530}
531
532static void malidp550_modeset(struct malidp_hw_device *hwdev, struct videomode *mode)
533{
534 u32 val = MALIDP_DE_DEFAULT_PREFETCH_START;
535
f877006d
AKH
536 malidp_hw_write(hwdev, hwdev->output_color_depth,
537 hwdev->hw->map.out_depth_base);
ad49f860
LD
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
578static 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
28ce675b
MA
623static 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
c2e7f82d
MA
637static 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
846c87a0
LD
670static int malidp550_enable_memwrite(struct malidp_hw_device *hwdev,
671 dma_addr_t *addrs, s32 *pitches,
89578d04
AG
672 int num_planes, u16 w, u16 h, u32 fmt_id,
673 const s16 *rgb2yuv_coeffs)
846c87a0
LD
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
1cb3cbe7
LD
681 hwdev->mw_state = MW_ONESHOT;
682
846c87a0
LD
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
89578d04
AG
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
846c87a0
LD
713 return 0;
714}
715
716static 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
ad49f860
LD
725static 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
a6993b21 753const struct malidp_hw malidp_device[MALIDP_MAX_DEVICES] = {
ad49f860
LD
754 [MALIDP_500] = {
755 .map = {
02725d31 756 .coeffs_base = MALIDP500_COEFFS_BASE,
ad49f860
LD
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,
613c5c7f
AG
769 .err_mask = MALIDP_DE_IRQ_UNDERRUN |
770 MALIDP500_DE_IRQ_AXI_ERR |
771 MALIDP500_DE_IRQ_SATURATION,
ad49f860
LD
772 },
773 .se_irq_map = {
89610dc2 774 .irq_mask = MALIDP500_SE_IRQ_CONF_MODE |
1cb3cbe7 775 MALIDP500_SE_IRQ_CONF_VALID |
89610dc2 776 MALIDP500_SE_IRQ_GLOBAL,
1cb3cbe7 777 .vsync_irq = MALIDP500_SE_IRQ_CONF_VALID,
613c5c7f
AG
778 .err_mask = MALIDP500_SE_IRQ_INIT_BUSY |
779 MALIDP500_SE_IRQ_AXI_ERROR |
780 MALIDP500_SE_IRQ_OVERRUN,
ad49f860
LD
781 },
782 .dc_irq_map = {
783 .irq_mask = MALIDP500_DE_IRQ_CONF_VALID,
784 .vsync_irq = MALIDP500_DE_IRQ_CONF_VALID,
785 },
6211b486
BS
786 .pixel_formats = malidp500_de_formats,
787 .n_pixel_formats = ARRAY_SIZE(malidp500_de_formats),
a228062c 788 .bus_align_bytes = 8,
ad49f860
LD
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,
28ce675b 797 .se_set_scaling_coeffs = malidp500_se_set_scaling_coeffs,
c2e7f82d 798 .se_calc_mclk = malidp500_se_calc_mclk,
1cb3cbe7
LD
799 .enable_memwrite = malidp500_enable_memwrite,
800 .disable_memwrite = malidp500_disable_memwrite,
83d642ee 801 .features = MALIDP_DEVICE_LV_HAS_3_STRIDES,
ad49f860
LD
802 },
803 [MALIDP_550] = {
804 .map = {
02725d31 805 .coeffs_base = MALIDP550_COEFFS_BASE,
ad49f860
LD
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,
613c5c7f
AG
816 .err_mask = MALIDP_DE_IRQ_UNDERRUN |
817 MALIDP550_DE_IRQ_SATURATION |
818 MALIDP550_DE_IRQ_AXI_ERR,
ad49f860
LD
819 },
820 .se_irq_map = {
613c5c7f 821 .irq_mask = MALIDP550_SE_IRQ_EOW,
846c87a0 822 .vsync_irq = MALIDP550_SE_IRQ_EOW,
613c5c7f
AG
823 .err_mask = MALIDP550_SE_IRQ_AXI_ERR |
824 MALIDP550_SE_IRQ_OVR |
825 MALIDP550_SE_IRQ_IBSY,
ad49f860
LD
826 },
827 .dc_irq_map = {
846c87a0
LD
828 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
829 MALIDP550_DC_IRQ_SE,
ad49f860
LD
830 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
831 },
6211b486
BS
832 .pixel_formats = malidp550_de_formats,
833 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
a228062c 834 .bus_align_bytes = 8,
ad49f860
LD
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,
28ce675b 843 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
c2e7f82d 844 .se_calc_mclk = malidp550_se_calc_mclk,
846c87a0
LD
845 .enable_memwrite = malidp550_enable_memwrite,
846 .disable_memwrite = malidp550_disable_memwrite,
83d642ee 847 .features = 0,
ad49f860
LD
848 },
849 [MALIDP_650] = {
850 .map = {
02725d31 851 .coeffs_base = MALIDP550_COEFFS_BASE,
ad49f860
LD
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,
613c5c7f
AG
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,
ad49f860
LD
871 },
872 .se_irq_map = {
613c5c7f 873 .irq_mask = MALIDP550_SE_IRQ_EOW,
846c87a0 874 .vsync_irq = MALIDP550_SE_IRQ_EOW,
613c5c7f
AG
875 .err_mask = MALIDP550_SE_IRQ_AXI_ERR |
876 MALIDP550_SE_IRQ_OVR |
877 MALIDP550_SE_IRQ_IBSY,
ad49f860
LD
878 },
879 .dc_irq_map = {
846c87a0
LD
880 .irq_mask = MALIDP550_DC_IRQ_CONF_VALID |
881 MALIDP550_DC_IRQ_SE,
ad49f860
LD
882 .vsync_irq = MALIDP550_DC_IRQ_CONF_VALID,
883 },
6211b486
BS
884 .pixel_formats = malidp550_de_formats,
885 .n_pixel_formats = ARRAY_SIZE(malidp550_de_formats),
a228062c 886 .bus_align_bytes = 16,
ad49f860
LD
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,
28ce675b 895 .se_set_scaling_coeffs = malidp550_se_set_scaling_coeffs,
c2e7f82d 896 .se_calc_mclk = malidp550_se_calc_mclk,
846c87a0
LD
897 .enable_memwrite = malidp550_enable_memwrite,
898 .disable_memwrite = malidp550_disable_memwrite,
83d642ee 899 .features = 0,
ad49f860
LD
900 },
901};
902
903u8 malidp_hw_get_format_id(const struct malidp_hw_regmap *map,
904 u8 layer_id, u32 format)
905{
906 unsigned int i;
907
6211b486
BS
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;
ad49f860
LD
912 }
913
914 return MALIDP_INVALID_FORMAT_ID;
915}
916
917static 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
a6993b21 921 if (hwdev->hw->map.features & MALIDP_REGMAP_HAS_CLEARIRQ)
ad49f860
LD
922 malidp_hw_write(hwdev, irq, base + MALIDP_REG_CLEARIRQ);
923 else
924 malidp_hw_write(hwdev, irq, base + MALIDP_REG_STATUS);
925}
926
927static 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;
a6993b21 932 struct malidp_hw *hw;
ad49f860
LD
933 const struct malidp_irq_map *de;
934 u32 status, mask, dc_status;
935 irqreturn_t ret = IRQ_NONE;
936
ad49f860 937 hwdev = malidp->dev;
a6993b21
LD
938 hw = hwdev->hw;
939 de = &hw->map.de_irq_map;
ad49f860 940
0df34a80
LD
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
ad49f860 949 /* first handle the config valid IRQ */
a6993b21
LD
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) {
ad49f860 952 malidp_hw_clear_irq(hwdev, MALIDP_DC_BLOCK, dc_status);
d862b2d6
LD
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 }
1cb3cbe7 960 atomic_set(&malidp->config_valid, MALIDP_CONFIG_VALID_DONE);
ad49f860
LD
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);
613c5c7f
AG
969 /* keep the status of the enabled interrupts, plus the error bits */
970 status &= (mask | de->err_mask);
d862b2d6 971 if ((status & de->vsync_irq) && malidp->crtc.enabled)
ad49f860
LD
972 drm_crtc_handle_vblank(&malidp->crtc);
973
613c5c7f
AG
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
ad49f860
LD
980 malidp_hw_clear_irq(hwdev, MALIDP_DE_BLOCK, status);
981
982 return (ret == IRQ_NONE) ? IRQ_HANDLED : ret;
983}
984
985static 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
ff8fc26a
AKH
995void 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
ad49f860
LD
1012int 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
ff8fc26a 1032 malidp_de_irq_hw_init(hwdev);
ad49f860
LD
1033
1034 return 0;
1035}
1036
62862cfb 1037void malidp_de_irq_fini(struct malidp_hw_device *hwdev)
ad49f860 1038{
ad49f860 1039 malidp_hw_disable_irq(hwdev, MALIDP_DE_BLOCK,
a6993b21 1040 hwdev->hw->map.de_irq_map.irq_mask);
ad49f860 1041 malidp_hw_disable_irq(hwdev, MALIDP_DC_BLOCK,
a6993b21 1042 hwdev->hw->map.dc_irq_map.irq_mask);
ad49f860
LD
1043}
1044
1045static 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;
a6993b21
LD
1050 struct malidp_hw *hw = hwdev->hw;
1051 const struct malidp_irq_map *se = &hw->map.se_irq_map;
ad49f860
LD
1052 u32 status, mask;
1053
0df34a80
LD
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
a6993b21 1062 status = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_STATUS);
613c5c7f 1063 if (!(status & (se->irq_mask | se->err_mask)))
ad49f860
LD
1064 return IRQ_NONE;
1065
613c5c7f
AG
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
a6993b21 1071 mask = malidp_hw_read(hwdev, hw->map.se_base + MALIDP_REG_MASKIRQ);
ad49f860 1072 status &= mask;
1cb3cbe7
LD
1073
1074 if (status & se->vsync_irq) {
1075 switch (hwdev->mw_state) {
8cbc5caf
BS
1076 case MW_ONESHOT:
1077 drm_writeback_signal_completion(&malidp->mw_connector, 0);
1078 break;
1cb3cbe7 1079 case MW_STOP:
8cbc5caf 1080 drm_writeback_signal_completion(&malidp->mw_connector, 0);
1cb3cbe7
LD
1081 /* disable writeback after stop */
1082 hwdev->mw_state = MW_NOT_ENABLED;
1083 break;
0735cfdf
LD
1084 case MW_RESTART:
1085 drm_writeback_signal_completion(&malidp->mw_connector, 0);
1086 /* fall through to a new start */
1cb3cbe7
LD
1087 case MW_START:
1088 /* writeback started, need to emulate one-shot mode */
1089 hw->disable_memwrite(hwdev);
1090 /*
0735cfdf
LD
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
1cb3cbe7 1094 */
0735cfdf
LD
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);
1cb3cbe7
LD
1099 break;
1100 }
1101 }
ad49f860
LD
1102
1103 malidp_hw_clear_irq(hwdev, MALIDP_SE_BLOCK, status);
1104
1105 return IRQ_HANDLED;
1106}
1107
ff8fc26a
AKH
1108void 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
ad49f860
LD
1118static irqreturn_t malidp_se_irq_thread_handler(int irq, void *arg)
1119{
1120 return IRQ_HANDLED;
1121}
1122
1123int 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
1cb3cbe7 1141 hwdev->mw_state = MW_NOT_ENABLED;
ff8fc26a 1142 malidp_se_irq_hw_init(hwdev);
ad49f860
LD
1143
1144 return 0;
1145}
1146
62862cfb 1147void malidp_se_irq_fini(struct malidp_hw_device *hwdev)
ad49f860 1148{
ad49f860 1149 malidp_hw_disable_irq(hwdev, MALIDP_SE_BLOCK,
a6993b21 1150 hwdev->hw->map.se_irq_map.irq_mask);
ad49f860 1151}