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
48cd2eb4f7Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,99,1,0)
4918781e08Smrg#include <dri.h>
50cd2eb4f7Smrg#endif
51de2362d3Smrg
52de2362d3Smrg#include "drmmode_display.h"
53de2362d3Smrg
54de2362d3Smrg/* DPMS */
55de2362d3Smrg#ifdef HAVE_XEXTPROTO_71
56de2362d3Smrg#include <X11/extensions/dpmsconst.h>
57de2362d3Smrg#else
58de2362d3Smrg#define DPMS_SERVER
59de2362d3Smrg#include <X11/extensions/dpms.h>
60de2362d3Smrg#endif
61de2362d3Smrg
6218781e08Smrg#define DEFAULT_NOMINAL_FRAME_RATE 60
6318781e08Smrg
6418781e08Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 22
6518781e08Smrg#define HAVE_NOTIFY_FD	1
6618781e08Smrg#endif
6718781e08Smrg
6818781e08Smrgstatic Bool
6918781e08Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height);
7018781e08Smrg
7118781e08Smrgstatic Bool
7218781e08SmrgRADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name)
7318781e08Smrg{
7418781e08Smrg    int i = 0;
7518781e08Smrg    char s1[20];
7618781e08Smrg
7718781e08Smrg    do {
7818781e08Smrg	switch(*s) {
7918781e08Smrg	case ',':
8018781e08Smrg  	    s1[i] = '\0';
8118781e08Smrg	    i = 0;
8218781e08Smrg	    if (strcmp(s1, output_name) == 0)
8318781e08Smrg		return TRUE;
8418781e08Smrg	    break;
8518781e08Smrg	case ' ':
8618781e08Smrg	case '\t':
8718781e08Smrg	case '\n':
8818781e08Smrg	case '\r':
8918781e08Smrg	    break;
9018781e08Smrg	default:
9118781e08Smrg	    s1[i] = *s;
9218781e08Smrg	    i++;
9318781e08Smrg	    break;
9418781e08Smrg	}
9518781e08Smrg    } while(*s++);
9618781e08Smrg
9718781e08Smrg    s1[i] = '\0';
9818781e08Smrg    if (strcmp(s1, output_name) == 0)
9918781e08Smrg	return TRUE;
10018781e08Smrg
10118781e08Smrg    return FALSE;
10218781e08Smrg}
10318781e08Smrg
1048bf5c682Smrg
105de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
106de2362d3Smrg					  int width, int height,
107de2362d3Smrg					  int depth, int bpp,
10818781e08Smrg					  int pitch,
10939413783Smrg					  struct radeon_buffer *bo)
110de2362d3Smrg{
111de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
112de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
113de2362d3Smrg	PixmapPtr pixmap;
114de2362d3Smrg
11518781e08Smrg	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth,
11618781e08Smrg					  RADEON_CREATE_PIXMAP_SCANOUT);
117de2362d3Smrg	if (!pixmap)
118de2362d3Smrg		return NULL;
119de2362d3Smrg
1207314432eSmrg	if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height,
1217314432eSmrg					    depth, bpp, pitch, NULL)) {
12218781e08Smrg		goto fail;
1237314432eSmrg	}
1247314432eSmrg
12518781e08Smrg	if (!info->use_glamor)
12618781e08Smrg		exaMoveInPixmap(pixmap);
12718781e08Smrg
12818781e08Smrg	if (!radeon_set_pixmap_bo(pixmap, bo))
12918781e08Smrg		goto fail;
13018781e08Smrg
13139413783Smrg	if (info->surf_man && !info->use_glamor) {
13239413783Smrg		struct radeon_surface *surface = radeon_get_pixmap_surface(pixmap);
13339413783Smrg
13439413783Smrg		if (!radeon_surface_initialize(info, surface, width, height, bpp / 8,
13539413783Smrg					       radeon_get_pixmap_tiling_flags(pixmap), 0))
13639413783Smrg			goto fail;
137de2362d3Smrg	}
138de2362d3Smrg
13918781e08Smrg	if (!info->use_glamor ||
14039413783Smrg	    radeon_glamor_create_textured_pixmap(pixmap, bo))
14118781e08Smrg		return pixmap;
14218781e08Smrg
14318781e08Smrgfail:
14418781e08Smrg	pScreen->DestroyPixmap(pixmap);
14518781e08Smrg	return NULL;
146de2362d3Smrg}
147de2362d3Smrg
148de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
149de2362d3Smrg{
150de2362d3Smrg	ScreenPtr pScreen = pixmap->drawable.pScreen;
151de2362d3Smrg
152de2362d3Smrg	(*pScreen->DestroyPixmap)(pixmap);
153de2362d3Smrg}
154de2362d3Smrg
155de2362d3Smrgstatic void
156de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr	scrn,
157de2362d3Smrg		     drmModeModeInfo *kmode,
158de2362d3Smrg		     DisplayModePtr	mode)
159de2362d3Smrg{
160de2362d3Smrg	memset(mode, 0, sizeof(DisplayModeRec));
161de2362d3Smrg	mode->status = MODE_OK;
162de2362d3Smrg
163de2362d3Smrg	mode->Clock = kmode->clock;
164de2362d3Smrg
165de2362d3Smrg	mode->HDisplay = kmode->hdisplay;
166de2362d3Smrg	mode->HSyncStart = kmode->hsync_start;
167de2362d3Smrg	mode->HSyncEnd = kmode->hsync_end;
168de2362d3Smrg	mode->HTotal = kmode->htotal;
169de2362d3Smrg	mode->HSkew = kmode->hskew;
170de2362d3Smrg
171de2362d3Smrg	mode->VDisplay = kmode->vdisplay;
172de2362d3Smrg	mode->VSyncStart = kmode->vsync_start;
173de2362d3Smrg	mode->VSyncEnd = kmode->vsync_end;
174de2362d3Smrg	mode->VTotal = kmode->vtotal;
175de2362d3Smrg	mode->VScan = kmode->vscan;
176de2362d3Smrg
177de2362d3Smrg	mode->Flags = kmode->flags; //& FLAG_BITS;
178de2362d3Smrg	mode->name = strdup(kmode->name);
179de2362d3Smrg
180de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_DRIVER)
181de2362d3Smrg		mode->type = M_T_DRIVER;
182de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
183de2362d3Smrg		mode->type |= M_T_PREFERRED;
184de2362d3Smrg	xf86SetModeCrtc (mode, scrn->adjustFlags);
185de2362d3Smrg}
186de2362d3Smrg
187de2362d3Smrgstatic void
188de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr	scrn,
189de2362d3Smrg		     drmModeModeInfo *kmode,
190de2362d3Smrg		     DisplayModePtr	mode)
191de2362d3Smrg{
192de2362d3Smrg	memset(kmode, 0, sizeof(*kmode));
193de2362d3Smrg
194de2362d3Smrg	kmode->clock = mode->Clock;
195de2362d3Smrg	kmode->hdisplay = mode->HDisplay;
196de2362d3Smrg	kmode->hsync_start = mode->HSyncStart;
197de2362d3Smrg	kmode->hsync_end = mode->HSyncEnd;
198de2362d3Smrg	kmode->htotal = mode->HTotal;
199de2362d3Smrg	kmode->hskew = mode->HSkew;
200de2362d3Smrg
201de2362d3Smrg	kmode->vdisplay = mode->VDisplay;
202de2362d3Smrg	kmode->vsync_start = mode->VSyncStart;
203de2362d3Smrg	kmode->vsync_end = mode->VSyncEnd;
204de2362d3Smrg	kmode->vtotal = mode->VTotal;
205de2362d3Smrg	kmode->vscan = mode->VScan;
206de2362d3Smrg
207de2362d3Smrg	kmode->flags = mode->Flags; //& FLAG_BITS;
208de2362d3Smrg	if (mode->name)
209de2362d3Smrg		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
210de2362d3Smrg	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
211de2362d3Smrg
212de2362d3Smrg}
213de2362d3Smrg
2148bf5c682Smrg/*
2158bf5c682Smrg * Utility helper for drmWaitVBlank
2168bf5c682Smrg */
2178bf5c682SmrgBool
2188bf5c682Smrgdrmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type,
2198bf5c682Smrg		    uint32_t target_seq, unsigned long signal, uint64_t *ust,
2208bf5c682Smrg		    uint32_t *result_seq)
2218bf5c682Smrg{
2228bf5c682Smrg	int crtc_id = drmmode_get_crtc_id(crtc);
2238bf5c682Smrg	ScrnInfoPtr scrn = crtc->scrn;
2248bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
2258bf5c682Smrg	drmVBlank vbl;
2268bf5c682Smrg
2278bf5c682Smrg	if (crtc_id == 1)
2288bf5c682Smrg		type |= DRM_VBLANK_SECONDARY;
2298bf5c682Smrg	else if (crtc_id > 1)
2308bf5c682Smrg		type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) &
2318bf5c682Smrg			DRM_VBLANK_HIGH_CRTC_MASK;
2328bf5c682Smrg
2338bf5c682Smrg	vbl.request.type = type;
2348bf5c682Smrg	vbl.request.sequence = target_seq;
2358bf5c682Smrg	vbl.request.signal = signal;
2368bf5c682Smrg
2378bf5c682Smrg	if (drmWaitVBlank(pRADEONEnt->fd, &vbl) != 0)
2388bf5c682Smrg		return FALSE;
2398bf5c682Smrg
2408bf5c682Smrg	if (ust)
2418bf5c682Smrg		*ust = (uint64_t)vbl.reply.tval_sec * 1000000 +
2428bf5c682Smrg			vbl.reply.tval_usec;
2438bf5c682Smrg	if (result_seq)
2448bf5c682Smrg		*result_seq = vbl.reply.sequence;
2458bf5c682Smrg
2468bf5c682Smrg	return TRUE;
2478bf5c682Smrg}
2488bf5c682Smrg
24918781e08Smrg/*
25018781e08Smrg * Retrieves present time in microseconds that is compatible
25118781e08Smrg * with units used by vblank timestamps. Depending on the kernel
25218781e08Smrg * version and DRM kernel module configuration, the vblank
25318781e08Smrg * timestamp can either be in real time or monotonic time
25418781e08Smrg */
25518781e08Smrgint drmmode_get_current_ust(int drm_fd, CARD64 *ust)
25618781e08Smrg{
25718781e08Smrg	uint64_t cap_value;
25818781e08Smrg	int ret;
25918781e08Smrg	struct timespec now;
26018781e08Smrg
26118781e08Smrg	ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value);
26218781e08Smrg	if (ret || !cap_value)
26318781e08Smrg		/* old kernel or drm_timestamp_monotonic turned off */
26418781e08Smrg		ret = clock_gettime(CLOCK_REALTIME, &now);
26518781e08Smrg	else
26618781e08Smrg		ret = clock_gettime(CLOCK_MONOTONIC, &now);
26718781e08Smrg	if (ret)
26818781e08Smrg		return ret;
26918781e08Smrg	*ust = ((CARD64)now.tv_sec * 1000000) + ((CARD64)now.tv_nsec / 1000);
27018781e08Smrg	return 0;
27118781e08Smrg}
27218781e08Smrg
27318781e08Smrg/*
27418781e08Smrg * Get current frame count and frame count timestamp of the crtc.
27518781e08Smrg */
27618781e08Smrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)
27718781e08Smrg{
27818781e08Smrg    ScrnInfoPtr scrn = crtc->scrn;
2798bf5c682Smrg    uint32_t seq;
28018781e08Smrg
2818bf5c682Smrg    if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) {
28218781e08Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
28318781e08Smrg		   "get vblank counter failed: %s\n", strerror(errno));
2848bf5c682Smrg	return -1;
28518781e08Smrg    }
28618781e08Smrg
2878bf5c682Smrg    *msc = seq;
28818781e08Smrg
28918781e08Smrg    return Success;
29018781e08Smrg}
29118781e08Smrg
292de2362d3Smrgstatic void
29318781e08Smrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
294de2362d3Smrg{
295de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
29618781e08Smrg	ScrnInfoPtr scrn = crtc->scrn;
2978bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
29818781e08Smrg	CARD64 ust;
29918781e08Smrg	int ret;
3007314432eSmrg
30118781e08Smrg	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
3028bf5c682Smrg		uint32_t seq;
30318781e08Smrg
30439413783Smrg		radeon_drm_wait_pending_flip(crtc);
30518781e08Smrg
30618781e08Smrg		/*
30718781e08Smrg		 * On->Off transition: record the last vblank time,
30818781e08Smrg		 * sequence number and frame period.
30918781e08Smrg		 */
3108bf5c682Smrg		if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust,
3118bf5c682Smrg					 &seq))
31218781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
31318781e08Smrg				   "%s cannot get last vblank counter\n",
31418781e08Smrg				   __func__);
31518781e08Smrg		else {
31618781e08Smrg			CARD64 nominal_frame_rate, pix_in_frame;
31718781e08Smrg
31818781e08Smrg			drmmode_crtc->dpms_last_ust = ust;
31918781e08Smrg			drmmode_crtc->dpms_last_seq = seq;
32018781e08Smrg			nominal_frame_rate = crtc->mode.Clock;
32118781e08Smrg			nominal_frame_rate *= 1000;
32218781e08Smrg			pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal;
32318781e08Smrg			if (nominal_frame_rate == 0 || pix_in_frame == 0)
32418781e08Smrg				nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE;
32518781e08Smrg			else
32618781e08Smrg				nominal_frame_rate /= pix_in_frame;
32718781e08Smrg			drmmode_crtc->dpms_last_fps = nominal_frame_rate;
32818781e08Smrg		}
32939413783Smrg
33039413783Smrg		drmmode_crtc->dpms_mode = mode;
33139413783Smrg		radeon_drm_queue_handle_deferred(crtc);
33218781e08Smrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) {
33318781e08Smrg		/*
33418781e08Smrg		 * Off->On transition: calculate and accumulate the
33518781e08Smrg		 * number of interpolated vblanks while we were in Off state
33618781e08Smrg		 */
3378bf5c682Smrg		ret = drmmode_get_current_ust(pRADEONEnt->fd, &ust);
33818781e08Smrg		if (ret)
33918781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
34018781e08Smrg				   "%s cannot get current time\n", __func__);
34118781e08Smrg		else if (drmmode_crtc->dpms_last_ust) {
34218781e08Smrg			CARD64 time_elapsed, delta_seq;
34318781e08Smrg			time_elapsed = ust - drmmode_crtc->dpms_last_ust;
34418781e08Smrg			delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps;
34518781e08Smrg			delta_seq /= 1000000;
34618781e08Smrg			drmmode_crtc->interpolated_vblanks += delta_seq;
34718781e08Smrg
34818781e08Smrg		}
34939413783Smrg
35039413783Smrg		drmmode_crtc->dpms_mode = DPMSModeOn;
3517821949aSmrg	}
35218781e08Smrg}
35318781e08Smrg
35418781e08Smrgstatic void
35518781e08Smrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
35618781e08Smrg{
35718781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3588bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
35918781e08Smrg
36018781e08Smrg	/* Disable unused CRTCs */
36118781e08Smrg	if (!crtc->enabled || mode != DPMSModeOn) {
36239413783Smrg		drmmode_do_crtc_dpms(crtc, DPMSModeOff);
3638bf5c682Smrg		drmModeSetCrtc(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
36418781e08Smrg			       0, 0, 0, NULL, 0, NULL);
3658bf5c682Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL);
36618781e08Smrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn)
36718781e08Smrg		crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
36818781e08Smrg					    crtc->x, crtc->y);
369de2362d3Smrg}
370de2362d3Smrg
371de2362d3Smrgstatic PixmapPtr
372de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode,
373de2362d3Smrg			ScrnInfoPtr pScrn, int fbcon_id)
374de2362d3Smrg{
3758bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
37618781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
37718781e08Smrg	PixmapPtr pixmap = info->fbcon_pixmap;
378b338b52fSmrg	struct radeon_buffer *bo = NULL;
379de2362d3Smrg	drmModeFBPtr fbcon;
380de2362d3Smrg	struct drm_gem_flink flink;
381de2362d3Smrg
38218781e08Smrg	if (pixmap)
38318781e08Smrg	    return pixmap;
38418781e08Smrg
3858bf5c682Smrg	fbcon = drmModeGetFB(pRADEONEnt->fd, fbcon_id);
38639413783Smrg	if (!fbcon)
387de2362d3Smrg		return NULL;
388de2362d3Smrg
389de2362d3Smrg	if (fbcon->depth != pScrn->depth ||
390de2362d3Smrg	    fbcon->width != pScrn->virtualX ||
391de2362d3Smrg	    fbcon->height != pScrn->virtualY)
392de2362d3Smrg		goto out_free_fb;
393de2362d3Smrg
394de2362d3Smrg	flink.handle = fbcon->handle;
3958bf5c682Smrg	if (ioctl(pRADEONEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
396de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
397de2362d3Smrg			   "Couldn't flink fbcon handle\n");
398de2362d3Smrg		goto out_free_fb;
399de2362d3Smrg	}
400de2362d3Smrg
40139413783Smrg	bo = calloc(1, sizeof(struct radeon_buffer));
40239413783Smrg	if (!bo) {
403de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
40439413783Smrg			   "Couldn't allocate BO for fbcon handle\n");
40539413783Smrg		goto out_free_fb;
40639413783Smrg	}
40739413783Smrg	bo->ref_count = 1;
40839413783Smrg
40939413783Smrg	bo->bo.radeon = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0);
410b338b52fSmrg	if (!bo->bo.radeon) {
41139413783Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
41239413783Smrg			   "Couldn't open BO for fbcon handle\n");
413de2362d3Smrg		goto out_free_fb;
414de2362d3Smrg	}
415de2362d3Smrg
416de2362d3Smrg	pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height,
41718781e08Smrg					  fbcon->depth, fbcon->bpp, fbcon->pitch,
41839413783Smrg					  bo);
41918781e08Smrg	info->fbcon_pixmap = pixmap;
420de2362d3Smrgout_free_fb:
421b338b52fSmrg	radeon_buffer_unref(&bo);
422de2362d3Smrg	drmModeFreeFB(fbcon);
423de2362d3Smrg	return pixmap;
424de2362d3Smrg}
425de2362d3Smrg
42618781e08Smrgstatic void
42718781e08Smrgdestroy_pixmap_for_fbcon(ScrnInfoPtr pScrn)
42818781e08Smrg{
42918781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
43018781e08Smrg
43118781e08Smrg	/* XXX: The current GPUVM support in the kernel doesn't allow removing
43218781e08Smrg	 * the virtual address range for this BO, so we need to keep around
43318781e08Smrg	 * the pixmap to avoid breaking glamor with GPUVM
43439413783Smrg	 *
43539413783Smrg	 * Similarly, need to keep around the pixmap with current glamor, to
43639413783Smrg	 * avoid issues due to a GEM handle lifetime conflict between us and
43739413783Smrg	 * Mesa
43818781e08Smrg	 */
43939413783Smrg	if (info->use_glamor &&
44039413783Smrg	    (info->ChipFamily >= CHIP_FAMILY_CAYMAN ||
44139413783Smrg	     xorgGetVersion() >= XORG_VERSION_NUMERIC(1,19,99,1,0)))
44218781e08Smrg		return;
44318781e08Smrg
44418781e08Smrg	if (info->fbcon_pixmap)
44518781e08Smrg		pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap);
44618781e08Smrg	info->fbcon_pixmap = NULL;
44718781e08Smrg}
44818781e08Smrg
449de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
450de2362d3Smrg{
451de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
452de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
453de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
4548bf5c682Smrg	PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen);
4558bf5c682Smrg	struct drmmode_fb *fb = radeon_pixmap_get_fb(dst);
456de2362d3Smrg	int fbcon_id = 0;
45718781e08Smrg	Bool force;
45818781e08Smrg	GCPtr gc;
459de2362d3Smrg	int i;
460de2362d3Smrg
461de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
462de2362d3Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
463de2362d3Smrg
464de2362d3Smrg		if (drmmode_crtc->mode_crtc->buffer_id)
465de2362d3Smrg			fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
466de2362d3Smrg	}
467de2362d3Smrg
468de2362d3Smrg	if (!fbcon_id)
46918781e08Smrg		return;
47018781e08Smrg
4718bf5c682Smrg	if (fbcon_id == fb->handle) {
47218781e08Smrg		/* in some rare case there might be no fbcon and we might already
47318781e08Smrg		 * be the one with the current fb to avoid a false deadlck in
47418781e08Smrg		 * kernel ttm code just do nothing as anyway there is nothing
47518781e08Smrg		 * to do
47618781e08Smrg		 */
47718781e08Smrg		return;
47818781e08Smrg	}
479de2362d3Smrg
480de2362d3Smrg	src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
481de2362d3Smrg	if (!src)
48218781e08Smrg		return;
4830d16fef4Smrg
48418781e08Smrg	gc = GetScratchGC(pScrn->depth, pScreen);
48518781e08Smrg	ValidateGC(&dst->drawable, gc);
48618781e08Smrg
48718781e08Smrg	force = info->accel_state->force;
48818781e08Smrg	info->accel_state->force = TRUE;
48918781e08Smrg	(*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0,
49018781e08Smrg			     pScrn->virtualX, pScrn->virtualY, 0, 0);
49118781e08Smrg	info->accel_state->force = force;
49218781e08Smrg
49318781e08Smrg	FreeScratchGC(gc);
494de2362d3Smrg
495de2362d3Smrg	pScreen->canDoBGNoneRoot = TRUE;
49618781e08Smrg	destroy_pixmap_for_fbcon(pScrn);
4977821949aSmrg	return;
49818781e08Smrg}
4990d16fef4Smrg
5008bf5c682Smrgvoid
50118781e08Smrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
50218781e08Smrg			     struct drmmode_scanout *scanout)
50318781e08Smrg{
50418781e08Smrg	if (scanout->pixmap) {
50518781e08Smrg		drmmode_destroy_bo_pixmap(scanout->pixmap);
50618781e08Smrg		scanout->pixmap = NULL;
50718781e08Smrg	}
50818781e08Smrg
50939413783Smrg	radeon_buffer_unref(&scanout->bo);
51018781e08Smrg}
51118781e08Smrg
5128bf5c682Smrgvoid
513446f62d6Smrgdrmmode_crtc_scanout_free(xf86CrtcPtr crtc)
51418781e08Smrg{
515446f62d6Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
516446f62d6Smrg
517446f62d6Smrg	if (drmmode_crtc->scanout_update_pending) {
518446f62d6Smrg		radeon_drm_wait_pending_flip(crtc);
519446f62d6Smrg		radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending);
520446f62d6Smrg		drmmode_crtc->scanout_update_pending = 0;
521446f62d6Smrg		radeon_drm_queue_handle_deferred(crtc);
522446f62d6Smrg	}
523446f62d6Smrg
5248bf5c682Smrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
5258bf5c682Smrg				     &drmmode_crtc->scanout[0]);
5268bf5c682Smrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
5278bf5c682Smrg				     &drmmode_crtc->scanout[1]);
52818781e08Smrg
5298bf5c682Smrg	if (drmmode_crtc->scanout_damage)
53018781e08Smrg		DamageDestroy(drmmode_crtc->scanout_damage);
53118781e08Smrg}
53218781e08Smrg
5338bf5c682SmrgPixmapPtr
5343ed65abbSmrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
5353ed65abbSmrg			    int width, int height)
53618781e08Smrg{
53718781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
53818781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
53918781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
54018781e08Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
54118781e08Smrg	struct radeon_surface surface;
54218781e08Smrg	uint32_t tiling = RADEON_CREATE_PIXMAP_TILING_MACRO;
54318781e08Smrg	int pitch;
54418781e08Smrg
5453ed65abbSmrg	if (scanout->pixmap) {
54618781e08Smrg		if (scanout->width == width && scanout->height == height)
5473ed65abbSmrg			return scanout->pixmap;
54818781e08Smrg
54918781e08Smrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
55018781e08Smrg	}
55118781e08Smrg
55218781e08Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600)
55318781e08Smrg		tiling |= RADEON_CREATE_PIXMAP_TILING_MICRO;
55418781e08Smrg	scanout->bo = radeon_alloc_pixmap_bo(pScrn, width, height, pScrn->depth,
55518781e08Smrg					     tiling, pScrn->bitsPerPixel,
55618781e08Smrg					     &pitch, &surface, &tiling);
5578bf5c682Smrg	if (!scanout->bo) {
5588bf5c682Smrg		ErrorF("failed to create CRTC scanout BO\n");
5598bf5c682Smrg		return NULL;
56018781e08Smrg	}
56118781e08Smrg
56218781e08Smrg	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
56318781e08Smrg						 width, height,
56418781e08Smrg						 pScrn->depth,
56518781e08Smrg						 pScrn->bitsPerPixel,
56639413783Smrg						 pitch, scanout->bo);
5678bf5c682Smrg	if (!scanout->pixmap) {
5688bf5c682Smrg		ErrorF("failed to create CRTC scanout pixmap\n");
5698bf5c682Smrg		goto error;
5708bf5c682Smrg	}
5718bf5c682Smrg
5728bf5c682Smrg	if (radeon_pixmap_get_fb(scanout->pixmap)) {
5733ed65abbSmrg		scanout->width = width;
5743ed65abbSmrg		scanout->height = height;
5753ed65abbSmrg	} else {
5768bf5c682Smrg		ErrorF("failed to create CRTC scanout FB\n");
5778bf5c682Smrgerror:
5783ed65abbSmrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
5793ed65abbSmrg	}
58018781e08Smrg
58118781e08Smrg	return scanout->pixmap;
58218781e08Smrg}
58318781e08Smrg
58418781e08Smrgstatic void
58518781e08Smrgradeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
58618781e08Smrg{
5878bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = closure;
5888bf5c682Smrg
5898bf5c682Smrg	if (drmmode_crtc->ignore_damage) {
5908bf5c682Smrg		RegionEmpty(&damage->damage);
5918bf5c682Smrg		drmmode_crtc->ignore_damage = FALSE;
5928bf5c682Smrg		return;
5938bf5c682Smrg	}
5948bf5c682Smrg
59518781e08Smrg	/* Only keep track of the extents */
59618781e08Smrg	RegionUninit(&damage->damage);
59718781e08Smrg	damage->damage.data = NULL;
59818781e08Smrg}
59918781e08Smrg
6008bf5c682Smrgstatic void
6018bf5c682Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure)
6028bf5c682Smrg{
6038bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = closure;
6048bf5c682Smrg
6058bf5c682Smrg	drmmode_crtc->scanout_damage = NULL;
6068bf5c682Smrg	RegionUninit(&drmmode_crtc->scanout_last_region);
6078bf5c682Smrg}
6088bf5c682Smrg
60918781e08Smrgstatic Bool
61018781e08Smrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc)
61118781e08Smrg{
61218781e08Smrg	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
61318781e08Smrg
61418781e08Smrg	/* Check for Option "SWcursor" */
61518781e08Smrg	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
61618781e08Smrg		return FALSE;
61718781e08Smrg
61818781e08Smrg	/* Fall back to SW cursor if the CRTC is transformed */
61918781e08Smrg	if (crtc->transformPresent)
62018781e08Smrg		return FALSE;
6210d16fef4Smrg
6228bf5c682Smrg#if XF86_CRTC_VERSION < 7
62318781e08Smrg	/* Xorg doesn't correctly handle cursor position transform in the
62418781e08Smrg	 * rotation case
62518781e08Smrg	 */
62618781e08Smrg	if (crtc->driverIsPerformingTransform &&
62718781e08Smrg	    (crtc->rotation & 0xf) != RR_Rotate_0)
62818781e08Smrg		return FALSE;
62918781e08Smrg#endif
63018781e08Smrg
63118781e08Smrg	/* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */
63218781e08Smrg	if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) &&
63318781e08Smrg	    !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list))
63418781e08Smrg		return FALSE;
63518781e08Smrg
63618781e08Smrg	return TRUE;
63718781e08Smrg}
63818781e08Smrg
6393ed65abbSmrgstatic void
6403ed65abbSmrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc)
6413ed65abbSmrg{
6423ed65abbSmrg	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
6433ed65abbSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
6443ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
6453ed65abbSmrg	int i;
6463ed65abbSmrg
6473ed65abbSmrg	drmmode_crtc->tear_free = FALSE;
6483ed65abbSmrg
6493ed65abbSmrg	for (i = 0; i < xf86_config->num_output; i++) {
6503ed65abbSmrg		xf86OutputPtr output = xf86_config->output[i];
6513ed65abbSmrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
6523ed65abbSmrg
6533ed65abbSmrg		if (output->crtc != crtc)
6543ed65abbSmrg			continue;
6553ed65abbSmrg
6563ed65abbSmrg		if (drmmode_output->tear_free == 1 ||
6573ed65abbSmrg		    (drmmode_output->tear_free == 2 &&
6588bf5c682Smrg		     (crtc->scrn->pScreen->isGPU ||
6593ed65abbSmrg		      info->shadow_primary ||
6603ed65abbSmrg		      crtc->transformPresent || crtc->rotation != RR_Rotate_0))) {
6613ed65abbSmrg			drmmode_crtc->tear_free = TRUE;
6623ed65abbSmrg			return;
6633ed65abbSmrg		}
6643ed65abbSmrg	}
6653ed65abbSmrg}
6663ed65abbSmrg
6673ed65abbSmrg#if XF86_CRTC_VERSION < 7
6683ed65abbSmrg#define XF86DriverTransformOutput TRUE
6693ed65abbSmrg#define XF86DriverTransformNone FALSE
6703ed65abbSmrg#endif
6713ed65abbSmrg
67218781e08Smrgstatic Bool
67318781e08Smrgdrmmode_handle_transform(xf86CrtcPtr crtc)
67418781e08Smrg{
67518781e08Smrg	Bool ret;
67618781e08Smrg
6778bf5c682Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
67839413783Smrg	crtc->driverIsPerformingTransform = XF86DriverTransformOutput;
6798bf5c682Smrg#else
6808bf5c682Smrg	crtc->driverIsPerformingTransform = !crtc->transformPresent &&
6818bf5c682Smrg		(crtc->rotation & 0xf) == RR_Rotate_0;
6828bf5c682Smrg#endif
68318781e08Smrg
68418781e08Smrg	ret = xf86CrtcRotate(crtc);
68518781e08Smrg
68618781e08Smrg	crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use;
68718781e08Smrg
68818781e08Smrg	return ret;
6890d16fef4Smrg}
6900d16fef4Smrg
6913ed65abbSmrg
6923ed65abbSmrgstatic void
6933ed65abbSmrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
6948bf5c682Smrg				  unsigned scanout_id, struct drmmode_fb **fb,
6958bf5c682Smrg				  int *x, int *y)
6963ed65abbSmrg{
6973ed65abbSmrg	ScrnInfoPtr scrn = crtc->scrn;
6983ed65abbSmrg	ScreenPtr screen = scrn->pScreen;
6993ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
7003ed65abbSmrg
7013ed65abbSmrg	if (drmmode_crtc->tear_free &&
7023ed65abbSmrg	    !drmmode_crtc->scanout[1].pixmap) {
7033ed65abbSmrg		RegionPtr region;
7043ed65abbSmrg		BoxPtr box;
7053ed65abbSmrg
7063ed65abbSmrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
7073ed65abbSmrg					    mode->HDisplay,
7083ed65abbSmrg					    mode->VDisplay);
7093ed65abbSmrg		region = &drmmode_crtc->scanout_last_region;
7103ed65abbSmrg		RegionUninit(region);
7113ed65abbSmrg		region->data = NULL;
7123ed65abbSmrg		box = RegionExtents(region);
7133ed65abbSmrg		box->x1 = crtc->x;
7143ed65abbSmrg		box->y1 = crtc->y;
7153ed65abbSmrg		box->x2 = crtc->x + mode->HDisplay;
7163ed65abbSmrg		box->y2 = crtc->y + mode->VDisplay;
7173ed65abbSmrg	}
7183ed65abbSmrg
7193ed65abbSmrg	if (scanout_id != drmmode_crtc->scanout_id) {
7203ed65abbSmrg		PixmapDirtyUpdatePtr dirty = NULL;
7213ed65abbSmrg
7223ed65abbSmrg		xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list,
7233ed65abbSmrg					 ent) {
7248bf5c682Smrg			if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
725cd2eb4f7Smrg				dirty->secondary_dst =
7263ed65abbSmrg					drmmode_crtc->scanout[scanout_id].pixmap;
7273ed65abbSmrg				break;
7283ed65abbSmrg			}
7293ed65abbSmrg		}
7303ed65abbSmrg
7313ed65abbSmrg		if (!drmmode_crtc->tear_free) {
7323ed65abbSmrg			GCPtr gc = GetScratchGC(scrn->depth, screen);
7333ed65abbSmrg
7343ed65abbSmrg			ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc);
7353ed65abbSmrg			gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable,
7363ed65abbSmrg					  &drmmode_crtc->scanout[0].pixmap->drawable,
7373ed65abbSmrg					  gc, 0, 0, mode->HDisplay, mode->VDisplay,
7383ed65abbSmrg					  0, 0);
7393ed65abbSmrg			FreeScratchGC(gc);
74039413783Smrg			radeon_finish(scrn, drmmode_crtc->scanout[0].bo);
7413ed65abbSmrg		}
7423ed65abbSmrg	}
7433ed65abbSmrg
7448bf5c682Smrg	*fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
7453ed65abbSmrg	*x = *y = 0;
7463ed65abbSmrg	drmmode_crtc->scanout_id = scanout_id;
7473ed65abbSmrg}
7483ed65abbSmrg
7493ed65abbSmrg
7503ed65abbSmrgstatic void
7513ed65abbSmrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
7528bf5c682Smrg			    unsigned scanout_id, struct drmmode_fb **fb, int *x,
7538bf5c682Smrg			    int *y)
7543ed65abbSmrg{
7553ed65abbSmrg	ScrnInfoPtr scrn = crtc->scrn;
7563ed65abbSmrg	ScreenPtr screen = scrn->pScreen;
7573ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
7583ed65abbSmrg
7598bf5c682Smrg	drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id],
7603ed65abbSmrg				    mode->HDisplay, mode->VDisplay);
7613ed65abbSmrg	if (drmmode_crtc->tear_free) {
7628bf5c682Smrg		drmmode_crtc_scanout_create(crtc,
7638bf5c682Smrg					    &drmmode_crtc->scanout[scanout_id ^ 1],
7643ed65abbSmrg					    mode->HDisplay, mode->VDisplay);
7653ed65abbSmrg	}
7663ed65abbSmrg
7678bf5c682Smrg	if (drmmode_crtc->scanout[scanout_id].pixmap &&
7688bf5c682Smrg	    (!drmmode_crtc->tear_free ||
7698bf5c682Smrg	     drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) {
77039413783Smrg		BoxRec extents = { .x1 = 0, .y1 = 0,
77139413783Smrg				   .x2 = scrn->virtualX, .y2 = scrn->virtualY };
7723ed65abbSmrg
7733ed65abbSmrg		if (!drmmode_crtc->scanout_damage) {
7743ed65abbSmrg			drmmode_crtc->scanout_damage =
7753ed65abbSmrg				DamageCreate(radeon_screen_damage_report,
7768bf5c682Smrg					     drmmode_screen_damage_destroy,
7778bf5c682Smrg					     DamageReportRawRegion,
7788bf5c682Smrg					     TRUE, screen, drmmode_crtc);
7798bf5c682Smrg			DamageRegister(&screen->root->drawable,
7803ed65abbSmrg				       drmmode_crtc->scanout_damage);
7813ed65abbSmrg		}
7823ed65abbSmrg
7838bf5c682Smrg		*fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
7843ed65abbSmrg		*x = *y = 0;
7853ed65abbSmrg
786446f62d6Smrg		if (radeon_scanout_do_update(crtc, scanout_id,
787446f62d6Smrg					     screen->GetWindowPixmap(screen->root),
788446f62d6Smrg					     extents)) {
789446f62d6Smrg			RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage));
790446f62d6Smrg			radeon_finish(scrn, drmmode_crtc->scanout[scanout_id].bo);
791446f62d6Smrg
792446f62d6Smrg			if (!drmmode_crtc->flip_pending) {
793446f62d6Smrg				radeon_drm_abort_entry(drmmode_crtc->
794446f62d6Smrg						       scanout_update_pending);
795446f62d6Smrg			}
796446f62d6Smrg		}
7973ed65abbSmrg	}
7983ed65abbSmrg}
7993ed65abbSmrg
8008bf5c682Smrgstatic void
8018bf5c682Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
8028bf5c682Smrg			  uint16_t *blue, int size)
8038bf5c682Smrg{
8048bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
8058bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
8068bf5c682Smrg
8078bf5c682Smrg	drmModeCrtcSetGamma(pRADEONEnt->fd,
8088bf5c682Smrg			    drmmode_crtc->mode_crtc->crtc_id, size, red, green,
8098bf5c682Smrg			    blue);
8108bf5c682Smrg}
8118bf5c682Smrg
8128bf5c682SmrgBool
8138bf5c682Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode,
8148bf5c682Smrg		 int x, int y)
8158bf5c682Smrg{
8168bf5c682Smrg	ScrnInfoPtr scrn = crtc->scrn;
8178bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
8188bf5c682Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
8198bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
8208bf5c682Smrg	uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
8218bf5c682Smrg	int output_count = 0;
8228bf5c682Smrg	drmModeModeInfo kmode;
8238bf5c682Smrg	Bool ret;
8248bf5c682Smrg	int i;
8258bf5c682Smrg
8268bf5c682Smrg	if (!output_ids)
8278bf5c682Smrg		return FALSE;
8288bf5c682Smrg
8298bf5c682Smrg	for (i = 0; i < xf86_config->num_output; i++) {
8308bf5c682Smrg		xf86OutputPtr output = xf86_config->output[i];
8318bf5c682Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
8328bf5c682Smrg
8338bf5c682Smrg		if (output->crtc != crtc)
8348bf5c682Smrg			continue;
8358bf5c682Smrg
8368bf5c682Smrg		output_ids[output_count] = drmmode_output->mode_output->connector_id;
8378bf5c682Smrg		output_count++;
8388bf5c682Smrg	}
8398bf5c682Smrg
8408bf5c682Smrg	drmmode_ConvertToKMode(scrn, &kmode, mode);
8418bf5c682Smrg
8428bf5c682Smrg	ret = drmModeSetCrtc(pRADEONEnt->fd,
8438bf5c682Smrg			     drmmode_crtc->mode_crtc->crtc_id,
8448bf5c682Smrg			     fb->handle, x, y, output_ids,
8458bf5c682Smrg			     output_count, &kmode) == 0;
8468bf5c682Smrg
8478bf5c682Smrg	if (ret) {
8488bf5c682Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, fb);
8498bf5c682Smrg	} else {
8508bf5c682Smrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
8518bf5c682Smrg			   "failed to set mode: %s\n", strerror(errno));
8528bf5c682Smrg	}
8538bf5c682Smrg
8548bf5c682Smrg	free(output_ids);
8558bf5c682Smrg	return ret;
8568bf5c682Smrg}
8578bf5c682Smrg
858de2362d3Smrgstatic Bool
859de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
860de2362d3Smrg		     Rotation rotation, int x, int y)
861de2362d3Smrg{
862de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
86318781e08Smrg	ScreenPtr pScreen = pScrn->pScreen;
864de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
8658bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
866de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
867de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
868446f62d6Smrg	Bool handle_deferred = FALSE;
8693ed65abbSmrg	unsigned scanout_id = 0;
870de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
871de2362d3Smrg	int saved_x, saved_y;
872de2362d3Smrg	Rotation saved_rotation;
873de2362d3Smrg	DisplayModeRec saved_mode;
87418781e08Smrg	Bool ret = FALSE;
875d1d00eb7Sjmcneill	uint32_t handle;
876de2362d3Smrg	int i;
8778bf5c682Smrg	struct drmmode_fb *fb = NULL;
8788bf5c682Smrg
8798bf5c682Smrg	/* The root window contents may be undefined before the WindowExposures
8808bf5c682Smrg	 * hook is called for it, so bail if we get here before that
8818bf5c682Smrg	 */
8828bf5c682Smrg	if (pScreen->WindowExposures == RADEONWindowExposures_oneshot)
8838bf5c682Smrg		return FALSE;
884de2362d3Smrg
885de2362d3Smrg	saved_mode = crtc->mode;
886de2362d3Smrg	saved_x = crtc->x;
887de2362d3Smrg	saved_y = crtc->y;
888de2362d3Smrg	saved_rotation = crtc->rotation;
889de2362d3Smrg
890de2362d3Smrg	if (mode) {
891de2362d3Smrg		crtc->mode = *mode;
892de2362d3Smrg		crtc->x = x;
893de2362d3Smrg		crtc->y = y;
894de2362d3Smrg		crtc->rotation = rotation;
895de2362d3Smrg
89618781e08Smrg		if (!drmmode_handle_transform(crtc))
897de2362d3Smrg			goto done;
89818781e08Smrg
8993ed65abbSmrg		drmmode_crtc_update_tear_free(crtc);
9003ed65abbSmrg		if (drmmode_crtc->tear_free)
9013ed65abbSmrg			scanout_id = drmmode_crtc->scanout_id;
90239413783Smrg		else
90339413783Smrg			drmmode_crtc->scanout_id = 0;
904de2362d3Smrg
9058bf5c682Smrg		if (drmmode_crtc->prime_scanout_pixmap) {
9063ed65abbSmrg			drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id,
9078bf5c682Smrg							  &fb, &x, &y);
9088bf5c682Smrg		} else if (drmmode_crtc->rotate.pixmap) {
9098bf5c682Smrg			fb = radeon_pixmap_get_fb(drmmode_crtc->rotate.pixmap);
91018781e08Smrg			x = y = 0;
91118781e08Smrg
9128bf5c682Smrg		} else if (!pScreen->isGPU &&
9133ed65abbSmrg			   (drmmode_crtc->tear_free ||
91418781e08Smrg			    crtc->driverIsPerformingTransform ||
91518781e08Smrg			    info->shadow_primary)) {
9163ed65abbSmrg			drmmode_crtc_scanout_update(crtc, mode, scanout_id,
9178bf5c682Smrg						    &fb, &x, &y);
918de2362d3Smrg		}
91918781e08Smrg
9208bf5c682Smrg		if (!fb)
9218bf5c682Smrg			fb = radeon_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root));
9228bf5c682Smrg		if (!fb) {
923d1d00eb7Sjmcneill			if (info->front_buffer->flags & RADEON_BO_FLAGS_GBM) {
924d1d00eb7Sjmcneill				handle = gbm_bo_get_handle(info->front_buffer->bo.gbm).u32;
925d1d00eb7Sjmcneill			} else {
926d1d00eb7Sjmcneill				handle = info->front_buffer->bo.radeon->handle;
927d1d00eb7Sjmcneill			}
9288bf5c682Smrg			fb = radeon_fb_create(pScrn, pRADEONEnt->fd,
9298bf5c682Smrg					      pScrn->virtualX, pScrn->virtualY,
9308bf5c682Smrg					      pScrn->displayWidth * info->pixel_bytes,
931d1d00eb7Sjmcneill					      handle);
9328bf5c682Smrg			/* Prevent refcnt of ad-hoc FBs from reaching 2 */
9338bf5c682Smrg			drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL);
9348bf5c682Smrg			drmmode_crtc->fb = fb;
9358bf5c682Smrg		}
9368bf5c682Smrg		if (!fb) {
9378bf5c682Smrg			ErrorF("failed to add FB for modeset\n");
9388bf5c682Smrg			goto done;
93918781e08Smrg		}
94018781e08Smrg
94139413783Smrg		radeon_drm_wait_pending_flip(crtc);
942446f62d6Smrg		handle_deferred = TRUE;
9438bf5c682Smrg
9448bf5c682Smrg		if (!drmmode_set_mode(crtc, fb, mode, x, y))
94518781e08Smrg			goto done;
9468bf5c682Smrg
9478bf5c682Smrg		ret = TRUE;
948de2362d3Smrg
94918781e08Smrg		if (pScreen)
95018781e08Smrg			xf86CrtcSetScreenSubpixelOrder(pScreen);
95118781e08Smrg
95218781e08Smrg		drmmode_crtc->need_modeset = FALSE;
95318781e08Smrg
954de2362d3Smrg		/* go through all the outputs and force DPMS them back on? */
955de2362d3Smrg		for (i = 0; i < xf86_config->num_output; i++) {
956de2362d3Smrg			xf86OutputPtr output = xf86_config->output[i];
957de2362d3Smrg
958de2362d3Smrg			if (output->crtc != crtc)
959de2362d3Smrg				continue;
960de2362d3Smrg
961de2362d3Smrg			output->funcs->dpms(output, DPMSModeOn);
962de2362d3Smrg		}
963de2362d3Smrg	}
964de2362d3Smrg
96518781e08Smrg	/* Compute index of this CRTC into xf86_config->crtc */
96618781e08Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
96718781e08Smrg		if (xf86_config->crtc[i] != crtc)
96818781e08Smrg			continue;
96918781e08Smrg
97018781e08Smrg		if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc))
97118781e08Smrg			info->hwcursor_disabled &= ~(1 << i);
97218781e08Smrg		else
97318781e08Smrg			info->hwcursor_disabled |= 1 << i;
97418781e08Smrg
97518781e08Smrg		break;
97618781e08Smrg	}
97718781e08Smrg
97818781e08Smrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR
97918781e08Smrg	if (!info->hwcursor_disabled)
98018781e08Smrg		xf86_reload_cursors(pScreen);
98118781e08Smrg#endif
982de2362d3Smrg
983de2362d3Smrgdone:
984de2362d3Smrg	if (!ret) {
985de2362d3Smrg		crtc->x = saved_x;
986de2362d3Smrg		crtc->y = saved_y;
987de2362d3Smrg		crtc->rotation = saved_rotation;
988de2362d3Smrg		crtc->mode = saved_mode;
98918781e08Smrg	} else {
9907821949aSmrg		crtc->active = TRUE;
99118781e08Smrg
9928bf5c682Smrg		if (drmmode_crtc->scanout[scanout_id].pixmap &&
9938bf5c682Smrg		    fb != radeon_pixmap_get_fb(drmmode_crtc->
99439413783Smrg					       scanout[scanout_id].pixmap)) {
995446f62d6Smrg			drmmode_crtc_scanout_free(crtc);
99639413783Smrg		} else if (!drmmode_crtc->tear_free) {
9973ed65abbSmrg			drmmode_crtc_scanout_destroy(drmmode,
9983ed65abbSmrg						     &drmmode_crtc->scanout[1]);
9993ed65abbSmrg		}
100018781e08Smrg	}
100118781e08Smrg
1002446f62d6Smrg	if (handle_deferred)
1003446f62d6Smrg		radeon_drm_queue_handle_deferred(crtc);
1004446f62d6Smrg
1005de2362d3Smrg	return ret;
1006de2362d3Smrg}
1007de2362d3Smrg
1008de2362d3Smrgstatic void
1009de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
1010de2362d3Smrg{
1011de2362d3Smrg
1012de2362d3Smrg}
1013de2362d3Smrg
1014de2362d3Smrgstatic void
1015de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
1016de2362d3Smrg{
1017de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
10188bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
1019de2362d3Smrg
10208bf5c682Smrg#if XF86_CRTC_VERSION < 7
102118781e08Smrg	if (crtc->driverIsPerformingTransform) {
102218781e08Smrg		x += crtc->x;
102318781e08Smrg		y += crtc->y;
102418781e08Smrg		xf86CrtcTransformCursorPos(crtc, &x, &y);
102518781e08Smrg	}
102618781e08Smrg#endif
102718781e08Smrg
1028446f62d6Smrg	drmmode_crtc->cursor_x = x;
1029446f62d6Smrg	drmmode_crtc->cursor_y = y;
1030446f62d6Smrg
10318bf5c682Smrg	drmModeMoveCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
1032de2362d3Smrg}
1033de2362d3Smrg
10348bf5c682Smrg#if XF86_CRTC_VERSION < 7
103518781e08Smrg
103618781e08Smrgstatic int
103718781e08Smrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height,
103818781e08Smrg			  int x_dst, int y_dst)
103918781e08Smrg{
104018781e08Smrg	int t;
104118781e08Smrg
104218781e08Smrg	switch (rotation & 0xf) {
104318781e08Smrg	case RR_Rotate_90:
104418781e08Smrg		t = x_dst;
104518781e08Smrg		x_dst = height - y_dst - 1;
104618781e08Smrg		y_dst = t;
104718781e08Smrg		break;
104818781e08Smrg	case RR_Rotate_180:
104918781e08Smrg		x_dst = width - x_dst - 1;
105018781e08Smrg		y_dst = height - y_dst - 1;
105118781e08Smrg		break;
105218781e08Smrg	case RR_Rotate_270:
105318781e08Smrg		t = x_dst;
105418781e08Smrg		x_dst = y_dst;
105518781e08Smrg		y_dst = width - t - 1;
105618781e08Smrg		break;
105718781e08Smrg	}
105818781e08Smrg
105918781e08Smrg	if (rotation & RR_Reflect_X)
106018781e08Smrg		x_dst = width - x_dst - 1;
106118781e08Smrg	if (rotation & RR_Reflect_Y)
106218781e08Smrg		y_dst = height - y_dst - 1;
106318781e08Smrg
106418781e08Smrg	return y_dst * height + x_dst;
106518781e08Smrg}
106618781e08Smrg
106718781e08Smrg#endif
106818781e08Smrg
1069446f62d6Smrgstatic Bool
1070446f62d6Smrgdrmmode_cursor_pixel(xf86CrtcPtr crtc, uint32_t *argb, Bool *premultiplied,
1071446f62d6Smrg		     Bool *apply_gamma)
10728bf5c682Smrg{
1073446f62d6Smrg	uint32_t alpha = *argb >> 24;
10748bf5c682Smrg	uint32_t rgb[3];
10758bf5c682Smrg	int i;
10768bf5c682Smrg
1077446f62d6Smrg	if (premultiplied) {
1078446f62d6Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1, 18, 4, 0, 0)
1079446f62d6Smrg		if (alpha == 0 && (*argb & 0xffffff) != 0) {
1080446f62d6Smrg			/* Doesn't look like premultiplied alpha */
1081446f62d6Smrg			*premultiplied = FALSE;
1082446f62d6Smrg			return FALSE;
1083446f62d6Smrg		}
1084446f62d6Smrg#endif
10858bf5c682Smrg
1086446f62d6Smrg		if (!(*apply_gamma))
1087446f62d6Smrg			return TRUE;
1088446f62d6Smrg
1089446f62d6Smrg		if (*argb > (alpha | alpha << 8 | alpha << 16 | alpha << 24)) {
1090446f62d6Smrg			/* Un-premultiplied R/G/B would overflow gamma LUT,
1091446f62d6Smrg			 * don't apply gamma correction
1092446f62d6Smrg			 */
1093446f62d6Smrg			*apply_gamma = FALSE;
1094446f62d6Smrg			return FALSE;
1095446f62d6Smrg		}
1096446f62d6Smrg	}
1097446f62d6Smrg
1098446f62d6Smrg	if (!alpha) {
1099446f62d6Smrg		*argb = 0;
1100446f62d6Smrg		return TRUE;
1101446f62d6Smrg	}
11028bf5c682Smrg
1103446f62d6Smrg	/* Extract RGB */
11048bf5c682Smrg	for (i = 0; i < 3; i++)
1105446f62d6Smrg		rgb[i] = (*argb >> (i * 8)) & 0xff;
1106446f62d6Smrg
1107446f62d6Smrg	if (premultiplied) {
1108446f62d6Smrg		/* Un-premultiply alpha */
1109446f62d6Smrg		for (i = 0; i < 3; i++)
1110446f62d6Smrg			rgb[i] = rgb[i] * 0xff / alpha;
1111446f62d6Smrg	}
11128bf5c682Smrg
1113446f62d6Smrg	if (*apply_gamma) {
1114446f62d6Smrg		rgb[0] = crtc->gamma_blue[rgb[0]] >> 8;
1115446f62d6Smrg		rgb[1] = crtc->gamma_green[rgb[1]] >> 8;
1116446f62d6Smrg		rgb[2] = crtc->gamma_red[rgb[2]] >> 8;
1117446f62d6Smrg	}
11188bf5c682Smrg
1119446f62d6Smrg	/* Premultiply alpha */
1120446f62d6Smrg	for (i = 0; i < 3; i++)
1121446f62d6Smrg		rgb[i] = rgb[i] * alpha / 0xff;
1122446f62d6Smrg
1123446f62d6Smrg	*argb = alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
1124446f62d6Smrg	return TRUE;
11258bf5c682Smrg}
11268bf5c682Smrg
1127de2362d3Smrgstatic void
1128de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
1129de2362d3Smrg{
113018781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
113118781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1132de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1133446f62d6Smrg	unsigned id = drmmode_crtc->cursor_id;
1134446f62d6Smrg	Bool premultiplied = TRUE;
1135446f62d6Smrg	Bool apply_gamma = TRUE;
1136446f62d6Smrg	uint32_t argb;
1137de2362d3Smrg	uint32_t *ptr;
1138de2362d3Smrg
1139446f62d6Smrg	if (drmmode_crtc->cursor &&
1140446f62d6Smrg	    XF86_CRTC_CONFIG_PTR(pScrn)->cursor != drmmode_crtc->cursor)
1141446f62d6Smrg		id ^= 1;
1142446f62d6Smrg
1143de2362d3Smrg	/* cursor should be mapped already */
1144446f62d6Smrg	ptr = (uint32_t *)(drmmode_crtc->cursor_bo[id]->ptr);
1145446f62d6Smrg
1146446f62d6Smrg	if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
1147446f62d6Smrg		apply_gamma = FALSE;
1148de2362d3Smrg
11498bf5c682Smrg#if XF86_CRTC_VERSION < 7
115018781e08Smrg	if (crtc->driverIsPerformingTransform) {
115118781e08Smrg		uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
115218781e08Smrg		int dstx, dsty;
115318781e08Smrg		int srcoffset;
115418781e08Smrg
1155446f62d6Smrgretry_transform:
115618781e08Smrg		for (dsty = 0; dsty < cursor_h; dsty++) {
115718781e08Smrg			for (dstx = 0; dstx < cursor_w; dstx++) {
115818781e08Smrg				srcoffset = drmmode_cursor_src_offset(crtc->rotation,
115918781e08Smrg								      cursor_w,
116018781e08Smrg								      cursor_h,
116118781e08Smrg								      dstx, dsty);
1162446f62d6Smrg				argb = image[srcoffset];
1163446f62d6Smrg				if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied,
1164446f62d6Smrg							  &apply_gamma))
1165446f62d6Smrg					goto retry_transform;
116618781e08Smrg
1167446f62d6Smrg				ptr[dsty * info->cursor_w + dstx] = cpu_to_le32(argb);
116818781e08Smrg			}
116918781e08Smrg		}
117018781e08Smrg	} else
117118781e08Smrg#endif
117218781e08Smrg	{
117318781e08Smrg		uint32_t cursor_size = info->cursor_w * info->cursor_h;
117418781e08Smrg		int i;
117518781e08Smrg
1176446f62d6Smrgretry:
1177446f62d6Smrg		for (i = 0; i < cursor_size; i++) {
1178446f62d6Smrg			argb = image[i];
1179446f62d6Smrg			if (!drmmode_cursor_pixel(crtc, &argb, &premultiplied,
1180446f62d6Smrg						  &apply_gamma))
1181446f62d6Smrg				goto retry;
1182446f62d6Smrg
1183446f62d6Smrg			ptr[i] = cpu_to_le32(argb);
1184446f62d6Smrg		}
1185446f62d6Smrg	}
1186446f62d6Smrg
1187446f62d6Smrg	if (id != drmmode_crtc->cursor_id) {
1188446f62d6Smrg		drmmode_crtc->cursor_id = id;
1189446f62d6Smrg		crtc->funcs->show_cursor(crtc);
119018781e08Smrg	}
1191de2362d3Smrg}
1192de2362d3Smrg
119318781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
119418781e08Smrg
119518781e08Smrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
119618781e08Smrg{
119718781e08Smrg	if (!drmmode_can_use_hw_cursor(crtc))
119818781e08Smrg		return FALSE;
119918781e08Smrg
120018781e08Smrg	drmmode_load_cursor_argb(crtc, image);
120118781e08Smrg	return TRUE;
120218781e08Smrg}
120318781e08Smrg
120418781e08Smrg#endif
1205de2362d3Smrg
1206de2362d3Smrgstatic void
1207de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc)
1208de2362d3Smrg{
120918781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
121018781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1211de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
12128bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1213de2362d3Smrg
12148bf5c682Smrg	drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
121518781e08Smrg			 info->cursor_w, info->cursor_h);
1216446f62d6Smrg	drmmode_crtc->cursor = NULL;
1217de2362d3Smrg}
1218de2362d3Smrg
1219de2362d3Smrgstatic void
1220de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc)
1221de2362d3Smrg{
122218781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
122318781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1224de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
12258bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1226446f62d6Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1227446f62d6Smrg	CursorPtr cursor = xf86_config->cursor;
1228446f62d6Smrg	int xhot = cursor->bits->xhot;
1229446f62d6Smrg	int yhot = cursor->bits->yhot;
123018781e08Smrg	static Bool use_set_cursor2 = TRUE;
1231446f62d6Smrg	struct drm_mode_cursor2 arg;
1232446f62d6Smrg
1233446f62d6Smrg	drmmode_crtc->cursor = xf86_config->cursor;
1234446f62d6Smrg
1235446f62d6Smrg	memset(&arg, 0, sizeof(arg));
1236446f62d6Smrg
1237446f62d6Smrg	arg.handle = drmmode_crtc->cursor_bo[drmmode_crtc->cursor_id]->handle;
1238446f62d6Smrg	arg.flags = DRM_MODE_CURSOR_BO;
1239446f62d6Smrg	arg.crtc_id = drmmode_crtc->mode_crtc->crtc_id;
1240446f62d6Smrg	arg.width = info->cursor_w;
1241446f62d6Smrg	arg.height = info->cursor_h;
1242446f62d6Smrg
1243446f62d6Smrg	if (crtc->rotation != RR_Rotate_0 &&
1244446f62d6Smrg	    crtc->rotation != (RR_Rotate_180 | RR_Reflect_X |
1245446f62d6Smrg			       RR_Reflect_Y)) {
1246446f62d6Smrg	    int t;
1247446f62d6Smrg
1248446f62d6Smrg	    /* Reflect & rotate hotspot position */
1249446f62d6Smrg	    if (crtc->rotation & RR_Reflect_X)
1250446f62d6Smrg		xhot = info->cursor_w - xhot - 1;
1251446f62d6Smrg	    if (crtc->rotation & RR_Reflect_Y)
1252446f62d6Smrg		yhot = info->cursor_h - yhot - 1;
1253446f62d6Smrg
1254446f62d6Smrg	    switch (crtc->rotation & 0xf) {
1255446f62d6Smrg	    case RR_Rotate_90:
1256446f62d6Smrg		t = xhot;
1257446f62d6Smrg		xhot = yhot;
1258446f62d6Smrg		yhot = info->cursor_w - t - 1;
1259446f62d6Smrg		break;
1260446f62d6Smrg	    case RR_Rotate_180:
1261446f62d6Smrg		xhot = info->cursor_w - xhot - 1;
1262446f62d6Smrg		yhot = info->cursor_h - yhot - 1;
1263446f62d6Smrg		break;
1264446f62d6Smrg	    case RR_Rotate_270:
1265446f62d6Smrg		t = xhot;
1266446f62d6Smrg		xhot = info->cursor_h - yhot - 1;
1267446f62d6Smrg		yhot = t;
1268446f62d6Smrg	    }
1269446f62d6Smrg	}
1270446f62d6Smrg
1271446f62d6Smrg	if (xhot != drmmode_crtc->cursor_xhot || yhot != drmmode_crtc->cursor_yhot) {
1272446f62d6Smrg	    arg.flags |= DRM_MODE_CURSOR_MOVE;
1273446f62d6Smrg	    arg.x = drmmode_crtc->cursor_x += drmmode_crtc->cursor_xhot - xhot;
1274446f62d6Smrg	    arg.y = drmmode_crtc->cursor_y += drmmode_crtc->cursor_yhot - yhot;
1275446f62d6Smrg	    drmmode_crtc->cursor_xhot = xhot;
1276446f62d6Smrg	    drmmode_crtc->cursor_yhot = yhot;
1277446f62d6Smrg	}
127818781e08Smrg
127918781e08Smrg	if (use_set_cursor2) {
128018781e08Smrg	    int ret;
128118781e08Smrg
1282446f62d6Smrg	    arg.hot_x = xhot;
1283446f62d6Smrg	    arg.hot_y = yhot;
12847314432eSmrg
1285446f62d6Smrg	    ret = drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR2, &arg);
1286cd2eb4f7Smrg	    if (ret == -1 && errno == EINVAL)
128718781e08Smrg		use_set_cursor2 = FALSE;
128818781e08Smrg	    else
128918781e08Smrg		return;
129018781e08Smrg	}
129118781e08Smrg
1292446f62d6Smrg	drmIoctl(pRADEONEnt->fd, DRM_IOCTL_MODE_CURSOR, &arg);
1293de2362d3Smrg}
1294de2362d3Smrg
12953ed65abbSmrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and
12963ed65abbSmrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for
12973ed65abbSmrg * anything else.
12983ed65abbSmrg */
1299de2362d3Smrgstatic void *
1300de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
1301de2362d3Smrg{
1302de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
13037821949aSmrg
13043ed65abbSmrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
13053ed65abbSmrg					 height))
13063ed65abbSmrg		return NULL;
13073ed65abbSmrg
13083ed65abbSmrg	return (void*)~0UL;
1309de2362d3Smrg}
1310de2362d3Smrg
1311de2362d3Smrgstatic PixmapPtr
1312de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1313de2362d3Smrg{
1314de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1315de2362d3Smrg
13163ed65abbSmrg	if (!data) {
13173ed65abbSmrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
13183ed65abbSmrg					    height);
13193ed65abbSmrg	}
13203ed65abbSmrg
13213ed65abbSmrg	return drmmode_crtc->rotate.pixmap;
1322de2362d3Smrg}
1323de2362d3Smrg
1324de2362d3Smrgstatic void
13257821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
1326de2362d3Smrg{
1327de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1328de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1329de2362d3Smrg
133018781e08Smrg	drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate);
13317821949aSmrg}
1332de2362d3Smrg
13337821949aSmrgstatic void
13347821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
13357821949aSmrg                      uint16_t *blue, int size)
13367821949aSmrg{
13378bf5c682Smrg	ScrnInfoPtr scrn = crtc->scrn;
13388bf5c682Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
13398bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
13408bf5c682Smrg	int i;
13418bf5c682Smrg
13428bf5c682Smrg	drmmode_crtc_gamma_do_set(crtc, red, green, blue, size);
13438bf5c682Smrg
13448bf5c682Smrg	/* Compute index of this CRTC into xf86_config->crtc */
13458bf5c682Smrg	for (i = 0; xf86_config->crtc[i] != crtc; i++) {}
13468bf5c682Smrg
13478bf5c682Smrg	if (info->hwcursor_disabled & (1 << i))
13488bf5c682Smrg		return;
13497314432eSmrg
13508bf5c682Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR
13518bf5c682Smrg	xf86CursorResetCursor(scrn->pScreen);
13528bf5c682Smrg#else
13538bf5c682Smrg	xf86_reload_cursors(scrn->pScreen);
13548bf5c682Smrg#endif
135518781e08Smrg}
135618781e08Smrg
135718781e08Smrgstatic Bool
135818781e08Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
135918781e08Smrg{
136018781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
13613ed65abbSmrg	unsigned scanout_id = drmmode_crtc->scanout_id;
136218781e08Smrg	ScreenPtr screen = crtc->scrn->pScreen;
136318781e08Smrg	PixmapDirtyUpdatePtr dirty;
136418781e08Smrg
136518781e08Smrg	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
13668bf5c682Smrg		if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
1367cd2eb4f7Smrg			PixmapStopDirtyTracking(dirty->src, dirty->secondary_dst);
13688bf5c682Smrg			break;
13698bf5c682Smrg		}
137018781e08Smrg	}
137118781e08Smrg
1372446f62d6Smrg	drmmode_crtc_scanout_free(crtc);
13738bf5c682Smrg	drmmode_crtc->prime_scanout_pixmap = NULL;
13748bf5c682Smrg
137518781e08Smrg	if (!ppix)
137618781e08Smrg		return TRUE;
137718781e08Smrg
137818781e08Smrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0],
137918781e08Smrg					 ppix->drawable.width,
138018781e08Smrg					 ppix->drawable.height))
138118781e08Smrg		return FALSE;
138218781e08Smrg
13833ed65abbSmrg	if (drmmode_crtc->tear_free &&
138418781e08Smrg	    !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
138518781e08Smrg					 ppix->drawable.width,
138618781e08Smrg					 ppix->drawable.height)) {
1387446f62d6Smrg		drmmode_crtc_scanout_free(crtc);
138818781e08Smrg		return FALSE;
138918781e08Smrg	}
139018781e08Smrg
13918bf5c682Smrg	drmmode_crtc->prime_scanout_pixmap = ppix;
13928bf5c682Smrg
13938bf5c682Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC
13948bf5c682Smrg	PixmapStartDirtyTracking(&ppix->drawable,
13958bf5c682Smrg				 drmmode_crtc->scanout[scanout_id].pixmap,
13968bf5c682Smrg				 0, 0, 0, 0, RR_Rotate_0);
13978bf5c682Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION)
13983ed65abbSmrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
139918781e08Smrg				 0, 0, 0, 0, RR_Rotate_0);
140018781e08Smrg#elif defined(HAS_DIRTYTRACKING2)
14013ed65abbSmrg	PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
140218781e08Smrg				  0, 0, 0, 0);
140318781e08Smrg#else
14043ed65abbSmrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0);
140518781e08Smrg#endif
140618781e08Smrg	return TRUE;
1407de2362d3Smrg}
1408de2362d3Smrg
140918781e08Smrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = {
1410de2362d3Smrg    .dpms = drmmode_crtc_dpms,
1411de2362d3Smrg    .set_mode_major = drmmode_set_mode_major,
1412de2362d3Smrg    .set_cursor_colors = drmmode_set_cursor_colors,
1413de2362d3Smrg    .set_cursor_position = drmmode_set_cursor_position,
1414de2362d3Smrg    .show_cursor = drmmode_show_cursor,
1415de2362d3Smrg    .hide_cursor = drmmode_hide_cursor,
1416de2362d3Smrg    .load_cursor_argb = drmmode_load_cursor_argb,
141718781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
141818781e08Smrg    .load_cursor_argb_check = drmmode_load_cursor_argb_check,
141918781e08Smrg#endif
1420de2362d3Smrg
1421de2362d3Smrg    .gamma_set = drmmode_crtc_gamma_set,
1422de2362d3Smrg    .shadow_create = drmmode_crtc_shadow_create,
1423de2362d3Smrg    .shadow_allocate = drmmode_crtc_shadow_allocate,
1424de2362d3Smrg    .shadow_destroy = drmmode_crtc_shadow_destroy,
1425de2362d3Smrg    .destroy = NULL, /* XXX */
142618781e08Smrg    .set_scanout_pixmap = drmmode_set_scanout_pixmap,
1427de2362d3Smrg};
1428de2362d3Smrg
1429de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc)
1430de2362d3Smrg{
1431de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1432de2362d3Smrg	return drmmode_crtc->hw_id;
1433de2362d3Smrg}
1434de2362d3Smrg
1435de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc)
1436de2362d3Smrg{
1437de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
14388bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
1439de2362d3Smrg	struct drm_radeon_info ginfo;
1440de2362d3Smrg	int r;
1441de2362d3Smrg	uint32_t tmp;
1442de2362d3Smrg
1443de2362d3Smrg	memset(&ginfo, 0, sizeof(ginfo));
1444de2362d3Smrg	ginfo.request = 0x4;
1445de2362d3Smrg	tmp = drmmode_crtc->mode_crtc->crtc_id;
1446de2362d3Smrg	ginfo.value = (uintptr_t)&tmp;
14478bf5c682Smrg	r = drmCommandWriteRead(pRADEONEnt->fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo));
1448de2362d3Smrg	if (r) {
1449de2362d3Smrg		drmmode_crtc->hw_id = -1;
1450de2362d3Smrg		return;
1451de2362d3Smrg	}
1452de2362d3Smrg	drmmode_crtc->hw_id = tmp;
1453de2362d3Smrg}
1454de2362d3Smrg
145518781e08Smrgstatic unsigned int
145618781e08Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
1457de2362d3Smrg{
1458de2362d3Smrg	xf86CrtcPtr crtc;
1459de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc;
146018781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
14618bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1462de2362d3Smrg
14638bf5c682Smrg	crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs);
146439413783Smrg	if (!crtc)
146518781e08Smrg		return 0;
1466de2362d3Smrg
1467de2362d3Smrg	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
14688bf5c682Smrg	drmmode_crtc->mode_crtc = drmModeGetCrtc(pRADEONEnt->fd, mode_res->crtcs[num]);
1469de2362d3Smrg	drmmode_crtc->drmmode = drmmode;
147018781e08Smrg	drmmode_crtc->dpms_mode = DPMSModeOff;
1471de2362d3Smrg	crtc->driver_private = drmmode_crtc;
1472de2362d3Smrg	drmmode_crtc_hw_id(crtc);
1473de2362d3Smrg
147418781e08Smrg	/* Mark num'th crtc as in use on this device. */
147518781e08Smrg	pRADEONEnt->assigned_crtcs |= (1 << num);
147618781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
147718781e08Smrg		       "Allocated crtc nr. %d to this screen.\n", num);
147818781e08Smrg
147918781e08Smrg	return 1;
1480de2362d3Smrg}
1481de2362d3Smrg
14828bf5c682Smrg/*
14838bf5c682Smrg * Update all of the property values for an output
14848bf5c682Smrg */
14858bf5c682Smrgstatic void
14868bf5c682Smrgdrmmode_output_update_properties(xf86OutputPtr output)
14878bf5c682Smrg{
14888bf5c682Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
14898bf5c682Smrg	int i, j, k;
14908bf5c682Smrg	int err;
14918bf5c682Smrg	drmModeConnectorPtr koutput;
14928bf5c682Smrg
14938bf5c682Smrg	/* Use the most recently fetched values from the kernel */
14948bf5c682Smrg	koutput = drmmode_output->mode_output;
14958bf5c682Smrg
14968bf5c682Smrg	if (!koutput)
14978bf5c682Smrg		return;
14988bf5c682Smrg
14998bf5c682Smrg	for (i = 0; i < drmmode_output->num_props; i++) {
15008bf5c682Smrg		drmmode_prop_ptr p = &drmmode_output->props[i];
15018bf5c682Smrg
15028bf5c682Smrg		for (j = 0; j < koutput->count_props; j++) {
15038bf5c682Smrg			if (koutput->props[j] != p->mode_prop->prop_id)
15048bf5c682Smrg				continue;
15058bf5c682Smrg
15068bf5c682Smrg			/* Check to see if the property value has changed */
15078bf5c682Smrg			if (koutput->prop_values[j] == p->value)
15088bf5c682Smrg				break;
15098bf5c682Smrg
15108bf5c682Smrg			p->value = koutput->prop_values[j];
15118bf5c682Smrg
15128bf5c682Smrg			if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
15138bf5c682Smrg				INT32 value = p->value;
15148bf5c682Smrg
15158bf5c682Smrg				err = RRChangeOutputProperty(output->randr_output,
15168bf5c682Smrg							     p->atoms[0], XA_INTEGER,
15178bf5c682Smrg							     32, PropModeReplace, 1,
15188bf5c682Smrg							     &value, FALSE, TRUE);
15198bf5c682Smrg				if (err != 0) {
15208bf5c682Smrg					xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
15218bf5c682Smrg						   "RRChangeOutputProperty error, %d\n",
15228bf5c682Smrg						   err);
15238bf5c682Smrg				}
15248bf5c682Smrg			} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
15258bf5c682Smrg				for (k = 0; k < p->mode_prop->count_enums; k++) {
15268bf5c682Smrg					if (p->mode_prop->enums[k].value == p->value)
15278bf5c682Smrg						break;
15288bf5c682Smrg				}
15298bf5c682Smrg				if (k < p->mode_prop->count_enums) {
15308bf5c682Smrg					err = RRChangeOutputProperty(output->randr_output,
15318bf5c682Smrg								     p->atoms[0], XA_ATOM,
15328bf5c682Smrg								     32, PropModeReplace, 1,
15338bf5c682Smrg								     &p->atoms[k + 1], FALSE,
15348bf5c682Smrg								     TRUE);
15358bf5c682Smrg					if (err != 0) {
15368bf5c682Smrg						xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
15378bf5c682Smrg							   "RRChangeOutputProperty error, %d\n",
15388bf5c682Smrg							   err);
15398bf5c682Smrg					}
15408bf5c682Smrg				}
15418bf5c682Smrg			}
15428bf5c682Smrg
15438bf5c682Smrg			break;
15448bf5c682Smrg		}
15458bf5c682Smrg        }
15468bf5c682Smrg}
15478bf5c682Smrg
1548de2362d3Smrgstatic xf86OutputStatus
1549de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output)
1550de2362d3Smrg{
1551de2362d3Smrg	/* go to the hw and retrieve a new output struct */
1552de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
15538bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1554de2362d3Smrg	xf86OutputStatus status;
1555de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
1556de2362d3Smrg
15578bf5c682Smrg	drmmode_output->mode_output =
15588bf5c682Smrg	    drmModeGetConnector(pRADEONEnt->fd, drmmode_output->output_id);
15598bf5c682Smrg	if (!drmmode_output->mode_output) {
15608bf5c682Smrg		drmmode_output->output_id = -1;
156118781e08Smrg		return XF86OutputStatusDisconnected;
15628bf5c682Smrg	}
15638bf5c682Smrg
15648bf5c682Smrg	drmmode_output_update_properties(output);
1565de2362d3Smrg
1566de2362d3Smrg	switch (drmmode_output->mode_output->connection) {
1567de2362d3Smrg	case DRM_MODE_CONNECTED:
1568de2362d3Smrg		status = XF86OutputStatusConnected;
1569de2362d3Smrg		break;
1570de2362d3Smrg	case DRM_MODE_DISCONNECTED:
1571de2362d3Smrg		status = XF86OutputStatusDisconnected;
1572de2362d3Smrg		break;
1573de2362d3Smrg	default:
1574de2362d3Smrg	case DRM_MODE_UNKNOWNCONNECTION:
1575de2362d3Smrg		status = XF86OutputStatusUnknown;
1576de2362d3Smrg		break;
1577de2362d3Smrg	}
1578de2362d3Smrg	return status;
1579de2362d3Smrg}
1580de2362d3Smrg
1581de2362d3Smrgstatic Bool
1582de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
1583de2362d3Smrg{
1584de2362d3Smrg	return MODE_OK;
1585de2362d3Smrg}
1586de2362d3Smrg
1587446f62d6Smrgstatic void
1588446f62d6Smrgdrmmode_output_attach_tile(xf86OutputPtr output)
1589446f62d6Smrg{
1590446f62d6Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0)
1591446f62d6Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1592446f62d6Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
1593446f62d6Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1594446f62d6Smrg	struct xf86CrtcTileInfo tile_info, *set = NULL;
1595446f62d6Smrg	int i;
1596446f62d6Smrg
1597446f62d6Smrg	if (!koutput) {
1598446f62d6Smrg		xf86OutputSetTile(output, NULL);
1599446f62d6Smrg		return;
1600446f62d6Smrg	}
1601446f62d6Smrg
1602446f62d6Smrg	/* look for a TILE property */
1603446f62d6Smrg	for (i = 0; i < koutput->count_props; i++) {
1604446f62d6Smrg		drmModePropertyPtr props;
1605446f62d6Smrg		props = drmModeGetProperty(pRADEONEnt->fd, koutput->props[i]);
1606446f62d6Smrg		if (!props)
1607446f62d6Smrg			continue;
1608446f62d6Smrg
1609446f62d6Smrg		if (!(props->flags & DRM_MODE_PROP_BLOB)) {
1610446f62d6Smrg			drmModeFreeProperty(props);
1611446f62d6Smrg			continue;
1612446f62d6Smrg		}
1613446f62d6Smrg
1614446f62d6Smrg		if (!strcmp(props->name, "TILE")) {
1615446f62d6Smrg			drmModeFreePropertyBlob(drmmode_output->tile_blob);
1616446f62d6Smrg			drmmode_output->tile_blob =
1617446f62d6Smrg				drmModeGetPropertyBlob(pRADEONEnt->fd,
1618446f62d6Smrg						       koutput->prop_values[i]);
1619446f62d6Smrg		}
1620446f62d6Smrg		drmModeFreeProperty(props);
1621446f62d6Smrg	}
1622446f62d6Smrg	if (drmmode_output->tile_blob) {
1623446f62d6Smrg		if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data,
1624446f62d6Smrg					   drmmode_output->tile_blob->length,
1625446f62d6Smrg					   &tile_info) == TRUE)
1626446f62d6Smrg			set = &tile_info;
1627446f62d6Smrg	}
1628446f62d6Smrg	xf86OutputSetTile(output, set);
1629446f62d6Smrg#endif
1630446f62d6Smrg}
1631446f62d6Smrg
16328bf5c682Smrgstatic int
16338bf5c682Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
16348bf5c682Smrg        int type, const char *name)
16358bf5c682Smrg{
16368bf5c682Smrg    int idx = -1;
16378bf5c682Smrg
16388bf5c682Smrg    for (int i = 0; i < koutput->count_props; i++) {
16398bf5c682Smrg        drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
16408bf5c682Smrg
16418bf5c682Smrg        if (!prop)
16428bf5c682Smrg            continue;
16438bf5c682Smrg
16448bf5c682Smrg        if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
16458bf5c682Smrg            idx = i;
16468bf5c682Smrg
16478bf5c682Smrg        drmModeFreeProperty(prop);
16488bf5c682Smrg
16498bf5c682Smrg        if (idx > -1)
16508bf5c682Smrg            break;
16518bf5c682Smrg    }
16528bf5c682Smrg
16538bf5c682Smrg    return idx;
16548bf5c682Smrg}
16558bf5c682Smrg
16568bf5c682Smrgstatic int
16578bf5c682Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
16588bf5c682Smrg        int type, const char *name)
16598bf5c682Smrg{
16608bf5c682Smrg    int idx = koutput_get_prop_idx(fd, koutput, type, name);
16618bf5c682Smrg
16628bf5c682Smrg    return (idx > -1) ? koutput->props[idx] : -1;
16638bf5c682Smrg}
16648bf5c682Smrg
16658bf5c682Smrgstatic drmModePropertyBlobPtr
16668bf5c682Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
16678bf5c682Smrg{
16688bf5c682Smrg    drmModePropertyBlobPtr blob = NULL;
16698bf5c682Smrg    int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
16708bf5c682Smrg
16718bf5c682Smrg    if (idx > -1)
16728bf5c682Smrg        blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
16738bf5c682Smrg
16748bf5c682Smrg    return blob;
16758bf5c682Smrg}
16768bf5c682Smrg
1677de2362d3Smrgstatic DisplayModePtr
1678de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output)
1679de2362d3Smrg{
1680de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1681de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
16828bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1683de2362d3Smrg	int i;
1684de2362d3Smrg	DisplayModePtr Modes = NULL, Mode;
1685de2362d3Smrg	xf86MonPtr mon = NULL;
1686de2362d3Smrg
168718781e08Smrg	if (!koutput)
168818781e08Smrg		return NULL;
168918781e08Smrg
16908bf5c682Smrg	drmModeFreePropertyBlob(drmmode_output->edid_blob);
16918bf5c682Smrg
1692de2362d3Smrg	/* look for an EDID property */
16938bf5c682Smrg	drmmode_output->edid_blob =
16948bf5c682Smrg		koutput_get_prop_blob(pRADEONEnt->fd, koutput, "EDID");
1695de2362d3Smrg
1696de2362d3Smrg	if (drmmode_output->edid_blob) {
1697de2362d3Smrg		mon = xf86InterpretEDID(output->scrn->scrnIndex,
1698de2362d3Smrg					drmmode_output->edid_blob->data);
1699de2362d3Smrg		if (mon && drmmode_output->edid_blob->length > 128)
1700de2362d3Smrg			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
1701de2362d3Smrg	}
1702de2362d3Smrg	xf86OutputSetEDID(output, mon);
1703de2362d3Smrg
1704446f62d6Smrg	drmmode_output_attach_tile(output);
1705446f62d6Smrg
1706de2362d3Smrg	/* modes should already be available */
1707de2362d3Smrg	for (i = 0; i < koutput->count_modes; i++) {
1708de2362d3Smrg		Mode = xnfalloc(sizeof(DisplayModeRec));
1709de2362d3Smrg
1710de2362d3Smrg		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
1711de2362d3Smrg		Modes = xf86ModesAdd(Modes, Mode);
1712de2362d3Smrg
1713de2362d3Smrg	}
1714de2362d3Smrg	return Modes;
1715de2362d3Smrg}
1716de2362d3Smrg
1717de2362d3Smrgstatic void
1718de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output)
1719de2362d3Smrg{
1720de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1721de2362d3Smrg	int i;
1722de2362d3Smrg
1723446f62d6Smrg	drmModeFreePropertyBlob(drmmode_output->edid_blob);
1724446f62d6Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1, 17, 99, 901, 0)
1725446f62d6Smrg	drmModeFreePropertyBlob(drmmode_output->tile_blob);
1726446f62d6Smrg#endif
1727446f62d6Smrg
1728de2362d3Smrg	for (i = 0; i < drmmode_output->num_props; i++) {
1729de2362d3Smrg		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
1730de2362d3Smrg		free(drmmode_output->props[i].atoms);
1731de2362d3Smrg	}
1732de2362d3Smrg	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
1733de2362d3Smrg		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
1734de2362d3Smrg	}
173518781e08Smrg	free(drmmode_output->mode_encoders);
1736de2362d3Smrg	free(drmmode_output->props);
1737de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
1738de2362d3Smrg	free(drmmode_output);
1739de2362d3Smrg	output->driver_private = NULL;
1740de2362d3Smrg}
1741de2362d3Smrg
1742de2362d3Smrgstatic void
1743de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode)
1744de2362d3Smrg{
1745de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
174618781e08Smrg	xf86CrtcPtr crtc = output->crtc;
1747de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
17488bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1749de2362d3Smrg
175018781e08Smrg	if (!koutput)
175118781e08Smrg		return;
175218781e08Smrg
17538bf5c682Smrg	if (mode != DPMSModeOn && crtc)
175418781e08Smrg		drmmode_do_crtc_dpms(crtc, mode);
175518781e08Smrg
17568bf5c682Smrg	drmModeConnectorSetProperty(pRADEONEnt->fd, koutput->connector_id,
1757de2362d3Smrg				    drmmode_output->dpms_enum_id, mode);
175818781e08Smrg
175918781e08Smrg	if (mode == DPMSModeOn && crtc) {
176018781e08Smrg	    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
176118781e08Smrg
176218781e08Smrg	    if (drmmode_crtc->need_modeset)
176318781e08Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x,
176418781e08Smrg				       crtc->y);
176518781e08Smrg	    else
176618781e08Smrg		drmmode_do_crtc_dpms(crtc, mode);
176718781e08Smrg	}
1768de2362d3Smrg}
1769de2362d3Smrg
1770de2362d3Smrg
1771de2362d3Smrgstatic Bool
1772de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop)
1773de2362d3Smrg{
1774de2362d3Smrg    if (!prop)
1775de2362d3Smrg	return TRUE;
1776de2362d3Smrg    /* ignore blob prop */
1777de2362d3Smrg    if (prop->flags & DRM_MODE_PROP_BLOB)
1778de2362d3Smrg	return TRUE;
1779de2362d3Smrg    /* ignore standard property */
1780de2362d3Smrg    if (!strcmp(prop->name, "EDID") ||
1781de2362d3Smrg	    !strcmp(prop->name, "DPMS"))
1782de2362d3Smrg	return TRUE;
1783de2362d3Smrg
1784de2362d3Smrg    return FALSE;
1785de2362d3Smrg}
1786de2362d3Smrg
1787de2362d3Smrgstatic void
1788de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output)
1789de2362d3Smrg{
17903ed65abbSmrg    RADEONInfoPtr info = RADEONPTR(output->scrn);
1791de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
1792de2362d3Smrg    drmModeConnectorPtr mode_output = drmmode_output->mode_output;
17938bf5c682Smrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
17943ed65abbSmrg    drmModePropertyPtr drmmode_prop, tearfree_prop;
1795de2362d3Smrg    int i, j, err;
179639413783Smrg    Atom name;
179739413783Smrg
179839413783Smrg    /* Create CONNECTOR_ID property */
179939413783Smrg    name = MakeAtom("CONNECTOR_ID", 12, TRUE);
180039413783Smrg    if (name != BAD_RESOURCE) {
180139413783Smrg	INT32 value = mode_output->connector_id;
180239413783Smrg
180339413783Smrg	err = RRConfigureOutputProperty(output->randr_output, name,
180439413783Smrg					FALSE, FALSE, TRUE, 1, &value);
180539413783Smrg	if (err != Success) {
180639413783Smrg	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
180739413783Smrg		       "RRConfigureOutputProperty error, %d\n", err);
180839413783Smrg	}
180939413783Smrg
181039413783Smrg	err = RRChangeOutputProperty(output->randr_output, name,
181139413783Smrg				     XA_INTEGER, 32, PropModeReplace, 1,
181239413783Smrg				     &value, FALSE, FALSE);
181339413783Smrg	if (err != Success) {
181439413783Smrg	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
181539413783Smrg		       "RRChangeOutputProperty error, %d\n", err);
181639413783Smrg	}
181739413783Smrg    }
1818de2362d3Smrg
18193ed65abbSmrg    drmmode_output->props = calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec));
1820de2362d3Smrg    if (!drmmode_output->props)
1821de2362d3Smrg	return;
1822de2362d3Smrg
1823de2362d3Smrg    drmmode_output->num_props = 0;
1824de2362d3Smrg    for (i = 0, j = 0; i < mode_output->count_props; i++) {
18258bf5c682Smrg	drmmode_prop = drmModeGetProperty(pRADEONEnt->fd, mode_output->props[i]);
1826de2362d3Smrg	if (drmmode_property_ignore(drmmode_prop)) {
1827de2362d3Smrg	    drmModeFreeProperty(drmmode_prop);
1828de2362d3Smrg	    continue;
1829de2362d3Smrg	}
1830de2362d3Smrg	drmmode_output->props[j].mode_prop = drmmode_prop;
1831de2362d3Smrg	drmmode_output->props[j].value = mode_output->prop_values[i];
1832de2362d3Smrg	drmmode_output->num_props++;
1833de2362d3Smrg	j++;
1834de2362d3Smrg    }
1835de2362d3Smrg
18363ed65abbSmrg    /* Userspace-only property for TearFree */
18373ed65abbSmrg    tearfree_prop = calloc(1, sizeof(*tearfree_prop));
18383ed65abbSmrg    tearfree_prop->flags = DRM_MODE_PROP_ENUM;
183939413783Smrg    strcpy(tearfree_prop->name, "TearFree");
18403ed65abbSmrg    tearfree_prop->count_enums = 3;
18413ed65abbSmrg    tearfree_prop->enums = calloc(tearfree_prop->count_enums,
18423ed65abbSmrg				  sizeof(*tearfree_prop->enums));
184339413783Smrg    strcpy(tearfree_prop->enums[0].name, "off");
184439413783Smrg    strcpy(tearfree_prop->enums[1].name, "on");
18453ed65abbSmrg    tearfree_prop->enums[1].value = 1;
184639413783Smrg    strcpy(tearfree_prop->enums[2].name, "auto");
18473ed65abbSmrg    tearfree_prop->enums[2].value = 2;
18483ed65abbSmrg    drmmode_output->props[j].mode_prop = tearfree_prop;
18493ed65abbSmrg    drmmode_output->props[j].value = info->tear_free;
18503ed65abbSmrg    drmmode_output->tear_free = info->tear_free;
18513ed65abbSmrg    drmmode_output->num_props++;
18523ed65abbSmrg
1853de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
1854de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
1855de2362d3Smrg	drmmode_prop = p->mode_prop;
1856de2362d3Smrg
1857de2362d3Smrg	if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1858de2362d3Smrg	    INT32 range[2];
1859de2362d3Smrg	    INT32 value = p->value;
1860de2362d3Smrg
1861de2362d3Smrg	    p->num_atoms = 1;
1862de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
1863de2362d3Smrg	    if (!p->atoms)
1864de2362d3Smrg		continue;
1865de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1866de2362d3Smrg	    range[0] = drmmode_prop->values[0];
1867de2362d3Smrg	    range[1] = drmmode_prop->values[1];
1868de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1869de2362d3Smrg		    FALSE, TRUE,
1870de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1871de2362d3Smrg		    2, range);
1872de2362d3Smrg	    if (err != 0) {
1873de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1874de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
1875de2362d3Smrg	    }
1876de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1877de2362d3Smrg		    XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE);
1878de2362d3Smrg	    if (err != 0) {
1879de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1880de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
1881de2362d3Smrg	    }
1882de2362d3Smrg	} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1883de2362d3Smrg	    p->num_atoms = drmmode_prop->count_enums + 1;
1884de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
1885de2362d3Smrg	    if (!p->atoms)
1886de2362d3Smrg		continue;
1887de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1888de2362d3Smrg	    for (j = 1; j <= drmmode_prop->count_enums; j++) {
1889de2362d3Smrg		struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
1890de2362d3Smrg		p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
1891de2362d3Smrg	    }
1892de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1893de2362d3Smrg		    FALSE, FALSE,
1894de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1895de2362d3Smrg		    p->num_atoms - 1, (INT32 *)&p->atoms[1]);
1896de2362d3Smrg	    if (err != 0) {
1897de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1898de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
1899de2362d3Smrg	    }
1900de2362d3Smrg	    for (j = 0; j < drmmode_prop->count_enums; j++)
1901de2362d3Smrg		if (drmmode_prop->enums[j].value == p->value)
1902de2362d3Smrg		    break;
1903de2362d3Smrg	    /* there's always a matching value */
1904de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1905de2362d3Smrg		    XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
1906de2362d3Smrg	    if (err != 0) {
1907de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1908de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
1909de2362d3Smrg	    }
1910de2362d3Smrg	}
1911de2362d3Smrg    }
1912de2362d3Smrg}
1913de2362d3Smrg
191439413783Smrgstatic void
191539413783Smrgdrmmode_output_set_tear_free(RADEONEntPtr pRADEONEnt,
191639413783Smrg			     drmmode_output_private_ptr drmmode_output,
191739413783Smrg			     xf86CrtcPtr crtc, int tear_free)
191839413783Smrg{
191939413783Smrg	if (drmmode_output->tear_free == tear_free)
192039413783Smrg		return;
192139413783Smrg
192239413783Smrg	drmmode_output->tear_free = tear_free;
192339413783Smrg
192439413783Smrg	if (crtc) {
192539413783Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
192639413783Smrg				       crtc->x, crtc->y);
192739413783Smrg	}
192839413783Smrg}
192939413783Smrg
1930de2362d3Smrgstatic Bool
1931de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property,
1932de2362d3Smrg		RRPropertyValuePtr value)
1933de2362d3Smrg{
1934de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
19358bf5c682Smrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1936de2362d3Smrg    int i;
1937de2362d3Smrg
1938de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
1939de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
1940de2362d3Smrg
1941de2362d3Smrg	if (p->atoms[0] != property)
1942de2362d3Smrg	    continue;
1943de2362d3Smrg
1944de2362d3Smrg	if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1945de2362d3Smrg	    uint32_t val;
1946de2362d3Smrg
1947de2362d3Smrg	    if (value->type != XA_INTEGER || value->format != 32 ||
1948de2362d3Smrg		    value->size != 1)
1949de2362d3Smrg		return FALSE;
1950de2362d3Smrg	    val = *(uint32_t *)value->data;
1951de2362d3Smrg
19528bf5c682Smrg	    drmModeConnectorSetProperty(pRADEONEnt->fd, drmmode_output->output_id,
1953de2362d3Smrg		    p->mode_prop->prop_id, (uint64_t)val);
1954de2362d3Smrg	    return TRUE;
1955de2362d3Smrg	} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1956de2362d3Smrg	    Atom	atom;
1957de2362d3Smrg	    const char	*name;
1958de2362d3Smrg	    int		j;
1959de2362d3Smrg
1960de2362d3Smrg	    if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
1961de2362d3Smrg		return FALSE;
1962de2362d3Smrg	    memcpy(&atom, value->data, 4);
19638bf5c682Smrg	    if (!(name = NameForAtom(atom)))
19648bf5c682Smrg                return FALSE;
1965de2362d3Smrg
1966de2362d3Smrg	    /* search for matching name string, then set its value down */
1967de2362d3Smrg	    for (j = 0; j < p->mode_prop->count_enums; j++) {
1968de2362d3Smrg		if (!strcmp(p->mode_prop->enums[j].name, name)) {
19693ed65abbSmrg		    if (i == (drmmode_output->num_props - 1)) {
197039413783Smrg			drmmode_output_set_tear_free(pRADEONEnt, drmmode_output,
197139413783Smrg						     output->crtc, j);
19723ed65abbSmrg		    } else {
19738bf5c682Smrg			drmModeConnectorSetProperty(pRADEONEnt->fd,
19743ed65abbSmrg						    drmmode_output->output_id,
19753ed65abbSmrg						    p->mode_prop->prop_id,
19763ed65abbSmrg						    p->mode_prop->enums[j].value);
19773ed65abbSmrg		    }
19783ed65abbSmrg
1979de2362d3Smrg		    return TRUE;
1980de2362d3Smrg		}
1981de2362d3Smrg	    }
1982de2362d3Smrg	}
1983de2362d3Smrg    }
1984de2362d3Smrg
1985de2362d3Smrg    return TRUE;
1986de2362d3Smrg}
1987de2362d3Smrg
1988de2362d3Smrgstatic Bool
1989de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property)
1990de2362d3Smrg{
1991de2362d3Smrg    return TRUE;
1992de2362d3Smrg}
1993de2362d3Smrg
1994de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = {
1995de2362d3Smrg    .dpms = drmmode_output_dpms,
1996de2362d3Smrg    .create_resources = drmmode_output_create_resources,
1997de2362d3Smrg    .set_property = drmmode_output_set_property,
1998de2362d3Smrg    .get_property = drmmode_output_get_property,
1999de2362d3Smrg    .detect = drmmode_output_detect,
2000de2362d3Smrg    .mode_valid = drmmode_output_mode_valid,
2001de2362d3Smrg
2002de2362d3Smrg    .get_modes = drmmode_output_get_modes,
2003de2362d3Smrg    .destroy = drmmode_output_destroy
2004de2362d3Smrg};
2005de2362d3Smrg
2006de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown,
2007de2362d3Smrg				      SubPixelHorizontalRGB,
2008de2362d3Smrg				      SubPixelHorizontalBGR,
2009de2362d3Smrg				      SubPixelVerticalRGB,
2010de2362d3Smrg				      SubPixelVerticalBGR,
2011de2362d3Smrg				      SubPixelNone };
2012de2362d3Smrg
2013de2362d3Smrgconst char *output_names[] = { "None",
2014de2362d3Smrg			       "VGA",
2015de2362d3Smrg			       "DVI",
2016de2362d3Smrg			       "DVI",
2017de2362d3Smrg			       "DVI",
2018de2362d3Smrg			       "Composite",
2019de2362d3Smrg			       "S-video",
2020de2362d3Smrg			       "LVDS",
2021de2362d3Smrg			       "CTV",
2022de2362d3Smrg			       "DIN",
2023de2362d3Smrg			       "DisplayPort",
2024de2362d3Smrg			       "HDMI",
2025de2362d3Smrg			       "HDMI",
2026de2362d3Smrg			       "TV",
2027de2362d3Smrg			       "eDP"
2028de2362d3Smrg};
2029de2362d3Smrg
203018781e08Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
203118781e08Smrg
203218781e08Smrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
203318781e08Smrg{
203418781e08Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
203518781e08Smrg	int i;
203618781e08Smrg	for (i = 0; i < xf86_config->num_output; i++) {
203718781e08Smrg		xf86OutputPtr output = xf86_config->output[i];
203818781e08Smrg		drmmode_output_private_ptr drmmode_output;
203918781e08Smrg
204018781e08Smrg		drmmode_output = output->driver_private;
204118781e08Smrg		if (drmmode_output->output_id == id)
204218781e08Smrg			return output;
204318781e08Smrg	}
204418781e08Smrg	return NULL;
204518781e08Smrg}
204618781e08Smrg
204718781e08Smrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
204818781e08Smrg{
204918781e08Smrg	char *conn;
205018781e08Smrg	char conn_id[5];
205118781e08Smrg	int id, len;
205218781e08Smrg	char *blob_data;
205318781e08Smrg
205418781e08Smrg	if (!path_blob)
205518781e08Smrg		return -1;
205618781e08Smrg
205718781e08Smrg	blob_data = path_blob->data;
205818781e08Smrg	/* we only handle MST paths for now */
205918781e08Smrg	if (strncmp(blob_data, "mst:", 4))
206018781e08Smrg		return -1;
206118781e08Smrg
206218781e08Smrg	conn = strchr(blob_data + 4, '-');
206318781e08Smrg	if (!conn)
206418781e08Smrg		return -1;
206518781e08Smrg	len = conn - (blob_data + 4);
206618781e08Smrg	if (len + 1 > 5)
206718781e08Smrg		return -1;
206818781e08Smrg	memcpy(conn_id, blob_data + 4, len);
206918781e08Smrg	conn_id[len] = '\0';
207018781e08Smrg	id = strtoul(conn_id, NULL, 10);
207118781e08Smrg
207218781e08Smrg	*conn_base_id = id;
207318781e08Smrg
207418781e08Smrg	*path = conn + 1;
207518781e08Smrg	return 0;
207618781e08Smrg}
207718781e08Smrg
2078de2362d3Smrgstatic void
207918781e08Smrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
208018781e08Smrg		    drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi)
208118781e08Smrg{
208218781e08Smrg	xf86OutputPtr output;
208318781e08Smrg	int conn_id;
208418781e08Smrg	char *extra_path;
208518781e08Smrg
208618781e08Smrg	output = NULL;
208718781e08Smrg	if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
208818781e08Smrg		output = find_output(pScrn, conn_id);
208918781e08Smrg	if (output) {
209018781e08Smrg		snprintf(name, 32, "%s-%s", output->name, extra_path);
209118781e08Smrg	} else {
20928bf5c682Smrg		if (koutput->connector_type >= NUM_OUTPUT_NAMES) {
209318781e08Smrg			snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
209418781e08Smrg				 koutput->connector_type_id - 1);
20958bf5c682Smrg		} else if (pScrn->is_gpu) {
209618781e08Smrg			snprintf(name, 32, "%s-%d-%d",
209718781e08Smrg				 output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1,
209818781e08Smrg				 koutput->connector_type_id - 1);
20998bf5c682Smrg		} else {
210018781e08Smrg			/* need to do smart conversion here for compat with non-kms ATI driver */
210118781e08Smrg			if (koutput->connector_type_id == 1) {
210218781e08Smrg				switch(koutput->connector_type) {
210318781e08Smrg				case DRM_MODE_CONNECTOR_DVII:
210418781e08Smrg				case DRM_MODE_CONNECTOR_DVID:
210518781e08Smrg				case DRM_MODE_CONNECTOR_DVIA:
210618781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
210718781e08Smrg					(*num_dvi)++;
210818781e08Smrg					break;
210918781e08Smrg				case DRM_MODE_CONNECTOR_HDMIA:
211018781e08Smrg				case DRM_MODE_CONNECTOR_HDMIB:
211118781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
211218781e08Smrg					(*num_hdmi)++;
211318781e08Smrg					break;
211418781e08Smrg				case DRM_MODE_CONNECTOR_VGA:
211518781e08Smrg				case DRM_MODE_CONNECTOR_DisplayPort:
211618781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
211718781e08Smrg						 koutput->connector_type_id - 1);
211818781e08Smrg					break;
211918781e08Smrg				default:
212018781e08Smrg					snprintf(name, 32, "%s", output_names[koutput->connector_type]);
212118781e08Smrg					break;
212218781e08Smrg				}
212318781e08Smrg			} else {
212418781e08Smrg				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
212518781e08Smrg					 koutput->connector_type_id - 1);
212618781e08Smrg			}
212718781e08Smrg		}
212818781e08Smrg	}
212918781e08Smrg}
213018781e08Smrg
213118781e08Smrgstatic unsigned int
213218781e08Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic)
21330d16fef4Smrg{
213418781e08Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
21358bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2136de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
2137de2362d3Smrg	xf86OutputPtr output;
2138de2362d3Smrg	drmModeConnectorPtr koutput;
2139de2362d3Smrg	drmModeEncoderPtr *kencoders = NULL;
2140de2362d3Smrg	drmmode_output_private_ptr drmmode_output;
214118781e08Smrg	drmModePropertyBlobPtr path_blob = NULL;
214239413783Smrg#if XF86_CRTC_VERSION >= 8
214339413783Smrg	Bool nonDesktop = FALSE;
214439413783Smrg#endif
2145de2362d3Smrg	char name[32];
2146de2362d3Smrg	int i;
2147de2362d3Smrg	const char *s;
2148de2362d3Smrg
21498bf5c682Smrg	koutput = drmModeGetConnector(pRADEONEnt->fd, mode_res->connectors[num]);
2150de2362d3Smrg	if (!koutput)
215118781e08Smrg		return 0;
215218781e08Smrg
21538bf5c682Smrg	path_blob = koutput_get_prop_blob(pRADEONEnt->fd, koutput, "PATH");
2154de2362d3Smrg
215539413783Smrg#if XF86_CRTC_VERSION >= 8
215639413783Smrg	i = koutput_get_prop_idx(pRADEONEnt->fd, koutput, DRM_MODE_PROP_RANGE,
215739413783Smrg				 "non-desktop");
215839413783Smrg	if (i >= 0)
215939413783Smrg		nonDesktop = koutput->prop_values[i] != 0;
216039413783Smrg#endif
216139413783Smrg
2162de2362d3Smrg	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
2163de2362d3Smrg	if (!kencoders) {
2164de2362d3Smrg		goto out_free_encoders;
2165de2362d3Smrg	}
2166de2362d3Smrg
2167de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
21688bf5c682Smrg		kencoders[i] = drmModeGetEncoder(pRADEONEnt->fd, koutput->encoders[i]);
2169de2362d3Smrg		if (!kencoders[i]) {
2170de2362d3Smrg			goto out_free_encoders;
2171de2362d3Smrg		}
2172de2362d3Smrg	}
2173de2362d3Smrg
217418781e08Smrg	drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi);
217518781e08Smrg	if (path_blob)
217618781e08Smrg		drmModeFreePropertyBlob(path_blob);
217718781e08Smrg
217818781e08Smrg	if (path_blob && dynamic) {
217918781e08Smrg		/* See if we have an output with this name already
218018781e08Smrg		 * and hook stuff up.
218118781e08Smrg		 */
218218781e08Smrg		for (i = 0; i < xf86_config->num_output; i++) {
218318781e08Smrg			output = xf86_config->output[i];
218418781e08Smrg
218518781e08Smrg			if (strncmp(output->name, name, 32))
218618781e08Smrg				continue;
218718781e08Smrg
218818781e08Smrg			drmmode_output = output->driver_private;
218918781e08Smrg			drmmode_output->output_id = mode_res->connectors[num];
219018781e08Smrg			drmmode_output->mode_output = koutput;
219139413783Smrg#if XF86_CRTC_VERSION >= 8
219239413783Smrg			output->non_desktop = nonDesktop;
219339413783Smrg#endif
219418781e08Smrg			for (i = 0; i < koutput->count_encoders; i++)
219518781e08Smrg				drmModeFreeEncoder(kencoders[i]);
219618781e08Smrg			free(kencoders);
219718781e08Smrg			return 0;
219818781e08Smrg		}
2199de2362d3Smrg	}
2200de2362d3Smrg
2201de2362d3Smrg	if (xf86IsEntityShared(pScrn->entityList[0])) {
2202de2362d3Smrg		if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
2203de2362d3Smrg			if (!RADEONZaphodStringMatches(pScrn, s, name))
2204de2362d3Smrg				goto out_free_encoders;
2205de2362d3Smrg		} else {
2206446f62d6Smrg			if (info->instance_id != num)
2207de2362d3Smrg				goto out_free_encoders;
2208de2362d3Smrg		}
2209de2362d3Smrg	}
2210de2362d3Smrg
2211de2362d3Smrg	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
2212de2362d3Smrg	if (!output) {
2213de2362d3Smrg		goto out_free_encoders;
2214de2362d3Smrg	}
2215de2362d3Smrg
2216de2362d3Smrg	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
2217de2362d3Smrg	if (!drmmode_output) {
2218de2362d3Smrg		xf86OutputDestroy(output);
2219de2362d3Smrg		goto out_free_encoders;
2220de2362d3Smrg	}
2221de2362d3Smrg
222218781e08Smrg	drmmode_output->output_id = mode_res->connectors[num];
2223de2362d3Smrg	drmmode_output->mode_output = koutput;
2224de2362d3Smrg	drmmode_output->mode_encoders = kencoders;
2225de2362d3Smrg	drmmode_output->drmmode = drmmode;
2226de2362d3Smrg	output->mm_width = koutput->mmWidth;
2227de2362d3Smrg	output->mm_height = koutput->mmHeight;
2228de2362d3Smrg
2229de2362d3Smrg	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
2230de2362d3Smrg	output->interlaceAllowed = TRUE;
2231de2362d3Smrg	output->doubleScanAllowed = TRUE;
2232de2362d3Smrg	output->driver_private = drmmode_output;
223339413783Smrg#if XF86_CRTC_VERSION >= 8
223439413783Smrg	output->non_desktop = nonDesktop;
223539413783Smrg#endif
2236de2362d3Smrg
2237de2362d3Smrg	output->possible_crtcs = 0xffffffff;
2238de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
2239de2362d3Smrg		output->possible_crtcs &= kencoders[i]->possible_crtcs;
2240de2362d3Smrg	}
2241de2362d3Smrg	/* work out the possible clones later */
2242de2362d3Smrg	output->possible_clones = 0;
2243de2362d3Smrg
22448bf5c682Smrg	drmmode_output->dpms_enum_id =
22458bf5c682Smrg		koutput_get_prop_id(pRADEONEnt->fd, koutput, DRM_MODE_PROP_ENUM,
22468bf5c682Smrg				    "DPMS");
2247de2362d3Smrg
224818781e08Smrg	if (dynamic) {
224918781e08Smrg		output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
225018781e08Smrg		drmmode_output_create_resources(output);
225118781e08Smrg	}
225218781e08Smrg
225318781e08Smrg	return 1;
2254de2362d3Smrgout_free_encoders:
2255de2362d3Smrg	if (kencoders){
2256de2362d3Smrg		for (i = 0; i < koutput->count_encoders; i++)
2257de2362d3Smrg			drmModeFreeEncoder(kencoders[i]);
2258de2362d3Smrg		free(kencoders);
2259de2362d3Smrg	}
2260de2362d3Smrg	drmModeFreeConnector(koutput);
226118781e08Smrg	return 0;
2262de2362d3Smrg}
2263de2362d3Smrg
2264de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
2265de2362d3Smrg{
2266de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout;
2267de2362d3Smrg	int i;
2268de2362d3Smrg	xf86OutputPtr clone_output;
2269de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2270de2362d3Smrg	int index_mask = 0;
2271de2362d3Smrg
2272de2362d3Smrg	if (drmmode_output->enc_clone_mask == 0)
2273de2362d3Smrg		return index_mask;
2274de2362d3Smrg
2275de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
2276de2362d3Smrg		clone_output = xf86_config->output[i];
2277de2362d3Smrg		clone_drmout = clone_output->driver_private;
2278de2362d3Smrg		if (output == clone_output)
2279de2362d3Smrg			continue;
2280de2362d3Smrg
2281de2362d3Smrg		if (clone_drmout->enc_mask == 0)
2282de2362d3Smrg			continue;
2283de2362d3Smrg		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
2284de2362d3Smrg			index_mask |= (1 << i);
2285de2362d3Smrg	}
2286de2362d3Smrg	return index_mask;
2287de2362d3Smrg}
2288de2362d3Smrg
2289de2362d3Smrg
2290de2362d3Smrgstatic void
229118781e08Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
2292de2362d3Smrg{
2293de2362d3Smrg	int i, j;
2294de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2295de2362d3Smrg
2296de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
2297de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
2298de2362d3Smrg		drmmode_output_private_ptr drmmode_output;
2299de2362d3Smrg
2300de2362d3Smrg		drmmode_output = output->driver_private;
2301de2362d3Smrg		drmmode_output->enc_clone_mask = 0xff;
2302de2362d3Smrg		/* and all the possible encoder clones for this output together */
2303de2362d3Smrg		for (j = 0; j < drmmode_output->mode_output->count_encoders; j++)
2304de2362d3Smrg		{
2305de2362d3Smrg			int k;
230618781e08Smrg			for (k = 0; k < mode_res->count_encoders; k++) {
230718781e08Smrg				if (mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id)
2308de2362d3Smrg					drmmode_output->enc_mask |= (1 << k);
2309de2362d3Smrg			}
2310de2362d3Smrg
2311de2362d3Smrg			drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones;
2312de2362d3Smrg		}
2313de2362d3Smrg	}
2314de2362d3Smrg
2315de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
2316de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
2317de2362d3Smrg		output->possible_clones = find_clones(scrn, output);
2318de2362d3Smrg	}
2319de2362d3Smrg}
2320de2362d3Smrg
2321de2362d3Smrg/* returns height alignment in pixels */
2322de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling)
2323de2362d3Smrg{
2324de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2325de2362d3Smrg	int height_align = 1;
2326de2362d3Smrg
2327de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2328de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
2329de2362d3Smrg			height_align =  info->num_channels * 8;
2330de2362d3Smrg		else if (tiling & RADEON_TILING_MICRO)
2331de2362d3Smrg			height_align = 8;
2332de2362d3Smrg		else
2333de2362d3Smrg			height_align = 8;
2334de2362d3Smrg	} else {
233518781e08Smrg		if (tiling & RADEON_TILING_MICRO_SQUARE)
233618781e08Smrg			height_align =  32;
233718781e08Smrg		else if (tiling)
2338de2362d3Smrg			height_align = 16;
2339de2362d3Smrg		else
2340de2362d3Smrg			height_align = 1;
2341de2362d3Smrg	}
2342de2362d3Smrg	return height_align;
2343de2362d3Smrg}
2344de2362d3Smrg
2345de2362d3Smrg/* returns pitch alignment in pixels */
2346de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
2347de2362d3Smrg{
2348de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2349de2362d3Smrg	int pitch_align = 1;
2350de2362d3Smrg
2351de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2352de2362d3Smrg		if (tiling & RADEON_TILING_MACRO) {
2353de2362d3Smrg			/* general surface requirements */
2354de2362d3Smrg			pitch_align = MAX(info->num_banks,
2355de2362d3Smrg					  (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8;
2356de2362d3Smrg			/* further restrictions for scanout */
2357de2362d3Smrg			pitch_align = MAX(info->num_banks * 8, pitch_align);
2358de2362d3Smrg		} else if (tiling & RADEON_TILING_MICRO) {
2359de2362d3Smrg			/* general surface requirements */
2360de2362d3Smrg			pitch_align = MAX(8, (info->group_bytes / (8 * bpe)));
2361de2362d3Smrg			/* further restrictions for scanout */
2362de2362d3Smrg			pitch_align = MAX(info->group_bytes / bpe, pitch_align);
2363de2362d3Smrg		} else {
2364de2362d3Smrg			if (info->have_tiling_info)
2365de2362d3Smrg				/* linear aligned requirements */
2366de2362d3Smrg				pitch_align = MAX(64, info->group_bytes / bpe);
2367de2362d3Smrg			else
2368de2362d3Smrg				/* default to 512 elements if we don't know the real
2369de2362d3Smrg				 * group size otherwise the kernel may reject the CS
2370de2362d3Smrg				 * if the group sizes don't match as the pitch won't
2371de2362d3Smrg				 * be aligned properly.
2372de2362d3Smrg				 */
2373de2362d3Smrg				pitch_align = 512;
2374de2362d3Smrg		}
2375de2362d3Smrg	} else {
2376de2362d3Smrg		/* general surface requirements */
2377de2362d3Smrg		if (tiling)
2378de2362d3Smrg			pitch_align = 256 / bpe;
2379de2362d3Smrg		else
2380de2362d3Smrg			pitch_align = 64;
2381de2362d3Smrg	}
2382de2362d3Smrg	return pitch_align;
2383de2362d3Smrg}
2384de2362d3Smrg
2385de2362d3Smrg/* returns base alignment in bytes */
2386de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
2387de2362d3Smrg{
2388de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2389de2362d3Smrg	int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling);
2390de2362d3Smrg	int height_align = drmmode_get_height_align(scrn, tiling);
2391de2362d3Smrg	int base_align = RADEON_GPU_PAGE_SIZE;
2392de2362d3Smrg
2393de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2394de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
2395de2362d3Smrg			base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe,
2396de2362d3Smrg					 pixel_align * bpe * height_align);
2397de2362d3Smrg		else {
2398de2362d3Smrg			if (info->have_tiling_info)
2399de2362d3Smrg				base_align = info->group_bytes;
2400de2362d3Smrg			else
2401de2362d3Smrg				/* default to 512 if we don't know the real
2402de2362d3Smrg				 * group size otherwise the kernel may reject the CS
2403de2362d3Smrg				 * if the group sizes don't match as the base won't
2404de2362d3Smrg				 * be aligned properly.
2405de2362d3Smrg				 */
2406de2362d3Smrg				base_align = 512;
2407de2362d3Smrg		}
2408de2362d3Smrg	}
2409de2362d3Smrg	return base_align;
2410de2362d3Smrg}
2411de2362d3Smrg
2412de2362d3Smrgstatic Bool
2413de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
2414de2362d3Smrg{
2415de2362d3Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2416de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
241739413783Smrg	struct radeon_buffer *old_front = NULL;
2418de2362d3Smrg	ScreenPtr   screen = xf86ScrnToScreen(scrn);
2419de2362d3Smrg	int	    i, pitch, old_width, old_height, old_pitch;
242039413783Smrg	int usage = CREATE_PIXMAP_USAGE_BACKING_PIXMAP;
242118781e08Smrg	int cpp = info->pixel_bytes;
242239413783Smrg	uint32_t tiling_flags;
2423de2362d3Smrg	PixmapPtr ppix = screen->GetScreenPixmap(screen);
2424de2362d3Smrg	void *fb_shadow;
2425de2362d3Smrg
2426de2362d3Smrg	if (scrn->virtualX == width && scrn->virtualY == height)
2427de2362d3Smrg		return TRUE;
2428de2362d3Smrg
242939413783Smrg	if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) {
243039413783Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
243139413783Smrg			   "Xorg tried resizing screen to %dx%d, but maximum "
243239413783Smrg			   "supported is %dx%d\n", width, height,
243339413783Smrg			   xf86_config->maxWidth, xf86_config->maxHeight);
243439413783Smrg		return FALSE;
2435de2362d3Smrg	}
2436de2362d3Smrg
243739413783Smrg	if (info->allowColorTiling && !info->shadow_primary) {
243839413783Smrg		if (info->ChipFamily < CHIP_FAMILY_R600 || info->allowColorTiling2D)
243939413783Smrg			usage |= RADEON_CREATE_PIXMAP_TILING_MACRO;
244039413783Smrg		else
244139413783Smrg			usage |= RADEON_CREATE_PIXMAP_TILING_MICRO;
2442de2362d3Smrg	}
2443de2362d3Smrg
244439413783Smrg	xf86DrvMsg(scrn->scrnIndex, X_INFO, "Allocate new frame buffer %dx%d\n",
244539413783Smrg		   width, height);
2446de2362d3Smrg
2447de2362d3Smrg	old_width = scrn->virtualX;
2448de2362d3Smrg	old_height = scrn->virtualY;
2449de2362d3Smrg	old_pitch = scrn->displayWidth;
245039413783Smrg	old_front = info->front_buffer;
2451de2362d3Smrg
2452de2362d3Smrg	scrn->virtualX = width;
2453de2362d3Smrg	scrn->virtualY = height;
2454de2362d3Smrg
245539413783Smrg	info->front_buffer = radeon_alloc_pixmap_bo(scrn, scrn->virtualX,
245639413783Smrg						    scrn->virtualY, scrn->depth,
245739413783Smrg						    usage, scrn->bitsPerPixel,
245839413783Smrg						    &pitch,
245939413783Smrg						    &info->front_surface,
246039413783Smrg						    &tiling_flags);
246139413783Smrg	if (!info->front_buffer)
2462de2362d3Smrg		goto fail;
2463de2362d3Smrg
246439413783Smrg	scrn->displayWidth = pitch / cpp;
246539413783Smrg
246639413783Smrg	if (!info->use_glamor) {
2467de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
246839413783Smrg		switch (cpp) {
246939413783Smrg		case 4:
247039413783Smrg			tiling_flags |= RADEON_TILING_SWAP_32BIT;
247139413783Smrg			break;
247239413783Smrg		case 2:
247339413783Smrg			tiling_flags |= RADEON_TILING_SWAP_16BIT;
247439413783Smrg			break;
247539413783Smrg		}
247639413783Smrg		if (info->ChipFamily < CHIP_FAMILY_R600 &&
247739413783Smrg		    info->r600_shadow_fb && tiling_flags)
247839413783Smrg			tiling_flags |= RADEON_TILING_SURFACE;
2479de2362d3Smrg#endif
248039413783Smrg		if (tiling_flags)
248139413783Smrg			radeon_bo_set_tiling(info->front_buffer->bo.radeon, tiling_flags, pitch);
248239413783Smrg	}
2483de2362d3Smrg
2484de2362d3Smrg	if (!info->r600_shadow_fb) {
248539413783Smrg		if (info->surf_man && !info->use_glamor)
248639413783Smrg			*radeon_get_pixmap_surface(ppix) = info->front_surface;
2487de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
2488de2362d3Smrg					   width, height, -1, -1, pitch, NULL);
2489de2362d3Smrg	} else {
249039413783Smrg		if (radeon_bo_map(info->front_buffer->bo.radeon, 1))
2491de2362d3Smrg			goto fail;
249239413783Smrg		fb_shadow = calloc(1, pitch * scrn->virtualY);
249339413783Smrg		if (!fb_shadow)
2494de2362d3Smrg			goto fail;
2495de2362d3Smrg		free(info->fb_shadow);
2496de2362d3Smrg		info->fb_shadow = fb_shadow;
2497de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
2498de2362d3Smrg					   width, height, -1, -1, pitch,
2499de2362d3Smrg					   info->fb_shadow);
2500de2362d3Smrg	}
250118781e08Smrg
250218781e08Smrg	if (info->use_glamor)
250318781e08Smrg		radeon_glamor_create_screen_resources(scrn->pScreen);
250418781e08Smrg
250518781e08Smrg	if (!info->r600_shadow_fb) {
250639413783Smrg		if (!radeon_set_pixmap_bo(ppix, info->front_buffer))
250718781e08Smrg			goto fail;
250818781e08Smrg	}
250918781e08Smrg
25108bf5c682Smrg	radeon_pixmap_clear(ppix);
251139413783Smrg	radeon_finish(scrn, info->front_buffer);
25120d16fef4Smrg
2513de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
2514de2362d3Smrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
2515de2362d3Smrg
2516de2362d3Smrg		if (!crtc->enabled)
2517de2362d3Smrg			continue;
2518de2362d3Smrg
2519de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode,
2520de2362d3Smrg				       crtc->rotation, crtc->x, crtc->y);
2521de2362d3Smrg	}
2522de2362d3Smrg
252339413783Smrg	radeon_buffer_unref(&old_front);
2524de2362d3Smrg
252539413783Smrg	radeon_kms_update_vram_limit(scrn, pitch * scrn->virtualY);
2526de2362d3Smrg	return TRUE;
2527de2362d3Smrg
2528de2362d3Smrg fail:
252939413783Smrg	radeon_buffer_unref(&info->front_buffer);
253039413783Smrg	info->front_buffer = old_front;
2531de2362d3Smrg	scrn->virtualX = old_width;
2532de2362d3Smrg	scrn->virtualY = old_height;
2533de2362d3Smrg	scrn->displayWidth = old_pitch;
2534de2362d3Smrg
2535de2362d3Smrg	return FALSE;
2536de2362d3Smrg}
2537de2362d3Smrg
253839413783Smrgstatic void
253939413783Smrgdrmmode_validate_leases(ScrnInfoPtr scrn)
254039413783Smrg{
254139413783Smrg#ifdef XF86_LEASE_VERSION
254239413783Smrg	ScreenPtr screen = scrn->pScreen;
254339413783Smrg	rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
254439413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
254539413783Smrg	drmModeLesseeListPtr lessees;
254639413783Smrg	RRLeasePtr lease, next;
254739413783Smrg	int l;
254839413783Smrg
254939413783Smrg	/* We can't talk to the kernel about leases when VT switched */
255039413783Smrg	if (!scrn->vtSema)
255139413783Smrg		return;
255239413783Smrg
255339413783Smrg	lessees = drmModeListLessees(pRADEONEnt->fd);
255439413783Smrg	if (!lessees)
255539413783Smrg		return;
255639413783Smrg
255739413783Smrg	xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
255839413783Smrg		drmmode_lease_private_ptr lease_private = lease->devPrivate;
255939413783Smrg
256039413783Smrg		for (l = 0; l < lessees->count; l++) {
256139413783Smrg			if (lessees->lessees[l] == lease_private->lessee_id)
256239413783Smrg				break;
256339413783Smrg		}
256439413783Smrg
256539413783Smrg		/* check to see if the lease has gone away */
256639413783Smrg		if (l == lessees->count) {
256739413783Smrg			free(lease_private);
256839413783Smrg			lease->devPrivate = NULL;
256939413783Smrg			xf86CrtcLeaseTerminated(lease);
257039413783Smrg		}
257139413783Smrg	}
257239413783Smrg
257339413783Smrg	free(lessees);
257439413783Smrg#endif
257539413783Smrg}
257639413783Smrg
257739413783Smrg#ifdef XF86_LEASE_VERSION
257839413783Smrg
257939413783Smrgstatic int
258039413783Smrgdrmmode_create_lease(RRLeasePtr lease, int *fd)
258139413783Smrg{
258239413783Smrg	ScreenPtr screen = lease->screen;
258339413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
258439413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
258539413783Smrg	drmmode_lease_private_ptr lease_private;
258639413783Smrg	int noutput = lease->numOutputs;
258739413783Smrg	int ncrtc = lease->numCrtcs;
258839413783Smrg	uint32_t *objects;
258939413783Smrg	size_t nobjects;
259039413783Smrg	int lease_fd;
259139413783Smrg	int c, o;
259239413783Smrg	int i;
259339413783Smrg
259439413783Smrg	nobjects = ncrtc + noutput;
259539413783Smrg	if (nobjects == 0 || nobjects > (SIZE_MAX / 4) ||
259639413783Smrg	    ncrtc > (SIZE_MAX - noutput))
259739413783Smrg		return BadValue;
259839413783Smrg
259939413783Smrg	lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
260039413783Smrg	if (!lease_private)
260139413783Smrg		return BadAlloc;
260239413783Smrg
260339413783Smrg	objects = malloc(nobjects * 4);
260439413783Smrg	if (!objects) {
260539413783Smrg		free(lease_private);
260639413783Smrg		return BadAlloc;
260739413783Smrg	}
260839413783Smrg
260939413783Smrg	i = 0;
261039413783Smrg
261139413783Smrg	/* Add CRTC ids */
261239413783Smrg	for (c = 0; c < ncrtc; c++) {
261339413783Smrg		xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
261439413783Smrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
261539413783Smrg
261639413783Smrg		objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
261739413783Smrg	}
261839413783Smrg
261939413783Smrg	/* Add connector ids */
262039413783Smrg	for (o = 0; o < noutput; o++) {
262139413783Smrg		xf86OutputPtr   output = lease->outputs[o]->devPrivate;
262239413783Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
262339413783Smrg
262439413783Smrg		objects[i++] = drmmode_output->mode_output->connector_id;
262539413783Smrg	}
262639413783Smrg
262739413783Smrg	/* call kernel to create lease */
262839413783Smrg	assert (i == nobjects);
262939413783Smrg
263039413783Smrg	lease_fd = drmModeCreateLease(pRADEONEnt->fd, objects, nobjects, 0,
263139413783Smrg				      &lease_private->lessee_id);
263239413783Smrg
263339413783Smrg	free(objects);
263439413783Smrg
263539413783Smrg	if (lease_fd < 0) {
263639413783Smrg		free(lease_private);
263739413783Smrg		return BadMatch;
263839413783Smrg	}
263939413783Smrg
264039413783Smrg	lease->devPrivate = lease_private;
264139413783Smrg
264239413783Smrg	xf86CrtcLeaseStarted(lease);
264339413783Smrg
264439413783Smrg	*fd = lease_fd;
264539413783Smrg	return Success;
264639413783Smrg}
264739413783Smrg
264839413783Smrgstatic void
264939413783Smrgdrmmode_terminate_lease(RRLeasePtr lease)
265039413783Smrg{
265139413783Smrg	drmmode_lease_private_ptr lease_private = lease->devPrivate;
265239413783Smrg	ScreenPtr screen = lease->screen;
265339413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
265439413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
265539413783Smrg
265639413783Smrg	if (drmModeRevokeLease(pRADEONEnt->fd, lease_private->lessee_id) == 0) {
265739413783Smrg		free(lease_private);
265839413783Smrg		lease->devPrivate = NULL;
265939413783Smrg		xf86CrtcLeaseTerminated(lease);
266039413783Smrg	}
266139413783Smrg}
266239413783Smrg
266339413783Smrg#endif // XF86_LEASE_VERSION
266439413783Smrg
2665de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
266639413783Smrg	.resize = drmmode_xf86crtc_resize,
266739413783Smrg#ifdef XF86_LEASE_VERSION
266839413783Smrg	.create_lease = drmmode_create_lease,
266939413783Smrg	.terminate_lease = drmmode_terminate_lease
267039413783Smrg#endif
2671de2362d3Smrg};
2672de2362d3Smrg
2673de2362d3Smrgstatic void
267418781e08Smrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
2675de2362d3Smrg{
26768bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
26778bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
267818781e08Smrg	drmmode_flipdata_ptr flipdata = event_data;
267939413783Smrg	int crtc_id = drmmode_get_crtc_id(crtc);
268039413783Smrg	struct drmmode_fb **fb = &flipdata->fb[crtc_id];
268139413783Smrg
268239413783Smrg	if (drmmode_crtc->flip_pending == *fb) {
268339413783Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending,
268439413783Smrg				     NULL);
268539413783Smrg	}
268639413783Smrg	drmmode_fb_reference(pRADEONEnt->fd, fb, NULL);
268718781e08Smrg
268818781e08Smrg	if (--flipdata->flip_count == 0) {
268918781e08Smrg		if (!flipdata->fe_crtc)
269018781e08Smrg			flipdata->fe_crtc = crtc;
269118781e08Smrg		flipdata->abort(flipdata->fe_crtc, flipdata->event_data);
269218781e08Smrg		free(flipdata);
269318781e08Smrg	}
2694de2362d3Smrg}
2695de2362d3Smrg
2696de2362d3Smrgstatic void
269718781e08Smrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
2698de2362d3Smrg{
26998bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
27008bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
270118781e08Smrg	drmmode_flipdata_ptr flipdata = event_data;
270239413783Smrg	int crtc_id = drmmode_get_crtc_id(crtc);
270339413783Smrg	struct drmmode_fb **fb = &flipdata->fb[crtc_id];
2704de2362d3Smrg
2705de2362d3Smrg	/* Is this the event whose info shall be delivered to higher level? */
270618781e08Smrg	if (crtc == flipdata->fe_crtc) {
2707de2362d3Smrg		/* Yes: Cache msc, ust for later delivery. */
2708de2362d3Smrg		flipdata->fe_frame = frame;
270918781e08Smrg		flipdata->fe_usec = usec;
2710de2362d3Smrg	}
2711de2362d3Smrg
2712446f62d6Smrg	if (*fb) {
2713446f62d6Smrg		if (drmmode_crtc->flip_pending == *fb) {
2714446f62d6Smrg			drmmode_fb_reference(pRADEONEnt->fd,
2715446f62d6Smrg					     &drmmode_crtc->flip_pending, NULL);
2716446f62d6Smrg		}
2717446f62d6Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, *fb);
2718446f62d6Smrg		drmmode_fb_reference(pRADEONEnt->fd, fb, NULL);
27198bf5c682Smrg	}
27208bf5c682Smrg
272118781e08Smrg	if (--flipdata->flip_count == 0) {
272218781e08Smrg		/* Deliver MSC & UST from reference/current CRTC to flip event
272318781e08Smrg		 * handler
272418781e08Smrg		 */
272518781e08Smrg		if (flipdata->fe_crtc)
272618781e08Smrg			flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame,
272718781e08Smrg					  flipdata->fe_usec, flipdata->event_data);
272818781e08Smrg		else
272918781e08Smrg			flipdata->handler(crtc, frame, usec, flipdata->event_data);
2730de2362d3Smrg
273118781e08Smrg		free(flipdata);
273218781e08Smrg	}
2733de2362d3Smrg}
2734de2362d3Smrg
2735de2362d3Smrg
273618781e08Smrg#if HAVE_NOTIFY_FD
273718781e08Smrgstatic void
273818781e08Smrgdrm_notify_fd(int fd, int ready, void *data)
273918781e08Smrg#else
2740de2362d3Smrgstatic void
2741de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p)
274218781e08Smrg#endif
2743de2362d3Smrg{
274439413783Smrg	drmmode_ptr drmmode = data;
274539413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(drmmode->scrn);
27468bf5c682Smrg
274718781e08Smrg#if !HAVE_NOTIFY_FD
2748de2362d3Smrg	fd_set *read_mask = p;
2749de2362d3Smrg
27508bf5c682Smrg	if (err >= 0 && FD_ISSET(pRADEONEnt->fd, read_mask))
275118781e08Smrg#endif
275218781e08Smrg	{
275339413783Smrg		radeon_drm_handle_event(pRADEONEnt->fd, &drmmode->event_context);
2754de2362d3Smrg	}
2755de2362d3Smrg}
2756de2362d3Smrg
27578bf5c682Smrgstatic Bool drmmode_probe_page_flip_target(RADEONEntPtr pRADEONEnt)
27583ed65abbSmrg{
27593ed65abbSmrg#ifdef DRM_CAP_PAGE_FLIP_TARGET
27603ed65abbSmrg	uint64_t cap_value;
27613ed65abbSmrg
27628bf5c682Smrg	return drmGetCap(pRADEONEnt->fd, DRM_CAP_PAGE_FLIP_TARGET,
27633ed65abbSmrg			 &cap_value) == 0 && cap_value != 0;
27643ed65abbSmrg#else
27653ed65abbSmrg	return FALSE;
27663ed65abbSmrg#endif
27673ed65abbSmrg}
27683ed65abbSmrg
27693ed65abbSmrgstatic int
27708bf5c682Smrgdrmmode_page_flip(RADEONEntPtr pRADEONEnt,
27718bf5c682Smrg		  drmmode_crtc_private_ptr drmmode_crtc, int fb_id,
27723ed65abbSmrg		  uint32_t flags, uintptr_t drm_queue_seq)
27733ed65abbSmrg{
27743ed65abbSmrg	flags |= DRM_MODE_PAGE_FLIP_EVENT;
27758bf5c682Smrg	return drmModePageFlip(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
27763ed65abbSmrg			       fb_id, flags, (void*)drm_queue_seq);
27773ed65abbSmrg}
27783ed65abbSmrg
27793ed65abbSmrgint
27803ed65abbSmrgdrmmode_page_flip_target_absolute(RADEONEntPtr pRADEONEnt,
27813ed65abbSmrg				  drmmode_crtc_private_ptr drmmode_crtc,
27823ed65abbSmrg				  int fb_id, uint32_t flags,
27833ed65abbSmrg				  uintptr_t drm_queue_seq, uint32_t target_msc)
27843ed65abbSmrg{
27853ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET
27863ed65abbSmrg	if (pRADEONEnt->has_page_flip_target) {
27873ed65abbSmrg		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE;
27888bf5c682Smrg		return drmModePageFlipTarget(pRADEONEnt->fd,
27893ed65abbSmrg					     drmmode_crtc->mode_crtc->crtc_id,
27903ed65abbSmrg					     fb_id, flags, (void*)drm_queue_seq,
27913ed65abbSmrg					     target_msc);
27923ed65abbSmrg	}
27933ed65abbSmrg#endif
27943ed65abbSmrg
27958bf5c682Smrg	return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags,
27968bf5c682Smrg				 drm_queue_seq);
27973ed65abbSmrg}
27983ed65abbSmrg
27993ed65abbSmrgint
28003ed65abbSmrgdrmmode_page_flip_target_relative(RADEONEntPtr pRADEONEnt,
28013ed65abbSmrg				  drmmode_crtc_private_ptr drmmode_crtc,
28023ed65abbSmrg				  int fb_id, uint32_t flags,
28033ed65abbSmrg				  uintptr_t drm_queue_seq, uint32_t target_msc)
28043ed65abbSmrg{
28053ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET
28063ed65abbSmrg	if (pRADEONEnt->has_page_flip_target) {
28073ed65abbSmrg		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE;
28088bf5c682Smrg		return drmModePageFlipTarget(pRADEONEnt->fd,
28093ed65abbSmrg					     drmmode_crtc->mode_crtc->crtc_id,
28103ed65abbSmrg					     fb_id, flags, (void*)drm_queue_seq,
28113ed65abbSmrg					     target_msc);
28123ed65abbSmrg	}
28133ed65abbSmrg#endif
28143ed65abbSmrg
28158bf5c682Smrg	return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags,
28168bf5c682Smrg				 drm_queue_seq);
28173ed65abbSmrg}
28183ed65abbSmrg
2819de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
2820de2362d3Smrg{
282118781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
282218781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
2823de2362d3Smrg	int i, num_dvi = 0, num_hdmi = 0;
282418781e08Smrg	drmModeResPtr mode_res;
282518781e08Smrg	unsigned int crtcs_needed = 0;
2826446f62d6Smrg	unsigned int crtcs_got = 0;
282718781e08Smrg	char *bus_id_string, *provider_name;
2828de2362d3Smrg
2829de2362d3Smrg	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
2830de2362d3Smrg
2831de2362d3Smrg	drmmode->scrn = pScrn;
28328bf5c682Smrg	mode_res = drmModeGetResources(pRADEONEnt->fd);
283318781e08Smrg	if (!mode_res)
2834de2362d3Smrg		return FALSE;
2835de2362d3Smrg
283618781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
283718781e08Smrg		       "Initializing outputs ...\n");
283818781e08Smrg	for (i = 0; i < mode_res->count_connectors; i++)
283918781e08Smrg		crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res,
284018781e08Smrg						    i, &num_dvi, &num_hdmi, 0);
284118781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
284218781e08Smrg		       "%d crtcs needed for screen.\n", crtcs_needed);
284318781e08Smrg
28448bf5c682Smrg	/* Need per-screen drmmode_crtc_funcs, based on our global template,
28458bf5c682Smrg	 * so we can disable some functions, depending on screen settings.
28468bf5c682Smrg	 */
28478bf5c682Smrg	info->drmmode_crtc_funcs = drmmode_crtc_funcs;
28488bf5c682Smrg
284918781e08Smrg	if (info->r600_shadow_fb) {
285018781e08Smrg		/* Rotation requires hardware acceleration */
28518bf5c682Smrg		info->drmmode_crtc_funcs.shadow_allocate = NULL;
28528bf5c682Smrg		info->drmmode_crtc_funcs.shadow_create = NULL;
28538bf5c682Smrg		info->drmmode_crtc_funcs.shadow_destroy = NULL;
285418781e08Smrg	}
285518781e08Smrg
28568bf5c682Smrg	/* Hw gamma lut's are currently bypassed by the hw at color depth 30,
28578bf5c682Smrg	 * so spare the server the effort to compute and update the cluts.
28588bf5c682Smrg	 */
28598bf5c682Smrg	if (pScrn->depth == 30)
28608bf5c682Smrg		info->drmmode_crtc_funcs.gamma_set = NULL;
28618bf5c682Smrg
286218781e08Smrg	drmmode->count_crtcs = mode_res->count_crtcs;
286318781e08Smrg	xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height);
286418781e08Smrg
2865446f62d6Smrg	for (i = 0; i < mode_res->count_crtcs; i++) {
286618781e08Smrg		if (!xf86IsEntityShared(pScrn->entityList[0]) ||
2867446f62d6Smrg		    (crtcs_got < crtcs_needed &&
2868446f62d6Smrg		     !(pRADEONEnt->assigned_crtcs & (1 << i))))
2869446f62d6Smrg			crtcs_got += drmmode_crtc_init(pScrn, drmmode, mode_res, i);
2870446f62d6Smrg	}
2871de2362d3Smrg
287218781e08Smrg	/* All ZaphodHeads outputs provided with matching crtcs? */
2873446f62d6Smrg	if (crtcs_got < crtcs_needed) {
2874446f62d6Smrg		if (crtcs_got == 0) {
2875446f62d6Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2876446f62d6Smrg				   "No ZaphodHeads CRTC available, needed %u\n",
2877446f62d6Smrg				   crtcs_needed);
2878446f62d6Smrg			return FALSE;
2879446f62d6Smrg		}
2880446f62d6Smrg
288118781e08Smrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
288218781e08Smrg			   "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
288318781e08Smrg			   crtcs_needed);
2884446f62d6Smrg	}
2885de2362d3Smrg
2886de2362d3Smrg	/* workout clones */
288718781e08Smrg	drmmode_clones_init(pScrn, drmmode, mode_res);
288818781e08Smrg
288918781e08Smrg	bus_id_string = DRICreatePCIBusID(info->PciInfo);
289018781e08Smrg	XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string);
289118781e08Smrg	free(bus_id_string);
289218781e08Smrg	xf86ProviderSetup(pScrn, NULL, provider_name);
289318781e08Smrg	free(provider_name);
2894de2362d3Smrg
2895de2362d3Smrg	xf86InitialConfiguration(pScrn, TRUE);
2896de2362d3Smrg
28978bf5c682Smrg	pRADEONEnt->has_page_flip_target = drmmode_probe_page_flip_target(pRADEONEnt);
28983ed65abbSmrg
289918781e08Smrg	drmModeFreeResources(mode_res);
2900de2362d3Smrg	return TRUE;
2901de2362d3Smrg}
2902de2362d3Smrg
2903de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
2904de2362d3Smrg{
2905de2362d3Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2906de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
2907de2362d3Smrg
290818781e08Smrg	if (info->dri2.pKernelDRMVersion->version_minor < 4)
290918781e08Smrg		return;
291018781e08Smrg
291118781e08Smrg	info->drmmode_inited = TRUE;
291218781e08Smrg	if (pRADEONEnt->fd_wakeup_registered != serverGeneration) {
291318781e08Smrg#if HAVE_NOTIFY_FD
291439413783Smrg		SetNotifyFd(pRADEONEnt->fd, drm_notify_fd, X_NOTIFY_READ,
291539413783Smrg			    &info->drmmode);
291618781e08Smrg#else
29178bf5c682Smrg		AddGeneralSocket(pRADEONEnt->fd);
2918de2362d3Smrg		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
291939413783Smrg					       drm_wakeup_handler,
292039413783Smrg					       &info->drmmode);
292118781e08Smrg#endif
2922de2362d3Smrg		pRADEONEnt->fd_wakeup_registered = serverGeneration;
292318781e08Smrg		pRADEONEnt->fd_wakeup_ref = 1;
292418781e08Smrg	} else
292518781e08Smrg		pRADEONEnt->fd_wakeup_ref++;
292618781e08Smrg}
292718781e08Smrg
292818781e08Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
292918781e08Smrg{
293018781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
293118781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
293218781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
293318781e08Smrg	int c;
293418781e08Smrg
293518781e08Smrg	if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited)
293618781e08Smrg		return;
293718781e08Smrg
2938446f62d6Smrg	for (c = 0; c < config->num_crtc; c++)
2939446f62d6Smrg		drmmode_crtc_scanout_free(config->crtc[c]);
2940446f62d6Smrg
294118781e08Smrg	if (pRADEONEnt->fd_wakeup_registered == serverGeneration &&
294218781e08Smrg	    !--pRADEONEnt->fd_wakeup_ref) {
294318781e08Smrg#if HAVE_NOTIFY_FD
29448bf5c682Smrg		RemoveNotifyFd(pRADEONEnt->fd);
294518781e08Smrg#else
29468bf5c682Smrg		RemoveGeneralSocket(pRADEONEnt->fd);
294718781e08Smrg		RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
29488bf5c682Smrg				drm_wakeup_handler, pScrn);
294918781e08Smrg#endif
295018781e08Smrg	}
2951de2362d3Smrg}
2952de2362d3Smrg
295318781e08Smrg
2954de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr)
2955de2362d3Smrg{
2956de2362d3Smrg	drmmode->bufmgr = bufmgr;
2957de2362d3Smrg	return TRUE;
2958de2362d3Smrg}
2959de2362d3Smrg
2960de2362d3Smrg
29618bf5c682Smrgstatic void drmmode_sprite_do_set_cursor(struct radeon_device_priv *device_priv,
29628bf5c682Smrg					 ScrnInfoPtr scrn, int x, int y)
29638bf5c682Smrg{
29648bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
29658bf5c682Smrg	CursorPtr cursor = device_priv->cursor;
29668bf5c682Smrg	Bool sprite_visible = device_priv->sprite_visible;
29678bf5c682Smrg
29688bf5c682Smrg	if (cursor) {
29698bf5c682Smrg		x -= cursor->bits->xhot;
29708bf5c682Smrg		y -= cursor->bits->yhot;
29718bf5c682Smrg
29728bf5c682Smrg		device_priv->sprite_visible =
29738bf5c682Smrg			x < scrn->virtualX && y < scrn->virtualY &&
29748bf5c682Smrg			(x + cursor->bits->width > 0) &&
29758bf5c682Smrg			(y + cursor->bits->height > 0);
29768bf5c682Smrg	} else {
29778bf5c682Smrg		device_priv->sprite_visible = FALSE;
29788bf5c682Smrg	}
29798bf5c682Smrg
29808bf5c682Smrg	info->sprites_visible += device_priv->sprite_visible - sprite_visible;
29818bf5c682Smrg}
29828bf5c682Smrg
298339413783Smrgstatic void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
298439413783Smrg				      CursorPtr pCursor, int x, int y)
29858bf5c682Smrg{
29868bf5c682Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
29878bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
29888bf5c682Smrg	struct radeon_device_priv *device_priv =
29898bf5c682Smrg		dixLookupScreenPrivate(&pDev->devPrivates,
29908bf5c682Smrg				       &radeon_device_private_key, pScreen);
29918bf5c682Smrg
29928bf5c682Smrg	device_priv->cursor = pCursor;
29938bf5c682Smrg	drmmode_sprite_do_set_cursor(device_priv, scrn, x, y);
29948bf5c682Smrg
299539413783Smrg	info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
29968bf5c682Smrg}
29978bf5c682Smrg
299839413783Smrgstatic void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
299939413783Smrg				       int x, int y)
30008bf5c682Smrg{
30018bf5c682Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
30028bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
30038bf5c682Smrg	struct radeon_device_priv *device_priv =
30048bf5c682Smrg		dixLookupScreenPrivate(&pDev->devPrivates,
30058bf5c682Smrg				       &radeon_device_private_key, pScreen);
30068bf5c682Smrg
30078bf5c682Smrg	drmmode_sprite_do_set_cursor(device_priv, scrn, x, y);
30088bf5c682Smrg
300939413783Smrg	info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
301039413783Smrg}
301139413783Smrg
301239413783Smrgstatic Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
301339413783Smrg						  ScreenPtr pScreen,
301439413783Smrg						  CursorPtr pCursor)
301539413783Smrg{
301639413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
301739413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
301839413783Smrg
301939413783Smrg	return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
302039413783Smrg}
302139413783Smrg
302239413783Smrgstatic Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
302339413783Smrg						    ScreenPtr pScreen,
302439413783Smrg						    CursorPtr pCursor)
302539413783Smrg{
302639413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
302739413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
302839413783Smrg
302939413783Smrg	return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
303039413783Smrg}
303139413783Smrg
303239413783Smrgstatic Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
303339413783Smrg						    ScreenPtr pScreen)
303439413783Smrg{
303539413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
303639413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
303739413783Smrg
303839413783Smrg	return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
30398bf5c682Smrg}
3040de2362d3Smrg
304139413783Smrgstatic void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
304239413783Smrg						 ScreenPtr pScreen)
304339413783Smrg{
304439413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
304539413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
304639413783Smrg
304739413783Smrg	info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
304839413783Smrg}
304939413783Smrg
305039413783SmrgmiPointerSpriteFuncRec drmmode_sprite_funcs = {
305139413783Smrg	.RealizeCursor = drmmode_sprite_realize_realize_cursor,
305239413783Smrg	.UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
305339413783Smrg	.SetCursor = drmmode_sprite_set_cursor,
305439413783Smrg	.MoveCursor = drmmode_sprite_move_cursor,
305539413783Smrg	.DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
305639413783Smrg	.DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
305739413783Smrg};
305839413783Smrg
305939413783Smrg
3060de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
3061de2362d3Smrg{
3062de2362d3Smrg	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
3063de2362d3Smrg	xf86OutputPtr  output = config->output[config->compat_output];
3064de2362d3Smrg	xf86CrtcPtr	crtc = output->crtc;
3065de2362d3Smrg
3066de2362d3Smrg	if (crtc && crtc->enabled) {
3067de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
3068de2362d3Smrg				       x, y);
3069de2362d3Smrg	}
3070de2362d3Smrg}
3071de2362d3Smrg
307218781e08SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
307318781e08Smrg			       Bool set_hw)
3074de2362d3Smrg{
3075de2362d3Smrg	xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
30768bf5c682Smrg	unsigned num_desired = 0, num_on = 0;
3077de2362d3Smrg	int c;
3078de2362d3Smrg
30798bf5c682Smrg	/* First, disable all unused CRTCs */
30808bf5c682Smrg	if (set_hw) {
30818bf5c682Smrg		for (c = 0; c < config->num_crtc; c++) {
30828bf5c682Smrg			xf86CrtcPtr crtc = config->crtc[c];
30838bf5c682Smrg
30848bf5c682Smrg			/* Skip disabled CRTCs */
30858bf5c682Smrg			if (crtc->enabled)
30868bf5c682Smrg				continue;
30878bf5c682Smrg
308839413783Smrg			drmmode_crtc_dpms(crtc, DPMSModeOff);
30898bf5c682Smrg		}
30908bf5c682Smrg	}
30918bf5c682Smrg
30928bf5c682Smrg	/* Then, try setting the chosen mode on each CRTC */
3093de2362d3Smrg	for (c = 0; c < config->num_crtc; c++) {
3094de2362d3Smrg		xf86CrtcPtr	crtc = config->crtc[c];
3095de2362d3Smrg		xf86OutputPtr	output = NULL;
3096de2362d3Smrg		int		o;
3097de2362d3Smrg
30988bf5c682Smrg		if (!crtc->enabled)
3099de2362d3Smrg			continue;
3100de2362d3Smrg
3101de2362d3Smrg		if (config->output[config->compat_output]->crtc == crtc)
3102de2362d3Smrg			output = config->output[config->compat_output];
3103de2362d3Smrg		else
3104de2362d3Smrg		{
3105de2362d3Smrg			for (o = 0; o < config->num_output; o++)
3106de2362d3Smrg				if (config->output[o]->crtc == crtc)
3107de2362d3Smrg				{
3108de2362d3Smrg					output = config->output[o];
3109de2362d3Smrg					break;
3110de2362d3Smrg				}
3111de2362d3Smrg		}
3112de2362d3Smrg		/* paranoia */
3113de2362d3Smrg		if (!output)
3114de2362d3Smrg			continue;
3115de2362d3Smrg
31168bf5c682Smrg		num_desired++;
31178bf5c682Smrg
3118de2362d3Smrg		/* Mark that we'll need to re-set the mode for sure */
3119de2362d3Smrg		memset(&crtc->mode, 0, sizeof(crtc->mode));
3120de2362d3Smrg		if (!crtc->desiredMode.CrtcHDisplay)
3121de2362d3Smrg		{
3122de2362d3Smrg			DisplayModePtr  mode = xf86OutputFindClosestMode (output, pScrn->currentMode);
3123de2362d3Smrg
31248bf5c682Smrg			if (!mode) {
31258bf5c682Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
31268bf5c682Smrg					   "Failed to find mode for CRTC %d\n", c);
31278bf5c682Smrg				continue;
31288bf5c682Smrg			}
3129de2362d3Smrg			crtc->desiredMode = *mode;
3130de2362d3Smrg			crtc->desiredRotation = RR_Rotate_0;
3131de2362d3Smrg			crtc->desiredX = 0;
3132de2362d3Smrg			crtc->desiredY = 0;
3133de2362d3Smrg		}
3134de2362d3Smrg
313518781e08Smrg		if (set_hw) {
31368bf5c682Smrg			if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode,
31378bf5c682Smrg							crtc->desiredRotation,
31388bf5c682Smrg							crtc->desiredX,
31398bf5c682Smrg							crtc->desiredY)) {
31408bf5c682Smrg				num_on++;
31418bf5c682Smrg			} else {
31428bf5c682Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
31438bf5c682Smrg					   "Failed to set mode on CRTC %d\n", c);
314439413783Smrg				RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y,
314539413783Smrg					  crtc->rotation, 0, NULL);
31468bf5c682Smrg			}
314718781e08Smrg		} else {
314818781e08Smrg			crtc->mode = crtc->desiredMode;
314918781e08Smrg			crtc->rotation = crtc->desiredRotation;
315018781e08Smrg			crtc->x = crtc->desiredX;
315118781e08Smrg			crtc->y = crtc->desiredY;
31528bf5c682Smrg			if (drmmode_handle_transform(crtc))
31538bf5c682Smrg				num_on++;
315418781e08Smrg		}
3155de2362d3Smrg	}
31568bf5c682Smrg
31578bf5c682Smrg	if (num_on == 0 && num_desired > 0) {
31588bf5c682Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n");
31598bf5c682Smrg		return FALSE;
31608bf5c682Smrg	}
31618bf5c682Smrg
316239413783Smrg	/* Validate leases on VT re-entry */
3163446f62d6Smrg	if (dixPrivateKeyRegistered(rrPrivKey))
3164446f62d6Smrg	    drmmode_validate_leases(pScrn);
316539413783Smrg
3166de2362d3Smrg	return TRUE;
3167de2362d3Smrg}
3168de2362d3Smrg
316918781e08SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
3170de2362d3Smrg{
3171de2362d3Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
317239413783Smrg    int i;
3173de2362d3Smrg
317418781e08Smrg    if (xf86_config->num_crtc) {
317518781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
317618781e08Smrg		       "Initializing kms color map\n");
317718781e08Smrg	if (!miCreateDefColormap(pScreen))
317818781e08Smrg	    return FALSE;
31798bf5c682Smrg
31808bf5c682Smrg	/* All radeons support 10 bit CLUTs. They get bypassed at depth 30. */
318139413783Smrg	if (pScrn->depth != 30) {
318239413783Smrg	    if (!xf86HandleColormaps(pScreen, 256, 10, NULL, NULL,
318339413783Smrg				     CMAP_PALETTED_TRUECOLOR
318439413783Smrg				     | CMAP_RELOAD_ON_MODE_SWITCH))
318539413783Smrg		return FALSE;
318639413783Smrg
318739413783Smrg	    for (i = 0; i < xf86_config->num_crtc; i++) {
318839413783Smrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
318939413783Smrg
319039413783Smrg		drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red,
319139413783Smrg					  crtc->gamma_green,
319239413783Smrg					  crtc->gamma_blue,
319339413783Smrg					  crtc->gamma_size);
319439413783Smrg	    }
319539413783Smrg	}
319618781e08Smrg    }
319739413783Smrg
319818781e08Smrg    return TRUE;
319918781e08Smrg}
32007314432eSmrg
320118781e08Smrgstatic Bool
320218781e08Smrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi,
320318781e08Smrg		    int *num_hdmi)
320418781e08Smrg{
320518781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
320618781e08Smrg	int i;
32077314432eSmrg
320818781e08Smrg	for (i = 0; i < config->num_output; i++) {
320918781e08Smrg		xf86OutputPtr output = config->output[i];
321018781e08Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
321118781e08Smrg
321218781e08Smrg		if (drmmode_output->output_id == output_id) {
321318781e08Smrg			switch(drmmode_output->mode_output->connector_type) {
321418781e08Smrg			case DRM_MODE_CONNECTOR_DVII:
321518781e08Smrg			case DRM_MODE_CONNECTOR_DVID:
321618781e08Smrg			case DRM_MODE_CONNECTOR_DVIA:
321718781e08Smrg				(*num_dvi)++;
321818781e08Smrg				break;
321918781e08Smrg			case DRM_MODE_CONNECTOR_HDMIA:
322018781e08Smrg			case DRM_MODE_CONNECTOR_HDMIB:
322118781e08Smrg				(*num_hdmi)++;
322218781e08Smrg				break;
322318781e08Smrg			}
322418781e08Smrg
322518781e08Smrg			return TRUE;
322618781e08Smrg		}
322718781e08Smrg	}
322818781e08Smrg
322918781e08Smrg	return FALSE;
32307314432eSmrg}
32317314432eSmrg
323218781e08Smrgvoid
323318781e08Smrgradeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode)
32340d16fef4Smrg{
323518781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
323618781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
323718781e08Smrg	drmModeResPtr mode_res;
323818781e08Smrg	int i, j;
323918781e08Smrg	Bool found;
324018781e08Smrg	Bool changed = FALSE;
324118781e08Smrg	int num_dvi = 0, num_hdmi = 0;
324218781e08Smrg
32438bf5c682Smrg	/* Try to re-set the mode on all the connectors with a BAD link-state:
32448bf5c682Smrg	 * This may happen if a link degrades and a new modeset is necessary, using
32458bf5c682Smrg	 * different link-training parameters. If the kernel found that the current
32468bf5c682Smrg	 * mode is not achievable anymore, it should have pruned the mode before
32478bf5c682Smrg	 * sending the hotplug event. Try to re-set the currently-set mode to keep
32488bf5c682Smrg	 * the display alive, this will fail if the mode has been pruned.
32498bf5c682Smrg	 * In any case, we will send randr events for the Desktop Environment to
32508bf5c682Smrg	 * deal with it, if it wants to.
32518bf5c682Smrg	 */
32528bf5c682Smrg	for (i = 0; i < config->num_output; i++) {
32538bf5c682Smrg		xf86OutputPtr output = config->output[i];
32548bf5c682Smrg		xf86CrtcPtr crtc = output->crtc;
32558bf5c682Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
32568bf5c682Smrg
32578bf5c682Smrg		drmmode_output_detect(output);
32588bf5c682Smrg
32598bf5c682Smrg		if (!crtc || !drmmode_output->mode_output)
32608bf5c682Smrg			continue;
32618bf5c682Smrg
32628bf5c682Smrg		/* Get an updated view of the properties for the current connector and
32638bf5c682Smrg		 * look for the link-status property
32648bf5c682Smrg		 */
32658bf5c682Smrg		for (j = 0; j < drmmode_output->num_props; j++) {
32668bf5c682Smrg			drmmode_prop_ptr p = &drmmode_output->props[j];
32678bf5c682Smrg
32688bf5c682Smrg			if (!strcmp(p->mode_prop->name, "link-status")) {
32698bf5c682Smrg				if (p->value != DRM_MODE_LINK_STATUS_BAD)
32708bf5c682Smrg					break;
32718bf5c682Smrg
32728bf5c682Smrg				/* the connector got a link failure, re-set the current mode */
32738bf5c682Smrg				drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
32748bf5c682Smrg						       crtc->x, crtc->y);
32758bf5c682Smrg
32768bf5c682Smrg				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
32778bf5c682Smrg					   "hotplug event: connector %u's link-state is BAD, "
32788bf5c682Smrg					   "tried resetting the current mode. You may be left"
32798bf5c682Smrg					   "with a black screen if this fails...\n",
32808bf5c682Smrg					   drmmode_output->mode_output->connector_id);
32818bf5c682Smrg
32828bf5c682Smrg				break;
32838bf5c682Smrg			}
32848bf5c682Smrg		}
32858bf5c682Smrg	}
32868bf5c682Smrg
32878bf5c682Smrg	mode_res = drmModeGetResources(pRADEONEnt->fd);
328818781e08Smrg	if (!mode_res)
328918781e08Smrg		goto out;
329018781e08Smrg
329118781e08Smrgrestart_destroy:
329218781e08Smrg	for (i = 0; i < config->num_output; i++) {
329318781e08Smrg		xf86OutputPtr output = config->output[i];
329418781e08Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
329518781e08Smrg		found = FALSE;
329618781e08Smrg		for (j = 0; j < mode_res->count_connectors; j++) {
329718781e08Smrg			if (mode_res->connectors[j] == drmmode_output->output_id) {
329818781e08Smrg				found = TRUE;
329918781e08Smrg				break;
330018781e08Smrg			}
330118781e08Smrg		}
330218781e08Smrg		if (found)
330318781e08Smrg			continue;
330418781e08Smrg
330518781e08Smrg		drmModeFreeConnector(drmmode_output->mode_output);
330618781e08Smrg		drmmode_output->mode_output = NULL;
330718781e08Smrg		drmmode_output->output_id = -1;
330818781e08Smrg
330918781e08Smrg		changed = TRUE;
331018781e08Smrg		if (drmmode->delete_dp_12_displays) {
331118781e08Smrg			RROutputDestroy(output->randr_output);
331218781e08Smrg			xf86OutputDestroy(output);
331318781e08Smrg			goto restart_destroy;
331418781e08Smrg		}
331518781e08Smrg	}
331618781e08Smrg
331718781e08Smrg	/* find new output ids we don't have outputs for */
331818781e08Smrg	for (i = 0; i < mode_res->count_connectors; i++) {
3319446f62d6Smrg		for (j = 0; j < pRADEONEnt->num_scrns; j++) {
3320446f62d6Smrg			if (drmmode_find_output(pRADEONEnt->scrn[j],
3321446f62d6Smrg						mode_res->connectors[i],
3322446f62d6Smrg						&num_dvi, &num_hdmi))
3323446f62d6Smrg				break;
3324446f62d6Smrg		}
3325446f62d6Smrg
3326446f62d6Smrg		if (j < pRADEONEnt->num_scrns)
332718781e08Smrg			continue;
332818781e08Smrg
332918781e08Smrg		if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi,
333018781e08Smrg					&num_hdmi, 1) != 0)
333118781e08Smrg			changed = TRUE;
333218781e08Smrg	}
333318781e08Smrg
333439413783Smrg	/* Check to see if a lessee has disappeared */
333539413783Smrg	drmmode_validate_leases(scrn);
333639413783Smrg
3337446f62d6Smrg	if (changed) {
333818781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0)
333918781e08Smrg		RRSetChanged(xf86ScrnToScreen(scrn));
334018781e08Smrg#else
334118781e08Smrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen);
334218781e08Smrg		rrScrPriv->changed = TRUE;
33430d16fef4Smrg#endif
334418781e08Smrg		RRTellChanged(xf86ScrnToScreen(scrn));
334518781e08Smrg	}
33467821949aSmrg
334718781e08Smrg	drmModeFreeResources(mode_res);
334818781e08Smrgout:
334918781e08Smrg	RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
335018781e08Smrg}
3351de2362d3Smrg#ifdef HAVE_LIBUDEV
3352de2362d3Smrgstatic void
3353de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure)
3354de2362d3Smrg{
3355de2362d3Smrg	drmmode_ptr drmmode = closure;
3356de2362d3Smrg	ScrnInfoPtr scrn = drmmode->scrn;
3357de2362d3Smrg	struct udev_device *dev;
335818781e08Smrg	Bool received = FALSE;
33593ed65abbSmrg	struct timeval tv = { 0, 0 };
33603ed65abbSmrg	fd_set readfd;
33613ed65abbSmrg
33623ed65abbSmrg	FD_ZERO(&readfd);
33633ed65abbSmrg	FD_SET(fd, &readfd);
33643ed65abbSmrg
33653ed65abbSmrg	while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 &&
33663ed65abbSmrg	       FD_ISSET(fd, &readfd)) {
33673ed65abbSmrg		/* select() ensured that this will not block */
33683ed65abbSmrg		dev = udev_monitor_receive_device(drmmode->uevent_monitor);
33693ed65abbSmrg		if (dev) {
33703ed65abbSmrg			udev_device_unref(dev);
33713ed65abbSmrg			received = TRUE;
33723ed65abbSmrg		}
337318781e08Smrg	}
337418781e08Smrg
337518781e08Smrg	if (received)
337618781e08Smrg		radeon_mode_hotplug(scrn, drmmode);
3377de2362d3Smrg}
3378de2362d3Smrg#endif
3379de2362d3Smrg
3380de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3381de2362d3Smrg{
3382de2362d3Smrg#ifdef HAVE_LIBUDEV
3383de2362d3Smrg	struct udev *u;
3384de2362d3Smrg	struct udev_monitor *mon;
3385de2362d3Smrg
3386de2362d3Smrg	u = udev_new();
3387de2362d3Smrg	if (!u)
3388de2362d3Smrg		return;
3389de2362d3Smrg	mon = udev_monitor_new_from_netlink(u, "udev");
3390de2362d3Smrg	if (!mon) {
3391de2362d3Smrg		udev_unref(u);
3392de2362d3Smrg		return;
3393de2362d3Smrg	}
3394de2362d3Smrg
3395de2362d3Smrg	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
3396de2362d3Smrg							    "drm",
3397de2362d3Smrg							    "drm_minor") < 0 ||
3398de2362d3Smrg	    udev_monitor_enable_receiving(mon) < 0) {
3399de2362d3Smrg		udev_monitor_unref(mon);
3400de2362d3Smrg		udev_unref(u);
3401de2362d3Smrg		return;
3402de2362d3Smrg	}
3403de2362d3Smrg
3404de2362d3Smrg	drmmode->uevent_handler =
3405de2362d3Smrg		xf86AddGeneralHandler(udev_monitor_get_fd(mon),
3406de2362d3Smrg				      drmmode_handle_uevents,
3407de2362d3Smrg				      drmmode);
3408de2362d3Smrg
3409de2362d3Smrg	drmmode->uevent_monitor = mon;
3410de2362d3Smrg#endif
3411de2362d3Smrg}
3412de2362d3Smrg
3413de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3414de2362d3Smrg{
3415de2362d3Smrg#ifdef HAVE_LIBUDEV
3416de2362d3Smrg	if (drmmode->uevent_handler) {
3417de2362d3Smrg		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
3418de2362d3Smrg		xf86RemoveGeneralHandler(drmmode->uevent_handler);
3419de2362d3Smrg
3420de2362d3Smrg		udev_monitor_unref(drmmode->uevent_monitor);
3421de2362d3Smrg		udev_unref(u);
3422de2362d3Smrg	}
3423de2362d3Smrg#endif
3424de2362d3Smrg}
3425de2362d3Smrg
342618781e08SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
34278bf5c682Smrg			PixmapPtr new_front, uint64_t id, void *data,
34288bf5c682Smrg			xf86CrtcPtr ref_crtc, radeon_drm_handler_proc handler,
342918781e08Smrg			radeon_drm_abort_proc abort,
34303ed65abbSmrg			enum drmmode_flip_sync flip_sync,
34313ed65abbSmrg			uint32_t target_msc)
3432de2362d3Smrg{
34333ed65abbSmrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
3434de2362d3Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
343518781e08Smrg	xf86CrtcPtr crtc = NULL;
3436de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
3437446f62d6Smrg	int crtc_id;
34383ed65abbSmrg	uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0;
3439de2362d3Smrg	drmmode_flipdata_ptr flipdata;
344039413783Smrg	Bool handle_deferred = FALSE;
344118781e08Smrg	uintptr_t drm_queue_seq = 0;
344239413783Smrg	struct drmmode_fb *fb;
344339413783Smrg	int i = 0;
3444de2362d3Smrg
3445446f62d6Smrg	flipdata = calloc(1, sizeof(*flipdata) + drmmode_crtc->drmmode->count_crtcs *
344639413783Smrg			  sizeof(flipdata->fb[0]));
34477821949aSmrg        if (!flipdata) {
34487821949aSmrg             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
34497821949aSmrg                        "flip queue: data alloc failed.\n");
345018781e08Smrg             goto error;
34517821949aSmrg        }
345218781e08Smrg
345339413783Smrg	fb = radeon_pixmap_get_fb(new_front);
345439413783Smrg	if (!fb) {
34558bf5c682Smrg		ErrorF("Failed to get FB for flip\n");
345618781e08Smrg		goto error;
34578bf5c682Smrg	}
345818781e08Smrg
3459de2362d3Smrg	/*
3460de2362d3Smrg	 * Queue flips on all enabled CRTCs
3461de2362d3Smrg	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
3462de2362d3Smrg	 * Right now it assumes a single shared fb across all CRTCs, with the
3463de2362d3Smrg	 * kernel fixing up the offset of each CRTC as necessary.
3464de2362d3Smrg	 *
3465de2362d3Smrg	 * Also, flips queued on disabled or incorrectly configured displays
3466de2362d3Smrg	 * may never complete; this is a configuration error.
3467de2362d3Smrg	 */
3468de2362d3Smrg
3469de2362d3Smrg        flipdata->event_data = data;
347018781e08Smrg        flipdata->handler = handler;
347118781e08Smrg        flipdata->abort = abort;
34728bf5c682Smrg        flipdata->fe_crtc = ref_crtc;
347318781e08Smrg
3474de2362d3Smrg	for (i = 0; i < config->num_crtc; i++) {
347518781e08Smrg		crtc = config->crtc[i];
34768bf5c682Smrg		drmmode_crtc = crtc->driver_private;
3477446f62d6Smrg		crtc_id = drmmode_get_crtc_id(crtc);
347818781e08Smrg
34798bf5c682Smrg		if (!drmmode_crtc_can_flip(crtc) ||
34808bf5c682Smrg		    (drmmode_crtc->tear_free && crtc != ref_crtc))
3481de2362d3Smrg			continue;
3482de2362d3Smrg
3483de2362d3Smrg		flipdata->flip_count++;
348418781e08Smrg
348518781e08Smrg		drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id,
348618781e08Smrg						       flipdata,
348718781e08Smrg						       drmmode_flip_handler,
3488446f62d6Smrg						       drmmode_flip_abort,
3489446f62d6Smrg						       TRUE);
349018781e08Smrg		if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
349118781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
349218781e08Smrg				   "Allocating DRM queue event entry failed.\n");
349318781e08Smrg			goto error;
349418781e08Smrg		}
3495de2362d3Smrg
34968bf5c682Smrg		if (drmmode_crtc->tear_free) {
34978bf5c682Smrg			BoxRec extents = { .x1 = 0, .y1 = 0,
34988bf5c682Smrg					   .x2 = new_front->drawable.width,
34998bf5c682Smrg					   .y2 = new_front->drawable.height };
35008bf5c682Smrg			int scanout_id = drmmode_crtc->scanout_id ^ 1;
35018bf5c682Smrg
35028bf5c682Smrg			if (flip_sync == FLIP_ASYNC) {
35038bf5c682Smrg				if (!drmmode_wait_vblank(crtc,
35048bf5c682Smrg							 DRM_VBLANK_RELATIVE |
35058bf5c682Smrg							 DRM_VBLANK_EVENT,
35068bf5c682Smrg							 0, drm_queue_seq,
35078bf5c682Smrg							 NULL, NULL))
35088bf5c682Smrg					goto flip_error;
35098bf5c682Smrg				goto next;
35108bf5c682Smrg			}
35118bf5c682Smrg
3512446f62d6Smrg			drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[crtc_id],
351339413783Smrg					     radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap));
3514446f62d6Smrg			if (!flipdata->fb[crtc_id]) {
35158bf5c682Smrg				ErrorF("Failed to get FB for TearFree flip\n");
35168bf5c682Smrg				goto error;
35178bf5c682Smrg			}
35188bf5c682Smrg
35198bf5c682Smrg			radeon_scanout_do_update(crtc, scanout_id, new_front,
352039413783Smrg						 extents);
352139413783Smrg			radeon_cs_flush_indirect(crtc->scrn);
352239413783Smrg
352339413783Smrg			if (drmmode_crtc->scanout_update_pending) {
352439413783Smrg				radeon_drm_wait_pending_flip(crtc);
352539413783Smrg				handle_deferred = TRUE;
352639413783Smrg				radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending);
352739413783Smrg				drmmode_crtc->scanout_update_pending = 0;
352839413783Smrg			}
352939413783Smrg		} else {
3530446f62d6Smrg			drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[crtc_id], fb);
35318bf5c682Smrg		}
35328bf5c682Smrg
35338bf5c682Smrg		if (crtc == ref_crtc) {
35343ed65abbSmrg			if (drmmode_page_flip_target_absolute(pRADEONEnt,
35353ed65abbSmrg							      drmmode_crtc,
3536446f62d6Smrg							      flipdata->fb[crtc_id]->handle,
35373ed65abbSmrg							      flip_flags,
35383ed65abbSmrg							      drm_queue_seq,
35393ed65abbSmrg							      target_msc) != 0)
35403ed65abbSmrg				goto flip_error;
35413ed65abbSmrg		} else {
35423ed65abbSmrg			if (drmmode_page_flip_target_relative(pRADEONEnt,
35433ed65abbSmrg							      drmmode_crtc,
3544446f62d6Smrg							      flipdata->fb[crtc_id]->handle,
35453ed65abbSmrg							      flip_flags,
35463ed65abbSmrg							      drm_queue_seq, 0) != 0)
35473ed65abbSmrg				goto flip_error;
3548de2362d3Smrg		}
35493ed65abbSmrg
35508bf5c682Smrg		if (drmmode_crtc->tear_free) {
35518bf5c682Smrg			drmmode_crtc->scanout_id ^= 1;
35528bf5c682Smrg			drmmode_crtc->ignore_damage = TRUE;
35538bf5c682Smrg		}
35548bf5c682Smrg
355539413783Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending,
3556446f62d6Smrg				     flipdata->fb[crtc_id]);
3557446f62d6Smrg
3558446f62d6Smrg	next:
355918781e08Smrg		drm_queue_seq = 0;
3560de2362d3Smrg	}
3561de2362d3Smrg
356239413783Smrg	if (handle_deferred)
356339413783Smrg		radeon_drm_queue_handle_deferred(ref_crtc);
356418781e08Smrg	if (flipdata->flip_count > 0)
356518781e08Smrg		return TRUE;
35660d16fef4Smrg
35673ed65abbSmrgflip_error:
35683ed65abbSmrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n",
35693ed65abbSmrg		   strerror(errno));
35703ed65abbSmrg
357118781e08Smrgerror:
357218781e08Smrg	if (drm_queue_seq)
357318781e08Smrg		radeon_drm_abort_entry(drm_queue_seq);
357418781e08Smrg	else if (crtc)
357518781e08Smrg		drmmode_flip_abort(crtc, flipdata);
35763ed65abbSmrg	else {
35773ed65abbSmrg		abort(NULL, data);
357818781e08Smrg		free(flipdata);
35793ed65abbSmrg	}
3580de2362d3Smrg
3581de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
3582de2362d3Smrg		   strerror(errno));
358339413783Smrg	if (handle_deferred)
358439413783Smrg		radeon_drm_queue_handle_deferred(ref_crtc);
3585de2362d3Smrg	return FALSE;
3586de2362d3Smrg}
3587