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 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 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