drmmode_display.c revision 446f62d6
1de2362d3Smrg/*
2de2362d3Smrg * Copyright © 2007 Red Hat, Inc.
3de2362d3Smrg *
4de2362d3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5de2362d3Smrg * copy of this software and associated documentation files (the "Software"),
6de2362d3Smrg * to deal in the Software without restriction, including without limitation
7de2362d3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8de2362d3Smrg * and/or sell copies of the Software, and to permit persons to whom the
9de2362d3Smrg * Software is furnished to do so, subject to the following conditions:
10de2362d3Smrg *
11de2362d3Smrg * The above copyright notice and this permission notice (including the next
12de2362d3Smrg * paragraph) shall be included in all copies or substantial portions of the
13de2362d3Smrg * Software.
14de2362d3Smrg *
15de2362d3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16de2362d3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17de2362d3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18de2362d3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19de2362d3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20de2362d3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21de2362d3Smrg * SOFTWARE.
22de2362d3Smrg *
23de2362d3Smrg * Authors:
24de2362d3Smrg *    Dave Airlie <airlied@redhat.com>
25de2362d3Smrg *
26de2362d3Smrg */
27de2362d3Smrg
28de2362d3Smrg#ifdef HAVE_CONFIG_H
29de2362d3Smrg#include "config.h"
30de2362d3Smrg#endif
31de2362d3Smrg
32de2362d3Smrg#include <errno.h>
33de2362d3Smrg#include <sys/ioctl.h>
3418781e08Smrg#include <time.h>
3518781e08Smrg#include "cursorstr.h"
3618781e08Smrg#include "damagestr.h"
378bf5c682Smrg#include "inputstr.h"
388bf5c682Smrg#include "list.h"
39de2362d3Smrg#include "micmap.h"
4039413783Smrg#include "mipointrst.h"
41de2362d3Smrg#include "xf86cmap.h"
4218781e08Smrg#include "xf86Priv.h"
43de2362d3Smrg#include "radeon.h"
4418781e08Smrg#include "radeon_bo_helper.h"
4518781e08Smrg#include "radeon_glamor.h"
46de2362d3Smrg#include "radeon_reg.h"
4718781e08Smrg
4818781e08Smrg#include <dri.h>
49de2362d3Smrg
50de2362d3Smrg#include "drmmode_display.h"
51de2362d3Smrg
52de2362d3Smrg/* DPMS */
53de2362d3Smrg#ifdef HAVE_XEXTPROTO_71
54de2362d3Smrg#include <X11/extensions/dpmsconst.h>
55de2362d3Smrg#else
56de2362d3Smrg#define DPMS_SERVER
57de2362d3Smrg#include <X11/extensions/dpms.h>
58de2362d3Smrg#endif
59de2362d3Smrg
6018781e08Smrg#define DEFAULT_NOMINAL_FRAME_RATE 60
6118781e08Smrg
6218781e08Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 22
6318781e08Smrg#define HAVE_NOTIFY_FD	1
6418781e08Smrg#endif
6518781e08Smrg
6618781e08Smrgstatic Bool
6718781e08Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height);
6818781e08Smrg
6918781e08Smrgstatic Bool
7018781e08SmrgRADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name)
7118781e08Smrg{
7218781e08Smrg    int i = 0;
7318781e08Smrg    char s1[20];
7418781e08Smrg
7518781e08Smrg    do {
7618781e08Smrg	switch(*s) {
7718781e08Smrg	case ',':
7818781e08Smrg  	    s1[i] = '\0';
7918781e08Smrg	    i = 0;
8018781e08Smrg	    if (strcmp(s1, output_name) == 0)
8118781e08Smrg		return TRUE;
8218781e08Smrg	    break;
8318781e08Smrg	case ' ':
8418781e08Smrg	case '\t':
8518781e08Smrg	case '\n':
8618781e08Smrg	case '\r':
8718781e08Smrg	    break;
8818781e08Smrg	default:
8918781e08Smrg	    s1[i] = *s;
9018781e08Smrg	    i++;
9118781e08Smrg	    break;
9218781e08Smrg	}
9318781e08Smrg    } while(*s++);
9418781e08Smrg
9518781e08Smrg    s1[i] = '\0';
9618781e08Smrg    if (strcmp(s1, output_name) == 0)
9718781e08Smrg	return TRUE;
9818781e08Smrg
9918781e08Smrg    return FALSE;
10018781e08Smrg}
10118781e08Smrg
1028bf5c682Smrg
103de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
104de2362d3Smrg					  int width, int height,
105de2362d3Smrg					  int depth, int bpp,
10618781e08Smrg					  int pitch,
10739413783Smrg					  struct radeon_buffer *bo)
108de2362d3Smrg{
109de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
110de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
111de2362d3Smrg	PixmapPtr pixmap;
112de2362d3Smrg
11318781e08Smrg	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth,
11418781e08Smrg					  RADEON_CREATE_PIXMAP_SCANOUT);
115de2362d3Smrg	if (!pixmap)
116de2362d3Smrg		return NULL;
117de2362d3Smrg
1187314432eSmrg	if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height,
1197314432eSmrg					    depth, bpp, pitch, NULL)) {
12018781e08Smrg		goto fail;
1217314432eSmrg	}
1227314432eSmrg
12318781e08Smrg	if (!info->use_glamor)
12418781e08Smrg		exaMoveInPixmap(pixmap);
12518781e08Smrg
12618781e08Smrg	if (!radeon_set_pixmap_bo(pixmap, bo))
12718781e08Smrg		goto fail;
12818781e08Smrg
12939413783Smrg	if (info->surf_man && !info->use_glamor) {
13039413783Smrg		struct radeon_surface *surface = radeon_get_pixmap_surface(pixmap);
13139413783Smrg
13239413783Smrg		if (!radeon_surface_initialize(info, surface, width, height, bpp / 8,
13339413783Smrg					       radeon_get_pixmap_tiling_flags(pixmap), 0))
13439413783Smrg			goto fail;
135de2362d3Smrg	}
136de2362d3Smrg
13718781e08Smrg	if (!info->use_glamor ||
13839413783Smrg	    radeon_glamor_create_textured_pixmap(pixmap, bo))
13918781e08Smrg		return pixmap;
14018781e08Smrg
14118781e08Smrgfail:
14218781e08Smrg	pScreen->DestroyPixmap(pixmap);
14318781e08Smrg	return NULL;
144de2362d3Smrg}
145de2362d3Smrg
146de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
147de2362d3Smrg{
148de2362d3Smrg	ScreenPtr pScreen = pixmap->drawable.pScreen;
149de2362d3Smrg
150de2362d3Smrg	(*pScreen->DestroyPixmap)(pixmap);
151de2362d3Smrg}
152de2362d3Smrg
153de2362d3Smrgstatic void
154de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr	scrn,
155de2362d3Smrg		     drmModeModeInfo *kmode,
156de2362d3Smrg		     DisplayModePtr	mode)
157de2362d3Smrg{
158de2362d3Smrg	memset(mode, 0, sizeof(DisplayModeRec));
159de2362d3Smrg	mode->status = MODE_OK;
160de2362d3Smrg
161de2362d3Smrg	mode->Clock = kmode->clock;
162de2362d3Smrg
163de2362d3Smrg	mode->HDisplay = kmode->hdisplay;
164de2362d3Smrg	mode->HSyncStart = kmode->hsync_start;
165de2362d3Smrg	mode->HSyncEnd = kmode->hsync_end;
166de2362d3Smrg	mode->HTotal = kmode->htotal;
167de2362d3Smrg	mode->HSkew = kmode->hskew;
168de2362d3Smrg
169de2362d3Smrg	mode->VDisplay = kmode->vdisplay;
170de2362d3Smrg	mode->VSyncStart = kmode->vsync_start;
171de2362d3Smrg	mode->VSyncEnd = kmode->vsync_end;
172de2362d3Smrg	mode->VTotal = kmode->vtotal;
173de2362d3Smrg	mode->VScan = kmode->vscan;
174de2362d3Smrg
175de2362d3Smrg	mode->Flags = kmode->flags; //& FLAG_BITS;
176de2362d3Smrg	mode->name = strdup(kmode->name);
177de2362d3Smrg
178de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_DRIVER)
179de2362d3Smrg		mode->type = M_T_DRIVER;
180de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
181de2362d3Smrg		mode->type |= M_T_PREFERRED;
182de2362d3Smrg	xf86SetModeCrtc (mode, scrn->adjustFlags);
183de2362d3Smrg}
184de2362d3Smrg
185de2362d3Smrgstatic void
186de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr	scrn,
187de2362d3Smrg		     drmModeModeInfo *kmode,
188de2362d3Smrg		     DisplayModePtr	mode)
189de2362d3Smrg{
190de2362d3Smrg	memset(kmode, 0, sizeof(*kmode));
191de2362d3Smrg
192de2362d3Smrg	kmode->clock = mode->Clock;
193de2362d3Smrg	kmode->hdisplay = mode->HDisplay;
194de2362d3Smrg	kmode->hsync_start = mode->HSyncStart;
195de2362d3Smrg	kmode->hsync_end = mode->HSyncEnd;
196de2362d3Smrg	kmode->htotal = mode->HTotal;
197de2362d3Smrg	kmode->hskew = mode->HSkew;
198de2362d3Smrg
199de2362d3Smrg	kmode->vdisplay = mode->VDisplay;
200de2362d3Smrg	kmode->vsync_start = mode->VSyncStart;
201de2362d3Smrg	kmode->vsync_end = mode->VSyncEnd;
202de2362d3Smrg	kmode->vtotal = mode->VTotal;
203de2362d3Smrg	kmode->vscan = mode->VScan;
204de2362d3Smrg
205de2362d3Smrg	kmode->flags = mode->Flags; //& FLAG_BITS;
206de2362d3Smrg	if (mode->name)
207de2362d3Smrg		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
208de2362d3Smrg	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
209de2362d3Smrg
210de2362d3Smrg}
211de2362d3Smrg
2128bf5c682Smrg/*
2138bf5c682Smrg * Utility helper for drmWaitVBlank
2148bf5c682Smrg */
2158bf5c682SmrgBool
2168bf5c682Smrgdrmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type,
2178bf5c682Smrg		    uint32_t target_seq, unsigned long signal, uint64_t *ust,
2188bf5c682Smrg		    uint32_t *result_seq)
2198bf5c682Smrg{
2208bf5c682Smrg	int crtc_id = drmmode_get_crtc_id(crtc);
2218bf5c682Smrg	ScrnInfoPtr scrn = crtc->scrn;
2228bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
2238bf5c682Smrg	drmVBlank vbl;
2248bf5c682Smrg
2258bf5c682Smrg	if (crtc_id == 1)
2268bf5c682Smrg		type |= DRM_VBLANK_SECONDARY;
2278bf5c682Smrg	else if (crtc_id > 1)
2288bf5c682Smrg		type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) &
2298bf5c682Smrg			DRM_VBLANK_HIGH_CRTC_MASK;
2308bf5c682Smrg
2318bf5c682Smrg	vbl.request.type = type;
2328bf5c682Smrg	vbl.request.sequence = target_seq;
2338bf5c682Smrg	vbl.request.signal = signal;
2348bf5c682Smrg
2358bf5c682Smrg	if (drmWaitVBlank(pRADEONEnt->fd, &vbl) != 0)
2368bf5c682Smrg		return FALSE;
2378bf5c682Smrg
2388bf5c682Smrg	if (ust)
2398bf5c682Smrg		*ust = (uint64_t)vbl.reply.tval_sec * 1000000 +
2408bf5c682Smrg			vbl.reply.tval_usec;
2418bf5c682Smrg	if (result_seq)
2428bf5c682Smrg		*result_seq = vbl.reply.sequence;
2438bf5c682Smrg
2448bf5c682Smrg	return TRUE;
2458bf5c682Smrg}
2468bf5c682Smrg
24718781e08Smrg/*
24818781e08Smrg * Retrieves present time in microseconds that is compatible
24918781e08Smrg * with units used by vblank timestamps. Depending on the kernel
25018781e08Smrg * version and DRM kernel module configuration, the vblank
25118781e08Smrg * timestamp can either be in real time or monotonic time
25218781e08Smrg */
25318781e08Smrgint drmmode_get_current_ust(int drm_fd, CARD64 *ust)
25418781e08Smrg{
25518781e08Smrg	uint64_t cap_value;
25618781e08Smrg	int ret;
25718781e08Smrg	struct timespec now;
25818781e08Smrg
25918781e08Smrg	ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value);
26018781e08Smrg	if (ret || !cap_value)
26118781e08Smrg		/* old kernel or drm_timestamp_monotonic turned off */
26218781e08Smrg		ret = clock_gettime(CLOCK_REALTIME, &now);
26318781e08Smrg	else
26418781e08Smrg		ret = clock_gettime(CLOCK_MONOTONIC, &now);
26518781e08Smrg	if (ret)
26618781e08Smrg		return ret;
26718781e08Smrg	*ust = ((CARD64)now.tv_sec * 1000000) + ((CARD64)now.tv_nsec / 1000);
26818781e08Smrg	return 0;
26918781e08Smrg}
27018781e08Smrg
27118781e08Smrg/*
27218781e08Smrg * Get current frame count and frame count timestamp of the crtc.
27318781e08Smrg */
27418781e08Smrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)
27518781e08Smrg{
27618781e08Smrg    ScrnInfoPtr scrn = crtc->scrn;
2778bf5c682Smrg    uint32_t seq;
27818781e08Smrg
2798bf5c682Smrg    if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) {
28018781e08Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
28118781e08Smrg		   "get vblank counter failed: %s\n", strerror(errno));
2828bf5c682Smrg	return -1;
28318781e08Smrg    }
28418781e08Smrg
2858bf5c682Smrg    *msc = seq;
28618781e08Smrg
28718781e08Smrg    return Success;
28818781e08Smrg}
28918781e08Smrg
290de2362d3Smrgstatic void
29118781e08Smrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
292de2362d3Smrg{
293de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
29418781e08Smrg	ScrnInfoPtr scrn = crtc->scrn;
2958bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
29618781e08Smrg	CARD64 ust;
29718781e08Smrg	int ret;
2987314432eSmrg
29918781e08Smrg	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
3008bf5c682Smrg		uint32_t seq;
30118781e08Smrg
30239413783Smrg		radeon_drm_wait_pending_flip(crtc);
30318781e08Smrg
30418781e08Smrg		/*
30518781e08Smrg		 * On->Off transition: record the last vblank time,
30618781e08Smrg		 * sequence number and frame period.
30718781e08Smrg		 */
3088bf5c682Smrg		if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust,
3098bf5c682Smrg					 &seq))
31018781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
31118781e08Smrg				   "%s cannot get last vblank counter\n",
31218781e08Smrg				   __func__);
31318781e08Smrg		else {
31418781e08Smrg			CARD64 nominal_frame_rate, pix_in_frame;
31518781e08Smrg
31618781e08Smrg			drmmode_crtc->dpms_last_ust = ust;
31718781e08Smrg			drmmode_crtc->dpms_last_seq = seq;
31818781e08Smrg			nominal_frame_rate = crtc->mode.Clock;
31918781e08Smrg			nominal_frame_rate *= 1000;
32018781e08Smrg			pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal;
32118781e08Smrg			if (nominal_frame_rate == 0 || pix_in_frame == 0)
32218781e08Smrg				nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE;
32318781e08Smrg			else
32418781e08Smrg				nominal_frame_rate /= pix_in_frame;
32518781e08Smrg			drmmode_crtc->dpms_last_fps = nominal_frame_rate;
32618781e08Smrg		}
32739413783Smrg
32839413783Smrg		drmmode_crtc->dpms_mode = mode;
32939413783Smrg		radeon_drm_queue_handle_deferred(crtc);
33018781e08Smrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) {
33118781e08Smrg		/*
33218781e08Smrg		 * Off->On transition: calculate and accumulate the
33318781e08Smrg		 * number of interpolated vblanks while we were in Off state
33418781e08Smrg		 */
3358bf5c682Smrg		ret = drmmode_get_current_ust(pRADEONEnt->fd, &ust);
33618781e08Smrg		if (ret)
33718781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
33818781e08Smrg				   "%s cannot get current time\n", __func__);
33918781e08Smrg		else if (drmmode_crtc->dpms_last_ust) {
34018781e08Smrg			CARD64 time_elapsed, delta_seq;
34118781e08Smrg			time_elapsed = ust - drmmode_crtc->dpms_last_ust;
34218781e08Smrg			delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps;
34318781e08Smrg			delta_seq /= 1000000;
34418781e08Smrg			drmmode_crtc->interpolated_vblanks += delta_seq;
34518781e08Smrg
34618781e08Smrg		}
34739413783Smrg
34839413783Smrg		drmmode_crtc->dpms_mode = DPMSModeOn;
3497821949aSmrg	}
35018781e08Smrg}
35118781e08Smrg
35218781e08Smrgstatic void
35318781e08Smrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
35418781e08Smrg{
35518781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3568bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
35718781e08Smrg
35818781e08Smrg	/* Disable unused CRTCs */
35918781e08Smrg	if (!crtc->enabled || mode != DPMSModeOn) {
36039413783Smrg		drmmode_do_crtc_dpms(crtc, DPMSModeOff);
3618bf5c682Smrg		drmModeSetCrtc(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
36218781e08Smrg			       0, 0, 0, NULL, 0, NULL);
3638bf5c682Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL);
36418781e08Smrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn)
36518781e08Smrg		crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
36618781e08Smrg					    crtc->x, crtc->y);
367de2362d3Smrg}
368de2362d3Smrg
369de2362d3Smrgstatic PixmapPtr
370de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode,
371de2362d3Smrg			ScrnInfoPtr pScrn, int fbcon_id)
372de2362d3Smrg{
3738bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
37418781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
37518781e08Smrg	PixmapPtr pixmap = info->fbcon_pixmap;
37639413783Smrg	struct radeon_buffer *bo;
377de2362d3Smrg	drmModeFBPtr fbcon;
378de2362d3Smrg	struct drm_gem_flink flink;
379de2362d3Smrg
38018781e08Smrg	if (pixmap)
38118781e08Smrg	    return pixmap;
38218781e08Smrg
3838bf5c682Smrg	fbcon = drmModeGetFB(pRADEONEnt->fd, fbcon_id);
38439413783Smrg	if (!fbcon)
385de2362d3Smrg		return NULL;
386de2362d3Smrg
387de2362d3Smrg	if (fbcon->depth != pScrn->depth ||
388de2362d3Smrg	    fbcon->width != pScrn->virtualX ||
389de2362d3Smrg	    fbcon->height != pScrn->virtualY)
390de2362d3Smrg		goto out_free_fb;
391de2362d3Smrg
392de2362d3Smrg	flink.handle = fbcon->handle;
3938bf5c682Smrg	if (ioctl(pRADEONEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
394de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
395de2362d3Smrg			   "Couldn't flink fbcon handle\n");
396de2362d3Smrg		goto out_free_fb;
397de2362d3Smrg	}
398de2362d3Smrg
39939413783Smrg	bo = calloc(1, sizeof(struct radeon_buffer));
40039413783Smrg	if (!bo) {
401de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
40239413783Smrg			   "Couldn't allocate BO for fbcon handle\n");
40339413783Smrg		goto out_free_fb;
40439413783Smrg	}
40539413783Smrg	bo->ref_count = 1;
40639413783Smrg
40739413783Smrg	bo->bo.radeon = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0);
40839413783Smrg	if (!bo) {
40939413783Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
41039413783Smrg			   "Couldn't open BO for fbcon handle\n");
411de2362d3Smrg		goto out_free_fb;
412de2362d3Smrg	}
413de2362d3Smrg
414de2362d3Smrg	pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height,
41518781e08Smrg					  fbcon->depth, fbcon->bpp, fbcon->pitch,
41639413783Smrg					  bo);
41718781e08Smrg	info->fbcon_pixmap = pixmap;
41839413783Smrg	radeon_buffer_unref(&bo);
419de2362d3Smrgout_free_fb:
420de2362d3Smrg	drmModeFreeFB(fbcon);
421de2362d3Smrg	return pixmap;
422de2362d3Smrg}
423de2362d3Smrg
42418781e08Smrgstatic void
42518781e08Smrgdestroy_pixmap_for_fbcon(ScrnInfoPtr pScrn)
42618781e08Smrg{
42718781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
42818781e08Smrg
42918781e08Smrg	/* XXX: The current GPUVM support in the kernel doesn't allow removing
43018781e08Smrg	 * the virtual address range for this BO, so we need to keep around
43118781e08Smrg	 * the pixmap to avoid breaking glamor with GPUVM
43239413783Smrg	 *
43339413783Smrg	 * Similarly, need to keep around the pixmap with current glamor, to
43439413783Smrg	 * avoid issues due to a GEM handle lifetime conflict between us and
43539413783Smrg	 * Mesa
43618781e08Smrg	 */
43739413783Smrg	if (info->use_glamor &&
43839413783Smrg	    (info->ChipFamily >= CHIP_FAMILY_CAYMAN ||
43939413783Smrg	     xorgGetVersion() >= XORG_VERSION_NUMERIC(1,19,99,1,0)))
44018781e08Smrg		return;
44118781e08Smrg
44218781e08Smrg	if (info->fbcon_pixmap)
44318781e08Smrg		pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap);
44418781e08Smrg	info->fbcon_pixmap = NULL;
44518781e08Smrg}
44618781e08Smrg
447de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
448de2362d3Smrg{
449de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
450de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
451de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
4528bf5c682Smrg	PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen);
4538bf5c682Smrg	struct drmmode_fb *fb = radeon_pixmap_get_fb(dst);
454de2362d3Smrg	int fbcon_id = 0;
45518781e08Smrg	Bool force;
45618781e08Smrg	GCPtr gc;
457de2362d3Smrg	int i;
458de2362d3Smrg
459de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
460de2362d3Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
461de2362d3Smrg
462de2362d3Smrg		if (drmmode_crtc->mode_crtc->buffer_id)
463de2362d3Smrg			fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
464de2362d3Smrg	}
465de2362d3Smrg
466de2362d3Smrg	if (!fbcon_id)
46718781e08Smrg		return;
46818781e08Smrg
4698bf5c682Smrg	if (fbcon_id == fb->handle) {
47018781e08Smrg		/* in some rare case there might be no fbcon and we might already
47118781e08Smrg		 * be the one with the current fb to avoid a false deadlck in
47218781e08Smrg		 * kernel ttm code just do nothing as anyway there is nothing
47318781e08Smrg		 * to do
47418781e08Smrg		 */
47518781e08Smrg		return;
47618781e08Smrg	}
477de2362d3Smrg
478de2362d3Smrg	src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
479de2362d3Smrg	if (!src)
48018781e08Smrg		return;
4810d16fef4Smrg
48218781e08Smrg	gc = GetScratchGC(pScrn->depth, pScreen);
48318781e08Smrg	ValidateGC(&dst->drawable, gc);
48418781e08Smrg
48518781e08Smrg	force = info->accel_state->force;
48618781e08Smrg	info->accel_state->force = TRUE;
48718781e08Smrg	(*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0,
48818781e08Smrg			     pScrn->virtualX, pScrn->virtualY, 0, 0);
48918781e08Smrg	info->accel_state->force = force;
49018781e08Smrg
49118781e08Smrg	FreeScratchGC(gc);
492de2362d3Smrg
493de2362d3Smrg	pScreen->canDoBGNoneRoot = TRUE;
49418781e08Smrg	destroy_pixmap_for_fbcon(pScrn);
4957821949aSmrg	return;
49618781e08Smrg}
4970d16fef4Smrg
4988bf5c682Smrgvoid
49918781e08Smrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
50018781e08Smrg			     struct drmmode_scanout *scanout)
50118781e08Smrg{
50218781e08Smrg	if (scanout->pixmap) {
50318781e08Smrg		drmmode_destroy_bo_pixmap(scanout->pixmap);
50418781e08Smrg		scanout->pixmap = NULL;
50518781e08Smrg	}
50618781e08Smrg
50739413783Smrg	radeon_buffer_unref(&scanout->bo);
50818781e08Smrg}
50918781e08Smrg
5108bf5c682Smrgvoid
511446f62d6Smrgdrmmode_crtc_scanout_free(xf86CrtcPtr crtc)
51218781e08Smrg{
513446f62d6Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
514446f62d6Smrg
515446f62d6Smrg	if (drmmode_crtc->scanout_update_pending) {
516446f62d6Smrg		radeon_drm_wait_pending_flip(crtc);
517446f62d6Smrg		radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending);
518446f62d6Smrg		drmmode_crtc->scanout_update_pending = 0;
519446f62d6Smrg		radeon_drm_queue_handle_deferred(crtc);
520446f62d6Smrg	}
521446f62d6Smrg
5228bf5c682Smrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
5238bf5c682Smrg				     &drmmode_crtc->scanout[0]);
5248bf5c682Smrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
5258bf5c682Smrg				     &drmmode_crtc->scanout[1]);
52618781e08Smrg
5278bf5c682Smrg	if (drmmode_crtc->scanout_damage)
52818781e08Smrg		DamageDestroy(drmmode_crtc->scanout_damage);
52918781e08Smrg}
53018781e08Smrg
5318bf5c682SmrgPixmapPtr
5323ed65abbSmrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
5333ed65abbSmrg			    int width, int height)
53418781e08Smrg{
53518781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
53618781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
53718781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
53818781e08Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
53918781e08Smrg	struct radeon_surface surface;
54018781e08Smrg	uint32_t tiling = RADEON_CREATE_PIXMAP_TILING_MACRO;
54118781e08Smrg	int pitch;
54218781e08Smrg
5433ed65abbSmrg	if (scanout->pixmap) {
54418781e08Smrg		if (scanout->width == width && scanout->height == height)
5453ed65abbSmrg			return scanout->pixmap;
54618781e08Smrg
54718781e08Smrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
54818781e08Smrg	}
54918781e08Smrg
55018781e08Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600)
55118781e08Smrg		tiling |= RADEON_CREATE_PIXMAP_TILING_MICRO;
55218781e08Smrg	scanout->bo = radeon_alloc_pixmap_bo(pScrn, width, height, pScrn->depth,
55318781e08Smrg					     tiling, pScrn->bitsPerPixel,
55418781e08Smrg					     &pitch, &surface, &tiling);
5558bf5c682Smrg	if (!scanout->bo) {
5568bf5c682Smrg		ErrorF("failed to create CRTC scanout BO\n");
5578bf5c682Smrg		return NULL;
55818781e08Smrg	}
55918781e08Smrg
56018781e08Smrg	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
56118781e08Smrg						 width, height,
56218781e08Smrg						 pScrn->depth,
56318781e08Smrg						 pScrn->bitsPerPixel,
56439413783Smrg						 pitch, scanout->bo);
5658bf5c682Smrg	if (!scanout->pixmap) {
5668bf5c682Smrg		ErrorF("failed to create CRTC scanout pixmap\n");
5678bf5c682Smrg		goto error;
5688bf5c682Smrg	}
5698bf5c682Smrg
5708bf5c682Smrg	if (radeon_pixmap_get_fb(scanout->pixmap)) {
5713ed65abbSmrg		scanout->width = width;
5723ed65abbSmrg		scanout->height = height;
5733ed65abbSmrg	} else {
5748bf5c682Smrg		ErrorF("failed to create CRTC scanout FB\n");
5758bf5c682Smrgerror:
5763ed65abbSmrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
5773ed65abbSmrg	}
57818781e08Smrg
57918781e08Smrg	return scanout->pixmap;
58018781e08Smrg}
58118781e08Smrg
58218781e08Smrgstatic void
58318781e08Smrgradeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
58418781e08Smrg{
5858bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = closure;
5868bf5c682Smrg
5878bf5c682Smrg	if (drmmode_crtc->ignore_damage) {
5888bf5c682Smrg		RegionEmpty(&damage->damage);
5898bf5c682Smrg		drmmode_crtc->ignore_damage = FALSE;
5908bf5c682Smrg		return;
5918bf5c682Smrg	}
5928bf5c682Smrg
59318781e08Smrg	/* Only keep track of the extents */
59418781e08Smrg	RegionUninit(&damage->damage);
59518781e08Smrg	damage->damage.data = NULL;
59618781e08Smrg}
59718781e08Smrg
5988bf5c682Smrgstatic void
5998bf5c682Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure)
6008bf5c682Smrg{
6018bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = closure;
6028bf5c682Smrg
6038bf5c682Smrg	drmmode_crtc->scanout_damage = NULL;
6048bf5c682Smrg	RegionUninit(&drmmode_crtc->scanout_last_region);
6058bf5c682Smrg}
6068bf5c682Smrg
60718781e08Smrgstatic Bool
60818781e08Smrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc)
60918781e08Smrg{
61018781e08Smrg	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
61118781e08Smrg
61218781e08Smrg	/* Check for Option "SWcursor" */
61318781e08Smrg	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
61418781e08Smrg		return FALSE;
61518781e08Smrg
61618781e08Smrg	/* Fall back to SW cursor if the CRTC is transformed */
61718781e08Smrg	if (crtc->transformPresent)
61818781e08Smrg		return FALSE;
6190d16fef4Smrg
6208bf5c682Smrg#if XF86_CRTC_VERSION < 7
62118781e08Smrg	/* Xorg doesn't correctly handle cursor position transform in the
62218781e08Smrg	 * rotation case
62318781e08Smrg	 */
62418781e08Smrg	if (crtc->driverIsPerformingTransform &&
62518781e08Smrg	    (crtc->rotation & 0xf) != RR_Rotate_0)
62618781e08Smrg		return FALSE;
62718781e08Smrg#endif
62818781e08Smrg
62918781e08Smrg	/* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */
63018781e08Smrg	if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) &&
63118781e08Smrg	    !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list))
63218781e08Smrg		return FALSE;
63318781e08Smrg
63418781e08Smrg	return TRUE;
63518781e08Smrg}
63618781e08Smrg
6373ed65abbSmrgstatic void
6383ed65abbSmrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc)
6393ed65abbSmrg{
6403ed65abbSmrg	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
6413ed65abbSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
6423ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
6433ed65abbSmrg	int i;
6443ed65abbSmrg
6453ed65abbSmrg	drmmode_crtc->tear_free = FALSE;
6463ed65abbSmrg
6473ed65abbSmrg	for (i = 0; i < xf86_config->num_output; i++) {
6483ed65abbSmrg		xf86OutputPtr output = xf86_config->output[i];
6493ed65abbSmrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
6503ed65abbSmrg
6513ed65abbSmrg		if (output->crtc != crtc)
6523ed65abbSmrg			continue;
6533ed65abbSmrg
6543ed65abbSmrg		if (drmmode_output->tear_free == 1 ||
6553ed65abbSmrg		    (drmmode_output->tear_free == 2 &&
6568bf5c682Smrg		     (crtc->scrn->pScreen->isGPU ||
6573ed65abbSmrg		      info->shadow_primary ||
6583ed65abbSmrg		      crtc->transformPresent || crtc->rotation != RR_Rotate_0))) {
6593ed65abbSmrg			drmmode_crtc->tear_free = TRUE;
6603ed65abbSmrg			return;
6613ed65abbSmrg		}
6623ed65abbSmrg	}
6633ed65abbSmrg}
6643ed65abbSmrg
6653ed65abbSmrg#if XF86_CRTC_VERSION < 7
6663ed65abbSmrg#define XF86DriverTransformOutput TRUE
6673ed65abbSmrg#define XF86DriverTransformNone FALSE
6683ed65abbSmrg#endif
6693ed65abbSmrg
67018781e08Smrgstatic Bool
67118781e08Smrgdrmmode_handle_transform(xf86CrtcPtr crtc)
67218781e08Smrg{
67318781e08Smrg	Bool ret;
67418781e08Smrg
6758bf5c682Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
67639413783Smrg	crtc->driverIsPerformingTransform = XF86DriverTransformOutput;
6778bf5c682Smrg#else
6788bf5c682Smrg	crtc->driverIsPerformingTransform = !crtc->transformPresent &&
6798bf5c682Smrg		(crtc->rotation & 0xf) == RR_Rotate_0;
6808bf5c682Smrg#endif
68118781e08Smrg
68218781e08Smrg	ret = xf86CrtcRotate(crtc);
68318781e08Smrg
68418781e08Smrg	crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use;
68518781e08Smrg
68618781e08Smrg	return ret;
6870d16fef4Smrg}
6880d16fef4Smrg
6893ed65abbSmrg
6903ed65abbSmrgstatic void
6913ed65abbSmrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
6928bf5c682Smrg				  unsigned scanout_id, struct drmmode_fb **fb,
6938bf5c682Smrg				  int *x, int *y)
6943ed65abbSmrg{
6953ed65abbSmrg	ScrnInfoPtr scrn = crtc->scrn;
6963ed65abbSmrg	ScreenPtr screen = scrn->pScreen;
6973ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
6983ed65abbSmrg
6993ed65abbSmrg	if (drmmode_crtc->tear_free &&
7003ed65abbSmrg	    !drmmode_crtc->scanout[1].pixmap) {
7013ed65abbSmrg		RegionPtr region;
7023ed65abbSmrg		BoxPtr box;
7033ed65abbSmrg
7043ed65abbSmrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
7053ed65abbSmrg					    mode->HDisplay,
7063ed65abbSmrg					    mode->VDisplay);
7073ed65abbSmrg		region = &drmmode_crtc->scanout_last_region;
7083ed65abbSmrg		RegionUninit(region);
7093ed65abbSmrg		region->data = NULL;
7103ed65abbSmrg		box = RegionExtents(region);
7113ed65abbSmrg		box->x1 = crtc->x;
7123ed65abbSmrg		box->y1 = crtc->y;
7133ed65abbSmrg		box->x2 = crtc->x + mode->HDisplay;
7143ed65abbSmrg		box->y2 = crtc->y + mode->VDisplay;
7153ed65abbSmrg	}
7163ed65abbSmrg
7173ed65abbSmrg	if (scanout_id != drmmode_crtc->scanout_id) {
7183ed65abbSmrg		PixmapDirtyUpdatePtr dirty = NULL;
7193ed65abbSmrg
7203ed65abbSmrg		xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list,
7213ed65abbSmrg					 ent) {
7228bf5c682Smrg			if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
7233ed65abbSmrg				dirty->slave_dst =
7243ed65abbSmrg					drmmode_crtc->scanout[scanout_id].pixmap;
7253ed65abbSmrg				break;
7263ed65abbSmrg			}
7273ed65abbSmrg		}
7283ed65abbSmrg
7293ed65abbSmrg		if (!drmmode_crtc->tear_free) {
7303ed65abbSmrg			GCPtr gc = GetScratchGC(scrn->depth, screen);
7313ed65abbSmrg
7323ed65abbSmrg			ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc);
7333ed65abbSmrg			gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable,
7343ed65abbSmrg					  &drmmode_crtc->scanout[0].pixmap->drawable,
7353ed65abbSmrg					  gc, 0, 0, mode->HDisplay, mode->VDisplay,
7363ed65abbSmrg					  0, 0);
7373ed65abbSmrg			FreeScratchGC(gc);
73839413783Smrg			radeon_finish(scrn, drmmode_crtc->scanout[0].bo);
7393ed65abbSmrg		}
7403ed65abbSmrg	}
7413ed65abbSmrg
7428bf5c682Smrg	*fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
7433ed65abbSmrg	*x = *y = 0;
7443ed65abbSmrg	drmmode_crtc->scanout_id = scanout_id;
7453ed65abbSmrg}
7463ed65abbSmrg
7473ed65abbSmrg
7483ed65abbSmrgstatic void
7493ed65abbSmrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
7508bf5c682Smrg			    unsigned scanout_id, struct drmmode_fb **fb, int *x,
7518bf5c682Smrg			    int *y)
7523ed65abbSmrg{
7533ed65abbSmrg	ScrnInfoPtr scrn = crtc->scrn;
7543ed65abbSmrg	ScreenPtr screen = scrn->pScreen;
7553ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
7563ed65abbSmrg
7578bf5c682Smrg	drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id],
7583ed65abbSmrg				    mode->HDisplay, mode->VDisplay);
7593ed65abbSmrg	if (drmmode_crtc->tear_free) {
7608bf5c682Smrg		drmmode_crtc_scanout_create(crtc,
7618bf5c682Smrg					    &drmmode_crtc->scanout[scanout_id ^ 1],
7623ed65abbSmrg					    mode->HDisplay, mode->VDisplay);
7633ed65abbSmrg	}
7643ed65abbSmrg
7658bf5c682Smrg	if (drmmode_crtc->scanout[scanout_id].pixmap &&
7668bf5c682Smrg	    (!drmmode_crtc->tear_free ||
7678bf5c682Smrg	     drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) {
76839413783Smrg		BoxRec extents = { .x1 = 0, .y1 = 0,
76939413783Smrg				   .x2 = scrn->virtualX, .y2 = scrn->virtualY };
7703ed65abbSmrg
7713ed65abbSmrg		if (!drmmode_crtc->scanout_damage) {
7723ed65abbSmrg			drmmode_crtc->scanout_damage =
7733ed65abbSmrg				DamageCreate(radeon_screen_damage_report,
7748bf5c682Smrg					     drmmode_screen_damage_destroy,
7758bf5c682Smrg					     DamageReportRawRegion,
7768bf5c682Smrg					     TRUE, screen, drmmode_crtc);
7778bf5c682Smrg			DamageRegister(&screen->root->drawable,
7783ed65abbSmrg				       drmmode_crtc->scanout_damage);
7793ed65abbSmrg		}
7803ed65abbSmrg
7818bf5c682Smrg		*fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
7823ed65abbSmrg		*x = *y = 0;
7833ed65abbSmrg
784446f62d6Smrg		if (radeon_scanout_do_update(crtc, scanout_id,
785446f62d6Smrg					     screen->GetWindowPixmap(screen->root),
786446f62d6Smrg					     extents)) {
787446f62d6Smrg			RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage));
788446f62d6Smrg			radeon_finish(scrn, drmmode_crtc->scanout[scanout_id].bo);
789446f62d6Smrg
790446f62d6Smrg			if (!drmmode_crtc->flip_pending) {
791446f62d6Smrg				radeon_drm_abort_entry(drmmode_crtc->
792446f62d6Smrg						       scanout_update_pending);
793446f62d6Smrg			}
794446f62d6Smrg		}
7953ed65abbSmrg	}
7963ed65abbSmrg}
7973ed65abbSmrg
7988bf5c682Smrgstatic void
7998bf5c682Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
8008bf5c682Smrg			  uint16_t *blue, int size)
8018bf5c682Smrg{
8028bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
8038bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
8048bf5c682Smrg
8058bf5c682Smrg	drmModeCrtcSetGamma(pRADEONEnt->fd,
8068bf5c682Smrg			    drmmode_crtc->mode_crtc->crtc_id, size, red, green,
8078bf5c682Smrg			    blue);
8088bf5c682Smrg}
8098bf5c682Smrg
8108bf5c682SmrgBool
8118bf5c682Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode,
8128bf5c682Smrg		 int x, int y)
8138bf5c682Smrg{
8148bf5c682Smrg	ScrnInfoPtr scrn = crtc->scrn;
8158bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
8168bf5c682Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
8178bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
8188bf5c682Smrg	uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
8198bf5c682Smrg	int output_count = 0;
8208bf5c682Smrg	drmModeModeInfo kmode;
8218bf5c682Smrg	Bool ret;
8228bf5c682Smrg	int i;
8238bf5c682Smrg
8248bf5c682Smrg	if (!output_ids)
8258bf5c682Smrg		return FALSE;
8268bf5c682Smrg
8278bf5c682Smrg	for (i = 0; i < xf86_config->num_output; i++) {
8288bf5c682Smrg		xf86OutputPtr output = xf86_config->output[i];
8298bf5c682Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
8308bf5c682Smrg
8318bf5c682Smrg		if (output->crtc != crtc)
8328bf5c682Smrg			continue;
8338bf5c682Smrg
8348bf5c682Smrg		output_ids[output_count] = drmmode_output->mode_output->connector_id;
8358bf5c682Smrg		output_count++;
8368bf5c682Smrg	}
8378bf5c682Smrg
8388bf5c682Smrg	drmmode_ConvertToKMode(scrn, &kmode, mode);
8398bf5c682Smrg
8408bf5c682Smrg	ret = drmModeSetCrtc(pRADEONEnt->fd,
8418bf5c682Smrg			     drmmode_crtc->mode_crtc->crtc_id,
8428bf5c682Smrg			     fb->handle, x, y, output_ids,
8438bf5c682Smrg			     output_count, &kmode) == 0;
8448bf5c682Smrg
8458bf5c682Smrg	if (ret) {
8468bf5c682Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, fb);
8478bf5c682Smrg	} else {
8488bf5c682Smrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
8498bf5c682Smrg			   "failed to set mode: %s\n", strerror(errno));
8508bf5c682Smrg	}
8518bf5c682Smrg
8528bf5c682Smrg	free(output_ids);
8538bf5c682Smrg	return ret;
8548bf5c682Smrg}
8558bf5c682Smrg
856de2362d3Smrgstatic Bool
857de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
858de2362d3Smrg		     Rotation rotation, int x, int y)
859de2362d3Smrg{
860de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
86118781e08Smrg	ScreenPtr pScreen = pScrn->pScreen;
862de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
8638bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
864de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
865de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
866446f62d6Smrg	Bool handle_deferred = FALSE;
8673ed65abbSmrg	unsigned scanout_id = 0;
868de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
869de2362d3Smrg	int saved_x, saved_y;
870de2362d3Smrg	Rotation saved_rotation;
871de2362d3Smrg	DisplayModeRec saved_mode;
87218781e08Smrg	Bool ret = FALSE;
873de2362d3Smrg	int i;
8748bf5c682Smrg	struct drmmode_fb *fb = NULL;
8758bf5c682Smrg
8768bf5c682Smrg	/* The root window contents may be undefined before the WindowExposures
8778bf5c682Smrg	 * hook is called for it, so bail if we get here before that
8788bf5c682Smrg	 */
8798bf5c682Smrg	if (pScreen->WindowExposures == RADEONWindowExposures_oneshot)
8808bf5c682Smrg		return FALSE;
881de2362d3Smrg
882de2362d3Smrg	saved_mode = crtc->mode;
883de2362d3Smrg	saved_x = crtc->x;
884de2362d3Smrg	saved_y = crtc->y;
885de2362d3Smrg	saved_rotation = crtc->rotation;
886de2362d3Smrg
887de2362d3Smrg	if (mode) {
888de2362d3Smrg		crtc->mode = *mode;
889de2362d3Smrg		crtc->x = x;
890de2362d3Smrg		crtc->y = y;
891de2362d3Smrg		crtc->rotation = rotation;
892de2362d3Smrg
89318781e08Smrg		if (!drmmode_handle_transform(crtc))
894de2362d3Smrg			goto done;
89518781e08Smrg
8963ed65abbSmrg		drmmode_crtc_update_tear_free(crtc);
8973ed65abbSmrg		if (drmmode_crtc->tear_free)
8983ed65abbSmrg			scanout_id = drmmode_crtc->scanout_id;
89939413783Smrg		else
90039413783Smrg			drmmode_crtc->scanout_id = 0;
901de2362d3Smrg
9028bf5c682Smrg		if (drmmode_crtc->prime_scanout_pixmap) {
9033ed65abbSmrg			drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id,
9048bf5c682Smrg							  &fb, &x, &y);
9058bf5c682Smrg		} else if (drmmode_crtc->rotate.pixmap) {
9068bf5c682Smrg			fb = radeon_pixmap_get_fb(drmmode_crtc->rotate.pixmap);
90718781e08Smrg			x = y = 0;
90818781e08Smrg
9098bf5c682Smrg		} else if (!pScreen->isGPU &&
9103ed65abbSmrg			   (drmmode_crtc->tear_free ||
91118781e08Smrg			    crtc->driverIsPerformingTransform ||
91218781e08Smrg			    info->shadow_primary)) {
9133ed65abbSmrg			drmmode_crtc_scanout_update(crtc, mode, scanout_id,
9148bf5c682Smrg						    &fb, &x, &y);
915de2362d3Smrg		}
91618781e08Smrg
9178bf5c682Smrg		if (!fb)
9188bf5c682Smrg			fb = radeon_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root));
9198bf5c682Smrg		if (!fb) {
9208bf5c682Smrg			fb = radeon_fb_create(pScrn, pRADEONEnt->fd,
9218bf5c682Smrg					      pScrn->virtualX, pScrn->virtualY,
9228bf5c682Smrg					      pScrn->displayWidth * info->pixel_bytes,
92339413783Smrg					      info->front_buffer->bo.radeon->handle);
9248bf5c682Smrg			/* Prevent refcnt of ad-hoc FBs from reaching 2 */
9258bf5c682Smrg			drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL);
9268bf5c682Smrg			drmmode_crtc->fb = fb;
9278bf5c682Smrg		}
9288bf5c682Smrg		if (!fb) {
9298bf5c682Smrg			ErrorF("failed to add FB for modeset\n");
9308bf5c682Smrg			goto done;
93118781e08Smrg		}
93218781e08Smrg
93339413783Smrg		radeon_drm_wait_pending_flip(crtc);
934446f62d6Smrg		handle_deferred = TRUE;
9358bf5c682Smrg
9368bf5c682Smrg		if (!drmmode_set_mode(crtc, fb, mode, x, y))
93718781e08Smrg			goto done;
9388bf5c682Smrg
9398bf5c682Smrg		ret = TRUE;
940de2362d3Smrg
94118781e08Smrg		if (pScreen)
94218781e08Smrg			xf86CrtcSetScreenSubpixelOrder(pScreen);
94318781e08Smrg
94418781e08Smrg		drmmode_crtc->need_modeset = FALSE;
94518781e08Smrg
946de2362d3Smrg		/* go through all the outputs and force DPMS them back on? */
947de2362d3Smrg		for (i = 0; i < xf86_config->num_output; i++) {
948de2362d3Smrg			xf86OutputPtr output = xf86_config->output[i];
949de2362d3Smrg
950de2362d3Smrg			if (output->crtc != crtc)
951de2362d3Smrg				continue;
952de2362d3Smrg
953de2362d3Smrg			output->funcs->dpms(output, DPMSModeOn);
954de2362d3Smrg		}
955de2362d3Smrg	}
956de2362d3Smrg
95718781e08Smrg	/* Compute index of this CRTC into xf86_config->crtc */
95818781e08Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
95918781e08Smrg		if (xf86_config->crtc[i] != crtc)
96018781e08Smrg			continue;
96118781e08Smrg
96218781e08Smrg		if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc))
96318781e08Smrg			info->hwcursor_disabled &= ~(1 << i);
96418781e08Smrg		else
96518781e08Smrg			info->hwcursor_disabled |= 1 << i;
96618781e08Smrg
96718781e08Smrg		break;
96818781e08Smrg	}
96918781e08Smrg
97018781e08Smrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR
97118781e08Smrg	if (!info->hwcursor_disabled)
97218781e08Smrg		xf86_reload_cursors(pScreen);
97318781e08Smrg#endif
974de2362d3Smrg
975de2362d3Smrgdone:
976de2362d3Smrg	if (!ret) {
977de2362d3Smrg		crtc->x = saved_x;
978de2362d3Smrg		crtc->y = saved_y;
979de2362d3Smrg		crtc->rotation = saved_rotation;
980de2362d3Smrg		crtc->mode = saved_mode;
98118781e08Smrg	} else {
9827821949aSmrg		crtc->active = TRUE;
98318781e08Smrg
9848bf5c682Smrg		if (drmmode_crtc->scanout[scanout_id].pixmap &&
9858bf5c682Smrg		    fb != radeon_pixmap_get_fb(drmmode_crtc->
98639413783Smrg					       scanout[scanout_id].pixmap)) {
987446f62d6Smrg			drmmode_crtc_scanout_free(crtc);
98839413783Smrg		} else if (!drmmode_crtc->tear_free) {
9893ed65abbSmrg			drmmode_crtc_scanout_destroy(drmmode,
9903ed65abbSmrg						     &drmmode_crtc->scanout[1]);
9913ed65abbSmrg		}
99218781e08Smrg	}
99318781e08Smrg
994446f62d6Smrg	if (handle_deferred)
995446f62d6Smrg		radeon_drm_queue_handle_deferred(crtc);
996446f62d6Smrg
997de2362d3Smrg	return ret;
998de2362d3Smrg}
999de2362d3Smrg
1000de2362d3Smrgstatic void
1001de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
1002de2362d3Smrg{
1003de2362d3Smrg
1004de2362d3Smrg}
1005de2362d3Smrg
1006de2362d3Smrgstatic void
1007de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
1008de2362d3Smrg{
1009de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
10108bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
1011de2362d3Smrg
10128bf5c682Smrg#if XF86_CRTC_VERSION < 7
101318781e08Smrg	if (crtc->driverIsPerformingTransform) {
101418781e08Smrg		x += crtc->x;
101518781e08Smrg		y += crtc->y;
101618781e08Smrg		xf86CrtcTransformCursorPos(crtc, &x, &y);
101718781e08Smrg	}
101818781e08Smrg#endif
101918781e08Smrg
1020446f62d6Smrg	drmmode_crtc->cursor_x = x;
1021446f62d6Smrg	drmmode_crtc->cursor_y = y;
1022446f62d6Smrg
10238bf5c682Smrg	drmModeMoveCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
1024de2362d3Smrg}
1025de2362d3Smrg
10268bf5c682Smrg#if XF86_CRTC_VERSION < 7
102718781e08Smrg
102818781e08Smrgstatic int
102918781e08Smrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height,
103018781e08Smrg			  int x_dst, int y_dst)
103118781e08Smrg{
103218781e08Smrg	int t;
103318781e08Smrg
103418781e08Smrg	switch (rotation & 0xf) {
103518781e08Smrg	case RR_Rotate_90:
103618781e08Smrg		t = x_dst;
103718781e08Smrg		x_dst = height - y_dst - 1;
103818781e08Smrg		y_dst = t;
103918781e08Smrg		break;
104018781e08Smrg	case RR_Rotate_180:
104118781e08Smrg		x_dst = width - x_dst - 1;
104218781e08Smrg		y_dst = height - y_dst - 1;
104318781e08Smrg		break;
104418781e08Smrg	case RR_Rotate_270:
104518781e08Smrg		t = x_dst;
104618781e08Smrg		x_dst = y_dst;
104718781e08Smrg		y_dst = width - t - 1;
104818781e08Smrg		break;
104918781e08Smrg	}
105018781e08Smrg
105118781e08Smrg	if (rotation & RR_Reflect_X)
105218781e08Smrg		x_dst = width - x_dst - 1;
105318781e08Smrg	if (rotation & RR_Reflect_Y)
105418781e08Smrg		y_dst = height - y_dst - 1;
105518781e08Smrg
105618781e08Smrg	return y_dst * height + x_dst;
105718781e08Smrg}
105818781e08Smrg
105918781e08Smrg#endif
106018781e08Smrg
1061446f62d6Smrgstatic Bool
1062446f62d6Smrgdrmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool *premultiplied,
1063446f62d6Smrg		     Bool *apply_gamma)
10648bf5c682Smrg{
1065446f62d6Smrg	uint32_t alpha = *argb >> 24;
10668bf5c682Smrg	uint32_t rgb[3];
10678bf5c682Smrg	int i;
10688bf5c682Smrg
1069446f62d6Smrg	if (premultiplied) {
1070446f62d6Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0)
1071446f62d6Smrg		if (alpha == 0 && (*argb & 0xffffff) != 0) {
1072446f62d6Smrg			/* Doesn't look like premultiplied alpha */
1073446f62d6Smrg			*premultiplied = FALSE;
1074446f62d6Smrg			return FALSE;
1075446f62d6Smrg		}
1076446f62d6Smrg#endif
10778bf5c682Smrg
1078446f62d6Smrg		if (!(*apply_gamma))
1079446f62d6Smrg			return TRUE;
1080446f62d6Smrg
1081446f62d6Smrg		if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) {
1082446f62d6Smrg			/* Un-premultiplied R/G/B would overflow gamma LUT,
1083446f62d6Smrg			 * don't apply gamma correction
1084446f62d6Smrg			 */
1085446f62d6Smrg			*apply_gamma = FALSE;
1086446f62d6Smrg			return FALSE;
1087446f62d6Smrg		}
1088446f62d6Smrg	}
1089446f62d6Smrg
1090446f62d6Smrg	if (!alpha) {
1091446f62d6Smrg		*argb = 0;
1092446f62d6Smrg		return TRUE;
1093446f62d6Smrg	}
10948bf5c682Smrg
1095446f62d6Smrg	/* Extract RGB */
10968bf5c682Smrg	for (i = 0; i < 3; i++)
1097446f62d6Smrg		rgb[i] = (*argb >> (i * 8)) & 0xff;
1098446f62d6Smrg
1099446f62d6Smrg	if (premultiplied) {
1100446f62d6Smrg		/* Un-premultiply alpha */
1101446f62d6Smrg		for (i = 0; i < 3; i++)
1102446f62d6Smrg			rgb[i] = rgb[i] * 0xff / alpha;
1103446f62d6Smrg	}
11048bf5c682Smrg
1105446f62d6Smrg	if (*apply_gamma) {
1106446f62d6Smrg		rgb[0] = crtc->gamma_blue[rgb[0]] >> 8;
1107446f62d6Smrg		rgb[1] = crtc->gamma_green[rgb[1]] >> 8;
1108446f62d6Smrg		rgb[2] = crtc->gamma_red[rgb[2]] >> 8;
1109446f62d6Smrg	}
11108bf5c682Smrg
1111446f62d6Smrg	/* Premultiply alpha */
1112446f62d6Smrg	for (i = 0; i < 3; i++)
1113446f62d6Smrg		rgb[i] = rgb[i] * alpha / 0xff;
1114446f62d6Smrg
1115446f62d6Smrg	*argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
1116446f62d6Smrg	return TRUE;
11178bf5c682Smrg}
11188bf5c682Smrg
1119de2362d3Smrgstatic void
1120de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
1121de2362d3Smrg{
112218781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
112318781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1124de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1125446f62d6Smrg	unsigned id = drmmode_crtc->cursor_id;
1126446f62d6Smrg	Bool premultiplied = TRUE;
1127446f62d6Smrg	Bool apply_gamma = TRUE;
1128446f62d6Smrg	uint32_t argb;
1129de2362d3Smrg	uint32_t *ptr;
1130de2362d3Smrg
1131446f62d6Smrg	if (drmmode_crtc->cursor &&
1132446f62d6Smrg	    XF86_CRTC_CONFIG_PTR(pScrn)->cursor != drmmode_crtc->cursor)
1133446f62d6Smrg		id ^= 1;
1134446f62d6Smrg
1135de2362d3Smrg	/* cursor should be mapped already */
1136446f62d6Smrg	ptr = (uint32_t *)(drmmode_crtc->cursor_bo[id]->ptr);
1137446f62d6Smrg
1138446f62d6Smrg	if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
1139446f62d6Smrg		apply_gamma = FALSE;
1140de2362d3Smrg
11418bf5c682Smrg#if XF86_CRTC_VERSION < 7
114218781e08Smrg	if (crtc->driverIsPerformingTransform) {
114318781e08Smrg		uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
114418781e08Smrg		int dstx, dsty;
114518781e08Smrg		int srcoffset;
114618781e08Smrg
1147446f62d6Smrgretry_transform:
114818781e08Smrg		for (dsty = 0; dsty < cursor_h; dsty++) {
114918781e08Smrg			for (dstx = 0; dstx < cursor_w; dstx++) {
115018781e08Smrg				srcoffset = drmmode_cursor_src_offset(crtc->rotation,
115118781e08Smrg								      cursor_w,
115218781e08Smrg								      cursor_h,
115318781e08Smrg								      dstx, dsty);
1154446f62d6Smrg				argb = image[srcoffset];
1155446f62d6Smrg				if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied,
1156446f62d6Smrg							  &apply_gamma))
1157446f62d6Smrg					goto retry_transform;
115818781e08Smrg
1159446f62d6Smrg				ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb);
116018781e08Smrg			}
116118781e08Smrg		}
116218781e08Smrg	} else
116318781e08Smrg#endif
116418781e08Smrg	{
116518781e08Smrg		uint32_t cursor_size = info->cursor_w * info->cursor_h;
116618781e08Smrg		int i;
116718781e08Smrg
1168446f62d6Smrgretry:
1169446f62d6Smrg		for (i = 0; i < cursor_size; i++) {
1170446f62d6Smrg			argb = image[i];
1171446f62d6Smrg			if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied,
1172446f62d6Smrg						  &apply_gamma))
1173446f62d6Smrg				goto retry;
1174446f62d6Smrg
1175446f62d6Smrg			ptr[i] = cpu_to_le32(argb);
1176446f62d6Smrg		}
1177446f62d6Smrg	}
1178446f62d6Smrg
1179446f62d6Smrg	if (id != drmmode_crtc->cursor_id) {
1180446f62d6Smrg		drmmode_crtc->cursor_id = id;
1181446f62d6Smrg		crtc->funcs->show_cursor(crtc);
118218781e08Smrg	}
1183de2362d3Smrg}
1184de2362d3Smrg
118518781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
118618781e08Smrg
118718781e08Smrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
118818781e08Smrg{
118918781e08Smrg	if (!drmmode_can_use_hw_cursor(crtc))
119018781e08Smrg		return FALSE;
119118781e08Smrg
119218781e08Smrg	drmmode_load_cursor_argb(crtc, image);
119318781e08Smrg	return TRUE;
119418781e08Smrg}
119518781e08Smrg
119618781e08Smrg#endif
1197de2362d3Smrg
1198de2362d3Smrgstatic void
1199de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc)
1200de2362d3Smrg{
120118781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
120218781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1203de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
12048bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1205de2362d3Smrg
12068bf5c682Smrg	drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
120718781e08Smrg			 info->cursor_w, info->cursor_h);
1208446f62d6Smrg	drmmode_crtc->cursor = NULL;
1209de2362d3Smrg}
1210de2362d3Smrg
1211de2362d3Smrgstatic void
1212de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc)
1213de2362d3Smrg{
121418781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
121518781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1216de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
12178bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1218446f62d6Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1219446f62d6Smrg	CursorPtr cursor = xf86_config->cursor;
1220446f62d6Smrg	int xhot = cursor->bits->xhot;
1221446f62d6Smrg	int yhot = cursor->bits->yhot;
122218781e08Smrg	static Bool use_set_cursor2 = TRUE;
1223446f62d6Smrg	struct drm_mode_cursor2 arg;
1224446f62d6Smrg
1225446f62d6Smrg	drmmode_crtc->cursor = xf86_config->cursor;
1226446f62d6Smrg
1227446f62d6Smrg	memset(&arg, 0, sizeof(arg));
1228446f62d6Smrg
1229446f62d6Smrg	arg.handle = drmmode_crtc->cursor_bo[drmmode_crtc->cursor_id]->handle;
1230446f62d6Smrg	arg.flags = DRM_MODE_CURSOR_BO;
1231446f62d6Smrg	arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id;
1232446f62d6Smrg	arg.width = info->cursor_w;
1233446f62d6Smrg	arg.height = info->cursor_h;
1234446f62d6Smrg
1235446f62d6Smrg	if (crtc->rotation != RR_Rotate_0 &&
1236446f62d6Smrg	    crtc->rotation != (RR_Rotate_180 | RR_Reflect_X |
1237446f62d6Smrg			       RR_Reflect_Y)) {
1238446f62d6Smrg	    int t;
1239446f62d6Smrg
1240446f62d6Smrg	    /* Reflect & rotate hotspot position */
1241446f62d6Smrg	    if (crtc->rotation & RR_Reflect_X)
1242446f62d6Smrg		xhot = info->cursor_w - xhot - 1;
1243446f62d6Smrg	    if (crtc->rotation & RR_Reflect_Y)
1244446f62d6Smrg		yhot = info->cursor_h - yhot - 1;
1245446f62d6Smrg
1246446f62d6Smrg	    switch (crtc->rotation & 0xf) {
1247446f62d6Smrg	    case RR_Rotate_90:
1248446f62d6Smrg		t = xhot;
1249446f62d6Smrg		xhot = yhot;
1250446f62d6Smrg		yhot = info->cursor_w - t - 1;
1251446f62d6Smrg		break;
1252446f62d6Smrg	    case RR_Rotate_180:
1253446f62d6Smrg		xhot = info->cursor_w - xhot - 1;
1254446f62d6Smrg		yhot = info->cursor_h - yhot - 1;
1255446f62d6Smrg		break;
1256446f62d6Smrg	    case RR_Rotate_270:
1257446f62d6Smrg		t = xhot;
1258446f62d6Smrg		xhot = info->cursor_h - yhot - 1;
1259446f62d6Smrg		yhot = t;
1260446f62d6Smrg	    }
1261446f62d6Smrg	}
1262446f62d6Smrg
1263446f62d6Smrg	if (xhot != drmmode_crtc->cursor_xhot || yhot != drmmode_crtc->cursor_yhot) {
1264446f62d6Smrg	    arg.flags |= DRM_MODE_CURSOR_MOVE;
1265446f62d6Smrg	    arg.x = drmmode_crtc->cursor_x += drmmode_crtc->cursor_xhot - xhot;
1266446f62d6Smrg	    arg.y = drmmode_crtc->cursor_y += drmmode_crtc->cursor_yhot - yhot;
1267446f62d6Smrg	    drmmode_crtc->cursor_xhot = xhot;
1268446f62d6Smrg	    drmmode_crtc->cursor_yhot = yhot;
1269446f62d6Smrg	}
127018781e08Smrg
127118781e08Smrg	if (use_set_cursor2) {
127218781e08Smrg	    int ret;
127318781e08Smrg
1274446f62d6Smrg	    arg.hot_x = xhot;
1275446f62d6Smrg	    arg.hot_y = yhot;
12767314432eSmrg
1277446f62d6Smrg	    ret = drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR2, &arg);
127818781e08Smrg	    if (ret == -EINVAL)
127918781e08Smrg		use_set_cursor2 = FALSE;
128018781e08Smrg	    else
128118781e08Smrg		return;
128218781e08Smrg	}
128318781e08Smrg
1284446f62d6Smrg	drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR, &arg);
1285de2362d3Smrg}
1286de2362d3Smrg
12873ed65abbSmrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and
12883ed65abbSmrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for
12893ed65abbSmrg * anything else.
12903ed65abbSmrg */
1291de2362d3Smrgstatic void *
1292de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
1293de2362d3Smrg{
1294de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
12957821949aSmrg
12963ed65abbSmrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
12973ed65abbSmrg					 height))
12983ed65abbSmrg		return NULL;
12993ed65abbSmrg
13003ed65abbSmrg	return (void*)~0UL;
1301de2362d3Smrg}
1302de2362d3Smrg
1303de2362d3Smrgstatic PixmapPtr
1304de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1305de2362d3Smrg{
1306de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1307de2362d3Smrg
13083ed65abbSmrg	if (!data) {
13093ed65abbSmrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
13103ed65abbSmrg					    height);
13113ed65abbSmrg	}
13123ed65abbSmrg
13133ed65abbSmrg	return drmmode_crtc->rotate.pixmap;
1314de2362d3Smrg}
1315de2362d3Smrg
1316de2362d3Smrgstatic void
13177821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
1318de2362d3Smrg{
1319de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1320de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1321de2362d3Smrg
132218781e08Smrg	drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate);
13237821949aSmrg}
1324de2362d3Smrg
13257821949aSmrgstatic void
13267821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
13277821949aSmrg                      uint16_t *blue, int size)
13287821949aSmrg{
13298bf5c682Smrg	ScrnInfoPtr scrn = crtc->scrn;
13308bf5c682Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
13318bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
13328bf5c682Smrg	int i;
13338bf5c682Smrg
13348bf5c682Smrg	drmmode_crtc_gamma_do_set(crtc, red, green, blue, size);
13358bf5c682Smrg
13368bf5c682Smrg	/* Compute index of this CRTC into xf86_config->crtc */
13378bf5c682Smrg	for (i = 0; xf86_config->crtc[i] != crtc; i++) {}
13388bf5c682Smrg
13398bf5c682Smrg	if (info->hwcursor_disabled & (1 << i))
13408bf5c682Smrg		return;
13417314432eSmrg
13428bf5c682Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR
13438bf5c682Smrg	xf86CursorResetCursor(scrn->pScreen);
13448bf5c682Smrg#else
13458bf5c682Smrg	xf86_reload_cursors(scrn->pScreen);
13468bf5c682Smrg#endif
134718781e08Smrg}
134818781e08Smrg
134918781e08Smrgstatic Bool
135018781e08Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
135118781e08Smrg{
135218781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
13533ed65abbSmrg	unsigned scanout_id = drmmode_crtc->scanout_id;
135418781e08Smrg	ScreenPtr screen = crtc->scrn->pScreen;
135518781e08Smrg	PixmapDirtyUpdatePtr dirty;
135618781e08Smrg
135718781e08Smrg	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
13588bf5c682Smrg		if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
13598bf5c682Smrg			PixmapStopDirtyTracking(dirty->src, dirty->slave_dst);
13608bf5c682Smrg			break;
13618bf5c682Smrg		}
136218781e08Smrg	}
136318781e08Smrg
1364446f62d6Smrg	drmmode_crtc_scanout_free(crtc);
13658bf5c682Smrg	drmmode_crtc->prime_scanout_pixmap = NULL;
13668bf5c682Smrg
136718781e08Smrg	if (!ppix)
136818781e08Smrg		return TRUE;
136918781e08Smrg
137018781e08Smrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0],
137118781e08Smrg					 ppix->drawable.width,
137218781e08Smrg					 ppix->drawable.height))
137318781e08Smrg		return FALSE;
137418781e08Smrg
13753ed65abbSmrg	if (drmmode_crtc->tear_free &&
137618781e08Smrg	    !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
137718781e08Smrg					 ppix->drawable.width,
137818781e08Smrg					 ppix->drawable.height)) {
1379446f62d6Smrg		drmmode_crtc_scanout_free(crtc);
138018781e08Smrg		return FALSE;
138118781e08Smrg	}
138218781e08Smrg
13838bf5c682Smrg	drmmode_crtc->prime_scanout_pixmap = ppix;
13848bf5c682Smrg
13858bf5c682Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC
13868bf5c682Smrg	PixmapStartDirtyTracking(&ppix->drawable,
13878bf5c682Smrg				 drmmode_crtc->scanout[scanout_id].pixmap,
13888bf5c682Smrg				 0, 0, 0, 0, RR_Rotate_0);
13898bf5c682Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION)
13903ed65abbSmrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
139118781e08Smrg				 0, 0, 0, 0, RR_Rotate_0);
139218781e08Smrg#elif defined(HAS_DIRTYTRACKING2)
13933ed65abbSmrg	PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
139418781e08Smrg				  0, 0, 0, 0);
139518781e08Smrg#else
13963ed65abbSmrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0);
139718781e08Smrg#endif
139818781e08Smrg	return TRUE;
1399de2362d3Smrg}
1400de2362d3Smrg
140118781e08Smrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = {
1402de2362d3Smrg    .dpms = drmmode_crtc_dpms,
1403de2362d3Smrg    .set_mode_major = drmmode_set_mode_major,
1404de2362d3Smrg    .set_cursor_colors = drmmode_set_cursor_colors,
1405de2362d3Smrg    .set_cursor_position = drmmode_set_cursor_position,
1406de2362d3Smrg    .show_cursor = drmmode_show_cursor,
1407de2362d3Smrg    .hide_cursor = drmmode_hide_cursor,
1408de2362d3Smrg    .load_cursor_argb = drmmode_load_cursor_argb,
140918781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
141018781e08Smrg    .load_cursor_argb_check = drmmode_load_cursor_argb_check,
141118781e08Smrg#endif
1412de2362d3Smrg
1413de2362d3Smrg    .gamma_set = drmmode_crtc_gamma_set,
1414de2362d3Smrg    .shadow_create = drmmode_crtc_shadow_create,
1415de2362d3Smrg    .shadow_allocate = drmmode_crtc_shadow_allocate,
1416de2362d3Smrg    .shadow_destroy = drmmode_crtc_shadow_destroy,
1417de2362d3Smrg    .destroy = NULL, /* XXX */
141818781e08Smrg    .set_scanout_pixmap = drmmode_set_scanout_pixmap,
1419de2362d3Smrg};
1420de2362d3Smrg
1421de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc)
1422de2362d3Smrg{
1423de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1424de2362d3Smrg	return drmmode_crtc->hw_id;
1425de2362d3Smrg}
1426de2362d3Smrg
1427de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc)
1428de2362d3Smrg{
1429de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
14308bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
1431de2362d3Smrg	struct drm_radeon_info ginfo;
1432de2362d3Smrg	int r;
1433de2362d3Smrg	uint32_t tmp;
1434de2362d3Smrg
1435de2362d3Smrg	memset(&ginfo, 0, sizeof(ginfo));
1436de2362d3Smrg	ginfo.request = 0x4;
1437de2362d3Smrg	tmp = drmmode_crtc->mode_crtc->crtc_id;
1438de2362d3Smrg	ginfo.value = (uintptr_t)&tmp;
14398bf5c682Smrg	r = drmCommandWriteRead(pRADEONEnt->fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo));
1440de2362d3Smrg	if (r) {
1441de2362d3Smrg		drmmode_crtc->hw_id = -1;
1442de2362d3Smrg		return;
1443de2362d3Smrg	}
1444de2362d3Smrg	drmmode_crtc->hw_id = tmp;
1445de2362d3Smrg}
1446de2362d3Smrg
144718781e08Smrgstatic unsigned int
144818781e08Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
1449de2362d3Smrg{
1450de2362d3Smrg	xf86CrtcPtr crtc;
1451de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc;
145218781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
14538bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1454de2362d3Smrg
14558bf5c682Smrg	crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs);
145639413783Smrg	if (!crtc)
145718781e08Smrg		return 0;
1458de2362d3Smrg
1459de2362d3Smrg	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
14608bf5c682Smrg	drmmode_crtc->mode_crtc = drmModeGetCrtc(pRADEONEnt->fd, mode_res->crtcs[num]);
1461de2362d3Smrg	drmmode_crtc->drmmode = drmmode;
146218781e08Smrg	drmmode_crtc->dpms_mode = DPMSModeOff;
1463de2362d3Smrg	crtc->driver_private = drmmode_crtc;
1464de2362d3Smrg	drmmode_crtc_hw_id(crtc);
1465de2362d3Smrg
146618781e08Smrg	/* Mark num'th crtc as in use on this device. */
146718781e08Smrg	pRADEONEnt->assigned_crtcs |= (1 << num);
146818781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
146918781e08Smrg		       "Allocated crtc nr. %d to this screen.\n", num);
147018781e08Smrg
147118781e08Smrg	return 1;
1472de2362d3Smrg}
1473de2362d3Smrg
14748bf5c682Smrg/*
14758bf5c682Smrg * Update all of the property values for an output
14768bf5c682Smrg */
14778bf5c682Smrgstatic void
14788bf5c682Smrgdrmmode_output_update_properties(xf86OutputPtr output)
14798bf5c682Smrg{
14808bf5c682Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
14818bf5c682Smrg	int i, j, k;
14828bf5c682Smrg	int err;
14838bf5c682Smrg	drmModeConnectorPtr koutput;
14848bf5c682Smrg
14858bf5c682Smrg	/* Use the most recently fetched values from the kernel */
14868bf5c682Smrg	koutput = drmmode_output->mode_output;
14878bf5c682Smrg
14888bf5c682Smrg	if (!koutput)
14898bf5c682Smrg		return;
14908bf5c682Smrg
14918bf5c682Smrg	for (i = 0; i < drmmode_output->num_props; i++) {
14928bf5c682Smrg		drmmode_prop_ptr p = &drmmode_output->props[i];
14938bf5c682Smrg
14948bf5c682Smrg		for (j = 0; j < koutput->count_props; j++) {
14958bf5c682Smrg			if (koutput->props[j] != p->mode_prop->prop_id)
14968bf5c682Smrg				continue;
14978bf5c682Smrg
14988bf5c682Smrg			/* Check to see if the property value has changed */
14998bf5c682Smrg			if (koutput->prop_values[j] == p->value)
15008bf5c682Smrg				break;
15018bf5c682Smrg
15028bf5c682Smrg			p->value = koutput->prop_values[j];
15038bf5c682Smrg
15048bf5c682Smrg			if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
15058bf5c682Smrg				INT32 value = p->value;
15068bf5c682Smrg
15078bf5c682Smrg				err = RRChangeOutputProperty(output->randr_output,
15088bf5c682Smrg							     p->atoms[0], XA_INTEGER,
15098bf5c682Smrg							     32, PropModeReplace, 1,
15108bf5c682Smrg							     &value, FALSE, TRUE);
15118bf5c682Smrg				if (err != 0) {
15128bf5c682Smrg					xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
15138bf5c682Smrg						   "RRChangeOutputProperty error, %d\n",
15148bf5c682Smrg						   err);
15158bf5c682Smrg				}
15168bf5c682Smrg			} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
15178bf5c682Smrg				for (k = 0; k < p->mode_prop->count_enums; k++) {
15188bf5c682Smrg					if (p->mode_prop->enums[k].value == p->value)
15198bf5c682Smrg						break;
15208bf5c682Smrg				}
15218bf5c682Smrg				if (k < p->mode_prop->count_enums) {
15228bf5c682Smrg					err = RRChangeOutputProperty(output->randr_output,
15238bf5c682Smrg								     p->atoms[0], XA_ATOM,
15248bf5c682Smrg								     32, PropModeReplace, 1,
15258bf5c682Smrg								     &p->atoms[k + 1], FALSE,
15268bf5c682Smrg								     TRUE);
15278bf5c682Smrg					if (err != 0) {
15288bf5c682Smrg						xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
15298bf5c682Smrg							   "RRChangeOutputProperty error, %d\n",
15308bf5c682Smrg							   err);
15318bf5c682Smrg					}
15328bf5c682Smrg				}
15338bf5c682Smrg			}
15348bf5c682Smrg
15358bf5c682Smrg			break;
15368bf5c682Smrg		}
15378bf5c682Smrg        }
15388bf5c682Smrg}
15398bf5c682Smrg
1540de2362d3Smrgstatic xf86OutputStatus
1541de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output)
1542de2362d3Smrg{
1543de2362d3Smrg	/* go to the hw and retrieve a new output struct */
1544de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
15458bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1546de2362d3Smrg	xf86OutputStatus status;
1547de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
1548de2362d3Smrg
15498bf5c682Smrg	drmmode_output->mode_output =
15508bf5c682Smrg	    drmModeGetConnector(pRADEONEnt->fd, drmmode_output->output_id);
15518bf5c682Smrg	if (!drmmode_output->mode_output) {
15528bf5c682Smrg		drmmode_output->output_id = -1;
155318781e08Smrg		return XF86OutputStatusDisconnected;
15548bf5c682Smrg	}
15558bf5c682Smrg
15568bf5c682Smrg	drmmode_output_update_properties(output);
1557de2362d3Smrg
1558de2362d3Smrg	switch (drmmode_output->mode_output->connection) {
1559de2362d3Smrg	case DRM_MODE_CONNECTED:
1560de2362d3Smrg		status = XF86OutputStatusConnected;
1561de2362d3Smrg		break;
1562de2362d3Smrg	case DRM_MODE_DISCONNECTED:
1563de2362d3Smrg		status = XF86OutputStatusDisconnected;
1564de2362d3Smrg		break;
1565de2362d3Smrg	default:
1566de2362d3Smrg	case DRM_MODE_UNKNOWNCONNECTION:
1567de2362d3Smrg		status = XF86OutputStatusUnknown;
1568de2362d3Smrg		break;
1569de2362d3Smrg	}
1570de2362d3Smrg	return status;
1571de2362d3Smrg}
1572de2362d3Smrg
1573de2362d3Smrgstatic Bool
1574de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
1575de2362d3Smrg{
1576de2362d3Smrg	return MODE_OK;
1577de2362d3Smrg}
1578de2362d3Smrg
1579446f62d6Smrgstatic void
1580446f62d6Smrgdrmmode_output_attach_tile(xf86OutputPtr output)
1581446f62d6Smrg{
1582446f62d6Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0)
1583446f62d6Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1584446f62d6Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
1585446f62d6Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1586446f62d6Smrg	struct xf86CrtcTileInfo tile_info, *set = NULL;
1587446f62d6Smrg	int i;
1588446f62d6Smrg
1589446f62d6Smrg	if (!koutput) {
1590446f62d6Smrg		xf86OutputSetTile(output, NULL);
1591446f62d6Smrg		return;
1592446f62d6Smrg	}
1593446f62d6Smrg
1594446f62d6Smrg	/* look for a TILE property */
1595446f62d6Smrg	for (i = 0; i < koutput->count_props; i++) {
1596446f62d6Smrg		drmModePropertyPtr props;
1597446f62d6Smrg		props = drmModeGetProperty(pRADEONEnt->fd, koutput->props[i]);
1598446f62d6Smrg		if (!props)
1599446f62d6Smrg			continue;
1600446f62d6Smrg
1601446f62d6Smrg		if (!(props->flags & DRM_MODE_PROP_BLOB)) {
1602446f62d6Smrg			drmModeFreeProperty(props);
1603446f62d6Smrg			continue;
1604446f62d6Smrg		}
1605446f62d6Smrg
1606446f62d6Smrg		if (!strcmp(props->name, "TILE")) {
1607446f62d6Smrg			drmModeFreePropertyBlob(drmmode_output->tile_blob);
1608446f62d6Smrg			drmmode_output->tile_blob =
1609446f62d6Smrg				drmModeGetPropertyBlob(pRADEONEnt->fd,
1610446f62d6Smrg						       koutput->prop_values[i]);
1611446f62d6Smrg		}
1612446f62d6Smrg		drmModeFreeProperty(props);
1613446f62d6Smrg	}
1614446f62d6Smrg	if (drmmode_output->tile_blob) {
1615446f62d6Smrg		if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data,
1616446f62d6Smrg					   drmmode_output->tile_blob->length,
1617446f62d6Smrg					   &tile_info) == TRUE)
1618446f62d6Smrg			set = &tile_info;
1619446f62d6Smrg	}
1620446f62d6Smrg	xf86OutputSetTile(output, set);
1621446f62d6Smrg#endif
1622446f62d6Smrg}
1623446f62d6Smrg
16248bf5c682Smrgstatic int
16258bf5c682Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
16268bf5c682Smrg        int type, const char *name)
16278bf5c682Smrg{
16288bf5c682Smrg    int idx = -1;
16298bf5c682Smrg
16308bf5c682Smrg    for (int i = 0; i < koutput->count_props; i++) {
16318bf5c682Smrg        drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
16328bf5c682Smrg
16338bf5c682Smrg        if (!prop)
16348bf5c682Smrg            continue;
16358bf5c682Smrg
16368bf5c682Smrg        if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
16378bf5c682Smrg            idx = i;
16388bf5c682Smrg
16398bf5c682Smrg        drmModeFreeProperty(prop);
16408bf5c682Smrg
16418bf5c682Smrg        if (idx > -1)
16428bf5c682Smrg            break;
16438bf5c682Smrg    }
16448bf5c682Smrg
16458bf5c682Smrg    return idx;
16468bf5c682Smrg}
16478bf5c682Smrg
16488bf5c682Smrgstatic int
16498bf5c682Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
16508bf5c682Smrg        int type, const char *name)
16518bf5c682Smrg{
16528bf5c682Smrg    int idx = koutput_get_prop_idx(fd, koutput, type, name);
16538bf5c682Smrg
16548bf5c682Smrg    return (idx > -1) ? koutput->props[idx] : -1;
16558bf5c682Smrg}
16568bf5c682Smrg
16578bf5c682Smrgstatic drmModePropertyBlobPtr
16588bf5c682Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
16598bf5c682Smrg{
16608bf5c682Smrg    drmModePropertyBlobPtr blob = NULL;
16618bf5c682Smrg    int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
16628bf5c682Smrg
16638bf5c682Smrg    if (idx > -1)
16648bf5c682Smrg        blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
16658bf5c682Smrg
16668bf5c682Smrg    return blob;
16678bf5c682Smrg}
16688bf5c682Smrg
1669de2362d3Smrgstatic DisplayModePtr
1670de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output)
1671de2362d3Smrg{
1672de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1673de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
16748bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1675de2362d3Smrg	int i;
1676de2362d3Smrg	DisplayModePtr Modes = NULL, Mode;
1677de2362d3Smrg	xf86MonPtr mon = NULL;
1678de2362d3Smrg
167918781e08Smrg	if (!koutput)
168018781e08Smrg		return NULL;
168118781e08Smrg
16828bf5c682Smrg	drmModeFreePropertyBlob(drmmode_output->edid_blob);
16838bf5c682Smrg
1684de2362d3Smrg	/* look for an EDID property */
16858bf5c682Smrg	drmmode_output->edid_blob =
16868bf5c682Smrg		koutput_get_prop_blob(pRADEONEnt->fd, koutput, "EDID");
1687de2362d3Smrg
1688de2362d3Smrg	if (drmmode_output->edid_blob) {
1689de2362d3Smrg		mon = xf86InterpretEDID(output->scrn->scrnIndex,
1690de2362d3Smrg					drmmode_output->edid_blob->data);
1691de2362d3Smrg		if (mon && drmmode_output->edid_blob->length > 128)
1692de2362d3Smrg			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
1693de2362d3Smrg	}
1694de2362d3Smrg	xf86OutputSetEDID(output, mon);
1695de2362d3Smrg
1696446f62d6Smrg	drmmode_output_attach_tile(output);
1697446f62d6Smrg
1698de2362d3Smrg	/* modes should already be available */
1699de2362d3Smrg	for (i = 0; i < koutput->count_modes; i++) {
1700de2362d3Smrg		Mode = xnfalloc(sizeof(DisplayModeRec));
1701de2362d3Smrg
1702de2362d3Smrg		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
1703de2362d3Smrg		Modes = xf86ModesAdd(Modes, Mode);
1704de2362d3Smrg
1705de2362d3Smrg	}
1706de2362d3Smrg	return Modes;
1707de2362d3Smrg}
1708de2362d3Smrg
1709de2362d3Smrgstatic void
1710de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output)
1711de2362d3Smrg{
1712de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1713de2362d3Smrg	int i;
1714de2362d3Smrg
1715446f62d6Smrg	drmModeFreePropertyBlob(drmmode_output->edid_blob);
1716446f62d6Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0)
1717446f62d6Smrg	drmModeFreePropertyBlob(drmmode_output->tile_blob);
1718446f62d6Smrg#endif
1719446f62d6Smrg
1720de2362d3Smrg	for (i = 0; i < drmmode_output->num_props; i++) {
1721de2362d3Smrg		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
1722de2362d3Smrg		free(drmmode_output->props[i].atoms);
1723de2362d3Smrg	}
1724de2362d3Smrg	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
1725de2362d3Smrg		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
1726de2362d3Smrg	}
172718781e08Smrg	free(drmmode_output->mode_encoders);
1728de2362d3Smrg	free(drmmode_output->props);
1729de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
1730de2362d3Smrg	free(drmmode_output);
1731de2362d3Smrg	output->driver_private = NULL;
1732de2362d3Smrg}
1733de2362d3Smrg
1734de2362d3Smrgstatic void
1735de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode)
1736de2362d3Smrg{
1737de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
173818781e08Smrg	xf86CrtcPtr crtc = output->crtc;
1739de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
17408bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1741de2362d3Smrg
174218781e08Smrg	if (!koutput)
174318781e08Smrg		return;
174418781e08Smrg
17458bf5c682Smrg	if (mode != DPMSModeOn && crtc)
174618781e08Smrg		drmmode_do_crtc_dpms(crtc, mode);
174718781e08Smrg
17488bf5c682Smrg	drmModeConnectorSetProperty(pRADEONEnt->fd, koutput->connector_id,
1749de2362d3Smrg				    drmmode_output->dpms_enum_id, mode);
175018781e08Smrg
175118781e08Smrg	if (mode == DPMSModeOn && crtc) {
175218781e08Smrg	    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
175318781e08Smrg
175418781e08Smrg	    if (drmmode_crtc->need_modeset)
175518781e08Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x,
175618781e08Smrg				       crtc->y);
175718781e08Smrg	    else
175818781e08Smrg		drmmode_do_crtc_dpms(crtc, mode);
175918781e08Smrg	}
1760de2362d3Smrg}
1761de2362d3Smrg
1762de2362d3Smrg
1763de2362d3Smrgstatic Bool
1764de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop)
1765de2362d3Smrg{
1766de2362d3Smrg    if (!prop)
1767de2362d3Smrg	return TRUE;
1768de2362d3Smrg    /* ignore blob prop */
1769de2362d3Smrg    if (prop->flags & DRM_MODE_PROP_BLOB)
1770de2362d3Smrg	return TRUE;
1771de2362d3Smrg    /* ignore standard property */
1772de2362d3Smrg    if (!strcmp(prop->name, "EDID") ||
1773de2362d3Smrg	    !strcmp(prop->name, "DPMS"))
1774de2362d3Smrg	return TRUE;
1775de2362d3Smrg
1776de2362d3Smrg    return FALSE;
1777de2362d3Smrg}
1778de2362d3Smrg
1779de2362d3Smrgstatic void
1780de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output)
1781de2362d3Smrg{
17823ed65abbSmrg    RADEONInfoPtr info = RADEONPTR(output->scrn);
1783de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
1784de2362d3Smrg    drmModeConnectorPtr mode_output = drmmode_output->mode_output;
17858bf5c682Smrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
17863ed65abbSmrg    drmModePropertyPtr drmmode_prop, tearfree_prop;
1787de2362d3Smrg    int i, j, err;
178839413783Smrg    Atom name;
178939413783Smrg
179039413783Smrg    /* Create CONNECTOR_ID property */
179139413783Smrg    name = MakeAtom("CONNECTOR_ID", 12, TRUE);
179239413783Smrg    if (name != BAD_RESOURCE) {
179339413783Smrg	INT32 value = mode_output->connector_id;
179439413783Smrg
179539413783Smrg	err = RRConfigureOutputProperty(output->randr_output, name,
179639413783Smrg					FALSE, FALSE, TRUE, 1, &value);
179739413783Smrg	if (err != Success) {
179839413783Smrg	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
179939413783Smrg		       "RRConfigureOutputProperty error, %d\n", err);
180039413783Smrg	}
180139413783Smrg
180239413783Smrg	err = RRChangeOutputProperty(output->randr_output, name,
180339413783Smrg				     XA_INTEGER, 32, PropModeReplace, 1,
180439413783Smrg				     &value, FALSE, FALSE);
180539413783Smrg	if (err != Success) {
180639413783Smrg	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
180739413783Smrg		       "RRChangeOutputProperty error, %d\n", err);
180839413783Smrg	}
180939413783Smrg    }
1810de2362d3Smrg
18113ed65abbSmrg    drmmode_output->props = calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec));
1812de2362d3Smrg    if (!drmmode_output->props)
1813de2362d3Smrg	return;
1814de2362d3Smrg
1815de2362d3Smrg    drmmode_output->num_props = 0;
1816de2362d3Smrg    for (i = 0, j = 0; i < mode_output->count_props; i++) {
18178bf5c682Smrg	drmmode_prop = drmModeGetProperty(pRADEONEnt->fd, mode_output->props[i]);
1818de2362d3Smrg	if (drmmode_property_ignore(drmmode_prop)) {
1819de2362d3Smrg	    drmModeFreeProperty(drmmode_prop);
1820de2362d3Smrg	    continue;
1821de2362d3Smrg	}
1822de2362d3Smrg	drmmode_output->props[j].mode_prop = drmmode_prop;
1823de2362d3Smrg	drmmode_output->props[j].value = mode_output->prop_values[i];
1824de2362d3Smrg	drmmode_output->num_props++;
1825de2362d3Smrg	j++;
1826de2362d3Smrg    }
1827de2362d3Smrg
18283ed65abbSmrg    /* Userspace-only property for TearFree */
18293ed65abbSmrg    tearfree_prop = calloc(1, sizeof(*tearfree_prop));
18303ed65abbSmrg    tearfree_prop->flags = DRM_MODE_PROP_ENUM;
183139413783Smrg    strcpy(tearfree_prop->name, "TearFree");
18323ed65abbSmrg    tearfree_prop->count_enums = 3;
18333ed65abbSmrg    tearfree_prop->enums = calloc(tearfree_prop->count_enums,
18343ed65abbSmrg				  sizeof(*tearfree_prop->enums));
183539413783Smrg    strcpy(tearfree_prop->enums[0].name, "off");
183639413783Smrg    strcpy(tearfree_prop->enums[1].name, "on");
18373ed65abbSmrg    tearfree_prop->enums[1].value = 1;
183839413783Smrg    strcpy(tearfree_prop->enums[2].name, "auto");
18393ed65abbSmrg    tearfree_prop->enums[2].value = 2;
18403ed65abbSmrg    drmmode_output->props[j].mode_prop = tearfree_prop;
18413ed65abbSmrg    drmmode_output->props[j].value = info->tear_free;
18423ed65abbSmrg    drmmode_output->tear_free = info->tear_free;
18433ed65abbSmrg    drmmode_output->num_props++;
18443ed65abbSmrg
1845de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
1846de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
1847de2362d3Smrg	drmmode_prop = p->mode_prop;
1848de2362d3Smrg
1849de2362d3Smrg	if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1850de2362d3Smrg	    INT32 range[2];
1851de2362d3Smrg	    INT32 value = p->value;
1852de2362d3Smrg
1853de2362d3Smrg	    p->num_atoms = 1;
1854de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
1855de2362d3Smrg	    if (!p->atoms)
1856de2362d3Smrg		continue;
1857de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1858de2362d3Smrg	    range[0] = drmmode_prop->values[0];
1859de2362d3Smrg	    range[1] = drmmode_prop->values[1];
1860de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1861de2362d3Smrg		    FALSE, TRUE,
1862de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1863de2362d3Smrg		    2, range);
1864de2362d3Smrg	    if (err != 0) {
1865de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1866de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
1867de2362d3Smrg	    }
1868de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1869de2362d3Smrg		    XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE);
1870de2362d3Smrg	    if (err != 0) {
1871de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1872de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
1873de2362d3Smrg	    }
1874de2362d3Smrg	} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1875de2362d3Smrg	    p->num_atoms = drmmode_prop->count_enums + 1;
1876de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
1877de2362d3Smrg	    if (!p->atoms)
1878de2362d3Smrg		continue;
1879de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1880de2362d3Smrg	    for (j = 1; j <= drmmode_prop->count_enums; j++) {
1881de2362d3Smrg		struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
1882de2362d3Smrg		p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
1883de2362d3Smrg	    }
1884de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1885de2362d3Smrg		    FALSE, FALSE,
1886de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1887de2362d3Smrg		    p->num_atoms - 1, (INT32 *)&p->atoms[1]);
1888de2362d3Smrg	    if (err != 0) {
1889de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1890de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
1891de2362d3Smrg	    }
1892de2362d3Smrg	    for (j = 0; j < drmmode_prop->count_enums; j++)
1893de2362d3Smrg		if (drmmode_prop->enums[j].value == p->value)
1894de2362d3Smrg		    break;
1895de2362d3Smrg	    /* there's always a matching value */
1896de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1897de2362d3Smrg		    XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
1898de2362d3Smrg	    if (err != 0) {
1899de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1900de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
1901de2362d3Smrg	    }
1902de2362d3Smrg	}
1903de2362d3Smrg    }
1904de2362d3Smrg}
1905de2362d3Smrg
190639413783Smrgstatic void
190739413783Smrgdrmmode_output_set_tear_free(RADEONEntPtr pRADEONEnt,
190839413783Smrg			     drmmode_output_private_ptr drmmode_output,
190939413783Smrg			     xf86CrtcPtr crtc, int tear_free)
191039413783Smrg{
191139413783Smrg	if (drmmode_output->tear_free == tear_free)
191239413783Smrg		return;
191339413783Smrg
191439413783Smrg	drmmode_output->tear_free = tear_free;
191539413783Smrg
191639413783Smrg	if (crtc) {
191739413783Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
191839413783Smrg				       crtc->x, crtc->y);
191939413783Smrg	}
192039413783Smrg}
192139413783Smrg
1922de2362d3Smrgstatic Bool
1923de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property,
1924de2362d3Smrg		RRPropertyValuePtr value)
1925de2362d3Smrg{
1926de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
19278bf5c682Smrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1928de2362d3Smrg    int i;
1929de2362d3Smrg
1930de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
1931de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
1932de2362d3Smrg
1933de2362d3Smrg	if (p->atoms[0] != property)
1934de2362d3Smrg	    continue;
1935de2362d3Smrg
1936de2362d3Smrg	if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1937de2362d3Smrg	    uint32_t val;
1938de2362d3Smrg
1939de2362d3Smrg	    if (value->type != XA_INTEGER || value->format != 32 ||
1940de2362d3Smrg		    value->size != 1)
1941de2362d3Smrg		return FALSE;
1942de2362d3Smrg	    val = *(uint32_t *)value->data;
1943de2362d3Smrg
19448bf5c682Smrg	    drmModeConnectorSetProperty(pRADEONEnt->fd, drmmode_output->output_id,
1945de2362d3Smrg		    p->mode_prop->prop_id, (uint64_t)val);
1946de2362d3Smrg	    return TRUE;
1947de2362d3Smrg	} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1948de2362d3Smrg	    Atom	atom;
1949de2362d3Smrg	    const char	*name;
1950de2362d3Smrg	    int		j;
1951de2362d3Smrg
1952de2362d3Smrg	    if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
1953de2362d3Smrg		return FALSE;
1954de2362d3Smrg	    memcpy(&atom, value->data, 4);
19558bf5c682Smrg	    if (!(name = NameForAtom(atom)))
19568bf5c682Smrg                return FALSE;
1957de2362d3Smrg
1958de2362d3Smrg	    /* search for matching name string, then set its value down */
1959de2362d3Smrg	    for (j = 0; j < p->mode_prop->count_enums; j++) {
1960de2362d3Smrg		if (!strcmp(p->mode_prop->enums[j].name, name)) {
19613ed65abbSmrg		    if (i == (drmmode_output->num_props - 1)) {
196239413783Smrg			drmmode_output_set_tear_free(pRADEONEnt, drmmode_output,
196339413783Smrg						     output->crtc, j);
19643ed65abbSmrg		    } else {
19658bf5c682Smrg			drmModeConnectorSetProperty(pRADEONEnt->fd,
19663ed65abbSmrg						    drmmode_output->output_id,
19673ed65abbSmrg						    p->mode_prop->prop_id,
19683ed65abbSmrg						    p->mode_prop->enums[j].value);
19693ed65abbSmrg		    }
19703ed65abbSmrg
1971de2362d3Smrg		    return TRUE;
1972de2362d3Smrg		}
1973de2362d3Smrg	    }
1974de2362d3Smrg	}
1975de2362d3Smrg    }
1976de2362d3Smrg
1977de2362d3Smrg    return TRUE;
1978de2362d3Smrg}
1979de2362d3Smrg
1980de2362d3Smrgstatic Bool
1981de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property)
1982de2362d3Smrg{
1983de2362d3Smrg    return TRUE;
1984de2362d3Smrg}
1985de2362d3Smrg
1986de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = {
1987de2362d3Smrg    .dpms = drmmode_output_dpms,
1988de2362d3Smrg    .create_resources = drmmode_output_create_resources,
1989de2362d3Smrg    .set_property = drmmode_output_set_property,
1990de2362d3Smrg    .get_property = drmmode_output_get_property,
1991de2362d3Smrg    .detect = drmmode_output_detect,
1992de2362d3Smrg    .mode_valid = drmmode_output_mode_valid,
1993de2362d3Smrg
1994de2362d3Smrg    .get_modes = drmmode_output_get_modes,
1995de2362d3Smrg    .destroy = drmmode_output_destroy
1996de2362d3Smrg};
1997de2362d3Smrg
1998de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown,
1999de2362d3Smrg				      SubPixelHorizontalRGB,
2000de2362d3Smrg				      SubPixelHorizontalBGR,
2001de2362d3Smrg				      SubPixelVerticalRGB,
2002de2362d3Smrg				      SubPixelVerticalBGR,
2003de2362d3Smrg				      SubPixelNone };
2004de2362d3Smrg
2005de2362d3Smrgconst char *output_names[] = { "None",
2006de2362d3Smrg			       "VGA",
2007de2362d3Smrg			       "DVI",
2008de2362d3Smrg			       "DVI",
2009de2362d3Smrg			       "DVI",
2010de2362d3Smrg			       "Composite",
2011de2362d3Smrg			       "S-video",
2012de2362d3Smrg			       "LVDS",
2013de2362d3Smrg			       "CTV",
2014de2362d3Smrg			       "DIN",
2015de2362d3Smrg			       "DisplayPort",
2016de2362d3Smrg			       "HDMI",
2017de2362d3Smrg			       "HDMI",
2018de2362d3Smrg			       "TV",
2019de2362d3Smrg			       "eDP"
2020de2362d3Smrg};
2021de2362d3Smrg
202218781e08Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
202318781e08Smrg
202418781e08Smrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
202518781e08Smrg{
202618781e08Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
202718781e08Smrg	int i;
202818781e08Smrg	for (i = 0; i < xf86_config->num_output; i++) {
202918781e08Smrg		xf86OutputPtr output = xf86_config->output[i];
203018781e08Smrg		drmmode_output_private_ptr drmmode_output;
203118781e08Smrg
203218781e08Smrg		drmmode_output = output->driver_private;
203318781e08Smrg		if (drmmode_output->output_id == id)
203418781e08Smrg			return output;
203518781e08Smrg	}
203618781e08Smrg	return NULL;
203718781e08Smrg}
203818781e08Smrg
203918781e08Smrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
204018781e08Smrg{
204118781e08Smrg	char *conn;
204218781e08Smrg	char conn_id[5];
204318781e08Smrg	int id, len;
204418781e08Smrg	char *blob_data;
204518781e08Smrg
204618781e08Smrg	if (!path_blob)
204718781e08Smrg		return -1;
204818781e08Smrg
204918781e08Smrg	blob_data = path_blob->data;
205018781e08Smrg	/* we only handle MST paths for now */
205118781e08Smrg	if (strncmp(blob_data, "mst:", 4))
205218781e08Smrg		return -1;
205318781e08Smrg
205418781e08Smrg	conn = strchr(blob_data + 4, '-');
205518781e08Smrg	if (!conn)
205618781e08Smrg		return -1;
205718781e08Smrg	len = conn - (blob_data + 4);
205818781e08Smrg	if (len + 1 > 5)
205918781e08Smrg		return -1;
206018781e08Smrg	memcpy(conn_id, blob_data + 4, len);
206118781e08Smrg	conn_id[len] = '\0';
206218781e08Smrg	id = strtoul(conn_id, NULL, 10);
206318781e08Smrg
206418781e08Smrg	*conn_base_id = id;
206518781e08Smrg
206618781e08Smrg	*path = conn + 1;
206718781e08Smrg	return 0;
206818781e08Smrg}
206918781e08Smrg
2070de2362d3Smrgstatic void
207118781e08Smrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
207218781e08Smrg		    drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi)
207318781e08Smrg{
207418781e08Smrg	xf86OutputPtr output;
207518781e08Smrg	int conn_id;
207618781e08Smrg	char *extra_path;
207718781e08Smrg
207818781e08Smrg	output = NULL;
207918781e08Smrg	if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
208018781e08Smrg		output = find_output(pScrn, conn_id);
208118781e08Smrg	if (output) {
208218781e08Smrg		snprintf(name, 32, "%s-%s", output->name, extra_path);
208318781e08Smrg	} else {
20848bf5c682Smrg		if (koutput->connector_type >= NUM_OUTPUT_NAMES) {
208518781e08Smrg			snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
208618781e08Smrg				 koutput->connector_type_id - 1);
20878bf5c682Smrg		} else if (pScrn->is_gpu) {
208818781e08Smrg			snprintf(name, 32, "%s-%d-%d",
208918781e08Smrg				 output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1,
209018781e08Smrg				 koutput->connector_type_id - 1);
20918bf5c682Smrg		} else {
209218781e08Smrg			/* need to do smart conversion here for compat with non-kms ATI driver */
209318781e08Smrg			if (koutput->connector_type_id == 1) {
209418781e08Smrg				switch(koutput->connector_type) {
209518781e08Smrg				case DRM_MODE_CONNECTOR_DVII:
209618781e08Smrg				case DRM_MODE_CONNECTOR_DVID:
209718781e08Smrg				case DRM_MODE_CONNECTOR_DVIA:
209818781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
209918781e08Smrg					(*num_dvi)++;
210018781e08Smrg					break;
210118781e08Smrg				case DRM_MODE_CONNECTOR_HDMIA:
210218781e08Smrg				case DRM_MODE_CONNECTOR_HDMIB:
210318781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
210418781e08Smrg					(*num_hdmi)++;
210518781e08Smrg					break;
210618781e08Smrg				case DRM_MODE_CONNECTOR_VGA:
210718781e08Smrg				case DRM_MODE_CONNECTOR_DisplayPort:
210818781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
210918781e08Smrg						 koutput->connector_type_id - 1);
211018781e08Smrg					break;
211118781e08Smrg				default:
211218781e08Smrg					snprintf(name, 32, "%s", output_names[koutput->connector_type]);
211318781e08Smrg					break;
211418781e08Smrg				}
211518781e08Smrg			} else {
211618781e08Smrg				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
211718781e08Smrg					 koutput->connector_type_id - 1);
211818781e08Smrg			}
211918781e08Smrg		}
212018781e08Smrg	}
212118781e08Smrg}
212218781e08Smrg
212318781e08Smrgstatic unsigned int
212418781e08Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic)
21250d16fef4Smrg{
212618781e08Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
21278bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2128de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
2129de2362d3Smrg	xf86OutputPtr output;
2130de2362d3Smrg	drmModeConnectorPtr koutput;
2131de2362d3Smrg	drmModeEncoderPtr *kencoders = NULL;
2132de2362d3Smrg	drmmode_output_private_ptr drmmode_output;
213318781e08Smrg	drmModePropertyBlobPtr path_blob = NULL;
213439413783Smrg#if XF86_CRTC_VERSION >= 8
213539413783Smrg	Bool nonDesktop = FALSE;
213639413783Smrg#endif
2137de2362d3Smrg	char name[32];
2138de2362d3Smrg	int i;
2139de2362d3Smrg	const char *s;
2140de2362d3Smrg
21418bf5c682Smrg	koutput = drmModeGetConnector(pRADEONEnt->fd, mode_res->connectors[num]);
2142de2362d3Smrg	if (!koutput)
214318781e08Smrg		return 0;
214418781e08Smrg
21458bf5c682Smrg	path_blob = koutput_get_prop_blob(pRADEONEnt->fd, koutput, "PATH");
2146de2362d3Smrg
214739413783Smrg#if XF86_CRTC_VERSION >= 8
214839413783Smrg	i = koutput_get_prop_idx(pRADEONEnt->fd, koutput, DRM_MODE_PROP_RANGE,
214939413783Smrg				 "non-desktop");
215039413783Smrg	if (i >= 0)
215139413783Smrg		nonDesktop = koutput->prop_values[i] != 0;
215239413783Smrg#endif
215339413783Smrg
2154de2362d3Smrg	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
2155de2362d3Smrg	if (!kencoders) {
2156de2362d3Smrg		goto out_free_encoders;
2157de2362d3Smrg	}
2158de2362d3Smrg
2159de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
21608bf5c682Smrg		kencoders[i] = drmModeGetEncoder(pRADEONEnt->fd, koutput->encoders[i]);
2161de2362d3Smrg		if (!kencoders[i]) {
2162de2362d3Smrg			goto out_free_encoders;
2163de2362d3Smrg		}
2164de2362d3Smrg	}
2165de2362d3Smrg
216618781e08Smrg	drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi);
216718781e08Smrg	if (path_blob)
216818781e08Smrg		drmModeFreePropertyBlob(path_blob);
216918781e08Smrg
217018781e08Smrg	if (path_blob && dynamic) {
217118781e08Smrg		/* See if we have an output with this name already
217218781e08Smrg		 * and hook stuff up.
217318781e08Smrg		 */
217418781e08Smrg		for (i = 0; i < xf86_config->num_output; i++) {
217518781e08Smrg			output = xf86_config->output[i];
217618781e08Smrg
217718781e08Smrg			if (strncmp(output->name, name, 32))
217818781e08Smrg				continue;
217918781e08Smrg
218018781e08Smrg			drmmode_output = output->driver_private;
218118781e08Smrg			drmmode_output->output_id = mode_res->connectors[num];
218218781e08Smrg			drmmode_output->mode_output = koutput;
218339413783Smrg#if XF86_CRTC_VERSION >= 8
218439413783Smrg			output->non_desktop = nonDesktop;
218539413783Smrg#endif
218618781e08Smrg			for (i = 0; i < koutput->count_encoders; i++)
218718781e08Smrg				drmModeFreeEncoder(kencoders[i]);
218818781e08Smrg			free(kencoders);
218918781e08Smrg			return 0;
219018781e08Smrg		}
2191de2362d3Smrg	}
2192de2362d3Smrg
2193de2362d3Smrg	if (xf86IsEntityShared(pScrn->entityList[0])) {
2194de2362d3Smrg		if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
2195de2362d3Smrg			if (!RADEONZaphodStringMatches(pScrn, s, name))
2196de2362d3Smrg				goto out_free_encoders;
2197de2362d3Smrg		} else {
2198446f62d6Smrg			if (info->instance_id != num)
2199de2362d3Smrg				goto out_free_encoders;
2200de2362d3Smrg		}
2201de2362d3Smrg	}
2202de2362d3Smrg
2203de2362d3Smrg	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
2204de2362d3Smrg	if (!output) {
2205de2362d3Smrg		goto out_free_encoders;
2206de2362d3Smrg	}
2207de2362d3Smrg
2208de2362d3Smrg	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
2209de2362d3Smrg	if (!drmmode_output) {
2210de2362d3Smrg		xf86OutputDestroy(output);
2211de2362d3Smrg		goto out_free_encoders;
2212de2362d3Smrg	}
2213de2362d3Smrg
221418781e08Smrg	drmmode_output->output_id = mode_res->connectors[num];
2215de2362d3Smrg	drmmode_output->mode_output = koutput;
2216de2362d3Smrg	drmmode_output->mode_encoders = kencoders;
2217de2362d3Smrg	drmmode_output->drmmode = drmmode;
2218de2362d3Smrg	output->mm_width = koutput->mmWidth;
2219de2362d3Smrg	output->mm_height = koutput->mmHeight;
2220de2362d3Smrg
2221de2362d3Smrg	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
2222de2362d3Smrg	output->interlaceAllowed = TRUE;
2223de2362d3Smrg	output->doubleScanAllowed = TRUE;
2224de2362d3Smrg	output->driver_private = drmmode_output;
222539413783Smrg#if XF86_CRTC_VERSION >= 8
222639413783Smrg	output->non_desktop = nonDesktop;
222739413783Smrg#endif
2228de2362d3Smrg
2229de2362d3Smrg	output->possible_crtcs = 0xffffffff;
2230de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
2231de2362d3Smrg		output->possible_crtcs &= kencoders[i]->possible_crtcs;
2232de2362d3Smrg	}
2233de2362d3Smrg	/* work out the possible clones later */
2234de2362d3Smrg	output->possible_clones = 0;
2235de2362d3Smrg
22368bf5c682Smrg	drmmode_output->dpms_enum_id =
22378bf5c682Smrg		koutput_get_prop_id(pRADEONEnt->fd, koutput, DRM_MODE_PROP_ENUM,
22388bf5c682Smrg				    "DPMS");
2239de2362d3Smrg
224018781e08Smrg	if (dynamic) {
224118781e08Smrg		output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
224218781e08Smrg		drmmode_output_create_resources(output);
224318781e08Smrg	}
224418781e08Smrg
224518781e08Smrg	return 1;
2246de2362d3Smrgout_free_encoders:
2247de2362d3Smrg	if (kencoders){
2248de2362d3Smrg		for (i = 0; i < koutput->count_encoders; i++)
2249de2362d3Smrg			drmModeFreeEncoder(kencoders[i]);
2250de2362d3Smrg		free(kencoders);
2251de2362d3Smrg	}
2252de2362d3Smrg	drmModeFreeConnector(koutput);
225318781e08Smrg	return 0;
2254de2362d3Smrg}
2255de2362d3Smrg
2256de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
2257de2362d3Smrg{
2258de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout;
2259de2362d3Smrg	int i;
2260de2362d3Smrg	xf86OutputPtr clone_output;
2261de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2262de2362d3Smrg	int index_mask = 0;
2263de2362d3Smrg
2264de2362d3Smrg	if (drmmode_output->enc_clone_mask == 0)
2265de2362d3Smrg		return index_mask;
2266de2362d3Smrg
2267de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
2268de2362d3Smrg		clone_output = xf86_config->output[i];
2269de2362d3Smrg		clone_drmout = clone_output->driver_private;
2270de2362d3Smrg		if (output == clone_output)
2271de2362d3Smrg			continue;
2272de2362d3Smrg
2273de2362d3Smrg		if (clone_drmout->enc_mask == 0)
2274de2362d3Smrg			continue;
2275de2362d3Smrg		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
2276de2362d3Smrg			index_mask |= (1 << i);
2277de2362d3Smrg	}
2278de2362d3Smrg	return index_mask;
2279de2362d3Smrg}
2280de2362d3Smrg
2281de2362d3Smrg
2282de2362d3Smrgstatic void
228318781e08Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
2284de2362d3Smrg{
2285de2362d3Smrg	int i, j;
2286de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2287de2362d3Smrg
2288de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
2289de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
2290de2362d3Smrg		drmmode_output_private_ptr drmmode_output;
2291de2362d3Smrg
2292de2362d3Smrg		drmmode_output = output->driver_private;
2293de2362d3Smrg		drmmode_output->enc_clone_mask = 0xff;
2294de2362d3Smrg		/* and all the possible encoder clones for this output together */
2295de2362d3Smrg		for (j = 0; j < drmmode_output->mode_output->count_encoders; j++)
2296de2362d3Smrg		{
2297de2362d3Smrg			int k;
229818781e08Smrg			for (k = 0; k < mode_res->count_encoders; k++) {
229918781e08Smrg				if (mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id)
2300de2362d3Smrg					drmmode_output->enc_mask |= (1 << k);
2301de2362d3Smrg			}
2302de2362d3Smrg
2303de2362d3Smrg			drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones;
2304de2362d3Smrg		}
2305de2362d3Smrg	}
2306de2362d3Smrg
2307de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
2308de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
2309de2362d3Smrg		output->possible_clones = find_clones(scrn, output);
2310de2362d3Smrg	}
2311de2362d3Smrg}
2312de2362d3Smrg
2313de2362d3Smrg/* returns height alignment in pixels */
2314de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling)
2315de2362d3Smrg{
2316de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2317de2362d3Smrg	int height_align = 1;
2318de2362d3Smrg
2319de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2320de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
2321de2362d3Smrg			height_align =  info->num_channels * 8;
2322de2362d3Smrg		else if (tiling & RADEON_TILING_MICRO)
2323de2362d3Smrg			height_align = 8;
2324de2362d3Smrg		else
2325de2362d3Smrg			height_align = 8;
2326de2362d3Smrg	} else {
232718781e08Smrg		if (tiling & RADEON_TILING_MICRO_SQUARE)
232818781e08Smrg			height_align =  32;
232918781e08Smrg		else if (tiling)
2330de2362d3Smrg			height_align = 16;
2331de2362d3Smrg		else
2332de2362d3Smrg			height_align = 1;
2333de2362d3Smrg	}
2334de2362d3Smrg	return height_align;
2335de2362d3Smrg}
2336de2362d3Smrg
2337de2362d3Smrg/* returns pitch alignment in pixels */
2338de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
2339de2362d3Smrg{
2340de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2341de2362d3Smrg	int pitch_align = 1;
2342de2362d3Smrg
2343de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2344de2362d3Smrg		if (tiling & RADEON_TILING_MACRO) {
2345de2362d3Smrg			/* general surface requirements */
2346de2362d3Smrg			pitch_align = MAX(info->num_banks,
2347de2362d3Smrg					  (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8;
2348de2362d3Smrg			/* further restrictions for scanout */
2349de2362d3Smrg			pitch_align = MAX(info->num_banks * 8, pitch_align);
2350de2362d3Smrg		} else if (tiling & RADEON_TILING_MICRO) {
2351de2362d3Smrg			/* general surface requirements */
2352de2362d3Smrg			pitch_align = MAX(8, (info->group_bytes / (8 * bpe)));
2353de2362d3Smrg			/* further restrictions for scanout */
2354de2362d3Smrg			pitch_align = MAX(info->group_bytes / bpe, pitch_align);
2355de2362d3Smrg		} else {
2356de2362d3Smrg			if (info->have_tiling_info)
2357de2362d3Smrg				/* linear aligned requirements */
2358de2362d3Smrg				pitch_align = MAX(64, info->group_bytes / bpe);
2359de2362d3Smrg			else
2360de2362d3Smrg				/* default to 512 elements if we don't know the real
2361de2362d3Smrg				 * group size otherwise the kernel may reject the CS
2362de2362d3Smrg				 * if the group sizes don't match as the pitch won't
2363de2362d3Smrg				 * be aligned properly.
2364de2362d3Smrg				 */
2365de2362d3Smrg				pitch_align = 512;
2366de2362d3Smrg		}
2367de2362d3Smrg	} else {
2368de2362d3Smrg		/* general surface requirements */
2369de2362d3Smrg		if (tiling)
2370de2362d3Smrg			pitch_align = 256 / bpe;
2371de2362d3Smrg		else
2372de2362d3Smrg			pitch_align = 64;
2373de2362d3Smrg	}
2374de2362d3Smrg	return pitch_align;
2375de2362d3Smrg}
2376de2362d3Smrg
2377de2362d3Smrg/* returns base alignment in bytes */
2378de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
2379de2362d3Smrg{
2380de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2381de2362d3Smrg	int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling);
2382de2362d3Smrg	int height_align = drmmode_get_height_align(scrn, tiling);
2383de2362d3Smrg	int base_align = RADEON_GPU_PAGE_SIZE;
2384de2362d3Smrg
2385de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2386de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
2387de2362d3Smrg			base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe,
2388de2362d3Smrg					 pixel_align * bpe * height_align);
2389de2362d3Smrg		else {
2390de2362d3Smrg			if (info->have_tiling_info)
2391de2362d3Smrg				base_align = info->group_bytes;
2392de2362d3Smrg			else
2393de2362d3Smrg				/* default to 512 if we don't know the real
2394de2362d3Smrg				 * group size otherwise the kernel may reject the CS
2395de2362d3Smrg				 * if the group sizes don't match as the base won't
2396de2362d3Smrg				 * be aligned properly.
2397de2362d3Smrg				 */
2398de2362d3Smrg				base_align = 512;
2399de2362d3Smrg		}
2400de2362d3Smrg	}
2401de2362d3Smrg	return base_align;
2402de2362d3Smrg}
2403de2362d3Smrg
2404de2362d3Smrgstatic Bool
2405de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
2406de2362d3Smrg{
2407de2362d3Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2408de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
240939413783Smrg	struct radeon_buffer *old_front = NULL;
2410de2362d3Smrg	ScreenPtr   screen = xf86ScrnToScreen(scrn);
2411de2362d3Smrg	int	    i, pitch, old_width, old_height, old_pitch;
241239413783Smrg	int usage = CREATE_PIXMAP_USAGE_BACKING_PIXMAP;
241318781e08Smrg	int cpp = info->pixel_bytes;
241439413783Smrg	uint32_t tiling_flags;
2415de2362d3Smrg	PixmapPtr ppix = screen->GetScreenPixmap(screen);
2416de2362d3Smrg	void *fb_shadow;
2417de2362d3Smrg
2418de2362d3Smrg	if (scrn->virtualX == width && scrn->virtualY == height)
2419de2362d3Smrg		return TRUE;
2420de2362d3Smrg
242139413783Smrg	if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) {
242239413783Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
242339413783Smrg			   "Xorg tried resizing screen to %dx%d, but maximum "
242439413783Smrg			   "supported is %dx%d\n", width, height,
242539413783Smrg			   xf86_config->maxWidth, xf86_config->maxHeight);
242639413783Smrg		return FALSE;
2427de2362d3Smrg	}
2428de2362d3Smrg
242939413783Smrg	if (info->allowColorTiling && !info->shadow_primary) {
243039413783Smrg		if (info->ChipFamily < CHIP_FAMILY_R600 || info->allowColorTiling2D)
243139413783Smrg			usage |= RADEON_CREATE_PIXMAP_TILING_MACRO;
243239413783Smrg		else
243339413783Smrg			usage |= RADEON_CREATE_PIXMAP_TILING_MICRO;
2434de2362d3Smrg	}
2435de2362d3Smrg
243639413783Smrg	xf86DrvMsg(scrn->scrnIndex, X_INFO, "Allocate new frame buffer %dx%d\n",
243739413783Smrg		   width, height);
2438de2362d3Smrg
2439de2362d3Smrg	old_width = scrn->virtualX;
2440de2362d3Smrg	old_height = scrn->virtualY;
2441de2362d3Smrg	old_pitch = scrn->displayWidth;
244239413783Smrg	old_front = info->front_buffer;
2443de2362d3Smrg
2444de2362d3Smrg	scrn->virtualX = width;
2445de2362d3Smrg	scrn->virtualY = height;
2446de2362d3Smrg
244739413783Smrg	info->front_buffer = radeon_alloc_pixmap_bo(scrn, scrn->virtualX,
244839413783Smrg						    scrn->virtualY, scrn->depth,
244939413783Smrg						    usage, scrn->bitsPerPixel,
245039413783Smrg						    &pitch,
245139413783Smrg						    &info->front_surface,
245239413783Smrg						    &tiling_flags);
245339413783Smrg	if (!info->front_buffer)
2454de2362d3Smrg		goto fail;
2455de2362d3Smrg
245639413783Smrg	scrn->displayWidth = pitch / cpp;
245739413783Smrg
245839413783Smrg	if (!info->use_glamor) {
2459de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
246039413783Smrg		switch (cpp) {
246139413783Smrg		case 4:
246239413783Smrg			tiling_flags |= RADEON_TILING_SWAP_32BIT;
246339413783Smrg			break;
246439413783Smrg		case 2:
246539413783Smrg			tiling_flags |= RADEON_TILING_SWAP_16BIT;
246639413783Smrg			break;
246739413783Smrg		}
246839413783Smrg		if (info->ChipFamily < CHIP_FAMILY_R600 &&
246939413783Smrg		    info->r600_shadow_fb && tiling_flags)
247039413783Smrg			tiling_flags |= RADEON_TILING_SURFACE;
2471de2362d3Smrg#endif
247239413783Smrg		if (tiling_flags)
247339413783Smrg			radeon_bo_set_tiling(info->front_buffer->bo.radeon, tiling_flags, pitch);
247439413783Smrg	}
2475de2362d3Smrg
2476de2362d3Smrg	if (!info->r600_shadow_fb) {
247739413783Smrg		if (info->surf_man && !info->use_glamor)
247839413783Smrg			*radeon_get_pixmap_surface(ppix) = info->front_surface;
2479de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
2480de2362d3Smrg					   width, height, -1, -1, pitch, NULL);
2481de2362d3Smrg	} else {
248239413783Smrg		if (radeon_bo_map(info->front_buffer->bo.radeon, 1))
2483de2362d3Smrg			goto fail;
248439413783Smrg		fb_shadow = calloc(1, pitch * scrn->virtualY);
248539413783Smrg		if (!fb_shadow)
2486de2362d3Smrg			goto fail;
2487de2362d3Smrg		free(info->fb_shadow);
2488de2362d3Smrg		info->fb_shadow = fb_shadow;
2489de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
2490de2362d3Smrg					   width, height, -1, -1, pitch,
2491de2362d3Smrg					   info->fb_shadow);
2492de2362d3Smrg	}
249318781e08Smrg
249418781e08Smrg	if (info->use_glamor)
249518781e08Smrg		radeon_glamor_create_screen_resources(scrn->pScreen);
249618781e08Smrg
249718781e08Smrg	if (!info->r600_shadow_fb) {
249839413783Smrg		if (!radeon_set_pixmap_bo(ppix, info->front_buffer))
249918781e08Smrg			goto fail;
250018781e08Smrg	}
250118781e08Smrg
25028bf5c682Smrg	radeon_pixmap_clear(ppix);
250339413783Smrg	radeon_finish(scrn, info->front_buffer);
25040d16fef4Smrg
2505de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
2506de2362d3Smrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
2507de2362d3Smrg
2508de2362d3Smrg		if (!crtc->enabled)
2509de2362d3Smrg			continue;
2510de2362d3Smrg
2511de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode,
2512de2362d3Smrg				       crtc->rotation, crtc->x, crtc->y);
2513de2362d3Smrg	}
2514de2362d3Smrg
251539413783Smrg	radeon_buffer_unref(&old_front);
2516de2362d3Smrg
251739413783Smrg	radeon_kms_update_vram_limit(scrn, pitch * scrn->virtualY);
2518de2362d3Smrg	return TRUE;
2519de2362d3Smrg
2520de2362d3Smrg fail:
252139413783Smrg	radeon_buffer_unref(&info->front_buffer);
252239413783Smrg	info->front_buffer = old_front;
2523de2362d3Smrg	scrn->virtualX = old_width;
2524de2362d3Smrg	scrn->virtualY = old_height;
2525de2362d3Smrg	scrn->displayWidth = old_pitch;
2526de2362d3Smrg
2527de2362d3Smrg	return FALSE;
2528de2362d3Smrg}
2529de2362d3Smrg
253039413783Smrgstatic void
253139413783Smrgdrmmode_validate_leases(ScrnInfoPtr scrn)
253239413783Smrg{
253339413783Smrg#ifdef XF86_LEASE_VERSION
253439413783Smrg	ScreenPtr screen = scrn->pScreen;
253539413783Smrg	rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
253639413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
253739413783Smrg	drmModeLesseeListPtr lessees;
253839413783Smrg	RRLeasePtr lease, next;
253939413783Smrg	int l;
254039413783Smrg
254139413783Smrg	/* We can't talk to the kernel about leases when VT switched */
254239413783Smrg	if (!scrn->vtSema)
254339413783Smrg		return;
254439413783Smrg
254539413783Smrg	lessees = drmModeListLessees(pRADEONEnt->fd);
254639413783Smrg	if (!lessees)
254739413783Smrg		return;
254839413783Smrg
254939413783Smrg	xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
255039413783Smrg		drmmode_lease_private_ptr lease_private = lease->devPrivate;
255139413783Smrg
255239413783Smrg		for (l = 0; l < lessees->count; l++) {
255339413783Smrg			if (lessees->lessees[l] == lease_private->lessee_id)
255439413783Smrg				break;
255539413783Smrg		}
255639413783Smrg
255739413783Smrg		/* check to see if the lease has gone away */
255839413783Smrg		if (l == lessees->count) {
255939413783Smrg			free(lease_private);
256039413783Smrg			lease->devPrivate = NULL;
256139413783Smrg			xf86CrtcLeaseTerminated(lease);
256239413783Smrg		}
256339413783Smrg	}
256439413783Smrg
256539413783Smrg	free(lessees);
256639413783Smrg#endif
256739413783Smrg}
256839413783Smrg
256939413783Smrg#ifdef XF86_LEASE_VERSION
257039413783Smrg
257139413783Smrgstatic int
257239413783Smrgdrmmode_create_lease(RRLeasePtr lease, int *fd)
257339413783Smrg{
257439413783Smrg	ScreenPtr screen = lease->screen;
257539413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
257639413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
257739413783Smrg	drmmode_lease_private_ptr lease_private;
257839413783Smrg	int noutput = lease->numOutputs;
257939413783Smrg	int ncrtc = lease->numCrtcs;
258039413783Smrg	uint32_t *objects;
258139413783Smrg	size_t nobjects;
258239413783Smrg	int lease_fd;
258339413783Smrg	int c, o;
258439413783Smrg	int i;
258539413783Smrg
258639413783Smrg	nobjects = ncrtc + noutput;
258739413783Smrg	if (nobjects == 0 || nobjects > (SIZE_MAX / 4) ||
258839413783Smrg	    ncrtc > (SIZE_MAX - noutput))
258939413783Smrg		return BadValue;
259039413783Smrg
259139413783Smrg	lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
259239413783Smrg	if (!lease_private)
259339413783Smrg		return BadAlloc;
259439413783Smrg
259539413783Smrg	objects = malloc(nobjects * 4);
259639413783Smrg	if (!objects) {
259739413783Smrg		free(lease_private);
259839413783Smrg		return BadAlloc;
259939413783Smrg	}
260039413783Smrg
260139413783Smrg	i = 0;
260239413783Smrg
260339413783Smrg	/* Add CRTC ids */
260439413783Smrg	for (c = 0; c < ncrtc; c++) {
260539413783Smrg		xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
260639413783Smrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
260739413783Smrg
260839413783Smrg		objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
260939413783Smrg	}
261039413783Smrg
261139413783Smrg	/* Add connector ids */
261239413783Smrg	for (o = 0; o < noutput; o++) {
261339413783Smrg		xf86OutputPtr   output = lease->outputs[o]->devPrivate;
261439413783Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
261539413783Smrg
261639413783Smrg		objects[i++] = drmmode_output->mode_output->connector_id;
261739413783Smrg	}
261839413783Smrg
261939413783Smrg	/* call kernel to create lease */
262039413783Smrg	assert (i == nobjects);
262139413783Smrg
262239413783Smrg	lease_fd = drmModeCreateLease(pRADEONEnt->fd, objects, nobjects, 0,
262339413783Smrg				      &lease_private->lessee_id);
262439413783Smrg
262539413783Smrg	free(objects);
262639413783Smrg
262739413783Smrg	if (lease_fd < 0) {
262839413783Smrg		free(lease_private);
262939413783Smrg		return BadMatch;
263039413783Smrg	}
263139413783Smrg
263239413783Smrg	lease->devPrivate = lease_private;
263339413783Smrg
263439413783Smrg	xf86CrtcLeaseStarted(lease);
263539413783Smrg
263639413783Smrg	*fd = lease_fd;
263739413783Smrg	return Success;
263839413783Smrg}
263939413783Smrg
264039413783Smrgstatic void
264139413783Smrgdrmmode_terminate_lease(RRLeasePtr lease)
264239413783Smrg{
264339413783Smrg	drmmode_lease_private_ptr lease_private = lease->devPrivate;
264439413783Smrg	ScreenPtr screen = lease->screen;
264539413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
264639413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
264739413783Smrg
264839413783Smrg	if (drmModeRevokeLease(pRADEONEnt->fd, lease_private->lessee_id) == 0) {
264939413783Smrg		free(lease_private);
265039413783Smrg		lease->devPrivate = NULL;
265139413783Smrg		xf86CrtcLeaseTerminated(lease);
265239413783Smrg	}
265339413783Smrg}
265439413783Smrg
265539413783Smrg#endif // XF86_LEASE_VERSION
265639413783Smrg
2657de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
265839413783Smrg	.resize = drmmode_xf86crtc_resize,
265939413783Smrg#ifdef XF86_LEASE_VERSION
266039413783Smrg	.create_lease = drmmode_create_lease,
266139413783Smrg	.terminate_lease = drmmode_terminate_lease
266239413783Smrg#endif
2663de2362d3Smrg};
2664de2362d3Smrg
2665de2362d3Smrgstatic void
266618781e08Smrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
2667de2362d3Smrg{
26688bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
26698bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
267018781e08Smrg	drmmode_flipdata_ptr flipdata = event_data;
267139413783Smrg	int crtc_id = drmmode_get_crtc_id(crtc);
267239413783Smrg	struct drmmode_fb **fb = &flipdata->fb[crtc_id];
267339413783Smrg
267439413783Smrg	if (drmmode_crtc->flip_pending == *fb) {
267539413783Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending,
267639413783Smrg				     NULL);
267739413783Smrg	}
267839413783Smrg	drmmode_fb_reference(pRADEONEnt->fd, fb, NULL);
267918781e08Smrg
268018781e08Smrg	if (--flipdata->flip_count == 0) {
268118781e08Smrg		if (!flipdata->fe_crtc)
268218781e08Smrg			flipdata->fe_crtc = crtc;
268318781e08Smrg		flipdata->abort(flipdata->fe_crtc, flipdata->event_data);
268418781e08Smrg		free(flipdata);
268518781e08Smrg	}
2686de2362d3Smrg}
2687de2362d3Smrg
2688de2362d3Smrgstatic void
268918781e08Smrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
2690de2362d3Smrg{
26918bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
26928bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
269318781e08Smrg	drmmode_flipdata_ptr flipdata = event_data;
269439413783Smrg	int crtc_id = drmmode_get_crtc_id(crtc);
269539413783Smrg	struct drmmode_fb **fb = &flipdata->fb[crtc_id];
2696de2362d3Smrg
2697de2362d3Smrg	/* Is this the event whose info shall be delivered to higher level? */
269818781e08Smrg	if (crtc == flipdata->fe_crtc) {
2699de2362d3Smrg		/* Yes: Cache msc, ust for later delivery. */
2700de2362d3Smrg		flipdata->fe_frame = frame;
270118781e08Smrg		flipdata->fe_usec = usec;
2702de2362d3Smrg	}
2703de2362d3Smrg
2704446f62d6Smrg	if (*fb) {
2705446f62d6Smrg		if (drmmode_crtc->flip_pending == *fb) {
2706446f62d6Smrg			drmmode_fb_reference(pRADEONEnt->fd,
2707446f62d6Smrg					     &drmmode_crtc->flip_pending, NULL);
2708446f62d6Smrg		}
2709446f62d6Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, *fb);
2710446f62d6Smrg		drmmode_fb_reference(pRADEONEnt->fd, fb, NULL);
27118bf5c682Smrg	}
27128bf5c682Smrg
271318781e08Smrg	if (--flipdata->flip_count == 0) {
271418781e08Smrg		/* Deliver MSC & UST from reference/current CRTC to flip event
271518781e08Smrg		 * handler
271618781e08Smrg		 */
271718781e08Smrg		if (flipdata->fe_crtc)
271818781e08Smrg			flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame,
271918781e08Smrg					  flipdata->fe_usec, flipdata->event_data);
272018781e08Smrg		else
272118781e08Smrg			flipdata->handler(crtc, frame, usec, flipdata->event_data);
2722de2362d3Smrg
272318781e08Smrg		free(flipdata);
272418781e08Smrg	}
2725de2362d3Smrg}
2726de2362d3Smrg
2727de2362d3Smrg
272818781e08Smrg#if HAVE_NOTIFY_FD
272918781e08Smrgstatic void
273018781e08Smrgdrm_notify_fd(int fd, int ready, void *data)
273118781e08Smrg#else
2732de2362d3Smrgstatic void
2733de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p)
273418781e08Smrg#endif
2735de2362d3Smrg{
273639413783Smrg	drmmode_ptr drmmode = data;
273739413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(drmmode->scrn);
27388bf5c682Smrg
273918781e08Smrg#if !HAVE_NOTIFY_FD
2740de2362d3Smrg	fd_set *read_mask = p;
2741de2362d3Smrg
27428bf5c682Smrg	if (err >= 0 && FD_ISSET(pRADEONEnt->fd, read_mask))
274318781e08Smrg#endif
274418781e08Smrg	{
274539413783Smrg		radeon_drm_handle_event(pRADEONEnt->fd, &drmmode->event_context);
2746de2362d3Smrg	}
2747de2362d3Smrg}
2748de2362d3Smrg
27498bf5c682Smrgstatic Bool drmmode_probe_page_flip_target(RADEONEntPtr pRADEONEnt)
27503ed65abbSmrg{
27513ed65abbSmrg#ifdef DRM_CAP_PAGE_FLIP_TARGET
27523ed65abbSmrg	uint64_t cap_value;
27533ed65abbSmrg
27548bf5c682Smrg	return drmGetCap(pRADEONEnt->fd, DRM_CAP_PAGE_FLIP_TARGET,
27553ed65abbSmrg			 &cap_value) == 0 && cap_value != 0;
27563ed65abbSmrg#else
27573ed65abbSmrg	return FALSE;
27583ed65abbSmrg#endif
27593ed65abbSmrg}
27603ed65abbSmrg
27613ed65abbSmrgstatic int
27628bf5c682Smrgdrmmode_page_flip(RADEONEntPtr pRADEONEnt,
27638bf5c682Smrg		  drmmode_crtc_private_ptr drmmode_crtc, int fb_id,
27643ed65abbSmrg		  uint32_t flags, uintptr_t drm_queue_seq)
27653ed65abbSmrg{
27663ed65abbSmrg	flags |= DRM_MODE_PAGE_FLIP_EVENT;
27678bf5c682Smrg	return drmModePageFlip(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
27683ed65abbSmrg			       fb_id, flags, (void*)drm_queue_seq);
27693ed65abbSmrg}
27703ed65abbSmrg
27713ed65abbSmrgint
27723ed65abbSmrgdrmmode_page_flip_target_absolute(RADEONEntPtr pRADEONEnt,
27733ed65abbSmrg				  drmmode_crtc_private_ptr drmmode_crtc,
27743ed65abbSmrg				  int fb_id, uint32_t flags,
27753ed65abbSmrg				  uintptr_t drm_queue_seq, uint32_t target_msc)
27763ed65abbSmrg{
27773ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET
27783ed65abbSmrg	if (pRADEONEnt->has_page_flip_target) {
27793ed65abbSmrg		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE;
27808bf5c682Smrg		return drmModePageFlipTarget(pRADEONEnt->fd,
27813ed65abbSmrg					     drmmode_crtc->mode_crtc->crtc_id,
27823ed65abbSmrg					     fb_id, flags, (void*)drm_queue_seq,
27833ed65abbSmrg					     target_msc);
27843ed65abbSmrg	}
27853ed65abbSmrg#endif
27863ed65abbSmrg
27878bf5c682Smrg	return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags,
27888bf5c682Smrg				 drm_queue_seq);
27893ed65abbSmrg}
27903ed65abbSmrg
27913ed65abbSmrgint
27923ed65abbSmrgdrmmode_page_flip_target_relative(RADEONEntPtr pRADEONEnt,
27933ed65abbSmrg				  drmmode_crtc_private_ptr drmmode_crtc,
27943ed65abbSmrg				  int fb_id, uint32_t flags,
27953ed65abbSmrg				  uintptr_t drm_queue_seq, uint32_t target_msc)
27963ed65abbSmrg{
27973ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET
27983ed65abbSmrg	if (pRADEONEnt->has_page_flip_target) {
27993ed65abbSmrg		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE;
28008bf5c682Smrg		return drmModePageFlipTarget(pRADEONEnt->fd,
28013ed65abbSmrg					     drmmode_crtc->mode_crtc->crtc_id,
28023ed65abbSmrg					     fb_id, flags, (void*)drm_queue_seq,
28033ed65abbSmrg					     target_msc);
28043ed65abbSmrg	}
28053ed65abbSmrg#endif
28063ed65abbSmrg
28078bf5c682Smrg	return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags,
28088bf5c682Smrg				 drm_queue_seq);
28093ed65abbSmrg}
28103ed65abbSmrg
2811de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
2812de2362d3Smrg{
281318781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
281418781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
2815de2362d3Smrg	int i, num_dvi = 0, num_hdmi = 0;
281618781e08Smrg	drmModeResPtr mode_res;
281718781e08Smrg	unsigned int crtcs_needed = 0;
2818446f62d6Smrg	unsigned int crtcs_got = 0;
281918781e08Smrg	char *bus_id_string, *provider_name;
2820de2362d3Smrg
2821de2362d3Smrg	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
2822de2362d3Smrg
2823de2362d3Smrg	drmmode->scrn = pScrn;
28248bf5c682Smrg	mode_res = drmModeGetResources(pRADEONEnt->fd);
282518781e08Smrg	if (!mode_res)
2826de2362d3Smrg		return FALSE;
2827de2362d3Smrg
282818781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
282918781e08Smrg		       "Initializing outputs ...\n");
283018781e08Smrg	for (i = 0; i < mode_res->count_connectors; i++)
283118781e08Smrg		crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res,
283218781e08Smrg						    i, &num_dvi, &num_hdmi, 0);
283318781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
283418781e08Smrg		       "%d crtcs needed for screen.\n", crtcs_needed);
283518781e08Smrg
28368bf5c682Smrg	/* Need per-screen drmmode_crtc_funcs, based on our global template,
28378bf5c682Smrg	 * so we can disable some functions, depending on screen settings.
28388bf5c682Smrg	 */
28398bf5c682Smrg	info->drmmode_crtc_funcs = drmmode_crtc_funcs;
28408bf5c682Smrg
284118781e08Smrg	if (info->r600_shadow_fb) {
284218781e08Smrg		/* Rotation requires hardware acceleration */
28438bf5c682Smrg		info->drmmode_crtc_funcs.shadow_allocate = NULL;
28448bf5c682Smrg		info->drmmode_crtc_funcs.shadow_create = NULL;
28458bf5c682Smrg		info->drmmode_crtc_funcs.shadow_destroy = NULL;
284618781e08Smrg	}
284718781e08Smrg
28488bf5c682Smrg	/* Hw gamma lut's are currently bypassed by the hw at color depth 30,
28498bf5c682Smrg	 * so spare the server the effort to compute and update the cluts.
28508bf5c682Smrg	 */
28518bf5c682Smrg	if (pScrn->depth == 30)
28528bf5c682Smrg		info->drmmode_crtc_funcs.gamma_set = NULL;
28538bf5c682Smrg
285418781e08Smrg	drmmode->count_crtcs = mode_res->count_crtcs;
285518781e08Smrg	xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height);
285618781e08Smrg
2857446f62d6Smrg	for (i = 0; i < mode_res->count_crtcs; i++) {
285818781e08Smrg		if (!xf86IsEntityShared(pScrn->entityList[0]) ||
2859446f62d6Smrg		    (crtcs_got < crtcs_needed &&
2860446f62d6Smrg		     !(pRADEONEnt->assigned_crtcs & (1 << i))))
2861446f62d6Smrg			crtcs_got += drmmode_crtc_init(pScrn, drmmode, mode_res, i);
2862446f62d6Smrg	}
2863de2362d3Smrg
286418781e08Smrg	/* All ZaphodHeads outputs provided with matching crtcs? */
2865446f62d6Smrg	if (crtcs_got < crtcs_needed) {
2866446f62d6Smrg		if (crtcs_got == 0) {
2867446f62d6Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2868446f62d6Smrg				   "No ZaphodHeads CRTC available, needed %u\n",
2869446f62d6Smrg				   crtcs_needed);
2870446f62d6Smrg			return FALSE;
2871446f62d6Smrg		}
2872446f62d6Smrg
287318781e08Smrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
287418781e08Smrg			   "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
287518781e08Smrg			   crtcs_needed);
2876446f62d6Smrg	}
2877de2362d3Smrg
2878de2362d3Smrg	/* workout clones */
287918781e08Smrg	drmmode_clones_init(pScrn, drmmode, mode_res);
288018781e08Smrg
288118781e08Smrg	bus_id_string = DRICreatePCIBusID(info->PciInfo);
288218781e08Smrg	XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string);
288318781e08Smrg	free(bus_id_string);
288418781e08Smrg	xf86ProviderSetup(pScrn, NULL, provider_name);
288518781e08Smrg	free(provider_name);
2886de2362d3Smrg
2887de2362d3Smrg	xf86InitialConfiguration(pScrn, TRUE);
2888de2362d3Smrg
28898bf5c682Smrg	pRADEONEnt->has_page_flip_target = drmmode_probe_page_flip_target(pRADEONEnt);
28903ed65abbSmrg
289118781e08Smrg	drmModeFreeResources(mode_res);
2892de2362d3Smrg	return TRUE;
2893de2362d3Smrg}
2894de2362d3Smrg
2895de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
2896de2362d3Smrg{
2897de2362d3Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2898de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
2899de2362d3Smrg
290018781e08Smrg	if (info->dri2.pKernelDRMVersion->version_minor < 4)
290118781e08Smrg		return;
290218781e08Smrg
290318781e08Smrg	info->drmmode_inited = TRUE;
290418781e08Smrg	if (pRADEONEnt->fd_wakeup_registered != serverGeneration) {
290518781e08Smrg#if HAVE_NOTIFY_FD
290639413783Smrg		SetNotifyFd(pRADEONEnt->fd, drm_notify_fd, X_NOTIFY_READ,
290739413783Smrg			    &info->drmmode);
290818781e08Smrg#else
29098bf5c682Smrg		AddGeneralSocket(pRADEONEnt->fd);
2910de2362d3Smrg		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
291139413783Smrg					       drm_wakeup_handler,
291239413783Smrg					       &info->drmmode);
291318781e08Smrg#endif
2914de2362d3Smrg		pRADEONEnt->fd_wakeup_registered = serverGeneration;
291518781e08Smrg		pRADEONEnt->fd_wakeup_ref = 1;
291618781e08Smrg	} else
291718781e08Smrg		pRADEONEnt->fd_wakeup_ref++;
291818781e08Smrg}
291918781e08Smrg
292018781e08Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
292118781e08Smrg{
292218781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
292318781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
292418781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
292518781e08Smrg	int c;
292618781e08Smrg
292718781e08Smrg	if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited)
292818781e08Smrg		return;
292918781e08Smrg
2930446f62d6Smrg	for (c = 0; c < config->num_crtc; c++)
2931446f62d6Smrg		drmmode_crtc_scanout_free(config->crtc[c]);
2932446f62d6Smrg
293318781e08Smrg	if (pRADEONEnt->fd_wakeup_registered == serverGeneration &&
293418781e08Smrg	    !--pRADEONEnt->fd_wakeup_ref) {
293518781e08Smrg#if HAVE_NOTIFY_FD
29368bf5c682Smrg		RemoveNotifyFd(pRADEONEnt->fd);
293718781e08Smrg#else
29388bf5c682Smrg		RemoveGeneralSocket(pRADEONEnt->fd);
293918781e08Smrg		RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
29408bf5c682Smrg				drm_wakeup_handler, pScrn);
294118781e08Smrg#endif
294218781e08Smrg	}
2943de2362d3Smrg}
2944de2362d3Smrg
294518781e08Smrg
2946de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr)
2947de2362d3Smrg{
2948de2362d3Smrg	drmmode->bufmgr = bufmgr;
2949de2362d3Smrg	return TRUE;
2950de2362d3Smrg}
2951de2362d3Smrg
2952de2362d3Smrg
29538bf5c682Smrgstatic void drmmode_sprite_do_set_cursor(struct radeon_device_priv *device_priv,
29548bf5c682Smrg					 ScrnInfoPtr scrn, int x, int y)
29558bf5c682Smrg{
29568bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
29578bf5c682Smrg	CursorPtr cursor = device_priv->cursor;
29588bf5c682Smrg	Bool sprite_visible = device_priv->sprite_visible;
29598bf5c682Smrg
29608bf5c682Smrg	if (cursor) {
29618bf5c682Smrg		x -= cursor->bits->xhot;
29628bf5c682Smrg		y -= cursor->bits->yhot;
29638bf5c682Smrg
29648bf5c682Smrg		device_priv->sprite_visible =
29658bf5c682Smrg			x < scrn->virtualX && y < scrn->virtualY &&
29668bf5c682Smrg			(x + cursor->bits->width > 0) &&
29678bf5c682Smrg			(y + cursor->bits->height > 0);
29688bf5c682Smrg	} else {
29698bf5c682Smrg		device_priv->sprite_visible = FALSE;
29708bf5c682Smrg	}
29718bf5c682Smrg
29728bf5c682Smrg	info->sprites_visible += device_priv->sprite_visible - sprite_visible;
29738bf5c682Smrg}
29748bf5c682Smrg
297539413783Smrgstatic void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
297639413783Smrg				      CursorPtr pCursor, int x, int y)
29778bf5c682Smrg{
29788bf5c682Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
29798bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
29808bf5c682Smrg	struct radeon_device_priv *device_priv =
29818bf5c682Smrg		dixLookupScreenPrivate(&pDev->devPrivates,
29828bf5c682Smrg				       &radeon_device_private_key, pScreen);
29838bf5c682Smrg
29848bf5c682Smrg	device_priv->cursor = pCursor;
29858bf5c682Smrg	drmmode_sprite_do_set_cursor(device_priv, scrn, x, y);
29868bf5c682Smrg
298739413783Smrg	info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
29888bf5c682Smrg}
29898bf5c682Smrg
299039413783Smrgstatic void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
299139413783Smrg				       int x, int y)
29928bf5c682Smrg{
29938bf5c682Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
29948bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
29958bf5c682Smrg	struct radeon_device_priv *device_priv =
29968bf5c682Smrg		dixLookupScreenPrivate(&pDev->devPrivates,
29978bf5c682Smrg				       &radeon_device_private_key, pScreen);
29988bf5c682Smrg
29998bf5c682Smrg	drmmode_sprite_do_set_cursor(device_priv, scrn, x, y);
30008bf5c682Smrg
300139413783Smrg	info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
300239413783Smrg}
300339413783Smrg
300439413783Smrgstatic Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
300539413783Smrg						  ScreenPtr pScreen,
300639413783Smrg						  CursorPtr pCursor)
300739413783Smrg{
300839413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
300939413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
301039413783Smrg
301139413783Smrg	return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
301239413783Smrg}
301339413783Smrg
301439413783Smrgstatic Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
301539413783Smrg						    ScreenPtr pScreen,
301639413783Smrg						    CursorPtr pCursor)
301739413783Smrg{
301839413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
301939413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
302039413783Smrg
302139413783Smrg	return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
302239413783Smrg}
302339413783Smrg
302439413783Smrgstatic Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
302539413783Smrg						    ScreenPtr pScreen)
302639413783Smrg{
302739413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
302839413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
302939413783Smrg
303039413783Smrg	return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
30318bf5c682Smrg}
3032de2362d3Smrg
303339413783Smrgstatic void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
303439413783Smrg						 ScreenPtr pScreen)
303539413783Smrg{
303639413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
303739413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
303839413783Smrg
303939413783Smrg	info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
304039413783Smrg}
304139413783Smrg
304239413783SmrgmiPointerSpriteFuncRec drmmode_sprite_funcs = {
304339413783Smrg	.RealizeCursor = drmmode_sprite_realize_realize_cursor,
304439413783Smrg	.UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
304539413783Smrg	.SetCursor = drmmode_sprite_set_cursor,
304639413783Smrg	.MoveCursor = drmmode_sprite_move_cursor,
304739413783Smrg	.DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
304839413783Smrg	.DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
304939413783Smrg};
305039413783Smrg
305139413783Smrg
3052de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
3053de2362d3Smrg{
3054de2362d3Smrg	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
3055de2362d3Smrg	xf86OutputPtr  output = config->output[config->compat_output];
3056de2362d3Smrg	xf86CrtcPtr	crtc = output->crtc;
3057de2362d3Smrg
3058de2362d3Smrg	if (crtc && crtc->enabled) {
3059de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
3060de2362d3Smrg				       x, y);
3061de2362d3Smrg	}
3062de2362d3Smrg}
3063de2362d3Smrg
306418781e08SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
306518781e08Smrg			       Bool set_hw)
3066de2362d3Smrg{
3067de2362d3Smrg	xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
30688bf5c682Smrg	unsigned num_desired = 0, num_on = 0;
3069de2362d3Smrg	int c;
3070de2362d3Smrg
30718bf5c682Smrg	/* First, disable all unused CRTCs */
30728bf5c682Smrg	if (set_hw) {
30738bf5c682Smrg		for (c = 0; c < config->num_crtc; c++) {
30748bf5c682Smrg			xf86CrtcPtr crtc = config->crtc[c];
30758bf5c682Smrg
30768bf5c682Smrg			/* Skip disabled CRTCs */
30778bf5c682Smrg			if (crtc->enabled)
30788bf5c682Smrg				continue;
30798bf5c682Smrg
308039413783Smrg			drmmode_crtc_dpms(crtc, DPMSModeOff);
30818bf5c682Smrg		}
30828bf5c682Smrg	}
30838bf5c682Smrg
30848bf5c682Smrg	/* Then, try setting the chosen mode on each CRTC */
3085de2362d3Smrg	for (c = 0; c < config->num_crtc; c++) {
3086de2362d3Smrg		xf86CrtcPtr	crtc = config->crtc[c];
3087de2362d3Smrg		xf86OutputPtr	output = NULL;
3088de2362d3Smrg		int		o;
3089de2362d3Smrg
30908bf5c682Smrg		if (!crtc->enabled)
3091de2362d3Smrg			continue;
3092de2362d3Smrg
3093de2362d3Smrg		if (config->output[config->compat_output]->crtc == crtc)
3094de2362d3Smrg			output = config->output[config->compat_output];
3095de2362d3Smrg		else
3096de2362d3Smrg		{
3097de2362d3Smrg			for (o = 0; o < config->num_output; o++)
3098de2362d3Smrg				if (config->output[o]->crtc == crtc)
3099de2362d3Smrg				{
3100de2362d3Smrg					output = config->output[o];
3101de2362d3Smrg					break;
3102de2362d3Smrg				}
3103de2362d3Smrg		}
3104de2362d3Smrg		/* paranoia */
3105de2362d3Smrg		if (!output)
3106de2362d3Smrg			continue;
3107de2362d3Smrg
31088bf5c682Smrg		num_desired++;
31098bf5c682Smrg
3110de2362d3Smrg		/* Mark that we'll need to re-set the mode for sure */
3111de2362d3Smrg		memset(&crtc->mode, 0, sizeof(crtc->mode));
3112de2362d3Smrg		if (!crtc->desiredMode.CrtcHDisplay)
3113de2362d3Smrg		{
3114de2362d3Smrg			DisplayModePtr  mode = xf86OutputFindClosestMode (output, pScrn->currentMode);
3115de2362d3Smrg
31168bf5c682Smrg			if (!mode) {
31178bf5c682Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
31188bf5c682Smrg					   "Failed to find mode for CRTC %d\n", c);
31198bf5c682Smrg				continue;
31208bf5c682Smrg			}
3121de2362d3Smrg			crtc->desiredMode = *mode;
3122de2362d3Smrg			crtc->desiredRotation = RR_Rotate_0;
3123de2362d3Smrg			crtc->desiredX = 0;
3124de2362d3Smrg			crtc->desiredY = 0;
3125de2362d3Smrg		}
3126de2362d3Smrg
312718781e08Smrg		if (set_hw) {
31288bf5c682Smrg			if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode,
31298bf5c682Smrg							crtc->desiredRotation,
31308bf5c682Smrg							crtc->desiredX,
31318bf5c682Smrg							crtc->desiredY)) {
31328bf5c682Smrg				num_on++;
31338bf5c682Smrg			} else {
31348bf5c682Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
31358bf5c682Smrg					   "Failed to set mode on CRTC %d\n", c);
313639413783Smrg				RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y,
313739413783Smrg					  crtc->rotation, 0, NULL);
31388bf5c682Smrg			}
313918781e08Smrg		} else {
314018781e08Smrg			crtc->mode = crtc->desiredMode;
314118781e08Smrg			crtc->rotation = crtc->desiredRotation;
314218781e08Smrg			crtc->x = crtc->desiredX;
314318781e08Smrg			crtc->y = crtc->desiredY;
31448bf5c682Smrg			if (drmmode_handle_transform(crtc))
31458bf5c682Smrg				num_on++;
314618781e08Smrg		}
3147de2362d3Smrg	}
31488bf5c682Smrg
31498bf5c682Smrg	if (num_on == 0 && num_desired > 0) {
31508bf5c682Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n");
31518bf5c682Smrg		return FALSE;
31528bf5c682Smrg	}
31538bf5c682Smrg
315439413783Smrg	/* Validate leases on VT re-entry */
3155446f62d6Smrg	if (dixPrivateKeyRegistered(rrPrivKey))
3156446f62d6Smrg	    drmmode_validate_leases(pScrn);
315739413783Smrg
3158de2362d3Smrg	return TRUE;
3159de2362d3Smrg}
3160de2362d3Smrg
316118781e08SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
3162de2362d3Smrg{
3163de2362d3Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
316439413783Smrg    int i;
3165de2362d3Smrg
316618781e08Smrg    if (xf86_config->num_crtc) {
316718781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
316818781e08Smrg		       "Initializing kms color map\n");
316918781e08Smrg	if (!miCreateDefColormap(pScreen))
317018781e08Smrg	    return FALSE;
31718bf5c682Smrg
31728bf5c682Smrg	/* All radeons support 10 bit CLUTs. They get bypassed at depth 30. */
317339413783Smrg	if (pScrn->depth != 30) {
317439413783Smrg	    if (!xf86HandleColormaps(pScreen, 256, 10, NULL, NULL,
317539413783Smrg				     CMAP_PALETTED_TRUECOLOR
317639413783Smrg				     | CMAP_RELOAD_ON_MODE_SWITCH))
317739413783Smrg		return FALSE;
317839413783Smrg
317939413783Smrg	    for (i = 0; i < xf86_config->num_crtc; i++) {
318039413783Smrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
318139413783Smrg
318239413783Smrg		drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red,
318339413783Smrg					  crtc->gamma_green,
318439413783Smrg					  crtc->gamma_blue,
318539413783Smrg					  crtc->gamma_size);
318639413783Smrg	    }
318739413783Smrg	}
318818781e08Smrg    }
318939413783Smrg
319018781e08Smrg    return TRUE;
319118781e08Smrg}
31927314432eSmrg
319318781e08Smrgstatic Bool
319418781e08Smrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi,
319518781e08Smrg		    int *num_hdmi)
319618781e08Smrg{
319718781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
319818781e08Smrg	int i;
31997314432eSmrg
320018781e08Smrg	for (i = 0; i < config->num_output; i++) {
320118781e08Smrg		xf86OutputPtr output = config->output[i];
320218781e08Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
320318781e08Smrg
320418781e08Smrg		if (drmmode_output->output_id == output_id) {
320518781e08Smrg			switch(drmmode_output->mode_output->connector_type) {
320618781e08Smrg			case DRM_MODE_CONNECTOR_DVII:
320718781e08Smrg			case DRM_MODE_CONNECTOR_DVID:
320818781e08Smrg			case DRM_MODE_CONNECTOR_DVIA:
320918781e08Smrg				(*num_dvi)++;
321018781e08Smrg				break;
321118781e08Smrg			case DRM_MODE_CONNECTOR_HDMIA:
321218781e08Smrg			case DRM_MODE_CONNECTOR_HDMIB:
321318781e08Smrg				(*num_hdmi)++;
321418781e08Smrg				break;
321518781e08Smrg			}
321618781e08Smrg
321718781e08Smrg			return TRUE;
321818781e08Smrg		}
321918781e08Smrg	}
322018781e08Smrg
322118781e08Smrg	return FALSE;
32227314432eSmrg}
32237314432eSmrg
322418781e08Smrgvoid
322518781e08Smrgradeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode)
32260d16fef4Smrg{
322718781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
322818781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
322918781e08Smrg	drmModeResPtr mode_res;
323018781e08Smrg	int i, j;
323118781e08Smrg	Bool found;
323218781e08Smrg	Bool changed = FALSE;
323318781e08Smrg	int num_dvi = 0, num_hdmi = 0;
323418781e08Smrg
32358bf5c682Smrg	/* Try to re-set the mode on all the connectors with a BAD link-state:
32368bf5c682Smrg	 * This may happen if a link degrades and a new modeset is necessary, using
32378bf5c682Smrg	 * different link-training parameters. If the kernel found that the current
32388bf5c682Smrg	 * mode is not achievable anymore, it should have pruned the mode before
32398bf5c682Smrg	 * sending the hotplug event. Try to re-set the currently-set mode to keep
32408bf5c682Smrg	 * the display alive, this will fail if the mode has been pruned.
32418bf5c682Smrg	 * In any case, we will send randr events for the Desktop Environment to
32428bf5c682Smrg	 * deal with it, if it wants to.
32438bf5c682Smrg	 */
32448bf5c682Smrg	for (i = 0; i < config->num_output; i++) {
32458bf5c682Smrg		xf86OutputPtr output = config->output[i];
32468bf5c682Smrg		xf86CrtcPtr crtc = output->crtc;
32478bf5c682Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
32488bf5c682Smrg
32498bf5c682Smrg		drmmode_output_detect(output);
32508bf5c682Smrg
32518bf5c682Smrg		if (!crtc || !drmmode_output->mode_output)
32528bf5c682Smrg			continue;
32538bf5c682Smrg
32548bf5c682Smrg		/* Get an updated view of the properties for the current connector and
32558bf5c682Smrg		 * look for the link-status property
32568bf5c682Smrg		 */
32578bf5c682Smrg		for (j = 0; j < drmmode_output->num_props; j++) {
32588bf5c682Smrg			drmmode_prop_ptr p = &drmmode_output->props[j];
32598bf5c682Smrg
32608bf5c682Smrg			if (!strcmp(p->mode_prop->name, "link-status")) {
32618bf5c682Smrg				if (p->value != DRM_MODE_LINK_STATUS_BAD)
32628bf5c682Smrg					break;
32638bf5c682Smrg
32648bf5c682Smrg				/* the connector got a link failure, re-set the current mode */
32658bf5c682Smrg				drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
32668bf5c682Smrg						       crtc->x, crtc->y);
32678bf5c682Smrg
32688bf5c682Smrg				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
32698bf5c682Smrg					   "hotplug event: connector %u's link-state is BAD, "
32708bf5c682Smrg					   "tried resetting the current mode. You may be left"
32718bf5c682Smrg					   "with a black screen if this fails...\n",
32728bf5c682Smrg					   drmmode_output->mode_output->connector_id);
32738bf5c682Smrg
32748bf5c682Smrg				break;
32758bf5c682Smrg			}
32768bf5c682Smrg		}
32778bf5c682Smrg	}
32788bf5c682Smrg
32798bf5c682Smrg	mode_res = drmModeGetResources(pRADEONEnt->fd);
328018781e08Smrg	if (!mode_res)
328118781e08Smrg		goto out;
328218781e08Smrg
328318781e08Smrgrestart_destroy:
328418781e08Smrg	for (i = 0; i < config->num_output; i++) {
328518781e08Smrg		xf86OutputPtr output = config->output[i];
328618781e08Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
328718781e08Smrg		found = FALSE;
328818781e08Smrg		for (j = 0; j < mode_res->count_connectors; j++) {
328918781e08Smrg			if (mode_res->connectors[j] == drmmode_output->output_id) {
329018781e08Smrg				found = TRUE;
329118781e08Smrg				break;
329218781e08Smrg			}
329318781e08Smrg		}
329418781e08Smrg		if (found)
329518781e08Smrg			continue;
329618781e08Smrg
329718781e08Smrg		drmModeFreeConnector(drmmode_output->mode_output);
329818781e08Smrg		drmmode_output->mode_output = NULL;
329918781e08Smrg		drmmode_output->output_id = -1;
330018781e08Smrg
330118781e08Smrg		changed = TRUE;
330218781e08Smrg		if (drmmode->delete_dp_12_displays) {
330318781e08Smrg			RROutputDestroy(output->randr_output);
330418781e08Smrg			xf86OutputDestroy(output);
330518781e08Smrg			goto restart_destroy;
330618781e08Smrg		}
330718781e08Smrg	}
330818781e08Smrg
330918781e08Smrg	/* find new output ids we don't have outputs for */
331018781e08Smrg	for (i = 0; i < mode_res->count_connectors; i++) {
3311446f62d6Smrg		for (j = 0; j < pRADEONEnt->num_scrns; j++) {
3312446f62d6Smrg			if (drmmode_find_output(pRADEONEnt->scrn[j],
3313446f62d6Smrg						mode_res->connectors[i],
3314446f62d6Smrg						&num_dvi, &num_hdmi))
3315446f62d6Smrg				break;
3316446f62d6Smrg		}
3317446f62d6Smrg
3318446f62d6Smrg		if (j < pRADEONEnt->num_scrns)
331918781e08Smrg			continue;
332018781e08Smrg
332118781e08Smrg		if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi,
332218781e08Smrg					&num_hdmi, 1) != 0)
332318781e08Smrg			changed = TRUE;
332418781e08Smrg	}
332518781e08Smrg
332639413783Smrg	/* Check to see if a lessee has disappeared */
332739413783Smrg	drmmode_validate_leases(scrn);
332839413783Smrg
3329446f62d6Smrg	if (changed) {
333018781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0)
333118781e08Smrg		RRSetChanged(xf86ScrnToScreen(scrn));
333218781e08Smrg#else
333318781e08Smrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen);
333418781e08Smrg		rrScrPriv->changed = TRUE;
33350d16fef4Smrg#endif
333618781e08Smrg		RRTellChanged(xf86ScrnToScreen(scrn));
333718781e08Smrg	}
33387821949aSmrg
333918781e08Smrg	drmModeFreeResources(mode_res);
334018781e08Smrgout:
334118781e08Smrg	RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
334218781e08Smrg}
3343de2362d3Smrg#ifdef HAVE_LIBUDEV
3344de2362d3Smrgstatic void
3345de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure)
3346de2362d3Smrg{
3347de2362d3Smrg	drmmode_ptr drmmode = closure;
3348de2362d3Smrg	ScrnInfoPtr scrn = drmmode->scrn;
3349de2362d3Smrg	struct udev_device *dev;
335018781e08Smrg	Bool received = FALSE;
33513ed65abbSmrg	struct timeval tv = { 0, 0 };
33523ed65abbSmrg	fd_set readfd;
33533ed65abbSmrg
33543ed65abbSmrg	FD_ZERO(&readfd);
33553ed65abbSmrg	FD_SET(fd, &readfd);
33563ed65abbSmrg
33573ed65abbSmrg	while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 &&
33583ed65abbSmrg	       FD_ISSET(fd, &readfd)) {
33593ed65abbSmrg		/* select() ensured that this will not block */
33603ed65abbSmrg		dev = udev_monitor_receive_device(drmmode->uevent_monitor);
33613ed65abbSmrg		if (dev) {
33623ed65abbSmrg			udev_device_unref(dev);
33633ed65abbSmrg			received = TRUE;
33643ed65abbSmrg		}
336518781e08Smrg	}
336618781e08Smrg
336718781e08Smrg	if (received)
336818781e08Smrg		radeon_mode_hotplug(scrn, drmmode);
3369de2362d3Smrg}
3370de2362d3Smrg#endif
3371de2362d3Smrg
3372de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3373de2362d3Smrg{
3374de2362d3Smrg#ifdef HAVE_LIBUDEV
3375de2362d3Smrg	struct udev *u;
3376de2362d3Smrg	struct udev_monitor *mon;
3377de2362d3Smrg
3378de2362d3Smrg	u = udev_new();
3379de2362d3Smrg	if (!u)
3380de2362d3Smrg		return;
3381de2362d3Smrg	mon = udev_monitor_new_from_netlink(u, "udev");
3382de2362d3Smrg	if (!mon) {
3383de2362d3Smrg		udev_unref(u);
3384de2362d3Smrg		return;
3385de2362d3Smrg	}
3386de2362d3Smrg
3387de2362d3Smrg	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
3388de2362d3Smrg							    "drm",
3389de2362d3Smrg							    "drm_minor") < 0 ||
3390de2362d3Smrg	    udev_monitor_enable_receiving(mon) < 0) {
3391de2362d3Smrg		udev_monitor_unref(mon);
3392de2362d3Smrg		udev_unref(u);
3393de2362d3Smrg		return;
3394de2362d3Smrg	}
3395de2362d3Smrg
3396de2362d3Smrg	drmmode->uevent_handler =
3397de2362d3Smrg		xf86AddGeneralHandler(udev_monitor_get_fd(mon),
3398de2362d3Smrg				      drmmode_handle_uevents,
3399de2362d3Smrg				      drmmode);
3400de2362d3Smrg
3401de2362d3Smrg	drmmode->uevent_monitor = mon;
3402de2362d3Smrg#endif
3403de2362d3Smrg}
3404de2362d3Smrg
3405de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3406de2362d3Smrg{
3407de2362d3Smrg#ifdef HAVE_LIBUDEV
3408de2362d3Smrg	if (drmmode->uevent_handler) {
3409de2362d3Smrg		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
3410de2362d3Smrg		xf86RemoveGeneralHandler(drmmode->uevent_handler);
3411de2362d3Smrg
3412de2362d3Smrg		udev_monitor_unref(drmmode->uevent_monitor);
3413de2362d3Smrg		udev_unref(u);
3414de2362d3Smrg	}
3415de2362d3Smrg#endif
3416de2362d3Smrg}
3417de2362d3Smrg
341818781e08SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
34198bf5c682Smrg			PixmapPtr new_front, uint64_t id, void *data,
34208bf5c682Smrg			xf86CrtcPtr ref_crtc, radeon_drm_handler_proc handler,
342118781e08Smrg			radeon_drm_abort_proc abort,
34223ed65abbSmrg			enum drmmode_flip_sync flip_sync,
34233ed65abbSmrg			uint32_t target_msc)
3424de2362d3Smrg{
34253ed65abbSmrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
3426de2362d3Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
342718781e08Smrg	xf86CrtcPtr crtc = NULL;
3428de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
3429446f62d6Smrg	int crtc_id;
34303ed65abbSmrg	uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0;
3431de2362d3Smrg	drmmode_flipdata_ptr flipdata;
343239413783Smrg	Bool handle_deferred = FALSE;
343318781e08Smrg	uintptr_t drm_queue_seq = 0;
343439413783Smrg	struct drmmode_fb *fb;
343539413783Smrg	int i = 0;
3436de2362d3Smrg
3437446f62d6Smrg	flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs *
343839413783Smrg			  sizeof(flipdata->fb[0]));
34397821949aSmrg        if (!flipdata) {
34407821949aSmrg             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
34417821949aSmrg                        "flip queue: data alloc failed.\n");
344218781e08Smrg             goto error;
34437821949aSmrg        }
344418781e08Smrg
344539413783Smrg	fb = radeon_pixmap_get_fb(new_front);
344639413783Smrg	if (!fb) {
34478bf5c682Smrg		ErrorF("Failed to get FB for flip\n");
344818781e08Smrg		goto error;
34498bf5c682Smrg	}
345018781e08Smrg
3451de2362d3Smrg	/*
3452de2362d3Smrg	 * Queue flips on all enabled CRTCs
3453de2362d3Smrg	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
3454de2362d3Smrg	 * Right now it assumes a single shared fb across all CRTCs, with the
3455de2362d3Smrg	 * kernel fixing up the offset of each CRTC as necessary.
3456de2362d3Smrg	 *
3457de2362d3Smrg	 * Also, flips queued on disabled or incorrectly configured displays
3458de2362d3Smrg	 * may never complete; this is a configuration error.
3459de2362d3Smrg	 */
3460de2362d3Smrg
3461de2362d3Smrg        flipdata->event_data = data;
346218781e08Smrg        flipdata->handler = handler;
346318781e08Smrg        flipdata->abort = abort;
34648bf5c682Smrg        flipdata->fe_crtc = ref_crtc;
346518781e08Smrg
3466de2362d3Smrg	for (i = 0; i < config->num_crtc; i++) {
346718781e08Smrg		crtc = config->crtc[i];
34688bf5c682Smrg		drmmode_crtc = crtc->driver_private;
3469446f62d6Smrg		crtc_id = drmmode_get_crtc_id(crtc);
347018781e08Smrg
34718bf5c682Smrg		if (!drmmode_crtc_can_flip(crtc) ||
34728bf5c682Smrg		    (drmmode_crtc->tear_free && crtc != ref_crtc))
3473de2362d3Smrg			continue;
3474de2362d3Smrg
3475de2362d3Smrg		flipdata->flip_count++;
347618781e08Smrg
347718781e08Smrg		drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id,
347818781e08Smrg						       flipdata,
347918781e08Smrg						       drmmode_flip_handler,
3480446f62d6Smrg						       drmmode_flip_abort,
3481446f62d6Smrg						       TRUE);
348218781e08Smrg		if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
348318781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
348418781e08Smrg				   "Allocating DRM queue event entry failed.\n");
348518781e08Smrg			goto error;
348618781e08Smrg		}
3487de2362d3Smrg
34888bf5c682Smrg		if (drmmode_crtc->tear_free) {
34898bf5c682Smrg			BoxRec extents = { .x1 = 0, .y1 = 0,
34908bf5c682Smrg					   .x2 = new_front->drawable.width,
34918bf5c682Smrg					   .y2 = new_front->drawable.height };
34928bf5c682Smrg			int scanout_id = drmmode_crtc->scanout_id ^ 1;
34938bf5c682Smrg
34948bf5c682Smrg			if (flip_sync == FLIP_ASYNC) {
34958bf5c682Smrg				if (!drmmode_wait_vblank(crtc,
34968bf5c682Smrg							 DRM_VBLANK_RELATIVE |
34978bf5c682Smrg							 DRM_VBLANK_EVENT,
34988bf5c682Smrg							 0, drm_queue_seq,
34998bf5c682Smrg							 NULL, NULL))
35008bf5c682Smrg					goto flip_error;
35018bf5c682Smrg				goto next;
35028bf5c682Smrg			}
35038bf5c682Smrg
3504446f62d6Smrg			drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[crtc_id],
350539413783Smrg					     radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap));
3506446f62d6Smrg			if (!flipdata->fb[crtc_id]) {
35078bf5c682Smrg				ErrorF("Failed to get FB for TearFree flip\n");
35088bf5c682Smrg				goto error;
35098bf5c682Smrg			}
35108bf5c682Smrg
35118bf5c682Smrg			radeon_scanout_do_update(crtc, scanout_id, new_front,
351239413783Smrg						 extents);
351339413783Smrg			radeon_cs_flush_indirect(crtc->scrn);
351439413783Smrg
351539413783Smrg			if (drmmode_crtc->scanout_update_pending) {
351639413783Smrg				radeon_drm_wait_pending_flip(crtc);
351739413783Smrg				handle_deferred = TRUE;
351839413783Smrg				radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending);
351939413783Smrg				drmmode_crtc->scanout_update_pending = 0;
352039413783Smrg			}
352139413783Smrg		} else {
3522446f62d6Smrg			drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[crtc_id], fb);
35238bf5c682Smrg		}
35248bf5c682Smrg
35258bf5c682Smrg		if (crtc == ref_crtc) {
35263ed65abbSmrg			if (drmmode_page_flip_target_absolute(pRADEONEnt,
35273ed65abbSmrg							      drmmode_crtc,
3528446f62d6Smrg							      flipdata->fb[crtc_id]->handle,
35293ed65abbSmrg							      flip_flags,
35303ed65abbSmrg							      drm_queue_seq,
35313ed65abbSmrg							      target_msc) != 0)
35323ed65abbSmrg				goto flip_error;
35333ed65abbSmrg		} else {
35343ed65abbSmrg			if (drmmode_page_flip_target_relative(pRADEONEnt,
35353ed65abbSmrg							      drmmode_crtc,
3536446f62d6Smrg							      flipdata->fb[crtc_id]->handle,
35373ed65abbSmrg							      flip_flags,
35383ed65abbSmrg							      drm_queue_seq, 0) != 0)
35393ed65abbSmrg				goto flip_error;
3540de2362d3Smrg		}
35413ed65abbSmrg
35428bf5c682Smrg		if (drmmode_crtc->tear_free) {
35438bf5c682Smrg			drmmode_crtc->scanout_id ^= 1;
35448bf5c682Smrg			drmmode_crtc->ignore_damage = TRUE;
35458bf5c682Smrg		}
35468bf5c682Smrg
354739413783Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending,
3548446f62d6Smrg				     flipdata->fb[crtc_id]);
3549446f62d6Smrg
3550446f62d6Smrg	next:
355118781e08Smrg		drm_queue_seq = 0;
3552de2362d3Smrg	}
3553de2362d3Smrg
355439413783Smrg	if (handle_deferred)
355539413783Smrg		radeon_drm_queue_handle_deferred(ref_crtc);
355618781e08Smrg	if (flipdata->flip_count > 0)
355718781e08Smrg		return TRUE;
35580d16fef4Smrg
35593ed65abbSmrgflip_error:
35603ed65abbSmrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n",
35613ed65abbSmrg		   strerror(errno));
35623ed65abbSmrg
356318781e08Smrgerror:
356418781e08Smrg	if (drm_queue_seq)
356518781e08Smrg		radeon_drm_abort_entry(drm_queue_seq);
356618781e08Smrg	else if (crtc)
356718781e08Smrg		drmmode_flip_abort(crtc, flipdata);
35683ed65abbSmrg	else {
35693ed65abbSmrg		abort(NULL, data);
357018781e08Smrg		free(flipdata);
35713ed65abbSmrg	}
3572de2362d3Smrg
3573de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
3574de2362d3Smrg		   strerror(errno));
357539413783Smrg	if (handle_deferred)
357639413783Smrg		radeon_drm_queue_handle_deferred(ref_crtc);
3577de2362d3Smrg	return FALSE;
3578de2362d3Smrg}
3579