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