1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
4 * Author:Mark Yao <mark.yao@rock-chips.com>
7 #include <linux/component.h>
8 #include <linux/mod_devicetable.h>
9 #include <linux/module.h>
11 #include <linux/platform_device.h>
13 #include <drm/drm_fourcc.h>
14 #include <drm/drm_plane.h>
15 #include <drm/drm_print.h>
17 #include "rockchip_drm_vop.h"
18 #include "rockchip_vop_reg.h"
19 #include "rockchip_drm_drv.h"
21 #define _VOP_REG(off, _mask, _shift, _write_mask, _relaxed) \
26 .write_mask = _write_mask, \
27 .relaxed = _relaxed, \
30 #define VOP_REG(off, _mask, _shift) \
31 _VOP_REG(off, _mask, _shift, false, true)
33 #define VOP_REG_SYNC(off, _mask, _shift) \
34 _VOP_REG(off, _mask, _shift, false, false)
36 #define VOP_REG_MASK_SYNC(off, _mask, _shift) \
37 _VOP_REG(off, _mask, _shift, true, false)
39 static const uint32_t formats_win_full[] = {
53 static const uint64_t format_modifiers_win_full[] = {
54 DRM_FORMAT_MOD_LINEAR,
55 DRM_FORMAT_MOD_INVALID,
58 static const uint64_t format_modifiers_win_full_afbc[] = {
60 DRM_FORMAT_MOD_LINEAR,
61 DRM_FORMAT_MOD_INVALID,
64 static const uint32_t formats_win_lite[] = {
75 static const uint64_t format_modifiers_win_lite[] = {
76 DRM_FORMAT_MOD_LINEAR,
77 DRM_FORMAT_MOD_INVALID,
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),
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),
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),
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 },
125 static const int rk3036_vop_intrs[] = {
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),
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),
148 static const struct vop_output rk3036_output = {
149 .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
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),
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),
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),
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 },
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),
200 static const int px30_vop_intrs[] = {
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),
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),
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),
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),
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),
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 .alpha_pre_mul = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 2),
268 .alpha_mode = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 1),
269 .alpha_en = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 0),
272 static const struct vop_win_phy px30_win1_data = {
273 .data_formats = formats_win_lite,
274 .nformats = ARRAY_SIZE(formats_win_lite),
275 .format_modifiers = format_modifiers_win_lite,
276 .enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
277 .format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
278 .rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
279 .dsp_info = VOP_REG(PX30_WIN1_DSP_INFO, 0xffffffff, 0),
280 .dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0),
281 .yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0),
282 .yrgb_vir = VOP_REG(PX30_WIN1_VIR, 0x1fff, 0),
283 .alpha_pre_mul = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 2),
284 .alpha_mode = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 1),
285 .alpha_en = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 0),
288 static const struct vop_win_phy px30_win2_data = {
289 .data_formats = formats_win_lite,
290 .nformats = ARRAY_SIZE(formats_win_lite),
291 .format_modifiers = format_modifiers_win_lite,
292 .gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4),
293 .enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0),
294 .format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5),
295 .rb_swap = VOP_REG(PX30_WIN2_CTRL0, 0x1, 20),
296 .dsp_info = VOP_REG(PX30_WIN2_DSP_INFO0, 0x0fff0fff, 0),
297 .dsp_st = VOP_REG(PX30_WIN2_DSP_ST0, 0x1fff1fff, 0),
298 .yrgb_mst = VOP_REG(PX30_WIN2_MST0, 0xffffffff, 0),
299 .yrgb_vir = VOP_REG(PX30_WIN2_VIR0_1, 0x1fff, 0),
300 .alpha_pre_mul = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 2),
301 .alpha_mode = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 1),
302 .alpha_en = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 0),
305 static const struct vop_win_data px30_vop_big_win_data[] = {
306 { .base = 0x00, .phy = &px30_win0_data,
307 .type = DRM_PLANE_TYPE_PRIMARY },
308 { .base = 0x00, .phy = &px30_win1_data,
309 .type = DRM_PLANE_TYPE_OVERLAY },
310 { .base = 0x00, .phy = &px30_win2_data,
311 .type = DRM_PLANE_TYPE_CURSOR },
314 static const struct vop_data px30_vop_big = {
316 .feature = VOP_FEATURE_INTERNAL_RGB,
317 .common = &px30_common,
318 .modeset = &px30_modeset,
319 .output = &px30_output,
320 .win = px30_vop_big_win_data,
321 .win_size = ARRAY_SIZE(px30_vop_big_win_data),
324 static const struct vop_win_data px30_vop_lit_win_data[] = {
325 { .base = 0x00, .phy = &px30_win1_data,
326 .type = DRM_PLANE_TYPE_PRIMARY },
329 static const struct vop_data px30_vop_lit = {
331 .feature = VOP_FEATURE_INTERNAL_RGB,
332 .common = &px30_common,
333 .modeset = &px30_modeset,
334 .output = &px30_output,
335 .win = px30_vop_lit_win_data,
336 .win_size = ARRAY_SIZE(px30_vop_lit_win_data),
339 static const struct vop_scl_regs rk3066_win_scl = {
340 .scale_yrgb_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
341 .scale_yrgb_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
342 .scale_cbcr_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
343 .scale_cbcr_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
346 static const struct vop_win_phy rk3066_win0_data = {
347 .scl = &rk3066_win_scl,
348 .data_formats = formats_win_full,
349 .nformats = ARRAY_SIZE(formats_win_full),
350 .format_modifiers = format_modifiers_win_full,
351 .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0),
352 .format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 4),
353 .rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 19),
354 .act_info = VOP_REG(RK3066_WIN0_ACT_INFO, 0x1fff1fff, 0),
355 .dsp_info = VOP_REG(RK3066_WIN0_DSP_INFO, 0x0fff0fff, 0),
356 .dsp_st = VOP_REG(RK3066_WIN0_DSP_ST, 0x1fff1fff, 0),
357 .yrgb_mst = VOP_REG(RK3066_WIN0_YRGB_MST0, 0xffffffff, 0),
358 .uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0),
359 .yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0),
360 .uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16),
363 static const struct vop_win_phy rk3066_win1_data = {
364 .data_formats = formats_win_full,
365 .nformats = ARRAY_SIZE(formats_win_full),
366 .format_modifiers = format_modifiers_win_full,
367 .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1),
368 .format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 7),
369 .rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 23),
370 .act_info = VOP_REG(RK3066_WIN1_ACT_INFO, 0x1fff1fff, 0),
371 .dsp_info = VOP_REG(RK3066_WIN1_DSP_INFO, 0x0fff0fff, 0),
372 .dsp_st = VOP_REG(RK3066_WIN1_DSP_ST, 0x1fff1fff, 0),
373 .yrgb_mst = VOP_REG(RK3066_WIN1_YRGB_MST, 0xffffffff, 0),
374 .uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0),
375 .yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0),
376 .uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16),
379 static const struct vop_win_phy rk3066_win2_data = {
380 .data_formats = formats_win_lite,
381 .nformats = ARRAY_SIZE(formats_win_lite),
382 .format_modifiers = format_modifiers_win_lite,
383 .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2),
384 .format = VOP_REG(RK3066_SYS_CTRL1, 0x7, 10),
385 .rb_swap = VOP_REG(RK3066_SYS_CTRL1, 0x1, 27),
386 .dsp_info = VOP_REG(RK3066_WIN2_DSP_INFO, 0x0fff0fff, 0),
387 .dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0),
388 .yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0),
389 .yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0),
392 static const struct vop_modeset rk3066_modeset = {
393 .htotal_pw = VOP_REG(RK3066_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
394 .hact_st_end = VOP_REG(RK3066_DSP_HACT_ST_END, 0x1fff1fff, 0),
395 .vtotal_pw = VOP_REG(RK3066_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
396 .vact_st_end = VOP_REG(RK3066_DSP_VACT_ST_END, 0x1fff1fff, 0),
399 static const struct vop_output rk3066_output = {
400 .pin_pol = VOP_REG(RK3066_DSP_CTRL0, 0x7, 4),
403 static const struct vop_common rk3066_common = {
404 .standby = VOP_REG(RK3066_SYS_CTRL0, 0x1, 1),
405 .out_mode = VOP_REG(RK3066_DSP_CTRL0, 0xf, 0),
406 .cfg_done = VOP_REG(RK3066_REG_CFG_DONE, 0x1, 0),
407 .dither_down_en = VOP_REG(RK3066_DSP_CTRL0, 0x1, 11),
408 .dither_down_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 10),
409 .dsp_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 24),
410 .dither_up = VOP_REG(RK3066_DSP_CTRL0, 0x1, 9),
411 .dsp_lut_en = VOP_REG(RK3066_SYS_CTRL1, 0x1, 31),
412 .data_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 25),
415 static const struct vop_win_data rk3066_vop_win_data[] = {
416 { .base = 0x00, .phy = &rk3066_win0_data,
417 .type = DRM_PLANE_TYPE_PRIMARY },
418 { .base = 0x00, .phy = &rk3066_win1_data,
419 .type = DRM_PLANE_TYPE_OVERLAY },
420 { .base = 0x00, .phy = &rk3066_win2_data,
421 .type = DRM_PLANE_TYPE_CURSOR },
424 static const int rk3066_vop_intrs[] = {
426 * hs_start interrupt fires at frame-start, so serves
427 * the same purpose as dsp_hold in the driver.
435 static const struct vop_intr rk3066_intr = {
436 .intrs = rk3066_vop_intrs,
437 .nintrs = ARRAY_SIZE(rk3066_vop_intrs),
438 .line_flag_num[0] = VOP_REG(RK3066_INT_STATUS, 0xfff, 12),
439 .status = VOP_REG(RK3066_INT_STATUS, 0xf, 0),
440 .enable = VOP_REG(RK3066_INT_STATUS, 0xf, 4),
441 .clear = VOP_REG(RK3066_INT_STATUS, 0xf, 8),
444 static const struct vop_data rk3066_vop = {
445 .version = VOP_VERSION(2, 1),
446 .intr = &rk3066_intr,
447 .common = &rk3066_common,
448 .modeset = &rk3066_modeset,
449 .output = &rk3066_output,
450 .win = rk3066_vop_win_data,
451 .win_size = ARRAY_SIZE(rk3066_vop_win_data),
454 static const struct vop_scl_regs rk3188_win_scl = {
455 .scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
456 .scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
457 .scale_cbcr_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
458 .scale_cbcr_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
461 static const struct vop_win_phy rk3188_win0_data = {
462 .scl = &rk3188_win_scl,
463 .data_formats = formats_win_full,
464 .nformats = ARRAY_SIZE(formats_win_full),
465 .format_modifiers = format_modifiers_win_full,
466 .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
467 .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
468 .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
469 .act_info = VOP_REG(RK3188_WIN0_ACT_INFO, 0x1fff1fff, 0),
470 .dsp_info = VOP_REG(RK3188_WIN0_DSP_INFO, 0x0fff0fff, 0),
471 .dsp_st = VOP_REG(RK3188_WIN0_DSP_ST, 0x1fff1fff, 0),
472 .yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0),
473 .uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0),
474 .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0),
477 static const struct vop_win_phy rk3188_win1_data = {
478 .data_formats = formats_win_lite,
479 .nformats = ARRAY_SIZE(formats_win_lite),
480 .format_modifiers = format_modifiers_win_lite,
481 .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1),
482 .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6),
483 .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19),
484 /* no act_info on window1 */
485 .dsp_info = VOP_REG(RK3188_WIN1_DSP_INFO, 0x07ff07ff, 0),
486 .dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0),
487 .yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0),
488 .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16),
491 static const struct vop_modeset rk3188_modeset = {
492 .htotal_pw = VOP_REG(RK3188_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
493 .hact_st_end = VOP_REG(RK3188_DSP_HACT_ST_END, 0x0fff0fff, 0),
494 .vtotal_pw = VOP_REG(RK3188_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
495 .vact_st_end = VOP_REG(RK3188_DSP_VACT_ST_END, 0x0fff0fff, 0),
498 static const struct vop_output rk3188_output = {
499 .pin_pol = VOP_REG(RK3188_DSP_CTRL0, 0xf, 4),
502 static const struct vop_common rk3188_common = {
503 .gate_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 31),
504 .standby = VOP_REG(RK3188_SYS_CTRL, 0x1, 30),
505 .out_mode = VOP_REG(RK3188_DSP_CTRL0, 0xf, 0),
506 .cfg_done = VOP_REG(RK3188_REG_CFG_DONE, 0x1, 0),
507 .dither_down_sel = VOP_REG(RK3188_DSP_CTRL0, 0x1, 27),
508 .dither_down_en = VOP_REG(RK3188_DSP_CTRL0, 0x1, 11),
509 .dither_down_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 10),
510 .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 24),
511 .dither_up = VOP_REG(RK3188_DSP_CTRL0, 0x1, 9),
512 .dsp_lut_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 28),
513 .data_blank = VOP_REG(RK3188_DSP_CTRL1, 0x1, 25),
516 static const struct vop_win_data rk3188_vop_win_data[] = {
517 { .base = 0x00, .phy = &rk3188_win0_data,
518 .type = DRM_PLANE_TYPE_PRIMARY },
519 { .base = 0x00, .phy = &rk3188_win1_data,
520 .type = DRM_PLANE_TYPE_CURSOR },
523 static const int rk3188_vop_intrs[] = {
525 * hs_start interrupt fires at frame-start, so serves
526 * the same purpose as dsp_hold in the driver.
534 static const struct vop_intr rk3188_vop_intr = {
535 .intrs = rk3188_vop_intrs,
536 .nintrs = ARRAY_SIZE(rk3188_vop_intrs),
537 .line_flag_num[0] = VOP_REG(RK3188_INT_STATUS, 0xfff, 12),
538 .status = VOP_REG(RK3188_INT_STATUS, 0xf, 0),
539 .enable = VOP_REG(RK3188_INT_STATUS, 0xf, 4),
540 .clear = VOP_REG(RK3188_INT_STATUS, 0xf, 8),
543 static const struct vop_data rk3188_vop = {
544 .intr = &rk3188_vop_intr,
545 .common = &rk3188_common,
546 .modeset = &rk3188_modeset,
547 .output = &rk3188_output,
548 .win = rk3188_vop_win_data,
549 .win_size = ARRAY_SIZE(rk3188_vop_win_data),
550 .feature = VOP_FEATURE_INTERNAL_RGB,
553 static const struct vop_scl_extension rk3288_win_full_scl_ext = {
554 .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
555 .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
556 .cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28),
557 .cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26),
558 .cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24),
559 .yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23),
560 .yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22),
561 .yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20),
562 .yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18),
563 .yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16),
564 .line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15),
565 .cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12),
566 .yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8),
567 .vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7),
568 .vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6),
569 .vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5),
570 .vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4),
571 .bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2),
572 .cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1),
573 .yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0),
574 .lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5),
577 static const struct vop_scl_regs rk3288_win_full_scl = {
578 .ext = &rk3288_win_full_scl_ext,
579 .scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
580 .scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
581 .scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
582 .scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
585 static const struct vop_win_phy rk3288_win01_data = {
586 .scl = &rk3288_win_full_scl,
587 .data_formats = formats_win_full,
588 .nformats = ARRAY_SIZE(formats_win_full),
589 .format_modifiers = format_modifiers_win_full,
590 .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
591 .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
592 .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
593 .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
594 .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
595 .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
596 .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
597 .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
598 .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
599 .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
600 .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
601 .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
602 .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0),
605 static const struct vop_win_phy rk3288_win23_data = {
606 .data_formats = formats_win_lite,
607 .nformats = ARRAY_SIZE(formats_win_lite),
608 .format_modifiers = format_modifiers_win_lite,
609 .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
610 .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
611 .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
612 .rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12),
613 .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0),
614 .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0),
615 .yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0),
616 .yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0),
617 .src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
618 .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0),
621 static const struct vop_modeset rk3288_modeset = {
622 .htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
623 .hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0),
624 .vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
625 .vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0),
626 .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
627 .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
630 static const struct vop_output rk3288_output = {
631 .pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4),
632 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
633 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
634 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
635 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
638 static const struct vop_common rk3288_common = {
639 .standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22),
640 .gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
641 .mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
642 .dither_down_sel = VOP_REG(RK3288_DSP_CTRL1, 0x1, 4),
643 .dither_down_mode = VOP_REG(RK3288_DSP_CTRL1, 0x1, 3),
644 .dither_down_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 2),
645 .pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1),
646 .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
647 .dsp_lut_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 0),
648 .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
649 .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18),
650 .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
651 .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0),
655 * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
656 * special support to get alpha blending working. For now, just use overlay
657 * window 3 for the drm cursor.
660 static const struct vop_win_data rk3288_vop_win_data[] = {
661 { .base = 0x00, .phy = &rk3288_win01_data,
662 .type = DRM_PLANE_TYPE_PRIMARY },
663 { .base = 0x40, .phy = &rk3288_win01_data,
664 .type = DRM_PLANE_TYPE_OVERLAY },
665 { .base = 0x00, .phy = &rk3288_win23_data,
666 .type = DRM_PLANE_TYPE_OVERLAY },
667 { .base = 0x50, .phy = &rk3288_win23_data,
668 .type = DRM_PLANE_TYPE_CURSOR },
671 static const int rk3288_vop_intrs[] = {
678 static const struct vop_intr rk3288_vop_intr = {
679 .intrs = rk3288_vop_intrs,
680 .nintrs = ARRAY_SIZE(rk3288_vop_intrs),
681 .line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12),
682 .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0),
683 .enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4),
684 .clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8),
687 static const struct vop_data rk3288_vop = {
688 .version = VOP_VERSION(3, 1),
689 .feature = VOP_FEATURE_OUTPUT_RGB10,
690 .intr = &rk3288_vop_intr,
691 .common = &rk3288_common,
692 .modeset = &rk3288_modeset,
693 .output = &rk3288_output,
694 .win = rk3288_vop_win_data,
695 .win_size = ARRAY_SIZE(rk3288_vop_win_data),
699 static const int rk3368_vop_intrs[] = {
709 static const struct vop_intr rk3368_vop_intr = {
710 .intrs = rk3368_vop_intrs,
711 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
712 .line_flag_num[0] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 0),
713 .line_flag_num[1] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 16),
714 .status = VOP_REG_MASK_SYNC(RK3368_INTR_STATUS, 0x3fff, 0),
715 .enable = VOP_REG_MASK_SYNC(RK3368_INTR_EN, 0x3fff, 0),
716 .clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0),
719 static const struct vop_win_phy rk3368_win01_data = {
720 .scl = &rk3288_win_full_scl,
721 .data_formats = formats_win_full,
722 .nformats = ARRAY_SIZE(formats_win_full),
723 .format_modifiers = format_modifiers_win_full,
724 .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
725 .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
726 .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12),
727 .x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21),
728 .y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22),
729 .act_info = VOP_REG(RK3368_WIN0_ACT_INFO, 0x1fff1fff, 0),
730 .dsp_info = VOP_REG(RK3368_WIN0_DSP_INFO, 0x0fff0fff, 0),
731 .dsp_st = VOP_REG(RK3368_WIN0_DSP_ST, 0x1fff1fff, 0),
732 .yrgb_mst = VOP_REG(RK3368_WIN0_YRGB_MST, 0xffffffff, 0),
733 .uv_mst = VOP_REG(RK3368_WIN0_CBR_MST, 0xffffffff, 0),
734 .yrgb_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 0),
735 .uv_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 16),
736 .src_alpha_ctl = VOP_REG(RK3368_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
737 .dst_alpha_ctl = VOP_REG(RK3368_WIN0_DST_ALPHA_CTRL, 0xff, 0),
738 .channel = VOP_REG(RK3368_WIN0_CTRL2, 0xff, 0),
741 static const struct vop_win_phy rk3368_win23_data = {
742 .data_formats = formats_win_lite,
743 .nformats = ARRAY_SIZE(formats_win_lite),
744 .format_modifiers = format_modifiers_win_lite,
745 .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
746 .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
747 .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
748 .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20),
749 .y_mir_en = VOP_REG(RK3368_WIN2_CTRL1, 0x1, 15),
750 .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0),
751 .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0),
752 .yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0),
753 .yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 0),
754 .src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
755 .dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xff, 0),
758 static const struct vop_win_data rk3368_vop_win_data[] = {
759 { .base = 0x00, .phy = &rk3368_win01_data,
760 .type = DRM_PLANE_TYPE_PRIMARY },
761 { .base = 0x40, .phy = &rk3368_win01_data,
762 .type = DRM_PLANE_TYPE_OVERLAY },
763 { .base = 0x00, .phy = &rk3368_win23_data,
764 .type = DRM_PLANE_TYPE_OVERLAY },
765 { .base = 0x50, .phy = &rk3368_win23_data,
766 .type = DRM_PLANE_TYPE_CURSOR },
769 static const struct vop_output rk3368_output = {
770 .rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19),
771 .hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23),
772 .edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27),
773 .mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31),
774 .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16),
775 .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20),
776 .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24),
777 .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28),
778 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
779 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
780 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
781 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
784 static const struct vop_misc rk3368_misc = {
785 .global_regdone_en = VOP_REG(RK3368_SYS_CTRL, 0x1, 11),
788 static const struct vop_data rk3368_vop = {
789 .version = VOP_VERSION(3, 2),
790 .intr = &rk3368_vop_intr,
791 .common = &rk3288_common,
792 .modeset = &rk3288_modeset,
793 .output = &rk3368_output,
794 .misc = &rk3368_misc,
795 .win = rk3368_vop_win_data,
796 .win_size = ARRAY_SIZE(rk3368_vop_win_data),
799 static const struct vop_intr rk3366_vop_intr = {
800 .intrs = rk3368_vop_intrs,
801 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
802 .line_flag_num[0] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 0),
803 .line_flag_num[1] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 16),
804 .status = VOP_REG_MASK_SYNC(RK3366_INTR_STATUS0, 0xffff, 0),
805 .enable = VOP_REG_MASK_SYNC(RK3366_INTR_EN0, 0xffff, 0),
806 .clear = VOP_REG_MASK_SYNC(RK3366_INTR_CLEAR0, 0xffff, 0),
809 static const struct vop_data rk3366_vop = {
810 .version = VOP_VERSION(3, 4),
811 .intr = &rk3366_vop_intr,
812 .common = &rk3288_common,
813 .modeset = &rk3288_modeset,
814 .output = &rk3368_output,
815 .misc = &rk3368_misc,
816 .win = rk3368_vop_win_data,
817 .win_size = ARRAY_SIZE(rk3368_vop_win_data),
820 static const struct vop_output rk3399_output = {
821 .dp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19),
822 .rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19),
823 .hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23),
824 .edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27),
825 .mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31),
826 .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16),
827 .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16),
828 .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20),
829 .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24),
830 .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28),
831 .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11),
832 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
833 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
834 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
835 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
836 .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
839 static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win01_data = {
840 .y2r_coefficients = {
841 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 0),
842 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 16),
843 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 0),
844 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 16),
845 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 0),
846 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 16),
847 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 0),
848 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 16),
849 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 16, 0xffff, 0),
850 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 20, 0xffffffff, 0),
851 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 24, 0xffffffff, 0),
852 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 28, 0xffffffff, 0),
856 static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win23_data = { };
858 static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = {
859 { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data,
860 .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1) },
861 { .base = 0x60, .phy = &rk3399_yuv2yuv_win01_data,
862 .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) },
863 { .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data },
864 { .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data },
868 static const struct vop_win_phy rk3399_win01_data = {
869 .scl = &rk3288_win_full_scl,
870 .data_formats = formats_win_full,
871 .nformats = ARRAY_SIZE(formats_win_full),
872 .format_modifiers = format_modifiers_win_full_afbc,
873 .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
874 .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
875 .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
876 .x_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 21),
877 .y_mir_en = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 22),
878 .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
879 .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
880 .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
881 .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
882 .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
883 .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
884 .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
885 .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
886 .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
887 .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0),
891 * rk3399 vop big windows register layout is same as rk3288, but we
892 * have a separate rk3399 win data array here so that we can advertise
893 * AFBC on the primary plane.
895 static const struct vop_win_data rk3399_vop_win_data[] = {
896 { .base = 0x00, .phy = &rk3399_win01_data,
897 .type = DRM_PLANE_TYPE_PRIMARY },
898 { .base = 0x40, .phy = &rk3368_win01_data,
899 .type = DRM_PLANE_TYPE_OVERLAY },
900 { .base = 0x00, .phy = &rk3368_win23_data,
901 .type = DRM_PLANE_TYPE_OVERLAY },
902 { .base = 0x50, .phy = &rk3368_win23_data,
903 .type = DRM_PLANE_TYPE_CURSOR },
906 static const struct vop_afbc rk3399_vop_afbc = {
907 .rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3),
908 .enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0),
909 .win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1),
910 .format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16),
911 .hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21),
912 .hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0),
913 .pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0),
916 static const struct vop_data rk3399_vop_big = {
917 .version = VOP_VERSION(3, 5),
918 .feature = VOP_FEATURE_OUTPUT_RGB10,
919 .intr = &rk3366_vop_intr,
920 .common = &rk3288_common,
921 .modeset = &rk3288_modeset,
922 .output = &rk3399_output,
923 .afbc = &rk3399_vop_afbc,
924 .misc = &rk3368_misc,
925 .win = rk3399_vop_win_data,
926 .win_size = ARRAY_SIZE(rk3399_vop_win_data),
927 .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,
930 static const struct vop_win_data rk3399_vop_lit_win_data[] = {
931 { .base = 0x00, .phy = &rk3368_win01_data,
932 .type = DRM_PLANE_TYPE_PRIMARY },
933 { .base = 0x00, .phy = &rk3368_win23_data,
934 .type = DRM_PLANE_TYPE_CURSOR},
937 static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = {
938 { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data,
939 .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1)},
940 { .base = 0x60, .phy = &rk3399_yuv2yuv_win23_data },
943 static const struct vop_data rk3399_vop_lit = {
944 .version = VOP_VERSION(3, 6),
945 .intr = &rk3366_vop_intr,
946 .common = &rk3288_common,
947 .modeset = &rk3288_modeset,
948 .output = &rk3399_output,
949 .misc = &rk3368_misc,
950 .win = rk3399_vop_lit_win_data,
951 .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
952 .win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data,
955 static const struct vop_win_data rk3228_vop_win_data[] = {
956 { .base = 0x00, .phy = &rk3288_win01_data,
957 .type = DRM_PLANE_TYPE_PRIMARY },
958 { .base = 0x40, .phy = &rk3288_win01_data,
959 .type = DRM_PLANE_TYPE_CURSOR },
962 static const struct vop_data rk3228_vop = {
963 .version = VOP_VERSION(3, 7),
964 .feature = VOP_FEATURE_OUTPUT_RGB10,
965 .intr = &rk3366_vop_intr,
966 .common = &rk3288_common,
967 .modeset = &rk3288_modeset,
968 .output = &rk3399_output,
969 .misc = &rk3368_misc,
970 .win = rk3228_vop_win_data,
971 .win_size = ARRAY_SIZE(rk3228_vop_win_data),
974 static const struct vop_modeset rk3328_modeset = {
975 .htotal_pw = VOP_REG(RK3328_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
976 .hact_st_end = VOP_REG(RK3328_DSP_HACT_ST_END, 0x1fff1fff, 0),
977 .vtotal_pw = VOP_REG(RK3328_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
978 .vact_st_end = VOP_REG(RK3328_DSP_VACT_ST_END, 0x1fff1fff, 0),
979 .hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
980 .vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
983 static const struct vop_output rk3328_output = {
984 .rgb_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 19),
985 .hdmi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 23),
986 .edp_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 27),
987 .mipi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 31),
988 .rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12),
989 .hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13),
990 .edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14),
991 .mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15),
992 .rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 16),
993 .hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 20),
994 .edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 24),
995 .mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 28),
998 static const struct vop_misc rk3328_misc = {
999 .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11),
1002 static const struct vop_common rk3328_common = {
1003 .standby = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 22),
1004 .dither_down_sel = VOP_REG(RK3328_DSP_CTRL1, 0x1, 4),
1005 .dither_down_mode = VOP_REG(RK3328_DSP_CTRL1, 0x1, 3),
1006 .dither_down_en = VOP_REG(RK3328_DSP_CTRL1, 0x1, 2),
1007 .pre_dither_down = VOP_REG(RK3328_DSP_CTRL1, 0x1, 1),
1008 .dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6),
1009 .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18),
1010 .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0),
1011 .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0),
1014 static const struct vop_intr rk3328_vop_intr = {
1015 .intrs = rk3368_vop_intrs,
1016 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
1017 .line_flag_num[0] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 0),
1018 .line_flag_num[1] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 16),
1019 .status = VOP_REG_MASK_SYNC(RK3328_INTR_STATUS0, 0xffff, 0),
1020 .enable = VOP_REG_MASK_SYNC(RK3328_INTR_EN0, 0xffff, 0),
1021 .clear = VOP_REG_MASK_SYNC(RK3328_INTR_CLEAR0, 0xffff, 0),
1024 static const struct vop_win_data rk3328_vop_win_data[] = {
1025 { .base = 0xd0, .phy = &rk3368_win01_data,
1026 .type = DRM_PLANE_TYPE_PRIMARY },
1027 { .base = 0x1d0, .phy = &rk3368_win01_data,
1028 .type = DRM_PLANE_TYPE_OVERLAY },
1029 { .base = 0x2d0, .phy = &rk3368_win01_data,
1030 .type = DRM_PLANE_TYPE_CURSOR },
1033 static const struct vop_data rk3328_vop = {
1034 .version = VOP_VERSION(3, 8),
1035 .feature = VOP_FEATURE_OUTPUT_RGB10,
1036 .intr = &rk3328_vop_intr,
1037 .common = &rk3328_common,
1038 .modeset = &rk3328_modeset,
1039 .output = &rk3328_output,
1040 .misc = &rk3328_misc,
1041 .win = rk3328_vop_win_data,
1042 .win_size = ARRAY_SIZE(rk3328_vop_win_data),
1045 static const struct of_device_id vop_driver_dt_match[] = {
1046 { .compatible = "rockchip,rk3036-vop",
1047 .data = &rk3036_vop },
1048 { .compatible = "rockchip,rk3126-vop",
1049 .data = &rk3126_vop },
1050 { .compatible = "rockchip,px30-vop-big",
1051 .data = &px30_vop_big },
1052 { .compatible = "rockchip,px30-vop-lit",
1053 .data = &px30_vop_lit },
1054 { .compatible = "rockchip,rk3066-vop",
1055 .data = &rk3066_vop },
1056 { .compatible = "rockchip,rk3188-vop",
1057 .data = &rk3188_vop },
1058 { .compatible = "rockchip,rk3288-vop",
1059 .data = &rk3288_vop },
1060 { .compatible = "rockchip,rk3368-vop",
1061 .data = &rk3368_vop },
1062 { .compatible = "rockchip,rk3366-vop",
1063 .data = &rk3366_vop },
1064 { .compatible = "rockchip,rk3399-vop-big",
1065 .data = &rk3399_vop_big },
1066 { .compatible = "rockchip,rk3399-vop-lit",
1067 .data = &rk3399_vop_lit },
1068 { .compatible = "rockchip,rk3228-vop",
1069 .data = &rk3228_vop },
1070 { .compatible = "rockchip,rk3328-vop",
1071 .data = &rk3328_vop },
1074 MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
1076 static int vop_probe(struct platform_device *pdev)
1078 struct device *dev = &pdev->dev;
1080 if (!dev->of_node) {
1081 DRM_DEV_ERROR(dev, "can't find vop devices\n");
1085 return component_add(dev, &vop_component_ops);
1088 static int vop_remove(struct platform_device *pdev)
1090 component_del(&pdev->dev, &vop_component_ops);
1095 struct platform_driver vop_platform_driver = {
1097 .remove = vop_remove,
1099 .name = "rockchip-vop",
1100 .of_match_table = of_match_ptr(vop_driver_dt_match),