Merge tag 'lsk-v4.4-17.06-android' of git://git.linaro.org/kernel/linux-linaro-stable.git
[firefly-linux-kernel-4.4.55.git] / drivers / gpu / drm / rockchip / rockchip_vop_reg.c
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_VER_MASK(off, _mask, s, _write_mask, _major, \
24                          _begin_minor, _end_minor) \
25                 {.offset = off, \
26                  .mask = _mask, \
27                  .shift = s, \
28                  .write_mask = _write_mask, \
29                  .major = _major, \
30                  .begin_minor = _begin_minor, \
31                  .end_minor = _end_minor,}
32
33 #define VOP_REG(off, _mask, s) \
34                 VOP_REG_VER_MASK(off, _mask, s, false, 0, 0, -1)
35
36 #define VOP_REG_MASK(off, _mask, s) \
37                 VOP_REG_VER_MASK(off, _mask, s, true, 0, 0, -1)
38
39 #define VOP_REG_VER(off, _mask, s, _major, _begin_minor, _end_minor) \
40                 VOP_REG_VER_MASK(off, _mask, s, false, \
41                                  _major, _begin_minor, _end_minor)
42
43
44 static const uint32_t formats_win_full[] = {
45         DRM_FORMAT_XRGB8888,
46         DRM_FORMAT_ARGB8888,
47         DRM_FORMAT_XBGR8888,
48         DRM_FORMAT_ABGR8888,
49         DRM_FORMAT_RGB888,
50         DRM_FORMAT_BGR888,
51         DRM_FORMAT_RGB565,
52         DRM_FORMAT_BGR565,
53         DRM_FORMAT_NV12,
54         DRM_FORMAT_NV16,
55         DRM_FORMAT_NV24,
56         DRM_FORMAT_NV12_10,
57         DRM_FORMAT_NV16_10,
58         DRM_FORMAT_NV24_10,
59 };
60
61 static const uint32_t formats_win_lite[] = {
62         DRM_FORMAT_XRGB8888,
63         DRM_FORMAT_ARGB8888,
64         DRM_FORMAT_XBGR8888,
65         DRM_FORMAT_ABGR8888,
66         DRM_FORMAT_RGB888,
67         DRM_FORMAT_BGR888,
68         DRM_FORMAT_RGB565,
69         DRM_FORMAT_BGR565,
70 };
71
72 static const struct vop_scl_extension rk3288_win_full_scl_ext = {
73         .cbcr_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 31),
74         .cbcr_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 30),
75         .cbcr_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 28),
76         .cbcr_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 26),
77         .cbcr_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 24),
78         .yrgb_vsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 23),
79         .yrgb_vsu_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 22),
80         .yrgb_hsd_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 20),
81         .yrgb_ver_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 18),
82         .yrgb_hor_scl_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 16),
83         .line_load_mode = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 15),
84         .cbcr_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0x7, 12),
85         .yrgb_axi_gather_num = VOP_REG(RK3288_WIN0_CTRL1, 0xf, 8),
86         .vsd_cbcr_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 7),
87         .vsd_cbcr_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 6),
88         .vsd_yrgb_gt2 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 5),
89         .vsd_yrgb_gt4 = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 4),
90         .bic_coe_sel = VOP_REG(RK3288_WIN0_CTRL1, 0x3, 2),
91         .cbcr_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 1),
92         .yrgb_axi_gather_en = VOP_REG(RK3288_WIN0_CTRL1, 0x1, 0),
93         .lb_mode = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 5),
94 };
95
96 static const struct vop_scl_regs rk3288_win_full_scl = {
97         .ext = &rk3288_win_full_scl_ext,
98         .scale_yrgb_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
99         .scale_yrgb_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
100         .scale_cbcr_x = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
101         .scale_cbcr_y = VOP_REG(RK3288_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
102 };
103
104 static const struct vop_win_phy rk3288_win01_data = {
105         .scl = &rk3288_win_full_scl,
106         .data_formats = formats_win_full,
107         .nformats = ARRAY_SIZE(formats_win_full),
108         .enable = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 0),
109         .format = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 1),
110         .fmt_10 = VOP_REG(RK3288_WIN0_CTRL0, 0x7, 4),
111         .rb_swap = VOP_REG(RK3288_WIN0_CTRL0, 0x1, 12),
112         .xmirror = VOP_REG_VER(RK3368_WIN0_CTRL0, 0x1, 21, 3, 2, -1),
113         .ymirror = VOP_REG_VER(RK3368_WIN0_CTRL0, 0x1, 22, 3, 2, -1),
114         .act_info = VOP_REG(RK3288_WIN0_ACT_INFO, 0x1fff1fff, 0),
115         .dsp_info = VOP_REG(RK3288_WIN0_DSP_INFO, 0x0fff0fff, 0),
116         .dsp_st = VOP_REG(RK3288_WIN0_DSP_ST, 0x1fff1fff, 0),
117         .yrgb_mst = VOP_REG(RK3288_WIN0_YRGB_MST, 0xffffffff, 0),
118         .uv_mst = VOP_REG(RK3288_WIN0_CBR_MST, 0xffffffff, 0),
119         .yrgb_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 0),
120         .uv_vir = VOP_REG(RK3288_WIN0_VIR, 0x3fff, 16),
121         .src_alpha_ctl = VOP_REG(RK3288_WIN0_SRC_ALPHA_CTRL, 0xffffffff, 0),
122         .dst_alpha_ctl = VOP_REG(RK3288_WIN0_DST_ALPHA_CTRL, 0xffffffff, 0),
123         .channel = VOP_REG_VER(RK3288_WIN0_CTRL2, 0xff, 0, 3, 8, 8),
124 };
125
126 static const struct vop_win_phy rk3288_win23_data = {
127         .data_formats = formats_win_lite,
128         .nformats = ARRAY_SIZE(formats_win_lite),
129         .gate = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 0),
130         .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 4),
131         .format = VOP_REG(RK3288_WIN2_CTRL0, 0x7, 1),
132         .rb_swap = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 12),
133         .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO0, 0x0fff0fff, 0),
134         .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST0, 0x1fff1fff, 0),
135         .yrgb_mst = VOP_REG(RK3288_WIN2_MST0, 0xffffffff, 0),
136         .yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 0),
137         .src_alpha_ctl = VOP_REG(RK3288_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
138         .dst_alpha_ctl = VOP_REG(RK3288_WIN2_DST_ALPHA_CTRL, 0xff, 0),
139 };
140
141 static const struct vop_win_phy rk3288_area1_data = {
142         .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 5),
143         .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO1, 0x0fff0fff, 0),
144         .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST1, 0x1fff1fff, 0),
145         .yrgb_mst = VOP_REG(RK3288_WIN2_MST1, 0xffffffff, 0),
146         .yrgb_vir = VOP_REG(RK3288_WIN2_VIR0_1, 0x1fff, 16),
147 };
148
149 static const struct vop_win_phy rk3288_area2_data = {
150         .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 6),
151         .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO2, 0x0fff0fff, 0),
152         .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST2, 0x1fff1fff, 0),
153         .yrgb_mst = VOP_REG(RK3288_WIN2_MST2, 0xffffffff, 0),
154         .yrgb_vir = VOP_REG(RK3288_WIN2_VIR2_3, 0x1fff, 0),
155 };
156
157 static const struct vop_win_phy rk3288_area3_data = {
158         .enable = VOP_REG(RK3288_WIN2_CTRL0, 0x1, 7),
159         .dsp_info = VOP_REG(RK3288_WIN2_DSP_INFO3, 0x0fff0fff, 0),
160         .dsp_st = VOP_REG(RK3288_WIN2_DSP_ST3, 0x1fff1fff, 0),
161         .yrgb_mst = VOP_REG(RK3288_WIN2_MST3, 0xffffffff, 0),
162         .yrgb_vir = VOP_REG(RK3288_WIN2_VIR2_3, 0x1fff, 16),
163 };
164
165 static const struct vop_win_phy *rk3288_area_data[] = {
166         &rk3288_area1_data,
167         &rk3288_area2_data,
168         &rk3288_area3_data
169 };
170
171 static const struct vop_ctrl rk3288_ctrl_data = {
172         .standby = VOP_REG(RK3288_SYS_CTRL, 0x1, 22),
173         .htotal_pw = VOP_REG(RK3288_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
174         .hact_st_end = VOP_REG(RK3288_DSP_HACT_ST_END, 0x1fff1fff, 0),
175         .vtotal_pw = VOP_REG(RK3288_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
176         .vact_st_end = VOP_REG(RK3288_DSP_VACT_ST_END, 0x1fff1fff, 0),
177         .vact_st_end_f1 = VOP_REG(RK3288_DSP_VACT_ST_END_F1, 0x1fff1fff, 0),
178         .vs_st_end_f1 = VOP_REG(RK3288_DSP_VS_ST_END_F1, 0x1fff1fff, 0),
179         .hpost_st_end = VOP_REG(RK3288_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
180         .vpost_st_end = VOP_REG(RK3288_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
181         .vpost_st_end_f1 = VOP_REG(RK3288_POST_DSP_VACT_INFO_F1, 0x1fff1fff, 0),
182         .post_scl_factor = VOP_REG(RK3288_POST_SCL_FACTOR_YRGB, 0xffffffff, 0),
183         .post_scl_ctrl = VOP_REG(RK3288_POST_SCL_CTRL, 0x3, 0),
184
185         .dsp_interlace = VOP_REG(RK3288_DSP_CTRL0, 0x1, 10),
186         .auto_gate_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 23),
187         .dsp_layer_sel = VOP_REG(RK3288_DSP_CTRL1, 0xff, 8),
188         .post_lb_mode = VOP_REG_VER(RK3288_SYS_CTRL, 0x1, 18, 3, 2, -1),
189         .global_regdone_en = VOP_REG_VER(RK3288_SYS_CTRL, 0x1, 11, 3, 2, -1),
190         .overlay_mode = VOP_REG_VER(RK3288_SYS_CTRL, 0x1, 16, 3, 2, -1),
191         .core_dclk_div = VOP_REG_VER(RK3366_DSP_CTRL0, 0x1, 4, 3, 4, -1),
192         .p2i_en = VOP_REG_VER(RK3366_DSP_CTRL0, 0x1, 5, 3, 4, -1),
193         .dclk_ddr = VOP_REG_VER(RK3366_DSP_CTRL0, 0x1, 8, 3, 4, -1),
194         .dp_en = VOP_REG_VER(RK3399_SYS_CTRL, 0x1, 11, 3, 5, -1),
195         .rgb_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 12),
196         .hdmi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 13),
197         .edp_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 14),
198         .mipi_en = VOP_REG(RK3288_SYS_CTRL, 0x1, 15),
199         .pin_pol = VOP_REG_VER(RK3288_DSP_CTRL0, 0xf, 4, 3, 0, 1),
200         .dp_pin_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0xf, 16, 3, 2, -1),
201         .rgb_pin_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0xf, 16, 3, 2, -1),
202         .hdmi_pin_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0xf, 20, 3, 2, -1),
203         .edp_pin_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0xf, 24, 3, 2, -1),
204         .mipi_pin_pol = VOP_REG_VER(RK3368_DSP_CTRL1, 0xf, 28, 3, 2, -1),
205
206         .dither_down = VOP_REG(RK3288_DSP_CTRL1, 0xf, 1),
207         .dither_up = VOP_REG(RK3288_DSP_CTRL1, 0x1, 6),
208
209         .dsp_out_yuv = VOP_REG_VER(RK3399_POST_SCL_CTRL, 0x1, 2, 3, 5, -1),
210         .dsp_data_swap = VOP_REG(RK3288_DSP_CTRL0, 0x1f, 12),
211         .dsp_ccir656_avg = VOP_REG(RK3288_DSP_CTRL0, 0x1, 20),
212         .dsp_blank = VOP_REG(RK3288_DSP_CTRL0, 0x3, 18),
213         .update_gamma_lut = VOP_REG_VER(RK3288_DSP_CTRL1, 0x1, 7, 3, 5, -1),
214         .lut_buffer_index = VOP_REG_VER(RK3399_DBG_POST_REG1, 0x1, 1, 3, 5, -1),
215         .dsp_lut_en = VOP_REG(RK3288_DSP_CTRL1, 0x1, 0),
216         .out_mode = VOP_REG(RK3288_DSP_CTRL0, 0xf, 0),
217
218         .afbdc_rstn = VOP_REG_VER(RK3399_AFBCD0_CTRL, 0x1, 3, 3, 5, -1),
219         .afbdc_en = VOP_REG_VER(RK3399_AFBCD0_CTRL, 0x1, 0, 3, 5, -1),
220         .afbdc_sel = VOP_REG_VER(RK3399_AFBCD0_CTRL, 0x3, 1, 3, 5, -1),
221         .afbdc_format = VOP_REG_VER(RK3399_AFBCD0_CTRL, 0x1f, 16, 3, 5, -1),
222         .afbdc_hreg_block_split = VOP_REG_VER(RK3399_AFBCD0_CTRL,
223                                               0x1, 21, 3, 5, -1),
224         .afbdc_hdr_ptr = VOP_REG_VER(RK3399_AFBCD0_HDR_PTR, 0xffffffff,
225                                      0, 3, 5, -1),
226         .afbdc_pic_size = VOP_REG_VER(RK3399_AFBCD0_PIC_SIZE, 0xffffffff,
227                                       0, 3, 5, -1),
228
229         .xmirror = VOP_REG(RK3288_DSP_CTRL0, 0x1, 22),
230         .ymirror = VOP_REG(RK3288_DSP_CTRL0, 0x1, 23),
231
232         .dsp_background = VOP_REG(RK3288_DSP_BG, 0xffffffff, 0),
233
234         .cfg_done = VOP_REG(RK3288_REG_CFG_DONE, 0x1, 0),
235 };
236
237 /*
238  * Note: rk3288 has a dedicated 'cursor' window, however, that window requires
239  * special support to get alpha blending working.  For now, just use overlay
240  * window 3 for the drm cursor.
241  *
242  */
243 static const struct vop_win_data rk3288_vop_win_data[] = {
244         { .base = 0x00, .phy = &rk3288_win01_data,
245           .type = DRM_PLANE_TYPE_PRIMARY },
246         { .base = 0x40, .phy = &rk3288_win01_data,
247           .type = DRM_PLANE_TYPE_OVERLAY },
248         { .base = 0x00, .phy = &rk3288_win23_data,
249           .type = DRM_PLANE_TYPE_OVERLAY,
250           .area = rk3288_area_data,
251           .area_size = ARRAY_SIZE(rk3288_area_data), },
252         { .base = 0x50, .phy = &rk3288_win23_data,
253           .type = DRM_PLANE_TYPE_CURSOR,
254           .area = rk3288_area_data,
255           .area_size = ARRAY_SIZE(rk3288_area_data), },
256 };
257
258 static const int rk3288_vop_intrs[] = {
259         DSP_HOLD_VALID_INTR,
260         FS_INTR,
261         LINE_FLAG_INTR,
262         BUS_ERROR_INTR,
263 };
264
265 static const struct vop_intr rk3288_vop_intr = {
266         .intrs = rk3288_vop_intrs,
267         .nintrs = ARRAY_SIZE(rk3288_vop_intrs),
268         .line_flag_num[0] = VOP_REG(RK3288_INTR_CTRL0, 0x1fff, 12),
269         .status = VOP_REG(RK3288_INTR_CTRL0, 0xf, 0),
270         .enable = VOP_REG(RK3288_INTR_CTRL0, 0xf, 4),
271         .clear = VOP_REG(RK3288_INTR_CTRL0, 0xf, 8),
272 };
273
274 static const struct vop_data rk3288_vop = {
275         .version = VOP_VERSION(3, 1),
276         .feature = VOP_FEATURE_OUTPUT_10BIT,
277         .max_input = {4096, 8192},
278         /*
279          * TODO: rk3288 have two vop, big one support 3840x2160,
280          * little one only support 2560x1600.
281          * Now force use 3840x2160.
282          */
283         .max_output = {3840, 2160},
284         .intr = &rk3288_vop_intr,
285         .ctrl = &rk3288_ctrl_data,
286         .win = rk3288_vop_win_data,
287         .win_size = ARRAY_SIZE(rk3288_vop_win_data),
288 };
289
290 static const int rk3368_vop_intrs[] = {
291         FS_INTR,
292         FS_NEW_INTR,
293         ADDR_SAME_INTR,
294         LINE_FLAG_INTR,
295         LINE_FLAG1_INTR,
296         BUS_ERROR_INTR,
297         WIN0_EMPTY_INTR,
298         WIN1_EMPTY_INTR,
299         WIN2_EMPTY_INTR,
300         WIN3_EMPTY_INTR,
301         HWC_EMPTY_INTR,
302         POST_BUF_EMPTY_INTR,
303         PWM_GEN_INTR,
304         DSP_HOLD_VALID_INTR,
305 };
306
307 static const struct vop_intr rk3368_vop_intr = {
308         .intrs = rk3368_vop_intrs,
309         .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
310         .line_flag_num[0] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 0),
311         .line_flag_num[1] = VOP_REG(RK3368_LINE_FLAG, 0xffff, 16),
312         .status = VOP_REG_MASK(RK3368_INTR_STATUS, 0x3fff, 0),
313         .enable = VOP_REG_MASK(RK3368_INTR_EN, 0x3fff, 0),
314         .clear = VOP_REG_MASK(RK3368_INTR_CLEAR, 0x3fff, 0),
315 };
316
317 static const struct vop_win_phy rk3368_win23_data = {
318         .data_formats = formats_win_lite,
319         .nformats = ARRAY_SIZE(formats_win_lite),
320         .gate = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 0),
321         .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 4),
322         .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 5),
323         .ymirror = VOP_REG(RK3368_WIN2_CTRL1, 0x1, 15),
324         .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 20),
325         .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO0, 0x0fff0fff, 0),
326         .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST0, 0x1fff1fff, 0),
327         .yrgb_mst = VOP_REG(RK3368_WIN2_MST0, 0xffffffff, 0),
328         .yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 0),
329         .src_alpha_ctl = VOP_REG(RK3368_WIN2_SRC_ALPHA_CTRL, 0xff, 0),
330         .dst_alpha_ctl = VOP_REG(RK3368_WIN2_DST_ALPHA_CTRL, 0xff, 0),
331 };
332
333 static const struct vop_win_phy rk3368_area1_data = {
334         .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 8),
335         .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 9),
336         .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 23),
337         .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO1, 0x0fff0fff, 0),
338         .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST1, 0x1fff1fff, 0),
339         .yrgb_mst = VOP_REG(RK3368_WIN2_MST1, 0xffffffff, 0),
340         .yrgb_vir = VOP_REG(RK3368_WIN2_VIR0_1, 0x1fff, 16),
341 };
342
343 static const struct vop_win_phy rk3368_area2_data = {
344         .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 12),
345         .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 13),
346         .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 26),
347         .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO2, 0x0fff0fff, 0),
348         .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST2, 0x1fff1fff, 0),
349         .yrgb_mst = VOP_REG(RK3368_WIN2_MST2, 0xffffffff, 0),
350         .yrgb_vir = VOP_REG(RK3368_WIN2_VIR2_3, 0x1fff, 0),
351 };
352
353 static const struct vop_win_phy rk3368_area3_data = {
354         .enable = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 16),
355         .format = VOP_REG(RK3368_WIN2_CTRL0, 0x3, 17),
356         .rb_swap = VOP_REG(RK3368_WIN2_CTRL0, 0x1, 29),
357         .dsp_info = VOP_REG(RK3368_WIN2_DSP_INFO3, 0x0fff0fff, 0),
358         .dsp_st = VOP_REG(RK3368_WIN2_DSP_ST3, 0x1fff1fff, 0),
359         .yrgb_mst = VOP_REG(RK3368_WIN2_MST3, 0xffffffff, 0),
360         .yrgb_vir = VOP_REG(RK3368_WIN2_VIR2_3, 0x1fff, 16),
361 };
362
363 static const struct vop_win_phy *rk3368_area_data[] = {
364         &rk3368_area1_data,
365         &rk3368_area2_data,
366         &rk3368_area3_data
367 };
368
369 static const struct vop_win_data rk3368_vop_win_data[] = {
370         { .base = 0x00, .phy = &rk3288_win01_data,
371           .type = DRM_PLANE_TYPE_PRIMARY },
372         { .base = 0x40, .phy = &rk3288_win01_data,
373           .type = DRM_PLANE_TYPE_OVERLAY },
374         { .base = 0x00, .phy = &rk3368_win23_data,
375           .type = DRM_PLANE_TYPE_OVERLAY,
376           .area = rk3368_area_data,
377           .area_size = ARRAY_SIZE(rk3368_area_data), },
378         { .base = 0x50, .phy = &rk3368_win23_data,
379           .type = DRM_PLANE_TYPE_CURSOR,
380           .area = rk3368_area_data,
381           .area_size = ARRAY_SIZE(rk3368_area_data), },
382 };
383
384 static const struct vop_data rk3368_vop = {
385         .version = VOP_VERSION(3, 2),
386         .max_input = {4096, 8192},
387         .max_output = {4096, 2160},
388         .intr = &rk3368_vop_intr,
389         .ctrl = &rk3288_ctrl_data,
390         .win = rk3368_vop_win_data,
391         .win_size = ARRAY_SIZE(rk3368_vop_win_data),
392 };
393
394 static const struct vop_intr rk3366_vop_intr = {
395         .intrs = rk3368_vop_intrs,
396         .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
397         .line_flag_num[0] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 0),
398         .line_flag_num[1] = VOP_REG(RK3366_LINE_FLAG, 0xffff, 16),
399         .status = VOP_REG_MASK(RK3366_INTR_STATUS0, 0xffff, 0),
400         .enable = VOP_REG_MASK(RK3366_INTR_EN0, 0xffff, 0),
401         .clear = VOP_REG_MASK(RK3366_INTR_CLEAR0, 0xffff, 0),
402 };
403
404 static const struct vop_data rk3366_vop = {
405         .version = VOP_VERSION(3, 4),
406         .max_input = {4096, 8192},
407         .max_output = {4096, 2160},
408         .intr = &rk3366_vop_intr,
409         .ctrl = &rk3288_ctrl_data,
410         .win = rk3368_vop_win_data,
411         .win_size = ARRAY_SIZE(rk3368_vop_win_data),
412 };
413
414 static const uint32_t vop_csc_y2r_bt601[] = {
415         0x00000400, 0x0400059c, 0xfd25fea0, 0x07170400,
416         0x00000000, 0xfffecab4, 0x00087932, 0xfff1d4f2,
417 };
418
419 static const uint32_t vop_csc_y2r_bt601_12_235[] = {
420         0x000004a8, 0x04a80662, 0xfcbffe6f, 0x081204a8,
421         0x00000000, 0xfff2134e, 0x00087b58, 0xffeeb4b0,
422 };
423
424 static const uint32_t vop_csc_r2y_bt601[] = {
425         0x02590132, 0xff530075, 0x0200fead, 0xfe530200,
426         0x0000ffad, 0x00000200, 0x00080200, 0x00080200,
427 };
428
429 static const uint32_t vop_csc_r2y_bt601_12_235[] = {
430         0x02040107, 0xff680064, 0x01c2fed6, 0xffb7fe87,
431         0x0000ffb7, 0x00010200, 0x00080200, 0x00080200,
432 };
433
434 static const uint32_t vop_csc_y2r_bt709[] = {
435         0x000004a8, 0x04a8072c, 0xfddeff26, 0x087304a8,
436         0x00000000, 0xfff08077, 0x0004cfed, 0xffedf1b8,
437 };
438
439 static const uint32_t vop_csc_r2y_bt709[] = {
440         0x027500bb, 0xff99003f, 0x01c2fea5, 0xfe6801c2,
441         0x0000ffd7, 0x00010200, 0x00080200, 0x00080200,
442 };
443
444 static const uint32_t vop_csc_y2r_bt2020[] = {
445         0x000004a8, 0x04a806b6, 0xfd66ff40, 0x089004a8,
446         0x00000000, 0xfff16bfc, 0x00058ae9, 0xffedb828,
447 };
448
449 static const uint32_t vop_csc_r2y_bt2020[] = {
450         0x025300e6, 0xff830034, 0x01c1febd, 0xfe6401c1,
451         0x0000ffdc, 0x00010200, 0x00080200, 0x00080200,
452 };
453
454 static const uint32_t vop_csc_r2r_bt709_to_bt2020[] = {
455         0xfda606a4, 0xff80ffb5, 0xfff80488, 0xff99ffed,
456         0x0000047a, 0x00000200, 0x00000200, 0x00000200,
457 };
458
459 static const uint32_t vop_csc_r2r_bt2020_to_bt709[] = {
460         0x01510282, 0x0047002c, 0x000c03ae, 0x005a0011,
461         0x00000394, 0x00000200, 0x00000200, 0x00000200,
462 };
463
464 static const struct vop_csc_table rk3399_csc_table = {
465         .y2r_bt601              = vop_csc_y2r_bt601,
466         .y2r_bt601_12_235       = vop_csc_y2r_bt601_12_235,
467         .r2y_bt601              = vop_csc_r2y_bt601,
468         .r2y_bt601_12_235       = vop_csc_r2y_bt601_12_235,
469
470         .y2r_bt709              = vop_csc_y2r_bt709,
471         .r2y_bt709              = vop_csc_r2y_bt709,
472
473         .y2r_bt2020             = vop_csc_y2r_bt2020,
474         .r2y_bt2020             = vop_csc_r2y_bt2020,
475
476         .r2r_bt709_to_bt2020    = vop_csc_r2r_bt709_to_bt2020,
477         .r2r_bt2020_to_bt709    = vop_csc_r2r_bt2020_to_bt709,
478 };
479
480 static const struct vop_csc rk3399_win0_csc = {
481         .r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 0),
482         .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 1),
483         .r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 2),
484         .y2r_offset = RK3399_WIN0_YUV2YUV_Y2R,
485         .r2r_offset = RK3399_WIN0_YUV2YUV_3X3,
486         .r2y_offset = RK3399_WIN0_YUV2YUV_R2Y,
487 };
488
489 static const struct vop_csc rk3399_win1_csc = {
490         .r2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 8),
491         .y2r_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 9),
492         .r2y_en = VOP_REG(RK3399_YUV2YUV_WIN, 0x1, 10),
493         .y2r_offset = RK3399_WIN1_YUV2YUV_Y2R,
494         .r2r_offset = RK3399_WIN1_YUV2YUV_3X3,
495         .r2y_offset = RK3399_WIN1_YUV2YUV_R2Y,
496 };
497
498 static const struct vop_win_data rk3399_vop_win_data[] = {
499         { .base = 0x00, .phy = &rk3288_win01_data, .csc = &rk3399_win0_csc,
500           .type = DRM_PLANE_TYPE_PRIMARY },
501         { .base = 0x40, .phy = &rk3288_win01_data, .csc = &rk3399_win1_csc,
502           .type = DRM_PLANE_TYPE_OVERLAY },
503         { .base = 0x00, .phy = &rk3368_win23_data,
504           .type = DRM_PLANE_TYPE_OVERLAY,
505           .area = rk3368_area_data,
506           .area_size = ARRAY_SIZE(rk3368_area_data), },
507         { .base = 0x50, .phy = &rk3368_win23_data,
508           .type = DRM_PLANE_TYPE_CURSOR,
509           .area = rk3368_area_data,
510           .area_size = ARRAY_SIZE(rk3368_area_data), },
511 };
512
513 static const struct vop_data rk3399_vop_big = {
514         .version = VOP_VERSION(3, 5),
515         .csc_table = &rk3399_csc_table,
516         .feature = VOP_FEATURE_OUTPUT_10BIT | VOP_FEATURE_AFBDC,
517         .max_input = {4096, 8192},
518         .max_output = {4096, 2160},
519         .intr = &rk3366_vop_intr,
520         .ctrl = &rk3288_ctrl_data,
521         .win = rk3399_vop_win_data,
522         .win_size = ARRAY_SIZE(rk3399_vop_win_data),
523 };
524
525 static const struct vop_win_data rk3399_vop_lit_win_data[] = {
526         { .base = 0x00, .phy = &rk3288_win01_data, .csc = &rk3399_win0_csc,
527           .type = DRM_PLANE_TYPE_PRIMARY },
528         { .phy = NULL },
529         { .base = 0x00, .phy = &rk3368_win23_data,
530           .type = DRM_PLANE_TYPE_CURSOR,
531           .area = rk3368_area_data,
532           .area_size = ARRAY_SIZE(rk3368_area_data), },
533         { .phy = NULL },
534 };
535
536
537 static const struct vop_data rk3399_vop_lit = {
538         .version = VOP_VERSION(3, 6),
539         .csc_table = &rk3399_csc_table,
540         .max_input = {4096, 8192},
541         .max_output = {2560, 1600},
542         .intr = &rk3366_vop_intr,
543         .ctrl = &rk3288_ctrl_data,
544         .win = rk3399_vop_lit_win_data,
545         .win_size = ARRAY_SIZE(rk3399_vop_lit_win_data),
546 };
547
548 static const struct vop_win_data rk322x_vop_win_data[] = {
549         { .base = 0x00, .phy = &rk3288_win01_data,
550           .type = DRM_PLANE_TYPE_PRIMARY },
551         { .base = 0x40, .phy = &rk3288_win01_data,
552           .type = DRM_PLANE_TYPE_CURSOR },
553 };
554
555 static const struct vop_data rk322x_vop = {
556         .version = VOP_VERSION(3, 7),
557         .feature = VOP_FEATURE_OUTPUT_10BIT,
558         .max_input = {4096, 8192},
559         .max_output = {4096, 2160},
560         .intr = &rk3366_vop_intr,
561         .ctrl = &rk3288_ctrl_data,
562         .win = rk322x_vop_win_data,
563         .win_size = ARRAY_SIZE(rk322x_vop_win_data),
564 };
565
566 static const struct vop_ctrl rk3328_ctrl_data = {
567         .standby = VOP_REG(RK3328_SYS_CTRL, 0x1, 22),
568         .auto_gate_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 23),
569         .htotal_pw = VOP_REG(RK3328_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
570         .hact_st_end = VOP_REG(RK3328_DSP_HACT_ST_END, 0x1fff1fff, 0),
571         .vtotal_pw = VOP_REG(RK3328_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
572         .vact_st_end = VOP_REG(RK3328_DSP_VACT_ST_END, 0x1fff1fff, 0),
573         .vact_st_end_f1 = VOP_REG(RK3328_DSP_VACT_ST_END_F1, 0x1fff1fff, 0),
574         .vs_st_end_f1 = VOP_REG(RK3328_DSP_VS_ST_END_F1, 0x1fff1fff, 0),
575         .hpost_st_end = VOP_REG(RK3328_POST_DSP_HACT_INFO, 0x1fff1fff, 0),
576         .vpost_st_end = VOP_REG(RK3328_POST_DSP_VACT_INFO, 0x1fff1fff, 0),
577         .vpost_st_end_f1 = VOP_REG(RK3328_POST_DSP_VACT_INFO_F1, 0x1fff1fff, 0),
578         .dsp_interlace = VOP_REG(RK3328_DSP_CTRL0, 0x1, 10),
579         .dsp_layer_sel = VOP_REG(RK3328_DSP_CTRL1, 0xff, 8),
580         .post_lb_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 18),
581         .global_regdone_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 11),
582         .overlay_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 16),
583         .core_dclk_div = VOP_REG(RK3328_DSP_CTRL0, 0x1, 4),
584         .p2i_en = VOP_REG(RK3328_DSP_CTRL0, 0x1, 5),
585         .rgb_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 12),
586         .hdmi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 13),
587         .edp_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 14),
588         .mipi_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 15),
589         .tve_dclk_en = VOP_REG(RK3328_SYS_CTRL, 0x1, 24),
590         .tve_dclk_pol = VOP_REG(RK3328_SYS_CTRL, 0x1, 25),
591         .tve_sw_mode = VOP_REG(RK3328_SYS_CTRL, 0x1, 26),
592         .sw_uv_offset_en  = VOP_REG(RK3328_SYS_CTRL, 0x1, 27),
593         .sw_genlock   = VOP_REG(RK3328_SYS_CTRL, 0x1, 28),
594         .sw_dac_sel = VOP_REG(RK3328_SYS_CTRL, 0x1, 29),
595         .rgb_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 16),
596         .hdmi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 20),
597         .edp_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 24),
598         .mipi_pin_pol = VOP_REG(RK3328_DSP_CTRL1, 0xf, 28),
599
600         .dither_down = VOP_REG(RK3328_DSP_CTRL1, 0xf, 1),
601         .dither_up = VOP_REG(RK3328_DSP_CTRL1, 0x1, 6),
602
603         .dsp_data_swap = VOP_REG(RK3328_DSP_CTRL0, 0x1f, 12),
604         .dsp_ccir656_avg = VOP_REG(RK3328_DSP_CTRL0, 0x1, 20),
605         .dsp_blank = VOP_REG(RK3328_DSP_CTRL0, 0x3, 18),
606         .dsp_lut_en = VOP_REG(RK3328_DSP_CTRL1, 0x1, 0),
607         .out_mode = VOP_REG(RK3328_DSP_CTRL0, 0xf, 0),
608
609         .xmirror = VOP_REG(RK3328_DSP_CTRL0, 0x1, 22),
610         .ymirror = VOP_REG(RK3328_DSP_CTRL0, 0x1, 23),
611
612         .dsp_background = VOP_REG(RK3328_DSP_BG, 0xffffffff, 0),
613
614         .cfg_done = VOP_REG(RK3328_REG_CFG_DONE, 0x1, 0),
615 };
616
617 static const struct vop_intr rk3328_vop_intr = {
618         .intrs = rk3368_vop_intrs,
619         .nintrs = ARRAY_SIZE(rk3368_vop_intrs),
620         .line_flag_num[0] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 0),
621         .line_flag_num[1] = VOP_REG(RK3328_LINE_FLAG, 0xffff, 16),
622         .status = VOP_REG_MASK(RK3328_INTR_STATUS0, 0xffff, 0),
623         .enable = VOP_REG_MASK(RK3328_INTR_EN0, 0xffff, 0),
624         .clear = VOP_REG_MASK(RK3328_INTR_CLEAR0, 0xffff, 0),
625 };
626
627 static const struct vop_win_data rk3328_vop_win_data[] = {
628         { .base = 0xd0, .phy = &rk3288_win01_data,
629           .type = DRM_PLANE_TYPE_PRIMARY },
630         { .base = 0x1d0, .phy = &rk3288_win01_data,
631           .type = DRM_PLANE_TYPE_OVERLAY },
632         { .base = 0x2d0, .phy = &rk3288_win01_data,
633           .type = DRM_PLANE_TYPE_CURSOR },
634 };
635
636 static const struct vop_data rk3328_vop = {
637         .version = VOP_VERSION(3, 8),
638         .feature = VOP_FEATURE_OUTPUT_10BIT,
639         .max_input = {4096, 8192},
640         .max_output = {4096, 2160},
641         .intr = &rk3328_vop_intr,
642         .ctrl = &rk3328_ctrl_data,
643         .win = rk3328_vop_win_data,
644         .win_size = ARRAY_SIZE(rk3328_vop_win_data),
645 };
646
647 static const struct vop_scl_regs rk3066_win_scl = {
648         .scale_yrgb_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 0x0),
649         .scale_yrgb_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_YRGB, 0xffff, 16),
650         .scale_cbcr_x = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 0x0),
651         .scale_cbcr_y = VOP_REG(RK3036_WIN0_SCL_FACTOR_CBR, 0xffff, 16),
652 };
653
654 static const struct vop_win_phy rk3036_win0_data = {
655         .scl = &rk3066_win_scl,
656         .data_formats = formats_win_full,
657         .nformats = ARRAY_SIZE(formats_win_full),
658         .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 0),
659         .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 3),
660         .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 15),
661         .act_info = VOP_REG(RK3036_WIN0_ACT_INFO, 0x1fff1fff, 0),
662         .dsp_info = VOP_REG(RK3036_WIN0_DSP_INFO, 0x0fff0fff, 0),
663         .dsp_st = VOP_REG(RK3036_WIN0_DSP_ST, 0x1fff1fff, 0),
664         .yrgb_mst = VOP_REG(RK3036_WIN0_YRGB_MST, 0xffffffff, 0),
665         .uv_mst = VOP_REG(RK3036_WIN0_CBR_MST, 0xffffffff, 0),
666         .yrgb_vir = VOP_REG(RK3036_WIN0_VIR, 0xffff, 0),
667         .uv_vir = VOP_REG(RK3036_WIN0_VIR, 0x1fff, 16),
668         .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 18),
669         .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 0)
670 };
671
672 static const struct vop_win_phy rk3036_win1_data = {
673         .data_formats = formats_win_lite,
674         .nformats = ARRAY_SIZE(formats_win_lite),
675         .enable = VOP_REG(RK3036_SYS_CTRL, 0x1, 1),
676         .format = VOP_REG(RK3036_SYS_CTRL, 0x7, 6),
677         .rb_swap = VOP_REG(RK3036_SYS_CTRL, 0x1, 19),
678         .act_info = VOP_REG(RK3036_WIN1_ACT_INFO, 0x1fff1fff, 0),
679         .dsp_info = VOP_REG(RK3036_WIN1_DSP_INFO, 0x0fff0fff, 0),
680         .dsp_st = VOP_REG(RK3036_WIN1_DSP_ST, 0x1fff1fff, 0),
681         .yrgb_mst = VOP_REG(RK3036_WIN1_MST, 0xffffffff, 0),
682         .yrgb_vir = VOP_REG(RK3036_WIN1_VIR, 0xffff, 0),
683         .alpha_mode = VOP_REG(RK3036_DSP_CTRL0, 0x1, 19),
684         .alpha_en = VOP_REG(RK3036_ALPHA_CTRL, 0x1, 1)
685 };
686
687 static const struct vop_win_data rk3036_vop_win_data[] = {
688         { .base = 0x00, .phy = &rk3036_win0_data,
689           .type = DRM_PLANE_TYPE_PRIMARY },
690         { .base = 0x00, .phy = &rk3036_win1_data,
691           .type = DRM_PLANE_TYPE_CURSOR },
692 };
693
694 static const int rk3036_vop_intrs[] = {
695         DSP_HOLD_VALID_INTR,
696         FS_INTR,
697         LINE_FLAG_INTR,
698         BUS_ERROR_INTR,
699 };
700
701 static const struct vop_intr rk3036_intr = {
702         .intrs = rk3036_vop_intrs,
703         .nintrs = ARRAY_SIZE(rk3036_vop_intrs),
704         .line_flag_num[0] = VOP_REG(RK3036_INT_STATUS, 0xfff, 12),
705         .status = VOP_REG(RK3036_INT_STATUS, 0xf, 0),
706         .enable = VOP_REG(RK3036_INT_STATUS, 0xf, 4),
707         .clear = VOP_REG(RK3036_INT_STATUS, 0xf, 8),
708 };
709
710 static const struct vop_ctrl rk3036_ctrl_data = {
711         .standby = VOP_REG(RK3036_SYS_CTRL, 0x1, 30),
712         .out_mode = VOP_REG(RK3036_DSP_CTRL0, 0xf, 0),
713         .dsp_blank = VOP_REG(RK3036_DSP_CTRL1, 0x1, 24),
714         .pin_pol = VOP_REG(RK3036_DSP_CTRL0, 0xf, 4),
715         .dsp_layer_sel = VOP_REG(RK3036_DSP_CTRL0, 0x1, 8),
716         .htotal_pw = VOP_REG(RK3036_DSP_HTOTAL_HS_END, 0x1fff1fff, 0),
717         .hact_st_end = VOP_REG(RK3036_DSP_HACT_ST_END, 0x1fff1fff, 0),
718         .vtotal_pw = VOP_REG(RK3036_DSP_VTOTAL_VS_END, 0x1fff1fff, 0),
719         .vact_st_end = VOP_REG(RK3036_DSP_VACT_ST_END, 0x1fff1fff, 0),
720         .cfg_done = VOP_REG(RK3036_REG_CFG_DONE, 0x1, 0),
721 };
722
723 static const struct vop_data rk3036_vop = {
724         .version = VOP_VERSION(2, 2),
725         .max_input = {1920, 1080},
726         .max_output = {1920, 1080},
727         .ctrl = &rk3036_ctrl_data,
728         .intr = &rk3036_intr,
729         .win = rk3036_vop_win_data,
730         .win_size = ARRAY_SIZE(rk3036_vop_win_data),
731 };
732
733 static const struct of_device_id vop_driver_dt_match[] = {
734         { .compatible = "rockchip,rk3036-vop",
735           .data = &rk3036_vop },
736         { .compatible = "rockchip,rk3288-vop",
737           .data = &rk3288_vop },
738         { .compatible = "rockchip,rk3368-vop",
739           .data = &rk3368_vop },
740         { .compatible = "rockchip,rk3366-vop",
741           .data = &rk3366_vop },
742         { .compatible = "rockchip,rk3399-vop-big",
743           .data = &rk3399_vop_big },
744         { .compatible = "rockchip,rk3399-vop-lit",
745           .data = &rk3399_vop_lit },
746         { .compatible = "rockchip,rk322x-vop",
747           .data = &rk322x_vop },
748         { .compatible = "rockchip,rk3328-vop",
749           .data = &rk3328_vop },
750         {},
751 };
752 MODULE_DEVICE_TABLE(of, vop_driver_dt_match);
753
754 static int vop_probe(struct platform_device *pdev)
755 {
756         struct device *dev = &pdev->dev;
757
758         if (!dev->of_node) {
759                 dev_err(dev, "can't find vop devices\n");
760                 return -ENODEV;
761         }
762
763         return component_add(dev, &vop_component_ops);
764 }
765
766 static int vop_remove(struct platform_device *pdev)
767 {
768         component_del(&pdev->dev, &vop_component_ops);
769
770         return 0;
771 }
772
773 struct platform_driver vop_platform_driver = {
774         .probe = vop_probe,
775         .remove = vop_remove,
776         .driver = {
777                 .name = "rockchip-vop",
778                 .owner = THIS_MODULE,
779                 .of_match_table = of_match_ptr(vop_driver_dt_match),
780         },
781 };
782
783 module_platform_driver(vop_platform_driver);
784
785 MODULE_AUTHOR("Mark Yao <mark.yao@rock-chips.com>");
786 MODULE_DESCRIPTION("ROCKCHIP VOP Driver");
787 MODULE_LICENSE("GPL v2");