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