drmmode_display.c revision 2a7e9763
1fda9279dSmrg/* 2fda9279dSmrg * Copyright © 2007 Red Hat, Inc. 3fda9279dSmrg * Copyright © 2008 Maarten Maathuis 4fda9279dSmrg * 5fda9279dSmrg * 6fda9279dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 7fda9279dSmrg * copy of this software and associated documentation files (the "Software"), 8fda9279dSmrg * to deal in the Software without restriction, including without limitation 9fda9279dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10fda9279dSmrg * and/or sell copies of the Software, and to permit persons to whom the 11fda9279dSmrg * Software is furnished to do so, subject to the following conditions: 12fda9279dSmrg * 13fda9279dSmrg * The above copyright notice and this permission notice (including the next 14fda9279dSmrg * paragraph) shall be included in all copies or substantial portions of the 15fda9279dSmrg * Software. 16fda9279dSmrg * 17fda9279dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18fda9279dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19fda9279dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20fda9279dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21fda9279dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22fda9279dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23fda9279dSmrg * SOFTWARE. 24fda9279dSmrg * 25fda9279dSmrg * Authors: 26fda9279dSmrg * Dave Airlie <airlied@redhat.com> 27fda9279dSmrg * 28fda9279dSmrg */ 29fda9279dSmrg 30fda9279dSmrg#ifdef HAVE_CONFIG_H 31fda9279dSmrg#include "config.h" 32fda9279dSmrg#endif 33fda9279dSmrg 34479f40c1Smrg#include "xorg-config.h" 35fda9279dSmrg#include "xorgVersion.h" 36479f40c1Smrg#include "Xdefs.h" 3746edf8f1Smrg#include "X11/Xdefs.h" 38fda9279dSmrg 39fda9279dSmrg#include "nv_include.h" 40fda9279dSmrg#include "xf86drmMode.h" 41fda9279dSmrg#include "X11/Xatom.h" 42fda9279dSmrg 43fda9279dSmrg#include <sys/ioctl.h> 44fda9279dSmrg#ifdef HAVE_LIBUDEV 45fda9279dSmrg#include "libudev.h" 46fda9279dSmrg#endif 47fda9279dSmrg 48fda9279dSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height); 49fda9279dSmrgtypedef struct { 50fda9279dSmrg int fd; 51fda9279dSmrg uint32_t fb_id; 52fda9279dSmrg int cpp; 53fda9279dSmrg drmEventContext event_context; 54fda9279dSmrg#ifdef HAVE_LIBUDEV 55fda9279dSmrg struct udev_monitor *uevent_monitor; 56fda9279dSmrg#endif 57fda9279dSmrg} drmmode_rec, *drmmode_ptr; 58fda9279dSmrg 59fda9279dSmrgtypedef struct { 60fda9279dSmrg drmmode_ptr drmmode; 61fda9279dSmrg drmModeCrtcPtr mode_crtc; 62fda9279dSmrg int hw_crtc_index; 63fda9279dSmrg struct nouveau_bo *cursor; 64fda9279dSmrg struct nouveau_bo *rotate_bo; 65fda9279dSmrg int rotate_pitch; 66fda9279dSmrg PixmapPtr rotate_pixmap; 67fda9279dSmrg uint32_t rotate_fb_id; 68fda9279dSmrg Bool cursor_visible; 69fda9279dSmrg int scanout_pixmap_x; 701090d90aSmrg int dpms_mode; 71fda9279dSmrg} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; 72fda9279dSmrg 73fda9279dSmrgtypedef struct { 74fda9279dSmrg drmModePropertyPtr mode_prop; 75fda9279dSmrg int index; /* Index within the kernel-side property arrays for 76fda9279dSmrg * this connector. */ 77fda9279dSmrg int num_atoms; /* if range prop, num_atoms == 1; if enum prop, 78fda9279dSmrg * num_atoms == num_enums + 1 */ 79fda9279dSmrg Atom *atoms; 80fda9279dSmrg} drmmode_prop_rec, *drmmode_prop_ptr; 81fda9279dSmrg 82fda9279dSmrgtypedef struct { 83fda9279dSmrg drmmode_ptr drmmode; 84fda9279dSmrg int output_id; 85fda9279dSmrg drmModeConnectorPtr mode_output; 86fda9279dSmrg drmModeEncoderPtr mode_encoder; 87fda9279dSmrg drmModePropertyBlobPtr edid_blob; 8822d74663Smrg drmModePropertyBlobPtr tile_blob; 89fda9279dSmrg int num_props; 90fda9279dSmrg drmmode_prop_ptr props; 91fda9279dSmrg} drmmode_output_private_rec, *drmmode_output_private_ptr; 92fda9279dSmrg 93fda9279dSmrgstatic void drmmode_output_dpms(xf86OutputPtr output, int mode); 94fda9279dSmrg 95fda9279dSmrgstatic drmmode_ptr 96fda9279dSmrgdrmmode_from_scrn(ScrnInfoPtr scrn) 97fda9279dSmrg{ 98fda9279dSmrg if (scrn) { 99fda9279dSmrg xf86CrtcConfigPtr conf = XF86_CRTC_CONFIG_PTR(scrn); 100fda9279dSmrg drmmode_crtc_private_ptr crtc = conf->crtc[0]->driver_private; 101fda9279dSmrg 102fda9279dSmrg return crtc->drmmode; 103fda9279dSmrg } 104fda9279dSmrg 105fda9279dSmrg return NULL; 106fda9279dSmrg} 107fda9279dSmrg 108fda9279dSmrgstatic inline struct nouveau_pixmap * 109fda9279dSmrgdrmmode_pixmap(PixmapPtr ppix) 110fda9279dSmrg{ 111fda9279dSmrg return nouveau_pixmap(ppix); 112fda9279dSmrg} 113fda9279dSmrg 114fda9279dSmrgint 115fda9279dSmrgdrmmode_crtc(xf86CrtcPtr crtc) 116fda9279dSmrg{ 117fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 118fda9279dSmrg return drmmode_crtc->mode_crtc->crtc_id; 119fda9279dSmrg} 120fda9279dSmrg 1211090d90aSmrgBool 1221090d90aSmrgdrmmode_crtc_on(xf86CrtcPtr crtc) 1231090d90aSmrg{ 1241090d90aSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1251090d90aSmrg 1261090d90aSmrg return crtc->enabled && drmmode_crtc->dpms_mode == DPMSModeOn; 1271090d90aSmrg} 1281090d90aSmrg 129fda9279dSmrgint 130fda9279dSmrgdrmmode_head(xf86CrtcPtr crtc) 131fda9279dSmrg{ 132fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 133fda9279dSmrg return drmmode_crtc->hw_crtc_index; 134fda9279dSmrg} 135fda9279dSmrg 136fda9279dSmrgvoid 137fda9279dSmrgdrmmode_swap(ScrnInfoPtr scrn, uint32_t next, uint32_t *prev) 138fda9279dSmrg{ 139fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 140fda9279dSmrg *prev = drmmode->fb_id; 141fda9279dSmrg drmmode->fb_id = next; 142fda9279dSmrg} 143fda9279dSmrg 144fda9279dSmrg#if !HAVE_XORG_LIST 145fda9279dSmrg#define xorg_list list 146fda9279dSmrg#define xorg_list_for_each_entry list_for_each_entry 147fda9279dSmrg#define xorg_list_for_each_entry_safe list_for_each_entry_safe 148fda9279dSmrg#define xorg_list_append list_append 149fda9279dSmrg#define xorg_list_del list_del 150fda9279dSmrg#endif 151fda9279dSmrg 152fda9279dSmrgstruct drmmode_event { 153fda9279dSmrg struct xorg_list head; 154fda9279dSmrg drmmode_ptr drmmode; 155fda9279dSmrg uint64_t name; 156fda9279dSmrg void (*func)(void *, uint64_t, uint64_t, uint32_t); 157fda9279dSmrg}; 158fda9279dSmrg 159fda9279dSmrgstatic struct xorg_list 160fda9279dSmrgdrmmode_events = { 161fda9279dSmrg .next = &drmmode_events, 162fda9279dSmrg .prev = &drmmode_events, 163fda9279dSmrg}; 164fda9279dSmrg 1652a7e9763Smrgstatic bool warned = false; 1662a7e9763Smrg 167fda9279dSmrgstatic void 168fda9279dSmrgdrmmode_event_handler(int fd, unsigned int frame, unsigned int tv_sec, 169fda9279dSmrg unsigned int tv_usec, void *event_data) 170fda9279dSmrg{ 171fda9279dSmrg const uint64_t ust = (uint64_t)tv_sec * 1000000 + tv_usec; 172fda9279dSmrg struct drmmode_event *e = event_data; 173fda9279dSmrg 1742a7e9763Smrg int counter = 0; 1752a7e9763Smrg 176fda9279dSmrg xorg_list_for_each_entry(e, &drmmode_events, head) { 1772a7e9763Smrg counter++; 178fda9279dSmrg if (e == event_data) { 179fda9279dSmrg xorg_list_del(&e->head); 180fda9279dSmrg e->func((void *)(e + 1), e->name, ust, frame); 181fda9279dSmrg free(e); 182fda9279dSmrg break; 183fda9279dSmrg } 184fda9279dSmrg } 1852a7e9763Smrg 1862a7e9763Smrg if (counter > 100 && !warned) { 1872a7e9763Smrg xf86DrvMsg(0, X_WARNING, 1882a7e9763Smrg "Event handler iterated %d times\n", counter); 1892a7e9763Smrg warned = true; 1902a7e9763Smrg } 191fda9279dSmrg} 192fda9279dSmrg 193fda9279dSmrgvoid 194fda9279dSmrgdrmmode_event_abort(ScrnInfoPtr scrn, uint64_t name, bool pending) 195fda9279dSmrg{ 196fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 197fda9279dSmrg struct drmmode_event *e, *t; 198fda9279dSmrg 199fda9279dSmrg xorg_list_for_each_entry_safe(e, t, &drmmode_events, head) { 200fda9279dSmrg if (e->drmmode == drmmode && e->name == name) { 201fda9279dSmrg xorg_list_del(&e->head); 202fda9279dSmrg if (!pending) 203fda9279dSmrg free(e); 204fda9279dSmrg break; 205fda9279dSmrg } 206fda9279dSmrg } 207fda9279dSmrg} 208fda9279dSmrg 209fda9279dSmrgvoid * 210fda9279dSmrgdrmmode_event_queue(ScrnInfoPtr scrn, uint64_t name, unsigned size, 211fda9279dSmrg void (*func)(void *, uint64_t, uint64_t, uint32_t), 212fda9279dSmrg void **event_data) 213fda9279dSmrg{ 214fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 215fda9279dSmrg struct drmmode_event *e; 216fda9279dSmrg 217fda9279dSmrg e = *event_data = calloc(1, sizeof(*e) + size); 218fda9279dSmrg if (e) { 219fda9279dSmrg e->drmmode = drmmode; 220fda9279dSmrg e->name = name; 221fda9279dSmrg e->func = func; 222fda9279dSmrg xorg_list_append(&e->head, &drmmode_events); 223fda9279dSmrg return (void *)(e + 1); 224fda9279dSmrg } 225fda9279dSmrg 226fda9279dSmrg return NULL; 227fda9279dSmrg} 228fda9279dSmrg 229fda9279dSmrgint 230fda9279dSmrgdrmmode_event_flush(ScrnInfoPtr scrn) 231fda9279dSmrg{ 232fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 233fda9279dSmrg return drmHandleEvent(drmmode->fd, &drmmode->event_context); 234fda9279dSmrg} 235fda9279dSmrg 236fda9279dSmrgvoid 237fda9279dSmrgdrmmode_event_fini(ScrnInfoPtr scrn) 238fda9279dSmrg{ 239fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 240fda9279dSmrg struct drmmode_event *e, *t; 241fda9279dSmrg 242fda9279dSmrg xorg_list_for_each_entry_safe(e, t, &drmmode_events, head) { 243fda9279dSmrg if (e->drmmode == drmmode) { 244fda9279dSmrg xorg_list_del(&e->head); 245fda9279dSmrg free(e); 246fda9279dSmrg } 247fda9279dSmrg } 248fda9279dSmrg} 249fda9279dSmrg 250fda9279dSmrgvoid 251fda9279dSmrgdrmmode_event_init(ScrnInfoPtr scrn) 252fda9279dSmrg{ 253fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 254fda9279dSmrg drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; 255fda9279dSmrg drmmode->event_context.vblank_handler = drmmode_event_handler; 256fda9279dSmrg drmmode->event_context.page_flip_handler = drmmode_event_handler; 257fda9279dSmrg} 258fda9279dSmrg 259fda9279dSmrgstatic PixmapPtr 260fda9279dSmrgdrmmode_pixmap_wrap(ScreenPtr pScreen, int width, int height, int depth, 261fda9279dSmrg int bpp, int pitch, struct nouveau_bo *bo, void *data) 262fda9279dSmrg{ 263fda9279dSmrg NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen)); 264fda9279dSmrg PixmapPtr ppix; 265fda9279dSmrg 266fda9279dSmrg if (pNv->AccelMethod > NONE) 267fda9279dSmrg data = NULL; 268fda9279dSmrg 269fda9279dSmrg ppix = pScreen->CreatePixmap(pScreen, 0, 0, depth, 0); 270fda9279dSmrg if (!ppix) 271fda9279dSmrg return NULL; 272fda9279dSmrg 273fda9279dSmrg pScreen->ModifyPixmapHeader(ppix, width, height, depth, bpp, 274fda9279dSmrg pitch, data); 275fda9279dSmrg if (pNv->AccelMethod > NONE) 276fda9279dSmrg nouveau_bo_ref(bo, &drmmode_pixmap(ppix)->bo); 277fda9279dSmrg 278fda9279dSmrg return ppix; 279fda9279dSmrg} 280fda9279dSmrg 281fda9279dSmrgstatic void 282fda9279dSmrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn, drmModeModeInfo *kmode, 283fda9279dSmrg DisplayModePtr mode) 284fda9279dSmrg{ 285fda9279dSmrg memset(mode, 0, sizeof(DisplayModeRec)); 286fda9279dSmrg mode->status = MODE_OK; 287fda9279dSmrg 288fda9279dSmrg mode->Clock = kmode->clock; 289fda9279dSmrg 290fda9279dSmrg mode->HDisplay = kmode->hdisplay; 291fda9279dSmrg mode->HSyncStart = kmode->hsync_start; 292fda9279dSmrg mode->HSyncEnd = kmode->hsync_end; 293fda9279dSmrg mode->HTotal = kmode->htotal; 294fda9279dSmrg mode->HSkew = kmode->hskew; 295fda9279dSmrg 296fda9279dSmrg mode->VDisplay = kmode->vdisplay; 297fda9279dSmrg mode->VSyncStart = kmode->vsync_start; 298fda9279dSmrg mode->VSyncEnd = kmode->vsync_end; 299fda9279dSmrg mode->VTotal = kmode->vtotal; 300fda9279dSmrg mode->VScan = kmode->vscan; 301fda9279dSmrg 302fda9279dSmrg mode->Flags = kmode->flags; //& FLAG_BITS; 303fda9279dSmrg mode->name = strdup(kmode->name); 304fda9279dSmrg 305fda9279dSmrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 306fda9279dSmrg mode->type = M_T_DRIVER; 307fda9279dSmrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 308fda9279dSmrg mode->type |= M_T_PREFERRED; 309fda9279dSmrg xf86SetModeCrtc (mode, scrn->adjustFlags); 310fda9279dSmrg} 311fda9279dSmrg 312fda9279dSmrgstatic void 313fda9279dSmrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn, drmModeModeInfo *kmode, 314fda9279dSmrg DisplayModePtr mode) 315fda9279dSmrg{ 316fda9279dSmrg memset(kmode, 0, sizeof(*kmode)); 317fda9279dSmrg 318fda9279dSmrg kmode->clock = mode->Clock; 319fda9279dSmrg kmode->hdisplay = mode->HDisplay; 320fda9279dSmrg kmode->hsync_start = mode->HSyncStart; 321fda9279dSmrg kmode->hsync_end = mode->HSyncEnd; 322fda9279dSmrg kmode->htotal = mode->HTotal; 323fda9279dSmrg kmode->hskew = mode->HSkew; 324fda9279dSmrg 325fda9279dSmrg kmode->vdisplay = mode->VDisplay; 326fda9279dSmrg kmode->vsync_start = mode->VSyncStart; 327fda9279dSmrg kmode->vsync_end = mode->VSyncEnd; 328fda9279dSmrg kmode->vtotal = mode->VTotal; 329fda9279dSmrg kmode->vscan = mode->VScan; 330fda9279dSmrg 331fda9279dSmrg kmode->flags = mode->Flags; //& FLAG_BITS; 332fda9279dSmrg if (mode->name) 333fda9279dSmrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 334fda9279dSmrg kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 335fda9279dSmrg 336fda9279dSmrg} 337fda9279dSmrg 338fda9279dSmrgstatic void 3391090d90aSmrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 340fda9279dSmrg{ 3411090d90aSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 3421090d90aSmrg drmmode_crtc->dpms_mode = mode; 343fda9279dSmrg} 344fda9279dSmrg 345fda9279dSmrgvoid 346fda9279dSmrgdrmmode_fbcon_copy(ScreenPtr pScreen) 347fda9279dSmrg{ 348fda9279dSmrg ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen); 349fda9279dSmrg NVPtr pNv = NVPTR(pScrn); 350fda9279dSmrg#if XORG_VERSION_CURRENT >= 10999001 351fda9279dSmrg ExaDriverPtr exa = pNv->EXADriverPtr; 352fda9279dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 353fda9279dSmrg struct nouveau_bo *bo = NULL; 354a33a703bSmrg PixmapPtr pspix, pdpix = NULL; 355fda9279dSmrg drmModeFBPtr fb; 356fda9279dSmrg unsigned w = pScrn->virtualX, h = pScrn->virtualY; 357fda9279dSmrg int i, ret, fbcon_id = 0; 358fda9279dSmrg 359fda9279dSmrg if (pNv->AccelMethod != EXA) 360fda9279dSmrg goto fallback; 361fda9279dSmrg 362a33a703bSmrg pdpix = drmmode_pixmap_wrap(pScreen, pScrn->virtualX, 363a33a703bSmrg pScrn->virtualY, pScrn->depth, 364a33a703bSmrg pScrn->bitsPerPixel, pScrn->displayWidth * 365a33a703bSmrg pScrn->bitsPerPixel / 8, pNv->scanout, 366a33a703bSmrg NULL); 367a33a703bSmrg if (!pdpix) { 368a33a703bSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 369a33a703bSmrg "Failed to init scanout pixmap for fbcon mirror\n"); 370a33a703bSmrg goto fallback; 371a33a703bSmrg } 372a33a703bSmrg 373fda9279dSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 374fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = 375fda9279dSmrg xf86_config->crtc[i]->driver_private; 376fda9279dSmrg 377fda9279dSmrg if (drmmode_crtc->mode_crtc->buffer_id) 378fda9279dSmrg fbcon_id = drmmode_crtc->mode_crtc->buffer_id; 379fda9279dSmrg } 380fda9279dSmrg 381fda9279dSmrg if (!fbcon_id) 382fda9279dSmrg goto fallback; 383fda9279dSmrg 384fda9279dSmrg fb = drmModeGetFB(pNv->dev->fd, fbcon_id); 385fda9279dSmrg if (!fb) { 386fda9279dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 387fda9279dSmrg "Failed to retrieve fbcon fb: id %d\n", fbcon_id); 388fda9279dSmrg goto fallback; 389fda9279dSmrg } 390fda9279dSmrg 391fda9279dSmrg if (fb->depth != pScrn->depth || fb->width != w || fb->height != h) { 392fda9279dSmrg drmFree(fb); 393fda9279dSmrg goto fallback; 394fda9279dSmrg } 395fda9279dSmrg 396fda9279dSmrg ret = nouveau_bo_wrap(pNv->dev, fb->handle, &bo); 397fda9279dSmrg if (ret) { 398fda9279dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 399fda9279dSmrg "Failed to retrieve fbcon buffer: handle=0x%08x\n", 400fda9279dSmrg fb->handle); 401fda9279dSmrg drmFree(fb); 402fda9279dSmrg goto fallback; 403fda9279dSmrg } 404fda9279dSmrg 405fda9279dSmrg pspix = drmmode_pixmap_wrap(pScreen, fb->width, fb->height, 406fda9279dSmrg fb->depth, fb->bpp, fb->pitch, bo, NULL); 407fda9279dSmrg nouveau_bo_ref(NULL, &bo); 408fda9279dSmrg drmFree(fb); 409fda9279dSmrg if (!pspix) { 410fda9279dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 411fda9279dSmrg "Failed to create pixmap for fbcon contents\n"); 412fda9279dSmrg goto fallback; 413fda9279dSmrg } 414fda9279dSmrg 415fda9279dSmrg exa->PrepareCopy(pspix, pdpix, 0, 0, GXcopy, ~0); 416fda9279dSmrg exa->Copy(pdpix, 0, 0, 0, 0, w, h); 417fda9279dSmrg exa->DoneCopy(pdpix); 418fda9279dSmrg PUSH_KICK(pNv->pushbuf); 419fda9279dSmrg 420fda9279dSmrg /* wait for completion before continuing, avoids seeing a momentary 421fda9279dSmrg * flash of "corruption" on occasion 422fda9279dSmrg */ 423fda9279dSmrg nouveau_bo_wait(pNv->scanout, NOUVEAU_BO_RDWR, pNv->client); 424fda9279dSmrg 425fda9279dSmrg pScreen->DestroyPixmap(pdpix); 426fda9279dSmrg pScreen->DestroyPixmap(pspix); 427fda9279dSmrg pScreen->canDoBGNoneRoot = TRUE; 428fda9279dSmrg return; 429fda9279dSmrg 430fda9279dSmrgfallback: 431a33a703bSmrg if (pdpix) { 432a33a703bSmrg if (exa->PrepareSolid(pdpix, GXcopy, ~0, 0)) { 433a33a703bSmrg exa->Solid(pdpix, 0, 0, w, h); 434a33a703bSmrg exa->DoneSolid(pdpix); 435a33a703bSmrg PUSH_KICK(pNv->pushbuf); 436a33a703bSmrg nouveau_bo_wait(pNv->scanout, NOUVEAU_BO_RDWR, pNv->client); 437a33a703bSmrg pScreen->DestroyPixmap(pdpix); 438a33a703bSmrg return; 439a33a703bSmrg } 440a33a703bSmrg pScreen->DestroyPixmap(pdpix); 441a33a703bSmrg } 442fda9279dSmrg#endif 443fda9279dSmrg if (nouveau_bo_map(pNv->scanout, NOUVEAU_BO_WR, pNv->client)) 444fda9279dSmrg return; 445fda9279dSmrg memset(pNv->scanout->map, 0x00, pNv->scanout->size); 446fda9279dSmrg} 447fda9279dSmrg 448fda9279dSmrgstatic Bool 449fda9279dSmrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 450fda9279dSmrg Rotation rotation, int x, int y) 451fda9279dSmrg{ 452fda9279dSmrg ScrnInfoPtr pScrn = crtc->scrn; 453fda9279dSmrg NVPtr pNv = NVPTR(pScrn); 454fda9279dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 455fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 456fda9279dSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 457fda9279dSmrg uint32_t *output_ids; 458fda9279dSmrg int output_count = 0; 459fda9279dSmrg int ret = TRUE; 460fda9279dSmrg int i; 461fda9279dSmrg int fb_id; 462fda9279dSmrg drmModeModeInfo kmode; 463fda9279dSmrg 464fda9279dSmrg if (drmmode->fb_id == 0) { 465fda9279dSmrg unsigned int pitch = 466fda9279dSmrg pScrn->displayWidth * (pScrn->bitsPerPixel / 8); 467fda9279dSmrg 468fda9279dSmrg ret = drmModeAddFB(drmmode->fd, 469fda9279dSmrg pScrn->virtualX, pScrn->virtualY, 470fda9279dSmrg pScrn->depth, pScrn->bitsPerPixel, 471fda9279dSmrg pitch, pNv->scanout->handle, 472fda9279dSmrg &drmmode->fb_id); 473fda9279dSmrg if (ret < 0) { 474fda9279dSmrg ErrorF("failed to add fb\n"); 475fda9279dSmrg return FALSE; 476fda9279dSmrg } 477fda9279dSmrg } 478fda9279dSmrg 479fda9279dSmrg if (!xf86CrtcRotate(crtc)) 480fda9279dSmrg return FALSE; 481fda9279dSmrg 482fda9279dSmrg output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 483fda9279dSmrg if (!output_ids) 484fda9279dSmrg return FALSE; 485fda9279dSmrg 486fda9279dSmrg for (i = 0; i < xf86_config->num_output; i++) { 487fda9279dSmrg xf86OutputPtr output = xf86_config->output[i]; 488fda9279dSmrg drmmode_output_private_ptr drmmode_output; 489fda9279dSmrg 490fda9279dSmrg if (output->crtc != crtc) 491fda9279dSmrg continue; 492fda9279dSmrg 493fda9279dSmrg drmmode_output = output->driver_private; 49422d74663Smrg if (drmmode_output->output_id == -1) 49522d74663Smrg continue; 496fda9279dSmrg output_ids[output_count] = 497fda9279dSmrg drmmode_output->mode_output->connector_id; 498fda9279dSmrg output_count++; 499fda9279dSmrg } 500fda9279dSmrg 501fda9279dSmrg drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); 502fda9279dSmrg 503fda9279dSmrg fb_id = drmmode->fb_id; 504fda9279dSmrg#ifdef NOUVEAU_PIXMAP_SHARING 505fda9279dSmrg if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) { 506fda9279dSmrg x = drmmode_crtc->scanout_pixmap_x; 507fda9279dSmrg y = 0; 508fda9279dSmrg } else 509fda9279dSmrg#endif 510fda9279dSmrg if (drmmode_crtc->rotate_fb_id) { 511fda9279dSmrg fb_id = drmmode_crtc->rotate_fb_id; 512fda9279dSmrg x = 0; 513fda9279dSmrg y = 0; 514fda9279dSmrg } 515fda9279dSmrg 516fda9279dSmrg ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 517fda9279dSmrg fb_id, x, y, output_ids, output_count, &kmode); 518fda9279dSmrg free(output_ids); 519fda9279dSmrg 520fda9279dSmrg if (ret) { 521fda9279dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 522fda9279dSmrg "failed to set mode: %s\n", strerror(-ret)); 523fda9279dSmrg return FALSE; 524fda9279dSmrg } 525fda9279dSmrg 526fda9279dSmrg /* Work around some xserver stupidity */ 527fda9279dSmrg for (i = 0; i < xf86_config->num_output; i++) { 528fda9279dSmrg xf86OutputPtr output = xf86_config->output[i]; 529fda9279dSmrg 530fda9279dSmrg if (output->crtc != crtc) 531fda9279dSmrg continue; 532fda9279dSmrg 533fda9279dSmrg drmmode_output_dpms(output, DPMSModeOn); 534fda9279dSmrg } 535fda9279dSmrg 536fda9279dSmrg crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 537fda9279dSmrg crtc->gamma_blue, crtc->gamma_size); 538fda9279dSmrg 539861b9feeSmrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 540861b9feeSmrg xf86CursorResetCursor(crtc->scrn->pScreen); 54122d74663Smrg#else 542fda9279dSmrg xf86_reload_cursors(crtc->scrn->pScreen); 543861b9feeSmrg#endif 544fda9279dSmrg 545fda9279dSmrg return TRUE; 546fda9279dSmrg} 547fda9279dSmrg 548fda9279dSmrgstatic void 549fda9279dSmrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 550fda9279dSmrg{ 551fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 552fda9279dSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 553fda9279dSmrg 554fda9279dSmrg drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 555fda9279dSmrg} 556fda9279dSmrg 557fda9279dSmrgstatic void 558fda9279dSmrgconvert_cursor(CARD32 *dst, CARD32 *src, int dw, int sw) 559fda9279dSmrg{ 560fda9279dSmrg int i, j; 561fda9279dSmrg 562fda9279dSmrg for (j = 0; j < sw; j++) { 563fda9279dSmrg for (i = 0; i < sw; i++) { 564fda9279dSmrg dst[j * dw + i] = src[j * sw + i]; 565fda9279dSmrg } 566fda9279dSmrg } 567fda9279dSmrg} 568fda9279dSmrg 569fda9279dSmrgstatic void 570fda9279dSmrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 571fda9279dSmrg{ 572fda9279dSmrg NVPtr pNv = NVPTR(crtc->scrn); 573fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 574fda9279dSmrg struct nouveau_bo *cursor = drmmode_crtc->cursor; 575fda9279dSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 576fda9279dSmrg 577fda9279dSmrg nouveau_bo_map(cursor, NOUVEAU_BO_WR, pNv->client); 578fda9279dSmrg convert_cursor(cursor->map, image, 64, nv_cursor_width(pNv)); 579fda9279dSmrg 580fda9279dSmrg if (drmmode_crtc->cursor_visible) { 581fda9279dSmrg drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 582fda9279dSmrg cursor->handle, 64, 64); 583fda9279dSmrg } 584fda9279dSmrg} 585fda9279dSmrg 586fda9279dSmrgstatic void 587fda9279dSmrgdrmmode_hide_cursor (xf86CrtcPtr crtc) 588fda9279dSmrg{ 589fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 590fda9279dSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 591fda9279dSmrg 592fda9279dSmrg drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 593fda9279dSmrg 0, 64, 64); 594fda9279dSmrg drmmode_crtc->cursor_visible = FALSE; 595fda9279dSmrg} 596fda9279dSmrg 597fda9279dSmrgstatic void 598fda9279dSmrgdrmmode_show_cursor (xf86CrtcPtr crtc) 599fda9279dSmrg{ 600fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 601fda9279dSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 602fda9279dSmrg 603fda9279dSmrg drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 604fda9279dSmrg drmmode_crtc->cursor->handle, 64, 64); 605fda9279dSmrg drmmode_crtc->cursor_visible = TRUE; 606fda9279dSmrg} 607fda9279dSmrg 608fda9279dSmrgstatic void * 609fda9279dSmrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 610fda9279dSmrg{ 611fda9279dSmrg ScrnInfoPtr scrn = crtc->scrn; 612fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 613fda9279dSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 614fda9279dSmrg void *virtual; 615fda9279dSmrg int ret; 616fda9279dSmrg 617fda9279dSmrg ret = nouveau_allocate_surface(scrn, width, height, 618fda9279dSmrg scrn->bitsPerPixel, 619fda9279dSmrg NOUVEAU_CREATE_PIXMAP_SCANOUT, 620fda9279dSmrg &drmmode_crtc->rotate_pitch, 621fda9279dSmrg &drmmode_crtc->rotate_bo); 622fda9279dSmrg if (!ret) { 623fda9279dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 624fda9279dSmrg "Couldn't allocate shadow memory for rotated CRTC\n"); 625fda9279dSmrg return NULL; 626fda9279dSmrg } 627fda9279dSmrg 628fda9279dSmrg ret = nouveau_bo_map(drmmode_crtc->rotate_bo, NOUVEAU_BO_RDWR, 629fda9279dSmrg NVPTR(scrn)->client); 630fda9279dSmrg if (ret) { 631fda9279dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 632fda9279dSmrg "Couldn't get virtual address of shadow scanout\n"); 633fda9279dSmrg nouveau_bo_ref(NULL, &drmmode_crtc->rotate_bo); 634fda9279dSmrg return NULL; 635fda9279dSmrg } 636fda9279dSmrg virtual = drmmode_crtc->rotate_bo->map; 637fda9279dSmrg 638fda9279dSmrg ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth, 639fda9279dSmrg crtc->scrn->bitsPerPixel, drmmode_crtc->rotate_pitch, 640fda9279dSmrg drmmode_crtc->rotate_bo->handle, 641fda9279dSmrg &drmmode_crtc->rotate_fb_id); 642fda9279dSmrg if (ret) { 643fda9279dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 644fda9279dSmrg "Error adding FB for shadow scanout: %s\n", 645fda9279dSmrg strerror(-ret)); 646fda9279dSmrg nouveau_bo_ref(NULL, &drmmode_crtc->rotate_bo); 647fda9279dSmrg return NULL; 648fda9279dSmrg } 649fda9279dSmrg 650fda9279dSmrg return virtual; 651fda9279dSmrg} 652fda9279dSmrg 653fda9279dSmrgstatic PixmapPtr 654fda9279dSmrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 655fda9279dSmrg{ 656fda9279dSmrg ScrnInfoPtr pScrn = crtc->scrn; 657fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 658fda9279dSmrg PixmapPtr rotate_pixmap; 659fda9279dSmrg 660fda9279dSmrg if (!data) 661fda9279dSmrg data = drmmode_crtc_shadow_allocate (crtc, width, height); 662fda9279dSmrg 663fda9279dSmrg rotate_pixmap = drmmode_pixmap_wrap(pScrn->pScreen, width, height, 664fda9279dSmrg pScrn->depth, pScrn->bitsPerPixel, 665fda9279dSmrg drmmode_crtc->rotate_pitch, 666fda9279dSmrg drmmode_crtc->rotate_bo, data); 667fda9279dSmrg 668fda9279dSmrg drmmode_crtc->rotate_pixmap = rotate_pixmap; 669fda9279dSmrg return drmmode_crtc->rotate_pixmap; 670fda9279dSmrg} 671fda9279dSmrg 672fda9279dSmrgstatic void 673fda9279dSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 674fda9279dSmrg{ 675fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 676fda9279dSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 677fda9279dSmrg 678fda9279dSmrg if (rotate_pixmap) 679fda9279dSmrg FreeScratchPixmapHeader(rotate_pixmap); 680fda9279dSmrg 681fda9279dSmrg if (data) { 682fda9279dSmrg drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id); 683fda9279dSmrg drmmode_crtc->rotate_fb_id = 0; 684fda9279dSmrg nouveau_bo_ref(NULL, &drmmode_crtc->rotate_bo); 685fda9279dSmrg drmmode_crtc->rotate_pixmap = NULL; 686fda9279dSmrg } 687fda9279dSmrg} 688fda9279dSmrg 689fda9279dSmrgstatic void 690fda9279dSmrgdrmmode_gamma_set(xf86CrtcPtr crtc, CARD16 *red, CARD16 *green, CARD16 *blue, 691fda9279dSmrg int size) 692fda9279dSmrg{ 693fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 694fda9279dSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 695fda9279dSmrg int ret; 696fda9279dSmrg 697fda9279dSmrg ret = drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 698fda9279dSmrg size, red, green, blue); 699fda9279dSmrg if (ret != 0) { 700fda9279dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 70122d74663Smrg "failed to set gamma with %d entries: %s\n", 70222d74663Smrg size, strerror(-ret)); 703fda9279dSmrg } 704fda9279dSmrg} 705fda9279dSmrg 706fda9279dSmrg#ifdef NOUVEAU_PIXMAP_SHARING 707fda9279dSmrgstatic Bool 708fda9279dSmrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 709fda9279dSmrg{ 710fda9279dSmrg ScreenPtr screen = xf86ScrnToScreen(crtc->scrn); 711fda9279dSmrg PixmapPtr screenpix = screen->GetScreenPixmap(screen); 712fda9279dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 713fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 714374ff59dSmrg drmmode_ptr drmmode = drmmode_crtc->drmmode; 715fda9279dSmrg int c, total_width = 0, max_height = 0, this_x = 0; 716fda9279dSmrg if (!ppix) { 717374ff59dSmrg if (crtc->randr_crtc->scanout_pixmap) { 71822d74663Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 71922d74663Smrg PixmapStopDirtyTracking(&crtc->randr_crtc->scanout_pixmap->drawable, screenpix); 72022d74663Smrg#else 72122d74663Smrg PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix); 72222d74663Smrg#endif 723374ff59dSmrg if (drmmode && drmmode->fb_id) { 724374ff59dSmrg drmModeRmFB(drmmode->fd, drmmode->fb_id); 725374ff59dSmrg drmmode->fb_id = 0; 726374ff59dSmrg } 727374ff59dSmrg } 728fda9279dSmrg drmmode_crtc->scanout_pixmap_x = 0; 729fda9279dSmrg return TRUE; 730fda9279dSmrg } 731fda9279dSmrg 732fda9279dSmrg /* iterate over all the attached crtcs - 733fda9279dSmrg work out bounding box */ 734fda9279dSmrg for (c = 0; c < xf86_config->num_crtc; c++) { 735fda9279dSmrg xf86CrtcPtr iter = xf86_config->crtc[c]; 736fda9279dSmrg if (!iter->enabled && iter != crtc) 737fda9279dSmrg continue; 738fda9279dSmrg if (iter == crtc) { 739fda9279dSmrg this_x = total_width; 740fda9279dSmrg total_width += ppix->drawable.width; 741fda9279dSmrg if (max_height < ppix->drawable.height) 742fda9279dSmrg max_height = ppix->drawable.height; 743fda9279dSmrg } else { 744fda9279dSmrg total_width += iter->mode.HDisplay; 745fda9279dSmrg if (max_height < iter->mode.VDisplay) 746fda9279dSmrg max_height = iter->mode.VDisplay; 747fda9279dSmrg } 748374ff59dSmrg#if !defined(HAS_DIRTYTRACKING_ROTATION) && !defined(HAS_DIRTYTRACKING2) 749fda9279dSmrg if (iter != crtc) { 750fda9279dSmrg ErrorF("Cannot do multiple crtcs without X server dirty tracking 2 interface\n"); 751fda9279dSmrg return FALSE; 752fda9279dSmrg } 753fda9279dSmrg#endif 754fda9279dSmrg } 755fda9279dSmrg 756fda9279dSmrg if (total_width != screenpix->drawable.width || 757fda9279dSmrg max_height != screenpix->drawable.height) { 758fda9279dSmrg Bool ret; 759fda9279dSmrg ret = drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height); 760fda9279dSmrg if (ret == FALSE) 761fda9279dSmrg return FALSE; 762fda9279dSmrg 763fda9279dSmrg screenpix = screen->GetScreenPixmap(screen); 764fda9279dSmrg screen->width = screenpix->drawable.width = total_width; 765fda9279dSmrg screen->height = screenpix->drawable.height = max_height; 766fda9279dSmrg } 767fda9279dSmrg drmmode_crtc->scanout_pixmap_x = this_x; 76822d74663Smrg 76922d74663Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC 77022d74663Smrg PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0, RR_Rotate_0); 77122d74663Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION) 77222d74663Smrg PixmapStartDirtyTracking(ppix, screenpix, 0, 0, this_x, 0, RR_Rotate_0); 773a33a703bSmrg#elif defined(HAS_DIRTYTRACKING2) 774fda9279dSmrg PixmapStartDirtyTracking2(ppix, screenpix, 0, 0, this_x, 0); 775fda9279dSmrg#else 776fda9279dSmrg PixmapStartDirtyTracking(ppix, screenpix, 0, 0); 777fda9279dSmrg#endif 778fda9279dSmrg return TRUE; 779fda9279dSmrg} 780fda9279dSmrg#endif 781fda9279dSmrg 782fda9279dSmrgstatic const xf86CrtcFuncsRec drmmode_crtc_funcs = { 783fda9279dSmrg .dpms = drmmode_crtc_dpms, 784fda9279dSmrg .set_mode_major = drmmode_set_mode_major, 785fda9279dSmrg .set_cursor_position = drmmode_set_cursor_position, 786fda9279dSmrg .show_cursor = drmmode_show_cursor, 787fda9279dSmrg .hide_cursor = drmmode_hide_cursor, 788fda9279dSmrg .load_cursor_argb = drmmode_load_cursor_argb, 789fda9279dSmrg .shadow_create = drmmode_crtc_shadow_create, 790fda9279dSmrg .shadow_allocate = drmmode_crtc_shadow_allocate, 791fda9279dSmrg .shadow_destroy = drmmode_crtc_shadow_destroy, 792fda9279dSmrg .gamma_set = drmmode_gamma_set, 793fda9279dSmrg 794fda9279dSmrg#ifdef NOUVEAU_PIXMAP_SHARING 795fda9279dSmrg .set_scanout_pixmap = drmmode_set_scanout_pixmap, 796fda9279dSmrg#endif 797fda9279dSmrg}; 798fda9279dSmrg 799fda9279dSmrg 800fda9279dSmrgstatic unsigned int 80122d74663Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num) 802fda9279dSmrg{ 803fda9279dSmrg NVPtr pNv = NVPTR(pScrn); 804fda9279dSmrg NVEntPtr pNVEnt = NVEntPriv(pScrn); 805fda9279dSmrg xf86CrtcPtr crtc; 806fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc; 807fda9279dSmrg int ret; 808fda9279dSmrg 809fda9279dSmrg crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); 810fda9279dSmrg if (crtc == NULL) 811fda9279dSmrg return 0; 812fda9279dSmrg 813fda9279dSmrg drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 814fda9279dSmrg drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, 81522d74663Smrg mode_res->crtcs[num]); 816fda9279dSmrg drmmode_crtc->drmmode = drmmode; 817fda9279dSmrg drmmode_crtc->hw_crtc_index = num; 818fda9279dSmrg 819fda9279dSmrg ret = nouveau_bo_new(pNv->dev, NOUVEAU_BO_GART | NOUVEAU_BO_MAP, 0, 820fda9279dSmrg 64*64*4, NULL, &drmmode_crtc->cursor); 821fda9279dSmrg assert(ret == 0); 822fda9279dSmrg 823fda9279dSmrg crtc->driver_private = drmmode_crtc; 824fda9279dSmrg 825fda9279dSmrg /* Mark num'th crtc as in use on this device. */ 826fda9279dSmrg pNVEnt->assigned_crtcs |= (1 << num); 827fda9279dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 828fda9279dSmrg "Allocated crtc nr. %d to this screen.\n", num); 829fda9279dSmrg 830fda9279dSmrg return 1; 831fda9279dSmrg} 832fda9279dSmrg 833fda9279dSmrgstatic xf86OutputStatus 834fda9279dSmrgdrmmode_output_detect(xf86OutputPtr output) 835fda9279dSmrg{ 836fda9279dSmrg /* go to the hw and retrieve a new output struct */ 837fda9279dSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 838fda9279dSmrg drmmode_ptr drmmode = drmmode_output->drmmode; 839fda9279dSmrg xf86OutputStatus status; 84022d74663Smrg 84122d74663Smrg if (drmmode_output->output_id == -1) 84222d74663Smrg return XF86OutputStatusDisconnected; 84322d74663Smrg 844fda9279dSmrg drmModeFreeConnector(drmmode_output->mode_output); 845fda9279dSmrg 846fda9279dSmrg drmmode_output->mode_output = 847fda9279dSmrg drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 848fda9279dSmrg 84922d74663Smrg if (!drmmode_output->mode_output) { 85022d74663Smrg drmmode_output->output_id = -1; 851fda9279dSmrg return XF86OutputStatusDisconnected; 85222d74663Smrg } 853fda9279dSmrg 854fda9279dSmrg switch (drmmode_output->mode_output->connection) { 855fda9279dSmrg case DRM_MODE_CONNECTED: 856fda9279dSmrg status = XF86OutputStatusConnected; 857fda9279dSmrg break; 858fda9279dSmrg case DRM_MODE_DISCONNECTED: 859fda9279dSmrg status = XF86OutputStatusDisconnected; 860fda9279dSmrg break; 861fda9279dSmrg default: 862fda9279dSmrg case DRM_MODE_UNKNOWNCONNECTION: 863fda9279dSmrg status = XF86OutputStatusUnknown; 864fda9279dSmrg break; 865fda9279dSmrg } 866fda9279dSmrg return status; 867fda9279dSmrg} 868fda9279dSmrg 869fda9279dSmrgstatic Bool 870fda9279dSmrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr mode) 871fda9279dSmrg{ 872fda9279dSmrg if (mode->type & M_T_DEFAULT) 873fda9279dSmrg /* Default modes are harmful here. */ 874fda9279dSmrg return MODE_BAD; 875fda9279dSmrg 876fda9279dSmrg return MODE_OK; 877fda9279dSmrg} 878fda9279dSmrg 87922d74663Smrgstatic int 88022d74663Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput, 88122d74663Smrg int type, const char *name) 88222d74663Smrg{ 88322d74663Smrg int idx = -1; 88422d74663Smrg 88522d74663Smrg for (int i = 0; i < koutput->count_props; i++) { 88622d74663Smrg drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]); 88722d74663Smrg 88822d74663Smrg if (!prop) 88922d74663Smrg continue; 89022d74663Smrg 89122d74663Smrg if (drm_property_type_is(prop, type) && !strcmp(prop->name, name)) 89222d74663Smrg idx = i; 89322d74663Smrg 89422d74663Smrg drmModeFreeProperty(prop); 89522d74663Smrg 89622d74663Smrg if (idx > -1) 89722d74663Smrg break; 89822d74663Smrg } 89922d74663Smrg 90022d74663Smrg return idx; 90122d74663Smrg} 90222d74663Smrg 90322d74663Smrgstatic drmModePropertyBlobPtr 90422d74663Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name) 90522d74663Smrg{ 90622d74663Smrg drmModePropertyBlobPtr blob = NULL; 90722d74663Smrg int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name); 90822d74663Smrg 90922d74663Smrg if (idx > -1) 91022d74663Smrg blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]); 91122d74663Smrg 91222d74663Smrg return blob; 91322d74663Smrg} 91422d74663Smrg 91522d74663Smrgstatic void 91622d74663Smrgdrmmode_output_attach_tile(xf86OutputPtr output) 91722d74663Smrg{ 91822d74663Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 91922d74663Smrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 92022d74663Smrg drmmode_ptr drmmode = drmmode_output->drmmode; 92122d74663Smrg struct xf86CrtcTileInfo tile_info, *set = NULL; 92222d74663Smrg 92322d74663Smrg if (!koutput) { 92422d74663Smrg xf86OutputSetTile(output, NULL); 92522d74663Smrg return; 92622d74663Smrg } 92722d74663Smrg 92822d74663Smrg drmModeFreePropertyBlob(drmmode_output->tile_blob); 92922d74663Smrg 93022d74663Smrg /* look for a TILE property */ 93122d74663Smrg drmmode_output->tile_blob = 93222d74663Smrg koutput_get_prop_blob(drmmode->fd, koutput, "TILE"); 93322d74663Smrg 93422d74663Smrg if (drmmode_output->tile_blob) { 93522d74663Smrg if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE) 93622d74663Smrg set = &tile_info; 93722d74663Smrg } 93822d74663Smrg xf86OutputSetTile(output, set); 93922d74663Smrg} 94022d74663Smrg 94122d74663Smrg 942fda9279dSmrgstatic DisplayModePtr 943fda9279dSmrgdrmmode_output_get_modes(xf86OutputPtr output) 944fda9279dSmrg{ 945fda9279dSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 946fda9279dSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 947fda9279dSmrg drmmode_ptr drmmode = drmmode_output->drmmode; 948fda9279dSmrg int i; 949fda9279dSmrg DisplayModePtr Modes = NULL, Mode; 950fda9279dSmrg xf86MonPtr ddc_mon = NULL; 951fda9279dSmrg 952fda9279dSmrg if (!koutput) 953fda9279dSmrg return NULL; 954fda9279dSmrg 955fda9279dSmrg /* look for an EDID property */ 95622d74663Smrg drmmode_output->edid_blob = 95722d74663Smrg koutput_get_prop_blob(drmmode->fd, koutput, "EDID"); 958fda9279dSmrg 959fda9279dSmrg if (drmmode_output->edid_blob) { 960fda9279dSmrg ddc_mon = xf86InterpretEDID(output->scrn->scrnIndex, 961fda9279dSmrg drmmode_output->edid_blob->data); 962fda9279dSmrg if (ddc_mon && drmmode_output->edid_blob->length > 128) 963fda9279dSmrg ddc_mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 964fda9279dSmrg } 965fda9279dSmrg xf86OutputSetEDID(output, ddc_mon); 966fda9279dSmrg 96722d74663Smrg drmmode_output_attach_tile(output); 96822d74663Smrg 969fda9279dSmrg /* modes should already be available */ 970fda9279dSmrg for (i = 0; i < koutput->count_modes; i++) { 971fda9279dSmrg Mode = xnfalloc(sizeof(DisplayModeRec)); 972fda9279dSmrg 973fda9279dSmrg drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 974fda9279dSmrg Mode); 975fda9279dSmrg Modes = xf86ModesAdd(Modes, Mode); 976fda9279dSmrg 977fda9279dSmrg } 978fda9279dSmrg return Modes; 979fda9279dSmrg} 980fda9279dSmrg 981fda9279dSmrgstatic void 982fda9279dSmrgdrmmode_output_destroy(xf86OutputPtr output) 983fda9279dSmrg{ 984fda9279dSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 985fda9279dSmrg int i; 986fda9279dSmrg 987fda9279dSmrg if (drmmode_output->edid_blob) 988fda9279dSmrg drmModeFreePropertyBlob(drmmode_output->edid_blob); 98922d74663Smrg if (drmmode_output->tile_blob) 99022d74663Smrg drmModeFreePropertyBlob(drmmode_output->tile_blob); 991fda9279dSmrg for (i = 0; i < drmmode_output->num_props; i++) { 992fda9279dSmrg drmModeFreeProperty(drmmode_output->props[i].mode_prop); 993fda9279dSmrg free(drmmode_output->props[i].atoms); 994fda9279dSmrg } 995fda9279dSmrg drmModeFreeConnector(drmmode_output->mode_output); 996fda9279dSmrg free(drmmode_output); 997fda9279dSmrg output->driver_private = NULL; 998fda9279dSmrg} 999fda9279dSmrg 1000fda9279dSmrgstatic void 1001fda9279dSmrgdrmmode_output_dpms(xf86OutputPtr output, int mode) 1002fda9279dSmrg{ 1003fda9279dSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1004fda9279dSmrg drmModeConnectorPtr koutput = drmmode_output->mode_output; 1005fda9279dSmrg drmModePropertyPtr props; 1006fda9279dSmrg drmmode_ptr drmmode = drmmode_output->drmmode; 1007fda9279dSmrg int mode_id = -1, i; 1008fda9279dSmrg 100922d74663Smrg if (!koutput) 101022d74663Smrg return; 101122d74663Smrg 1012fda9279dSmrg for (i = 0; i < koutput->count_props; i++) { 1013fda9279dSmrg props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 101411c9f444Sriastradh if (props && (props->flags & DRM_MODE_PROP_ENUM)) { 1015fda9279dSmrg if (!strcmp(props->name, "DPMS")) { 1016fda9279dSmrg mode_id = koutput->props[i]; 1017fda9279dSmrg drmModeFreeProperty(props); 1018fda9279dSmrg break; 1019fda9279dSmrg } 1020fda9279dSmrg drmModeFreeProperty(props); 1021fda9279dSmrg } 1022fda9279dSmrg } 1023fda9279dSmrg 1024fda9279dSmrg if (mode_id < 0) 1025fda9279dSmrg return; 1026fda9279dSmrg 1027fda9279dSmrg drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, 1028fda9279dSmrg mode_id, mode); 1029fda9279dSmrg} 1030fda9279dSmrg 1031fda9279dSmrgstatic Bool 1032fda9279dSmrgdrmmode_property_ignore(drmModePropertyPtr prop) 1033fda9279dSmrg{ 1034fda9279dSmrg if (!prop) 1035fda9279dSmrg return TRUE; 1036fda9279dSmrg /* ignore blob prop */ 1037fda9279dSmrg if (prop->flags & DRM_MODE_PROP_BLOB) 1038fda9279dSmrg return TRUE; 1039fda9279dSmrg /* ignore standard property */ 1040fda9279dSmrg if (!strcmp(prop->name, "EDID") || 1041fda9279dSmrg !strcmp(prop->name, "DPMS")) 1042fda9279dSmrg return TRUE; 1043fda9279dSmrg 1044fda9279dSmrg return FALSE; 1045fda9279dSmrg} 1046fda9279dSmrg 1047fda9279dSmrgstatic void 1048fda9279dSmrgdrmmode_output_create_resources(xf86OutputPtr output) 1049fda9279dSmrg{ 1050fda9279dSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1051fda9279dSmrg drmModeConnectorPtr mode_output = drmmode_output->mode_output; 1052fda9279dSmrg drmmode_ptr drmmode = drmmode_output->drmmode; 1053fda9279dSmrg drmModePropertyPtr drmmode_prop; 1054fda9279dSmrg uint32_t value; 1055fda9279dSmrg int i, j, err; 1056fda9279dSmrg 1057fda9279dSmrg drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); 1058fda9279dSmrg if (!drmmode_output->props) 1059fda9279dSmrg return; 1060fda9279dSmrg 1061fda9279dSmrg drmmode_output->num_props = 0; 1062fda9279dSmrg for (i = 0, j = 0; i < mode_output->count_props; i++) { 1063fda9279dSmrg drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); 1064fda9279dSmrg if (drmmode_property_ignore(drmmode_prop)) { 1065fda9279dSmrg drmModeFreeProperty(drmmode_prop); 1066fda9279dSmrg continue; 1067fda9279dSmrg } 1068fda9279dSmrg drmmode_output->props[j].mode_prop = drmmode_prop; 1069fda9279dSmrg drmmode_output->props[j].index = i; 1070fda9279dSmrg drmmode_output->num_props++; 1071fda9279dSmrg j++; 1072fda9279dSmrg } 1073fda9279dSmrg 1074fda9279dSmrg for (i = 0; i < drmmode_output->num_props; i++) { 1075fda9279dSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1076fda9279dSmrg drmmode_prop = p->mode_prop; 1077fda9279dSmrg 1078fda9279dSmrg value = drmmode_output->mode_output->prop_values[p->index]; 1079fda9279dSmrg 1080fda9279dSmrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 1081fda9279dSmrg INT32 range[2]; 1082fda9279dSmrg 1083fda9279dSmrg p->num_atoms = 1; 1084fda9279dSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1085fda9279dSmrg if (!p->atoms) 1086fda9279dSmrg continue; 1087fda9279dSmrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1088fda9279dSmrg range[0] = drmmode_prop->values[0]; 1089fda9279dSmrg range[1] = drmmode_prop->values[1]; 1090fda9279dSmrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1091fda9279dSmrg FALSE, TRUE, 1092fda9279dSmrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1093fda9279dSmrg 2, range); 1094fda9279dSmrg if (err != 0) { 1095fda9279dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1096fda9279dSmrg "RRConfigureOutputProperty error, %d\n", err); 1097fda9279dSmrg } 1098fda9279dSmrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1099fda9279dSmrg XA_INTEGER, 32, PropModeReplace, 1, 1100fda9279dSmrg &value, FALSE, FALSE); 1101fda9279dSmrg if (err != 0) { 1102fda9279dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1103fda9279dSmrg "RRChangeOutputProperty error, %d\n", err); 1104fda9279dSmrg } 1105fda9279dSmrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1106fda9279dSmrg p->num_atoms = drmmode_prop->count_enums + 1; 1107fda9279dSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1108fda9279dSmrg if (!p->atoms) 1109fda9279dSmrg continue; 1110fda9279dSmrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1111fda9279dSmrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 1112fda9279dSmrg struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 1113fda9279dSmrg p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 1114fda9279dSmrg } 1115fda9279dSmrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1116fda9279dSmrg FALSE, FALSE, 1117fda9279dSmrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1118fda9279dSmrg p->num_atoms - 1, (INT32 *)&p->atoms[1]); 1119fda9279dSmrg if (err != 0) { 1120fda9279dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1121fda9279dSmrg "RRConfigureOutputProperty error, %d\n", err); 1122fda9279dSmrg } 1123fda9279dSmrg for (j = 0; j < drmmode_prop->count_enums; j++) 1124fda9279dSmrg if (drmmode_prop->enums[j].value == value) 1125fda9279dSmrg break; 1126fda9279dSmrg /* there's always a matching value */ 1127fda9279dSmrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1128fda9279dSmrg XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE); 1129fda9279dSmrg if (err != 0) { 1130fda9279dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1131fda9279dSmrg "RRChangeOutputProperty error, %d\n", err); 1132fda9279dSmrg } 1133fda9279dSmrg } 1134fda9279dSmrg } 1135fda9279dSmrg} 1136fda9279dSmrg 1137fda9279dSmrgstatic Bool 1138fda9279dSmrgdrmmode_output_set_property(xf86OutputPtr output, Atom property, 1139fda9279dSmrg RRPropertyValuePtr value) 1140fda9279dSmrg{ 1141fda9279dSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1142fda9279dSmrg drmmode_ptr drmmode = drmmode_output->drmmode; 1143fda9279dSmrg int i, ret; 1144fda9279dSmrg 1145fda9279dSmrg for (i = 0; i < drmmode_output->num_props; i++) { 1146fda9279dSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1147fda9279dSmrg 1148fda9279dSmrg if (p->atoms[0] != property) 1149fda9279dSmrg continue; 1150fda9279dSmrg 1151fda9279dSmrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1152fda9279dSmrg uint32_t val; 1153fda9279dSmrg 1154fda9279dSmrg if (value->type != XA_INTEGER || value->format != 32 || 1155fda9279dSmrg value->size != 1) 1156fda9279dSmrg return FALSE; 1157fda9279dSmrg val = *(uint32_t *)value->data; 1158fda9279dSmrg 1159fda9279dSmrg ret = drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 1160fda9279dSmrg p->mode_prop->prop_id, (uint64_t)val); 1161fda9279dSmrg 1162fda9279dSmrg if (ret) 1163fda9279dSmrg return FALSE; 1164fda9279dSmrg 1165fda9279dSmrg return TRUE; 1166fda9279dSmrg 1167fda9279dSmrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1168fda9279dSmrg Atom atom; 1169fda9279dSmrg const char *name; 1170fda9279dSmrg int j; 1171fda9279dSmrg 1172fda9279dSmrg if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 1173fda9279dSmrg return FALSE; 1174fda9279dSmrg memcpy(&atom, value->data, 4); 117522d74663Smrg if (!(name = NameForAtom(atom))) 117622d74663Smrg return FALSE; 1177fda9279dSmrg 1178fda9279dSmrg /* search for matching name string, then set its value down */ 1179fda9279dSmrg for (j = 0; j < p->mode_prop->count_enums; j++) { 1180fda9279dSmrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 1181fda9279dSmrg ret = drmModeConnectorSetProperty(drmmode->fd, 1182fda9279dSmrg drmmode_output->output_id, 1183fda9279dSmrg p->mode_prop->prop_id, 1184fda9279dSmrg p->mode_prop->enums[j].value); 1185fda9279dSmrg 1186fda9279dSmrg if (ret) 1187fda9279dSmrg return FALSE; 1188fda9279dSmrg 1189fda9279dSmrg return TRUE; 1190fda9279dSmrg } 1191fda9279dSmrg } 1192fda9279dSmrg 1193fda9279dSmrg return FALSE; 1194fda9279dSmrg } 1195fda9279dSmrg } 1196fda9279dSmrg 1197fda9279dSmrg return TRUE; 1198fda9279dSmrg} 1199fda9279dSmrg 1200fda9279dSmrgstatic Bool 1201fda9279dSmrgdrmmode_output_get_property(xf86OutputPtr output, Atom property) 1202fda9279dSmrg{ 1203fda9279dSmrg 1204fda9279dSmrg drmmode_output_private_ptr drmmode_output = output->driver_private; 1205fda9279dSmrg drmmode_ptr drmmode = drmmode_output->drmmode; 1206fda9279dSmrg uint32_t value; 1207fda9279dSmrg int err, i; 1208fda9279dSmrg 1209fda9279dSmrg if (output->scrn->vtSema) { 1210fda9279dSmrg drmModeFreeConnector(drmmode_output->mode_output); 1211fda9279dSmrg drmmode_output->mode_output = 1212fda9279dSmrg drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 1213fda9279dSmrg } 1214fda9279dSmrg 1215fda9279dSmrg if (!drmmode_output->mode_output) 1216fda9279dSmrg return FALSE; 1217fda9279dSmrg 1218fda9279dSmrg for (i = 0; i < drmmode_output->num_props; i++) { 1219fda9279dSmrg drmmode_prop_ptr p = &drmmode_output->props[i]; 1220fda9279dSmrg if (p->atoms[0] != property) 1221fda9279dSmrg continue; 1222fda9279dSmrg 1223fda9279dSmrg value = drmmode_output->mode_output->prop_values[p->index]; 1224fda9279dSmrg 1225fda9279dSmrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1226fda9279dSmrg err = RRChangeOutputProperty(output->randr_output, 1227fda9279dSmrg property, XA_INTEGER, 32, 1228fda9279dSmrg PropModeReplace, 1, &value, 1229fda9279dSmrg FALSE, FALSE); 1230fda9279dSmrg 1231fda9279dSmrg return !err; 1232fda9279dSmrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1233fda9279dSmrg int j; 1234fda9279dSmrg 1235fda9279dSmrg /* search for matching name string, then set its value down */ 1236fda9279dSmrg for (j = 0; j < p->mode_prop->count_enums; j++) { 1237fda9279dSmrg if (p->mode_prop->enums[j].value == value) 1238fda9279dSmrg break; 1239fda9279dSmrg } 1240fda9279dSmrg 1241fda9279dSmrg err = RRChangeOutputProperty(output->randr_output, property, 1242fda9279dSmrg XA_ATOM, 32, PropModeReplace, 1, 1243fda9279dSmrg &p->atoms[j+1], FALSE, FALSE); 1244fda9279dSmrg 1245fda9279dSmrg return !err; 1246fda9279dSmrg } 1247fda9279dSmrg } 1248fda9279dSmrg 1249fda9279dSmrg return FALSE; 1250fda9279dSmrg} 1251fda9279dSmrg 1252fda9279dSmrgstatic const xf86OutputFuncsRec drmmode_output_funcs = { 1253fda9279dSmrg .create_resources = drmmode_output_create_resources, 1254fda9279dSmrg .dpms = drmmode_output_dpms, 1255fda9279dSmrg .detect = drmmode_output_detect, 1256fda9279dSmrg .mode_valid = drmmode_output_mode_valid, 1257fda9279dSmrg .get_modes = drmmode_output_get_modes, 1258fda9279dSmrg .set_property = drmmode_output_set_property, 1259fda9279dSmrg .get_property = drmmode_output_get_property, 1260fda9279dSmrg .destroy = drmmode_output_destroy 1261fda9279dSmrg}; 1262fda9279dSmrg 1263fda9279dSmrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown, 1264fda9279dSmrg SubPixelHorizontalRGB, 1265fda9279dSmrg SubPixelHorizontalBGR, 1266fda9279dSmrg SubPixelVerticalRGB, 1267fda9279dSmrg SubPixelVerticalBGR, 1268fda9279dSmrg SubPixelNone }; 1269fda9279dSmrg 1270fda9279dSmrgconst char *output_names[] = { "None", 1271fda9279dSmrg "VGA", 1272fda9279dSmrg "DVI-I", 1273fda9279dSmrg "DVI-D", 1274fda9279dSmrg "DVI-A", 1275fda9279dSmrg "Composite", 1276fda9279dSmrg "SVIDEO", 1277fda9279dSmrg "LVDS", 1278fda9279dSmrg "CTV", 1279fda9279dSmrg "DIN", 1280fda9279dSmrg "DP", 1281fda9279dSmrg "HDMI", 1282fda9279dSmrg "HDMI", 1283fda9279dSmrg "TV", 1284fda9279dSmrg "eDP", 1285fda9279dSmrg}; 1286fda9279dSmrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0])) 1287fda9279dSmrg 1288fda9279dSmrgstatic Bool 1289fda9279dSmrgdrmmode_zaphod_match(ScrnInfoPtr pScrn, const char *s, char *output_name) 1290fda9279dSmrg{ 1291fda9279dSmrg int i = 0; 1292fda9279dSmrg char s1[20]; 1293fda9279dSmrg 1294fda9279dSmrg do { 1295fda9279dSmrg switch(*s) { 1296fda9279dSmrg case ',': 1297fda9279dSmrg s1[i] = '\0'; 1298fda9279dSmrg i = 0; 1299fda9279dSmrg if (strcmp(s1, output_name) == 0) 1300fda9279dSmrg return TRUE; 1301fda9279dSmrg break; 1302fda9279dSmrg case ' ': 1303fda9279dSmrg case '\t': 1304fda9279dSmrg case '\n': 1305fda9279dSmrg case '\r': 1306fda9279dSmrg break; 1307fda9279dSmrg default: 1308fda9279dSmrg s1[i] = *s; 1309fda9279dSmrg i++; 1310fda9279dSmrg break; 1311fda9279dSmrg } 1312fda9279dSmrg } while(*s++); 1313fda9279dSmrg 1314fda9279dSmrg s1[i] = '\0'; 1315fda9279dSmrg if (strcmp(s1, output_name) == 0) 1316fda9279dSmrg return TRUE; 1317fda9279dSmrg 1318fda9279dSmrg return FALSE; 1319fda9279dSmrg} 1320fda9279dSmrg 132122d74663Smrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 132222d74663Smrg{ 132322d74663Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 132422d74663Smrg int i; 132522d74663Smrg for (i = 0; i < xf86_config->num_output; i++) { 132622d74663Smrg xf86OutputPtr output = xf86_config->output[i]; 132722d74663Smrg drmmode_output_private_ptr drmmode_output; 132822d74663Smrg 132922d74663Smrg drmmode_output = output->driver_private; 133022d74663Smrg if (drmmode_output->output_id == id) 133122d74663Smrg return output; 133222d74663Smrg } 133322d74663Smrg return NULL; 133422d74663Smrg} 133522d74663Smrg 133622d74663Smrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 133722d74663Smrg{ 133822d74663Smrg char *conn; 133922d74663Smrg char conn_id[5]; 134022d74663Smrg int id, len; 134122d74663Smrg char *blob_data; 134222d74663Smrg 134322d74663Smrg if (!path_blob) 134422d74663Smrg return -1; 134522d74663Smrg 134622d74663Smrg blob_data = path_blob->data; 134722d74663Smrg /* we only handle MST paths for now */ 134822d74663Smrg if (strncmp(blob_data, "mst:", 4)) 134922d74663Smrg return -1; 135022d74663Smrg 135122d74663Smrg conn = strchr(blob_data + 4, '-'); 135222d74663Smrg if (!conn) 135322d74663Smrg return -1; 135422d74663Smrg len = conn - (blob_data + 4); 135522d74663Smrg if (len + 1 > 5) 135622d74663Smrg return -1; 135722d74663Smrg memcpy(conn_id, blob_data + 4, len); 135822d74663Smrg conn_id[len] = '\0'; 135922d74663Smrg id = strtoul(conn_id, NULL, 10); 136022d74663Smrg 136122d74663Smrg *conn_base_id = id; 136222d74663Smrg 136322d74663Smrg *path = conn + 1; 136422d74663Smrg return 0; 136522d74663Smrg} 136622d74663Smrg 136722d74663Smrgstatic void 136822d74663Smrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 136922d74663Smrg drmModePropertyBlobPtr path_blob) 137022d74663Smrg{ 137122d74663Smrg int ret; 137222d74663Smrg char *extra_path; 137322d74663Smrg int conn_id; 137422d74663Smrg xf86OutputPtr output; 137522d74663Smrg 137622d74663Smrg ret = parse_path_blob(path_blob, &conn_id, &extra_path); 137722d74663Smrg if (ret == -1) 137822d74663Smrg goto fallback; 137922d74663Smrg 138022d74663Smrg output = find_output(pScrn, conn_id); 138122d74663Smrg if (!output) 138222d74663Smrg goto fallback; 138322d74663Smrg 138422d74663Smrg snprintf(name, 32, "%s-%s", output->name, extra_path); 138522d74663Smrg return; 138622d74663Smrg 138722d74663Smrgfallback: 138822d74663Smrg if (koutput->connector_type >= ARRAY_SIZE(output_names)) 138922d74663Smrg snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id); 139022d74663Smrg else if (pScrn->is_gpu) 139122d74663Smrg snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id); 139222d74663Smrg else 139322d74663Smrg snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id); 139422d74663Smrg} 139522d74663Smrg 1396fda9279dSmrgstatic unsigned int 139722d74663Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift) 1398fda9279dSmrg{ 1399fda9279dSmrg NVPtr pNv = NVPTR(pScrn); 1400fda9279dSmrg xf86OutputPtr output; 140122d74663Smrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1402fda9279dSmrg drmModeConnectorPtr koutput; 1403fda9279dSmrg drmModeEncoderPtr kencoder; 1404fda9279dSmrg drmmode_output_private_ptr drmmode_output; 1405fda9279dSmrg const char *s; 1406fda9279dSmrg char name[32]; 140722d74663Smrg drmModePropertyBlobPtr path_blob = NULL; 140822d74663Smrg int i; 1409fda9279dSmrg 1410fda9279dSmrg koutput = drmModeGetConnector(drmmode->fd, 141122d74663Smrg mode_res->connectors[num]); 1412fda9279dSmrg if (!koutput) 1413fda9279dSmrg return 0; 1414fda9279dSmrg 141522d74663Smrg path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH"); 141622d74663Smrg 141722d74663Smrg drmmode_create_name(pScrn, koutput, name, path_blob); 141822d74663Smrg 141922d74663Smrg if (path_blob) 142022d74663Smrg drmModeFreePropertyBlob(path_blob); 142122d74663Smrg 142222d74663Smrg if (path_blob && dynamic) { 142322d74663Smrg /* see if we have an output with this name already 142422d74663Smrg and hook stuff up */ 142522d74663Smrg for (i = 0; i < xf86_config->num_output; i++) { 142622d74663Smrg output = xf86_config->output[i]; 142722d74663Smrg 142822d74663Smrg if (strncmp(output->name, name, 32)) 142922d74663Smrg continue; 143022d74663Smrg 143122d74663Smrg drmmode_output = output->driver_private; 143222d74663Smrg drmmode_output->output_id = mode_res->connectors[num]; 143322d74663Smrg drmmode_output->mode_output = koutput; 143422d74663Smrg return 1; 143522d74663Smrg } 143622d74663Smrg } 143722d74663Smrg 143822d74663Smrg 1439fda9279dSmrg kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]); 1440fda9279dSmrg if (!kencoder) { 1441fda9279dSmrg drmModeFreeConnector(koutput); 1442fda9279dSmrg return 0; 1443fda9279dSmrg } 1444fda9279dSmrg 1445fda9279dSmrg if (xf86IsEntityShared(pScrn->entityList[0])) { 1446fda9279dSmrg s = xf86GetOptValString(pNv->Options, OPTION_ZAPHOD_HEADS); 1447fda9279dSmrg if (s) { 1448fda9279dSmrg if (!drmmode_zaphod_match(pScrn, s, name)) { 1449fda9279dSmrg drmModeFreeEncoder(kencoder); 1450fda9279dSmrg drmModeFreeConnector(koutput); 1451fda9279dSmrg return 0; 1452fda9279dSmrg } 1453fda9279dSmrg } else { 1454fda9279dSmrg if (pNv->Primary && (num != 0)) { 1455fda9279dSmrg drmModeFreeEncoder(kencoder); 1456fda9279dSmrg drmModeFreeConnector(koutput); 1457fda9279dSmrg return 0; 1458fda9279dSmrg } else 1459fda9279dSmrg if (pNv->Secondary && (num != 1)) { 1460fda9279dSmrg drmModeFreeEncoder(kencoder); 1461fda9279dSmrg drmModeFreeConnector(koutput); 1462fda9279dSmrg return 0; 1463fda9279dSmrg } 1464fda9279dSmrg } 1465fda9279dSmrg } 1466fda9279dSmrg 1467fda9279dSmrg output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 1468fda9279dSmrg if (!output) { 1469fda9279dSmrg drmModeFreeEncoder(kencoder); 1470fda9279dSmrg drmModeFreeConnector(koutput); 1471fda9279dSmrg return 0; 1472fda9279dSmrg } 1473fda9279dSmrg 1474fda9279dSmrg drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 1475fda9279dSmrg if (!drmmode_output) { 1476fda9279dSmrg xf86OutputDestroy(output); 1477fda9279dSmrg drmModeFreeConnector(koutput); 1478fda9279dSmrg drmModeFreeEncoder(kencoder); 1479fda9279dSmrg return 0; 1480fda9279dSmrg } 1481fda9279dSmrg 148222d74663Smrg drmmode_output->output_id = mode_res->connectors[num]; 1483fda9279dSmrg drmmode_output->mode_output = koutput; 1484fda9279dSmrg drmmode_output->mode_encoder = kencoder; 1485fda9279dSmrg drmmode_output->drmmode = drmmode; 1486fda9279dSmrg output->mm_width = koutput->mmWidth; 1487fda9279dSmrg output->mm_height = koutput->mmHeight; 1488fda9279dSmrg 1489fda9279dSmrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 1490fda9279dSmrg output->driver_private = drmmode_output; 1491fda9279dSmrg 1492a33a703bSmrg output->possible_crtcs = kencoder->possible_crtcs >> crtcshift; 1493a33a703bSmrg output->possible_clones = kencoder->possible_clones >> crtcshift; 1494fda9279dSmrg 1495fda9279dSmrg output->interlaceAllowed = true; 1496fda9279dSmrg output->doubleScanAllowed = true; 1497fda9279dSmrg 149822d74663Smrg if (dynamic) 149922d74663Smrg output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output); 150022d74663Smrg 1501fda9279dSmrg return 1; 1502fda9279dSmrg} 1503fda9279dSmrg 1504fda9279dSmrgstatic Bool 1505fda9279dSmrgdrmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 1506fda9279dSmrg{ 1507fda9279dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1508fda9279dSmrg ScreenPtr screen = xf86ScrnToScreen(scrn); 1509fda9279dSmrg NVPtr pNv = NVPTR(scrn); 1510fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc = NULL; 1511fda9279dSmrg drmmode_ptr drmmode = NULL; 1512fda9279dSmrg uint32_t old_width, old_height, old_pitch, old_fb_id = 0; 1513fda9279dSmrg struct nouveau_bo *old_bo = NULL; 1514fda9279dSmrg int ret, i, pitch; 1515fda9279dSmrg PixmapPtr ppix; 1516fda9279dSmrg 1517fda9279dSmrg if (xf86_config->num_crtc) { 1518fda9279dSmrg drmmode_crtc = xf86_config->crtc[0]->driver_private; 1519fda9279dSmrg drmmode = drmmode_crtc->drmmode; 1520fda9279dSmrg } 1521fda9279dSmrg ErrorF("resize called %d %d\n", width, height); 1522fda9279dSmrg 1523fda9279dSmrg if (scrn->virtualX == width && scrn->virtualY == height) 1524fda9279dSmrg return TRUE; 1525fda9279dSmrg 1526fda9279dSmrg old_width = scrn->virtualX; 1527fda9279dSmrg old_height = scrn->virtualY; 1528fda9279dSmrg old_pitch = scrn->displayWidth; 1529fda9279dSmrg if (drmmode) 1530fda9279dSmrg old_fb_id = drmmode->fb_id; 1531fda9279dSmrg nouveau_bo_ref(pNv->scanout, &old_bo); 1532fda9279dSmrg nouveau_bo_ref(NULL, &pNv->scanout); 1533fda9279dSmrg 1534fda9279dSmrg ret = nouveau_allocate_surface(scrn, width, height, 1535fda9279dSmrg scrn->bitsPerPixel, 1536fda9279dSmrg NOUVEAU_CREATE_PIXMAP_SCANOUT, 1537fda9279dSmrg &pitch, &pNv->scanout); 1538fda9279dSmrg if (!ret) 1539fda9279dSmrg goto fail; 1540fda9279dSmrg 1541fda9279dSmrg scrn->virtualX = width; 1542fda9279dSmrg scrn->virtualY = height; 1543fda9279dSmrg scrn->displayWidth = pitch / (scrn->bitsPerPixel >> 3); 1544fda9279dSmrg 1545fda9279dSmrg nouveau_bo_map(pNv->scanout, NOUVEAU_BO_RDWR, pNv->client); 1546fda9279dSmrg 1547fda9279dSmrg if (drmmode) { 1548fda9279dSmrg ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth, 1549fda9279dSmrg scrn->bitsPerPixel, pitch, pNv->scanout->handle, 1550fda9279dSmrg &drmmode->fb_id); 1551fda9279dSmrg if (ret) 1552fda9279dSmrg goto fail; 1553fda9279dSmrg } 1554fda9279dSmrg 1555fda9279dSmrg if (pNv->ShadowPtr) { 1556fda9279dSmrg free(pNv->ShadowPtr); 1557fda9279dSmrg pNv->ShadowPitch = pitch; 1558fda9279dSmrg pNv->ShadowPtr = malloc(pNv->ShadowPitch * height); 1559fda9279dSmrg } 1560fda9279dSmrg 1561fda9279dSmrg ppix = screen->GetScreenPixmap(screen); 15622a7e9763Smrg if (pNv->AccelMethod > NONE) 1563fda9279dSmrg nouveau_bo_ref(pNv->scanout, &drmmode_pixmap(ppix)->bo); 1564fda9279dSmrg screen->ModifyPixmapHeader(ppix, width, height, -1, -1, pitch, 1565fda9279dSmrg (pNv->AccelMethod > NONE || pNv->ShadowPtr) ? 1566fda9279dSmrg pNv->ShadowPtr : pNv->scanout->map); 1567fda9279dSmrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) < 9 1568fda9279dSmrg scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr; 1569fda9279dSmrg#endif 1570fda9279dSmrg 1571fda9279dSmrg if (pNv->AccelMethod == EXA) { 1572fda9279dSmrg pNv->EXADriverPtr->PrepareSolid(ppix, GXcopy, ~0, 0); 1573fda9279dSmrg pNv->EXADriverPtr->Solid(ppix, 0, 0, width, height); 1574fda9279dSmrg pNv->EXADriverPtr->DoneSolid(ppix); 1575fda9279dSmrg nouveau_bo_map(pNv->scanout, NOUVEAU_BO_RDWR, pNv->client); 1576fda9279dSmrg } else { 1577fda9279dSmrg memset(pNv->scanout->map, 0x00, pNv->scanout->size); 1578fda9279dSmrg } 1579fda9279dSmrg 1580fda9279dSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 1581fda9279dSmrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 1582fda9279dSmrg 1583fda9279dSmrg if (!crtc->enabled) 1584fda9279dSmrg continue; 1585fda9279dSmrg 1586fda9279dSmrg drmmode_set_mode_major(crtc, &crtc->mode, 1587fda9279dSmrg crtc->rotation, crtc->x, crtc->y); 1588fda9279dSmrg } 1589fda9279dSmrg 1590fda9279dSmrg if (old_fb_id) 1591fda9279dSmrg drmModeRmFB(drmmode->fd, old_fb_id); 1592fda9279dSmrg nouveau_bo_ref(NULL, &old_bo); 1593fda9279dSmrg 1594fda9279dSmrg return TRUE; 1595fda9279dSmrg 1596fda9279dSmrg fail: 1597fda9279dSmrg nouveau_bo_ref(old_bo, &pNv->scanout); 1598fda9279dSmrg scrn->virtualX = old_width; 1599fda9279dSmrg scrn->virtualY = old_height; 1600fda9279dSmrg scrn->displayWidth = old_pitch; 1601fda9279dSmrg if (drmmode) 1602fda9279dSmrg drmmode->fb_id = old_fb_id; 1603fda9279dSmrg 1604fda9279dSmrg return FALSE; 1605fda9279dSmrg} 1606fda9279dSmrg 1607fda9279dSmrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 1608fda9279dSmrg drmmode_xf86crtc_resize 1609fda9279dSmrg}; 1610fda9279dSmrg 1611fda9279dSmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp) 1612fda9279dSmrg{ 1613fda9279dSmrg drmmode_ptr drmmode; 161422d74663Smrg drmModeResPtr mode_res; 1615fda9279dSmrg NVEntPtr pNVEnt = NVEntPriv(pScrn); 1616fda9279dSmrg int i; 1617fda9279dSmrg unsigned int crtcs_needed = 0; 1618a33a703bSmrg int crtcshift; 1619fda9279dSmrg 16201090d90aSmrg drmmode = xnfcalloc(sizeof(*drmmode), 1); 1621fda9279dSmrg drmmode->fd = fd; 1622fda9279dSmrg drmmode->fb_id = 0; 1623fda9279dSmrg 1624fda9279dSmrg xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 1625fda9279dSmrg 1626fda9279dSmrg drmmode->cpp = cpp; 162722d74663Smrg mode_res = drmModeGetResources(drmmode->fd); 162822d74663Smrg if (!mode_res) 1629fda9279dSmrg return FALSE; 1630fda9279dSmrg 163122d74663Smrg xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, 163222d74663Smrg mode_res->max_height); 1633fda9279dSmrg 163422d74663Smrg if (!mode_res->count_connectors || 163522d74663Smrg !mode_res->count_crtcs) { 1636fda9279dSmrg free(drmmode); 1637fda9279dSmrg goto done; 1638fda9279dSmrg } 1639fda9279dSmrg 1640fda9279dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Initializing outputs ...\n"); 1641a33a703bSmrg crtcshift = ffs(pNVEnt->assigned_crtcs ^ 0xffffffff) - 1; 164222d74663Smrg for (i = 0; i < mode_res->count_connectors; i++) 164322d74663Smrg crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE, crtcshift); 1644fda9279dSmrg 1645fda9279dSmrg xf86DrvMsg(pScrn->scrnIndex, X_INFO, 1646fda9279dSmrg "%d crtcs needed for screen.\n", crtcs_needed); 1647fda9279dSmrg 164822d74663Smrg for (i = 0; i < mode_res->count_crtcs; i++) { 1649fda9279dSmrg if (!xf86IsEntityShared(pScrn->entityList[0]) || 1650fda9279dSmrg (crtcs_needed && !(pNVEnt->assigned_crtcs & (1 << i)))) 165122d74663Smrg crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i); 1652fda9279dSmrg } 1653fda9279dSmrg 1654fda9279dSmrg /* All ZaphodHeads outputs provided with matching crtcs? */ 1655fda9279dSmrg if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0)) 1656fda9279dSmrg xf86DrvMsg(pScrn->scrnIndex, X_WARNING, 1657fda9279dSmrg "%d ZaphodHeads crtcs unavailable. Trouble!\n", 1658fda9279dSmrg crtcs_needed); 1659fda9279dSmrg 1660fda9279dSmrgdone: 166122d74663Smrg drmModeFreeResources(mode_res); 166222d74663Smrg 1663fda9279dSmrg#ifdef NOUVEAU_PIXMAP_SHARING 1664fda9279dSmrg xf86ProviderSetup(pScrn, NULL, "nouveau"); 1665fda9279dSmrg#endif 1666fda9279dSmrg 1667fda9279dSmrg xf86InitialConfiguration(pScrn, TRUE); 1668fda9279dSmrg 1669fda9279dSmrg return TRUE; 1670fda9279dSmrg} 1671fda9279dSmrg 1672fda9279dSmrgvoid 1673fda9279dSmrgdrmmode_adjust_frame(ScrnInfoPtr scrn, int x, int y) 1674fda9279dSmrg{ 1675fda9279dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1676fda9279dSmrg xf86OutputPtr output = config->output[config->compat_output]; 1677fda9279dSmrg xf86CrtcPtr crtc = output->crtc; 1678fda9279dSmrg 1679fda9279dSmrg if (!crtc || !crtc->enabled) 1680fda9279dSmrg return; 1681fda9279dSmrg 1682fda9279dSmrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y); 1683fda9279dSmrg} 1684fda9279dSmrg 1685fda9279dSmrgvoid 1686fda9279dSmrgdrmmode_remove_fb(ScrnInfoPtr pScrn) 1687fda9279dSmrg{ 1688fda9279dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1689fda9279dSmrg xf86CrtcPtr crtc = NULL; 1690fda9279dSmrg drmmode_crtc_private_ptr drmmode_crtc; 1691fda9279dSmrg drmmode_ptr drmmode; 1692fda9279dSmrg 1693fda9279dSmrg if (config && config->num_crtc) 1694fda9279dSmrg crtc = config->crtc[0]; 1695fda9279dSmrg if (!crtc) 1696fda9279dSmrg return; 1697fda9279dSmrg 1698fda9279dSmrg drmmode_crtc = crtc->driver_private; 1699fda9279dSmrg drmmode = drmmode_crtc->drmmode; 1700fda9279dSmrg 1701fda9279dSmrg if (drmmode->fb_id) 1702fda9279dSmrg drmModeRmFB(drmmode->fd, drmmode->fb_id); 1703fda9279dSmrg drmmode->fb_id = 0; 1704fda9279dSmrg} 1705fda9279dSmrg 1706fda9279dSmrgint 1707fda9279dSmrgdrmmode_cursor_init(ScreenPtr pScreen) 1708fda9279dSmrg{ 1709fda9279dSmrg NVPtr pNv = NVPTR(xf86ScreenToScrn(pScreen)); 1710fda9279dSmrg int size = nv_cursor_width(pNv); 1711fda9279dSmrg int flags = HARDWARE_CURSOR_TRUECOLOR_AT_8BPP | 1712fda9279dSmrg HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_32 | 1713fda9279dSmrg (pNv->dev->chipset >= 0x11 ? HARDWARE_CURSOR_ARGB : 0) | 1714fda9279dSmrg HARDWARE_CURSOR_UPDATE_UNHIDDEN; 1715fda9279dSmrg 1716fda9279dSmrg return xf86_cursors_init(pScreen, size, size, flags); 1717fda9279dSmrg} 1718fda9279dSmrg 1719fda9279dSmrg#ifdef HAVE_LIBUDEV 172022d74663Smrg 172122d74663Smrg#define DRM_MODE_LINK_STATUS_GOOD 0 172222d74663Smrg#define DRM_MODE_LINK_STATUS_BAD 1 172322d74663Smrg 1724fda9279dSmrgstatic void 1725fda9279dSmrgdrmmode_handle_uevents(ScrnInfoPtr scrn) 1726fda9279dSmrg{ 172722d74663Smrg struct udev_device *dev; 172822d74663Smrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 172922d74663Smrg drmModeResPtr mode_res; 173022d74663Smrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 173122d74663Smrg int i, j; 173222d74663Smrg Bool found = FALSE; 173322d74663Smrg Bool changed = FALSE; 173422d74663Smrg 173522d74663Smrg while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) { 173622d74663Smrg udev_device_unref(dev); 173722d74663Smrg found = TRUE; 173822d74663Smrg } 173922d74663Smrg if (!found) 174022d74663Smrg return; 174122d74663Smrg 174222d74663Smrg /* Try to re-set the mode on all the connectors with a BAD link-state: 174322d74663Smrg * This may happen if a link degrades and a new modeset is necessary, using 174422d74663Smrg * different link-training parameters. If the kernel found that the current 174522d74663Smrg * mode is not achievable anymore, it should have pruned the mode before 174622d74663Smrg * sending the hotplug event. Try to re-set the currently-set mode to keep 174722d74663Smrg * the display alive, this will fail if the mode has been pruned. 174822d74663Smrg * In any case, we will send randr events for the Desktop Environment to 174922d74663Smrg * deal with it, if it wants to. 175022d74663Smrg */ 175122d74663Smrg for (i = 0; i < config->num_output; i++) { 175222d74663Smrg xf86OutputPtr output = config->output[i]; 175322d74663Smrg xf86CrtcPtr crtc = output->crtc; 175422d74663Smrg drmmode_output_private_ptr drmmode_output = output->driver_private; 175522d74663Smrg uint32_t con_id, idx; 175622d74663Smrg drmModeConnectorPtr koutput; 175722d74663Smrg 175822d74663Smrg if (crtc == NULL || drmmode_output->mode_output == NULL) 175922d74663Smrg continue; 176022d74663Smrg 176122d74663Smrg con_id = drmmode_output->mode_output->connector_id; 176222d74663Smrg /* Get an updated view of the properties for the current connector and 176322d74663Smrg * look for the link-status property 176422d74663Smrg */ 176522d74663Smrg koutput = drmModeGetConnectorCurrent(drmmode->fd, con_id); 176622d74663Smrg if (!koutput) 176722d74663Smrg continue; 176822d74663Smrg 176922d74663Smrg idx = koutput_get_prop_idx(drmmode->fd, koutput, 177022d74663Smrg DRM_MODE_PROP_ENUM, "link-status"); 177122d74663Smrg 177222d74663Smrg if ((idx > -1) && 177322d74663Smrg (koutput->prop_values[idx] == DRM_MODE_LINK_STATUS_BAD)) { 177422d74663Smrg /* the connector got a link failure, re-set the current mode */ 177522d74663Smrg drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 177622d74663Smrg crtc->x, crtc->y); 177722d74663Smrg 177822d74663Smrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 177922d74663Smrg "hotplug event: connector %u's link-state is BAD, " 178022d74663Smrg "tried resetting the current mode. You may be left" 178122d74663Smrg "with a black screen if this fails...\n", con_id); 178222d74663Smrg } 178322d74663Smrg 178422d74663Smrg drmModeFreeConnector(koutput); 178522d74663Smrg } 178622d74663Smrg 178722d74663Smrg mode_res = drmModeGetResources(drmmode->fd); 178822d74663Smrg if (!mode_res) 178922d74663Smrg goto out; 179022d74663Smrg 179122d74663Smrg if (mode_res->count_crtcs != config->num_crtc) { 179222d74663Smrg ErrorF("number of CRTCs changed - failed to handle, %d vs %d\n", mode_res->count_crtcs, config->num_crtc); 179322d74663Smrg goto out_free_res; 179422d74663Smrg } 179522d74663Smrg 179622d74663Smrg /* figure out if we have gotten rid of any connectors 179722d74663Smrg traverse old output list looking for outputs */ 179822d74663Smrg for (i = 0; i < config->num_output; i++) { 179922d74663Smrg xf86OutputPtr output = config->output[i]; 180022d74663Smrg drmmode_output_private_ptr drmmode_output; 180122d74663Smrg 180222d74663Smrg drmmode_output = output->driver_private; 180322d74663Smrg found = FALSE; 180422d74663Smrg for (j = 0; j < mode_res->count_connectors; j++) { 180522d74663Smrg if (mode_res->connectors[j] == drmmode_output->output_id) { 180622d74663Smrg found = TRUE; 180722d74663Smrg break; 180822d74663Smrg } 180922d74663Smrg } 181022d74663Smrg if (found) 181122d74663Smrg continue; 181222d74663Smrg 181322d74663Smrg drmModeFreeConnector(drmmode_output->mode_output); 181422d74663Smrg drmmode_output->mode_output = NULL; 181522d74663Smrg drmmode_output->output_id = -1; 181622d74663Smrg 181722d74663Smrg changed = TRUE; 181822d74663Smrg } 181922d74663Smrg 182022d74663Smrg /* find new output ids we don't have outputs for */ 182122d74663Smrg for (i = 0; i < mode_res->count_connectors; i++) { 182222d74663Smrg found = FALSE; 182322d74663Smrg 182422d74663Smrg for (j = 0; j < config->num_output; j++) { 182522d74663Smrg xf86OutputPtr output = config->output[j]; 182622d74663Smrg drmmode_output_private_ptr drmmode_output; 182722d74663Smrg 182822d74663Smrg drmmode_output = output->driver_private; 182922d74663Smrg if (mode_res->connectors[i] == drmmode_output->output_id) { 183022d74663Smrg found = TRUE; 183122d74663Smrg break; 183222d74663Smrg } 183322d74663Smrg } 183422d74663Smrg if (found) 183522d74663Smrg continue; 183622d74663Smrg 183722d74663Smrg changed = TRUE; 183822d74663Smrg drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0); 183922d74663Smrg } 184022d74663Smrg 184122d74663Smrg if (changed) { 184222d74663Smrg RRSetChanged(xf86ScrnToScreen(scrn)); 184322d74663Smrg RRTellChanged(xf86ScrnToScreen(scrn)); 184422d74663Smrg } 184522d74663Smrg 184622d74663Smrgout_free_res: 184722d74663Smrg drmModeFreeResources(mode_res); 184822d74663Smrgout: 184922d74663Smrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 185022d74663Smrg} 1851fda9279dSmrg 185222d74663Smrg#undef DRM_MODE_LINK_STATUS_BAD 185322d74663Smrg#undef DRM_MODE_LINK_STATUS_GOOD 1854fda9279dSmrg 185522d74663Smrg#endif 1856fda9279dSmrg 1857c694fe25Smrg#ifdef HAVE_LIBUDEV 1858374ff59dSmrg#if HAVE_NOTIFY_FD 1859374ff59dSmrgstatic void 1860374ff59dSmrgdrmmode_udev_notify(int fd, int notify, void *data) 1861374ff59dSmrg{ 1862374ff59dSmrg ScrnInfoPtr scrn = data; 1863374ff59dSmrg drmmode_handle_uevents(scrn); 1864374ff59dSmrg} 1865374ff59dSmrg#endif 1866c694fe25Smrg#endif 1867374ff59dSmrg 18681090d90aSmrgstatic bool has_randr(void) 18691090d90aSmrg{ 18701090d90aSmrg#if HAS_DIXREGISTERPRIVATEKEY 18711090d90aSmrg return dixPrivateKeyRegistered(rrPrivKey); 18721090d90aSmrg#else 18731090d90aSmrg return *rrPrivKey; 18741090d90aSmrg#endif 18751090d90aSmrg} 18761090d90aSmrg 1877fda9279dSmrgstatic void 1878fda9279dSmrgdrmmode_uevent_init(ScrnInfoPtr scrn) 1879fda9279dSmrg{ 1880fda9279dSmrg#ifdef HAVE_LIBUDEV 1881fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1882fda9279dSmrg struct udev *u; 1883fda9279dSmrg struct udev_monitor *mon; 1884fda9279dSmrg 18851090d90aSmrg /* RandR will be disabled if Xinerama is active, and so generating 18861090d90aSmrg * RR hotplug events is then forbidden. 18871090d90aSmrg */ 18881090d90aSmrg if (!has_randr()) 18891090d90aSmrg return; 18901090d90aSmrg 1891fda9279dSmrg u = udev_new(); 1892fda9279dSmrg if (!u) 1893fda9279dSmrg return; 1894fda9279dSmrg mon = udev_monitor_new_from_netlink(u, "udev"); 1895fda9279dSmrg if (!mon) { 1896fda9279dSmrg udev_unref(u); 1897fda9279dSmrg return; 1898fda9279dSmrg } 1899fda9279dSmrg 1900fda9279dSmrg if (udev_monitor_filter_add_match_subsystem_devtype(mon, 1901fda9279dSmrg "drm", 1902fda9279dSmrg "drm_minor") < 0 || 1903fda9279dSmrg udev_monitor_enable_receiving(mon) < 0) { 1904fda9279dSmrg udev_monitor_unref(mon); 1905fda9279dSmrg udev_unref(u); 1906fda9279dSmrg return; 1907fda9279dSmrg } 1908fda9279dSmrg 1909374ff59dSmrg#if HAVE_NOTIFY_FD 1910374ff59dSmrg SetNotifyFd(udev_monitor_get_fd(mon), drmmode_udev_notify, X_NOTIFY_READ, scrn); 1911374ff59dSmrg#else 1912fda9279dSmrg AddGeneralSocket(udev_monitor_get_fd(mon)); 1913374ff59dSmrg#endif 1914fda9279dSmrg drmmode->uevent_monitor = mon; 1915fda9279dSmrg#endif 1916fda9279dSmrg} 1917fda9279dSmrg 1918fda9279dSmrgstatic void 1919fda9279dSmrgdrmmode_uevent_fini(ScrnInfoPtr scrn) 1920fda9279dSmrg{ 1921fda9279dSmrg#ifdef HAVE_LIBUDEV 1922fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1923fda9279dSmrg 1924fda9279dSmrg if (drmmode->uevent_monitor) { 1925fda9279dSmrg struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 1926fda9279dSmrg 1927374ff59dSmrg#if HAVE_NOTIFY_FD 1928374ff59dSmrg RemoveNotifyFd(udev_monitor_get_fd(drmmode->uevent_monitor)); 1929374ff59dSmrg#else 1930fda9279dSmrg RemoveGeneralSocket(udev_monitor_get_fd(drmmode->uevent_monitor)); 1931374ff59dSmrg#endif 1932fda9279dSmrg udev_monitor_unref(drmmode->uevent_monitor); 1933fda9279dSmrg udev_unref(u); 1934fda9279dSmrg } 1935fda9279dSmrg#endif 1936fda9279dSmrg} 1937fda9279dSmrg 1938374ff59dSmrg#if HAVE_NOTIFY_FD 1939374ff59dSmrgstatic void 1940374ff59dSmrgdrmmode_notify_fd(int fd, int notify, void *data) 1941374ff59dSmrg{ 1942374ff59dSmrg ScrnInfoPtr scrn = data; 1943374ff59dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1944374ff59dSmrg drmHandleEvent(drmmode->fd, &drmmode->event_context); 1945374ff59dSmrg} 1946374ff59dSmrg#else 1947374ff59dSmrg 1948fda9279dSmrgstatic void 1949fda9279dSmrgdrmmode_wakeup_handler(pointer data, int err, pointer p) 1950fda9279dSmrg{ 1951fda9279dSmrg ScrnInfoPtr scrn = data; 1952fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1953fda9279dSmrg fd_set *read_mask = p; 1954fda9279dSmrg 1955fda9279dSmrg if (scrn == NULL || err < 0) 1956fda9279dSmrg return; 1957fda9279dSmrg 1958fda9279dSmrg if (FD_ISSET(drmmode->fd, read_mask)) 1959fda9279dSmrg drmHandleEvent(drmmode->fd, &drmmode->event_context); 1960fda9279dSmrg 1961fda9279dSmrg#ifdef HAVE_LIBUDEV 1962fda9279dSmrg if (FD_ISSET(udev_monitor_get_fd(drmmode->uevent_monitor), read_mask)) 1963fda9279dSmrg drmmode_handle_uevents(scrn); 1964fda9279dSmrg#endif 1965fda9279dSmrg} 1966374ff59dSmrg#endif 1967fda9279dSmrg 1968fda9279dSmrgvoid 1969fda9279dSmrgdrmmode_screen_init(ScreenPtr pScreen) 1970fda9279dSmrg{ 1971fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 1972fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 1973fda9279dSmrg NVEntPtr pNVEnt = NVEntPriv(scrn); 1974fda9279dSmrg 1975fda9279dSmrg /* Setup handler for DRM events */ 1976fda9279dSmrg drmmode_event_init(scrn); 1977fda9279dSmrg 1978fda9279dSmrg /* Setup handler for udevevents */ 1979fda9279dSmrg drmmode_uevent_init(scrn); 1980fda9279dSmrg 1981fda9279dSmrg /* Register wakeup handler only once per servergen, so ZaphodHeads work */ 1982fda9279dSmrg if (pNVEnt->fd_wakeup_registered != serverGeneration) { 1983fda9279dSmrg /* Register a wakeup handler to get informed on DRM events */ 1984374ff59dSmrg#if HAVE_NOTIFY_FD 1985374ff59dSmrg SetNotifyFd(drmmode->fd, drmmode_notify_fd, X_NOTIFY_READ, scrn); 1986374ff59dSmrg#else 1987fda9279dSmrg AddGeneralSocket(drmmode->fd); 1988fda9279dSmrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 1989fda9279dSmrg drmmode_wakeup_handler, scrn); 1990374ff59dSmrg#endif 1991fda9279dSmrg pNVEnt->fd_wakeup_registered = serverGeneration; 1992fda9279dSmrg pNVEnt->fd_wakeup_ref = 1; 1993fda9279dSmrg } 1994fda9279dSmrg else 1995fda9279dSmrg pNVEnt->fd_wakeup_ref++; 1996fda9279dSmrg} 1997fda9279dSmrg 1998fda9279dSmrgvoid 1999fda9279dSmrgdrmmode_screen_fini(ScreenPtr pScreen) 2000fda9279dSmrg{ 2001fda9279dSmrg ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen); 2002fda9279dSmrg drmmode_ptr drmmode = drmmode_from_scrn(scrn); 2003fda9279dSmrg NVEntPtr pNVEnt = NVEntPriv(scrn); 2004fda9279dSmrg 2005fda9279dSmrg /* Unregister wakeup handler after last x-screen for this servergen dies. */ 2006fda9279dSmrg if (pNVEnt->fd_wakeup_registered == serverGeneration && 2007fda9279dSmrg !--pNVEnt->fd_wakeup_ref) { 2008fda9279dSmrg 2009374ff59dSmrg#if HAVE_NOTIFY_FD 2010374ff59dSmrg RemoveNotifyFd(drmmode->fd); 2011374ff59dSmrg#else 2012fda9279dSmrg /* Unregister wakeup handler */ 2013fda9279dSmrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 2014fda9279dSmrg drmmode_wakeup_handler, scrn); 2015fda9279dSmrg RemoveGeneralSocket(drmmode->fd); 2016374ff59dSmrg#endif 2017fda9279dSmrg } 2018fda9279dSmrg 2019fda9279dSmrg /* Tear down udev event handler */ 2020fda9279dSmrg drmmode_uevent_fini(scrn); 2021fda9279dSmrg 2022fda9279dSmrg /* Tear down DRM event handler */ 2023fda9279dSmrg drmmode_event_fini(scrn); 2024fda9279dSmrg} 2025