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