1 // SPDX-License-Identifier: (GPL-2.0+ OR MIT) 2 /* 3 * Copyright (c) 2020 Rockchip Electronics Co., Ltd. 4 * Author: Andy Yan <andy.yan@rock-chips.com> 5 */ 6 #include <linux/bitfield.h> 7 #include <linux/clk.h> 8 #include <linux/component.h> 9 #include <linux/delay.h> 10 #include <linux/iopoll.h> 11 #include <linux/kernel.h> 12 #include <linux/media-bus-format.h> 13 #include <linux/mfd/syscon.h> 14 #include <linux/module.h> 15 #include <linux/of.h> 16 #include <linux/of_graph.h> 17 #include <linux/platform_device.h> 18 #include <linux/pm_runtime.h> 19 #include <linux/regmap.h> 20 #include <linux/swab.h> 21 22 #include <drm/drm.h> 23 #include <drm/drm_atomic.h> 24 #include <drm/drm_atomic_uapi.h> 25 #include <drm/drm_blend.h> 26 #include <drm/drm_crtc.h> 27 #include <linux/debugfs.h> 28 #include <drm/drm_debugfs.h> 29 #include <drm/drm_flip_work.h> 30 #include <drm/drm_framebuffer.h> 31 #include <drm/drm_gem_framebuffer_helper.h> 32 #include <drm/drm_print.h> 33 #include <drm/drm_probe_helper.h> 34 #include <drm/drm_vblank.h> 35 36 #include <uapi/linux/videodev2.h> 37 38 #include "rockchip_drm_gem.h" 39 #include "rockchip_drm_vop2.h" 40 #include "rockchip_rgb.h" 41 42 /* 43 * VOP2 architecture 44 * 45 +----------+ +-------------+ +-----------+ 46 | Cluster | | Sel 1 from 6| | 1 from 3 | 47 | window0 | | Layer0 | | RGB | 48 +----------+ +-------------+ +---------------+ +-------------+ +-----------+ 49 +----------+ +-------------+ |N from 6 layers| | | 50 | Cluster | | Sel 1 from 6| | Overlay0 +--->| Video Port0 | +-----------+ 51 | window1 | | Layer1 | | | | | | 1 from 3 | 52 +----------+ +-------------+ +---------------+ +-------------+ | LVDS | 53 +----------+ +-------------+ +-----------+ 54 | Esmart | | Sel 1 from 6| 55 | window0 | | Layer2 | +---------------+ +-------------+ +-----------+ 56 +----------+ +-------------+ |N from 6 Layers| | | +--> | 1 from 3 | 57 +----------+ +-------------+ --------> | Overlay1 +--->| Video Port1 | | MIPI | 58 | Esmart | | Sel 1 from 6| --------> | | | | +-----------+ 59 | Window1 | | Layer3 | +---------------+ +-------------+ 60 +----------+ +-------------+ +-----------+ 61 +----------+ +-------------+ | 1 from 3 | 62 | Smart | | Sel 1 from 6| +---------------+ +-------------+ | HDMI | 63 | Window0 | | Layer4 | |N from 6 Layers| | | +-----------+ 64 +----------+ +-------------+ | Overlay2 +--->| Video Port2 | 65 +----------+ +-------------+ | | | | +-----------+ 66 | Smart | | Sel 1 from 6| +---------------+ +-------------+ | 1 from 3 | 67 | Window1 | | Layer5 | | eDP | 68 +----------+ +-------------+ +-----------+ 69 * 70 */ 71 72 enum vop2_data_format { 73 VOP2_FMT_ARGB8888 = 0, 74 VOP2_FMT_RGB888, 75 VOP2_FMT_RGB565, 76 VOP2_FMT_XRGB101010, 77 VOP2_FMT_YUV420SP, 78 VOP2_FMT_YUV422SP, 79 VOP2_FMT_YUV444SP, 80 VOP2_FMT_YUYV422 = 8, 81 VOP2_FMT_YUYV420, 82 VOP2_FMT_VYUY422, 83 VOP2_FMT_VYUY420, 84 VOP2_FMT_YUV420SP_TILE_8x4 = 0x10, 85 VOP2_FMT_YUV420SP_TILE_16x2, 86 VOP2_FMT_YUV422SP_TILE_8x4, 87 VOP2_FMT_YUV422SP_TILE_16x2, 88 VOP2_FMT_YUV420SP_10, 89 VOP2_FMT_YUV422SP_10, 90 VOP2_FMT_YUV444SP_10, 91 }; 92 93 enum vop2_afbc_format { 94 VOP2_AFBC_FMT_RGB565, 95 VOP2_AFBC_FMT_ARGB2101010 = 2, 96 VOP2_AFBC_FMT_YUV420_10BIT, 97 VOP2_AFBC_FMT_RGB888, 98 VOP2_AFBC_FMT_ARGB8888, 99 VOP2_AFBC_FMT_YUV420 = 9, 100 VOP2_AFBC_FMT_YUV422 = 0xb, 101 VOP2_AFBC_FMT_YUV422_10BIT = 0xe, 102 VOP2_AFBC_FMT_INVALID = -1, 103 }; 104 105 #define VOP2_MAX_DCLK_RATE 600000000UL 106 107 /* 108 * bus-format types. 109 */ 110 struct drm_bus_format_enum_list { 111 int type; 112 const char *name; 113 }; 114 115 static const struct drm_bus_format_enum_list drm_bus_format_enum_list[] = { 116 { DRM_MODE_CONNECTOR_Unknown, "Unknown" }, 117 { MEDIA_BUS_FMT_RGB565_1X16, "RGB565_1X16" }, 118 { MEDIA_BUS_FMT_RGB666_1X18, "RGB666_1X18" }, 119 { MEDIA_BUS_FMT_RGB666_1X24_CPADHI, "RGB666_1X24_CPADHI" }, 120 { MEDIA_BUS_FMT_RGB666_1X7X3_SPWG, "RGB666_1X7X3_SPWG" }, 121 { MEDIA_BUS_FMT_YUV8_1X24, "YUV8_1X24" }, 122 { MEDIA_BUS_FMT_UYYVYY8_0_5X24, "UYYVYY8_0_5X24" }, 123 { MEDIA_BUS_FMT_YUV10_1X30, "YUV10_1X30" }, 124 { MEDIA_BUS_FMT_UYYVYY10_0_5X30, "UYYVYY10_0_5X30" }, 125 { MEDIA_BUS_FMT_RGB888_3X8, "RGB888_3X8" }, 126 { MEDIA_BUS_FMT_RGB888_1X24, "RGB888_1X24" }, 127 { MEDIA_BUS_FMT_RGB888_1X7X4_SPWG, "RGB888_1X7X4_SPWG" }, 128 { MEDIA_BUS_FMT_RGB888_1X7X4_JEIDA, "RGB888_1X7X4_JEIDA" }, 129 { MEDIA_BUS_FMT_UYVY8_2X8, "UYVY8_2X8" }, 130 { MEDIA_BUS_FMT_YUYV8_1X16, "YUYV8_1X16" }, 131 { MEDIA_BUS_FMT_UYVY8_1X16, "UYVY8_1X16" }, 132 { MEDIA_BUS_FMT_RGB101010_1X30, "RGB101010_1X30" }, 133 { MEDIA_BUS_FMT_YUYV10_1X20, "YUYV10_1X20" }, 134 }; 135 136 static DRM_ENUM_NAME_FN(drm_get_bus_format_name, drm_bus_format_enum_list) 137 138 static const struct regmap_config vop2_regmap_config; 139 140 static void vop2_lock(struct vop2 *vop2) 141 { 142 mutex_lock(&vop2->vop2_lock); 143 } 144 145 static void vop2_unlock(struct vop2 *vop2) 146 { 147 mutex_unlock(&vop2->vop2_lock); 148 } 149 150 static void vop2_win_disable(struct vop2_win *win) 151 { 152 vop2_win_write(win, VOP2_WIN_ENABLE, 0); 153 154 if (vop2_cluster_window(win)) 155 vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 0); 156 } 157 158 static u32 vop2_get_bpp(const struct drm_format_info *format) 159 { 160 switch (format->format) { 161 case DRM_FORMAT_YUV420_8BIT: 162 return 12; 163 case DRM_FORMAT_YUV420_10BIT: 164 return 15; 165 case DRM_FORMAT_VUY101010: 166 return 30; 167 default: 168 return drm_format_info_bpp(format, 0); 169 } 170 } 171 172 static enum vop2_data_format vop2_convert_format(u32 format) 173 { 174 switch (format) { 175 case DRM_FORMAT_XRGB2101010: 176 case DRM_FORMAT_ARGB2101010: 177 case DRM_FORMAT_XBGR2101010: 178 case DRM_FORMAT_ABGR2101010: 179 return VOP2_FMT_XRGB101010; 180 case DRM_FORMAT_XRGB8888: 181 case DRM_FORMAT_ARGB8888: 182 case DRM_FORMAT_XBGR8888: 183 case DRM_FORMAT_ABGR8888: 184 return VOP2_FMT_ARGB8888; 185 case DRM_FORMAT_RGB888: 186 case DRM_FORMAT_BGR888: 187 return VOP2_FMT_RGB888; 188 case DRM_FORMAT_RGB565: 189 case DRM_FORMAT_BGR565: 190 return VOP2_FMT_RGB565; 191 case DRM_FORMAT_NV12: 192 case DRM_FORMAT_NV21: 193 case DRM_FORMAT_YUV420_8BIT: 194 return VOP2_FMT_YUV420SP; 195 case DRM_FORMAT_NV15: 196 case DRM_FORMAT_YUV420_10BIT: 197 return VOP2_FMT_YUV420SP_10; 198 case DRM_FORMAT_NV16: 199 case DRM_FORMAT_NV61: 200 return VOP2_FMT_YUV422SP; 201 case DRM_FORMAT_NV20: 202 case DRM_FORMAT_Y210: 203 return VOP2_FMT_YUV422SP_10; 204 case DRM_FORMAT_NV24: 205 case DRM_FORMAT_NV42: 206 return VOP2_FMT_YUV444SP; 207 case DRM_FORMAT_NV30: 208 return VOP2_FMT_YUV444SP_10; 209 case DRM_FORMAT_YUYV: 210 case DRM_FORMAT_YVYU: 211 return VOP2_FMT_VYUY422; 212 case DRM_FORMAT_VYUY: 213 case DRM_FORMAT_UYVY: 214 return VOP2_FMT_YUYV422; 215 default: 216 DRM_ERROR("unsupported format[%08x]\n", format); 217 return -EINVAL; 218 } 219 } 220 221 static enum vop2_afbc_format vop2_convert_afbc_format(u32 format) 222 { 223 switch (format) { 224 case DRM_FORMAT_XRGB2101010: 225 case DRM_FORMAT_ARGB2101010: 226 case DRM_FORMAT_XBGR2101010: 227 case DRM_FORMAT_ABGR2101010: 228 return VOP2_AFBC_FMT_ARGB2101010; 229 case DRM_FORMAT_XRGB8888: 230 case DRM_FORMAT_ARGB8888: 231 case DRM_FORMAT_XBGR8888: 232 case DRM_FORMAT_ABGR8888: 233 return VOP2_AFBC_FMT_ARGB8888; 234 case DRM_FORMAT_RGB888: 235 case DRM_FORMAT_BGR888: 236 return VOP2_AFBC_FMT_RGB888; 237 case DRM_FORMAT_RGB565: 238 case DRM_FORMAT_BGR565: 239 return VOP2_AFBC_FMT_RGB565; 240 case DRM_FORMAT_YUV420_8BIT: 241 return VOP2_AFBC_FMT_YUV420; 242 case DRM_FORMAT_YUV420_10BIT: 243 return VOP2_AFBC_FMT_YUV420_10BIT; 244 case DRM_FORMAT_YVYU: 245 case DRM_FORMAT_YUYV: 246 case DRM_FORMAT_VYUY: 247 case DRM_FORMAT_UYVY: 248 return VOP2_AFBC_FMT_YUV422; 249 case DRM_FORMAT_Y210: 250 return VOP2_AFBC_FMT_YUV422_10BIT; 251 default: 252 return VOP2_AFBC_FMT_INVALID; 253 } 254 255 return VOP2_AFBC_FMT_INVALID; 256 } 257 258 static bool vop2_win_rb_swap(u32 format) 259 { 260 switch (format) { 261 case DRM_FORMAT_XBGR2101010: 262 case DRM_FORMAT_ABGR2101010: 263 case DRM_FORMAT_XBGR8888: 264 case DRM_FORMAT_ABGR8888: 265 case DRM_FORMAT_BGR888: 266 case DRM_FORMAT_BGR565: 267 return true; 268 default: 269 return false; 270 } 271 } 272 273 static bool vop2_afbc_uv_swap(u32 format) 274 { 275 switch (format) { 276 case DRM_FORMAT_YUYV: 277 case DRM_FORMAT_Y210: 278 case DRM_FORMAT_YUV420_8BIT: 279 case DRM_FORMAT_YUV420_10BIT: 280 return true; 281 default: 282 return false; 283 } 284 } 285 286 static bool vop2_win_uv_swap(u32 format) 287 { 288 switch (format) { 289 case DRM_FORMAT_NV12: 290 case DRM_FORMAT_NV16: 291 case DRM_FORMAT_NV24: 292 case DRM_FORMAT_NV15: 293 case DRM_FORMAT_NV20: 294 case DRM_FORMAT_NV30: 295 case DRM_FORMAT_YUYV: 296 case DRM_FORMAT_UYVY: 297 return true; 298 default: 299 return false; 300 } 301 } 302 303 static bool vop2_win_dither_up(u32 format) 304 { 305 switch (format) { 306 case DRM_FORMAT_BGR565: 307 case DRM_FORMAT_RGB565: 308 return true; 309 default: 310 return false; 311 } 312 } 313 314 static bool vop2_output_uv_swap(u32 bus_format, u32 output_mode) 315 { 316 /* 317 * FIXME: 318 * 319 * There is no media type for YUV444 output, 320 * so when out_mode is AAAA or P888, assume output is YUV444 on 321 * yuv format. 322 * 323 * From H/W testing, YUV444 mode need a rb swap. 324 */ 325 if (bus_format == MEDIA_BUS_FMT_YVYU8_1X16 || 326 bus_format == MEDIA_BUS_FMT_VYUY8_1X16 || 327 bus_format == MEDIA_BUS_FMT_YVYU8_2X8 || 328 bus_format == MEDIA_BUS_FMT_VYUY8_2X8 || 329 ((bus_format == MEDIA_BUS_FMT_YUV8_1X24 || 330 bus_format == MEDIA_BUS_FMT_YUV10_1X30) && 331 (output_mode == ROCKCHIP_OUT_MODE_AAAA || 332 output_mode == ROCKCHIP_OUT_MODE_P888))) 333 return true; 334 else 335 return false; 336 } 337 338 static bool vop2_output_rg_swap(struct vop2 *vop2, u32 bus_format) 339 { 340 if (vop2->version == VOP_VERSION_RK3588) { 341 if (bus_format == MEDIA_BUS_FMT_YUV8_1X24 || 342 bus_format == MEDIA_BUS_FMT_YUV10_1X30) 343 return true; 344 } 345 346 return false; 347 } 348 349 static bool is_yuv_output(u32 bus_format) 350 { 351 switch (bus_format) { 352 case MEDIA_BUS_FMT_YUV8_1X24: 353 case MEDIA_BUS_FMT_YUV10_1X30: 354 case MEDIA_BUS_FMT_UYYVYY8_0_5X24: 355 case MEDIA_BUS_FMT_UYYVYY10_0_5X30: 356 case MEDIA_BUS_FMT_YUYV8_2X8: 357 case MEDIA_BUS_FMT_YVYU8_2X8: 358 case MEDIA_BUS_FMT_UYVY8_2X8: 359 case MEDIA_BUS_FMT_VYUY8_2X8: 360 case MEDIA_BUS_FMT_YUYV8_1X16: 361 case MEDIA_BUS_FMT_YVYU8_1X16: 362 case MEDIA_BUS_FMT_UYVY8_1X16: 363 case MEDIA_BUS_FMT_VYUY8_1X16: 364 return true; 365 default: 366 return false; 367 } 368 } 369 370 static bool rockchip_vop2_mod_supported(struct drm_plane *plane, u32 format, 371 u64 modifier) 372 { 373 struct vop2_win *win = to_vop2_win(plane); 374 struct vop2 *vop2 = win->vop2; 375 int i; 376 377 /* No support for implicit modifiers */ 378 if (modifier == DRM_FORMAT_MOD_INVALID) 379 return false; 380 381 /* The cluster window on 3568 is AFBC-only */ 382 if (vop2->version == VOP_VERSION_RK3568 && vop2_cluster_window(win) && 383 !drm_is_afbc(modifier)) { 384 drm_dbg_kms(vop2->drm, 385 "Cluster window only supports format with afbc\n"); 386 return false; 387 } 388 389 /* 10bpc formats on 3588 are AFBC-only */ 390 if (vop2->version == VOP_VERSION_RK3588 && !drm_is_afbc(modifier) && 391 (format == DRM_FORMAT_XRGB2101010 || format == DRM_FORMAT_XBGR2101010)) { 392 drm_dbg_kms(vop2->drm, "Only support 10bpc format with afbc\n"); 393 return false; 394 } 395 396 /* Linear is otherwise supported everywhere */ 397 if (modifier == DRM_FORMAT_MOD_LINEAR) 398 return true; 399 400 /* Not all format+modifier combinations are allowable */ 401 if (vop2_convert_afbc_format(format) == VOP2_AFBC_FMT_INVALID) 402 return false; 403 404 /* Different windows have different format/modifier support */ 405 for (i = 0; i < plane->modifier_count; i++) { 406 if (plane->modifiers[i] == modifier) 407 return true; 408 } 409 410 return false; 411 } 412 413 /* 414 * 0: Full mode, 16 lines for one tail 415 * 1: half block mode, 8 lines one tail 416 */ 417 static bool vop2_half_block_enable(struct drm_plane_state *pstate) 418 { 419 if (pstate->rotation & (DRM_MODE_ROTATE_270 | DRM_MODE_ROTATE_90)) 420 return false; 421 else 422 return true; 423 } 424 425 static u32 vop2_afbc_transform_offset(struct drm_plane_state *pstate, 426 bool afbc_half_block_en) 427 { 428 struct drm_rect *src = &pstate->src; 429 struct drm_framebuffer *fb = pstate->fb; 430 u32 bpp = vop2_get_bpp(fb->format); 431 u32 vir_width = (fb->pitches[0] << 3) / bpp; 432 u32 width = drm_rect_width(src) >> 16; 433 u32 height = drm_rect_height(src) >> 16; 434 u32 act_xoffset = src->x1 >> 16; 435 u32 act_yoffset = src->y1 >> 16; 436 u32 align16_crop = 0; 437 u32 align64_crop = 0; 438 u32 height_tmp; 439 u8 tx, ty; 440 u8 bottom_crop_line_num = 0; 441 442 /* 16 pixel align */ 443 if (height & 0xf) 444 align16_crop = 16 - (height & 0xf); 445 446 height_tmp = height + align16_crop; 447 448 /* 64 pixel align */ 449 if (height_tmp & 0x3f) 450 align64_crop = 64 - (height_tmp & 0x3f); 451 452 bottom_crop_line_num = align16_crop + align64_crop; 453 454 switch (pstate->rotation & 455 (DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y | 456 DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270)) { 457 case DRM_MODE_REFLECT_X | DRM_MODE_REFLECT_Y: 458 tx = 16 - ((act_xoffset + width) & 0xf); 459 ty = bottom_crop_line_num - act_yoffset; 460 break; 461 case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90: 462 tx = bottom_crop_line_num - act_yoffset; 463 ty = vir_width - width - act_xoffset; 464 break; 465 case DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_270: 466 tx = act_yoffset; 467 ty = act_xoffset; 468 break; 469 case DRM_MODE_REFLECT_X: 470 tx = 16 - ((act_xoffset + width) & 0xf); 471 ty = act_yoffset; 472 break; 473 case DRM_MODE_REFLECT_Y: 474 tx = act_xoffset; 475 ty = bottom_crop_line_num - act_yoffset; 476 break; 477 case DRM_MODE_ROTATE_90: 478 tx = bottom_crop_line_num - act_yoffset; 479 ty = act_xoffset; 480 break; 481 case DRM_MODE_ROTATE_270: 482 tx = act_yoffset; 483 ty = vir_width - width - act_xoffset; 484 break; 485 case 0: 486 tx = act_xoffset; 487 ty = act_yoffset; 488 break; 489 } 490 491 if (afbc_half_block_en) 492 ty &= 0x7f; 493 494 #define TRANSFORM_XOFFSET GENMASK(7, 0) 495 #define TRANSFORM_YOFFSET GENMASK(23, 16) 496 return FIELD_PREP(TRANSFORM_XOFFSET, tx) | 497 FIELD_PREP(TRANSFORM_YOFFSET, ty); 498 } 499 500 /* 501 * A Cluster window has 2048 x 16 line buffer, which can 502 * works at 2048 x 16(Full) or 4096 x 8 (Half) mode. 503 * for Cluster_lb_mode register: 504 * 0: half mode, for plane input width range 2048 ~ 4096 505 * 1: half mode, for cluster work at 2 * 2048 plane mode 506 * 2: half mode, for rotate_90/270 mode 507 * 508 */ 509 static int vop2_get_cluster_lb_mode(struct vop2_win *win, 510 struct drm_plane_state *pstate) 511 { 512 if ((pstate->rotation & DRM_MODE_ROTATE_270) || 513 (pstate->rotation & DRM_MODE_ROTATE_90)) 514 return 2; 515 else 516 return 0; 517 } 518 519 static u16 vop2_scale_factor(u32 src, u32 dst) 520 { 521 u32 fac; 522 int shift; 523 524 if (src == dst) 525 return 0; 526 527 if (dst < 2) 528 return U16_MAX; 529 530 if (src < 2) 531 return 0; 532 533 if (src > dst) 534 shift = 12; 535 else 536 shift = 16; 537 538 src--; 539 dst--; 540 541 fac = DIV_ROUND_UP(src << shift, dst) - 1; 542 543 if (fac > U16_MAX) 544 return U16_MAX; 545 546 return fac; 547 } 548 549 static void vop2_setup_scale(struct vop2 *vop2, const struct vop2_win *win, 550 u32 src_w, u32 src_h, u32 dst_w, 551 u32 dst_h, u32 pixel_format) 552 { 553 const struct drm_format_info *info; 554 u16 hor_scl_mode, ver_scl_mode; 555 u16 hscl_filter_mode, vscl_filter_mode; 556 uint16_t cbcr_src_w = src_w; 557 uint16_t cbcr_src_h = src_h; 558 u8 gt2 = 0; 559 u8 gt4 = 0; 560 u32 val; 561 562 info = drm_format_info(pixel_format); 563 564 if (src_h >= (4 * dst_h)) { 565 gt4 = 1; 566 src_h >>= 2; 567 } else if (src_h >= (2 * dst_h)) { 568 gt2 = 1; 569 src_h >>= 1; 570 } 571 572 hor_scl_mode = scl_get_scl_mode(src_w, dst_w); 573 ver_scl_mode = scl_get_scl_mode(src_h, dst_h); 574 575 if (hor_scl_mode == SCALE_UP) 576 hscl_filter_mode = VOP2_SCALE_UP_BIC; 577 else 578 hscl_filter_mode = VOP2_SCALE_DOWN_BIL; 579 580 if (ver_scl_mode == SCALE_UP) 581 vscl_filter_mode = VOP2_SCALE_UP_BIL; 582 else 583 vscl_filter_mode = VOP2_SCALE_DOWN_BIL; 584 585 /* 586 * RK3568 VOP Esmart/Smart dsp_w should be even pixel 587 * at scale down mode 588 */ 589 if (!(win->data->feature & WIN_FEATURE_AFBDC)) { 590 if ((hor_scl_mode == SCALE_DOWN) && (dst_w & 0x1)) { 591 drm_dbg(vop2->drm, "%s dst_w[%d] should align as 2 pixel\n", 592 win->data->name, dst_w); 593 dst_w++; 594 } 595 } 596 597 val = vop2_scale_factor(src_w, dst_w); 598 vop2_win_write(win, VOP2_WIN_SCALE_YRGB_X, val); 599 val = vop2_scale_factor(src_h, dst_h); 600 vop2_win_write(win, VOP2_WIN_SCALE_YRGB_Y, val); 601 602 vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT4, gt4); 603 vop2_win_write(win, VOP2_WIN_VSD_YRGB_GT2, gt2); 604 605 vop2_win_write(win, VOP2_WIN_YRGB_HOR_SCL_MODE, hor_scl_mode); 606 vop2_win_write(win, VOP2_WIN_YRGB_VER_SCL_MODE, ver_scl_mode); 607 608 if (vop2_cluster_window(win)) 609 return; 610 611 vop2_win_write(win, VOP2_WIN_YRGB_HSCL_FILTER_MODE, hscl_filter_mode); 612 vop2_win_write(win, VOP2_WIN_YRGB_VSCL_FILTER_MODE, vscl_filter_mode); 613 614 if (info->is_yuv) { 615 cbcr_src_w /= info->hsub; 616 cbcr_src_h /= info->vsub; 617 618 gt4 = 0; 619 gt2 = 0; 620 621 if (cbcr_src_h >= (4 * dst_h)) { 622 gt4 = 1; 623 cbcr_src_h >>= 2; 624 } else if (cbcr_src_h >= (2 * dst_h)) { 625 gt2 = 1; 626 cbcr_src_h >>= 1; 627 } 628 629 hor_scl_mode = scl_get_scl_mode(cbcr_src_w, dst_w); 630 ver_scl_mode = scl_get_scl_mode(cbcr_src_h, dst_h); 631 632 val = vop2_scale_factor(cbcr_src_w, dst_w); 633 vop2_win_write(win, VOP2_WIN_SCALE_CBCR_X, val); 634 635 val = vop2_scale_factor(cbcr_src_h, dst_h); 636 vop2_win_write(win, VOP2_WIN_SCALE_CBCR_Y, val); 637 638 vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT4, gt4); 639 vop2_win_write(win, VOP2_WIN_VSD_CBCR_GT2, gt2); 640 vop2_win_write(win, VOP2_WIN_CBCR_HOR_SCL_MODE, hor_scl_mode); 641 vop2_win_write(win, VOP2_WIN_CBCR_VER_SCL_MODE, ver_scl_mode); 642 vop2_win_write(win, VOP2_WIN_CBCR_HSCL_FILTER_MODE, hscl_filter_mode); 643 vop2_win_write(win, VOP2_WIN_CBCR_VSCL_FILTER_MODE, vscl_filter_mode); 644 } 645 } 646 647 static int vop2_convert_csc_mode(int csc_mode) 648 { 649 switch (csc_mode) { 650 case V4L2_COLORSPACE_SMPTE170M: 651 case V4L2_COLORSPACE_470_SYSTEM_M: 652 case V4L2_COLORSPACE_470_SYSTEM_BG: 653 return CSC_BT601L; 654 case V4L2_COLORSPACE_REC709: 655 case V4L2_COLORSPACE_SMPTE240M: 656 case V4L2_COLORSPACE_DEFAULT: 657 return CSC_BT709L; 658 case V4L2_COLORSPACE_JPEG: 659 return CSC_BT601F; 660 case V4L2_COLORSPACE_BT2020: 661 return CSC_BT2020; 662 default: 663 return CSC_BT709L; 664 } 665 } 666 667 /* 668 * colorspace path: 669 * Input Win csc Output 670 * 1. YUV(2020) --> Y2R->2020To709->R2Y --> YUV_OUTPUT(601/709) 671 * RGB --> R2Y __/ 672 * 673 * 2. YUV(2020) --> bypasss --> YUV_OUTPUT(2020) 674 * RGB --> 709To2020->R2Y __/ 675 * 676 * 3. YUV(2020) --> Y2R->2020To709 --> RGB_OUTPUT(709) 677 * RGB --> R2Y __/ 678 * 679 * 4. YUV(601/709)-> Y2R->709To2020->R2Y --> YUV_OUTPUT(2020) 680 * RGB --> 709To2020->R2Y __/ 681 * 682 * 5. YUV(601/709)-> bypass --> YUV_OUTPUT(709) 683 * RGB --> R2Y __/ 684 * 685 * 6. YUV(601/709)-> bypass --> YUV_OUTPUT(601) 686 * RGB --> R2Y(601) __/ 687 * 688 * 7. YUV --> Y2R(709) --> RGB_OUTPUT(709) 689 * RGB --> bypass __/ 690 * 691 * 8. RGB --> 709To2020->R2Y --> YUV_OUTPUT(2020) 692 * 693 * 9. RGB --> R2Y(709) --> YUV_OUTPUT(709) 694 * 695 * 10. RGB --> R2Y(601) --> YUV_OUTPUT(601) 696 * 697 * 11. RGB --> bypass --> RGB_OUTPUT(709) 698 */ 699 700 static void vop2_setup_csc_mode(struct vop2_video_port *vp, 701 struct vop2_win *win, 702 struct drm_plane_state *pstate) 703 { 704 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(vp->crtc.state); 705 int is_input_yuv = pstate->fb->format->is_yuv; 706 int is_output_yuv = is_yuv_output(vcstate->bus_format); 707 int input_csc = V4L2_COLORSPACE_DEFAULT; 708 int output_csc = vcstate->color_space; 709 bool r2y_en, y2r_en; 710 int csc_mode; 711 712 if (is_input_yuv && !is_output_yuv) { 713 y2r_en = true; 714 r2y_en = false; 715 csc_mode = vop2_convert_csc_mode(input_csc); 716 } else if (!is_input_yuv && is_output_yuv) { 717 y2r_en = false; 718 r2y_en = true; 719 csc_mode = vop2_convert_csc_mode(output_csc); 720 } else { 721 y2r_en = false; 722 r2y_en = false; 723 csc_mode = false; 724 } 725 726 vop2_win_write(win, VOP2_WIN_Y2R_EN, y2r_en); 727 vop2_win_write(win, VOP2_WIN_R2Y_EN, r2y_en); 728 vop2_win_write(win, VOP2_WIN_CSC_MODE, csc_mode); 729 } 730 731 static void vop2_crtc_enable_irq(struct vop2_video_port *vp, u32 irq) 732 { 733 struct vop2 *vop2 = vp->vop2; 734 735 vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irq << 16 | irq); 736 vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16 | irq); 737 } 738 739 static void vop2_crtc_disable_irq(struct vop2_video_port *vp, u32 irq) 740 { 741 struct vop2 *vop2 = vp->vop2; 742 743 vop2_writel(vop2, RK3568_VP_INT_EN(vp->id), irq << 16); 744 } 745 746 static int vop2_core_clks_prepare_enable(struct vop2 *vop2) 747 { 748 int ret; 749 750 ret = clk_prepare_enable(vop2->hclk); 751 if (ret < 0) { 752 drm_err(vop2->drm, "failed to enable hclk - %d\n", ret); 753 return ret; 754 } 755 756 ret = clk_prepare_enable(vop2->aclk); 757 if (ret < 0) { 758 drm_err(vop2->drm, "failed to enable aclk - %d\n", ret); 759 goto err; 760 } 761 762 ret = clk_prepare_enable(vop2->pclk); 763 if (ret < 0) { 764 drm_err(vop2->drm, "failed to enable pclk - %d\n", ret); 765 goto err1; 766 } 767 768 return 0; 769 err1: 770 clk_disable_unprepare(vop2->aclk); 771 err: 772 clk_disable_unprepare(vop2->hclk); 773 774 return ret; 775 } 776 777 static void rk3588_vop2_power_domain_enable_all(struct vop2 *vop2) 778 { 779 u32 pd; 780 781 pd = vop2_readl(vop2, RK3588_SYS_PD_CTRL); 782 pd &= ~(VOP2_PD_CLUSTER0 | VOP2_PD_CLUSTER1 | VOP2_PD_CLUSTER2 | 783 VOP2_PD_CLUSTER3 | VOP2_PD_ESMART); 784 785 vop2_writel(vop2, RK3588_SYS_PD_CTRL, pd); 786 } 787 788 static void vop2_enable(struct vop2 *vop2) 789 { 790 int ret; 791 u32 version; 792 793 ret = pm_runtime_resume_and_get(vop2->dev); 794 if (ret < 0) { 795 drm_err(vop2->drm, "failed to get pm runtime: %d\n", ret); 796 return; 797 } 798 799 ret = vop2_core_clks_prepare_enable(vop2); 800 if (ret) { 801 pm_runtime_put_sync(vop2->dev); 802 return; 803 } 804 805 ret = rockchip_drm_dma_attach_device(vop2->drm, vop2->dev); 806 if (ret) { 807 drm_err(vop2->drm, "failed to attach dma mapping, %d\n", ret); 808 return; 809 } 810 811 version = vop2_readl(vop2, RK3568_VERSION_INFO); 812 if (version != vop2->version) { 813 drm_err(vop2->drm, "Hardware version(0x%08x) mismatch\n", version); 814 return; 815 } 816 817 /* 818 * rk3566 share the same vop version with rk3568, so 819 * we need to use soc_id for identification here. 820 */ 821 if (vop2->data->soc_id == 3566) 822 vop2_writel(vop2, RK3568_OTP_WIN_EN, 1); 823 824 if (vop2->version == VOP_VERSION_RK3588) 825 rk3588_vop2_power_domain_enable_all(vop2); 826 827 if (vop2->version <= VOP_VERSION_RK3588) { 828 vop2->old_layer_sel = vop2_readl(vop2, RK3568_OVL_LAYER_SEL); 829 vop2->old_port_sel = vop2_readl(vop2, RK3568_OVL_PORT_SEL); 830 } 831 832 vop2_writel(vop2, RK3568_REG_CFG_DONE, RK3568_REG_CFG_DONE__GLB_CFG_DONE_EN); 833 834 /* 835 * Disable auto gating, this is a workaround to 836 * avoid display image shift when a window enabled. 837 */ 838 regmap_clear_bits(vop2->map, RK3568_SYS_AUTO_GATING_CTRL, 839 RK3568_SYS_AUTO_GATING_CTRL__AUTO_GATING_EN); 840 841 vop2_writel(vop2, RK3568_SYS0_INT_CLR, 842 VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); 843 vop2_writel(vop2, RK3568_SYS0_INT_EN, 844 VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); 845 vop2_writel(vop2, RK3568_SYS1_INT_CLR, 846 VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); 847 vop2_writel(vop2, RK3568_SYS1_INT_EN, 848 VOP2_INT_BUS_ERRPR << 16 | VOP2_INT_BUS_ERRPR); 849 } 850 851 static void vop2_disable(struct vop2 *vop2) 852 { 853 rockchip_drm_dma_detach_device(vop2->drm, vop2->dev); 854 855 pm_runtime_put_sync(vop2->dev); 856 857 regcache_drop_region(vop2->map, 0, vop2_regmap_config.max_register); 858 859 clk_disable_unprepare(vop2->pclk); 860 clk_disable_unprepare(vop2->aclk); 861 clk_disable_unprepare(vop2->hclk); 862 } 863 864 static bool vop2_vp_dsp_lut_is_enabled(struct vop2_video_port *vp) 865 { 866 u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL); 867 868 return dsp_ctrl & RK3568_VP_DSP_CTRL__DSP_LUT_EN; 869 } 870 871 static void vop2_vp_dsp_lut_disable(struct vop2_video_port *vp) 872 { 873 u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL); 874 875 dsp_ctrl &= ~RK3568_VP_DSP_CTRL__DSP_LUT_EN; 876 vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); 877 } 878 879 static bool vop2_vp_dsp_lut_poll_disabled(struct vop2_video_port *vp) 880 { 881 u32 dsp_ctrl; 882 int ret = readx_poll_timeout(vop2_vp_dsp_lut_is_enabled, vp, dsp_ctrl, 883 !dsp_ctrl, 5, 30 * 1000); 884 if (ret) { 885 drm_err(vp->vop2->drm, "display LUT RAM enable timeout!\n"); 886 return false; 887 } 888 889 return true; 890 } 891 892 static void vop2_vp_dsp_lut_enable(struct vop2_video_port *vp) 893 { 894 u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL); 895 896 dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_LUT_EN; 897 vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); 898 } 899 900 static void vop2_vp_dsp_lut_update_enable(struct vop2_video_port *vp) 901 { 902 u32 dsp_ctrl = vop2_vp_read(vp, RK3568_VP_DSP_CTRL); 903 904 dsp_ctrl |= RK3588_VP_DSP_CTRL__GAMMA_UPDATE_EN; 905 vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); 906 } 907 908 static inline bool vop2_supports_seamless_gamma_lut_update(struct vop2 *vop2) 909 { 910 return vop2->version != VOP_VERSION_RK3568; 911 } 912 913 static bool vop2_gamma_lut_in_use(struct vop2 *vop2, struct vop2_video_port *vp) 914 { 915 const int nr_vps = vop2->data->nr_vps; 916 int gamma_en_vp_id; 917 918 for (gamma_en_vp_id = 0; gamma_en_vp_id < nr_vps; gamma_en_vp_id++) 919 if (vop2_vp_dsp_lut_is_enabled(&vop2->vps[gamma_en_vp_id])) 920 break; 921 922 return gamma_en_vp_id != nr_vps && gamma_en_vp_id != vp->id; 923 } 924 925 static void vop2_crtc_atomic_disable(struct drm_crtc *crtc, 926 struct drm_atomic_state *state) 927 { 928 struct vop2_video_port *vp = to_vop2_video_port(crtc); 929 struct vop2 *vop2 = vp->vop2; 930 struct drm_crtc_state *old_crtc_state; 931 int ret; 932 933 vop2_lock(vop2); 934 935 old_crtc_state = drm_atomic_get_old_crtc_state(state, crtc); 936 drm_atomic_helper_disable_planes_on_crtc(old_crtc_state, false); 937 938 drm_crtc_vblank_off(crtc); 939 940 /* 941 * Vop standby will take effect at end of current frame, 942 * if dsp hold valid irq happen, it means standby complete. 943 * 944 * we must wait standby complete when we want to disable aclk, 945 * if not, memory bus maybe dead. 946 */ 947 reinit_completion(&vp->dsp_hold_completion); 948 949 vop2_crtc_enable_irq(vp, VP_INT_DSP_HOLD_VALID); 950 951 vop2_vp_write(vp, RK3568_VP_DSP_CTRL, RK3568_VP_DSP_CTRL__STANDBY); 952 953 ret = wait_for_completion_timeout(&vp->dsp_hold_completion, 954 msecs_to_jiffies(50)); 955 if (!ret) 956 drm_info(vop2->drm, "wait for vp%d dsp_hold timeout\n", vp->id); 957 958 vop2_crtc_disable_irq(vp, VP_INT_DSP_HOLD_VALID); 959 960 if (vp->dclk_src) 961 clk_set_parent(vp->dclk, vp->dclk_src); 962 963 clk_disable_unprepare(vp->dclk); 964 965 vop2->enable_count--; 966 967 if (!vop2->enable_count) 968 vop2_disable(vop2); 969 970 vop2_unlock(vop2); 971 972 if (crtc->state->event && !crtc->state->active) { 973 spin_lock_irq(&crtc->dev->event_lock); 974 drm_crtc_send_vblank_event(crtc, crtc->state->event); 975 spin_unlock_irq(&crtc->dev->event_lock); 976 977 crtc->state->event = NULL; 978 } 979 } 980 981 static int vop2_plane_atomic_check(struct drm_plane *plane, 982 struct drm_atomic_state *astate) 983 { 984 struct drm_plane_state *pstate = drm_atomic_get_new_plane_state(astate, plane); 985 struct drm_framebuffer *fb = pstate->fb; 986 struct drm_crtc *crtc = pstate->crtc; 987 struct drm_crtc_state *cstate; 988 struct vop2_video_port *vp; 989 struct vop2_win *win = to_vop2_win(plane); 990 struct vop2 *vop2; 991 const struct vop2_data *vop2_data; 992 struct drm_rect *dest = &pstate->dst; 993 struct drm_rect *src = &pstate->src; 994 int min_scale = FRAC_16_16(1, 8); 995 int max_scale = FRAC_16_16(8, 1); 996 int src_x, src_w, src_h; 997 int dest_w, dest_h; 998 int format; 999 int ret; 1000 1001 if (!crtc) 1002 return 0; 1003 1004 vp = to_vop2_video_port(crtc); 1005 vop2 = vp->vop2; 1006 vop2_data = vop2->data; 1007 1008 cstate = drm_atomic_get_new_crtc_state(pstate->state, crtc); 1009 if (WARN_ON(!cstate)) 1010 return -EINVAL; 1011 1012 ret = drm_atomic_helper_check_plane_state(pstate, cstate, 1013 min_scale, max_scale, 1014 true, true); 1015 if (ret) 1016 return ret; 1017 1018 if (!pstate->visible) 1019 return 0; 1020 1021 format = vop2_convert_format(fb->format->format); 1022 /* We shouldn't be able to create a fb for an unsupported format */ 1023 if (WARN_ON(format < 0)) 1024 return format; 1025 1026 /* Co-ordinates have now been clipped */ 1027 src_x = src->x1 >> 16; 1028 src_w = drm_rect_width(src) >> 16; 1029 src_h = drm_rect_height(src) >> 16; 1030 dest_w = drm_rect_width(dest); 1031 dest_h = drm_rect_height(dest); 1032 1033 if (src_w < 4 || src_h < 4 || dest_w < 4 || dest_h < 4) { 1034 drm_dbg_kms(vop2->drm, "Invalid size: %dx%d->%dx%d, min size is 4x4\n", 1035 src_w, src_h, dest_w, dest_h); 1036 return -EINVAL; 1037 } 1038 1039 if (src_w > vop2_data->max_input.width || 1040 src_h > vop2_data->max_input.height) { 1041 drm_dbg_kms(vop2->drm, "Invalid source: %dx%d. max input: %dx%d\n", 1042 src_w, src_h, 1043 vop2_data->max_input.width, 1044 vop2_data->max_input.height); 1045 return -EINVAL; 1046 } 1047 1048 /* 1049 * Src.x1 can be odd when do clip, but yuv plane start point 1050 * need align with 2 pixel. 1051 */ 1052 if (fb->format->is_yuv && src_x % 2) { 1053 drm_dbg_kms(vop2->drm, "Invalid Source: Yuv format not support odd xpos\n"); 1054 return -EINVAL; 1055 } 1056 1057 /* 1058 * This is workaround solution for IC design: 1059 * esmart can't support scale down when src_w % 16 == 1. 1060 */ 1061 if (!vop2_cluster_window(win) && src_w > dest_w && (src_w & 1)) { 1062 drm_dbg_kms(vop2->drm, 1063 "Esmart windows cannot downscale odd-width source regions\n"); 1064 return -EINVAL; 1065 } 1066 1067 if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier) && src_w % 4) { 1068 drm_dbg_kms(vop2->drm, 1069 "AFBC source rectangles must be 4-pixel aligned; is %d\n", 1070 src_w); 1071 return -EINVAL; 1072 } 1073 1074 if (drm_is_afbc(fb->modifier) && 1075 pstate->rotation & 1076 (DRM_MODE_REFLECT_X | DRM_MODE_ROTATE_90 | DRM_MODE_ROTATE_270) && 1077 (fb->pitches[0] << 3) / vop2_get_bpp(fb->format) % 64) { 1078 drm_dbg_kms(vop2->drm, 1079 "AFBC buffers must be 64-pixel aligned for horizontal rotation or mirroring\n"); 1080 return -EINVAL; 1081 } 1082 1083 if ((cstate->background_color << 16) && 1084 (fb->format->has_alpha || pstate->alpha != 0xffff)) { 1085 drm_dbg_kms(vop2->drm, 1086 "Alpha-blending with background color is unsupported\n"); 1087 return -EINVAL; 1088 } 1089 1090 return 0; 1091 } 1092 1093 static void vop2_plane_atomic_disable(struct drm_plane *plane, 1094 struct drm_atomic_state *state) 1095 { 1096 struct drm_plane_state *old_pstate = NULL; 1097 struct vop2_win *win = to_vop2_win(plane); 1098 struct vop2 *vop2 = win->vop2; 1099 1100 drm_dbg(vop2->drm, "%s disable\n", win->data->name); 1101 1102 if (state) 1103 old_pstate = drm_atomic_get_old_plane_state(state, plane); 1104 if (old_pstate && !old_pstate->crtc) 1105 return; 1106 1107 vop2_win_disable(win); 1108 vop2_win_write(win, VOP2_WIN_YUV_CLIP, 0); 1109 } 1110 1111 /* 1112 * The color key is 10 bit, so all format should 1113 * convert to 10 bit here. 1114 */ 1115 static void vop2_plane_setup_color_key(struct drm_plane *plane, u32 color_key) 1116 { 1117 struct drm_plane_state *pstate = plane->state; 1118 struct drm_framebuffer *fb = pstate->fb; 1119 struct vop2_win *win = to_vop2_win(plane); 1120 u32 color_key_en = 0; 1121 u32 r = 0; 1122 u32 g = 0; 1123 u32 b = 0; 1124 1125 if (!(color_key & VOP2_COLOR_KEY_MASK) || fb->format->is_yuv) { 1126 vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, 0); 1127 return; 1128 } 1129 1130 switch (fb->format->format) { 1131 case DRM_FORMAT_RGB565: 1132 case DRM_FORMAT_BGR565: 1133 r = (color_key & 0xf800) >> 11; 1134 g = (color_key & 0x7e0) >> 5; 1135 b = (color_key & 0x1f); 1136 r <<= 5; 1137 g <<= 4; 1138 b <<= 5; 1139 color_key_en = 1; 1140 break; 1141 case DRM_FORMAT_XRGB8888: 1142 case DRM_FORMAT_ARGB8888: 1143 case DRM_FORMAT_XBGR8888: 1144 case DRM_FORMAT_ABGR8888: 1145 case DRM_FORMAT_RGB888: 1146 case DRM_FORMAT_BGR888: 1147 r = (color_key & 0xff0000) >> 16; 1148 g = (color_key & 0xff00) >> 8; 1149 b = (color_key & 0xff); 1150 r <<= 2; 1151 g <<= 2; 1152 b <<= 2; 1153 color_key_en = 1; 1154 break; 1155 } 1156 1157 vop2_win_write(win, VOP2_WIN_COLOR_KEY_EN, color_key_en); 1158 vop2_win_write(win, VOP2_WIN_COLOR_KEY, (r << 20) | (g << 10) | b); 1159 } 1160 1161 static void vop2_plane_atomic_update(struct drm_plane *plane, 1162 struct drm_atomic_state *state) 1163 { 1164 struct drm_plane_state *pstate = plane->state; 1165 struct drm_crtc *crtc = pstate->crtc; 1166 struct vop2_win *win = to_vop2_win(plane); 1167 struct vop2_video_port *vp = to_vop2_video_port(crtc); 1168 struct drm_display_mode *adjusted_mode = &crtc->state->adjusted_mode; 1169 struct vop2 *vop2 = win->vop2; 1170 struct drm_framebuffer *fb = pstate->fb; 1171 u32 bpp = vop2_get_bpp(fb->format); 1172 u32 src_w, src_h, dsp_w, dsp_h; 1173 u32 act_info, dsp_info; 1174 u32 format; 1175 u32 afbc_format; 1176 u32 rb_swap; 1177 u32 uv_swap; 1178 struct drm_rect *src = &pstate->src; 1179 struct drm_rect *dest = &pstate->dst; 1180 u32 afbc_tile_num; 1181 u32 transform_offset; 1182 bool dither_up; 1183 bool xmirror = pstate->rotation & DRM_MODE_REFLECT_X ? true : false; 1184 bool ymirror = pstate->rotation & DRM_MODE_REFLECT_Y ? true : false; 1185 bool rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270; 1186 bool rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90; 1187 struct rockchip_gem_object *rk_obj; 1188 unsigned long offset; 1189 bool half_block_en; 1190 bool afbc_en; 1191 dma_addr_t yrgb_mst; 1192 dma_addr_t uv_mst; 1193 1194 /* 1195 * can't update plane when vop2 is disabled. 1196 */ 1197 if (WARN_ON(!crtc)) 1198 return; 1199 1200 if (!pstate->visible) { 1201 vop2_plane_atomic_disable(plane, state); 1202 return; 1203 } 1204 1205 afbc_en = drm_is_afbc(fb->modifier); 1206 1207 offset = (src->x1 >> 16) * fb->format->cpp[0]; 1208 1209 /* 1210 * AFBC HDR_PTR must set to the zero offset of the framebuffer. 1211 */ 1212 if (afbc_en) 1213 offset = 0; 1214 else if (pstate->rotation & DRM_MODE_REFLECT_Y) 1215 offset += ((src->y2 >> 16) - 1) * fb->pitches[0]; 1216 else 1217 offset += (src->y1 >> 16) * fb->pitches[0]; 1218 1219 rk_obj = to_rockchip_obj(fb->obj[0]); 1220 1221 yrgb_mst = rk_obj->dma_addr + offset + fb->offsets[0]; 1222 if (fb->format->is_yuv) { 1223 int hsub = fb->format->hsub; 1224 int vsub = fb->format->vsub; 1225 1226 offset = (src->x1 >> 16) * fb->format->cpp[1] / hsub; 1227 offset += (src->y1 >> 16) * fb->pitches[1] / vsub; 1228 1229 if ((pstate->rotation & DRM_MODE_REFLECT_Y) && !afbc_en) 1230 offset += fb->pitches[1] * ((pstate->src_h >> 16) - 2) / vsub; 1231 1232 rk_obj = to_rockchip_obj(fb->obj[0]); 1233 uv_mst = rk_obj->dma_addr + offset + fb->offsets[1]; 1234 } 1235 1236 src_w = drm_rect_width(src) >> 16; 1237 src_h = drm_rect_height(src) >> 16; 1238 dsp_w = drm_rect_width(dest); 1239 dsp_h = drm_rect_height(dest); 1240 1241 /* drm_atomic_helper_check_plane_state calls drm_rect_clip_scaled for 1242 * us, which keeps our planes bounded within the CRTC active area 1243 */ 1244 if (WARN_ON(dest->x1 + dsp_w > adjusted_mode->hdisplay) || 1245 WARN_ON(dest->y1 + dsp_h > adjusted_mode->vdisplay) || 1246 WARN_ON(dsp_w < 4) || WARN_ON(dsp_h < 4) || 1247 WARN_ON(src_w < 4) || WARN_ON(src_h < 4)) 1248 return; 1249 1250 if (vop2->version == VOP_VERSION_RK3568 && drm_is_afbc(fb->modifier)) 1251 if (WARN_ON(src_w % 4)) 1252 return; 1253 1254 act_info = (src_h - 1) << 16 | ((src_w - 1) & 0xffff); 1255 dsp_info = (dsp_h - 1) << 16 | ((dsp_w - 1) & 0xffff); 1256 1257 format = vop2_convert_format(fb->format->format); 1258 half_block_en = vop2_half_block_enable(pstate); 1259 1260 drm_dbg(vop2->drm, "vp%d update %s[%dx%d->%dx%d@%dx%d] fmt[%p4cc_%s] addr[%pad]\n", 1261 vp->id, win->data->name, src_w, src_h, dsp_w, dsp_h, 1262 dest->x1, dest->y1, 1263 &fb->format->format, 1264 afbc_en ? "AFBC" : "", &yrgb_mst); 1265 1266 if (vop2->version > VOP_VERSION_RK3568) { 1267 vop2_win_write(win, VOP2_WIN_AXI_BUS_ID, win->data->axi_bus_id); 1268 vop2_win_write(win, VOP2_WIN_AXI_YRGB_R_ID, win->data->axi_yrgb_r_id); 1269 vop2_win_write(win, VOP2_WIN_AXI_UV_R_ID, win->data->axi_uv_r_id); 1270 } 1271 1272 if (vop2->version >= VOP_VERSION_RK3576) 1273 vop2_win_write(win, VOP2_WIN_VP_SEL, vp->id); 1274 1275 if (vop2_cluster_window(win)) 1276 vop2_win_write(win, VOP2_WIN_AFBC_HALF_BLOCK_EN, half_block_en); 1277 1278 if (afbc_en) { 1279 u32 stride, block_w; 1280 1281 /* the afbc superblock is 16 x 16 or 32 x 8 */ 1282 block_w = fb->modifier & AFBC_FORMAT_MOD_BLOCK_SIZE_32x8 ? 32 : 16; 1283 1284 afbc_format = vop2_convert_afbc_format(fb->format->format); 1285 1286 /* Enable color transform for YTR */ 1287 if (fb->modifier & AFBC_FORMAT_MOD_YTR) 1288 afbc_format |= (1 << 4); 1289 1290 afbc_tile_num = ALIGN(src_w, block_w) / block_w; 1291 1292 /* 1293 * AFBC pic_vir_width is count by pixel, this is different 1294 * with WIN_VIR_STRIDE. 1295 */ 1296 stride = (fb->pitches[0] << 3) / bpp; 1297 1298 /* It's for head stride, each head size is 16 byte */ 1299 stride = ALIGN(stride, block_w) / block_w * 16; 1300 1301 uv_swap = vop2_afbc_uv_swap(fb->format->format); 1302 /* 1303 * This is a workaround for crazy IC design, Cluster 1304 * and Esmart/Smart use different format configuration map: 1305 * YUV420_10BIT: 0x10 for Cluster, 0x14 for Esmart/Smart. 1306 * 1307 * This is one thing we can make the convert simple: 1308 * AFBCD decode all the YUV data to YUV444. So we just 1309 * set all the yuv 10 bit to YUV444_10. 1310 */ 1311 if (fb->format->is_yuv && bpp == 10) 1312 format = VOP2_CLUSTER_YUV444_10; 1313 1314 if (vop2_cluster_window(win)) 1315 vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 1); 1316 vop2_win_write(win, VOP2_WIN_AFBC_FORMAT, afbc_format); 1317 vop2_win_write(win, VOP2_WIN_AFBC_UV_SWAP, uv_swap); 1318 /* 1319 * On rk3566/8, this bit is auto gating enable, 1320 * but this function is not work well so we need 1321 * to disable it for these two platform. 1322 * On rk3588, and the following new soc(rk3528/rk3576), 1323 * this bit is gating disable, we should write 1 to 1324 * disable gating when enable afbc. 1325 */ 1326 if (vop2->version == VOP_VERSION_RK3568) 1327 vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 0); 1328 else 1329 vop2_win_write(win, VOP2_WIN_AFBC_AUTO_GATING_EN, 1); 1330 1331 if (fb->modifier & AFBC_FORMAT_MOD_SPLIT) 1332 vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 1); 1333 else 1334 vop2_win_write(win, VOP2_WIN_AFBC_BLOCK_SPLIT_EN, 0); 1335 1336 if (vop2->version >= VOP_VERSION_RK3576) { 1337 vop2_win_write(win, VOP2_WIN_AFBC_PLD_OFFSET_EN, 1); 1338 vop2_win_write(win, VOP2_WIN_AFBC_PLD_OFFSET, yrgb_mst); 1339 } 1340 1341 transform_offset = vop2_afbc_transform_offset(pstate, half_block_en); 1342 vop2_win_write(win, VOP2_WIN_AFBC_HDR_PTR, yrgb_mst); 1343 vop2_win_write(win, VOP2_WIN_AFBC_PIC_SIZE, act_info); 1344 vop2_win_write(win, VOP2_WIN_TRANSFORM_OFFSET, transform_offset); 1345 vop2_win_write(win, VOP2_WIN_AFBC_PIC_OFFSET, ((src->x1 >> 16) | src->y1)); 1346 vop2_win_write(win, VOP2_WIN_AFBC_DSP_OFFSET, (dest->x1 | (dest->y1 << 16))); 1347 vop2_win_write(win, VOP2_WIN_AFBC_PIC_VIR_WIDTH, stride); 1348 vop2_win_write(win, VOP2_WIN_AFBC_TILE_NUM, afbc_tile_num); 1349 vop2_win_write(win, VOP2_WIN_XMIRROR, xmirror); 1350 vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_270, rotate_270); 1351 vop2_win_write(win, VOP2_WIN_AFBC_ROTATE_90, rotate_90); 1352 } else { 1353 if (vop2_cluster_window(win)) { 1354 vop2_win_write(win, VOP2_WIN_AFBC_ENABLE, 0); 1355 vop2_win_write(win, VOP2_WIN_TRANSFORM_OFFSET, 0); 1356 } 1357 1358 vop2_win_write(win, VOP2_WIN_YRGB_VIR, DIV_ROUND_UP(fb->pitches[0], 4)); 1359 } 1360 1361 vop2_win_write(win, VOP2_WIN_YMIRROR, ymirror); 1362 1363 if (rotate_90 || rotate_270) { 1364 act_info = swahw32(act_info); 1365 src_w = drm_rect_height(src) >> 16; 1366 src_h = drm_rect_width(src) >> 16; 1367 } 1368 1369 vop2_win_write(win, VOP2_WIN_FORMAT, format); 1370 vop2_win_write(win, VOP2_WIN_YRGB_MST, yrgb_mst); 1371 1372 rb_swap = vop2_win_rb_swap(fb->format->format); 1373 vop2_win_write(win, VOP2_WIN_RB_SWAP, rb_swap); 1374 uv_swap = vop2_win_uv_swap(fb->format->format); 1375 vop2_win_write(win, VOP2_WIN_UV_SWAP, uv_swap); 1376 1377 if (fb->format->is_yuv) { 1378 vop2_win_write(win, VOP2_WIN_UV_VIR, DIV_ROUND_UP(fb->pitches[1], 4)); 1379 vop2_win_write(win, VOP2_WIN_UV_MST, uv_mst); 1380 } 1381 1382 vop2_setup_scale(vop2, win, src_w, src_h, dsp_w, dsp_h, fb->format->format); 1383 if (!vop2_cluster_window(win)) 1384 vop2_plane_setup_color_key(plane, 0); 1385 vop2_win_write(win, VOP2_WIN_ACT_INFO, act_info); 1386 vop2_win_write(win, VOP2_WIN_DSP_INFO, dsp_info); 1387 vop2_win_write(win, VOP2_WIN_DSP_ST, dest->y1 << 16 | (dest->x1 & 0xffff)); 1388 1389 vop2_setup_csc_mode(vp, win, pstate); 1390 1391 dither_up = vop2_win_dither_up(fb->format->format); 1392 vop2_win_write(win, VOP2_WIN_DITHER_UP, dither_up); 1393 1394 vop2_win_write(win, VOP2_WIN_ENABLE, 1); 1395 1396 if (vop2_cluster_window(win)) { 1397 int lb_mode = vop2_get_cluster_lb_mode(win, pstate); 1398 1399 vop2_win_write(win, VOP2_WIN_CLUSTER_LB_MODE, lb_mode); 1400 vop2_win_write(win, VOP2_WIN_CLUSTER_ENABLE, 1); 1401 } 1402 } 1403 1404 static const struct drm_plane_helper_funcs vop2_plane_helper_funcs = { 1405 .atomic_check = vop2_plane_atomic_check, 1406 .atomic_update = vop2_plane_atomic_update, 1407 .atomic_disable = vop2_plane_atomic_disable, 1408 }; 1409 1410 static const struct drm_plane_funcs vop2_plane_funcs = { 1411 .update_plane = drm_atomic_helper_update_plane, 1412 .disable_plane = drm_atomic_helper_disable_plane, 1413 .destroy = drm_plane_cleanup, 1414 .reset = drm_atomic_helper_plane_reset, 1415 .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state, 1416 .atomic_destroy_state = drm_atomic_helper_plane_destroy_state, 1417 .format_mod_supported = rockchip_vop2_mod_supported, 1418 }; 1419 1420 static int vop2_crtc_enable_vblank(struct drm_crtc *crtc) 1421 { 1422 struct vop2_video_port *vp = to_vop2_video_port(crtc); 1423 1424 vop2_crtc_enable_irq(vp, VP_INT_FS_FIELD); 1425 1426 return 0; 1427 } 1428 1429 static void vop2_crtc_disable_vblank(struct drm_crtc *crtc) 1430 { 1431 struct vop2_video_port *vp = to_vop2_video_port(crtc); 1432 1433 vop2_crtc_disable_irq(vp, VP_INT_FS_FIELD); 1434 } 1435 1436 static enum drm_mode_status vop2_crtc_mode_valid(struct drm_crtc *crtc, 1437 const struct drm_display_mode *mode) 1438 { 1439 struct vop2_video_port *vp = to_vop2_video_port(crtc); 1440 1441 if (mode->hdisplay > vp->data->max_output.width) 1442 return MODE_BAD_HVALUE; 1443 1444 return MODE_OK; 1445 } 1446 1447 static bool vop2_crtc_mode_fixup(struct drm_crtc *crtc, 1448 const struct drm_display_mode *mode, 1449 struct drm_display_mode *adj_mode) 1450 { 1451 drm_mode_set_crtcinfo(adj_mode, CRTC_INTERLACE_HALVE_V | 1452 CRTC_STEREO_DOUBLE); 1453 1454 return true; 1455 } 1456 1457 static void vop2_crtc_write_gamma_lut(struct vop2 *vop2, struct drm_crtc *crtc) 1458 { 1459 const struct vop2_video_port *vp = to_vop2_video_port(crtc); 1460 const struct vop2_video_port_data *vp_data = &vop2->data->vp[vp->id]; 1461 struct drm_color_lut *lut = crtc->state->gamma_lut->data; 1462 unsigned int i, bpc = ilog2(vp_data->gamma_lut_len); 1463 u32 word; 1464 1465 for (i = 0; i < crtc->gamma_size; i++) { 1466 word = (drm_color_lut_extract(lut[i].blue, bpc) << (2 * bpc)) | 1467 (drm_color_lut_extract(lut[i].green, bpc) << bpc) | 1468 drm_color_lut_extract(lut[i].red, bpc); 1469 1470 writel(word, vop2->lut_regs + i * 4); 1471 } 1472 } 1473 1474 static void vop2_crtc_atomic_set_gamma_seamless(struct vop2 *vop2, 1475 struct vop2_video_port *vp, 1476 struct drm_crtc *crtc) 1477 { 1478 vop2_writel(vop2, RK3568_LUT_PORT_SEL, 1479 FIELD_PREP(RK3588_LUT_PORT_SEL__GAMMA_AHB_WRITE_SEL, vp->id)); 1480 vop2_vp_dsp_lut_enable(vp); 1481 vop2_crtc_write_gamma_lut(vop2, crtc); 1482 vop2_vp_dsp_lut_update_enable(vp); 1483 } 1484 1485 static void vop2_crtc_atomic_set_gamma_rk356x(struct vop2 *vop2, 1486 struct vop2_video_port *vp, 1487 struct drm_crtc *crtc) 1488 { 1489 vop2_vp_dsp_lut_disable(vp); 1490 vop2_cfg_done(vp); 1491 if (!vop2_vp_dsp_lut_poll_disabled(vp)) 1492 return; 1493 1494 vop2_writel(vop2, RK3568_LUT_PORT_SEL, vp->id); 1495 vop2_crtc_write_gamma_lut(vop2, crtc); 1496 vop2_vp_dsp_lut_enable(vp); 1497 } 1498 1499 static void vop2_crtc_atomic_try_set_gamma(struct vop2 *vop2, 1500 struct vop2_video_port *vp, 1501 struct drm_crtc *crtc, 1502 struct drm_crtc_state *crtc_state) 1503 { 1504 if (!vop2->lut_regs) 1505 return; 1506 1507 if (!crtc_state->gamma_lut) { 1508 vop2_vp_dsp_lut_disable(vp); 1509 return; 1510 } 1511 1512 if (vop2_supports_seamless_gamma_lut_update(vop2)) 1513 vop2_crtc_atomic_set_gamma_seamless(vop2, vp, crtc); 1514 else 1515 vop2_crtc_atomic_set_gamma_rk356x(vop2, vp, crtc); 1516 } 1517 1518 static inline void vop2_crtc_atomic_try_set_gamma_locked(struct vop2 *vop2, 1519 struct vop2_video_port *vp, 1520 struct drm_crtc *crtc, 1521 struct drm_crtc_state *crtc_state) 1522 { 1523 vop2_lock(vop2); 1524 vop2_crtc_atomic_try_set_gamma(vop2, vp, crtc, crtc_state); 1525 vop2_unlock(vop2); 1526 } 1527 1528 static void vop2_dither_setup(struct drm_crtc *crtc, u32 *dsp_ctrl) 1529 { 1530 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); 1531 1532 switch (vcstate->bus_format) { 1533 case MEDIA_BUS_FMT_RGB565_1X16: 1534 *dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN; 1535 break; 1536 case MEDIA_BUS_FMT_RGB666_1X18: 1537 case MEDIA_BUS_FMT_RGB666_1X24_CPADHI: 1538 case MEDIA_BUS_FMT_RGB666_1X7X3_SPWG: 1539 *dsp_ctrl |= RK3568_VP_DSP_CTRL__DITHER_DOWN_EN; 1540 *dsp_ctrl |= RGB888_TO_RGB666; 1541 break; 1542 case MEDIA_BUS_FMT_YUV8_1X24: 1543 case MEDIA_BUS_FMT_UYYVYY8_0_5X24: 1544 *dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN; 1545 break; 1546 default: 1547 break; 1548 } 1549 1550 if (vcstate->output_mode != ROCKCHIP_OUT_MODE_AAAA) 1551 *dsp_ctrl |= RK3568_VP_DSP_CTRL__PRE_DITHER_DOWN_EN; 1552 1553 *dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__DITHER_DOWN_SEL, 1554 DITHER_DOWN_ALLEGRO); 1555 } 1556 1557 static void vop2_post_config(struct drm_crtc *crtc) 1558 { 1559 struct vop2_video_port *vp = to_vop2_video_port(crtc); 1560 struct vop2 *vop2 = vp->vop2; 1561 struct drm_display_mode *mode = &crtc->state->adjusted_mode; 1562 u64 bgcolor = crtc->state->background_color; 1563 u16 vtotal = mode->crtc_vtotal; 1564 u16 hdisplay = mode->crtc_hdisplay; 1565 u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start; 1566 u16 vdisplay = mode->crtc_vdisplay; 1567 u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start; 1568 u32 left_margin = 100, right_margin = 100; 1569 u32 top_margin = 100, bottom_margin = 100; 1570 u16 hsize = hdisplay * (left_margin + right_margin) / 200; 1571 u16 vsize = vdisplay * (top_margin + bottom_margin) / 200; 1572 u16 hact_end, vact_end; 1573 u32 val; 1574 1575 vop2->ops->setup_bg_dly(vp); 1576 1577 vsize = rounddown(vsize, 2); 1578 hsize = rounddown(hsize, 2); 1579 hact_st += hdisplay * (100 - left_margin) / 200; 1580 hact_end = hact_st + hsize; 1581 val = hact_st << 16; 1582 val |= hact_end; 1583 vop2_vp_write(vp, RK3568_VP_POST_DSP_HACT_INFO, val); 1584 vact_st += vdisplay * (100 - top_margin) / 200; 1585 vact_end = vact_st + vsize; 1586 val = vact_st << 16; 1587 val |= vact_end; 1588 vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO, val); 1589 val = scl_cal_scale2(vdisplay, vsize) << 16; 1590 val |= scl_cal_scale2(hdisplay, hsize); 1591 vop2_vp_write(vp, RK3568_VP_POST_SCL_FACTOR_YRGB, val); 1592 1593 val = 0; 1594 if (hdisplay != hsize) 1595 val |= RK3568_VP_POST_SCL_CTRL__HSCALEDOWN; 1596 if (vdisplay != vsize) 1597 val |= RK3568_VP_POST_SCL_CTRL__VSCALEDOWN; 1598 vop2_vp_write(vp, RK3568_VP_POST_SCL_CTRL, val); 1599 1600 if (mode->flags & DRM_MODE_FLAG_INTERLACE) { 1601 u16 vact_st_f1 = vtotal + vact_st + 1; 1602 u16 vact_end_f1 = vact_st_f1 + vsize; 1603 1604 val = vact_st_f1 << 16 | vact_end_f1; 1605 vop2_vp_write(vp, RK3568_VP_POST_DSP_VACT_INFO_F1, val); 1606 } 1607 1608 /* 1609 * Background color is programmed with 10 bits of precision. 1610 * Since performance is more important than accuracy here, 1611 * make use of the DRM_ARGB64_GET*_BPCS() helpers. 1612 */ 1613 val = FIELD_PREP(RK3568_VP_DSP_BG__DSP_BG_RED, DRM_ARGB64_GETR_BPCS(bgcolor, 10)); 1614 FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_GREEN, &val, DRM_ARGB64_GETG_BPCS(bgcolor, 10)); 1615 FIELD_MODIFY(RK3568_VP_DSP_BG__DSP_BG_BLUE, &val, DRM_ARGB64_GETB_BPCS(bgcolor, 10)); 1616 vop2_vp_write(vp, RK3568_VP_DSP_BG, val); 1617 } 1618 1619 static int us_to_vertical_line(struct drm_display_mode *mode, int us) 1620 { 1621 return us * mode->clock / mode->htotal / 1000; 1622 } 1623 1624 static void vop2_crtc_atomic_enable(struct drm_crtc *crtc, 1625 struct drm_atomic_state *state) 1626 { 1627 struct vop2_video_port *vp = to_vop2_video_port(crtc); 1628 struct vop2 *vop2 = vp->vop2; 1629 const struct vop2_data *vop2_data = vop2->data; 1630 const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; 1631 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 1632 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(crtc->state); 1633 struct drm_display_mode *mode = &crtc->state->adjusted_mode; 1634 unsigned long clock = mode->crtc_clock * 1000; 1635 u16 hsync_len = mode->crtc_hsync_end - mode->crtc_hsync_start; 1636 u16 hdisplay = mode->crtc_hdisplay; 1637 u16 htotal = mode->crtc_htotal; 1638 u16 hact_st = mode->crtc_htotal - mode->crtc_hsync_start; 1639 u16 hact_end = hact_st + hdisplay; 1640 u16 vdisplay = mode->crtc_vdisplay; 1641 u16 vtotal = mode->crtc_vtotal; 1642 u16 vsync_len = mode->crtc_vsync_end - mode->crtc_vsync_start; 1643 u16 vact_st = mode->crtc_vtotal - mode->crtc_vsync_start; 1644 u16 vact_end = vact_st + vdisplay; 1645 u8 out_mode; 1646 u32 dsp_ctrl = 0; 1647 int act_end; 1648 u32 val, polflags; 1649 int ret; 1650 struct drm_encoder *encoder; 1651 1652 drm_dbg(vop2->drm, "Update mode to %dx%d%s%d, type: %d for vp%d\n", 1653 hdisplay, vdisplay, mode->flags & DRM_MODE_FLAG_INTERLACE ? "i" : "p", 1654 drm_mode_vrefresh(mode), vcstate->output_type, vp->id); 1655 1656 vop2_lock(vop2); 1657 1658 ret = clk_prepare_enable(vp->dclk); 1659 if (ret < 0) { 1660 drm_err(vop2->drm, "failed to enable dclk for video port%d - %d\n", 1661 vp->id, ret); 1662 vop2_unlock(vop2); 1663 return; 1664 } 1665 1666 if (!vop2->enable_count) 1667 vop2_enable(vop2); 1668 1669 vop2->enable_count++; 1670 1671 vcstate->yuv_overlay = is_yuv_output(vcstate->bus_format); 1672 1673 vop2_crtc_enable_irq(vp, VP_INT_POST_BUF_EMPTY); 1674 1675 polflags = 0; 1676 if (vcstate->bus_flags & DRM_BUS_FLAG_PIXDATA_DRIVE_NEGEDGE) 1677 polflags |= POLFLAG_DCLK_INV; 1678 if (mode->flags & DRM_MODE_FLAG_PHSYNC) 1679 polflags |= BIT(HSYNC_POSITIVE); 1680 if (mode->flags & DRM_MODE_FLAG_PVSYNC) 1681 polflags |= BIT(VSYNC_POSITIVE); 1682 1683 drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { 1684 struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); 1685 1686 /* 1687 * for drive a high resolution(4KP120, 8K), vop on rk3588/rk3576 need 1688 * process multi(1/2/4/8) pixels per cycle, so the dclk feed by the 1689 * system cru may be the 1/2 or 1/4 of mode->clock. 1690 */ 1691 clock = vop2->ops->setup_intf_mux(vp, rkencoder->crtc_endpoint_id, polflags); 1692 } 1693 1694 if (!clock) { 1695 vop2_unlock(vop2); 1696 return; 1697 } 1698 1699 if (vcstate->output_mode == ROCKCHIP_OUT_MODE_AAAA && 1700 !(vp_data->feature & VOP2_VP_FEATURE_OUTPUT_10BIT)) 1701 out_mode = ROCKCHIP_OUT_MODE_P888; 1702 else 1703 out_mode = vcstate->output_mode; 1704 1705 dsp_ctrl |= FIELD_PREP(RK3568_VP_DSP_CTRL__OUT_MODE, out_mode); 1706 1707 if (vop2_output_uv_swap(vcstate->bus_format, vcstate->output_mode)) 1708 dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RB_SWAP; 1709 if (vop2_output_rg_swap(vop2, vcstate->bus_format)) 1710 dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_RG_SWAP; 1711 1712 if (vcstate->yuv_overlay) 1713 dsp_ctrl |= RK3568_VP_DSP_CTRL__POST_DSP_OUT_R2Y; 1714 1715 vop2_dither_setup(crtc, &dsp_ctrl); 1716 1717 vop2_vp_write(vp, RK3568_VP_DSP_HTOTAL_HS_END, (htotal << 16) | hsync_len); 1718 val = hact_st << 16; 1719 val |= hact_end; 1720 vop2_vp_write(vp, RK3568_VP_DSP_HACT_ST_END, val); 1721 1722 val = vact_st << 16; 1723 val |= vact_end; 1724 vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END, val); 1725 1726 if (mode->flags & DRM_MODE_FLAG_INTERLACE) { 1727 u16 vact_st_f1 = vtotal + vact_st + 1; 1728 u16 vact_end_f1 = vact_st_f1 + vdisplay; 1729 1730 val = vact_st_f1 << 16 | vact_end_f1; 1731 vop2_vp_write(vp, RK3568_VP_DSP_VACT_ST_END_F1, val); 1732 1733 val = vtotal << 16 | (vtotal + vsync_len); 1734 vop2_vp_write(vp, RK3568_VP_DSP_VS_ST_END_F1, val); 1735 dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_INTERLACE; 1736 dsp_ctrl |= RK3568_VP_DSP_CTRL__DSP_FILED_POL; 1737 dsp_ctrl |= RK3568_VP_DSP_CTRL__P2I_EN; 1738 vtotal += vtotal + 1; 1739 act_end = vact_end_f1; 1740 } else { 1741 act_end = vact_end; 1742 } 1743 1744 vop2_writel(vop2, RK3568_VP_LINE_FLAG(vp->id), 1745 (act_end - us_to_vertical_line(mode, 0)) << 16 | act_end); 1746 1747 vop2_vp_write(vp, RK3568_VP_DSP_VTOTAL_VS_END, vtotal << 16 | vsync_len); 1748 1749 if (mode->flags & DRM_MODE_FLAG_DBLCLK) { 1750 dsp_ctrl |= RK3568_VP_DSP_CTRL__CORE_DCLK_DIV; 1751 clock *= 2; 1752 } 1753 1754 vop2_vp_write(vp, RK3568_VP_MIPI_CTRL, 0); 1755 1756 /* 1757 * Switch to HDMI PHY PLL as DCLK source for display modes up 1758 * to 4K@60Hz, if available, otherwise keep using the system CRU. 1759 */ 1760 if (vop2->pll_hdmiphy0 || vop2->pll_hdmiphy1) { 1761 unsigned long max_dclk = DIV_ROUND_CLOSEST_ULL(VOP2_MAX_DCLK_RATE * 8, 1762 vcstate->output_bpc); 1763 if (clock <= max_dclk) { 1764 drm_for_each_encoder_mask(encoder, crtc->dev, crtc_state->encoder_mask) { 1765 struct rockchip_encoder *rkencoder = to_rockchip_encoder(encoder); 1766 1767 if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI0) { 1768 if (!vop2->pll_hdmiphy0) 1769 break; 1770 1771 if (!vp->dclk_src) 1772 vp->dclk_src = clk_get_parent(vp->dclk); 1773 1774 ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy0); 1775 if (ret < 0) 1776 drm_warn(vop2->drm, 1777 "Could not switch to HDMI0 PHY PLL: %d\n", 1778 ret); 1779 break; 1780 } 1781 1782 if (rkencoder->crtc_endpoint_id == ROCKCHIP_VOP2_EP_HDMI1) { 1783 if (!vop2->pll_hdmiphy1) 1784 break; 1785 1786 if (!vp->dclk_src) 1787 vp->dclk_src = clk_get_parent(vp->dclk); 1788 1789 ret = clk_set_parent(vp->dclk, vop2->pll_hdmiphy1); 1790 if (ret < 0) 1791 drm_warn(vop2->drm, 1792 "Could not switch to HDMI1 PHY PLL: %d\n", 1793 ret); 1794 break; 1795 } 1796 } 1797 } 1798 } 1799 1800 clk_set_rate(vp->dclk, clock); 1801 1802 vop2_post_config(crtc); 1803 1804 vop2_cfg_done(vp); 1805 1806 vop2_vp_write(vp, RK3568_VP_DSP_CTRL, dsp_ctrl); 1807 1808 vop2_crtc_atomic_try_set_gamma(vop2, vp, crtc, crtc_state); 1809 1810 drm_crtc_vblank_on(crtc); 1811 1812 vop2_unlock(vop2); 1813 } 1814 1815 static int vop2_crtc_atomic_check_gamma(struct vop2_video_port *vp, 1816 struct drm_crtc *crtc, 1817 struct drm_atomic_state *state, 1818 struct drm_crtc_state *crtc_state) 1819 { 1820 struct vop2 *vop2 = vp->vop2; 1821 unsigned int len; 1822 1823 if (!vp->vop2->lut_regs || !crtc_state->color_mgmt_changed || 1824 !crtc_state->gamma_lut) 1825 return 0; 1826 1827 len = drm_color_lut_size(crtc_state->gamma_lut); 1828 if (len != crtc->gamma_size) { 1829 drm_dbg(vop2->drm, "Invalid LUT size; got %d, expected %d\n", 1830 len, crtc->gamma_size); 1831 return -EINVAL; 1832 } 1833 1834 if (!vop2_supports_seamless_gamma_lut_update(vop2) && vop2_gamma_lut_in_use(vop2, vp)) { 1835 drm_info(vop2->drm, "Gamma LUT can be enabled for only one CRTC at a time\n"); 1836 return -EINVAL; 1837 } 1838 1839 return 0; 1840 } 1841 1842 static int vop2_crtc_atomic_check(struct drm_crtc *crtc, 1843 struct drm_atomic_state *state) 1844 { 1845 struct vop2_video_port *vp = to_vop2_video_port(crtc); 1846 struct drm_plane *plane; 1847 int nplanes = 0; 1848 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 1849 int ret; 1850 1851 ret = vop2_crtc_atomic_check_gamma(vp, crtc, state, crtc_state); 1852 if (ret) 1853 return ret; 1854 1855 drm_atomic_crtc_state_for_each_plane(plane, crtc_state) 1856 nplanes++; 1857 1858 if (nplanes > vp->nlayers) 1859 return -EINVAL; 1860 1861 return 0; 1862 } 1863 1864 static void vop2_crtc_atomic_begin(struct drm_crtc *crtc, 1865 struct drm_atomic_state *state) 1866 { 1867 struct vop2_video_port *vp = to_vop2_video_port(crtc); 1868 struct vop2 *vop2 = vp->vop2; 1869 1870 vop2->ops->setup_overlay(vp); 1871 } 1872 1873 static void vop2_crtc_atomic_flush(struct drm_crtc *crtc, 1874 struct drm_atomic_state *state) 1875 { 1876 struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc); 1877 struct vop2_video_port *vp = to_vop2_video_port(crtc); 1878 struct vop2 *vop2 = vp->vop2; 1879 1880 /* In case of modeset, gamma lut update already happened in atomic enable */ 1881 if (!drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->color_mgmt_changed) 1882 vop2_crtc_atomic_try_set_gamma_locked(vop2, vp, crtc, crtc_state); 1883 1884 vop2_post_config(crtc); 1885 1886 vop2_cfg_done(vp); 1887 1888 spin_lock_irq(&crtc->dev->event_lock); 1889 1890 if (crtc->state->event) { 1891 WARN_ON(drm_crtc_vblank_get(crtc)); 1892 vp->event = crtc->state->event; 1893 crtc->state->event = NULL; 1894 } 1895 1896 spin_unlock_irq(&crtc->dev->event_lock); 1897 } 1898 1899 static const struct drm_crtc_helper_funcs vop2_crtc_helper_funcs = { 1900 .mode_fixup = vop2_crtc_mode_fixup, 1901 .mode_valid = vop2_crtc_mode_valid, 1902 .atomic_check = vop2_crtc_atomic_check, 1903 .atomic_begin = vop2_crtc_atomic_begin, 1904 .atomic_flush = vop2_crtc_atomic_flush, 1905 .atomic_enable = vop2_crtc_atomic_enable, 1906 .atomic_disable = vop2_crtc_atomic_disable, 1907 }; 1908 1909 static void vop2_dump_connector_on_crtc(struct drm_crtc *crtc, struct seq_file *s) 1910 { 1911 struct drm_connector_list_iter conn_iter; 1912 struct drm_connector *connector; 1913 1914 drm_connector_list_iter_begin(crtc->dev, &conn_iter); 1915 drm_for_each_connector_iter(connector, &conn_iter) { 1916 if (crtc->state->connector_mask & drm_connector_mask(connector)) 1917 seq_printf(s, " Connector: %s\n", connector->name); 1918 } 1919 drm_connector_list_iter_end(&conn_iter); 1920 } 1921 1922 static int vop2_plane_state_dump(struct seq_file *s, struct drm_plane *plane) 1923 { 1924 struct vop2_win *win = to_vop2_win(plane); 1925 struct drm_plane_state *pstate = plane->state; 1926 struct drm_rect *src, *dst; 1927 struct drm_framebuffer *fb; 1928 struct drm_gem_object *obj; 1929 struct rockchip_gem_object *rk_obj; 1930 bool xmirror; 1931 bool ymirror; 1932 bool rotate_270; 1933 bool rotate_90; 1934 dma_addr_t fb_addr; 1935 int i; 1936 1937 seq_printf(s, " %s: %s\n", win->data->name, !pstate ? 1938 "DISABLED" : pstate->crtc ? "ACTIVE" : "DISABLED"); 1939 1940 if (!pstate || !pstate->fb) 1941 return 0; 1942 1943 fb = pstate->fb; 1944 src = &pstate->src; 1945 dst = &pstate->dst; 1946 xmirror = pstate->rotation & DRM_MODE_REFLECT_X ? true : false; 1947 ymirror = pstate->rotation & DRM_MODE_REFLECT_Y ? true : false; 1948 rotate_270 = pstate->rotation & DRM_MODE_ROTATE_270; 1949 rotate_90 = pstate->rotation & DRM_MODE_ROTATE_90; 1950 1951 seq_printf(s, "\twin_id: %d\n", win->win_id); 1952 1953 seq_printf(s, "\tformat: %p4cc%s glb_alpha[0x%x]\n", 1954 &fb->format->format, 1955 drm_is_afbc(fb->modifier) ? "[AFBC]" : "", 1956 pstate->alpha >> 8); 1957 seq_printf(s, "\trotate: xmirror: %d ymirror: %d rotate_90: %d rotate_270: %d\n", 1958 xmirror, ymirror, rotate_90, rotate_270); 1959 seq_printf(s, "\tzpos: %d\n", pstate->normalized_zpos); 1960 seq_printf(s, "\tsrc: pos[%d, %d] rect[%d x %d]\n", src->x1 >> 16, 1961 src->y1 >> 16, drm_rect_width(src) >> 16, 1962 drm_rect_height(src) >> 16); 1963 seq_printf(s, "\tdst: pos[%d, %d] rect[%d x %d]\n", dst->x1, dst->y1, 1964 drm_rect_width(dst), drm_rect_height(dst)); 1965 1966 for (i = 0; i < fb->format->num_planes; i++) { 1967 obj = fb->obj[i]; 1968 rk_obj = to_rockchip_obj(obj); 1969 fb_addr = rk_obj->dma_addr + fb->offsets[i]; 1970 1971 seq_printf(s, "\tbuf[%d]: addr: %pad pitch: %d offset: %d\n", 1972 i, &fb_addr, fb->pitches[i], fb->offsets[i]); 1973 } 1974 1975 return 0; 1976 } 1977 1978 static int vop2_crtc_state_dump(struct drm_crtc *crtc, struct seq_file *s) 1979 { 1980 struct vop2_video_port *vp = to_vop2_video_port(crtc); 1981 struct drm_crtc_state *cstate = crtc->state; 1982 struct rockchip_crtc_state *vcstate; 1983 struct drm_display_mode *mode; 1984 struct drm_plane *plane; 1985 bool interlaced; 1986 1987 seq_printf(s, "Video Port%d: %s\n", vp->id, !cstate ? 1988 "DISABLED" : cstate->active ? "ACTIVE" : "DISABLED"); 1989 1990 if (!cstate || !cstate->active) 1991 return 0; 1992 1993 mode = &crtc->state->adjusted_mode; 1994 vcstate = to_rockchip_crtc_state(cstate); 1995 interlaced = !!(mode->flags & DRM_MODE_FLAG_INTERLACE); 1996 1997 vop2_dump_connector_on_crtc(crtc, s); 1998 seq_printf(s, "\tbus_format[%x]: %s\n", vcstate->bus_format, 1999 drm_get_bus_format_name(vcstate->bus_format)); 2000 seq_printf(s, "\toutput_mode[%x]", vcstate->output_mode); 2001 seq_printf(s, " color_space[%d]\n", vcstate->color_space); 2002 seq_printf(s, "\tbackground color (10bpc): r=0x%x g=0x%x b=0x%x\n", 2003 DRM_ARGB64_GETR_BPCS(cstate->background_color, 10), 2004 DRM_ARGB64_GETG_BPCS(cstate->background_color, 10), 2005 DRM_ARGB64_GETB_BPCS(cstate->background_color, 10)); 2006 seq_printf(s, " Display mode: %dx%d%s%d\n", 2007 mode->hdisplay, mode->vdisplay, interlaced ? "i" : "p", 2008 drm_mode_vrefresh(mode)); 2009 seq_printf(s, "\tclk[%d] real_clk[%d] type[%x] flag[%x]\n", 2010 mode->clock, mode->crtc_clock, mode->type, mode->flags); 2011 seq_printf(s, "\tH: %d %d %d %d\n", mode->hdisplay, mode->hsync_start, 2012 mode->hsync_end, mode->htotal); 2013 seq_printf(s, "\tV: %d %d %d %d\n", mode->vdisplay, mode->vsync_start, 2014 mode->vsync_end, mode->vtotal); 2015 2016 drm_atomic_crtc_for_each_plane(plane, crtc) { 2017 vop2_plane_state_dump(s, plane); 2018 } 2019 2020 return 0; 2021 } 2022 2023 static int vop2_summary_show(struct seq_file *s, void *data) 2024 { 2025 struct drm_info_node *node = s->private; 2026 struct drm_minor *minor = node->minor; 2027 struct drm_device *drm_dev = minor->dev; 2028 struct drm_crtc *crtc; 2029 2030 drm_modeset_lock_all(drm_dev); 2031 drm_for_each_crtc(crtc, drm_dev) { 2032 vop2_crtc_state_dump(crtc, s); 2033 } 2034 drm_modeset_unlock_all(drm_dev); 2035 2036 return 0; 2037 } 2038 2039 static void vop2_regs_print(struct vop2 *vop2, struct seq_file *s, 2040 const struct vop2_regs_dump *dump, bool active_only) 2041 { 2042 resource_size_t start; 2043 u32 val; 2044 int i; 2045 2046 if (dump->en_mask && active_only) { 2047 val = vop2_readl(vop2, dump->base + dump->en_reg); 2048 if ((val & dump->en_mask) != dump->en_val) 2049 return; 2050 } 2051 2052 seq_printf(s, "\n%s:\n", dump->name); 2053 2054 start = vop2->res->start + dump->base; 2055 for (i = 0; i < dump->size >> 2; i += 4) { 2056 seq_printf(s, "%08x: %08x %08x %08x %08x\n", (u32)start + i * 4, 2057 vop2_readl(vop2, dump->base + (4 * i)), 2058 vop2_readl(vop2, dump->base + (4 * (i + 1))), 2059 vop2_readl(vop2, dump->base + (4 * (i + 2))), 2060 vop2_readl(vop2, dump->base + (4 * (i + 3)))); 2061 } 2062 } 2063 2064 static void __vop2_regs_dump(struct seq_file *s, bool active_only) 2065 { 2066 struct drm_info_node *node = s->private; 2067 struct vop2 *vop2 = node->info_ent->data; 2068 struct drm_minor *minor = node->minor; 2069 struct drm_device *drm_dev = minor->dev; 2070 const struct vop2_regs_dump *dump; 2071 unsigned int i; 2072 2073 drm_modeset_lock_all(drm_dev); 2074 2075 regcache_drop_region(vop2->map, 0, vop2_regmap_config.max_register); 2076 2077 if (vop2->enable_count) { 2078 for (i = 0; i < vop2->data->regs_dump_size; i++) { 2079 dump = &vop2->data->regs_dump[i]; 2080 vop2_regs_print(vop2, s, dump, active_only); 2081 } 2082 } else { 2083 seq_puts(s, "VOP disabled\n"); 2084 } 2085 drm_modeset_unlock_all(drm_dev); 2086 } 2087 2088 static int vop2_regs_show(struct seq_file *s, void *arg) 2089 { 2090 __vop2_regs_dump(s, false); 2091 2092 return 0; 2093 } 2094 2095 static int vop2_active_regs_show(struct seq_file *s, void *data) 2096 { 2097 __vop2_regs_dump(s, true); 2098 2099 return 0; 2100 } 2101 2102 static struct drm_info_list vop2_debugfs_list[] = { 2103 { "summary", vop2_summary_show, 0, NULL }, 2104 { "active_regs", vop2_active_regs_show, 0, NULL }, 2105 { "regs", vop2_regs_show, 0, NULL }, 2106 }; 2107 2108 static void vop2_debugfs_init(struct vop2 *vop2, struct drm_minor *minor) 2109 { 2110 struct dentry *root; 2111 unsigned int i; 2112 2113 root = debugfs_create_dir("vop2", minor->debugfs_root); 2114 if (!IS_ERR(root)) { 2115 for (i = 0; i < ARRAY_SIZE(vop2_debugfs_list); i++) 2116 vop2_debugfs_list[i].data = vop2; 2117 2118 drm_debugfs_create_files(vop2_debugfs_list, 2119 ARRAY_SIZE(vop2_debugfs_list), 2120 root, minor); 2121 } 2122 } 2123 2124 static int vop2_crtc_late_register(struct drm_crtc *crtc) 2125 { 2126 struct vop2_video_port *vp = to_vop2_video_port(crtc); 2127 struct vop2 *vop2 = vp->vop2; 2128 2129 if (drm_crtc_index(crtc) == 0) 2130 vop2_debugfs_init(vop2, crtc->dev->primary); 2131 2132 return 0; 2133 } 2134 2135 static struct drm_crtc_state *vop2_crtc_duplicate_state(struct drm_crtc *crtc) 2136 { 2137 struct rockchip_crtc_state *vcstate; 2138 2139 if (WARN_ON(!crtc->state)) 2140 return NULL; 2141 2142 vcstate = kmemdup(to_rockchip_crtc_state(crtc->state), 2143 sizeof(*vcstate), GFP_KERNEL); 2144 if (!vcstate) 2145 return NULL; 2146 2147 __drm_atomic_helper_crtc_duplicate_state(crtc, &vcstate->base); 2148 2149 return &vcstate->base; 2150 } 2151 2152 static void vop2_crtc_destroy_state(struct drm_crtc *crtc, 2153 struct drm_crtc_state *state) 2154 { 2155 struct rockchip_crtc_state *vcstate = to_rockchip_crtc_state(state); 2156 2157 __drm_atomic_helper_crtc_destroy_state(&vcstate->base); 2158 kfree(vcstate); 2159 } 2160 2161 static void vop2_crtc_reset(struct drm_crtc *crtc) 2162 { 2163 struct rockchip_crtc_state *vcstate = kzalloc_obj(*vcstate); 2164 2165 if (crtc->state) 2166 vop2_crtc_destroy_state(crtc, crtc->state); 2167 2168 if (vcstate) 2169 __drm_atomic_helper_crtc_reset(crtc, &vcstate->base); 2170 else 2171 __drm_atomic_helper_crtc_reset(crtc, NULL); 2172 } 2173 2174 static const struct drm_crtc_funcs vop2_crtc_funcs = { 2175 .set_config = drm_atomic_helper_set_config, 2176 .page_flip = drm_atomic_helper_page_flip, 2177 .destroy = drm_crtc_cleanup, 2178 .reset = vop2_crtc_reset, 2179 .atomic_duplicate_state = vop2_crtc_duplicate_state, 2180 .atomic_destroy_state = vop2_crtc_destroy_state, 2181 .enable_vblank = vop2_crtc_enable_vblank, 2182 .disable_vblank = vop2_crtc_disable_vblank, 2183 .late_register = vop2_crtc_late_register, 2184 }; 2185 2186 static irqreturn_t rk3576_vp_isr(int irq, void *data) 2187 { 2188 struct vop2_video_port *vp = data; 2189 struct vop2 *vop2 = vp->vop2; 2190 struct drm_crtc *crtc = &vp->crtc; 2191 uint32_t irqs; 2192 int ret = IRQ_NONE; 2193 2194 if (!pm_runtime_get_if_in_use(vop2->dev)) 2195 return IRQ_NONE; 2196 2197 irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id)); 2198 vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs); 2199 2200 if (irqs & VP_INT_DSP_HOLD_VALID) { 2201 complete(&vp->dsp_hold_completion); 2202 ret = IRQ_HANDLED; 2203 } 2204 2205 if (irqs & VP_INT_FS_FIELD) { 2206 drm_crtc_handle_vblank(crtc); 2207 spin_lock(&crtc->dev->event_lock); 2208 if (vp->event) { 2209 u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE); 2210 2211 if (!(val & BIT(vp->id))) { 2212 drm_crtc_send_vblank_event(crtc, vp->event); 2213 vp->event = NULL; 2214 drm_crtc_vblank_put(crtc); 2215 } 2216 } 2217 spin_unlock(&crtc->dev->event_lock); 2218 2219 ret = IRQ_HANDLED; 2220 } 2221 2222 if (irqs & VP_INT_POST_BUF_EMPTY) { 2223 drm_err_ratelimited(vop2->drm, "POST_BUF_EMPTY irq err at vp%d\n", vp->id); 2224 ret = IRQ_HANDLED; 2225 } 2226 2227 pm_runtime_put(vop2->dev); 2228 2229 return ret; 2230 } 2231 2232 static irqreturn_t vop2_isr(int irq, void *data) 2233 { 2234 struct vop2 *vop2 = data; 2235 const struct vop2_data *vop2_data = vop2->data; 2236 u32 axi_irqs[VOP2_SYS_AXI_BUS_NUM]; 2237 int ret = IRQ_NONE; 2238 int i; 2239 2240 /* 2241 * The irq is shared with the iommu. If the runtime-pm state of the 2242 * vop2-device is disabled the irq has to be targeted at the iommu. 2243 */ 2244 if (!pm_runtime_get_if_in_use(vop2->dev)) 2245 return IRQ_NONE; 2246 2247 if (vop2->version < VOP_VERSION_RK3576) { 2248 for (i = 0; i < vop2_data->nr_vps; i++) { 2249 struct vop2_video_port *vp = &vop2->vps[i]; 2250 struct drm_crtc *crtc = &vp->crtc; 2251 u32 irqs; 2252 2253 irqs = vop2_readl(vop2, RK3568_VP_INT_STATUS(vp->id)); 2254 vop2_writel(vop2, RK3568_VP_INT_CLR(vp->id), irqs << 16 | irqs); 2255 2256 if (irqs & VP_INT_DSP_HOLD_VALID) { 2257 complete(&vp->dsp_hold_completion); 2258 ret = IRQ_HANDLED; 2259 } 2260 2261 if (irqs & VP_INT_FS_FIELD) { 2262 drm_crtc_handle_vblank(crtc); 2263 spin_lock(&crtc->dev->event_lock); 2264 if (vp->event) { 2265 u32 val = vop2_readl(vop2, RK3568_REG_CFG_DONE); 2266 2267 if (!(val & BIT(vp->id))) { 2268 drm_crtc_send_vblank_event(crtc, vp->event); 2269 vp->event = NULL; 2270 drm_crtc_vblank_put(crtc); 2271 } 2272 } 2273 spin_unlock(&crtc->dev->event_lock); 2274 2275 ret = IRQ_HANDLED; 2276 } 2277 2278 if (irqs & VP_INT_POST_BUF_EMPTY) { 2279 drm_err_ratelimited(vop2->drm, 2280 "POST_BUF_EMPTY irq err at vp%d\n", 2281 vp->id); 2282 ret = IRQ_HANDLED; 2283 } 2284 } 2285 } 2286 2287 axi_irqs[0] = vop2_readl(vop2, RK3568_SYS0_INT_STATUS); 2288 vop2_writel(vop2, RK3568_SYS0_INT_CLR, axi_irqs[0] << 16 | axi_irqs[0]); 2289 axi_irqs[1] = vop2_readl(vop2, RK3568_SYS1_INT_STATUS); 2290 vop2_writel(vop2, RK3568_SYS1_INT_CLR, axi_irqs[1] << 16 | axi_irqs[1]); 2291 2292 for (i = 0; i < ARRAY_SIZE(axi_irqs); i++) { 2293 if (axi_irqs[i] & VOP2_INT_BUS_ERRPR) { 2294 drm_err_ratelimited(vop2->drm, "BUS_ERROR irq err\n"); 2295 ret = IRQ_HANDLED; 2296 } 2297 } 2298 2299 pm_runtime_put(vop2->dev); 2300 2301 return ret; 2302 } 2303 2304 static int vop2_plane_init(struct vop2 *vop2, struct vop2_win *win, 2305 unsigned long possible_crtcs) 2306 { 2307 const struct vop2_win_data *win_data = win->data; 2308 unsigned int blend_caps = BIT(DRM_MODE_BLEND_PIXEL_NONE) | 2309 BIT(DRM_MODE_BLEND_PREMULTI) | 2310 BIT(DRM_MODE_BLEND_COVERAGE); 2311 int ret; 2312 2313 ret = drm_universal_plane_init(vop2->drm, &win->base, possible_crtcs, 2314 &vop2_plane_funcs, win_data->formats, 2315 win_data->nformats, 2316 win_data->format_modifiers, 2317 win->type, win_data->name); 2318 if (ret) { 2319 drm_err(vop2->drm, "failed to initialize plane %d\n", ret); 2320 return ret; 2321 } 2322 2323 drm_plane_helper_add(&win->base, &vop2_plane_helper_funcs); 2324 2325 if (win->data->supported_rotations) 2326 drm_plane_create_rotation_property(&win->base, DRM_MODE_ROTATE_0, 2327 DRM_MODE_ROTATE_0 | 2328 win->data->supported_rotations); 2329 drm_plane_create_alpha_property(&win->base); 2330 drm_plane_create_blend_mode_property(&win->base, blend_caps); 2331 drm_plane_create_zpos_property(&win->base, win->win_id, 0, 2332 vop2->registered_num_wins - 1); 2333 2334 return 0; 2335 } 2336 2337 /* 2338 * On RK3566 these windows don't have an independent 2339 * framebuffer. They can only share/mirror the framebuffer 2340 * with smart0, esmart0 and cluster0 respectively. 2341 * And RK3566 share the same vop version with Rk3568, so we 2342 * need to use soc_id for identification here. 2343 */ 2344 static bool vop2_is_mirror_win(struct vop2_win *win) 2345 { 2346 struct vop2 *vop2 = win->vop2; 2347 2348 if (vop2->data->soc_id == 3566) { 2349 switch (win->data->phys_id) { 2350 case ROCKCHIP_VOP2_SMART1: 2351 case ROCKCHIP_VOP2_ESMART1: 2352 case ROCKCHIP_VOP2_CLUSTER1: 2353 return true; 2354 default: 2355 return false; 2356 } 2357 } else { 2358 return false; 2359 } 2360 } 2361 2362 static int vop2_create_crtcs(struct vop2 *vop2) 2363 { 2364 const struct vop2_data *vop2_data = vop2->data; 2365 struct drm_device *drm = vop2->drm; 2366 struct device *dev = vop2->dev; 2367 struct drm_plane *plane; 2368 struct device_node *port; 2369 struct vop2_video_port *vp; 2370 struct vop2_win *win; 2371 u32 possible_crtcs; 2372 int i, j, nvp, nvps = 0; 2373 int ret; 2374 2375 for (i = 0; i < vop2_data->nr_vps; i++) { 2376 const struct vop2_video_port_data *vp_data; 2377 struct device_node *np; 2378 char dclk_name[9]; 2379 2380 vp_data = &vop2_data->vp[i]; 2381 vp = &vop2->vps[i]; 2382 vp->vop2 = vop2; 2383 vp->id = vp_data->id; 2384 vp->data = vp_data; 2385 2386 snprintf(dclk_name, sizeof(dclk_name), "dclk_vp%d", vp->id); 2387 vp->dclk = devm_clk_get(vop2->dev, dclk_name); 2388 if (IS_ERR(vp->dclk)) 2389 return dev_err_probe(drm->dev, PTR_ERR(vp->dclk), 2390 "failed to get %s\n", dclk_name); 2391 2392 np = of_graph_get_remote_node(dev->of_node, i, -1); 2393 if (!np) { 2394 drm_dbg(vop2->drm, "%s: No remote for vp%d\n", __func__, i); 2395 continue; 2396 } 2397 of_node_put(np); 2398 2399 port = of_graph_get_port_by_id(dev->of_node, i); 2400 if (!port) 2401 return dev_err_probe(drm->dev, -ENOENT, 2402 "no port node found for video_port%d\n", i); 2403 vp->crtc.port = port; 2404 nvps++; 2405 } 2406 2407 nvp = 0; 2408 /* Register a primary plane for every crtc */ 2409 for (i = 0; i < vop2_data->nr_vps; i++) { 2410 vp = &vop2->vps[i]; 2411 2412 if (!vp->crtc.port) 2413 continue; 2414 2415 for (j = 0; j < vop2->registered_num_wins; j++) { 2416 win = &vop2->win[j]; 2417 2418 /* Aready registered as primary plane */ 2419 if (win->base.type == DRM_PLANE_TYPE_PRIMARY) 2420 continue; 2421 2422 /* If this win can not attached to this VP */ 2423 if (!(win->data->possible_vp_mask & BIT(vp->id))) 2424 continue; 2425 2426 if (vop2_is_mirror_win(win)) 2427 continue; 2428 2429 if (win->type == DRM_PLANE_TYPE_PRIMARY) { 2430 possible_crtcs = BIT(nvp); 2431 vp->primary_plane = win; 2432 ret = vop2_plane_init(vop2, win, possible_crtcs); 2433 if (ret) 2434 return dev_err_probe(drm->dev, ret, 2435 "failed to init primary plane %s\n", 2436 win->data->name); 2437 nvp++; 2438 break; 2439 } 2440 } 2441 2442 if (!vp->primary_plane) 2443 return dev_err_probe(drm->dev, -ENOENT, 2444 "no primary plane for vp %d\n", i); 2445 } 2446 2447 /* Register all unused window as overlay plane */ 2448 for (i = 0; i < vop2->registered_num_wins; i++) { 2449 win = &vop2->win[i]; 2450 2451 /* Aready registered as primary plane */ 2452 if (win->base.type == DRM_PLANE_TYPE_PRIMARY) 2453 continue; 2454 2455 if (vop2_is_mirror_win(win)) 2456 continue; 2457 2458 win->type = DRM_PLANE_TYPE_OVERLAY; 2459 2460 possible_crtcs = 0; 2461 nvp = 0; 2462 for (j = 0; j < vop2_data->nr_vps; j++) { 2463 vp = &vop2->vps[j]; 2464 2465 if (!vp->crtc.port) 2466 continue; 2467 2468 if (win->data->possible_vp_mask & BIT(vp->id)) 2469 possible_crtcs |= BIT(nvp); 2470 nvp++; 2471 } 2472 2473 ret = vop2_plane_init(vop2, win, possible_crtcs); 2474 if (ret) 2475 return dev_err_probe(drm->dev, ret, "failed to init overlay plane %s\n", 2476 win->data->name); 2477 } 2478 2479 for (i = 0; i < vop2_data->nr_vps; i++) { 2480 vp = &vop2->vps[i]; 2481 2482 if (!vp->crtc.port) 2483 continue; 2484 2485 plane = &vp->primary_plane->base; 2486 2487 ret = drm_crtc_init_with_planes(drm, &vp->crtc, plane, NULL, 2488 &vop2_crtc_funcs, 2489 "video_port%d", vp->id); 2490 if (ret) 2491 return dev_err_probe(drm->dev, ret, 2492 "crtc init for video_port%d failed\n", i); 2493 2494 drm_crtc_attach_background_color_property(&vp->crtc); 2495 2496 drm_crtc_helper_add(&vp->crtc, &vop2_crtc_helper_funcs); 2497 if (vop2->lut_regs) { 2498 const struct vop2_video_port_data *vp_data = &vop2_data->vp[vp->id]; 2499 2500 drm_mode_crtc_set_gamma_size(&vp->crtc, vp_data->gamma_lut_len); 2501 drm_crtc_enable_color_mgmt(&vp->crtc, 0, false, vp_data->gamma_lut_len); 2502 } 2503 init_completion(&vp->dsp_hold_completion); 2504 } 2505 2506 /* 2507 * On the VOP2 it's very hard to change the number of layers on a VP 2508 * during runtime, so we distribute the layers equally over the used 2509 * VPs 2510 */ 2511 for (i = 0; i < vop2->data->nr_vps; i++) { 2512 struct vop2_video_port *vp = &vop2->vps[i]; 2513 2514 if (vp->crtc.port) 2515 vp->nlayers = vop2_data->win_size / nvps; 2516 } 2517 2518 return 0; 2519 } 2520 2521 static void vop2_destroy_crtcs(struct vop2 *vop2) 2522 { 2523 struct drm_device *drm = vop2->drm; 2524 struct list_head *crtc_list = &drm->mode_config.crtc_list; 2525 struct list_head *plane_list = &drm->mode_config.plane_list; 2526 struct drm_crtc *crtc, *tmpc; 2527 struct drm_plane *plane, *tmpp; 2528 2529 list_for_each_entry_safe(plane, tmpp, plane_list, head) 2530 drm_plane_cleanup(plane); 2531 2532 /* 2533 * Destroy CRTC after vop2_plane_destroy() since vop2_disable_plane() 2534 * references the CRTC. 2535 */ 2536 list_for_each_entry_safe(crtc, tmpc, crtc_list, head) { 2537 of_node_put(crtc->port); 2538 drm_crtc_cleanup(crtc); 2539 } 2540 } 2541 2542 static int vop2_find_rgb_encoder(struct vop2 *vop2) 2543 { 2544 struct device_node *node = vop2->dev->of_node; 2545 struct device_node *endpoint; 2546 int i; 2547 2548 for (i = 0; i < vop2->data->nr_vps; i++) { 2549 endpoint = of_graph_get_endpoint_by_regs(node, i, 2550 ROCKCHIP_VOP2_EP_RGB0); 2551 if (!endpoint) 2552 continue; 2553 2554 of_node_put(endpoint); 2555 return i; 2556 } 2557 2558 return -ENOENT; 2559 } 2560 2561 static int vop2_regmap_init(struct vop2_win *win, const struct reg_field *regs, 2562 int nr_regs) 2563 { 2564 struct vop2 *vop2 = win->vop2; 2565 int i; 2566 2567 for (i = 0; i < nr_regs; i++) { 2568 const struct reg_field field = { 2569 .reg = (regs[i].reg != 0xffffffff) ? 2570 regs[i].reg + win->offset : regs[i].reg, 2571 .lsb = regs[i].lsb, 2572 .msb = regs[i].msb 2573 }; 2574 2575 win->reg[i] = devm_regmap_field_alloc(vop2->dev, vop2->map, field); 2576 if (IS_ERR(win->reg[i])) 2577 return PTR_ERR(win->reg[i]); 2578 } 2579 2580 return 0; 2581 }; 2582 2583 static int vop2_win_init(struct vop2 *vop2) 2584 { 2585 const struct vop2_data *vop2_data = vop2->data; 2586 struct vop2_win *win; 2587 int i, ret; 2588 2589 for (i = 0; i < vop2_data->win_size; i++) { 2590 const struct vop2_win_data *win_data = &vop2_data->win[i]; 2591 2592 win = &vop2->win[i]; 2593 win->data = win_data; 2594 win->type = win_data->type; 2595 win->offset = win_data->base; 2596 win->win_id = i; 2597 win->vop2 = vop2; 2598 if (vop2_cluster_window(win)) 2599 ret = vop2_regmap_init(win, vop2->data->cluster_reg, 2600 vop2->data->nr_cluster_regs); 2601 else 2602 ret = vop2_regmap_init(win, vop2->data->smart_reg, 2603 vop2->data->nr_smart_regs); 2604 if (ret) 2605 return ret; 2606 } 2607 2608 vop2->registered_num_wins = vop2_data->win_size; 2609 2610 return 0; 2611 } 2612 2613 /* 2614 * The window and video port registers are only updated when config 2615 * done is written. Until that they read back the old value. As we 2616 * read-modify-write these registers mark them as non-volatile. This 2617 * makes sure we read the new values from the regmap register cache. 2618 */ 2619 static const struct regmap_range vop2_nonvolatile_range[] = { 2620 regmap_reg_range(RK3568_VP0_CTRL_BASE, RK3588_VP3_CTRL_BASE + 255), 2621 regmap_reg_range(0x1000, 0x23ff), 2622 }; 2623 2624 static const struct regmap_access_table vop2_volatile_table = { 2625 .no_ranges = vop2_nonvolatile_range, 2626 .n_no_ranges = ARRAY_SIZE(vop2_nonvolatile_range), 2627 }; 2628 2629 static const struct regmap_config vop2_regmap_config = { 2630 .reg_bits = 32, 2631 .val_bits = 32, 2632 .reg_stride = 4, 2633 .max_register = 0x3000, 2634 .name = "vop2", 2635 .volatile_table = &vop2_volatile_table, 2636 .cache_type = REGCACHE_MAPLE, 2637 }; 2638 2639 static int vop2_bind(struct device *dev, struct device *master, void *data) 2640 { 2641 struct platform_device *pdev = to_platform_device(dev); 2642 const struct vop2_data *vop2_data; 2643 struct drm_device *drm = data; 2644 struct vop2 *vop2; 2645 struct resource *res; 2646 size_t alloc_size; 2647 int ret; 2648 2649 vop2_data = of_device_get_match_data(dev); 2650 if (!vop2_data) 2651 return -ENODEV; 2652 2653 /* Allocate vop2 struct and its vop2_win array */ 2654 alloc_size = struct_size(vop2, win, vop2_data->win_size); 2655 vop2 = devm_kzalloc(dev, alloc_size, GFP_KERNEL); 2656 if (!vop2) 2657 return -ENOMEM; 2658 2659 vop2->dev = dev; 2660 vop2->data = vop2_data; 2661 vop2->ops = vop2_data->ops; 2662 vop2->version = vop2_data->version; 2663 vop2->drm = drm; 2664 2665 dev_set_drvdata(dev, vop2); 2666 2667 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vop"); 2668 if (!res) 2669 return dev_err_probe(drm->dev, -EINVAL, 2670 "failed to get vop2 register byname\n"); 2671 2672 vop2->res = res; 2673 vop2->regs = devm_ioremap_resource(dev, res); 2674 if (IS_ERR(vop2->regs)) 2675 return PTR_ERR(vop2->regs); 2676 vop2->len = resource_size(res); 2677 2678 vop2->map = devm_regmap_init_mmio(dev, vop2->regs, &vop2_regmap_config); 2679 if (IS_ERR(vop2->map)) 2680 return PTR_ERR(vop2->map); 2681 2682 /* Set the bounds for framebuffer creation */ 2683 drm->mode_config.min_width = 4; 2684 drm->mode_config.min_height = 4; 2685 drm->mode_config.max_width = vop2_data->max_input.width; 2686 drm->mode_config.max_height = vop2_data->max_input.height; 2687 2688 ret = vop2_win_init(vop2); 2689 if (ret) 2690 return ret; 2691 2692 res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "gamma-lut"); 2693 if (res) { 2694 vop2->lut_regs = devm_ioremap_resource(dev, res); 2695 if (IS_ERR(vop2->lut_regs)) 2696 return PTR_ERR(vop2->lut_regs); 2697 } 2698 if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_GRF) { 2699 vop2->sys_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,grf"); 2700 if (IS_ERR(vop2->sys_grf)) 2701 return dev_err_probe(drm->dev, PTR_ERR(vop2->sys_grf), 2702 "cannot get sys_grf\n"); 2703 } 2704 2705 if (vop2_data->feature & VOP2_FEATURE_HAS_VOP_GRF) { 2706 vop2->vop_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vop-grf"); 2707 if (IS_ERR(vop2->vop_grf)) 2708 return dev_err_probe(drm->dev, PTR_ERR(vop2->vop_grf), 2709 "cannot get vop_grf\n"); 2710 } 2711 2712 if (vop2_data->feature & VOP2_FEATURE_HAS_VO1_GRF) { 2713 vop2->vo1_grf = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,vo1-grf"); 2714 if (IS_ERR(vop2->vo1_grf)) 2715 return dev_err_probe(drm->dev, PTR_ERR(vop2->vo1_grf), 2716 "cannot get vo1_grf\n"); 2717 } 2718 2719 if (vop2_data->feature & VOP2_FEATURE_HAS_SYS_PMU) { 2720 vop2->sys_pmu = syscon_regmap_lookup_by_phandle(dev->of_node, "rockchip,pmu"); 2721 if (IS_ERR(vop2->sys_pmu)) 2722 return dev_err_probe(drm->dev, PTR_ERR(vop2->sys_pmu), 2723 "cannot get sys_pmu\n"); 2724 } 2725 2726 vop2->hclk = devm_clk_get(vop2->dev, "hclk"); 2727 if (IS_ERR(vop2->hclk)) 2728 return dev_err_probe(drm->dev, PTR_ERR(vop2->hclk), 2729 "failed to get hclk source\n"); 2730 2731 vop2->aclk = devm_clk_get(vop2->dev, "aclk"); 2732 if (IS_ERR(vop2->aclk)) 2733 return dev_err_probe(drm->dev, PTR_ERR(vop2->aclk), 2734 "failed to get aclk source\n"); 2735 2736 vop2->pclk = devm_clk_get_optional(vop2->dev, "pclk_vop"); 2737 if (IS_ERR(vop2->pclk)) 2738 return dev_err_probe(drm->dev, PTR_ERR(vop2->pclk), 2739 "failed to get pclk source\n"); 2740 2741 vop2->pll_hdmiphy0 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy0"); 2742 if (IS_ERR(vop2->pll_hdmiphy0)) 2743 return dev_err_probe(drm->dev, PTR_ERR(vop2->pll_hdmiphy0), 2744 "failed to get pll_hdmiphy0\n"); 2745 2746 vop2->pll_hdmiphy1 = devm_clk_get_optional(vop2->dev, "pll_hdmiphy1"); 2747 if (IS_ERR(vop2->pll_hdmiphy1)) 2748 return dev_err_probe(drm->dev, PTR_ERR(vop2->pll_hdmiphy1), 2749 "failed to get pll_hdmiphy1\n"); 2750 2751 vop2->irq = platform_get_irq(pdev, 0); 2752 if (vop2->irq < 0) 2753 return dev_err_probe(drm->dev, vop2->irq, "cannot find irq for vop2\n"); 2754 2755 mutex_init(&vop2->vop2_lock); 2756 mutex_init(&vop2->ovl_lock); 2757 2758 ret = devm_request_irq(dev, vop2->irq, vop2_isr, IRQF_SHARED, dev_name(dev), vop2); 2759 if (ret) 2760 return ret; 2761 2762 ret = vop2_create_crtcs(vop2); 2763 if (ret) 2764 return ret; 2765 2766 if (vop2->version >= VOP_VERSION_RK3576) { 2767 struct drm_crtc *crtc; 2768 2769 drm_for_each_crtc(crtc, drm) { 2770 struct vop2_video_port *vp = to_vop2_video_port(crtc); 2771 int vp_irq; 2772 const char *irq_name = devm_kasprintf(dev, GFP_KERNEL, "vp%d", vp->id); 2773 2774 if (!irq_name) 2775 return -ENOMEM; 2776 2777 vp_irq = platform_get_irq_byname(pdev, irq_name); 2778 if (vp_irq < 0) 2779 return dev_err_probe(drm->dev, vp_irq, 2780 "cannot find irq for vop2 vp%d\n", vp->id); 2781 2782 ret = devm_request_irq(dev, vp_irq, rk3576_vp_isr, IRQF_SHARED, irq_name, 2783 vp); 2784 if (ret) 2785 dev_err_probe(drm->dev, ret, 2786 "request irq for vop2 vp%d failed\n", vp->id); 2787 } 2788 } 2789 2790 ret = vop2_find_rgb_encoder(vop2); 2791 if (ret >= 0) { 2792 vop2->rgb = rockchip_rgb_init(dev, &vop2->vps[ret].crtc, 2793 vop2->drm, ret); 2794 if (IS_ERR(vop2->rgb)) { 2795 if (PTR_ERR(vop2->rgb) == -EPROBE_DEFER) { 2796 ret = PTR_ERR(vop2->rgb); 2797 goto err_crtcs; 2798 } 2799 vop2->rgb = NULL; 2800 } 2801 } 2802 2803 rockchip_drm_dma_init_device(vop2->drm, vop2->dev); 2804 2805 pm_runtime_enable(&pdev->dev); 2806 2807 return 0; 2808 2809 err_crtcs: 2810 vop2_destroy_crtcs(vop2); 2811 2812 return ret; 2813 } 2814 2815 static void vop2_unbind(struct device *dev, struct device *master, void *data) 2816 { 2817 struct vop2 *vop2 = dev_get_drvdata(dev); 2818 2819 pm_runtime_disable(dev); 2820 2821 if (vop2->rgb) 2822 rockchip_rgb_fini(vop2->rgb); 2823 2824 vop2_destroy_crtcs(vop2); 2825 } 2826 2827 const struct component_ops vop2_component_ops = { 2828 .bind = vop2_bind, 2829 .unbind = vop2_unbind, 2830 }; 2831 EXPORT_SYMBOL_GPL(vop2_component_ops); 2832