Loading...
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
18static 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
35static 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
59static 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
81static 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
92static const uint64_t format_modifiers[] = {
93 DRM_FORMAT_MOD_LINEAR,
94 DRM_FORMAT_MOD_INVALID,
95};
96
97static 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
134static 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 */
175static 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
261static 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_r_id/uv_r_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 */
325static 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 .axi_bus_id = 0,
337 .axi_yrgb_r_id = 2,
338 .axi_uv_r_id = 3,
339 .max_upscale_factor = 4,
340 .max_downscale_factor = 4,
341 .dly = { 4, 26, 29 },
342 .type = DRM_PLANE_TYPE_PRIMARY,
343 .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
344 }, {
345 .name = "Cluster1-win0",
346 .phys_id = ROCKCHIP_VOP2_CLUSTER1,
347 .base = 0x1200,
348 .formats = formats_cluster,
349 .nformats = ARRAY_SIZE(formats_cluster),
350 .format_modifiers = format_modifiers_afbc,
351 .layer_sel_id = 1,
352 .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
353 DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
354 .type = DRM_PLANE_TYPE_PRIMARY,
355 .axi_bus_id = 0,
356 .axi_yrgb_r_id = 6,
357 .axi_uv_r_id = 7,
358 .max_upscale_factor = 4,
359 .max_downscale_factor = 4,
360 .dly = { 4, 26, 29 },
361 .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
362 }, {
363 .name = "Cluster2-win0",
364 .phys_id = ROCKCHIP_VOP2_CLUSTER2,
365 .base = 0x1400,
366 .formats = formats_cluster,
367 .nformats = ARRAY_SIZE(formats_cluster),
368 .format_modifiers = format_modifiers_afbc,
369 .layer_sel_id = 4,
370 .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
371 DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
372 .type = DRM_PLANE_TYPE_PRIMARY,
373 .axi_bus_id = 1,
374 .axi_yrgb_r_id = 2,
375 .axi_uv_r_id = 3,
376 .max_upscale_factor = 4,
377 .max_downscale_factor = 4,
378 .dly = { 4, 26, 29 },
379 .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
380 }, {
381 .name = "Cluster3-win0",
382 .phys_id = ROCKCHIP_VOP2_CLUSTER3,
383 .base = 0x1600,
384 .formats = formats_cluster,
385 .nformats = ARRAY_SIZE(formats_cluster),
386 .format_modifiers = format_modifiers_afbc,
387 .layer_sel_id = 5,
388 .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
389 DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
390 .type = DRM_PLANE_TYPE_PRIMARY,
391 .axi_bus_id = 1,
392 .axi_yrgb_r_id = 6,
393 .axi_uv_r_id = 7,
394 .max_upscale_factor = 4,
395 .max_downscale_factor = 4,
396 .dly = { 4, 26, 29 },
397 .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
398 }, {
399 .name = "Esmart0-win0",
400 .phys_id = ROCKCHIP_VOP2_ESMART0,
401 .formats = formats_esmart,
402 .nformats = ARRAY_SIZE(formats_esmart),
403 .format_modifiers = format_modifiers,
404 .base = 0x1800,
405 .layer_sel_id = 2,
406 .supported_rotations = DRM_MODE_REFLECT_Y,
407 .type = DRM_PLANE_TYPE_OVERLAY,
408 .axi_bus_id = 0,
409 .axi_yrgb_r_id = 0x0a,
410 .axi_uv_r_id = 0x0b,
411 .max_upscale_factor = 8,
412 .max_downscale_factor = 8,
413 .dly = { 23, 45, 48 },
414 }, {
415 .name = "Esmart1-win0",
416 .phys_id = ROCKCHIP_VOP2_ESMART1,
417 .formats = formats_esmart,
418 .nformats = ARRAY_SIZE(formats_esmart),
419 .format_modifiers = format_modifiers,
420 .base = 0x1a00,
421 .layer_sel_id = 3,
422 .supported_rotations = DRM_MODE_REFLECT_Y,
423 .type = DRM_PLANE_TYPE_OVERLAY,
424 .axi_bus_id = 0,
425 .axi_yrgb_r_id = 0x0c,
426 .axi_uv_r_id = 0x01,
427 .max_upscale_factor = 8,
428 .max_downscale_factor = 8,
429 .dly = { 23, 45, 48 },
430 }, {
431 .name = "Esmart2-win0",
432 .phys_id = ROCKCHIP_VOP2_ESMART2,
433 .base = 0x1c00,
434 .formats = formats_esmart,
435 .nformats = ARRAY_SIZE(formats_esmart),
436 .format_modifiers = format_modifiers,
437 .layer_sel_id = 6,
438 .supported_rotations = DRM_MODE_REFLECT_Y,
439 .type = DRM_PLANE_TYPE_OVERLAY,
440 .axi_bus_id = 1,
441 .axi_yrgb_r_id = 0x0a,
442 .axi_uv_r_id = 0x0b,
443 .max_upscale_factor = 8,
444 .max_downscale_factor = 8,
445 .dly = { 23, 45, 48 },
446 }, {
447 .name = "Esmart3-win0",
448 .phys_id = ROCKCHIP_VOP2_ESMART3,
449 .formats = formats_esmart,
450 .nformats = ARRAY_SIZE(formats_esmart),
451 .format_modifiers = format_modifiers,
452 .base = 0x1e00,
453 .layer_sel_id = 7,
454 .supported_rotations = DRM_MODE_REFLECT_Y,
455 .type = DRM_PLANE_TYPE_OVERLAY,
456 .axi_bus_id = 1,
457 .axi_yrgb_r_id = 0x0c,
458 .axi_uv_r_id = 0x0d,
459 .max_upscale_factor = 8,
460 .max_downscale_factor = 8,
461 .dly = { 23, 45, 48 },
462 },
463};
464
465static const struct vop2_data rk3566_vop = {
466 .feature = VOP2_FEATURE_HAS_SYS_GRF,
467 .nr_vps = 3,
468 .max_input = { 4096, 2304 },
469 .max_output = { 4096, 2304 },
470 .vp = rk3568_vop_video_ports,
471 .win = rk3568_vop_win_data,
472 .win_size = ARRAY_SIZE(rk3568_vop_win_data),
473 .soc_id = 3566,
474};
475
476static const struct vop2_data rk3568_vop = {
477 .feature = VOP2_FEATURE_HAS_SYS_GRF,
478 .nr_vps = 3,
479 .max_input = { 4096, 2304 },
480 .max_output = { 4096, 2304 },
481 .vp = rk3568_vop_video_ports,
482 .win = rk3568_vop_win_data,
483 .win_size = ARRAY_SIZE(rk3568_vop_win_data),
484 .soc_id = 3568,
485};
486
487static const struct vop2_data rk3588_vop = {
488 .feature = VOP2_FEATURE_HAS_SYS_GRF | VOP2_FEATURE_HAS_VO1_GRF |
489 VOP2_FEATURE_HAS_VOP_GRF | VOP2_FEATURE_HAS_SYS_PMU,
490 .nr_vps = 4,
491 .max_input = { 4096, 4320 },
492 .max_output = { 4096, 4320 },
493 .vp = rk3588_vop_video_ports,
494 .win = rk3588_vop_win_data,
495 .win_size = ARRAY_SIZE(rk3588_vop_win_data),
496 .soc_id = 3588,
497};
498
499static const struct of_device_id vop2_dt_match[] = {
500 {
501 .compatible = "rockchip,rk3566-vop",
502 .data = &rk3566_vop,
503 }, {
504 .compatible = "rockchip,rk3568-vop",
505 .data = &rk3568_vop,
506 }, {
507 .compatible = "rockchip,rk3588-vop",
508 .data = &rk3588_vop
509 }, {
510 },
511};
512MODULE_DEVICE_TABLE(of, vop2_dt_match);
513
514static int vop2_probe(struct platform_device *pdev)
515{
516 struct device *dev = &pdev->dev;
517
518 return component_add(dev, &vop2_component_ops);
519}
520
521static void vop2_remove(struct platform_device *pdev)
522{
523 component_del(&pdev->dev, &vop2_component_ops);
524}
525
526struct platform_driver vop2_platform_driver = {
527 .probe = vop2_probe,
528 .remove = vop2_remove,
529 .driver = {
530 .name = "rockchip-vop2",
531 .of_match_table = vop2_dt_match,
532 },
533};
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
18static const uint32_t formats_win_full_10bit[] = {
19 DRM_FORMAT_XRGB8888,
20 DRM_FORMAT_ARGB8888,
21 DRM_FORMAT_XBGR8888,
22 DRM_FORMAT_ABGR8888,
23 DRM_FORMAT_RGB888,
24 DRM_FORMAT_BGR888,
25 DRM_FORMAT_RGB565,
26 DRM_FORMAT_BGR565,
27 DRM_FORMAT_NV12,
28 DRM_FORMAT_NV16,
29 DRM_FORMAT_NV24,
30};
31
32static const uint32_t formats_win_full_10bit_yuyv[] = {
33 DRM_FORMAT_XRGB8888,
34 DRM_FORMAT_ARGB8888,
35 DRM_FORMAT_XBGR8888,
36 DRM_FORMAT_ABGR8888,
37 DRM_FORMAT_RGB888,
38 DRM_FORMAT_BGR888,
39 DRM_FORMAT_RGB565,
40 DRM_FORMAT_BGR565,
41 DRM_FORMAT_NV12,
42 DRM_FORMAT_NV16,
43 DRM_FORMAT_NV24,
44 DRM_FORMAT_YVYU,
45 DRM_FORMAT_VYUY,
46};
47
48static const uint32_t formats_win_lite[] = {
49 DRM_FORMAT_XRGB8888,
50 DRM_FORMAT_ARGB8888,
51 DRM_FORMAT_XBGR8888,
52 DRM_FORMAT_ABGR8888,
53 DRM_FORMAT_RGB888,
54 DRM_FORMAT_BGR888,
55 DRM_FORMAT_RGB565,
56 DRM_FORMAT_BGR565,
57};
58
59static const uint64_t format_modifiers[] = {
60 DRM_FORMAT_MOD_LINEAR,
61 DRM_FORMAT_MOD_INVALID,
62};
63
64static const uint64_t format_modifiers_afbc[] = {
65 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16),
66
67 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
68 AFBC_FORMAT_MOD_SPARSE),
69
70 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
71 AFBC_FORMAT_MOD_YTR),
72
73 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
74 AFBC_FORMAT_MOD_CBR),
75
76 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
77 AFBC_FORMAT_MOD_YTR |
78 AFBC_FORMAT_MOD_SPARSE),
79
80 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
81 AFBC_FORMAT_MOD_CBR |
82 AFBC_FORMAT_MOD_SPARSE),
83
84 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
85 AFBC_FORMAT_MOD_YTR |
86 AFBC_FORMAT_MOD_CBR),
87
88 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
89 AFBC_FORMAT_MOD_YTR |
90 AFBC_FORMAT_MOD_CBR |
91 AFBC_FORMAT_MOD_SPARSE),
92
93 /* SPLIT mandates SPARSE, RGB modes mandates YTR */
94 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16 |
95 AFBC_FORMAT_MOD_YTR |
96 AFBC_FORMAT_MOD_SPARSE |
97 AFBC_FORMAT_MOD_SPLIT),
98 DRM_FORMAT_MOD_INVALID,
99};
100
101static const struct vop2_video_port_data rk3568_vop_video_ports[] = {
102 {
103 .id = 0,
104 .feature = VOP_FEATURE_OUTPUT_10BIT,
105 .gamma_lut_len = 1024,
106 .cubic_lut_len = 9 * 9 * 9,
107 .max_output = { 4096, 2304 },
108 .pre_scan_max_dly = { 69, 53, 53, 42 },
109 .offset = 0xc00,
110 }, {
111 .id = 1,
112 .gamma_lut_len = 1024,
113 .max_output = { 2048, 1536 },
114 .pre_scan_max_dly = { 40, 40, 40, 40 },
115 .offset = 0xd00,
116 }, {
117 .id = 2,
118 .gamma_lut_len = 1024,
119 .max_output = { 1920, 1080 },
120 .pre_scan_max_dly = { 40, 40, 40, 40 },
121 .offset = 0xe00,
122 },
123};
124
125/*
126 * rk3568 vop with 2 cluster, 2 esmart win, 2 smart win.
127 * Every cluster can work as 4K win or split into two win.
128 * All win in cluster support AFBCD.
129 *
130 * Every esmart win and smart win support 4 Multi-region.
131 *
132 * Scale filter mode:
133 *
134 * * Cluster: bicubic for horizontal scale up, others use bilinear
135 * * ESmart:
136 * * nearest-neighbor/bilinear/bicubic for scale up
137 * * nearest-neighbor/bilinear/average for scale down
138 *
139 *
140 * @TODO describe the wind like cpu-map dt nodes;
141 */
142static const struct vop2_win_data rk3568_vop_win_data[] = {
143 {
144 .name = "Smart0-win0",
145 .phys_id = ROCKCHIP_VOP2_SMART0,
146 .base = 0x1c00,
147 .formats = formats_win_lite,
148 .nformats = ARRAY_SIZE(formats_win_lite),
149 .format_modifiers = format_modifiers,
150 .layer_sel_id = 3,
151 .supported_rotations = DRM_MODE_REFLECT_Y,
152 .type = DRM_PLANE_TYPE_PRIMARY,
153 .max_upscale_factor = 8,
154 .max_downscale_factor = 8,
155 .dly = { 20, 47, 41 },
156 }, {
157 .name = "Smart1-win0",
158 .phys_id = ROCKCHIP_VOP2_SMART1,
159 .formats = formats_win_lite,
160 .nformats = ARRAY_SIZE(formats_win_lite),
161 .format_modifiers = format_modifiers,
162 .base = 0x1e00,
163 .layer_sel_id = 7,
164 .supported_rotations = DRM_MODE_REFLECT_Y,
165 .type = DRM_PLANE_TYPE_PRIMARY,
166 .max_upscale_factor = 8,
167 .max_downscale_factor = 8,
168 .dly = { 20, 47, 41 },
169 }, {
170 .name = "Esmart1-win0",
171 .phys_id = ROCKCHIP_VOP2_ESMART1,
172 .formats = formats_win_full_10bit_yuyv,
173 .nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
174 .format_modifiers = format_modifiers,
175 .base = 0x1a00,
176 .layer_sel_id = 6,
177 .supported_rotations = DRM_MODE_REFLECT_Y,
178 .type = DRM_PLANE_TYPE_PRIMARY,
179 .max_upscale_factor = 8,
180 .max_downscale_factor = 8,
181 .dly = { 20, 47, 41 },
182 }, {
183 .name = "Esmart0-win0",
184 .phys_id = ROCKCHIP_VOP2_ESMART0,
185 .formats = formats_win_full_10bit_yuyv,
186 .nformats = ARRAY_SIZE(formats_win_full_10bit_yuyv),
187 .format_modifiers = format_modifiers,
188 .base = 0x1800,
189 .layer_sel_id = 2,
190 .supported_rotations = DRM_MODE_REFLECT_Y,
191 .type = DRM_PLANE_TYPE_PRIMARY,
192 .max_upscale_factor = 8,
193 .max_downscale_factor = 8,
194 .dly = { 20, 47, 41 },
195 }, {
196 .name = "Cluster0-win0",
197 .phys_id = ROCKCHIP_VOP2_CLUSTER0,
198 .base = 0x1000,
199 .formats = formats_win_full_10bit,
200 .nformats = ARRAY_SIZE(formats_win_full_10bit),
201 .format_modifiers = format_modifiers_afbc,
202 .layer_sel_id = 0,
203 .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
204 DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
205 .max_upscale_factor = 4,
206 .max_downscale_factor = 4,
207 .dly = { 0, 27, 21 },
208 .type = DRM_PLANE_TYPE_OVERLAY,
209 .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
210 }, {
211 .name = "Cluster1-win0",
212 .phys_id = ROCKCHIP_VOP2_CLUSTER1,
213 .base = 0x1200,
214 .formats = formats_win_full_10bit,
215 .nformats = ARRAY_SIZE(formats_win_full_10bit),
216 .format_modifiers = format_modifiers_afbc,
217 .layer_sel_id = 1,
218 .supported_rotations = DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270 |
219 DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y,
220 .type = DRM_PLANE_TYPE_OVERLAY,
221 .max_upscale_factor = 4,
222 .max_downscale_factor = 4,
223 .dly = { 0, 27, 21 },
224 .feature = WIN_FEATURE_AFBDC | WIN_FEATURE_CLUSTER,
225 },
226};
227
228static const struct vop2_data rk3566_vop = {
229 .nr_vps = 3,
230 .max_input = { 4096, 2304 },
231 .max_output = { 4096, 2304 },
232 .vp = rk3568_vop_video_ports,
233 .win = rk3568_vop_win_data,
234 .win_size = ARRAY_SIZE(rk3568_vop_win_data),
235 .soc_id = 3566,
236};
237
238static const struct vop2_data rk3568_vop = {
239 .nr_vps = 3,
240 .max_input = { 4096, 2304 },
241 .max_output = { 4096, 2304 },
242 .vp = rk3568_vop_video_ports,
243 .win = rk3568_vop_win_data,
244 .win_size = ARRAY_SIZE(rk3568_vop_win_data),
245 .soc_id = 3568,
246};
247
248static const struct of_device_id vop2_dt_match[] = {
249 {
250 .compatible = "rockchip,rk3566-vop",
251 .data = &rk3566_vop,
252 }, {
253 .compatible = "rockchip,rk3568-vop",
254 .data = &rk3568_vop,
255 }, {
256 },
257};
258MODULE_DEVICE_TABLE(of, vop2_dt_match);
259
260static int vop2_probe(struct platform_device *pdev)
261{
262 struct device *dev = &pdev->dev;
263
264 return component_add(dev, &vop2_component_ops);
265}
266
267static int vop2_remove(struct platform_device *pdev)
268{
269 component_del(&pdev->dev, &vop2_component_ops);
270
271 return 0;
272}
273
274struct platform_driver vop2_platform_driver = {
275 .probe = vop2_probe,
276 .remove = vop2_remove,
277 .driver = {
278 .name = "rockchip-vop2",
279 .of_match_table = of_match_ptr(vop2_dt_match),
280 },
281};