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