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