drmmode_display.c revision 53ba5c8b
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 <sys/types.h> 33#include <sys/stat.h> 34#include <fcntl.h> 35#include <unistd.h> 36#include <errno.h> 37 38#include "xorg-server.h" 39#include "xorgVersion.h" 40 41#include "i830.h" 42#include "intel_bufmgr.h" 43#include "xf86drmMode.h" 44#include "X11/Xatom.h" 45 46typedef struct { 47 int fd; 48 uint32_t fb_id; 49 drmModeResPtr mode_res; 50 int cpp; 51} drmmode_rec, *drmmode_ptr; 52 53typedef struct { 54 drmmode_ptr drmmode; 55 drmModeCrtcPtr mode_crtc; 56 dri_bo *cursor; 57 dri_bo *rotate_bo; 58 uint32_t rotate_fb_id; 59} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr; 60 61typedef struct { 62 drmModePropertyPtr mode_prop; 63 uint64_t value; 64 int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */ 65 Atom *atoms; 66} drmmode_prop_rec, *drmmode_prop_ptr; 67 68struct fixed_panel_lvds { 69 int hdisplay; 70 int vdisplay; 71}; 72typedef struct { 73 drmmode_ptr drmmode; 74 int output_id; 75 drmModeConnectorPtr mode_output; 76 drmModeEncoderPtr mode_encoder; 77 drmModePropertyBlobPtr edid_blob; 78 int num_props; 79 drmmode_prop_ptr props; 80 void *private_data; 81 int dpms_mode; 82 char *backlight_iface; 83 int backlight_active_level; 84 int backlight_max; 85} drmmode_output_private_rec, *drmmode_output_private_ptr; 86 87static void 88drmmode_output_dpms(xf86OutputPtr output, int mode); 89 90#define BACKLIGHT_CLASS "/sys/class/backlight" 91 92/* 93 * List of available kernel interfaces in priority order 94 */ 95static char *backlight_interfaces[] = { 96 "asus-laptop", 97 "eeepc", 98 "thinkpad_screen", 99 "acpi_video1", 100 "acpi_video0", 101 "fujitsu-laptop", 102 "sony", 103 "samsung", 104 NULL, 105}; 106/* 107 * Must be long enough for BACKLIGHT_CLASS + '/' + longest in above table + 108 * '/' + "max_backlight" 109 */ 110#define BACKLIGHT_PATH_LEN 80 111/* Enough for 10 digits of backlight + '\n' + '\0' */ 112#define BACKLIGHT_VALUE_LEN 12 113 114static void 115drmmode_backlight_set(xf86OutputPtr output, int level) 116{ 117 drmmode_output_private_ptr drmmode_output = output->driver_private; 118 char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; 119 int fd, len, ret; 120 121 if (level > drmmode_output->backlight_max) 122 level = drmmode_output->backlight_max; 123 if (! drmmode_output->backlight_iface || level < 0) 124 return; 125 126 len = snprintf(val, BACKLIGHT_VALUE_LEN, "%d\n", level); 127 sprintf(path, "%s/%s/brightness", 128 BACKLIGHT_CLASS, drmmode_output->backlight_iface); 129 fd = open(path, O_RDWR); 130 if (fd == -1) { 131 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s for backlight " 132 "control: %s\n", path, strerror(errno)); 133 return; 134 } 135 136 ret = write(fd, val, len); 137 if (ret == -1) { 138 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "write to %s for backlight " 139 "control failed: %s\n", path, strerror(errno)); 140 } 141 142 close(fd); 143} 144 145static int 146drmmode_backlight_get(xf86OutputPtr output) 147{ 148 drmmode_output_private_ptr drmmode_output = output->driver_private; 149 char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; 150 int fd, level; 151 152 if (! drmmode_output->backlight_iface) 153 return -1; 154 155 sprintf(path, "%s/%s/actual_brightness", 156 BACKLIGHT_CLASS, drmmode_output->backlight_iface); 157 fd = open(path, O_RDONLY); 158 if (fd == -1) { 159 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s " 160 "for backlight control: %s\n", path, strerror(errno)); 161 return -1; 162 } 163 164 memset(val, 0, sizeof(val)); 165 if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) { 166 close(fd); 167 return -1; 168 } 169 170 close(fd); 171 172 level = atoi(val); 173 if (level > drmmode_output->backlight_max) 174 level = drmmode_output->backlight_max; 175 if (level < 0) 176 level = -1; 177 return level; 178} 179 180static int 181drmmode_backlight_get_max(xf86OutputPtr output) 182{ 183 drmmode_output_private_ptr drmmode_output = output->driver_private; 184 char path[BACKLIGHT_PATH_LEN], val[BACKLIGHT_VALUE_LEN]; 185 int fd, max = 0; 186 187 sprintf(path, "%s/%s/max_brightness", 188 BACKLIGHT_CLASS, drmmode_output->backlight_iface); 189 fd = open(path, O_RDONLY); 190 if (fd == -1) { 191 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, "failed to open %s " 192 "for backlight control: %s\n", path, strerror(errno)); 193 return 0; 194 } 195 196 memset(val, 0, sizeof(val)); 197 if (read(fd, val, BACKLIGHT_VALUE_LEN) == -1) { 198 close(fd); 199 return -1; 200 } 201 202 close(fd); 203 204 max = atoi(val); 205 if (max <= 0) 206 max = -1; 207 return max; 208} 209 210static void 211drmmode_backlight_init(xf86OutputPtr output) 212{ 213 drmmode_output_private_ptr drmmode_output = output->driver_private; 214 char path[BACKLIGHT_PATH_LEN]; 215 struct stat buf; 216 int i; 217 218 for (i = 0; backlight_interfaces[i] != NULL; i++) { 219 sprintf(path, "%s/%s", BACKLIGHT_CLASS, backlight_interfaces[i]); 220 if (!stat(path, &buf)) { 221 drmmode_output->backlight_iface = backlight_interfaces[i]; 222 xf86DrvMsg(output->scrn->scrnIndex, X_INFO, 223 "found backlight control interface %s\n", path); 224 drmmode_output->backlight_max = drmmode_backlight_get_max(output); 225 drmmode_output->backlight_active_level = drmmode_backlight_get(output); 226 return; 227 } 228 } 229 drmmode_output->backlight_iface = NULL; 230} 231 232 233static void 234drmmode_ConvertFromKMode(ScrnInfoPtr scrn, 235 drmModeModeInfoPtr kmode, 236 DisplayModePtr mode) 237{ 238 memset(mode, 0, sizeof(DisplayModeRec)); 239 mode->status = MODE_OK; 240 241 mode->Clock = kmode->clock; 242 243 mode->HDisplay = kmode->hdisplay; 244 mode->HSyncStart = kmode->hsync_start; 245 mode->HSyncEnd = kmode->hsync_end; 246 mode->HTotal = kmode->htotal; 247 mode->HSkew = kmode->hskew; 248 249 mode->VDisplay = kmode->vdisplay; 250 mode->VSyncStart = kmode->vsync_start; 251 mode->VSyncEnd = kmode->vsync_end; 252 mode->VTotal = kmode->vtotal; 253 mode->VScan = kmode->vscan; 254 255 mode->Flags = kmode->flags; //& FLAG_BITS; 256 mode->name = strdup(kmode->name); 257 258 if (kmode->type & DRM_MODE_TYPE_DRIVER) 259 mode->type = M_T_DRIVER; 260 if (kmode->type & DRM_MODE_TYPE_PREFERRED) 261 mode->type |= M_T_PREFERRED; 262 xf86SetModeCrtc (mode, scrn->adjustFlags); 263} 264 265static void 266drmmode_ConvertToKMode(ScrnInfoPtr scrn, 267 drmModeModeInfoPtr kmode, 268 DisplayModePtr mode) 269{ 270 memset(kmode, 0, sizeof(*kmode)); 271 272 kmode->clock = mode->Clock; 273 kmode->hdisplay = mode->HDisplay; 274 kmode->hsync_start = mode->HSyncStart; 275 kmode->hsync_end = mode->HSyncEnd; 276 kmode->htotal = mode->HTotal; 277 kmode->hskew = mode->HSkew; 278 279 kmode->vdisplay = mode->VDisplay; 280 kmode->vsync_start = mode->VSyncStart; 281 kmode->vsync_end = mode->VSyncEnd; 282 kmode->vtotal = mode->VTotal; 283 kmode->vscan = mode->VScan; 284 285 kmode->flags = mode->Flags; //& FLAG_BITS; 286 if (mode->name) 287 strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 288 kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 289 290} 291 292static void 293drmmode_crtc_dpms(xf86CrtcPtr drmmode_crtc, int mode) 294{ 295 296} 297 298static Bool 299drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 300 Rotation rotation, int x, int y) 301{ 302 ScrnInfoPtr pScrn = crtc->scrn; 303 I830Ptr pI830 = I830PTR(pScrn); 304 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 305 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 306 drmmode_ptr drmmode = drmmode_crtc->drmmode; 307 int saved_x, saved_y; 308 Rotation saved_rotation; 309 DisplayModeRec saved_mode; 310 uint32_t *output_ids; 311 int output_count = 0; 312 int ret = TRUE; 313 int i; 314 int fb_id; 315 drmModeModeInfo kmode; 316 unsigned int pitch = pScrn->displayWidth * pI830->cpp; 317 318 if (drmmode->fb_id == 0) { 319 ret = drmModeAddFB(drmmode->fd, 320 pScrn->virtualX, pScrn->virtualY, 321 pScrn->depth, pScrn->bitsPerPixel, 322 pitch, pI830->front_buffer->bo->handle, 323 &drmmode->fb_id); 324 if (ret < 0) { 325 ErrorF("failed to add fb\n"); 326 return FALSE; 327 } 328 } 329 330 saved_mode = crtc->mode; 331 saved_x = crtc->x; 332 saved_y = crtc->y; 333 saved_rotation = crtc->rotation; 334 335 crtc->mode = *mode; 336 crtc->x = x; 337 crtc->y = y; 338 crtc->rotation = rotation; 339 340 output_ids = xcalloc(sizeof(uint32_t), xf86_config->num_output); 341 if (!output_ids) { 342 ret = FALSE; 343 goto done; 344 } 345 346 for (i = 0; i < xf86_config->num_output; i++) { 347 xf86OutputPtr output = xf86_config->output[i]; 348 drmmode_output_private_ptr drmmode_output; 349 350 if (output->crtc != crtc) 351 continue; 352 353 drmmode_output = output->driver_private; 354 output_ids[output_count] = 355 drmmode_output->mode_output->connector_id; 356 output_count++; 357 } 358 359#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,5,99,0,0) 360 if (!xf86CrtcRotate(crtc, mode, rotation)) 361 goto done; 362#else 363 if (!xf86CrtcRotate(crtc)) 364 goto done; 365#endif 366 367#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0) 368 crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 369 crtc->gamma_blue, crtc->gamma_size); 370#endif 371 372 drmmode_ConvertToKMode(crtc->scrn, &kmode, mode); 373 374 375 fb_id = drmmode->fb_id; 376 if (drmmode_crtc->rotate_fb_id) { 377 fb_id = drmmode_crtc->rotate_fb_id; 378 x = 0; 379 y = 0; 380 } 381 ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 382 fb_id, x, y, output_ids, output_count, &kmode); 383 if (ret) 384 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 385 "failed to set mode: %s", strerror(-ret)); 386 else 387 ret = TRUE; 388 389 /* Turn on any outputs on this crtc that may have been disabled */ 390 for (i = 0; i < xf86_config->num_output; i++) { 391 xf86OutputPtr output = xf86_config->output[i]; 392 393 if (output->crtc != crtc) 394 continue; 395 396 drmmode_output_dpms(output, DPMSModeOn); 397 } 398 399 i830_set_max_gtt_map_size(pScrn); 400 401 if (pScrn->pScreen) 402 xf86_reload_cursors(pScrn->pScreen); 403done: 404 if (!ret) { 405 crtc->x = saved_x; 406 crtc->y = saved_y; 407 crtc->rotation = saved_rotation; 408 crtc->mode = saved_mode; 409 } 410 return ret; 411} 412 413static void 414drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg) 415{ 416 417} 418 419static void 420drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 421{ 422 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 423 drmmode_ptr drmmode = drmmode_crtc->drmmode; 424 425 drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y); 426} 427 428static void 429drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image) 430{ 431 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 432 int ret; 433 434 /* cursor should be mapped already */ 435 ret = dri_bo_subdata(drmmode_crtc->cursor, 0, 64*64*4, image); 436 if (ret) 437 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 438 "failed to set cursor: %s", strerror(-ret)); 439 440 return; 441} 442 443 444static void 445drmmode_hide_cursor (xf86CrtcPtr crtc) 446{ 447 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 448 drmmode_ptr drmmode = drmmode_crtc->drmmode; 449 450 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 451 0, 64, 64); 452} 453 454static void 455drmmode_show_cursor (xf86CrtcPtr crtc) 456{ 457 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 458 drmmode_ptr drmmode = drmmode_crtc->drmmode; 459 460 drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 461 drmmode_crtc->cursor->handle, 64, 64); 462} 463 464static void * 465drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 466{ 467 ScrnInfoPtr pScrn = crtc->scrn; 468 I830Ptr pI830 = I830PTR(pScrn); 469 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 470 drmmode_ptr drmmode = drmmode_crtc->drmmode; 471 int size, ret; 472 unsigned long rotate_pitch; 473 474 width = i830_pad_drawable_width(width, drmmode->cpp); 475 rotate_pitch = width * drmmode->cpp; 476 size = rotate_pitch * height; 477 478 drmmode_crtc->rotate_bo = 479 drm_intel_bo_alloc(pI830->bufmgr, "rotate", size, 4096); 480 481 if (!drmmode_crtc->rotate_bo) { 482 xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 483 "Couldn't allocate shadow memory for rotated CRTC\n"); 484 return NULL; 485 } 486 487 ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth, 488 crtc->scrn->bitsPerPixel, rotate_pitch, 489 drmmode_crtc->rotate_bo->handle, 490 &drmmode_crtc->rotate_fb_id); 491 if (ret) { 492 ErrorF("failed to add rotate fb\n"); 493 drm_intel_bo_unreference(drmmode_crtc->rotate_bo); 494 return NULL; 495 } 496 497 return drmmode_crtc->rotate_bo; 498} 499 500static PixmapPtr 501drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 502{ 503 ScrnInfoPtr pScrn = crtc->scrn; 504 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 505 drmmode_ptr drmmode = drmmode_crtc->drmmode; 506 unsigned long rotate_pitch; 507 PixmapPtr rotate_pixmap; 508 509 if (!data) { 510 data = drmmode_crtc_shadow_allocate (crtc, width, height); 511 if (!data) { 512 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 513 "Couldn't allocate shadow pixmap for rotated CRTC\n"); 514 return NULL; 515 } 516 } 517 518 rotate_pitch = 519 i830_pad_drawable_width(width, drmmode->cpp) * drmmode->cpp; 520 rotate_pixmap = GetScratchPixmapHeader(pScrn->pScreen, 521 width, height, 522 pScrn->depth, 523 pScrn->bitsPerPixel, 524 rotate_pitch, 525 NULL); 526 527 if (rotate_pixmap == NULL) { 528 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 529 "Couldn't allocate shadow pixmap for rotated CRTC\n"); 530 return NULL; 531 } 532 533 if (drmmode_crtc->rotate_bo) 534 i830_set_pixmap_bo(rotate_pixmap, drmmode_crtc->rotate_bo); 535 536 return rotate_pixmap; 537} 538 539static void 540drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 541{ 542 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 543 drmmode_ptr drmmode = drmmode_crtc->drmmode; 544 545 if (rotate_pixmap) { 546 i830_set_pixmap_bo(rotate_pixmap, NULL); 547 FreeScratchPixmapHeader(rotate_pixmap); 548 } 549 550 551 if (data) { 552 /* Be sure to sync acceleration before the memory gets 553 * unbound. */ 554 drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id); 555 drmmode_crtc->rotate_fb_id = 0; 556 dri_bo_unreference(drmmode_crtc->rotate_bo); 557 drmmode_crtc->rotate_bo = NULL; 558 } 559} 560 561static void 562drmmode_crtc_gamma_set(xf86CrtcPtr crtc, 563 CARD16 *red, CARD16 *green, CARD16 *blue, int size) 564{ 565 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 566 drmmode_ptr drmmode = drmmode_crtc->drmmode; 567 568 drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 569 size, red, green, blue); 570} 571 572static const xf86CrtcFuncsRec drmmode_crtc_funcs = { 573 .dpms = drmmode_crtc_dpms, 574 .set_mode_major = drmmode_set_mode_major, 575 .set_cursor_colors = drmmode_set_cursor_colors, 576 .set_cursor_position = drmmode_set_cursor_position, 577 .show_cursor = drmmode_show_cursor, 578 .hide_cursor = drmmode_hide_cursor, 579 .load_cursor_argb = drmmode_load_cursor_argb, 580 .shadow_create = drmmode_crtc_shadow_create, 581 .shadow_allocate = drmmode_crtc_shadow_allocate, 582 .shadow_destroy = drmmode_crtc_shadow_destroy, 583 .gamma_set = drmmode_crtc_gamma_set, 584 .destroy = NULL, /* XXX */ 585}; 586 587 588static void 589drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) 590{ 591 xf86CrtcPtr crtc; 592 drmmode_crtc_private_ptr drmmode_crtc; 593 594 crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs); 595 if (crtc == NULL) 596 return; 597 598 drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1); 599 drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, 600 drmmode->mode_res->crtcs[num]); 601 drmmode_crtc->drmmode = drmmode; 602 crtc->driver_private = drmmode_crtc; 603 604 return; 605} 606 607void 608drmmode_crtc_set_cursor_bo(xf86CrtcPtr crtc, dri_bo *cursor) 609{ 610 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 611 drmmode_crtc->cursor = cursor; 612} 613 614static xf86OutputStatus 615drmmode_output_detect(xf86OutputPtr output) 616{ 617 /* go to the hw and retrieve a new output struct */ 618 drmmode_output_private_ptr drmmode_output = output->driver_private; 619 drmmode_ptr drmmode = drmmode_output->drmmode; 620 xf86OutputStatus status; 621 drmModeFreeConnector(drmmode_output->mode_output); 622 623 drmmode_output->mode_output = 624 drmModeGetConnector(drmmode->fd, drmmode_output->output_id); 625 626 switch (drmmode_output->mode_output->connection) { 627 case DRM_MODE_CONNECTED: 628 status = XF86OutputStatusConnected; 629 break; 630 case DRM_MODE_DISCONNECTED: 631 status = XF86OutputStatusDisconnected; 632 break; 633 default: 634 case DRM_MODE_UNKNOWNCONNECTION: 635 status = XF86OutputStatusUnknown; 636 break; 637 } 638 return status; 639} 640 641static Bool 642drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 643{ 644 drmmode_output_private_ptr drmmode_output = output->driver_private; 645 drmModeConnectorPtr koutput = drmmode_output->mode_output; 646 struct fixed_panel_lvds *p_lvds = drmmode_output->private_data; 647 648 /* 649 * If the connector type is LVDS, we will use the panel limit to 650 * verfiy whether the mode is valid. 651 */ 652 if ((koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) && p_lvds) { 653 if (pModes->HDisplay > p_lvds->hdisplay || 654 pModes->VDisplay > p_lvds->vdisplay) 655 return MODE_PANEL; 656 else 657 return MODE_OK; 658 } 659 return MODE_OK; 660} 661 662static void fill_detailed_lvds_block(struct detailed_monitor_section *det_mon, 663 DisplayModePtr mode) 664{ 665 struct detailed_timings *timing = &det_mon->section.d_timings; 666 667 det_mon->type = DT; 668 timing->clock = mode->Clock * 1000; 669 timing->h_active = mode->HDisplay; 670 timing->h_blanking = mode->HTotal - mode->HDisplay; 671 timing->v_active = mode->VDisplay; 672 timing->v_blanking = mode->VTotal - mode->VDisplay; 673 timing->h_sync_off = mode->HSyncStart - mode->HDisplay; 674 timing->h_sync_width = mode->HSyncEnd - mode->HSyncStart; 675 timing->v_sync_off = mode->VSyncStart - mode->VDisplay; 676 timing->v_sync_width = mode->VSyncEnd - mode->VSyncStart; 677 678 if (mode->Flags & V_PVSYNC) 679 timing->misc |= 0x02; 680 681 if (mode->Flags & V_PHSYNC) 682 timing->misc |= 0x01; 683} 684 685static int drmmode_output_lvds_edid(xf86OutputPtr output, 686 struct fixed_panel_lvds *p_lvds) 687{ 688 drmmode_output_private_ptr drmmode_output = output->driver_private; 689 drmModeConnectorPtr koutput = drmmode_output->mode_output; 690 int i, j; 691 DisplayModePtr pmode; 692 xf86MonPtr edid_mon; 693 drmModeModeInfo *mode_ptr; 694 struct detailed_monitor_section *det_mon; 695 696 if (output->MonInfo) { 697 /* 698 * If there exists the EDID, we will either find a DS_RANGES 699 * or replace a DS_VENDOR block, smashing it into a DS_RANGES 700 * block with opern refresh to match all the default modes. 701 */ 702 int edid_det_block_num; 703 edid_mon = output->MonInfo; 704 edid_mon->features.msc |= 0x01; 705 j = -1; 706 edid_det_block_num = sizeof(edid_mon->det_mon) / 707 sizeof(edid_mon->det_mon[0]); 708 for (i = 0; i < edid_det_block_num; i++) { 709 if (edid_mon->det_mon[i].type >= DS_VENDOR && j == -1) 710 j = i; 711 if (edid_mon->det_mon[i].type == DS_RANGES) { 712 j = i; 713 break; 714 } 715 } 716 if (j != -1) { 717 struct monitor_ranges *ranges = 718 &edid_mon->det_mon[j].section.ranges; 719 edid_mon->det_mon[j].type = DS_RANGES; 720 ranges->min_v = 0; 721 ranges->max_v = 200; 722 ranges->min_h = 0; 723 ranges->max_h = 200; 724 } 725 return 0; 726 } 727 /* 728 * If there is no EDID, we will construct a bogus EDID for LVDS output 729 * device. This is similar to what we have done in i830_lvds.c 730 */ 731 edid_mon = NULL; 732 edid_mon = xcalloc(1, sizeof(xf86Monitor)); 733 if (!edid_mon) { 734 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 735 "Can't allocate memory for edid_mon.\n"); 736 return 0; 737 } 738 /* Find the fixed panel mode. 739 * In theory when there is no EDID, KMS kernel will return only one 740 * mode. And this can be regarded as fixed lvds panel mode. 741 * But it will be better to traverse the mode list to get the fixed 742 * lvds panel mode again as we don't know whether some new modes 743 * are added for the LVDS output device 744 */ 745 j = 0; 746 for (i = 0; i < koutput->count_modes; i++) { 747 mode_ptr = &koutput->modes[i]; 748 if ((mode_ptr->hdisplay == p_lvds->hdisplay) && 749 (mode_ptr->vdisplay == p_lvds->vdisplay)) { 750 /* find the fixed panel mode */ 751 j = i; 752 break; 753 } 754 } 755 pmode = xnfalloc(sizeof(DisplayModeRec)); 756 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[j], pmode); 757 /*support DPM, instead of DPMS*/ 758 edid_mon->features.dpms |= 0x1; 759 /*defaultly support RGB color display*/ 760 edid_mon->features.display_type |= 0x1; 761 /*defaultly display support continuous-freqencey*/ 762 edid_mon->features.msc |= 0x1; 763 /*defaultly the EDID version is 1.4 */ 764 edid_mon->ver.version = 1; 765 edid_mon->ver.revision = 4; 766 det_mon = edid_mon->det_mon; 767 if (pmode) { 768 /* now we construct new EDID monitor, 769 * so filled one detailed timing block 770 */ 771 fill_detailed_lvds_block(det_mon, pmode); 772 /* the filed timing block should be set preferred*/ 773 edid_mon->features.msc |= 0x2; 774 det_mon = det_mon + 1; 775 } 776 /* Set wide sync ranges so we get all modes 777 * handed to valid_mode for checking 778 */ 779 det_mon->type = DS_RANGES; 780 det_mon->section.ranges.min_v = 0; 781 det_mon->section.ranges.max_v = 200; 782 det_mon->section.ranges.min_h = 0; 783 det_mon->section.ranges.max_h = 200; 784 output->MonInfo = edid_mon; 785 return 0; 786} 787 788static DisplayModePtr 789drmmode_output_get_modes(xf86OutputPtr output) 790{ 791 drmmode_output_private_ptr drmmode_output = output->driver_private; 792 drmModeConnectorPtr koutput = drmmode_output->mode_output; 793 drmmode_ptr drmmode = drmmode_output->drmmode; 794 int i; 795 DisplayModePtr Modes = NULL, Mode; 796 drmModePropertyPtr props; 797 struct fixed_panel_lvds *p_lvds; 798 drmModeModeInfo *mode_ptr; 799 800 /* look for an EDID property */ 801 for (i = 0; i < koutput->count_props; i++) { 802 props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 803 if (!props) 804 continue; 805 if (!(props->flags & DRM_MODE_PROP_BLOB)) { 806 drmModeFreeProperty(props); 807 continue; 808 } 809 810 if (!strcmp(props->name, "EDID")) { 811 drmModeFreePropertyBlob(drmmode_output->edid_blob); 812 drmmode_output->edid_blob = 813 drmModeGetPropertyBlob(drmmode->fd, 814 koutput->prop_values[i]); 815 } 816 drmModeFreeProperty(props); 817 } 818 819 if (drmmode_output->edid_blob) 820 xf86OutputSetEDID(output, 821 xf86InterpretEDID(output->scrn->scrnIndex, 822 drmmode_output->edid_blob->data)); 823 else 824 xf86OutputSetEDID(output, 825 xf86InterpretEDID(output->scrn->scrnIndex, 826 NULL)); 827 828 /* modes should already be available */ 829 for (i = 0; i < koutput->count_modes; i++) { 830 Mode = xnfalloc(sizeof(DisplayModeRec)); 831 832 drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], 833 Mode); 834 Modes = xf86ModesAdd(Modes, Mode); 835 836 } 837 p_lvds = drmmode_output->private_data; 838 /* 839 * If the connector type is LVDS, we will traverse the kernel mode to 840 * get the panel limit. 841 * If it is incorrect, please fix me. 842 */ 843 if ((koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) && p_lvds) { 844 p_lvds->hdisplay = 0; 845 p_lvds->vdisplay = 0; 846 for (i = 0; i < koutput->count_modes; i++) { 847 mode_ptr = &koutput->modes[i]; 848 if ((mode_ptr->hdisplay >= p_lvds->hdisplay) && 849 (mode_ptr->vdisplay >= p_lvds->vdisplay)) { 850 p_lvds->hdisplay = mode_ptr->hdisplay; 851 p_lvds->vdisplay = mode_ptr->vdisplay; 852 } 853 } 854 if (!p_lvds->hdisplay || !p_lvds->vdisplay) 855 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 856 "Incorrect KMS mode.\n"); 857 drmmode_output_lvds_edid(output, p_lvds); 858 } 859 return Modes; 860} 861 862static void 863drmmode_output_destroy(xf86OutputPtr output) 864{ 865 drmmode_output_private_ptr drmmode_output = output->driver_private; 866 int i; 867 868 if (drmmode_output->edid_blob) 869 drmModeFreePropertyBlob(drmmode_output->edid_blob); 870 for (i = 0; i < drmmode_output->num_props; i++) { 871 drmModeFreeProperty(drmmode_output->props[i].mode_prop); 872 xfree(drmmode_output->props[i].atoms); 873 } 874 xfree(drmmode_output->props); 875 drmModeFreeConnector(drmmode_output->mode_output); 876 if (drmmode_output->private_data) { 877 xfree(drmmode_output->private_data); 878 drmmode_output->private_data = NULL; 879 } 880 if (drmmode_output->backlight_iface) 881 drmmode_backlight_set(output, drmmode_output->backlight_active_level); 882 xfree(drmmode_output); 883 output->driver_private = NULL; 884} 885 886static void 887drmmode_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode) 888{ 889 drmmode_output_private_ptr drmmode_output = output->driver_private; 890 891 if (!drmmode_output->backlight_iface) 892 return; 893 894 if (mode == DPMSModeOn) { 895 /* If we're going from off->on we may need to turn on the backlight. */ 896 if (oldmode != DPMSModeOn) 897 drmmode_backlight_set(output, drmmode_output->backlight_active_level); 898 } else { 899 /* Only save the current backlight value if we're going from on to off. */ 900 if (oldmode == DPMSModeOn) 901 drmmode_output->backlight_active_level = drmmode_backlight_get(output); 902 drmmode_backlight_set(output, 0); 903 } 904} 905 906static void 907drmmode_output_dpms(xf86OutputPtr output, int mode) 908{ 909 drmmode_output_private_ptr drmmode_output = output->driver_private; 910 drmModeConnectorPtr koutput = drmmode_output->mode_output; 911 drmmode_ptr drmmode = drmmode_output->drmmode; 912 int i; 913 drmModePropertyPtr props; 914 915 for (i = 0; i < koutput->count_props; i++) { 916 props = drmModeGetProperty(drmmode->fd, koutput->props[i]); 917 if (!props) 918 continue; 919 920 if (!strcmp(props->name, "DPMS")) { 921 drmModeConnectorSetProperty(drmmode->fd, 922 drmmode_output->output_id, 923 props->prop_id, 924 mode); 925 drmmode_output_dpms_backlight(output, 926 drmmode_output->dpms_mode, 927 mode); 928 drmmode_output->dpms_mode = mode; 929 drmModeFreeProperty(props); 930 return; 931 } 932 drmModeFreeProperty(props); 933 } 934} 935 936int 937drmmode_output_dpms_status(xf86OutputPtr output) 938{ 939 drmmode_output_private_ptr drmmode_output = output->driver_private; 940 941 return drmmode_output->dpms_mode; 942} 943 944static Bool 945drmmode_property_ignore(drmModePropertyPtr prop) 946{ 947 if (!prop) 948 return TRUE; 949 /* ignore blob prop */ 950 if (prop->flags & DRM_MODE_PROP_BLOB) 951 return TRUE; 952 /* ignore standard property */ 953 if (!strcmp(prop->name, "EDID") || 954 !strcmp(prop->name, "DPMS")) 955 return TRUE; 956 957 return FALSE; 958} 959 960#define BACKLIGHT_NAME "Backlight" 961#define BACKLIGHT_DEPRECATED_NAME "BACKLIGHT" 962static Atom backlight_atom, backlight_deprecated_atom; 963 964static void 965drmmode_output_create_resources(xf86OutputPtr output) 966{ 967 drmmode_output_private_ptr drmmode_output = output->driver_private; 968 drmModeConnectorPtr mode_output = drmmode_output->mode_output; 969 drmmode_ptr drmmode = drmmode_output->drmmode; 970 drmModePropertyPtr drmmode_prop; 971 int i, j, err; 972 973 drmmode_output->props = xcalloc(mode_output->count_props, sizeof(drmmode_prop_rec)); 974 if (!drmmode_output->props) 975 return; 976 977 drmmode_output->num_props = 0; 978 for (i = 0, j = 0; i < mode_output->count_props; i++) { 979 drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]); 980 if (drmmode_property_ignore(drmmode_prop)) { 981 drmModeFreeProperty(drmmode_prop); 982 continue; 983 } 984 drmmode_output->props[j].mode_prop = drmmode_prop; 985 drmmode_output->props[j].value = mode_output->prop_values[i]; 986 drmmode_output->num_props++; 987 j++; 988 } 989 990 for (i = 0; i < drmmode_output->num_props; i++) { 991 drmmode_prop_ptr p = &drmmode_output->props[i]; 992 drmmode_prop = p->mode_prop; 993 994 if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 995 INT32 range[2]; 996 997 p->num_atoms = 1; 998 p->atoms = xcalloc(p->num_atoms, sizeof(Atom)); 999 if (!p->atoms) 1000 continue; 1001 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1002 range[0] = drmmode_prop->values[0]; 1003 range[1] = drmmode_prop->values[1]; 1004 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1005 FALSE, TRUE, 1006 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1007 2, range); 1008 if (err != 0) { 1009 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1010 "RRConfigureOutputProperty error, %d\n", err); 1011 } 1012 err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1013 XA_INTEGER, 32, PropModeReplace, 1, &p->value, FALSE, TRUE); 1014 if (err != 0) { 1015 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1016 "RRChangeOutputProperty error, %d\n", err); 1017 } 1018 } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1019 p->num_atoms = drmmode_prop->count_enums + 1; 1020 p->atoms = xcalloc(p->num_atoms, sizeof(Atom)); 1021 if (!p->atoms) 1022 continue; 1023 p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1024 for (j = 1; j <= drmmode_prop->count_enums; j++) { 1025 struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 1026 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 1027 } 1028 err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1029 FALSE, FALSE, 1030 drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1031 p->num_atoms - 1, (INT32 *)&p->atoms[1]); 1032 if (err != 0) { 1033 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1034 "RRConfigureOutputProperty error, %d\n", err); 1035 } 1036 for (j = 0; j < drmmode_prop->count_enums; j++) 1037 if (drmmode_prop->enums[j].value == p->value) 1038 break; 1039 /* there's always a matching value */ 1040 err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1041 XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE); 1042 if (err != 0) { 1043 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1044 "RRChangeOutputProperty error, %d\n", err); 1045 } 1046 } 1047 } 1048 1049 if (drmmode_output->backlight_iface) { 1050 INT32 data, backlight_range[2]; 1051 /* Set up the backlight property, which takes effect immediately 1052 * and accepts values only within the backlight_range. */ 1053 backlight_atom = MakeAtom(BACKLIGHT_NAME, sizeof(BACKLIGHT_NAME) - 1, TRUE); 1054 backlight_deprecated_atom = MakeAtom(BACKLIGHT_DEPRECATED_NAME, 1055 sizeof(BACKLIGHT_DEPRECATED_NAME) - 1, TRUE); 1056 1057 backlight_range[0] = 0; 1058 backlight_range[1] = drmmode_output->backlight_max; 1059 err = RRConfigureOutputProperty(output->randr_output, backlight_atom, 1060 FALSE, TRUE, FALSE, 2, backlight_range); 1061 if (err != 0) { 1062 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1063 "RRConfigureOutputProperty error, %d\n", err); 1064 } 1065 err = RRConfigureOutputProperty(output->randr_output, backlight_deprecated_atom, 1066 FALSE, TRUE, FALSE, 2, backlight_range); 1067 if (err != 0) { 1068 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1069 "RRConfigureOutputProperty error, %d\n", err); 1070 } 1071 /* Set the current value of the backlight property */ 1072 data = drmmode_output->backlight_active_level; 1073 err = RRChangeOutputProperty(output->randr_output, backlight_atom, 1074 XA_INTEGER, 32, PropModeReplace, 1, &data, 1075 FALSE, TRUE); 1076 if (err != 0) { 1077 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1078 "RRChangeOutputProperty error, %d\n", err); 1079 } 1080 err = RRChangeOutputProperty(output->randr_output, backlight_deprecated_atom, 1081 XA_INTEGER, 32, PropModeReplace, 1, &data, 1082 FALSE, TRUE); 1083 if (err != 0) { 1084 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1085 "RRChangeOutputProperty error, %d\n", err); 1086 } 1087 } 1088} 1089 1090static Bool 1091drmmode_output_set_property(xf86OutputPtr output, Atom property, 1092 RRPropertyValuePtr value) 1093{ 1094 drmmode_output_private_ptr drmmode_output = output->driver_private; 1095 drmmode_ptr drmmode = drmmode_output->drmmode; 1096 int i; 1097 1098 if (property == backlight_atom || property == backlight_deprecated_atom) { 1099 INT32 val; 1100 1101 if (value->type != XA_INTEGER || value->format != 32 || 1102 value->size != 1) 1103 { 1104 return FALSE; 1105 } 1106 1107 val = *(INT32 *)value->data; 1108 if (val < 0 || val > drmmode_output->backlight_max) 1109 return FALSE; 1110 1111 if (drmmode_output->dpms_mode == DPMSModeOn) 1112 drmmode_backlight_set(output, val); 1113 drmmode_output->backlight_active_level = val; 1114 return TRUE; 1115 } 1116 1117 for (i = 0; i < drmmode_output->num_props; i++) { 1118 drmmode_prop_ptr p = &drmmode_output->props[i]; 1119 1120 if (p->atoms[0] != property) 1121 continue; 1122 1123 if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1124 uint32_t val; 1125 1126 if (value->type != XA_INTEGER || value->format != 32 || 1127 value->size != 1) 1128 return FALSE; 1129 val = *(uint32_t *)value->data; 1130 1131 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 1132 p->mode_prop->prop_id, (uint64_t)val); 1133 return TRUE; 1134 } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1135 Atom atom; 1136 const char *name; 1137 int j; 1138 1139 if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 1140 return FALSE; 1141 memcpy(&atom, value->data, 4); 1142 name = NameForAtom(atom); 1143 1144 /* search for matching name string, then set its value down */ 1145 for (j = 0; j < p->mode_prop->count_enums; j++) { 1146 if (!strcmp(p->mode_prop->enums[j].name, name)) { 1147 drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id, 1148 p->mode_prop->prop_id, p->mode_prop->enums[j].value); 1149 return TRUE; 1150 } 1151 } 1152 } 1153 } 1154 1155 return TRUE; 1156} 1157 1158static Bool 1159drmmode_output_get_property(xf86OutputPtr output, Atom property) 1160{ 1161 drmmode_output_private_ptr drmmode_output = output->driver_private; 1162 int err; 1163 1164 if (property == backlight_atom || property == backlight_deprecated_atom) { 1165 INT32 val; 1166 1167 if (! drmmode_output->backlight_iface) 1168 return FALSE; 1169 1170 val = drmmode_backlight_get(output); 1171 if (val < 0) 1172 return FALSE; 1173 err = RRChangeOutputProperty(output->randr_output, property, 1174 XA_INTEGER, 32, PropModeReplace, 1, &val, 1175 FALSE, TRUE); 1176 if (err != 0) { 1177 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1178 "RRChangeOutputProperty error, %d\n", err); 1179 return FALSE; 1180 } 1181 1182 return TRUE; 1183 } 1184 1185 return TRUE; 1186} 1187 1188static const xf86OutputFuncsRec drmmode_output_funcs = { 1189 .create_resources = drmmode_output_create_resources, 1190#ifdef RANDR_12_INTERFACE 1191 .set_property = drmmode_output_set_property, 1192 .get_property = drmmode_output_get_property, 1193#endif 1194 .dpms = drmmode_output_dpms, 1195#if 0 1196 1197 .save = drmmode_crt_save, 1198 .restore = drmmode_crt_restore, 1199 .mode_fixup = drmmode_crt_mode_fixup, 1200 .prepare = drmmode_output_prepare, 1201 .mode_set = drmmode_crt_mode_set, 1202 .commit = drmmode_output_commit, 1203#endif 1204 .detect = drmmode_output_detect, 1205 .mode_valid = drmmode_output_mode_valid, 1206 1207 .get_modes = drmmode_output_get_modes, 1208 .destroy = drmmode_output_destroy 1209}; 1210 1211static int subpixel_conv_table[7] = { 0, SubPixelUnknown, 1212 SubPixelHorizontalRGB, 1213 SubPixelHorizontalBGR, 1214 SubPixelVerticalRGB, 1215 SubPixelVerticalBGR, 1216 SubPixelNone }; 1217 1218static const char *output_names[] = { "None", 1219 "VGA", 1220 "DVI", 1221 "DVI", 1222 "DVI", 1223 "Composite", 1224 "TV", 1225 "LVDS", 1226 "CTV", 1227 "DIN", 1228 "DP", 1229 "HDMI", 1230 "HDMI", 1231}; 1232 1233 1234static void 1235drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num) 1236{ 1237 xf86OutputPtr output; 1238 drmModeConnectorPtr koutput; 1239 drmModeEncoderPtr kencoder; 1240 drmmode_output_private_ptr drmmode_output; 1241 char name[32]; 1242 1243 koutput = drmModeGetConnector(drmmode->fd, 1244 drmmode->mode_res->connectors[num]); 1245 if (!koutput) 1246 return; 1247 1248 kencoder = drmModeGetEncoder(drmmode->fd, koutput->encoders[0]); 1249 if (!kencoder) { 1250 drmModeFreeConnector(koutput); 1251 return; 1252 } 1253 1254 snprintf(name, 32, "%s%d", output_names[koutput->connector_type], 1255 koutput->connector_type_id); 1256 1257 output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name); 1258 if (!output) { 1259 drmModeFreeEncoder(kencoder); 1260 drmModeFreeConnector(koutput); 1261 return; 1262 } 1263 1264 drmmode_output = xcalloc(sizeof(drmmode_output_private_rec), 1); 1265 if (!drmmode_output) { 1266 xf86OutputDestroy(output); 1267 drmModeFreeConnector(koutput); 1268 drmModeFreeEncoder(kencoder); 1269 return; 1270 } 1271 /* 1272 * If the connector type of the output device is LVDS, we will 1273 * allocate the private_data to store the panel limit. 1274 * For example: hdisplay, vdisplay 1275 */ 1276 drmmode_output->private_data = NULL; 1277 if (koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) { 1278 drmmode_output->private_data = xcalloc( 1279 sizeof(struct fixed_panel_lvds), 1); 1280 if (!drmmode_output->private_data) 1281 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1282 "Can't allocate private memory for LVDS.\n"); 1283 } 1284 drmmode_output->output_id = drmmode->mode_res->connectors[num]; 1285 drmmode_output->mode_output = koutput; 1286 drmmode_output->mode_encoder = kencoder; 1287 drmmode_output->drmmode = drmmode; 1288 output->mm_width = koutput->mmWidth; 1289 output->mm_height = koutput->mmHeight; 1290 1291 output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 1292 output->driver_private = drmmode_output; 1293 1294 if (koutput->connector_type == DRM_MODE_CONNECTOR_LVDS) 1295 drmmode_backlight_init(output); 1296 1297 output->possible_crtcs = kencoder->possible_crtcs; 1298 output->possible_clones = kencoder->possible_clones; 1299 return; 1300} 1301 1302static Bool 1303drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) 1304{ 1305 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1306 drmmode_crtc_private_ptr 1307 drmmode_crtc = xf86_config->crtc[0]->driver_private; 1308 drmmode_ptr drmmode = drmmode_crtc->drmmode; 1309 I830Ptr pI830 = I830PTR(scrn); 1310 i830_memory *old_front = NULL; 1311 Bool tiled, ret; 1312 ScreenPtr screen = screenInfo.screens[scrn->scrnIndex]; 1313 uint32_t old_fb_id; 1314 int i, pitch, old_width, old_height, old_pitch; 1315 1316 if (scrn->virtualX == width && scrn->virtualY == height) 1317 return TRUE; 1318 1319 pitch = i830_pad_drawable_width(width, pI830->cpp); 1320 tiled = i830_tiled_width(pI830, &pitch, pI830->cpp); 1321 xf86DrvMsg(scrn->scrnIndex, X_INFO, 1322 "Allocate new frame buffer %dx%d stride %d\n", 1323 width, height, pitch); 1324 1325 old_width = scrn->virtualX; 1326 old_height = scrn->virtualY; 1327 old_pitch = scrn->displayWidth; 1328 old_fb_id = drmmode->fb_id; 1329 old_front = pI830->front_buffer; 1330 1331 scrn->virtualX = width; 1332 scrn->virtualY = height; 1333 scrn->displayWidth = pitch; 1334 pI830->front_buffer = i830_allocate_framebuffer(scrn); 1335 if (!pI830->front_buffer) 1336 goto fail; 1337 1338 ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth, 1339 scrn->bitsPerPixel, pitch * pI830->cpp, 1340 pI830->front_buffer->bo->handle, 1341 &drmmode->fb_id); 1342 if (ret) 1343 goto fail; 1344 1345 i830_set_pixmap_bo(screen->GetScreenPixmap(screen), pI830->front_buffer->bo); 1346 1347 screen->ModifyPixmapHeader(screen->GetScreenPixmap(screen), 1348 width, height, -1, -1, pitch * pI830->cpp, NULL); 1349 1350 for (i = 0; i < xf86_config->num_crtc; i++) { 1351 xf86CrtcPtr crtc = xf86_config->crtc[i]; 1352 1353 if (!crtc->enabled) 1354 continue; 1355 1356 drmmode_set_mode_major(crtc, &crtc->mode, 1357 crtc->rotation, crtc->x, crtc->y); 1358 } 1359 1360 if (old_fb_id) 1361 drmModeRmFB(drmmode->fd, old_fb_id); 1362 if (old_front) 1363 i830_free_memory(scrn, old_front); 1364 1365 return TRUE; 1366 1367 fail: 1368 if (pI830->front_buffer) 1369 i830_free_memory(scrn, pI830->front_buffer); 1370 pI830->front_buffer = old_front; 1371 scrn->virtualX = old_width; 1372 scrn->virtualY = old_height; 1373 scrn->displayWidth = old_pitch; 1374 drmmode->fb_id = old_fb_id; 1375 1376 return FALSE; 1377} 1378 1379static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { 1380 drmmode_xf86crtc_resize 1381}; 1382 1383Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp) 1384{ 1385 xf86CrtcConfigPtr xf86_config; 1386 drmmode_ptr drmmode; 1387 int i; 1388 1389 drmmode = xnfalloc(sizeof *drmmode); 1390 drmmode->fd = fd; 1391 drmmode->fb_id = 0; 1392 1393 xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs); 1394 xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1395 1396 drmmode->cpp = cpp; 1397 drmmode->mode_res = drmModeGetResources(drmmode->fd); 1398 if (!drmmode->mode_res) { 1399 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, 1400 "failed to get resources: %s\n", strerror(errno)); 1401 return FALSE; 1402 } 1403 1404 xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, 1405 drmmode->mode_res->max_height); 1406 for (i = 0; i < drmmode->mode_res->count_crtcs; i++) 1407 drmmode_crtc_init(pScrn, drmmode, i); 1408 1409 for (i = 0; i < drmmode->mode_res->count_connectors; i++) 1410 drmmode_output_init(pScrn, drmmode, i); 1411 1412 xf86InitialConfiguration(pScrn, TRUE); 1413 1414 return TRUE; 1415} 1416 1417int 1418drmmode_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc) 1419{ 1420 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; 1421 1422 return drm_intel_get_pipe_from_crtc_id (bufmgr, drmmode_crtc->mode_crtc->crtc_id); 1423} 1424 1425void drmmode_closefb(ScrnInfoPtr scrn) 1426{ 1427 xf86CrtcConfigPtr xf86_config; 1428 drmmode_crtc_private_ptr drmmode_crtc; 1429 drmmode_ptr drmmode; 1430 1431 xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1432 1433 drmmode_crtc = xf86_config->crtc[0]->driver_private; 1434 drmmode = drmmode_crtc->drmmode; 1435 1436 drmModeRmFB(drmmode->fd, drmmode->fb_id); 1437 drmmode->fb_id = 0; 1438} 1439