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

source code of linux/drivers/gpu/drm/arm/malidp_hw.c