2 * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3 * Author:Mark Yao <mark.yao@rock-chips.com>
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.
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.
17 #include <linux/kernel.h>
18 #include <linux/component.h>
20 #include "rockchip_drm_vop.h"
21 #include "rockchip_vop_reg.h"
23 #define _VOP_REG(off, _mask, _shift, _write_mask, _relaxed) \
28 .write_mask = _write_mask, \
29 .relaxed = _relaxed, \
32 #define VOP_REG(off, _mask, _shift) \
33 _VOP_REG(off, _mask, _shift, false, true)
35 #define VOP_REG_SYNC(off, _mask, _shift) \
36 _VOP_REG(off, _mask, _shift, false, false)
38 #define VOP_REG_MASK_SYNC(off, _mask, _shift) \
39 _VOP_REG(off, _mask, _shift, true, false)
41 static const uint32_t formats_win_full
[] = {
55 static const uint32_t formats_win_lite
[] = {
66 static 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),
73 static 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),
89 static 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),
102 static 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
},
109 static const int rk3036_vop_intrs
[] = {
116 static 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),
125 static 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),
132 static const struct vop_output rk3036_output
= {
133 .pin_pol
= VOP_REG(RK3036_DSP_CTRL0
, 0xf, 4),
136 static 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),
143 static 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
),
152 static 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),
164 static 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
},
171 static 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
),
180 static const struct vop_scl_extension rk3288_win_full_scl_ext
= {
181 .cbcr_vsd_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 31),
182 .cbcr_vsu_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 30),
183 .cbcr_hsd_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x3, 28),
184 .cbcr_ver_scl_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x3, 26),
185 .cbcr_hor_scl_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x3, 24),
186 .yrgb_vsd_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 23),
187 .yrgb_vsu_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 22),
188 .yrgb_hsd_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x3, 20),
189 .yrgb_ver_scl_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x3, 18),
190 .yrgb_hor_scl_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x3, 16),
191 .line_load_mode
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 15),
192 .cbcr_axi_gather_num
= VOP_REG(RK3288_WIN0_CTRL1
, 0x7, 12),
193 .yrgb_axi_gather_num
= VOP_REG(RK3288_WIN0_CTRL1
, 0xf, 8),
194 .vsd_cbcr_gt2
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 7),
195 .vsd_cbcr_gt4
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 6),
196 .vsd_yrgb_gt2
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 5),
197 .vsd_yrgb_gt4
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 4),
198 .bic_coe_sel
= VOP_REG(RK3288_WIN0_CTRL1
, 0x3, 2),
199 .cbcr_axi_gather_en
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 1),
200 .yrgb_axi_gather_en
= VOP_REG(RK3288_WIN0_CTRL1
, 0x1, 0),
201 .lb_mode
= VOP_REG(RK3288_WIN0_CTRL0
, 0x7, 5),
204 static const struct vop_scl_regs rk3288_win_full_scl
= {
205 .ext
= &rk3288_win_full_scl_ext
,
206 .scale_yrgb_x
= VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB
, 0xffff, 0x0),
207 .scale_yrgb_y
= VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB
, 0xffff, 16),
208 .scale_cbcr_x
= VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR
, 0xffff, 0x0),
209 .scale_cbcr_y
= VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR
, 0xffff, 16),
212 static const struct vop_win_phy rk3288_win01_data
= {
213 .scl
= &rk3288_win_full_scl
,
214 .data_formats
= formats_win_full
,
215 .nformats
= ARRAY_SIZE(formats_win_full
),
216 .enable
= VOP_REG(RK3288_WIN0_CTRL0
, 0x1, 0),
217 .format
= VOP_REG(RK3288_WIN0_CTRL0
, 0x7, 1),
218 .rb_swap
= VOP_REG(RK3288_WIN0_CTRL0
, 0x1, 12),
219 .act_info
= VOP_REG(RK3288_WIN0_ACT_INFO
, 0x1fff1fff, 0),
220 .dsp_info
= VOP_REG(RK3288_WIN0_DSP_INFO
, 0x0fff0fff, 0),
221 .dsp_st
= VOP_REG(RK3288_WIN0_DSP_ST
, 0x1fff1fff, 0),
222 .yrgb_mst
= VOP_REG(RK3288_WIN0_YRGB_MST
, 0xffffffff, 0),
223 .uv_mst
= VOP_REG(RK3288_WIN0_CBR_MST
, 0xffffffff, 0),
224 .yrgb_vir
= VOP_REG(RK3288_WIN0_VIR
, 0x3fff, 0),
225 .uv_vir
= VOP_REG(RK3288_WIN0_VIR
, 0x3fff, 16),
226 .src_alpha_ctl
= VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL
, 0xff, 0),
227 .dst_alpha_ctl
= VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL
, 0xff, 0),
228 .channel
= VOP_REG(RK3288_WIN0_CTRL2
, 0xff, 0),
231 static const struct vop_win_phy rk3288_win23_data
= {
232 .data_formats
= formats_win_lite
,
233 .nformats
= ARRAY_SIZE(formats_win_lite
),
234 .enable
= VOP_REG(RK3288_WIN2_CTRL0
, 0x1, 4),
235 .gate
= VOP_REG(RK3288_WIN2_CTRL0
, 0x1, 0),
236 .format
= VOP_REG(RK3288_WIN2_CTRL0
, 0x7, 1),
237 .rb_swap
= VOP_REG(RK3288_WIN2_CTRL0
, 0x1, 12),
238 .dsp_info
= VOP_REG(RK3288_WIN2_DSP_INFO0
, 0x0fff0fff, 0),
239 .dsp_st
= VOP_REG(RK3288_WIN2_DSP_ST0
, 0x1fff1fff, 0),
240 .yrgb_mst
= VOP_REG(RK3288_WIN2_MST0
, 0xffffffff, 0),
241 .yrgb_vir
= VOP_REG(RK3288_WIN2_VIR0_1
, 0x1fff, 0),
242 .src_alpha_ctl
= VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL
, 0xff, 0),
243 .dst_alpha_ctl
= VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL
, 0xff, 0),
246 static const struct vop_modeset rk3288_modeset
= {
247 .htotal_pw
= VOP_REG(RK3288_DSP_HTOTAL_HS_END
, 0x1fff1fff, 0),
248 .hact_st_end
= VOP_REG(RK3288_DSP_HACT_ST_END
, 0x1fff1fff, 0),
249 .vtotal_pw
= VOP_REG(RK3288_DSP_VTOTAL_VS_END
, 0x1fff1fff, 0),
250 .vact_st_end
= VOP_REG(RK3288_DSP_VACT_ST_END
, 0x1fff1fff, 0),
251 .hpost_st_end
= VOP_REG(RK3288_POST_DSP_HACT_INFO
, 0x1fff1fff, 0),
252 .vpost_st_end
= VOP_REG(RK3288_POST_DSP_VACT_INFO
, 0x1fff1fff, 0),
255 static const struct vop_output rk3288_output
= {
256 .pin_pol
= VOP_REG(RK3288_DSP_CTRL0
, 0xf, 4),
257 .rgb_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 12),
258 .hdmi_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 13),
259 .edp_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 14),
260 .mipi_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 15),
263 static const struct vop_common rk3288_common
= {
264 .standby
= VOP_REG_SYNC(RK3288_SYS_CTRL
, 0x1, 22),
265 .gate_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 23),
266 .mmu_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 20),
267 .pre_dither_down
= VOP_REG(RK3288_DSP_CTRL1
, 0x1, 1),
268 .dither_down
= VOP_REG(RK3288_DSP_CTRL1
, 0xf, 1),
269 .dither_up
= VOP_REG(RK3288_DSP_CTRL1
, 0x1, 6),
270 .data_blank
= VOP_REG(RK3288_DSP_CTRL0
, 0x1, 19),
271 .dsp_blank
= VOP_REG(RK3288_DSP_CTRL0
, 0x3, 18),
272 .out_mode
= VOP_REG(RK3288_DSP_CTRL0
, 0xf, 0),
273 .cfg_done
= VOP_REG_SYNC(RK3288_REG_CFG_DONE
, 0x1, 0),
277 * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
278 * special support to get alpha blending working. For now, just use overlay
279 * window 3 for the drm cursor.
282 static const struct vop_win_data rk3288_vop_win_data
[] = {
283 { .base
= 0x00, .phy
= &rk3288_win01_data
,
284 .type
= DRM_PLANE_TYPE_PRIMARY
},
285 { .base
= 0x40, .phy
= &rk3288_win01_data
,
286 .type
= DRM_PLANE_TYPE_OVERLAY
},
287 { .base
= 0x00, .phy
= &rk3288_win23_data
,
288 .type
= DRM_PLANE_TYPE_OVERLAY
},
289 { .base
= 0x50, .phy
= &rk3288_win23_data
,
290 .type
= DRM_PLANE_TYPE_CURSOR
},
293 static const int rk3288_vop_intrs
[] = {
300 static const struct vop_intr rk3288_vop_intr
= {
301 .intrs
= rk3288_vop_intrs
,
302 .nintrs
= ARRAY_SIZE(rk3288_vop_intrs
),
303 .line_flag_num
[0] = VOP_REG(RK3288_INTR_CTRL0
, 0x1fff, 12),
304 .status
= VOP_REG(RK3288_INTR_CTRL0
, 0xf, 0),
305 .enable
= VOP_REG(RK3288_INTR_CTRL0
, 0xf, 4),
306 .clear
= VOP_REG(RK3288_INTR_CTRL0
, 0xf, 8),
309 static const struct vop_data rk3288_vop
= {
310 .version
= VOP_VERSION(3, 1),
311 .feature
= VOP_FEATURE_OUTPUT_RGB10
,
312 .intr
= &rk3288_vop_intr
,
313 .common
= &rk3288_common
,
314 .modeset
= &rk3288_modeset
,
315 .output
= &rk3288_output
,
316 .win
= rk3288_vop_win_data
,
317 .win_size
= ARRAY_SIZE(rk3288_vop_win_data
),
320 static const int rk3368_vop_intrs
[] = {
330 static const struct vop_intr rk3368_vop_intr
= {
331 .intrs
= rk3368_vop_intrs
,
332 .nintrs
= ARRAY_SIZE(rk3368_vop_intrs
),
333 .line_flag_num
[0] = VOP_REG(RK3368_LINE_FLAG
, 0xffff, 0),
334 .line_flag_num
[1] = VOP_REG(RK3368_LINE_FLAG
, 0xffff, 16),
335 .status
= VOP_REG_MASK_SYNC(RK3368_INTR_STATUS
, 0x3fff, 0),
336 .enable
= VOP_REG_MASK_SYNC(RK3368_INTR_EN
, 0x3fff, 0),
337 .clear
= VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR
, 0x3fff, 0),
340 static const struct vop_win_phy rk3368_win23_data
= {
341 .data_formats
= formats_win_lite
,
342 .nformats
= ARRAY_SIZE(formats_win_lite
),
343 .gate
= VOP_REG(RK3368_WIN2_CTRL0
, 0x1, 0),
344 .enable
= VOP_REG(RK3368_WIN2_CTRL0
, 0x1, 4),
345 .format
= VOP_REG(RK3368_WIN2_CTRL0
, 0x3, 5),
346 .rb_swap
= VOP_REG(RK3368_WIN2_CTRL0
, 0x1, 20),
347 .dsp_info
= VOP_REG(RK3368_WIN2_DSP_INFO0
, 0x0fff0fff, 0),
348 .dsp_st
= VOP_REG(RK3368_WIN2_DSP_ST0
, 0x1fff1fff, 0),
349 .yrgb_mst
= VOP_REG(RK3368_WIN2_MST0
, 0xffffffff, 0),
350 .yrgb_vir
= VOP_REG(RK3368_WIN2_VIR0_1
, 0x1fff, 0),
351 .src_alpha_ctl
= VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL
, 0xff, 0),
352 .dst_alpha_ctl
= VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL
, 0xff, 0),
355 static const struct vop_win_data rk3368_vop_win_data
[] = {
356 { .base
= 0x00, .phy
= &rk3288_win01_data
,
357 .type
= DRM_PLANE_TYPE_PRIMARY
},
358 { .base
= 0x40, .phy
= &rk3288_win01_data
,
359 .type
= DRM_PLANE_TYPE_OVERLAY
},
360 { .base
= 0x00, .phy
= &rk3368_win23_data
,
361 .type
= DRM_PLANE_TYPE_OVERLAY
},
362 { .base
= 0x50, .phy
= &rk3368_win23_data
,
363 .type
= DRM_PLANE_TYPE_CURSOR
},
366 static const struct vop_output rk3368_output
= {
367 .rgb_pin_pol
= VOP_REG(RK3368_DSP_CTRL1
, 0xf, 16),
368 .hdmi_pin_pol
= VOP_REG(RK3368_DSP_CTRL1
, 0xf, 20),
369 .edp_pin_pol
= VOP_REG(RK3368_DSP_CTRL1
, 0xf, 24),
370 .mipi_pin_pol
= VOP_REG(RK3368_DSP_CTRL1
, 0xf, 28),
371 .rgb_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 12),
372 .hdmi_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 13),
373 .edp_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 14),
374 .mipi_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 15),
377 static const struct vop_misc rk3368_misc
= {
378 .global_regdone_en
= VOP_REG(RK3368_SYS_CTRL
, 0x1, 11),
381 static const struct vop_data rk3368_vop
= {
382 .version
= VOP_VERSION(3, 2),
383 .intr
= &rk3368_vop_intr
,
384 .common
= &rk3288_common
,
385 .modeset
= &rk3288_modeset
,
386 .output
= &rk3368_output
,
387 .misc
= &rk3368_misc
,
388 .win
= rk3368_vop_win_data
,
389 .win_size
= ARRAY_SIZE(rk3368_vop_win_data
),
392 static const struct vop_intr rk3366_vop_intr
= {
393 .intrs
= rk3368_vop_intrs
,
394 .nintrs
= ARRAY_SIZE(rk3368_vop_intrs
),
395 .line_flag_num
[0] = VOP_REG(RK3366_LINE_FLAG
, 0xffff, 0),
396 .line_flag_num
[1] = VOP_REG(RK3366_LINE_FLAG
, 0xffff, 16),
397 .status
= VOP_REG_MASK_SYNC(RK3366_INTR_STATUS0
, 0xffff, 0),
398 .enable
= VOP_REG_MASK_SYNC(RK3366_INTR_EN0
, 0xffff, 0),
399 .clear
= VOP_REG_MASK_SYNC(RK3366_INTR_CLEAR0
, 0xffff, 0),
402 static const struct vop_data rk3366_vop
= {
403 .version
= VOP_VERSION(3, 4),
404 .intr
= &rk3366_vop_intr
,
405 .common
= &rk3288_common
,
406 .modeset
= &rk3288_modeset
,
407 .output
= &rk3368_output
,
408 .misc
= &rk3368_misc
,
409 .win
= rk3368_vop_win_data
,
410 .win_size
= ARRAY_SIZE(rk3368_vop_win_data
),
413 static const struct vop_output rk3399_output
= {
414 .dp_pin_pol
= VOP_REG(RK3399_DSP_CTRL1
, 0xf, 16),
415 .rgb_pin_pol
= VOP_REG(RK3368_DSP_CTRL1
, 0xf, 16),
416 .hdmi_pin_pol
= VOP_REG(RK3368_DSP_CTRL1
, 0xf, 20),
417 .edp_pin_pol
= VOP_REG(RK3368_DSP_CTRL1
, 0xf, 24),
418 .mipi_pin_pol
= VOP_REG(RK3368_DSP_CTRL1
, 0xf, 28),
419 .dp_en
= VOP_REG(RK3399_SYS_CTRL
, 0x1, 11),
420 .rgb_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 12),
421 .hdmi_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 13),
422 .edp_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 14),
423 .mipi_en
= VOP_REG(RK3288_SYS_CTRL
, 0x1, 15),
426 static const struct vop_data rk3399_vop_big
= {
427 .version
= VOP_VERSION(3, 5),
428 .feature
= VOP_FEATURE_OUTPUT_RGB10
,
429 .intr
= &rk3366_vop_intr
,
430 .common
= &rk3288_common
,
431 .modeset
= &rk3288_modeset
,
432 .output
= &rk3399_output
,
433 .misc
= &rk3368_misc
,
434 .win
= rk3368_vop_win_data
,
435 .win_size
= ARRAY_SIZE(rk3368_vop_win_data
),
438 static const struct vop_win_data rk3399_vop_lit_win_data
[] = {
439 { .base
= 0x00, .phy
= &rk3288_win01_data
,
440 .type
= DRM_PLANE_TYPE_PRIMARY
},
441 { .base
= 0x00, .phy
= &rk3368_win23_data
,
442 .type
= DRM_PLANE_TYPE_CURSOR
},
445 static const struct vop_data rk3399_vop_lit
= {
446 .version
= VOP_VERSION(3, 6),
447 .intr
= &rk3366_vop_intr
,
448 .common
= &rk3288_common
,
449 .modeset
= &rk3288_modeset
,
450 .output
= &rk3399_output
,
451 .misc
= &rk3368_misc
,
452 .win
= rk3399_vop_lit_win_data
,
453 .win_size
= ARRAY_SIZE(rk3399_vop_lit_win_data
),
456 static const struct vop_win_data rk3228_vop_win_data
[] = {
457 { .base
= 0x00, .phy
= &rk3288_win01_data
,
458 .type
= DRM_PLANE_TYPE_PRIMARY
},
459 { .base
= 0x40, .phy
= &rk3288_win01_data
,
460 .type
= DRM_PLANE_TYPE_CURSOR
},
463 static const struct vop_data rk3228_vop
= {
464 .version
= VOP_VERSION(3, 7),
465 .feature
= VOP_FEATURE_OUTPUT_RGB10
,
466 .intr
= &rk3366_vop_intr
,
467 .common
= &rk3288_common
,
468 .modeset
= &rk3288_modeset
,
469 .output
= &rk3399_output
,
470 .misc
= &rk3368_misc
,
471 .win
= rk3228_vop_win_data
,
472 .win_size
= ARRAY_SIZE(rk3228_vop_win_data
),
475 static const struct vop_modeset rk3328_modeset
= {
476 .htotal_pw
= VOP_REG(RK3328_DSP_HTOTAL_HS_END
, 0x1fff1fff, 0),
477 .hact_st_end
= VOP_REG(RK3328_DSP_HACT_ST_END
, 0x1fff1fff, 0),
478 .vtotal_pw
= VOP_REG(RK3328_DSP_VTOTAL_VS_END
, 0x1fff1fff, 0),
479 .vact_st_end
= VOP_REG(RK3328_DSP_VACT_ST_END
, 0x1fff1fff, 0),
480 .hpost_st_end
= VOP_REG(RK3328_POST_DSP_HACT_INFO
, 0x1fff1fff, 0),
481 .vpost_st_end
= VOP_REG(RK3328_POST_DSP_VACT_INFO
, 0x1fff1fff, 0),
484 static const struct vop_output rk3328_output
= {
485 .rgb_en
= VOP_REG(RK3328_SYS_CTRL
, 0x1, 12),
486 .hdmi_en
= VOP_REG(RK3328_SYS_CTRL
, 0x1, 13),
487 .edp_en
= VOP_REG(RK3328_SYS_CTRL
, 0x1, 14),
488 .mipi_en
= VOP_REG(RK3328_SYS_CTRL
, 0x1, 15),
489 .rgb_pin_pol
= VOP_REG(RK3328_DSP_CTRL1
, 0xf, 16),
490 .hdmi_pin_pol
= VOP_REG(RK3328_DSP_CTRL1
, 0xf, 20),
491 .edp_pin_pol
= VOP_REG(RK3328_DSP_CTRL1
, 0xf, 24),
492 .mipi_pin_pol
= VOP_REG(RK3328_DSP_CTRL1
, 0xf, 28),
495 static const struct vop_misc rk3328_misc
= {
496 .global_regdone_en
= VOP_REG(RK3328_SYS_CTRL
, 0x1, 11),
499 static const struct vop_common rk3328_common
= {
500 .standby
= VOP_REG_SYNC(RK3328_SYS_CTRL
, 0x1, 22),
501 .dither_down
= VOP_REG(RK3328_DSP_CTRL1
, 0xf, 1),
502 .dither_up
= VOP_REG(RK3328_DSP_CTRL1
, 0x1, 6),
503 .dsp_blank
= VOP_REG(RK3328_DSP_CTRL0
, 0x3, 18),
504 .out_mode
= VOP_REG(RK3328_DSP_CTRL0
, 0xf, 0),
505 .cfg_done
= VOP_REG_SYNC(RK3328_REG_CFG_DONE
, 0x1, 0),
508 static const struct vop_intr rk3328_vop_intr
= {
509 .intrs
= rk3368_vop_intrs
,
510 .nintrs
= ARRAY_SIZE(rk3368_vop_intrs
),
511 .line_flag_num
[0] = VOP_REG(RK3328_LINE_FLAG
, 0xffff, 0),
512 .line_flag_num
[1] = VOP_REG(RK3328_LINE_FLAG
, 0xffff, 16),
513 .status
= VOP_REG_MASK_SYNC(RK3328_INTR_STATUS0
, 0xffff, 0),
514 .enable
= VOP_REG_MASK_SYNC(RK3328_INTR_EN0
, 0xffff, 0),
515 .clear
= VOP_REG_MASK_SYNC(RK3328_INTR_CLEAR0
, 0xffff, 0),
518 static const struct vop_win_data rk3328_vop_win_data
[] = {
519 { .base
= 0xd0, .phy
= &rk3288_win01_data
,
520 .type
= DRM_PLANE_TYPE_PRIMARY
},
521 { .base
= 0x1d0, .phy
= &rk3288_win01_data
,
522 .type
= DRM_PLANE_TYPE_OVERLAY
},
523 { .base
= 0x2d0, .phy
= &rk3288_win01_data
,
524 .type
= DRM_PLANE_TYPE_CURSOR
},
527 static const struct vop_data rk3328_vop
= {
528 .version
= VOP_VERSION(3, 8),
529 .feature
= VOP_FEATURE_OUTPUT_RGB10
,
530 .intr
= &rk3328_vop_intr
,
531 .common
= &rk3328_common
,
532 .modeset
= &rk3328_modeset
,
533 .output
= &rk3328_output
,
534 .misc
= &rk3328_misc
,
535 .win
= rk3328_vop_win_data
,
536 .win_size
= ARRAY_SIZE(rk3328_vop_win_data
),
539 static const struct of_device_id vop_driver_dt_match
[] = {
540 { .compatible
= "rockchip,rk3036-vop",
541 .data
= &rk3036_vop
},
542 { .compatible
= "rockchip,rk3126-vop",
543 .data
= &rk3126_vop
},
544 { .compatible
= "rockchip,rk3288-vop",
545 .data
= &rk3288_vop
},
546 { .compatible
= "rockchip,rk3368-vop",
547 .data
= &rk3368_vop
},
548 { .compatible
= "rockchip,rk3366-vop",
549 .data
= &rk3366_vop
},
550 { .compatible
= "rockchip,rk3399-vop-big",
551 .data
= &rk3399_vop_big
},
552 { .compatible
= "rockchip,rk3399-vop-lit",
553 .data
= &rk3399_vop_lit
},
554 { .compatible
= "rockchip,rk3228-vop",
555 .data
= &rk3228_vop
},
556 { .compatible
= "rockchip,rk3328-vop",
557 .data
= &rk3328_vop
},
560 MODULE_DEVICE_TABLE(of
, vop_driver_dt_match
);
562 static int vop_probe(struct platform_device
*pdev
)
564 struct device
*dev
= &pdev
->dev
;
567 DRM_DEV_ERROR(dev
, "can't find vop devices\n");
571 return component_add(dev
, &vop_component_ops
);
574 static int vop_remove(struct platform_device
*pdev
)
576 component_del(&pdev
->dev
, &vop_component_ops
);
581 struct platform_driver vop_platform_driver
= {
583 .remove
= vop_remove
,
585 .name
= "rockchip-vop",
586 .of_match_table
= of_match_ptr(vop_driver_dt_match
),