drmmode_display.c revision 921a55d8
1/* 2 * Copyright © 2007 Red Hat, Inc. 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining a 5 * copy of this software and associated documentation files (the "Software"), 6 * to deal in the Software without restriction, including without limitation 7 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8 * and/or sell copies of the Software, and to permit persons to whom the 9 * Software is furnished to do so, subject to the following conditions: 10 * 11 * The above copyright notice and this permission notice (including the next 12 * paragraph) shall be included in all copies or substantial portions of the 13 * Software. 14 * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 * SOFTWARE. 22 * 23 * Authors: 24 * Dave Airlie <airlied@redhat.com> 25 * 26 */ 27 28#ifdef HAVE_CONFIG_H 29#include "config.h" 30#endif 31 32#include <errno.h> 33#ifdef XF86DRM_MODE 34#include <sys/ioctl.h> 35#include "micmap.h" 36#include "xf86cmap.h" 37#include "radeon.h" 38#include "radeon_reg.h" 39#include "radeon_drm.h" 40#include "sarea.h" 41 42#include "drmmode_display.h" 43 44/* DPMS */ 45#ifdef HAVE_XEXTPROTO_71 46#include <X11/extensions/dpmsconst.h> 47#else 48#define DPMS_SERVER 49#include <X11/extensions/dpms.h> 50#endif 51 52static PixmapPtr drmmode_create_bo_pixmap(ScreenPtr pScreen, 53 int width, int height, 54 int depth, int bpp, 55 int pitch, struct radeon_bo *bo) 56{ 57 PixmapPtr pixmap; 58 59 pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0); 60 if (!pixmap) 61 return NULL; 62 63 if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height, 64 depth, bpp, pitch, NULL)) { 65 return NULL; 66 } 67 68 exaMoveInPixmap(pixmap); 69 radeon_set_pixmap_bo(pixmap, bo); 70 71 return pixmap; 72} 73 74static void drmmode_destroy_bo_pixmap(PixmapPtr pixmap) 75{ 76 ScreenPtr pScreen = pixmap->drawable.pScreen; 77 78 (*pScreen->DestroyPixmap)(pixmap); 79} 80 81static void 82drmmode_ConvertFromKMode(ScrnInfoPtr scrn, 83 drmModeModeInfo *kmode, 84 DisplayModePtr mode) 85{ 86 memset(mode, 0, sizeof(DisplayModeRec)); 87 mode->status = MODE_OK; 88 89 mode->Clock = kmode->clock; 90 91 mode->HDisplay = kmode->hdisplay; 92 mode->HSyncStart = kmode->hsync_start; 93 mode->HSyncEnd = kmode->hsync_end; 94 mode->HTotal = kmode->htotal; 95 mode->HSkew = kmode->hskew; 96 97 mode->VDisplay = kmode->vdisplay; 98 mode->VSyncStart = kmode->vsync_start; 99 mode->VSyncEnd = kmode->vsync_end; 100 mode->VTotal = kmode->vtotal; 101 mode->VScan = kmode->vscan; 102 103 mode->Flags = kmode->flags; //& FLAG_BITS; 104 mode->name = strdup(kmode->name); 105 106 if (kmode->type & DRM_MODE_TYPE_DRIVER) 107 mode->type = M_T_DRIVER; 108 if (kmode->type & DRM_MODE_TYPE_PREFERRED) 109 mode->type |= M_T_PREFERRED; 110 xf86SetModeCrtc (mode, scrn->adjustFlags); 111} 112 113static void 114drmmode_ConvertToKMode(ScrnInfoPtr scrn, 115 drmModeModeInfo *kmode, 116 DisplayModePtr mode) 117{ 118 memset(kmode, 0, sizeof(*kmode)); 119 120 kmode->clock = mode->Clock; 121 kmode->hdisplay = mode->HDisplay; 122 kmode->hsync_start = mode->HSyncStart; 123 kmode->hsync_end = mode->HSyncEnd; 124 kmode->htotal = mode->HTotal; 125 kmode->hskew = mode->HSkew; 126 127 kmode->vdisplay = mode->VDisplay; 128 kmode->vsync_start = mode->VSyncStart; 129 kmode->vsync_end = mode->VSyncEnd; 130 kmode->vtotal = mode->VTotal; 131 kmode->vscan = mode->VScan; 132 133 kmode->flags = mode->Flags; //& FLAG_BITS; 134 if (mode->name) 135 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 136 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 137 138} 139 140static void 141drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode) 142{ 143#if 0 144 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 145// drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 146// drmmode_ptr drmmode = drmmode_crtc->drmmode; 147 148 /* bonghits in the randr 1.2 - uses dpms to disable crtc - bad buzz */ 149 if (mode == DPMSModeOff) { 150// drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 151// 0, 0, 0, NULL, 0, NULL); 152 } 153#endif 154} 155 156static PixmapPtr 157create_pixmap_for_fbcon(drmmode_ptr drmmode, 158 ScrnInfoPtr pScrn, int crtc_id) 159{ 160 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 161 drmmode_crtc_private_ptr drmmode_crtc; 162 ScreenPtr pScreen = pScrn->pScreen; 163 PixmapPtr pixmap; 164 struct radeon_bo *bo; 165 drmModeFBPtr fbcon; 166 struct drm_gem_flink flink; 167 168 drmmode_crtc = xf86_config->crtc[crtc_id]->driver_private; 169 170 fbcon = drmModeGetFB(drmmode->fd, drmmode_crtc->mode_crtc->buffer_id); 171 if (fbcon == NULL) 172 return NULL; 173 174 flink.handle = fbcon->handle; 175 if (ioctl(drmmode->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { 176 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 177 "Couldn't flink fbcon handle\n"); 178 return NULL; 179 } 180 181 bo = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0); 182 if (bo == NULL) { 183 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 184 "Couldn't allocate bo for fbcon handle\n"); 185 return NULL; 186 } 187 188 pixmap = drmmode_create_bo_pixmap(pScreen, fbcon->width, fbcon->height, 189 fbcon->depth, fbcon->bpp, 190 fbcon->pitch, bo); 191 if (!pixmap) 192 return NULL; 193 194 radeon_bo_unref(bo); 195 drmModeFreeFB(fbcon); 196 return pixmap; 197} 198 199void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 200{ 201 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 202 RADEONInfoPtr info = RADEONPTR(pScrn); 203 PixmapPtr src, dst; 204 ScreenPtr pScreen = pScrn->pScreen; 205 int crtc_id = 0; 206 int i; 207 int pitch; 208 uint32_t tiling_flags = 0; 209 Bool ret; 210 211 if (info->accelOn == FALSE) 212 return; 213 214 for (i = 0; i < xf86_config->num_crtc; i++) { 215 xf86CrtcPtr crtc = xf86_config->crtc[i]; 216 drmmode_crtc_private_ptr drmmode_crtc; 217 218 drmmode_crtc = crtc->driver_private; 219 if (drmmode_crtc->mode_crtc->buffer_id) 220 crtc_id = i; 221 } 222 223 src = create_pixmap_for_fbcon(drmmode, pScrn, crtc_id); 224 if (!src) 225 return; 226 227 if (info->allowColorTiling) { 228 if (info->ChipFamily >= CHIP_FAMILY_R600) 229 tiling_flags |= RADEON_TILING_MICRO; 230 else 231 tiling_flags |= RADEON_TILING_MACRO; 232 } 233 234 pitch = RADEON_ALIGN(pScrn->displayWidth, 235 drmmode_get_pitch_align(pScrn, info->CurrentLayout.pixel_bytes, tiling_flags)) * 236 info->CurrentLayout.pixel_bytes; 237 238 dst = drmmode_create_bo_pixmap(pScreen, pScrn->virtualX, 239 pScrn->virtualY, pScrn->depth, 240 pScrn->bitsPerPixel, pitch, 241 info->front_bo); 242 if (!dst) 243 goto out_free_src; 244 245 ret = info->accel_state->exa->PrepareCopy (src, dst, 246 -1, -1, GXcopy, FB_ALLONES); 247 if (!ret) 248 goto out_free_src; 249 info->accel_state->exa->Copy (dst, 0, 0, 0, 0, 250 pScrn->virtualX, pScrn->virtualY); 251 info->accel_state->exa->DoneCopy (dst); 252 radeon_cs_flush_indirect(pScrn); 253 254 drmmode_destroy_bo_pixmap(dst); 255 out_free_src: 256 drmmode_destroy_bo_pixmap(src); 257 258} 259 260static Bool 261drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 262 Rotation rotation, int x, int y) 263{ 264 ScrnInfoPtr pScrn = crtc->scrn; 265 RADEONInfoPtr info = RADEONPTR(pScrn); 266 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 267 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 268 drmmode_ptr drmmode = drmmode_crtc->drmmode; 269 int saved_x, saved_y; 270 Rotation saved_rotation; 271 DisplayModeRec saved_mode; 272 uint32_t *output_ids; 273 int output_count = 0; 274 Bool ret = TRUE; 275 int i; 276 int fb_id; 277 drmModeModeInfo kmode; 278 int pitch; 279 uint32_t tiling_flags = 0; 280 int height; 281 282 if (info->allowColorTiling) { 283 if (info->ChipFamily >= CHIP_FAMILY_R600) 284 tiling_flags |= RADEON_TILING_MICRO; 285 else 286 tiling_flags |= RADEON_TILING_MACRO; 287 } 288 289 pitch = RADEON_ALIGN(pScrn->displayWidth, drmmode_get_pitch_align(pScrn, info->CurrentLayout.pixel_bytes, tiling_flags)) * 290 info->CurrentLayout.pixel_bytes; 291 height = RADEON_ALIGN(pScrn->virtualY, drmmode_get_height_align(pScrn, tiling_flags)); 292 293 if (drmmode->fb_id == 0) { 294 ret = drmModeAddFB(drmmode->fd, 295 pScrn->virtualX, height, 296 pScrn->depth, pScrn->bitsPerPixel, 297 pitch, 298 info->front_bo->handle, 299 &drmmode->fb_id); 300 if (ret < 0) { 301 ErrorF("failed to add fb\n"); 302 return FALSE; 303 } 304 } 305 306 saved_mode = crtc->mode; 307 saved_x = crtc->x; 308 saved_y = crtc->y; 309 saved_rotation = crtc->rotation; 310 311 if (mode) { 312 crtc->mode = *mode; 313 crtc->x = x; 314 crtc->y = y; 315 crtc->rotation = rotation; 316#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,99,0,0) 317 crtc->transformPresent = FALSE; 318#endif 319 } 320 321 output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 322 if (!output_ids) { 323 ret = FALSE; 324 goto done; 325 } 326 327 if (mode) { 328 for (i = 0; i < xf86_config->num_output; i++) { 329 xf86OutputPtr output = xf86_config->output[i]; 330 drmmode_output_private_ptr drmmode_output; 331 332 if (output->crtc != crtc) 333 continue; 334 335 drmmode_output = output->driver_private; 336 output_ids[output_count] = drmmode_output->mode_output->connector_id; 337 output_count++; 338 } 339 340 if (!xf86CrtcRotate(crtc)) { 341 goto done; 342 } 343#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0) 344 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 345 crtc->gamma_blue, crtc->gamma_size); 346#endif 347 348 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); 349 350 fb_id = drmmode->fb_id; 351 if (drmmode_crtc->rotate_fb_id) { 352 fb_id = drmmode_crtc->rotate_fb_id; 353 x = y = 0; 354 } 355 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 356 fb_id, x, y, output_ids, output_count, &kmode); 357 if (ret) 358 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 359 "failed to set mode: %s", strerror(-ret)); 360 else 361 ret = TRUE; 362 363 if (crtc->scrn->pScreen) 364 xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen); 365 /* go through all the outputs and force DPMS them back on? */ 366 for (i = 0; i < xf86_config->num_output; i++) { 367 xf86OutputPtr output = xf86_config->output[i]; 368 369 if (output->crtc != crtc) 370 continue; 371 372 output->funcs->dpms(output, DPMSModeOn); 373 } 374 } 375 376 if (pScrn->pScreen && 377 !xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) 378 xf86_reload_cursors(pScrn->pScreen); 379 380done: 381 if (!ret) { 382 crtc->x = saved_x; 383 crtc->y = saved_y; 384 crtc->rotation = saved_rotation; 385 crtc->mode = saved_mode; 386 } 387#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3 388 else 389 crtc->active = TRUE; 390#endif 391 392 return ret; 393} 394 395static void 396drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 397{ 398 399} 400 401static void 402drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 403{ 404 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 405 drmmode_ptr drmmode = drmmode_crtc->drmmode; 406 407 drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 408} 409 410static void 411drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 412{ 413 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 414 void *ptr; 415 416 /* cursor should be mapped already */ 417 ptr = drmmode_crtc->cursor_bo->ptr; 418 419 memcpy (ptr, image, 64 * 64 * 4); 420 421 return; 422} 423 424 425static void 426drmmode_hide_cursor (xf86CrtcPtr crtc) 427{ 428 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 429 drmmode_ptr drmmode = drmmode_crtc->drmmode; 430 431 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 64, 64); 432 433} 434 435static void 436drmmode_show_cursor (xf86CrtcPtr crtc) 437{ 438 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 439 drmmode_ptr drmmode = drmmode_crtc->drmmode; 440 uint32_t handle = drmmode_crtc->cursor_bo->handle; 441 442 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 64, 64); 443} 444 445static void * 446drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 447{ 448 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 449 drmmode_ptr drmmode = drmmode_crtc->drmmode; 450 int size; 451 struct radeon_bo *rotate_bo; 452 int ret; 453 unsigned long rotate_pitch; 454 int base_align; 455 456 rotate_pitch = 457 RADEON_ALIGN(width, drmmode_get_pitch_align(crtc->scrn, drmmode->cpp, 0)) * drmmode->cpp; 458 height = RADEON_ALIGN(height, drmmode_get_height_align(crtc->scrn, 0)); 459 base_align = drmmode_get_base_align(crtc->scrn, drmmode->cpp, 0); 460 size = RADEON_ALIGN(rotate_pitch * height, RADEON_GPU_PAGE_SIZE); 461 462 rotate_bo = radeon_bo_open(drmmode->bufmgr, 0, size, base_align, RADEON_GEM_DOMAIN_VRAM, 0); 463 if (rotate_bo == NULL) 464 return NULL; 465 466 radeon_bo_map(rotate_bo, 1); 467 468 ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth, 469 crtc->scrn->bitsPerPixel, rotate_pitch, 470 rotate_bo->handle, 471 &drmmode_crtc->rotate_fb_id); 472 if (ret) { 473 ErrorF("failed to add rotate fb\n"); 474 } 475 476 drmmode_crtc->rotate_bo = rotate_bo; 477 return drmmode_crtc->rotate_bo->ptr; 478} 479 480static PixmapPtr 481drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 482{ 483 ScrnInfoPtr pScrn = crtc->scrn; 484 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 485 drmmode_ptr drmmode = drmmode_crtc->drmmode; 486 unsigned long rotate_pitch; 487 PixmapPtr rotate_pixmap; 488 489 if (!data) 490 data = drmmode_crtc_shadow_allocate (crtc, width, height); 491 492 rotate_pitch = RADEON_ALIGN(width, 64) * drmmode->cpp; 493 494 rotate_pixmap = drmmode_create_bo_pixmap(pScrn->pScreen, 495 width, height, 496 pScrn->depth, 497 pScrn->bitsPerPixel, 498 rotate_pitch, 499 drmmode_crtc->rotate_bo); 500 if (rotate_pixmap == NULL) { 501 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 502 "Couldn't allocate shadow pixmap for rotated CRTC\n"); 503 } 504 return rotate_pixmap; 505 506} 507 508static void 509drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 510{ 511 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 512 drmmode_ptr drmmode = drmmode_crtc->drmmode; 513 514 if (rotate_pixmap) 515 drmmode_destroy_bo_pixmap(rotate_pixmap); 516 517 if (data) { 518 drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id); 519 drmmode_crtc->rotate_fb_id = 0; 520 radeon_bo_unmap(drmmode_crtc->rotate_bo); 521 radeon_bo_unref(drmmode_crtc->rotate_bo); 522 drmmode_crtc->rotate_bo = NULL; 523 } 524 525} 526 527static void 528drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green, 529 uint16_t *blue, int size) 530{ 531 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 532 drmmode_ptr drmmode = drmmode_crtc->drmmode; 533 534 drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 535 size, red, green, blue); 536} 537 538static const xf86CrtcFuncsRec drmmode_crtc_funcs = { 539 .dpms = drmmode_crtc_dpms, 540 .set_mode_major = drmmode_set_mode_major, 541 .set_cursor_colors = drmmode_set_cursor_colors, 542 .set_cursor_position = drmmode_set_cursor_position, 543 .show_cursor = drmmode_show_cursor, 544 .hide_cursor = drmmode_hide_cursor, 545 .load_cursor_argb = drmmode_load_cursor_argb, 546 547 .gamma_set = drmmode_crtc_gamma_set, 548 .shadow_create = drmmode_crtc_shadow_create, 549 .shadow_allocate = drmmode_crtc_shadow_allocate, 550 .shadow_destroy = drmmode_crtc_shadow_destroy, 551 .destroy = NULL, /* XXX */ 552}; 553 554int drmmode_get_crtc_id(xf86CrtcPtr crtc) 555{ 556 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 557 return drmmode_crtc->hw_id; 558} 559 560void drmmode_crtc_hw_id(xf86CrtcPtr crtc) 561{ 562 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 563 ScrnInfoPtr pScrn = crtc->scrn; 564 RADEONInfoPtr info = RADEONPTR(pScrn); 565 struct drm_radeon_info ginfo; 566 int r; 567 uint32_t tmp; 568 569 memset(&ginfo, 0, sizeof(ginfo)); 570 ginfo.request = 0x4; 571 tmp = drmmode_crtc->mode_crtc->crtc_id; 572 ginfo.value = (uintptr_t)&tmp; 573 r = drmCommandWriteRead(info->dri->drmFD, DRM_RADEON_INFO, &ginfo, sizeof(ginfo)); 574 if (r) { 575 drmmode_crtc->hw_id = -1; 576 return; 577 } 578 drmmode_crtc->hw_id = tmp; 579} 580 581static void 582drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) 583{ 584 xf86CrtcPtr crtc; 585 drmmode_crtc_private_ptr drmmode_crtc; 586 587 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); 588 if (crtc == NULL) 589 return; 590 591 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 592 drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]); 593 drmmode_crtc->drmmode = drmmode; 594 crtc->driver_private = drmmode_crtc; 595 drmmode_crtc_hw_id(crtc); 596 597 return; 598} 599 600static xf86OutputStatus 601drmmode_output_detect(xf86OutputPtr output) 602{ 603 /* go to the hw and retrieve a new output struct */ 604 drmmode_output_private_ptr drmmode_output = output->driver_private; 605 drmmode_ptr drmmode = drmmode_output->drmmode; 606 xf86OutputStatus status; 607 drmModeFreeConnector(drmmode_output->mode_output); 608 609 drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 610 611 switch (drmmode_output->mode_output->connection) { 612 case DRM_MODE_CONNECTED: 613 status = XF86OutputStatusConnected; 614 break; 615 case DRM_MODE_DISCONNECTED: 616 status = XF86OutputStatusDisconnected; 617 break; 618 default: 619 case DRM_MODE_UNKNOWNCONNECTION: 620 status = XF86OutputStatusUnknown; 621 break; 622 } 623 return status; 624} 625 626static Bool 627drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 628{ 629 return MODE_OK; 630} 631 632static DisplayModePtr 633drmmode_output_get_modes(xf86OutputPtr output) 634{ 635 drmmode_output_private_ptr drmmode_output = output->driver_private; 636 drmModeConnectorPtr koutput = drmmode_output->mode_output; 637 drmmode_ptr drmmode = drmmode_output->drmmode; 638 int i; 639 DisplayModePtr Modes = NULL, Mode; 640 drmModePropertyPtr props; 641 xf86MonPtr mon = NULL; 642 643 /* look for an EDID property */ 644 for (i = 0; i < koutput->count_props; i++) { 645 props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 646 if (props && (props->flags & DRM_MODE_PROP_BLOB)) { 647 if (!strcmp(props->name, "EDID")) { 648 if (drmmode_output->edid_blob) 649 drmModeFreePropertyBlob(drmmode_output->edid_blob); 650 drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]); 651 } 652 drmModeFreeProperty(props); 653 } 654 } 655 656 if (drmmode_output->edid_blob) { 657 mon = xf86InterpretEDID(output->scrn->scrnIndex, 658 drmmode_output->edid_blob->data); 659 if (mon && drmmode_output->edid_blob->length > 128) 660 mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 661 } 662 xf86OutputSetEDID(output, mon); 663 664 /* modes should already be available */ 665 for (i = 0; i < koutput->count_modes; i++) { 666 Mode = xnfalloc(sizeof(DisplayModeRec)); 667 668 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode); 669 Modes = xf86ModesAdd(Modes, Mode); 670 671 } 672 return Modes; 673} 674 675static void 676drmmode_output_destroy(xf86OutputPtr output) 677{ 678 drmmode_output_private_ptr drmmode_output = output->driver_private; 679 int i; 680 681 if (drmmode_output->edid_blob) 682 drmModeFreePropertyBlob(drmmode_output->edid_blob); 683 for (i = 0; i < drmmode_output->num_props; i++) { 684 drmModeFreeProperty(drmmode_output->props[i].mode_prop); 685 free(drmmode_output->props[i].atoms); 686 } 687 for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) { 688 drmModeFreeEncoder(drmmode_output->mode_encoders[i]); 689 free(drmmode_output->mode_encoders); 690 } 691 free(drmmode_output->props); 692 drmModeFreeConnector(drmmode_output->mode_output); 693 free(drmmode_output); 694 output->driver_private = NULL; 695} 696 697static void 698drmmode_output_dpms(xf86OutputPtr output, int mode) 699{ 700 drmmode_output_private_ptr drmmode_output = output->driver_private; 701 drmModeConnectorPtr koutput = drmmode_output->mode_output; 702 drmmode_ptr drmmode = drmmode_output->drmmode; 703 704 drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id, 705 drmmode_output->dpms_enum_id, mode); 706 return; 707} 708 709 710static Bool 711drmmode_property_ignore(drmModePropertyPtr prop) 712{ 713 if (!prop) 714 return TRUE; 715 /* ignore blob prop */ 716 if (prop->flags & DRM_MODE_PROP_BLOB) 717 return TRUE; 718 /* ignore standard property */ 719 if (!strcmp(prop->name, "EDID") || 720 !strcmp(prop->name, "DPMS")) 721 return TRUE; 722 723 return FALSE; 724} 725 726static void 727drmmode_output_create_resources(xf86OutputPtr output) 728{ 729 drmmode_output_private_ptr drmmode_output = output->driver_private; 730 drmModeConnectorPtr mode_output = drmmode_output->mode_output; 731 drmmode_ptr drmmode = drmmode_output->drmmode; 732 drmModePropertyPtr drmmode_prop; 733 int i, j, err; 734 735 drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec)); 736 if (!drmmode_output->props) 737 return; 738 739 drmmode_output->num_props = 0; 740 for (i = 0, j = 0; i < mode_output->count_props; i++) { 741 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); 742 if (drmmode_property_ignore(drmmode_prop)) { 743 drmModeFreeProperty(drmmode_prop); 744 continue; 745 } 746 drmmode_output->props[j].mode_prop = drmmode_prop; 747 drmmode_output->props[j].value = mode_output->prop_values[i]; 748 drmmode_output->num_props++; 749 j++; 750 } 751 752 for (i = 0; i < drmmode_output->num_props; i++) { 753 drmmode_prop_ptr p = &drmmode_output->props[i]; 754 drmmode_prop = p->mode_prop; 755 756 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 757 INT32 range[2]; 758 INT32 value = p->value; 759 760 p->num_atoms = 1; 761 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 762 if (!p->atoms) 763 continue; 764 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 765 range[0] = drmmode_prop->values[0]; 766 range[1] = drmmode_prop->values[1]; 767 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 768 FALSE, TRUE, 769 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 770 2, range); 771 if (err != 0) { 772 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 773 "RRConfigureOutputProperty error, %d\n", err); 774 } 775 err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 776 XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE); 777 if (err != 0) { 778 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 779 "RRChangeOutputProperty error, %d\n", err); 780 } 781 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 782 p->num_atoms = drmmode_prop->count_enums + 1; 783 p->atoms = calloc(p->num_atoms, sizeof(Atom)); 784 if (!p->atoms) 785 continue; 786 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 787 for (j = 1; j <= drmmode_prop->count_enums; j++) { 788 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 789 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 790 } 791 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 792 FALSE, FALSE, 793 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 794 p->num_atoms - 1, (INT32 *)&p->atoms[1]); 795 if (err != 0) { 796 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 797 "RRConfigureOutputProperty error, %d\n", err); 798 } 799 for (j = 0; j < drmmode_prop->count_enums; j++) 800 if (drmmode_prop->enums[j].value == p->value) 801 break; 802 /* there's always a matching value */ 803 err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 804 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); 805 if (err != 0) { 806 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 807 "RRChangeOutputProperty error, %d\n", err); 808 } 809 } 810 } 811} 812 813static Bool 814drmmode_output_set_property(xf86OutputPtr output, Atom property, 815 RRPropertyValuePtr value) 816{ 817 drmmode_output_private_ptr drmmode_output = output->driver_private; 818 drmmode_ptr drmmode = drmmode_output->drmmode; 819 int i; 820 821 for (i = 0; i < drmmode_output->num_props; i++) { 822 drmmode_prop_ptr p = &drmmode_output->props[i]; 823 824 if (p->atoms[0] != property) 825 continue; 826 827 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 828 uint32_t val; 829 830 if (value->type != XA_INTEGER || value->format != 32 || 831 value->size != 1) 832 return FALSE; 833 val = *(uint32_t *)value->data; 834 835 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 836 p->mode_prop->prop_id, (uint64_t)val); 837 return TRUE; 838 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 839 Atom atom; 840 const char *name; 841 int j; 842 843 if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 844 return FALSE; 845 memcpy(&atom, value->data, 4); 846 name = NameForAtom(atom); 847 848 /* search for matching name string, then set its value down */ 849 for (j = 0; j < p->mode_prop->count_enums; j++) { 850 if (!strcmp(p->mode_prop->enums[j].name, name)) { 851 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 852 p->mode_prop->prop_id, p->mode_prop->enums[j].value); 853 return TRUE; 854 } 855 } 856 } 857 } 858 859 return TRUE; 860} 861 862static Bool 863drmmode_output_get_property(xf86OutputPtr output, Atom property) 864{ 865 return TRUE; 866} 867 868static const xf86OutputFuncsRec drmmode_output_funcs = { 869 .dpms = drmmode_output_dpms, 870 .create_resources = drmmode_output_create_resources, 871#ifdef RANDR_12_INTERFACE 872 .set_property = drmmode_output_set_property, 873 .get_property = drmmode_output_get_property, 874#endif 875#if 0 876 877 .save = drmmode_crt_save, 878 .restore = drmmode_crt_restore, 879 .mode_fixup = drmmode_crt_mode_fixup, 880 .prepare = drmmode_output_prepare, 881 .mode_set = drmmode_crt_mode_set, 882 .commit = drmmode_output_commit, 883#endif 884 .detect = drmmode_output_detect, 885 .mode_valid = drmmode_output_mode_valid, 886 887 .get_modes = drmmode_output_get_modes, 888 .destroy = drmmode_output_destroy 889}; 890 891static int subpixel_conv_table[7] = { 0, SubPixelUnknown, 892 SubPixelHorizontalRGB, 893 SubPixelHorizontalBGR, 894 SubPixelVerticalRGB, 895 SubPixelVerticalBGR, 896 SubPixelNone }; 897 898const char *output_names[] = { "None", 899 "VGA", 900 "DVI", 901 "DVI", 902 "DVI", 903 "Composite", 904 "S-video", 905 "LVDS", 906 "CTV", 907 "DIN", 908 "DisplayPort", 909 "HDMI", 910 "HDMI", 911 "TV", 912 "eDP" 913}; 914 915static void 916drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dvi, int *num_hdmi) 917{ 918 RADEONInfoPtr info = RADEONPTR(pScrn); 919 xf86OutputPtr output; 920 drmModeConnectorPtr koutput; 921 drmModeEncoderPtr *kencoders = NULL; 922 drmmode_output_private_ptr drmmode_output; 923 drmModePropertyPtr props; 924 char name[32]; 925 int i; 926 const char *s; 927 928 koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]); 929 if (!koutput) 930 return; 931 932 kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 933 if (!kencoders) { 934 goto out_free_encoders; 935 } 936 937 for (i = 0; i < koutput->count_encoders; i++) { 938 kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]); 939 if (!kencoders[i]) { 940 goto out_free_encoders; 941 } 942 } 943 944 /* need to do smart conversion here for compat with non-kms ATI driver */ 945 if (koutput->connector_type_id == 1) { 946 switch(koutput->connector_type) { 947 case DRM_MODE_CONNECTOR_DVII: 948 case DRM_MODE_CONNECTOR_DVID: 949 case DRM_MODE_CONNECTOR_DVIA: 950 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi); 951 (*num_dvi)++; 952 break; 953 case DRM_MODE_CONNECTOR_HDMIA: 954 case DRM_MODE_CONNECTOR_HDMIB: 955 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi); 956 (*num_hdmi)++; 957 break; 958 case DRM_MODE_CONNECTOR_VGA: 959 case DRM_MODE_CONNECTOR_DisplayPort: 960 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 961 break; 962 default: 963 snprintf(name, 32, "%s", output_names[koutput->connector_type]); 964 break; 965 } 966 } else { 967 snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1); 968 } 969 970 if (xf86IsEntityShared(pScrn->entityList[0])) { 971 if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) { 972 if (!RADEONZaphodStringMatches(pScrn, s, name)) 973 goto out_free_encoders; 974 } else { 975 if (info->IsPrimary && (num != 0)) 976 goto out_free_encoders; 977 else if (info->IsSecondary && (num != 1)) 978 goto out_free_encoders; 979 } 980 } 981 982 output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 983 if (!output) { 984 goto out_free_encoders; 985 } 986 987 drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1); 988 if (!drmmode_output) { 989 xf86OutputDestroy(output); 990 goto out_free_encoders; 991 } 992 993 drmmode_output->output_id = drmmode->mode_res->connectors[num]; 994 drmmode_output->mode_output = koutput; 995 drmmode_output->mode_encoders = kencoders; 996 drmmode_output->drmmode = drmmode; 997 output->mm_width = koutput->mmWidth; 998 output->mm_height = koutput->mmHeight; 999 1000 output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 1001 output->interlaceAllowed = TRUE; 1002 output->doubleScanAllowed = TRUE; 1003 output->driver_private = drmmode_output; 1004 1005 output->possible_crtcs = 0x7f; 1006 for (i = 0; i < koutput->count_encoders; i++) { 1007 output->possible_crtcs &= kencoders[i]->possible_crtcs; 1008 } 1009 /* work out the possible clones later */ 1010 output->possible_clones = 0; 1011 1012 for (i = 0; i < koutput->count_props; i++) { 1013 props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 1014 if (props && (props->flags && DRM_MODE_PROP_ENUM)) { 1015 if (!strcmp(props->name, "DPMS")) { 1016 drmmode_output->dpms_enum_id = koutput->props[i]; 1017 drmModeFreeProperty(props); 1018 break; 1019 } 1020 drmModeFreeProperty(props); 1021 } 1022 } 1023 1024 return; 1025out_free_encoders: 1026 if (kencoders){ 1027 for (i = 0; i < koutput->count_encoders; i++) 1028 drmModeFreeEncoder(kencoders[i]); 1029 free(kencoders); 1030 } 1031 drmModeFreeConnector(koutput); 1032 1033} 1034 1035uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 1036{ 1037 drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout; 1038 int i; 1039 xf86OutputPtr clone_output; 1040 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1041 int index_mask = 0; 1042 1043 if (drmmode_output->enc_clone_mask == 0) 1044 return index_mask; 1045 1046 for (i = 0; i < xf86_config->num_output; i++) { 1047 clone_output = xf86_config->output[i]; 1048 clone_drmout = clone_output->driver_private; 1049 if (output == clone_output) 1050 continue; 1051 1052 if (clone_drmout->enc_mask == 0) 1053 continue; 1054 if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask) 1055 index_mask |= (1 << i); 1056 } 1057 return index_mask; 1058} 1059 1060 1061static void 1062drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 1063{ 1064 int i, j; 1065 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1066 1067 for (i = 0; i < xf86_config->num_output; i++) { 1068 xf86OutputPtr output = xf86_config->output[i]; 1069 drmmode_output_private_ptr drmmode_output; 1070 1071 drmmode_output = output->driver_private; 1072 drmmode_output->enc_clone_mask = 0xff; 1073 /* and all the possible encoder clones for this output together */ 1074 for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) 1075 { 1076 int k; 1077 for (k = 0; k < drmmode->mode_res->count_encoders; k++) { 1078 if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id) 1079 drmmode_output->enc_mask |= (1 << k); 1080 } 1081 1082 drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones; 1083 } 1084 } 1085 1086 for (i = 0; i < xf86_config->num_output; i++) { 1087 xf86OutputPtr output = xf86_config->output[i]; 1088 output->possible_clones = find_clones(scrn, output); 1089 } 1090} 1091 1092/* returns height alignment in pixels */ 1093int drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling) 1094{ 1095 RADEONInfoPtr info = RADEONPTR(scrn); 1096 int height_align = 1; 1097 1098 if (info->ChipFamily >= CHIP_FAMILY_R600) { 1099 if (tiling & RADEON_TILING_MACRO) 1100 height_align = info->num_channels * 8; 1101 else if (tiling & RADEON_TILING_MICRO) 1102 height_align = 8; 1103 else 1104 height_align = 8; 1105 } else { 1106 if (tiling) 1107 height_align = 16; 1108 else 1109 height_align = 1; 1110 } 1111 return height_align; 1112} 1113 1114/* returns pitch alignment in pixels */ 1115int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 1116{ 1117 RADEONInfoPtr info = RADEONPTR(scrn); 1118 int pitch_align = 1; 1119 1120 if (info->ChipFamily >= CHIP_FAMILY_R600) { 1121 if (tiling & RADEON_TILING_MACRO) { 1122 /* general surface requirements */ 1123 pitch_align = MAX(info->num_banks, 1124 (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8; 1125 /* further restrictions for scanout */ 1126 pitch_align = MAX(info->num_banks * 8, pitch_align); 1127 } else if (tiling & RADEON_TILING_MICRO) { 1128 /* general surface requirements */ 1129 pitch_align = MAX(8, (info->group_bytes / (8 * bpe))); 1130 /* further restrictions for scanout */ 1131 pitch_align = MAX(info->group_bytes / bpe, pitch_align); 1132 } else { 1133 /* general surface requirements */ 1134 pitch_align = info->group_bytes / bpe; 1135 /* further restrictions for scanout */ 1136 pitch_align = MAX(32, pitch_align); 1137 } 1138 } else { 1139 /* general surface requirements */ 1140 if (tiling) 1141 pitch_align = 256 / bpe; 1142 else 1143 pitch_align = 64; 1144 } 1145 return pitch_align; 1146} 1147 1148/* returns base alignment in bytes */ 1149int drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling) 1150{ 1151 RADEONInfoPtr info = RADEONPTR(scrn); 1152 int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling); 1153 int height_align = drmmode_get_height_align(scrn, tiling); 1154 int base_align = RADEON_GPU_PAGE_SIZE; 1155 1156 if (info->ChipFamily >= CHIP_FAMILY_R600) { 1157 if (tiling & RADEON_TILING_MACRO) 1158 base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe, 1159 pixel_align * bpe * height_align); 1160 else 1161 base_align = info->group_bytes; 1162 } 1163 return base_align; 1164} 1165 1166static Bool 1167drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 1168{ 1169 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1170 drmmode_crtc_private_ptr 1171 drmmode_crtc = xf86_config->crtc[0]->driver_private; 1172 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1173 RADEONInfoPtr info = RADEONPTR(scrn); 1174 struct radeon_bo *old_front = NULL; 1175 Bool ret; 1176 ScreenPtr screen = screenInfo.screens[scrn->scrnIndex]; 1177 uint32_t old_fb_id; 1178 int i, pitch, old_width, old_height, old_pitch; 1179 int screen_size; 1180 int cpp = info->CurrentLayout.pixel_bytes; 1181 struct radeon_bo *front_bo; 1182 uint32_t tiling_flags = 0; 1183 PixmapPtr ppix = screen->GetScreenPixmap(screen); 1184 void *fb_shadow; 1185 1186 if (scrn->virtualX == width && scrn->virtualY == height) 1187 return TRUE; 1188 1189 front_bo = info->front_bo; 1190 radeon_cs_flush_indirect(scrn); 1191 1192 if (front_bo) 1193 radeon_bo_wait(front_bo); 1194 1195 if (info->allowColorTiling) { 1196 if (info->ChipFamily >= CHIP_FAMILY_R600) 1197 tiling_flags |= RADEON_TILING_MICRO; 1198 else 1199 tiling_flags |= RADEON_TILING_MACRO; 1200 } 1201 1202 pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(scrn, cpp, tiling_flags)) * cpp; 1203 height = RADEON_ALIGN(height, drmmode_get_height_align(scrn, tiling_flags)); 1204 screen_size = RADEON_ALIGN(pitch * height, RADEON_GPU_PAGE_SIZE); 1205 1206 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1207 "Allocate new frame buffer %dx%d stride %d\n", 1208 width, height, pitch / cpp); 1209 1210 old_width = scrn->virtualX; 1211 old_height = scrn->virtualY; 1212 old_pitch = scrn->displayWidth; 1213 old_fb_id = drmmode->fb_id; 1214 old_front = info->front_bo; 1215 1216 scrn->virtualX = width; 1217 scrn->virtualY = height; 1218 scrn->displayWidth = pitch / cpp; 1219 1220 info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, 0, RADEON_GEM_DOMAIN_VRAM, 0); 1221 if (!info->front_bo) 1222 goto fail; 1223 1224#if X_BYTE_ORDER == X_BIG_ENDIAN 1225 switch (cpp) { 1226 case 4: 1227 tiling_flags |= RADEON_TILING_SWAP_32BIT; 1228 break; 1229 case 2: 1230 tiling_flags |= RADEON_TILING_SWAP_16BIT; 1231 break; 1232 } 1233#endif 1234 if (tiling_flags) 1235 radeon_bo_set_tiling(info->front_bo, tiling_flags, pitch); 1236 1237 ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth, 1238 scrn->bitsPerPixel, pitch, 1239 info->front_bo->handle, 1240 &drmmode->fb_id); 1241 if (ret) 1242 goto fail; 1243 1244 if (!info->r600_shadow_fb) { 1245 radeon_set_pixmap_bo(ppix, info->front_bo); 1246 screen->ModifyPixmapHeader(ppix, 1247 width, height, -1, -1, pitch, NULL); 1248 } else { 1249 if (radeon_bo_map(info->front_bo, 1)) 1250 goto fail; 1251 fb_shadow = calloc(1, screen_size); 1252 if (fb_shadow == NULL) 1253 goto fail; 1254 free(info->fb_shadow); 1255 info->fb_shadow = fb_shadow; 1256 screen->ModifyPixmapHeader(ppix, 1257 width, height, -1, -1, pitch, 1258 info->fb_shadow); 1259 } 1260#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,9,99,1,0) 1261 scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr; 1262#endif 1263 1264 for (i = 0; i < xf86_config->num_crtc; i++) { 1265 xf86CrtcPtr crtc = xf86_config->crtc[i]; 1266 1267 if (!crtc->enabled) 1268 continue; 1269 1270 drmmode_set_mode_major(crtc, &crtc->mode, 1271 crtc->rotation, crtc->x, crtc->y); 1272 } 1273 1274 if (old_fb_id) 1275 drmModeRmFB(drmmode->fd, old_fb_id); 1276 if (old_front) 1277 radeon_bo_unref(old_front); 1278 1279 radeon_kms_update_vram_limit(scrn, screen_size); 1280 return TRUE; 1281 1282 fail: 1283 if (info->front_bo) 1284 radeon_bo_unref(info->front_bo); 1285 info->front_bo = old_front; 1286 scrn->virtualX = old_width; 1287 scrn->virtualY = old_height; 1288 scrn->displayWidth = old_pitch; 1289 drmmode->fb_id = old_fb_id; 1290 1291 return FALSE; 1292} 1293 1294static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 1295 drmmode_xf86crtc_resize 1296}; 1297 1298static void 1299drmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec, 1300 unsigned int tv_usec, void *event_data) 1301{ 1302 radeon_dri2_frame_event_handler(frame, tv_sec, tv_usec, event_data); 1303} 1304 1305static void 1306drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec, 1307 unsigned int tv_usec, void *event_data) 1308{ 1309 drmmode_flipevtcarrier_ptr flipcarrier = event_data; 1310 drmmode_ptr drmmode = flipcarrier->drmmode; 1311 1312 /* Is this the event whose info shall be delivered to higher level? */ 1313 if (flipcarrier->dispatch_me) { 1314 /* Yes: Cache msc, ust for later delivery. */ 1315 drmmode->fe_frame = frame; 1316 drmmode->fe_tv_sec = tv_sec; 1317 drmmode->fe_tv_usec = tv_usec; 1318 } 1319 free(flipcarrier); 1320 1321 /* Last crtc completed flip? */ 1322 drmmode->flip_count--; 1323 if (drmmode->flip_count > 0) 1324 return; 1325 1326 /* Release framebuffer */ 1327 drmModeRmFB(drmmode->fd, drmmode->old_fb_id); 1328 1329 if (drmmode->event_data == NULL) 1330 return; 1331 1332 /* Deliver cached msc, ust from reference crtc to flip event handler */ 1333 radeon_dri2_flip_event_handler(drmmode->fe_frame, drmmode->fe_tv_sec, 1334 drmmode->fe_tv_usec, drmmode->event_data); 1335} 1336 1337 1338static void 1339drm_wakeup_handler(pointer data, int err, pointer p) 1340{ 1341 drmmode_ptr drmmode = data; 1342 fd_set *read_mask = p; 1343 1344 if (err >= 0 && FD_ISSET(drmmode->fd, read_mask)) { 1345 drmHandleEvent(drmmode->fd, &drmmode->event_context); 1346 } 1347} 1348 1349Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) 1350{ 1351 RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn); 1352 xf86CrtcConfigPtr xf86_config; 1353 RADEONInfoPtr info = RADEONPTR(pScrn); 1354 int i, num_dvi = 0, num_hdmi = 0; 1355 1356 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 1357 xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1358 1359 drmmode->scrn = pScrn; 1360 drmmode->cpp = cpp; 1361 drmmode->mode_res = drmModeGetResources(drmmode->fd); 1362 if (!drmmode->mode_res) 1363 return FALSE; 1364 1365 xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height); 1366 for (i = 0; i < drmmode->mode_res->count_crtcs; i++) 1367 if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i) 1368 drmmode_crtc_init(pScrn, drmmode, i); 1369 1370 for (i = 0; i < drmmode->mode_res->count_connectors; i++) 1371 drmmode_output_init(pScrn, drmmode, i, &num_dvi, &num_hdmi); 1372 1373 /* workout clones */ 1374 drmmode_clones_init(pScrn, drmmode); 1375 1376 xf86InitialConfiguration(pScrn, TRUE); 1377 1378 drmmode->flip_count = 0; 1379 drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION; 1380 drmmode->event_context.vblank_handler = drmmode_vblank_handler; 1381 drmmode->event_context.page_flip_handler = drmmode_flip_handler; 1382 if (!pRADEONEnt->fd_wakeup_registered && info->dri->pKernelDRMVersion->version_minor >= 4) { 1383 drmmode->flip_count = 0; 1384 AddGeneralSocket(drmmode->fd); 1385 RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 1386 drm_wakeup_handler, drmmode); 1387 pRADEONEnt->fd_wakeup_registered = TRUE; 1388 } 1389 1390 return TRUE; 1391} 1392 1393Bool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr) 1394{ 1395 drmmode->bufmgr = bufmgr; 1396 return TRUE; 1397} 1398 1399 1400 1401void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo) 1402{ 1403 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1404 xf86CrtcPtr crtc = xf86_config->crtc[id]; 1405 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1406 1407 drmmode_crtc->cursor_bo = bo; 1408} 1409 1410void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y, int flags) 1411{ 1412 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1413 xf86OutputPtr output = config->output[config->compat_output]; 1414 xf86CrtcPtr crtc = output->crtc; 1415 1416 if (crtc && crtc->enabled) { 1417 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, 1418 x, y); 1419 } 1420} 1421 1422Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode) 1423{ 1424 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); 1425 int c; 1426 1427 drmmode_copy_fb(pScrn, drmmode); 1428 1429 for (c = 0; c < config->num_crtc; c++) { 1430 xf86CrtcPtr crtc = config->crtc[c]; 1431 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1432 xf86OutputPtr output = NULL; 1433 int o; 1434 1435 /* Skip disabled CRTCs */ 1436 if (!crtc->enabled) { 1437 drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 1438 0, 0, 0, NULL, 0, NULL); 1439 continue; 1440 } 1441 1442 if (config->output[config->compat_output]->crtc == crtc) 1443 output = config->output[config->compat_output]; 1444 else 1445 { 1446 for (o = 0; o < config->num_output; o++) 1447 if (config->output[o]->crtc == crtc) 1448 { 1449 output = config->output[o]; 1450 break; 1451 } 1452 } 1453 /* paranoia */ 1454 if (!output) 1455 continue; 1456 1457 /* Mark that we'll need to re-set the mode for sure */ 1458 memset(&crtc->mode, 0, sizeof(crtc->mode)); 1459 if (!crtc->desiredMode.CrtcHDisplay) 1460 { 1461 DisplayModePtr mode = xf86OutputFindClosestMode (output, pScrn->currentMode); 1462 1463 if (!mode) 1464 return FALSE; 1465 crtc->desiredMode = *mode; 1466 crtc->desiredRotation = RR_Rotate_0; 1467 crtc->desiredX = 0; 1468 crtc->desiredY = 0; 1469 } 1470 1471 if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation, 1472 crtc->desiredX, crtc->desiredY)) 1473 return FALSE; 1474 } 1475 return TRUE; 1476} 1477 1478static void drmmode_load_palette(ScrnInfoPtr pScrn, int numColors, 1479 int *indices, LOCO *colors, VisualPtr pVisual) 1480{ 1481 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1482 uint16_t lut_r[256], lut_g[256], lut_b[256]; 1483 int index, j, i; 1484 int c; 1485 1486 for (c = 0; c < xf86_config->num_crtc; c++) { 1487 xf86CrtcPtr crtc = xf86_config->crtc[c]; 1488 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1489 1490 for (i = 0 ; i < 256; i++) { 1491 lut_r[i] = drmmode_crtc->lut_r[i] << 6; 1492 lut_g[i] = drmmode_crtc->lut_g[i] << 6; 1493 lut_b[i] = drmmode_crtc->lut_b[i] << 6; 1494 } 1495 1496 switch(pScrn->depth) { 1497 case 15: 1498 for (i = 0; i < numColors; i++) { 1499 index = indices[i]; 1500 for (j = 0; j < 8; j++) { 1501 lut_r[index * 8 + j] = colors[index].red << 6; 1502 lut_g[index * 8 + j] = colors[index].green << 6; 1503 lut_b[index * 8 + j] = colors[index].blue << 6; 1504 } 1505 } 1506 break; 1507 case 16: 1508 for (i = 0; i < numColors; i++) { 1509 index = indices[i]; 1510 1511 if (i <= 31) { 1512 for (j = 0; j < 8; j++) { 1513 lut_r[index * 8 + j] = colors[index].red << 6; 1514 lut_b[index * 8 + j] = colors[index].blue << 6; 1515 } 1516 } 1517 1518 for (j = 0; j < 4; j++) { 1519 lut_g[index * 4 + j] = colors[index].green << 6; 1520 } 1521 } 1522 break; 1523 default: 1524 for (i = 0; i < numColors; i++) { 1525 index = indices[i]; 1526 lut_r[index] = colors[index].red << 6; 1527 lut_g[index] = colors[index].green << 6; 1528 lut_b[index] = colors[index].blue << 6; 1529 } 1530 break; 1531 } 1532 1533 /* Make the change through RandR */ 1534#ifdef RANDR_12_INTERFACE 1535 if (crtc->randr_crtc) 1536 RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b); 1537 else 1538#endif 1539 crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256); 1540 } 1541} 1542 1543Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn) 1544{ 1545 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG, 1546 "Initializing kms color map\n"); 1547 if (!miCreateDefColormap(pScreen)) 1548 return FALSE; 1549 /* all radeons support 10 bit CLUTs */ 1550 if (!xf86HandleColormaps(pScreen, 256, 10, 1551 drmmode_load_palette, NULL, 1552 CMAP_PALETTED_TRUECOLOR 1553#if 0 /* This option messes up text mode! (eich@suse.de) */ 1554 | CMAP_LOAD_EVEN_IF_OFFSCREEN 1555#endif 1556 | CMAP_RELOAD_ON_MODE_SWITCH)) 1557 return FALSE; 1558 return TRUE; 1559} 1560 1561#ifdef HAVE_LIBUDEV 1562static void 1563drmmode_handle_uevents(int fd, void *closure) 1564{ 1565 drmmode_ptr drmmode = closure; 1566 ScrnInfoPtr scrn = drmmode->scrn; 1567 struct udev_device *dev; 1568 dev = udev_monitor_receive_device(drmmode->uevent_monitor); 1569 if (!dev) 1570 return; 1571 1572 RRGetInfo(screenInfo.screens[scrn->scrnIndex], TRUE); 1573 udev_device_unref(dev); 1574} 1575#endif 1576 1577void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode) 1578{ 1579#ifdef HAVE_LIBUDEV 1580 struct udev *u; 1581 struct udev_monitor *mon; 1582 1583 u = udev_new(); 1584 if (!u) 1585 return; 1586 mon = udev_monitor_new_from_netlink(u, "udev"); 1587 if (!mon) { 1588 udev_unref(u); 1589 return; 1590 } 1591 1592 if (udev_monitor_filter_add_match_subsystem_devtype(mon, 1593 "drm", 1594 "drm_minor") < 0 || 1595 udev_monitor_enable_receiving(mon) < 0) { 1596 udev_monitor_unref(mon); 1597 udev_unref(u); 1598 return; 1599 } 1600 1601 drmmode->uevent_handler = 1602 xf86AddGeneralHandler(udev_monitor_get_fd(mon), 1603 drmmode_handle_uevents, 1604 drmmode); 1605 1606 drmmode->uevent_monitor = mon; 1607#endif 1608} 1609 1610void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode) 1611{ 1612#ifdef HAVE_LIBUDEV 1613 if (drmmode->uevent_handler) { 1614 struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor); 1615 xf86RemoveGeneralHandler(drmmode->uevent_handler); 1616 1617 udev_monitor_unref(drmmode->uevent_monitor); 1618 udev_unref(u); 1619 } 1620#endif 1621} 1622 1623Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id) 1624{ 1625 RADEONInfoPtr info = RADEONPTR(scrn); 1626 xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1627 drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; 1628 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1629 unsigned int pitch; 1630 int i, old_fb_id; 1631 uint32_t tiling_flags = 0; 1632 int height; 1633 drmmode_flipevtcarrier_ptr flipcarrier; 1634 1635 if (info->allowColorTiling) { 1636 if (info->ChipFamily >= CHIP_FAMILY_R600) 1637 tiling_flags |= RADEON_TILING_MICRO; 1638 else 1639 tiling_flags |= RADEON_TILING_MACRO; 1640 } 1641 1642 pitch = RADEON_ALIGN(scrn->displayWidth, drmmode_get_pitch_align(scrn, info->CurrentLayout.pixel_bytes, tiling_flags)) * 1643 info->CurrentLayout.pixel_bytes; 1644 height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags)); 1645 1646 /* 1647 * Create a new handle for the back buffer 1648 */ 1649 old_fb_id = drmmode->fb_id; 1650 if (drmModeAddFB(drmmode->fd, scrn->virtualX, height, 1651 scrn->depth, scrn->bitsPerPixel, pitch, 1652 new_front->handle, &drmmode->fb_id)) 1653 goto error_out; 1654 1655 /* 1656 * Queue flips on all enabled CRTCs 1657 * Note that if/when we get per-CRTC buffers, we'll have to update this. 1658 * Right now it assumes a single shared fb across all CRTCs, with the 1659 * kernel fixing up the offset of each CRTC as necessary. 1660 * 1661 * Also, flips queued on disabled or incorrectly configured displays 1662 * may never complete; this is a configuration error. 1663 */ 1664 drmmode->fe_frame = 0; 1665 drmmode->fe_tv_sec = 0; 1666 drmmode->fe_tv_usec = 0; 1667 1668 for (i = 0; i < config->num_crtc; i++) { 1669 if (!config->crtc[i]->enabled) 1670 continue; 1671 1672 drmmode->event_data = data; 1673 drmmode->flip_count++; 1674 drmmode_crtc = config->crtc[i]->driver_private; 1675 1676 flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec)); 1677 if (!flipcarrier) { 1678 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1679 "flip queue: carrier alloc failed.\n"); 1680 goto error_undo; 1681 } 1682 1683 /* Only the reference crtc will finally deliver its page flip 1684 * completion event. All other crtc's events will be discarded. 1685 */ 1686 flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id); 1687 flipcarrier->drmmode = drmmode; 1688 1689 if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 1690 drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) { 1691 xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1692 "flip queue failed: %s\n", strerror(errno)); 1693 free(flipcarrier); 1694 goto error_undo; 1695 } 1696 } 1697 1698 drmmode->old_fb_id = old_fb_id; 1699 return TRUE; 1700 1701error_undo: 1702 drmModeRmFB(drmmode->fd, drmmode->fb_id); 1703 drmmode->fb_id = old_fb_id; 1704 1705error_out: 1706 xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 1707 strerror(errno)); 1708 return FALSE; 1709} 1710 1711#endif 1712