1a67719d1SMark Yao /*
2a67719d1SMark Yao  * Copyright (C) Fuzhou Rockchip Electronics Co.Ltd
3a67719d1SMark Yao  * Author:Mark Yao <mark.yao@rock-chips.com>
4a67719d1SMark Yao  *
5a67719d1SMark Yao  * This software is licensed under the terms of the GNU General Public
6a67719d1SMark Yao  * License version 2, as published by the Free Software Foundation, and
7a67719d1SMark Yao  * may be copied, distributed, and modified under those terms.
8a67719d1SMark Yao  *
9a67719d1SMark Yao  * This program is distributed in the hope that it will be useful,
10a67719d1SMark Yao  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11a67719d1SMark Yao  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12a67719d1SMark Yao  * GNU General Public License for more details.
13a67719d1SMark Yao  */
14a67719d1SMark Yao 
15a67719d1SMark Yao #include <drm/drmP.h>
16a67719d1SMark Yao 
17a67719d1SMark Yao #include <linux/kernel.h>
18a67719d1SMark Yao #include <linux/component.h>
19a67719d1SMark Yao 
20a67719d1SMark Yao #include "rockchip_drm_vop.h"
21a67719d1SMark Yao #include "rockchip_vop_reg.h"
22a67719d1SMark Yao 
239548e1b4SMark yao #define _VOP_REG(off, _mask, _shift, _write_mask, _relaxed) \
249548e1b4SMark yao 		{ \
259548e1b4SMark yao 		 .offset = off, \
26a67719d1SMark Yao 		 .mask = _mask, \
279548e1b4SMark yao 		 .shift = _shift, \
289548e1b4SMark yao 		 .write_mask = _write_mask, \
299548e1b4SMark yao 		 .relaxed = _relaxed, \
309548e1b4SMark yao 		}
31d49463ecSMark Yao 
329548e1b4SMark yao #define VOP_REG(off, _mask, _shift) \
339548e1b4SMark yao 		_VOP_REG(off, _mask, _shift, false, true)
349548e1b4SMark yao 
359548e1b4SMark yao #define VOP_REG_SYNC(off, _mask, _shift) \
369548e1b4SMark yao 		_VOP_REG(off, _mask, _shift, false, false)
379548e1b4SMark yao 
389548e1b4SMark yao #define VOP_REG_MASK_SYNC(off, _mask, _shift) \
399548e1b4SMark yao 		_VOP_REG(off, _mask, _shift, true, false)
40a67719d1SMark Yao 
41f7673453SMark Yao static const uint32_t formats_win_full[] = {
42a67719d1SMark Yao 	DRM_FORMAT_XRGB8888,
43a67719d1SMark Yao 	DRM_FORMAT_ARGB8888,
44a67719d1SMark Yao 	DRM_FORMAT_XBGR8888,
45a67719d1SMark Yao 	DRM_FORMAT_ABGR8888,
46a67719d1SMark Yao 	DRM_FORMAT_RGB888,
47a67719d1SMark Yao 	DRM_FORMAT_BGR888,
48a67719d1SMark Yao 	DRM_FORMAT_RGB565,
49a67719d1SMark Yao 	DRM_FORMAT_BGR565,
50a67719d1SMark Yao 	DRM_FORMAT_NV12,
51a67719d1SMark Yao 	DRM_FORMAT_NV16,
52a67719d1SMark Yao 	DRM_FORMAT_NV24,
53a67719d1SMark Yao };
54a67719d1SMark Yao 
55f7673453SMark Yao static const uint32_t formats_win_lite[] = {
56a67719d1SMark Yao 	DRM_FORMAT_XRGB8888,
57a67719d1SMark Yao 	DRM_FORMAT_ARGB8888,
58a67719d1SMark Yao 	DRM_FORMAT_XBGR8888,
59a67719d1SMark Yao 	DRM_FORMAT_ABGR8888,
60a67719d1SMark Yao 	DRM_FORMAT_RGB888,
61a67719d1SMark Yao 	DRM_FORMAT_BGR888,
62a67719d1SMark Yao 	DRM_FORMAT_RGB565,
63a67719d1SMark Yao 	DRM_FORMAT_BGR565,
64a67719d1SMark Yao };
65a67719d1SMark Yao 
66b51502adSMark Yao static const struct vop_scl_regs rk3036_win_scl = {
67b51502adSMark Yao 	.scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
68b51502adSMark Yao 	.scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
69b51502adSMark Yao 	.scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
70b51502adSMark Yao 	.scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
71b51502adSMark Yao };
72b51502adSMark Yao 
73b51502adSMark Yao static const struct vop_win_phy rk3036_win0_data = {
74b51502adSMark Yao 	.scl = &rk3036_win_scl,
75b51502adSMark Yao 	.data_formats = formats_win_full,
76b51502adSMark Yao 	.nformats = ARRAY_SIZE(formats_win_full),
77b51502adSMark Yao 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
78b51502adSMark Yao 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
79b51502adSMark Yao 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
80b51502adSMark Yao 	.act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0),
81b51502adSMark Yao 	.dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0),
82b51502adSMark Yao 	.dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0),
83b51502adSMark Yao 	.yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0),
84b51502adSMark Yao 	.uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0),
85b51502adSMark Yao 	.yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0),
86b51502adSMark Yao 	.uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16),
87b51502adSMark Yao };
88b51502adSMark Yao 
89b51502adSMark Yao static const struct vop_win_phy rk3036_win1_data = {
90b51502adSMark Yao 	.data_formats = formats_win_lite,
91b51502adSMark Yao 	.nformats = ARRAY_SIZE(formats_win_lite),
92b51502adSMark Yao 	.enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
93b51502adSMark Yao 	.format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
94b51502adSMark Yao 	.rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
95b51502adSMark Yao 	.act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0),
96b51502adSMark Yao 	.dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0),
97b51502adSMark Yao 	.dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0),
98b51502adSMark Yao 	.yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0),
99b51502adSMark Yao 	.yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
100b51502adSMark Yao };
101b51502adSMark Yao 
102b51502adSMark Yao static const struct vop_win_data rk3036_vop_win_data[] = {
103b51502adSMark Yao 	{ .base = 0x00, .phy = &rk3036_win0_data,
104b51502adSMark Yao 	  .type = DRM_PLANE_TYPE_PRIMARY },
105b51502adSMark Yao 	{ .base = 0x00, .phy = &rk3036_win1_data,
106b51502adSMark Yao 	  .type = DRM_PLANE_TYPE_CURSOR },
107b51502adSMark Yao };
108b51502adSMark Yao 
109b51502adSMark Yao static const int rk3036_vop_intrs[] = {
110b51502adSMark Yao 	DSP_HOLD_VALID_INTR,
111b51502adSMark Yao 	FS_INTR,
112b51502adSMark Yao 	LINE_FLAG_INTR,
113b51502adSMark Yao 	BUS_ERROR_INTR,
114b51502adSMark Yao };
115b51502adSMark Yao 
116b51502adSMark Yao static const struct vop_intr rk3036_intr = {
117b51502adSMark Yao 	.intrs = rk3036_vop_intrs,
118b51502adSMark Yao 	.nintrs = ARRAY_SIZE(rk3036_vop_intrs),
119ac6560dfSMark yao 	.line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12),
1209a61c54bSMark yao 	.status = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 0),
1219a61c54bSMark yao 	.enable = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 4),
1229a61c54bSMark yao 	.clear = VOP_REG_SYNC(RK3036_INT_STATUS, 0xf, 8),
123b51502adSMark Yao };
124b51502adSMark Yao 
1259a61c54bSMark yao static const struct vop_modeset rk3036_modeset = {
126b51502adSMark Yao 	.htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
127b51502adSMark Yao 	.hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0),
128b51502adSMark Yao 	.vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
129b51502adSMark Yao 	.vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0),
1309a61c54bSMark yao };
1319a61c54bSMark yao 
1329a61c54bSMark yao static const struct vop_output rk3036_output = {
1339a61c54bSMark yao 	.pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
1349a61c54bSMark yao };
1359a61c54bSMark yao 
1369a61c54bSMark yao static const struct vop_common rk3036_common = {
1379a61c54bSMark yao 	.standby = VOP_REG_SYNC(RK3036_SYS_CTRL, 0x1, 30),
1389a61c54bSMark yao 	.out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0),
1399a61c54bSMark yao 	.dsp_blank = VOP_REG(RK3036_DSP_CTRL1, 0x1, 24),
1409548e1b4SMark yao 	.cfg_done = VOP_REG_SYNC(RK3036_REG_CFG_DONE, 0x1, 0),
141b51502adSMark Yao };
142b51502adSMark Yao 
143b51502adSMark Yao static const struct vop_data rk3036_vop = {
144b51502adSMark Yao 	.intr = &rk3036_intr,
1459a61c54bSMark yao 	.common = &rk3036_common,
1469a61c54bSMark yao 	.modeset = &rk3036_modeset,
1479a61c54bSMark yao 	.output = &rk3036_output,
148b51502adSMark Yao 	.win = rk3036_vop_win_data,
149b51502adSMark Yao 	.win_size = ARRAY_SIZE(rk3036_vop_win_data),
150b51502adSMark Yao };
151b51502adSMark Yao 
152f7673453SMark Yao static const struct vop_scl_extension rk3288_win_full_scl_ext = {
153f7673453SMark Yao 	.cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
154f7673453SMark Yao 	.cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
155f7673453SMark Yao 	.cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28),
156f7673453SMark Yao 	.cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26),
157f7673453SMark Yao 	.cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24),
158f7673453SMark Yao 	.yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23),
159f7673453SMark Yao 	.yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22),
160f7673453SMark Yao 	.yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20),
161f7673453SMark Yao 	.yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18),
162f7673453SMark Yao 	.yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16),
163f7673453SMark Yao 	.line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15),
164f7673453SMark Yao 	.cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12),
165f7673453SMark Yao 	.yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8),
166f7673453SMark Yao 	.vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7),
167f7673453SMark Yao 	.vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6),
168f7673453SMark Yao 	.vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5),
169f7673453SMark Yao 	.vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4),
170f7673453SMark Yao 	.bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2),
171f7673453SMark Yao 	.cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1),
172f7673453SMark Yao 	.yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0),
173f7673453SMark Yao 	.lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5),
1741194fffbSMark Yao };
1751194fffbSMark Yao 
176f7673453SMark Yao static const struct vop_scl_regs rk3288_win_full_scl = {
177f7673453SMark Yao 	.ext = &rk3288_win_full_scl_ext,
178f7673453SMark Yao 	.scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
179f7673453SMark Yao 	.scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
180f7673453SMark Yao 	.scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
181f7673453SMark Yao 	.scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
182a67719d1SMark Yao };
183a67719d1SMark Yao 
184f7673453SMark Yao static const struct vop_win_phy rk3288_win01_data = {
185f7673453SMark Yao 	.scl = &rk3288_win_full_scl,
186f7673453SMark Yao 	.data_formats = formats_win_full,
187f7673453SMark Yao 	.nformats = ARRAY_SIZE(formats_win_full),
188f7673453SMark Yao 	.enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
189f7673453SMark Yao 	.format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
190f7673453SMark Yao 	.rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
191f7673453SMark Yao 	.act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
192f7673453SMark Yao 	.dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
193f7673453SMark Yao 	.dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
194f7673453SMark Yao 	.yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
195f7673453SMark Yao 	.uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
196f7673453SMark Yao 	.yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
197f7673453SMark Yao 	.uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
198f7673453SMark Yao 	.src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xff, 0),
199f7673453SMark Yao 	.dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xff, 0),
2009dd2aca4SMark yao 	.channel = VOP_REG(RK3288_WIN0_CTRL2, 0xff, 0),
201a67719d1SMark Yao };
202a67719d1SMark Yao 
203f7673453SMark Yao static const struct vop_win_phy rk3288_win23_data = {
204f7673453SMark Yao 	.data_formats = formats_win_lite,
205f7673453SMark Yao 	.nformats = ARRAY_SIZE(formats_win_lite),
20660b7ae7fSMark yao 	.enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
20760b7ae7fSMark yao 	.gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
208f7673453SMark Yao 	.format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
209f7673453SMark Yao 	.rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12),
210f7673453SMark Yao 	.dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0),
211f7673453SMark Yao 	.dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0),
212f7673453SMark Yao 	.yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0),
213f7673453SMark Yao 	.yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0),
214f7673453SMark Yao 	.src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
215f7673453SMark Yao 	.dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0),
216a67719d1SMark Yao };
217a67719d1SMark Yao 
2189a61c54bSMark yao static const struct vop_modeset rk3288_modeset = {
219f7673453SMark Yao 	.htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
220f7673453SMark Yao 	.hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0),
221f7673453SMark Yao 	.vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
222f7673453SMark Yao 	.vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0),
223f7673453SMark Yao 	.hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
224f7673453SMark Yao 	.vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
2259a61c54bSMark yao };
2269a61c54bSMark yao 
2279a61c54bSMark yao static const struct vop_output rk3288_output = {
2289a61c54bSMark yao 	.pin_pol = VOP_REG(RK3288_DSP_CTRL0, 0xf, 4),
2299a61c54bSMark yao 	.rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
2309a61c54bSMark yao 	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
2319a61c54bSMark yao 	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
2329a61c54bSMark yao 	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
2339a61c54bSMark yao };
2349a61c54bSMark yao 
2359a61c54bSMark yao static const struct vop_common rk3288_common = {
2369a61c54bSMark yao 	.standby = VOP_REG_SYNC(RK3288_SYS_CTRL, 0x1, 22),
2379a61c54bSMark yao 	.gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
2389a61c54bSMark yao 	.mmu_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 20),
2399a61c54bSMark yao 	.dither_down = VOP_REG(RK3288_DSP_CTRL1, 0xf, 1),
2409a61c54bSMark yao 	.dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
2419a61c54bSMark yao 	.data_blank = VOP_REG(RK3288_DSP_CTRL0, 0x1, 19),
2429a61c54bSMark yao 	.dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18),
2439a61c54bSMark yao 	.out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
2449548e1b4SMark yao 	.cfg_done = VOP_REG_SYNC(RK3288_REG_CFG_DONE, 0x1, 0),
245a67719d1SMark Yao };
246a67719d1SMark Yao 
247a67719d1SMark Yao /*
248a67719d1SMark Yao  * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
249a67719d1SMark Yao  * special support to get alpha blending working.  For now, just use overlay
250a67719d1SMark Yao  * window 3 for the drm cursor.
251a67719d1SMark Yao  *
252a67719d1SMark Yao  */
253a67719d1SMark Yao static const struct vop_win_data rk3288_vop_win_data[] = {
254f7673453SMark Yao 	{ .base = 0x00, .phy = &rk3288_win01_data,
255f7673453SMark Yao 	  .type = DRM_PLANE_TYPE_PRIMARY },
256f7673453SMark Yao 	{ .base = 0x40, .phy = &rk3288_win01_data,
257f7673453SMark Yao 	  .type = DRM_PLANE_TYPE_OVERLAY },
258f7673453SMark Yao 	{ .base = 0x00, .phy = &rk3288_win23_data,
259f7673453SMark Yao 	  .type = DRM_PLANE_TYPE_OVERLAY },
260f7673453SMark Yao 	{ .base = 0x50, .phy = &rk3288_win23_data,
261f7673453SMark Yao 	  .type = DRM_PLANE_TYPE_CURSOR },
262a67719d1SMark Yao };
263a67719d1SMark Yao 
264a67719d1SMark Yao static const int rk3288_vop_intrs[] = {
265a67719d1SMark Yao 	DSP_HOLD_VALID_INTR,
266a67719d1SMark Yao 	FS_INTR,
267a67719d1SMark Yao 	LINE_FLAG_INTR,
268a67719d1SMark Yao 	BUS_ERROR_INTR,
269a67719d1SMark Yao };
270a67719d1SMark Yao 
271a67719d1SMark Yao static const struct vop_intr rk3288_vop_intr = {
272a67719d1SMark Yao 	.intrs = rk3288_vop_intrs,
273a67719d1SMark Yao 	.nintrs = ARRAY_SIZE(rk3288_vop_intrs),
274ac6560dfSMark yao 	.line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12),
275f7673453SMark Yao 	.status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0),
276f7673453SMark Yao 	.enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4),
277f7673453SMark Yao 	.clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8),
278a67719d1SMark Yao };
279a67719d1SMark Yao 
280a67719d1SMark Yao static const struct vop_data rk3288_vop = {
281eb5cb6aaSMark yao 	.version = VOP_VERSION(3, 1),
282efd11cc8SMark yao 	.feature = VOP_FEATURE_OUTPUT_RGB10,
283a67719d1SMark Yao 	.intr = &rk3288_vop_intr,
2849a61c54bSMark yao 	.common = &rk3288_common,
2859a61c54bSMark yao 	.modeset = &rk3288_modeset,
2869a61c54bSMark yao 	.output = &rk3288_output,
287a67719d1SMark Yao 	.win = rk3288_vop_win_data,
288a67719d1SMark Yao 	.win_size = ARRAY_SIZE(rk3288_vop_win_data),
289a67719d1SMark Yao };
290a67719d1SMark Yao 
291eb5cb6aaSMark yao static const int rk3368_vop_intrs[] = {
2920a63bfd0SMark Yao 	FS_INTR,
2930a63bfd0SMark Yao 	0, 0,
2940a63bfd0SMark Yao 	LINE_FLAG_INTR,
2950a63bfd0SMark Yao 	0,
2960a63bfd0SMark Yao 	BUS_ERROR_INTR,
2970a63bfd0SMark Yao 	0, 0, 0, 0, 0, 0, 0,
2980a63bfd0SMark Yao 	DSP_HOLD_VALID_INTR,
299f7673453SMark Yao };
300f7673453SMark Yao 
301eb5cb6aaSMark yao static const struct vop_intr rk3368_vop_intr = {
302eb5cb6aaSMark yao 	.intrs = rk3368_vop_intrs,
303eb5cb6aaSMark yao 	.nintrs = ARRAY_SIZE(rk3368_vop_intrs),
304eb5cb6aaSMark yao 	.line_flag_num[0] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 0),
305eb5cb6aaSMark yao 	.line_flag_num[1] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 16),
306eb5cb6aaSMark yao 	.status = VOP_REG_MASK_SYNC(RK3368_INTR_STATUS, 0x3fff, 0),
307eb5cb6aaSMark yao 	.enable = VOP_REG_MASK_SYNC(RK3368_INTR_EN, 0x3fff, 0),
308eb5cb6aaSMark yao 	.clear = VOP_REG_MASK_SYNC(RK3368_INTR_CLEAR, 0x3fff, 0),
309eb5cb6aaSMark yao };
310eb5cb6aaSMark yao 
311eb5cb6aaSMark yao static const struct vop_win_phy rk3368_win23_data = {
312eb5cb6aaSMark yao 	.data_formats = formats_win_lite,
313eb5cb6aaSMark yao 	.nformats = ARRAY_SIZE(formats_win_lite),
314eb5cb6aaSMark yao 	.gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
315eb5cb6aaSMark yao 	.enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
316eb5cb6aaSMark yao 	.format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
317eb5cb6aaSMark yao 	.rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20),
318eb5cb6aaSMark yao 	.dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0),
319eb5cb6aaSMark yao 	.dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0),
320eb5cb6aaSMark yao 	.yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0),
321eb5cb6aaSMark yao 	.yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 0),
322eb5cb6aaSMark yao 	.src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
323eb5cb6aaSMark yao 	.dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xff, 0),
324eb5cb6aaSMark yao };
325eb5cb6aaSMark yao 
326eb5cb6aaSMark yao static const struct vop_win_data rk3368_vop_win_data[] = {
327eb5cb6aaSMark yao 	{ .base = 0x00, .phy = &rk3288_win01_data,
328eb5cb6aaSMark yao 	  .type = DRM_PLANE_TYPE_PRIMARY },
329eb5cb6aaSMark yao 	{ .base = 0x40, .phy = &rk3288_win01_data,
330eb5cb6aaSMark yao 	  .type = DRM_PLANE_TYPE_OVERLAY },
331eb5cb6aaSMark yao 	{ .base = 0x00, .phy = &rk3368_win23_data,
332eb5cb6aaSMark yao 	  .type = DRM_PLANE_TYPE_OVERLAY },
333eb5cb6aaSMark yao 	{ .base = 0x50, .phy = &rk3368_win23_data,
334eb5cb6aaSMark yao 	  .type = DRM_PLANE_TYPE_CURSOR },
335eb5cb6aaSMark yao };
336eb5cb6aaSMark yao 
337eb5cb6aaSMark yao static const struct vop_output rk3368_output = {
338eb5cb6aaSMark yao 	.rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16),
339eb5cb6aaSMark yao 	.hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20),
340eb5cb6aaSMark yao 	.edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24),
341eb5cb6aaSMark yao 	.mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28),
342eb5cb6aaSMark yao 	.rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
343eb5cb6aaSMark yao 	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
344eb5cb6aaSMark yao 	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
345eb5cb6aaSMark yao 	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
346eb5cb6aaSMark yao };
347eb5cb6aaSMark yao 
348eb5cb6aaSMark yao static const struct vop_misc rk3368_misc = {
349eb5cb6aaSMark yao 	.global_regdone_en = VOP_REG(RK3368_SYS_CTRL, 0x1, 11),
350eb5cb6aaSMark yao };
351eb5cb6aaSMark yao 
352eb5cb6aaSMark yao static const struct vop_data rk3368_vop = {
353eb5cb6aaSMark yao 	.version = VOP_VERSION(3, 2),
354eb5cb6aaSMark yao 	.intr = &rk3368_vop_intr,
355eb5cb6aaSMark yao 	.common = &rk3288_common,
356eb5cb6aaSMark yao 	.modeset = &rk3288_modeset,
357eb5cb6aaSMark yao 	.output = &rk3368_output,
358eb5cb6aaSMark yao 	.misc = &rk3368_misc,
359eb5cb6aaSMark yao 	.win = rk3368_vop_win_data,
360eb5cb6aaSMark yao 	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
361eb5cb6aaSMark yao };
362eb5cb6aaSMark yao 
363eb5cb6aaSMark yao static const struct vop_intr rk3366_vop_intr = {
364eb5cb6aaSMark yao 	.intrs = rk3368_vop_intrs,
365eb5cb6aaSMark yao 	.nintrs = ARRAY_SIZE(rk3368_vop_intrs),
366eb5cb6aaSMark yao 	.line_flag_num[0] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 0),
367eb5cb6aaSMark yao 	.line_flag_num[1] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 16),
368eb5cb6aaSMark yao 	.status = VOP_REG_MASK_SYNC(RK3366_INTR_STATUS0, 0xffff, 0),
369eb5cb6aaSMark yao 	.enable = VOP_REG_MASK_SYNC(RK3366_INTR_EN0, 0xffff, 0),
370eb5cb6aaSMark yao 	.clear = VOP_REG_MASK_SYNC(RK3366_INTR_CLEAR0, 0xffff, 0),
371eb5cb6aaSMark yao };
372eb5cb6aaSMark yao 
373eb5cb6aaSMark yao static const struct vop_data rk3366_vop = {
374eb5cb6aaSMark yao 	.version = VOP_VERSION(3, 4),
375eb5cb6aaSMark yao 	.intr = &rk3366_vop_intr,
376eb5cb6aaSMark yao 	.common = &rk3288_common,
377eb5cb6aaSMark yao 	.modeset = &rk3288_modeset,
378eb5cb6aaSMark yao 	.output = &rk3368_output,
379eb5cb6aaSMark yao 	.misc = &rk3368_misc,
380eb5cb6aaSMark yao 	.win = rk3368_vop_win_data,
381eb5cb6aaSMark yao 	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
382f7673453SMark Yao };
383f7673453SMark Yao 
3849a61c54bSMark yao static const struct vop_output rk3399_output = {
3859a61c54bSMark yao 	.dp_pin_pol = VOP_REG(RK3399_DSP_CTRL1, 0xf, 16),
386eb5cb6aaSMark yao 	.rgb_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 16),
387eb5cb6aaSMark yao 	.hdmi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 20),
388eb5cb6aaSMark yao 	.edp_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 24),
389eb5cb6aaSMark yao 	.mipi_pin_pol = VOP_REG(RK3368_DSP_CTRL1, 0xf, 28),
3909a61c54bSMark yao 	.dp_en = VOP_REG(RK3399_SYS_CTRL, 0x1, 11),
3919a61c54bSMark yao 	.rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
3929a61c54bSMark yao 	.hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
3939a61c54bSMark yao 	.edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
3949a61c54bSMark yao 	.mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
3959a61c54bSMark yao };
3969a61c54bSMark yao 
3970a63bfd0SMark Yao static const struct vop_data rk3399_vop_big = {
398eb5cb6aaSMark yao 	.version = VOP_VERSION(3, 5),
399efd11cc8SMark yao 	.feature = VOP_FEATURE_OUTPUT_RGB10,
400eb5cb6aaSMark yao 	.intr = &rk3366_vop_intr,
4019a61c54bSMark yao 	.common = &rk3288_common,
4029a61c54bSMark yao 	.modeset = &rk3288_modeset,
4039a61c54bSMark yao 	.output = &rk3399_output,
404eb5cb6aaSMark yao 	.misc = &rk3368_misc,
405eb5cb6aaSMark yao 	.win = rk3368_vop_win_data,
406eb5cb6aaSMark yao 	.win_size = ARRAY_SIZE(rk3368_vop_win_data),
4070a63bfd0SMark Yao };
4080a63bfd0SMark Yao 
4090a63bfd0SMark Yao static const struct vop_win_data rk3399_vop_lit_win_data[] = {
4100a63bfd0SMark Yao 	{ .base = 0x00, .phy = &rk3288_win01_data,
411f7673453SMark Yao 	  .type = DRM_PLANE_TYPE_PRIMARY },
412eb5cb6aaSMark yao 	{ .base = 0x00, .phy = &rk3368_win23_data,
413f7673453SMark Yao 	  .type = DRM_PLANE_TYPE_CURSOR},
414f7673453SMark Yao };
415f7673453SMark Yao 
4160a63bfd0SMark Yao static const struct vop_data rk3399_vop_lit = {
417eb5cb6aaSMark yao 	.version = VOP_VERSION(3, 6),
418eb5cb6aaSMark yao 	.intr = &rk3366_vop_intr,
4199a61c54bSMark yao 	.common = &rk3288_common,
4209a61c54bSMark yao 	.modeset = &rk3288_modeset,
4219a61c54bSMark yao 	.output = &rk3399_output,
422eb5cb6aaSMark yao 	.misc = &rk3368_misc,
4230a63bfd0SMark Yao 	.win = rk3399_vop_lit_win_data,
4240a63bfd0SMark Yao 	.win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
425f7673453SMark Yao };
426f7673453SMark Yao 
427eb5cb6aaSMark yao static const struct vop_win_data rk3228_vop_win_data[] = {
428eb5cb6aaSMark yao 	{ .base = 0x00, .phy = &rk3288_win01_data,
429eb5cb6aaSMark yao 	  .type = DRM_PLANE_TYPE_PRIMARY },
430eb5cb6aaSMark yao 	{ .base = 0x40, .phy = &rk3288_win01_data,
431eb5cb6aaSMark yao 	  .type = DRM_PLANE_TYPE_CURSOR },
432eb5cb6aaSMark yao };
433eb5cb6aaSMark yao 
434eb5cb6aaSMark yao static const struct vop_data rk3228_vop = {
435eb5cb6aaSMark yao 	.version = VOP_VERSION(3, 7),
436eb5cb6aaSMark yao 	.feature = VOP_FEATURE_OUTPUT_RGB10,
437eb5cb6aaSMark yao 	.intr = &rk3366_vop_intr,
438eb5cb6aaSMark yao 	.common = &rk3288_common,
439eb5cb6aaSMark yao 	.modeset = &rk3288_modeset,
440eb5cb6aaSMark yao 	.output = &rk3399_output,
441eb5cb6aaSMark yao 	.misc = &rk3368_misc,
442eb5cb6aaSMark yao 	.win = rk3228_vop_win_data,
443eb5cb6aaSMark yao 	.win_size = ARRAY_SIZE(rk3228_vop_win_data),
444eb5cb6aaSMark yao };
445eb5cb6aaSMark yao 
446eb5cb6aaSMark yao static const struct vop_modeset rk3328_modeset = {
447eb5cb6aaSMark yao 	.htotal_pw = VOP_REG(RK3328_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
448eb5cb6aaSMark yao 	.hact_st_end = VOP_REG(RK3328_DSP_HACT_ST_END, 0x1fff1fff, 0),
449eb5cb6aaSMark yao 	.vtotal_pw = VOP_REG(RK3328_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
450eb5cb6aaSMark yao 	.vact_st_end = VOP_REG(RK3328_DSP_VACT_ST_END, 0x1fff1fff, 0),
451eb5cb6aaSMark yao 	.hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
452eb5cb6aaSMark yao 	.vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
453eb5cb6aaSMark yao };
454eb5cb6aaSMark yao 
455eb5cb6aaSMark yao static const struct vop_output rk3328_output = {
456eb5cb6aaSMark yao 	.rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12),
457eb5cb6aaSMark yao 	.hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13),
458eb5cb6aaSMark yao 	.edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14),
459eb5cb6aaSMark yao 	.mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15),
460eb5cb6aaSMark yao 	.rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 16),
461eb5cb6aaSMark yao 	.hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 20),
462eb5cb6aaSMark yao 	.edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 24),
463eb5cb6aaSMark yao 	.mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 28),
464eb5cb6aaSMark yao };
465eb5cb6aaSMark yao 
466eb5cb6aaSMark yao static const struct vop_misc rk3328_misc = {
467eb5cb6aaSMark yao 	.global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11),
468eb5cb6aaSMark yao };
469eb5cb6aaSMark yao 
470eb5cb6aaSMark yao static const struct vop_common rk3328_common = {
471eb5cb6aaSMark yao 	.standby = VOP_REG_SYNC(RK3328_SYS_CTRL, 0x1, 22),
472eb5cb6aaSMark yao 	.dither_down = VOP_REG(RK3328_DSP_CTRL1, 0xf, 1),
473eb5cb6aaSMark yao 	.dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6),
474eb5cb6aaSMark yao 	.dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18),
475eb5cb6aaSMark yao 	.out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0),
476eb5cb6aaSMark yao 	.cfg_done = VOP_REG_SYNC(RK3328_REG_CFG_DONE, 0x1, 0),
477eb5cb6aaSMark yao };
478eb5cb6aaSMark yao 
479eb5cb6aaSMark yao static const struct vop_intr rk3328_vop_intr = {
480eb5cb6aaSMark yao 	.intrs = rk3368_vop_intrs,
481eb5cb6aaSMark yao 	.nintrs = ARRAY_SIZE(rk3368_vop_intrs),
482eb5cb6aaSMark yao 	.line_flag_num[0] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 0),
483eb5cb6aaSMark yao 	.line_flag_num[1] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 16),
484eb5cb6aaSMark yao 	.status = VOP_REG_MASK_SYNC(RK3328_INTR_STATUS0, 0xffff, 0),
485eb5cb6aaSMark yao 	.enable = VOP_REG_MASK_SYNC(RK3328_INTR_EN0, 0xffff, 0),
486eb5cb6aaSMark yao 	.clear = VOP_REG_MASK_SYNC(RK3328_INTR_CLEAR0, 0xffff, 0),
487eb5cb6aaSMark yao };
488eb5cb6aaSMark yao 
489eb5cb6aaSMark yao static const struct vop_win_data rk3328_vop_win_data[] = {
490eb5cb6aaSMark yao 	{ .base = 0xd0, .phy = &rk3288_win01_data,
491eb5cb6aaSMark yao 	  .type = DRM_PLANE_TYPE_PRIMARY },
492eb5cb6aaSMark yao 	{ .base = 0x1d0, .phy = &rk3288_win01_data,
493eb5cb6aaSMark yao 	  .type = DRM_PLANE_TYPE_OVERLAY },
494eb5cb6aaSMark yao 	{ .base = 0x2d0, .phy = &rk3288_win01_data,
495eb5cb6aaSMark yao 	  .type = DRM_PLANE_TYPE_CURSOR },
496eb5cb6aaSMark yao };
497eb5cb6aaSMark yao 
498eb5cb6aaSMark yao static const struct vop_data rk3328_vop = {
499eb5cb6aaSMark yao 	.version = VOP_VERSION(3, 8),
500eb5cb6aaSMark yao 	.feature = VOP_FEATURE_OUTPUT_RGB10,
501eb5cb6aaSMark yao 	.intr = &rk3328_vop_intr,
502eb5cb6aaSMark yao 	.common = &rk3328_common,
503eb5cb6aaSMark yao 	.modeset = &rk3328_modeset,
504eb5cb6aaSMark yao 	.output = &rk3328_output,
505eb5cb6aaSMark yao 	.misc = &rk3328_misc,
506eb5cb6aaSMark yao 	.win = rk3328_vop_win_data,
507eb5cb6aaSMark yao 	.win_size = ARRAY_SIZE(rk3328_vop_win_data),
508eb5cb6aaSMark yao };
509eb5cb6aaSMark yao 
510a67719d1SMark Yao static const struct of_device_id vop_driver_dt_match[] = {
511f7673453SMark Yao 	{ .compatible = "rockchip,rk3036-vop",
512f7673453SMark Yao 	  .data = &rk3036_vop },
513b51502adSMark Yao 	{ .compatible = "rockchip,rk3288-vop",
514b51502adSMark Yao 	  .data = &rk3288_vop },
515eb5cb6aaSMark yao 	{ .compatible = "rockchip,rk3368-vop",
516eb5cb6aaSMark yao 	  .data = &rk3368_vop },
517eb5cb6aaSMark yao 	{ .compatible = "rockchip,rk3366-vop",
518eb5cb6aaSMark yao 	  .data = &rk3366_vop },
5190a63bfd0SMark Yao 	{ .compatible = "rockchip,rk3399-vop-big",
5200a63bfd0SMark Yao 	  .data = &rk3399_vop_big },
5210a63bfd0SMark Yao 	{ .compatible = "rockchip,rk3399-vop-lit",
5220a63bfd0SMark Yao 	  .data = &rk3399_vop_lit },
523eb5cb6aaSMark yao 	{ .compatible = "rockchip,rk3228-vop",
524eb5cb6aaSMark yao 	  .data = &rk3228_vop },
525eb5cb6aaSMark yao 	{ .compatible = "rockchip,rk3328-vop",
526eb5cb6aaSMark yao 	  .data = &rk3328_vop },
527a67719d1SMark Yao 	{},
528a67719d1SMark Yao };
529a67719d1SMark Yao MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
530a67719d1SMark Yao 
531a67719d1SMark Yao static int vop_probe(struct platform_device *pdev)
532a67719d1SMark Yao {
533a67719d1SMark Yao 	struct device *dev = &pdev->dev;
534a67719d1SMark Yao 
535a67719d1SMark Yao 	if (!dev->of_node) {
536d8dd6804SHaneen Mohammed 		DRM_DEV_ERROR(dev, "can't find vop devices\n");
537a67719d1SMark Yao 		return -ENODEV;
538a67719d1SMark Yao 	}
539a67719d1SMark Yao 
540a67719d1SMark Yao 	return component_add(dev, &vop_component_ops);
541a67719d1SMark Yao }
542a67719d1SMark Yao 
543a67719d1SMark Yao static int vop_remove(struct platform_device *pdev)
544a67719d1SMark Yao {
545a67719d1SMark Yao 	component_del(&pdev->dev, &vop_component_ops);
546a67719d1SMark Yao 
547a67719d1SMark Yao 	return 0;
548a67719d1SMark Yao }
549a67719d1SMark Yao 
5508820b68bSJeffy Chen struct platform_driver vop_platform_driver = {
551a67719d1SMark Yao 	.probe = vop_probe,
552a67719d1SMark Yao 	.remove = vop_remove,
553a67719d1SMark Yao 	.driver = {
554a67719d1SMark Yao 		.name = "rockchip-vop",
555a67719d1SMark Yao 		.of_match_table = of_match_ptr(vop_driver_dt_match),
556a67719d1SMark Yao 	},
557a67719d1SMark Yao };
558