xref: /linux/drivers/gpu/drm/rockchip/rockchip_vop2_reg.c (revision e70140ba0d2b1a30467d4af6bcfe761327b9ec95)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (C) Rockchip Electronics Co.Ltd
4  * Author: Andy Yan <andy.yan@rock-chips.com>
5  */
6 
7 #include <linux/kernel.h>
8 #include <linux/component.h>
9 #include <linux/mod_devicetable.h>
10 #include <linux/platform_device.h>
11 #include <linux/of.h>
12 #include <drm/drm_fourcc.h>
13 #include <drm/drm_plane.h>
14 #include <drm/drm_print.h>
15 
16 #include "rockchip_drm_vop2.h"
17 
18 static const uint32_t formats_cluster[] = {
19 	DRM_FORMAT_XRGB2101010,
20 	DRM_FORMAT_XBGR2101010,
21 	DRM_FORMAT_XRGB8888,
22 	DRM_FORMAT_ARGB8888,
23 	DRM_FORMAT_XBGR8888,
24 	DRM_FORMAT_ABGR8888,
25 	DRM_FORMAT_RGB888,
26 	DRM_FORMAT_BGR888,
27 	DRM_FORMAT_RGB565,
28 	DRM_FORMAT_BGR565,
29 	DRM_FORMAT_YUV420_8BIT, /* yuv420_8bit non-Linear mode only */
30 	DRM_FORMAT_YUV420_10BIT, /* yuv420_10bit non-Linear mode only */
31 	DRM_FORMAT_YUYV, /* yuv422_8bit non-Linear mode only*/
32 	DRM_FORMAT_Y210, /* yuv422_10bit non-Linear mode only */
33 };
34 
35 static const uint32_t formats_esmart[] = {
36 	DRM_FORMAT_XRGB8888,
37 	DRM_FORMAT_ARGB8888,
38 	DRM_FORMAT_XBGR8888,
39 	DRM_FORMAT_ABGR8888,
40 	DRM_FORMAT_RGB888,
41 	DRM_FORMAT_BGR888,
42 	DRM_FORMAT_RGB565,
43 	DRM_FORMAT_BGR565,
44 	DRM_FORMAT_NV12, /* yuv420_8bit linear mode, 2 plane */
45 	DRM_FORMAT_NV21, /* yvu420_8bit linear mode, 2 plane */
46 	DRM_FORMAT_NV16, /* yuv422_8bit linear mode, 2 plane */
47 	DRM_FORMAT_NV61, /* yvu422_8bit linear mode, 2 plane */
48 	DRM_FORMAT_NV20, /* yuv422_10bit linear mode, 2 plane, no padding */
49 	DRM_FORMAT_NV24, /* yuv444_8bit linear mode, 2 plane */
50 	DRM_FORMAT_NV42, /* yvu444_8bit linear mode, 2 plane */
51 	DRM_FORMAT_NV30, /* yuv444_10bit linear mode, 2 plane, no padding */
52 	DRM_FORMAT_NV15, /* yuv420_10bit linear mode, 2 plane, no padding */
53 	DRM_FORMAT_YVYU, /* yuv422_8bit[YVYU] linear mode */
54 	DRM_FORMAT_VYUY, /* yuv422_8bit[VYUY] linear mode */
55 	DRM_FORMAT_YUYV, /* yuv422_8bit[YUYV] linear mode */
56 	DRM_FORMAT_UYVY, /* yuv422_8bit[UYVY] linear mode */
57 };
58 
59 static const uint32_t formats_rk356x_esmart[] = {
60 	DRM_FORMAT_XRGB8888,
61 	DRM_FORMAT_ARGB8888,
62 	DRM_FORMAT_XBGR8888,
63 	DRM_FORMAT_ABGR8888,
64 	DRM_FORMAT_RGB888,
65 	DRM_FORMAT_BGR888,
66 	DRM_FORMAT_RGB565,
67 	DRM_FORMAT_BGR565,
68 	DRM_FORMAT_NV12, /* yuv420_8bit linear mode, 2 plane */
69 	DRM_FORMAT_NV21, /* yuv420_8bit linear mode, 2 plane */
70 	DRM_FORMAT_NV15, /* yuv420_10bit linear mode, 2 plane, no padding */
71 	DRM_FORMAT_NV16, /* yuv422_8bit linear mode, 2 plane */
72 	DRM_FORMAT_NV61, /* yuv422_8bit linear mode, 2 plane */
73 	DRM_FORMAT_NV20, /* yuv422_10bit linear mode, 2 plane, no padding */
74 	DRM_FORMAT_NV24, /* yuv444_8bit linear mode, 2 plane */
75 	DRM_FORMAT_NV42, /* yuv444_8bit linear mode, 2 plane */
76 	DRM_FORMAT_NV30, /* yuv444_10bit linear mode, 2 plane, no padding */
77 	DRM_FORMAT_YVYU, /* yuv422_8bit[YVYU] linear mode */
78 	DRM_FORMAT_VYUY, /* yuv422_8bit[VYUY] linear mode */
79 };
80 
81 static const uint32_t formats_smart[] = {
82 	DRM_FORMAT_XRGB8888,
83 	DRM_FORMAT_ARGB8888,
84 	DRM_FORMAT_XBGR8888,
85 	DRM_FORMAT_ABGR8888,
86 	DRM_FORMAT_RGB888,
87 	DRM_FORMAT_BGR888,
88 	DRM_FORMAT_RGB565,
89 	DRM_FORMAT_BGR565,
90 };
91 
92 static const uint64_t format_modifiers[] = {
93 	DRM_FORMAT_MOD_LINEAR,
94 	DRM_FORMAT_MOD_INVALID,
95 };
96 
97 static const uint64_t format_modifiers_afbc[] = {
98 	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16),
99 
100 	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
101 				AFBC_FORMAT_MOD_SPARSE),
102 
103 	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
104 				AFBC_FORMAT_MOD_YTR),
105 
106 	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
107 				AFBC_FORMAT_MOD_CBR),
108 
109 	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
110 				AFBC_FORMAT_MOD_YTR |
111 				AFBC_FORMAT_MOD_SPARSE),
112 
113 	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
114 				AFBC_FORMAT_MOD_CBR |
115 				AFBC_FORMAT_MOD_SPARSE),
116 
117 	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
118 				AFBC_FORMAT_MOD_YTR |
119 				AFBC_FORMAT_MOD_CBR),
120 
121 	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
122 				AFBC_FORMAT_MOD_YTR |
123 				AFBC_FORMAT_MOD_CBR |
124 				AFBC_FORMAT_MOD_SPARSE),
125 
126 	/* SPLIT mandates SPARSE, RGB modes mandates YTR */
127 	DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
128 				AFBC_FORMAT_MOD_YTR |
129 				AFBC_FORMAT_MOD_SPARSE |
130 				AFBC_FORMAT_MOD_SPLIT),
131 	DRM_FORMAT_MOD_INVALID,
132 };
133 
134 static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
135 	{
136 		.id = 0,
137 		.feature = VOP2_VP_FEATURE_OUTPUT_10BIT,
138 		.gamma_lut_len = 1024,
139 		.cubic_lut_len = 9 * 9 * 9,
140 		.max_output = { 4096, 2304 },
141 		.pre_scan_max_dly = { 69, 53, 53, 42 },
142 		.offset = 0xc00,
143 	}, {
144 		.id = 1,
145 		.gamma_lut_len = 1024,
146 		.max_output = { 2048, 1536 },
147 		.pre_scan_max_dly = { 40, 40, 40, 40 },
148 		.offset = 0xd00,
149 	}, {
150 		.id = 2,
151 		.gamma_lut_len = 1024,
152 		.max_output = { 1920, 1080 },
153 		.pre_scan_max_dly = { 40, 40, 40, 40 },
154 		.offset = 0xe00,
155 	},
156 };
157 
158 /*
159  * rk3568 vop with 2 cluster, 2 esmart win, 2 smart win.
160  * Every cluster can work as 4K win or split into two win.
161  * All win in cluster support AFBCD.
162  *
163  * Every esmart win and smart win support 4 Multi-region.
164  *
165  * Scale filter mode:
166  *
167  * * Cluster:  bicubic for horizontal scale up, others use bilinear
168  * * ESmart:
169  *    * nearest-neighbor/bilinear/bicubic for scale up
170  *    * nearest-neighbor/bilinear/average for scale down
171  *
172  *
173  * @TODO describe the wind like cpu-map dt nodes;
174  */
175 static const struct vop2_win_data rk3568_vop_win_data[] = {
176 	{
177 		.name = "Smart0-win0",
178 		.phys_id = ROCKCHIP_VOP2_SMART0,
179 		.base = 0x1c00,
180 		.formats = formats_smart,
181 		.nformats = ARRAY_SIZE(formats_smart),
182 		.format_modifiers = format_modifiers,
183 		.layer_sel_id = 3,
184 		.supported_rotations = DRM_MODE_REFLECT_Y,
185 		.type = DRM_PLANE_TYPE_PRIMARY,
186 		.max_upscale_factor = 8,
187 		.max_downscale_factor = 8,
188 		.dly = { 20, 47, 41 },
189 	}, {
190 		.name = "Smart1-win0",
191 		.phys_id = ROCKCHIP_VOP2_SMART1,
192 		.formats = formats_smart,
193 		.nformats = ARRAY_SIZE(formats_smart),
194 		.format_modifiers = format_modifiers,
195 		.base = 0x1e00,
196 		.layer_sel_id = 7,
197 		.supported_rotations = DRM_MODE_REFLECT_Y,
198 		.type = DRM_PLANE_TYPE_PRIMARY,
199 		.max_upscale_factor = 8,
200 		.max_downscale_factor = 8,
201 		.dly = { 20, 47, 41 },
202 	}, {
203 		.name = "Esmart1-win0",
204 		.phys_id = ROCKCHIP_VOP2_ESMART1,
205 		.formats = formats_rk356x_esmart,
206 		.nformats = ARRAY_SIZE(formats_rk356x_esmart),
207 		.format_modifiers = format_modifiers,
208 		.base = 0x1a00,
209 		.layer_sel_id = 6,
210 		.supported_rotations = DRM_MODE_REFLECT_Y,
211 		.type = DRM_PLANE_TYPE_PRIMARY,
212 		.max_upscale_factor = 8,
213 		.max_downscale_factor = 8,
214 		.dly = { 20, 47, 41 },
215 	}, {
216 		.name = "Esmart0-win0",
217 		.phys_id = ROCKCHIP_VOP2_ESMART0,
218 		.formats = formats_rk356x_esmart,
219 		.nformats = ARRAY_SIZE(formats_rk356x_esmart),
220 		.format_modifiers = format_modifiers,
221 		.base = 0x1800,
222 		.layer_sel_id = 2,
223 		.supported_rotations = DRM_MODE_REFLECT_Y,
224 		.type = DRM_PLANE_TYPE_PRIMARY,
225 		.max_upscale_factor = 8,
226 		.max_downscale_factor = 8,
227 		.dly = { 20, 47, 41 },
228 	}, {
229 		.name = "Cluster0-win0",
230 		.phys_id = ROCKCHIP_VOP2_CLUSTER0,
231 		.base = 0x1000,
232 		.formats = formats_cluster,
233 		.nformats = ARRAY_SIZE(formats_cluster),
234 		.format_modifiers = format_modifiers_afbc,
235 		.layer_sel_id = 0,
236 		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
237 					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
238 		.max_upscale_factor = 4,
239 		.max_downscale_factor = 4,
240 		.dly = { 0, 27, 21 },
241 		.type = DRM_PLANE_TYPE_OVERLAY,
242 		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
243 	}, {
244 		.name = "Cluster1-win0",
245 		.phys_id = ROCKCHIP_VOP2_CLUSTER1,
246 		.base = 0x1200,
247 		.formats = formats_cluster,
248 		.nformats = ARRAY_SIZE(formats_cluster),
249 		.format_modifiers = format_modifiers_afbc,
250 		.layer_sel_id = 1,
251 		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
252 					DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
253 		.type = DRM_PLANE_TYPE_OVERLAY,
254 		.max_upscale_factor = 4,
255 		.max_downscale_factor = 4,
256 		.dly = { 0, 27, 21 },
257 		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
258 	},
259 };
260 
261 static const struct vop2_video_port_data rk3588_vop_video_ports[] = {
262 	{
263 		.id = 0,
264 		.feature = VOP2_VP_FEATURE_OUTPUT_10BIT,
265 		.gamma_lut_len = 1024,
266 		.cubic_lut_len = 9 * 9 * 9, /* 9x9x9 */
267 		.max_output = { 4096, 2304 },
268 		/* hdr2sdr sdr2hdr hdr2hdr sdr2sdr */
269 		.pre_scan_max_dly = { 76, 65, 65, 54 },
270 		.offset = 0xc00,
271 	}, {
272 		.id = 1,
273 		.feature = VOP2_VP_FEATURE_OUTPUT_10BIT,
274 		.gamma_lut_len = 1024,
275 		.cubic_lut_len = 729, /* 9x9x9 */
276 		.max_output = { 4096, 2304 },
277 		.pre_scan_max_dly = { 76, 65, 65, 54 },
278 		.offset = 0xd00,
279 	}, {
280 		.id = 2,
281 		.feature = VOP2_VP_FEATURE_OUTPUT_10BIT,
282 		.gamma_lut_len = 1024,
283 		.cubic_lut_len = 17 * 17 * 17, /* 17x17x17 */
284 		.max_output = { 4096, 2304 },
285 		.pre_scan_max_dly = { 52, 52, 52, 52 },
286 		.offset = 0xe00,
287 	}, {
288 		.id = 3,
289 		.gamma_lut_len = 1024,
290 		.max_output = { 2048, 1536 },
291 		.pre_scan_max_dly = { 52, 52, 52, 52 },
292 		.offset = 0xf00,
293 	},
294 };
295 
296 /*
297  * rk3588 vop with 4 cluster, 4 esmart win.
298  * Every cluster can work as 4K win or split into two win.
299  * All win in cluster support AFBCD.
300  *
301  * Every esmart win and smart win support 4 Multi-region.
302  *
303  * Scale filter mode:
304  *
305  * * Cluster:  bicubic for horizontal scale up, others use bilinear
306  * * ESmart:
307  *    * nearest-neighbor/bilinear/bicubic for scale up
308  *    * nearest-neighbor/bilinear/average for scale down
309  *
310  * AXI Read ID assignment:
311  * Two AXI bus:
312  * AXI0 is a read/write bus with a higher performance.
313  * AXI1 is a read only bus.
314  *
315  * Every window on a AXI bus must assigned two unique
316  * read id(yrgb_id/uv_id, valid id are 0x1~0xe).
317  *
318  * AXI0:
319  * Cluster0/1, Esmart0/1, WriteBack
320  *
321  * AXI 1:
322  * Cluster2/3, Esmart2/3
323  *
324  */
325 static const struct vop2_win_data rk3588_vop_win_data[] = {
326 	{
327 		.name = "Cluster0-win0",
328 		.phys_id = ROCKCHIP_VOP2_CLUSTER0,
329 		.base = 0x1000,
330 		.formats = formats_cluster,
331 		.nformats = ARRAY_SIZE(formats_cluster),
332 		.format_modifiers = format_modifiers_afbc,
333 		.layer_sel_id = 0,
334 		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
335 				       DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
336 		.max_upscale_factor = 4,
337 		.max_downscale_factor = 4,
338 		.dly = { 4, 26, 29 },
339 		.type = DRM_PLANE_TYPE_PRIMARY,
340 		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
341 	}, {
342 		.name = "Cluster1-win0",
343 		.phys_id = ROCKCHIP_VOP2_CLUSTER1,
344 		.base = 0x1200,
345 		.formats = formats_cluster,
346 		.nformats = ARRAY_SIZE(formats_cluster),
347 		.format_modifiers = format_modifiers_afbc,
348 		.layer_sel_id = 1,
349 		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
350 				       DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
351 		.type = DRM_PLANE_TYPE_PRIMARY,
352 		.max_upscale_factor = 4,
353 		.max_downscale_factor = 4,
354 		.dly = { 4, 26, 29 },
355 		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
356 	}, {
357 		.name = "Cluster2-win0",
358 		.phys_id = ROCKCHIP_VOP2_CLUSTER2,
359 		.base = 0x1400,
360 		.formats = formats_cluster,
361 		.nformats = ARRAY_SIZE(formats_cluster),
362 		.format_modifiers = format_modifiers_afbc,
363 		.layer_sel_id = 4,
364 		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
365 				       DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
366 		.type = DRM_PLANE_TYPE_PRIMARY,
367 		.max_upscale_factor = 4,
368 		.max_downscale_factor = 4,
369 		.dly = { 4, 26, 29 },
370 		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
371 	}, {
372 		.name = "Cluster3-win0",
373 		.phys_id = ROCKCHIP_VOP2_CLUSTER3,
374 		.base = 0x1600,
375 		.formats = formats_cluster,
376 		.nformats = ARRAY_SIZE(formats_cluster),
377 		.format_modifiers = format_modifiers_afbc,
378 		.layer_sel_id = 5,
379 		.supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
380 				       DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
381 		.type = DRM_PLANE_TYPE_PRIMARY,
382 		.max_upscale_factor = 4,
383 		.max_downscale_factor = 4,
384 		.dly = { 4, 26, 29 },
385 		.feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
386 	}, {
387 		.name = "Esmart0-win0",
388 		.phys_id = ROCKCHIP_VOP2_ESMART0,
389 		.formats = formats_esmart,
390 		.nformats = ARRAY_SIZE(formats_esmart),
391 		.format_modifiers = format_modifiers,
392 		.base = 0x1800,
393 		.layer_sel_id = 2,
394 		.supported_rotations = DRM_MODE_REFLECT_Y,
395 		.type = DRM_PLANE_TYPE_OVERLAY,
396 		.max_upscale_factor = 8,
397 		.max_downscale_factor = 8,
398 		.dly = { 23, 45, 48 },
399 	}, {
400 		.name = "Esmart1-win0",
401 		.phys_id = ROCKCHIP_VOP2_ESMART1,
402 		.formats = formats_esmart,
403 		.nformats = ARRAY_SIZE(formats_esmart),
404 		.format_modifiers = format_modifiers,
405 		.base = 0x1a00,
406 		.layer_sel_id = 3,
407 		.supported_rotations = DRM_MODE_REFLECT_Y,
408 		.type = DRM_PLANE_TYPE_OVERLAY,
409 		.max_upscale_factor = 8,
410 		.max_downscale_factor = 8,
411 		.dly = { 23, 45, 48 },
412 	}, {
413 		.name = "Esmart2-win0",
414 		.phys_id = ROCKCHIP_VOP2_ESMART2,
415 		.base = 0x1c00,
416 		.formats = formats_esmart,
417 		.nformats = ARRAY_SIZE(formats_esmart),
418 		.format_modifiers = format_modifiers,
419 		.layer_sel_id = 6,
420 		.supported_rotations = DRM_MODE_REFLECT_Y,
421 		.type = DRM_PLANE_TYPE_OVERLAY,
422 		.max_upscale_factor = 8,
423 		.max_downscale_factor = 8,
424 		.dly = { 23, 45, 48 },
425 	}, {
426 		.name = "Esmart3-win0",
427 		.phys_id = ROCKCHIP_VOP2_ESMART3,
428 		.formats = formats_esmart,
429 		.nformats = ARRAY_SIZE(formats_esmart),
430 		.format_modifiers = format_modifiers,
431 		.base = 0x1e00,
432 		.layer_sel_id = 7,
433 		.supported_rotations = DRM_MODE_REFLECT_Y,
434 		.type = DRM_PLANE_TYPE_OVERLAY,
435 		.max_upscale_factor = 8,
436 		.max_downscale_factor = 8,
437 		.dly = { 23, 45, 48 },
438 	},
439 };
440 
441 static const struct vop2_data rk3566_vop = {
442 	.feature = VOP2_FEATURE_HAS_SYS_GRF,
443 	.nr_vps = 3,
444 	.max_input = { 4096, 2304 },
445 	.max_output = { 4096, 2304 },
446 	.vp = rk3568_vop_video_ports,
447 	.win = rk3568_vop_win_data,
448 	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
449 	.soc_id = 3566,
450 };
451 
452 static const struct vop2_data rk3568_vop = {
453 	.feature = VOP2_FEATURE_HAS_SYS_GRF,
454 	.nr_vps = 3,
455 	.max_input = { 4096, 2304 },
456 	.max_output = { 4096, 2304 },
457 	.vp = rk3568_vop_video_ports,
458 	.win = rk3568_vop_win_data,
459 	.win_size = ARRAY_SIZE(rk3568_vop_win_data),
460 	.soc_id = 3568,
461 };
462 
463 static const struct vop2_data rk3588_vop = {
464 	.feature = VOP2_FEATURE_HAS_SYS_GRF | VOP2_FEATURE_HAS_VO1_GRF |
465 		   VOP2_FEATURE_HAS_VOP_GRF | VOP2_FEATURE_HAS_SYS_PMU,
466 	.nr_vps = 4,
467 	.max_input = { 4096, 4320 },
468 	.max_output = { 4096, 4320 },
469 	.vp = rk3588_vop_video_ports,
470 	.win = rk3588_vop_win_data,
471 	.win_size = ARRAY_SIZE(rk3588_vop_win_data),
472 	.soc_id = 3588,
473 };
474 
475 static const struct of_device_id vop2_dt_match[] = {
476 	{
477 		.compatible = "rockchip,rk3566-vop",
478 		.data = &rk3566_vop,
479 	}, {
480 		.compatible = "rockchip,rk3568-vop",
481 		.data = &rk3568_vop,
482 	}, {
483 		.compatible = "rockchip,rk3588-vop",
484 		.data = &rk3588_vop
485 	}, {
486 	},
487 };
488 MODULE_DEVICE_TABLE(of, vop2_dt_match);
489 
vop2_probe(struct platform_device * pdev)490 static int vop2_probe(struct platform_device *pdev)
491 {
492 	struct device *dev = &pdev->dev;
493 
494 	return component_add(dev, &vop2_component_ops);
495 }
496 
vop2_remove(struct platform_device * pdev)497 static void vop2_remove(struct platform_device *pdev)
498 {
499 	component_del(&pdev->dev, &vop2_component_ops);
500 }
501 
502 struct platform_driver vop2_platform_driver = {
503 	.probe = vop2_probe,
504 	.remove = vop2_remove,
505 	.driver = {
506 		.name = "rockchip-vop2",
507 		.of_match_table = vop2_dt_match,
508 	},
509 };
510