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_win0_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_scl_regs rk3036_win1_scl = {
88 .scale_yrgb_x = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 0x0),
89 .scale_yrgb_y = VOP_REG(RK3036_WIN1_SCL_FACTOR_YRGB, 0xffff, 16),
92 static const struct vop_win_phy rk3036_win0_data = {
93 .scl = &rk3036_win0_scl,
94 .data_formats = formats_win_full,
95 .nformats = ARRAY_SIZE(formats_win_full),
96 .format_modifiers = format_modifiers_win_full,
97 .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
98 .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
99 .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
100 .act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0),
101 .dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0),
102 .dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0),
103 .yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0),
104 .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0),
105 .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0),
106 .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16),
109 static const struct vop_win_phy rk3036_win1_data = {
110 .scl = &rk3036_win1_scl,
111 .data_formats = formats_win_lite,
112 .nformats = ARRAY_SIZE(formats_win_lite),
113 .format_modifiers = format_modifiers_win_lite,
114 .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
115 .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
116 .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
117 .act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0),
118 .dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0),
119 .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0),
120 .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0),
121 .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
124 static const struct vop_win_data rk3036_vop_win_data[] = {
125 { .base = 0x00, .phy = &rk3036_win0_data,
126 .type = DRM_PLANE_TYPE_PRIMARY },
127 { .base = 0x00, .phy = &rk3036_win1_data,
128 .type = DRM_PLANE_TYPE_CURSOR },
131 static const int rk3036_vop_intrs[] = {
138 static const struct vop_intr rk3036_intr = {
139 .intrs = rk3036_vop_intrs,
140 .nintrs = ARRAY_SIZE(rk3036_vop_intrs),
141 .line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12),
142 .status = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 0),
143 .enable = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 4),
144 .clear = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 8),
147 static const struct vop_modeset rk3036_modeset = {
148 .htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
149 .hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0),
150 .vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
151 .vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0),
154 static const struct vop_output rk3036_output = {
155 .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
158 static const struct vop_common rk3036_common = {
159 .standby = VOP_REG_SYNC(RK3036_SYS_CTRL, 0x1, 30),
160 .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0),
161 .dsp_blank = VOP_REG(RK3036_DSP_CTRL1, 0x1, 24),
162 .dither_down_sel = VOP_REG(RK3036_DSP_CTRL0, 0x1, 27),
163 .dither_down_en = VOP_REG(RK3036_DSP_CTRL0, 0x1, 11),
164 .dither_down_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 10),
165 .cfg_done = VOP_REG_SYNC(RK3036_REG_CFG_DONE, 0x1, 0),
168 static const struct vop_data rk3036_vop = {
169 .intr = &rk3036_intr,
170 .common = &rk3036_common,
171 .modeset = &rk3036_modeset,
172 .output = &rk3036_output,
173 .win = rk3036_vop_win_data,
174 .win_size = ARRAY_SIZE(rk3036_vop_win_data),
177 static const struct vop_win_phy rk3126_win1_data = {
178 .data_formats = formats_win_lite,
179 .nformats = ARRAY_SIZE(formats_win_lite),
180 .format_modifiers = format_modifiers_win_lite,
181 .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
182 .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
183 .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
184 .dsp_info = VOP_REG(RK3126_WIN1_DSP_INFO, 0x0fff0fff, 0),
185 .dsp_st = VOP_REG(RK3126_WIN1_DSP_ST, 0x1fff1fff, 0),
186 .yrgb_mst = VOP_REG(RK3126_WIN1_MST, 0xffffffff, 0),
187 .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
190 static const struct vop_win_data rk3126_vop_win_data[] = {
191 { .base = 0x00, .phy = &rk3036_win0_data,
192 .type = DRM_PLANE_TYPE_PRIMARY },
193 { .base = 0x00, .phy = &rk3126_win1_data,
194 .type = DRM_PLANE_TYPE_CURSOR },
197 static const struct vop_data rk3126_vop = {
198 .intr = &rk3036_intr,
199 .common = &rk3036_common,
200 .modeset = &rk3036_modeset,
201 .output = &rk3036_output,
202 .win = rk3126_vop_win_data,
203 .win_size = ARRAY_SIZE(rk3126_vop_win_data),
206 static const int px30_vop_intrs[] = {
216 static const struct vop_intr px30_intr = {
217 .intrs = px30_vop_intrs,
218 .nintrs = ARRAY_SIZE(px30_vop_intrs),
219 .line_flag_num[0] = VOP_REG(PX30_LINE_FLAG, 0xfff, 0),
220 .status = VOP_REG_MASK_SYNC(PX30_INTR_STATUS, 0xffff, 0),
221 .enable = VOP_REG_MASK_SYNC(PX30_INTR_EN, 0xffff, 0),
222 .clear = VOP_REG_MASK_SYNC(PX30_INTR_CLEAR, 0xffff, 0),
225 static const struct vop_common px30_common = {
226 .standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1),
227 .out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16),
228 .dsp_blank = VOP_REG(PX30_DSP_CTRL2, 0x1, 14),
229 .dither_down_en = VOP_REG(PX30_DSP_CTRL2, 0x1, 8),
230 .dither_down_sel = VOP_REG(PX30_DSP_CTRL2, 0x1, 7),
231 .dither_down_mode = VOP_REG(PX30_DSP_CTRL2, 0x1, 6),
232 .cfg_done = VOP_REG_SYNC(PX30_REG_CFG_DONE, 0x1, 0),
235 static const struct vop_modeset px30_modeset = {
236 .htotal_pw = VOP_REG(PX30_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
237 .hact_st_end = VOP_REG(PX30_DSP_HACT_ST_END, 0x0fff0fff, 0),
238 .vtotal_pw = VOP_REG(PX30_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
239 .vact_st_end = VOP_REG(PX30_DSP_VACT_ST_END, 0x0fff0fff, 0),
242 static const struct vop_output px30_output = {
243 .rgb_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 1),
244 .rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 2),
245 .rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0),
246 .mipi_dclk_pol = VOP_REG(PX30_DSP_CTRL0, 0x1, 25),
247 .mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0x7, 26),
248 .mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24),
251 static const struct vop_scl_regs px30_win_scl = {
252 .scale_yrgb_x = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
253 .scale_yrgb_y = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
254 .scale_cbcr_x = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
255 .scale_cbcr_y = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
258 static const struct vop_win_phy px30_win0_data = {
259 .scl = &px30_win_scl,
260 .data_formats = formats_win_full,
261 .nformats = ARRAY_SIZE(formats_win_full),
262 .format_modifiers = format_modifiers_win_full,
263 .enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0),
264 .format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1),
265 .rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12),
266 .act_info = VOP_REG(PX30_WIN0_ACT_INFO, 0xffffffff, 0),
267 .dsp_info = VOP_REG(PX30_WIN0_DSP_INFO, 0xffffffff, 0),
268 .dsp_st = VOP_REG(PX30_WIN0_DSP_ST, 0xffffffff, 0),
269 .yrgb_mst = VOP_REG(PX30_WIN0_YRGB_MST0, 0xffffffff, 0),
270 .uv_mst = VOP_REG(PX30_WIN0_CBR_MST0, 0xffffffff, 0),
271 .yrgb_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 0),
272 .uv_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 16),
273 .alpha_pre_mul = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 2),
274 .alpha_mode = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 1),
275 .alpha_en = VOP_REG(PX30_WIN0_ALPHA_CTRL, 0x1, 0),
278 static const struct vop_win_phy px30_win1_data = {
279 .data_formats = formats_win_lite,
280 .nformats = ARRAY_SIZE(formats_win_lite),
281 .format_modifiers = format_modifiers_win_lite,
282 .enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
283 .format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
284 .rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
285 .dsp_info = VOP_REG(PX30_WIN1_DSP_INFO, 0xffffffff, 0),
286 .dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0),
287 .yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0),
288 .yrgb_vir = VOP_REG(PX30_WIN1_VIR, 0x1fff, 0),
289 .alpha_pre_mul = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 2),
290 .alpha_mode = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 1),
291 .alpha_en = VOP_REG(PX30_WIN1_ALPHA_CTRL, 0x1, 0),
294 static const struct vop_win_phy px30_win2_data = {
295 .data_formats = formats_win_lite,
296 .nformats = ARRAY_SIZE(formats_win_lite),
297 .format_modifiers = format_modifiers_win_lite,
298 .gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4),
299 .enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0),
300 .format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5),
301 .rb_swap = VOP_REG(PX30_WIN2_CTRL0, 0x1, 20),
302 .dsp_info = VOP_REG(PX30_WIN2_DSP_INFO0, 0x0fff0fff, 0),
303 .dsp_st = VOP_REG(PX30_WIN2_DSP_ST0, 0x1fff1fff, 0),
304 .yrgb_mst = VOP_REG(PX30_WIN2_MST0, 0xffffffff, 0),
305 .yrgb_vir = VOP_REG(PX30_WIN2_VIR0_1, 0x1fff, 0),
306 .alpha_pre_mul = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 2),
307 .alpha_mode = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 1),
308 .alpha_en = VOP_REG(PX30_WIN2_ALPHA_CTRL, 0x1, 0),
311 static const struct vop_win_data px30_vop_big_win_data[] = {
312 { .base = 0x00, .phy = &px30_win0_data,
313 .type = DRM_PLANE_TYPE_PRIMARY },
314 { .base = 0x00, .phy = &px30_win1_data,
315 .type = DRM_PLANE_TYPE_OVERLAY },
316 { .base = 0x00, .phy = &px30_win2_data,
317 .type = DRM_PLANE_TYPE_CURSOR },
320 static const struct vop_data px30_vop_big = {
322 .feature = VOP_FEATURE_INTERNAL_RGB,
323 .common = &px30_common,
324 .modeset = &px30_modeset,
325 .output = &px30_output,
326 .win = px30_vop_big_win_data,
327 .win_size = ARRAY_SIZE(px30_vop_big_win_data),
330 static const struct vop_win_data px30_vop_lit_win_data[] = {
331 { .base = 0x00, .phy = &px30_win1_data,
332 .type = DRM_PLANE_TYPE_PRIMARY },
335 static const struct vop_data px30_vop_lit = {
337 .feature = VOP_FEATURE_INTERNAL_RGB,
338 .common = &px30_common,
339 .modeset = &px30_modeset,
340 .output = &px30_output,
341 .win = px30_vop_lit_win_data,
342 .win_size = ARRAY_SIZE(px30_vop_lit_win_data),
345 static const struct vop_scl_regs rk3066_win_scl = {
346 .scale_yrgb_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
347 .scale_yrgb_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
348 .scale_cbcr_x = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
349 .scale_cbcr_y = VOP_REG(RK3066_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
352 static const struct vop_win_phy rk3066_win0_data = {
353 .scl = &rk3066_win_scl,
354 .data_formats = formats_win_full,
355 .nformats = ARRAY_SIZE(formats_win_full),
356 .format_modifiers = format_modifiers_win_full,
357 .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 0),
358 .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 4),
359 .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 19),
360 .act_info = VOP_REG(RK3066_WIN0_ACT_INFO, 0x1fff1fff, 0),
361 .dsp_info = VOP_REG(RK3066_WIN0_DSP_INFO, 0x0fff0fff, 0),
362 .dsp_st = VOP_REG(RK3066_WIN0_DSP_ST, 0x1fff1fff, 0),
363 .yrgb_mst = VOP_REG(RK3066_WIN0_YRGB_MST0, 0xffffffff, 0),
364 .uv_mst = VOP_REG(RK3066_WIN0_CBR_MST0, 0xffffffff, 0),
365 .yrgb_vir = VOP_REG(RK3066_WIN0_VIR, 0xffff, 0),
366 .uv_vir = VOP_REG(RK3066_WIN0_VIR, 0x1fff, 16),
369 static const struct vop_win_phy rk3066_win1_data = {
370 .scl = &rk3066_win_scl,
371 .data_formats = formats_win_full,
372 .nformats = ARRAY_SIZE(formats_win_full),
373 .format_modifiers = format_modifiers_win_full,
374 .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 1),
375 .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 7),
376 .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 23),
377 .act_info = VOP_REG(RK3066_WIN1_ACT_INFO, 0x1fff1fff, 0),
378 .dsp_info = VOP_REG(RK3066_WIN1_DSP_INFO, 0x0fff0fff, 0),
379 .dsp_st = VOP_REG(RK3066_WIN1_DSP_ST, 0x1fff1fff, 0),
380 .yrgb_mst = VOP_REG(RK3066_WIN1_YRGB_MST, 0xffffffff, 0),
381 .uv_mst = VOP_REG(RK3066_WIN1_CBR_MST, 0xffffffff, 0),
382 .yrgb_vir = VOP_REG(RK3066_WIN1_VIR, 0xffff, 0),
383 .uv_vir = VOP_REG(RK3066_WIN1_VIR, 0x1fff, 16),
386 static const struct vop_win_phy rk3066_win2_data = {
387 .data_formats = formats_win_lite,
388 .nformats = ARRAY_SIZE(formats_win_lite),
389 .format_modifiers = format_modifiers_win_lite,
390 .enable = VOP_REG(RK3066_SYS_CTRL1, 0x1, 2),
391 .format = VOP_REG(RK3066_SYS_CTRL0, 0x7, 10),
392 .rb_swap = VOP_REG(RK3066_SYS_CTRL0, 0x1, 27),
393 .dsp_info = VOP_REG(RK3066_WIN2_DSP_INFO, 0x0fff0fff, 0),
394 .dsp_st = VOP_REG(RK3066_WIN2_DSP_ST, 0x1fff1fff, 0),
395 .yrgb_mst = VOP_REG(RK3066_WIN2_MST, 0xffffffff, 0),
396 .yrgb_vir = VOP_REG(RK3066_WIN2_VIR, 0xffff, 0),
399 static const struct vop_modeset rk3066_modeset = {
400 .htotal_pw = VOP_REG(RK3066_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
401 .hact_st_end = VOP_REG(RK3066_DSP_HACT_ST_END, 0x1fff1fff, 0),
402 .vtotal_pw = VOP_REG(RK3066_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
403 .vact_st_end = VOP_REG(RK3066_DSP_VACT_ST_END, 0x1fff1fff, 0),
406 static const struct vop_output rk3066_output = {
407 .pin_pol = VOP_REG(RK3066_DSP_CTRL0, 0x7, 4),
410 static const struct vop_common rk3066_common = {
411 .standby = VOP_REG(RK3066_SYS_CTRL0, 0x1, 1),
412 .out_mode = VOP_REG(RK3066_DSP_CTRL0, 0xf, 0),
413 .cfg_done = VOP_REG(RK3066_REG_CFG_DONE, 0x1, 0),
414 .dither_down_en = VOP_REG(RK3066_DSP_CTRL0, 0x1, 11),
415 .dither_down_mode = VOP_REG(RK3066_DSP_CTRL0, 0x1, 10),
416 .dsp_blank = VOP_REG(RK3066_DSP_CTRL1, 0x1, 24),
419 static const struct vop_win_data rk3066_vop_win_data[] = {
420 { .base = 0x00, .phy = &rk3066_win0_data,
421 .type = DRM_PLANE_TYPE_PRIMARY },
422 { .base = 0x00, .phy = &rk3066_win1_data,
423 .type = DRM_PLANE_TYPE_OVERLAY },
424 { .base = 0x00, .phy = &rk3066_win2_data,
425 .type = DRM_PLANE_TYPE_CURSOR },
428 static const int rk3066_vop_intrs[] = {
430 * hs_start interrupt fires at frame-start, so serves
431 * the same purpose as dsp_hold in the driver.
439 static const struct vop_intr rk3066_intr = {
440 .intrs = rk3066_vop_intrs,
441 .nintrs = ARRAY_SIZE(rk3066_vop_intrs),
442 .line_flag_num[0] = VOP_REG(RK3066_INT_STATUS, 0xfff, 12),
443 .status = VOP_REG(RK3066_INT_STATUS, 0xf, 0),
444 .enable = VOP_REG(RK3066_INT_STATUS, 0xf, 4),
445 .clear = VOP_REG(RK3066_INT_STATUS, 0xf, 8),
448 static const struct vop_data rk3066_vop = {
449 .version = VOP_VERSION(2, 1),
450 .intr = &rk3066_intr,
451 .common = &rk3066_common,
452 .modeset = &rk3066_modeset,
453 .output = &rk3066_output,
454 .win = rk3066_vop_win_data,
455 .win_size = ARRAY_SIZE(rk3066_vop_win_data),
458 static const struct vop_scl_regs rk3188_win_scl = {
459 .scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
460 .scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
461 .scale_cbcr_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
462 .scale_cbcr_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
465 static const struct vop_win_phy rk3188_win0_data = {
466 .scl = &rk3188_win_scl,
467 .data_formats = formats_win_full,
468 .nformats = ARRAY_SIZE(formats_win_full),
469 .format_modifiers = format_modifiers_win_full,
470 .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
471 .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
472 .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
473 .act_info = VOP_REG(RK3188_WIN0_ACT_INFO, 0x1fff1fff, 0),
474 .dsp_info = VOP_REG(RK3188_WIN0_DSP_INFO, 0x0fff0fff, 0),
475 .dsp_st = VOP_REG(RK3188_WIN0_DSP_ST, 0x1fff1fff, 0),
476 .yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0),
477 .uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0),
478 .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0),
481 static const struct vop_win_phy rk3188_win1_data = {
482 .data_formats = formats_win_lite,
483 .nformats = ARRAY_SIZE(formats_win_lite),
484 .format_modifiers = format_modifiers_win_lite,
485 .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1),
486 .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6),
487 .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19),
488 /* no act_info on window1 */
489 .dsp_info = VOP_REG(RK3188_WIN1_DSP_INFO, 0x07ff07ff, 0),
490 .dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0),
491 .yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0),
492 .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16),
495 static const struct vop_modeset rk3188_modeset = {
496 .htotal_pw = VOP_REG(RK3188_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
497 .hact_st_end = VOP_REG(RK3188_DSP_HACT_ST_END, 0x0fff0fff, 0),
498 .vtotal_pw = VOP_REG(RK3188_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
499 .vact_st_end = VOP_REG(RK3188_DSP_VACT_ST_END, 0x0fff0fff, 0),
502 static const struct vop_output rk3188_output = {
503 .pin_pol = VOP_REG(RK3188_DSP_CTRL0, 0xf, 4),
506 static const struct vop_common rk3188_common = {
507 .gate_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 31),
508 .standby = VOP_REG(RK3188_SYS_CTRL, 0x1, 30),
509 .out_mode = VOP_REG(RK3188_DSP_CTRL0, 0xf, 0),
510 .cfg_done = VOP_REG(RK3188_REG_CFG_DONE, 0x1, 0),
511 .dither_down_sel = VOP_REG(RK3188_DSP_CTRL0, 0x1, 27),
512 .dither_down_en = VOP_REG(RK3188_DSP_CTRL0, 0x1, 11),
513 .dither_down_mode = VOP_REG(RK3188_DSP_CTRL0, 0x1, 10),
514 .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24),
517 static const struct vop_win_data rk3188_vop_win_data[] = {
518 { .base = 0x00, .phy = &rk3188_win0_data,
519 .type = DRM_PLANE_TYPE_PRIMARY },
520 { .base = 0x00, .phy = &rk3188_win1_data,
521 .type = DRM_PLANE_TYPE_CURSOR },
524 static const int rk3188_vop_intrs[] = {
526 * hs_start interrupt fires at frame-start, so serves
527 * the same purpose as dsp_hold in the driver.
535 static const struct vop_intr rk3188_vop_intr = {
536 .intrs = rk3188_vop_intrs,
537 .nintrs = ARRAY_SIZE(rk3188_vop_intrs),
538 .line_flag_num[0] = VOP_REG(RK3188_INT_STATUS, 0xfff, 12),
539 .status = VOP_REG(RK3188_INT_STATUS, 0xf, 0),
540 .enable = VOP_REG(RK3188_INT_STATUS, 0xf, 4),
541 .clear = VOP_REG(RK3188_INT_STATUS, 0xf, 8),
544 static const struct vop_data rk3188_vop = {
545 .intr = &rk3188_vop_intr,
546 .common = &rk3188_common,
547 .modeset = &rk3188_modeset,
548 .output = &rk3188_output,
549 .win = rk3188_vop_win_data,
550 .win_size = ARRAY_SIZE(rk3188_vop_win_data),
551 .feature = VOP_FEATURE_INTERNAL_RGB,
554 static const struct vop_scl_extension rk3288_win_full_scl_ext = {
555 .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
556 .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
557 .cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28),
558 .cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26),
559 .cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24),
560 .yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23),
561 .yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22),
562 .yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20),
563 .yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18),
564 .yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16),
565 .line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15),
566 .cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12),
567 .yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8),
568 .vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7),
569 .vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6),
570 .vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5),
571 .vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4),
572 .bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2),
573 .cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1),
574 .yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0),
575 .lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5),
578 static const struct vop_scl_regs rk3288_win_full_scl = {
579 .ext = &rk3288_win_full_scl_ext,
580 .scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
581 .scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
582 .scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
583 .scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
586 static const struct vop_win_phy rk3288_win01_data = {
587 .scl = &rk3288_win_full_scl,
588 .data_formats = formats_win_full,
589 .nformats = ARRAY_SIZE(formats_win_full),
590 .format_modifiers = format_modifiers_win_full,
591 .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
592 .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
593 .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
594 .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
595 .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
596 .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
597 .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
598 .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
599 .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
600 .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
601 .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
602 .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
603 .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0),
606 static const struct vop_win_phy rk3288_win23_data = {
607 .data_formats = formats_win_lite,
608 .nformats = ARRAY_SIZE(formats_win_lite),
609 .format_modifiers = format_modifiers_win_lite,
610 .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
611 .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
612 .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
613 .rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12),
614 .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0),
615 .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0),
616 .yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0),
617 .yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0),
618 .src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
619 .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0),
622 static const struct vop_modeset rk3288_modeset = {
623 .htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
624 .hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0),
625 .vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
626 .vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0),
627 .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
628 .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
631 static const struct vop_output rk3288_output = {
632 .pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4),
633 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
634 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
635 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
636 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
639 static const struct vop_common rk3288_common = {
640 .standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22),
641 .gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
642 .mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
643 .dither_down_sel = VOP_REG(RK3288_DSP_CTRL1, 0x1, 4),
644 .dither_down_mode = VOP_REG(RK3288_DSP_CTRL1, 0x1, 3),
645 .dither_down_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 2),
646 .pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1),
647 .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
648 .dsp_lut_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 0),
649 .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
650 .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18),
651 .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
652 .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0),
656 * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
657 * special support to get alpha blending working. For now, just use overlay
658 * window 3 for the drm cursor.
661 static const struct vop_win_data rk3288_vop_win_data[] = {
662 { .base = 0x00, .phy = &rk3288_win01_data,
663 .type = DRM_PLANE_TYPE_PRIMARY },
664 { .base = 0x40, .phy = &rk3288_win01_data,
665 .type = DRM_PLANE_TYPE_OVERLAY },
666 { .base = 0x00, .phy = &rk3288_win23_data,
667 .type = DRM_PLANE_TYPE_OVERLAY },
668 { .base = 0x50, .phy = &rk3288_win23_data,
669 .type = DRM_PLANE_TYPE_CURSOR },
672 static const int rk3288_vop_intrs[] = {
679 static const struct vop_intr rk3288_vop_intr = {
680 .intrs = rk3288_vop_intrs,
681 .nintrs = ARRAY_SIZE(rk3288_vop_intrs),
682 .line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12),
683 .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0),
684 .enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4),
685 .clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8),
688 static const struct vop_data rk3288_vop = {
689 .version = VOP_VERSION(3, 1),
690 .feature = VOP_FEATURE_OUTPUT_RGB10,
691 .intr = &rk3288_vop_intr,
692 .common = &rk3288_common,
693 .modeset = &rk3288_modeset,
694 .output = &rk3288_output,
695 .win = rk3288_vop_win_data,
696 .win_size = ARRAY_SIZE(rk3288_vop_win_data),
700 static const int rk3368_vop_intrs[] = {
710 static const struct vop_intr rk3368_vop_intr = {
711 .intrs = rk3368_vop_intrs,
712 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
713 .line_flag_num[0] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 0),
714 .line_flag_num[1] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 16),
715 .status = VOP_REG_MASK_SYNC(RK3368_INTR_STATUS, 0x3fff, 0),
716 .enable = VOP_REG_MASK_SYNC(RK3368_INTR_EN, 0x3fff, 0),
717 .clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0),
720 static const struct vop_win_phy rk3368_win01_data = {
721 .scl = &rk3288_win_full_scl,
722 .data_formats = formats_win_full,
723 .nformats = ARRAY_SIZE(formats_win_full),
724 .format_modifiers = format_modifiers_win_full,
725 .enable = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 0),
726 .format = VOP_REG(RK3368_WIN0_CTRL0, 0x7, 1),
727 .rb_swap = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 12),
728 .x_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 21),
729 .y_mir_en = VOP_REG(RK3368_WIN0_CTRL0, 0x1, 22),
730 .act_info = VOP_REG(RK3368_WIN0_ACT_INFO, 0x1fff1fff, 0),
731 .dsp_info = VOP_REG(RK3368_WIN0_DSP_INFO, 0x0fff0fff, 0),
732 .dsp_st = VOP_REG(RK3368_WIN0_DSP_ST, 0x1fff1fff, 0),
733 .yrgb_mst = VOP_REG(RK3368_WIN0_YRGB_MST, 0xffffffff, 0),
734 .uv_mst = VOP_REG(RK3368_WIN0_CBR_MST, 0xffffffff, 0),
735 .yrgb_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 0),
736 .uv_vir = VOP_REG(RK3368_WIN0_VIR, 0x3fff, 16),
737 .src_alpha_ctl = VOP_REG(RK3368_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
738 .dst_alpha_ctl = VOP_REG(RK3368_WIN0_DST_ALPHA_CTRL, 0xff, 0),
739 .channel = VOP_REG(RK3368_WIN0_CTRL2, 0xff, 0),
742 static const struct vop_win_phy rk3368_win23_data = {
743 .data_formats = formats_win_lite,
744 .nformats = ARRAY_SIZE(formats_win_lite),
745 .format_modifiers = format_modifiers_win_lite,
746 .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
747 .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
748 .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
749 .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20),
750 .y_mir_en = VOP_REG(RK3368_WIN2_CTRL1, 0x1, 15),
751 .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0),
752 .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0),
753 .yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0),
754 .yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 0),
755 .src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
756 .dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xff, 0),
759 static const struct vop_win_data rk3368_vop_win_data[] = {
760 { .base = 0x00, .phy = &rk3368_win01_data,
761 .type = DRM_PLANE_TYPE_PRIMARY },
762 { .base = 0x40, .phy = &rk3368_win01_data,
763 .type = DRM_PLANE_TYPE_OVERLAY },
764 { .base = 0x00, .phy = &rk3368_win23_data,
765 .type = DRM_PLANE_TYPE_OVERLAY },
766 { .base = 0x50, .phy = &rk3368_win23_data,
767 .type = DRM_PLANE_TYPE_CURSOR },
770 static const struct vop_output rk3368_output = {
771 .rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19),
772 .hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23),
773 .edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27),
774 .mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31),
775 .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16),
776 .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20),
777 .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24),
778 .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28),
779 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
780 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
781 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
782 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
785 static const struct vop_misc rk3368_misc = {
786 .global_regdone_en = VOP_REG(RK3368_SYS_CTRL, 0x1, 11),
789 static const struct vop_data rk3368_vop = {
790 .version = VOP_VERSION(3, 2),
791 .intr = &rk3368_vop_intr,
792 .common = &rk3288_common,
793 .modeset = &rk3288_modeset,
794 .output = &rk3368_output,
795 .misc = &rk3368_misc,
796 .win = rk3368_vop_win_data,
797 .win_size = ARRAY_SIZE(rk3368_vop_win_data),
800 static const struct vop_intr rk3366_vop_intr = {
801 .intrs = rk3368_vop_intrs,
802 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
803 .line_flag_num[0] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 0),
804 .line_flag_num[1] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 16),
805 .status = VOP_REG_MASK_SYNC(RK3366_INTR_STATUS0, 0xffff, 0),
806 .enable = VOP_REG_MASK_SYNC(RK3366_INTR_EN0, 0xffff, 0),
807 .clear = VOP_REG_MASK_SYNC(RK3366_INTR_CLEAR0, 0xffff, 0),
810 static const struct vop_data rk3366_vop = {
811 .version = VOP_VERSION(3, 4),
812 .intr = &rk3366_vop_intr,
813 .common = &rk3288_common,
814 .modeset = &rk3288_modeset,
815 .output = &rk3368_output,
816 .misc = &rk3368_misc,
817 .win = rk3368_vop_win_data,
818 .win_size = ARRAY_SIZE(rk3368_vop_win_data),
821 static const struct vop_output rk3399_output = {
822 .dp_dclk_pol = VOP_REG(RK3399_DSP_CTRL1, 0x1, 19),
823 .rgb_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 19),
824 .hdmi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 23),
825 .edp_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 27),
826 .mipi_dclk_pol = VOP_REG(RK3368_DSP_CTRL1, 0x1, 31),
827 .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0x7, 16),
828 .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 16),
829 .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 20),
830 .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 24),
831 .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0x7, 28),
832 .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11),
833 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
834 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
835 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
836 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
837 .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
840 static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win01_data = {
841 .y2r_coefficients = {
842 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 0),
843 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 0, 0xffff, 16),
844 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 0),
845 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 4, 0xffff, 16),
846 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 0),
847 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 8, 0xffff, 16),
848 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 0),
849 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 12, 0xffff, 16),
850 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 16, 0xffff, 0),
851 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 20, 0xffffffff, 0),
852 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 24, 0xffffffff, 0),
853 VOP_REG(RK3399_WIN0_YUV2YUV_Y2R + 28, 0xffffffff, 0),
857 static const struct vop_yuv2yuv_phy rk3399_yuv2yuv_win23_data = { };
859 static const struct vop_win_yuv2yuv_data rk3399_vop_big_win_yuv2yuv_data[] = {
860 { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data,
861 .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1) },
862 { .base = 0x60, .phy = &rk3399_yuv2yuv_win01_data,
863 .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9) },
864 { .base = 0xC0, .phy = &rk3399_yuv2yuv_win23_data },
865 { .base = 0x120, .phy = &rk3399_yuv2yuv_win23_data },
869 static const struct vop_win_phy rk3399_win01_data = {
870 .scl = &rk3288_win_full_scl,
871 .data_formats = formats_win_full,
872 .nformats = ARRAY_SIZE(formats_win_full),
873 .format_modifiers = format_modifiers_win_full_afbc,
874 .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
875 .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
876 .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
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),
890 * rk3399 vop big windows register layout is same as rk3288, but we
891 * have a separate rk3399 win data array here so that we can advertise
892 * AFBC on the primary plane.
894 static const struct vop_win_data rk3399_vop_win_data[] = {
895 { .base = 0x00, .phy = &rk3399_win01_data,
896 .type = DRM_PLANE_TYPE_PRIMARY },
897 { .base = 0x40, .phy = &rk3288_win01_data,
898 .type = DRM_PLANE_TYPE_OVERLAY },
899 { .base = 0x00, .phy = &rk3288_win23_data,
900 .type = DRM_PLANE_TYPE_OVERLAY },
901 { .base = 0x50, .phy = &rk3288_win23_data,
902 .type = DRM_PLANE_TYPE_CURSOR },
905 static const struct vop_afbc rk3399_vop_afbc = {
906 .rstn = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 3),
907 .enable = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 0),
908 .win_sel = VOP_REG(RK3399_AFBCD0_CTRL, 0x3, 1),
909 .format = VOP_REG(RK3399_AFBCD0_CTRL, 0x1f, 16),
910 .hreg_block_split = VOP_REG(RK3399_AFBCD0_CTRL, 0x1, 21),
911 .hdr_ptr = VOP_REG(RK3399_AFBCD0_HDR_PTR, 0xffffffff, 0),
912 .pic_size = VOP_REG(RK3399_AFBCD0_PIC_SIZE, 0xffffffff, 0),
915 static const struct vop_data rk3399_vop_big = {
916 .version = VOP_VERSION(3, 5),
917 .feature = VOP_FEATURE_OUTPUT_RGB10,
918 .intr = &rk3366_vop_intr,
919 .common = &rk3288_common,
920 .modeset = &rk3288_modeset,
921 .output = &rk3399_output,
922 .afbc = &rk3399_vop_afbc,
923 .misc = &rk3368_misc,
924 .win = rk3399_vop_win_data,
925 .win_size = ARRAY_SIZE(rk3399_vop_win_data),
926 .win_yuv2yuv = rk3399_vop_big_win_yuv2yuv_data,
929 static const struct vop_win_data rk3399_vop_lit_win_data[] = {
930 { .base = 0x00, .phy = &rk3368_win01_data,
931 .type = DRM_PLANE_TYPE_PRIMARY },
932 { .base = 0x00, .phy = &rk3368_win23_data,
933 .type = DRM_PLANE_TYPE_CURSOR},
936 static const struct vop_win_yuv2yuv_data rk3399_vop_lit_win_yuv2yuv_data[] = {
937 { .base = 0x00, .phy = &rk3399_yuv2yuv_win01_data,
938 .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1)},
939 { .base = 0x60, .phy = &rk3399_yuv2yuv_win23_data },
942 static const struct vop_data rk3399_vop_lit = {
943 .version = VOP_VERSION(3, 6),
944 .intr = &rk3366_vop_intr,
945 .common = &rk3288_common,
946 .modeset = &rk3288_modeset,
947 .output = &rk3399_output,
948 .misc = &rk3368_misc,
949 .win = rk3399_vop_lit_win_data,
950 .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
951 .win_yuv2yuv = rk3399_vop_lit_win_yuv2yuv_data,
954 static const struct vop_win_data rk3228_vop_win_data[] = {
955 { .base = 0x00, .phy = &rk3288_win01_data,
956 .type = DRM_PLANE_TYPE_PRIMARY },
957 { .base = 0x40, .phy = &rk3288_win01_data,
958 .type = DRM_PLANE_TYPE_CURSOR },
961 static const struct vop_data rk3228_vop = {
962 .version = VOP_VERSION(3, 7),
963 .feature = VOP_FEATURE_OUTPUT_RGB10,
964 .intr = &rk3366_vop_intr,
965 .common = &rk3288_common,
966 .modeset = &rk3288_modeset,
967 .output = &rk3399_output,
968 .misc = &rk3368_misc,
969 .win = rk3228_vop_win_data,
970 .win_size = ARRAY_SIZE(rk3228_vop_win_data),
973 static const struct vop_modeset rk3328_modeset = {
974 .htotal_pw = VOP_REG(RK3328_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
975 .hact_st_end = VOP_REG(RK3328_DSP_HACT_ST_END, 0x1fff1fff, 0),
976 .vtotal_pw = VOP_REG(RK3328_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
977 .vact_st_end = VOP_REG(RK3328_DSP_VACT_ST_END, 0x1fff1fff, 0),
978 .hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
979 .vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
982 static const struct vop_output rk3328_output = {
983 .rgb_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 19),
984 .hdmi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 23),
985 .edp_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 27),
986 .mipi_dclk_pol = VOP_REG(RK3328_DSP_CTRL1, 0x1, 31),
987 .rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12),
988 .hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13),
989 .edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14),
990 .mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15),
991 .rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 16),
992 .hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 20),
993 .edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 24),
994 .mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0x7, 28),
997 static const struct vop_misc rk3328_misc = {
998 .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11),
1001 static const struct vop_common rk3328_common = {
1002 .standby = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 22),
1003 .dither_down_sel = VOP_REG(RK3328_DSP_CTRL1, 0x1, 4),
1004 .dither_down_mode = VOP_REG(RK3328_DSP_CTRL1, 0x1, 3),
1005 .dither_down_en = VOP_REG(RK3328_DSP_CTRL1, 0x1, 2),
1006 .pre_dither_down = VOP_REG(RK3328_DSP_CTRL1, 0x1, 1),
1007 .dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6),
1008 .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18),
1009 .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0),
1010 .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0),
1013 static const struct vop_intr rk3328_vop_intr = {
1014 .intrs = rk3368_vop_intrs,
1015 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
1016 .line_flag_num[0] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 0),
1017 .line_flag_num[1] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 16),
1018 .status = VOP_REG_MASK_SYNC(RK3328_INTR_STATUS0, 0xffff, 0),
1019 .enable = VOP_REG_MASK_SYNC(RK3328_INTR_EN0, 0xffff, 0),
1020 .clear = VOP_REG_MASK_SYNC(RK3328_INTR_CLEAR0, 0xffff, 0),
1023 static const struct vop_win_data rk3328_vop_win_data[] = {
1024 { .base = 0xd0, .phy = &rk3368_win01_data,
1025 .type = DRM_PLANE_TYPE_PRIMARY },
1026 { .base = 0x1d0, .phy = &rk3368_win01_data,
1027 .type = DRM_PLANE_TYPE_OVERLAY },
1028 { .base = 0x2d0, .phy = &rk3368_win01_data,
1029 .type = DRM_PLANE_TYPE_CURSOR },
1032 static const struct vop_data rk3328_vop = {
1033 .version = VOP_VERSION(3, 8),
1034 .feature = VOP_FEATURE_OUTPUT_RGB10,
1035 .intr = &rk3328_vop_intr,
1036 .common = &rk3328_common,
1037 .modeset = &rk3328_modeset,
1038 .output = &rk3328_output,
1039 .misc = &rk3328_misc,
1040 .win = rk3328_vop_win_data,
1041 .win_size = ARRAY_SIZE(rk3328_vop_win_data),
1044 static const struct of_device_id vop_driver_dt_match[] = {
1045 { .compatible = "rockchip,rk3036-vop",
1046 .data = &rk3036_vop },
1047 { .compatible = "rockchip,rk3126-vop",
1048 .data = &rk3126_vop },
1049 { .compatible = "rockchip,px30-vop-big",
1050 .data = &px30_vop_big },
1051 { .compatible = "rockchip,px30-vop-lit",
1052 .data = &px30_vop_lit },
1053 { .compatible = "rockchip,rk3066-vop",
1054 .data = &rk3066_vop },
1055 { .compatible = "rockchip,rk3188-vop",
1056 .data = &rk3188_vop },
1057 { .compatible = "rockchip,rk3288-vop",
1058 .data = &rk3288_vop },
1059 { .compatible = "rockchip,rk3368-vop",
1060 .data = &rk3368_vop },
1061 { .compatible = "rockchip,rk3366-vop",
1062 .data = &rk3366_vop },
1063 { .compatible = "rockchip,rk3399-vop-big",
1064 .data = &rk3399_vop_big },
1065 { .compatible = "rockchip,rk3399-vop-lit",
1066 .data = &rk3399_vop_lit },
1067 { .compatible = "rockchip,rk3228-vop",
1068 .data = &rk3228_vop },
1069 { .compatible = "rockchip,rk3328-vop",
1070 .data = &rk3328_vop },
1073 MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
1075 static int vop_probe(struct platform_device *pdev)
1077 struct device *dev = &pdev->dev;
1079 if (!dev->of_node) {
1080 DRM_DEV_ERROR(dev, "can't find vop devices\n");
1084 return component_add(dev, &vop_component_ops);
1087 static int vop_remove(struct platform_device *pdev)
1089 component_del(&pdev->dev, &vop_component_ops);
1094 struct platform_driver vop_platform_driver = {
1096 .remove = vop_remove,
1098 .name = "rockchip-vop",
1099 .of_match_table = of_match_ptr(vop_driver_dt_match),