1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4  * Author:Mark Yao <mark.yao@rock-chips.com>
5  */
6 
7 #include <linux/component.h>
8 #include <linux/mod_devicetable.h>
9 #include <linux/module.h>
10 #include <linux/of.h>
11 #include <linux/platform_device.h>
12 
13 #include <drm/drm_fourcc.h>
14 #include <drm/drm_plane.h>
15 #include <drm/drm_print.h>
16 
17 #include "rockchip_drm_vop.h"
18 #include "rockchip_vop_reg.h"
19 #include "rockchip_drm_drv.h"
20 
21 #define _VOP_REG(off, _mask, _shift, _write_mask, _relaxed) \
22 		{ \
23 		 .offset = off, \
24 		 .mask = _mask, \
25 		 .shift = _shift, \
26 		 .write_mask = _write_mask, \
27 		 .relaxed = _relaxed, \
28 		}
29 
30 #define VOP_REG(off, _mask, _shift) \
31 		_VOP_REG(off, _mask, _shift, false, true)
32 
33 #define VOP_REG_SYNC(off, _mask, _shift) \
34 		_VOP_REG(off, _mask, _shift, false, false)
35 
36 #define VOP_REG_MASK_SYNC(off, _mask, _shift) \
37 		_VOP_REG(off, _mask, _shift, true, false)
38 
39 static const uint32_t formats_win_full[] = {
40 	DRM_FORMAT_XRGB8888,
41 	DRM_FORMAT_ARGB8888,
42 	DRM_FORMAT_XBGR8888,
43 	DRM_FORMAT_ABGR8888,
44 	DRM_FORMAT_RGB888,
45 	DRM_FORMAT_BGR888,
46 	DRM_FORMAT_RGB565,
47 	DRM_FORMAT_BGR565,
48 	DRM_FORMAT_NV12,
49 	DRM_FORMAT_NV16,
50 	DRM_FORMAT_NV24,
51 };
52 
53 static const uint64_t format_modifiers_win_full[] = {
54 	DRM_FORMAT_MOD_LINEAR,
55 	DRM_FORMAT_MOD_INVALID,
56 };
57 
58 static const uint64_t format_modifiers_win_full_afbc[] = {
59 	ROCKCHIP_AFBC_MOD,
60 	DRM_FORMAT_MOD_LINEAR,
61 	DRM_FORMAT_MOD_INVALID,
62 };
63 
64 static const uint32_t formats_win_lite[] = {
65 	DRM_FORMAT_XRGB8888,
66 	DRM_FORMAT_ARGB8888,
67 	DRM_FORMAT_XBGR8888,
68 	DRM_FORMAT_ABGR8888,
69 	DRM_FORMAT_RGB888,
70 	DRM_FORMAT_BGR888,
71 	DRM_FORMAT_RGB565,
72 	DRM_FORMAT_BGR565,
73 };
74 
75 static const uint64_t format_modifiers_win_lite[] = {
76 	DRM_FORMAT_MOD_LINEAR,
77 	DRM_FORMAT_MOD_INVALID,
78 };
79 
80 static const struct vop_scl_regs rk3036_win_scl = {
81 	.scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
82 	.scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
83 	.scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
84 	.scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
85 };
86 
87 static const struct vop_win_phy rk3036_win0_data = {
88 	.scl = &rk3036_win_scl,
89 	.data_formats = formats_win_full,
90 	.nformats = ARRAY_SIZE(formats_win_full),
91 	.format_modifiers = format_modifiers_win_full,
92 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
93 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
94 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
95 	.act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0),
96 	.dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0),
97 	.dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0),
98 	.yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0),
99 	.uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0),
100 	.yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0),
101 	.uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16),
102 };
103 
104 static const struct vop_win_phy rk3036_win1_data = {
105 	.data_formats = formats_win_lite,
106 	.nformats = ARRAY_SIZE(formats_win_lite),
107 	.format_modifiers = format_modifiers_win_lite,
108 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
109 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
110 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
111 	.act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0),
112 	.dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0),
113 	.dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0),
114 	.yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0),
115 	.yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
116 };
117 
118 static const struct vop_win_data rk3036_vop_win_data[] = {
119 	{ .base = 0x00, .phy = &rk3036_win0_data,
120 	  .type = DRM_PLANE_TYPE_PRIMARY },
121 	{ .base = 0x00, .phy = &rk3036_win1_data,
122 	  .type = DRM_PLANE_TYPE_CURSOR },
123 };
124 
125 static const int rk3036_vop_intrs[] = {
126 	DSP_HOLD_VALID_INTR,
127 	FS_INTR,
128 	LINE_FLAG_INTR,
129 	BUS_ERROR_INTR,
130 };
131 
132 static const struct vop_intr rk3036_intr = {
133 	.intrs = rk3036_vop_intrs,
134 	.nintrs = ARRAY_SIZE(rk3036_vop_intrs),
135 	.line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12),
136 	.status = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 0),
137 	.enable = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 4),
138 	.clear = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 8),
139 };
140 
141 static const struct vop_modeset rk3036_modeset = {
142 	.htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
143 	.hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0),
144 	.vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
145 	.vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0),
146 };
147 
148 static const struct vop_output rk3036_output = {
149 	.pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
150 };
151 
152 static const struct vop_common rk3036_common = {
153 	.standby = VOP_REG_SYNC(RK3036_SYS_CTRL, 0x1, 30),
154 	.out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0),
155 	.dsp_blank = VOP_REG(RK3036_DSP_CTRL1, 0x1, 24),
156 	.dither_down_sel = VOP_REG(RK3036_DSP_CTRL0, 0x1, 27),
157 	.dither_down_en = VOP_REG(RK3036_DSP_CTRL0, 0x1, 11),
158 	.dither_down_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 10),
159 	.cfg_done = VOP_REG_SYNC(RK3036_REG_CFG_DONE, 0x1, 0),
160 };
161 
162 static const struct vop_data rk3036_vop = {
163 	.intr = &rk3036_intr,
164 	.common = &rk3036_common,
165 	.modeset = &rk3036_modeset,
166 	.output = &rk3036_output,
167 	.win = rk3036_vop_win_data,
168 	.win_size = ARRAY_SIZE(rk3036_vop_win_data),
169 };
170 
171 static const struct vop_win_phy rk3126_win1_data = {
172 	.data_formats = formats_win_lite,
173 	.nformats = ARRAY_SIZE(formats_win_lite),
174 	.format_modifiers = format_modifiers_win_lite,
175 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
176 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
177 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
178 	.dsp_info = VOP_REG(RK3126_WIN1_DSP_INFO, 0x0fff0fff, 0),
179 	.dsp_st = VOP_REG(RK3126_WIN1_DSP_ST, 0x1fff1fff, 0),
180 	.yrgb_mst = VOP_REG(RK3126_WIN1_MST, 0xffffffff, 0),
181 	.yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
182 };
183 
184 static const struct vop_win_data rk3126_vop_win_data[] = {
185 	{ .base = 0x00, .phy = &rk3036_win0_data,
186 	  .type = DRM_PLANE_TYPE_PRIMARY },
187 	{ .base = 0x00, .phy = &rk3126_win1_data,
188 	  .type = DRM_PLANE_TYPE_CURSOR },
189 };
190 
191 static const struct vop_data rk3126_vop = {
192 	.intr = &rk3036_intr,
193 	.common = &rk3036_common,
194 	.modeset = &rk3036_modeset,
195 	.output = &rk3036_output,
196 	.win = rk3126_vop_win_data,
197 	.win_size = ARRAY_SIZE(rk3126_vop_win_data),
198 };
199 
200 static const int px30_vop_intrs[] = {
201 	FS_INTR,
202 	0, 0,
203 	LINE_FLAG_INTR,
204 	0,
205 	BUS_ERROR_INTR,
206 	0, 0,
207 	DSP_HOLD_VALID_INTR,
208 };
209 
210 static const struct vop_intr px30_intr = {
211 	.intrs = px30_vop_intrs,
212 	.nintrs = ARRAY_SIZE(px30_vop_intrs),
213 	.line_flag_num[0] = VOP_REG(PX30_LINE_FLAG, 0xfff, 0),
214 	.status = VOP_REG_MASK_SYNC(PX30_INTR_STATUS, 0xffff, 0),
215 	.enable = VOP_REG_MASK_SYNC(PX30_INTR_EN, 0xffff, 0),
216 	.clear = VOP_REG_MASK_SYNC(PX30_INTR_CLEAR, 0xffff, 0),
217 };
218 
219 static const struct vop_common px30_common = {
220 	.standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1),
221 	.out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16),
222 	.dsp_blank = VOP_REG(PX30_DSP_CTRL2, 0x1, 14),
223 	.dither_down_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 8),
224 	.dither_down_sel = VOP_REG(PX30_DSP_CTRL2, 0x1, 7),
225 	.dither_down_mode = VOP_REG(PX30_DSP_CTRL2, 0x1, 6),
226 	.cfg_done = VOP_REG_SYNC(PX30_REG_CFG_DONE, 0x1, 0),
227 };
228 
229 static const struct vop_modeset px30_modeset = {
230 	.htotal_pw = VOP_REG(PX30_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
231 	.hact_st_end = VOP_REG(PX30_DSP_HACT_ST_END, 0x0fff0fff, 0),
232 	.vtotal_pw = VOP_REG(PX30_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
233 	.vact_st_end = VOP_REG(PX30_DSP_VACT_ST_END, 0x0fff0fff, 0),
234 };
235 
236 static const struct vop_output px30_output = {
237 	.rgb_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 1),
238 	.rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 2),
239 	.rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0),
240 	.mipi_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 25),
241 	.mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 26),
242 	.mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24),
243 };
244 
245 static const struct vop_scl_regs px30_win_scl = {
246 	.scale_yrgb_x = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
247 	.scale_yrgb_y = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
248 	.scale_cbcr_x = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
249 	.scale_cbcr_y = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
250 };
251 
252 static const struct vop_win_phy px30_win0_data = {
253 	.scl = &px30_win_scl,
254 	.data_formats = formats_win_full,
255 	.nformats = ARRAY_SIZE(formats_win_full),
256 	.format_modifiers = format_modifiers_win_full,
257 	.enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0),
258 	.format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1),
259 	.rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12),
260 	.act_info = VOP_REG(PX30_WIN0_ACT_INFO, 0xffffffff, 0),
261 	.dsp_info = VOP_REG(PX30_WIN0_DSP_INFO, 0xffffffff, 0),
262 	.dsp_st = VOP_REG(PX30_WIN0_DSP_ST, 0xffffffff, 0),
263 	.yrgb_mst = VOP_REG(PX30_WIN0_YRGB_MST0, 0xffffffff, 0),
264 	.uv_mst = VOP_REG(PX30_WIN0_CBR_MST0, 0xffffffff, 0),
265 	.yrgb_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 0),
266 	.uv_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 16),
267 };
268 
269 static const struct vop_win_phy px30_win1_data = {
270 	.data_formats = formats_win_lite,
271 	.nformats = ARRAY_SIZE(formats_win_lite),
272 	.format_modifiers = format_modifiers_win_lite,
273 	.enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
274 	.format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
275 	.rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
276 	.dsp_info = VOP_REG(PX30_WIN1_DSP_INFO, 0xffffffff, 0),
277 	.dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0),
278 	.yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0),
279 	.yrgb_vir = VOP_REG(PX30_WIN1_VIR, 0x1fff, 0),
280 };
281 
282 static const struct vop_win_phy px30_win2_data = {
283 	.data_formats = formats_win_lite,
284 	.nformats = ARRAY_SIZE(formats_win_lite),
285 	.format_modifiers = format_modifiers_win_lite,
286 	.gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4),
287 	.enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0),
288 	.format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5),
289 	.rb_swap = VOP_REG(PX30_WIN2_CTRL0, 0x1, 20),
290 	.dsp_info = VOP_REG(PX30_WIN2_DSP_INFO0, 0x0fff0fff, 0),
291 	.dsp_st = VOP_REG(PX30_WIN2_DSP_ST0, 0x1fff1fff, 0),
292 	.yrgb_mst = VOP_REG(PX30_WIN2_MST0, 0xffffffff, 0),
293 	.yrgb_vir = VOP_REG(PX30_WIN2_VIR0_1, 0x1fff, 0),
294 };
295 
296 static const struct vop_win_data px30_vop_big_win_data[] = {
297 	{ .base = 0x00, .phy = &px30_win0_data,
298 	  .type = DRM_PLANE_TYPE_PRIMARY },
299 	{ .base = 0x00, .phy = &px30_win1_data,
300 	  .type = DRM_PLANE_TYPE_OVERLAY },
301 	{ .base = 0x00, .phy = &px30_win2_data,
302 	  .type = DRM_PLANE_TYPE_CURSOR },
303 };
304 
305 static const struct vop_data px30_vop_big = {
306 	.intr = &px30_intr,
307 	.feature = VOP_FEATURE_INTERNAL_RGB,
308 	.common = &px30_common,
309 	.modeset = &px30_modeset,
310 	.output = &px30_output,
311 	.win = px30_vop_big_win_data,
312 	.win_size = ARRAY_SIZE(px30_vop_big_win_data),
313 };
314 
315 static const struct vop_win_data px30_vop_lit_win_data[] = {
316 	{ .base = 0x00, .phy = &px30_win1_data,
317 	  .type = DRM_PLANE_TYPE_PRIMARY },
318 };
319 
320 static const struct vop_data px30_vop_lit = {
321 	.intr = &px30_intr,
322 	.feature = VOP_FEATURE_INTERNAL_RGB,
323 	.common = &px30_common,
324 	.modeset = &px30_modeset,
325 	.output = &px30_output,
326 	.win = px30_vop_lit_win_data,
327 	.win_size = ARRAY_SIZE(px30_vop_lit_win_data),
328 };
329 
330 static const struct vop_scl_regs rk3066_win_scl = {
331 	.scale_yrgb_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
332 	.scale_yrgb_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
333 	.scale_cbcr_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
334 	.scale_cbcr_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
335 };
336 
337 static const struct vop_win_phy rk3066_win0_data = {
338 	.scl = &rk3066_win_scl,
339 	.data_formats = formats_win_full,
340 	.nformats = ARRAY_SIZE(formats_win_full),
341 	.format_modifiers = format_modifiers_win_full,
342 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0),
343 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4),
344 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19),
345 	.act_info = VOP_REG(RK3066_WIN0_ACT_INFO, 0x1fff1fff, 0),
346 	.dsp_info = VOP_REG(RK3066_WIN0_DSP_INFO, 0x0fff0fff, 0),
347 	.dsp_st = VOP_REG(RK3066_WIN0_DSP_ST, 0x1fff1fff, 0),
348 	.yrgb_mst = VOP_REG(RK3066_WIN0_YRGB_MST0, 0xffffffff, 0),
349 	.uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0),
350 	.yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0),
351 	.uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16),
352 };
353 
354 static const struct vop_win_phy rk3066_win1_data = {
355 	.scl = &rk3066_win_scl,
356 	.data_formats = formats_win_full,
357 	.nformats = ARRAY_SIZE(formats_win_full),
358 	.format_modifiers = format_modifiers_win_full,
359 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1),
360 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7),
361 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23),
362 	.act_info = VOP_REG(RK3066_WIN1_ACT_INFO, 0x1fff1fff, 0),
363 	.dsp_info = VOP_REG(RK3066_WIN1_DSP_INFO, 0x0fff0fff, 0),
364 	.dsp_st = VOP_REG(RK3066_WIN1_DSP_ST, 0x1fff1fff, 0),
365 	.yrgb_mst = VOP_REG(RK3066_WIN1_YRGB_MST, 0xffffffff, 0),
366 	.uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0),
367 	.yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0),
368 	.uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16),
369 };
370 
371 static const struct vop_win_phy rk3066_win2_data = {
372 	.data_formats = formats_win_lite,
373 	.nformats = ARRAY_SIZE(formats_win_lite),
374 	.format_modifiers = format_modifiers_win_lite,
375 	.enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2),
376 	.format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10),
377 	.rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27),
378 	.dsp_info = VOP_REG(RK3066_WIN2_DSP_INFO, 0x0fff0fff, 0),
379 	.dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0),
380 	.yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0),
381 	.yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0),
382 };
383 
384 static const struct vop_modeset rk3066_modeset = {
385 	.htotal_pw = VOP_REG(RK3066_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
386 	.hact_st_end = VOP_REG(RK3066_DSP_HACT_ST_END, 0x1fff1fff, 0),
387 	.vtotal_pw = VOP_REG(RK3066_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
388 	.vact_st_end = VOP_REG(RK3066_DSP_VACT_ST_END, 0x1fff1fff, 0),
389 };
390 
391 static const struct vop_output rk3066_output = {
392 	.pin_pol = VOP_REG(RK3066_DSP_CTRL0, 0x7, 4),
393 };
394 
395 static const struct vop_common rk3066_common = {
396 	.standby = VOP_REG(RK3066_SYS_CTRL0, 0x1, 1),
397 	.out_mode = VOP_REG(RK3066_DSP_CTRL0, 0xf, 0),
398 	.cfg_done = VOP_REG(RK3066_REG_CFG_DONE, 0x1, 0),
399 	.dither_down_en = VOP_REG(RK3066_DSP_CTRL0, 0x1, 11),
400 	.dither_down_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 10),
401 	.dsp_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 24),
402 };
403 
404 static const struct vop_win_data rk3066_vop_win_data[] = {
405 	{ .base = 0x00, .phy = &rk3066_win0_data,
406 	  .type = DRM_PLANE_TYPE_PRIMARY },
407 	{ .base = 0x00, .phy = &rk3066_win1_data,
408 	  .type = DRM_PLANE_TYPE_OVERLAY },
409 	{ .base = 0x00, .phy = &rk3066_win2_data,
410 	  .type = DRM_PLANE_TYPE_CURSOR },
411 };
412 
413 static const int rk3066_vop_intrs[] = {
414 	/*
415 	 * hs_start interrupt fires at frame-start, so serves
416 	 * the same purpose as dsp_hold in the driver.
417 	 */
418 	DSP_HOLD_VALID_INTR,
419 	FS_INTR,
420 	LINE_FLAG_INTR,
421 	BUS_ERROR_INTR,
422 };
423 
424 static const struct vop_intr rk3066_intr = {
425 	.intrs = rk3066_vop_intrs,
426 	.nintrs = ARRAY_SIZE(rk3066_vop_intrs),
427 	.line_flag_num[0] = VOP_REG(RK3066_INT_STATUS, 0xfff, 12),
428 	.status = VOP_REG(RK3066_INT_STATUS, 0xf, 0),
429 	.enable = VOP_REG(RK3066_INT_STATUS, 0xf, 4),
430 	.clear = VOP_REG(RK3066_INT_STATUS, 0xf, 8),
431 };
432 
433 static const struct vop_data rk3066_vop = {
434 	.version = VOP_VERSION(2, 1),
435 	.intr = &rk3066_intr,
436 	.common = &rk3066_common,
437 	.modeset = &rk3066_modeset,
438 	.output = &rk3066_output,
439 	.win = rk3066_vop_win_data,
440 	.win_size = ARRAY_SIZE(rk3066_vop_win_data),
441 };
442 
443 static const struct vop_scl_regs rk3188_win_scl = {
444 	.scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
445 	.scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
446 	.scale_cbcr_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
447 	.scale_cbcr_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
448 };
449 
450 static const struct vop_win_phy rk3188_win0_data = {
451 	.scl = &rk3188_win_scl,
452 	.data_formats = formats_win_full,
453 	.nformats = ARRAY_SIZE(formats_win_full),
454 	.format_modifiers = format_modifiers_win_full,
455 	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
456 	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
457 	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
458 	.act_info = VOP_REG(RK3188_WIN0_ACT_INFO, 0x1fff1fff, 0),
459 	.dsp_info = VOP_REG(RK3188_WIN0_DSP_INFO, 0x0fff0fff, 0),
460 	.dsp_st = VOP_REG(RK3188_WIN0_DSP_ST, 0x1fff1fff, 0),
461 	.yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0),
462 	.uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0),
463 	.yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0),
464 };
465 
466 static const struct vop_win_phy rk3188_win1_data = {
467 	.data_formats = formats_win_lite,
468 	.nformats = ARRAY_SIZE(formats_win_lite),
469 	.format_modifiers = format_modifiers_win_lite,
470 	.enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1),
471 	.format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6),
472 	.rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19),
473 	/* no act_info on window1 */
474 	.dsp_info = VOP_REG(RK3188_WIN1_DSP_INFO, 0x07ff07ff, 0),
475 	.dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0),
476 	.yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0),
477 	.yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16),
478 };
479 
480 static const struct vop_modeset rk3188_modeset = {
481 	.htotal_pw = VOP_REG(RK3188_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
482 	.hact_st_end = VOP_REG(RK3188_DSP_HACT_ST_END, 0x0fff0fff, 0),
483 	.vtotal_pw = VOP_REG(RK3188_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
484 	.vact_st_end = VOP_REG(RK3188_DSP_VACT_ST_END, 0x0fff0fff, 0),
485 };
486 
487 static const struct vop_output rk3188_output = {
488 	.pin_pol = VOP_REG(RK3188_DSP_CTRL0, 0xf, 4),
489 };
490 
491 static const struct vop_common rk3188_common = {
492 	.gate_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 31),
493 	.standby = VOP_REG(RK3188_SYS_CTRL, 0x1, 30),
494 	.out_mode = VOP_REG(RK3188_DSP_CTRL0, 0xf, 0),
495 	.cfg_done = VOP_REG(RK3188_REG_CFG_DONE, 0x1, 0),
496 	.dither_down_sel = VOP_REG(RK3188_DSP_CTRL0, 0x1, 27),
497 	.dither_down_en = VOP_REG(RK3188_DSP_CTRL0, 0x1, 11),
498 	.dither_down_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 10),
499 	.dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24),
500 };
501 
502 static const struct vop_win_data rk3188_vop_win_data[] = {
503 	{ .base = 0x00, .phy = &rk3188_win0_data,
504 	  .type = DRM_PLANE_TYPE_PRIMARY },
505 	{ .base = 0x00, .phy = &rk3188_win1_data,
506 	  .type = DRM_PLANE_TYPE_CURSOR },
507 };
508 
509 static const int rk3188_vop_intrs[] = {
510 	/*
511 	 * hs_start interrupt fires at frame-start, so serves
512 	 * the same purpose as dsp_hold in the driver.
513 	 */
514 	DSP_HOLD_VALID_INTR,
515 	FS_INTR,
516 	LINE_FLAG_INTR,
517 	BUS_ERROR_INTR,
518 };
519 
520 static const struct vop_intr rk3188_vop_intr = {
521 	.intrs = rk3188_vop_intrs,
522 	.nintrs = ARRAY_SIZE(rk3188_vop_intrs),
523 	.line_flag_num[0] = VOP_REG(RK3188_INT_STATUS, 0xfff, 12),
524 	.status = VOP_REG(RK3188_INT_STATUS, 0xf, 0),
525 	.enable = VOP_REG(RK3188_INT_STATUS, 0xf, 4),
526 	.clear = VOP_REG(RK3188_INT_STATUS, 0xf, 8),
527 };
528 
529 static const struct vop_data rk3188_vop = {
530 	.intr = &rk3188_vop_intr,
531 	.common = &rk3188_common,
532 	.modeset = &rk3188_modeset,
533 	.output = &rk3188_output,
534 	.win = rk3188_vop_win_data,
535 	.win_size = ARRAY_SIZE(rk3188_vop_win_data),
536 	.feature = VOP_FEATURE_INTERNAL_RGB,
537 };
538 
539 static const struct vop_scl_extension rk3288_win_full_scl_ext = {
540 	.cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
541 	.cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
542 	.cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28),
543 	.cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26),
544 	.cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24),
545 	.yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23),
546 	.yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22),
547 	.yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20),
548 	.yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18),
549 	.yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16),
550 	.line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15),
551 	.cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12),
552 	.yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8),
553 	.vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7),
554 	.vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6),
555 	.vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5),
556 	.vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4),
557 	.bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2),
558 	.cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1),
559 	.yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0),
560 	.lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5),
561 };
562 
563 static const struct vop_scl_regs rk3288_win_full_scl = {
564 	.ext = &rk3288_win_full_scl_ext,
565 	.scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
566 	.scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
567 	.scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
568 	.scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
569 };
570 
571 static const struct vop_win_phy rk3288_win01_data = {
572 	.scl = &rk3288_win_full_scl,
573 	.data_formats = formats_win_full,
574 	.nformats = ARRAY_SIZE(formats_win_full),
575 	.format_modifiers = format_modifiers_win_full,
576 	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
577 	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
578 	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
579 	.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
580 	.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
581 	.dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
582 	.yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
583 	.uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
584 	.yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
585 	.uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
586 	.src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
587 	.dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
588 	.channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0),
589 };
590 
591 static const struct vop_win_phy rk3288_win23_data = {
592 	.data_formats = formats_win_lite,
593 	.nformats = ARRAY_SIZE(formats_win_lite),
594 	.format_modifiers = format_modifiers_win_lite,
595 	.enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
596 	.gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
597 	.format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
598 	.rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12),
599 	.dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0),
600 	.dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0),
601 	.yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0),
602 	.yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0),
603 	.src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
604 	.dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0),
605 };
606 
607 static const struct vop_modeset rk3288_modeset = {
608 	.htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
609 	.hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0),
610 	.vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
611 	.vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0),
612 	.hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
613 	.vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
614 };
615 
616 static const struct vop_output rk3288_output = {
617 	.pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4),
618 	.rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
619 	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
620 	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
621 	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
622 };
623 
624 static const struct vop_common rk3288_common = {
625 	.standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22),
626 	.gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
627 	.mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
628 	.dither_down_sel = VOP_REG(RK3288_DSP_CTRL1, 0x1, 4),
629 	.dither_down_mode = VOP_REG(RK3288_DSP_CTRL1, 0x1, 3),
630 	.dither_down_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 2),
631 	.pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1),
632 	.dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
633 	.dsp_lut_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 0),
634 	.data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
635 	.dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18),
636 	.out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
637 	.cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0),
638 };
639 
640 /*
641  * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
642  * special support to get alpha blending working.  For now, just use overlay
643  * window 3 for the drm cursor.
644  *
645  */
646 static const struct vop_win_data rk3288_vop_win_data[] = {
647 	{ .base = 0x00, .phy = &rk3288_win01_data,
648 	  .type = DRM_PLANE_TYPE_PRIMARY },
649 	{ .base = 0x40, .phy = &rk3288_win01_data,
650 	  .type = DRM_PLANE_TYPE_OVERLAY },
651 	{ .base = 0x00, .phy = &rk3288_win23_data,
652 	  .type = DRM_PLANE_TYPE_OVERLAY },
653 	{ .base = 0x50, .phy = &rk3288_win23_data,
654 	  .type = DRM_PLANE_TYPE_CURSOR },
655 };
656 
657 static const int rk3288_vop_intrs[] = {
658 	DSP_HOLD_VALID_INTR,
659 	FS_INTR,
660 	LINE_FLAG_INTR,
661 	BUS_ERROR_INTR,
662 };
663 
664 static const struct vop_intr rk3288_vop_intr = {
665 	.intrs = rk3288_vop_intrs,
666 	.nintrs = ARRAY_SIZE(rk3288_vop_intrs),
667 	.line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12),
668 	.status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0),
669 	.enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4),
670 	.clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8),
671 };
672 
673 static const struct vop_data rk3288_vop = {
674 	.version = VOP_VERSION(3, 1),
675 	.feature = VOP_FEATURE_OUTPUT_RGB10,
676 	.intr = &rk3288_vop_intr,
677 	.common = &rk3288_common,
678 	.modeset = &rk3288_modeset,
679 	.output = &rk3288_output,
680 	.win = rk3288_vop_win_data,
681 	.win_size = ARRAY_SIZE(rk3288_vop_win_data),
682 	.lut_size = 1024,
683 };
684 
685 static const int rk3368_vop_intrs[] = {
686 	FS_INTR,
687 	0, 0,
688 	LINE_FLAG_INTR,
689 	0,
690 	BUS_ERROR_INTR,
691 	0, 0, 0, 0, 0, 0, 0,
692 	DSP_HOLD_VALID_INTR,
693 };
694 
695 static const struct vop_intr rk3368_vop_intr = {
696 	.intrs = rk3368_vop_intrs,
697 	.nintrs = ARRAY_SIZE(rk3368_vop_intrs),
698 	.line_flag_num[0] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 0),
699 	.line_flag_num[1] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 16),
700 	.status = VOP_REG_MASK_SYNC(RK3368_INTR_STATUS, 0x3fff, 0),
701 	.enable = VOP_REG_MASK_SYNC(RK3368_INTR_EN, 0x3fff, 0),
702 	.clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0),
703 };
704 
705 static const struct vop_win_phy rk3368_win01_data = {
706 	.scl = &rk3288_win_full_scl,
707 	.data_formats = formats_win_full,
708 	.nformats = ARRAY_SIZE(formats_win_full),
709 	.format_modifiers = format_modifiers_win_full,
710 	.enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
711 	.format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
712 	.rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12),
713 	.x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21),
714 	.y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22),
715 	.act_info = VOP_REG(RK3368_WIN0_ACT_INFO, 0x1fff1fff, 0),
716 	.dsp_info = VOP_REG(RK3368_WIN0_DSP_INFO, 0x0fff0fff, 0),
717 	.dsp_st = VOP_REG(RK3368_WIN0_DSP_ST, 0x1fff1fff, 0),
718 	.yrgb_mst = VOP_REG(RK3368_WIN0_YRGB_MST, 0xffffffff, 0),
719 	.uv_mst = VOP_REG(RK3368_WIN0_CBR_MST, 0xffffffff, 0),
720 	.yrgb_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 0),
721 	.uv_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 16),
722 	.src_alpha_ctl = VOP_REG(RK3368_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
723 	.dst_alpha_ctl = VOP_REG(RK3368_WIN0_DST_ALPHA_CTRL, 0xff, 0),
724 	.channel = VOP_REG(RK3368_WIN0_CTRL2, 0xff, 0),
725 };
726 
727 static const struct vop_win_phy rk3368_win23_data = {
728 	.data_formats = formats_win_lite,
729 	.nformats = ARRAY_SIZE(formats_win_lite),
730 	.format_modifiers = format_modifiers_win_lite,
731 	.gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
732 	.enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
733 	.format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
734 	.rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20),
735 	.y_mir_en = VOP_REG(RK3368_WIN2_CTRL1, 0x1, 15),
736 	.dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0),
737 	.dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0),
738 	.yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0),
739 	.yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 0),
740 	.src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
741 	.dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xff, 0),
742 };
743 
744 static const struct vop_win_data rk3368_vop_win_data[] = {
745 	{ .base = 0x00, .phy = &rk3368_win01_data,
746 	  .type = DRM_PLANE_TYPE_PRIMARY },
747 	{ .base = 0x40, .phy = &rk3368_win01_data,
748 	  .type = DRM_PLANE_TYPE_OVERLAY },
749 	{ .base = 0x00, .phy = &rk3368_win23_data,
750 	  .type = DRM_PLANE_TYPE_OVERLAY },
751 	{ .base = 0x50, .phy = &rk3368_win23_data,
752 	  .type = DRM_PLANE_TYPE_CURSOR },
753 };
754 
755 static const struct vop_output rk3368_output = {
756 	.rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19),
757 	.hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23),
758 	.edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27),
759 	.mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31),
760 	.rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16),
761 	.hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20),
762 	.edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24),
763 	.mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28),
764 	.rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
765 	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
766 	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
767 	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
768 };
769 
770 static const struct vop_misc rk3368_misc = {
771 	.global_regdone_en = VOP_REG(RK3368_SYS_CTRL, 0x1, 11),
772 };
773 
774 static const struct vop_data rk3368_vop = {
775 	.version = VOP_VERSION(3, 2),
776 	.intr = &rk3368_vop_intr,
777 	.common = &rk3288_common,
778 	.modeset = &rk3288_modeset,
779 	.output = &rk3368_output,
780 	.misc = &rk3368_misc,
781 	.win = rk3368_vop_win_data,
782 	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
783 };
784 
785 static const struct vop_intr rk3366_vop_intr = {
786 	.intrs = rk3368_vop_intrs,
787 	.nintrs = ARRAY_SIZE(rk3368_vop_intrs),
788 	.line_flag_num[0] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 0),
789 	.line_flag_num[1] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 16),
790 	.status = VOP_REG_MASK_SYNC(RK3366_INTR_STATUS0, 0xffff, 0),
791 	.enable = VOP_REG_MASK_SYNC(RK3366_INTR_EN0, 0xffff, 0),
792 	.clear = VOP_REG_MASK_SYNC(RK3366_INTR_CLEAR0, 0xffff, 0),
793 };
794 
795 static const struct vop_data rk3366_vop = {
796 	.version = VOP_VERSION(3, 4),
797 	.intr = &rk3366_vop_intr,
798 	.common = &rk3288_common,
799 	.modeset = &rk3288_modeset,
800 	.output = &rk3368_output,
801 	.misc = &rk3368_misc,
802 	.win = rk3368_vop_win_data,
803 	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
804 };
805 
806 static const struct vop_output rk3399_output = {
807 	.dp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19),
808 	.rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19),
809 	.hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23),
810 	.edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27),
811 	.mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31),
812 	.dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16),
813 	.rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16),
814 	.hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20),
815 	.edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24),
816 	.mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28),
817 	.dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11),
818 	.rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
819 	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
820 	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
821 	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
822 	.mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
823 };
824 
825 static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win01_data = {
826 	.y2r_coefficients = {
827 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 0),
828 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 16),
829 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 0),
830 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 16),
831 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 0),
832 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 16),
833 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 0),
834 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 16),
835 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 16, 0xffff, 0),
836 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 20, 0xffffffff, 0),
837 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 24, 0xffffffff, 0),
838 		VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 28, 0xffffffff, 0),
839 	},
840 };
841 
842 static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win23_data = { };
843 
844 static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = {
845 	{ .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data,
846 	  .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1) },
847 	{ .base = 0x60, .phy = &rk3399_yuv2yuv_win01_data,
848 	  .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) },
849 	{ .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data },
850 	{ .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data },
851 
852 };
853 
854 static const struct vop_win_phy rk3399_win01_data = {
855 	.scl = &rk3288_win_full_scl,
856 	.data_formats = formats_win_full,
857 	.nformats = ARRAY_SIZE(formats_win_full),
858 	.format_modifiers = format_modifiers_win_full_afbc,
859 	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
860 	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
861 	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
862 	.y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
863 	.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
864 	.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
865 	.dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
866 	.yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
867 	.uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
868 	.yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
869 	.uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
870 	.src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
871 	.dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
872 };
873 
874 /*
875  * rk3399 vop big windows register layout is same as rk3288, but we
876  * have a separate rk3399 win data array here so that we can advertise
877  * AFBC on the primary plane.
878  */
879 static const struct vop_win_data rk3399_vop_win_data[] = {
880 	{ .base = 0x00, .phy = &rk3399_win01_data,
881 	  .type = DRM_PLANE_TYPE_PRIMARY },
882 	{ .base = 0x40, .phy = &rk3288_win01_data,
883 	  .type = DRM_PLANE_TYPE_OVERLAY },
884 	{ .base = 0x00, .phy = &rk3288_win23_data,
885 	  .type = DRM_PLANE_TYPE_OVERLAY },
886 	{ .base = 0x50, .phy = &rk3288_win23_data,
887 	  .type = DRM_PLANE_TYPE_CURSOR },
888 };
889 
890 static const struct vop_afbc rk3399_vop_afbc = {
891 	.rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3),
892 	.enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0),
893 	.win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1),
894 	.format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16),
895 	.hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21),
896 	.hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0),
897 	.pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0),
898 };
899 
900 static const struct vop_data rk3399_vop_big = {
901 	.version = VOP_VERSION(3, 5),
902 	.feature = VOP_FEATURE_OUTPUT_RGB10,
903 	.intr = &rk3366_vop_intr,
904 	.common = &rk3288_common,
905 	.modeset = &rk3288_modeset,
906 	.output = &rk3399_output,
907 	.afbc = &rk3399_vop_afbc,
908 	.misc = &rk3368_misc,
909 	.win = rk3399_vop_win_data,
910 	.win_size = ARRAY_SIZE(rk3399_vop_win_data),
911 	.win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,
912 };
913 
914 static const struct vop_win_data rk3399_vop_lit_win_data[] = {
915 	{ .base = 0x00, .phy = &rk3368_win01_data,
916 	  .type = DRM_PLANE_TYPE_PRIMARY },
917 	{ .base = 0x00, .phy = &rk3368_win23_data,
918 	  .type = DRM_PLANE_TYPE_CURSOR},
919 };
920 
921 static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = {
922 	{ .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data,
923 	  .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1)},
924 	{ .base = 0x60, .phy = &rk3399_yuv2yuv_win23_data },
925 };
926 
927 static const struct vop_data rk3399_vop_lit = {
928 	.version = VOP_VERSION(3, 6),
929 	.intr = &rk3366_vop_intr,
930 	.common = &rk3288_common,
931 	.modeset = &rk3288_modeset,
932 	.output = &rk3399_output,
933 	.misc = &rk3368_misc,
934 	.win = rk3399_vop_lit_win_data,
935 	.win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
936 	.win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data,
937 };
938 
939 static const struct vop_win_data rk3228_vop_win_data[] = {
940 	{ .base = 0x00, .phy = &rk3288_win01_data,
941 	  .type = DRM_PLANE_TYPE_PRIMARY },
942 	{ .base = 0x40, .phy = &rk3288_win01_data,
943 	  .type = DRM_PLANE_TYPE_CURSOR },
944 };
945 
946 static const struct vop_data rk3228_vop = {
947 	.version = VOP_VERSION(3, 7),
948 	.feature = VOP_FEATURE_OUTPUT_RGB10,
949 	.intr = &rk3366_vop_intr,
950 	.common = &rk3288_common,
951 	.modeset = &rk3288_modeset,
952 	.output = &rk3399_output,
953 	.misc = &rk3368_misc,
954 	.win = rk3228_vop_win_data,
955 	.win_size = ARRAY_SIZE(rk3228_vop_win_data),
956 };
957 
958 static const struct vop_modeset rk3328_modeset = {
959 	.htotal_pw = VOP_REG(RK3328_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
960 	.hact_st_end = VOP_REG(RK3328_DSP_HACT_ST_END, 0x1fff1fff, 0),
961 	.vtotal_pw = VOP_REG(RK3328_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
962 	.vact_st_end = VOP_REG(RK3328_DSP_VACT_ST_END, 0x1fff1fff, 0),
963 	.hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
964 	.vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
965 };
966 
967 static const struct vop_output rk3328_output = {
968 	.rgb_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 19),
969 	.hdmi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 23),
970 	.edp_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 27),
971 	.mipi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 31),
972 	.rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12),
973 	.hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13),
974 	.edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14),
975 	.mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15),
976 	.rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 16),
977 	.hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 20),
978 	.edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 24),
979 	.mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 28),
980 };
981 
982 static const struct vop_misc rk3328_misc = {
983 	.global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11),
984 };
985 
986 static const struct vop_common rk3328_common = {
987 	.standby = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 22),
988 	.dither_down_sel = VOP_REG(RK3328_DSP_CTRL1, 0x1, 4),
989 	.dither_down_mode = VOP_REG(RK3328_DSP_CTRL1, 0x1, 3),
990 	.dither_down_en = VOP_REG(RK3328_DSP_CTRL1, 0x1, 2),
991 	.pre_dither_down = VOP_REG(RK3328_DSP_CTRL1, 0x1, 1),
992 	.dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6),
993 	.dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18),
994 	.out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0),
995 	.cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0),
996 };
997 
998 static const struct vop_intr rk3328_vop_intr = {
999 	.intrs = rk3368_vop_intrs,
1000 	.nintrs = ARRAY_SIZE(rk3368_vop_intrs),
1001 	.line_flag_num[0] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 0),
1002 	.line_flag_num[1] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 16),
1003 	.status = VOP_REG_MASK_SYNC(RK3328_INTR_STATUS0, 0xffff, 0),
1004 	.enable = VOP_REG_MASK_SYNC(RK3328_INTR_EN0, 0xffff, 0),
1005 	.clear = VOP_REG_MASK_SYNC(RK3328_INTR_CLEAR0, 0xffff, 0),
1006 };
1007 
1008 static const struct vop_win_data rk3328_vop_win_data[] = {
1009 	{ .base = 0xd0, .phy = &rk3368_win01_data,
1010 	  .type = DRM_PLANE_TYPE_PRIMARY },
1011 	{ .base = 0x1d0, .phy = &rk3368_win01_data,
1012 	  .type = DRM_PLANE_TYPE_OVERLAY },
1013 	{ .base = 0x2d0, .phy = &rk3368_win01_data,
1014 	  .type = DRM_PLANE_TYPE_CURSOR },
1015 };
1016 
1017 static const struct vop_data rk3328_vop = {
1018 	.version = VOP_VERSION(3, 8),
1019 	.feature = VOP_FEATURE_OUTPUT_RGB10,
1020 	.intr = &rk3328_vop_intr,
1021 	.common = &rk3328_common,
1022 	.modeset = &rk3328_modeset,
1023 	.output = &rk3328_output,
1024 	.misc = &rk3328_misc,
1025 	.win = rk3328_vop_win_data,
1026 	.win_size = ARRAY_SIZE(rk3328_vop_win_data),
1027 };
1028 
1029 static const struct of_device_id vop_driver_dt_match[] = {
1030 	{ .compatible = "rockchip,rk3036-vop",
1031 	  .data = &rk3036_vop },
1032 	{ .compatible = "rockchip,rk3126-vop",
1033 	  .data = &rk3126_vop },
1034 	{ .compatible = "rockchip,px30-vop-big",
1035 	  .data = &px30_vop_big },
1036 	{ .compatible = "rockchip,px30-vop-lit",
1037 	  .data = &px30_vop_lit },
1038 	{ .compatible = "rockchip,rk3066-vop",
1039 	  .data = &rk3066_vop },
1040 	{ .compatible = "rockchip,rk3188-vop",
1041 	  .data = &rk3188_vop },
1042 	{ .compatible = "rockchip,rk3288-vop",
1043 	  .data = &rk3288_vop },
1044 	{ .compatible = "rockchip,rk3368-vop",
1045 	  .data = &rk3368_vop },
1046 	{ .compatible = "rockchip,rk3366-vop",
1047 	  .data = &rk3366_vop },
1048 	{ .compatible = "rockchip,rk3399-vop-big",
1049 	  .data = &rk3399_vop_big },
1050 	{ .compatible = "rockchip,rk3399-vop-lit",
1051 	  .data = &rk3399_vop_lit },
1052 	{ .compatible = "rockchip,rk3228-vop",
1053 	  .data = &rk3228_vop },
1054 	{ .compatible = "rockchip,rk3328-vop",
1055 	  .data = &rk3328_vop },
1056 	{},
1057 };
1058 MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
1059 
1060 static int vop_probe(struct platform_device *pdev)
1061 {
1062 	struct device *dev = &pdev->dev;
1063 
1064 	if (!dev->of_node) {
1065 		DRM_DEV_ERROR(dev, "can't find vop devices\n");
1066 		return -ENODEV;
1067 	}
1068 
1069 	return component_add(dev, &vop_component_ops);
1070 }
1071 
1072 static int vop_remove(struct platform_device *pdev)
1073 {
1074 	component_del(&pdev->dev, &vop_component_ops);
1075 
1076 	return 0;
1077 }
1078 
1079 struct platform_driver vop_platform_driver = {
1080 	.probe = vop_probe,
1081 	.remove = vop_remove,
1082 	.driver = {
1083 		.name = "rockchip-vop",
1084 		.of_match_table = of_match_ptr(vop_driver_dt_match),
1085 	},
1086 };
1087