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 0,
365 FS_INTR,
366 LINE_FLAG_INTR,
367 BUS_ERROR_INTR,
368};
369
370static const struct vop_intr rk3188_vop_intr = {
371 .intrs = rk3188_vop_intrs,
372 .nintrs = ARRAY_SIZE(rk3188_vop_intrs),
373 .line_flag_num[0] = VOP_REG(RK3188_INT_STATUS, 0xfff, 12),
374 .status = VOP_REG(RK3188_INT_STATUS, 0xf, 0),
375 .enable = VOP_REG(RK3188_INT_STATUS, 0xf, 4),
376 .clear = VOP_REG(RK3188_INT_STATUS, 0xf, 8),
377};
378
379static const struct vop_data rk3188_vop = {
380 .intr = &rk3188_vop_intr,
381 .common = &rk3188_common,
382 .modeset = &rk3188_modeset,
383 .output = &rk3188_output,
384 .win = rk3188_vop_win_data,
385 .win_size = ARRAY_SIZE(rk3188_vop_win_data),
386 .feature = VOP_FEATURE_INTERNAL_RGB,
387};
388
389static const struct vop_scl_extension rk3288_win_full_scl_ext = {
390 .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
391 .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
392 .cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28),
393 .cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26),
394 .cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24),
395 .yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23),
396 .yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22),
397 .yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20),
398 .yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18),
399 .yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16),
400 .line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15),
401 .cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12),
402 .yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8),
403 .vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7),
404 .vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6),
405 .vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5),
406 .vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4),
407 .bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2),
408 .cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1),
409 .yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0),
410 .lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5),
411};
412
413static const struct vop_scl_regs rk3288_win_full_scl = {
414 .ext = &rk3288_win_full_scl_ext,
415 .scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
416 .scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
417 .scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
418 .scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
419};
420
421static const struct vop_win_phy rk3288_win01_data = {
422 .scl = &rk3288_win_full_scl,
423 .data_formats = formats_win_full,
424 .nformats = ARRAY_SIZE(formats_win_full),
425 .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
426 .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
427 .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
428 .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
429 .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
430 .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
431 .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
432 .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
433 .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
434 .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
435 .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
436 .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
437 .channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0),
438};
439
440static const struct vop_win_phy rk3288_win23_data = {
441 .data_formats = formats_win_lite,
442 .nformats = ARRAY_SIZE(formats_win_lite),
443 .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
444 .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
445 .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
446 .rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12),
447 .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0),
448 .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0),
449 .yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0),
450 .yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0),
451 .src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
452 .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0),
453};
454
455static const struct vop_modeset rk3288_modeset = {
456 .htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
457 .hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0),
458 .vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
459 .vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0),
460 .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
461 .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
462};
463
464static const struct vop_output rk3288_output = {
465 .pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4),
466 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
467 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
468 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
469 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
470};
471
472static const struct vop_common rk3288_common = {
473 .standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22),
474 .gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
475 .mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
476 .pre_dither_down = VOP_REG(RK3288_DSP_CTRL1, 0x1, 1),
477 .dither_down = VOP_REG(RK3288_DSP_CTRL1, 0xf, 1),
478 .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
479 .data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
480 .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18),
481 .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
482 .cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0),
483};
484
485/*
486 * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
487 * special support to get alpha blending working. For now, just use overlay
488 * window 3 for the drm cursor.
489 *
490 */
491static const struct vop_win_data rk3288_vop_win_data[] = {
492 { .base = 0x00, .phy = &rk3288_win01_data,
493 .type = DRM_PLANE_TYPE_PRIMARY },
494 { .base = 0x40, .phy = &rk3288_win01_data,
495 .type = DRM_PLANE_TYPE_OVERLAY },
496 { .base = 0x00, .phy = &rk3288_win23_data,
497 .type = DRM_PLANE_TYPE_OVERLAY },
498 { .base = 0x50, .phy = &rk3288_win23_data,
499 .type = DRM_PLANE_TYPE_CURSOR },
500};
501
502static const int rk3288_vop_intrs[] = {
503 DSP_HOLD_VALID_INTR,
504 FS_INTR,
505 LINE_FLAG_INTR,
506 BUS_ERROR_INTR,
507};
508
509static const struct vop_intr rk3288_vop_intr = {
510 .intrs = rk3288_vop_intrs,
511 .nintrs = ARRAY_SIZE(rk3288_vop_intrs),
512 .line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12),
513 .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0),
514 .enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4),
515 .clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8),
516};
517
518static const struct vop_data rk3288_vop = {
519 .version = VOP_VERSION(3, 1),
520 .feature = VOP_FEATURE_OUTPUT_RGB10,
521 .intr = &rk3288_vop_intr,
522 .common = &rk3288_common,
523 .modeset = &rk3288_modeset,
524 .output = &rk3288_output,
525 .win = rk3288_vop_win_data,
526 .win_size = ARRAY_SIZE(rk3288_vop_win_data),
527};
528
529static const int rk3368_vop_intrs[] = {
530 FS_INTR,
531 0, 0,
532 LINE_FLAG_INTR,
533 0,
534 BUS_ERROR_INTR,
535 0, 0, 0, 0, 0, 0, 0,
536 DSP_HOLD_VALID_INTR,
537};
538
539static const struct vop_intr rk3368_vop_intr = {
540 .intrs = rk3368_vop_intrs,
541 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
542 .line_flag_num[0] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 0),
543 .line_flag_num[1] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 16),
544 .status = VOP_REG_MASK_SYNC(RK3368_INTR_STATUS, 0x3fff, 0),
545 .enable = VOP_REG_MASK_SYNC(RK3368_INTR_EN, 0x3fff, 0),
546 .clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0),
547};
548
549static const struct vop_win_phy rk3368_win23_data = {
550 .data_formats = formats_win_lite,
551 .nformats = ARRAY_SIZE(formats_win_lite),
552 .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
553 .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
554 .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
555 .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20),
556 .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0),
557 .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0),
558 .yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0),
559 .yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 0),
560 .src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
561 .dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xff, 0),
562};
563
564static const struct vop_win_data rk3368_vop_win_data[] = {
565 { .base = 0x00, .phy = &rk3288_win01_data,
566 .type = DRM_PLANE_TYPE_PRIMARY },
567 { .base = 0x40, .phy = &rk3288_win01_data,
568 .type = DRM_PLANE_TYPE_OVERLAY },
569 { .base = 0x00, .phy = &rk3368_win23_data,
570 .type = DRM_PLANE_TYPE_OVERLAY },
571 { .base = 0x50, .phy = &rk3368_win23_data,
572 .type = DRM_PLANE_TYPE_CURSOR },
573};
574
575static const struct vop_output rk3368_output = {
576 .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16),
577 .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20),
578 .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24),
579 .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28),
580 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
581 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
582 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
583 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
584};
585
586static const struct vop_misc rk3368_misc = {
587 .global_regdone_en = VOP_REG(RK3368_SYS_CTRL, 0x1, 11),
588};
589
590static const struct vop_data rk3368_vop = {
591 .version = VOP_VERSION(3, 2),
592 .intr = &rk3368_vop_intr,
593 .common = &rk3288_common,
594 .modeset = &rk3288_modeset,
595 .output = &rk3368_output,
596 .misc = &rk3368_misc,
597 .win = rk3368_vop_win_data,
598 .win_size = ARRAY_SIZE(rk3368_vop_win_data),
599};
600
601static const struct vop_intr rk3366_vop_intr = {
602 .intrs = rk3368_vop_intrs,
603 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
604 .line_flag_num[0] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 0),
605 .line_flag_num[1] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 16),
606 .status = VOP_REG_MASK_SYNC(RK3366_INTR_STATUS0, 0xffff, 0),
607 .enable = VOP_REG_MASK_SYNC(RK3366_INTR_EN0, 0xffff, 0),
608 .clear = VOP_REG_MASK_SYNC(RK3366_INTR_CLEAR0, 0xffff, 0),
609};
610
611static const struct vop_data rk3366_vop = {
612 .version = VOP_VERSION(3, 4),
613 .intr = &rk3366_vop_intr,
614 .common = &rk3288_common,
615 .modeset = &rk3288_modeset,
616 .output = &rk3368_output,
617 .misc = &rk3368_misc,
618 .win = rk3368_vop_win_data,
619 .win_size = ARRAY_SIZE(rk3368_vop_win_data),
620};
621
622static const struct vop_output rk3399_output = {
623 .dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16),
624 .rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16),
625 .hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20),
626 .edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24),
627 .mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28),
628 .dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11),
629 .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
630 .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
631 .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
632 .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
633};
634
635static const struct vop_data rk3399_vop_big = {
636 .version = VOP_VERSION(3, 5),
637 .feature = VOP_FEATURE_OUTPUT_RGB10,
638 .intr = &rk3366_vop_intr,
639 .common = &rk3288_common,
640 .modeset = &rk3288_modeset,
641 .output = &rk3399_output,
642 .misc = &rk3368_misc,
643 .win = rk3368_vop_win_data,
644 .win_size = ARRAY_SIZE(rk3368_vop_win_data),
645};
646
647static const struct vop_win_data rk3399_vop_lit_win_data[] = {
648 { .base = 0x00, .phy = &rk3288_win01_data,
649 .type = DRM_PLANE_TYPE_PRIMARY },
650 { .base = 0x00, .phy = &rk3368_win23_data,
651 .type = DRM_PLANE_TYPE_CURSOR},
652};
653
654static const struct vop_data rk3399_vop_lit = {
655 .version = VOP_VERSION(3, 6),
656 .intr = &rk3366_vop_intr,
657 .common = &rk3288_common,
658 .modeset = &rk3288_modeset,
659 .output = &rk3399_output,
660 .misc = &rk3368_misc,
661 .win = rk3399_vop_lit_win_data,
662 .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
663};
664
665static const struct vop_win_data rk3228_vop_win_data[] = {
666 { .base = 0x00, .phy = &rk3288_win01_data,
667 .type = DRM_PLANE_TYPE_PRIMARY },
668 { .base = 0x40, .phy = &rk3288_win01_data,
669 .type = DRM_PLANE_TYPE_CURSOR },
670};
671
672static const struct vop_data rk3228_vop = {
673 .version = VOP_VERSION(3, 7),
674 .feature = VOP_FEATURE_OUTPUT_RGB10,
675 .intr = &rk3366_vop_intr,
676 .common = &rk3288_common,
677 .modeset = &rk3288_modeset,
678 .output = &rk3399_output,
679 .misc = &rk3368_misc,
680 .win = rk3228_vop_win_data,
681 .win_size = ARRAY_SIZE(rk3228_vop_win_data),
682};
683
684static const struct vop_modeset rk3328_modeset = {
685 .htotal_pw = VOP_REG(RK3328_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
686 .hact_st_end = VOP_REG(RK3328_DSP_HACT_ST_END, 0x1fff1fff, 0),
687 .vtotal_pw = VOP_REG(RK3328_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
688 .vact_st_end = VOP_REG(RK3328_DSP_VACT_ST_END, 0x1fff1fff, 0),
689 .hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
690 .vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
691};
692
693static const struct vop_output rk3328_output = {
694 .rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12),
695 .hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13),
696 .edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14),
697 .mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15),
698 .rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 16),
699 .hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 20),
700 .edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 24),
701 .mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 28),
702};
703
704static const struct vop_misc rk3328_misc = {
705 .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11),
706};
707
708static const struct vop_common rk3328_common = {
709 .standby = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 22),
710 .dither_down = VOP_REG(RK3328_DSP_CTRL1, 0xf, 1),
711 .dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6),
712 .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18),
713 .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0),
714 .cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0),
715};
716
717static const struct vop_intr rk3328_vop_intr = {
718 .intrs = rk3368_vop_intrs,
719 .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
720 .line_flag_num[0] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 0),
721 .line_flag_num[1] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 16),
722 .status = VOP_REG_MASK_SYNC(RK3328_INTR_STATUS0, 0xffff, 0),
723 .enable = VOP_REG_MASK_SYNC(RK3328_INTR_EN0, 0xffff, 0),
724 .clear = VOP_REG_MASK_SYNC(RK3328_INTR_CLEAR0, 0xffff, 0),
725};
726
727static const struct vop_win_data rk3328_vop_win_data[] = {
728 { .base = 0xd0, .phy = &rk3288_win01_data,
729 .type = DRM_PLANE_TYPE_PRIMARY },
730 { .base = 0x1d0, .phy = &rk3288_win01_data,
731 .type = DRM_PLANE_TYPE_OVERLAY },
732 { .base = 0x2d0, .phy = &rk3288_win01_data,
733 .type = DRM_PLANE_TYPE_CURSOR },
734};
735
736static const struct vop_data rk3328_vop = {
737 .version = VOP_VERSION(3, 8),
738 .feature = VOP_FEATURE_OUTPUT_RGB10,
739 .intr = &rk3328_vop_intr,
740 .common = &rk3328_common,
741 .modeset = &rk3328_modeset,
742 .output = &rk3328_output,
743 .misc = &rk3328_misc,
744 .win = rk3328_vop_win_data,
745 .win_size = ARRAY_SIZE(rk3328_vop_win_data),
746};
747
748static const struct of_device_id vop_driver_dt_match[] = {
749 { .compatible = "rockchip,rk3036-vop",
750 .data = &rk3036_vop },
751 { .compatible = "rockchip,rk3126-vop",
752 .data = &rk3126_vop },
753 { .compatible = "rockchip,px30-vop-big",
754 .data = &px30_vop_big },
755 { .compatible = "rockchip,px30-vop-lit",
756 .data = &px30_vop_lit },
757 { .compatible = "rockchip,rk3188-vop",
758 .data = &rk3188_vop },
759 { .compatible = "rockchip,rk3288-vop",
760 .data = &rk3288_vop },
761 { .compatible = "rockchip,rk3368-vop",
762 .data = &rk3368_vop },
763 { .compatible = "rockchip,rk3366-vop",
764 .data = &rk3366_vop },
765 { .compatible = "rockchip,rk3399-vop-big",
766 .data = &rk3399_vop_big },
767 { .compatible = "rockchip,rk3399-vop-lit",
768 .data = &rk3399_vop_lit },
769 { .compatible = "rockchip,rk3228-vop",
770 .data = &rk3228_vop },
771 { .compatible = "rockchip,rk3328-vop",
772 .data = &rk3328_vop },
773 {},
774};
775MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
776
777static int vop_probe(struct platform_device *pdev)
778{
779 struct device *dev = &pdev->dev;
780
781 if (!dev->of_node) {
782 DRM_DEV_ERROR(dev, "can't find vop devices\n");
783 return -ENODEV;
784 }
785
786 return component_add(dev, &vop_component_ops);
787}
788
789static int vop_remove(struct platform_device *pdev)
790{
791 component_del(&pdev->dev, &vop_component_ops);
792
793 return 0;
794}
795
796struct platform_driver vop_platform_driver = {
797 .probe = vop_probe,
798 .remove = vop_remove,
799 .driver = {
800 .name = "rockchip-vop",
801 .of_match_table = of_match_ptr(vop_driver_dt_match),
802 },
803};