Linux kernel mirror (for testing)
git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel
os
linux
1/*
2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3 * Author:Mark Yao <mark.yao@rock-chips.com>
4 *
5 * This software is licensed under the terms of the GNU General Public
6 * License version 2, as published by the Free Software Foundation, and
7 * may be copied, distributed, and modified under those terms.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 */
14
15#include <drm/drmP.h>
16
17#include <linux/kernel.h>
18#include <linux/component.h>
19
20#include "rockchip_drm_vop.h"
21#include "rockchip_vop_reg.h"
22
23#define _VOP_REG(off, _mask, _shift, _write_mask, _relaxed) \
24 { \
25 .offset = off, \
26 .mask = _mask, \
27 .shift = _shift, \
28 .write_mask = _write_mask, \
29 .relaxed = _relaxed, \
30 }
31
32#define VOP_REG(off, _mask, _shift) \
33 _VOP_REG(off, _mask, _shift, false, true)
34
35#define VOP_REG_SYNC(off, _mask, _shift) \
36 _VOP_REG(off, _mask, _shift, false, false)
37
38#define VOP_REG_MASK_SYNC(off, _mask, _shift) \
39 _VOP_REG(off, _mask, _shift, true, false)
40
41static const uint32_t formats_win_full[] = {
42 DRM_FORMAT_XRGB8888,
43 DRM_FORMAT_ARGB8888,
44 DRM_FORMAT_XBGR8888,
45 DRM_FORMAT_ABGR8888,
46 DRM_FORMAT_RGB888,
47 DRM_FORMAT_BGR888,
48 DRM_FORMAT_RGB565,
49 DRM_FORMAT_BGR565,
50 DRM_FORMAT_NV12,
51 DRM_FORMAT_NV16,
52 DRM_FORMAT_NV24,
53};
54
55static const uint32_t formats_win_lite[] = {
56 DRM_FORMAT_XRGB8888,
57 DRM_FORMAT_ARGB8888,
58 DRM_FORMAT_XBGR8888,
59 DRM_FORMAT_ABGR8888,
60 DRM_FORMAT_RGB888,
61 DRM_FORMAT_BGR888,
62 DRM_FORMAT_RGB565,
63 DRM_FORMAT_BGR565,
64};
65
66static const struct vop_scl_regs rk3036_win_scl = {
67 .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
68 .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
69 .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
70 .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
71};
72
73static const struct vop_win_phy rk3036_win0_data = {
74 .scl = &rk3036_win_scl,
75 .data_formats = formats_win_full,
76 .nformats = ARRAY_SIZE(formats_win_full),
77 .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
78 .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
79 .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
80 .act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0),
81 .dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0),
82 .dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0),
83 .yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0),
84 .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0),
85 .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0),
86 .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16),
87};
88
89static const struct vop_win_phy rk3036_win1_data = {
90 .data_formats = formats_win_lite,
91 .nformats = ARRAY_SIZE(formats_win_lite),
92 .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
93 .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
94 .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
95 .act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0),
96 .dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0),
97 .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0),
98 .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0),
99 .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
100};
101
102static const struct vop_win_data rk3036_vop_win_data[] = {
103 { .base = 0x00, .phy = &rk3036_win0_data,
104 .type = DRM_PLANE_TYPE_PRIMARY },
105 { .base = 0x00, .phy = &rk3036_win1_data,
106 .type = DRM_PLANE_TYPE_CURSOR },
107};
108
109static const int rk3036_vop_intrs[] = {
110 DSP_HOLD_VALID_INTR,
111 FS_INTR,
112 LINE_FLAG_INTR,
113 BUS_ERROR_INTR,
114};
115
116static const struct vop_intr rk3036_intr = {
117 .intrs = rk3036_vop_intrs,
118 .nintrs = ARRAY_SIZE(rk3036_vop_intrs),
119 .line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12),
120 .status = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 0),
121 .enable = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 4),
122 .clear = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 8),
123};
124
125static const struct vop_modeset rk3036_modeset = {
126 .htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
127 .hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0),
128 .vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
129 .vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0),
130};
131
132static const struct vop_output rk3036_output = {
133 .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
134};
135
136static const struct vop_common rk3036_common = {
137 .standby = VOP_REG_SYNC(RK3036_SYS_CTRL, 0x1, 30),
138 .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0),
139 .dsp_blank = VOP_REG(RK3036_DSP_CTRL1, 0x1, 24),
140 .cfg_done = VOP_REG_SYNC(RK3036_REG_CFG_DONE, 0x1, 0),
141};
142
143static const struct vop_data rk3036_vop = {
144 .intr = &rk3036_intr,
145 .common = &rk3036_common,
146 .modeset = &rk3036_modeset,
147 .output = &rk3036_output,
148 .win = rk3036_vop_win_data,
149 .win_size = ARRAY_SIZE(rk3036_vop_win_data),
150};
151
152static const struct vop_win_phy rk3126_win1_data = {
153 .data_formats = formats_win_lite,
154 .nformats = ARRAY_SIZE(formats_win_lite),
155 .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
156 .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
157 .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
158 .dsp_info = VOP_REG(RK3126_WIN1_DSP_INFO, 0x0fff0fff, 0),
159 .dsp_st = VOP_REG(RK3126_WIN1_DSP_ST, 0x1fff1fff, 0),
160 .yrgb_mst = VOP_REG(RK3126_WIN1_MST, 0xffffffff, 0),
161 .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
162};
163
164static const struct vop_win_data rk3126_vop_win_data[] = {
165 { .base = 0x00, .phy = &rk3036_win0_data,
166 .type = DRM_PLANE_TYPE_PRIMARY },
167 { .base = 0x00, .phy = &rk3126_win1_data,
168 .type = DRM_PLANE_TYPE_CURSOR },
169};
170
171static const struct vop_data rk3126_vop = {
172 .intr = &rk3036_intr,
173 .common = &rk3036_common,
174 .modeset = &rk3036_modeset,
175 .output = &rk3036_output,
176 .win = rk3126_vop_win_data,
177 .win_size = ARRAY_SIZE(rk3126_vop_win_data),
178};
179
180static const int px30_vop_intrs[] = {
181 FS_INTR,
182 0, 0,
183 LINE_FLAG_INTR,
184 0,
185 BUS_ERROR_INTR,
186 0, 0,
187 DSP_HOLD_VALID_INTR,
188};
189
190static const struct vop_intr px30_intr = {
191 .intrs = px30_vop_intrs,
192 .nintrs = ARRAY_SIZE(px30_vop_intrs),
193 .line_flag_num[0] = VOP_REG(PX30_LINE_FLAG, 0xfff, 0),
194 .status = VOP_REG_MASK_SYNC(PX30_INTR_STATUS, 0xffff, 0),
195 .enable = VOP_REG_MASK_SYNC(PX30_INTR_EN, 0xffff, 0),
196 .clear = VOP_REG_MASK_SYNC(PX30_INTR_CLEAR, 0xffff, 0),
197};
198
199static const struct vop_common px30_common = {
200 .standby = VOP_REG_SYNC(PX30_SYS_CTRL2, 0x1, 1),
201 .out_mode = VOP_REG(PX30_DSP_CTRL2, 0xf, 16),
202 .dsp_blank = VOP_REG(PX30_DSP_CTRL2, 0x1, 14),
203 .cfg_done = VOP_REG_SYNC(PX30_REG_CFG_DONE, 0x1, 0),
204};
205
206static const struct vop_modeset px30_modeset = {
207 .htotal_pw = VOP_REG(PX30_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
208 .hact_st_end = VOP_REG(PX30_DSP_HACT_ST_END, 0x0fff0fff, 0),
209 .vtotal_pw = VOP_REG(PX30_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
210 .vact_st_end = VOP_REG(PX30_DSP_VACT_ST_END, 0x0fff0fff, 0),
211};
212
213static const struct vop_output px30_output = {
214 .rgb_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0xf, 1),
215 .mipi_pin_pol = VOP_REG(PX30_DSP_CTRL0, 0xf, 25),
216 .rgb_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 0),
217 .mipi_en = VOP_REG(PX30_DSP_CTRL0, 0x1, 24),
218};
219
220static const struct vop_scl_regs px30_win_scl = {
221 .scale_yrgb_x = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
222 .scale_yrgb_y = VOP_REG(PX30_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
223 .scale_cbcr_x = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
224 .scale_cbcr_y = VOP_REG(PX30_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
225};
226
227static const struct vop_win_phy px30_win0_data = {
228 .scl = &px30_win_scl,
229 .data_formats = formats_win_full,
230 .nformats = ARRAY_SIZE(formats_win_full),
231 .enable = VOP_REG(PX30_WIN0_CTRL0, 0x1, 0),
232 .format = VOP_REG(PX30_WIN0_CTRL0, 0x7, 1),
233 .rb_swap = VOP_REG(PX30_WIN0_CTRL0, 0x1, 12),
234 .act_info = VOP_REG(PX30_WIN0_ACT_INFO, 0xffffffff, 0),
235 .dsp_info = VOP_REG(PX30_WIN0_DSP_INFO, 0xffffffff, 0),
236 .dsp_st = VOP_REG(PX30_WIN0_DSP_ST, 0xffffffff, 0),
237 .yrgb_mst = VOP_REG(PX30_WIN0_YRGB_MST0, 0xffffffff, 0),
238 .uv_mst = VOP_REG(PX30_WIN0_CBR_MST0, 0xffffffff, 0),
239 .yrgb_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 0),
240 .uv_vir = VOP_REG(PX30_WIN0_VIR, 0x1fff, 16),
241};
242
243static const struct vop_win_phy px30_win1_data = {
244 .data_formats = formats_win_lite,
245 .nformats = ARRAY_SIZE(formats_win_lite),
246 .enable = VOP_REG(PX30_WIN1_CTRL0, 0x1, 0),
247 .format = VOP_REG(PX30_WIN1_CTRL0, 0x7, 4),
248 .rb_swap = VOP_REG(PX30_WIN1_CTRL0, 0x1, 12),
249 .dsp_info = VOP_REG(PX30_WIN1_DSP_INFO, 0xffffffff, 0),
250 .dsp_st = VOP_REG(PX30_WIN1_DSP_ST, 0xffffffff, 0),
251 .yrgb_mst = VOP_REG(PX30_WIN1_MST, 0xffffffff, 0),
252 .yrgb_vir = VOP_REG(PX30_WIN1_VIR, 0x1fff, 0),
253};
254
255static const struct vop_win_phy px30_win2_data = {
256 .data_formats = formats_win_lite,
257 .nformats = ARRAY_SIZE(formats_win_lite),
258 .gate = VOP_REG(PX30_WIN2_CTRL0, 0x1, 4),
259 .enable = VOP_REG(PX30_WIN2_CTRL0, 0x1, 0),
260 .format = VOP_REG(PX30_WIN2_CTRL0, 0x3, 5),
261 .rb_swap = VOP_REG(PX30_WIN2_CTRL0, 0x1, 20),
262 .dsp_info = VOP_REG(PX30_WIN2_DSP_INFO0, 0x0fff0fff, 0),
263 .dsp_st = VOP_REG(PX30_WIN2_DSP_ST0, 0x1fff1fff, 0),
264 .yrgb_mst = VOP_REG(PX30_WIN2_MST0, 0xffffffff, 0),
265 .yrgb_vir = VOP_REG(PX30_WIN2_VIR0_1, 0x1fff, 0),
266};
267
268static const struct vop_win_data px30_vop_big_win_data[] = {
269 { .base = 0x00, .phy = &px30_win0_data,
270 .type = DRM_PLANE_TYPE_PRIMARY },
271 { .base = 0x00, .phy = &px30_win1_data,
272 .type = DRM_PLANE_TYPE_OVERLAY },
273 { .base = 0x00, .phy = &px30_win2_data,
274 .type = DRM_PLANE_TYPE_CURSOR },
275};
276
277static const struct vop_data px30_vop_big = {
278 .intr = &px30_intr,
279 .feature = VOP_FEATURE_INTERNAL_RGB,
280 .common = &px30_common,
281 .modeset = &px30_modeset,
282 .output = &px30_output,
283 .win = px30_vop_big_win_data,
284 .win_size = ARRAY_SIZE(px30_vop_big_win_data),
285};
286
287static const struct vop_win_data px30_vop_lit_win_data[] = {
288 { .base = 0x00, .phy = &px30_win1_data,
289 .type = DRM_PLANE_TYPE_PRIMARY },
290};
291
292static const struct vop_data px30_vop_lit = {
293 .intr = &px30_intr,
294 .feature = VOP_FEATURE_INTERNAL_RGB,
295 .common = &px30_common,
296 .modeset = &px30_modeset,
297 .output = &px30_output,
298 .win = px30_vop_lit_win_data,
299 .win_size = ARRAY_SIZE(px30_vop_lit_win_data),
300};
301
302static const struct vop_scl_regs rk3188_win_scl = {
303 .scale_yrgb_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
304 .scale_yrgb_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
305 .scale_cbcr_x = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
306 .scale_cbcr_y = VOP_REG(RK3188_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
307};
308
309static const struct vop_win_phy rk3188_win0_data = {
310 .scl = &rk3188_win_scl,
311 .data_formats = formats_win_full,
312 .nformats = ARRAY_SIZE(formats_win_full),
313 .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 0),
314 .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 3),
315 .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 15),
316 .act_info = VOP_REG(RK3188_WIN0_ACT_INFO, 0x1fff1fff, 0),
317 .dsp_info = VOP_REG(RK3188_WIN0_DSP_INFO, 0x0fff0fff, 0),
318 .dsp_st = VOP_REG(RK3188_WIN0_DSP_ST, 0x1fff1fff, 0),
319 .yrgb_mst = VOP_REG(RK3188_WIN0_YRGB_MST0, 0xffffffff, 0),
320 .uv_mst = VOP_REG(RK3188_WIN0_CBR_MST0, 0xffffffff, 0),
321 .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 0),
322};
323
324static const struct vop_win_phy rk3188_win1_data = {
325 .data_formats = formats_win_lite,
326 .nformats = ARRAY_SIZE(formats_win_lite),
327 .enable = VOP_REG(RK3188_SYS_CTRL, 0x1, 1),
328 .format = VOP_REG(RK3188_SYS_CTRL, 0x7, 6),
329 .rb_swap = VOP_REG(RK3188_SYS_CTRL, 0x1, 19),
330 /* no act_info on window1 */
331 .dsp_info = VOP_REG(RK3188_WIN1_DSP_INFO, 0x07ff07ff, 0),
332 .dsp_st = VOP_REG(RK3188_WIN1_DSP_ST, 0x0fff0fff, 0),
333 .yrgb_mst = VOP_REG(RK3188_WIN1_MST, 0xffffffff, 0),
334 .yrgb_vir = VOP_REG(RK3188_WIN_VIR, 0x1fff, 16),
335};
336
337static const struct vop_modeset rk3188_modeset = {
338 .htotal_pw = VOP_REG(RK3188_DSP_HTOTAL_HS_END, 0x0fff0fff, 0),
339 .hact_st_end = VOP_REG(RK3188_DSP_HACT_ST_END, 0x0fff0fff, 0),
340 .vtotal_pw = VOP_REG(RK3188_DSP_VTOTAL_VS_END, 0x0fff0fff, 0),
341 .vact_st_end = VOP_REG(RK3188_DSP_VACT_ST_END, 0x0fff0fff, 0),
342};
343
344static const struct vop_output rk3188_output = {
345 .pin_pol = VOP_REG(RK3188_DSP_CTRL0, 0xf, 4),
346};
347
348static const struct vop_common rk3188_common = {
349 .gate_en = VOP_REG(RK3188_SYS_CTRL, 0x1, 31),
350 .standby = VOP_REG(RK3188_SYS_CTRL, 0x1, 30),
351 .out_mode = VOP_REG(RK3188_DSP_CTRL0, 0xf, 0),
352 .cfg_done = VOP_REG(RK3188_REG_CFG_DONE, 0x1, 0),
353 .dsp_blank = VOP_REG(RK3188_DSP_CTRL1, 0x3, 24),
354};
355
356static const struct vop_win_data rk3188_vop_win_data[] = {
357 { .base = 0x00, .phy = &rk3188_win0_data,
358 .type = DRM_PLANE_TYPE_PRIMARY },
359 { .base = 0x00, .phy = &rk3188_win1_data,
360 .type = DRM_PLANE_TYPE_CURSOR },
361};
362
363static const int rk3188_vop_intrs[] = {
364 /*
365 * hs_start interrupt fires at frame-start, so serves
366 * the same purpose as dsp_hold in the driver.
367 */
368 DSP_HOLD_VALID_INTR,
369 FS_INTR,
370 LINE_FLAG_INTR,
371 BUS_ERROR_INTR,
372};
373
374static const struct vop_intr rk3188_vop_intr = {
375 .intrs = rk3188_vop_intrs,
376 .nintrs = ARRAY_SIZE(rk3188_vop_intrs),
377 .line_flag_num[0] = VOP_REG(RK3188_INT_STATUS, 0xfff, 12),
378 .status = VOP_REG(RK3188_INT_STATUS, 0xf, 0),
379 .enable = VOP_REG(RK3188_INT_STATUS, 0xf, 4),
380 .clear = VOP_REG(RK3188_INT_STATUS, 0xf, 8),
381};
382
383static const struct vop_data rk3188_vop = {
384 .intr = &rk3188_vop_intr,
385 .common = &rk3188_common,
386 .modeset = &rk3188_modeset,
387 .output = &rk3188_output,
388 .win = rk3188_vop_win_data,
389 .win_size = ARRAY_SIZE(rk3188_vop_win_data),
390 .feature = VOP_FEATURE_INTERNAL_RGB,
391};
392
393static const struct vop_scl_extension rk3288_win_full_scl_ext = {
394 .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
395 .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
396 .cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28),
397 .cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26),
398 .cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24),
399 .yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23),
400 .yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22),
401 .yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20),
402 .yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18),
403 .yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16),
404 .line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15),
405 .cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12),
406 .yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8),
407 .vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7),
408 .vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6),
409 .vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5),
410 .vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4),
411 .bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2),
412 .cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1),
413 .yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0),
414 .lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5),
415};
416
417static const struct vop_scl_regs rk3288_win_full_scl = {
418 .ext = &rk3288_win_full_scl_ext,
419 .scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
420 .scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
421 .scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
422 .scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
423};
424
425static const struct vop_win_phy rk3288_win01_data = {
426 .scl = &rk3288_win_full_scl,
427 .data_formats = formats_win_full,
428 .nformats = ARRAY_SIZE(formats_win_full),
429 .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
430 .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
431 .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
432 .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
433 .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
434 .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
435 .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
436 .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
437 .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
438 .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
439 .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
440 .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
441 .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0),
442};
443
444static const struct vop_win_phy rk3288_win23_data = {
445 .data_formats = formats_win_lite,
446 .nformats = ARRAY_SIZE(formats_win_lite),
447 .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
448 .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
449 .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
450 .rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12),
451 .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0),
452 .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0),
453 .yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0),
454 .yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0),
455 .src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
456 .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0),
457};
458
459static const struct vop_modeset rk3288_modeset = {
460 .htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
461 .hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0),
462 .vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
463 .vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0),
464 .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
465 .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
466};
467
468static const struct vop_output rk3288_output = {
469 .pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4),
470 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
471 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
472 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
473 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
474};
475
476static const struct vop_common rk3288_common = {
477 .standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22),
478 .gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
479 .mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
480 .pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1),
481 .dither_down = VOP_REG(RK3288_DSP_CTRL1, 0xf, 1),
482 .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
483 .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
484 .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18),
485 .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
486 .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0),
487};
488
489/*
490 * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
491 * special support to get alpha blending working. For now, just use overlay
492 * window 3 for the drm cursor.
493 *
494 */
495static const struct vop_win_data rk3288_vop_win_data[] = {
496 { .base = 0x00, .phy = &rk3288_win01_data,
497 .type = DRM_PLANE_TYPE_PRIMARY },
498 { .base = 0x40, .phy = &rk3288_win01_data,
499 .type = DRM_PLANE_TYPE_OVERLAY },
500 { .base = 0x00, .phy = &rk3288_win23_data,
501 .type = DRM_PLANE_TYPE_OVERLAY },
502 { .base = 0x50, .phy = &rk3288_win23_data,
503 .type = DRM_PLANE_TYPE_CURSOR },
504};
505
506static const int rk3288_vop_intrs[] = {
507 DSP_HOLD_VALID_INTR,
508 FS_INTR,
509 LINE_FLAG_INTR,
510 BUS_ERROR_INTR,
511};
512
513static const struct vop_intr rk3288_vop_intr = {
514 .intrs = rk3288_vop_intrs,
515 .nintrs = ARRAY_SIZE(rk3288_vop_intrs),
516 .line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12),
517 .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0),
518 .enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4),
519 .clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8),
520};
521
522static const struct vop_data rk3288_vop = {
523 .version = VOP_VERSION(3, 1),
524 .feature = VOP_FEATURE_OUTPUT_RGB10,
525 .intr = &rk3288_vop_intr,
526 .common = &rk3288_common,
527 .modeset = &rk3288_modeset,
528 .output = &rk3288_output,
529 .win = rk3288_vop_win_data,
530 .win_size = ARRAY_SIZE(rk3288_vop_win_data),
531};
532
533static const int rk3368_vop_intrs[] = {
534 FS_INTR,
535 0, 0,
536 LINE_FLAG_INTR,
537 0,
538 BUS_ERROR_INTR,
539 0, 0, 0, 0, 0, 0, 0,
540 DSP_HOLD_VALID_INTR,
541};
542
543static const struct vop_intr rk3368_vop_intr = {
544 .intrs = rk3368_vop_intrs,
545 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
546 .line_flag_num[0] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 0),
547 .line_flag_num[1] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 16),
548 .status = VOP_REG_MASK_SYNC(RK3368_INTR_STATUS, 0x3fff, 0),
549 .enable = VOP_REG_MASK_SYNC(RK3368_INTR_EN, 0x3fff, 0),
550 .clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0),
551};
552
553static const struct vop_win_phy rk3368_win23_data = {
554 .data_formats = formats_win_lite,
555 .nformats = ARRAY_SIZE(formats_win_lite),
556 .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
557 .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
558 .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
559 .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20),
560 .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0),
561 .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0),
562 .yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0),
563 .yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 0),
564 .src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
565 .dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xff, 0),
566};
567
568static const struct vop_win_data rk3368_vop_win_data[] = {
569 { .base = 0x00, .phy = &rk3288_win01_data,
570 .type = DRM_PLANE_TYPE_PRIMARY },
571 { .base = 0x40, .phy = &rk3288_win01_data,
572 .type = DRM_PLANE_TYPE_OVERLAY },
573 { .base = 0x00, .phy = &rk3368_win23_data,
574 .type = DRM_PLANE_TYPE_OVERLAY },
575 { .base = 0x50, .phy = &rk3368_win23_data,
576 .type = DRM_PLANE_TYPE_CURSOR },
577};
578
579static const struct vop_output rk3368_output = {
580 .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16),
581 .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20),
582 .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24),
583 .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28),
584 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
585 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
586 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
587 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
588};
589
590static const struct vop_misc rk3368_misc = {
591 .global_regdone_en = VOP_REG(RK3368_SYS_CTRL, 0x1, 11),
592};
593
594static const struct vop_data rk3368_vop = {
595 .version = VOP_VERSION(3, 2),
596 .intr = &rk3368_vop_intr,
597 .common = &rk3288_common,
598 .modeset = &rk3288_modeset,
599 .output = &rk3368_output,
600 .misc = &rk3368_misc,
601 .win = rk3368_vop_win_data,
602 .win_size = ARRAY_SIZE(rk3368_vop_win_data),
603};
604
605static const struct vop_intr rk3366_vop_intr = {
606 .intrs = rk3368_vop_intrs,
607 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
608 .line_flag_num[0] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 0),
609 .line_flag_num[1] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 16),
610 .status = VOP_REG_MASK_SYNC(RK3366_INTR_STATUS0, 0xffff, 0),
611 .enable = VOP_REG_MASK_SYNC(RK3366_INTR_EN0, 0xffff, 0),
612 .clear = VOP_REG_MASK_SYNC(RK3366_INTR_CLEAR0, 0xffff, 0),
613};
614
615static const struct vop_data rk3366_vop = {
616 .version = VOP_VERSION(3, 4),
617 .intr = &rk3366_vop_intr,
618 .common = &rk3288_common,
619 .modeset = &rk3288_modeset,
620 .output = &rk3368_output,
621 .misc = &rk3368_misc,
622 .win = rk3368_vop_win_data,
623 .win_size = ARRAY_SIZE(rk3368_vop_win_data),
624};
625
626static const struct vop_output rk3399_output = {
627 .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16),
628 .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16),
629 .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20),
630 .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24),
631 .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28),
632 .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11),
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),
637 .mipi_dual_channel_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 3),
638};
639
640static const struct vop_data rk3399_vop_big = {
641 .version = VOP_VERSION(3, 5),
642 .feature = VOP_FEATURE_OUTPUT_RGB10,
643 .intr = &rk3366_vop_intr,
644 .common = &rk3288_common,
645 .modeset = &rk3288_modeset,
646 .output = &rk3399_output,
647 .misc = &rk3368_misc,
648 .win = rk3368_vop_win_data,
649 .win_size = ARRAY_SIZE(rk3368_vop_win_data),
650};
651
652static const struct vop_win_data rk3399_vop_lit_win_data[] = {
653 { .base = 0x00, .phy = &rk3288_win01_data,
654 .type = DRM_PLANE_TYPE_PRIMARY },
655 { .base = 0x00, .phy = &rk3368_win23_data,
656 .type = DRM_PLANE_TYPE_CURSOR},
657};
658
659static const struct vop_data rk3399_vop_lit = {
660 .version = VOP_VERSION(3, 6),
661 .intr = &rk3366_vop_intr,
662 .common = &rk3288_common,
663 .modeset = &rk3288_modeset,
664 .output = &rk3399_output,
665 .misc = &rk3368_misc,
666 .win = rk3399_vop_lit_win_data,
667 .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
668};
669
670static const struct vop_win_data rk3228_vop_win_data[] = {
671 { .base = 0x00, .phy = &rk3288_win01_data,
672 .type = DRM_PLANE_TYPE_PRIMARY },
673 { .base = 0x40, .phy = &rk3288_win01_data,
674 .type = DRM_PLANE_TYPE_CURSOR },
675};
676
677static const struct vop_data rk3228_vop = {
678 .version = VOP_VERSION(3, 7),
679 .feature = VOP_FEATURE_OUTPUT_RGB10,
680 .intr = &rk3366_vop_intr,
681 .common = &rk3288_common,
682 .modeset = &rk3288_modeset,
683 .output = &rk3399_output,
684 .misc = &rk3368_misc,
685 .win = rk3228_vop_win_data,
686 .win_size = ARRAY_SIZE(rk3228_vop_win_data),
687};
688
689static const struct vop_modeset rk3328_modeset = {
690 .htotal_pw = VOP_REG(RK3328_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
691 .hact_st_end = VOP_REG(RK3328_DSP_HACT_ST_END, 0x1fff1fff, 0),
692 .vtotal_pw = VOP_REG(RK3328_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
693 .vact_st_end = VOP_REG(RK3328_DSP_VACT_ST_END, 0x1fff1fff, 0),
694 .hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
695 .vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
696};
697
698static const struct vop_output rk3328_output = {
699 .rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12),
700 .hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13),
701 .edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14),
702 .mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15),
703 .rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 16),
704 .hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 20),
705 .edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 24),
706 .mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 28),
707};
708
709static const struct vop_misc rk3328_misc = {
710 .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11),
711};
712
713static const struct vop_common rk3328_common = {
714 .standby = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 22),
715 .dither_down = VOP_REG(RK3328_DSP_CTRL1, 0xf, 1),
716 .dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6),
717 .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18),
718 .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0),
719 .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0),
720};
721
722static const struct vop_intr rk3328_vop_intr = {
723 .intrs = rk3368_vop_intrs,
724 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
725 .line_flag_num[0] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 0),
726 .line_flag_num[1] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 16),
727 .status = VOP_REG_MASK_SYNC(RK3328_INTR_STATUS0, 0xffff, 0),
728 .enable = VOP_REG_MASK_SYNC(RK3328_INTR_EN0, 0xffff, 0),
729 .clear = VOP_REG_MASK_SYNC(RK3328_INTR_CLEAR0, 0xffff, 0),
730};
731
732static const struct vop_win_data rk3328_vop_win_data[] = {
733 { .base = 0xd0, .phy = &rk3288_win01_data,
734 .type = DRM_PLANE_TYPE_PRIMARY },
735 { .base = 0x1d0, .phy = &rk3288_win01_data,
736 .type = DRM_PLANE_TYPE_OVERLAY },
737 { .base = 0x2d0, .phy = &rk3288_win01_data,
738 .type = DRM_PLANE_TYPE_CURSOR },
739};
740
741static const struct vop_data rk3328_vop = {
742 .version = VOP_VERSION(3, 8),
743 .feature = VOP_FEATURE_OUTPUT_RGB10,
744 .intr = &rk3328_vop_intr,
745 .common = &rk3328_common,
746 .modeset = &rk3328_modeset,
747 .output = &rk3328_output,
748 .misc = &rk3328_misc,
749 .win = rk3328_vop_win_data,
750 .win_size = ARRAY_SIZE(rk3328_vop_win_data),
751};
752
753static const struct of_device_id vop_driver_dt_match[] = {
754 { .compatible = "rockchip,rk3036-vop",
755 .data = &rk3036_vop },
756 { .compatible = "rockchip,rk3126-vop",
757 .data = &rk3126_vop },
758 { .compatible = "rockchip,px30-vop-big",
759 .data = &px30_vop_big },
760 { .compatible = "rockchip,px30-vop-lit",
761 .data = &px30_vop_lit },
762 { .compatible = "rockchip,rk3188-vop",
763 .data = &rk3188_vop },
764 { .compatible = "rockchip,rk3288-vop",
765 .data = &rk3288_vop },
766 { .compatible = "rockchip,rk3368-vop",
767 .data = &rk3368_vop },
768 { .compatible = "rockchip,rk3366-vop",
769 .data = &rk3366_vop },
770 { .compatible = "rockchip,rk3399-vop-big",
771 .data = &rk3399_vop_big },
772 { .compatible = "rockchip,rk3399-vop-lit",
773 .data = &rk3399_vop_lit },
774 { .compatible = "rockchip,rk3228-vop",
775 .data = &rk3228_vop },
776 { .compatible = "rockchip,rk3328-vop",
777 .data = &rk3328_vop },
778 {},
779};
780MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
781
782static int vop_probe(struct platform_device *pdev)
783{
784 struct device *dev = &pdev->dev;
785
786 if (!dev->of_node) {
787 DRM_DEV_ERROR(dev, "can't find vop devices\n");
788 return -ENODEV;
789 }
790
791 return component_add(dev, &vop_component_ops);
792}
793
794static int vop_remove(struct platform_device *pdev)
795{
796 component_del(&pdev->dev, &vop_component_ops);
797
798 return 0;
799}
800
801struct platform_driver vop_platform_driver = {
802 .probe = vop_probe,
803 .remove = vop_remove,
804 .driver = {
805 .name = "rockchip-vop",
806 .of_match_table = of_match_ptr(vop_driver_dt_match),
807 },
808};