1 /* 2 * Copyright 2007 Red Hat, Inc. 3 * Copyright 2008 Maarten Maathuis 4 * 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining a 7 * copy of this software and associated documentation files (the "Software"), 8 * to deal in the Software without restriction, including without limitation 9 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10 * and/or sell copies of the Software, and to permit persons to whom the 11 * Software is furnished to do so, subject to the following conditions: 12 * 13 * The above copyright notice and this permission notice (including the next 14 * paragraph) shall be included in all copies or substantial portions of the 15 * Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 * SOFTWARE. 24 * 25 * Authors: 26 * Dave Airlie <airlied (at) redhat.com> 27 * 28 */ 29 30 #ifdef HAVE_CONFIG_H 31 #include "config.h" 32 #endif 33 34 #include "xorg-config.h" 35 #include "xorgVersion.h" 36 #include "Xdefs.h" 37 #include "X11/Xdefs.h" 38 39 #include "nv_include.h" 40 #include "xf86drmMode.h" 41 #include "X11/Xatom.h" 42 43 #include <sys/ioctl.h> 44 #ifdef HAVE_LIBUDEV 45 #include "libudev.h" 46 #endif 47 48 static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height); 49 typedef struct { 50 int fd; 51 uint32_t fb_id; 52 int cpp; 53 drmEventContext event_context; 54 #ifdef HAVE_LIBUDEV 55 struct udev_monitor *uevent_monitor; 56 #endif 57 } drmmode_rec, *drmmode_ptr; 58 59 typedef struct { 60 drmmode_ptr drmmode; 61 drmModeCrtcPtr mode_crtc; 62 int hw_crtc_index; 63 struct nouveau_bo *cursor; 64 struct nouveau_bo *rotate_bo; 65 int rotate_pitch; 66 PixmapPtr rotate_pixmap; 67 uint32_t rotate_fb_id; 68 Bool cursor_visible; 69 int scanout_pixmap_x; 70 int dpms_mode; 71 } drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; 72 73 typedef struct { 74 drmModePropertyPtr mode_prop; 75 int index; /* Index within the kernel-side property arrays for 76 * this connector. */ 77 int num_atoms; /* if range prop, num_atoms == 1; if enum prop, 78 * num_atoms == num_enums + 1 */ 79 Atom *atoms; 80 } drmmode_prop_rec, *drmmode_prop_ptr; 81 82 typedef struct { 83 drmmode_ptr drmmode; 84 int output_id; 85 drmModeConnectorPtr mode_output; 86 drmModeEncoderPtr mode_encoder; 87 drmModePropertyBlobPtr edid_blob; 88 drmModePropertyBlobPtr tile_blob; 89 int num_props; 90 drmmode_prop_ptr props; 91 } drmmode_output_private_rec, *drmmode_output_private_ptr; 92 93 static void drmmode_output_dpms(xf86OutputPtr output, int mode); 94 95 static drmmode_ptr 96 drmmode_from_scrn(ScrnInfoPtr scrn) 97 { 98 if (scrn) { 99 xf86CrtcConfigPtr conf = XF86_CRTC_CONFIG_PTR(scrn); 100 drmmode_crtc_private_ptr crtc = conf->crtc[0]->driver_private; 101 102 return crtc->drmmode; 103 } 104 105 return NULL; 106 } 107 108 static inline struct nouveau_pixmap * 109 drmmode_pixmap(PixmapPtr ppix) 110 { 111 return nouveau_pixmap(ppix); 112 } 113 114 int 115 drmmode_crtc(xf86CrtcPtr crtc) 116 { 117 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 118 return drmmode_crtc->mode_crtc->crtc_id; 119 } 120 121 Bool 122 xf86_crtc_on(xf86CrtcPtr crtc) 123 { 124 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 125 126 return crtc->enabled && drmmode_crtc->dpms_mode == DPMSModeOn; 127 } 128 129 int 130 drmmode_head(xf86CrtcPtr crtc) 131 { 132 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 133 return drmmode_crtc->hw_crtc_index; 134 } 135 136 void 137 drmmode_swap(ScrnInfoPtr scrn, uint32_t next, uint32_t *prev) 138 { 139 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 140 *prev = drmmode->fb_id; 141 drmmode->fb_id = next; 142 } 143 144 struct drmmode_event { 145 struct xorg_list head; 146 drmmode_ptr drmmode; 147 uint64_t name; 148 void (*func)(void *, uint64_t, uint64_t, uint32_t); 149 }; 150 151 static struct xorg_list 152 drmmode_events = { 153 .next = &drmmode_events, 154 .prev = &drmmode_events, 155 }; 156 157 static bool warned = false; 158 159 static void 160 drmmode_event_handler(int fd, unsigned int frame, unsigned int tv_sec, 161 unsigned int tv_usec, void *event_data) 162 { 163 const uint64_t ust = (uint64_t)tv_sec * 1000000 + tv_usec; 164 struct drmmode_event *e = event_data; 165 166 int counter = 0; 167 168 xorg_list_for_each_entry(e, &drmmode_events, head) { 169 counter++; 170 if (e == event_data) { 171 xorg_list_del(&e->head); 172 e->func((void *)(e + 1), e->name, ust, frame); 173 free(e); 174 break; 175 } 176 } 177 178 if (counter > 100 && !warned) { 179 xf86DrvMsg(0, X_WARNING, 180 "Event handler iterated %d times\n", counter); 181 warned = true; 182 } 183 } 184 185 void 186 drmmode_event_abort(ScrnInfoPtr scrn, uint64_t name, bool pending) 187 { 188 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 189 struct drmmode_event *e, *t; 190 191 xorg_list_for_each_entry_safe(e, t, &drmmode_events, head) { 192 if (e->drmmode == drmmode && e->name == name) { 193 xorg_list_del(&e->head); 194 if (!pending) 195 free(e); 196 break; 197 } 198 } 199 } 200 201 void * 202 drmmode_event_queue(ScrnInfoPtr scrn, uint64_t name, unsigned size, 203 void (*func)(void *, uint64_t, uint64_t, uint32_t), 204 void **event_data) 205 { 206 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 207 struct drmmode_event *e; 208 209 e = *event_data = calloc(1, sizeof(*e) + size); 210 if (e) { 211 e->drmmode = drmmode; 212 e->name = name; 213 e->func = func; 214 xorg_list_append(&e->head, &drmmode_events); 215 return (void *)(e + 1); 216 } 217 218 return NULL; 219 } 220 221 int 222 drmmode_event_flush(ScrnInfoPtr scrn) 223 { 224 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 225 return drmHandleEvent(drmmode->fd, &drmmode->event_context); 226 } 227 228 void 229 drmmode_event_fini(ScrnInfoPtr scrn) 230 { 231 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 232 struct drmmode_event *e, *t; 233 234 xorg_list_for_each_entry_safe(e, t, &drmmode_events, head) { 235 if (e->drmmode == drmmode) { 236 xorg_list_del(&e->head); 237 free(e); 238 } 239 } 240 } 241 242 void 243 drmmode_event_init(ScrnInfoPtr scrn) 244 { 245 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 246 drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; 247 drmmode->event_context.vblank_handler = drmmode_event_handler; 248 drmmode->event_context.page_flip_handler = drmmode_event_handler; 249 } 250 251 static PixmapPtr 252 drmmode_pixmap_wrap(ScreenPtr pScreen, int width, int height, int depth, 253 int bpp, int pitch, struct nouveau_bo *bo, void *data) 254 { 255 NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen)); 256 PixmapPtr ppix; 257 258 if (pNv->AccelMethod > NONE) 259 data = NULL; 260 261 ppix = pScreen->CreatePixmap(pScreen, 0, 0, depth, 0); 262 if (!ppix) 263 return NULL; 264 265 pScreen->ModifyPixmapHeader(ppix, width, height, depth, bpp, 266 pitch, data); 267 if (pNv->AccelMethod > NONE) 268 nouveau_bo_ref(bo, &drmmode_pixmap(ppix)->bo); 269 270 return ppix; 271 } 272 273 static void 274 drmmode_ConvertFromKMode(ScrnInfoPtr scrn, drmModeModeInfo *kmode, 275 DisplayModePtr mode) 276 { 277 memset(mode, 0, sizeof(DisplayModeRec)); 278 mode->status = MODE_OK; 279 280 mode->Clock = kmode->clock; 281 282 mode->HDisplay = kmode->hdisplay; 283 mode->HSyncStart = kmode->hsync_start; 284 mode->HSyncEnd = kmode->hsync_end; 285 mode->HTotal = kmode->htotal; 286 mode->HSkew = kmode->hskew; 287 288 mode->VDisplay = kmode->vdisplay; 289 mode->VSyncStart = kmode->vsync_start; 290 mode->VSyncEnd = kmode->vsync_end; 291 mode->VTotal = kmode->vtotal; 292 mode->VScan = kmode->vscan; 293 294 mode->Flags = kmode->flags; //& FLAG_BITS; 295 mode->name = strdup(kmode->name); 296 297 if (kmode->type & DRM_MODE_TYPE_DRIVER) 298 mode->type = M_T_DRIVER; 299 if (kmode->type & DRM_MODE_TYPE_PREFERRED) 300 mode->type |= M_T_PREFERRED; 301 xf86SetModeCrtc (mode, scrn->adjustFlags); 302 } 303 304 static void 305 drmmode_ConvertToKMode(ScrnInfoPtr scrn, drmModeModeInfo *kmode, 306 DisplayModePtr mode) 307 { 308 memset(kmode, 0, sizeof(*kmode)); 309 310 kmode->clock = mode->Clock; 311 kmode->hdisplay = mode->HDisplay; 312 kmode->hsync_start = mode->HSyncStart; 313 kmode->hsync_end = mode->HSyncEnd; 314 kmode->htotal = mode->HTotal; 315 kmode->hskew = mode->HSkew; 316 317 kmode->vdisplay = mode->VDisplay; 318 kmode->vsync_start = mode->VSyncStart; 319 kmode->vsync_end = mode->VSyncEnd; 320 kmode->vtotal = mode->VTotal; 321 kmode->vscan = mode->VScan; 322 323 kmode->flags = mode->Flags; //& FLAG_BITS; 324 if (mode->name) 325 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 326 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 327 328 } 329 330 static void 331 drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 332 { 333 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 334 drmmode_crtc->dpms_mode = mode; 335 } 336 337 void 338 drmmode_fbcon_copy(ScreenPtr pScreen) 339 { 340 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 341 NVPtr pNv = NVPTR(pScrn); 342 if (nouveau_bo_map(pNv->scanout, NOUVEAU_BO_WR, pNv->client)) 343 return; 344 memset(pNv->scanout->map, 0x00, pNv->scanout->size); 345 } 346 347 static Bool 348 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 349 Rotation rotation, int x, int y) 350 { 351 ScrnInfoPtr pScrn = crtc->scrn; 352 NVPtr pNv = NVPTR(pScrn); 353 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 354 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 355 drmmode_ptr drmmode = drmmode_crtc->drmmode; 356 uint32_t *output_ids; 357 int output_count = 0; 358 int ret = TRUE; 359 int i; 360 int fb_id; 361 drmModeModeInfo kmode; 362 363 if (drmmode->fb_id == 0) { 364 unsigned int pitch = 365 pScrn->displayWidth * (pScrn->bitsPerPixel / 8); 366 367 ret = drmModeAddFB(drmmode->fd, 368 pScrn->virtualX, pScrn->virtualY, 369 pScrn->depth, pScrn->bitsPerPixel, 370 pitch, pNv->scanout->handle, 371 &drmmode->fb_id); 372 if (ret < 0) { 373 ErrorF("failed to add fb\n"); 374 return FALSE; 375 } 376 } 377 378 if (!xf86CrtcRotate(crtc)) 379 return FALSE; 380 381 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 382 if (!output_ids) 383 return FALSE; 384 385 for (i = 0; i < xf86_config->num_output; i++) { 386 xf86OutputPtr output = xf86_config->output[i]; 387 drmmode_output_private_ptr drmmode_output; 388 389 if (output->crtc != crtc) 390 continue; 391 392 drmmode_output = output->driver_private; 393 if (drmmode_output->output_id == -1) 394 continue; 395 output_ids[output_count] = 396 drmmode_output->mode_output->connector_id; 397 output_count++; 398 } 399 400 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); 401 402 fb_id = drmmode->fb_id; 403 #ifdef NOUVEAU_PIXMAP_SHARING 404 if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) { 405 x = drmmode_crtc->scanout_pixmap_x; 406 y = 0; 407 } else 408 #endif 409 if (drmmode_crtc->rotate_fb_id) { 410 fb_id = drmmode_crtc->rotate_fb_id; 411 x = 0; 412 y = 0; 413 } 414 415 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 416 fb_id, x, y, output_ids, output_count, &kmode); 417 free(output_ids); 418 419 if (ret) { 420 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 421 "failed to set mode: %s\n", strerror(-ret)); 422 return FALSE; 423 } 424 425 /* Work around some xserver stupidity */ 426 for (i = 0; i < xf86_config->num_output; i++) { 427 xf86OutputPtr output = xf86_config->output[i]; 428 429 if (output->crtc != crtc) 430 continue; 431 432 drmmode_output_dpms(output, DPMSModeOn); 433 } 434 435 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 436 crtc->gamma_blue, crtc->gamma_size); 437 438 #ifdef HAVE_XF86_CURSOR_RESET_CURSOR 439 xf86CursorResetCursor(crtc->scrn->pScreen); 440 #else 441 xf86_reload_cursors(crtc->scrn->pScreen); 442 #endif 443 444 return TRUE; 445 } 446 447 static void 448 drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 449 { 450 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 451 drmmode_ptr drmmode = drmmode_crtc->drmmode; 452 453 drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 454 } 455 456 static void 457 convert_cursor(CARD32 *dst, CARD32 *src, int dw, int sw) 458 { 459 int i, j; 460 461 for (j = 0; j < sw; j++) { 462 for (i = 0; i < sw; i++) { 463 dst[j * dw + i] = src[j * sw + i]; 464 } 465 } 466 } 467 468 static void 469 drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 470 { 471 NVPtr pNv = NVPTR(crtc->scrn); 472 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 473 struct nouveau_bo *cursor = drmmode_crtc->cursor; 474 drmmode_ptr drmmode = drmmode_crtc->drmmode; 475 476 nouveau_bo_map(cursor, NOUVEAU_BO_WR, pNv->client); 477 convert_cursor(cursor->map, image, 64, nv_cursor_width(pNv)); 478 479 if (drmmode_crtc->cursor_visible) { 480 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 481 cursor->handle, 64, 64); 482 } 483 } 484 485 static void 486 drmmode_hide_cursor (xf86CrtcPtr crtc) 487 { 488 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 489 drmmode_ptr drmmode = drmmode_crtc->drmmode; 490 491 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 492 0, 64, 64); 493 drmmode_crtc->cursor_visible = FALSE; 494 } 495 496 static void 497 drmmode_show_cursor (xf86CrtcPtr crtc) 498 { 499 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 500 drmmode_ptr drmmode = drmmode_crtc->drmmode; 501 502 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 503 drmmode_crtc->cursor->handle, 64, 64); 504 drmmode_crtc->cursor_visible = TRUE; 505 } 506 507 static void * 508 drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 509 { 510 ScrnInfoPtr scrn = crtc->scrn; 511 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 512 drmmode_ptr drmmode = drmmode_crtc->drmmode; 513 void *virtual; 514 int ret; 515 516 ret = nouveau_allocate_surface(scrn, width, height, 517 scrn->bitsPerPixel, 518 NOUVEAU_CREATE_PIXMAP_SCANOUT, 519 &drmmode_crtc->rotate_pitch, 520 &drmmode_crtc->rotate_bo); 521 if (!ret) { 522 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 523 "Couldn't allocate shadow memory for rotated CRTC\n"); 524 return NULL; 525 } 526 527 ret = nouveau_bo_map(drmmode_crtc->rotate_bo, NOUVEAU_BO_RDWR, 528 NVPTR(scrn)->client); 529 if (ret) { 530 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 531 "Couldn't get virtual address of shadow scanout\n"); 532 nouveau_bo_ref(NULL, &drmmode_crtc->rotate_bo); 533 return NULL; 534 } 535 virtual = drmmode_crtc->rotate_bo->map; 536 537 ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth, 538 crtc->scrn->bitsPerPixel, drmmode_crtc->rotate_pitch, 539 drmmode_crtc->rotate_bo->handle, 540 &drmmode_crtc->rotate_fb_id); 541 if (ret) { 542 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 543 "Error adding FB for shadow scanout: %s\n", 544 strerror(-ret)); 545 nouveau_bo_ref(NULL, &drmmode_crtc->rotate_bo); 546 return NULL; 547 } 548 549 return virtual; 550 } 551 552 static PixmapPtr 553 drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 554 { 555 ScrnInfoPtr pScrn = crtc->scrn; 556 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 557 PixmapPtr rotate_pixmap; 558 559 if (!data) 560 data = drmmode_crtc_shadow_allocate (crtc, width, height); 561 562 rotate_pixmap = drmmode_pixmap_wrap(pScrn->pScreen, width, height, 563 pScrn->depth, pScrn->bitsPerPixel, 564 drmmode_crtc->rotate_pitch, 565 drmmode_crtc->rotate_bo, data); 566 567 drmmode_crtc->rotate_pixmap = rotate_pixmap; 568 return drmmode_crtc->rotate_pixmap; 569 } 570 571 static void 572 drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 573 { 574 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 575 drmmode_ptr drmmode = drmmode_crtc->drmmode; 576 577 if (rotate_pixmap) 578 FreeScratchPixmapHeader(rotate_pixmap); 579 580 if (data) { 581 drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id); 582 drmmode_crtc->rotate_fb_id = 0; 583 nouveau_bo_ref(NULL, &drmmode_crtc->rotate_bo); 584 drmmode_crtc->rotate_pixmap = NULL; 585 } 586 } 587 588 static void 589 drmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, 590 int size) 591 { 592 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 593 drmmode_ptr drmmode = drmmode_crtc->drmmode; 594 int ret; 595 596 ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 597 size, red, green, blue); 598 if (ret != 0) { 599 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 600 "failed to set gamma with %d entries: %s\n", 601 size, strerror(-ret)); 602 } 603 } 604 605 #ifdef NOUVEAU_PIXMAP_SHARING 606 static Bool 607 drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 608 { 609 ScreenPtr screen = xf86ScrnToScreen(crtc->scrn); 610 PixmapPtr screenpix = screen->GetScreenPixmap(screen); 611 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 612 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 613 drmmode_ptr drmmode = drmmode_crtc->drmmode; 614 int c, total_width = 0, max_height = 0, this_x = 0; 615 if (!ppix) { 616 if (crtc->randr_crtc->scanout_pixmap) { 617 #ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 618 PixmapStopDirtyTracking(&crtc->randr_crtc->scanout_pixmap->drawable, screenpix); 619 #else 620 PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix); 621 #endif 622 if (drmmode && drmmode->fb_id) { 623 drmModeRmFB(drmmode->fd, drmmode->fb_id); 624 drmmode->fb_id = 0; 625 } 626 } 627 drmmode_crtc->scanout_pixmap_x = 0; 628 return TRUE; 629 } 630 631 /* iterate over all the attached crtcs - 632 work out bounding box */ 633 for (c = 0; c < xf86_config->num_crtc; c++) { 634 xf86CrtcPtr iter = xf86_config->crtc[c]; 635 if (!iter->enabled && iter != crtc) 636 continue; 637 if (iter == crtc) { 638 this_x = total_width; 639 total_width += ppix->drawable.width; 640 if (max_height < ppix->drawable.height) 641 max_height = ppix->drawable.height; 642 } else { 643 total_width += iter->mode.HDisplay; 644 if (max_height < iter->mode.VDisplay) 645 max_height = iter->mode.VDisplay; 646 } 647 } 648 649 if (total_width != screenpix->drawable.width || 650 max_height != screenpix->drawable.height) { 651 Bool ret; 652 ret = drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height); 653 if (ret == FALSE) 654 return FALSE; 655 656 screenpix = screen->GetScreenPixmap(screen); 657 screen->width = screenpix->drawable.width = total_width; 658 screen->height = screenpix->drawable.height = max_height; 659 } 660 drmmode_crtc->scanout_pixmap_x = this_x; 661 662 #ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 663 PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0, RR_Rotate_0); 664 #else 665 PixmapStartDirtyTracking(ppix, screenpix, 0, 0, this_x, 0, RR_Rotate_0); 666 #endif 667 return TRUE; 668 } 669 #endif 670 671 static const xf86CrtcFuncsRec drmmode_crtc_funcs = { 672 .dpms = drmmode_crtc_dpms, 673 .set_mode_major = drmmode_set_mode_major, 674 .set_cursor_position = drmmode_set_cursor_position, 675 .show_cursor = drmmode_show_cursor, 676 .hide_cursor = drmmode_hide_cursor, 677 .load_cursor_argb = drmmode_load_cursor_argb, 678 .shadow_create = drmmode_crtc_shadow_create, 679 .shadow_allocate = drmmode_crtc_shadow_allocate, 680 .shadow_destroy = drmmode_crtc_shadow_destroy, 681 .gamma_set = drmmode_gamma_set, 682 683 #ifdef NOUVEAU_PIXMAP_SHARING 684 .set_scanout_pixmap = drmmode_set_scanout_pixmap, 685 #endif 686 }; 687 688 689 static unsigned int 690 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 691 { 692 NVPtr pNv = NVPTR(pScrn); 693 NVEntPtr pNVEnt = NVEntPriv(pScrn); 694 xf86CrtcPtr crtc; 695 drmmode_crtc_private_ptr drmmode_crtc; 696 int ret; 697 698 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); 699 if (crtc == NULL) 700 return 0; 701 702 drmmode_crtc = XNFcallocarray(sizeof(drmmode_crtc_private_rec), 1); 703 drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, 704 mode_res->crtcs[num]); 705 drmmode_crtc->drmmode = drmmode; 706 drmmode_crtc->hw_crtc_index = num; 707 708 ret = nouveau_bo_new(pNv->dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 709 64*64*4, NULL, &drmmode_crtc->cursor); 710 assert(ret == 0); 711 712 crtc->driver_private = drmmode_crtc; 713 714 /* Mark num'th crtc as in use on this device. */ 715 pNVEnt->assigned_crtcs |= (1 << num); 716 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 717 "Allocated crtc nr. %d to this screen.\n", num); 718 719 return 1; 720 } 721 722 static xf86OutputStatus 723 drmmode_output_detect(xf86OutputPtr output) 724 { 725 /* go to the hw and retrieve a new output struct */ 726 drmmode_output_private_ptr drmmode_output = output->driver_private; 727 drmmode_ptr drmmode = drmmode_output->drmmode; 728 xf86OutputStatus status; 729 730 if (drmmode_output->output_id == -1) 731 return XF86OutputStatusDisconnected; 732 733 drmModeFreeConnector(drmmode_output->mode_output); 734 735 drmmode_output->mode_output = 736 drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 737 738 if (!drmmode_output->mode_output) { 739 drmmode_output->output_id = -1; 740 return XF86OutputStatusDisconnected; 741 } 742 743 switch (drmmode_output->mode_output->connection) { 744 case DRM_MODE_CONNECTED: 745 status = XF86OutputStatusConnected; 746 break; 747 case DRM_MODE_DISCONNECTED: 748 status = XF86OutputStatusDisconnected; 749 break; 750 default: 751 case DRM_MODE_UNKNOWNCONNECTION: 752 status = XF86OutputStatusUnknown; 753 break; 754 } 755 return status; 756 } 757 758 static Bool 759 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode) 760 { 761 if (mode->type & M_T_DEFAULT) 762 /* Default modes are harmful here. */ 763 return MODE_BAD; 764 765 return MODE_OK; 766 } 767 768 static int 769 koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 770 int type, const char *name) 771 { 772 int idx = -1; 773 774 for (int i = 0; i < koutput->count_props; i++) { 775 drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 776 777 if (!prop) 778 continue; 779 780 if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 781 idx = i; 782 783 drmModeFreeProperty(prop); 784 785 if (idx > -1) 786 break; 787 } 788 789 return idx; 790 } 791 792 static drmModePropertyBlobPtr 793 koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 794 { 795 drmModePropertyBlobPtr blob = NULL; 796 int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 797 798 if (idx > -1) 799 blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 800 801 return blob; 802 } 803 804 static void 805 drmmode_output_attach_tile(xf86OutputPtr output) 806 { 807 drmmode_output_private_ptr drmmode_output = output->driver_private; 808 drmModeConnectorPtr koutput = drmmode_output->mode_output; 809 drmmode_ptr drmmode = drmmode_output->drmmode; 810 struct xf86CrtcTileInfo tile_info, *set = NULL; 811 812 if (!koutput) { 813 xf86OutputSetTile(output, NULL); 814 return; 815 } 816 817 drmModeFreePropertyBlob(drmmode_output->tile_blob); 818 819 /* look for a TILE property */ 820 drmmode_output->tile_blob = 821 koutput_get_prop_blob(drmmode->fd, koutput, "TILE"); 822 823 if (drmmode_output->tile_blob) { 824 if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE) 825 set = &tile_info; 826 } 827 xf86OutputSetTile(output, set); 828 } 829 830 831 static DisplayModePtr 832 drmmode_output_get_modes(xf86OutputPtr output) 833 { 834 drmmode_output_private_ptr drmmode_output = output->driver_private; 835 drmModeConnectorPtr koutput = drmmode_output->mode_output; 836 drmmode_ptr drmmode = drmmode_output->drmmode; 837 int i; 838 DisplayModePtr Modes = NULL, Mode; 839 xf86MonPtr ddc_mon = NULL; 840 841 if (!koutput) 842 return NULL; 843 844 /* look for an EDID property */ 845 drmmode_output->edid_blob = 846 koutput_get_prop_blob(drmmode->fd, koutput, "EDID"); 847 848 if (drmmode_output->edid_blob) { 849 ddc_mon = xf86InterpretEDID(output->scrn->scrnIndex, 850 drmmode_output->edid_blob->data); 851 if (ddc_mon && drmmode_output->edid_blob->length > 128) 852 ddc_mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 853 } 854 xf86OutputSetEDID(output, ddc_mon); 855 856 drmmode_output_attach_tile(output); 857 858 /* modes should already be available */ 859 for (i = 0; i < koutput->count_modes; i++) { 860 Mode = XNFalloc(sizeof(DisplayModeRec)); 861 862 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 863 Mode); 864 Modes = xf86ModesAdd(Modes, Mode); 865 866 } 867 return Modes; 868 } 869 870 static void 871 drmmode_output_destroy(xf86OutputPtr output) 872 { 873 drmmode_output_private_ptr drmmode_output = output->driver_private; 874 int i; 875 876 if (drmmode_output->edid_blob) 877 drmModeFreePropertyBlob(drmmode_output->edid_blob); 878 if (drmmode_output->tile_blob) 879 drmModeFreePropertyBlob(drmmode_output->tile_blob); 880 for (i = 0; i < drmmode_output->num_props; i++) { 881 drmModeFreeProperty(drmmode_output->props[i].mode_prop); 882 free(drmmode_output->props[i].atoms); 883 } 884 drmModeFreeConnector(drmmode_output->mode_output); 885 free(drmmode_output); 886 output->driver_private = NULL; 887 } 888 889 static void 890 drmmode_output_dpms(xf86OutputPtr output, int mode) 891 { 892 drmmode_output_private_ptr drmmode_output = output->driver_private; 893 drmModeConnectorPtr koutput = drmmode_output->mode_output; 894 drmModePropertyPtr props; 895 drmmode_ptr drmmode = drmmode_output->drmmode; 896 int mode_id = -1, i; 897 898 if (!koutput) 899 return; 900 901 for (i = 0; i < koutput->count_props; i++) { 902 props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 903 if (props && (props->flags & DRM_MODE_PROP_ENUM)) { 904 if (!strcmp(props->name, "DPMS")) { 905 mode_id = koutput->props[i]; 906 drmModeFreeProperty(props); 907 break; 908 } 909 drmModeFreeProperty(props); 910 } 911 } 912 913 if (mode_id < 0) 914 return; 915 916 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, 917 mode_id, mode); 918 } 919 920 static Bool 921 drmmode_property_ignore(drmModePropertyPtr prop) 922 { 923 if (!prop) 924 return TRUE; 925 /* ignore blob prop */ 926 if (prop->flags & DRM_MODE_PROP_BLOB) 927 return TRUE; 928 /* ignore standard property */ 929 if (!strcmp(prop->name, "EDID") || 930 !strcmp(prop->name, "DPMS")) 931 return TRUE; 932 933 return FALSE; 934 } 935 936 static void 937 drmmode_output_create_resources(xf86OutputPtr output) 938 { 939 drmmode_output_private_ptr drmmode_output = output->driver_private; 940 drmModeConnectorPtr mode_output = drmmode_output->mode_output; 941 drmmode_ptr drmmode = drmmode_output->drmmode; 942 drmModePropertyPtr drmmode_prop; 943 uint32_t value; 944 int i, j, err; 945 946 drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); 947 if (!drmmode_output->props) 948 return; 949 950 drmmode_output->num_props = 0; 951 for (i = 0, j = 0; i < mode_output->count_props; i++) { 952 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); 953 if (drmmode_property_ignore(drmmode_prop)) { 954 drmModeFreeProperty(drmmode_prop); 955 continue; 956 } 957 drmmode_output->props[j].mode_prop = drmmode_prop; 958 drmmode_output->props[j].index = i; 959 drmmode_output->num_props++; 960 j++; 961 } 962 963 for (i = 0; i < drmmode_output->num_props; i++) { 964 drmmode_prop_ptr p = &drmmode_output->props[i]; 965 drmmode_prop = p->mode_prop; 966 967 value = drmmode_output->mode_output->prop_values[p->index]; 968 969 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 970 INT32 range[2]; 971 972 p->num_atoms = 1; 973 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 974 if (!p->atoms) 975 continue; 976 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 977 range[0] = drmmode_prop->values[0]; 978 range[1] = drmmode_prop->values[1]; 979 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 980 FALSE, TRUE, 981 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 982 2, range); 983 if (err != 0) { 984 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 985 "RRConfigureOutputProperty error, %d\n", err); 986 } 987 err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 988 XA_INTEGER, 32, PropModeReplace, 1, 989 &value, FALSE, FALSE); 990 if (err != 0) { 991 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 992 "RRChangeOutputProperty error, %d\n", err); 993 } 994 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 995 p->num_atoms = drmmode_prop->count_enums + 1; 996 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 997 if (!p->atoms) 998 continue; 999 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1000 for (j = 1; j <= drmmode_prop->count_enums; j++) { 1001 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 1002 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 1003 } 1004 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1005 FALSE, FALSE, 1006 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1007 p->num_atoms - 1, (INT32 *)&p->atoms[1]); 1008 if (err != 0) { 1009 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1010 "RRConfigureOutputProperty error, %d\n", err); 1011 } 1012 for (j = 0; j < drmmode_prop->count_enums; j++) 1013 if (drmmode_prop->enums[j].value == value) 1014 break; 1015 /* there's always a matching value */ 1016 err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1017 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE); 1018 if (err != 0) { 1019 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1020 "RRChangeOutputProperty error, %d\n", err); 1021 } 1022 } 1023 } 1024 } 1025 1026 static Bool 1027 drmmode_output_set_property(xf86OutputPtr output, Atom property, 1028 RRPropertyValuePtr value) 1029 { 1030 drmmode_output_private_ptr drmmode_output = output->driver_private; 1031 drmmode_ptr drmmode = drmmode_output->drmmode; 1032 int i, ret; 1033 1034 for (i = 0; i < drmmode_output->num_props; i++) { 1035 drmmode_prop_ptr p = &drmmode_output->props[i]; 1036 1037 if (p->atoms[0] != property) 1038 continue; 1039 1040 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1041 uint32_t val; 1042 1043 if (value->type != XA_INTEGER || value->format != 32 || 1044 value->size != 1) 1045 return FALSE; 1046 val = *(uint32_t *)value->data; 1047 1048 ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 1049 p->mode_prop->prop_id, (uint64_t)val); 1050 1051 if (ret) 1052 return FALSE; 1053 1054 return TRUE; 1055 1056 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1057 Atom atom; 1058 const char *name; 1059 int j; 1060 1061 if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 1062 return FALSE; 1063 memcpy(&atom, value->data, 4); 1064 if (!(name = NameForAtom(atom))) 1065 return FALSE; 1066 1067 /* search for matching name string, then set its value down */ 1068 for (j = 0; j < p->mode_prop->count_enums; j++) { 1069 if (!strcmp(p->mode_prop->enums[j].name, name)) { 1070 ret = drmModeConnectorSetProperty(drmmode->fd, 1071 drmmode_output->output_id, 1072 p->mode_prop->prop_id, 1073 p->mode_prop->enums[j].value); 1074 1075 if (ret) 1076 return FALSE; 1077 1078 return TRUE; 1079 } 1080 } 1081 1082 return FALSE; 1083 } 1084 } 1085 1086 return TRUE; 1087 } 1088 1089 static Bool 1090 drmmode_output_get_property(xf86OutputPtr output, Atom property) 1091 { 1092 1093 drmmode_output_private_ptr drmmode_output = output->driver_private; 1094 drmmode_ptr drmmode = drmmode_output->drmmode; 1095 uint32_t value; 1096 int err, i; 1097 1098 if (output->scrn->vtSema) { 1099 drmModeFreeConnector(drmmode_output->mode_output); 1100 drmmode_output->mode_output = 1101 drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 1102 } 1103 1104 if (!drmmode_output->mode_output) 1105 return FALSE; 1106 1107 for (i = 0; i < drmmode_output->num_props; i++) { 1108 drmmode_prop_ptr p = &drmmode_output->props[i]; 1109 if (p->atoms[0] != property) 1110 continue; 1111 1112 value = drmmode_output->mode_output->prop_values[p->index]; 1113 1114 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1115 err = RRChangeOutputProperty(output->randr_output, 1116 property, XA_INTEGER, 32, 1117 PropModeReplace, 1, &value, 1118 FALSE, FALSE); 1119 1120 return !err; 1121 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1122 int j; 1123 1124 /* search for matching name string, then set its value down */ 1125 for (j = 0; j < p->mode_prop->count_enums; j++) { 1126 if (p->mode_prop->enums[j].value == value) 1127 break; 1128 } 1129 1130 err = RRChangeOutputProperty(output->randr_output, property, 1131 XA_ATOM, 32, PropModeReplace, 1, 1132 &p->atoms[j+1], FALSE, FALSE); 1133 1134 return !err; 1135 } 1136 } 1137 1138 return FALSE; 1139 } 1140 1141 static const xf86OutputFuncsRec drmmode_output_funcs = { 1142 .create_resources = drmmode_output_create_resources, 1143 .dpms = drmmode_output_dpms, 1144 .detect = drmmode_output_detect, 1145 .mode_valid = drmmode_output_mode_valid, 1146 .get_modes = drmmode_output_get_modes, 1147 .set_property = drmmode_output_set_property, 1148 .get_property = drmmode_output_get_property, 1149 .destroy = drmmode_output_destroy 1150 }; 1151 1152 static int subpixel_conv_table[7] = { 0, SubPixelUnknown, 1153 SubPixelHorizontalRGB, 1154 SubPixelHorizontalBGR, 1155 SubPixelVerticalRGB, 1156 SubPixelVerticalBGR, 1157 SubPixelNone }; 1158 1159 const char *output_names[] = { "None", 1160 "VGA", 1161 "DVI-I", 1162 "DVI-D", 1163 "DVI-A", 1164 "Composite", 1165 "SVIDEO", 1166 "LVDS", 1167 "CTV", 1168 "DIN", 1169 "DP", 1170 "HDMI", 1171 "HDMI", 1172 "TV", 1173 "eDP", 1174 }; 1175 #define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 1176 1177 static Bool 1178 drmmode_zaphod_match(ScrnInfoPtr pScrn, const char *s, char *output_name) 1179 { 1180 int i = 0; 1181 char s1[20]; 1182 1183 do { 1184 switch(*s) { 1185 case ',': 1186 s1[i] = '\0'; 1187 i = 0; 1188 if (strcmp(s1, output_name) == 0) 1189 return TRUE; 1190 break; 1191 case ' ': 1192 case '\t': 1193 case '\n': 1194 case '\r': 1195 break; 1196 default: 1197 s1[i] = *s; 1198 i++; 1199 break; 1200 } 1201 } while(*s++); 1202 1203 s1[i] = '\0'; 1204 if (strcmp(s1, output_name) == 0) 1205 return TRUE; 1206 1207 return FALSE; 1208 } 1209 1210 static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 1211 { 1212 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1213 int i; 1214 for (i = 0; i < xf86_config->num_output; i++) { 1215 xf86OutputPtr output = xf86_config->output[i]; 1216 drmmode_output_private_ptr drmmode_output; 1217 1218 drmmode_output = output->driver_private; 1219 if (drmmode_output->output_id == id) 1220 return output; 1221 } 1222 return NULL; 1223 } 1224 1225 static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 1226 { 1227 char *conn; 1228 char conn_id[5]; 1229 int id, len; 1230 char *blob_data; 1231 1232 if (!path_blob) 1233 return -1; 1234 1235 blob_data = path_blob->data; 1236 /* we only handle MST paths for now */ 1237 if (strncmp(blob_data, "mst:", 4)) 1238 return -1; 1239 1240 conn = strchr(blob_data + 4, '-'); 1241 if (!conn) 1242 return -1; 1243 len = conn - (blob_data + 4); 1244 if (len + 1 > 5) 1245 return -1; 1246 memcpy(conn_id, blob_data + 4, len); 1247 conn_id[len] = '\0'; 1248 id = strtoul(conn_id, NULL, 10); 1249 1250 *conn_base_id = id; 1251 1252 *path = conn + 1; 1253 return 0; 1254 } 1255 1256 static void 1257 drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 1258 drmModePropertyBlobPtr path_blob) 1259 { 1260 int ret; 1261 char *extra_path; 1262 int conn_id; 1263 xf86OutputPtr output; 1264 1265 ret = parse_path_blob(path_blob, &conn_id, &extra_path); 1266 if (ret == -1) 1267 goto fallback; 1268 1269 output = find_output(pScrn, conn_id); 1270 if (!output) 1271 goto fallback; 1272 1273 snprintf(name, 32, "%s-%s", output->name, extra_path); 1274 return; 1275 1276 fallback: 1277 if (koutput->connector_type >= ARRAY_SIZE(output_names)) 1278 snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id); 1279 else if (pScrn->is_gpu) 1280 snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id); 1281 else 1282 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id); 1283 } 1284 1285 static unsigned int 1286 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift) 1287 { 1288 NVPtr pNv = NVPTR(pScrn); 1289 xf86OutputPtr output; 1290 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1291 drmModeConnectorPtr koutput; 1292 drmModeEncoderPtr kencoder; 1293 drmmode_output_private_ptr drmmode_output; 1294 const char *s; 1295 char name[32]; 1296 drmModePropertyBlobPtr path_blob = NULL; 1297 int i; 1298 1299 koutput = drmModeGetConnector(drmmode->fd, 1300 mode_res->connectors[num]); 1301 if (!koutput) 1302 return 0; 1303 1304 path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH"); 1305 1306 drmmode_create_name(pScrn, koutput, name, path_blob); 1307 1308 if (path_blob) 1309 drmModeFreePropertyBlob(path_blob); 1310 1311 if (path_blob && dynamic) { 1312 /* see if we have an output with this name already 1313 and hook stuff up */ 1314 for (i = 0; i < xf86_config->num_output; i++) { 1315 output = xf86_config->output[i]; 1316 1317 if (strncmp(output->name, name, 32)) 1318 continue; 1319 1320 drmmode_output = output->driver_private; 1321 drmmode_output->output_id = mode_res->connectors[num]; 1322 drmmode_output->mode_output = koutput; 1323 return 1; 1324 } 1325 } 1326 1327 1328 kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]); 1329 if (!kencoder) { 1330 drmModeFreeConnector(koutput); 1331 return 0; 1332 } 1333 1334 if (xf86IsEntityShared(pScrn->entityList[0])) { 1335 s = xf86GetOptValString(pNv->Options, OPTION_ZAPHOD_HEADS); 1336 if (s) { 1337 if (!drmmode_zaphod_match(pScrn, s, name)) { 1338 drmModeFreeEncoder(kencoder); 1339 drmModeFreeConnector(koutput); 1340 return 0; 1341 } 1342 } else { 1343 if (pNv->Primary && (num != 0)) { 1344 drmModeFreeEncoder(kencoder); 1345 drmModeFreeConnector(koutput); 1346 return 0; 1347 } else 1348 if (pNv->Secondary && (num != 1)) { 1349 drmModeFreeEncoder(kencoder); 1350 drmModeFreeConnector(koutput); 1351 return 0; 1352 } 1353 } 1354 } 1355 1356 output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 1357 if (!output) { 1358 drmModeFreeEncoder(kencoder); 1359 drmModeFreeConnector(koutput); 1360 return 0; 1361 } 1362 1363 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 1364 if (!drmmode_output) { 1365 xf86OutputDestroy(output); 1366 drmModeFreeConnector(koutput); 1367 drmModeFreeEncoder(kencoder); 1368 return 0; 1369 } 1370 1371 drmmode_output->output_id = mode_res->connectors[num]; 1372 drmmode_output->mode_output = koutput; 1373 drmmode_output->mode_encoder = kencoder; 1374 drmmode_output->drmmode = drmmode; 1375 output->mm_width = koutput->mmWidth; 1376 output->mm_height = koutput->mmHeight; 1377 1378 output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 1379 output->driver_private = drmmode_output; 1380 1381 output->possible_crtcs = kencoder->possible_crtcs >> crtcshift; 1382 output->possible_clones = kencoder->possible_clones >> crtcshift; 1383 1384 output->interlaceAllowed = true; 1385 output->doubleScanAllowed = true; 1386 1387 if (dynamic) 1388 output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 1389 1390 return 1; 1391 } 1392 1393 static Bool 1394 drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 1395 { 1396 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1397 ScreenPtr screen = xf86ScrnToScreen(scrn); 1398 NVPtr pNv = NVPTR(scrn); 1399 drmmode_crtc_private_ptr drmmode_crtc = NULL; 1400 drmmode_ptr drmmode = NULL; 1401 uint32_t old_width, old_height, old_pitch, old_fb_id = 0; 1402 struct nouveau_bo *old_bo = NULL; 1403 int ret, i, pitch; 1404 PixmapPtr ppix; 1405 1406 if (xf86_config->num_crtc) { 1407 drmmode_crtc = xf86_config->crtc[0]->driver_private; 1408 drmmode = drmmode_crtc->drmmode; 1409 } 1410 ErrorF("resize called %d %d\n", width, height); 1411 1412 if (scrn->virtualX == width && scrn->virtualY == height) 1413 return TRUE; 1414 1415 old_width = scrn->virtualX; 1416 old_height = scrn->virtualY; 1417 old_pitch = scrn->displayWidth; 1418 if (drmmode) 1419 old_fb_id = drmmode->fb_id; 1420 nouveau_bo_ref(pNv->scanout, &old_bo); 1421 nouveau_bo_ref(NULL, &pNv->scanout); 1422 1423 ret = nouveau_allocate_surface(scrn, width, height, 1424 scrn->bitsPerPixel, 1425 NOUVEAU_CREATE_PIXMAP_SCANOUT, 1426 &pitch, &pNv->scanout); 1427 if (!ret) 1428 goto fail; 1429 1430 scrn->virtualX = width; 1431 scrn->virtualY = height; 1432 scrn->displayWidth = pitch / (scrn->bitsPerPixel >> 3); 1433 1434 nouveau_bo_map(pNv->scanout, NOUVEAU_BO_RDWR, pNv->client); 1435 1436 if (drmmode) { 1437 ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth, 1438 scrn->bitsPerPixel, pitch, pNv->scanout->handle, 1439 &drmmode->fb_id); 1440 if (ret) 1441 goto fail; 1442 } 1443 1444 if (pNv->ShadowPtr) { 1445 free(pNv->ShadowPtr); 1446 pNv->ShadowPitch = pitch; 1447 pNv->ShadowPtr = malloc(pNv->ShadowPitch * height); 1448 } 1449 1450 ppix = screen->GetScreenPixmap(screen); 1451 if (pNv->AccelMethod > NONE) 1452 nouveau_bo_ref(pNv->scanout, &drmmode_pixmap(ppix)->bo); 1453 screen->ModifyPixmapHeader(ppix, width, height, -1, -1, pitch, 1454 (pNv->AccelMethod > NONE || pNv->ShadowPtr) ? 1455 pNv->ShadowPtr : pNv->scanout->map); 1456 1457 if (pNv->AccelMethod == EXA) { 1458 pNv->EXADriverPtr->PrepareSolid(ppix, GXcopy, ~0, 0); 1459 pNv->EXADriverPtr->Solid(ppix, 0, 0, width, height); 1460 pNv->EXADriverPtr->DoneSolid(ppix); 1461 nouveau_bo_map(pNv->scanout, NOUVEAU_BO_RDWR, pNv->client); 1462 } else { 1463 memset(pNv->scanout->map, 0x00, pNv->scanout->size); 1464 } 1465 1466 for (i = 0; i < xf86_config->num_crtc; i++) { 1467 xf86CrtcPtr crtc = xf86_config->crtc[i]; 1468 1469 if (!crtc->enabled) 1470 continue; 1471 1472 drmmode_set_mode_major(crtc, &crtc->mode, 1473 crtc->rotation, crtc->x, crtc->y); 1474 } 1475 1476 if (old_fb_id) 1477 drmModeRmFB(drmmode->fd, old_fb_id); 1478 nouveau_bo_ref(NULL, &old_bo); 1479 1480 return TRUE; 1481 1482 fail: 1483 nouveau_bo_ref(old_bo, &pNv->scanout); 1484 scrn->virtualX = old_width; 1485 scrn->virtualY = old_height; 1486 scrn->displayWidth = old_pitch; 1487 if (drmmode) 1488 drmmode->fb_id = old_fb_id; 1489 1490 return FALSE; 1491 } 1492 1493 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 1494 drmmode_xf86crtc_resize 1495 }; 1496 1497 Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp) 1498 { 1499 drmmode_ptr drmmode; 1500 drmModeResPtr mode_res; 1501 NVEntPtr pNVEnt = NVEntPriv(pScrn); 1502 int i; 1503 unsigned int crtcs_needed = 0; 1504 int crtcshift; 1505 1506 drmmode = XNFcallocarray(sizeof(*drmmode), 1); 1507 drmmode->fd = fd; 1508 drmmode->fb_id = 0; 1509 1510 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 1511 1512 drmmode->cpp = cpp; 1513 mode_res = drmModeGetResources(drmmode->fd); 1514 if (!mode_res) 1515 return FALSE; 1516 1517 xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, 1518 mode_res->max_height); 1519 1520 if (!mode_res->count_connectors || 1521 !mode_res->count_crtcs) { 1522 free(drmmode); 1523 goto done; 1524 } 1525 1526 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing outputs ...\n"); 1527 crtcshift = ffs(pNVEnt->assigned_crtcs ^ 0xffffffff) - 1; 1528 for (i = 0; i < mode_res->count_connectors; i++) 1529 crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE, crtcshift); 1530 1531 xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1532 "%d crtcs needed for screen.\n", crtcs_needed); 1533 1534 for (i = 0; i < mode_res->count_crtcs; i++) { 1535 if (!xf86IsEntityShared(pScrn->entityList[0]) || 1536 (crtcs_needed && !(pNVEnt->assigned_crtcs & (1 << i)))) 1537 crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i); 1538 } 1539 1540 /* All ZaphodHeads outputs provided with matching crtcs? */ 1541 if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0)) 1542 xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1543 "%d ZaphodHeads crtcs unavailable. Trouble!\n", 1544 crtcs_needed); 1545 1546 done: 1547 drmModeFreeResources(mode_res); 1548 1549 #ifdef NOUVEAU_PIXMAP_SHARING 1550 xf86ProviderSetup(pScrn, NULL, "nouveau"); 1551 #endif 1552 1553 xf86InitialConfiguration(pScrn, TRUE); 1554 1555 return TRUE; 1556 } 1557 1558 void 1559 drmmode_adjust_frame(ScrnInfoPtr scrn, int x, int y) 1560 { 1561 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1562 xf86OutputPtr output = config->output[config->compat_output]; 1563 xf86CrtcPtr crtc = output->crtc; 1564 1565 if (!crtc || !crtc->enabled) 1566 return; 1567 1568 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); 1569 } 1570 1571 void 1572 drmmode_remove_fb(ScrnInfoPtr pScrn) 1573 { 1574 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1575 xf86CrtcPtr crtc = NULL; 1576 drmmode_crtc_private_ptr drmmode_crtc; 1577 drmmode_ptr drmmode; 1578 1579 if (config && config->num_crtc) 1580 crtc = config->crtc[0]; 1581 if (!crtc) 1582 return; 1583 1584 drmmode_crtc = crtc->driver_private; 1585 drmmode = drmmode_crtc->drmmode; 1586 1587 if (drmmode->fb_id) 1588 drmModeRmFB(drmmode->fd, drmmode->fb_id); 1589 drmmode->fb_id = 0; 1590 } 1591 1592 int 1593 drmmode_cursor_init(ScreenPtr pScreen) 1594 { 1595 NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen)); 1596 int size = nv_cursor_width(pNv); 1597 int flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | 1598 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 | 1599 (pNv->dev->chipset >= 0x11 ? HARDWARE_CURSOR_ARGB : 0) | 1600 HARDWARE_CURSOR_UPDATE_UNHIDDEN; 1601 1602 return xf86_cursors_init(pScreen, size, size, flags); 1603 } 1604 1605 #ifdef HAVE_LIBUDEV 1606 1607 #define DRM_MODE_LINK_STATUS_GOOD 0 1608 #define DRM_MODE_LINK_STATUS_BAD 1 1609 1610 static void 1611 drmmode_handle_uevents(ScrnInfoPtr scrn) 1612 { 1613 struct udev_device *dev; 1614 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1615 drmModeResPtr mode_res; 1616 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1617 int i, j; 1618 Bool found = FALSE; 1619 Bool changed = FALSE; 1620 1621 while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) { 1622 udev_device_unref(dev); 1623 found = TRUE; 1624 } 1625 if (!found) 1626 return; 1627 1628 /* Try to re-set the mode on all the connectors with a BAD link-state: 1629 * This may happen if a link degrades and a new modeset is necessary, using 1630 * different link-training parameters. If the kernel found that the current 1631 * mode is not achievable anymore, it should have pruned the mode before 1632 * sending the hotplug event. Try to re-set the currently-set mode to keep 1633 * the display alive, this will fail if the mode has been pruned. 1634 * In any case, we will send randr events for the Desktop Environment to 1635 * deal with it, if it wants to. 1636 */ 1637 for (i = 0; i < config->num_output; i++) { 1638 xf86OutputPtr output = config->output[i]; 1639 xf86CrtcPtr crtc = output->crtc; 1640 drmmode_output_private_ptr drmmode_output = output->driver_private; 1641 uint32_t con_id, idx; 1642 drmModeConnectorPtr koutput; 1643 1644 if (crtc == NULL || drmmode_output->mode_output == NULL) 1645 continue; 1646 1647 con_id = drmmode_output->mode_output->connector_id; 1648 /* Get an updated view of the properties for the current connector and 1649 * look for the link-status property 1650 */ 1651 koutput = drmModeGetConnectorCurrent(drmmode->fd, con_id); 1652 if (!koutput) 1653 continue; 1654 1655 idx = koutput_get_prop_idx(drmmode->fd, koutput, 1656 DRM_MODE_PROP_ENUM, "link-status"); 1657 1658 if ((idx > -1) && 1659 (koutput->prop_values[idx] == DRM_MODE_LINK_STATUS_BAD)) { 1660 /* the connector got a link failure, re-set the current mode */ 1661 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 1662 crtc->x, crtc->y); 1663 1664 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1665 "hotplug event: connector %u's link-state is BAD, " 1666 "tried resetting the current mode. You may be left" 1667 "with a black screen if this fails...\n", con_id); 1668 } 1669 1670 drmModeFreeConnector(koutput); 1671 } 1672 1673 mode_res = drmModeGetResources(drmmode->fd); 1674 if (!mode_res) 1675 goto out; 1676 1677 if (mode_res->count_crtcs != config->num_crtc) { 1678 ErrorF("number of CRTCs changed - failed to handle, %d vs %d\n", mode_res->count_crtcs, config->num_crtc); 1679 goto out_free_res; 1680 } 1681 1682 /* figure out if we have gotten rid of any connectors 1683 traverse old output list looking for outputs */ 1684 for (i = 0; i < config->num_output; i++) { 1685 xf86OutputPtr output = config->output[i]; 1686 drmmode_output_private_ptr drmmode_output; 1687 1688 drmmode_output = output->driver_private; 1689 found = FALSE; 1690 for (j = 0; j < mode_res->count_connectors; j++) { 1691 if (mode_res->connectors[j] == drmmode_output->output_id) { 1692 found = TRUE; 1693 break; 1694 } 1695 } 1696 if (found) 1697 continue; 1698 1699 drmModeFreeConnector(drmmode_output->mode_output); 1700 drmmode_output->mode_output = NULL; 1701 drmmode_output->output_id = -1; 1702 1703 changed = TRUE; 1704 } 1705 1706 /* find new output ids we don't have outputs for */ 1707 for (i = 0; i < mode_res->count_connectors; i++) { 1708 found = FALSE; 1709 1710 for (j = 0; j < config->num_output; j++) { 1711 xf86OutputPtr output = config->output[j]; 1712 drmmode_output_private_ptr drmmode_output; 1713 1714 drmmode_output = output->driver_private; 1715 if (mode_res->connectors[i] == drmmode_output->output_id) { 1716 found = TRUE; 1717 break; 1718 } 1719 } 1720 if (found) 1721 continue; 1722 1723 changed = TRUE; 1724 drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0); 1725 } 1726 1727 if (changed) { 1728 RRSetChanged(xf86ScrnToScreen(scrn)); 1729 RRTellChanged(xf86ScrnToScreen(scrn)); 1730 } 1731 1732 out_free_res: 1733 drmModeFreeResources(mode_res); 1734 out: 1735 RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 1736 } 1737 1738 #undef DRM_MODE_LINK_STATUS_BAD 1739 #undef DRM_MODE_LINK_STATUS_GOOD 1740 1741 #endif 1742 1743 #ifdef HAVE_LIBUDEV 1744 #if HAVE_NOTIFY_FD 1745 static void 1746 drmmode_udev_notify(int fd, int notify, void *data) 1747 { 1748 ScrnInfoPtr scrn = data; 1749 drmmode_handle_uevents(scrn); 1750 } 1751 #endif 1752 #endif 1753 1754 static bool has_randr(void) 1755 { 1756 return dixPrivateKeyRegistered(rrPrivKey); 1757 } 1758 1759 static void 1760 drmmode_uevent_init(ScrnInfoPtr scrn) 1761 { 1762 #ifdef HAVE_LIBUDEV 1763 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1764 struct udev *u; 1765 struct udev_monitor *mon; 1766 1767 /* RandR will be disabled if Xinerama is active, and so generating 1768 * RR hotplug events is then forbidden. 1769 */ 1770 if (!has_randr()) 1771 return; 1772 1773 u = udev_new(); 1774 if (!u) 1775 return; 1776 mon = udev_monitor_new_from_netlink(u, "udev"); 1777 if (!mon) { 1778 udev_unref(u); 1779 return; 1780 } 1781 1782 if (udev_monitor_filter_add_match_subsystem_devtype(mon, 1783 "drm", 1784 "drm_minor") < 0 || 1785 udev_monitor_enable_receiving(mon) < 0) { 1786 udev_monitor_unref(mon); 1787 udev_unref(u); 1788 return; 1789 } 1790 1791 #if HAVE_NOTIFY_FD 1792 SetNotifyFd(udev_monitor_get_fd(mon), drmmode_udev_notify, X_NOTIFY_READ, scrn); 1793 #else 1794 AddGeneralSocket(udev_monitor_get_fd(mon)); 1795 #endif 1796 drmmode->uevent_monitor = mon; 1797 #endif 1798 } 1799 1800 static void 1801 drmmode_uevent_fini(ScrnInfoPtr scrn) 1802 { 1803 #ifdef HAVE_LIBUDEV 1804 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1805 1806 if (drmmode->uevent_monitor) { 1807 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 1808 1809 #if HAVE_NOTIFY_FD 1810 RemoveNotifyFd(udev_monitor_get_fd(drmmode->uevent_monitor)); 1811 #else 1812 RemoveGeneralSocket(udev_monitor_get_fd(drmmode->uevent_monitor)); 1813 #endif 1814 udev_monitor_unref(drmmode->uevent_monitor); 1815 udev_unref(u); 1816 } 1817 #endif 1818 } 1819 1820 #if HAVE_NOTIFY_FD 1821 static void 1822 drmmode_notify_fd(int fd, int notify, void *data) 1823 { 1824 ScrnInfoPtr scrn = data; 1825 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1826 drmHandleEvent(drmmode->fd, &drmmode->event_context); 1827 } 1828 #else 1829 1830 static void 1831 drmmode_wakeup_handler(pointer data, int err, pointer p) 1832 { 1833 ScrnInfoPtr scrn = data; 1834 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1835 fd_set *read_mask = p; 1836 1837 if (scrn == NULL || err < 0) 1838 return; 1839 1840 if (FD_ISSET(drmmode->fd, read_mask)) 1841 drmHandleEvent(drmmode->fd, &drmmode->event_context); 1842 1843 #ifdef HAVE_LIBUDEV 1844 if (FD_ISSET(udev_monitor_get_fd(drmmode->uevent_monitor), read_mask)) 1845 drmmode_handle_uevents(scrn); 1846 #endif 1847 } 1848 #endif 1849 1850 void 1851 drmmode_screen_init(ScreenPtr pScreen) 1852 { 1853 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 1854 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1855 NVEntPtr pNVEnt = NVEntPriv(scrn); 1856 1857 /* Setup handler for DRM events */ 1858 drmmode_event_init(scrn); 1859 1860 /* Setup handler for udevevents */ 1861 drmmode_uevent_init(scrn); 1862 1863 /* Register wakeup handler only once per servergen, so ZaphodHeads work */ 1864 if (pNVEnt->fd_wakeup_registered != serverGeneration) { 1865 /* Register a wakeup handler to get informed on DRM events */ 1866 #if HAVE_NOTIFY_FD 1867 SetNotifyFd(drmmode->fd, drmmode_notify_fd, X_NOTIFY_READ, scrn); 1868 #else 1869 AddGeneralSocket(drmmode->fd); 1870 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 1871 drmmode_wakeup_handler, scrn); 1872 #endif 1873 pNVEnt->fd_wakeup_registered = serverGeneration; 1874 pNVEnt->fd_wakeup_ref = 1; 1875 } 1876 else 1877 pNVEnt->fd_wakeup_ref++; 1878 } 1879 1880 void 1881 drmmode_screen_fini(ScreenPtr pScreen) 1882 { 1883 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 1884 drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1885 NVEntPtr pNVEnt = NVEntPriv(scrn); 1886 1887 /* Unregister wakeup handler after last x-screen for this servergen dies. */ 1888 if (pNVEnt->fd_wakeup_registered == serverGeneration && 1889 !--pNVEnt->fd_wakeup_ref) { 1890 1891 #if HAVE_NOTIFY_FD 1892 RemoveNotifyFd(drmmode->fd); 1893 #else 1894 /* Unregister wakeup handler */ 1895 RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 1896 drmmode_wakeup_handler, scrn); 1897 RemoveGeneralSocket(drmmode->fd); 1898 #endif 1899 } 1900 1901 /* Tear down udev event handler */ 1902 drmmode_uevent_fini(scrn); 1903 1904 /* Tear down DRM event handler */ 1905 drmmode_event_fini(scrn); 1906 } 1907