1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) Rockchip Electronics Co.Ltd
4 * Author: Andy Yan <andy.yan@rock-chips.com>
7 #include <linux/kernel.h>
8 #include <linux/component.h>
9 #include <linux/mod_devicetable.h>
10 #include <linux/platform_device.h>
12 #include <drm/drm_fourcc.h>
13 #include <drm/drm_plane.h>
14 #include <drm/drm_print.h>
16 #include "rockchip_drm_vop2.h"
18 static const uint32_t formats_cluster
[] = {
19 DRM_FORMAT_XRGB2101010
,
20 DRM_FORMAT_XBGR2101010
,
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 */
35 static const uint32_t formats_esmart
[] = {
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 */
59 static const uint32_t formats_rk356x_esmart
[] = {
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 */
81 static const uint32_t formats_smart
[] = {
92 static const uint64_t format_modifiers
[] = {
93 DRM_FORMAT_MOD_LINEAR
,
94 DRM_FORMAT_MOD_INVALID
,
97 static const uint64_t format_modifiers_afbc
[] = {
98 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
),
100 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
101 AFBC_FORMAT_MOD_SPARSE
),
103 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
104 AFBC_FORMAT_MOD_YTR
),
106 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
107 AFBC_FORMAT_MOD_CBR
),
109 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
110 AFBC_FORMAT_MOD_YTR
|
111 AFBC_FORMAT_MOD_SPARSE
),
113 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
114 AFBC_FORMAT_MOD_CBR
|
115 AFBC_FORMAT_MOD_SPARSE
),
117 DRM_FORMAT_MOD_ARM_AFBC(AFBC_FORMAT_MOD_BLOCK_SIZE_16x16
|
118 AFBC_FORMAT_MOD_YTR
|
119 AFBC_FORMAT_MOD_CBR
),
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
),
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
,
134 static const struct vop2_video_port_data rk3568_vop_video_ports
[] = {
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 },
145 .gamma_lut_len
= 1024,
146 .max_output
= { 2048, 1536 },
147 .pre_scan_max_dly
= { 40, 40, 40, 40 },
151 .gamma_lut_len
= 1024,
152 .max_output
= { 1920, 1080 },
153 .pre_scan_max_dly
= { 40, 40, 40, 40 },
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.
163 * Every esmart win and smart win support 4 Multi-region.
167 * * Cluster: bicubic for horizontal scale up, others use bilinear
169 * * nearest-neighbor/bilinear/bicubic for scale up
170 * * nearest-neighbor/bilinear/average for scale down
173 * @TODO describe the wind like cpu-map dt nodes;
175 static const struct vop2_win_data rk3568_vop_win_data
[] = {
177 .name
= "Smart0-win0",
178 .phys_id
= ROCKCHIP_VOP2_SMART0
,
180 .formats
= formats_smart
,
181 .nformats
= ARRAY_SIZE(formats_smart
),
182 .format_modifiers
= format_modifiers
,
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 },
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
,
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 },
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
,
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 },
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
,
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 },
229 .name
= "Cluster0-win0",
230 .phys_id
= ROCKCHIP_VOP2_CLUSTER0
,
232 .formats
= formats_cluster
,
233 .nformats
= ARRAY_SIZE(formats_cluster
),
234 .format_modifiers
= format_modifiers_afbc
,
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
,
244 .name
= "Cluster1-win0",
245 .phys_id
= ROCKCHIP_VOP2_CLUSTER1
,
247 .formats
= formats_cluster
,
248 .nformats
= ARRAY_SIZE(formats_cluster
),
249 .format_modifiers
= format_modifiers_afbc
,
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
,
261 static const struct vop2_video_port_data rk3588_vop_video_ports
[] = {
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 },
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 },
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 },
289 .gamma_lut_len
= 1024,
290 .max_output
= { 2048, 1536 },
291 .pre_scan_max_dly
= { 52, 52, 52, 52 },
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.
301 * Every esmart win and smart win support 4 Multi-region.
305 * * Cluster: bicubic for horizontal scale up, others use bilinear
307 * * nearest-neighbor/bilinear/bicubic for scale up
308 * * nearest-neighbor/bilinear/average for scale down
310 * AXI Read ID assignment:
312 * AXI0 is a read/write bus with a higher performance.
313 * AXI1 is a read only bus.
315 * Every window on a AXI bus must assigned two unique
316 * read id(yrgb_id/uv_id, valid id are 0x1~0xe).
319 * Cluster0/1, Esmart0/1, WriteBack
322 * Cluster2/3, Esmart2/3
325 static const struct vop2_win_data rk3588_vop_win_data
[] = {
327 .name
= "Cluster0-win0",
328 .phys_id
= ROCKCHIP_VOP2_CLUSTER0
,
330 .formats
= formats_cluster
,
331 .nformats
= ARRAY_SIZE(formats_cluster
),
332 .format_modifiers
= format_modifiers_afbc
,
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
,
342 .name
= "Cluster1-win0",
343 .phys_id
= ROCKCHIP_VOP2_CLUSTER1
,
345 .formats
= formats_cluster
,
346 .nformats
= ARRAY_SIZE(formats_cluster
),
347 .format_modifiers
= format_modifiers_afbc
,
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
,
357 .name
= "Cluster2-win0",
358 .phys_id
= ROCKCHIP_VOP2_CLUSTER2
,
360 .formats
= formats_cluster
,
361 .nformats
= ARRAY_SIZE(formats_cluster
),
362 .format_modifiers
= format_modifiers_afbc
,
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
,
372 .name
= "Cluster3-win0",
373 .phys_id
= ROCKCHIP_VOP2_CLUSTER3
,
375 .formats
= formats_cluster
,
376 .nformats
= ARRAY_SIZE(formats_cluster
),
377 .format_modifiers
= format_modifiers_afbc
,
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
,
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
,
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 },
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
,
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 },
413 .name
= "Esmart2-win0",
414 .phys_id
= ROCKCHIP_VOP2_ESMART2
,
416 .formats
= formats_esmart
,
417 .nformats
= ARRAY_SIZE(formats_esmart
),
418 .format_modifiers
= format_modifiers
,
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 },
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
,
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 },
441 static const struct vop2_data rk3566_vop
= {
442 .feature
= VOP2_FEATURE_HAS_SYS_GRF
,
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
),
452 static const struct vop2_data rk3568_vop
= {
453 .feature
= VOP2_FEATURE_HAS_SYS_GRF
,
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
),
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
,
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
),
475 static const struct of_device_id vop2_dt_match
[] = {
477 .compatible
= "rockchip,rk3566-vop",
480 .compatible
= "rockchip,rk3568-vop",
483 .compatible
= "rockchip,rk3588-vop",
488 MODULE_DEVICE_TABLE(of
, vop2_dt_match
);
490 static int vop2_probe(struct platform_device
*pdev
)
492 struct device
*dev
= &pdev
->dev
;
494 return component_add(dev
, &vop2_component_ops
);
497 static void vop2_remove(struct platform_device
*pdev
)
499 component_del(&pdev
->dev
, &vop2_component_ops
);
502 struct platform_driver vop2_platform_driver
= {
504 .remove
= vop2_remove
,
506 .name
= "rockchip-vop2",
507 .of_match_table
= vop2_dt_match
,