1428d7b3dSmrg/* 2428d7b3dSmrg * Copyright © 2007 Red Hat, Inc. 3428d7b3dSmrg * 4428d7b3dSmrg * Permission is hereby granted, free of charge, to any person obtaining a 5428d7b3dSmrg * copy of this software and associated documentation files (the "Software"), 6428d7b3dSmrg * to deal in the Software without restriction, including without limitation 7428d7b3dSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8428d7b3dSmrg * and/or sell copies of the Software, and to permit persons to whom the 9428d7b3dSmrg * Software is furnished to do so, subject to the following conditions: 10428d7b3dSmrg * 11428d7b3dSmrg * The above copyright notice and this permission notice (including the next 12428d7b3dSmrg * paragraph) shall be included in all copies or substantial portions of the 13428d7b3dSmrg * Software. 14428d7b3dSmrg * 15428d7b3dSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16428d7b3dSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17428d7b3dSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18428d7b3dSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19428d7b3dSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20428d7b3dSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21428d7b3dSmrg * SOFTWARE. 22428d7b3dSmrg * 23428d7b3dSmrg * Authors: 24428d7b3dSmrg * Dave Airlie <airlied@redhat.com> 25428d7b3dSmrg * 26428d7b3dSmrg */ 27428d7b3dSmrg 28428d7b3dSmrg#ifdef HAVE_CONFIG_H 29428d7b3dSmrg#include "config.h" 30428d7b3dSmrg#endif 31428d7b3dSmrg 32428d7b3dSmrg#include <sys/types.h> 33428d7b3dSmrg#include <sys/stat.h> 34428d7b3dSmrg#include <sys/poll.h> 35428d7b3dSmrg#include <fcntl.h> 36428d7b3dSmrg#include <unistd.h> 37428d7b3dSmrg#include <errno.h> 38428d7b3dSmrg#include <sys/ioctl.h> 39428d7b3dSmrg 40428d7b3dSmrg#include "xorg-server.h" 41428d7b3dSmrg#include "xorgVersion.h" 42428d7b3dSmrg 43428d7b3dSmrg#include "intel.h" 44428d7b3dSmrg#include "intel_bufmgr.h" 45428d7b3dSmrg#include "intel_options.h" 46428d7b3dSmrg#include "backlight.h" 47428d7b3dSmrg#include "xf86drm.h" 48428d7b3dSmrg#include "xf86drmMode.h" 49428d7b3dSmrg#include "X11/Xatom.h" 50428d7b3dSmrg#if defined(HAVE_X11_EXTENSIONS_DPMSCONST_H) 51428d7b3dSmrg#include <X11/extensions/dpmsconst.h> 52428d7b3dSmrg#else 53428d7b3dSmrg#define DPMSModeOn 0 54428d7b3dSmrg#define DPMSModeOff 3 55428d7b3dSmrg#endif 56428d7b3dSmrg#include "xf86DDC.h" 57428d7b3dSmrg#include "fb.h" 58428d7b3dSmrg 59428d7b3dSmrg#if USE_UXA 60428d7b3dSmrg#include "intel_uxa.h" 61428d7b3dSmrg#endif 62428d7b3dSmrg 63428d7b3dSmrg#define KNOWN_MODE_FLAGS ((1<<14)-1) 64428d7b3dSmrg 65428d7b3dSmrgstruct intel_drm_queue { 66428d7b3dSmrg struct list list; 67428d7b3dSmrg xf86CrtcPtr crtc; 68428d7b3dSmrg uint32_t seq; 69428d7b3dSmrg void *data; 70428d7b3dSmrg ScrnInfoPtr scrn; 71428d7b3dSmrg intel_drm_handler_proc handler; 72428d7b3dSmrg intel_drm_abort_proc abort; 73428d7b3dSmrg}; 74428d7b3dSmrg 75428d7b3dSmrgstatic uint32_t intel_drm_seq; 76428d7b3dSmrgstatic struct list intel_drm_queue; 77428d7b3dSmrg 78428d7b3dSmrgstruct intel_mode { 79428d7b3dSmrg int fd; 80428d7b3dSmrg uint32_t fb_id; 81428d7b3dSmrg int cpp; 82428d7b3dSmrg 83428d7b3dSmrg drmEventContext event_context; 84428d7b3dSmrg int old_fb_id; 85428d7b3dSmrg int flip_count; 86428d7b3dSmrg uint64_t fe_msc; 87428d7b3dSmrg uint64_t fe_usec; 88428d7b3dSmrg 89428d7b3dSmrg struct list outputs; 90428d7b3dSmrg struct list crtcs; 91428d7b3dSmrg 92428d7b3dSmrg void *pageflip_data; 93428d7b3dSmrg intel_pageflip_handler_proc pageflip_handler; 94428d7b3dSmrg intel_pageflip_abort_proc pageflip_abort; 95428d7b3dSmrg 96428d7b3dSmrg Bool delete_dp_12_displays; 97428d7b3dSmrg}; 98428d7b3dSmrg 99428d7b3dSmrgstruct intel_pageflip { 100428d7b3dSmrg struct intel_mode *mode; 101428d7b3dSmrg Bool dispatch_me; 102428d7b3dSmrg}; 103428d7b3dSmrg 104428d7b3dSmrgstruct intel_crtc { 105428d7b3dSmrg struct intel_mode *mode; 106428d7b3dSmrg drmModeModeInfo kmode; 107428d7b3dSmrg drmModeCrtcPtr mode_crtc; 108428d7b3dSmrg int pipe; 109428d7b3dSmrg dri_bo *cursor; 110428d7b3dSmrg dri_bo *rotate_bo; 111428d7b3dSmrg uint32_t rotate_pitch; 112428d7b3dSmrg uint32_t rotate_fb_id; 113428d7b3dSmrg xf86CrtcPtr crtc; 114428d7b3dSmrg struct list link; 115428d7b3dSmrg PixmapPtr scanout_pixmap; 116428d7b3dSmrg uint32_t scanout_fb_id; 117428d7b3dSmrg int32_t vblank_offset; 118428d7b3dSmrg uint32_t msc_prev; 119428d7b3dSmrg uint64_t msc_high; 120428d7b3dSmrg}; 121428d7b3dSmrg 122428d7b3dSmrgstruct intel_property { 123428d7b3dSmrg drmModePropertyPtr mode_prop; 124428d7b3dSmrg uint64_t value; 125428d7b3dSmrg int num_atoms; /* if range prop, num_atoms == 1; if enum prop, num_atoms == num_enums + 1 */ 126428d7b3dSmrg Atom *atoms; 127428d7b3dSmrg}; 128428d7b3dSmrg 129428d7b3dSmrgstruct intel_output { 130428d7b3dSmrg struct intel_mode *mode; 131428d7b3dSmrg int output_id; 132428d7b3dSmrg drmModeConnectorPtr mode_output; 133428d7b3dSmrg drmModeEncoderPtr *mode_encoders; 134428d7b3dSmrg drmModePropertyBlobPtr edid_blob; 135428d7b3dSmrg int num_props; 136428d7b3dSmrg struct intel_property *props; 137428d7b3dSmrg void *private_data; 138428d7b3dSmrg 139428d7b3dSmrg Bool has_panel_limits; 140428d7b3dSmrg int panel_hdisplay; 141428d7b3dSmrg int panel_vdisplay; 142428d7b3dSmrg 143428d7b3dSmrg int dpms_mode; 144428d7b3dSmrg struct backlight backlight; 145428d7b3dSmrg int backlight_active_level; 146428d7b3dSmrg xf86OutputPtr output; 147428d7b3dSmrg struct list link; 148428d7b3dSmrg int enc_mask; 149428d7b3dSmrg int enc_clone_mask; 150428d7b3dSmrg}; 151428d7b3dSmrg 152428d7b3dSmrgstatic void 153428d7b3dSmrgintel_output_dpms(xf86OutputPtr output, int mode); 154428d7b3dSmrg 155428d7b3dSmrgstatic void 156428d7b3dSmrgintel_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode); 157428d7b3dSmrg 158428d7b3dSmrgstatic inline int 159428d7b3dSmrgcrtc_id(struct intel_crtc *crtc) 160428d7b3dSmrg{ 161428d7b3dSmrg return crtc->mode_crtc->crtc_id; 162428d7b3dSmrg} 163428d7b3dSmrg 164428d7b3dSmrgstatic void 165428d7b3dSmrgintel_output_backlight_set(xf86OutputPtr output, int level) 166428d7b3dSmrg{ 167428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 168428d7b3dSmrg if (backlight_set(&intel_output->backlight, level) < 0) { 169428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 170428d7b3dSmrg "failed to set backlight %s to brightness level %d, disabling\n", 171428d7b3dSmrg intel_output->backlight.iface, level); 172428d7b3dSmrg backlight_disable(&intel_output->backlight); 173428d7b3dSmrg } 174428d7b3dSmrg} 175428d7b3dSmrg 176428d7b3dSmrgstatic int 177428d7b3dSmrgintel_output_backlight_get(xf86OutputPtr output) 178428d7b3dSmrg{ 179428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 180428d7b3dSmrg return backlight_get(&intel_output->backlight); 181428d7b3dSmrg} 182428d7b3dSmrg 183428d7b3dSmrgstatic void 184428d7b3dSmrgintel_output_backlight_init(xf86OutputPtr output) 185428d7b3dSmrg{ 186428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 187428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(output->scrn); 188428d7b3dSmrg const char *str; 189428d7b3dSmrg 190428d7b3dSmrg#if !USE_BACKLIGHT 191428d7b3dSmrg return; 192428d7b3dSmrg#endif 193428d7b3dSmrg 194428d7b3dSmrg str = xf86GetOptValString(intel->Options, OPTION_BACKLIGHT); 195428d7b3dSmrg if (str != NULL) { 196428d7b3dSmrg if (backlight_exists(str) != BL_NONE) { 197428d7b3dSmrg intel_output->backlight_active_level = 198428d7b3dSmrg backlight_open(&intel_output->backlight, 199428d7b3dSmrg strdup(str)); 200428d7b3dSmrg if (intel_output->backlight_active_level != -1) { 201428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_CONFIG, 202428d7b3dSmrg "found backlight control interface %s\n", str); 203428d7b3dSmrg return; 204428d7b3dSmrg } 205428d7b3dSmrg } 206428d7b3dSmrg 207428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 208428d7b3dSmrg "unrecognised backlight control interface %s\n", str); 209428d7b3dSmrg } 210428d7b3dSmrg 211428d7b3dSmrg intel_output->backlight_active_level = 212428d7b3dSmrg backlight_open(&intel_output->backlight, NULL); 213428d7b3dSmrg if (intel_output->backlight_active_level != -1) { 214428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_PROBED, 215428d7b3dSmrg "found backlight control interface %s\n", 216428d7b3dSmrg intel_output->backlight.iface); 217428d7b3dSmrg return; 218428d7b3dSmrg } 219428d7b3dSmrg} 220428d7b3dSmrg 221428d7b3dSmrgstatic void 222428d7b3dSmrgmode_from_kmode(ScrnInfoPtr scrn, 223428d7b3dSmrg drmModeModeInfoPtr kmode, 224428d7b3dSmrg DisplayModePtr mode) 225428d7b3dSmrg{ 226428d7b3dSmrg memset(mode, 0, sizeof(DisplayModeRec)); 227428d7b3dSmrg mode->status = MODE_OK; 228428d7b3dSmrg 229428d7b3dSmrg mode->Clock = kmode->clock; 230428d7b3dSmrg 231428d7b3dSmrg mode->HDisplay = kmode->hdisplay; 232428d7b3dSmrg mode->HSyncStart = kmode->hsync_start; 233428d7b3dSmrg mode->HSyncEnd = kmode->hsync_end; 234428d7b3dSmrg mode->HTotal = kmode->htotal; 235428d7b3dSmrg mode->HSkew = kmode->hskew; 236428d7b3dSmrg 237428d7b3dSmrg mode->VDisplay = kmode->vdisplay; 238428d7b3dSmrg mode->VSyncStart = kmode->vsync_start; 239428d7b3dSmrg mode->VSyncEnd = kmode->vsync_end; 240428d7b3dSmrg mode->VTotal = kmode->vtotal; 241428d7b3dSmrg mode->VScan = kmode->vscan; 242428d7b3dSmrg 243428d7b3dSmrg mode->Flags = kmode->flags; 244428d7b3dSmrg mode->name = strdup(kmode->name); 245428d7b3dSmrg 246428d7b3dSmrg if (kmode->type & DRM_MODE_TYPE_DRIVER) 247428d7b3dSmrg mode->type = M_T_DRIVER; 248428d7b3dSmrg if (kmode->type & DRM_MODE_TYPE_PREFERRED) 249428d7b3dSmrg mode->type |= M_T_PREFERRED; 250428d7b3dSmrg 251428d7b3dSmrg if (mode->status == MODE_OK && kmode->flags & ~KNOWN_MODE_FLAGS) 252428d7b3dSmrg mode->status = MODE_BAD; /* unknown flags => unhandled */ 253428d7b3dSmrg 254428d7b3dSmrg xf86SetModeCrtc (mode, scrn->adjustFlags); 255428d7b3dSmrg} 256428d7b3dSmrg 257428d7b3dSmrgstatic void 258428d7b3dSmrgmode_to_kmode(ScrnInfoPtr scrn, 259428d7b3dSmrg drmModeModeInfoPtr kmode, 260428d7b3dSmrg DisplayModePtr mode) 261428d7b3dSmrg{ 262428d7b3dSmrg memset(kmode, 0, sizeof(*kmode)); 263428d7b3dSmrg 264428d7b3dSmrg kmode->clock = mode->Clock; 265428d7b3dSmrg kmode->hdisplay = mode->HDisplay; 266428d7b3dSmrg kmode->hsync_start = mode->HSyncStart; 267428d7b3dSmrg kmode->hsync_end = mode->HSyncEnd; 268428d7b3dSmrg kmode->htotal = mode->HTotal; 269428d7b3dSmrg kmode->hskew = mode->HSkew; 270428d7b3dSmrg 271428d7b3dSmrg kmode->vdisplay = mode->VDisplay; 272428d7b3dSmrg kmode->vsync_start = mode->VSyncStart; 273428d7b3dSmrg kmode->vsync_end = mode->VSyncEnd; 274428d7b3dSmrg kmode->vtotal = mode->VTotal; 275428d7b3dSmrg kmode->vscan = mode->VScan; 276428d7b3dSmrg 277428d7b3dSmrg kmode->flags = mode->Flags; 278428d7b3dSmrg if (mode->name) 279428d7b3dSmrg strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN); 280428d7b3dSmrg kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0; 281428d7b3dSmrg} 282428d7b3dSmrg 283428d7b3dSmrgstatic void 284428d7b3dSmrgintel_crtc_dpms(xf86CrtcPtr crtc, int mode) 285428d7b3dSmrg{ 286428d7b3dSmrg} 287428d7b3dSmrg 288428d7b3dSmrgvoid 289428d7b3dSmrgintel_mode_disable_unused_functions(ScrnInfoPtr scrn) 290428d7b3dSmrg{ 291428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 292428d7b3dSmrg struct intel_mode *mode = intel_get_screen_private(scrn)->modes; 293428d7b3dSmrg int i; 294428d7b3dSmrg 295428d7b3dSmrg /* Force off for consistency between kernel and ddx */ 296428d7b3dSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 297428d7b3dSmrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 298428d7b3dSmrg if (!crtc->enabled) 299428d7b3dSmrg drmModeSetCrtc(mode->fd, crtc_id(crtc->driver_private), 300428d7b3dSmrg 0, 0, 0, NULL, 0, NULL); 301428d7b3dSmrg } 302428d7b3dSmrg} 303428d7b3dSmrg 304428d7b3dSmrgstatic Bool 305428d7b3dSmrgintel_crtc_apply(xf86CrtcPtr crtc) 306428d7b3dSmrg{ 307428d7b3dSmrg ScrnInfoPtr scrn = crtc->scrn; 308428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 309428d7b3dSmrg struct intel_mode *mode = intel_crtc->mode; 310428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 311428d7b3dSmrg uint32_t *output_ids; 312428d7b3dSmrg int output_count = 0; 313428d7b3dSmrg int fb_id, x, y; 314428d7b3dSmrg int i, ret = FALSE; 315428d7b3dSmrg 316428d7b3dSmrg output_ids = calloc(sizeof(uint32_t), xf86_config->num_output); 317428d7b3dSmrg if (!output_ids) 318428d7b3dSmrg return FALSE; 319428d7b3dSmrg 320428d7b3dSmrg for (i = 0; i < xf86_config->num_output; i++) { 321428d7b3dSmrg xf86OutputPtr output = xf86_config->output[i]; 322428d7b3dSmrg struct intel_output *intel_output; 323428d7b3dSmrg 324428d7b3dSmrg /* Make sure we mark the output as off (and save the backlight) 325428d7b3dSmrg * before the kernel turns it off due to changing the pipe. 326428d7b3dSmrg * This is necessary as the kernel may turn off the backlight 327428d7b3dSmrg * and we lose track of the user settings. 328428d7b3dSmrg */ 329428d7b3dSmrg if (output->crtc == NULL) 330428d7b3dSmrg output->funcs->dpms(output, DPMSModeOff); 331428d7b3dSmrg 332428d7b3dSmrg if (output->crtc != crtc) 333428d7b3dSmrg continue; 334428d7b3dSmrg 335428d7b3dSmrg intel_output = output->driver_private; 336428d7b3dSmrg if (!intel_output->mode_output) 337428d7b3dSmrg return FALSE; 338428d7b3dSmrg 339428d7b3dSmrg output_ids[output_count] = 340428d7b3dSmrg intel_output->mode_output->connector_id; 341428d7b3dSmrg output_count++; 342428d7b3dSmrg } 343428d7b3dSmrg 344428d7b3dSmrg if (!intel_crtc->scanout_fb_id) { 345428d7b3dSmrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,5,99,0,0) 346428d7b3dSmrg if (!xf86CrtcRotate(crtc, mode, rotation)) 347428d7b3dSmrg goto done; 348428d7b3dSmrg#else 349428d7b3dSmrg if (!xf86CrtcRotate(crtc)) 350428d7b3dSmrg goto done; 351428d7b3dSmrg#endif 352428d7b3dSmrg } 353428d7b3dSmrg 354428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0) 355428d7b3dSmrg crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green, 356428d7b3dSmrg crtc->gamma_blue, crtc->gamma_size); 357428d7b3dSmrg#endif 358428d7b3dSmrg 359428d7b3dSmrg x = crtc->x; 360428d7b3dSmrg y = crtc->y; 361428d7b3dSmrg fb_id = mode->fb_id; 362428d7b3dSmrg if (intel_crtc->rotate_fb_id) { 363428d7b3dSmrg fb_id = intel_crtc->rotate_fb_id; 364428d7b3dSmrg x = 0; 365428d7b3dSmrg y = 0; 366428d7b3dSmrg } else if (intel_crtc->scanout_fb_id && intel_crtc->scanout_pixmap->drawable.width >= crtc->mode.HDisplay && intel_crtc->scanout_pixmap->drawable.height >= crtc->mode.VDisplay) { 367428d7b3dSmrg fb_id = intel_crtc->scanout_fb_id; 368428d7b3dSmrg x = 0; 369428d7b3dSmrg y = 0; 370428d7b3dSmrg } 371428d7b3dSmrg ret = drmModeSetCrtc(mode->fd, crtc_id(intel_crtc), 372428d7b3dSmrg fb_id, x, y, output_ids, output_count, 373428d7b3dSmrg &intel_crtc->kmode); 374428d7b3dSmrg if (ret) { 375428d7b3dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 376428d7b3dSmrg "failed to set mode: %s\n", strerror(-ret)); 377428d7b3dSmrg ret = FALSE; 378428d7b3dSmrg } else { 379428d7b3dSmrg ret = TRUE; 380428d7b3dSmrg 381428d7b3dSmrg /* Force DPMS to On for all outputs, which the kernel will have done 382428d7b3dSmrg * with the mode set. Also, restore the backlight level 383428d7b3dSmrg */ 384428d7b3dSmrg for (i = 0; i < xf86_config->num_output; i++) { 385428d7b3dSmrg xf86OutputPtr output = xf86_config->output[i]; 386428d7b3dSmrg struct intel_output *intel_output; 387428d7b3dSmrg 388428d7b3dSmrg if (output->crtc != crtc) 389428d7b3dSmrg continue; 390428d7b3dSmrg 391428d7b3dSmrg intel_output = output->driver_private; 392428d7b3dSmrg intel_output_dpms_backlight(output, intel_output->dpms_mode, DPMSModeOn); 393428d7b3dSmrg intel_output->dpms_mode = DPMSModeOn; 394428d7b3dSmrg } 395428d7b3dSmrg } 396428d7b3dSmrg 397428d7b3dSmrg if (scrn->pScreen) 398428d7b3dSmrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR 399428d7b3dSmrg xf86CursorResetCursor(scrn->pScreen); 400428d7b3dSmrg#else 401428d7b3dSmrg xf86_reload_cursors(scrn->pScreen); 402428d7b3dSmrg#endif 403428d7b3dSmrg 404428d7b3dSmrgdone: 405428d7b3dSmrg free(output_ids); 406428d7b3dSmrg return ret; 407428d7b3dSmrg} 408428d7b3dSmrg 409428d7b3dSmrgstatic Bool 410428d7b3dSmrgintel_crtc_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode, 411428d7b3dSmrg Rotation rotation, int x, int y) 412428d7b3dSmrg{ 413428d7b3dSmrg ScrnInfoPtr scrn = crtc->scrn; 414428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 415428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 416428d7b3dSmrg struct intel_mode *intel_mode = intel_crtc->mode; 417428d7b3dSmrg int saved_x, saved_y; 418428d7b3dSmrg Rotation saved_rotation; 419428d7b3dSmrg DisplayModeRec saved_mode; 420428d7b3dSmrg int ret = TRUE; 421428d7b3dSmrg unsigned int pitch = scrn->displayWidth * intel->cpp; 422428d7b3dSmrg 423428d7b3dSmrg if (intel_mode->fb_id == 0) { 424428d7b3dSmrg ret = drmModeAddFB(intel_mode->fd, 425428d7b3dSmrg scrn->virtualX, scrn->virtualY, 426428d7b3dSmrg scrn->depth, scrn->bitsPerPixel, 427428d7b3dSmrg pitch, intel->front_buffer->handle, 428428d7b3dSmrg &intel_mode->fb_id); 429428d7b3dSmrg if (ret < 0) { 430428d7b3dSmrg ErrorF("failed to add fb\n"); 431428d7b3dSmrg return FALSE; 432428d7b3dSmrg } 433428d7b3dSmrg 434428d7b3dSmrg drm_intel_bo_disable_reuse(intel->front_buffer); 435428d7b3dSmrg } 436428d7b3dSmrg 437428d7b3dSmrg saved_mode = crtc->mode; 438428d7b3dSmrg saved_x = crtc->x; 439428d7b3dSmrg saved_y = crtc->y; 440428d7b3dSmrg saved_rotation = crtc->rotation; 441428d7b3dSmrg 442428d7b3dSmrg crtc->mode = *mode; 443428d7b3dSmrg crtc->x = x; 444428d7b3dSmrg crtc->y = y; 445428d7b3dSmrg crtc->rotation = rotation; 446428d7b3dSmrg 447428d7b3dSmrg intel_flush(intel); 448428d7b3dSmrg 449428d7b3dSmrg mode_to_kmode(crtc->scrn, &intel_crtc->kmode, mode); 450428d7b3dSmrg ret = intel_crtc_apply(crtc); 451428d7b3dSmrg if (!ret) { 452428d7b3dSmrg crtc->x = saved_x; 453428d7b3dSmrg crtc->y = saved_y; 454428d7b3dSmrg crtc->rotation = saved_rotation; 455428d7b3dSmrg crtc->mode = saved_mode; 456428d7b3dSmrg } 457428d7b3dSmrg return ret; 458428d7b3dSmrg} 459428d7b3dSmrg 460428d7b3dSmrgstatic void 461428d7b3dSmrgintel_crtc_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg) 462428d7b3dSmrg{ 463428d7b3dSmrg 464428d7b3dSmrg} 465428d7b3dSmrg 466428d7b3dSmrgstatic void 467428d7b3dSmrgintel_crtc_set_cursor_position (xf86CrtcPtr crtc, int x, int y) 468428d7b3dSmrg{ 469428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 470428d7b3dSmrg struct intel_mode *mode = intel_crtc->mode; 471428d7b3dSmrg 472428d7b3dSmrg drmModeMoveCursor(mode->fd, crtc_id(intel_crtc), x, y); 473428d7b3dSmrg} 474428d7b3dSmrg 475428d7b3dSmrgstatic int 476428d7b3dSmrg__intel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image) 477428d7b3dSmrg{ 478428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 479428d7b3dSmrg int ret; 480428d7b3dSmrg 481428d7b3dSmrg ret = dri_bo_subdata(intel_crtc->cursor, 0, 64*64*4, image); 482428d7b3dSmrg if (ret) 483428d7b3dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 484428d7b3dSmrg "failed to set cursor: %s\n", strerror(-ret)); 485428d7b3dSmrg 486428d7b3dSmrg return ret; 487428d7b3dSmrg} 488428d7b3dSmrg 489428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,2) 490428d7b3dSmrgstatic Bool 491428d7b3dSmrgintel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image) 492428d7b3dSmrg{ 493428d7b3dSmrg return __intel_crtc_load_cursor_argb(crtc, image) == 0; 494428d7b3dSmrg} 495428d7b3dSmrg#else 496428d7b3dSmrgstatic void 497428d7b3dSmrgintel_crtc_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image) 498428d7b3dSmrg{ 499428d7b3dSmrg __intel_crtc_load_cursor_argb(crtc, image); 500428d7b3dSmrg} 501428d7b3dSmrg#endif 502428d7b3dSmrg 503428d7b3dSmrgstatic void 504428d7b3dSmrgintel_crtc_hide_cursor(xf86CrtcPtr crtc) 505428d7b3dSmrg{ 506428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 507428d7b3dSmrg struct intel_mode *mode = intel_crtc->mode; 508428d7b3dSmrg 509428d7b3dSmrg drmModeSetCursor(mode->fd, crtc_id(intel_crtc), 0, 64, 64); 510428d7b3dSmrg} 511428d7b3dSmrg 512428d7b3dSmrgstatic void 513428d7b3dSmrgintel_crtc_show_cursor(xf86CrtcPtr crtc) 514428d7b3dSmrg{ 515428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 516428d7b3dSmrg struct intel_mode *mode = intel_crtc->mode; 517428d7b3dSmrg 518428d7b3dSmrg drmModeSetCursor(mode->fd, crtc_id(intel_crtc), 519428d7b3dSmrg intel_crtc->cursor->handle, 64, 64); 520428d7b3dSmrg} 521428d7b3dSmrg 522428d7b3dSmrgstatic void * 523428d7b3dSmrgintel_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height) 524428d7b3dSmrg{ 525428d7b3dSmrg ScrnInfoPtr scrn = crtc->scrn; 526428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 527428d7b3dSmrg struct intel_mode *mode = intel_crtc->mode; 528428d7b3dSmrg int rotate_pitch; 529428d7b3dSmrg uint32_t tiling; 530428d7b3dSmrg int ret; 531428d7b3dSmrg 532428d7b3dSmrg intel_crtc->rotate_bo = intel_allocate_framebuffer(scrn, 533428d7b3dSmrg width, height, 534428d7b3dSmrg mode->cpp, 535428d7b3dSmrg &rotate_pitch, 536428d7b3dSmrg &tiling); 537428d7b3dSmrg 538428d7b3dSmrg if (!intel_crtc->rotate_bo) { 539428d7b3dSmrg xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR, 540428d7b3dSmrg "Couldn't allocate shadow memory for rotated CRTC\n"); 541428d7b3dSmrg return NULL; 542428d7b3dSmrg } 543428d7b3dSmrg 544428d7b3dSmrg ret = drmModeAddFB(mode->fd, width, height, crtc->scrn->depth, 545428d7b3dSmrg crtc->scrn->bitsPerPixel, rotate_pitch, 546428d7b3dSmrg intel_crtc->rotate_bo->handle, 547428d7b3dSmrg &intel_crtc->rotate_fb_id); 548428d7b3dSmrg if (ret) { 549428d7b3dSmrg ErrorF("failed to add rotate fb\n"); 550428d7b3dSmrg drm_intel_bo_unreference(intel_crtc->rotate_bo); 551428d7b3dSmrg return NULL; 552428d7b3dSmrg } 553428d7b3dSmrg 554428d7b3dSmrg intel_crtc->rotate_pitch = rotate_pitch; 555428d7b3dSmrg return intel_crtc->rotate_bo; 556428d7b3dSmrg} 557428d7b3dSmrg 558428d7b3dSmrgstatic PixmapPtr 559428d7b3dSmrgintel_create_pixmap_header(ScreenPtr pScreen, int width, int height, int depth, 560428d7b3dSmrg int bitsPerPixel, int devKind, void *pPixData) 561428d7b3dSmrg{ 562428d7b3dSmrg PixmapPtr pixmap; 563428d7b3dSmrg 564428d7b3dSmrg /* width and height of 0 means don't allocate any pixmap data */ 565428d7b3dSmrg pixmap = (*pScreen->CreatePixmap) (pScreen, 0, 0, depth, 0); 566428d7b3dSmrg 567428d7b3dSmrg if (pixmap) { 568428d7b3dSmrg if ((*pScreen->ModifyPixmapHeader) (pixmap, width, height, depth, 569428d7b3dSmrg bitsPerPixel, devKind, pPixData)) 570428d7b3dSmrg { 571428d7b3dSmrg return pixmap; 572428d7b3dSmrg } 573428d7b3dSmrg (*pScreen->DestroyPixmap) (pixmap); 574428d7b3dSmrg } 575428d7b3dSmrg return NullPixmap; 576428d7b3dSmrg} 577428d7b3dSmrg 578428d7b3dSmrgstatic PixmapPtr 579428d7b3dSmrgintel_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) 580428d7b3dSmrg{ 581428d7b3dSmrg ScrnInfoPtr scrn = crtc->scrn; 582428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 583428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 584428d7b3dSmrg PixmapPtr rotate_pixmap; 585428d7b3dSmrg 586428d7b3dSmrg if (!data) { 587428d7b3dSmrg data = intel_crtc_shadow_allocate (crtc, width, height); 588428d7b3dSmrg if (!data) { 589428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 590428d7b3dSmrg "Couldn't allocate shadow pixmap for rotated CRTC\n"); 591428d7b3dSmrg return NULL; 592428d7b3dSmrg } 593428d7b3dSmrg } 594428d7b3dSmrg if (intel_crtc->rotate_bo == NULL) { 595428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 596428d7b3dSmrg "Couldn't allocate shadow pixmap for rotated CRTC\n"); 597428d7b3dSmrg return NULL; 598428d7b3dSmrg } 599428d7b3dSmrg 600428d7b3dSmrg rotate_pixmap = intel_create_pixmap_header(scrn->pScreen, 601428d7b3dSmrg width, height, 602428d7b3dSmrg scrn->depth, 603428d7b3dSmrg scrn->bitsPerPixel, 604428d7b3dSmrg intel_crtc->rotate_pitch, 605428d7b3dSmrg NULL); 606428d7b3dSmrg 607428d7b3dSmrg if (rotate_pixmap == NULL) { 608428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 609428d7b3dSmrg "Couldn't allocate shadow pixmap for rotated CRTC\n"); 610428d7b3dSmrg return NULL; 611428d7b3dSmrg } 612428d7b3dSmrg 613428d7b3dSmrg intel_set_pixmap_bo(rotate_pixmap, intel_crtc->rotate_bo); 614428d7b3dSmrg 615428d7b3dSmrg intel->shadow_present = TRUE; 616428d7b3dSmrg 617428d7b3dSmrg return rotate_pixmap; 618428d7b3dSmrg} 619428d7b3dSmrg 620428d7b3dSmrgstatic void 621428d7b3dSmrgintel_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) 622428d7b3dSmrg{ 623428d7b3dSmrg ScrnInfoPtr scrn = crtc->scrn; 624428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 625428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 626428d7b3dSmrg struct intel_mode *mode = intel_crtc->mode; 627428d7b3dSmrg 628428d7b3dSmrg if (rotate_pixmap) { 629428d7b3dSmrg intel_set_pixmap_bo(rotate_pixmap, NULL); 630428d7b3dSmrg rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap); 631428d7b3dSmrg } 632428d7b3dSmrg 633428d7b3dSmrg if (data) { 634428d7b3dSmrg /* Be sure to sync acceleration before the memory gets 635428d7b3dSmrg * unbound. */ 636428d7b3dSmrg drmModeRmFB(mode->fd, intel_crtc->rotate_fb_id); 637428d7b3dSmrg intel_crtc->rotate_fb_id = 0; 638428d7b3dSmrg 639428d7b3dSmrg dri_bo_unreference(intel_crtc->rotate_bo); 640428d7b3dSmrg intel_crtc->rotate_bo = NULL; 641428d7b3dSmrg } 642428d7b3dSmrg 643428d7b3dSmrg intel->shadow_present = FALSE; 644428d7b3dSmrg} 645428d7b3dSmrg 646428d7b3dSmrgstatic void 647428d7b3dSmrgintel_crtc_gamma_set(xf86CrtcPtr crtc, 648428d7b3dSmrg CARD16 *red, CARD16 *green, CARD16 *blue, int size) 649428d7b3dSmrg{ 650428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 651428d7b3dSmrg struct intel_mode *mode = intel_crtc->mode; 652428d7b3dSmrg 653428d7b3dSmrg drmModeCrtcSetGamma(mode->fd, crtc_id(intel_crtc), 654428d7b3dSmrg size, red, green, blue); 655428d7b3dSmrg} 656428d7b3dSmrg 657428d7b3dSmrgstatic void 658428d7b3dSmrgintel_crtc_destroy(xf86CrtcPtr crtc) 659428d7b3dSmrg{ 660428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 661428d7b3dSmrg 662428d7b3dSmrg if (intel_crtc->cursor) { 663428d7b3dSmrg drmModeSetCursor(intel_crtc->mode->fd, crtc_id(intel_crtc), 0, 64, 64); 664428d7b3dSmrg drm_intel_bo_unreference(intel_crtc->cursor); 665428d7b3dSmrg intel_crtc->cursor = NULL; 666428d7b3dSmrg } 667428d7b3dSmrg 668428d7b3dSmrg list_del(&intel_crtc->link); 669428d7b3dSmrg free(intel_crtc); 670428d7b3dSmrg 671428d7b3dSmrg crtc->driver_private = NULL; 672428d7b3dSmrg} 673428d7b3dSmrg 674428d7b3dSmrg#ifdef INTEL_PIXMAP_SHARING 675428d7b3dSmrgstatic Bool 676428d7b3dSmrgintel_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix) 677428d7b3dSmrg{ 678428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 679428d7b3dSmrg ScrnInfoPtr scrn = crtc->scrn; 680428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 681428d7b3dSmrg dri_bo *bo; 682428d7b3dSmrg 683428d7b3dSmrg if (ppix == intel_crtc->scanout_pixmap) 684428d7b3dSmrg return TRUE; 685428d7b3dSmrg 686428d7b3dSmrg if (!ppix) { 687428d7b3dSmrg intel_crtc->scanout_pixmap = NULL; 688428d7b3dSmrg if (intel_crtc->scanout_fb_id) { 689428d7b3dSmrg drmModeRmFB(intel->drmSubFD, intel_crtc->scanout_fb_id); 690428d7b3dSmrg intel_crtc->scanout_fb_id = 0; 691428d7b3dSmrg } 692428d7b3dSmrg return TRUE; 693428d7b3dSmrg } 694428d7b3dSmrg 695428d7b3dSmrg bo = intel_get_pixmap_bo(ppix); 696428d7b3dSmrg if (intel->front_buffer) { 697428d7b3dSmrg ErrorF("have front buffer\n"); 698428d7b3dSmrg } 699428d7b3dSmrg 700428d7b3dSmrg drm_intel_bo_disable_reuse(bo); 701428d7b3dSmrg 702428d7b3dSmrg intel_crtc->scanout_pixmap = ppix; 703428d7b3dSmrg return drmModeAddFB(intel->drmSubFD, ppix->drawable.width, 704428d7b3dSmrg ppix->drawable.height, ppix->drawable.depth, 705428d7b3dSmrg ppix->drawable.bitsPerPixel, ppix->devKind, 706428d7b3dSmrg bo->handle, &intel_crtc->scanout_fb_id) == 0; 707428d7b3dSmrg} 708428d7b3dSmrg#endif 709428d7b3dSmrg 710428d7b3dSmrgstatic const xf86CrtcFuncsRec intel_crtc_funcs = { 711428d7b3dSmrg .dpms = intel_crtc_dpms, 712428d7b3dSmrg .set_mode_major = intel_crtc_set_mode_major, 713428d7b3dSmrg .set_cursor_colors = intel_crtc_set_cursor_colors, 714428d7b3dSmrg .set_cursor_position = intel_crtc_set_cursor_position, 715428d7b3dSmrg .show_cursor = intel_crtc_show_cursor, 716428d7b3dSmrg .hide_cursor = intel_crtc_hide_cursor, 717428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,902,3) 718428d7b3dSmrg .load_cursor_argb_check = intel_crtc_load_cursor_argb, 719428d7b3dSmrg#else 720428d7b3dSmrg .load_cursor_argb = intel_crtc_load_cursor_argb, 721428d7b3dSmrg#endif 722428d7b3dSmrg .shadow_create = intel_crtc_shadow_create, 723428d7b3dSmrg .shadow_allocate = intel_crtc_shadow_allocate, 724428d7b3dSmrg .shadow_destroy = intel_crtc_shadow_destroy, 725428d7b3dSmrg .gamma_set = intel_crtc_gamma_set, 726428d7b3dSmrg .destroy = intel_crtc_destroy, 727428d7b3dSmrg#ifdef INTEL_PIXMAP_SHARING 728428d7b3dSmrg .set_scanout_pixmap = intel_set_scanout_pixmap, 729428d7b3dSmrg#endif 730428d7b3dSmrg}; 731428d7b3dSmrg 732428d7b3dSmrgstatic void 733428d7b3dSmrgintel_crtc_init(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_res, int num) 734428d7b3dSmrg{ 735428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 736428d7b3dSmrg xf86CrtcPtr crtc; 737428d7b3dSmrg struct intel_crtc *intel_crtc; 738428d7b3dSmrg 739428d7b3dSmrg intel_crtc = calloc(sizeof(struct intel_crtc), 1); 740428d7b3dSmrg if (intel_crtc == NULL) 741428d7b3dSmrg return; 742428d7b3dSmrg 743428d7b3dSmrg crtc = xf86CrtcCreate(scrn, &intel_crtc_funcs); 744428d7b3dSmrg if (crtc == NULL) { 745428d7b3dSmrg free(intel_crtc); 746428d7b3dSmrg return; 747428d7b3dSmrg } 748428d7b3dSmrg 749428d7b3dSmrg intel_crtc->mode_crtc = drmModeGetCrtc(mode->fd, 750428d7b3dSmrg mode_res->crtcs[num]); 751428d7b3dSmrg if (intel_crtc->mode_crtc == NULL) { 752428d7b3dSmrg free(intel_crtc); 753428d7b3dSmrg return; 754428d7b3dSmrg } 755428d7b3dSmrg 756428d7b3dSmrg intel_crtc->mode = mode; 757428d7b3dSmrg crtc->driver_private = intel_crtc; 758428d7b3dSmrg 759428d7b3dSmrg intel_crtc->pipe = drm_intel_get_pipe_from_crtc_id(intel->bufmgr, 760428d7b3dSmrg crtc_id(intel_crtc)); 761428d7b3dSmrg 762428d7b3dSmrg intel_crtc->cursor = drm_intel_bo_alloc(intel->bufmgr, "ARGB cursor", 763428d7b3dSmrg 4*64*64, 4096); 764428d7b3dSmrg 765428d7b3dSmrg intel_crtc->crtc = crtc; 766428d7b3dSmrg list_add(&intel_crtc->link, &mode->crtcs); 767428d7b3dSmrg} 768428d7b3dSmrg 769428d7b3dSmrgstatic Bool 770428d7b3dSmrgis_panel(int type) 771428d7b3dSmrg{ 772428d7b3dSmrg return (type == DRM_MODE_CONNECTOR_LVDS || 773428d7b3dSmrg type == DRM_MODE_CONNECTOR_eDP); 774428d7b3dSmrg} 775428d7b3dSmrg 776428d7b3dSmrgstatic xf86OutputStatus 777428d7b3dSmrgintel_output_detect(xf86OutputPtr output) 778428d7b3dSmrg{ 779428d7b3dSmrg /* go to the hw and retrieve a new output struct */ 780428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 781428d7b3dSmrg struct intel_mode *mode = intel_output->mode; 782428d7b3dSmrg xf86OutputStatus status; 783428d7b3dSmrg 784428d7b3dSmrg drmModeFreeConnector(intel_output->mode_output); 785428d7b3dSmrg intel_output->mode_output = 786428d7b3dSmrg drmModeGetConnector(mode->fd, intel_output->output_id); 787428d7b3dSmrg if (intel_output->mode_output == NULL) { 788428d7b3dSmrg /* and hope we are safe everywhere else */ 789428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 790428d7b3dSmrg "drmModeGetConnector failed, reporting output disconnected\n"); 791428d7b3dSmrg return XF86OutputStatusDisconnected; 792428d7b3dSmrg } 793428d7b3dSmrg 794428d7b3dSmrg switch (intel_output->mode_output->connection) { 795428d7b3dSmrg case DRM_MODE_CONNECTED: 796428d7b3dSmrg status = XF86OutputStatusConnected; 797428d7b3dSmrg break; 798428d7b3dSmrg case DRM_MODE_DISCONNECTED: 799428d7b3dSmrg status = XF86OutputStatusDisconnected; 800428d7b3dSmrg break; 801428d7b3dSmrg default: 802428d7b3dSmrg case DRM_MODE_UNKNOWNCONNECTION: 803428d7b3dSmrg status = XF86OutputStatusUnknown; 804428d7b3dSmrg break; 805428d7b3dSmrg } 806428d7b3dSmrg return status; 807428d7b3dSmrg} 808428d7b3dSmrg 809428d7b3dSmrgstatic Bool 810428d7b3dSmrgintel_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes) 811428d7b3dSmrg{ 812428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 813428d7b3dSmrg 814428d7b3dSmrg /* 815428d7b3dSmrg * If the connector type is a panel, we will use the panel limit to 816428d7b3dSmrg * verfiy whether the mode is valid. 817428d7b3dSmrg */ 818428d7b3dSmrg if (intel_output->has_panel_limits) { 819428d7b3dSmrg if (pModes->HDisplay > intel_output->panel_hdisplay || 820428d7b3dSmrg pModes->VDisplay > intel_output->panel_vdisplay) 821428d7b3dSmrg return MODE_PANEL; 822428d7b3dSmrg } 823428d7b3dSmrg 824428d7b3dSmrg return MODE_OK; 825428d7b3dSmrg} 826428d7b3dSmrg 827428d7b3dSmrgstatic void 828428d7b3dSmrgintel_output_attach_edid(xf86OutputPtr output) 829428d7b3dSmrg{ 830428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 831428d7b3dSmrg drmModeConnectorPtr koutput = intel_output->mode_output; 832428d7b3dSmrg struct intel_mode *mode = intel_output->mode; 833428d7b3dSmrg xf86MonPtr mon = NULL; 834428d7b3dSmrg int i; 835428d7b3dSmrg 836428d7b3dSmrg if (!koutput) { 837428d7b3dSmrg xf86OutputSetEDID(output, mon); 838428d7b3dSmrg return; 839428d7b3dSmrg } 840428d7b3dSmrg 841428d7b3dSmrg /* look for an EDID property */ 842428d7b3dSmrg for (i = 0; i < koutput->count_props; i++) { 843428d7b3dSmrg drmModePropertyPtr props; 844428d7b3dSmrg 845428d7b3dSmrg props = drmModeGetProperty(mode->fd, koutput->props[i]); 846428d7b3dSmrg if (!props) 847428d7b3dSmrg continue; 848428d7b3dSmrg 849428d7b3dSmrg if (!(props->flags & DRM_MODE_PROP_BLOB)) { 850428d7b3dSmrg drmModeFreeProperty(props); 851428d7b3dSmrg continue; 852428d7b3dSmrg } 853428d7b3dSmrg 854428d7b3dSmrg if (!strcmp(props->name, "EDID")) { 855428d7b3dSmrg drmModeFreePropertyBlob(intel_output->edid_blob); 856428d7b3dSmrg intel_output->edid_blob = 857428d7b3dSmrg drmModeGetPropertyBlob(mode->fd, 858428d7b3dSmrg koutput->prop_values[i]); 859428d7b3dSmrg } 860428d7b3dSmrg drmModeFreeProperty(props); 861428d7b3dSmrg } 862428d7b3dSmrg 863428d7b3dSmrg if (intel_output->edid_blob) { 864428d7b3dSmrg mon = xf86InterpretEDID(output->scrn->scrnIndex, 865428d7b3dSmrg intel_output->edid_blob->data); 866428d7b3dSmrg 867428d7b3dSmrg if (mon && intel_output->edid_blob->length > 128) 868428d7b3dSmrg mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA; 869428d7b3dSmrg } 870428d7b3dSmrg 871428d7b3dSmrg xf86OutputSetEDID(output, mon); 872428d7b3dSmrg} 873428d7b3dSmrg 874428d7b3dSmrgstatic DisplayModePtr 875428d7b3dSmrgintel_output_panel_edid(xf86OutputPtr output, DisplayModePtr modes) 876428d7b3dSmrg{ 877428d7b3dSmrg xf86MonPtr mon = output->MonInfo; 878428d7b3dSmrg 879428d7b3dSmrg if (!mon || !GTF_SUPPORTED(mon->features.msc)) { 880428d7b3dSmrg DisplayModePtr i, m, p = NULL; 881428d7b3dSmrg int max_x = 0, max_y = 0; 882428d7b3dSmrg float max_vrefresh = 0.0; 883428d7b3dSmrg 884428d7b3dSmrg for (m = modes; m; m = m->next) { 885428d7b3dSmrg if (m->type & M_T_PREFERRED) 886428d7b3dSmrg p = m; 887428d7b3dSmrg max_x = max(max_x, m->HDisplay); 888428d7b3dSmrg max_y = max(max_y, m->VDisplay); 889428d7b3dSmrg max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m)); 890428d7b3dSmrg } 891428d7b3dSmrg 892428d7b3dSmrg max_vrefresh = max(max_vrefresh, 60.0); 893428d7b3dSmrg max_vrefresh *= (1 + SYNC_TOLERANCE); 894428d7b3dSmrg 895428d7b3dSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,6,99,0,0) 896428d7b3dSmrg m = xf86GetDefaultModes(); 897428d7b3dSmrg#else 898428d7b3dSmrg m = xf86GetDefaultModes(0,0); 899428d7b3dSmrg#endif 900428d7b3dSmrg 901428d7b3dSmrg xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0); 902428d7b3dSmrg 903428d7b3dSmrg for (i = m; i; i = i->next) { 904428d7b3dSmrg if (xf86ModeVRefresh(i) > max_vrefresh) 905428d7b3dSmrg i->status = MODE_VSYNC; 906428d7b3dSmrg if (p && i->HDisplay >= p->HDisplay && 907428d7b3dSmrg i->VDisplay >= p->VDisplay && 908428d7b3dSmrg xf86ModeVRefresh(i) >= xf86ModeVRefresh(p)) 909428d7b3dSmrg i->status = MODE_VSYNC; 910428d7b3dSmrg } 911428d7b3dSmrg 912428d7b3dSmrg xf86PruneInvalidModes(output->scrn, &m, FALSE); 913428d7b3dSmrg 914428d7b3dSmrg modes = xf86ModesAdd(modes, m); 915428d7b3dSmrg } 916428d7b3dSmrg 917428d7b3dSmrg return modes; 918428d7b3dSmrg} 919428d7b3dSmrg 920428d7b3dSmrgstatic DisplayModePtr 921428d7b3dSmrgintel_output_get_modes(xf86OutputPtr output) 922428d7b3dSmrg{ 923428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 924428d7b3dSmrg drmModeConnectorPtr koutput = intel_output->mode_output; 925428d7b3dSmrg DisplayModePtr Modes = NULL; 926428d7b3dSmrg int i; 927428d7b3dSmrg 928428d7b3dSmrg intel_output_attach_edid(output); 929428d7b3dSmrg 930428d7b3dSmrg if (!koutput) 931428d7b3dSmrg return Modes; 932428d7b3dSmrg 933428d7b3dSmrg /* modes should already be available */ 934428d7b3dSmrg for (i = 0; i < koutput->count_modes; i++) { 935428d7b3dSmrg DisplayModePtr Mode; 936428d7b3dSmrg 937428d7b3dSmrg Mode = calloc(1, sizeof(DisplayModeRec)); 938428d7b3dSmrg if (Mode) { 939428d7b3dSmrg mode_from_kmode(output->scrn, &koutput->modes[i], Mode); 940428d7b3dSmrg Modes = xf86ModesAdd(Modes, Mode); 941428d7b3dSmrg } 942428d7b3dSmrg } 943428d7b3dSmrg 944428d7b3dSmrg /* 945428d7b3dSmrg * If the connector type is a panel, we will traverse the kernel mode to 946428d7b3dSmrg * get the panel limit. And then add all the standard modes to fake 947428d7b3dSmrg * the fullscreen experience. 948428d7b3dSmrg * If it is incorrect, please fix me. 949428d7b3dSmrg */ 950428d7b3dSmrg intel_output->has_panel_limits = FALSE; 951428d7b3dSmrg if (is_panel(koutput->connector_type)) { 952428d7b3dSmrg for (i = 0; i < koutput->count_modes; i++) { 953428d7b3dSmrg drmModeModeInfo *mode_ptr; 954428d7b3dSmrg 955428d7b3dSmrg mode_ptr = &koutput->modes[i]; 956428d7b3dSmrg if (mode_ptr->hdisplay > intel_output->panel_hdisplay) 957428d7b3dSmrg intel_output->panel_hdisplay = mode_ptr->hdisplay; 958428d7b3dSmrg if (mode_ptr->vdisplay > intel_output->panel_vdisplay) 959428d7b3dSmrg intel_output->panel_vdisplay = mode_ptr->vdisplay; 960428d7b3dSmrg } 961428d7b3dSmrg 962428d7b3dSmrg intel_output->has_panel_limits = 963428d7b3dSmrg intel_output->panel_hdisplay && 964428d7b3dSmrg intel_output->panel_vdisplay; 965428d7b3dSmrg 966428d7b3dSmrg Modes = intel_output_panel_edid(output, Modes); 967428d7b3dSmrg } 968428d7b3dSmrg 969428d7b3dSmrg return Modes; 970428d7b3dSmrg} 971428d7b3dSmrg 972428d7b3dSmrgstatic void 973428d7b3dSmrgintel_output_destroy(xf86OutputPtr output) 974428d7b3dSmrg{ 975428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 976428d7b3dSmrg int i; 977428d7b3dSmrg 978428d7b3dSmrg drmModeFreePropertyBlob(intel_output->edid_blob); 979428d7b3dSmrg 980428d7b3dSmrg for (i = 0; i < intel_output->num_props; i++) { 981428d7b3dSmrg drmModeFreeProperty(intel_output->props[i].mode_prop); 982428d7b3dSmrg free(intel_output->props[i].atoms); 983428d7b3dSmrg } 984428d7b3dSmrg free(intel_output->props); 985428d7b3dSmrg for (i = 0; i < intel_output->mode_output->count_encoders; i++) { 986428d7b3dSmrg drmModeFreeEncoder(intel_output->mode_encoders[i]); 987428d7b3dSmrg } 988428d7b3dSmrg free(intel_output->mode_encoders); 989428d7b3dSmrg drmModeFreeConnector(intel_output->mode_output); 990428d7b3dSmrg intel_output->mode_output = NULL; 991428d7b3dSmrg 992428d7b3dSmrg list_del(&intel_output->link); 993428d7b3dSmrg backlight_close(&intel_output->backlight); 994428d7b3dSmrg free(intel_output); 995428d7b3dSmrg 996428d7b3dSmrg output->driver_private = NULL; 997428d7b3dSmrg} 998428d7b3dSmrg 999428d7b3dSmrgstatic void 1000428d7b3dSmrgintel_output_dpms_backlight(xf86OutputPtr output, int oldmode, int mode) 1001428d7b3dSmrg{ 1002428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 1003428d7b3dSmrg 1004428d7b3dSmrg if (!intel_output->backlight.iface) 1005428d7b3dSmrg return; 1006428d7b3dSmrg 1007428d7b3dSmrg if (mode == DPMSModeOn) { 1008428d7b3dSmrg /* If we're going from off->on we may need to turn on the backlight. */ 1009428d7b3dSmrg if (oldmode != DPMSModeOn) 1010428d7b3dSmrg intel_output_backlight_set(output, 1011428d7b3dSmrg intel_output->backlight_active_level); 1012428d7b3dSmrg } else { 1013428d7b3dSmrg /* Only save the current backlight value if we're going from on to off. */ 1014428d7b3dSmrg if (oldmode == DPMSModeOn) 1015428d7b3dSmrg intel_output->backlight_active_level = intel_output_backlight_get(output); 1016428d7b3dSmrg intel_output_backlight_set(output, 0); 1017428d7b3dSmrg } 1018428d7b3dSmrg} 1019428d7b3dSmrg 1020428d7b3dSmrgstatic void 1021428d7b3dSmrgintel_output_dpms(xf86OutputPtr output, int dpms) 1022428d7b3dSmrg{ 1023428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 1024428d7b3dSmrg drmModeConnectorPtr koutput = intel_output->mode_output; 1025428d7b3dSmrg struct intel_mode *mode = intel_output->mode; 1026428d7b3dSmrg int i; 1027428d7b3dSmrg 1028428d7b3dSmrg if (!koutput) 1029428d7b3dSmrg return; 1030428d7b3dSmrg 1031428d7b3dSmrg for (i = 0; i < koutput->count_props; i++) { 1032428d7b3dSmrg drmModePropertyPtr props; 1033428d7b3dSmrg 1034428d7b3dSmrg props = drmModeGetProperty(mode->fd, koutput->props[i]); 1035428d7b3dSmrg if (!props) 1036428d7b3dSmrg continue; 1037428d7b3dSmrg 1038428d7b3dSmrg if (!strcmp(props->name, "DPMS")) { 1039428d7b3dSmrg /* Make sure to reverse the order between on and off. */ 1040428d7b3dSmrg if (dpms != DPMSModeOn) 1041428d7b3dSmrg intel_output_dpms_backlight(output, 1042428d7b3dSmrg intel_output->dpms_mode, 1043428d7b3dSmrg dpms); 1044428d7b3dSmrg 1045428d7b3dSmrg drmModeConnectorSetProperty(mode->fd, 1046428d7b3dSmrg intel_output->output_id, 1047428d7b3dSmrg props->prop_id, 1048428d7b3dSmrg dpms); 1049428d7b3dSmrg 1050428d7b3dSmrg if (dpms == DPMSModeOn) 1051428d7b3dSmrg intel_output_dpms_backlight(output, 1052428d7b3dSmrg intel_output->dpms_mode, 1053428d7b3dSmrg dpms); 1054428d7b3dSmrg intel_output->dpms_mode = dpms; 1055428d7b3dSmrg drmModeFreeProperty(props); 1056428d7b3dSmrg return; 1057428d7b3dSmrg } 1058428d7b3dSmrg 1059428d7b3dSmrg drmModeFreeProperty(props); 1060428d7b3dSmrg } 1061428d7b3dSmrg} 1062428d7b3dSmrg 1063428d7b3dSmrgint 1064428d7b3dSmrgintel_output_dpms_status(xf86OutputPtr output) 1065428d7b3dSmrg{ 1066428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 1067428d7b3dSmrg return intel_output->dpms_mode; 1068428d7b3dSmrg} 1069428d7b3dSmrg 1070428d7b3dSmrgstatic Bool 1071428d7b3dSmrgintel_property_ignore(drmModePropertyPtr prop) 1072428d7b3dSmrg{ 1073428d7b3dSmrg if (!prop) 1074428d7b3dSmrg return TRUE; 1075428d7b3dSmrg 1076428d7b3dSmrg /* ignore blob prop */ 1077428d7b3dSmrg if (prop->flags & DRM_MODE_PROP_BLOB) 1078428d7b3dSmrg return TRUE; 1079428d7b3dSmrg 1080428d7b3dSmrg /* ignore standard property */ 1081428d7b3dSmrg if (!strcmp(prop->name, "EDID") || 1082428d7b3dSmrg !strcmp(prop->name, "DPMS")) 1083428d7b3dSmrg return TRUE; 1084428d7b3dSmrg 1085428d7b3dSmrg return FALSE; 1086428d7b3dSmrg} 1087428d7b3dSmrg 1088428d7b3dSmrgstatic void 1089428d7b3dSmrgintel_output_create_ranged_atom(xf86OutputPtr output, Atom *atom, 1090428d7b3dSmrg const char *name, INT32 min, INT32 max, 1091428d7b3dSmrg uint64_t value, Bool immutable) 1092428d7b3dSmrg{ 1093428d7b3dSmrg int err; 1094428d7b3dSmrg INT32 atom_range[2]; 1095428d7b3dSmrg 1096428d7b3dSmrg atom_range[0] = min; 1097428d7b3dSmrg atom_range[1] = max; 1098428d7b3dSmrg 1099428d7b3dSmrg *atom = MakeAtom(name, strlen(name), TRUE); 1100428d7b3dSmrg 1101428d7b3dSmrg err = RRConfigureOutputProperty(output->randr_output, *atom, FALSE, 1102428d7b3dSmrg TRUE, immutable, 2, atom_range); 1103428d7b3dSmrg if (err != 0) 1104428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1105428d7b3dSmrg "RRConfigureOutputProperty error, %d\n", err); 1106428d7b3dSmrg 1107428d7b3dSmrg err = RRChangeOutputProperty(output->randr_output, *atom, XA_INTEGER, 1108428d7b3dSmrg 32, PropModeReplace, 1, &value, FALSE, 1109428d7b3dSmrg FALSE); 1110428d7b3dSmrg if (err != 0) 1111428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1112428d7b3dSmrg "RRChangeOutputProperty error, %d\n", err); 1113428d7b3dSmrg} 1114428d7b3dSmrg 1115428d7b3dSmrg#define BACKLIGHT_NAME "Backlight" 1116428d7b3dSmrg#define BACKLIGHT_DEPRECATED_NAME "BACKLIGHT" 1117428d7b3dSmrgstatic Atom backlight_atom, backlight_deprecated_atom; 1118428d7b3dSmrg 1119428d7b3dSmrgstatic void 1120428d7b3dSmrgintel_output_create_resources(xf86OutputPtr output) 1121428d7b3dSmrg{ 1122428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 1123428d7b3dSmrg drmModeConnectorPtr mode_output = intel_output->mode_output; 1124428d7b3dSmrg struct intel_mode *mode = intel_output->mode; 1125428d7b3dSmrg int i, j, err; 1126428d7b3dSmrg 1127428d7b3dSmrg intel_output->props = calloc(mode_output->count_props, 1128428d7b3dSmrg sizeof(struct intel_property)); 1129428d7b3dSmrg if (!intel_output->props) 1130428d7b3dSmrg return; 1131428d7b3dSmrg 1132428d7b3dSmrg intel_output->num_props = 0; 1133428d7b3dSmrg for (i = j = 0; i < mode_output->count_props; i++) { 1134428d7b3dSmrg drmModePropertyPtr drmmode_prop; 1135428d7b3dSmrg 1136428d7b3dSmrg drmmode_prop = drmModeGetProperty(mode->fd, 1137428d7b3dSmrg mode_output->props[i]); 1138428d7b3dSmrg if (intel_property_ignore(drmmode_prop)) { 1139428d7b3dSmrg drmModeFreeProperty(drmmode_prop); 1140428d7b3dSmrg continue; 1141428d7b3dSmrg } 1142428d7b3dSmrg 1143428d7b3dSmrg intel_output->props[j].mode_prop = drmmode_prop; 1144428d7b3dSmrg intel_output->props[j].value = mode_output->prop_values[i]; 1145428d7b3dSmrg j++; 1146428d7b3dSmrg } 1147428d7b3dSmrg intel_output->num_props = j; 1148428d7b3dSmrg 1149428d7b3dSmrg for (i = 0; i < intel_output->num_props; i++) { 1150428d7b3dSmrg struct intel_property *p = &intel_output->props[i]; 1151428d7b3dSmrg drmModePropertyPtr drmmode_prop = p->mode_prop; 1152428d7b3dSmrg 1153428d7b3dSmrg if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) { 1154428d7b3dSmrg p->num_atoms = 1; 1155428d7b3dSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1156428d7b3dSmrg if (!p->atoms) 1157428d7b3dSmrg continue; 1158428d7b3dSmrg 1159428d7b3dSmrg intel_output_create_ranged_atom(output, &p->atoms[0], 1160428d7b3dSmrg drmmode_prop->name, 1161428d7b3dSmrg drmmode_prop->values[0], 1162428d7b3dSmrg drmmode_prop->values[1], 1163428d7b3dSmrg p->value, 1164428d7b3dSmrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE); 1165428d7b3dSmrg 1166428d7b3dSmrg } else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) { 1167428d7b3dSmrg p->num_atoms = drmmode_prop->count_enums + 1; 1168428d7b3dSmrg p->atoms = calloc(p->num_atoms, sizeof(Atom)); 1169428d7b3dSmrg if (!p->atoms) 1170428d7b3dSmrg continue; 1171428d7b3dSmrg 1172428d7b3dSmrg p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE); 1173428d7b3dSmrg for (j = 1; j <= drmmode_prop->count_enums; j++) { 1174428d7b3dSmrg struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1]; 1175428d7b3dSmrg p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE); 1176428d7b3dSmrg } 1177428d7b3dSmrg 1178428d7b3dSmrg err = RRConfigureOutputProperty(output->randr_output, p->atoms[0], 1179428d7b3dSmrg FALSE, FALSE, 1180428d7b3dSmrg drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE, 1181428d7b3dSmrg p->num_atoms - 1, (INT32 *)&p->atoms[1]); 1182428d7b3dSmrg if (err != 0) { 1183428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1184428d7b3dSmrg "RRConfigureOutputProperty error, %d\n", err); 1185428d7b3dSmrg } 1186428d7b3dSmrg 1187428d7b3dSmrg for (j = 0; j < drmmode_prop->count_enums; j++) 1188428d7b3dSmrg if (drmmode_prop->enums[j].value == p->value) 1189428d7b3dSmrg break; 1190428d7b3dSmrg /* there's always a matching value */ 1191428d7b3dSmrg err = RRChangeOutputProperty(output->randr_output, p->atoms[0], 1192428d7b3dSmrg XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, FALSE); 1193428d7b3dSmrg if (err != 0) { 1194428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1195428d7b3dSmrg "RRChangeOutputProperty error, %d\n", err); 1196428d7b3dSmrg } 1197428d7b3dSmrg } 1198428d7b3dSmrg } 1199428d7b3dSmrg 1200428d7b3dSmrg if (intel_output->backlight.iface) { 1201428d7b3dSmrg /* Set up the backlight property, which takes effect 1202428d7b3dSmrg * immediately and accepts values only within the 1203428d7b3dSmrg * backlight_range. 1204428d7b3dSmrg */ 1205428d7b3dSmrg intel_output_create_ranged_atom(output, &backlight_atom, 1206428d7b3dSmrg BACKLIGHT_NAME, 0, 1207428d7b3dSmrg intel_output->backlight.max, 1208428d7b3dSmrg intel_output->backlight_active_level, 1209428d7b3dSmrg FALSE); 1210428d7b3dSmrg intel_output_create_ranged_atom(output, 1211428d7b3dSmrg &backlight_deprecated_atom, 1212428d7b3dSmrg BACKLIGHT_DEPRECATED_NAME, 0, 1213428d7b3dSmrg intel_output->backlight.max, 1214428d7b3dSmrg intel_output->backlight_active_level, 1215428d7b3dSmrg FALSE); 1216428d7b3dSmrg } 1217428d7b3dSmrg} 1218428d7b3dSmrg 1219428d7b3dSmrgstatic Bool 1220428d7b3dSmrgintel_output_set_property(xf86OutputPtr output, Atom property, 1221428d7b3dSmrg RRPropertyValuePtr value) 1222428d7b3dSmrg{ 1223428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 1224428d7b3dSmrg struct intel_mode *mode = intel_output->mode; 1225428d7b3dSmrg int i; 1226428d7b3dSmrg 1227428d7b3dSmrg if (property == backlight_atom || property == backlight_deprecated_atom) { 1228428d7b3dSmrg INT32 val; 1229428d7b3dSmrg 1230428d7b3dSmrg if (value->type != XA_INTEGER || value->format != 32 || 1231428d7b3dSmrg value->size != 1) 1232428d7b3dSmrg { 1233428d7b3dSmrg return FALSE; 1234428d7b3dSmrg } 1235428d7b3dSmrg 1236428d7b3dSmrg val = *(INT32 *)value->data; 1237428d7b3dSmrg if (val < 0 || val > intel_output->backlight.max) 1238428d7b3dSmrg return FALSE; 1239428d7b3dSmrg 1240428d7b3dSmrg if (intel_output->dpms_mode == DPMSModeOn) 1241428d7b3dSmrg intel_output_backlight_set(output, val); 1242428d7b3dSmrg intel_output->backlight_active_level = val; 1243428d7b3dSmrg return TRUE; 1244428d7b3dSmrg } 1245428d7b3dSmrg 1246428d7b3dSmrg for (i = 0; i < intel_output->num_props; i++) { 1247428d7b3dSmrg struct intel_property *p = &intel_output->props[i]; 1248428d7b3dSmrg 1249428d7b3dSmrg if (p->atoms[0] != property) 1250428d7b3dSmrg continue; 1251428d7b3dSmrg 1252428d7b3dSmrg if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) { 1253428d7b3dSmrg uint32_t val; 1254428d7b3dSmrg 1255428d7b3dSmrg if (value->type != XA_INTEGER || value->format != 32 || 1256428d7b3dSmrg value->size != 1) 1257428d7b3dSmrg return FALSE; 1258428d7b3dSmrg val = *(uint32_t *)value->data; 1259428d7b3dSmrg 1260428d7b3dSmrg drmModeConnectorSetProperty(mode->fd, intel_output->output_id, 1261428d7b3dSmrg p->mode_prop->prop_id, (uint64_t)val); 1262428d7b3dSmrg return TRUE; 1263428d7b3dSmrg } else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) { 1264428d7b3dSmrg Atom atom; 1265428d7b3dSmrg const char *name; 1266428d7b3dSmrg int j; 1267428d7b3dSmrg 1268428d7b3dSmrg if (value->type != XA_ATOM || value->format != 32 || value->size != 1) 1269428d7b3dSmrg return FALSE; 1270428d7b3dSmrg memcpy(&atom, value->data, 4); 1271428d7b3dSmrg name = NameForAtom(atom); 1272428d7b3dSmrg if (name == NULL) 1273428d7b3dSmrg return FALSE; 1274428d7b3dSmrg 1275428d7b3dSmrg /* search for matching name string, then set its value down */ 1276428d7b3dSmrg for (j = 0; j < p->mode_prop->count_enums; j++) { 1277428d7b3dSmrg if (!strcmp(p->mode_prop->enums[j].name, name)) { 1278428d7b3dSmrg drmModeConnectorSetProperty(mode->fd, intel_output->output_id, 1279428d7b3dSmrg p->mode_prop->prop_id, p->mode_prop->enums[j].value); 1280428d7b3dSmrg return TRUE; 1281428d7b3dSmrg } 1282428d7b3dSmrg } 1283428d7b3dSmrg return FALSE; 1284428d7b3dSmrg } 1285428d7b3dSmrg } 1286428d7b3dSmrg 1287428d7b3dSmrg /* We didn't recognise this property, just report success in order 1288428d7b3dSmrg * to allow the set to continue, otherwise we break setting of 1289428d7b3dSmrg * common properties like EDID. 1290428d7b3dSmrg */ 1291428d7b3dSmrg return TRUE; 1292428d7b3dSmrg} 1293428d7b3dSmrg 1294428d7b3dSmrgstatic Bool 1295428d7b3dSmrgintel_output_get_property(xf86OutputPtr output, Atom property) 1296428d7b3dSmrg{ 1297428d7b3dSmrg struct intel_output *intel_output = output->driver_private; 1298428d7b3dSmrg int err; 1299428d7b3dSmrg 1300428d7b3dSmrg if (property == backlight_atom || property == backlight_deprecated_atom) { 1301428d7b3dSmrg INT32 val; 1302428d7b3dSmrg 1303428d7b3dSmrg if (!intel_output->backlight.iface) 1304428d7b3dSmrg return FALSE; 1305428d7b3dSmrg 1306428d7b3dSmrg if (intel_output->dpms_mode == DPMSModeOn) { 1307428d7b3dSmrg val = intel_output_backlight_get(output); 1308428d7b3dSmrg if (val < 0) 1309428d7b3dSmrg return FALSE; 1310428d7b3dSmrg } else { 1311428d7b3dSmrg val = intel_output->backlight_active_level; 1312428d7b3dSmrg } 1313428d7b3dSmrg 1314428d7b3dSmrg err = RRChangeOutputProperty(output->randr_output, property, 1315428d7b3dSmrg XA_INTEGER, 32, PropModeReplace, 1, &val, 1316428d7b3dSmrg FALSE, FALSE); 1317428d7b3dSmrg if (err != 0) { 1318428d7b3dSmrg xf86DrvMsg(output->scrn->scrnIndex, X_ERROR, 1319428d7b3dSmrg "RRChangeOutputProperty error, %d\n", err); 1320428d7b3dSmrg return FALSE; 1321428d7b3dSmrg } 1322428d7b3dSmrg 1323428d7b3dSmrg return TRUE; 1324428d7b3dSmrg } 1325428d7b3dSmrg 1326428d7b3dSmrg return FALSE; 1327428d7b3dSmrg} 1328428d7b3dSmrg 1329428d7b3dSmrgstatic const xf86OutputFuncsRec intel_output_funcs = { 1330428d7b3dSmrg .create_resources = intel_output_create_resources, 1331428d7b3dSmrg#ifdef RANDR_12_INTERFACE 1332428d7b3dSmrg .set_property = intel_output_set_property, 1333428d7b3dSmrg .get_property = intel_output_get_property, 1334428d7b3dSmrg#endif 1335428d7b3dSmrg .dpms = intel_output_dpms, 1336428d7b3dSmrg#if 0 1337428d7b3dSmrg 1338428d7b3dSmrg .save = drmmode_crt_save, 1339428d7b3dSmrg .restore = drmmode_crt_restore, 1340428d7b3dSmrg .mode_fixup = drmmode_crt_mode_fixup, 1341428d7b3dSmrg .prepare = intel_output_prepare, 1342428d7b3dSmrg .mode_set = drmmode_crt_mode_set, 1343428d7b3dSmrg .commit = intel_output_commit, 1344428d7b3dSmrg#endif 1345428d7b3dSmrg .detect = intel_output_detect, 1346428d7b3dSmrg .mode_valid = intel_output_mode_valid, 1347428d7b3dSmrg 1348428d7b3dSmrg .get_modes = intel_output_get_modes, 1349428d7b3dSmrg .destroy = intel_output_destroy 1350428d7b3dSmrg}; 1351428d7b3dSmrg 1352428d7b3dSmrgstatic const int subpixel_conv_table[7] = { 1353428d7b3dSmrg 0, 1354428d7b3dSmrg SubPixelUnknown, 1355428d7b3dSmrg SubPixelHorizontalRGB, 1356428d7b3dSmrg SubPixelHorizontalBGR, 1357428d7b3dSmrg SubPixelVerticalRGB, 1358428d7b3dSmrg SubPixelVerticalBGR, 1359428d7b3dSmrg SubPixelNone 1360428d7b3dSmrg}; 1361428d7b3dSmrg 1362428d7b3dSmrgstatic const char *output_names[] = { 1363428d7b3dSmrg "None", 1364428d7b3dSmrg "VGA", 1365428d7b3dSmrg "DVI", 1366428d7b3dSmrg "DVI", 1367428d7b3dSmrg "DVI", 1368428d7b3dSmrg "Composite", 1369428d7b3dSmrg "TV", 1370428d7b3dSmrg "LVDS", 1371428d7b3dSmrg "CTV", 1372428d7b3dSmrg "DIN", 1373428d7b3dSmrg "DP", 1374428d7b3dSmrg "HDMI", 1375428d7b3dSmrg "HDMI", 1376428d7b3dSmrg "TV", 1377428d7b3dSmrg "eDP", 1378428d7b3dSmrg}; 1379428d7b3dSmrg 1380428d7b3dSmrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id) 1381428d7b3dSmrg{ 1382428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn); 1383428d7b3dSmrg int i; 1384428d7b3dSmrg for (i = 0; i < xf86_config->num_output; i++) { 1385428d7b3dSmrg xf86OutputPtr output = xf86_config->output[i]; 1386428d7b3dSmrg struct intel_output *intel_output; 1387428d7b3dSmrg 1388428d7b3dSmrg intel_output = output->driver_private; 1389428d7b3dSmrg if (intel_output->output_id == id) 1390428d7b3dSmrg return output; 1391428d7b3dSmrg } 1392428d7b3dSmrg return NULL; 1393428d7b3dSmrg} 1394428d7b3dSmrg 1395428d7b3dSmrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path) 1396428d7b3dSmrg{ 1397428d7b3dSmrg char *conn; 1398428d7b3dSmrg char conn_id[5]; 1399428d7b3dSmrg int id, len; 1400428d7b3dSmrg char *blob_data; 1401428d7b3dSmrg 1402428d7b3dSmrg if (!path_blob) 1403428d7b3dSmrg return -1; 1404428d7b3dSmrg 1405428d7b3dSmrg blob_data = path_blob->data; 1406428d7b3dSmrg /* we only handle MST paths for now */ 1407428d7b3dSmrg if (strncmp(blob_data, "mst:", 4)) 1408428d7b3dSmrg return -1; 1409428d7b3dSmrg 1410428d7b3dSmrg conn = strchr(blob_data + 4, '-'); 1411428d7b3dSmrg if (!conn) 1412428d7b3dSmrg return -1; 1413428d7b3dSmrg len = conn - (blob_data + 4); 1414428d7b3dSmrg if (len + 1 > 5) 1415428d7b3dSmrg return -1; 1416428d7b3dSmrg memcpy(conn_id, blob_data + 4, len); 1417428d7b3dSmrg conn_id[len] = '\0'; 1418428d7b3dSmrg id = strtoul(conn_id, NULL, 10); 1419428d7b3dSmrg 1420428d7b3dSmrg *conn_base_id = id; 1421428d7b3dSmrg 1422428d7b3dSmrg *path = conn + 1; 1423428d7b3dSmrg return 0; 1424428d7b3dSmrg} 1425428d7b3dSmrg 1426428d7b3dSmrgstatic void 1427428d7b3dSmrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name, 1428428d7b3dSmrg drmModePropertyBlobPtr path_blob) 1429428d7b3dSmrg{ 1430428d7b3dSmrg xf86OutputPtr output; 1431428d7b3dSmrg int conn_id; 1432428d7b3dSmrg char *extra_path; 1433428d7b3dSmrg 1434428d7b3dSmrg output = NULL; 1435428d7b3dSmrg if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0) 1436428d7b3dSmrg output = find_output(pScrn, conn_id); 1437428d7b3dSmrg if (output) { 1438428d7b3dSmrg snprintf(name, 32, "%s-%s", output->name, extra_path); 1439428d7b3dSmrg } else { 1440428d7b3dSmrg const char *output_name; 1441428d7b3dSmrg 1442428d7b3dSmrg if (koutput->connector_type < ARRAY_SIZE(output_names)) 1443428d7b3dSmrg output_name = output_names[koutput->connector_type]; 1444428d7b3dSmrg else 1445428d7b3dSmrg output_name = "UNKNOWN"; 1446428d7b3dSmrg 1447428d7b3dSmrg snprintf(name, 32, "%s%d", 1448428d7b3dSmrg output_name, koutput->connector_type_id); 1449428d7b3dSmrg } 1450428d7b3dSmrg} 1451428d7b3dSmrg 1452428d7b3dSmrgstatic void 1453428d7b3dSmrgintel_output_init(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_res, int num, int dynamic) 1454428d7b3dSmrg{ 1455428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1456428d7b3dSmrg xf86OutputPtr output; 1457428d7b3dSmrg drmModeConnectorPtr koutput; 1458428d7b3dSmrg drmModeEncoderPtr *kencoders = NULL; 1459428d7b3dSmrg struct intel_output *intel_output; 1460428d7b3dSmrg char name[32]; 1461428d7b3dSmrg drmModePropertyPtr props; 1462428d7b3dSmrg drmModePropertyBlobPtr path_blob = NULL; 1463428d7b3dSmrg int i; 1464428d7b3dSmrg 1465428d7b3dSmrg koutput = drmModeGetConnector(mode->fd, 1466428d7b3dSmrg mode_res->connectors[num]); 1467428d7b3dSmrg if (!koutput) 1468428d7b3dSmrg return; 1469428d7b3dSmrg for (i = 0; i < koutput->count_props; i++) { 1470428d7b3dSmrg props = drmModeGetProperty(mode->fd, koutput->props[i]); 1471428d7b3dSmrg if (props && (props->flags & DRM_MODE_PROP_BLOB)) { 1472428d7b3dSmrg if (!strcmp(props->name, "PATH")) { 1473428d7b3dSmrg path_blob = drmModeGetPropertyBlob(mode->fd, koutput->prop_values[i]); 1474428d7b3dSmrg 1475428d7b3dSmrg drmModeFreeProperty(props); 1476428d7b3dSmrg break; 1477428d7b3dSmrg } 1478428d7b3dSmrg drmModeFreeProperty(props); 1479428d7b3dSmrg } 1480428d7b3dSmrg } 1481428d7b3dSmrg 1482428d7b3dSmrg drmmode_create_name(scrn, koutput, name, path_blob); 1483428d7b3dSmrg if (path_blob) 1484428d7b3dSmrg drmModeFreePropertyBlob(path_blob); 1485428d7b3dSmrg 1486428d7b3dSmrg if (path_blob && dynamic) { 1487428d7b3dSmrg /* See if we have an output with this name already 1488428d7b3dSmrg * and hook stuff up. 1489428d7b3dSmrg */ 1490428d7b3dSmrg for (i = 0; i < xf86_config->num_output; i++) { 1491428d7b3dSmrg output = xf86_config->output[i]; 1492428d7b3dSmrg 1493428d7b3dSmrg if (strncmp(output->name, name, 32)) 1494428d7b3dSmrg continue; 1495428d7b3dSmrg 1496428d7b3dSmrg intel_output = output->driver_private; 1497428d7b3dSmrg intel_output->output_id = mode_res->connectors[num]; 1498428d7b3dSmrg intel_output->mode_output = koutput; 1499428d7b3dSmrg return; 1500428d7b3dSmrg } 1501428d7b3dSmrg } 1502428d7b3dSmrg kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders); 1503428d7b3dSmrg if (!kencoders) { 1504428d7b3dSmrg goto out_free_encoders; 1505428d7b3dSmrg } 1506428d7b3dSmrg 1507428d7b3dSmrg for (i = 0; i < koutput->count_encoders; i++) { 1508428d7b3dSmrg kencoders[i] = drmModeGetEncoder(mode->fd, koutput->encoders[i]); 1509428d7b3dSmrg if (!kencoders[i]) 1510428d7b3dSmrg goto out_free_encoders; 1511428d7b3dSmrg } 1512428d7b3dSmrg 1513428d7b3dSmrg output = xf86OutputCreate (scrn, &intel_output_funcs, name); 1514428d7b3dSmrg if (!output) { 1515428d7b3dSmrg goto out_free_encoders; 1516428d7b3dSmrg } 1517428d7b3dSmrg 1518428d7b3dSmrg intel_output = calloc(sizeof(struct intel_output), 1); 1519428d7b3dSmrg if (!intel_output) { 1520428d7b3dSmrg xf86OutputDestroy(output); 1521428d7b3dSmrg goto out_free_encoders; 1522428d7b3dSmrg } 1523428d7b3dSmrg 1524428d7b3dSmrg intel_output->output_id = mode_res->connectors[num]; 1525428d7b3dSmrg intel_output->mode_output = koutput; 1526428d7b3dSmrg intel_output->mode_encoders = kencoders; 1527428d7b3dSmrg intel_output->mode = mode; 1528428d7b3dSmrg 1529428d7b3dSmrg output->mm_width = koutput->mmWidth; 1530428d7b3dSmrg output->mm_height = koutput->mmHeight; 1531428d7b3dSmrg 1532428d7b3dSmrg output->subpixel_order = subpixel_conv_table[koutput->subpixel]; 1533428d7b3dSmrg output->driver_private = intel_output; 1534428d7b3dSmrg 1535428d7b3dSmrg if (is_panel(koutput->connector_type)) 1536428d7b3dSmrg intel_output_backlight_init(output); 1537428d7b3dSmrg 1538428d7b3dSmrg output->possible_crtcs = 0x7f; 1539428d7b3dSmrg for (i = 0; i < koutput->count_encoders; i++) { 1540428d7b3dSmrg output->possible_crtcs &= kencoders[i]->possible_crtcs; 1541428d7b3dSmrg } 1542428d7b3dSmrg output->interlaceAllowed = TRUE; 1543428d7b3dSmrg 1544428d7b3dSmrg intel_output->output = output; 1545428d7b3dSmrg 1546428d7b3dSmrg if (dynamic) { 1547428d7b3dSmrg output->randr_output = RROutputCreate(xf86ScrnToScreen(scrn), output->name, strlen(output->name), output); 1548428d7b3dSmrg intel_output_create_resources(output); 1549428d7b3dSmrg } 1550428d7b3dSmrg 1551428d7b3dSmrg list_add(&intel_output->link, &mode->outputs); 1552428d7b3dSmrg return; 1553428d7b3dSmrg 1554428d7b3dSmrgout_free_encoders: 1555428d7b3dSmrg if (kencoders) { 1556428d7b3dSmrg for (i = 0; i < koutput->count_encoders; i++) 1557428d7b3dSmrg drmModeFreeEncoder(kencoders[i]); 1558428d7b3dSmrg free(kencoders); 1559428d7b3dSmrg } 1560428d7b3dSmrg drmModeFreeConnector(koutput); 1561428d7b3dSmrg} 1562428d7b3dSmrg 1563428d7b3dSmrgstatic Bool 1564428d7b3dSmrgintel_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height) 1565428d7b3dSmrg{ 1566428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 1567428d7b3dSmrg struct intel_crtc *intel_crtc = xf86_config->crtc[0]->driver_private; 1568428d7b3dSmrg struct intel_mode *mode = intel_crtc->mode; 1569428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 1570428d7b3dSmrg drm_intel_bo *old_front = NULL; 1571428d7b3dSmrg Bool ret; 1572428d7b3dSmrg uint32_t old_fb_id; 1573428d7b3dSmrg int i, old_width, old_height, old_pitch; 1574428d7b3dSmrg int pitch; 1575428d7b3dSmrg uint32_t tiling; 1576428d7b3dSmrg 1577428d7b3dSmrg if (scrn->virtualX == width && scrn->virtualY == height) 1578428d7b3dSmrg return TRUE; 1579428d7b3dSmrg 1580428d7b3dSmrg intel_flush(intel); 1581428d7b3dSmrg 1582428d7b3dSmrg old_width = scrn->virtualX; 1583428d7b3dSmrg old_height = scrn->virtualY; 1584428d7b3dSmrg old_pitch = scrn->displayWidth; 1585428d7b3dSmrg old_fb_id = mode->fb_id; 1586428d7b3dSmrg old_front = intel->front_buffer; 1587428d7b3dSmrg 1588428d7b3dSmrg if (intel->back_buffer) { 1589428d7b3dSmrg drm_intel_bo_unreference(intel->back_buffer); 1590428d7b3dSmrg intel->back_buffer = NULL; 1591428d7b3dSmrg } 1592428d7b3dSmrg 1593428d7b3dSmrg intel->front_buffer = intel_allocate_framebuffer(scrn, 1594428d7b3dSmrg width, height, 1595428d7b3dSmrg intel->cpp, 1596428d7b3dSmrg &pitch, &tiling); 1597428d7b3dSmrg if (!intel->front_buffer) 1598428d7b3dSmrg goto fail; 1599428d7b3dSmrg 1600428d7b3dSmrg ret = drmModeAddFB(mode->fd, width, height, scrn->depth, 1601428d7b3dSmrg scrn->bitsPerPixel, pitch, 1602428d7b3dSmrg intel->front_buffer->handle, 1603428d7b3dSmrg &mode->fb_id); 1604428d7b3dSmrg if (ret) 1605428d7b3dSmrg goto fail; 1606428d7b3dSmrg 1607428d7b3dSmrg intel->front_pitch = pitch; 1608428d7b3dSmrg intel->front_tiling = tiling; 1609428d7b3dSmrg 1610428d7b3dSmrg scrn->virtualX = width; 1611428d7b3dSmrg scrn->virtualY = height; 1612428d7b3dSmrg 1613428d7b3dSmrg if (!intel_uxa_create_screen_resources(scrn->pScreen)) 1614428d7b3dSmrg goto fail; 1615428d7b3dSmrg 1616428d7b3dSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 1617428d7b3dSmrg xf86CrtcPtr crtc = xf86_config->crtc[i]; 1618428d7b3dSmrg 1619428d7b3dSmrg if (!crtc->enabled) 1620428d7b3dSmrg continue; 1621428d7b3dSmrg 1622428d7b3dSmrg if (!intel_crtc_apply(crtc)) 1623428d7b3dSmrg goto fail; 1624428d7b3dSmrg } 1625428d7b3dSmrg 1626428d7b3dSmrg if (old_fb_id) 1627428d7b3dSmrg drmModeRmFB(mode->fd, old_fb_id); 1628428d7b3dSmrg if (old_front) 1629428d7b3dSmrg drm_intel_bo_unreference(old_front); 1630428d7b3dSmrg 1631428d7b3dSmrg return TRUE; 1632428d7b3dSmrg 1633428d7b3dSmrgfail: 1634428d7b3dSmrg if (intel->front_buffer) 1635428d7b3dSmrg drm_intel_bo_unreference(intel->front_buffer); 1636428d7b3dSmrg intel->front_buffer = old_front; 1637428d7b3dSmrg scrn->virtualX = old_width; 1638428d7b3dSmrg scrn->virtualY = old_height; 1639428d7b3dSmrg scrn->displayWidth = old_pitch; 1640428d7b3dSmrg if (old_fb_id != mode->fb_id) 1641428d7b3dSmrg drmModeRmFB(mode->fd, mode->fb_id); 1642428d7b3dSmrg mode->fb_id = old_fb_id; 1643428d7b3dSmrg 1644428d7b3dSmrg return FALSE; 1645428d7b3dSmrg} 1646428d7b3dSmrg 1647428d7b3dSmrgstatic void 1648428d7b3dSmrgintel_pageflip_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc, 1649428d7b3dSmrg uint64_t frame, uint64_t usec, void *data); 1650428d7b3dSmrg 1651428d7b3dSmrgstatic void 1652428d7b3dSmrgintel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data); 1653428d7b3dSmrg 1654428d7b3dSmrgstatic void 1655428d7b3dSmrgintel_pageflip_complete(struct intel_mode *mode); 1656428d7b3dSmrg 1657428d7b3dSmrgstatic void 1658428d7b3dSmrgintel_drm_abort_seq (ScrnInfoPtr scrn, uint32_t seq); 1659428d7b3dSmrg 1660428d7b3dSmrgBool 1661428d7b3dSmrgintel_do_pageflip(intel_screen_private *intel, 1662428d7b3dSmrg dri_bo *new_front, 1663428d7b3dSmrg int ref_crtc_hw_id, 1664428d7b3dSmrg Bool async, 1665428d7b3dSmrg void *pageflip_data, 1666428d7b3dSmrg intel_pageflip_handler_proc pageflip_handler, 1667428d7b3dSmrg intel_pageflip_abort_proc pageflip_abort) 1668428d7b3dSmrg{ 1669428d7b3dSmrg ScrnInfoPtr scrn = intel->scrn; 1670428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 1671428d7b3dSmrg struct intel_crtc *crtc = config->crtc[0]->driver_private; 1672428d7b3dSmrg struct intel_mode *mode = crtc->mode; 1673428d7b3dSmrg unsigned int pitch = scrn->displayWidth * intel->cpp; 1674428d7b3dSmrg struct intel_pageflip *flip; 1675428d7b3dSmrg uint32_t new_fb_id; 1676428d7b3dSmrg uint32_t flags; 1677428d7b3dSmrg uint32_t seq; 1678428d7b3dSmrg int i; 1679428d7b3dSmrg 1680428d7b3dSmrg /* 1681428d7b3dSmrg * Create a new handle for the back buffer 1682428d7b3dSmrg */ 1683428d7b3dSmrg if (drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY, 1684428d7b3dSmrg scrn->depth, scrn->bitsPerPixel, pitch, 1685428d7b3dSmrg new_front->handle, &new_fb_id)) 1686428d7b3dSmrg goto error_out; 1687428d7b3dSmrg 1688428d7b3dSmrg drm_intel_bo_disable_reuse(new_front); 1689428d7b3dSmrg intel_flush(intel); 1690428d7b3dSmrg 1691428d7b3dSmrg mode->pageflip_data = pageflip_data; 1692428d7b3dSmrg mode->pageflip_handler = pageflip_handler; 1693428d7b3dSmrg mode->pageflip_abort = pageflip_abort; 1694428d7b3dSmrg 1695428d7b3dSmrg /* 1696428d7b3dSmrg * Queue flips on all enabled CRTCs 1697428d7b3dSmrg * Note that if/when we get per-CRTC buffers, we'll have to update this. 1698428d7b3dSmrg * Right now it assumes a single shared fb across all CRTCs, with the 1699428d7b3dSmrg * kernel fixing up the offset of each CRTC as necessary. 1700428d7b3dSmrg * 1701428d7b3dSmrg * Also, flips queued on disabled or incorrectly configured displays 1702428d7b3dSmrg * may never complete; this is a configuration error. 1703428d7b3dSmrg */ 1704428d7b3dSmrg mode->fe_msc = 0; 1705428d7b3dSmrg mode->fe_usec = 0; 1706428d7b3dSmrg 1707428d7b3dSmrg flags = DRM_MODE_PAGE_FLIP_EVENT; 1708428d7b3dSmrg if (async) 1709428d7b3dSmrg flags |= DRM_MODE_PAGE_FLIP_ASYNC; 1710428d7b3dSmrg for (i = 0; i < config->num_crtc; i++) { 1711428d7b3dSmrg if (!intel_crtc_on(config->crtc[i])) 1712428d7b3dSmrg continue; 1713428d7b3dSmrg 1714428d7b3dSmrg crtc = config->crtc[i]->driver_private; 1715428d7b3dSmrg 1716428d7b3dSmrg flip = calloc(1, sizeof(struct intel_pageflip)); 1717428d7b3dSmrg if (flip == NULL) { 1718428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1719428d7b3dSmrg "flip queue: carrier alloc failed.\n"); 1720428d7b3dSmrg goto error_undo; 1721428d7b3dSmrg } 1722428d7b3dSmrg 1723428d7b3dSmrg /* Only the reference crtc will finally deliver its page flip 1724428d7b3dSmrg * completion event. All other crtc's events will be discarded. 1725428d7b3dSmrg */ 1726428d7b3dSmrg flip->dispatch_me = (intel_crtc_to_pipe(crtc->crtc) == ref_crtc_hw_id); 1727428d7b3dSmrg flip->mode = mode; 1728428d7b3dSmrg 1729428d7b3dSmrg seq = intel_drm_queue_alloc(scrn, config->crtc[i], flip, intel_pageflip_handler, intel_pageflip_abort); 1730428d7b3dSmrg if (!seq) { 1731428d7b3dSmrg free(flip); 1732428d7b3dSmrg goto error_undo; 1733428d7b3dSmrg } 1734428d7b3dSmrg 1735428d7b3dSmrgagain: 1736428d7b3dSmrg if (drmModePageFlip(mode->fd, 1737428d7b3dSmrg crtc_id(crtc), 1738428d7b3dSmrg new_fb_id, 1739428d7b3dSmrg flags, (void *)(uintptr_t)seq)) { 1740428d7b3dSmrg if (intel_mode_read_drm_events(intel)) { 1741428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1742428d7b3dSmrg "flip queue retry\n"); 1743428d7b3dSmrg goto again; 1744428d7b3dSmrg } 1745428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, 1746428d7b3dSmrg "flip queue failed: %s\n", strerror(errno)); 1747428d7b3dSmrg if (seq) 1748428d7b3dSmrg intel_drm_abort_seq(scrn, seq); 1749428d7b3dSmrg free(flip); 1750428d7b3dSmrg goto error_undo; 1751428d7b3dSmrg } 1752428d7b3dSmrg mode->flip_count++; 1753428d7b3dSmrg } 1754428d7b3dSmrg 1755428d7b3dSmrg mode->old_fb_id = mode->fb_id; 1756428d7b3dSmrg mode->fb_id = new_fb_id; 1757428d7b3dSmrg 1758428d7b3dSmrg if (!mode->flip_count) 1759428d7b3dSmrg intel_pageflip_complete(mode); 1760428d7b3dSmrg 1761428d7b3dSmrg return TRUE; 1762428d7b3dSmrg 1763428d7b3dSmrgerror_undo: 1764428d7b3dSmrg drmModeRmFB(mode->fd, new_fb_id); 1765428d7b3dSmrg for (i = 0; i < config->num_crtc; i++) { 1766428d7b3dSmrg if (config->crtc[i]->enabled) 1767428d7b3dSmrg intel_crtc_apply(config->crtc[i]); 1768428d7b3dSmrg } 1769428d7b3dSmrg 1770428d7b3dSmrgerror_out: 1771428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", 1772428d7b3dSmrg strerror(errno)); 1773428d7b3dSmrg 1774428d7b3dSmrg mode->flip_count = 0; 1775428d7b3dSmrg return FALSE; 1776428d7b3dSmrg} 1777428d7b3dSmrg 1778428d7b3dSmrgstatic const xf86CrtcConfigFuncsRec intel_xf86crtc_config_funcs = { 1779428d7b3dSmrg intel_xf86crtc_resize 1780428d7b3dSmrg}; 1781428d7b3dSmrg 1782428d7b3dSmrg/* 1783428d7b3dSmrg * Enqueue a potential drm response; when the associated response 1784428d7b3dSmrg * appears, we've got data to pass to the handler from here 1785428d7b3dSmrg */ 1786428d7b3dSmrguint32_t 1787428d7b3dSmrgintel_drm_queue_alloc(ScrnInfoPtr scrn, 1788428d7b3dSmrg xf86CrtcPtr crtc, 1789428d7b3dSmrg void *data, 1790428d7b3dSmrg intel_drm_handler_proc handler, 1791428d7b3dSmrg intel_drm_abort_proc abort) 1792428d7b3dSmrg{ 1793428d7b3dSmrg struct intel_drm_queue *q; 1794428d7b3dSmrg 1795428d7b3dSmrg q = calloc(1, sizeof(struct intel_drm_queue)); 1796428d7b3dSmrg if (!q) 1797428d7b3dSmrg return 0; 1798428d7b3dSmrg 1799428d7b3dSmrg if (!intel_drm_seq) 1800428d7b3dSmrg ++intel_drm_seq; 1801428d7b3dSmrg q->seq = intel_drm_seq++; 1802428d7b3dSmrg q->scrn = scrn; 1803428d7b3dSmrg q->crtc = crtc; 1804428d7b3dSmrg q->data = data; 1805428d7b3dSmrg q->handler = handler; 1806428d7b3dSmrg q->abort = abort; 1807428d7b3dSmrg 1808428d7b3dSmrg list_add(&q->list, &intel_drm_queue); 1809428d7b3dSmrg 1810428d7b3dSmrg return q->seq; 1811428d7b3dSmrg} 1812428d7b3dSmrg 1813428d7b3dSmrg/* 1814428d7b3dSmrg * Abort one queued DRM entry, removing it 1815428d7b3dSmrg * from the list, calling the abort function and 1816428d7b3dSmrg * freeing the memory 1817428d7b3dSmrg */ 1818428d7b3dSmrgstatic void 1819428d7b3dSmrgintel_drm_abort_one(struct intel_drm_queue *q) 1820428d7b3dSmrg{ 1821428d7b3dSmrg list_del(&q->list); 1822428d7b3dSmrg q->abort(q->scrn, q->crtc, q->data); 1823428d7b3dSmrg free(q); 1824428d7b3dSmrg} 1825428d7b3dSmrg 1826428d7b3dSmrg/* 1827428d7b3dSmrg * Externally usable abort function that uses a callback to match a single queued 1828428d7b3dSmrg * entry to abort 1829428d7b3dSmrg */ 1830428d7b3dSmrgvoid 1831428d7b3dSmrgintel_drm_abort(ScrnInfoPtr scrn, Bool (*match)(void *data, void *match_data), void *match_data) 1832428d7b3dSmrg{ 1833428d7b3dSmrg struct intel_drm_queue *q; 1834428d7b3dSmrg 1835428d7b3dSmrg list_for_each_entry(q, &intel_drm_queue, list) { 1836428d7b3dSmrg if (match(q->data, match_data)) { 1837428d7b3dSmrg intel_drm_abort_one(q); 1838428d7b3dSmrg break; 1839428d7b3dSmrg } 1840428d7b3dSmrg } 1841428d7b3dSmrg} 1842428d7b3dSmrg 1843428d7b3dSmrg/* 1844428d7b3dSmrg * Abort by drm queue sequence number 1845428d7b3dSmrg */ 1846428d7b3dSmrgstatic void 1847428d7b3dSmrgintel_drm_abort_seq(ScrnInfoPtr scrn, uint32_t seq) 1848428d7b3dSmrg{ 1849428d7b3dSmrg struct intel_drm_queue *q; 1850428d7b3dSmrg 1851428d7b3dSmrg list_for_each_entry(q, &intel_drm_queue, list) { 1852428d7b3dSmrg if (q->seq == seq) { 1853428d7b3dSmrg intel_drm_abort_one(q); 1854428d7b3dSmrg break; 1855428d7b3dSmrg } 1856428d7b3dSmrg } 1857428d7b3dSmrg} 1858428d7b3dSmrg 1859428d7b3dSmrg/* 1860428d7b3dSmrg * Abort all queued entries on a specific scrn, used 1861428d7b3dSmrg * when resetting the X server 1862428d7b3dSmrg */ 1863428d7b3dSmrgstatic void 1864428d7b3dSmrgintel_drm_abort_scrn(ScrnInfoPtr scrn) 1865428d7b3dSmrg{ 1866428d7b3dSmrg struct intel_drm_queue *q, *tmp; 1867428d7b3dSmrg 1868428d7b3dSmrg list_for_each_entry_safe(q, tmp, &intel_drm_queue, list) { 1869428d7b3dSmrg if (q->scrn == scrn) 1870428d7b3dSmrg intel_drm_abort_one(q); 1871428d7b3dSmrg } 1872428d7b3dSmrg} 1873428d7b3dSmrg 1874428d7b3dSmrgstatic uint32_t pipe_select(int pipe) 1875428d7b3dSmrg{ 1876428d7b3dSmrg if (pipe > 1) 1877428d7b3dSmrg return pipe << DRM_VBLANK_HIGH_CRTC_SHIFT; 1878428d7b3dSmrg else if (pipe > 0) 1879428d7b3dSmrg return DRM_VBLANK_SECONDARY; 1880428d7b3dSmrg else 1881428d7b3dSmrg return 0; 1882428d7b3dSmrg} 1883428d7b3dSmrg 1884428d7b3dSmrg/* 1885428d7b3dSmrg * Get the current msc/ust value from the kernel 1886428d7b3dSmrg */ 1887428d7b3dSmrgstatic int 1888428d7b3dSmrgintel_get_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint32_t *msc, uint64_t *ust) 1889428d7b3dSmrg{ 1890428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 1891428d7b3dSmrg drmVBlank vbl; 1892428d7b3dSmrg 1893428d7b3dSmrg /* Get current count */ 1894428d7b3dSmrg vbl.request.type = DRM_VBLANK_RELATIVE | pipe_select(intel_crtc_to_pipe(crtc)); 1895428d7b3dSmrg vbl.request.sequence = 0; 1896428d7b3dSmrg vbl.request.signal = 0; 1897428d7b3dSmrg if (drmWaitVBlank(intel->drmSubFD, &vbl)) { 1898428d7b3dSmrg *msc = 0; 1899428d7b3dSmrg *ust = 0; 1900428d7b3dSmrg return BadMatch; 1901428d7b3dSmrg } else { 1902428d7b3dSmrg *msc = vbl.reply.sequence; 1903428d7b3dSmrg *ust = (CARD64) vbl.reply.tval_sec * 1000000 + vbl.reply.tval_usec; 1904428d7b3dSmrg return Success; 1905428d7b3dSmrg } 1906428d7b3dSmrg} 1907428d7b3dSmrg 1908428d7b3dSmrg/* 1909428d7b3dSmrg * Convert a 32-bit kernel MSC sequence number to a 64-bit local sequence 1910428d7b3dSmrg * number, adding in the vblank_offset and high 32 bits, and dealing 1911428d7b3dSmrg * with 64-bit wrapping 1912428d7b3dSmrg */ 1913428d7b3dSmrguint64_t 1914428d7b3dSmrgintel_sequence_to_crtc_msc(xf86CrtcPtr crtc, uint32_t sequence) 1915428d7b3dSmrg{ 1916428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 1917428d7b3dSmrg 1918428d7b3dSmrg sequence += intel_crtc->vblank_offset; 1919428d7b3dSmrg if ((int32_t) (sequence - intel_crtc->msc_prev) < -0x40000000) 1920428d7b3dSmrg intel_crtc->msc_high += 0x100000000L; 1921428d7b3dSmrg intel_crtc->msc_prev = sequence; 1922428d7b3dSmrg return intel_crtc->msc_high + sequence; 1923428d7b3dSmrg} 1924428d7b3dSmrg 1925428d7b3dSmrg/* 1926428d7b3dSmrg * Get the current 64-bit adjust MSC and UST value 1927428d7b3dSmrg */ 1928428d7b3dSmrgint 1929428d7b3dSmrgintel_get_crtc_msc_ust(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t *msc, uint64_t *ust) 1930428d7b3dSmrg{ 1931428d7b3dSmrg uint32_t sequence; 1932428d7b3dSmrg int ret; 1933428d7b3dSmrg 1934428d7b3dSmrg ret = intel_get_msc_ust(scrn, crtc, &sequence, ust); 1935428d7b3dSmrg if (ret) 1936428d7b3dSmrg return ret; 1937428d7b3dSmrg 1938428d7b3dSmrg *msc = intel_sequence_to_crtc_msc(crtc, sequence); 1939428d7b3dSmrg return 0; 1940428d7b3dSmrg} 1941428d7b3dSmrg 1942428d7b3dSmrg/* 1943428d7b3dSmrg * Convert a 64-bit adjusted MSC value into a 32-bit kernel sequence number, 1944428d7b3dSmrg * removing the high 32 bits and subtracting out the vblank_offset term. 1945428d7b3dSmrg * 1946428d7b3dSmrg * This also updates the vblank_offset when it notices that the value should 1947428d7b3dSmrg * change. 1948428d7b3dSmrg */ 1949428d7b3dSmrg 1950428d7b3dSmrg#define MAX_VBLANK_OFFSET 1000 1951428d7b3dSmrg 1952428d7b3dSmrguint32_t 1953428d7b3dSmrgintel_crtc_msc_to_sequence(ScrnInfoPtr scrn, xf86CrtcPtr crtc, uint64_t expect) 1954428d7b3dSmrg{ 1955428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 1956428d7b3dSmrg uint64_t msc, ust; 1957428d7b3dSmrg 1958428d7b3dSmrg if (intel_get_crtc_msc_ust(scrn, crtc, &msc, &ust) == 0) { 1959428d7b3dSmrg int64_t diff = expect - msc; 1960428d7b3dSmrg 1961428d7b3dSmrg /* We're way off here, assume that the kernel has lost its mind 1962428d7b3dSmrg * and smack the vblank back to something sensible 1963428d7b3dSmrg */ 1964428d7b3dSmrg if (diff < -MAX_VBLANK_OFFSET || diff > MAX_VBLANK_OFFSET) { 1965428d7b3dSmrg intel_crtc->vblank_offset += (int32_t) diff; 1966428d7b3dSmrg if (intel_crtc->vblank_offset > -MAX_VBLANK_OFFSET && 1967428d7b3dSmrg intel_crtc->vblank_offset < MAX_VBLANK_OFFSET) 1968428d7b3dSmrg intel_crtc->vblank_offset = 0; 1969428d7b3dSmrg } 1970428d7b3dSmrg } 1971428d7b3dSmrg 1972428d7b3dSmrg return (uint32_t) (expect - intel_crtc->vblank_offset); 1973428d7b3dSmrg} 1974428d7b3dSmrg 1975428d7b3dSmrg/* 1976428d7b3dSmrg * General DRM kernel handler. Looks for the matching sequence number in the 1977428d7b3dSmrg * drm event queue and calls the handler for it. 1978428d7b3dSmrg */ 1979428d7b3dSmrgstatic void 1980428d7b3dSmrgintel_drm_handler(int fd, uint32_t frame, uint32_t sec, uint32_t usec, void *user_ptr) 1981428d7b3dSmrg{ 1982428d7b3dSmrg uint32_t user_data = (intptr_t)user_ptr; 1983428d7b3dSmrg struct intel_drm_queue *q; 1984428d7b3dSmrg 1985428d7b3dSmrg list_for_each_entry(q, &intel_drm_queue, list) { 1986428d7b3dSmrg if (q->seq == user_data) { 1987428d7b3dSmrg list_del(&q->list); 1988428d7b3dSmrg q->handler(q->scrn, q->crtc, 1989428d7b3dSmrg intel_sequence_to_crtc_msc(q->crtc, frame), 1990428d7b3dSmrg (uint64_t)sec * 1000000 + usec, q->data); 1991428d7b3dSmrg free(q); 1992428d7b3dSmrg break; 1993428d7b3dSmrg } 1994428d7b3dSmrg } 1995428d7b3dSmrg} 1996428d7b3dSmrg 1997428d7b3dSmrg 1998428d7b3dSmrg/* 1999428d7b3dSmrg * Notify the page flip caller that the flip is 2000428d7b3dSmrg * complete 2001428d7b3dSmrg */ 2002428d7b3dSmrgstatic void 2003428d7b3dSmrgintel_pageflip_complete(struct intel_mode *mode) 2004428d7b3dSmrg{ 2005428d7b3dSmrg /* Release framebuffer */ 2006428d7b3dSmrg drmModeRmFB(mode->fd, mode->old_fb_id); 2007428d7b3dSmrg 2008428d7b3dSmrg if (!mode->pageflip_handler) 2009428d7b3dSmrg return; 2010428d7b3dSmrg 2011428d7b3dSmrg mode->pageflip_handler(mode->fe_msc, mode->fe_usec, 2012428d7b3dSmrg mode->pageflip_data); 2013428d7b3dSmrg} 2014428d7b3dSmrg 2015428d7b3dSmrg/* 2016428d7b3dSmrg * One pageflip event has completed. Update the saved msc/ust values 2017428d7b3dSmrg * as needed, then check to see if the whole set of events are 2018428d7b3dSmrg * complete and notify the application at that point 2019428d7b3dSmrg */ 2020428d7b3dSmrgstatic struct intel_mode * 2021428d7b3dSmrgintel_handle_pageflip(struct intel_pageflip *flip, uint64_t msc, uint64_t usec) 2022428d7b3dSmrg{ 2023428d7b3dSmrg struct intel_mode *mode = flip->mode; 2024428d7b3dSmrg 2025428d7b3dSmrg if (flip->dispatch_me) { 2026428d7b3dSmrg /* Yes: Cache msc, ust for later delivery. */ 2027428d7b3dSmrg mode->fe_msc = msc; 2028428d7b3dSmrg mode->fe_usec = usec; 2029428d7b3dSmrg } 2030428d7b3dSmrg free(flip); 2031428d7b3dSmrg 2032428d7b3dSmrg /* Last crtc completed flip? */ 2033428d7b3dSmrg mode->flip_count--; 2034428d7b3dSmrg if (mode->flip_count > 0) 2035428d7b3dSmrg return NULL; 2036428d7b3dSmrg 2037428d7b3dSmrg return mode; 2038428d7b3dSmrg} 2039428d7b3dSmrg 2040428d7b3dSmrg/* 2041428d7b3dSmrg * Called from the DRM event queue when a single flip has completed 2042428d7b3dSmrg */ 2043428d7b3dSmrgstatic void 2044428d7b3dSmrgintel_pageflip_handler(ScrnInfoPtr scrn, xf86CrtcPtr crtc, 2045428d7b3dSmrg uint64_t msc, uint64_t usec, void *data) 2046428d7b3dSmrg{ 2047428d7b3dSmrg struct intel_pageflip *flip = data; 2048428d7b3dSmrg struct intel_mode *mode = intel_handle_pageflip(flip, msc, usec); 2049428d7b3dSmrg 2050428d7b3dSmrg if (!mode) 2051428d7b3dSmrg return; 2052428d7b3dSmrg intel_pageflip_complete(mode); 2053428d7b3dSmrg} 2054428d7b3dSmrg 2055428d7b3dSmrg/* 2056428d7b3dSmrg * Called from the DRM queue abort code when a flip has been aborted 2057428d7b3dSmrg */ 2058428d7b3dSmrgstatic void 2059428d7b3dSmrgintel_pageflip_abort(ScrnInfoPtr scrn, xf86CrtcPtr crtc, void *data) 2060428d7b3dSmrg{ 2061428d7b3dSmrg struct intel_pageflip *flip = data; 2062428d7b3dSmrg struct intel_mode *mode = intel_handle_pageflip(flip, 0, 0); 2063428d7b3dSmrg 2064428d7b3dSmrg if (!mode) 2065428d7b3dSmrg return; 2066428d7b3dSmrg 2067428d7b3dSmrg /* Release framebuffer */ 2068428d7b3dSmrg drmModeRmFB(mode->fd, mode->old_fb_id); 2069428d7b3dSmrg 2070428d7b3dSmrg if (!mode->pageflip_abort) 2071428d7b3dSmrg return; 2072428d7b3dSmrg 2073428d7b3dSmrg mode->pageflip_abort(mode->pageflip_data); 2074428d7b3dSmrg} 2075428d7b3dSmrg 2076428d7b3dSmrg/* 2077428d7b3dSmrg * Check for pending DRM events and process them. 2078428d7b3dSmrg */ 2079428d7b3dSmrg#if HAVE_NOTIFY_FD 2080428d7b3dSmrgstatic void drmmode_notify_fd(int fd, int notify, void *data) 2081428d7b3dSmrg{ 2082428d7b3dSmrg struct intel_mode *mode = data; 2083428d7b3dSmrg 2084428d7b3dSmrg drmHandleEvent(fd, &mode->event_context); 2085428d7b3dSmrg} 2086428d7b3dSmrg#else 2087428d7b3dSmrgstatic void 2088428d7b3dSmrgdrm_wakeup_handler(pointer data, int err, pointer p) 2089428d7b3dSmrg{ 2090428d7b3dSmrg struct intel_mode *mode; 2091428d7b3dSmrg fd_set *read_mask; 2092428d7b3dSmrg 2093428d7b3dSmrg if (data == NULL || err < 0) 2094428d7b3dSmrg return; 2095428d7b3dSmrg 2096428d7b3dSmrg mode = data; 2097428d7b3dSmrg read_mask = p; 2098428d7b3dSmrg if (FD_ISSET(mode->fd, read_mask)) 2099428d7b3dSmrg drmHandleEvent(mode->fd, &mode->event_context); 2100428d7b3dSmrg} 2101428d7b3dSmrg#endif 2102428d7b3dSmrg 2103428d7b3dSmrg/* 2104428d7b3dSmrg * If there are any available, read drm_events 2105428d7b3dSmrg */ 2106428d7b3dSmrgint 2107428d7b3dSmrgintel_mode_read_drm_events(struct intel_screen_private *intel) 2108428d7b3dSmrg{ 2109428d7b3dSmrg struct intel_mode *mode = intel->modes; 2110428d7b3dSmrg struct pollfd p = { .fd = mode->fd, .events = POLLIN }; 2111428d7b3dSmrg int r; 2112428d7b3dSmrg 2113428d7b3dSmrg do { 2114428d7b3dSmrg r = poll(&p, 1, 0); 2115428d7b3dSmrg } while (r == -1 && (errno == EINTR || errno == EAGAIN)); 2116428d7b3dSmrg 2117428d7b3dSmrg if (r <= 0) 2118428d7b3dSmrg return 0; 2119428d7b3dSmrg 2120428d7b3dSmrg return drmHandleEvent(mode->fd, &mode->event_context); 2121428d7b3dSmrg} 2122428d7b3dSmrg 2123428d7b3dSmrg/* 2124428d7b3dSmrg * Libdrm's possible_clones is a mask of encoders, Xorg's possible_clones is a 2125428d7b3dSmrg * mask of outputs. This function sets Xorg's possible_clones based on the 2126428d7b3dSmrg * values read from libdrm. 2127428d7b3dSmrg */ 2128428d7b3dSmrgstatic uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output) 2129428d7b3dSmrg{ 2130428d7b3dSmrg struct intel_output *intel_output = output->driver_private, *clone_drmout; 2131428d7b3dSmrg int i; 2132428d7b3dSmrg xf86OutputPtr clone_output; 2133428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2134428d7b3dSmrg int index_mask = 0; 2135428d7b3dSmrg 2136428d7b3dSmrg if (intel_output->enc_clone_mask == 0) 2137428d7b3dSmrg return index_mask; 2138428d7b3dSmrg 2139428d7b3dSmrg for (i = 0; i < xf86_config->num_output; i++) { 2140428d7b3dSmrg clone_output = xf86_config->output[i]; 2141428d7b3dSmrg clone_drmout = clone_output->driver_private; 2142428d7b3dSmrg if (output == clone_output) 2143428d7b3dSmrg continue; 2144428d7b3dSmrg 2145428d7b3dSmrg if (clone_drmout->enc_mask == 0) 2146428d7b3dSmrg continue; 2147428d7b3dSmrg if (intel_output->enc_clone_mask == clone_drmout->enc_mask) 2148428d7b3dSmrg index_mask |= (1 << i); 2149428d7b3dSmrg } 2150428d7b3dSmrg return index_mask; 2151428d7b3dSmrg} 2152428d7b3dSmrgstatic void 2153428d7b3dSmrgintel_compute_possible_clones(ScrnInfoPtr scrn, struct intel_mode *mode, drmModeResPtr mode_res) 2154428d7b3dSmrg{ 2155428d7b3dSmrg int i, j; 2156428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2157428d7b3dSmrg 2158428d7b3dSmrg for (i = 0; i < xf86_config->num_output; i++) { 2159428d7b3dSmrg xf86OutputPtr output = xf86_config->output[i]; 2160428d7b3dSmrg struct intel_output *intel_output; 2161428d7b3dSmrg 2162428d7b3dSmrg intel_output = output->driver_private; 2163428d7b3dSmrg intel_output->enc_clone_mask = 0xff; 2164428d7b3dSmrg /* and all the possible encoder clones for this output together */ 2165428d7b3dSmrg for (j = 0; j < intel_output->mode_output->count_encoders; j++) 2166428d7b3dSmrg { 2167428d7b3dSmrg int k; 2168428d7b3dSmrg for (k = 0; k < mode_res->count_encoders; k++) { 2169428d7b3dSmrg if (mode_res->encoders[k] == intel_output->mode_encoders[j]->encoder_id) 2170428d7b3dSmrg intel_output->enc_mask |= (1 << k); 2171428d7b3dSmrg } 2172428d7b3dSmrg 2173428d7b3dSmrg intel_output->enc_clone_mask &= intel_output->mode_encoders[j]->possible_clones; 2174428d7b3dSmrg } 2175428d7b3dSmrg } 2176428d7b3dSmrg 2177428d7b3dSmrg for (i = 0; i < xf86_config->num_output; i++) { 2178428d7b3dSmrg xf86OutputPtr output = xf86_config->output[i]; 2179428d7b3dSmrg output->possible_clones = find_clones(scrn, output); 2180428d7b3dSmrg } 2181428d7b3dSmrg} 2182428d7b3dSmrg 2183428d7b3dSmrgBool intel_mode_pre_init(ScrnInfoPtr scrn, int fd, int cpp) 2184428d7b3dSmrg{ 2185428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 2186428d7b3dSmrg struct drm_i915_getparam gp; 2187428d7b3dSmrg struct intel_mode *mode; 2188428d7b3dSmrg unsigned int i; 2189428d7b3dSmrg int has_flipping; 2190428d7b3dSmrg drmModeResPtr mode_res; 2191428d7b3dSmrg 2192428d7b3dSmrg mode = calloc(1, sizeof *mode); 2193428d7b3dSmrg if (!mode) 2194428d7b3dSmrg return FALSE; 2195428d7b3dSmrg 2196428d7b3dSmrg mode->fd = fd; 2197428d7b3dSmrg 2198428d7b3dSmrg list_init(&mode->crtcs); 2199428d7b3dSmrg list_init(&mode->outputs); 2200428d7b3dSmrg 2201428d7b3dSmrg xf86CrtcConfigInit(scrn, &intel_xf86crtc_config_funcs); 2202428d7b3dSmrg 2203428d7b3dSmrg mode->cpp = cpp; 2204428d7b3dSmrg mode_res = drmModeGetResources(mode->fd); 2205428d7b3dSmrg if (!mode_res) { 2206428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2207428d7b3dSmrg "failed to get resources: %s\n", strerror(errno)); 2208428d7b3dSmrg free(mode); 2209428d7b3dSmrg return FALSE; 2210428d7b3dSmrg } 2211428d7b3dSmrg 2212428d7b3dSmrg xf86CrtcSetSizeRange(scrn, 320, 200, mode_res->max_width, 2213428d7b3dSmrg mode_res->max_height); 2214428d7b3dSmrg for (i = 0; i < mode_res->count_crtcs; i++) 2215428d7b3dSmrg intel_crtc_init(scrn, mode, mode_res, i); 2216428d7b3dSmrg 2217428d7b3dSmrg for (i = 0; i < mode_res->count_connectors; i++) 2218428d7b3dSmrg intel_output_init(scrn, mode, mode_res, i, 0); 2219428d7b3dSmrg 2220428d7b3dSmrg intel_compute_possible_clones(scrn, mode, mode_res); 2221428d7b3dSmrg 2222428d7b3dSmrg#ifdef INTEL_PIXMAP_SHARING 2223428d7b3dSmrg xf86ProviderSetup(scrn, NULL, "Intel"); 2224428d7b3dSmrg#endif 2225428d7b3dSmrg 2226428d7b3dSmrg xf86InitialConfiguration(scrn, TRUE); 2227428d7b3dSmrg 2228428d7b3dSmrg mode->event_context.version = DRM_EVENT_CONTEXT_VERSION; 2229428d7b3dSmrg mode->event_context.vblank_handler = intel_drm_handler; 2230428d7b3dSmrg mode->event_context.page_flip_handler = intel_drm_handler; 2231428d7b3dSmrg 2232428d7b3dSmrg /* XXX assumes only one intel screen */ 2233428d7b3dSmrg list_init(&intel_drm_queue); 2234428d7b3dSmrg intel_drm_seq = 0; 2235428d7b3dSmrg 2236428d7b3dSmrg has_flipping = 0; 2237428d7b3dSmrg gp.param = I915_PARAM_HAS_PAGEFLIPPING; 2238428d7b3dSmrg gp.value = &has_flipping; 2239428d7b3dSmrg (void)drmCommandWriteRead(intel->drmSubFD, DRM_I915_GETPARAM, &gp, 2240428d7b3dSmrg sizeof(gp)); 2241428d7b3dSmrg if (has_flipping && intel->swapbuffers_wait) { 2242428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_INFO, 2243428d7b3dSmrg "Kernel page flipping support detected, enabling\n"); 2244428d7b3dSmrg intel->use_pageflipping = TRUE; 2245428d7b3dSmrg } 2246428d7b3dSmrg 2247428d7b3dSmrg if (xf86ReturnOptValBool(intel->Options, OPTION_DELETE_DP12, FALSE)) { 2248428d7b3dSmrg mode->delete_dp_12_displays = TRUE; 2249428d7b3dSmrg } 2250428d7b3dSmrg 2251428d7b3dSmrg intel->modes = mode; 2252428d7b3dSmrg drmModeFreeResources(mode_res); 2253428d7b3dSmrg return TRUE; 2254428d7b3dSmrg} 2255428d7b3dSmrg 2256428d7b3dSmrgvoid 2257428d7b3dSmrgintel_mode_init(struct intel_screen_private *intel) 2258428d7b3dSmrg{ 2259428d7b3dSmrg struct intel_mode *mode = intel->modes; 2260428d7b3dSmrg 2261428d7b3dSmrg /* We need to re-register the mode->fd for the synchronisation 2262428d7b3dSmrg * feedback on every server generation, so perform the 2263428d7b3dSmrg * registration within ScreenInit and not PreInit. 2264428d7b3dSmrg */ 2265428d7b3dSmrg mode->flip_count = 0; 2266428d7b3dSmrg#if HAVE_NOTIFY_FD 2267428d7b3dSmrg SetNotifyFd(mode->fd, drmmode_notify_fd, X_NOTIFY_READ, mode); 2268428d7b3dSmrg#else 2269428d7b3dSmrg AddGeneralSocket(mode->fd); 2270428d7b3dSmrg RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 2271428d7b3dSmrg drm_wakeup_handler, mode); 2272428d7b3dSmrg#endif 2273428d7b3dSmrg} 2274428d7b3dSmrg 2275428d7b3dSmrgvoid 2276428d7b3dSmrgintel_mode_remove_fb(intel_screen_private *intel) 2277428d7b3dSmrg{ 2278428d7b3dSmrg struct intel_mode *mode = intel->modes; 2279428d7b3dSmrg 2280428d7b3dSmrg if (mode->fb_id) { 2281428d7b3dSmrg drmModeRmFB(mode->fd, mode->fb_id); 2282428d7b3dSmrg mode->fb_id = 0; 2283428d7b3dSmrg } 2284428d7b3dSmrg} 2285428d7b3dSmrg 2286428d7b3dSmrgvoid 2287428d7b3dSmrgintel_mode_close(intel_screen_private *intel) 2288428d7b3dSmrg{ 2289428d7b3dSmrg struct intel_mode *mode = intel->modes; 2290428d7b3dSmrg 2291428d7b3dSmrg if (mode == NULL) 2292428d7b3dSmrg return; 2293428d7b3dSmrg 2294428d7b3dSmrg intel_drm_abort_scrn(intel->scrn); 2295428d7b3dSmrg 2296428d7b3dSmrg#if HAVE_NOTIFY_FD 2297428d7b3dSmrg RemoveNotifyFd(mode->fd); 2298428d7b3dSmrg#else 2299428d7b3dSmrg RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA, 2300428d7b3dSmrg drm_wakeup_handler, mode); 2301428d7b3dSmrg RemoveGeneralSocket(mode->fd); 2302428d7b3dSmrg#endif 2303428d7b3dSmrg} 2304428d7b3dSmrg 2305428d7b3dSmrgvoid 2306428d7b3dSmrgintel_mode_fini(intel_screen_private *intel) 2307428d7b3dSmrg{ 2308428d7b3dSmrg struct intel_mode *mode = intel->modes; 2309428d7b3dSmrg 2310428d7b3dSmrg if (mode == NULL) 2311428d7b3dSmrg return; 2312428d7b3dSmrg 2313428d7b3dSmrg while(!list_is_empty(&mode->crtcs)) { 2314428d7b3dSmrg xf86CrtcDestroy(list_first_entry(&mode->crtcs, 2315428d7b3dSmrg struct intel_crtc, 2316428d7b3dSmrg link)->crtc); 2317428d7b3dSmrg } 2318428d7b3dSmrg 2319428d7b3dSmrg while(!list_is_empty(&mode->outputs)) { 2320428d7b3dSmrg xf86OutputDestroy(list_first_entry(&mode->outputs, 2321428d7b3dSmrg struct intel_output, 2322428d7b3dSmrg link)->output); 2323428d7b3dSmrg } 2324428d7b3dSmrg 2325428d7b3dSmrg if (mode->fb_id) 2326428d7b3dSmrg drmModeRmFB(mode->fd, mode->fb_id); 2327428d7b3dSmrg 2328428d7b3dSmrg /* mode->rotate_fb_id should have been destroyed already */ 2329428d7b3dSmrg 2330428d7b3dSmrg free(mode); 2331428d7b3dSmrg intel->modes = NULL; 2332428d7b3dSmrg} 2333428d7b3dSmrg 2334428d7b3dSmrg/* for the mode overlay */ 2335428d7b3dSmrgint 2336428d7b3dSmrgintel_crtc_id(xf86CrtcPtr crtc) 2337428d7b3dSmrg{ 2338428d7b3dSmrg return crtc_id(crtc->driver_private); 2339428d7b3dSmrg} 2340428d7b3dSmrg 2341428d7b3dSmrgint intel_crtc_to_pipe(xf86CrtcPtr crtc) 2342428d7b3dSmrg{ 2343428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 2344428d7b3dSmrg return intel_crtc->pipe; 2345428d7b3dSmrg} 2346428d7b3dSmrg 2347428d7b3dSmrgBool intel_crtc_on(xf86CrtcPtr crtc) 2348428d7b3dSmrg{ 2349428d7b3dSmrg struct intel_crtc *intel_crtc = crtc->driver_private; 2350428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn); 2351428d7b3dSmrg drmModeCrtcPtr drm_crtc; 2352428d7b3dSmrg Bool ret; 2353428d7b3dSmrg int i; 2354428d7b3dSmrg 2355428d7b3dSmrg if (!crtc->enabled) 2356428d7b3dSmrg return FALSE; 2357428d7b3dSmrg 2358428d7b3dSmrg /* Kernel manages CRTC status based on output config */ 2359428d7b3dSmrg ret = FALSE; 2360428d7b3dSmrg for (i = 0; i < xf86_config->num_output; i++) { 2361428d7b3dSmrg xf86OutputPtr output = xf86_config->output[i]; 2362428d7b3dSmrg if (output->crtc == crtc && 2363428d7b3dSmrg intel_output_dpms_status(output) == DPMSModeOn) { 2364428d7b3dSmrg ret = TRUE; 2365428d7b3dSmrg break; 2366428d7b3dSmrg } 2367428d7b3dSmrg } 2368428d7b3dSmrg if (!ret) 2369428d7b3dSmrg return FALSE; 2370428d7b3dSmrg 2371428d7b3dSmrg /* And finally check with the kernel that the fb is bound */ 2372428d7b3dSmrg drm_crtc = drmModeGetCrtc(intel_crtc->mode->fd, crtc_id(intel_crtc)); 2373428d7b3dSmrg if (drm_crtc == NULL) 2374428d7b3dSmrg return FALSE; 2375428d7b3dSmrg 2376428d7b3dSmrg ret = (drm_crtc->mode_valid && 2377428d7b3dSmrg (intel_crtc->mode->fb_id == drm_crtc->buffer_id || 2378428d7b3dSmrg intel_crtc->mode->old_fb_id == drm_crtc->buffer_id)); 2379428d7b3dSmrg free(drm_crtc); 2380428d7b3dSmrg 2381428d7b3dSmrg return ret; 2382428d7b3dSmrg} 2383428d7b3dSmrg 2384428d7b3dSmrg 2385428d7b3dSmrgstatic PixmapPtr 2386428d7b3dSmrgintel_create_pixmap_for_bo(ScreenPtr pScreen, dri_bo *bo, 2387428d7b3dSmrg int width, int height, 2388428d7b3dSmrg int depth, int bpp, 2389428d7b3dSmrg int pitch) 2390428d7b3dSmrg{ 2391428d7b3dSmrg PixmapPtr pixmap; 2392428d7b3dSmrg 2393428d7b3dSmrg pixmap = pScreen->CreatePixmap(pScreen, 0, 0, depth, 0); 2394428d7b3dSmrg if (pixmap == NullPixmap) 2395428d7b3dSmrg return pixmap; 2396428d7b3dSmrg 2397428d7b3dSmrg if (!pScreen->ModifyPixmapHeader(pixmap, 2398428d7b3dSmrg width, height, 2399428d7b3dSmrg depth, bpp, 2400428d7b3dSmrg pitch, NULL)) { 2401428d7b3dSmrg pScreen->DestroyPixmap(pixmap); 2402428d7b3dSmrg return NullPixmap; 2403428d7b3dSmrg } 2404428d7b3dSmrg 2405428d7b3dSmrg intel_set_pixmap_bo(pixmap, bo); 2406428d7b3dSmrg return pixmap; 2407428d7b3dSmrg} 2408428d7b3dSmrg 2409428d7b3dSmrgstatic PixmapPtr 2410428d7b3dSmrgintel_create_pixmap_for_fbcon(ScrnInfoPtr scrn, int fbcon_id) 2411428d7b3dSmrg{ 2412428d7b3dSmrg ScreenPtr pScreen = xf86ScrnToScreen(scrn); 2413428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 2414428d7b3dSmrg struct intel_mode *mode = intel->modes; 2415428d7b3dSmrg int fd = mode->fd; 2416428d7b3dSmrg drmModeFBPtr fbcon; 2417428d7b3dSmrg struct drm_gem_flink flink; 2418428d7b3dSmrg drm_intel_bo *bo; 2419428d7b3dSmrg PixmapPtr pixmap = NullPixmap; 2420428d7b3dSmrg 2421428d7b3dSmrg fbcon = drmModeGetFB(fd, fbcon_id); 2422428d7b3dSmrg if (fbcon == NULL) 2423428d7b3dSmrg return NULL; 2424428d7b3dSmrg 2425428d7b3dSmrg if (fbcon->depth != scrn->depth || 2426428d7b3dSmrg fbcon->width != scrn->virtualX || 2427428d7b3dSmrg fbcon->height != scrn->virtualY) 2428428d7b3dSmrg goto out_free_fb; 2429428d7b3dSmrg 2430428d7b3dSmrg flink.handle = fbcon->handle; 2431428d7b3dSmrg if (ioctl(fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) { 2432428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2433428d7b3dSmrg "Couldn't flink fbcon handle\n"); 2434428d7b3dSmrg goto out_free_fb; 2435428d7b3dSmrg } 2436428d7b3dSmrg 2437428d7b3dSmrg bo = drm_intel_bo_gem_create_from_name(intel->bufmgr, 2438428d7b3dSmrg "fbcon", flink.name); 2439428d7b3dSmrg if (bo == NULL) { 2440428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2441428d7b3dSmrg "Couldn't allocate bo for fbcon handle\n"); 2442428d7b3dSmrg goto out_free_fb; 2443428d7b3dSmrg } 2444428d7b3dSmrg 2445428d7b3dSmrg pixmap = intel_create_pixmap_for_bo(pScreen, bo, 2446428d7b3dSmrg fbcon->width, fbcon->height, 2447428d7b3dSmrg fbcon->depth, fbcon->bpp, 2448428d7b3dSmrg fbcon->pitch); 2449428d7b3dSmrg if (pixmap == NullPixmap) 2450428d7b3dSmrg xf86DrvMsg(scrn->scrnIndex, X_ERROR, 2451428d7b3dSmrg "Couldn't allocate pixmap fbcon contents\n"); 2452428d7b3dSmrg drm_intel_bo_unreference(bo); 2453428d7b3dSmrgout_free_fb: 2454428d7b3dSmrg drmModeFreeFB(fbcon); 2455428d7b3dSmrg 2456428d7b3dSmrg return pixmap; 2457428d7b3dSmrg} 2458428d7b3dSmrg 2459428d7b3dSmrgvoid intel_copy_fb(ScrnInfoPtr scrn) 2460428d7b3dSmrg{ 2461428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2462428d7b3dSmrg ScreenPtr pScreen = xf86ScrnToScreen(scrn); 2463428d7b3dSmrg intel_screen_private *intel = intel_get_screen_private(scrn); 2464428d7b3dSmrg PixmapPtr src, dst; 2465428d7b3dSmrg unsigned int pitch = scrn->displayWidth * intel->cpp; 2466428d7b3dSmrg struct intel_crtc *intel_crtc; 2467428d7b3dSmrg int i, fbcon_id; 2468428d7b3dSmrg 2469428d7b3dSmrg if (intel->force_fallback) 2470428d7b3dSmrg return; 2471428d7b3dSmrg 2472428d7b3dSmrg fbcon_id = 0; 2473428d7b3dSmrg for (i = 0; i < xf86_config->num_crtc; i++) { 2474428d7b3dSmrg intel_crtc = xf86_config->crtc[i]->driver_private; 2475428d7b3dSmrg if (intel_crtc->mode_crtc->buffer_id) 2476428d7b3dSmrg fbcon_id = intel_crtc->mode_crtc->buffer_id; 2477428d7b3dSmrg } 2478428d7b3dSmrg if (!fbcon_id) 2479428d7b3dSmrg return; 2480428d7b3dSmrg 2481428d7b3dSmrg src = intel_create_pixmap_for_fbcon(scrn, fbcon_id); 2482428d7b3dSmrg if (src == NULL) 2483428d7b3dSmrg return; 2484428d7b3dSmrg 2485428d7b3dSmrg /* We dont have a screen Pixmap yet */ 2486428d7b3dSmrg dst = intel_create_pixmap_for_bo(pScreen, intel->front_buffer, 2487428d7b3dSmrg scrn->virtualX, scrn->virtualY, 2488428d7b3dSmrg scrn->depth, scrn->bitsPerPixel, 2489428d7b3dSmrg pitch); 2490428d7b3dSmrg if (dst == NullPixmap) 2491428d7b3dSmrg goto cleanup_src; 2492428d7b3dSmrg 2493428d7b3dSmrg if (!intel->uxa_driver->prepare_copy(src, dst, 2494428d7b3dSmrg -1, -1, 2495428d7b3dSmrg GXcopy, FB_ALLONES)) 2496428d7b3dSmrg goto cleanup_dst; 2497428d7b3dSmrg 2498428d7b3dSmrg intel->uxa_driver->copy(dst, 2499428d7b3dSmrg 0, 0, 2500428d7b3dSmrg 0, 0, 2501428d7b3dSmrg scrn->virtualX, scrn->virtualY); 2502428d7b3dSmrg intel->uxa_driver->done_copy(dst); 2503428d7b3dSmrg#if ABI_VIDEODRV_VERSION >= SET_ABI_VERSION(10, 0) 2504428d7b3dSmrg pScreen->canDoBGNoneRoot = TRUE; 2505428d7b3dSmrg#endif 2506428d7b3dSmrg 2507428d7b3dSmrgcleanup_dst: 2508428d7b3dSmrg (*pScreen->DestroyPixmap)(dst); 2509428d7b3dSmrgcleanup_src: 2510428d7b3dSmrg (*pScreen->DestroyPixmap)(src); 2511428d7b3dSmrg} 2512428d7b3dSmrg 2513428d7b3dSmrgvoid 2514428d7b3dSmrgintel_mode_hotplug(struct intel_screen_private *intel) 2515428d7b3dSmrg{ 2516428d7b3dSmrg ScrnInfoPtr scrn = intel->scrn; 2517428d7b3dSmrg xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); 2518428d7b3dSmrg drmModeResPtr mode_res; 2519428d7b3dSmrg int i, j; 2520428d7b3dSmrg Bool found; 2521428d7b3dSmrg Bool changed = FALSE; 2522428d7b3dSmrg struct intel_mode *mode = intel->modes; 2523428d7b3dSmrg mode_res = drmModeGetResources(intel->drmSubFD); 2524428d7b3dSmrg if (!mode_res) 2525428d7b3dSmrg goto out; 2526428d7b3dSmrg 2527428d7b3dSmrgrestart_destroy: 2528428d7b3dSmrg for (i = 0; i < config->num_output; i++) { 2529428d7b3dSmrg xf86OutputPtr output = config->output[i]; 2530428d7b3dSmrg struct intel_output *intel_output; 2531428d7b3dSmrg 2532428d7b3dSmrg intel_output = output->driver_private; 2533428d7b3dSmrg found = FALSE; 2534428d7b3dSmrg for (j = 0; j < mode_res->count_connectors; j++) { 2535428d7b3dSmrg if (mode_res->connectors[j] == intel_output->output_id) { 2536428d7b3dSmrg found = TRUE; 2537428d7b3dSmrg break; 2538428d7b3dSmrg } 2539428d7b3dSmrg } 2540428d7b3dSmrg if (found) 2541428d7b3dSmrg continue; 2542428d7b3dSmrg 2543428d7b3dSmrg drmModeFreeConnector(intel_output->mode_output); 2544428d7b3dSmrg intel_output->mode_output = NULL; 2545428d7b3dSmrg intel_output->output_id = -1; 2546428d7b3dSmrg 2547428d7b3dSmrg changed = TRUE; 2548428d7b3dSmrg if (mode->delete_dp_12_displays) { 2549428d7b3dSmrg RROutputDestroy(output->randr_output); 2550428d7b3dSmrg xf86OutputDestroy(output); 2551428d7b3dSmrg goto restart_destroy; 2552428d7b3dSmrg } 2553428d7b3dSmrg } 2554428d7b3dSmrg 2555428d7b3dSmrg /* find new output ids we don't have outputs for */ 2556428d7b3dSmrg for (i = 0; i < mode_res->count_connectors; i++) { 2557428d7b3dSmrg found = FALSE; 2558428d7b3dSmrg 2559428d7b3dSmrg for (j = 0; j < config->num_output; j++) { 2560428d7b3dSmrg xf86OutputPtr output = config->output[j]; 2561428d7b3dSmrg struct intel_output *intel_output; 2562428d7b3dSmrg 2563428d7b3dSmrg intel_output = output->driver_private; 2564428d7b3dSmrg if (mode_res->connectors[i] == intel_output->output_id) { 2565428d7b3dSmrg found = TRUE; 2566428d7b3dSmrg break; 2567428d7b3dSmrg } 2568428d7b3dSmrg } 2569428d7b3dSmrg if (found) 2570428d7b3dSmrg continue; 2571428d7b3dSmrg 2572428d7b3dSmrg changed = TRUE; 2573428d7b3dSmrg intel_output_init(scrn, intel->modes, mode_res, i, 1); 2574428d7b3dSmrg } 2575428d7b3dSmrg 2576428d7b3dSmrg if (changed) { 2577428d7b3dSmrg RRSetChanged(xf86ScrnToScreen(scrn)); 2578428d7b3dSmrg RRTellChanged(xf86ScrnToScreen(scrn)); 2579428d7b3dSmrg } 2580428d7b3dSmrg 2581428d7b3dSmrg drmModeFreeResources(mode_res); 2582428d7b3dSmrgout: 2583428d7b3dSmrg RRGetInfo(xf86ScrnToScreen(scrn), TRUE); 2584428d7b3dSmrg} 2585428d7b3dSmrg 2586428d7b3dSmrgvoid intel_box_intersect(BoxPtr dest, BoxPtr a, BoxPtr b) 2587428d7b3dSmrg{ 2588428d7b3dSmrg dest->x1 = a->x1 > b->x1 ? a->x1 : b->x1; 2589428d7b3dSmrg dest->x2 = a->x2 < b->x2 ? a->x2 : b->x2; 2590428d7b3dSmrg if (dest->x1 >= dest->x2) { 2591428d7b3dSmrg dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 2592428d7b3dSmrg return; 2593428d7b3dSmrg } 2594428d7b3dSmrg 2595428d7b3dSmrg dest->y1 = a->y1 > b->y1 ? a->y1 : b->y1; 2596428d7b3dSmrg dest->y2 = a->y2 < b->y2 ? a->y2 : b->y2; 2597428d7b3dSmrg if (dest->y1 >= dest->y2) 2598428d7b3dSmrg dest->x1 = dest->x2 = dest->y1 = dest->y2 = 0; 2599428d7b3dSmrg} 2600428d7b3dSmrg 2601428d7b3dSmrgvoid intel_crtc_box(xf86CrtcPtr crtc, BoxPtr crtc_box) 2602428d7b3dSmrg{ 2603428d7b3dSmrg if (crtc->enabled) { 2604428d7b3dSmrg crtc_box->x1 = crtc->x; 2605428d7b3dSmrg crtc_box->x2 = 2606428d7b3dSmrg crtc->x + xf86ModeWidth(&crtc->mode, crtc->rotation); 2607428d7b3dSmrg crtc_box->y1 = crtc->y; 2608428d7b3dSmrg crtc_box->y2 = 2609428d7b3dSmrg crtc->y + xf86ModeHeight(&crtc->mode, crtc->rotation); 2610428d7b3dSmrg } else 2611428d7b3dSmrg crtc_box->x1 = crtc_box->x2 = crtc_box->y1 = crtc_box->y2 = 0; 2612428d7b3dSmrg} 2613428d7b3dSmrg 2614428d7b3dSmrgstatic int intel_box_area(BoxPtr box) 2615428d7b3dSmrg{ 2616428d7b3dSmrg return (int)(box->x2 - box->x1) * (int)(box->y2 - box->y1); 2617428d7b3dSmrg} 2618428d7b3dSmrg 2619428d7b3dSmrg/* 2620428d7b3dSmrg * Return the crtc covering 'box'. If two crtcs cover a portion of 2621428d7b3dSmrg * 'box', then prefer 'desired'. If 'desired' is NULL, then prefer the crtc 2622428d7b3dSmrg * with greater coverage 2623428d7b3dSmrg */ 2624428d7b3dSmrg 2625428d7b3dSmrgxf86CrtcPtr 2626428d7b3dSmrgintel_covering_crtc(ScrnInfoPtr scrn, 2627428d7b3dSmrg BoxPtr box, xf86CrtcPtr desired, BoxPtr crtc_box_ret) 2628428d7b3dSmrg{ 2629428d7b3dSmrg xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn); 2630428d7b3dSmrg xf86CrtcPtr crtc, best_crtc; 2631428d7b3dSmrg int coverage, best_coverage; 2632428d7b3dSmrg int c; 2633428d7b3dSmrg BoxRec crtc_box, cover_box; 2634428d7b3dSmrg 2635428d7b3dSmrg best_crtc = NULL; 2636428d7b3dSmrg best_coverage = 0; 2637428d7b3dSmrg crtc_box_ret->x1 = 0; 2638428d7b3dSmrg crtc_box_ret->x2 = 0; 2639428d7b3dSmrg crtc_box_ret->y1 = 0; 2640428d7b3dSmrg crtc_box_ret->y2 = 0; 2641428d7b3dSmrg for (c = 0; c < xf86_config->num_crtc; c++) { 2642428d7b3dSmrg crtc = xf86_config->crtc[c]; 2643428d7b3dSmrg 2644428d7b3dSmrg /* If the CRTC is off, treat it as not covering */ 2645428d7b3dSmrg if (!intel_crtc_on(crtc)) 2646428d7b3dSmrg continue; 2647428d7b3dSmrg 2648428d7b3dSmrg intel_crtc_box(crtc, &crtc_box); 2649428d7b3dSmrg intel_box_intersect(&cover_box, &crtc_box, box); 2650428d7b3dSmrg coverage = intel_box_area(&cover_box); 2651428d7b3dSmrg if (coverage && crtc == desired) { 2652428d7b3dSmrg *crtc_box_ret = crtc_box; 2653428d7b3dSmrg return crtc; 2654428d7b3dSmrg } 2655428d7b3dSmrg if (coverage > best_coverage) { 2656428d7b3dSmrg *crtc_box_ret = crtc_box; 2657428d7b3dSmrg best_crtc = crtc; 2658428d7b3dSmrg best_coverage = coverage; 2659428d7b3dSmrg } 2660428d7b3dSmrg } 2661428d7b3dSmrg return best_crtc; 2662428d7b3dSmrg} 2663