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