drmmode_display.c revision 504d986f
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 "micmap.h" 38#include "xf86cmap.h" 39#include "xf86Priv.h" 40#include "sarea.h" 41 42#include "drmmode_display.h" 43#include "amdgpu_bo_helper.h" 44#include "amdgpu_glamor.h" 45#include "amdgpu_list.h" 46#include "amdgpu_pixmap.h" 47 48#ifdef AMDGPU_PIXMAP_SHARING 49#include <dri.h> 50#endif 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 99static PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn, 100 int width, int height, 101 int depth, int bpp, 102 int pitch, 103 struct amdgpu_buffer *bo) 104{ 105 ScreenPtr pScreen = pScrn->pScreen; 106 PixmapPtr pixmap; 107 108 pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 109 AMDGPU_CREATE_PIXMAP_SCANOUT); 110 if (!pixmap) 111 return NULL; 112 113 if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height, 114 depth, bpp, pitch, NULL)) 115 goto fail; 116 117 if (!amdgpu_glamor_create_textured_pixmap(pixmap, bo)) 118 goto fail; 119 120 if (amdgpu_set_pixmap_bo(pixmap, bo)) 121 return pixmap; 122 123fail: 124 pScreen->DestroyPixmap(pixmap); 125 return NULL; 126} 127 128static void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 129{ 130 ScreenPtr pScreen = pixmap->drawable.pScreen; 131 132 (*pScreen->DestroyPixmap) (pixmap); 133} 134 135static void 136drmmode_ConvertFromKMode(ScrnInfoPtr scrn, 137 drmModeModeInfo * kmode, DisplayModePtr mode) 138{ 139 memset(mode, 0, sizeof(DisplayModeRec)); 140 mode->status = MODE_OK; 141 142 mode->Clock = kmode->clock; 143 144 mode->HDisplay = kmode->hdisplay; 145 mode->HSyncStart = kmode->hsync_start; 146 mode->HSyncEnd = kmode->hsync_end; 147 mode->HTotal = kmode->htotal; 148 mode->HSkew = kmode->hskew; 149 150 mode->VDisplay = kmode->vdisplay; 151 mode->VSyncStart = kmode->vsync_start; 152 mode->VSyncEnd = kmode->vsync_end; 153 mode->VTotal = kmode->vtotal; 154 mode->VScan = kmode->vscan; 155 156 mode->Flags = kmode->flags; //& FLAG_BITS; 157 mode->name = strdup(kmode->name); 158 159 if (kmode->type & DRM_MODE_TYPE_DRIVER) 160 mode->type = M_T_DRIVER; 161 if (kmode->type & DRM_MODE_TYPE_PREFERRED) 162 mode->type |= M_T_PREFERRED; 163 xf86SetModeCrtc(mode, scrn->adjustFlags); 164} 165 166static void 167drmmode_ConvertToKMode(ScrnInfoPtr scrn, 168 drmModeModeInfo * kmode, DisplayModePtr mode) 169{ 170 memset(kmode, 0, sizeof(*kmode)); 171 172 kmode->clock = mode->Clock; 173 kmode->hdisplay = mode->HDisplay; 174 kmode->hsync_start = mode->HSyncStart; 175 kmode->hsync_end = mode->HSyncEnd; 176 kmode->htotal = mode->HTotal; 177 kmode->hskew = mode->HSkew; 178 179 kmode->vdisplay = mode->VDisplay; 180 kmode->vsync_start = mode->VSyncStart; 181 kmode->vsync_end = mode->VSyncEnd; 182 kmode->vtotal = mode->VTotal; 183 kmode->vscan = mode->VScan; 184 185 kmode->flags = mode->Flags; //& FLAG_BITS; 186 if (mode->name) 187 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 188 kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0; 189 190} 191 192/* 193 * Retrieves present time in microseconds that is compatible 194 * with units used by vblank timestamps. Depending on the kernel 195 * version and DRM kernel module configuration, the vblank 196 * timestamp can either be in real time or monotonic time 197 */ 198int drmmode_get_current_ust(int drm_fd, CARD64 * ust) 199{ 200 uint64_t cap_value; 201 int ret; 202 struct timespec now; 203 204 ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value); 205 if (ret || !cap_value) 206 /* old kernel or drm_timestamp_monotonic turned off */ 207 ret = clock_gettime(CLOCK_REALTIME, &now); 208 else 209 ret = clock_gettime(CLOCK_MONOTONIC, &now); 210 if (ret) 211 return ret; 212 *ust = ((CARD64) now.tv_sec * 1000000) + ((CARD64) now.tv_nsec / 1000); 213 return 0; 214} 215 216/* 217 * Get current frame count and frame count timestamp of the crtc. 218 */ 219int drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc) 220{ 221 ScrnInfoPtr scrn = crtc->scrn; 222 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 223 drmVBlank vbl; 224 int ret; 225 226 vbl.request.type = DRM_VBLANK_RELATIVE; 227 vbl.request.type |= amdgpu_populate_vbl_request_type(crtc); 228 vbl.request.sequence = 0; 229 230 ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl); 231 if (ret) { 232 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 233 "get vblank counter failed: %s\n", strerror(errno)); 234 return ret; 235 } 236 237 *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec; 238 *msc = vbl.reply.sequence; 239 240 return Success; 241} 242 243static void 244drmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode) 245{ 246 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 247 ScrnInfoPtr scrn = crtc->scrn; 248 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 249 CARD64 ust; 250 int ret; 251 252 drmmode_crtc->pending_dpms_mode = mode; 253 254 if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) { 255 drmVBlank vbl; 256 257 /* Wait for any pending flip to finish */ 258 if (drmmode_crtc->flip_pending) 259 return; 260 261 /* 262 * On->Off transition: record the last vblank time, 263 * sequence number and frame period. 264 */ 265 vbl.request.type = DRM_VBLANK_RELATIVE; 266 vbl.request.type |= amdgpu_populate_vbl_request_type(crtc); 267 vbl.request.sequence = 0; 268 ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl); 269 if (ret) 270 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 271 "%s cannot get last vblank counter\n", 272 __func__); 273 else { 274 CARD64 seq = (CARD64) vbl.reply.sequence; 275 CARD64 nominal_frame_rate, pix_in_frame; 276 277 ust = ((CARD64) vbl.reply.tval_sec * 1000000) + 278 vbl.reply.tval_usec; 279 drmmode_crtc->dpms_last_ust = ust; 280 drmmode_crtc->dpms_last_seq = seq; 281 nominal_frame_rate = crtc->mode.Clock; 282 nominal_frame_rate *= 1000; 283 pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal; 284 if (nominal_frame_rate == 0 || pix_in_frame == 0) 285 nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE; 286 else 287 nominal_frame_rate /= pix_in_frame; 288 drmmode_crtc->dpms_last_fps = nominal_frame_rate; 289 } 290 } else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) { 291 /* 292 * Off->On transition: calculate and accumulate the 293 * number of interpolated vblanks while we were in Off state 294 */ 295 ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust); 296 if (ret) 297 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 298 "%s cannot get current time\n", __func__); 299 else if (drmmode_crtc->dpms_last_ust) { 300 CARD64 time_elapsed, delta_seq; 301 time_elapsed = ust - drmmode_crtc->dpms_last_ust; 302 delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps; 303 delta_seq /= 1000000; 304 drmmode_crtc->interpolated_vblanks += delta_seq; 305 306 } 307 } 308 drmmode_crtc->dpms_mode = mode; 309} 310 311static void 312drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 313{ 314 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 315 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 316 317 /* Disable unused CRTCs and enable/disable active CRTCs */ 318 if (!crtc->enabled || mode != DPMSModeOn) { 319 /* Wait for any pending flip to finish */ 320 if (drmmode_crtc->flip_pending) 321 return; 322 323 drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 324 0, 0, 0, NULL, 0, NULL); 325 } else if (drmmode_crtc->dpms_mode != DPMSModeOn) 326 crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, 327 crtc->x, crtc->y); 328} 329 330static PixmapPtr 331create_pixmap_for_fbcon(drmmode_ptr drmmode, 332 ScrnInfoPtr pScrn, int fbcon_id) 333{ 334 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 335 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 336 PixmapPtr pixmap = info->fbcon_pixmap; 337 struct amdgpu_buffer *bo; 338 drmModeFBPtr fbcon; 339 struct drm_gem_flink flink; 340 struct amdgpu_bo_import_result import = {0}; 341 342 if (pixmap) 343 return pixmap; 344 345 fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id); 346 if (fbcon == NULL) 347 return NULL; 348 349 if (fbcon->depth != pScrn->depth || 350 fbcon->width != pScrn->virtualX || 351 fbcon->height != pScrn->virtualY) 352 goto out_free_fb; 353 354 flink.handle = fbcon->handle; 355 if (ioctl(pAMDGPUEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { 356 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 357 "Couldn't flink fbcon handle\n"); 358 goto out_free_fb; 359 } 360 361 bo = calloc(1, sizeof(struct amdgpu_buffer)); 362 if (bo == NULL) { 363 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 364 "Couldn't allocate bo for fbcon handle\n"); 365 goto out_free_fb; 366 } 367 bo->ref_count = 1; 368 369 if (amdgpu_bo_import(pAMDGPUEnt->pDev, 370 amdgpu_bo_handle_type_gem_flink_name, flink.name, 371 &import) != 0) { 372 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 373 "Couldn't import BO for fbcon handle\n"); 374 goto out_free_bo; 375 } 376 bo->bo.amdgpu = import.buf_handle; 377 378 pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height, 379 fbcon->depth, fbcon->bpp, 380 fbcon->pitch, bo); 381 info->fbcon_pixmap = pixmap; 382out_free_bo: 383 amdgpu_bo_unref(&bo); 384out_free_fb: 385 drmModeFreeFB(fbcon); 386 return pixmap; 387} 388 389void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 390{ 391 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 392 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 393 PixmapPtr src, dst; 394 ScreenPtr pScreen = pScrn->pScreen; 395 int fbcon_id = 0; 396 GCPtr gc; 397 int i; 398 399 for (i = 0; i < xf86_config->num_crtc; i++) { 400 drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private; 401 402 if (drmmode_crtc->mode_crtc->buffer_id) 403 fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 404 } 405 406 if (!fbcon_id) 407 return; 408 409 if (fbcon_id == drmmode->fb_id) { 410 /* in some rare case there might be no fbcon and we might already 411 * be the one with the current fb to avoid a false deadlck in 412 * kernel ttm code just do nothing as anyway there is nothing 413 * to do 414 */ 415 return; 416 } 417 418 src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id); 419 if (!src) 420 return; 421 422 dst = pScreen->GetScreenPixmap(pScreen); 423 424 gc = GetScratchGC(pScrn->depth, pScreen); 425 ValidateGC(&dst->drawable, gc); 426 427 (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0, 428 pScrn->virtualX, pScrn->virtualY, 0, 0); 429 430 FreeScratchGC(gc); 431 432 amdgpu_glamor_finish(pScrn); 433 434 pScreen->canDoBGNoneRoot = TRUE; 435 436 if (info->fbcon_pixmap) 437 pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap); 438 info->fbcon_pixmap = NULL; 439 440 return; 441} 442 443static void 444drmmode_crtc_scanout_destroy(drmmode_ptr drmmode, 445 struct drmmode_scanout *scanout) 446{ 447 448 if (scanout->pixmap) { 449 drmmode_destroy_bo_pixmap(scanout->pixmap); 450 scanout->pixmap = NULL; 451 } 452 453 if (scanout->bo) { 454 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn); 455 456 drmModeRmFB(pAMDGPUEnt->fd, scanout->fb_id); 457 scanout->fb_id = 0; 458 amdgpu_bo_unref(&scanout->bo); 459 scanout->bo = NULL; 460 } 461} 462 463static void 464drmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc) 465{ 466 if (drmmode_crtc->flip_pending) { 467 drmmode_crtc->scanout_destroy[0] = drmmode_crtc->scanout[0]; 468 drmmode_crtc->scanout[0].pixmap = NULL; 469 drmmode_crtc->scanout[0].bo = NULL; 470 drmmode_crtc->scanout_destroy[1] = drmmode_crtc->scanout[1]; 471 drmmode_crtc->scanout[1].pixmap = NULL; 472 drmmode_crtc->scanout[1].bo = NULL; 473 } else { 474 drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 475 &drmmode_crtc->scanout[0]); 476 drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 477 &drmmode_crtc->scanout[1]); 478 } 479 480 if (drmmode_crtc->scanout_damage) { 481 DamageDestroy(drmmode_crtc->scanout_damage); 482 drmmode_crtc->scanout_damage = NULL; 483 RegionUninit(&drmmode_crtc->scanout_last_region); 484 } 485} 486 487void 488drmmode_scanout_free(ScrnInfoPtr scrn) 489{ 490 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 491 int c; 492 493 for (c = 0; c < xf86_config->num_crtc; c++) 494 drmmode_crtc_scanout_free(xf86_config->crtc[c]->driver_private); 495} 496 497static void * 498drmmode_crtc_scanout_allocate(xf86CrtcPtr crtc, 499 struct drmmode_scanout *scanout, 500 int width, int height) 501{ 502 ScrnInfoPtr pScrn = crtc->scrn; 503 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 504 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 505 drmmode_ptr drmmode = drmmode_crtc->drmmode; 506 int ret; 507 int pitch; 508 union gbm_bo_handle bo_handle; 509 510 if (scanout->bo) { 511 if (scanout->width == width && scanout->height == height) 512 return scanout->bo; 513 514 drmmode_crtc_scanout_destroy(drmmode, scanout); 515 } 516 517 scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height, 518 pScrn->depth, 0, 519 pScrn->bitsPerPixel, &pitch); 520 if (!scanout->bo) { 521 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 522 "Failed to allocate rotation buffer memory\n"); 523 return NULL; 524 } 525 526 bo_handle = gbm_bo_get_handle(scanout->bo->bo.gbm); 527 ret = drmModeAddFB(pAMDGPUEnt->fd, width, height, pScrn->depth, 528 pScrn->bitsPerPixel, pitch, 529 bo_handle.u32, &scanout->fb_id); 530 if (ret) { 531 ErrorF("failed to add rotate fb\n"); 532 amdgpu_bo_unref(&scanout->bo); 533 scanout->bo = NULL; 534 return NULL; 535 } 536 537 scanout->width = width; 538 scanout->height = height; 539 return scanout->bo; 540} 541 542static PixmapPtr 543drmmode_crtc_scanout_create(xf86CrtcPtr crtc, 544 struct drmmode_scanout *scanout, 545 int width, int height) 546{ 547 ScrnInfoPtr pScrn = crtc->scrn; 548 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 549 drmmode_ptr drmmode = drmmode_crtc->drmmode; 550 unsigned long rotate_pitch; 551 552 if (scanout->pixmap) { 553 if (scanout->width == width && scanout->height == height) 554 return scanout->pixmap; 555 556 drmmode_crtc_scanout_destroy(drmmode, scanout); 557 } 558 559 if (!scanout->bo) { 560 if (!drmmode_crtc_scanout_allocate(crtc, scanout, width, height)) 561 return NULL; 562 } 563 564 rotate_pitch = gbm_bo_get_stride(scanout->bo->bo.gbm); 565 566 scanout->pixmap = drmmode_create_bo_pixmap(pScrn, 567 width, height, 568 pScrn->depth, 569 pScrn->bitsPerPixel, 570 rotate_pitch, 571 scanout->bo); 572 if (scanout->pixmap == NULL) { 573 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 574 "Couldn't allocate shadow pixmap for rotated CRTC\n"); 575 } 576 return scanout->pixmap; 577 578} 579 580static void 581amdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure) 582{ 583 /* Only keep track of the extents */ 584 RegionUninit(&damage->damage); 585 damage->damage.data = NULL; 586} 587 588static Bool 589drmmode_can_use_hw_cursor(xf86CrtcPtr crtc) 590{ 591 AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 592 593 /* Check for Option "SWcursor" */ 594 if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 595 return FALSE; 596 597 /* Fall back to SW cursor if the CRTC is transformed */ 598 if (crtc->transformPresent) 599 return FALSE; 600 601#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 602 /* Xorg doesn't correctly handle cursor position transform in the 603 * rotation case 604 */ 605 if (crtc->driverIsPerformingTransform && 606 (crtc->rotation & 0xf) != RR_Rotate_0) 607 return FALSE; 608#endif 609 610#if defined(AMDGPU_PIXMAP_SHARING) 611 /* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */ 612 if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) && 613 !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list)) 614 return FALSE; 615#endif 616 617 return TRUE; 618} 619 620#if XF86_CRTC_VERSION >= 4 621 622static Bool 623drmmode_handle_transform(xf86CrtcPtr crtc) 624{ 625 Bool ret; 626 627#if XF86_CRTC_VERSION >= 7 628 if (crtc->transformPresent || crtc->rotation != RR_Rotate_0) 629 crtc->driverIsPerformingTransform = XF86DriverTransformOutput; 630 else 631 crtc->driverIsPerformingTransform = XF86DriverTransformNone; 632#else 633 AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 634 635 crtc->driverIsPerformingTransform = crtc->transformPresent || 636 (info->tear_free && crtc->rotation != RR_Rotate_0); 637#endif 638 639 ret = xf86CrtcRotate(crtc); 640 641 crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use; 642 643 return ret; 644} 645 646#else 647 648static Bool 649drmmode_handle_transform(xf86CrtcPtr crtc) 650{ 651 return xf86CrtcRotate(crtc); 652} 653 654#endif 655 656static Bool 657drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 658 Rotation rotation, int x, int y) 659{ 660 ScrnInfoPtr pScrn = crtc->scrn; 661 ScreenPtr pScreen = pScrn->pScreen; 662 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 663 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 664 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 665 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 666 drmmode_ptr drmmode = drmmode_crtc->drmmode; 667 int saved_x, saved_y; 668 Rotation saved_rotation; 669 DisplayModeRec saved_mode; 670 uint32_t *output_ids = NULL; 671 int output_count = 0; 672 Bool ret = FALSE; 673 int i; 674 int fb_id; 675 drmModeModeInfo kmode; 676 uint32_t bo_handle; 677 678 saved_mode = crtc->mode; 679 saved_x = crtc->x; 680 saved_y = crtc->y; 681 saved_rotation = crtc->rotation; 682 683 if (mode) { 684 crtc->mode = *mode; 685 crtc->x = x; 686 crtc->y = y; 687 crtc->rotation = rotation; 688 689 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 690 if (!output_ids) 691 goto done; 692 693 for (i = 0; i < xf86_config->num_output; i++) { 694 xf86OutputPtr output = xf86_config->output[i]; 695 drmmode_output_private_ptr drmmode_output; 696 697 if (output->crtc != crtc) 698 continue; 699 700 drmmode_output = output->driver_private; 701 output_ids[output_count] = 702 drmmode_output->mode_output->connector_id; 703 output_count++; 704 } 705 706 if (!drmmode_handle_transform(crtc)) 707 goto done; 708 709 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 710 crtc->gamma_blue, crtc->gamma_size); 711 712 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); 713 714 fb_id = drmmode->fb_id; 715#ifdef AMDGPU_PIXMAP_SHARING 716 if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) { 717 fb_id = drmmode_crtc->scanout[0].fb_id; 718 x = y = 0; 719 } else 720#endif 721 if (drmmode_crtc->rotate.fb_id) { 722 fb_id = drmmode_crtc->rotate.fb_id; 723 x = y = 0; 724 } else if ( 725#ifdef AMDGPU_PIXMAP_SHARING 726 !pScreen->isGPU && 727#endif 728 (info->tear_free || 729#if XF86_CRTC_VERSION >= 4 730 crtc->driverIsPerformingTransform || 731#endif 732 info->shadow_primary)) { 733 for (i = 0; i < (info->tear_free ? 2 : 1); i++) { 734 drmmode_crtc_scanout_create(crtc, 735 &drmmode_crtc->scanout[i], 736 mode->HDisplay, 737 mode->VDisplay); 738 } 739 740 if (drmmode_crtc->scanout[0].pixmap && 741 (!info->tear_free || drmmode_crtc->scanout[1].pixmap)) { 742 RegionPtr pRegion; 743 BoxPtr pBox; 744 745 if (!drmmode_crtc->scanout_damage) { 746 drmmode_crtc->scanout_damage = 747 DamageCreate(amdgpu_screen_damage_report, 748 NULL, DamageReportRawRegion, 749 TRUE, pScreen, NULL); 750 DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable, 751 drmmode_crtc->scanout_damage); 752 } 753 754 pRegion = DamageRegion(drmmode_crtc->scanout_damage); 755 RegionUninit(pRegion); 756 pRegion->data = NULL; 757 pBox = RegionExtents(pRegion); 758 pBox->x1 = 0; 759 pBox->y1 = 0; 760 pBox->x2 = max(pBox->x2, pScrn->virtualX); 761 pBox->y2 = max(pBox->y2, pScrn->virtualY); 762 763 drmmode_crtc->scanout_id = 0; 764 fb_id = drmmode_crtc->scanout[0].fb_id; 765 x = y = 0; 766 767 amdgpu_scanout_update_handler(crtc, 0, 0, drmmode_crtc); 768 amdgpu_glamor_finish(pScrn); 769 } 770 } 771 772 if (fb_id == 0) { 773 if (!amdgpu_bo_get_handle(info->front_buffer, &bo_handle)) { 774 ErrorF("failed to get BO handle for FB\n"); 775 goto done; 776 } 777 778 if (drmModeAddFB(pAMDGPUEnt->fd, 779 pScrn->virtualX, 780 pScrn->virtualY, 781 pScrn->depth, pScrn->bitsPerPixel, 782 pScrn->displayWidth * info->pixel_bytes, 783 bo_handle, &drmmode->fb_id) < 0) { 784 ErrorF("failed to add fb\n"); 785 goto done; 786 } 787 788 fb_id = drmmode->fb_id; 789 } 790 791 /* Wait for any pending flip to finish */ 792 do {} while (drmmode_crtc->flip_pending && 793 drmHandleEvent(pAMDGPUEnt->fd, 794 &drmmode->event_context) > 0); 795 796 if (drmModeSetCrtc(pAMDGPUEnt->fd, 797 drmmode_crtc->mode_crtc->crtc_id, 798 fb_id, x, y, output_ids, 799 output_count, &kmode) != 0) { 800 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 801 "failed to set mode: %s\n", strerror(errno)); 802 goto done; 803 } else 804 ret = TRUE; 805 806 if (pScreen) 807 xf86CrtcSetScreenSubpixelOrder(pScreen); 808 809 drmmode_crtc->need_modeset = FALSE; 810 811 /* go through all the outputs and force DPMS them back on? */ 812 for (i = 0; i < xf86_config->num_output; i++) { 813 xf86OutputPtr output = xf86_config->output[i]; 814 815 if (output->crtc != crtc) 816 continue; 817 818 output->funcs->dpms(output, DPMSModeOn); 819 } 820 } 821 822 /* Compute index of this CRTC into xf86_config->crtc */ 823 for (i = 0; i < xf86_config->num_crtc; i++) { 824 if (xf86_config->crtc[i] != crtc) 825 continue; 826 827 if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc)) 828 info->hwcursor_disabled &= ~(1 << i); 829 else 830 info->hwcursor_disabled |= 1 << i; 831 832 break; 833 } 834 835#ifndef HAVE_XF86_CURSOR_RESET_CURSOR 836 if (!info->hwcursor_disabled) 837 xf86_reload_cursors(pScreen); 838#endif 839 840done: 841 free(output_ids); 842 if (!ret) { 843 crtc->x = saved_x; 844 crtc->y = saved_y; 845 crtc->rotation = saved_rotation; 846 crtc->mode = saved_mode; 847 } else { 848 crtc->active = TRUE; 849 850 if (fb_id != drmmode_crtc->scanout[0].fb_id) 851 drmmode_crtc_scanout_free(drmmode_crtc); 852 } 853 854 return ret; 855} 856 857static void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 858{ 859 860} 861 862static void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y) 863{ 864 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 865 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 866 867#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 868 if (crtc->driverIsPerformingTransform) { 869 x += crtc->x; 870 y += crtc->y; 871 xf86CrtcTransformCursorPos(crtc, &x, &y); 872 } 873#endif 874 875 drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 876} 877 878#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 879 880static int 881drmmode_cursor_src_offset(Rotation rotation, int width, int height, 882 int x_dst, int y_dst) 883{ 884 int t; 885 886 switch (rotation & 0xf) { 887 case RR_Rotate_90: 888 t = x_dst; 889 x_dst = height - y_dst - 1; 890 y_dst = t; 891 break; 892 case RR_Rotate_180: 893 x_dst = width - x_dst - 1; 894 y_dst = height - y_dst - 1; 895 break; 896 case RR_Rotate_270: 897 t = x_dst; 898 x_dst = y_dst; 899 y_dst = width - t - 1; 900 break; 901 } 902 903 if (rotation & RR_Reflect_X) 904 x_dst = width - x_dst - 1; 905 if (rotation & RR_Reflect_Y) 906 y_dst = height - y_dst - 1; 907 908 return y_dst * height + x_dst; 909} 910 911#endif 912 913static void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_t *ptr) 914{ 915 ScrnInfoPtr pScrn = crtc->scrn; 916 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 917 918#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7 919 if (crtc->driverIsPerformingTransform) { 920 uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h; 921 int dstx, dsty; 922 int srcoffset; 923 924 for (dsty = 0; dsty < cursor_h; dsty++) { 925 for (dstx = 0; dstx < cursor_w; dstx++) { 926 srcoffset = drmmode_cursor_src_offset(crtc->rotation, 927 cursor_w, 928 cursor_h, 929 dstx, dsty); 930 931 ptr[dsty * info->cursor_w + dstx] = 932 cpu_to_le32(image[srcoffset]); 933 } 934 } 935 } else 936#endif 937 { 938 uint32_t cursor_size = info->cursor_w * info->cursor_h; 939 int i; 940 941 for (i = 0; i < cursor_size; i++) 942 ptr[i] = cpu_to_le32(image[i]); 943 } 944} 945 946static void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image) 947{ 948 ScrnInfoPtr pScrn = crtc->scrn; 949 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 950 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 951 uint32_t cursor_size = info->cursor_w * info->cursor_h; 952 953 if (info->gbm) { 954 uint32_t ptr[cursor_size]; 955 956 drmmode_do_load_cursor_argb(crtc, image, ptr); 957 gbm_bo_write(drmmode_crtc->cursor_buffer->bo.gbm, ptr, cursor_size * 4); 958 } else { 959 /* cursor should be mapped already */ 960 uint32_t *ptr = (uint32_t *) (drmmode_crtc->cursor_buffer->cpu_ptr); 961 962 drmmode_do_load_cursor_argb(crtc, image, ptr); 963 } 964} 965 966#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 967 968static Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image) 969{ 970 if (!drmmode_can_use_hw_cursor(crtc)) 971 return FALSE; 972 973 drmmode_load_cursor_argb(crtc, image); 974 return TRUE; 975} 976 977#endif 978 979static void drmmode_hide_cursor(xf86CrtcPtr crtc) 980{ 981 ScrnInfoPtr pScrn = crtc->scrn; 982 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 983 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 984 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 985 986 drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 987 info->cursor_w, info->cursor_h); 988 989} 990 991static void drmmode_show_cursor(xf86CrtcPtr crtc) 992{ 993 ScrnInfoPtr pScrn = crtc->scrn; 994 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 995 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 996 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 997 uint32_t bo_handle; 998 static Bool use_set_cursor2 = TRUE; 999 1000 if (!amdgpu_bo_get_handle(drmmode_crtc->cursor_buffer, &bo_handle)) { 1001 ErrorF("failed to get BO handle for cursor\n"); 1002 return; 1003 } 1004 1005 if (use_set_cursor2) { 1006 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 1007 CursorPtr cursor = xf86_config->cursor; 1008 int xhot = cursor->bits->xhot; 1009 int yhot = cursor->bits->yhot; 1010 int ret; 1011 1012 if (crtc->rotation != RR_Rotate_0 && 1013 crtc->rotation != (RR_Rotate_180 | RR_Reflect_X | 1014 RR_Reflect_Y)) { 1015 int t; 1016 1017 /* Reflect & rotate hotspot position */ 1018 if (crtc->rotation & RR_Reflect_X) 1019 xhot = info->cursor_w - xhot - 1; 1020 if (crtc->rotation & RR_Reflect_Y) 1021 yhot = info->cursor_h - yhot - 1; 1022 1023 switch (crtc->rotation & 0xf) { 1024 case RR_Rotate_90: 1025 t = xhot; 1026 xhot = yhot; 1027 yhot = info->cursor_w - t - 1; 1028 break; 1029 case RR_Rotate_180: 1030 xhot = info->cursor_w - xhot - 1; 1031 yhot = info->cursor_h - yhot - 1; 1032 break; 1033 case RR_Rotate_270: 1034 t = xhot; 1035 xhot = info->cursor_h - yhot - 1; 1036 yhot = t; 1037 } 1038 } 1039 1040 ret = drmModeSetCursor2(pAMDGPUEnt->fd, 1041 drmmode_crtc->mode_crtc->crtc_id, 1042 bo_handle, 1043 info->cursor_w, info->cursor_h, 1044 xhot, yhot); 1045 if (ret == -EINVAL) 1046 use_set_cursor2 = FALSE; 1047 else 1048 return; 1049 } 1050 1051 drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, bo_handle, 1052 info->cursor_w, info->cursor_h); 1053} 1054 1055static void *drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, 1056 int height) 1057{ 1058 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1059 1060 return drmmode_crtc_scanout_allocate(crtc, &drmmode_crtc->rotate, 1061 width, height); 1062} 1063 1064static PixmapPtr 1065drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 1066{ 1067 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1068 1069 /* Xorg passes in the return value of drmmode_crtc_shadow_allocate 1070 * for data, but that's redundant for drmmode_crtc_scanout_create. 1071 */ 1072 return drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width, 1073 height); 1074} 1075 1076static void 1077drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, 1078 void *data) 1079{ 1080 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1081 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1082 1083 drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate); 1084} 1085 1086static void 1087drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green, 1088 uint16_t * blue, int size) 1089{ 1090 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1091 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 1092 1093 drmModeCrtcSetGamma(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 1094 size, red, green, blue); 1095} 1096 1097#ifdef AMDGPU_PIXMAP_SHARING 1098static Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 1099{ 1100 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1101 AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn); 1102 ScreenPtr screen = crtc->scrn->pScreen; 1103 PixmapDirtyUpdatePtr dirty; 1104 1105 xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) { 1106 if (dirty->slave_dst != 1107 drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap) 1108 continue; 1109 1110 PixmapStopDirtyTracking(dirty->src, dirty->slave_dst); 1111 drmmode_crtc_scanout_free(drmmode_crtc); 1112 break; 1113 } 1114 1115 if (!ppix) 1116 return TRUE; 1117 1118 if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0], 1119 ppix->drawable.width, 1120 ppix->drawable.height)) 1121 return FALSE; 1122 1123 if (info->tear_free && 1124 !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1], 1125 ppix->drawable.width, 1126 ppix->drawable.height)) { 1127 drmmode_crtc_scanout_free(drmmode_crtc); 1128 return FALSE; 1129 } 1130 1131#ifdef HAS_DIRTYTRACKING_ROTATION 1132 PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[0].pixmap, 1133 0, 0, 0, 0, RR_Rotate_0); 1134#elif defined(HAS_DIRTYTRACKING2) 1135 PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[0].pixmap, 1136 0, 0, 0, 0); 1137#else 1138 PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[0].pixmap, 0, 0); 1139#endif 1140 return TRUE; 1141} 1142#endif 1143 1144static xf86CrtcFuncsRec drmmode_crtc_funcs = { 1145 .dpms = drmmode_crtc_dpms, 1146 .set_mode_major = drmmode_set_mode_major, 1147 .set_cursor_colors = drmmode_set_cursor_colors, 1148 .set_cursor_position = drmmode_set_cursor_position, 1149 .show_cursor = drmmode_show_cursor, 1150 .hide_cursor = drmmode_hide_cursor, 1151 .load_cursor_argb = drmmode_load_cursor_argb, 1152#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0) 1153 .load_cursor_argb_check = drmmode_load_cursor_argb_check, 1154#endif 1155 1156 .gamma_set = drmmode_crtc_gamma_set, 1157 .shadow_create = drmmode_crtc_shadow_create, 1158 .shadow_allocate = drmmode_crtc_shadow_allocate, 1159 .shadow_destroy = drmmode_crtc_shadow_destroy, 1160 .destroy = NULL, /* XXX */ 1161#ifdef AMDGPU_PIXMAP_SHARING 1162 .set_scanout_pixmap = drmmode_set_scanout_pixmap, 1163#endif 1164}; 1165 1166int drmmode_get_crtc_id(xf86CrtcPtr crtc) 1167{ 1168 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1169 return drmmode_crtc->hw_id; 1170} 1171 1172void drmmode_crtc_hw_id(xf86CrtcPtr crtc) 1173{ 1174 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1175 ScrnInfoPtr pScrn = crtc->scrn; 1176 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1177 int r; 1178 1179 r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev, 1180 drmmode_crtc->mode_crtc->crtc_id, 1181 &drmmode_crtc->hw_id); 1182 if (r) 1183 drmmode_crtc->hw_id = -1; 1184} 1185 1186static unsigned int 1187drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 1188{ 1189 xf86CrtcPtr crtc; 1190 drmmode_crtc_private_ptr drmmode_crtc; 1191 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1192 1193 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); 1194 if (crtc == NULL) 1195 return 0; 1196 1197 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 1198 drmmode_crtc->mode_crtc = 1199 drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]); 1200 drmmode_crtc->drmmode = drmmode; 1201 drmmode_crtc->dpms_mode = DPMSModeOff; 1202 drmmode_crtc->pending_dpms_mode = DPMSModeOff; 1203 crtc->driver_private = drmmode_crtc; 1204 drmmode_crtc_hw_id(crtc); 1205 1206 /* Mark num'th crtc as in use on this device. */ 1207 pAMDGPUEnt->assigned_crtcs |= (1 << num); 1208 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 1209 "Allocated crtc nr. %d to this screen.\n", num); 1210 1211 return 1; 1212} 1213 1214static xf86OutputStatus drmmode_output_detect(xf86OutputPtr output) 1215{ 1216 /* go to the hw and retrieve a new output struct */ 1217 drmmode_output_private_ptr drmmode_output = output->driver_private; 1218 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 1219 xf86OutputStatus status; 1220 drmModeFreeConnector(drmmode_output->mode_output); 1221 1222 drmmode_output->mode_output = 1223 drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id); 1224 if (!drmmode_output->mode_output) 1225 return XF86OutputStatusDisconnected; 1226 1227 switch (drmmode_output->mode_output->connection) { 1228 case DRM_MODE_CONNECTED: 1229 status = XF86OutputStatusConnected; 1230 break; 1231 case DRM_MODE_DISCONNECTED: 1232 status = XF86OutputStatusDisconnected; 1233 break; 1234 default: 1235 case DRM_MODE_UNKNOWNCONNECTION: 1236 status = XF86OutputStatusUnknown; 1237 break; 1238 } 1239 return status; 1240} 1241 1242static Bool 1243drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 1244{ 1245 return MODE_OK; 1246} 1247 1248static DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output) 1249{ 1250 drmmode_output_private_ptr drmmode_output = output->driver_private; 1251 drmModeConnectorPtr koutput = drmmode_output->mode_output; 1252 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 1253 int i; 1254 DisplayModePtr Modes = NULL, Mode; 1255 drmModePropertyPtr props; 1256 xf86MonPtr mon = NULL; 1257 1258 if (!koutput) 1259 return NULL; 1260 1261 /* look for an EDID property */ 1262 for (i = 0; i < koutput->count_props; i++) { 1263 props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]); 1264 if (props && (props->flags & DRM_MODE_PROP_BLOB)) { 1265 if (!strcmp(props->name, "EDID")) { 1266 if (drmmode_output->edid_blob) 1267 drmModeFreePropertyBlob 1268 (drmmode_output->edid_blob); 1269 drmmode_output->edid_blob = 1270 drmModeGetPropertyBlob(pAMDGPUEnt->fd, 1271 koutput->prop_values 1272 [i]); 1273 } 1274 } 1275 if (props) 1276 drmModeFreeProperty(props); 1277 } 1278 1279 if (drmmode_output->edid_blob) { 1280 mon = xf86InterpretEDID(output->scrn->scrnIndex, 1281 drmmode_output->edid_blob->data); 1282 if (mon && drmmode_output->edid_blob->length > 128) 1283 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 1284 } 1285 xf86OutputSetEDID(output, mon); 1286 1287 /* modes should already be available */ 1288 for (i = 0; i < koutput->count_modes; i++) { 1289 Mode = xnfalloc(sizeof(DisplayModeRec)); 1290 1291 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 1292 Mode); 1293 Modes = xf86ModesAdd(Modes, Mode); 1294 1295 } 1296 return Modes; 1297} 1298 1299static void drmmode_output_destroy(xf86OutputPtr output) 1300{ 1301 drmmode_output_private_ptr drmmode_output = output->driver_private; 1302 int i; 1303 1304 if (drmmode_output->edid_blob) 1305 drmModeFreePropertyBlob(drmmode_output->edid_blob); 1306 for (i = 0; i < drmmode_output->num_props; i++) { 1307 drmModeFreeProperty(drmmode_output->props[i].mode_prop); 1308 free(drmmode_output->props[i].atoms); 1309 } 1310 for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 1311 drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 1312 } 1313 free(drmmode_output->mode_encoders); 1314 free(drmmode_output->props); 1315 drmModeFreeConnector(drmmode_output->mode_output); 1316 free(drmmode_output); 1317 output->driver_private = NULL; 1318} 1319 1320static void drmmode_output_dpms(xf86OutputPtr output, int mode) 1321{ 1322 drmmode_output_private_ptr drmmode_output = output->driver_private; 1323 xf86CrtcPtr crtc = output->crtc; 1324 drmModeConnectorPtr koutput = drmmode_output->mode_output; 1325 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 1326 1327 if (!koutput) 1328 return; 1329 1330 if (mode != DPMSModeOn && crtc) { 1331 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1332 1333 drmmode_do_crtc_dpms(crtc, mode); 1334 1335 /* Wait for any pending flip to finish */ 1336 if (drmmode_crtc->flip_pending) 1337 return; 1338 } 1339 1340 drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id, 1341 drmmode_output->dpms_enum_id, mode); 1342 1343 if (mode == DPMSModeOn && crtc) { 1344 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1345 1346 if (drmmode_crtc->need_modeset) 1347 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 1348 crtc->x, crtc->y); 1349 else 1350 drmmode_do_crtc_dpms(output->crtc, mode); 1351 } 1352} 1353 1354static Bool drmmode_property_ignore(drmModePropertyPtr prop) 1355{ 1356 if (!prop) 1357 return TRUE; 1358 /* ignore blob prop */ 1359 if (prop->flags & DRM_MODE_PROP_BLOB) 1360 return TRUE; 1361 /* ignore standard property */ 1362 if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS")) 1363 return TRUE; 1364 1365 return FALSE; 1366} 1367 1368static void drmmode_output_create_resources(xf86OutputPtr output) 1369{ 1370 drmmode_output_private_ptr drmmode_output = output->driver_private; 1371 drmModeConnectorPtr mode_output = drmmode_output->mode_output; 1372 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 1373 drmModePropertyPtr drmmode_prop; 1374 int i, j, err; 1375 1376 drmmode_output->props = 1377 calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); 1378 if (!drmmode_output->props) 1379 return; 1380 1381 drmmode_output->num_props = 0; 1382 for (i = 0, j = 0; i < mode_output->count_props; i++) { 1383 drmmode_prop = 1384 drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]); 1385 if (drmmode_property_ignore(drmmode_prop)) { 1386 drmModeFreeProperty(drmmode_prop); 1387 continue; 1388 } 1389 drmmode_output->props[j].mode_prop = drmmode_prop; 1390 drmmode_output->props[j].value = mode_output->prop_values[i]; 1391 drmmode_output->num_props++; 1392 j++; 1393 } 1394 1395 for (i = 0; i < drmmode_output->num_props; i++) { 1396 drmmode_prop_ptr p = &drmmode_output->props[i]; 1397 drmmode_prop = p->mode_prop; 1398 1399 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 1400 INT32 range[2]; 1401 INT32 value = p->value; 1402 1403 p->num_atoms = 1; 1404 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1405 if (!p->atoms) 1406 continue; 1407 p->atoms[0] = 1408 MakeAtom(drmmode_prop->name, 1409 strlen(drmmode_prop->name), TRUE); 1410 range[0] = drmmode_prop->values[0]; 1411 range[1] = drmmode_prop->values[1]; 1412 err = 1413 RRConfigureOutputProperty(output->randr_output, 1414 p->atoms[0], FALSE, TRUE, 1415 drmmode_prop->flags & 1416 DRM_MODE_PROP_IMMUTABLE ? 1417 TRUE : FALSE, 2, range); 1418 if (err != 0) { 1419 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1420 "RRConfigureOutputProperty error, %d\n", 1421 err); 1422 } 1423 err = 1424 RRChangeOutputProperty(output->randr_output, 1425 p->atoms[0], XA_INTEGER, 32, 1426 PropModeReplace, 1, &value, 1427 FALSE, TRUE); 1428 if (err != 0) { 1429 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1430 "RRChangeOutputProperty error, %d\n", 1431 err); 1432 } 1433 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1434 p->num_atoms = drmmode_prop->count_enums + 1; 1435 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1436 if (!p->atoms) 1437 continue; 1438 p->atoms[0] = 1439 MakeAtom(drmmode_prop->name, 1440 strlen(drmmode_prop->name), TRUE); 1441 for (j = 1; j <= drmmode_prop->count_enums; j++) { 1442 struct drm_mode_property_enum *e = 1443 &drmmode_prop->enums[j - 1]; 1444 p->atoms[j] = 1445 MakeAtom(e->name, strlen(e->name), TRUE); 1446 } 1447 err = 1448 RRConfigureOutputProperty(output->randr_output, 1449 p->atoms[0], FALSE, FALSE, 1450 drmmode_prop->flags & 1451 DRM_MODE_PROP_IMMUTABLE ? 1452 TRUE : FALSE, 1453 p->num_atoms - 1, 1454 (INT32 *) & p->atoms[1]); 1455 if (err != 0) { 1456 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1457 "RRConfigureOutputProperty error, %d\n", 1458 err); 1459 } 1460 for (j = 0; j < drmmode_prop->count_enums; j++) 1461 if (drmmode_prop->enums[j].value == p->value) 1462 break; 1463 /* there's always a matching value */ 1464 err = 1465 RRChangeOutputProperty(output->randr_output, 1466 p->atoms[0], XA_ATOM, 32, 1467 PropModeReplace, 1, 1468 &p->atoms[j + 1], FALSE, 1469 TRUE); 1470 if (err != 0) { 1471 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1472 "RRChangeOutputProperty error, %d\n", 1473 err); 1474 } 1475 } 1476 } 1477} 1478 1479static Bool 1480drmmode_output_set_property(xf86OutputPtr output, Atom property, 1481 RRPropertyValuePtr value) 1482{ 1483 drmmode_output_private_ptr drmmode_output = output->driver_private; 1484 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn); 1485 int i; 1486 1487 for (i = 0; i < drmmode_output->num_props; i++) { 1488 drmmode_prop_ptr p = &drmmode_output->props[i]; 1489 1490 if (p->atoms[0] != property) 1491 continue; 1492 1493 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1494 uint32_t val; 1495 1496 if (value->type != XA_INTEGER || value->format != 32 || 1497 value->size != 1) 1498 return FALSE; 1499 val = *(uint32_t *) value->data; 1500 1501 drmModeConnectorSetProperty(pAMDGPUEnt->fd, 1502 drmmode_output->output_id, 1503 p->mode_prop->prop_id, 1504 (uint64_t) val); 1505 return TRUE; 1506 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1507 Atom atom; 1508 const char *name; 1509 int j; 1510 1511 if (value->type != XA_ATOM || value->format != 32 1512 || value->size != 1) 1513 return FALSE; 1514 memcpy(&atom, value->data, 4); 1515 name = NameForAtom(atom); 1516 1517 /* search for matching name string, then set its value down */ 1518 for (j = 0; j < p->mode_prop->count_enums; j++) { 1519 if (!strcmp(p->mode_prop->enums[j].name, name)) { 1520 drmModeConnectorSetProperty(pAMDGPUEnt->fd, 1521 drmmode_output->output_id, 1522 p->mode_prop->prop_id, 1523 p->mode_prop->enums 1524 [j].value); 1525 return TRUE; 1526 } 1527 } 1528 } 1529 } 1530 1531 return TRUE; 1532} 1533 1534static Bool drmmode_output_get_property(xf86OutputPtr output, Atom property) 1535{ 1536 return TRUE; 1537} 1538 1539static const xf86OutputFuncsRec drmmode_output_funcs = { 1540 .dpms = drmmode_output_dpms, 1541 .create_resources = drmmode_output_create_resources, 1542 .set_property = drmmode_output_set_property, 1543 .get_property = drmmode_output_get_property, 1544#if 0 1545 1546 .save = drmmode_crt_save, 1547 .restore = drmmode_crt_restore, 1548 .mode_fixup = drmmode_crt_mode_fixup, 1549 .prepare = drmmode_output_prepare, 1550 .mode_set = drmmode_crt_mode_set, 1551 .commit = drmmode_output_commit, 1552#endif 1553 .detect = drmmode_output_detect, 1554 .mode_valid = drmmode_output_mode_valid, 1555 1556 .get_modes = drmmode_output_get_modes, 1557 .destroy = drmmode_output_destroy 1558}; 1559 1560static int subpixel_conv_table[7] = { 0, SubPixelUnknown, 1561 SubPixelHorizontalRGB, 1562 SubPixelHorizontalBGR, 1563 SubPixelVerticalRGB, 1564 SubPixelVerticalBGR, 1565 SubPixelNone 1566}; 1567 1568const char *output_names[] = { "None", 1569 "VGA", 1570 "DVI-I", 1571 "DVI-D", 1572 "DVI-A", 1573 "Composite", 1574 "S-video", 1575 "LVDS", 1576 "CTV", 1577 "DIN", 1578 "DisplayPort", 1579 "HDMI-A", 1580 "HDMI-B", 1581 "TV", 1582 "eDP", 1583 "Virtual", 1584 "DSI", 1585}; 1586 1587#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 1588 1589static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 1590{ 1591 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1592 int i; 1593 for (i = 0; i < xf86_config->num_output; i++) { 1594 xf86OutputPtr output = xf86_config->output[i]; 1595 drmmode_output_private_ptr drmmode_output; 1596 drmmode_output = output->driver_private; 1597 if (drmmode_output->output_id == id) 1598 return output; 1599 } 1600 return NULL; 1601} 1602 1603static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 1604{ 1605 char *conn; 1606 char conn_id[5]; 1607 int id, len; 1608 char *blob_data; 1609 1610 if (!path_blob) 1611 return -1; 1612 1613 blob_data = path_blob->data; 1614 /* we only handle MST paths for now */ 1615 if (strncmp(blob_data, "mst:", 4)) 1616 return -1; 1617 1618 conn = strchr(blob_data + 4, '-'); 1619 if (!conn) 1620 return -1; 1621 len = conn - (blob_data + 4); 1622 if (len + 1 > 5) 1623 return -1; 1624 memcpy(conn_id, blob_data + 4, len); 1625 conn_id[len] = '\0'; 1626 id = strtoul(conn_id, NULL, 10); 1627 1628 *conn_base_id = id; 1629 1630 *path = conn + 1; 1631 return 0; 1632} 1633 1634static void 1635drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 1636 drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi) 1637{ 1638 xf86OutputPtr output; 1639 int conn_id; 1640 char *extra_path; 1641 1642 output = NULL; 1643 if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 1644 output = find_output(pScrn, conn_id); 1645 if (output) { 1646 snprintf(name, 32, "%s-%s", output->name, extra_path); 1647 } else { 1648 if (koutput->connector_type >= NUM_OUTPUT_NAMES) 1649 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1); 1650#ifdef AMDGPU_PIXMAP_SHARING 1651 else if (pScrn->is_gpu) 1652 snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], 1653 pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1); 1654#endif 1655 else { 1656 /* need to do smart conversion here for compat with non-kms ATI driver */ 1657 if (koutput->connector_type_id == 1) { 1658 switch(koutput->connector_type) { 1659 case DRM_MODE_CONNECTOR_DVII: 1660 case DRM_MODE_CONNECTOR_DVID: 1661 case DRM_MODE_CONNECTOR_DVIA: 1662 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 1663 (*num_dvi)++; 1664 break; 1665 case DRM_MODE_CONNECTOR_HDMIA: 1666 case DRM_MODE_CONNECTOR_HDMIB: 1667 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 1668 (*num_hdmi)++; 1669 break; 1670 case DRM_MODE_CONNECTOR_VGA: 1671 case DRM_MODE_CONNECTOR_DisplayPort: 1672 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 1673 break; 1674 default: 1675 snprintf(name, 32, "%s", output_names[koutput->connector_type]); 1676 break; 1677 } 1678 } else { 1679 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 1680 } 1681 } 1682 } 1683} 1684 1685 1686static unsigned int 1687drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic) 1688{ 1689 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1690 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 1691 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 1692 xf86OutputPtr output; 1693 drmModeConnectorPtr koutput; 1694 drmModeEncoderPtr *kencoders = NULL; 1695 drmmode_output_private_ptr drmmode_output; 1696 drmModePropertyPtr props; 1697 drmModePropertyBlobPtr path_blob = NULL; 1698 char name[32]; 1699 int i; 1700 const char *s; 1701 1702 koutput = 1703 drmModeGetConnector(pAMDGPUEnt->fd, 1704 mode_res->connectors[num]); 1705 if (!koutput) 1706 return 0; 1707 1708 for (i = 0; i < koutput->count_props; i++) { 1709 props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]); 1710 if (props && (props->flags & DRM_MODE_PROP_BLOB)) { 1711 if (!strcmp(props->name, "PATH")) { 1712 path_blob = drmModeGetPropertyBlob(pAMDGPUEnt->fd, koutput->prop_values[i]); 1713 drmModeFreeProperty(props); 1714 break; 1715 } 1716 drmModeFreeProperty(props); 1717 } 1718 } 1719 1720 kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 1721 if (!kencoders) { 1722 goto out_free_encoders; 1723 } 1724 1725 for (i = 0; i < koutput->count_encoders; i++) { 1726 kencoders[i] = 1727 drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]); 1728 if (!kencoders[i]) { 1729 goto out_free_encoders; 1730 } 1731 } 1732 1733 drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi); 1734 if (path_blob) { 1735 drmModeFreePropertyBlob(path_blob); 1736 } 1737 1738 if (path_blob && dynamic) { 1739 /* See if we have an output with this name already 1740 * and hook stuff up. 1741 */ 1742 for (i = 0; i < xf86_config->num_output; i++) { 1743 output = xf86_config->output[i]; 1744 1745 if (strncmp(output->name, name, 32)) 1746 continue; 1747 1748 drmmode_output = output->driver_private; 1749 drmmode_output->output_id = mode_res->connectors[num]; 1750 drmmode_output->mode_output = koutput; 1751 for (i = 0; i < koutput->count_encoders; i++) { 1752 drmModeFreeEncoder(kencoders[i]); 1753 } 1754 free(kencoders); 1755 return 1; 1756 } 1757 } 1758 1759 if (xf86IsEntityShared(pScrn->entityList[0])) { 1760 if ((s = 1761 xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 1762 if (!AMDGPUZaphodStringMatches(pScrn, s, name)) 1763 goto out_free_encoders; 1764 } else { 1765 if (!info->IsSecondary && (num != 0)) 1766 goto out_free_encoders; 1767 else if (info->IsSecondary && (num != 1)) 1768 goto out_free_encoders; 1769 } 1770 } 1771 1772 output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name); 1773 if (!output) { 1774 goto out_free_encoders; 1775 } 1776 1777 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 1778 if (!drmmode_output) { 1779 xf86OutputDestroy(output); 1780 goto out_free_encoders; 1781 } 1782 1783 drmmode_output->output_id = mode_res->connectors[num]; 1784 drmmode_output->mode_output = koutput; 1785 drmmode_output->mode_encoders = kencoders; 1786 drmmode_output->drmmode = drmmode; 1787 output->mm_width = koutput->mmWidth; 1788 output->mm_height = koutput->mmHeight; 1789 1790 output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 1791 output->interlaceAllowed = TRUE; 1792 output->doubleScanAllowed = TRUE; 1793 output->driver_private = drmmode_output; 1794 1795 output->possible_crtcs = 0xffffffff; 1796 for (i = 0; i < koutput->count_encoders; i++) { 1797 output->possible_crtcs &= kencoders[i]->possible_crtcs; 1798 } 1799 /* work out the possible clones later */ 1800 output->possible_clones = 0; 1801 1802 for (i = 0; i < koutput->count_props; i++) { 1803 props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]); 1804 if (props && (props->flags & DRM_MODE_PROP_ENUM)) { 1805 if (!strcmp(props->name, "DPMS")) { 1806 drmmode_output->dpms_enum_id = 1807 koutput->props[i]; 1808 drmModeFreeProperty(props); 1809 break; 1810 } 1811 drmModeFreeProperty(props); 1812 } 1813 } 1814 1815 if (dynamic) { 1816 output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 1817 drmmode_output_create_resources(output); 1818 } 1819 1820 return 1; 1821out_free_encoders: 1822 if (kencoders) { 1823 for (i = 0; i < koutput->count_encoders; i++) 1824 drmModeFreeEncoder(kencoders[i]); 1825 free(kencoders); 1826 } 1827 drmModeFreeConnector(koutput); 1828 return 0; 1829} 1830 1831uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 1832{ 1833 drmmode_output_private_ptr drmmode_output = 1834 output->driver_private, clone_drmout; 1835 int i; 1836 xf86OutputPtr clone_output; 1837 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1838 int index_mask = 0; 1839 1840 if (drmmode_output->enc_clone_mask == 0) 1841 return index_mask; 1842 1843 for (i = 0; i < xf86_config->num_output; i++) { 1844 clone_output = xf86_config->output[i]; 1845 clone_drmout = clone_output->driver_private; 1846 if (output == clone_output) 1847 continue; 1848 1849 if (clone_drmout->enc_mask == 0) 1850 continue; 1851 if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 1852 index_mask |= (1 << i); 1853 } 1854 return index_mask; 1855} 1856 1857static void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res) 1858{ 1859 int i, j; 1860 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1861 1862 for (i = 0; i < xf86_config->num_output; i++) { 1863 xf86OutputPtr output = xf86_config->output[i]; 1864 drmmode_output_private_ptr drmmode_output; 1865 1866 drmmode_output = output->driver_private; 1867 drmmode_output->enc_clone_mask = 0xff; 1868 /* and all the possible encoder clones for this output together */ 1869 for (j = 0; j < drmmode_output->mode_output->count_encoders; 1870 j++) { 1871 int k; 1872 for (k = 0; k < mode_res->count_encoders; k++) { 1873 if (mode_res->encoders[k] == 1874 drmmode_output-> 1875 mode_encoders[j]->encoder_id) 1876 drmmode_output->enc_mask |= (1 << k); 1877 } 1878 1879 drmmode_output->enc_clone_mask &= 1880 drmmode_output->mode_encoders[j]->possible_clones; 1881 } 1882 } 1883 1884 for (i = 0; i < xf86_config->num_output; i++) { 1885 xf86OutputPtr output = xf86_config->output[i]; 1886 output->possible_clones = find_clones(scrn, output); 1887 } 1888} 1889 1890/* returns pitch alignment in pixels */ 1891int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe) 1892{ 1893 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 1894 1895 if (info->have_tiling_info) 1896 /* linear aligned requirements */ 1897 return MAX(64, info->group_bytes / bpe); 1898 else 1899 /* default to 512 elements if we don't know the real 1900 * group size otherwise the kernel may reject the CS 1901 * if the group sizes don't match as the pitch won't 1902 * be aligned properly. 1903 */ 1904 return 512; 1905} 1906 1907static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 1908{ 1909 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1910 drmmode_crtc_private_ptr 1911 drmmode_crtc = xf86_config->crtc[0]->driver_private; 1912 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1913 AMDGPUInfoPtr info = AMDGPUPTR(scrn); 1914 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 1915 struct amdgpu_buffer *old_front = NULL; 1916 ScreenPtr screen = xf86ScrnToScreen(scrn); 1917 uint32_t old_fb_id; 1918 int i, pitch, old_width, old_height, old_pitch; 1919 int cpp = info->pixel_bytes; 1920 PixmapPtr ppix = screen->GetScreenPixmap(screen); 1921 void *fb_shadow; 1922 int hint = 0; 1923 xRectangle rect; 1924 GCPtr gc; 1925 1926 if (scrn->virtualX == width && scrn->virtualY == height) 1927 return TRUE; 1928 1929 if (info->shadow_primary) 1930 hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT; 1931 else if (!info->use_glamor) 1932 hint = AMDGPU_CREATE_PIXMAP_LINEAR; 1933 1934 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1935 "Allocate new frame buffer %dx%d\n", width, height); 1936 1937 old_width = scrn->virtualX; 1938 old_height = scrn->virtualY; 1939 old_pitch = scrn->displayWidth; 1940 old_fb_id = drmmode->fb_id; 1941 drmmode->fb_id = 0; 1942 old_front = info->front_buffer; 1943 1944 scrn->virtualX = width; 1945 scrn->virtualY = height; 1946 1947 info->front_buffer = 1948 amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY, 1949 scrn->depth, hint, scrn->bitsPerPixel, 1950 &pitch); 1951 if (!info->front_buffer) { 1952 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1953 "Failed to allocate front buffer memory\n"); 1954 goto fail; 1955 } 1956 1957 if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) { 1958 xf86DrvMsg(scrn->scrnIndex, X_ERROR, 1959 "Failed to map front buffer memory\n"); 1960 goto fail; 1961 } 1962 1963 xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch); 1964 scrn->displayWidth = pitch / cpp; 1965 1966 if (info->use_glamor || 1967 (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 1968 screen->ModifyPixmapHeader(ppix, 1969 width, height, -1, -1, pitch, info->front_buffer->cpu_ptr); 1970 } else { 1971 fb_shadow = calloc(1, pitch * scrn->virtualY); 1972 if (fb_shadow == NULL) 1973 goto fail; 1974 free(info->fb_shadow); 1975 info->fb_shadow = fb_shadow; 1976 screen->ModifyPixmapHeader(ppix, 1977 width, height, -1, -1, pitch, 1978 info->fb_shadow); 1979 } 1980 1981 if (!amdgpu_glamor_create_screen_resources(scrn->pScreen)) 1982 goto fail; 1983 1984 if (info->use_glamor || 1985 (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) { 1986 if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer)) 1987 goto fail; 1988 } 1989 1990 /* Clear new buffer */ 1991 gc = GetScratchGC(ppix->drawable.depth, scrn->pScreen); 1992 ValidateGC(&ppix->drawable, gc); 1993 rect.x = 0; 1994 rect.y = 0; 1995 rect.width = width; 1996 rect.height = height; 1997 info->force_accel = TRUE; 1998 (*gc->ops->PolyFillRect)(&ppix->drawable, gc, 1, &rect); 1999 info->force_accel = FALSE; 2000 FreeScratchGC(gc); 2001 amdgpu_glamor_finish(scrn); 2002 2003 for (i = 0; i < xf86_config->num_crtc; i++) { 2004 xf86CrtcPtr crtc = xf86_config->crtc[i]; 2005 2006 if (!crtc->enabled) 2007 continue; 2008 2009 drmmode_set_mode_major(crtc, &crtc->mode, 2010 crtc->rotation, crtc->x, crtc->y); 2011 } 2012 2013 if (old_fb_id) 2014 drmModeRmFB(pAMDGPUEnt->fd, old_fb_id); 2015 if (old_front) { 2016 amdgpu_bo_unref(&old_front); 2017 } 2018 2019 return TRUE; 2020 2021fail: 2022 if (info->front_buffer) { 2023 amdgpu_bo_unref(&info->front_buffer); 2024 } 2025 info->front_buffer = old_front; 2026 scrn->virtualX = old_width; 2027 scrn->virtualY = old_height; 2028 scrn->displayWidth = old_pitch; 2029 drmmode->fb_id = old_fb_id; 2030 2031 return FALSE; 2032} 2033 2034static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 2035 drmmode_xf86crtc_resize 2036}; 2037 2038void 2039drmmode_clear_pending_flip(xf86CrtcPtr crtc) 2040{ 2041 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2042 2043 drmmode_crtc->flip_pending = FALSE; 2044 2045 if (!crtc->enabled || 2046 (drmmode_crtc->pending_dpms_mode != DPMSModeOn && 2047 drmmode_crtc->dpms_mode != drmmode_crtc->pending_dpms_mode)) { 2048 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 2049 int o; 2050 2051 for (o = 0; o < xf86_config->num_output; o++) { 2052 xf86OutputPtr output = xf86_config->output[o]; 2053 2054 if (output->crtc != crtc) 2055 continue; 2056 2057 drmmode_output_dpms(output, drmmode_crtc->pending_dpms_mode); 2058 } 2059 2060 drmmode_crtc_dpms(crtc, drmmode_crtc->pending_dpms_mode); 2061 } 2062 2063 drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 2064 &drmmode_crtc->scanout_destroy[0]); 2065 drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode, 2066 &drmmode_crtc->scanout_destroy[1]); 2067} 2068 2069static void 2070drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data) 2071{ 2072 drmmode_flipdata_ptr flipdata = event_data; 2073 2074 if (--flipdata->flip_count == 0) { 2075 if (!flipdata->fe_crtc) 2076 flipdata->fe_crtc = crtc; 2077 flipdata->abort(flipdata->fe_crtc, flipdata->event_data); 2078 free(flipdata); 2079 } 2080 2081 drmmode_clear_pending_flip(crtc); 2082} 2083 2084static void 2085drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data) 2086{ 2087 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn); 2088 drmmode_flipdata_ptr flipdata = event_data; 2089 2090 /* Is this the event whose info shall be delivered to higher level? */ 2091 if (crtc == flipdata->fe_crtc) { 2092 /* Yes: Cache msc, ust for later delivery. */ 2093 flipdata->fe_frame = frame; 2094 flipdata->fe_usec = usec; 2095 } 2096 2097 if (--flipdata->flip_count == 0) { 2098 /* Deliver MSC & UST from reference/current CRTC to flip event 2099 * handler 2100 */ 2101 if (flipdata->fe_crtc) 2102 flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame, 2103 flipdata->fe_usec, flipdata->event_data); 2104 else 2105 flipdata->handler(crtc, frame, usec, flipdata->event_data); 2106 2107 /* Release framebuffer */ 2108 drmModeRmFB(pAMDGPUEnt->fd, flipdata->old_fb_id); 2109 2110 free(flipdata); 2111 } 2112 2113 drmmode_clear_pending_flip(crtc); 2114} 2115 2116#if HAVE_NOTIFY_FD 2117static void drmmode_notify_fd(int fd, int notify, void *data) 2118{ 2119 drmmode_ptr drmmode = data; 2120 drmHandleEvent(fd, &drmmode->event_context); 2121} 2122#else 2123static void drm_wakeup_handler(pointer data, int err, pointer p) 2124{ 2125 drmmode_ptr drmmode = data; 2126 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn); 2127 fd_set *read_mask = p; 2128 2129 if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) { 2130 drmHandleEvent(pAMDGPUEnt->fd, &drmmode->event_context); 2131 } 2132} 2133#endif 2134 2135Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 2136{ 2137 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2138 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2139 int i, num_dvi = 0, num_hdmi = 0; 2140 unsigned int crtcs_needed = 0; 2141 drmModeResPtr mode_res; 2142#ifdef AMDGPU_PIXMAP_SHARING 2143 char *bus_id_string, *provider_name; 2144#endif 2145 2146 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 2147 2148 drmmode->scrn = pScrn; 2149 drmmode->cpp = cpp; 2150 mode_res = drmModeGetResources(pAMDGPUEnt->fd); 2151 if (!mode_res) 2152 return FALSE; 2153 2154 drmmode->count_crtcs = mode_res->count_crtcs; 2155 xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, 2156 mode_res->max_height); 2157 2158 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2159 "Initializing outputs ...\n"); 2160 for (i = 0; i < mode_res->count_connectors; i++) 2161 crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0); 2162 2163 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2164 "%d crtcs needed for screen.\n", crtcs_needed); 2165 2166 if (!info->use_glamor) { 2167 /* Rotation requires hardware acceleration */ 2168 drmmode_crtc_funcs.shadow_allocate = NULL; 2169 drmmode_crtc_funcs.shadow_create = NULL; 2170 drmmode_crtc_funcs.shadow_destroy = NULL; 2171 } 2172 2173 for (i = 0; i < mode_res->count_crtcs; i++) 2174 if (!xf86IsEntityShared(pScrn->entityList[0]) || 2175 (crtcs_needed && !(pAMDGPUEnt->assigned_crtcs & (1 << i)))) 2176 crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i); 2177 2178 /* All ZaphodHeads outputs provided with matching crtcs? */ 2179 if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0)) 2180 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 2181 "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n", 2182 crtcs_needed); 2183 2184 /* workout clones */ 2185 drmmode_clones_init(pScrn, drmmode, mode_res); 2186 2187#ifdef AMDGPU_PIXMAP_SHARING 2188 bus_id_string = DRICreatePCIBusID(info->PciInfo); 2189 XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string); 2190 free(bus_id_string); 2191 xf86ProviderSetup(pScrn, NULL, provider_name); 2192 free(provider_name); 2193#endif 2194 2195 xf86InitialConfiguration(pScrn, TRUE); 2196 2197 drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; 2198 drmmode->event_context.vblank_handler = amdgpu_drm_queue_handler; 2199 drmmode->event_context.page_flip_handler = amdgpu_drm_queue_handler; 2200 2201 drmModeFreeResources(mode_res); 2202 return TRUE; 2203} 2204 2205void drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 2206{ 2207 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2208 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2209 2210 info->drmmode_inited = TRUE; 2211 if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) { 2212#if HAVE_NOTIFY_FD 2213 SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode); 2214#else 2215 AddGeneralSocket(pAMDGPUEnt->fd); 2216 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 2217 drm_wakeup_handler, drmmode); 2218#endif 2219 pAMDGPUEnt->fd_wakeup_registered = serverGeneration; 2220 pAMDGPUEnt->fd_wakeup_ref = 1; 2221 } else 2222 pAMDGPUEnt->fd_wakeup_ref++; 2223} 2224 2225void drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 2226{ 2227 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2228 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2229 AMDGPUInfoPtr info = AMDGPUPTR(pScrn); 2230 int c; 2231 2232 if (!info->drmmode_inited) 2233 return; 2234 2235 if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration && 2236 !--pAMDGPUEnt->fd_wakeup_ref) { 2237#if HAVE_NOTIFY_FD 2238 RemoveNotifyFd(pAMDGPUEnt->fd); 2239#else 2240 RemoveGeneralSocket(pAMDGPUEnt->fd); 2241 RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA, 2242 drm_wakeup_handler, drmmode); 2243#endif 2244 } 2245 2246 for (c = 0; c < config->num_crtc; c++) { 2247 xf86CrtcPtr crtc = config->crtc[c]; 2248 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2249 2250 drmmode_crtc_scanout_destroy(&info->drmmode, &drmmode_crtc->scanout[0]); 2251 drmmode_crtc_scanout_destroy(&info->drmmode, &drmmode_crtc->scanout[1]); 2252 } 2253} 2254 2255void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, 2256 struct amdgpu_buffer *bo) 2257{ 2258 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2259 xf86CrtcPtr crtc = xf86_config->crtc[id]; 2260 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2261 2262 drmmode_crtc->cursor_buffer = bo; 2263} 2264 2265void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y) 2266{ 2267 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2268 xf86OutputPtr output = config->output[config->compat_output]; 2269 xf86CrtcPtr crtc = output->crtc; 2270 2271 if (crtc && crtc->enabled) { 2272 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); 2273 } 2274} 2275 2276Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, 2277 Bool set_hw) 2278{ 2279 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 2280 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); 2281 int c; 2282 2283 for (c = 0; c < config->num_crtc; c++) { 2284 xf86CrtcPtr crtc = config->crtc[c]; 2285 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 2286 xf86OutputPtr output = NULL; 2287 int o; 2288 2289 /* Skip disabled CRTCs */ 2290 if (!crtc->enabled) { 2291 if (set_hw) { 2292 drmmode_do_crtc_dpms(crtc, DPMSModeOff); 2293 drmModeSetCrtc(pAMDGPUEnt->fd, 2294 drmmode_crtc->mode_crtc->crtc_id, 2295 0, 0, 0, NULL, 0, NULL); 2296 } 2297 continue; 2298 } 2299 2300 if (config->output[config->compat_output]->crtc == crtc) 2301 output = config->output[config->compat_output]; 2302 else { 2303 for (o = 0; o < config->num_output; o++) 2304 if (config->output[o]->crtc == crtc) { 2305 output = config->output[o]; 2306 break; 2307 } 2308 } 2309 /* paranoia */ 2310 if (!output) 2311 continue; 2312 2313 /* Mark that we'll need to re-set the mode for sure */ 2314 memset(&crtc->mode, 0, sizeof(crtc->mode)); 2315 if (!crtc->desiredMode.CrtcHDisplay) { 2316 DisplayModePtr mode = xf86OutputFindClosestMode(output, 2317 pScrn-> 2318 currentMode); 2319 2320 if (!mode) 2321 return FALSE; 2322 crtc->desiredMode = *mode; 2323 crtc->desiredRotation = RR_Rotate_0; 2324 crtc->desiredX = 0; 2325 crtc->desiredY = 0; 2326 } 2327 2328 if (set_hw) { 2329 if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, 2330 crtc->desiredRotation, 2331 crtc->desiredX, 2332 crtc->desiredY)) 2333 return FALSE; 2334 } else { 2335 crtc->mode = crtc->desiredMode; 2336 crtc->rotation = crtc->desiredRotation; 2337 crtc->x = crtc->desiredX; 2338 crtc->y = crtc->desiredY; 2339 if (!drmmode_handle_transform(crtc)) 2340 return FALSE; 2341 } 2342 } 2343 return TRUE; 2344} 2345 2346Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 2347{ 2348 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 2349 2350 if (xf86_config->num_crtc) { 2351 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG, 2352 "Initializing kms color map\n"); 2353 if (!miCreateDefColormap(pScreen)) 2354 return FALSE; 2355 /* all amdgpus support 10 bit CLUTs */ 2356 if (!xf86HandleColormaps(pScreen, 256, 10, 2357 NULL, NULL, 2358 CMAP_PALETTED_TRUECOLOR 2359#if 0 /* This option messes up text mode! (eich@suse.de) */ 2360 | CMAP_LOAD_EVEN_IF_OFFSCREEN 2361#endif 2362 | CMAP_RELOAD_ON_MODE_SWITCH)) 2363 return FALSE; 2364 } 2365 return TRUE; 2366} 2367 2368static Bool 2369drmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi, 2370 int *num_hdmi) 2371{ 2372 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2373 int i; 2374 2375 for (i = 0; i < config->num_output; i++) { 2376 xf86OutputPtr output = config->output[i]; 2377 drmmode_output_private_ptr drmmode_output = output->driver_private; 2378 2379 if (drmmode_output->output_id == output_id) { 2380 switch(drmmode_output->mode_output->connector_type) { 2381 case DRM_MODE_CONNECTOR_DVII: 2382 case DRM_MODE_CONNECTOR_DVID: 2383 case DRM_MODE_CONNECTOR_DVIA: 2384 (*num_dvi)++; 2385 break; 2386 case DRM_MODE_CONNECTOR_HDMIA: 2387 case DRM_MODE_CONNECTOR_HDMIB: 2388 (*num_hdmi)++; 2389 break; 2390 } 2391 2392 return TRUE; 2393 } 2394 } 2395 2396 return FALSE; 2397} 2398 2399void 2400amdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode) 2401{ 2402 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2403 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 2404 drmModeResPtr mode_res; 2405 int i, j; 2406 Bool found; 2407 Bool changed = FALSE; 2408 int num_dvi = 0, num_hdmi = 0; 2409 2410 mode_res = drmModeGetResources(pAMDGPUEnt->fd); 2411 if (!mode_res) 2412 goto out; 2413 2414restart_destroy: 2415 for (i = 0; i < config->num_output; i++) { 2416 xf86OutputPtr output = config->output[i]; 2417 drmmode_output_private_ptr drmmode_output = output->driver_private; 2418 found = FALSE; 2419 for (j = 0; j < mode_res->count_connectors; j++) { 2420 if (mode_res->connectors[j] == drmmode_output->output_id) { 2421 found = TRUE; 2422 break; 2423 } 2424 } 2425 if (found) 2426 continue; 2427 2428 drmModeFreeConnector(drmmode_output->mode_output); 2429 drmmode_output->mode_output = NULL; 2430 drmmode_output->output_id = -1; 2431 2432 changed = TRUE; 2433 if (drmmode->delete_dp_12_displays) { 2434 RROutputDestroy(output->randr_output); 2435 xf86OutputDestroy(output); 2436 goto restart_destroy; 2437 } 2438 } 2439 2440 /* find new output ids we don't have outputs for */ 2441 for (i = 0; i < mode_res->count_connectors; i++) { 2442 if (drmmode_find_output(pAMDGPUEnt->primary_scrn, 2443 mode_res->connectors[i], 2444 &num_dvi, &num_hdmi) || 2445 (pAMDGPUEnt->secondary_scrn && 2446 drmmode_find_output(pAMDGPUEnt->secondary_scrn, 2447 mode_res->connectors[i], 2448 &num_dvi, &num_hdmi))) 2449 continue; 2450 2451 if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi, 2452 &num_hdmi, 1) != 0) 2453 changed = TRUE; 2454 } 2455 2456 if (changed && dixPrivateKeyRegistered(rrPrivKey)) { 2457#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0) 2458 RRSetChanged(xf86ScrnToScreen(scrn)); 2459#else 2460 rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen); 2461 rrScrPriv->changed = TRUE; 2462#endif 2463 RRTellChanged(xf86ScrnToScreen(scrn)); 2464 } 2465 2466 drmModeFreeResources(mode_res); 2467out: 2468 RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 2469} 2470 2471#ifdef HAVE_LIBUDEV 2472static void drmmode_handle_uevents(int fd, void *closure) 2473{ 2474 drmmode_ptr drmmode = closure; 2475 ScrnInfoPtr scrn = drmmode->scrn; 2476 struct udev_device *dev; 2477 Bool received = FALSE; 2478 2479 while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) { 2480 udev_device_unref(dev); 2481 received = TRUE; 2482 } 2483 2484 if (received) 2485 amdgpu_mode_hotplug(scrn, drmmode); 2486} 2487#endif 2488 2489void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 2490{ 2491#ifdef HAVE_LIBUDEV 2492 struct udev *u; 2493 struct udev_monitor *mon; 2494 2495 u = udev_new(); 2496 if (!u) 2497 return; 2498 mon = udev_monitor_new_from_netlink(u, "udev"); 2499 if (!mon) { 2500 udev_unref(u); 2501 return; 2502 } 2503 2504 if (udev_monitor_filter_add_match_subsystem_devtype(mon, 2505 "drm", 2506 "drm_minor") < 0 || 2507 udev_monitor_enable_receiving(mon) < 0) { 2508 udev_monitor_unref(mon); 2509 udev_unref(u); 2510 return; 2511 } 2512 2513 drmmode->uevent_handler = 2514 xf86AddGeneralHandler(udev_monitor_get_fd(mon), 2515 drmmode_handle_uevents, drmmode); 2516 2517 drmmode->uevent_monitor = mon; 2518#endif 2519} 2520 2521void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 2522{ 2523#ifdef HAVE_LIBUDEV 2524 if (drmmode->uevent_handler) { 2525 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 2526 xf86RemoveGeneralHandler(drmmode->uevent_handler); 2527 2528 udev_monitor_unref(drmmode->uevent_monitor); 2529 udev_unref(u); 2530 } 2531#endif 2532} 2533 2534Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, 2535 PixmapPtr new_front, uint64_t id, void *data, 2536 int ref_crtc_hw_id, amdgpu_drm_handler_proc handler, 2537 amdgpu_drm_abort_proc abort, 2538 enum drmmode_flip_sync flip_sync) 2539{ 2540 AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); 2541 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2542 xf86CrtcPtr crtc = NULL; 2543 drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 2544 drmmode_ptr drmmode = drmmode_crtc->drmmode; 2545 int i; 2546 uint32_t flip_flags = DRM_MODE_PAGE_FLIP_EVENT; 2547 drmmode_flipdata_ptr flipdata; 2548 uintptr_t drm_queue_seq = 0; 2549 uint32_t new_front_handle; 2550 2551 if (!amdgpu_pixmap_get_handle(new_front, &new_front_handle)) { 2552 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2553 "flip queue: data alloc failed.\n"); 2554 return FALSE; 2555 } 2556 2557 flipdata = calloc(1, sizeof(drmmode_flipdata_rec)); 2558 if (!flipdata) { 2559 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2560 "flip queue: data alloc failed.\n"); 2561 goto error; 2562 } 2563 2564 /* 2565 * Create a new handle for the back buffer 2566 */ 2567 flipdata->old_fb_id = drmmode->fb_id; 2568 if (drmModeAddFB(pAMDGPUEnt->fd, new_front->drawable.width, 2569 new_front->drawable.height, scrn->depth, 2570 scrn->bitsPerPixel, new_front->devKind, 2571 new_front_handle, &drmmode->fb_id)) 2572 goto error; 2573 2574 /* 2575 * Queue flips on all enabled CRTCs 2576 * Note that if/when we get per-CRTC buffers, we'll have to update this. 2577 * Right now it assumes a single shared fb across all CRTCs, with the 2578 * kernel fixing up the offset of each CRTC as necessary. 2579 * 2580 * Also, flips queued on disabled or incorrectly configured displays 2581 * may never complete; this is a configuration error. 2582 */ 2583 2584 flipdata->event_data = data; 2585 flipdata->handler = handler; 2586 flipdata->abort = abort; 2587 2588 if (flip_sync == FLIP_ASYNC) 2589 flip_flags |= DRM_MODE_PAGE_FLIP_ASYNC; 2590 2591 for (i = 0; i < config->num_crtc; i++) { 2592 crtc = config->crtc[i]; 2593 2594 if (!crtc->enabled) 2595 continue; 2596 2597 flipdata->flip_count++; 2598 drmmode_crtc = crtc->driver_private; 2599 2600 /* Only the reference crtc will finally deliver its page flip 2601 * completion event. All other crtc's events will be discarded. 2602 */ 2603 if (drmmode_crtc->hw_id == ref_crtc_hw_id) 2604 flipdata->fe_crtc = crtc; 2605 2606 drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id, 2607 flipdata, 2608 drmmode_flip_handler, 2609 drmmode_flip_abort); 2610 if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) { 2611 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2612 "Allocating DRM queue event entry failed.\n"); 2613 goto error; 2614 } 2615 2616 if (drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 2617 drmmode->fb_id, flip_flags, 2618 (void*)drm_queue_seq)) { 2619 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 2620 "flip queue failed: %s\n", strerror(errno)); 2621 goto error; 2622 } 2623 drmmode_crtc->flip_pending = TRUE; 2624 drm_queue_seq = 0; 2625 } 2626 2627 if (flipdata->flip_count > 0) 2628 return TRUE; 2629 2630error: 2631 if (flipdata && flipdata->flip_count <= 1) { 2632 drmModeRmFB(pAMDGPUEnt->fd, drmmode->fb_id); 2633 drmmode->fb_id = flipdata->old_fb_id; 2634 } 2635 2636 if (drm_queue_seq) 2637 amdgpu_drm_abort_entry(drm_queue_seq); 2638 else if (crtc) 2639 drmmode_flip_abort(crtc, flipdata); 2640 else if (flipdata && flipdata->flip_count <= 1) 2641 free(flipdata); 2642 2643 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 2644 strerror(errno)); 2645 return FALSE; 2646} 2647