1/* 2 * Copyright © 2007 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Dave Airlie <airlied@redhat.com> 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include <errno.h> 33#include <sys/ioctl.h> 34#include <time.h> 35#include "cursorstr.h" 36#include "damagestr.h" 37#include "inputstr.h" 38#include "list.h" 39#include "micmap.h" 40#include "mipointrst.h" 41#include "xf86cmap.h" 42#include "xf86Priv.h" 43#include <xf86drm.h> 44 45#include "drmmode_display.h" 46#include "amdgpu_bo_helper.h" 47#include "amdgpu_glamor.h" 48#include "amdgpu_pixmap.h" 49 50/* DPMS */ 51#ifdef HAVE_XEXTPROTO_71 52#include <X11/extensions/dpmsconst.h> 53#else 54#define DPMS_SERVER 55#include <X11/extensions/dpms.h> 56#endif 57 58#include <gbm.h> 59 60#define DEFAULT_NOMINAL_FRAME_RATE 60 61 62static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height); 63 64static Bool 65AMDGPUZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name) 66{ 67 int i = 0; 68 char s1[20]; 69 70 do { 71 switch (*s) { 72 case ',': 73 s1[i] = '\0'; 74 i = 0; 75 if (strcmp(s1, output_name) == 0) 76 return TRUE; 77 break; 78 case ' ': 79 case '\t': 80 case '\n': 81 case '\r': 82 break; 83 default: 84 s1[i] = *s; 85 i++; 86 break; 87 } 88 } while (*s++); 89 90 s1[i] = '\0'; 91 if (strcmp(s1, output_name) == 0) 92 return TRUE; 93 94 return FALSE; 95} 96 97 98static void 99drmmode_ConvertFromKMode(ScrnInfoPtr scrn, 100 drmModeModeInfo * kmode, DisplayModePtr mode) 101{ 102 memset(mode, 0, sizeof(DisplayModeRec)); 103 mode->status = MODE_OK; 104 105 mode->Clock = kmode->clock; 106 107 mode->HDisplay = kmode->hdisplay; 108 mode->HSyncStart = kmode->hsync_start; 109 mode->HSyncEnd = kmode->hsync_end; 110 mode->HTotal = kmode->htotal; 111 mode->HSkew = kmode->hskew; 112 113 mode->VDisplay = kmode->vdisplay; 114 mode->VSyncStart = kmode->vsync_start; 115 mode->VSyncEnd = kmode->vsync_end; 116 mode->VTotal = kmode->vtotal; 117 mode->VScan = kmode->vscan; 118 119 mode->Flags = kmode->flags; //& FLAG_BITS; 120 mode->name = strdup(kmode->name); 121 122 if (kmode->type & DRM_MODE_TYPE_DRIVER) 123 mode->type = M_T_DRIVER; 124 if (kmode->type & DRM_MODE_TYPE_PREFERRED) 125 mode->type |= M_T_PREFERRED; 126 xf86SetModeCrtc(mode, scrn->adjustFlags); 127} 128 129static void 130drmmode_ConvertToKMode(ScrnInfoPtr scrn, 131 drmModeModeInfo * kmode, DisplayModePtr mode) 132{ 133 memset(kmode, 0, sizeof(*kmode)); 134 135 kmode->clock = mode->Clock; 136 kmode->hdisplay = mode->HDisplay; 137 kmode->hsync_start = mode->HSyncStart; 138 kmode->hsync_end = mode->HSyncEnd; 139 kmode->htotal = mode->HTotal; 140 kmode->hskew = mode->HSkew; 141 142 kmode->vdisplay = mode->VDisplay; 143 kmode->vsync_start = mode->VSyncStart; 144 kmode->vsync_end = mode->VSyncEnd; 145 kmode->vtotal = mode->VTotal; 146 kmode->vscan = mode->VScan; 147 148 kmode->flags = mode->Flags; //& FLAG_BITS; 149 if (mode->name) 150 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 151 kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0; 152 153} 154 155/* 156 * Utility helper for drmWaitVBlank 157 */ 158Bool 159drmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type, 160 uint32_t target_seq, unsigned long signal, uint64_t *ust, 161 uint32_t *result_seq) 162{ 163 int crtc_id = drmmode_get_crtc_id(crtc); 164 ScrnInfoPtr scrn = crtc->scrn; 165 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 166 drmVBlank vbl; 167 168 if (crtc_id == 1) 169 type |= DRM_VBLANK_SECONDARY; 170 else if (crtc_id > 1) 171 type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) & 172 DRM_VBLANK_HIGH_CRTC_MASK; 173 174 vbl.request.type = type; 175 vbl.request.sequence = target_seq; 176 vbl.request.signal = signal; 177 178 if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl) != 0) 179 return FALSE; 180 181 if (ust) 182 *ust = (uint64_t)vbl.reply.tval_sec * 1000000 + 183 vbl.reply.tval_usec; 184 if (result_seq) 185 *result_seq = vbl.reply.sequence; 186 187 return TRUE; 188} 189 190/* 191 * Retrieves present time in microseconds that is compatible 192 * with units used by vblank timestamps. Depending on the kernel 193 * version and DRM kernel module configuration, the vblank 194 * timestamp can either be in real time or monotonic time 195 */ 196int drmmode_get_current_ust(int drm_fd, CARD64 * ust) 197{ 198 uint64_t cap_value; 199 int ret; 200 struct timespec now; 201 202 ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 203 if (ret || !cap_value) 204 /* old kernel or drm_timestamp_monotonic turned off */ 205 ret = clock_gettime(CLOCK_REALTIME, &now); 206 else 207 ret = clock_gettime(CLOCK_MONOTONIC, &now); 208 if (ret) 209 return ret; 210 *ust = ((CARD64) now.tv_sec * 1000000) + ((CARD64) now.tv_nsec / 1000); 211 return 0; 212} 213 214/* 215 * Get current frame count and frame count timestamp of the crtc. 216 */ 217int drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 218{ 219 ScrnInfoPtr scrn = crtc->scrn; 220 uint32_t seq; 221 222 if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) { 223 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 224 "get vblank counter failed: %s\n", strerror(errno)); 225 return -1; 226 } 227 228 *msc = seq; 229 230 return Success; 231} 232 233static uint32_t 234drmmode_crtc_get_prop_id(uint32_t drm_fd, 235 drmModeObjectPropertiesPtr props, 236 char const* name) 237{ 238 uint32_t i, prop_id = 0; 239 240 for (i = 0; !prop_id && i < props->count_props; ++i) { 241 drmModePropertyPtr drm_prop = 242 drmModeGetProperty(drm_fd, props->props[i]); 243 244 if (!drm_prop) 245 continue; 246 247 if (strcmp(drm_prop->name, name) == 0) 248 prop_id = drm_prop->prop_id; 249 250 drmModeFreeProperty(drm_prop); 251 } 252 253 return prop_id; 254} 255 256static void drmmode_crtc_vrr_init(int drm_fd, xf86CrtcPtr crtc) 257{ 258 drmModeObjectPropertiesPtr drm_props; 259 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 260 drmmode_ptr drmmode = drmmode_crtc->drmmode; 261 262 if (drmmode->vrr_prop_id) 263 return; 264 265 drm_props = drmModeObjectGetProperties(drm_fd, 266 drmmode_crtc->mode_crtc->crtc_id, 267 DRM_MODE_OBJECT_CRTC); 268 269 if (!drm_props) 270 return; 271 272 drmmode->vrr_prop_id = drmmode_crtc_get_prop_id(drm_fd, 273 drm_props, 274 "VRR_ENABLED"); 275 276 drmModeFreeObjectProperties(drm_props); 277} 278 279void drmmode_crtc_set_vrr(xf86CrtcPtr crtc, Bool enabled) 280{ 281 ScrnInfoPtr pScrn = crtc->scrn; 282 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 283 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 284 drmmode_ptr drmmode = drmmode_crtc->drmmode; 285 286 if (drmmode->vrr_prop_id && 287 drmmode_crtc->vrr_enabled != enabled && 288 drmModeObjectSetProperty(pAMDGPUEnt->fd, 289 drmmode_crtc->mode_crtc->crtc_id, 290 DRM_MODE_OBJECT_CRTC, 291 drmmode->vrr_prop_id, 292 enabled) == 0) 293 drmmode_crtc->vrr_enabled = enabled; 294} 295 296static void 297drmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 298{ 299 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 300 ScrnInfoPtr scrn = crtc->scrn; 301 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 302 CARD64 ust; 303 int ret; 304 305 if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 306 uint32_t seq; 307 308 amdgpu_drm_wait_pending_flip(crtc); 309 310 /* 311 * On->Off transition: record the last vblank time, 312 * sequence number and frame period. 313 */ 314 if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust, 315 &seq)) 316 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 317 "%s cannot get last vblank counter\n", 318 __func__); 319 else { 320 CARD64 nominal_frame_rate, pix_in_frame; 321 322 drmmode_crtc->dpms_last_ust = ust; 323 drmmode_crtc->dpms_last_seq = seq; 324 nominal_frame_rate = crtc->mode.Clock; 325 nominal_frame_rate *= 1000; 326 pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 327 if (nominal_frame_rate == 0 || pix_in_frame == 0) 328 nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 329 else 330 nominal_frame_rate /= pix_in_frame; 331 drmmode_crtc->dpms_last_fps = nominal_frame_rate; 332 } 333 334 drmmode_crtc->dpms_mode = mode; 335 amdgpu_drm_queue_handle_deferred(crtc); 336 } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 337 /* 338 * Off->On transition: calculate and accumulate the 339 * number of interpolated vblanks while we were in Off state 340 */ 341 ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust); 342 if (ret) 343 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 344 "%s cannot get current time\n", __func__); 345 else if (drmmode_crtc->dpms_last_ust) { 346 CARD64 time_elapsed, delta_seq; 347 time_elapsed = ust - drmmode_crtc->dpms_last_ust; 348 delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 349 delta_seq /= 1000000; 350 drmmode_crtc->interpolated_vblanks += delta_seq; 351 352 } 353 354 drmmode_crtc->dpms_mode = DPMSModeOn; 355 } 356} 357 358static void 359drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 360{ 361 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 362 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 363 364 /* Disable unused CRTCs and enable/disable active CRTCs */ 365 if (!crtc->enabled || mode != DPMSModeOn) { 366 drmmode_do_crtc_dpms(crtc, DPMSModeOff); 367 drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 368 0, 0, 0, NULL, 0, NULL); 369 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 370 } else if (drmmode_crtc->dpms_mode != DPMSModeOn) 371 crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 372 crtc->x, crtc->y); 373} 374 375#ifdef USE_GLAMOR 376 377static PixmapPtr 378create_pixmap_for_fbcon(drmmode_ptr drmmode, 379 ScrnInfoPtr pScrn, int fbcon_id) 380{ 381 ScreenPtr pScreen = pScrn->pScreen; 382 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 383 PixmapPtr pixmap = NULL; 384 drmModeFBPtr fbcon; 385 386 fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id); 387 if (!fbcon) 388 return NULL; 389 390 if (fbcon->depth != pScrn->depth || 391 fbcon->width != pScrn->virtualX || 392 fbcon->height != pScrn->virtualY) 393 goto out_free_fb; 394 395 pixmap = fbCreatePixmap(pScreen, 0, 0, fbcon->depth, 0); 396 if (!pixmap) 397 goto out_free_fb; 398 399 pScreen->ModifyPixmapHeader(pixmap, fbcon->width, fbcon->height, 0, 0, 400 fbcon->pitch, NULL); 401 pixmap->devPrivate.ptr = NULL; 402 403 if (!glamor_egl_create_textured_pixmap(pixmap, fbcon->handle, 404 pixmap->devKind)) { 405 pScreen->DestroyPixmap(pixmap); 406 pixmap = NULL; 407 } 408 409out_free_fb: 410 drmModeFreeFB(fbcon); 411 return pixmap; 412} 413 414#endif /* USE_GLAMOR */ 415 416void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 417{ 418#ifdef USE_GLAMOR 419 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 420 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 421 ScreenPtr pScreen = pScrn->pScreen; 422 PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen); 423 struct drmmode_fb *fb = amdgpu_pixmap_get_fb(dst); 424 int fbcon_id = 0; 425 GCPtr gc; 426 int i; 427 428 if (!info->use_glamor) 429 return; 430 431 for (i = 0; i < xf86_config->num_crtc; i++) { 432 drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 433 434 if (drmmode_crtc->mode_crtc->buffer_id) 435 fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 436 } 437 438 if (!fbcon_id) 439 return; 440 441 if (fbcon_id == fb->handle) { 442 /* in some rare case there might be no fbcon and we might already 443 * be the one with the current fb to avoid a false deadlck in 444 * kernel ttm code just do nothing as anyway there is nothing 445 * to do 446 */ 447 return; 448 } 449 450 src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 451 if (!src) 452 return; 453 454 gc = GetScratchGC(pScrn->depth, pScreen); 455 ValidateGC(&dst->drawable, gc); 456 457 (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, 458 pScrn->virtualX, pScrn->virtualY, 0, 0); 459 460 FreeScratchGC(gc); 461 462 pScreen->canDoBGNoneRoot = TRUE; 463 pScreen->DestroyPixmap(src); 464#endif 465 466 return; 467} 468 469void 470drmmode_crtc_scanout_free(xf86CrtcPtr crtc) 471{ 472 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 473 474 if (drmmode_crtc->scanout_update_pending) { 475 amdgpu_drm_wait_pending_flip(crtc); 476 amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 477 drmmode_crtc->scanout_update_pending = 0; 478 amdgpu_drm_queue_handle_deferred(crtc); 479 } 480 481 drmmode_crtc_scanout_destroy(&drmmode_crtc->scanout[0]); 482 drmmode_crtc_scanout_destroy(&drmmode_crtc->scanout[1]); 483 484 if (drmmode_crtc->scanout_damage) 485 DamageDestroy(drmmode_crtc->scanout_damage); 486} 487 488static Bool 489drmmode_crtc_scanout_create(xf86CrtcPtr crtc, PixmapPtr *scanout, 490 int width, int height) 491{ 492 ScrnInfoPtr pScrn = crtc->scrn; 493 ScreenPtr screen = pScrn->pScreen; 494 495 if (*scanout) { 496 if ((*scanout)->drawable.width == width && 497 (*scanout)->drawable.height == height) 498 return TRUE; 499 500 drmmode_crtc_scanout_destroy(scanout); 501 } 502 503 *scanout = screen->CreatePixmap(screen, width, height, pScrn->depth, 504 AMDGPU_CREATE_PIXMAP_SCANOUT); 505 if (!*scanout) { 506 ErrorF("failed to create CRTC scanout pixmap\n"); 507 goto error; 508 } 509 510 if (!amdgpu_pixmap_get_fb(*scanout)) { 511 ErrorF("failed to create CRTC scanout FB\n"); 512error: 513 drmmode_crtc_scanout_destroy(scanout); 514 return FALSE; 515 } 516 517 return TRUE; 518} 519 520static void 521amdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 522{ 523 drmmode_crtc_private_ptr drmmode_crtc = closure; 524 525 if (drmmode_crtc->ignore_damage) { 526 RegionEmpty(&damage->damage); 527 drmmode_crtc->ignore_damage = FALSE; 528 return; 529 } 530 531 /* Only keep track of the extents */ 532 RegionUninit(&damage->damage); 533 damage->damage.data = NULL; 534} 535 536static void 537drmmode_screen_damage_destroy(DamagePtr damage, void *closure) 538{ 539 drmmode_crtc_private_ptr drmmode_crtc = closure; 540 541 drmmode_crtc->scanout_damage = NULL; 542 RegionUninit(&drmmode_crtc->scanout_last_region); 543} 544 545static Bool 546drmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 547{ 548 AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 549 550 /* Check for Option "SWcursor" */ 551 if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 552 return FALSE; 553 554 /* Fall back to SW cursor if the CRTC is transformed */ 555 if (crtc->transformPresent) 556 return FALSE; 557 558#if XF86_CRTC_VERSION < 7 559 /* Xorg doesn't correctly handle cursor position transform in the 560 * rotation case 561 */ 562 if (crtc->driverIsPerformingTransform && 563 (crtc->rotation & 0xf) != RR_Rotate_0) 564 return FALSE; 565#endif 566 567 /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 568 if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 569 !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 570 return FALSE; 571 572 return TRUE; 573} 574 575static void 576drmmode_crtc_update_tear_free(xf86CrtcPtr crtc) 577{ 578 AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 579 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 580 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 581 int i; 582 583 drmmode_crtc->tear_free = FALSE; 584 585 for (i = 0; i < xf86_config->num_output; i++) { 586 xf86OutputPtr output = xf86_config->output[i]; 587 drmmode_output_private_ptr drmmode_output = output->driver_private; 588 589 if (output->crtc != crtc) 590 continue; 591 592 if (drmmode_output->tear_free == 1 || 593 (drmmode_output->tear_free == 2 && 594 (crtc->scrn->pScreen->isGPU || 595 info->shadow_primary || 596 crtc->transformPresent || crtc->rotation != RR_Rotate_0))) { 597 drmmode_crtc->tear_free = TRUE; 598 return; 599 } 600 } 601} 602 603#if XF86_CRTC_VERSION < 7 604#define XF86DriverTransformOutput TRUE 605#define XF86DriverTransformNone FALSE 606#endif 607 608static Bool 609drmmode_handle_transform(xf86CrtcPtr crtc) 610{ 611 Bool ret; 612 613#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 614 crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 615#else 616 crtc->driverIsPerformingTransform = !crtc->transformPresent && 617 (crtc->rotation & 0xf) == RR_Rotate_0; 618#endif 619 620 ret = xf86CrtcRotate(crtc); 621 622 crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 623 624 return ret; 625} 626 627 628static void 629drmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 630 unsigned scanout_id, struct drmmode_fb **fb, 631 int *x, int *y) 632{ 633 ScrnInfoPtr scrn = crtc->scrn; 634 ScreenPtr screen = scrn->pScreen; 635 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 636 637 if (drmmode_crtc->tear_free && !drmmode_crtc->scanout[1]) { 638 RegionPtr region; 639 BoxPtr box; 640 641 drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 642 mode->HDisplay, 643 mode->VDisplay); 644 region = &drmmode_crtc->scanout_last_region; 645 RegionUninit(region); 646 region->data = NULL; 647 box = RegionExtents(region); 648 box->x1 = crtc->x; 649 box->y1 = crtc->y; 650 box->x2 = crtc->x + mode->HDisplay; 651 box->y2 = crtc->y + mode->VDisplay; 652 } 653 654 if (scanout_id != drmmode_crtc->scanout_id) { 655 PixmapDirtyUpdatePtr dirty = NULL; 656 657 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, 658 ent) { 659 if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 660 dirty->secondary_dst = 661 drmmode_crtc->scanout[scanout_id]; 662 break; 663 } 664 } 665 666 if (!drmmode_crtc->tear_free) { 667 GCPtr gc = GetScratchGC(scrn->depth, screen); 668 669 ValidateGC(&drmmode_crtc->scanout[0]->drawable, gc); 670 gc->ops->CopyArea(&drmmode_crtc->scanout[1]->drawable, 671 &drmmode_crtc->scanout[0]->drawable, 672 gc, 0, 0, mode->HDisplay, mode->VDisplay, 673 0, 0); 674 FreeScratchGC(gc); 675 amdgpu_glamor_finish(scrn); 676 } 677 } 678 679 *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id]); 680 *x = *y = 0; 681 drmmode_crtc->scanout_id = scanout_id; 682} 683 684 685static void 686drmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode, 687 unsigned scanout_id, struct drmmode_fb **fb, int *x, 688 int *y) 689{ 690 ScrnInfoPtr scrn = crtc->scrn; 691 ScreenPtr screen = scrn->pScreen; 692 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 693 694 drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id], 695 mode->HDisplay, mode->VDisplay); 696 if (drmmode_crtc->tear_free) { 697 drmmode_crtc_scanout_create(crtc, 698 &drmmode_crtc->scanout[scanout_id ^ 1], 699 mode->HDisplay, mode->VDisplay); 700 } 701 702 if (drmmode_crtc->scanout[scanout_id] && 703 (!drmmode_crtc->tear_free || 704 drmmode_crtc->scanout[scanout_id ^ 1])) { 705 BoxRec extents = { .x1 = 0, .y1 = 0, 706 .x2 = scrn->virtualX, .y2 = scrn->virtualY }; 707 708 if (!drmmode_crtc->scanout_damage) { 709 drmmode_crtc->scanout_damage = 710 DamageCreate(amdgpu_screen_damage_report, 711 drmmode_screen_damage_destroy, 712 DamageReportRawRegion, 713 TRUE, screen, drmmode_crtc); 714 DamageRegister(&screen->root->drawable, 715 drmmode_crtc->scanout_damage); 716 } 717 718 *fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id]); 719 *x = *y = 0; 720 721 if (amdgpu_scanout_do_update(crtc, scanout_id, 722 screen->GetWindowPixmap(screen->root), 723 extents)) { 724 RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage)); 725 amdgpu_glamor_finish(scrn); 726 727 if (!drmmode_crtc->flip_pending) { 728 amdgpu_drm_abort_entry(drmmode_crtc-> 729 scanout_update_pending); 730 } 731 } 732 } 733} 734 735static char *cm_prop_names[] = { 736 "DEGAMMA_LUT", 737 "CTM", 738 "GAMMA_LUT", 739 "DEGAMMA_LUT_SIZE", 740 "GAMMA_LUT_SIZE", 741}; 742 743/** 744 * Return the enum of the color management property with the given name. 745 */ 746static enum drmmode_cm_prop get_cm_enum_from_str(const char *prop_name) 747{ 748 enum drmmode_cm_prop ret; 749 750 for (ret = 0; ret < CM_NUM_PROPS; ret++) { 751 if (!strcmp(prop_name, cm_prop_names[ret])) 752 return ret; 753 } 754 return CM_INVALID_PROP; 755} 756 757/** 758 * If legacy LUT is a, and non-legacy LUT is b, then the result of b(a(x)) is 759 * returned in out_lut. out_lut's length is expected to be the same as the 760 * non-legacy LUT b. 761 * 762 * @a_(red|green|blue): The red, green, and blue components of the legacy LUT. 763 * @b_lut: The non-legacy LUT, in DRM's color LUT format. 764 * @out_lut: The composed LUT, in DRM's color LUT format. 765 * @len_a: Length of legacy lut. 766 * @len_b: Length of non-legacy lut. 767 */ 768static void drmmode_lut_compose(uint16_t *a_red, 769 uint16_t *a_green, 770 uint16_t *a_blue, 771 struct drm_color_lut *b_lut, 772 struct drm_color_lut *out_lut, 773 uint32_t len_a, uint32_t len_b) 774{ 775 uint32_t i_l, i_r, i; 776 uint32_t i_amax, i_bmax; 777 uint32_t coeff_ibmax; 778 uint32_t j; 779 uint64_t a_out_ibmax; 780 int color; 781 size_t struct_size = sizeof(struct drm_color_lut); 782 783 uint32_t max_lut = (1 << 16) - 1; 784 785 i_amax = len_a - 1; 786 i_bmax = len_b - 1; 787 788 /* A linear interpolation is done on the legacy LUT before it is 789 * composed, to bring it up-to-size with the non-legacy LUT. The 790 * interpolation uses integers by keeping things multiplied until the 791 * last moment. 792 */ 793 for (color = 0; color < 3; color++) { 794 uint16_t *a, *b, *out; 795 796 /* Set the initial pointers to the right color components. The 797 * inner for-loop will then maintain the correct offset from 798 * the initial element. 799 */ 800 if (color == 0) { 801 a = a_red; 802 b = &b_lut[0].red; 803 out = &out_lut[0].red; 804 } else if (color == 1) { 805 a = a_green; 806 b = &b_lut[0].green; 807 out = &out_lut[0].green; 808 } else { 809 a = a_blue; 810 b = &b_lut[0].blue; 811 out = &out_lut[0].blue; 812 } 813 814 for (i = 0; i < len_b; i++) { 815 /* i_l and i_r tracks the left and right elements in 816 * a_lut, to the sample point i. Also handle last 817 * element edge case, when i_l = i_amax. 818 */ 819 i_l = i * i_amax / i_bmax; 820 i_r = i_l + !!(i_amax - i_l); 821 822 /* coeff is intended to be in [0, 1), depending on 823 * where sample i is between i_l and i_r. We keep it 824 * multiplied with i_bmax throughout to maintain 825 * precision */ 826 coeff_ibmax = (i * i_amax) - (i_l * i_bmax); 827 a_out_ibmax = i_bmax * a[i_l] + 828 coeff_ibmax * (a[i_r] - a[i_l]); 829 830 /* j = floor((a_out/max_lut)*i_bmax). 831 * i.e. the element in LUT b that a_out maps to. We 832 * have to divide by max_lut to normalize a_out, since 833 * values in the LUTs are [0, 1<<16) 834 */ 835 j = a_out_ibmax / max_lut; 836 *(uint16_t*)((void*)out + (i*struct_size)) = 837 *(uint16_t*)((void*)b + (j*struct_size)); 838 } 839 } 840 841 for (i = 0; i < len_b; i++) 842 out_lut[i].reserved = 0; 843} 844 845/** 846 * Resize a LUT, using linear interpolation. 847 * 848 * @in_(red|green|blue): Legacy LUT components 849 * @out_lut: The resized LUT is returned here, in DRM color LUT format. 850 * @len_in: Length of legacy LUT. 851 * @len_out: Length of out_lut, i.e. the target size. 852 */ 853static void drmmode_lut_interpolate(uint16_t *in_red, 854 uint16_t *in_green, 855 uint16_t *in_blue, 856 struct drm_color_lut *out_lut, 857 uint32_t len_in, uint32_t len_out) 858{ 859 uint32_t i_l, i_r, i; 860 uint32_t i_amax, i_bmax; 861 uint32_t coeff_ibmax; 862 uint64_t out_ibmax; 863 int color; 864 size_t struct_size = sizeof(struct drm_color_lut); 865 866 i_amax = len_in - 1; 867 i_bmax = len_out - 1; 868 869 /* See @drmmode_lut_compose for details */ 870 for (color = 0; color < 3; color++) { 871 uint16_t *in, *out; 872 873 if (color == 0) { 874 in = in_red; 875 out = &out_lut[0].red; 876 } else if (color == 1) { 877 in = in_green; 878 out = &out_lut[0].green; 879 } else { 880 in = in_blue; 881 out = &out_lut[0].blue; 882 } 883 884 for (i = 0; i < len_out; i++) { 885 i_l = i * i_amax / i_bmax; 886 i_r = i_l + !!(i_amax - i_l); 887 888 coeff_ibmax = (i * i_amax) - (i_l * i_bmax); 889 out_ibmax = i_bmax * in[i_l] + 890 coeff_ibmax * (in[i_r] - in[i_l]); 891 892 *(uint16_t*)((void*)out + (i*struct_size)) = 893 out_ibmax / i_bmax; 894 } 895 } 896 897 for (i = 0; i < len_out; i++) 898 out_lut[i].reserved = 0; 899} 900 901/** 902 * Configure and change a color property on a CRTC, through RandR. Only the 903 * specified output will be affected, even if the CRTC is attached to multiple 904 * outputs. Note that changes will be non-pending: the changes won't be pushed 905 * to kernel driver. 906 * 907 * @output: RandR output to set the property on. 908 * @crtc: The driver-private CRTC object containing the color properties. 909 * If this is NULL, "disabled" values of 0 will be used. 910 * @cm_prop_index: Color management property to configure and change. 911 * 912 * Return 0 on success, X-defined error code otherwise. 913 */ 914static int rr_configure_and_change_cm_property(xf86OutputPtr output, 915 drmmode_crtc_private_ptr crtc, 916 enum drmmode_cm_prop cm_prop_index) 917{ 918 drmmode_output_private_ptr drmmode_output = output->driver_private; 919 drmmode_ptr drmmode = drmmode_output->drmmode; 920 Bool need_configure = TRUE; 921 unsigned long length = 0; 922 void *data = NULL; 923 int format = 0; 924 uint32_t zero = 0; 925 INT32 range[2]; 926 Atom atom; 927 int err; 928 929 if (cm_prop_index == CM_INVALID_PROP) 930 return BadName; 931 932 switch(cm_prop_index) { 933 case CM_GAMMA_LUT_SIZE: 934 format = 32; 935 length = 1; 936 data = &drmmode->gamma_lut_size; 937 range[0] = 0; 938 range[1] = -1; 939 break; 940 case CM_DEGAMMA_LUT_SIZE: 941 format = 32; 942 length = 1; 943 data = &drmmode->degamma_lut_size; 944 range[0] = 0; 945 range[1] = -1; 946 break; 947 case CM_GAMMA_LUT: 948 format = 16; 949 range[0] = 0; 950 range[1] = (1 << 16) - 1; // Max 16 bit unsigned int. 951 if (crtc && crtc->gamma_lut) { 952 /* Convert from 8bit size to 16bit size */ 953 length = sizeof(*crtc->gamma_lut) >> 1; 954 length *= drmmode->gamma_lut_size; 955 data = crtc->gamma_lut; 956 } else { 957 length = 1; 958 data = &zero; 959 } 960 break; 961 case CM_DEGAMMA_LUT: 962 format = 16; 963 range[0] = 0; 964 range[1] = (1 << 16) - 1; 965 if (crtc && crtc->degamma_lut) { 966 length = sizeof(*crtc->degamma_lut) >> 1; 967 length *= drmmode->degamma_lut_size; 968 data = crtc->degamma_lut; 969 } else { 970 length = 1; 971 data = &zero; 972 } 973 break; 974 case CM_CTM: 975 /* CTM is fixed-point S31.32 format. */ 976 format = 32; 977 need_configure = FALSE; 978 if (crtc && crtc->ctm) { 979 /* Convert from 8bit size to 32bit size */ 980 length = sizeof(*crtc->ctm) >> 2; 981 data = crtc->ctm; 982 } else { 983 length = 1; 984 data = &zero; 985 } 986 break; 987 default: 988 return BadName; 989 } 990 991 atom = MakeAtom(cm_prop_names[cm_prop_index], 992 strlen(cm_prop_names[cm_prop_index]), 993 TRUE); 994 if (!atom) 995 return BadAlloc; 996 997 if (need_configure) { 998 err = RRConfigureOutputProperty(output->randr_output, atom, 999 FALSE, TRUE, FALSE, 2, range); 1000 if (err) { 1001 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1002 "Configuring color management property %s failed with %d\n", 1003 cm_prop_names[cm_prop_index], err); 1004 return err; 1005 } 1006 } 1007 1008 /* Always issue a non-pending change. We'll push cm properties 1009 * ourselves. 1010 */ 1011 err = RRChangeOutputProperty(output->randr_output, atom, 1012 XA_INTEGER, format, 1013 PropModeReplace, 1014 length, data, FALSE, FALSE); 1015 if (err) 1016 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1017 "Changing color management property %s failed with %d\n", 1018 cm_prop_names[cm_prop_index], err); 1019 return err; 1020} 1021 1022/** 1023* Stage a color management property. This parses the property value, according 1024* to the cm property type, then stores it within the driver-private CRTC 1025* object. 1026* 1027* @crtc: The CRTC to stage the new color management properties in 1028* @cm_prop_index: The color property to stage 1029* @value: The RandR property value to stage 1030* 1031* Return 0 on success, X-defined error code on failure. 1032*/ 1033static int drmmode_crtc_stage_cm_prop(xf86CrtcPtr crtc, 1034 enum drmmode_cm_prop cm_prop_index, 1035 RRPropertyValuePtr value) 1036{ 1037 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1038 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1039 size_t expected_bytes = 0; 1040 void **blob_data = NULL; 1041 Bool use_default = FALSE; 1042 1043 /* Update properties on the driver-private CRTC */ 1044 switch (cm_prop_index) { 1045 case CM_GAMMA_LUT: 1046 /* Calculate the expected size of value in bytes */ 1047 expected_bytes = sizeof(struct drm_color_lut) * 1048 drmmode->gamma_lut_size; 1049 1050 /* For gamma and degamma, we allow a default SRGB curve to be 1051 * set via setting a single element 1052 * 1053 * Otherwise, value size is in terms of the value format. 1054 * Ensure it's also in bytes (<< 1) before comparing with the 1055 * expected bytes. 1056 */ 1057 if (value->size == 1) 1058 use_default = TRUE; 1059 else if (value->type != XA_INTEGER || value->format != 16 || 1060 (size_t)(value->size << 1) != expected_bytes) 1061 return BadLength; 1062 1063 blob_data = (void**)&drmmode_crtc->gamma_lut; 1064 break; 1065 case CM_DEGAMMA_LUT: 1066 expected_bytes = sizeof(struct drm_color_lut) * 1067 drmmode->degamma_lut_size; 1068 1069 if (value->size == 1) 1070 use_default = TRUE; 1071 else if (value->type != XA_INTEGER || value->format != 16 || 1072 (size_t)(value->size << 1) != expected_bytes) 1073 return BadLength; 1074 1075 blob_data = (void**)&drmmode_crtc->degamma_lut; 1076 break; 1077 case CM_CTM: 1078 expected_bytes = sizeof(struct drm_color_ctm); 1079 1080 if (value->size == 1) 1081 use_default = TRUE; 1082 if (value->type != XA_INTEGER || value->format != 32 || 1083 (size_t)(value->size << 2) != expected_bytes) 1084 return BadLength; 1085 1086 blob_data = (void**)&drmmode_crtc->ctm; 1087 break; 1088 default: 1089 return BadName; 1090 } 1091 1092 free(*blob_data); 1093 if (!use_default) { 1094 *blob_data = malloc(expected_bytes); 1095 if (!*blob_data) 1096 return BadAlloc; 1097 memcpy(*blob_data, value->data, expected_bytes); 1098 } else 1099 *blob_data = NULL; 1100 1101 return Success; 1102} 1103 1104/** 1105 * Push staged color management properties on the CRTC to DRM. 1106 * 1107 * @crtc: The CRTC containing staged properties 1108 * @cm_prop_index: The color property to push 1109 * 1110 * Return 0 on success, X-defined error codes on failure. 1111 */ 1112static int drmmode_crtc_push_cm_prop(xf86CrtcPtr crtc, 1113 enum drmmode_cm_prop cm_prop_index) 1114{ 1115 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1116 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 1117 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1118 Bool free_blob_data = FALSE; 1119 uint32_t created_blob_id = 0; 1120 uint32_t drm_prop_id; 1121 size_t expected_bytes = 0; 1122 void *blob_data = NULL; 1123 int ret; 1124 1125 switch (cm_prop_index) { 1126 case CM_GAMMA_LUT: 1127 /* Calculate the expected size of value in bytes */ 1128 expected_bytes = sizeof(struct drm_color_lut) * 1129 drmmode->gamma_lut_size; 1130 1131 /* Legacy gamma LUT is disabled on deep 30bpp color. In which 1132 * case, directly use non-legacy LUT. 1133 */ 1134 if (!crtc->funcs->gamma_set) { 1135 blob_data = drmmode_crtc->gamma_lut; 1136 goto do_push; 1137 } 1138 1139 blob_data = malloc(expected_bytes); 1140 if (!blob_data) 1141 return BadAlloc; 1142 1143 free_blob_data = TRUE; 1144 /* 1145 * Compose legacy and non-legacy LUT if non-legacy was set. 1146 * Otherwise, interpolate legacy LUT to non-legacy size. 1147 */ 1148 if (drmmode_crtc->gamma_lut) { 1149 drmmode_lut_compose(crtc->gamma_red, 1150 crtc->gamma_green, 1151 crtc->gamma_blue, 1152 drmmode_crtc->gamma_lut, 1153 blob_data, crtc->gamma_size, 1154 drmmode->gamma_lut_size); 1155 } else { 1156 drmmode_lut_interpolate(crtc->gamma_red, 1157 crtc->gamma_green, 1158 crtc->gamma_blue, 1159 blob_data, 1160 crtc->gamma_size, 1161 drmmode->gamma_lut_size); 1162 } 1163 break; 1164 case CM_DEGAMMA_LUT: 1165 expected_bytes = sizeof(struct drm_color_lut) * 1166 drmmode->degamma_lut_size; 1167 blob_data = drmmode_crtc->degamma_lut; 1168 break; 1169 case CM_CTM: 1170 expected_bytes = sizeof(struct drm_color_ctm); 1171 blob_data = drmmode_crtc->ctm; 1172 break; 1173 default: 1174 return BadName; 1175 } 1176 1177do_push: 1178 if (blob_data) { 1179 ret = drmModeCreatePropertyBlob(pAMDGPUEnt->fd, 1180 blob_data, expected_bytes, 1181 &created_blob_id); 1182 if (ret) { 1183 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 1184 "Creating DRM blob failed with errno %d\n", 1185 ret); 1186 if (free_blob_data) 1187 free(blob_data); 1188 return BadRequest; 1189 } 1190 } 1191 1192 drm_prop_id = drmmode_crtc->drmmode->cm_prop_ids[cm_prop_index]; 1193 ret = drmModeObjectSetProperty(pAMDGPUEnt->fd, 1194 drmmode_crtc->mode_crtc->crtc_id, 1195 DRM_MODE_OBJECT_CRTC, 1196 drm_prop_id, 1197 (uint64_t)created_blob_id); 1198 1199 /* If successful, kernel will have a reference already. Safe to destroy 1200 * the blob either way. 1201 */ 1202 if (blob_data) 1203 drmModeDestroyPropertyBlob(pAMDGPUEnt->fd, created_blob_id); 1204 1205 if (ret) { 1206 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 1207 "Setting DRM property blob failed with errno %d\n", 1208 ret); 1209 if (free_blob_data) 1210 free(blob_data); 1211 return BadRequest; 1212 } 1213 1214 if (free_blob_data) 1215 free(blob_data); 1216 1217 return Success; 1218} 1219 1220static void 1221drmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 1222 uint16_t *blue, int size) 1223{ 1224 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1225 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 1226 int ret; 1227 1228 /* Use legacy if no support for non-legacy gamma */ 1229 if (!drmmode_cm_enabled(drmmode_crtc->drmmode)) { 1230 drmModeCrtcSetGamma(pAMDGPUEnt->fd, 1231 drmmode_crtc->mode_crtc->crtc_id, 1232 size, red, green, blue); 1233 return; 1234 } 1235 1236 ret = drmmode_crtc_push_cm_prop(crtc, CM_GAMMA_LUT); 1237 if (ret) 1238 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 1239 "Setting Gamma LUT failed with errno %d\n", 1240 ret); 1241} 1242 1243Bool 1244drmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode, 1245 int x, int y) 1246{ 1247 ScrnInfoPtr scrn = crtc->scrn; 1248 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 1249 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1250 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1251 uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 1252 int output_count = 0; 1253 drmModeModeInfo kmode; 1254 Bool ret; 1255 int i; 1256 1257 if (!output_ids) 1258 return FALSE; 1259 1260 for (i = 0; i < xf86_config->num_output; i++) { 1261 xf86OutputPtr output = xf86_config->output[i]; 1262 drmmode_output_private_ptr drmmode_output = output->driver_private; 1263 1264 if (output->crtc != crtc) 1265 continue; 1266 1267 output_ids[output_count] = drmmode_output->mode_output->connector_id; 1268 output_count++; 1269 } 1270 1271 drmmode_ConvertToKMode(scrn, &kmode, mode); 1272 1273 ret = drmModeSetCrtc(pAMDGPUEnt->fd, 1274 drmmode_crtc->mode_crtc->crtc_id, 1275 fb->handle, x, y, output_ids, 1276 output_count, &kmode) == 0; 1277 1278 if (ret) { 1279 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb); 1280 } else { 1281 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1282 "failed to set mode: %s\n", strerror(errno)); 1283 } 1284 1285 free(output_ids); 1286 return ret; 1287} 1288 1289static Bool 1290drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 1291 Rotation rotation, int x, int y) 1292{ 1293 ScrnInfoPtr pScrn = crtc->scrn; 1294 ScreenPtr pScreen = pScrn->pScreen; 1295 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1296 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1297 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 1298 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1299 Bool handle_deferred = FALSE; 1300 unsigned scanout_id = 0; 1301 int saved_x, saved_y; 1302 Rotation saved_rotation; 1303 DisplayModeRec saved_mode; 1304 Bool ret = FALSE; 1305 int i; 1306 struct drmmode_fb *fb = NULL; 1307 1308 /* The root window contents may be undefined before the WindowExposures 1309 * hook is called for it, so bail if we get here before that 1310 */ 1311 if (pScreen->WindowExposures == AMDGPUWindowExposures_oneshot) 1312 return FALSE; 1313 1314 saved_mode = crtc->mode; 1315 saved_x = crtc->x; 1316 saved_y = crtc->y; 1317 saved_rotation = crtc->rotation; 1318 1319 if (mode) { 1320 crtc->mode = *mode; 1321 crtc->x = x; 1322 crtc->y = y; 1323 crtc->rotation = rotation; 1324 1325 if (!drmmode_handle_transform(crtc)) 1326 goto done; 1327 1328 drmmode_crtc_update_tear_free(crtc); 1329 if (drmmode_crtc->tear_free) 1330 scanout_id = drmmode_crtc->scanout_id; 1331 else 1332 drmmode_crtc->scanout_id = 0; 1333 1334 if (drmmode_crtc->prime_scanout_pixmap) { 1335 drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id, 1336 &fb, &x, &y); 1337 } else if (drmmode_crtc->rotate) { 1338 fb = amdgpu_pixmap_get_fb(drmmode_crtc->rotate); 1339 x = y = 0; 1340 1341 } else if (!pScreen->isGPU && 1342 (drmmode_crtc->tear_free || 1343 crtc->driverIsPerformingTransform || 1344 info->shadow_primary)) { 1345 drmmode_crtc_scanout_update(crtc, mode, scanout_id, 1346 &fb, &x, &y); 1347 } 1348 1349 if (!fb) 1350 fb = amdgpu_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root)); 1351 if (!fb) { 1352 union gbm_bo_handle bo_handle; 1353 1354 bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm); 1355 fb = amdgpu_fb_create(pScrn, pAMDGPUEnt->fd, 1356 pScrn->virtualX, pScrn->virtualY, 1357 pScrn->displayWidth * info->pixel_bytes, 1358 bo_handle.u32); 1359 /* Prevent refcnt of ad-hoc FBs from reaching 2 */ 1360 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL); 1361 drmmode_crtc->fb = fb; 1362 } 1363 if (!fb) { 1364 ErrorF("failed to add FB for modeset\n"); 1365 goto done; 1366 } 1367 1368 amdgpu_drm_wait_pending_flip(crtc); 1369 handle_deferred = TRUE; 1370 1371 if (!drmmode_set_mode(crtc, fb, mode, x, y)) 1372 goto done; 1373 1374 ret = TRUE; 1375 1376 if (pScreen) 1377 xf86CrtcSetScreenSubpixelOrder(pScreen); 1378 1379 drmmode_crtc->need_modeset = FALSE; 1380 1381 /* go through all the outputs and force DPMS them back on? */ 1382 for (i = 0; i < xf86_config->num_output; i++) { 1383 xf86OutputPtr output = xf86_config->output[i]; 1384 1385 if (output->crtc != crtc) 1386 continue; 1387 1388 output->funcs->dpms(output, DPMSModeOn); 1389 } 1390 } 1391 1392 /* Compute index of this CRTC into xf86_config->crtc */ 1393 for (i = 0; i < xf86_config->num_crtc; i++) { 1394 if (xf86_config->crtc[i] != crtc) 1395 continue; 1396 1397 if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 1398 info->hwcursor_disabled &= ~(1 << i); 1399 else 1400 info->hwcursor_disabled |= 1 << i; 1401 1402 break; 1403 } 1404 1405#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 1406 if (!info->hwcursor_disabled) 1407 xf86_reload_cursors(pScreen); 1408#endif 1409 1410done: 1411 if (!ret) { 1412 crtc->x = saved_x; 1413 crtc->y = saved_y; 1414 crtc->rotation = saved_rotation; 1415 crtc->mode = saved_mode; 1416 } else { 1417 crtc->active = TRUE; 1418 1419 if (drmmode_crtc->scanout[scanout_id] && 1420 fb != amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id])) { 1421 drmmode_crtc_scanout_free(crtc); 1422 } else if (!drmmode_crtc->tear_free) { 1423 drmmode_crtc_scanout_destroy(&drmmode_crtc->scanout[1]); 1424 } 1425 } 1426 1427 if (handle_deferred) 1428 amdgpu_drm_queue_handle_deferred(crtc); 1429 1430 return ret; 1431} 1432 1433static void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 1434{ 1435 1436} 1437 1438static void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y) 1439{ 1440 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1441 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 1442 1443#if XF86_CRTC_VERSION < 7 1444 if (crtc->driverIsPerformingTransform) { 1445 x += crtc->x; 1446 y += crtc->y; 1447 xf86CrtcTransformCursorPos(crtc, &x, &y); 1448 } 1449#endif 1450 1451 drmmode_crtc->cursor_x = x; 1452 drmmode_crtc->cursor_y = y; 1453 1454 drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 1455} 1456 1457#if XF86_CRTC_VERSION < 7 1458 1459static int 1460drmmode_cursor_src_offset(Rotation rotation, int width, int height, 1461 int x_dst, int y_dst) 1462{ 1463 int t; 1464 1465 switch (rotation & 0xf) { 1466 case RR_Rotate_90: 1467 t = x_dst; 1468 x_dst = height - y_dst - 1; 1469 y_dst = t; 1470 break; 1471 case RR_Rotate_180: 1472 x_dst = width - x_dst - 1; 1473 y_dst = height - y_dst - 1; 1474 break; 1475 case RR_Rotate_270: 1476 t = x_dst; 1477 x_dst = y_dst; 1478 y_dst = width - t - 1; 1479 break; 1480 } 1481 1482 if (rotation & RR_Reflect_X) 1483 x_dst = width - x_dst - 1; 1484 if (rotation & RR_Reflect_Y) 1485 y_dst = height - y_dst - 1; 1486 1487 return y_dst * height + x_dst; 1488} 1489 1490#endif 1491 1492static Bool 1493drmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool *premultiplied, 1494 Bool *apply_gamma) 1495{ 1496 uint32_t alpha = *argb >> 24; 1497 uint32_t rgb[3]; 1498 int i; 1499 1500 if (premultiplied) { 1501#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0) 1502 if (alpha == 0 && (*argb & 0xffffff) != 0) { 1503 /* Doesn't look like premultiplied alpha */ 1504 *premultiplied = FALSE; 1505 return FALSE; 1506 } 1507#endif 1508 1509 if (!(*apply_gamma)) 1510 return TRUE; 1511 1512 if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) { 1513 /* Un-premultiplied R/G/B would overflow gamma LUT, 1514 * don't apply gamma correction 1515 */ 1516 *apply_gamma = FALSE; 1517 return FALSE; 1518 } 1519 } 1520 1521 if (!alpha) { 1522 *argb = 0; 1523 return TRUE; 1524 } 1525 1526 /* Extract RGB */ 1527 for (i = 0; i < 3; i++) 1528 rgb[i] = (*argb >> (i * 8)) & 0xff; 1529 1530 if (premultiplied) { 1531 /* Un-premultiply alpha */ 1532 for (i = 0; i < 3; i++) 1533 rgb[i] = rgb[i] * 0xff / alpha; 1534 } 1535 1536 if (*apply_gamma) { 1537 rgb[0] = crtc->gamma_blue[rgb[0]] >> 8; 1538 rgb[1] = crtc->gamma_green[rgb[1]] >> 8; 1539 rgb[2] = crtc->gamma_red[rgb[2]] >> 8; 1540 } 1541 1542 /* Premultiply alpha */ 1543 for (i = 0; i < 3; i++) 1544 rgb[i] = rgb[i] * alpha / 0xff; 1545 1546 *argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0]; 1547 return TRUE; 1548} 1549 1550static void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) 1551{ 1552 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1553 ScrnInfoPtr pScrn = crtc->scrn; 1554 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1555 unsigned id = drmmode_crtc->cursor_id; 1556 Bool premultiplied = TRUE; 1557 Bool apply_gamma = TRUE; 1558 uint32_t argb; 1559 uint32_t *ptr; 1560 1561 if ((crtc->scrn->depth != 24 && crtc->scrn->depth != 32) || 1562 drmmode_cm_enabled(&info->drmmode)) 1563 apply_gamma = FALSE; 1564 1565 if (drmmode_crtc->cursor && 1566 XF86_CRTC_CONFIG_PTR(pScrn)->cursor != drmmode_crtc->cursor) 1567 id ^= 1; 1568 1569 ptr = (uint32_t *) (drmmode_crtc->cursor_buffer[id]->cpu_ptr); 1570 1571#if XF86_CRTC_VERSION < 7 1572 if (crtc->driverIsPerformingTransform) { 1573 uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 1574 int dstx, dsty; 1575 int srcoffset; 1576 1577retry_transform: 1578 for (dsty = 0; dsty < cursor_h; dsty++) { 1579 for (dstx = 0; dstx < cursor_w; dstx++) { 1580 srcoffset = drmmode_cursor_src_offset(crtc->rotation, 1581 cursor_w, 1582 cursor_h, 1583 dstx, dsty); 1584 argb = image[srcoffset]; 1585 if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 1586 &apply_gamma)) 1587 goto retry_transform; 1588 1589 ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb); 1590 } 1591 } 1592 } else 1593#endif 1594 { 1595 uint32_t cursor_size = info->cursor_w * info->cursor_h; 1596 int i; 1597 1598retry: 1599 for (i = 0; i < cursor_size; i++) { 1600 argb = image[i]; 1601 if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied, 1602 &apply_gamma)) 1603 goto retry; 1604 1605 ptr[i] = cpu_to_le32(argb); 1606 } 1607 } 1608 1609 if (id != drmmode_crtc->cursor_id) { 1610 drmmode_crtc->cursor_id = id; 1611 crtc->funcs->show_cursor(crtc); 1612 } 1613} 1614 1615#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1616 1617static Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 1618{ 1619 if (!drmmode_can_use_hw_cursor(crtc)) 1620 return FALSE; 1621 1622 drmmode_load_cursor_argb(crtc, image); 1623 return TRUE; 1624} 1625 1626#endif 1627 1628static void drmmode_hide_cursor(xf86CrtcPtr crtc) 1629{ 1630 ScrnInfoPtr pScrn = crtc->scrn; 1631 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1632 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1633 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1634 1635 drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 1636 info->cursor_w, info->cursor_h); 1637 drmmode_crtc->cursor = NULL; 1638} 1639 1640static void drmmode_show_cursor(xf86CrtcPtr crtc) 1641{ 1642 ScrnInfoPtr pScrn = crtc->scrn; 1643 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1644 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1645 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1646 struct amdgpu_buffer *cursor_buffer = 1647 drmmode_crtc->cursor_buffer[drmmode_crtc->cursor_id]; 1648 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1649 CursorPtr cursor = xf86_config->cursor; 1650 int xhot = cursor->bits->xhot; 1651 int yhot = cursor->bits->yhot; 1652 static Bool use_set_cursor2 = TRUE; 1653 struct drm_mode_cursor2 arg; 1654 1655 drmmode_crtc->cursor = xf86_config->cursor; 1656 1657 memset(&arg, 0, sizeof(arg)); 1658 1659 if (!amdgpu_bo_get_handle(cursor_buffer, &arg.handle)) { 1660 ErrorF("failed to get BO handle for cursor\n"); 1661 return; 1662 } 1663 1664 arg.flags = DRM_MODE_CURSOR_BO; 1665 arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id; 1666 arg.width = info->cursor_w; 1667 arg.height = info->cursor_h; 1668 1669 if (crtc->rotation != RR_Rotate_0 && 1670 crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 1671 RR_Reflect_Y)) { 1672 int t; 1673 1674 /* Reflect & rotate hotspot position */ 1675 if (crtc->rotation & RR_Reflect_X) 1676 xhot = info->cursor_w - xhot - 1; 1677 if (crtc->rotation & RR_Reflect_Y) 1678 yhot = info->cursor_h - yhot - 1; 1679 1680 switch (crtc->rotation & 0xf) { 1681 case RR_Rotate_90: 1682 t = xhot; 1683 xhot = yhot; 1684 yhot = info->cursor_w - t - 1; 1685 break; 1686 case RR_Rotate_180: 1687 xhot = info->cursor_w - xhot - 1; 1688 yhot = info->cursor_h - yhot - 1; 1689 break; 1690 case RR_Rotate_270: 1691 t = xhot; 1692 xhot = info->cursor_h - yhot - 1; 1693 yhot = t; 1694 } 1695 } 1696 1697 if (xhot != drmmode_crtc->cursor_xhot || yhot != drmmode_crtc->cursor_yhot) { 1698 arg.flags |= DRM_MODE_CURSOR_MOVE; 1699 arg.x = drmmode_crtc->cursor_x += drmmode_crtc->cursor_xhot - xhot; 1700 arg.y = drmmode_crtc->cursor_y += drmmode_crtc->cursor_yhot - yhot; 1701 drmmode_crtc->cursor_xhot = xhot; 1702 drmmode_crtc->cursor_yhot = yhot; 1703 } 1704 1705 if (use_set_cursor2) { 1706 int ret; 1707 1708 arg.hot_x = xhot; 1709 arg.hot_y = yhot; 1710 1711 ret = drmIoctl(pAMDGPUEnt->fd, DRM_IOCTL_MODE_CURSOR2, &arg); 1712 if (ret == -1 && errno == EINVAL) 1713 use_set_cursor2 = FALSE; 1714 else 1715 return; 1716 } 1717 1718 drmIoctl(pAMDGPUEnt->fd, DRM_IOCTL_MODE_CURSOR, &arg); 1719} 1720 1721/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and 1722 * passes that back to drmmode_crtc_scanout_create; it doesn't use it for 1723 * anything else. 1724 */ 1725static void * 1726drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 1727{ 1728 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1729 1730 if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 1731 height)) 1732 return NULL; 1733 1734 return (void*)~0UL; 1735} 1736 1737static PixmapPtr 1738drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1739{ 1740 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1741 1742 if (!data) { 1743 drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 1744 height); 1745 } 1746 1747 return drmmode_crtc->rotate; 1748} 1749 1750static void 1751drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, 1752 void *data) 1753{ 1754 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1755 1756 drmmode_crtc_scanout_destroy(&drmmode_crtc->rotate); 1757} 1758 1759static void 1760drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green, 1761 uint16_t * blue, int size) 1762{ 1763 ScrnInfoPtr scrn = crtc->scrn; 1764 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1765 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 1766 int i; 1767 1768 drmmode_crtc_gamma_do_set(crtc, red, green, blue, size); 1769 1770 /* Compute index of this CRTC into xf86_config->crtc */ 1771 for (i = 0; xf86_config->crtc[i] != crtc; i++) {} 1772 1773 if (info->hwcursor_disabled & (1 << i)) 1774 return; 1775 1776#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 1777 xf86CursorResetCursor(scrn->pScreen); 1778#else 1779 xf86_reload_cursors(scrn->pScreen); 1780#endif 1781} 1782 1783static Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 1784{ 1785 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1786 unsigned scanout_id = drmmode_crtc->scanout_id; 1787 ScreenPtr screen = crtc->scrn->pScreen; 1788 PixmapDirtyUpdatePtr dirty; 1789 1790 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 1791 if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) { 1792 PixmapStopDirtyTracking(dirty->src, dirty->secondary_dst); 1793 break; 1794 } 1795 } 1796 1797 drmmode_crtc_scanout_free(crtc); 1798 drmmode_crtc->prime_scanout_pixmap = NULL; 1799 1800 if (!ppix) 1801 return TRUE; 1802 1803 if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 1804 ppix->drawable.width, 1805 ppix->drawable.height)) 1806 return FALSE; 1807 1808 if (drmmode_crtc->tear_free && 1809 !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 1810 ppix->drawable.width, 1811 ppix->drawable.height)) { 1812 drmmode_crtc_scanout_free(crtc); 1813 return FALSE; 1814 } 1815 1816 drmmode_crtc->prime_scanout_pixmap = ppix; 1817 1818#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 1819 PixmapStartDirtyTracking(&ppix->drawable, 1820 drmmode_crtc->scanout[scanout_id], 1821 0, 0, 0, 0, RR_Rotate_0); 1822#elif defined(HAS_DIRTYTRACKING_ROTATION) 1823 PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id], 1824 0, 0, 0, 0, RR_Rotate_0); 1825#elif defined(HAS_DIRTYTRACKING2) 1826 PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id], 1827 0, 0, 0, 0); 1828#else 1829 PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id], 0, 0); 1830#endif 1831 return TRUE; 1832} 1833 1834static void drmmode_crtc_destroy(xf86CrtcPtr crtc) 1835{ 1836 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1837 1838 drmModeFreeCrtc(drmmode_crtc->mode_crtc); 1839 1840 /* Free LUTs and CTM */ 1841 free(drmmode_crtc->gamma_lut); 1842 free(drmmode_crtc->degamma_lut); 1843 free(drmmode_crtc->ctm); 1844 1845 free(drmmode_crtc); 1846 crtc->driver_private = NULL; 1847} 1848 1849 1850static xf86CrtcFuncsRec drmmode_crtc_funcs = { 1851 .dpms = drmmode_crtc_dpms, 1852 .set_mode_major = drmmode_set_mode_major, 1853 .set_cursor_colors = drmmode_set_cursor_colors, 1854 .set_cursor_position = drmmode_set_cursor_position, 1855 .show_cursor = drmmode_show_cursor, 1856 .hide_cursor = drmmode_hide_cursor, 1857 .load_cursor_argb = drmmode_load_cursor_argb, 1858#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1859 .load_cursor_argb_check = drmmode_load_cursor_argb_check, 1860#endif 1861 1862 .gamma_set = drmmode_crtc_gamma_set, 1863 .shadow_create = drmmode_crtc_shadow_create, 1864 .shadow_allocate = drmmode_crtc_shadow_allocate, 1865 .shadow_destroy = drmmode_crtc_shadow_destroy, 1866 .destroy = drmmode_crtc_destroy, 1867 .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1868}; 1869 1870int drmmode_get_crtc_id(xf86CrtcPtr crtc) 1871{ 1872 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1873 return drmmode_crtc->hw_id; 1874} 1875 1876void drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1877{ 1878 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1879 ScrnInfoPtr pScrn = crtc->scrn; 1880 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1881 int r; 1882 1883 r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev, 1884 drmmode_crtc->mode_crtc->crtc_id, 1885 &drmmode_crtc->hw_id); 1886 if (r) 1887 drmmode_crtc->hw_id = -1; 1888} 1889 1890/** 1891 * Initialize color management properties for the given CRTC by programming 1892 * the default gamma/degamma LUTs and CTM. 1893 * 1894 * If the CRTC does not support color management, or if errors occur during 1895 * initialization, all color properties on the driver-private CRTC will left 1896 * as NULL. 1897 * 1898 * @drm_fd: DRM file descriptor 1899 * @crtc: CRTC to initialize color management on. 1900 */ 1901static void drmmode_crtc_cm_init(int drm_fd, xf86CrtcPtr crtc) 1902{ 1903 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1904 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1905 int i; 1906 1907 if (!drmmode_cm_enabled(drmmode)) 1908 return; 1909 1910 /* Init CTM to identity. Values are in S31.32 fixed-point format */ 1911 drmmode_crtc->ctm = calloc(1, sizeof(*drmmode_crtc->ctm)); 1912 if (!drmmode_crtc->ctm) { 1913 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 1914 "Memory error initializing CTM for CRTC%d", 1915 drmmode_get_crtc_id(crtc)); 1916 return; 1917 } 1918 1919 drmmode_crtc->ctm->matrix[0] = drmmode_crtc->ctm->matrix[4] = 1920 drmmode_crtc->ctm->matrix[8] = (uint64_t)1 << 32; 1921 1922 /* Push properties to reset properties currently in hardware */ 1923 for (i = 0; i < CM_GAMMA_LUT; i++) { 1924 if (drmmode_crtc_push_cm_prop(crtc, i)) 1925 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 1926 "Failed to initialize color management " 1927 "property %s on CRTC%d. Property value may " 1928 "not reflect actual hardware state.\n", 1929 cm_prop_names[i], 1930 drmmode_get_crtc_id(crtc)); 1931 } 1932} 1933 1934static unsigned int 1935drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 1936{ 1937 xf86CrtcPtr crtc; 1938 drmmode_crtc_private_ptr drmmode_crtc; 1939 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1940 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1941 1942 crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs); 1943 if (!crtc) 1944 return 0; 1945 1946 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 1947 drmmode_crtc->mode_crtc = 1948 drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]); 1949 drmmode_crtc->drmmode = drmmode; 1950 drmmode_crtc->dpms_mode = DPMSModeOff; 1951 crtc->driver_private = drmmode_crtc; 1952 drmmode_crtc_hw_id(crtc); 1953 1954 drmmode_crtc_cm_init(pAMDGPUEnt->fd, crtc); 1955 drmmode_crtc_vrr_init(pAMDGPUEnt->fd, crtc); 1956 1957 /* Mark num'th crtc as in use on this device. */ 1958 pAMDGPUEnt->assigned_crtcs |= (1 << num); 1959 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 1960 "Allocated crtc nr. %d to this screen.\n", num); 1961 1962 return 1; 1963} 1964 1965/* 1966 * Update all of the property values for an output 1967 */ 1968static void 1969drmmode_output_update_properties(xf86OutputPtr output) 1970{ 1971 drmmode_output_private_ptr drmmode_output = output->driver_private; 1972 int i, j, k; 1973 int err; 1974 drmModeConnectorPtr koutput; 1975 1976 /* Use the most recently fetched values from the kernel */ 1977 koutput = drmmode_output->mode_output; 1978 1979 if (!koutput) 1980 return; 1981 1982 for (i = 0; i < drmmode_output->num_props; i++) { 1983 drmmode_prop_ptr p = &drmmode_output->props[i]; 1984 1985 for (j = 0; j < koutput->count_props; j++) { 1986 if (koutput->props[j] != p->mode_prop->prop_id) 1987 continue; 1988 1989 /* Check to see if the property value has changed */ 1990 if (koutput->prop_values[j] == p->value) 1991 break; 1992 1993 p->value = koutput->prop_values[j]; 1994 1995 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1996 INT32 value = p->value; 1997 1998 err = RRChangeOutputProperty(output->randr_output, 1999 p->atoms[0], XA_INTEGER, 2000 32, PropModeReplace, 1, 2001 &value, FALSE, TRUE); 2002 if (err != 0) { 2003 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2004 "RRChangeOutputProperty error, %d\n", 2005 err); 2006 } 2007 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 2008 for (k = 0; k < p->mode_prop->count_enums; k++) { 2009 if (p->mode_prop->enums[k].value == p->value) 2010 break; 2011 } 2012 if (k < p->mode_prop->count_enums) { 2013 err = RRChangeOutputProperty(output->randr_output, 2014 p->atoms[0], XA_ATOM, 2015 32, PropModeReplace, 1, 2016 &p->atoms[k + 1], FALSE, 2017 TRUE); 2018 if (err != 0) { 2019 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2020 "RRChangeOutputProperty error, %d\n", 2021 err); 2022 } 2023 } 2024 } 2025 2026 break; 2027 } 2028 } 2029} 2030 2031static xf86OutputStatus drmmode_output_detect(xf86OutputPtr output) 2032{ 2033 /* go to the hw and retrieve a new output struct */ 2034 drmmode_output_private_ptr drmmode_output = output->driver_private; 2035 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2036 xf86OutputStatus status; 2037 drmModeFreeConnector(drmmode_output->mode_output); 2038 2039 drmmode_output->mode_output = 2040 drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id); 2041 if (!drmmode_output->mode_output) { 2042 drmmode_output->output_id = -1; 2043 return XF86OutputStatusDisconnected; 2044 } 2045 2046 drmmode_output_update_properties(output); 2047 2048 switch (drmmode_output->mode_output->connection) { 2049 case DRM_MODE_CONNECTED: 2050 status = XF86OutputStatusConnected; 2051 break; 2052 case DRM_MODE_DISCONNECTED: 2053 status = XF86OutputStatusDisconnected; 2054 break; 2055 default: 2056 case DRM_MODE_UNKNOWNCONNECTION: 2057 status = XF86OutputStatusUnknown; 2058 break; 2059 } 2060 return status; 2061} 2062 2063static Bool 2064drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 2065{ 2066 return MODE_OK; 2067} 2068 2069static void 2070drmmode_output_attach_tile(xf86OutputPtr output) 2071{ 2072#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 2073 drmmode_output_private_ptr drmmode_output = output->driver_private; 2074 drmModeConnectorPtr koutput = drmmode_output->mode_output; 2075 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2076 struct xf86CrtcTileInfo tile_info, *set = NULL; 2077 int i; 2078 2079 if (!koutput) { 2080 xf86OutputSetTile(output, NULL); 2081 return; 2082 } 2083 2084 /* look for a TILE property */ 2085 for (i = 0; i < koutput->count_props; i++) { 2086 drmModePropertyPtr props; 2087 props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]); 2088 if (!props) 2089 continue; 2090 2091 if (!(props->flags & DRM_MODE_PROP_BLOB)) { 2092 drmModeFreeProperty(props); 2093 continue; 2094 } 2095 2096 if (!strcmp(props->name, "TILE")) { 2097 drmModeFreePropertyBlob(drmmode_output->tile_blob); 2098 drmmode_output->tile_blob = 2099 drmModeGetPropertyBlob(pAMDGPUEnt->fd, 2100 koutput->prop_values[i]); 2101 } 2102 drmModeFreeProperty(props); 2103 } 2104 if (drmmode_output->tile_blob) { 2105 if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, 2106 drmmode_output->tile_blob->length, 2107 &tile_info) == TRUE) 2108 set = &tile_info; 2109 } 2110 xf86OutputSetTile(output, set); 2111#endif 2112} 2113 2114static int 2115koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 2116 int type, const char *name) 2117{ 2118 int idx = -1; 2119 2120 for (int i = 0; i < koutput->count_props; i++) { 2121 drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 2122 2123 if (!prop) 2124 continue; 2125 2126 if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 2127 idx = i; 2128 2129 drmModeFreeProperty(prop); 2130 2131 if (idx > -1) 2132 break; 2133 } 2134 2135 return idx; 2136} 2137 2138static int 2139koutput_get_prop_id(int fd, drmModeConnectorPtr koutput, 2140 int type, const char *name) 2141{ 2142 int idx = koutput_get_prop_idx(fd, koutput, type, name); 2143 2144 return (idx > -1) ? koutput->props[idx] : -1; 2145} 2146 2147static drmModePropertyBlobPtr 2148koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 2149{ 2150 drmModePropertyBlobPtr blob = NULL; 2151 int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 2152 2153 if (idx > -1) 2154 blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 2155 2156 return blob; 2157} 2158 2159static DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) 2160{ 2161 drmmode_output_private_ptr drmmode_output = output->driver_private; 2162 drmModeConnectorPtr koutput = drmmode_output->mode_output; 2163 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2164 int i; 2165 DisplayModePtr Modes = NULL, Mode; 2166 xf86MonPtr mon = NULL; 2167 2168 if (!koutput) 2169 return NULL; 2170 2171 drmModeFreePropertyBlob(drmmode_output->edid_blob); 2172 2173 /* look for an EDID property */ 2174 drmmode_output->edid_blob = 2175 koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "EDID"); 2176 2177 if (drmmode_output->edid_blob) { 2178 mon = xf86InterpretEDID(output->scrn->scrnIndex, 2179 drmmode_output->edid_blob->data); 2180 if (mon && drmmode_output->edid_blob->length > 128) 2181 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 2182 } 2183 xf86OutputSetEDID(output, mon); 2184 2185 drmmode_output_attach_tile(output); 2186 2187 /* modes should already be available */ 2188 for (i = 0; i < koutput->count_modes; i++) { 2189 Mode = xnfalloc(sizeof(DisplayModeRec)); 2190 2191 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 2192 Mode); 2193 Modes = xf86ModesAdd(Modes, Mode); 2194 2195 } 2196 return Modes; 2197} 2198 2199static void drmmode_output_destroy(xf86OutputPtr output) 2200{ 2201 drmmode_output_private_ptr drmmode_output = output->driver_private; 2202 int i; 2203 2204 drmModeFreePropertyBlob(drmmode_output->edid_blob); 2205#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0) 2206 drmModeFreePropertyBlob(drmmode_output->tile_blob); 2207#endif 2208 2209 for (i = 0; i < drmmode_output->num_props; i++) { 2210 drmModeFreeProperty(drmmode_output->props[i].mode_prop); 2211 free(drmmode_output->props[i].atoms); 2212 } 2213 for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 2214 drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 2215 } 2216 free(drmmode_output->mode_encoders); 2217 free(drmmode_output->props); 2218 drmModeFreeConnector(drmmode_output->mode_output); 2219 free(drmmode_output); 2220 output->driver_private = NULL; 2221} 2222 2223static void drmmode_output_dpms(xf86OutputPtr output, int mode) 2224{ 2225 drmmode_output_private_ptr drmmode_output = output->driver_private; 2226 xf86CrtcPtr crtc = output->crtc; 2227 drmModeConnectorPtr koutput = drmmode_output->mode_output; 2228 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2229 2230 if (!koutput) 2231 return; 2232 2233 if (mode != DPMSModeOn && crtc) 2234 drmmode_do_crtc_dpms(crtc, mode); 2235 2236 drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id, 2237 drmmode_output->dpms_enum_id, mode); 2238 2239 if (mode == DPMSModeOn && crtc) { 2240 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2241 2242 if (drmmode_crtc->need_modeset) 2243 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2244 crtc->x, crtc->y); 2245 else 2246 drmmode_do_crtc_dpms(output->crtc, mode); 2247 } 2248} 2249 2250static Bool drmmode_property_ignore(drmModePropertyPtr prop) 2251{ 2252 if (!prop) 2253 return TRUE; 2254 /* ignore blob prop */ 2255 if (prop->flags & DRM_MODE_PROP_BLOB) 2256 return TRUE; 2257 /* ignore standard property */ 2258 if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS")) 2259 return TRUE; 2260 2261 return FALSE; 2262} 2263 2264static void drmmode_output_create_resources(xf86OutputPtr output) 2265{ 2266 AMDGPUInfoPtr info = AMDGPUPTR(output->scrn); 2267 drmmode_output_private_ptr drmmode_output = output->driver_private; 2268 drmmode_crtc_private_ptr drmmode_crtc; 2269 drmModeConnectorPtr mode_output = drmmode_output->mode_output; 2270 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2271 drmModePropertyPtr drmmode_prop, tearfree_prop; 2272 int i, j, err; 2273 Atom name; 2274 2275 /* Create CONNECTOR_ID property */ 2276 name = MakeAtom("CONNECTOR_ID", 12, TRUE); 2277 if (name != BAD_RESOURCE) { 2278 INT32 value = mode_output->connector_id; 2279 2280 err = RRConfigureOutputProperty(output->randr_output, name, 2281 FALSE, FALSE, TRUE, 1, &value); 2282 if (err != Success) { 2283 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2284 "RRConfigureOutputProperty error, %d\n", err); 2285 } 2286 2287 err = RRChangeOutputProperty(output->randr_output, name, 2288 XA_INTEGER, 32, PropModeReplace, 1, 2289 &value, FALSE, FALSE); 2290 if (err != Success) { 2291 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2292 "RRChangeOutputProperty error, %d\n", err); 2293 } 2294 } 2295 2296 drmmode_output->props = 2297 calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec)); 2298 if (!drmmode_output->props) 2299 return; 2300 2301 drmmode_output->num_props = 0; 2302 for (i = 0, j = 0; i < mode_output->count_props; i++) { 2303 drmmode_prop = 2304 drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]); 2305 if (drmmode_property_ignore(drmmode_prop)) { 2306 drmModeFreeProperty(drmmode_prop); 2307 continue; 2308 } 2309 drmmode_output->props[j].mode_prop = drmmode_prop; 2310 drmmode_output->props[j].value = mode_output->prop_values[i]; 2311 drmmode_output->num_props++; 2312 j++; 2313 } 2314 2315 /* Userspace-only property for TearFree */ 2316 tearfree_prop = calloc(1, sizeof(*tearfree_prop)); 2317 tearfree_prop->flags = DRM_MODE_PROP_ENUM; 2318 strcpy(tearfree_prop->name, "TearFree"); 2319 tearfree_prop->count_enums = 3; 2320 tearfree_prop->enums = calloc(tearfree_prop->count_enums, 2321 sizeof(*tearfree_prop->enums)); 2322 strcpy(tearfree_prop->enums[0].name, "off"); 2323 strcpy(tearfree_prop->enums[1].name, "on"); 2324 tearfree_prop->enums[1].value = 1; 2325 strcpy(tearfree_prop->enums[2].name, "auto"); 2326 tearfree_prop->enums[2].value = 2; 2327 drmmode_output->props[j].mode_prop = tearfree_prop; 2328 drmmode_output->props[j].value = info->tear_free; 2329 drmmode_output->tear_free = info->tear_free; 2330 drmmode_output->num_props++; 2331 2332 for (i = 0; i < drmmode_output->num_props; i++) { 2333 drmmode_prop_ptr p = &drmmode_output->props[i]; 2334 drmmode_prop = p->mode_prop; 2335 2336 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 2337 INT32 range[2]; 2338 INT32 value = p->value; 2339 2340 p->num_atoms = 1; 2341 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2342 if (!p->atoms) 2343 continue; 2344 p->atoms[0] = 2345 MakeAtom(drmmode_prop->name, 2346 strlen(drmmode_prop->name), TRUE); 2347 range[0] = drmmode_prop->values[0]; 2348 range[1] = drmmode_prop->values[1]; 2349 err = 2350 RRConfigureOutputProperty(output->randr_output, 2351 p->atoms[0], FALSE, TRUE, 2352 drmmode_prop->flags & 2353 DRM_MODE_PROP_IMMUTABLE ? 2354 TRUE : FALSE, 2, range); 2355 if (err != 0) { 2356 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2357 "RRConfigureOutputProperty error, %d\n", 2358 err); 2359 } 2360 err = 2361 RRChangeOutputProperty(output->randr_output, 2362 p->atoms[0], XA_INTEGER, 32, 2363 PropModeReplace, 1, &value, 2364 FALSE, TRUE); 2365 if (err != 0) { 2366 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2367 "RRChangeOutputProperty error, %d\n", 2368 err); 2369 } 2370 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 2371 p->num_atoms = drmmode_prop->count_enums + 1; 2372 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 2373 if (!p->atoms) 2374 continue; 2375 p->atoms[0] = 2376 MakeAtom(drmmode_prop->name, 2377 strlen(drmmode_prop->name), TRUE); 2378 for (j = 1; j <= drmmode_prop->count_enums; j++) { 2379 struct drm_mode_property_enum *e = 2380 &drmmode_prop->enums[j - 1]; 2381 p->atoms[j] = 2382 MakeAtom(e->name, strlen(e->name), TRUE); 2383 } 2384 err = 2385 RRConfigureOutputProperty(output->randr_output, 2386 p->atoms[0], FALSE, FALSE, 2387 drmmode_prop->flags & 2388 DRM_MODE_PROP_IMMUTABLE ? 2389 TRUE : FALSE, 2390 p->num_atoms - 1, 2391 (INT32 *) & p->atoms[1]); 2392 if (err != 0) { 2393 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2394 "RRConfigureOutputProperty error, %d\n", 2395 err); 2396 } 2397 for (j = 0; j < drmmode_prop->count_enums; j++) 2398 if (drmmode_prop->enums[j].value == p->value) 2399 break; 2400 /* there's always a matching value */ 2401 err = 2402 RRChangeOutputProperty(output->randr_output, 2403 p->atoms[0], XA_ATOM, 32, 2404 PropModeReplace, 1, 2405 &p->atoms[j + 1], FALSE, 2406 TRUE); 2407 if (err != 0) { 2408 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2409 "RRChangeOutputProperty error, %d\n", 2410 err); 2411 } 2412 } 2413 } 2414 2415 /* Do not configure cm properties on output if there's no support. */ 2416 if (!drmmode_cm_enabled(drmmode_output->drmmode)) 2417 return; 2418 2419 drmmode_crtc = output->crtc ? output->crtc->driver_private : NULL; 2420 2421 for (i = 0; i < CM_NUM_PROPS; i++) 2422 rr_configure_and_change_cm_property(output, drmmode_crtc, i); 2423} 2424 2425static void 2426drmmode_output_set_tear_free(AMDGPUEntPtr pAMDGPUEnt, 2427 drmmode_output_private_ptr drmmode_output, 2428 xf86CrtcPtr crtc, int tear_free) 2429{ 2430 if (drmmode_output->tear_free == tear_free) 2431 return; 2432 2433 drmmode_output->tear_free = tear_free; 2434 2435 if (crtc) { 2436 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 2437 crtc->x, crtc->y); 2438 } 2439} 2440 2441static Bool 2442drmmode_output_set_property(xf86OutputPtr output, Atom property, 2443 RRPropertyValuePtr value) 2444{ 2445 drmmode_output_private_ptr drmmode_output = output->driver_private; 2446 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 2447 enum drmmode_cm_prop cm_prop_index; 2448 int i; 2449 2450 cm_prop_index = get_cm_enum_from_str(NameForAtom(property)); 2451 if (cm_prop_index >= 0 && cm_prop_index < CM_DEGAMMA_LUT_SIZE) { 2452 if (!output->crtc) 2453 return FALSE; 2454 if (drmmode_crtc_stage_cm_prop(output->crtc, cm_prop_index, 2455 value)) 2456 return FALSE; 2457 if (drmmode_crtc_push_cm_prop(output->crtc, cm_prop_index)) 2458 return FALSE; 2459 return TRUE; 2460 } 2461 2462 for (i = 0; i < drmmode_output->num_props; i++) { 2463 drmmode_prop_ptr p = &drmmode_output->props[i]; 2464 2465 if (p->atoms[0] != property) 2466 continue; 2467 2468 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 2469 uint32_t val; 2470 2471 if (value->type != XA_INTEGER || value->format != 32 || 2472 value->size != 1) 2473 return FALSE; 2474 val = *(uint32_t *) value->data; 2475 2476 drmModeConnectorSetProperty(pAMDGPUEnt->fd, 2477 drmmode_output->output_id, 2478 p->mode_prop->prop_id, 2479 (uint64_t) val); 2480 return TRUE; 2481 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 2482 Atom atom; 2483 const char *name; 2484 int j; 2485 2486 if (value->type != XA_ATOM || value->format != 32 2487 || value->size != 1) 2488 return FALSE; 2489 memcpy(&atom, value->data, 4); 2490 if (!(name = NameForAtom(atom))) 2491 return FALSE; 2492 2493 /* search for matching name string, then set its value down */ 2494 for (j = 0; j < p->mode_prop->count_enums; j++) { 2495 if (!strcmp(p->mode_prop->enums[j].name, name)) { 2496 if (i == (drmmode_output->num_props - 1)) { 2497 drmmode_output_set_tear_free(pAMDGPUEnt, 2498 drmmode_output, 2499 output->crtc, j); 2500 } else { 2501 drmModeConnectorSetProperty(pAMDGPUEnt->fd, 2502 drmmode_output->output_id, 2503 p->mode_prop->prop_id, 2504 p->mode_prop->enums[j].value); 2505 } 2506 2507 return TRUE; 2508 } 2509 } 2510 } 2511 } 2512 2513 return TRUE; 2514} 2515 2516static Bool drmmode_output_get_property(xf86OutputPtr output, Atom property) 2517{ 2518 drmmode_crtc_private_ptr drmmode_crtc; 2519 enum drmmode_cm_prop cm_prop_id; 2520 int ret; 2521 2522 /* First, see if it's a cm property */ 2523 cm_prop_id = get_cm_enum_from_str(NameForAtom(property)); 2524 if (output->crtc && cm_prop_id != CM_INVALID_PROP) { 2525 drmmode_crtc = output->crtc->driver_private; 2526 2527 ret = rr_configure_and_change_cm_property(output, drmmode_crtc, 2528 cm_prop_id); 2529 if (ret) { 2530 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 2531 "Error getting color property: %d\n", 2532 ret); 2533 return FALSE; 2534 } 2535 return TRUE; 2536 } 2537 2538 /* Otherwise, must be an output property. */ 2539 return TRUE; 2540} 2541 2542static const xf86OutputFuncsRec drmmode_output_funcs = { 2543 .dpms = drmmode_output_dpms, 2544 .create_resources = drmmode_output_create_resources, 2545 .set_property = drmmode_output_set_property, 2546 .get_property = drmmode_output_get_property, 2547 .detect = drmmode_output_detect, 2548 .mode_valid = drmmode_output_mode_valid, 2549 2550 .get_modes = drmmode_output_get_modes, 2551 .destroy = drmmode_output_destroy 2552}; 2553 2554static int subpixel_conv_table[7] = { 0, SubPixelUnknown, 2555 SubPixelHorizontalRGB, 2556 SubPixelHorizontalBGR, 2557 SubPixelVerticalRGB, 2558 SubPixelVerticalBGR, 2559 SubPixelNone 2560}; 2561 2562const char *output_names[] = { "None", 2563 "VGA", 2564 "DVI-I", 2565 "DVI-D", 2566 "DVI-A", 2567 "Composite", 2568 "S-video", 2569 "LVDS", 2570 "CTV", 2571 "DIN", 2572 "DisplayPort", 2573 "HDMI-A", 2574 "HDMI-B", 2575 "TV", 2576 "eDP", 2577 "Virtual", 2578 "DSI", 2579}; 2580 2581#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 2582 2583static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 2584{ 2585 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2586 int i; 2587 for (i = 0; i < xf86_config->num_output; i++) { 2588 xf86OutputPtr output = xf86_config->output[i]; 2589 drmmode_output_private_ptr drmmode_output; 2590 drmmode_output = output->driver_private; 2591 if (drmmode_output->output_id == id) 2592 return output; 2593 } 2594 return NULL; 2595} 2596 2597static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 2598{ 2599 char *conn; 2600 char conn_id[5]; 2601 int id, len; 2602 char *blob_data; 2603 2604 if (!path_blob) 2605 return -1; 2606 2607 blob_data = path_blob->data; 2608 /* we only handle MST paths for now */ 2609 if (strncmp(blob_data, "mst:", 4)) 2610 return -1; 2611 2612 conn = strchr(blob_data + 4, '-'); 2613 if (!conn) 2614 return -1; 2615 len = conn - (blob_data + 4); 2616 if (len + 1 > 5) 2617 return -1; 2618 memcpy(conn_id, blob_data + 4, len); 2619 conn_id[len] = '\0'; 2620 id = strtoul(conn_id, NULL, 10); 2621 2622 *conn_base_id = id; 2623 2624 *path = conn + 1; 2625 return 0; 2626} 2627 2628static void 2629drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 2630 drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 2631{ 2632 xf86OutputPtr output; 2633 int conn_id; 2634 char *extra_path; 2635 2636 output = NULL; 2637 if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 2638 output = find_output(pScrn, conn_id); 2639 if (output) { 2640 snprintf(name, 32, "%s-%s", output->name, extra_path); 2641 } else { 2642 if (koutput->connector_type >= NUM_OUTPUT_NAMES) { 2643 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1); 2644 } else if (pScrn->is_gpu) { 2645 snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], 2646 pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); 2647 } else { 2648 /* need to do smart conversion here for compat with non-kms ATI driver */ 2649 if (koutput->connector_type_id == 1) { 2650 switch(koutput->connector_type) { 2651 case DRM_MODE_CONNECTOR_DVII: 2652 case DRM_MODE_CONNECTOR_DVID: 2653 case DRM_MODE_CONNECTOR_DVIA: 2654 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 2655 (*num_dvi)++; 2656 break; 2657 case DRM_MODE_CONNECTOR_HDMIA: 2658 case DRM_MODE_CONNECTOR_HDMIB: 2659 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 2660 (*num_hdmi)++; 2661 break; 2662 case DRM_MODE_CONNECTOR_VGA: 2663 case DRM_MODE_CONNECTOR_DisplayPort: 2664 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2665 break; 2666 default: 2667 snprintf(name, 32, "%s", output_names[koutput->connector_type]); 2668 break; 2669 } 2670 } else { 2671 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 2672 } 2673 } 2674 } 2675} 2676 2677 2678static unsigned int 2679drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 2680{ 2681 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2682 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2683 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2684 xf86OutputPtr output; 2685 drmModeConnectorPtr koutput; 2686 drmModeEncoderPtr *kencoders = NULL; 2687 drmmode_output_private_ptr drmmode_output; 2688 drmModePropertyBlobPtr path_blob = NULL; 2689#if XF86_CRTC_VERSION >= 8 2690 Bool nonDesktop = FALSE; 2691#endif 2692 char name[32]; 2693 int i; 2694 const char *s; 2695 2696 koutput = 2697 drmModeGetConnector(pAMDGPUEnt->fd, 2698 mode_res->connectors[num]); 2699 if (!koutput) 2700 return 0; 2701 2702 path_blob = koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "PATH"); 2703 2704#if XF86_CRTC_VERSION >= 8 2705 i = koutput_get_prop_idx(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_RANGE, 2706 "non-desktop"); 2707 if (i >= 0) 2708 nonDesktop = koutput->prop_values[i] != 0; 2709#endif 2710 2711 kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 2712 if (!kencoders) { 2713 goto out_free_encoders; 2714 } 2715 2716 for (i = 0; i < koutput->count_encoders; i++) { 2717 kencoders[i] = 2718 drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]); 2719 if (!kencoders[i]) { 2720 goto out_free_encoders; 2721 } 2722 } 2723 2724 drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 2725 if (path_blob) { 2726 drmModeFreePropertyBlob(path_blob); 2727 } 2728 2729 if (path_blob && dynamic) { 2730 /* See if we have an output with this name already 2731 * and hook stuff up. 2732 */ 2733 for (i = 0; i < xf86_config->num_output; i++) { 2734 output = xf86_config->output[i]; 2735 2736 if (strncmp(output->name, name, 32)) 2737 continue; 2738 2739 drmmode_output = output->driver_private; 2740 drmmode_output->output_id = mode_res->connectors[num]; 2741 drmmode_output->mode_output = koutput; 2742#if XF86_CRTC_VERSION >= 8 2743 output->non_desktop = nonDesktop; 2744#endif 2745 for (i = 0; i < koutput->count_encoders; i++) { 2746 drmModeFreeEncoder(kencoders[i]); 2747 } 2748 free(kencoders); 2749 return 1; 2750 } 2751 } 2752 2753 if (xf86IsEntityShared(pScrn->entityList[0])) { 2754 if ((s = 2755 xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 2756 if (!AMDGPUZaphodStringMatches(pScrn, s, name)) 2757 goto out_free_encoders; 2758 } else { 2759 if (info->instance_id != num) 2760 goto out_free_encoders; 2761 } 2762 } 2763 2764 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); 2765 if (!output) { 2766 goto out_free_encoders; 2767 } 2768 2769 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 2770 if (!drmmode_output) { 2771 xf86OutputDestroy(output); 2772 goto out_free_encoders; 2773 } 2774 2775 drmmode_output->output_id = mode_res->connectors[num]; 2776 drmmode_output->mode_output = koutput; 2777 drmmode_output->mode_encoders = kencoders; 2778 drmmode_output->drmmode = drmmode; 2779 output->mm_width = koutput->mmWidth; 2780 output->mm_height = koutput->mmHeight; 2781 2782 output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 2783 output->interlaceAllowed = TRUE; 2784 output->doubleScanAllowed = TRUE; 2785 output->driver_private = drmmode_output; 2786#if XF86_CRTC_VERSION >= 8 2787 output->non_desktop = nonDesktop; 2788#endif 2789 2790 output->possible_crtcs = 0xffffffff; 2791 for (i = 0; i < koutput->count_encoders; i++) { 2792 output->possible_crtcs &= kencoders[i]->possible_crtcs; 2793 } 2794 /* work out the possible clones later */ 2795 output->possible_clones = 0; 2796 2797 drmmode_output->dpms_enum_id = 2798 koutput_get_prop_id(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_ENUM, 2799 "DPMS"); 2800 2801 if (dynamic) { 2802 output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 2803 drmmode_output_create_resources(output); 2804 } 2805 2806 return 1; 2807out_free_encoders: 2808 if (kencoders) { 2809 for (i = 0; i < koutput->count_encoders; i++) 2810 drmModeFreeEncoder(kencoders[i]); 2811 free(kencoders); 2812 } 2813 drmModeFreeConnector(koutput); 2814 return 0; 2815} 2816 2817uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2818{ 2819 drmmode_output_private_ptr drmmode_output = 2820 output->driver_private, clone_drmout; 2821 int i; 2822 xf86OutputPtr clone_output; 2823 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2824 int index_mask = 0; 2825 2826 if (drmmode_output->enc_clone_mask == 0) 2827 return index_mask; 2828 2829 for (i = 0; i < xf86_config->num_output; i++) { 2830 clone_output = xf86_config->output[i]; 2831 clone_drmout = clone_output->driver_private; 2832 if (output == clone_output) 2833 continue; 2834 2835 if (clone_drmout->enc_mask == 0) 2836 continue; 2837 if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 2838 index_mask |= (1 << i); 2839 } 2840 return index_mask; 2841} 2842 2843static void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 2844{ 2845 int i, j; 2846 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2847 2848 for (i = 0; i < xf86_config->num_output; i++) { 2849 xf86OutputPtr output = xf86_config->output[i]; 2850 drmmode_output_private_ptr drmmode_output; 2851 2852 drmmode_output = output->driver_private; 2853 drmmode_output->enc_clone_mask = 0xff; 2854 /* and all the possible encoder clones for this output together */ 2855 for (j = 0; j < drmmode_output->mode_output->count_encoders; 2856 j++) { 2857 int k; 2858 for (k = 0; k < mode_res->count_encoders; k++) { 2859 if (mode_res->encoders[k] == 2860 drmmode_output-> 2861 mode_encoders[j]->encoder_id) 2862 drmmode_output->enc_mask |= (1 << k); 2863 } 2864 2865 drmmode_output->enc_clone_mask &= 2866 drmmode_output->mode_encoders[j]->possible_clones; 2867 } 2868 } 2869 2870 for (i = 0; i < xf86_config->num_output; i++) { 2871 xf86OutputPtr output = xf86_config->output[i]; 2872 output->possible_clones = find_clones(scrn, output); 2873 } 2874} 2875 2876/* returns pitch alignment in pixels */ 2877int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe) 2878{ 2879 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2880 2881 if (info->have_tiling_info) 2882 /* linear aligned requirements */ 2883 return MAX(64, info->group_bytes / bpe); 2884 else 2885 /* default to 512 elements if we don't know the real 2886 * group size otherwise the kernel may reject the CS 2887 * if the group sizes don't match as the pitch won't 2888 * be aligned properly. 2889 */ 2890 return 512; 2891} 2892 2893static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 2894{ 2895 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2896 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 2897 struct amdgpu_buffer *old_front = NULL; 2898 ScreenPtr screen = xf86ScrnToScreen(scrn); 2899 int i, pitch, old_width, old_height, old_pitch; 2900 int cpp = info->pixel_bytes; 2901 PixmapPtr ppix = screen->GetScreenPixmap(screen); 2902 int hint = AMDGPU_CREATE_PIXMAP_SCANOUT; 2903 void *fb_shadow; 2904 2905 if (scrn->virtualX == width && scrn->virtualY == height) 2906 return TRUE; 2907 2908 if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) { 2909 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2910 "Xorg tried resizing screen to %dx%d, but maximum " 2911 "supported is %dx%d\n", width, height, 2912 xf86_config->maxWidth, xf86_config->maxHeight); 2913 return FALSE; 2914 } 2915 2916 if (info->shadow_primary) 2917 hint |= AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT; 2918 else if (!info->use_glamor) 2919 hint |= AMDGPU_CREATE_PIXMAP_LINEAR; 2920 2921 xf86DrvMsg(scrn->scrnIndex, X_INFO, 2922 "Allocate new frame buffer %dx%d\n", width, height); 2923 2924 old_width = scrn->virtualX; 2925 old_height = scrn->virtualY; 2926 old_pitch = scrn->displayWidth; 2927 old_front = info->front_buffer; 2928 2929 scrn->virtualX = width; 2930 scrn->virtualY = height; 2931 2932 info->front_buffer = 2933 amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY, 2934 scrn->depth, hint, scrn->bitsPerPixel, 2935 &pitch); 2936 if (!info->front_buffer) { 2937 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2938 "Failed to allocate front buffer memory\n"); 2939 goto fail; 2940 } 2941 2942 if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) { 2943 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2944 "Failed to map front buffer memory\n"); 2945 goto fail; 2946 } 2947 2948 xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch); 2949 scrn->displayWidth = pitch / cpp; 2950 2951 if (info->use_glamor || 2952 (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 2953 screen->ModifyPixmapHeader(ppix, 2954 width, height, -1, -1, pitch, info->front_buffer->cpu_ptr); 2955 } else { 2956 fb_shadow = calloc(1, pitch * scrn->virtualY); 2957 if (!fb_shadow) 2958 goto fail; 2959 free(info->fb_shadow); 2960 info->fb_shadow = fb_shadow; 2961 screen->ModifyPixmapHeader(ppix, 2962 width, height, -1, -1, pitch, 2963 info->fb_shadow); 2964 } 2965 2966 if (!amdgpu_glamor_create_screen_resources(scrn->pScreen)) 2967 goto fail; 2968 2969 if (info->use_glamor || info->dri2.enabled) { 2970 if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer)) 2971 goto fail; 2972 } 2973 2974 amdgpu_pixmap_clear(ppix); 2975 amdgpu_glamor_finish(scrn); 2976 2977 for (i = 0; i < xf86_config->num_crtc; i++) { 2978 xf86CrtcPtr crtc = xf86_config->crtc[i]; 2979 2980 if (!crtc->enabled) 2981 continue; 2982 2983 drmmode_set_mode_major(crtc, &crtc->mode, 2984 crtc->rotation, crtc->x, crtc->y); 2985 } 2986 2987 if (old_front) { 2988 amdgpu_bo_unref(&old_front); 2989 } 2990 2991 return TRUE; 2992 2993fail: 2994 if (info->front_buffer) { 2995 amdgpu_bo_unref(&info->front_buffer); 2996 } 2997 info->front_buffer = old_front; 2998 scrn->virtualX = old_width; 2999 scrn->virtualY = old_height; 3000 scrn->displayWidth = old_pitch; 3001 3002 return FALSE; 3003} 3004 3005static void 3006drmmode_validate_leases(ScrnInfoPtr scrn) 3007{ 3008#ifdef XF86_LEASE_VERSION 3009 ScreenPtr screen = scrn->pScreen; 3010 rrScrPrivPtr scr_priv = rrGetScrPriv(screen); 3011 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3012 drmModeLesseeListPtr lessees; 3013 RRLeasePtr lease, next; 3014 int l; 3015 3016 /* We can't talk to the kernel about leases when VT switched */ 3017 if (!scrn->vtSema) 3018 return; 3019 3020 lessees = drmModeListLessees(pAMDGPUEnt->fd); 3021 if (!lessees) 3022 return; 3023 3024 xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) { 3025 drmmode_lease_private_ptr lease_private = lease->devPrivate; 3026 3027 for (l = 0; l < lessees->count; l++) { 3028 if (lessees->lessees[l] == lease_private->lessee_id) 3029 break; 3030 } 3031 3032 /* check to see if the lease has gone away */ 3033 if (l == lessees->count) { 3034 free(lease_private); 3035 lease->devPrivate = NULL; 3036 xf86CrtcLeaseTerminated(lease); 3037 } 3038 } 3039 3040 free(lessees); 3041#endif 3042} 3043 3044#ifdef XF86_LEASE_VERSION 3045 3046static int 3047drmmode_create_lease(RRLeasePtr lease, int *fd) 3048{ 3049 ScreenPtr screen = lease->screen; 3050 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3051 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3052 drmmode_lease_private_ptr lease_private; 3053 int noutput = lease->numOutputs; 3054 int ncrtc = lease->numCrtcs; 3055 uint32_t *objects; 3056 size_t nobjects; 3057 int lease_fd; 3058 int c, o; 3059 int i; 3060 3061 nobjects = ncrtc + noutput; 3062 if (nobjects == 0 || nobjects > (SIZE_MAX / 4) || 3063 ncrtc > (SIZE_MAX - noutput)) 3064 return BadValue; 3065 3066 lease_private = calloc(1, sizeof (drmmode_lease_private_rec)); 3067 if (!lease_private) 3068 return BadAlloc; 3069 3070 objects = malloc(nobjects * 4); 3071 if (!objects) { 3072 free(lease_private); 3073 return BadAlloc; 3074 } 3075 3076 i = 0; 3077 3078 /* Add CRTC ids */ 3079 for (c = 0; c < ncrtc; c++) { 3080 xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate; 3081 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3082 3083 objects[i++] = drmmode_crtc->mode_crtc->crtc_id; 3084 } 3085 3086 /* Add connector ids */ 3087 for (o = 0; o < noutput; o++) { 3088 xf86OutputPtr output = lease->outputs[o]->devPrivate; 3089 drmmode_output_private_ptr drmmode_output = output->driver_private; 3090 3091 objects[i++] = drmmode_output->mode_output->connector_id; 3092 } 3093 3094 /* call kernel to create lease */ 3095 assert (i == nobjects); 3096 3097 lease_fd = drmModeCreateLease(pAMDGPUEnt->fd, objects, nobjects, 0, 3098 &lease_private->lessee_id); 3099 3100 free(objects); 3101 3102 if (lease_fd < 0) { 3103 free(lease_private); 3104 return BadMatch; 3105 } 3106 3107 lease->devPrivate = lease_private; 3108 3109 xf86CrtcLeaseStarted(lease); 3110 3111 *fd = lease_fd; 3112 return Success; 3113} 3114 3115static void 3116drmmode_terminate_lease(RRLeasePtr lease) 3117{ 3118 drmmode_lease_private_ptr lease_private = lease->devPrivate; 3119 ScreenPtr screen = lease->screen; 3120 ScrnInfoPtr scrn = xf86ScreenToScrn(screen); 3121 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3122 3123 if (drmModeRevokeLease(pAMDGPUEnt->fd, lease_private->lessee_id) == 0) { 3124 free(lease_private); 3125 lease->devPrivate = NULL; 3126 xf86CrtcLeaseTerminated(lease); 3127 } 3128} 3129 3130#endif // XF86_LEASE_VERSION 3131 3132static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 3133 .resize = drmmode_xf86crtc_resize, 3134#ifdef XF86_LEASE_VERSION 3135 .create_lease = drmmode_create_lease, 3136 .terminate_lease = drmmode_terminate_lease 3137#endif 3138}; 3139 3140static void 3141drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 3142{ 3143 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3144 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 3145 drmmode_flipdata_ptr flipdata = event_data; 3146 int crtc_id = drmmode_get_crtc_id(crtc); 3147 struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 3148 3149 if (drmmode_crtc->flip_pending == *fb) { 3150 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 3151 NULL); 3152 } 3153 drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 3154 3155 if (--flipdata->flip_count == 0) { 3156 if (!flipdata->fe_crtc) 3157 flipdata->fe_crtc = crtc; 3158 flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 3159 free(flipdata); 3160 } 3161} 3162 3163static void 3164drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 3165{ 3166 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 3167 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3168 drmmode_flipdata_ptr flipdata = event_data; 3169 int crtc_id = drmmode_get_crtc_id(crtc); 3170 struct drmmode_fb **fb = &flipdata->fb[crtc_id]; 3171 3172 /* Is this the event whose info shall be delivered to higher level? */ 3173 if (crtc == flipdata->fe_crtc) { 3174 /* Yes: Cache msc, ust for later delivery. */ 3175 flipdata->fe_frame = frame; 3176 flipdata->fe_usec = usec; 3177 } 3178 3179 if (*fb) { 3180 if (drmmode_crtc->flip_pending == *fb) { 3181 drmmode_fb_reference(pAMDGPUEnt->fd, 3182 &drmmode_crtc->flip_pending, NULL); 3183 } 3184 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, *fb); 3185 drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL); 3186 } 3187 3188 if (--flipdata->flip_count == 0) { 3189 /* Deliver MSC & UST from reference/current CRTC to flip event 3190 * handler 3191 */ 3192 if (flipdata->fe_crtc) 3193 flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 3194 flipdata->fe_usec, flipdata->event_data); 3195 else 3196 flipdata->handler(crtc, frame, usec, flipdata->event_data); 3197 3198 free(flipdata); 3199 } 3200} 3201 3202#if HAVE_NOTIFY_FD 3203static void drmmode_notify_fd(int fd, int notify, void *data) 3204{ 3205 drmmode_ptr drmmode = data; 3206 amdgpu_drm_handle_event(fd, &drmmode->event_context); 3207} 3208#else 3209static void drm_wakeup_handler(pointer data, int err, pointer p) 3210{ 3211 drmmode_ptr drmmode = data; 3212 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn); 3213 fd_set *read_mask = p; 3214 3215 if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) { 3216 amdgpu_drm_handle_event(pAMDGPUEnt->fd, &drmmode->event_context); 3217 } 3218} 3219#endif 3220 3221static Bool drmmode_probe_page_flip_target(AMDGPUEntPtr pAMDGPUEnt) 3222{ 3223 uint64_t cap_value; 3224 3225 return drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, 3226 &cap_value) == 0 && cap_value != 0; 3227} 3228 3229static int 3230drmmode_page_flip(AMDGPUEntPtr pAMDGPUEnt, drmmode_crtc_private_ptr drmmode_crtc, 3231 int fb_id, uint32_t flags, uintptr_t drm_queue_seq) 3232{ 3233 flags |= DRM_MODE_PAGE_FLIP_EVENT; 3234 return drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 3235 fb_id, flags, (void*)drm_queue_seq); 3236} 3237 3238int 3239drmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt, 3240 drmmode_crtc_private_ptr drmmode_crtc, 3241 int fb_id, uint32_t flags, 3242 uintptr_t drm_queue_seq, uint32_t target_msc) 3243{ 3244 if (pAMDGPUEnt->has_page_flip_target) { 3245 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; 3246 return drmModePageFlipTarget(pAMDGPUEnt->fd, 3247 drmmode_crtc->mode_crtc->crtc_id, 3248 fb_id, flags, (void*)drm_queue_seq, 3249 target_msc); 3250 } 3251 3252 return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 3253 drm_queue_seq); 3254} 3255 3256int 3257drmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt, 3258 drmmode_crtc_private_ptr drmmode_crtc, 3259 int fb_id, uint32_t flags, 3260 uintptr_t drm_queue_seq, uint32_t target_msc) 3261{ 3262 if (pAMDGPUEnt->has_page_flip_target) { 3263 flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; 3264 return drmModePageFlipTarget(pAMDGPUEnt->fd, 3265 drmmode_crtc->mode_crtc->crtc_id, 3266 fb_id, flags, (void*)drm_queue_seq, 3267 target_msc); 3268 } 3269 3270 return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, 3271 drm_queue_seq); 3272} 3273 3274/** 3275 * Initialize DDX color management support. It does two things: 3276 * 3277 * 1. Cache DRM color management property type IDs, as they do not change. They 3278 * will be used later to modify color management via DRM, or to determine if 3279 * there's kernel support for color management. 3280 * 3281 * 2. Cache degamma/gamma LUT sizes, since all CRTCs have the same LUT sizes on 3282 * AMD hardware. 3283 * 3284 * If the cached ID's are all 0 after calling this function, then color 3285 * management is not supported. For short, checking if the gamma LUT size 3286 * property ID == 0 is sufficient. 3287 * 3288 * This should be called before CRTCs are initialized within pre_init, as the 3289 * cached values will be used there. 3290 * 3291 * @drm_fd: DRM file descriptor 3292 * @drmmode: drmmode object, where the cached IDs are stored 3293 * @mode_res: The DRM mode resource containing the CRTC ids 3294 */ 3295static void drmmode_cm_init(int drm_fd, drmmode_ptr drmmode, 3296 drmModeResPtr mode_res) 3297{ 3298 drmModeObjectPropertiesPtr drm_props; 3299 drmModePropertyPtr drm_prop; 3300 enum drmmode_cm_prop cm_prop; 3301 uint32_t cm_enabled = 0; 3302 uint32_t cm_all_enabled = (1 << CM_NUM_PROPS) - 1; 3303 int i; 3304 3305 memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 3306 drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 3307 3308 if (!mode_res->crtcs) 3309 return; 3310 3311 /* AMD hardware has color management support on all pipes. It is 3312 * therefore sufficient to only check the first CRTC. 3313 */ 3314 drm_props = drmModeObjectGetProperties(drm_fd, 3315 mode_res->crtcs[0], 3316 DRM_MODE_OBJECT_CRTC); 3317 if (!drm_props) 3318 return; 3319 3320 for (i = 0; i < drm_props->count_props; i++) { 3321 drm_prop = drmModeGetProperty(drm_fd, 3322 drm_props->props[i]); 3323 if (!drm_prop) 3324 continue; 3325 3326 cm_prop = get_cm_enum_from_str(drm_prop->name); 3327 if (cm_prop == CM_INVALID_PROP) 3328 continue; 3329 3330 if (cm_prop == CM_DEGAMMA_LUT_SIZE) 3331 drmmode->degamma_lut_size = drm_props->prop_values[i]; 3332 else if (cm_prop == CM_GAMMA_LUT_SIZE) 3333 drmmode->gamma_lut_size = drm_props->prop_values[i]; 3334 3335 drmmode->cm_prop_ids[cm_prop] = drm_props->props[i]; 3336 cm_enabled |= 1 << cm_prop; 3337 3338 drmModeFreeProperty(drm_prop); 3339 } 3340 drmModeFreeObjectProperties(drm_props); 3341 3342 /* cm is enabled only if all prop ids are found */ 3343 if (cm_enabled == cm_all_enabled) 3344 return; 3345 3346 /* Otherwise, disable DDX cm support */ 3347 memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids)); 3348 drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0; 3349} 3350 3351Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 3352{ 3353 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3354 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3355 int i, num_dvi = 0, num_hdmi = 0; 3356 unsigned int crtcs_needed = 0; 3357 unsigned int crtcs_got = 0; 3358 drmModeResPtr mode_res; 3359 char *provider_name; 3360 3361 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 3362 3363 drmmode->scrn = pScrn; 3364 mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3365 if (!mode_res) 3366 return FALSE; 3367 3368 drmmode->count_crtcs = mode_res->count_crtcs; 3369 xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, 3370 mode_res->max_height); 3371 3372 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3373 "Initializing outputs ...\n"); 3374 for (i = 0; i < mode_res->count_connectors; i++) 3375 crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0); 3376 3377 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3378 "%d crtcs needed for screen.\n", crtcs_needed); 3379 3380 /* Need per-screen drmmode_crtc_funcs, based on our global template, 3381 * so we can disable some functions, depending on screen settings. 3382 */ 3383 info->drmmode_crtc_funcs = drmmode_crtc_funcs; 3384 3385 if (!info->use_glamor) { 3386 /* Rotation requires hardware acceleration */ 3387 info->drmmode_crtc_funcs.shadow_allocate = NULL; 3388 info->drmmode_crtc_funcs.shadow_create = NULL; 3389 info->drmmode_crtc_funcs.shadow_destroy = NULL; 3390 } 3391 3392 drmmode_cm_init(pAMDGPUEnt->fd, drmmode, mode_res); 3393 3394 /* Spare the server the effort to compute and update unused CLUTs. */ 3395 if (pScrn->depth == 30 && !drmmode_cm_enabled(drmmode)) 3396 info->drmmode_crtc_funcs.gamma_set = NULL; 3397 3398 for (i = 0; i < mode_res->count_crtcs; i++) { 3399 if (!xf86IsEntityShared(pScrn->entityList[0]) || 3400 (crtcs_got < crtcs_needed && 3401 !(pAMDGPUEnt->assigned_crtcs & (1 << i)))) 3402 crtcs_got += drmmode_crtc_init(pScrn, drmmode, mode_res, i); 3403 } 3404 3405 /* All ZaphodHeads outputs provided with matching crtcs? */ 3406 if (crtcs_got < crtcs_needed) { 3407 if (crtcs_got == 0) { 3408 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 3409 "No ZaphodHeads CRTC available, needed %u\n", 3410 crtcs_needed); 3411 return FALSE; 3412 } 3413 3414 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3415 "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 3416 crtcs_needed); 3417 } 3418 3419 /* workout clones */ 3420 drmmode_clones_init(pScrn, drmmode, mode_res); 3421 3422 XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, pAMDGPUEnt->busid); 3423 xf86ProviderSetup(pScrn, NULL, provider_name); 3424 free(provider_name); 3425 3426 xf86InitialConfiguration(pScrn, TRUE); 3427 3428 pAMDGPUEnt->has_page_flip_target = drmmode_probe_page_flip_target(pAMDGPUEnt); 3429 3430 drmModeFreeResources(mode_res); 3431 return TRUE; 3432} 3433 3434void drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3435{ 3436 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3437 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3438 3439 info->drmmode_inited = TRUE; 3440 if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) { 3441#if HAVE_NOTIFY_FD 3442 SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode); 3443#else 3444 AddGeneralSocket(pAMDGPUEnt->fd); 3445 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3446 drm_wakeup_handler, drmmode); 3447#endif 3448 pAMDGPUEnt->fd_wakeup_registered = serverGeneration; 3449 pAMDGPUEnt->fd_wakeup_ref = 1; 3450 } else 3451 pAMDGPUEnt->fd_wakeup_ref++; 3452} 3453 3454void drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 3455{ 3456 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3457 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 3458 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3459 int c; 3460 3461 if (!info->drmmode_inited) 3462 return; 3463 3464 for (c = 0; c < config->num_crtc; c++) 3465 drmmode_crtc_scanout_free(config->crtc[c]); 3466 3467 if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration && 3468 !--pAMDGPUEnt->fd_wakeup_ref) { 3469#if HAVE_NOTIFY_FD 3470 RemoveNotifyFd(pAMDGPUEnt->fd); 3471#else 3472 RemoveGeneralSocket(pAMDGPUEnt->fd); 3473 RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 3474 drm_wakeup_handler, drmmode); 3475#endif 3476 } 3477} 3478 3479static void drmmode_sprite_do_set_cursor(struct amdgpu_device_priv *device_priv, 3480 ScrnInfoPtr scrn, int x, int y) 3481{ 3482 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3483 CursorPtr cursor = device_priv->cursor; 3484 Bool sprite_visible = device_priv->sprite_visible; 3485 3486 if (cursor) { 3487 x -= cursor->bits->xhot; 3488 y -= cursor->bits->yhot; 3489 3490 device_priv->sprite_visible = 3491 x < scrn->virtualX && y < scrn->virtualY && 3492 (x + cursor->bits->width > 0) && 3493 (y + cursor->bits->height > 0); 3494 } else { 3495 device_priv->sprite_visible = FALSE; 3496 } 3497 3498 info->sprites_visible += device_priv->sprite_visible - sprite_visible; 3499} 3500 3501static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 3502 CursorPtr pCursor, int x, int y) 3503{ 3504 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3505 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3506 struct amdgpu_device_priv *device_priv = 3507 dixLookupScreenPrivate(&pDev->devPrivates, 3508 &amdgpu_device_private_key, pScreen); 3509 3510 device_priv->cursor = pCursor; 3511 drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 3512 3513 info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y); 3514} 3515 3516static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, 3517 int x, int y) 3518{ 3519 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3520 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3521 struct amdgpu_device_priv *device_priv = 3522 dixLookupScreenPrivate(&pDev->devPrivates, 3523 &amdgpu_device_private_key, pScreen); 3524 3525 drmmode_sprite_do_set_cursor(device_priv, scrn, x, y); 3526 3527 info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y); 3528} 3529 3530static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev, 3531 ScreenPtr pScreen, 3532 CursorPtr pCursor) 3533{ 3534 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3535 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3536 3537 return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor); 3538} 3539 3540static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev, 3541 ScreenPtr pScreen, 3542 CursorPtr pCursor) 3543{ 3544 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3545 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3546 3547 return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor); 3548} 3549 3550static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev, 3551 ScreenPtr pScreen) 3552{ 3553 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3554 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3555 3556 return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen); 3557} 3558 3559static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev, 3560 ScreenPtr pScreen) 3561{ 3562 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 3563 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3564 3565 info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen); 3566} 3567 3568miPointerSpriteFuncRec drmmode_sprite_funcs = { 3569 .RealizeCursor = drmmode_sprite_realize_realize_cursor, 3570 .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor, 3571 .SetCursor = drmmode_sprite_set_cursor, 3572 .MoveCursor = drmmode_sprite_move_cursor, 3573 .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize, 3574 .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup, 3575}; 3576 3577 3578void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 3579{ 3580 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3581 xf86OutputPtr output = config->output[config->compat_output]; 3582 xf86CrtcPtr crtc = output->crtc; 3583 3584 if (crtc && crtc->enabled) { 3585 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); 3586 } 3587} 3588 3589Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 3590 Bool set_hw) 3591{ 3592 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 3593 unsigned num_desired = 0, num_on = 0; 3594 int c; 3595 3596 /* First, disable all unused CRTCs */ 3597 if (set_hw) { 3598 for (c = 0; c < config->num_crtc; c++) { 3599 xf86CrtcPtr crtc = config->crtc[c]; 3600 3601 /* Skip disabled CRTCs */ 3602 if (crtc->enabled) 3603 continue; 3604 3605 drmmode_crtc_dpms(crtc, DPMSModeOff); 3606 } 3607 } 3608 3609 /* Then, try setting the chosen mode on each CRTC */ 3610 for (c = 0; c < config->num_crtc; c++) { 3611 xf86CrtcPtr crtc = config->crtc[c]; 3612 xf86OutputPtr output = NULL; 3613 int o; 3614 3615 if (!crtc->enabled) 3616 continue; 3617 3618 if (config->output[config->compat_output]->crtc == crtc) 3619 output = config->output[config->compat_output]; 3620 else { 3621 for (o = 0; o < config->num_output; o++) 3622 if (config->output[o]->crtc == crtc) { 3623 output = config->output[o]; 3624 break; 3625 } 3626 } 3627 /* paranoia */ 3628 if (!output) 3629 continue; 3630 3631 num_desired++; 3632 3633 /* Mark that we'll need to re-set the mode for sure */ 3634 memset(&crtc->mode, 0, sizeof(crtc->mode)); 3635 if (!crtc->desiredMode.CrtcHDisplay) { 3636 DisplayModePtr mode = xf86OutputFindClosestMode(output, 3637 pScrn-> 3638 currentMode); 3639 3640 if (!mode) { 3641 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3642 "Failed to find mode for CRTC %d\n", c); 3643 continue; 3644 } 3645 crtc->desiredMode = *mode; 3646 crtc->desiredRotation = RR_Rotate_0; 3647 crtc->desiredX = 0; 3648 crtc->desiredY = 0; 3649 } 3650 3651 if (set_hw) { 3652 if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 3653 crtc->desiredRotation, 3654 crtc->desiredX, 3655 crtc->desiredY)) { 3656 num_on++; 3657 } else { 3658 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 3659 "Failed to set mode on CRTC %d\n", c); 3660 RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y, 3661 crtc->rotation, 0, NULL); 3662 } 3663 } else { 3664 crtc->mode = crtc->desiredMode; 3665 crtc->rotation = crtc->desiredRotation; 3666 crtc->x = crtc->desiredX; 3667 crtc->y = crtc->desiredY; 3668 if (drmmode_handle_transform(crtc)) 3669 num_on++; 3670 } 3671 } 3672 3673 if (num_on == 0 && num_desired > 0) { 3674 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n"); 3675 return FALSE; 3676 } 3677 3678 /* Validate leases on VT re-entry */ 3679 if (dixPrivateKeyRegistered(rrPrivKey)) 3680 drmmode_validate_leases(pScrn); 3681 3682 return TRUE; 3683} 3684 3685Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 3686{ 3687 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 3688 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 3689 int i; 3690 3691 if (xf86_config->num_crtc) { 3692 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 3693 "Initializing kms color map\n"); 3694 if (!miCreateDefColormap(pScreen)) 3695 return FALSE; 3696 3697 if (pScrn->depth == 30) { 3698 if (!drmmode_cm_enabled(&info->drmmode)) 3699 return TRUE; 3700 3701 for (i = 0; i < xf86_config->num_crtc; i++) { 3702 xf86CrtcPtr crtc = xf86_config->crtc[i]; 3703 void *gamma; 3704 3705 if (crtc->gamma_size == 1024) 3706 continue; 3707 3708 gamma = malloc(1024 * 3 * sizeof(CARD16)); 3709 if (!gamma) { 3710 ErrorF("Failed to allocate gamma LUT memory\n"); 3711 return FALSE; 3712 } 3713 3714 free(crtc->gamma_red); 3715 crtc->gamma_size = 1024; 3716 crtc->gamma_red = gamma; 3717 crtc->gamma_green = crtc->gamma_red + crtc->gamma_size; 3718 crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size; 3719 } 3720 } 3721 3722 /* All Radeons support 10 bit CLUTs. */ 3723 if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10, 3724 NULL, NULL, CMAP_PALETTED_TRUECOLOR 3725 | CMAP_RELOAD_ON_MODE_SWITCH)) 3726 return FALSE; 3727 3728 for (i = 0; i < xf86_config->num_crtc; i++) { 3729 xf86CrtcPtr crtc = xf86_config->crtc[i]; 3730 3731 drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red, 3732 crtc->gamma_green, 3733 crtc->gamma_blue, 3734 crtc->gamma_size); 3735 } 3736 } 3737 3738 return TRUE; 3739} 3740 3741static Bool 3742drmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 3743 int *num_hdmi) 3744{ 3745 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3746 int i; 3747 3748 for (i = 0; i < config->num_output; i++) { 3749 xf86OutputPtr output = config->output[i]; 3750 drmmode_output_private_ptr drmmode_output = output->driver_private; 3751 3752 if (drmmode_output->output_id == output_id) { 3753 switch(drmmode_output->mode_output->connector_type) { 3754 case DRM_MODE_CONNECTOR_DVII: 3755 case DRM_MODE_CONNECTOR_DVID: 3756 case DRM_MODE_CONNECTOR_DVIA: 3757 (*num_dvi)++; 3758 break; 3759 case DRM_MODE_CONNECTOR_HDMIA: 3760 case DRM_MODE_CONNECTOR_HDMIB: 3761 (*num_hdmi)++; 3762 break; 3763 } 3764 3765 return TRUE; 3766 } 3767 } 3768 3769 return FALSE; 3770} 3771 3772void 3773amdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3774{ 3775 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3776 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3777 drmModeResPtr mode_res; 3778 int i, j; 3779 Bool found; 3780 Bool changed = FALSE; 3781 int num_dvi = 0, num_hdmi = 0; 3782 3783 /* Try to re-set the mode on all the connectors with a BAD link-state: 3784 * This may happen if a link degrades and a new modeset is necessary, using 3785 * different link-training parameters. If the kernel found that the current 3786 * mode is not achievable anymore, it should have pruned the mode before 3787 * sending the hotplug event. Try to re-set the currently-set mode to keep 3788 * the display alive, this will fail if the mode has been pruned. 3789 * In any case, we will send randr events for the Desktop Environment to 3790 * deal with it, if it wants to. 3791 */ 3792 for (i = 0; i < config->num_output; i++) { 3793 xf86OutputPtr output = config->output[i]; 3794 xf86CrtcPtr crtc = output->crtc; 3795 drmmode_output_private_ptr drmmode_output = output->driver_private; 3796 3797 drmmode_output_detect(output); 3798 3799 if (!crtc || !drmmode_output->mode_output) 3800 continue; 3801 3802 /* Get an updated view of the properties for the current connector and 3803 * look for the link-status property 3804 */ 3805 for (j = 0; j < drmmode_output->num_props; j++) { 3806 drmmode_prop_ptr p = &drmmode_output->props[j]; 3807 3808 if (!strcmp(p->mode_prop->name, "link-status")) { 3809 if (p->value != DRM_MODE_LINK_STATUS_BAD) 3810 break; 3811 3812 /* the connector got a link failure, re-set the current mode */ 3813 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 3814 crtc->x, crtc->y); 3815 3816 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 3817 "hotplug event: connector %u's link-state is BAD, " 3818 "tried resetting the current mode. You may be left" 3819 "with a black screen if this fails...\n", 3820 drmmode_output->mode_output->connector_id); 3821 3822 break; 3823 } 3824 } 3825 } 3826 3827 mode_res = drmModeGetResources(pAMDGPUEnt->fd); 3828 if (!mode_res) 3829 goto out; 3830 3831restart_destroy: 3832 for (i = 0; i < config->num_output; i++) { 3833 xf86OutputPtr output = config->output[i]; 3834 drmmode_output_private_ptr drmmode_output = output->driver_private; 3835 found = FALSE; 3836 for (j = 0; j < mode_res->count_connectors; j++) { 3837 if (mode_res->connectors[j] == drmmode_output->output_id) { 3838 found = TRUE; 3839 break; 3840 } 3841 } 3842 if (found) 3843 continue; 3844 3845 drmModeFreeConnector(drmmode_output->mode_output); 3846 drmmode_output->mode_output = NULL; 3847 drmmode_output->output_id = -1; 3848 3849 changed = TRUE; 3850 if (drmmode->delete_dp_12_displays) { 3851 RROutputDestroy(output->randr_output); 3852 xf86OutputDestroy(output); 3853 goto restart_destroy; 3854 } 3855 } 3856 3857 /* find new output ids we don't have outputs for */ 3858 for (i = 0; i < mode_res->count_connectors; i++) { 3859 for (j = 0; j < pAMDGPUEnt->num_scrns; j++) { 3860 if (drmmode_find_output(pAMDGPUEnt->scrn[j], 3861 mode_res->connectors[i], 3862 &num_dvi, &num_hdmi)) 3863 break; 3864 } 3865 3866 if (j < pAMDGPUEnt->num_scrns) 3867 continue; 3868 3869 if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 3870 &num_hdmi, 1) != 0) 3871 changed = TRUE; 3872 } 3873 3874 /* Check to see if a lessee has disappeared */ 3875 drmmode_validate_leases(scrn); 3876 3877 if (changed) { 3878#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 3879 RRSetChanged(xf86ScrnToScreen(scrn)); 3880#else 3881 rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 3882 rrScrPriv->changed = TRUE; 3883#endif 3884 RRTellChanged(xf86ScrnToScreen(scrn)); 3885 } 3886 3887 drmModeFreeResources(mode_res); 3888out: 3889 RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 3890} 3891 3892#ifdef HAVE_LIBUDEV 3893static void drmmode_handle_uevents(int fd, void *closure) 3894{ 3895 drmmode_ptr drmmode = closure; 3896 ScrnInfoPtr scrn = drmmode->scrn; 3897 struct udev_device *dev; 3898 Bool received = FALSE; 3899 struct timeval tv = { 0, 0 }; 3900 fd_set readfd; 3901 3902 FD_ZERO(&readfd); 3903 FD_SET(fd, &readfd); 3904 3905 while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 && 3906 FD_ISSET(fd, &readfd)) { 3907 /* select() ensured that this will not block */ 3908 dev = udev_monitor_receive_device(drmmode->uevent_monitor); 3909 if (dev) { 3910 udev_device_unref(dev); 3911 received = TRUE; 3912 } 3913 } 3914 3915 if (received) 3916 amdgpu_mode_hotplug(scrn, drmmode); 3917} 3918#endif 3919 3920void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3921{ 3922#ifdef HAVE_LIBUDEV 3923 struct udev *u; 3924 struct udev_monitor *mon; 3925 3926 u = udev_new(); 3927 if (!u) 3928 return; 3929 mon = udev_monitor_new_from_netlink(u, "udev"); 3930 if (!mon) { 3931 udev_unref(u); 3932 return; 3933 } 3934 3935 if (udev_monitor_filter_add_match_subsystem_devtype(mon, 3936 "drm", 3937 "drm_minor") < 0 || 3938 udev_monitor_enable_receiving(mon) < 0) { 3939 udev_monitor_unref(mon); 3940 udev_unref(u); 3941 return; 3942 } 3943 3944 drmmode->uevent_handler = 3945 xf86AddGeneralHandler(udev_monitor_get_fd(mon), 3946 drmmode_handle_uevents, drmmode); 3947 3948 drmmode->uevent_monitor = mon; 3949#endif 3950} 3951 3952void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 3953{ 3954#ifdef HAVE_LIBUDEV 3955 if (drmmode->uevent_handler) { 3956 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 3957 xf86RemoveGeneralHandler(drmmode->uevent_handler); 3958 3959 udev_monitor_unref(drmmode->uevent_monitor); 3960 udev_unref(u); 3961 } 3962#endif 3963} 3964 3965Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 3966 PixmapPtr new_front, uint64_t id, void *data, 3967 xf86CrtcPtr ref_crtc, amdgpu_drm_handler_proc handler, 3968 amdgpu_drm_abort_proc abort, 3969 enum drmmode_flip_sync flip_sync, 3970 uint32_t target_msc) 3971{ 3972 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 3973 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 3974 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 3975 xf86CrtcPtr crtc = NULL; 3976 drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 3977 int crtc_id; 3978 uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; 3979 uint32_t sec_flip_flags = flip_flags; 3980 drmmode_flipdata_ptr flipdata; 3981 Bool handle_deferred = FALSE; 3982 uintptr_t drm_queue_seq = 0; 3983 struct drmmode_fb *fb; 3984 int i = 0; 3985 3986 /* 3987 * Flip secondary non-ref_crtc crtc's async if possible and requested 3988 * by xorg.conf option "AsyncFlipSecondaries". Otherwise follow the lead 3989 * of flip_sync. 3990 */ 3991 if (info->can_async_flip && info->async_flip_secondaries) 3992 sec_flip_flags |= DRM_MODE_PAGE_FLIP_ASYNC; 3993 3994 flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs * 3995 sizeof(flipdata->fb[0])); 3996 if (!flipdata) { 3997 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 3998 "flip queue: data alloc failed.\n"); 3999 goto error; 4000 } 4001 4002 fb = amdgpu_pixmap_get_fb(new_front); 4003 if (!fb) { 4004 ErrorF("Failed to get FB for flip\n"); 4005 goto error; 4006 } 4007 4008 /* 4009 * Queue flips on all enabled CRTCs 4010 * Note that if/when we get per-CRTC buffers, we'll have to update this. 4011 * Right now it assumes a single shared fb across all CRTCs, with the 4012 * kernel fixing up the offset of each CRTC as necessary. 4013 * 4014 * Also, flips queued on disabled or incorrectly configured displays 4015 * may never complete; this is a configuration error. 4016 */ 4017 4018 flipdata->event_data = data; 4019 flipdata->handler = handler; 4020 flipdata->abort = abort; 4021 flipdata->fe_crtc = ref_crtc; 4022 4023 for (i = 0; i < config->num_crtc; i++) { 4024 crtc = config->crtc[i]; 4025 drmmode_crtc = crtc->driver_private; 4026 crtc_id = drmmode_get_crtc_id(crtc); 4027 4028 if (!drmmode_crtc_can_flip(crtc) || 4029 (drmmode_crtc->tear_free && crtc != ref_crtc)) 4030 continue; 4031 4032 flipdata->flip_count++; 4033 4034 drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id, 4035 flipdata, 4036 drmmode_flip_handler, 4037 drmmode_flip_abort, 4038 TRUE); 4039 if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 4040 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 4041 "Allocating DRM queue event entry failed.\n"); 4042 goto error; 4043 } 4044 4045 if (drmmode_crtc->tear_free) { 4046 BoxRec extents = { .x1 = 0, .y1 = 0, 4047 .x2 = new_front->drawable.width, 4048 .y2 = new_front->drawable.height }; 4049 int scanout_id = drmmode_crtc->scanout_id ^ 1; 4050 4051 if (flip_sync == FLIP_ASYNC) { 4052 if (!drmmode_wait_vblank(crtc, 4053 DRM_VBLANK_RELATIVE | 4054 DRM_VBLANK_EVENT, 4055 0, drm_queue_seq, 4056 NULL, NULL)) 4057 goto flip_error; 4058 goto next; 4059 } 4060 4061 drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[crtc_id], 4062 amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id])); 4063 if (!flipdata->fb[crtc_id]) { 4064 ErrorF("Failed to get FB for TearFree flip\n"); 4065 goto error; 4066 } 4067 4068 amdgpu_scanout_do_update(crtc, scanout_id, new_front, 4069 extents); 4070 amdgpu_glamor_flush(crtc->scrn); 4071 4072 if (drmmode_crtc->scanout_update_pending) { 4073 amdgpu_drm_wait_pending_flip(crtc); 4074 handle_deferred = TRUE; 4075 amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending); 4076 drmmode_crtc->scanout_update_pending = 0; 4077 } 4078 } else { 4079 drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[crtc_id], fb); 4080 } 4081 4082 if (crtc == ref_crtc) { 4083 if (drmmode_page_flip_target_absolute(pAMDGPUEnt, 4084 drmmode_crtc, 4085 flipdata->fb[crtc_id]->handle, 4086 flip_flags, 4087 drm_queue_seq, 4088 target_msc) != 0) 4089 goto flip_error; 4090 } else { 4091 if (drmmode_page_flip_target_relative(pAMDGPUEnt, 4092 drmmode_crtc, 4093 flipdata->fb[crtc_id]->handle, 4094 sec_flip_flags, 4095 drm_queue_seq, 0) != 0) 4096 goto flip_error; 4097 } 4098 4099 if (drmmode_crtc->tear_free) { 4100 drmmode_crtc->scanout_id ^= 1; 4101 drmmode_crtc->ignore_damage = TRUE; 4102 } 4103 4104 drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, 4105 flipdata->fb[crtc_id]); 4106 4107 next: 4108 drm_queue_seq = 0; 4109 } 4110 4111 if (handle_deferred) 4112 amdgpu_drm_queue_handle_deferred(ref_crtc); 4113 if (flipdata->flip_count > 0) 4114 return TRUE; 4115 4116flip_error: 4117 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", 4118 strerror(errno)); 4119 4120error: 4121 if (drm_queue_seq) 4122 amdgpu_drm_abort_entry(drm_queue_seq); 4123 else if (crtc) 4124 drmmode_flip_abort(crtc, flipdata); 4125 else { 4126 abort(NULL, data); 4127 free(flipdata); 4128 } 4129 4130 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 4131 strerror(errno)); 4132 if (handle_deferred) 4133 amdgpu_drm_queue_handle_deferred(ref_crtc); 4134 return FALSE; 4135} 4136