drmmode_display.c revision 39413783
1de2362d3Smrg/*
2de2362d3Smrg * Copyright © 2007 Red Hat, Inc.
3de2362d3Smrg *
4de2362d3Smrg * Permission is hereby granted, free of charge, to any person obtaining a
5de2362d3Smrg * copy of this software and associated documentation files (the "Software"),
6de2362d3Smrg * to deal in the Software without restriction, including without limitation
7de2362d3Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8de2362d3Smrg * and/or sell copies of the Software, and to permit persons to whom the
9de2362d3Smrg * Software is furnished to do so, subject to the following conditions:
10de2362d3Smrg *
11de2362d3Smrg * The above copyright notice and this permission notice (including the next
12de2362d3Smrg * paragraph) shall be included in all copies or substantial portions of the
13de2362d3Smrg * Software.
14de2362d3Smrg *
15de2362d3Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16de2362d3Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17de2362d3Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18de2362d3Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19de2362d3Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20de2362d3Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21de2362d3Smrg * SOFTWARE.
22de2362d3Smrg *
23de2362d3Smrg * Authors:
24de2362d3Smrg *    Dave Airlie <airlied@redhat.com>
25de2362d3Smrg *
26de2362d3Smrg */
27de2362d3Smrg
28de2362d3Smrg#ifdef HAVE_CONFIG_H
29de2362d3Smrg#include "config.h"
30de2362d3Smrg#endif
31de2362d3Smrg
32de2362d3Smrg#include <errno.h>
33de2362d3Smrg#include <sys/ioctl.h>
3418781e08Smrg#include <time.h>
3518781e08Smrg#include "cursorstr.h"
3618781e08Smrg#include "damagestr.h"
378bf5c682Smrg#include "inputstr.h"
388bf5c682Smrg#include "list.h"
39de2362d3Smrg#include "micmap.h"
4039413783Smrg#include "mipointrst.h"
41de2362d3Smrg#include "xf86cmap.h"
4218781e08Smrg#include "xf86Priv.h"
43de2362d3Smrg#include "radeon.h"
4418781e08Smrg#include "radeon_bo_helper.h"
4518781e08Smrg#include "radeon_glamor.h"
46de2362d3Smrg#include "radeon_reg.h"
4718781e08Smrg
4818781e08Smrg#include <dri.h>
49de2362d3Smrg
50de2362d3Smrg#include "drmmode_display.h"
51de2362d3Smrg
52de2362d3Smrg/* DPMS */
53de2362d3Smrg#ifdef HAVE_XEXTPROTO_71
54de2362d3Smrg#include <X11/extensions/dpmsconst.h>
55de2362d3Smrg#else
56de2362d3Smrg#define DPMS_SERVER
57de2362d3Smrg#include <X11/extensions/dpms.h>
58de2362d3Smrg#endif
59de2362d3Smrg
6018781e08Smrg#define DEFAULT_NOMINAL_FRAME_RATE 60
6118781e08Smrg
6218781e08Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 22
6318781e08Smrg#define HAVE_NOTIFY_FD	1
6418781e08Smrg#endif
6518781e08Smrg
6618781e08Smrgstatic Bool
6718781e08Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height);
6818781e08Smrg
6918781e08Smrgstatic Bool
7018781e08SmrgRADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name)
7118781e08Smrg{
7218781e08Smrg    int i = 0;
7318781e08Smrg    char s1[20];
7418781e08Smrg
7518781e08Smrg    do {
7618781e08Smrg	switch(*s) {
7718781e08Smrg	case ',':
7818781e08Smrg  	    s1[i] = '\0';
7918781e08Smrg	    i = 0;
8018781e08Smrg	    if (strcmp(s1, output_name) == 0)
8118781e08Smrg		return TRUE;
8218781e08Smrg	    break;
8318781e08Smrg	case ' ':
8418781e08Smrg	case '\t':
8518781e08Smrg	case '\n':
8618781e08Smrg	case '\r':
8718781e08Smrg	    break;
8818781e08Smrg	default:
8918781e08Smrg	    s1[i] = *s;
9018781e08Smrg	    i++;
9118781e08Smrg	    break;
9218781e08Smrg	}
9318781e08Smrg    } while(*s++);
9418781e08Smrg
9518781e08Smrg    s1[i] = '\0';
9618781e08Smrg    if (strcmp(s1, output_name) == 0)
9718781e08Smrg	return TRUE;
9818781e08Smrg
9918781e08Smrg    return FALSE;
10018781e08Smrg}
10118781e08Smrg
1028bf5c682Smrg
103de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
104de2362d3Smrg					  int width, int height,
105de2362d3Smrg					  int depth, int bpp,
10618781e08Smrg					  int pitch,
10739413783Smrg					  struct radeon_buffer *bo)
108de2362d3Smrg{
109de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
110de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
111de2362d3Smrg	PixmapPtr pixmap;
112de2362d3Smrg
11318781e08Smrg	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth,
11418781e08Smrg					  RADEON_CREATE_PIXMAP_SCANOUT);
115de2362d3Smrg	if (!pixmap)
116de2362d3Smrg		return NULL;
117de2362d3Smrg
1187314432eSmrg	if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height,
1197314432eSmrg					    depth, bpp, pitch, NULL)) {
12018781e08Smrg		goto fail;
1217314432eSmrg	}
1227314432eSmrg
12318781e08Smrg	if (!info->use_glamor)
12418781e08Smrg		exaMoveInPixmap(pixmap);
12518781e08Smrg
12618781e08Smrg	if (!radeon_set_pixmap_bo(pixmap, bo))
12718781e08Smrg		goto fail;
12818781e08Smrg
12939413783Smrg	if (info->surf_man && !info->use_glamor) {
13039413783Smrg		struct radeon_surface *surface = radeon_get_pixmap_surface(pixmap);
13139413783Smrg
13239413783Smrg		if (!radeon_surface_initialize(info, surface, width, height, bpp / 8,
13339413783Smrg					       radeon_get_pixmap_tiling_flags(pixmap), 0))
13439413783Smrg			goto fail;
135de2362d3Smrg	}
136de2362d3Smrg
13718781e08Smrg	if (!info->use_glamor ||
13839413783Smrg	    radeon_glamor_create_textured_pixmap(pixmap, bo))
13918781e08Smrg		return pixmap;
14018781e08Smrg
14118781e08Smrgfail:
14218781e08Smrg	pScreen->DestroyPixmap(pixmap);
14318781e08Smrg	return NULL;
144de2362d3Smrg}
145de2362d3Smrg
146de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
147de2362d3Smrg{
148de2362d3Smrg	ScreenPtr pScreen = pixmap->drawable.pScreen;
149de2362d3Smrg
150de2362d3Smrg	(*pScreen->DestroyPixmap)(pixmap);
151de2362d3Smrg}
152de2362d3Smrg
153de2362d3Smrgstatic void
154de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr	scrn,
155de2362d3Smrg		     drmModeModeInfo *kmode,
156de2362d3Smrg		     DisplayModePtr	mode)
157de2362d3Smrg{
158de2362d3Smrg	memset(mode, 0, sizeof(DisplayModeRec));
159de2362d3Smrg	mode->status = MODE_OK;
160de2362d3Smrg
161de2362d3Smrg	mode->Clock = kmode->clock;
162de2362d3Smrg
163de2362d3Smrg	mode->HDisplay = kmode->hdisplay;
164de2362d3Smrg	mode->HSyncStart = kmode->hsync_start;
165de2362d3Smrg	mode->HSyncEnd = kmode->hsync_end;
166de2362d3Smrg	mode->HTotal = kmode->htotal;
167de2362d3Smrg	mode->HSkew = kmode->hskew;
168de2362d3Smrg
169de2362d3Smrg	mode->VDisplay = kmode->vdisplay;
170de2362d3Smrg	mode->VSyncStart = kmode->vsync_start;
171de2362d3Smrg	mode->VSyncEnd = kmode->vsync_end;
172de2362d3Smrg	mode->VTotal = kmode->vtotal;
173de2362d3Smrg	mode->VScan = kmode->vscan;
174de2362d3Smrg
175de2362d3Smrg	mode->Flags = kmode->flags; //& FLAG_BITS;
176de2362d3Smrg	mode->name = strdup(kmode->name);
177de2362d3Smrg
178de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_DRIVER)
179de2362d3Smrg		mode->type = M_T_DRIVER;
180de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
181de2362d3Smrg		mode->type |= M_T_PREFERRED;
182de2362d3Smrg	xf86SetModeCrtc (mode, scrn->adjustFlags);
183de2362d3Smrg}
184de2362d3Smrg
185de2362d3Smrgstatic void
186de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr	scrn,
187de2362d3Smrg		     drmModeModeInfo *kmode,
188de2362d3Smrg		     DisplayModePtr	mode)
189de2362d3Smrg{
190de2362d3Smrg	memset(kmode, 0, sizeof(*kmode));
191de2362d3Smrg
192de2362d3Smrg	kmode->clock = mode->Clock;
193de2362d3Smrg	kmode->hdisplay = mode->HDisplay;
194de2362d3Smrg	kmode->hsync_start = mode->HSyncStart;
195de2362d3Smrg	kmode->hsync_end = mode->HSyncEnd;
196de2362d3Smrg	kmode->htotal = mode->HTotal;
197de2362d3Smrg	kmode->hskew = mode->HSkew;
198de2362d3Smrg
199de2362d3Smrg	kmode->vdisplay = mode->VDisplay;
200de2362d3Smrg	kmode->vsync_start = mode->VSyncStart;
201de2362d3Smrg	kmode->vsync_end = mode->VSyncEnd;
202de2362d3Smrg	kmode->vtotal = mode->VTotal;
203de2362d3Smrg	kmode->vscan = mode->VScan;
204de2362d3Smrg
205de2362d3Smrg	kmode->flags = mode->Flags; //& FLAG_BITS;
206de2362d3Smrg	if (mode->name)
207de2362d3Smrg		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
208de2362d3Smrg	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
209de2362d3Smrg
210de2362d3Smrg}
211de2362d3Smrg
2128bf5c682Smrg/*
2138bf5c682Smrg * Utility helper for drmWaitVBlank
2148bf5c682Smrg */
2158bf5c682SmrgBool
2168bf5c682Smrgdrmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type,
2178bf5c682Smrg		    uint32_t target_seq, unsigned long signal, uint64_t *ust,
2188bf5c682Smrg		    uint32_t *result_seq)
2198bf5c682Smrg{
2208bf5c682Smrg	int crtc_id = drmmode_get_crtc_id(crtc);
2218bf5c682Smrg	ScrnInfoPtr scrn = crtc->scrn;
2228bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
2238bf5c682Smrg	drmVBlank vbl;
2248bf5c682Smrg
2258bf5c682Smrg	if (crtc_id == 1)
2268bf5c682Smrg		type |= DRM_VBLANK_SECONDARY;
2278bf5c682Smrg	else if (crtc_id > 1)
2288bf5c682Smrg		type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) &
2298bf5c682Smrg			DRM_VBLANK_HIGH_CRTC_MASK;
2308bf5c682Smrg
2318bf5c682Smrg	vbl.request.type = type;
2328bf5c682Smrg	vbl.request.sequence = target_seq;
2338bf5c682Smrg	vbl.request.signal = signal;
2348bf5c682Smrg
2358bf5c682Smrg	if (drmWaitVBlank(pRADEONEnt->fd, &vbl) != 0)
2368bf5c682Smrg		return FALSE;
2378bf5c682Smrg
2388bf5c682Smrg	if (ust)
2398bf5c682Smrg		*ust = (uint64_t)vbl.reply.tval_sec * 1000000 +
2408bf5c682Smrg			vbl.reply.tval_usec;
2418bf5c682Smrg	if (result_seq)
2428bf5c682Smrg		*result_seq = vbl.reply.sequence;
2438bf5c682Smrg
2448bf5c682Smrg	return TRUE;
2458bf5c682Smrg}
2468bf5c682Smrg
24718781e08Smrg/*
24818781e08Smrg * Retrieves present time in microseconds that is compatible
24918781e08Smrg * with units used by vblank timestamps. Depending on the kernel
25018781e08Smrg * version and DRM kernel module configuration, the vblank
25118781e08Smrg * timestamp can either be in real time or monotonic time
25218781e08Smrg */
25318781e08Smrgint drmmode_get_current_ust(int drm_fd, CARD64 *ust)
25418781e08Smrg{
25518781e08Smrg	uint64_t cap_value;
25618781e08Smrg	int ret;
25718781e08Smrg	struct timespec now;
25818781e08Smrg
25918781e08Smrg	ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value);
26018781e08Smrg	if (ret || !cap_value)
26118781e08Smrg		/* old kernel or drm_timestamp_monotonic turned off */
26218781e08Smrg		ret = clock_gettime(CLOCK_REALTIME, &now);
26318781e08Smrg	else
26418781e08Smrg		ret = clock_gettime(CLOCK_MONOTONIC, &now);
26518781e08Smrg	if (ret)
26618781e08Smrg		return ret;
26718781e08Smrg	*ust = ((CARD64)now.tv_sec * 1000000) + ((CARD64)now.tv_nsec / 1000);
26818781e08Smrg	return 0;
26918781e08Smrg}
27018781e08Smrg
27118781e08Smrg/*
27218781e08Smrg * Get current frame count and frame count timestamp of the crtc.
27318781e08Smrg */
27418781e08Smrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)
27518781e08Smrg{
27618781e08Smrg    ScrnInfoPtr scrn = crtc->scrn;
2778bf5c682Smrg    uint32_t seq;
27818781e08Smrg
2798bf5c682Smrg    if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) {
28018781e08Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
28118781e08Smrg		   "get vblank counter failed: %s\n", strerror(errno));
2828bf5c682Smrg	return -1;
28318781e08Smrg    }
28418781e08Smrg
2858bf5c682Smrg    *msc = seq;
28618781e08Smrg
28718781e08Smrg    return Success;
28818781e08Smrg}
28918781e08Smrg
290de2362d3Smrgstatic void
29118781e08Smrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
292de2362d3Smrg{
293de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
29418781e08Smrg	ScrnInfoPtr scrn = crtc->scrn;
2958bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
29618781e08Smrg	CARD64 ust;
29718781e08Smrg	int ret;
2987314432eSmrg
29918781e08Smrg	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
3008bf5c682Smrg		uint32_t seq;
30118781e08Smrg
30239413783Smrg		radeon_drm_wait_pending_flip(crtc);
30318781e08Smrg
30418781e08Smrg		/*
30518781e08Smrg		 * On->Off transition: record the last vblank time,
30618781e08Smrg		 * sequence number and frame period.
30718781e08Smrg		 */
3088bf5c682Smrg		if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust,
3098bf5c682Smrg					 &seq))
31018781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
31118781e08Smrg				   "%s cannot get last vblank counter\n",
31218781e08Smrg				   __func__);
31318781e08Smrg		else {
31418781e08Smrg			CARD64 nominal_frame_rate, pix_in_frame;
31518781e08Smrg
31618781e08Smrg			drmmode_crtc->dpms_last_ust = ust;
31718781e08Smrg			drmmode_crtc->dpms_last_seq = seq;
31818781e08Smrg			nominal_frame_rate = crtc->mode.Clock;
31918781e08Smrg			nominal_frame_rate *= 1000;
32018781e08Smrg			pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal;
32118781e08Smrg			if (nominal_frame_rate == 0 || pix_in_frame == 0)
32218781e08Smrg				nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE;
32318781e08Smrg			else
32418781e08Smrg				nominal_frame_rate /= pix_in_frame;
32518781e08Smrg			drmmode_crtc->dpms_last_fps = nominal_frame_rate;
32618781e08Smrg		}
32739413783Smrg
32839413783Smrg		drmmode_crtc->dpms_mode = mode;
32939413783Smrg		radeon_drm_queue_handle_deferred(crtc);
33018781e08Smrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) {
33118781e08Smrg		/*
33218781e08Smrg		 * Off->On transition: calculate and accumulate the
33318781e08Smrg		 * number of interpolated vblanks while we were in Off state
33418781e08Smrg		 */
3358bf5c682Smrg		ret = drmmode_get_current_ust(pRADEONEnt->fd, &ust);
33618781e08Smrg		if (ret)
33718781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
33818781e08Smrg				   "%s cannot get current time\n", __func__);
33918781e08Smrg		else if (drmmode_crtc->dpms_last_ust) {
34018781e08Smrg			CARD64 time_elapsed, delta_seq;
34118781e08Smrg			time_elapsed = ust - drmmode_crtc->dpms_last_ust;
34218781e08Smrg			delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps;
34318781e08Smrg			delta_seq /= 1000000;
34418781e08Smrg			drmmode_crtc->interpolated_vblanks += delta_seq;
34518781e08Smrg
34618781e08Smrg		}
34739413783Smrg
34839413783Smrg		drmmode_crtc->dpms_mode = DPMSModeOn;
3497821949aSmrg	}
35018781e08Smrg}
35118781e08Smrg
35218781e08Smrgstatic void
35318781e08Smrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
35418781e08Smrg{
35518781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3568bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
35718781e08Smrg
35818781e08Smrg	/* Disable unused CRTCs */
35918781e08Smrg	if (!crtc->enabled || mode != DPMSModeOn) {
36039413783Smrg		drmmode_do_crtc_dpms(crtc, DPMSModeOff);
3618bf5c682Smrg		drmModeSetCrtc(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
36218781e08Smrg			       0, 0, 0, NULL, 0, NULL);
3638bf5c682Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL);
36418781e08Smrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn)
36518781e08Smrg		crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
36618781e08Smrg					    crtc->x, crtc->y);
367de2362d3Smrg}
368de2362d3Smrg
369de2362d3Smrgstatic PixmapPtr
370de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode,
371de2362d3Smrg			ScrnInfoPtr pScrn, int fbcon_id)
372de2362d3Smrg{
3738bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
37418781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
37518781e08Smrg	PixmapPtr pixmap = info->fbcon_pixmap;
37639413783Smrg	struct radeon_buffer *bo;
377de2362d3Smrg	drmModeFBPtr fbcon;
378de2362d3Smrg	struct drm_gem_flink flink;
379de2362d3Smrg
38018781e08Smrg	if (pixmap)
38118781e08Smrg	    return pixmap;
38218781e08Smrg
3838bf5c682Smrg	fbcon = drmModeGetFB(pRADEONEnt->fd, fbcon_id);
38439413783Smrg	if (!fbcon)
385de2362d3Smrg		return NULL;
386de2362d3Smrg
387de2362d3Smrg	if (fbcon->depth != pScrn->depth ||
388de2362d3Smrg	    fbcon->width != pScrn->virtualX ||
389de2362d3Smrg	    fbcon->height != pScrn->virtualY)
390de2362d3Smrg		goto out_free_fb;
391de2362d3Smrg
392de2362d3Smrg	flink.handle = fbcon->handle;
3938bf5c682Smrg	if (ioctl(pRADEONEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
394de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
395de2362d3Smrg			   "Couldn't flink fbcon handle\n");
396de2362d3Smrg		goto out_free_fb;
397de2362d3Smrg	}
398de2362d3Smrg
39939413783Smrg	bo = calloc(1, sizeof(struct radeon_buffer));
40039413783Smrg	if (!bo) {
401de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
40239413783Smrg			   "Couldn't allocate BO for fbcon handle\n");
40339413783Smrg		goto out_free_fb;
40439413783Smrg	}
40539413783Smrg	bo->ref_count = 1;
40639413783Smrg
40739413783Smrg	bo->bo.radeon = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0);
40839413783Smrg	if (!bo) {
40939413783Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
41039413783Smrg			   "Couldn't open BO for fbcon handle\n");
411de2362d3Smrg		goto out_free_fb;
412de2362d3Smrg	}
413de2362d3Smrg
414de2362d3Smrg	pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height,
41518781e08Smrg					  fbcon->depth, fbcon->bpp, fbcon->pitch,
41639413783Smrg					  bo);
41718781e08Smrg	info->fbcon_pixmap = pixmap;
41839413783Smrg	radeon_buffer_unref(&bo);
419de2362d3Smrgout_free_fb:
420de2362d3Smrg	drmModeFreeFB(fbcon);
421de2362d3Smrg	return pixmap;
422de2362d3Smrg}
423de2362d3Smrg
42418781e08Smrgstatic void
42518781e08Smrgdestroy_pixmap_for_fbcon(ScrnInfoPtr pScrn)
42618781e08Smrg{
42718781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
42818781e08Smrg
42918781e08Smrg	/* XXX: The current GPUVM support in the kernel doesn't allow removing
43018781e08Smrg	 * the virtual address range for this BO, so we need to keep around
43118781e08Smrg	 * the pixmap to avoid breaking glamor with GPUVM
43239413783Smrg	 *
43339413783Smrg	 * Similarly, need to keep around the pixmap with current glamor, to
43439413783Smrg	 * avoid issues due to a GEM handle lifetime conflict between us and
43539413783Smrg	 * Mesa
43618781e08Smrg	 */
43739413783Smrg	if (info->use_glamor &&
43839413783Smrg	    (info->ChipFamily >= CHIP_FAMILY_CAYMAN ||
43939413783Smrg	     xorgGetVersion() >= XORG_VERSION_NUMERIC(1,19,99,1,0)))
44018781e08Smrg		return;
44118781e08Smrg
44218781e08Smrg	if (info->fbcon_pixmap)
44318781e08Smrg		pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap);
44418781e08Smrg	info->fbcon_pixmap = NULL;
44518781e08Smrg}
44618781e08Smrg
447de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
448de2362d3Smrg{
449de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
450de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
451de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
4528bf5c682Smrg	PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen);
4538bf5c682Smrg	struct drmmode_fb *fb = radeon_pixmap_get_fb(dst);
454de2362d3Smrg	int fbcon_id = 0;
45518781e08Smrg	Bool force;
45618781e08Smrg	GCPtr gc;
457de2362d3Smrg	int i;
458de2362d3Smrg
459de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
460de2362d3Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
461de2362d3Smrg
462de2362d3Smrg		if (drmmode_crtc->mode_crtc->buffer_id)
463de2362d3Smrg			fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
464de2362d3Smrg	}
465de2362d3Smrg
466de2362d3Smrg	if (!fbcon_id)
46718781e08Smrg		return;
46818781e08Smrg
4698bf5c682Smrg	if (fbcon_id == fb->handle) {
47018781e08Smrg		/* in some rare case there might be no fbcon and we might already
47118781e08Smrg		 * be the one with the current fb to avoid a false deadlck in
47218781e08Smrg		 * kernel ttm code just do nothing as anyway there is nothing
47318781e08Smrg		 * to do
47418781e08Smrg		 */
47518781e08Smrg		return;
47618781e08Smrg	}
477de2362d3Smrg
478de2362d3Smrg	src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
479de2362d3Smrg	if (!src)
48018781e08Smrg		return;
4810d16fef4Smrg
48218781e08Smrg	gc = GetScratchGC(pScrn->depth, pScreen);
48318781e08Smrg	ValidateGC(&dst->drawable, gc);
48418781e08Smrg
48518781e08Smrg	force = info->accel_state->force;
48618781e08Smrg	info->accel_state->force = TRUE;
48718781e08Smrg	(*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0,
48818781e08Smrg			     pScrn->virtualX, pScrn->virtualY, 0, 0);
48918781e08Smrg	info->accel_state->force = force;
49018781e08Smrg
49118781e08Smrg	FreeScratchGC(gc);
492de2362d3Smrg
493de2362d3Smrg	pScreen->canDoBGNoneRoot = TRUE;
49418781e08Smrg	destroy_pixmap_for_fbcon(pScrn);
4957821949aSmrg	return;
49618781e08Smrg}
4970d16fef4Smrg
4988bf5c682Smrgvoid
49918781e08Smrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
50018781e08Smrg			     struct drmmode_scanout *scanout)
50118781e08Smrg{
50218781e08Smrg	if (scanout->pixmap) {
50318781e08Smrg		drmmode_destroy_bo_pixmap(scanout->pixmap);
50418781e08Smrg		scanout->pixmap = NULL;
50518781e08Smrg	}
50618781e08Smrg
50739413783Smrg	radeon_buffer_unref(&scanout->bo);
50818781e08Smrg}
50918781e08Smrg
5108bf5c682Smrgvoid
51118781e08Smrgdrmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc)
51218781e08Smrg{
5138bf5c682Smrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
5148bf5c682Smrg				     &drmmode_crtc->scanout[0]);
5158bf5c682Smrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
5168bf5c682Smrg				     &drmmode_crtc->scanout[1]);
51718781e08Smrg
5188bf5c682Smrg	if (drmmode_crtc->scanout_damage)
51918781e08Smrg		DamageDestroy(drmmode_crtc->scanout_damage);
52018781e08Smrg}
52118781e08Smrg
5228bf5c682SmrgPixmapPtr
5233ed65abbSmrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
5243ed65abbSmrg			    int width, int height)
52518781e08Smrg{
52618781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
52718781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
52818781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
52918781e08Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
53018781e08Smrg	struct radeon_surface surface;
53118781e08Smrg	uint32_t tiling = RADEON_CREATE_PIXMAP_TILING_MACRO;
53218781e08Smrg	int pitch;
53318781e08Smrg
5343ed65abbSmrg	if (scanout->pixmap) {
53518781e08Smrg		if (scanout->width == width && scanout->height == height)
5363ed65abbSmrg			return scanout->pixmap;
53718781e08Smrg
53818781e08Smrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
53918781e08Smrg	}
54018781e08Smrg
54118781e08Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600)
54218781e08Smrg		tiling |= RADEON_CREATE_PIXMAP_TILING_MICRO;
54318781e08Smrg	scanout->bo = radeon_alloc_pixmap_bo(pScrn, width, height, pScrn->depth,
54418781e08Smrg					     tiling, pScrn->bitsPerPixel,
54518781e08Smrg					     &pitch, &surface, &tiling);
5468bf5c682Smrg	if (!scanout->bo) {
5478bf5c682Smrg		ErrorF("failed to create CRTC scanout BO\n");
5488bf5c682Smrg		return NULL;
54918781e08Smrg	}
55018781e08Smrg
55118781e08Smrg	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
55218781e08Smrg						 width, height,
55318781e08Smrg						 pScrn->depth,
55418781e08Smrg						 pScrn->bitsPerPixel,
55539413783Smrg						 pitch, scanout->bo);
5568bf5c682Smrg	if (!scanout->pixmap) {
5578bf5c682Smrg		ErrorF("failed to create CRTC scanout pixmap\n");
5588bf5c682Smrg		goto error;
5598bf5c682Smrg	}
5608bf5c682Smrg
5618bf5c682Smrg	if (radeon_pixmap_get_fb(scanout->pixmap)) {
5623ed65abbSmrg		scanout->width = width;
5633ed65abbSmrg		scanout->height = height;
5643ed65abbSmrg	} else {
5658bf5c682Smrg		ErrorF("failed to create CRTC scanout FB\n");
5668bf5c682Smrgerror:
5673ed65abbSmrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
5683ed65abbSmrg	}
56918781e08Smrg
57018781e08Smrg	return scanout->pixmap;
57118781e08Smrg}
57218781e08Smrg
57318781e08Smrgstatic void
57418781e08Smrgradeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
57518781e08Smrg{
5768bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = closure;
5778bf5c682Smrg
5788bf5c682Smrg	if (drmmode_crtc->ignore_damage) {
5798bf5c682Smrg		RegionEmpty(&damage->damage);
5808bf5c682Smrg		drmmode_crtc->ignore_damage = FALSE;
5818bf5c682Smrg		return;
5828bf5c682Smrg	}
5838bf5c682Smrg
58418781e08Smrg	/* Only keep track of the extents */
58518781e08Smrg	RegionUninit(&damage->damage);
58618781e08Smrg	damage->damage.data = NULL;
58718781e08Smrg}
58818781e08Smrg
5898bf5c682Smrgstatic void
5908bf5c682Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure)
5918bf5c682Smrg{
5928bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = closure;
5938bf5c682Smrg
5948bf5c682Smrg	drmmode_crtc->scanout_damage = NULL;
5958bf5c682Smrg	RegionUninit(&drmmode_crtc->scanout_last_region);
5968bf5c682Smrg}
5978bf5c682Smrg
59818781e08Smrgstatic Bool
59918781e08Smrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc)
60018781e08Smrg{
60118781e08Smrg	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
60218781e08Smrg
60318781e08Smrg	/* Check for Option "SWcursor" */
60418781e08Smrg	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
60518781e08Smrg		return FALSE;
60618781e08Smrg
60718781e08Smrg	/* Fall back to SW cursor if the CRTC is transformed */
60818781e08Smrg	if (crtc->transformPresent)
60918781e08Smrg		return FALSE;
6100d16fef4Smrg
6118bf5c682Smrg#if XF86_CRTC_VERSION < 7
61218781e08Smrg	/* Xorg doesn't correctly handle cursor position transform in the
61318781e08Smrg	 * rotation case
61418781e08Smrg	 */
61518781e08Smrg	if (crtc->driverIsPerformingTransform &&
61618781e08Smrg	    (crtc->rotation & 0xf) != RR_Rotate_0)
61718781e08Smrg		return FALSE;
61818781e08Smrg#endif
61918781e08Smrg
62018781e08Smrg	/* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */
62118781e08Smrg	if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) &&
62218781e08Smrg	    !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list))
62318781e08Smrg		return FALSE;
62418781e08Smrg
62518781e08Smrg	return TRUE;
62618781e08Smrg}
62718781e08Smrg
6283ed65abbSmrgstatic void
6293ed65abbSmrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc)
6303ed65abbSmrg{
6313ed65abbSmrg	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
6323ed65abbSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
6333ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
6343ed65abbSmrg	int i;
6353ed65abbSmrg
6363ed65abbSmrg	drmmode_crtc->tear_free = FALSE;
6373ed65abbSmrg
6383ed65abbSmrg	for (i = 0; i < xf86_config->num_output; i++) {
6393ed65abbSmrg		xf86OutputPtr output = xf86_config->output[i];
6403ed65abbSmrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
6413ed65abbSmrg
6423ed65abbSmrg		if (output->crtc != crtc)
6433ed65abbSmrg			continue;
6443ed65abbSmrg
6453ed65abbSmrg		if (drmmode_output->tear_free == 1 ||
6463ed65abbSmrg		    (drmmode_output->tear_free == 2 &&
6478bf5c682Smrg		     (crtc->scrn->pScreen->isGPU ||
6483ed65abbSmrg		      info->shadow_primary ||
6493ed65abbSmrg		      crtc->transformPresent || crtc->rotation != RR_Rotate_0))) {
6503ed65abbSmrg			drmmode_crtc->tear_free = TRUE;
6513ed65abbSmrg			return;
6523ed65abbSmrg		}
6533ed65abbSmrg	}
6543ed65abbSmrg}
6553ed65abbSmrg
6563ed65abbSmrg#if XF86_CRTC_VERSION < 7
6573ed65abbSmrg#define XF86DriverTransformOutput TRUE
6583ed65abbSmrg#define XF86DriverTransformNone FALSE
6593ed65abbSmrg#endif
6603ed65abbSmrg
66118781e08Smrgstatic Bool
66218781e08Smrgdrmmode_handle_transform(xf86CrtcPtr crtc)
66318781e08Smrg{
66418781e08Smrg	Bool ret;
66518781e08Smrg
6668bf5c682Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
66739413783Smrg	crtc->driverIsPerformingTransform = XF86DriverTransformOutput;
6688bf5c682Smrg#else
6698bf5c682Smrg	crtc->driverIsPerformingTransform = !crtc->transformPresent &&
6708bf5c682Smrg		(crtc->rotation & 0xf) == RR_Rotate_0;
6718bf5c682Smrg#endif
67218781e08Smrg
67318781e08Smrg	ret = xf86CrtcRotate(crtc);
67418781e08Smrg
67518781e08Smrg	crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use;
67618781e08Smrg
67718781e08Smrg	return ret;
6780d16fef4Smrg}
6790d16fef4Smrg
6803ed65abbSmrg
6813ed65abbSmrgstatic void
6823ed65abbSmrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
6838bf5c682Smrg				  unsigned scanout_id, struct drmmode_fb **fb,
6848bf5c682Smrg				  int *x, int *y)
6853ed65abbSmrg{
6863ed65abbSmrg	ScrnInfoPtr scrn = crtc->scrn;
6873ed65abbSmrg	ScreenPtr screen = scrn->pScreen;
6883ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
6893ed65abbSmrg
6903ed65abbSmrg	if (drmmode_crtc->tear_free &&
6913ed65abbSmrg	    !drmmode_crtc->scanout[1].pixmap) {
6923ed65abbSmrg		RegionPtr region;
6933ed65abbSmrg		BoxPtr box;
6943ed65abbSmrg
6953ed65abbSmrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
6963ed65abbSmrg					    mode->HDisplay,
6973ed65abbSmrg					    mode->VDisplay);
6983ed65abbSmrg		region = &drmmode_crtc->scanout_last_region;
6993ed65abbSmrg		RegionUninit(region);
7003ed65abbSmrg		region->data = NULL;
7013ed65abbSmrg		box = RegionExtents(region);
7023ed65abbSmrg		box->x1 = crtc->x;
7033ed65abbSmrg		box->y1 = crtc->y;
7043ed65abbSmrg		box->x2 = crtc->x + mode->HDisplay;
7053ed65abbSmrg		box->y2 = crtc->y + mode->VDisplay;
7063ed65abbSmrg	}
7073ed65abbSmrg
7083ed65abbSmrg	if (scanout_id != drmmode_crtc->scanout_id) {
7093ed65abbSmrg		PixmapDirtyUpdatePtr dirty = NULL;
7103ed65abbSmrg
7113ed65abbSmrg		xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list,
7123ed65abbSmrg					 ent) {
7138bf5c682Smrg			if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
7143ed65abbSmrg				dirty->slave_dst =
7153ed65abbSmrg					drmmode_crtc->scanout[scanout_id].pixmap;
7163ed65abbSmrg				break;
7173ed65abbSmrg			}
7183ed65abbSmrg		}
7193ed65abbSmrg
7203ed65abbSmrg		if (!drmmode_crtc->tear_free) {
7213ed65abbSmrg			GCPtr gc = GetScratchGC(scrn->depth, screen);
7223ed65abbSmrg
7233ed65abbSmrg			ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc);
7243ed65abbSmrg			gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable,
7253ed65abbSmrg					  &drmmode_crtc->scanout[0].pixmap->drawable,
7263ed65abbSmrg					  gc, 0, 0, mode->HDisplay, mode->VDisplay,
7273ed65abbSmrg					  0, 0);
7283ed65abbSmrg			FreeScratchGC(gc);
72939413783Smrg			radeon_finish(scrn, drmmode_crtc->scanout[0].bo);
7303ed65abbSmrg		}
7313ed65abbSmrg	}
7323ed65abbSmrg
7338bf5c682Smrg	*fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
7343ed65abbSmrg	*x = *y = 0;
7353ed65abbSmrg	drmmode_crtc->scanout_id = scanout_id;
7363ed65abbSmrg}
7373ed65abbSmrg
7383ed65abbSmrg
7393ed65abbSmrgstatic void
7403ed65abbSmrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
7418bf5c682Smrg			    unsigned scanout_id, struct drmmode_fb **fb, int *x,
7428bf5c682Smrg			    int *y)
7433ed65abbSmrg{
7443ed65abbSmrg	ScrnInfoPtr scrn = crtc->scrn;
7453ed65abbSmrg	ScreenPtr screen = scrn->pScreen;
7463ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
7473ed65abbSmrg
7488bf5c682Smrg	drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id],
7493ed65abbSmrg				    mode->HDisplay, mode->VDisplay);
7503ed65abbSmrg	if (drmmode_crtc->tear_free) {
7518bf5c682Smrg		drmmode_crtc_scanout_create(crtc,
7528bf5c682Smrg					    &drmmode_crtc->scanout[scanout_id ^ 1],
7533ed65abbSmrg					    mode->HDisplay, mode->VDisplay);
7543ed65abbSmrg	}
7553ed65abbSmrg
7568bf5c682Smrg	if (drmmode_crtc->scanout[scanout_id].pixmap &&
7578bf5c682Smrg	    (!drmmode_crtc->tear_free ||
7588bf5c682Smrg	     drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) {
75939413783Smrg		BoxRec extents = { .x1 = 0, .y1 = 0,
76039413783Smrg				   .x2 = scrn->virtualX, .y2 = scrn->virtualY };
7613ed65abbSmrg
7623ed65abbSmrg		if (!drmmode_crtc->scanout_damage) {
7633ed65abbSmrg			drmmode_crtc->scanout_damage =
7643ed65abbSmrg				DamageCreate(radeon_screen_damage_report,
7658bf5c682Smrg					     drmmode_screen_damage_destroy,
7668bf5c682Smrg					     DamageReportRawRegion,
7678bf5c682Smrg					     TRUE, screen, drmmode_crtc);
7688bf5c682Smrg			DamageRegister(&screen->root->drawable,
7693ed65abbSmrg				       drmmode_crtc->scanout_damage);
7703ed65abbSmrg		}
7713ed65abbSmrg
7728bf5c682Smrg		*fb = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
7733ed65abbSmrg		*x = *y = 0;
7743ed65abbSmrg
7758bf5c682Smrg		radeon_scanout_do_update(crtc, scanout_id,
7768bf5c682Smrg					 screen->GetWindowPixmap(screen->root),
77739413783Smrg					 extents);
77839413783Smrg		RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage));
77939413783Smrg		radeon_finish(scrn, drmmode_crtc->scanout[scanout_id].bo);
7803ed65abbSmrg	}
7813ed65abbSmrg}
7823ed65abbSmrg
7838bf5c682Smrgstatic void
7848bf5c682Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
7858bf5c682Smrg			  uint16_t *blue, int size)
7868bf5c682Smrg{
7878bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
7888bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
7898bf5c682Smrg
7908bf5c682Smrg	drmModeCrtcSetGamma(pRADEONEnt->fd,
7918bf5c682Smrg			    drmmode_crtc->mode_crtc->crtc_id, size, red, green,
7928bf5c682Smrg			    blue);
7938bf5c682Smrg}
7948bf5c682Smrg
7958bf5c682SmrgBool
7968bf5c682Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode,
7978bf5c682Smrg		 int x, int y)
7988bf5c682Smrg{
7998bf5c682Smrg	ScrnInfoPtr scrn = crtc->scrn;
8008bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
8018bf5c682Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
8028bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
8038bf5c682Smrg	uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
8048bf5c682Smrg	int output_count = 0;
8058bf5c682Smrg	drmModeModeInfo kmode;
8068bf5c682Smrg	Bool ret;
8078bf5c682Smrg	int i;
8088bf5c682Smrg
8098bf5c682Smrg	if (!output_ids)
8108bf5c682Smrg		return FALSE;
8118bf5c682Smrg
8128bf5c682Smrg	for (i = 0; i < xf86_config->num_output; i++) {
8138bf5c682Smrg		xf86OutputPtr output = xf86_config->output[i];
8148bf5c682Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
8158bf5c682Smrg
8168bf5c682Smrg		if (output->crtc != crtc)
8178bf5c682Smrg			continue;
8188bf5c682Smrg
8198bf5c682Smrg		output_ids[output_count] = drmmode_output->mode_output->connector_id;
8208bf5c682Smrg		output_count++;
8218bf5c682Smrg	}
8228bf5c682Smrg
8238bf5c682Smrg	drmmode_ConvertToKMode(scrn, &kmode, mode);
8248bf5c682Smrg
8258bf5c682Smrg	ret = drmModeSetCrtc(pRADEONEnt->fd,
8268bf5c682Smrg			     drmmode_crtc->mode_crtc->crtc_id,
8278bf5c682Smrg			     fb->handle, x, y, output_ids,
8288bf5c682Smrg			     output_count, &kmode) == 0;
8298bf5c682Smrg
8308bf5c682Smrg	if (ret) {
8318bf5c682Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, fb);
8328bf5c682Smrg	} else {
8338bf5c682Smrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
8348bf5c682Smrg			   "failed to set mode: %s\n", strerror(errno));
8358bf5c682Smrg	}
8368bf5c682Smrg
8378bf5c682Smrg	free(output_ids);
8388bf5c682Smrg	return ret;
8398bf5c682Smrg}
8408bf5c682Smrg
841de2362d3Smrgstatic Bool
842de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
843de2362d3Smrg		     Rotation rotation, int x, int y)
844de2362d3Smrg{
845de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
84618781e08Smrg	ScreenPtr pScreen = pScrn->pScreen;
847de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
8488bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
849de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
850de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
8513ed65abbSmrg	unsigned scanout_id = 0;
852de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
853de2362d3Smrg	int saved_x, saved_y;
854de2362d3Smrg	Rotation saved_rotation;
855de2362d3Smrg	DisplayModeRec saved_mode;
85618781e08Smrg	Bool ret = FALSE;
857de2362d3Smrg	int i;
8588bf5c682Smrg	struct drmmode_fb *fb = NULL;
8598bf5c682Smrg
8608bf5c682Smrg	/* The root window contents may be undefined before the WindowExposures
8618bf5c682Smrg	 * hook is called for it, so bail if we get here before that
8628bf5c682Smrg	 */
8638bf5c682Smrg	if (pScreen->WindowExposures == RADEONWindowExposures_oneshot)
8648bf5c682Smrg		return FALSE;
865de2362d3Smrg
866de2362d3Smrg	saved_mode = crtc->mode;
867de2362d3Smrg	saved_x = crtc->x;
868de2362d3Smrg	saved_y = crtc->y;
869de2362d3Smrg	saved_rotation = crtc->rotation;
870de2362d3Smrg
871de2362d3Smrg	if (mode) {
872de2362d3Smrg		crtc->mode = *mode;
873de2362d3Smrg		crtc->x = x;
874de2362d3Smrg		crtc->y = y;
875de2362d3Smrg		crtc->rotation = rotation;
876de2362d3Smrg
87718781e08Smrg		if (!drmmode_handle_transform(crtc))
878de2362d3Smrg			goto done;
87918781e08Smrg
8803ed65abbSmrg		drmmode_crtc_update_tear_free(crtc);
8813ed65abbSmrg		if (drmmode_crtc->tear_free)
8823ed65abbSmrg			scanout_id = drmmode_crtc->scanout_id;
88339413783Smrg		else
88439413783Smrg			drmmode_crtc->scanout_id = 0;
885de2362d3Smrg
8868bf5c682Smrg		if (drmmode_crtc->prime_scanout_pixmap) {
8873ed65abbSmrg			drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id,
8888bf5c682Smrg							  &fb, &x, &y);
8898bf5c682Smrg		} else if (drmmode_crtc->rotate.pixmap) {
8908bf5c682Smrg			fb = radeon_pixmap_get_fb(drmmode_crtc->rotate.pixmap);
89118781e08Smrg			x = y = 0;
89218781e08Smrg
8938bf5c682Smrg		} else if (!pScreen->isGPU &&
8943ed65abbSmrg			   (drmmode_crtc->tear_free ||
89518781e08Smrg			    crtc->driverIsPerformingTransform ||
89618781e08Smrg			    info->shadow_primary)) {
8973ed65abbSmrg			drmmode_crtc_scanout_update(crtc, mode, scanout_id,
8988bf5c682Smrg						    &fb, &x, &y);
899de2362d3Smrg		}
90018781e08Smrg
9018bf5c682Smrg		if (!fb)
9028bf5c682Smrg			fb = radeon_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root));
9038bf5c682Smrg		if (!fb) {
9048bf5c682Smrg			fb = radeon_fb_create(pScrn, pRADEONEnt->fd,
9058bf5c682Smrg					      pScrn->virtualX, pScrn->virtualY,
9068bf5c682Smrg					      pScrn->displayWidth * info->pixel_bytes,
90739413783Smrg					      info->front_buffer->bo.radeon->handle);
9088bf5c682Smrg			/* Prevent refcnt of ad-hoc FBs from reaching 2 */
9098bf5c682Smrg			drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, NULL);
9108bf5c682Smrg			drmmode_crtc->fb = fb;
9118bf5c682Smrg		}
9128bf5c682Smrg		if (!fb) {
9138bf5c682Smrg			ErrorF("failed to add FB for modeset\n");
9148bf5c682Smrg			goto done;
91518781e08Smrg		}
91618781e08Smrg
91739413783Smrg		radeon_drm_wait_pending_flip(crtc);
9188bf5c682Smrg
9198bf5c682Smrg		if (!drmmode_set_mode(crtc, fb, mode, x, y))
92018781e08Smrg			goto done;
9218bf5c682Smrg
9228bf5c682Smrg		ret = TRUE;
923de2362d3Smrg
92418781e08Smrg		if (pScreen)
92518781e08Smrg			xf86CrtcSetScreenSubpixelOrder(pScreen);
92618781e08Smrg
92718781e08Smrg		drmmode_crtc->need_modeset = FALSE;
92818781e08Smrg
929de2362d3Smrg		/* go through all the outputs and force DPMS them back on? */
930de2362d3Smrg		for (i = 0; i < xf86_config->num_output; i++) {
931de2362d3Smrg			xf86OutputPtr output = xf86_config->output[i];
932de2362d3Smrg
933de2362d3Smrg			if (output->crtc != crtc)
934de2362d3Smrg				continue;
935de2362d3Smrg
936de2362d3Smrg			output->funcs->dpms(output, DPMSModeOn);
937de2362d3Smrg		}
938de2362d3Smrg	}
939de2362d3Smrg
94018781e08Smrg	/* Compute index of this CRTC into xf86_config->crtc */
94118781e08Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
94218781e08Smrg		if (xf86_config->crtc[i] != crtc)
94318781e08Smrg			continue;
94418781e08Smrg
94518781e08Smrg		if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc))
94618781e08Smrg			info->hwcursor_disabled &= ~(1 << i);
94718781e08Smrg		else
94818781e08Smrg			info->hwcursor_disabled |= 1 << i;
94918781e08Smrg
95018781e08Smrg		break;
95118781e08Smrg	}
95218781e08Smrg
95318781e08Smrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR
95418781e08Smrg	if (!info->hwcursor_disabled)
95518781e08Smrg		xf86_reload_cursors(pScreen);
95618781e08Smrg#endif
957de2362d3Smrg
958de2362d3Smrgdone:
959de2362d3Smrg	if (!ret) {
960de2362d3Smrg		crtc->x = saved_x;
961de2362d3Smrg		crtc->y = saved_y;
962de2362d3Smrg		crtc->rotation = saved_rotation;
963de2362d3Smrg		crtc->mode = saved_mode;
96418781e08Smrg	} else {
9657821949aSmrg		crtc->active = TRUE;
96618781e08Smrg
9678bf5c682Smrg		if (drmmode_crtc->scanout[scanout_id].pixmap &&
9688bf5c682Smrg		    fb != radeon_pixmap_get_fb(drmmode_crtc->
96939413783Smrg					       scanout[scanout_id].pixmap)) {
97039413783Smrg			radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending);
97139413783Smrg			drmmode_crtc->scanout_update_pending = 0;
97218781e08Smrg			drmmode_crtc_scanout_free(drmmode_crtc);
97339413783Smrg		} else if (!drmmode_crtc->tear_free) {
9743ed65abbSmrg			drmmode_crtc_scanout_destroy(drmmode,
9753ed65abbSmrg						     &drmmode_crtc->scanout[1]);
9763ed65abbSmrg		}
97718781e08Smrg	}
97818781e08Smrg
97939413783Smrg	radeon_drm_queue_handle_deferred(crtc);
980de2362d3Smrg	return ret;
981de2362d3Smrg}
982de2362d3Smrg
983de2362d3Smrgstatic void
984de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
985de2362d3Smrg{
986de2362d3Smrg
987de2362d3Smrg}
988de2362d3Smrg
989de2362d3Smrgstatic void
990de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
991de2362d3Smrg{
992de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
9938bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
994de2362d3Smrg
9958bf5c682Smrg#if XF86_CRTC_VERSION < 7
99618781e08Smrg	if (crtc->driverIsPerformingTransform) {
99718781e08Smrg		x += crtc->x;
99818781e08Smrg		y += crtc->y;
99918781e08Smrg		xf86CrtcTransformCursorPos(crtc, &x, &y);
100018781e08Smrg	}
100118781e08Smrg#endif
100218781e08Smrg
10038bf5c682Smrg	drmModeMoveCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
1004de2362d3Smrg}
1005de2362d3Smrg
10068bf5c682Smrg#if XF86_CRTC_VERSION < 7
100718781e08Smrg
100818781e08Smrgstatic int
100918781e08Smrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height,
101018781e08Smrg			  int x_dst, int y_dst)
101118781e08Smrg{
101218781e08Smrg	int t;
101318781e08Smrg
101418781e08Smrg	switch (rotation & 0xf) {
101518781e08Smrg	case RR_Rotate_90:
101618781e08Smrg		t = x_dst;
101718781e08Smrg		x_dst = height - y_dst - 1;
101818781e08Smrg		y_dst = t;
101918781e08Smrg		break;
102018781e08Smrg	case RR_Rotate_180:
102118781e08Smrg		x_dst = width - x_dst - 1;
102218781e08Smrg		y_dst = height - y_dst - 1;
102318781e08Smrg		break;
102418781e08Smrg	case RR_Rotate_270:
102518781e08Smrg		t = x_dst;
102618781e08Smrg		x_dst = y_dst;
102718781e08Smrg		y_dst = width - t - 1;
102818781e08Smrg		break;
102918781e08Smrg	}
103018781e08Smrg
103118781e08Smrg	if (rotation & RR_Reflect_X)
103218781e08Smrg		x_dst = width - x_dst - 1;
103318781e08Smrg	if (rotation & RR_Reflect_Y)
103418781e08Smrg		y_dst = height - y_dst - 1;
103518781e08Smrg
103618781e08Smrg	return y_dst * height + x_dst;
103718781e08Smrg}
103818781e08Smrg
103918781e08Smrg#endif
104018781e08Smrg
10418bf5c682Smrgstatic uint32_t
10428bf5c682Smrgdrmmode_cursor_gamma(xf86CrtcPtr crtc, uint32_t argb)
10438bf5c682Smrg{
10448bf5c682Smrg	uint32_t alpha = argb >> 24;
10458bf5c682Smrg	uint32_t rgb[3];
10468bf5c682Smrg	int i;
10478bf5c682Smrg
10488bf5c682Smrg	if (!alpha)
10498bf5c682Smrg		return 0;
10508bf5c682Smrg
10518bf5c682Smrg	if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
10528bf5c682Smrg		return argb;
10538bf5c682Smrg
10548bf5c682Smrg	/* Un-premultiply alpha */
10558bf5c682Smrg	for (i = 0; i < 3; i++)
10568bf5c682Smrg		rgb[i] = ((argb >> (i * 8)) & 0xff) * 0xff / alpha;
10578bf5c682Smrg
10588bf5c682Smrg	/* Apply gamma correction and pre-multiply alpha */
10598bf5c682Smrg	rgb[0] = (crtc->gamma_blue[rgb[0]] >> 8) * alpha / 0xff;
10608bf5c682Smrg	rgb[1] = (crtc->gamma_green[rgb[1]] >> 8) * alpha / 0xff;
10618bf5c682Smrg	rgb[2] = (crtc->gamma_red[rgb[2]] >> 8) * alpha / 0xff;
10628bf5c682Smrg
10638bf5c682Smrg	return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
10648bf5c682Smrg}
10658bf5c682Smrg
1066de2362d3Smrgstatic void
1067de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
1068de2362d3Smrg{
106918781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
107018781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1071de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1072de2362d3Smrg	uint32_t *ptr;
1073de2362d3Smrg
1074de2362d3Smrg	/* cursor should be mapped already */
1075de2362d3Smrg	ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr);
1076de2362d3Smrg
10778bf5c682Smrg#if XF86_CRTC_VERSION < 7
107818781e08Smrg	if (crtc->driverIsPerformingTransform) {
107918781e08Smrg		uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
108018781e08Smrg		int dstx, dsty;
108118781e08Smrg		int srcoffset;
108218781e08Smrg
108318781e08Smrg		for (dsty = 0; dsty < cursor_h; dsty++) {
108418781e08Smrg			for (dstx = 0; dstx < cursor_w; dstx++) {
108518781e08Smrg				srcoffset = drmmode_cursor_src_offset(crtc->rotation,
108618781e08Smrg								      cursor_w,
108718781e08Smrg								      cursor_h,
108818781e08Smrg								      dstx, dsty);
108918781e08Smrg
109018781e08Smrg				ptr[dsty * info->cursor_w + dstx] =
10918bf5c682Smrg					cpu_to_le32(drmmode_cursor_gamma(crtc,
10928bf5c682Smrg									 image[srcoffset]));
109318781e08Smrg			}
109418781e08Smrg		}
109518781e08Smrg	} else
109618781e08Smrg#endif
109718781e08Smrg	{
109818781e08Smrg		uint32_t cursor_size = info->cursor_w * info->cursor_h;
109918781e08Smrg		int i;
110018781e08Smrg
110118781e08Smrg		for (i = 0; i < cursor_size; i++)
11028bf5c682Smrg			ptr[i] = cpu_to_le32(drmmode_cursor_gamma(crtc, image[i]));
110318781e08Smrg	}
1104de2362d3Smrg}
1105de2362d3Smrg
110618781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
110718781e08Smrg
110818781e08Smrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
110918781e08Smrg{
111018781e08Smrg	if (!drmmode_can_use_hw_cursor(crtc))
111118781e08Smrg		return FALSE;
111218781e08Smrg
111318781e08Smrg	drmmode_load_cursor_argb(crtc, image);
111418781e08Smrg	return TRUE;
111518781e08Smrg}
111618781e08Smrg
111718781e08Smrg#endif
1118de2362d3Smrg
1119de2362d3Smrgstatic void
1120de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc)
1121de2362d3Smrg{
112218781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
112318781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1124de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
11258bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1126de2362d3Smrg
11278bf5c682Smrg	drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
112818781e08Smrg			 info->cursor_w, info->cursor_h);
1129de2362d3Smrg
1130de2362d3Smrg}
1131de2362d3Smrg
1132de2362d3Smrgstatic void
1133de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc)
1134de2362d3Smrg{
113518781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
113618781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1137de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
11388bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1139de2362d3Smrg	uint32_t handle = drmmode_crtc->cursor_bo->handle;
114018781e08Smrg	static Bool use_set_cursor2 = TRUE;
114118781e08Smrg
114218781e08Smrg	if (use_set_cursor2) {
114318781e08Smrg	    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
114418781e08Smrg	    CursorPtr cursor = xf86_config->cursor;
114518781e08Smrg	    int xhot = cursor->bits->xhot;
114618781e08Smrg	    int yhot = cursor->bits->yhot;
114718781e08Smrg	    int ret;
114818781e08Smrg
114918781e08Smrg	    if (crtc->rotation != RR_Rotate_0 &&
115018781e08Smrg		crtc->rotation != (RR_Rotate_180 | RR_Reflect_X |
115118781e08Smrg				   RR_Reflect_Y)) {
115218781e08Smrg		int t;
115318781e08Smrg
115418781e08Smrg		/* Reflect & rotate hotspot position */
115518781e08Smrg		if (crtc->rotation & RR_Reflect_X)
115618781e08Smrg		    xhot = info->cursor_w - xhot - 1;
115718781e08Smrg		if (crtc->rotation & RR_Reflect_Y)
115818781e08Smrg		    yhot = info->cursor_h - yhot - 1;
115918781e08Smrg
116018781e08Smrg		switch (crtc->rotation & 0xf) {
116118781e08Smrg		case RR_Rotate_90:
116218781e08Smrg		    t = xhot;
116318781e08Smrg		    xhot = yhot;
116418781e08Smrg		    yhot = info->cursor_w - t - 1;
116518781e08Smrg		    break;
116618781e08Smrg		case RR_Rotate_180:
116718781e08Smrg		    xhot = info->cursor_w - xhot - 1;
116818781e08Smrg		    yhot = info->cursor_h - yhot - 1;
116918781e08Smrg		    break;
117018781e08Smrg		case RR_Rotate_270:
117118781e08Smrg		    t = xhot;
117218781e08Smrg		    xhot = info->cursor_h - yhot - 1;
117318781e08Smrg		    yhot = t;
117418781e08Smrg		}
117518781e08Smrg	    }
11767314432eSmrg
117718781e08Smrg	    ret =
11788bf5c682Smrg		drmModeSetCursor2(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
117918781e08Smrg				  handle, info->cursor_w, info->cursor_h,
118018781e08Smrg				  xhot, yhot);
118118781e08Smrg	    if (ret == -EINVAL)
118218781e08Smrg		use_set_cursor2 = FALSE;
118318781e08Smrg	    else
118418781e08Smrg		return;
118518781e08Smrg	}
118618781e08Smrg
11878bf5c682Smrg	drmModeSetCursor(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id, handle,
118818781e08Smrg			 info->cursor_w, info->cursor_h);
1189de2362d3Smrg}
1190de2362d3Smrg
11913ed65abbSmrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and
11923ed65abbSmrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for
11933ed65abbSmrg * anything else.
11943ed65abbSmrg */
1195de2362d3Smrgstatic void *
1196de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
1197de2362d3Smrg{
1198de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
11997821949aSmrg
12003ed65abbSmrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
12013ed65abbSmrg					 height))
12023ed65abbSmrg		return NULL;
12033ed65abbSmrg
12043ed65abbSmrg	return (void*)~0UL;
1205de2362d3Smrg}
1206de2362d3Smrg
1207de2362d3Smrgstatic PixmapPtr
1208de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1209de2362d3Smrg{
1210de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1211de2362d3Smrg
12123ed65abbSmrg	if (!data) {
12133ed65abbSmrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
12143ed65abbSmrg					    height);
12153ed65abbSmrg	}
12163ed65abbSmrg
12173ed65abbSmrg	return drmmode_crtc->rotate.pixmap;
1218de2362d3Smrg}
1219de2362d3Smrg
1220de2362d3Smrgstatic void
12217821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
1222de2362d3Smrg{
1223de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1224de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1225de2362d3Smrg
122618781e08Smrg	drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate);
12277821949aSmrg}
1228de2362d3Smrg
12297821949aSmrgstatic void
12307821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
12317821949aSmrg                      uint16_t *blue, int size)
12327821949aSmrg{
12338bf5c682Smrg	ScrnInfoPtr scrn = crtc->scrn;
12348bf5c682Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
12358bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
12368bf5c682Smrg	int i;
12378bf5c682Smrg
12388bf5c682Smrg	drmmode_crtc_gamma_do_set(crtc, red, green, blue, size);
12398bf5c682Smrg
12408bf5c682Smrg	/* Compute index of this CRTC into xf86_config->crtc */
12418bf5c682Smrg	for (i = 0; xf86_config->crtc[i] != crtc; i++) {}
12428bf5c682Smrg
12438bf5c682Smrg	if (info->hwcursor_disabled & (1 << i))
12448bf5c682Smrg		return;
12457314432eSmrg
12468bf5c682Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR
12478bf5c682Smrg	xf86CursorResetCursor(scrn->pScreen);
12488bf5c682Smrg#else
12498bf5c682Smrg	xf86_reload_cursors(scrn->pScreen);
12508bf5c682Smrg#endif
125118781e08Smrg}
125218781e08Smrg
125318781e08Smrgstatic Bool
125418781e08Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
125518781e08Smrg{
125618781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
12573ed65abbSmrg	unsigned scanout_id = drmmode_crtc->scanout_id;
125818781e08Smrg	ScreenPtr screen = crtc->scrn->pScreen;
125918781e08Smrg	PixmapDirtyUpdatePtr dirty;
126018781e08Smrg
126118781e08Smrg	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
12628bf5c682Smrg		if (radeon_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
12638bf5c682Smrg			PixmapStopDirtyTracking(dirty->src, dirty->slave_dst);
12648bf5c682Smrg			break;
12658bf5c682Smrg		}
126618781e08Smrg	}
126718781e08Smrg
12688bf5c682Smrg	drmmode_crtc_scanout_free(drmmode_crtc);
12698bf5c682Smrg	drmmode_crtc->prime_scanout_pixmap = NULL;
12708bf5c682Smrg
127118781e08Smrg	if (!ppix)
127218781e08Smrg		return TRUE;
127318781e08Smrg
127418781e08Smrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0],
127518781e08Smrg					 ppix->drawable.width,
127618781e08Smrg					 ppix->drawable.height))
127718781e08Smrg		return FALSE;
127818781e08Smrg
12793ed65abbSmrg	if (drmmode_crtc->tear_free &&
128018781e08Smrg	    !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
128118781e08Smrg					 ppix->drawable.width,
128218781e08Smrg					 ppix->drawable.height)) {
128318781e08Smrg		drmmode_crtc_scanout_free(drmmode_crtc);
128418781e08Smrg		return FALSE;
128518781e08Smrg	}
128618781e08Smrg
12878bf5c682Smrg	drmmode_crtc->prime_scanout_pixmap = ppix;
12888bf5c682Smrg
12898bf5c682Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC
12908bf5c682Smrg	PixmapStartDirtyTracking(&ppix->drawable,
12918bf5c682Smrg				 drmmode_crtc->scanout[scanout_id].pixmap,
12928bf5c682Smrg				 0, 0, 0, 0, RR_Rotate_0);
12938bf5c682Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION)
12943ed65abbSmrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
129518781e08Smrg				 0, 0, 0, 0, RR_Rotate_0);
129618781e08Smrg#elif defined(HAS_DIRTYTRACKING2)
12973ed65abbSmrg	PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
129818781e08Smrg				  0, 0, 0, 0);
129918781e08Smrg#else
13003ed65abbSmrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0);
130118781e08Smrg#endif
130218781e08Smrg	return TRUE;
1303de2362d3Smrg}
1304de2362d3Smrg
130518781e08Smrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = {
1306de2362d3Smrg    .dpms = drmmode_crtc_dpms,
1307de2362d3Smrg    .set_mode_major = drmmode_set_mode_major,
1308de2362d3Smrg    .set_cursor_colors = drmmode_set_cursor_colors,
1309de2362d3Smrg    .set_cursor_position = drmmode_set_cursor_position,
1310de2362d3Smrg    .show_cursor = drmmode_show_cursor,
1311de2362d3Smrg    .hide_cursor = drmmode_hide_cursor,
1312de2362d3Smrg    .load_cursor_argb = drmmode_load_cursor_argb,
131318781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
131418781e08Smrg    .load_cursor_argb_check = drmmode_load_cursor_argb_check,
131518781e08Smrg#endif
1316de2362d3Smrg
1317de2362d3Smrg    .gamma_set = drmmode_crtc_gamma_set,
1318de2362d3Smrg    .shadow_create = drmmode_crtc_shadow_create,
1319de2362d3Smrg    .shadow_allocate = drmmode_crtc_shadow_allocate,
1320de2362d3Smrg    .shadow_destroy = drmmode_crtc_shadow_destroy,
1321de2362d3Smrg    .destroy = NULL, /* XXX */
132218781e08Smrg    .set_scanout_pixmap = drmmode_set_scanout_pixmap,
1323de2362d3Smrg};
1324de2362d3Smrg
1325de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc)
1326de2362d3Smrg{
1327de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1328de2362d3Smrg	return drmmode_crtc->hw_id;
1329de2362d3Smrg}
1330de2362d3Smrg
1331de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc)
1332de2362d3Smrg{
1333de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
13348bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
1335de2362d3Smrg	struct drm_radeon_info ginfo;
1336de2362d3Smrg	int r;
1337de2362d3Smrg	uint32_t tmp;
1338de2362d3Smrg
1339de2362d3Smrg	memset(&ginfo, 0, sizeof(ginfo));
1340de2362d3Smrg	ginfo.request = 0x4;
1341de2362d3Smrg	tmp = drmmode_crtc->mode_crtc->crtc_id;
1342de2362d3Smrg	ginfo.value = (uintptr_t)&tmp;
13438bf5c682Smrg	r = drmCommandWriteRead(pRADEONEnt->fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo));
1344de2362d3Smrg	if (r) {
1345de2362d3Smrg		drmmode_crtc->hw_id = -1;
1346de2362d3Smrg		return;
1347de2362d3Smrg	}
1348de2362d3Smrg	drmmode_crtc->hw_id = tmp;
1349de2362d3Smrg}
1350de2362d3Smrg
135118781e08Smrgstatic unsigned int
135218781e08Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
1353de2362d3Smrg{
1354de2362d3Smrg	xf86CrtcPtr crtc;
1355de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc;
135618781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
13578bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1358de2362d3Smrg
13598bf5c682Smrg	crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs);
136039413783Smrg	if (!crtc)
136118781e08Smrg		return 0;
1362de2362d3Smrg
1363de2362d3Smrg	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
13648bf5c682Smrg	drmmode_crtc->mode_crtc = drmModeGetCrtc(pRADEONEnt->fd, mode_res->crtcs[num]);
1365de2362d3Smrg	drmmode_crtc->drmmode = drmmode;
136618781e08Smrg	drmmode_crtc->dpms_mode = DPMSModeOff;
1367de2362d3Smrg	crtc->driver_private = drmmode_crtc;
1368de2362d3Smrg	drmmode_crtc_hw_id(crtc);
1369de2362d3Smrg
137018781e08Smrg	/* Mark num'th crtc as in use on this device. */
137118781e08Smrg	pRADEONEnt->assigned_crtcs |= (1 << num);
137218781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
137318781e08Smrg		       "Allocated crtc nr. %d to this screen.\n", num);
137418781e08Smrg
137518781e08Smrg	return 1;
1376de2362d3Smrg}
1377de2362d3Smrg
13788bf5c682Smrg/*
13798bf5c682Smrg * Update all of the property values for an output
13808bf5c682Smrg */
13818bf5c682Smrgstatic void
13828bf5c682Smrgdrmmode_output_update_properties(xf86OutputPtr output)
13838bf5c682Smrg{
13848bf5c682Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
13858bf5c682Smrg	int i, j, k;
13868bf5c682Smrg	int err;
13878bf5c682Smrg	drmModeConnectorPtr koutput;
13888bf5c682Smrg
13898bf5c682Smrg	/* Use the most recently fetched values from the kernel */
13908bf5c682Smrg	koutput = drmmode_output->mode_output;
13918bf5c682Smrg
13928bf5c682Smrg	if (!koutput)
13938bf5c682Smrg		return;
13948bf5c682Smrg
13958bf5c682Smrg	for (i = 0; i < drmmode_output->num_props; i++) {
13968bf5c682Smrg		drmmode_prop_ptr p = &drmmode_output->props[i];
13978bf5c682Smrg
13988bf5c682Smrg		for (j = 0; j < koutput->count_props; j++) {
13998bf5c682Smrg			if (koutput->props[j] != p->mode_prop->prop_id)
14008bf5c682Smrg				continue;
14018bf5c682Smrg
14028bf5c682Smrg			/* Check to see if the property value has changed */
14038bf5c682Smrg			if (koutput->prop_values[j] == p->value)
14048bf5c682Smrg				break;
14058bf5c682Smrg
14068bf5c682Smrg			p->value = koutput->prop_values[j];
14078bf5c682Smrg
14088bf5c682Smrg			if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
14098bf5c682Smrg				INT32 value = p->value;
14108bf5c682Smrg
14118bf5c682Smrg				err = RRChangeOutputProperty(output->randr_output,
14128bf5c682Smrg							     p->atoms[0], XA_INTEGER,
14138bf5c682Smrg							     32, PropModeReplace, 1,
14148bf5c682Smrg							     &value, FALSE, TRUE);
14158bf5c682Smrg				if (err != 0) {
14168bf5c682Smrg					xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
14178bf5c682Smrg						   "RRChangeOutputProperty error, %d\n",
14188bf5c682Smrg						   err);
14198bf5c682Smrg				}
14208bf5c682Smrg			} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
14218bf5c682Smrg				for (k = 0; k < p->mode_prop->count_enums; k++) {
14228bf5c682Smrg					if (p->mode_prop->enums[k].value == p->value)
14238bf5c682Smrg						break;
14248bf5c682Smrg				}
14258bf5c682Smrg				if (k < p->mode_prop->count_enums) {
14268bf5c682Smrg					err = RRChangeOutputProperty(output->randr_output,
14278bf5c682Smrg								     p->atoms[0], XA_ATOM,
14288bf5c682Smrg								     32, PropModeReplace, 1,
14298bf5c682Smrg								     &p->atoms[k + 1], FALSE,
14308bf5c682Smrg								     TRUE);
14318bf5c682Smrg					if (err != 0) {
14328bf5c682Smrg						xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
14338bf5c682Smrg							   "RRChangeOutputProperty error, %d\n",
14348bf5c682Smrg							   err);
14358bf5c682Smrg					}
14368bf5c682Smrg				}
14378bf5c682Smrg			}
14388bf5c682Smrg
14398bf5c682Smrg			break;
14408bf5c682Smrg		}
14418bf5c682Smrg        }
14428bf5c682Smrg}
14438bf5c682Smrg
1444de2362d3Smrgstatic xf86OutputStatus
1445de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output)
1446de2362d3Smrg{
1447de2362d3Smrg	/* go to the hw and retrieve a new output struct */
1448de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
14498bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1450de2362d3Smrg	xf86OutputStatus status;
1451de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
1452de2362d3Smrg
14538bf5c682Smrg	drmmode_output->mode_output =
14548bf5c682Smrg	    drmModeGetConnector(pRADEONEnt->fd, drmmode_output->output_id);
14558bf5c682Smrg	if (!drmmode_output->mode_output) {
14568bf5c682Smrg		drmmode_output->output_id = -1;
145718781e08Smrg		return XF86OutputStatusDisconnected;
14588bf5c682Smrg	}
14598bf5c682Smrg
14608bf5c682Smrg	drmmode_output_update_properties(output);
1461de2362d3Smrg
1462de2362d3Smrg	switch (drmmode_output->mode_output->connection) {
1463de2362d3Smrg	case DRM_MODE_CONNECTED:
1464de2362d3Smrg		status = XF86OutputStatusConnected;
1465de2362d3Smrg		break;
1466de2362d3Smrg	case DRM_MODE_DISCONNECTED:
1467de2362d3Smrg		status = XF86OutputStatusDisconnected;
1468de2362d3Smrg		break;
1469de2362d3Smrg	default:
1470de2362d3Smrg	case DRM_MODE_UNKNOWNCONNECTION:
1471de2362d3Smrg		status = XF86OutputStatusUnknown;
1472de2362d3Smrg		break;
1473de2362d3Smrg	}
1474de2362d3Smrg	return status;
1475de2362d3Smrg}
1476de2362d3Smrg
1477de2362d3Smrgstatic Bool
1478de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
1479de2362d3Smrg{
1480de2362d3Smrg	return MODE_OK;
1481de2362d3Smrg}
1482de2362d3Smrg
14838bf5c682Smrgstatic int
14848bf5c682Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
14858bf5c682Smrg        int type, const char *name)
14868bf5c682Smrg{
14878bf5c682Smrg    int idx = -1;
14888bf5c682Smrg
14898bf5c682Smrg    for (int i = 0; i < koutput->count_props; i++) {
14908bf5c682Smrg        drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
14918bf5c682Smrg
14928bf5c682Smrg        if (!prop)
14938bf5c682Smrg            continue;
14948bf5c682Smrg
14958bf5c682Smrg        if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
14968bf5c682Smrg            idx = i;
14978bf5c682Smrg
14988bf5c682Smrg        drmModeFreeProperty(prop);
14998bf5c682Smrg
15008bf5c682Smrg        if (idx > -1)
15018bf5c682Smrg            break;
15028bf5c682Smrg    }
15038bf5c682Smrg
15048bf5c682Smrg    return idx;
15058bf5c682Smrg}
15068bf5c682Smrg
15078bf5c682Smrgstatic int
15088bf5c682Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
15098bf5c682Smrg        int type, const char *name)
15108bf5c682Smrg{
15118bf5c682Smrg    int idx = koutput_get_prop_idx(fd, koutput, type, name);
15128bf5c682Smrg
15138bf5c682Smrg    return (idx > -1) ? koutput->props[idx] : -1;
15148bf5c682Smrg}
15158bf5c682Smrg
15168bf5c682Smrgstatic drmModePropertyBlobPtr
15178bf5c682Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
15188bf5c682Smrg{
15198bf5c682Smrg    drmModePropertyBlobPtr blob = NULL;
15208bf5c682Smrg    int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
15218bf5c682Smrg
15228bf5c682Smrg    if (idx > -1)
15238bf5c682Smrg        blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
15248bf5c682Smrg
15258bf5c682Smrg    return blob;
15268bf5c682Smrg}
15278bf5c682Smrg
1528de2362d3Smrgstatic DisplayModePtr
1529de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output)
1530de2362d3Smrg{
1531de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1532de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
15338bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1534de2362d3Smrg	int i;
1535de2362d3Smrg	DisplayModePtr Modes = NULL, Mode;
1536de2362d3Smrg	xf86MonPtr mon = NULL;
1537de2362d3Smrg
153818781e08Smrg	if (!koutput)
153918781e08Smrg		return NULL;
154018781e08Smrg
15418bf5c682Smrg	drmModeFreePropertyBlob(drmmode_output->edid_blob);
15428bf5c682Smrg
1543de2362d3Smrg	/* look for an EDID property */
15448bf5c682Smrg	drmmode_output->edid_blob =
15458bf5c682Smrg		koutput_get_prop_blob(pRADEONEnt->fd, koutput, "EDID");
1546de2362d3Smrg
1547de2362d3Smrg	if (drmmode_output->edid_blob) {
1548de2362d3Smrg		mon = xf86InterpretEDID(output->scrn->scrnIndex,
1549de2362d3Smrg					drmmode_output->edid_blob->data);
1550de2362d3Smrg		if (mon && drmmode_output->edid_blob->length > 128)
1551de2362d3Smrg			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
1552de2362d3Smrg	}
1553de2362d3Smrg	xf86OutputSetEDID(output, mon);
1554de2362d3Smrg
1555de2362d3Smrg	/* modes should already be available */
1556de2362d3Smrg	for (i = 0; i < koutput->count_modes; i++) {
1557de2362d3Smrg		Mode = xnfalloc(sizeof(DisplayModeRec));
1558de2362d3Smrg
1559de2362d3Smrg		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
1560de2362d3Smrg		Modes = xf86ModesAdd(Modes, Mode);
1561de2362d3Smrg
1562de2362d3Smrg	}
1563de2362d3Smrg	return Modes;
1564de2362d3Smrg}
1565de2362d3Smrg
1566de2362d3Smrgstatic void
1567de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output)
1568de2362d3Smrg{
1569de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1570de2362d3Smrg	int i;
1571de2362d3Smrg
1572de2362d3Smrg	if (drmmode_output->edid_blob)
1573de2362d3Smrg		drmModeFreePropertyBlob(drmmode_output->edid_blob);
1574de2362d3Smrg	for (i = 0; i < drmmode_output->num_props; i++) {
1575de2362d3Smrg		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
1576de2362d3Smrg		free(drmmode_output->props[i].atoms);
1577de2362d3Smrg	}
1578de2362d3Smrg	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
1579de2362d3Smrg		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
1580de2362d3Smrg	}
158118781e08Smrg	free(drmmode_output->mode_encoders);
1582de2362d3Smrg	free(drmmode_output->props);
1583de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
1584de2362d3Smrg	free(drmmode_output);
1585de2362d3Smrg	output->driver_private = NULL;
1586de2362d3Smrg}
1587de2362d3Smrg
1588de2362d3Smrgstatic void
1589de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode)
1590de2362d3Smrg{
1591de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
159218781e08Smrg	xf86CrtcPtr crtc = output->crtc;
1593de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
15948bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1595de2362d3Smrg
159618781e08Smrg	if (!koutput)
159718781e08Smrg		return;
159818781e08Smrg
15998bf5c682Smrg	if (mode != DPMSModeOn && crtc)
160018781e08Smrg		drmmode_do_crtc_dpms(crtc, mode);
160118781e08Smrg
16028bf5c682Smrg	drmModeConnectorSetProperty(pRADEONEnt->fd, koutput->connector_id,
1603de2362d3Smrg				    drmmode_output->dpms_enum_id, mode);
160418781e08Smrg
160518781e08Smrg	if (mode == DPMSModeOn && crtc) {
160618781e08Smrg	    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
160718781e08Smrg
160818781e08Smrg	    if (drmmode_crtc->need_modeset)
160918781e08Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x,
161018781e08Smrg				       crtc->y);
161118781e08Smrg	    else
161218781e08Smrg		drmmode_do_crtc_dpms(crtc, mode);
161318781e08Smrg	}
1614de2362d3Smrg}
1615de2362d3Smrg
1616de2362d3Smrg
1617de2362d3Smrgstatic Bool
1618de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop)
1619de2362d3Smrg{
1620de2362d3Smrg    if (!prop)
1621de2362d3Smrg	return TRUE;
1622de2362d3Smrg    /* ignore blob prop */
1623de2362d3Smrg    if (prop->flags & DRM_MODE_PROP_BLOB)
1624de2362d3Smrg	return TRUE;
1625de2362d3Smrg    /* ignore standard property */
1626de2362d3Smrg    if (!strcmp(prop->name, "EDID") ||
1627de2362d3Smrg	    !strcmp(prop->name, "DPMS"))
1628de2362d3Smrg	return TRUE;
1629de2362d3Smrg
1630de2362d3Smrg    return FALSE;
1631de2362d3Smrg}
1632de2362d3Smrg
1633de2362d3Smrgstatic void
1634de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output)
1635de2362d3Smrg{
16363ed65abbSmrg    RADEONInfoPtr info = RADEONPTR(output->scrn);
1637de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
1638de2362d3Smrg    drmModeConnectorPtr mode_output = drmmode_output->mode_output;
16398bf5c682Smrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
16403ed65abbSmrg    drmModePropertyPtr drmmode_prop, tearfree_prop;
1641de2362d3Smrg    int i, j, err;
164239413783Smrg    Atom name;
164339413783Smrg
164439413783Smrg    /* Create CONNECTOR_ID property */
164539413783Smrg    name = MakeAtom("CONNECTOR_ID", 12, TRUE);
164639413783Smrg    if (name != BAD_RESOURCE) {
164739413783Smrg	INT32 value = mode_output->connector_id;
164839413783Smrg
164939413783Smrg	err = RRConfigureOutputProperty(output->randr_output, name,
165039413783Smrg					FALSE, FALSE, TRUE, 1, &value);
165139413783Smrg	if (err != Success) {
165239413783Smrg	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
165339413783Smrg		       "RRConfigureOutputProperty error, %d\n", err);
165439413783Smrg	}
165539413783Smrg
165639413783Smrg	err = RRChangeOutputProperty(output->randr_output, name,
165739413783Smrg				     XA_INTEGER, 32, PropModeReplace, 1,
165839413783Smrg				     &value, FALSE, FALSE);
165939413783Smrg	if (err != Success) {
166039413783Smrg	    xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
166139413783Smrg		       "RRChangeOutputProperty error, %d\n", err);
166239413783Smrg	}
166339413783Smrg    }
1664de2362d3Smrg
16653ed65abbSmrg    drmmode_output->props = calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec));
1666de2362d3Smrg    if (!drmmode_output->props)
1667de2362d3Smrg	return;
1668de2362d3Smrg
1669de2362d3Smrg    drmmode_output->num_props = 0;
1670de2362d3Smrg    for (i = 0, j = 0; i < mode_output->count_props; i++) {
16718bf5c682Smrg	drmmode_prop = drmModeGetProperty(pRADEONEnt->fd, mode_output->props[i]);
1672de2362d3Smrg	if (drmmode_property_ignore(drmmode_prop)) {
1673de2362d3Smrg	    drmModeFreeProperty(drmmode_prop);
1674de2362d3Smrg	    continue;
1675de2362d3Smrg	}
1676de2362d3Smrg	drmmode_output->props[j].mode_prop = drmmode_prop;
1677de2362d3Smrg	drmmode_output->props[j].value = mode_output->prop_values[i];
1678de2362d3Smrg	drmmode_output->num_props++;
1679de2362d3Smrg	j++;
1680de2362d3Smrg    }
1681de2362d3Smrg
16823ed65abbSmrg    /* Userspace-only property for TearFree */
16833ed65abbSmrg    tearfree_prop = calloc(1, sizeof(*tearfree_prop));
16843ed65abbSmrg    tearfree_prop->flags = DRM_MODE_PROP_ENUM;
168539413783Smrg    strcpy(tearfree_prop->name, "TearFree");
16863ed65abbSmrg    tearfree_prop->count_enums = 3;
16873ed65abbSmrg    tearfree_prop->enums = calloc(tearfree_prop->count_enums,
16883ed65abbSmrg				  sizeof(*tearfree_prop->enums));
168939413783Smrg    strcpy(tearfree_prop->enums[0].name, "off");
169039413783Smrg    strcpy(tearfree_prop->enums[1].name, "on");
16913ed65abbSmrg    tearfree_prop->enums[1].value = 1;
169239413783Smrg    strcpy(tearfree_prop->enums[2].name, "auto");
16933ed65abbSmrg    tearfree_prop->enums[2].value = 2;
16943ed65abbSmrg    drmmode_output->props[j].mode_prop = tearfree_prop;
16953ed65abbSmrg    drmmode_output->props[j].value = info->tear_free;
16963ed65abbSmrg    drmmode_output->tear_free = info->tear_free;
16973ed65abbSmrg    drmmode_output->num_props++;
16983ed65abbSmrg
1699de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
1700de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
1701de2362d3Smrg	drmmode_prop = p->mode_prop;
1702de2362d3Smrg
1703de2362d3Smrg	if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1704de2362d3Smrg	    INT32 range[2];
1705de2362d3Smrg	    INT32 value = p->value;
1706de2362d3Smrg
1707de2362d3Smrg	    p->num_atoms = 1;
1708de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
1709de2362d3Smrg	    if (!p->atoms)
1710de2362d3Smrg		continue;
1711de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1712de2362d3Smrg	    range[0] = drmmode_prop->values[0];
1713de2362d3Smrg	    range[1] = drmmode_prop->values[1];
1714de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1715de2362d3Smrg		    FALSE, TRUE,
1716de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1717de2362d3Smrg		    2, range);
1718de2362d3Smrg	    if (err != 0) {
1719de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1720de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
1721de2362d3Smrg	    }
1722de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1723de2362d3Smrg		    XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE);
1724de2362d3Smrg	    if (err != 0) {
1725de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1726de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
1727de2362d3Smrg	    }
1728de2362d3Smrg	} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1729de2362d3Smrg	    p->num_atoms = drmmode_prop->count_enums + 1;
1730de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
1731de2362d3Smrg	    if (!p->atoms)
1732de2362d3Smrg		continue;
1733de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1734de2362d3Smrg	    for (j = 1; j <= drmmode_prop->count_enums; j++) {
1735de2362d3Smrg		struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
1736de2362d3Smrg		p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
1737de2362d3Smrg	    }
1738de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1739de2362d3Smrg		    FALSE, FALSE,
1740de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1741de2362d3Smrg		    p->num_atoms - 1, (INT32 *)&p->atoms[1]);
1742de2362d3Smrg	    if (err != 0) {
1743de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1744de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
1745de2362d3Smrg	    }
1746de2362d3Smrg	    for (j = 0; j < drmmode_prop->count_enums; j++)
1747de2362d3Smrg		if (drmmode_prop->enums[j].value == p->value)
1748de2362d3Smrg		    break;
1749de2362d3Smrg	    /* there's always a matching value */
1750de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1751de2362d3Smrg		    XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
1752de2362d3Smrg	    if (err != 0) {
1753de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1754de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
1755de2362d3Smrg	    }
1756de2362d3Smrg	}
1757de2362d3Smrg    }
1758de2362d3Smrg}
1759de2362d3Smrg
176039413783Smrgstatic void
176139413783Smrgdrmmode_output_set_tear_free(RADEONEntPtr pRADEONEnt,
176239413783Smrg			     drmmode_output_private_ptr drmmode_output,
176339413783Smrg			     xf86CrtcPtr crtc, int tear_free)
176439413783Smrg{
176539413783Smrg	if (drmmode_output->tear_free == tear_free)
176639413783Smrg		return;
176739413783Smrg
176839413783Smrg	drmmode_output->tear_free = tear_free;
176939413783Smrg
177039413783Smrg	if (crtc) {
177139413783Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
177239413783Smrg				       crtc->x, crtc->y);
177339413783Smrg	}
177439413783Smrg}
177539413783Smrg
1776de2362d3Smrgstatic Bool
1777de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property,
1778de2362d3Smrg		RRPropertyValuePtr value)
1779de2362d3Smrg{
1780de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
17818bf5c682Smrg    RADEONEntPtr pRADEONEnt = RADEONEntPriv(output->scrn);
1782de2362d3Smrg    int i;
1783de2362d3Smrg
1784de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
1785de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
1786de2362d3Smrg
1787de2362d3Smrg	if (p->atoms[0] != property)
1788de2362d3Smrg	    continue;
1789de2362d3Smrg
1790de2362d3Smrg	if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1791de2362d3Smrg	    uint32_t val;
1792de2362d3Smrg
1793de2362d3Smrg	    if (value->type != XA_INTEGER || value->format != 32 ||
1794de2362d3Smrg		    value->size != 1)
1795de2362d3Smrg		return FALSE;
1796de2362d3Smrg	    val = *(uint32_t *)value->data;
1797de2362d3Smrg
17988bf5c682Smrg	    drmModeConnectorSetProperty(pRADEONEnt->fd, drmmode_output->output_id,
1799de2362d3Smrg		    p->mode_prop->prop_id, (uint64_t)val);
1800de2362d3Smrg	    return TRUE;
1801de2362d3Smrg	} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1802de2362d3Smrg	    Atom	atom;
1803de2362d3Smrg	    const char	*name;
1804de2362d3Smrg	    int		j;
1805de2362d3Smrg
1806de2362d3Smrg	    if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
1807de2362d3Smrg		return FALSE;
1808de2362d3Smrg	    memcpy(&atom, value->data, 4);
18098bf5c682Smrg	    if (!(name = NameForAtom(atom)))
18108bf5c682Smrg                return FALSE;
1811de2362d3Smrg
1812de2362d3Smrg	    /* search for matching name string, then set its value down */
1813de2362d3Smrg	    for (j = 0; j < p->mode_prop->count_enums; j++) {
1814de2362d3Smrg		if (!strcmp(p->mode_prop->enums[j].name, name)) {
18153ed65abbSmrg		    if (i == (drmmode_output->num_props - 1)) {
181639413783Smrg			drmmode_output_set_tear_free(pRADEONEnt, drmmode_output,
181739413783Smrg						     output->crtc, j);
18183ed65abbSmrg		    } else {
18198bf5c682Smrg			drmModeConnectorSetProperty(pRADEONEnt->fd,
18203ed65abbSmrg						    drmmode_output->output_id,
18213ed65abbSmrg						    p->mode_prop->prop_id,
18223ed65abbSmrg						    p->mode_prop->enums[j].value);
18233ed65abbSmrg		    }
18243ed65abbSmrg
1825de2362d3Smrg		    return TRUE;
1826de2362d3Smrg		}
1827de2362d3Smrg	    }
1828de2362d3Smrg	}
1829de2362d3Smrg    }
1830de2362d3Smrg
1831de2362d3Smrg    return TRUE;
1832de2362d3Smrg}
1833de2362d3Smrg
1834de2362d3Smrgstatic Bool
1835de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property)
1836de2362d3Smrg{
1837de2362d3Smrg    return TRUE;
1838de2362d3Smrg}
1839de2362d3Smrg
1840de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = {
1841de2362d3Smrg    .dpms = drmmode_output_dpms,
1842de2362d3Smrg    .create_resources = drmmode_output_create_resources,
1843de2362d3Smrg    .set_property = drmmode_output_set_property,
1844de2362d3Smrg    .get_property = drmmode_output_get_property,
1845de2362d3Smrg    .detect = drmmode_output_detect,
1846de2362d3Smrg    .mode_valid = drmmode_output_mode_valid,
1847de2362d3Smrg
1848de2362d3Smrg    .get_modes = drmmode_output_get_modes,
1849de2362d3Smrg    .destroy = drmmode_output_destroy
1850de2362d3Smrg};
1851de2362d3Smrg
1852de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown,
1853de2362d3Smrg				      SubPixelHorizontalRGB,
1854de2362d3Smrg				      SubPixelHorizontalBGR,
1855de2362d3Smrg				      SubPixelVerticalRGB,
1856de2362d3Smrg				      SubPixelVerticalBGR,
1857de2362d3Smrg				      SubPixelNone };
1858de2362d3Smrg
1859de2362d3Smrgconst char *output_names[] = { "None",
1860de2362d3Smrg			       "VGA",
1861de2362d3Smrg			       "DVI",
1862de2362d3Smrg			       "DVI",
1863de2362d3Smrg			       "DVI",
1864de2362d3Smrg			       "Composite",
1865de2362d3Smrg			       "S-video",
1866de2362d3Smrg			       "LVDS",
1867de2362d3Smrg			       "CTV",
1868de2362d3Smrg			       "DIN",
1869de2362d3Smrg			       "DisplayPort",
1870de2362d3Smrg			       "HDMI",
1871de2362d3Smrg			       "HDMI",
1872de2362d3Smrg			       "TV",
1873de2362d3Smrg			       "eDP"
1874de2362d3Smrg};
1875de2362d3Smrg
187618781e08Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
187718781e08Smrg
187818781e08Smrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
187918781e08Smrg{
188018781e08Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
188118781e08Smrg	int i;
188218781e08Smrg	for (i = 0; i < xf86_config->num_output; i++) {
188318781e08Smrg		xf86OutputPtr output = xf86_config->output[i];
188418781e08Smrg		drmmode_output_private_ptr drmmode_output;
188518781e08Smrg
188618781e08Smrg		drmmode_output = output->driver_private;
188718781e08Smrg		if (drmmode_output->output_id == id)
188818781e08Smrg			return output;
188918781e08Smrg	}
189018781e08Smrg	return NULL;
189118781e08Smrg}
189218781e08Smrg
189318781e08Smrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
189418781e08Smrg{
189518781e08Smrg	char *conn;
189618781e08Smrg	char conn_id[5];
189718781e08Smrg	int id, len;
189818781e08Smrg	char *blob_data;
189918781e08Smrg
190018781e08Smrg	if (!path_blob)
190118781e08Smrg		return -1;
190218781e08Smrg
190318781e08Smrg	blob_data = path_blob->data;
190418781e08Smrg	/* we only handle MST paths for now */
190518781e08Smrg	if (strncmp(blob_data, "mst:", 4))
190618781e08Smrg		return -1;
190718781e08Smrg
190818781e08Smrg	conn = strchr(blob_data + 4, '-');
190918781e08Smrg	if (!conn)
191018781e08Smrg		return -1;
191118781e08Smrg	len = conn - (blob_data + 4);
191218781e08Smrg	if (len + 1 > 5)
191318781e08Smrg		return -1;
191418781e08Smrg	memcpy(conn_id, blob_data + 4, len);
191518781e08Smrg	conn_id[len] = '\0';
191618781e08Smrg	id = strtoul(conn_id, NULL, 10);
191718781e08Smrg
191818781e08Smrg	*conn_base_id = id;
191918781e08Smrg
192018781e08Smrg	*path = conn + 1;
192118781e08Smrg	return 0;
192218781e08Smrg}
192318781e08Smrg
1924de2362d3Smrgstatic void
192518781e08Smrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
192618781e08Smrg		    drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi)
192718781e08Smrg{
192818781e08Smrg	xf86OutputPtr output;
192918781e08Smrg	int conn_id;
193018781e08Smrg	char *extra_path;
193118781e08Smrg
193218781e08Smrg	output = NULL;
193318781e08Smrg	if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
193418781e08Smrg		output = find_output(pScrn, conn_id);
193518781e08Smrg	if (output) {
193618781e08Smrg		snprintf(name, 32, "%s-%s", output->name, extra_path);
193718781e08Smrg	} else {
19388bf5c682Smrg		if (koutput->connector_type >= NUM_OUTPUT_NAMES) {
193918781e08Smrg			snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
194018781e08Smrg				 koutput->connector_type_id - 1);
19418bf5c682Smrg		} else if (pScrn->is_gpu) {
194218781e08Smrg			snprintf(name, 32, "%s-%d-%d",
194318781e08Smrg				 output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1,
194418781e08Smrg				 koutput->connector_type_id - 1);
19458bf5c682Smrg		} else {
194618781e08Smrg			/* need to do smart conversion here for compat with non-kms ATI driver */
194718781e08Smrg			if (koutput->connector_type_id == 1) {
194818781e08Smrg				switch(koutput->connector_type) {
194918781e08Smrg				case DRM_MODE_CONNECTOR_DVII:
195018781e08Smrg				case DRM_MODE_CONNECTOR_DVID:
195118781e08Smrg				case DRM_MODE_CONNECTOR_DVIA:
195218781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
195318781e08Smrg					(*num_dvi)++;
195418781e08Smrg					break;
195518781e08Smrg				case DRM_MODE_CONNECTOR_HDMIA:
195618781e08Smrg				case DRM_MODE_CONNECTOR_HDMIB:
195718781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
195818781e08Smrg					(*num_hdmi)++;
195918781e08Smrg					break;
196018781e08Smrg				case DRM_MODE_CONNECTOR_VGA:
196118781e08Smrg				case DRM_MODE_CONNECTOR_DisplayPort:
196218781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
196318781e08Smrg						 koutput->connector_type_id - 1);
196418781e08Smrg					break;
196518781e08Smrg				default:
196618781e08Smrg					snprintf(name, 32, "%s", output_names[koutput->connector_type]);
196718781e08Smrg					break;
196818781e08Smrg				}
196918781e08Smrg			} else {
197018781e08Smrg				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
197118781e08Smrg					 koutput->connector_type_id - 1);
197218781e08Smrg			}
197318781e08Smrg		}
197418781e08Smrg	}
197518781e08Smrg}
197618781e08Smrg
197718781e08Smrgstatic unsigned int
197818781e08Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic)
19790d16fef4Smrg{
198018781e08Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
19818bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1982de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1983de2362d3Smrg	xf86OutputPtr output;
1984de2362d3Smrg	drmModeConnectorPtr koutput;
1985de2362d3Smrg	drmModeEncoderPtr *kencoders = NULL;
1986de2362d3Smrg	drmmode_output_private_ptr drmmode_output;
198718781e08Smrg	drmModePropertyBlobPtr path_blob = NULL;
198839413783Smrg#if XF86_CRTC_VERSION >= 8
198939413783Smrg	Bool nonDesktop = FALSE;
199039413783Smrg#endif
1991de2362d3Smrg	char name[32];
1992de2362d3Smrg	int i;
1993de2362d3Smrg	const char *s;
1994de2362d3Smrg
19958bf5c682Smrg	koutput = drmModeGetConnector(pRADEONEnt->fd, mode_res->connectors[num]);
1996de2362d3Smrg	if (!koutput)
199718781e08Smrg		return 0;
199818781e08Smrg
19998bf5c682Smrg	path_blob = koutput_get_prop_blob(pRADEONEnt->fd, koutput, "PATH");
2000de2362d3Smrg
200139413783Smrg#if XF86_CRTC_VERSION >= 8
200239413783Smrg	i = koutput_get_prop_idx(pRADEONEnt->fd, koutput, DRM_MODE_PROP_RANGE,
200339413783Smrg				 "non-desktop");
200439413783Smrg	if (i >= 0)
200539413783Smrg		nonDesktop = koutput->prop_values[i] != 0;
200639413783Smrg#endif
200739413783Smrg
2008de2362d3Smrg	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
2009de2362d3Smrg	if (!kencoders) {
2010de2362d3Smrg		goto out_free_encoders;
2011de2362d3Smrg	}
2012de2362d3Smrg
2013de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
20148bf5c682Smrg		kencoders[i] = drmModeGetEncoder(pRADEONEnt->fd, koutput->encoders[i]);
2015de2362d3Smrg		if (!kencoders[i]) {
2016de2362d3Smrg			goto out_free_encoders;
2017de2362d3Smrg		}
2018de2362d3Smrg	}
2019de2362d3Smrg
202018781e08Smrg	drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi);
202118781e08Smrg	if (path_blob)
202218781e08Smrg		drmModeFreePropertyBlob(path_blob);
202318781e08Smrg
202418781e08Smrg	if (path_blob && dynamic) {
202518781e08Smrg		/* See if we have an output with this name already
202618781e08Smrg		 * and hook stuff up.
202718781e08Smrg		 */
202818781e08Smrg		for (i = 0; i < xf86_config->num_output; i++) {
202918781e08Smrg			output = xf86_config->output[i];
203018781e08Smrg
203118781e08Smrg			if (strncmp(output->name, name, 32))
203218781e08Smrg				continue;
203318781e08Smrg
203418781e08Smrg			drmmode_output = output->driver_private;
203518781e08Smrg			drmmode_output->output_id = mode_res->connectors[num];
203618781e08Smrg			drmmode_output->mode_output = koutput;
203739413783Smrg#if XF86_CRTC_VERSION >= 8
203839413783Smrg			output->non_desktop = nonDesktop;
203939413783Smrg#endif
204018781e08Smrg			for (i = 0; i < koutput->count_encoders; i++)
204118781e08Smrg				drmModeFreeEncoder(kencoders[i]);
204218781e08Smrg			free(kencoders);
204318781e08Smrg			return 0;
204418781e08Smrg		}
2045de2362d3Smrg	}
2046de2362d3Smrg
2047de2362d3Smrg	if (xf86IsEntityShared(pScrn->entityList[0])) {
2048de2362d3Smrg		if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
2049de2362d3Smrg			if (!RADEONZaphodStringMatches(pScrn, s, name))
2050de2362d3Smrg				goto out_free_encoders;
2051de2362d3Smrg		} else {
205218781e08Smrg			if (!info->IsSecondary && (num != 0))
2053de2362d3Smrg				goto out_free_encoders;
2054de2362d3Smrg			else if (info->IsSecondary && (num != 1))
2055de2362d3Smrg				goto out_free_encoders;
2056de2362d3Smrg		}
2057de2362d3Smrg	}
2058de2362d3Smrg
2059de2362d3Smrg	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
2060de2362d3Smrg	if (!output) {
2061de2362d3Smrg		goto out_free_encoders;
2062de2362d3Smrg	}
2063de2362d3Smrg
2064de2362d3Smrg	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
2065de2362d3Smrg	if (!drmmode_output) {
2066de2362d3Smrg		xf86OutputDestroy(output);
2067de2362d3Smrg		goto out_free_encoders;
2068de2362d3Smrg	}
2069de2362d3Smrg
207018781e08Smrg	drmmode_output->output_id = mode_res->connectors[num];
2071de2362d3Smrg	drmmode_output->mode_output = koutput;
2072de2362d3Smrg	drmmode_output->mode_encoders = kencoders;
2073de2362d3Smrg	drmmode_output->drmmode = drmmode;
2074de2362d3Smrg	output->mm_width = koutput->mmWidth;
2075de2362d3Smrg	output->mm_height = koutput->mmHeight;
2076de2362d3Smrg
2077de2362d3Smrg	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
2078de2362d3Smrg	output->interlaceAllowed = TRUE;
2079de2362d3Smrg	output->doubleScanAllowed = TRUE;
2080de2362d3Smrg	output->driver_private = drmmode_output;
208139413783Smrg#if XF86_CRTC_VERSION >= 8
208239413783Smrg	output->non_desktop = nonDesktop;
208339413783Smrg#endif
2084de2362d3Smrg
2085de2362d3Smrg	output->possible_crtcs = 0xffffffff;
2086de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
2087de2362d3Smrg		output->possible_crtcs &= kencoders[i]->possible_crtcs;
2088de2362d3Smrg	}
2089de2362d3Smrg	/* work out the possible clones later */
2090de2362d3Smrg	output->possible_clones = 0;
2091de2362d3Smrg
20928bf5c682Smrg	drmmode_output->dpms_enum_id =
20938bf5c682Smrg		koutput_get_prop_id(pRADEONEnt->fd, koutput, DRM_MODE_PROP_ENUM,
20948bf5c682Smrg				    "DPMS");
2095de2362d3Smrg
209618781e08Smrg	if (dynamic) {
209718781e08Smrg		output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
209818781e08Smrg		drmmode_output_create_resources(output);
209918781e08Smrg	}
210018781e08Smrg
210118781e08Smrg	return 1;
2102de2362d3Smrgout_free_encoders:
2103de2362d3Smrg	if (kencoders){
2104de2362d3Smrg		for (i = 0; i < koutput->count_encoders; i++)
2105de2362d3Smrg			drmModeFreeEncoder(kencoders[i]);
2106de2362d3Smrg		free(kencoders);
2107de2362d3Smrg	}
2108de2362d3Smrg	drmModeFreeConnector(koutput);
210918781e08Smrg	return 0;
2110de2362d3Smrg}
2111de2362d3Smrg
2112de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
2113de2362d3Smrg{
2114de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout;
2115de2362d3Smrg	int i;
2116de2362d3Smrg	xf86OutputPtr clone_output;
2117de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2118de2362d3Smrg	int index_mask = 0;
2119de2362d3Smrg
2120de2362d3Smrg	if (drmmode_output->enc_clone_mask == 0)
2121de2362d3Smrg		return index_mask;
2122de2362d3Smrg
2123de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
2124de2362d3Smrg		clone_output = xf86_config->output[i];
2125de2362d3Smrg		clone_drmout = clone_output->driver_private;
2126de2362d3Smrg		if (output == clone_output)
2127de2362d3Smrg			continue;
2128de2362d3Smrg
2129de2362d3Smrg		if (clone_drmout->enc_mask == 0)
2130de2362d3Smrg			continue;
2131de2362d3Smrg		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
2132de2362d3Smrg			index_mask |= (1 << i);
2133de2362d3Smrg	}
2134de2362d3Smrg	return index_mask;
2135de2362d3Smrg}
2136de2362d3Smrg
2137de2362d3Smrg
2138de2362d3Smrgstatic void
213918781e08Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
2140de2362d3Smrg{
2141de2362d3Smrg	int i, j;
2142de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2143de2362d3Smrg
2144de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
2145de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
2146de2362d3Smrg		drmmode_output_private_ptr drmmode_output;
2147de2362d3Smrg
2148de2362d3Smrg		drmmode_output = output->driver_private;
2149de2362d3Smrg		drmmode_output->enc_clone_mask = 0xff;
2150de2362d3Smrg		/* and all the possible encoder clones for this output together */
2151de2362d3Smrg		for (j = 0; j < drmmode_output->mode_output->count_encoders; j++)
2152de2362d3Smrg		{
2153de2362d3Smrg			int k;
215418781e08Smrg			for (k = 0; k < mode_res->count_encoders; k++) {
215518781e08Smrg				if (mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id)
2156de2362d3Smrg					drmmode_output->enc_mask |= (1 << k);
2157de2362d3Smrg			}
2158de2362d3Smrg
2159de2362d3Smrg			drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones;
2160de2362d3Smrg		}
2161de2362d3Smrg	}
2162de2362d3Smrg
2163de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
2164de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
2165de2362d3Smrg		output->possible_clones = find_clones(scrn, output);
2166de2362d3Smrg	}
2167de2362d3Smrg}
2168de2362d3Smrg
2169de2362d3Smrg/* returns height alignment in pixels */
2170de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling)
2171de2362d3Smrg{
2172de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2173de2362d3Smrg	int height_align = 1;
2174de2362d3Smrg
2175de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2176de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
2177de2362d3Smrg			height_align =  info->num_channels * 8;
2178de2362d3Smrg		else if (tiling & RADEON_TILING_MICRO)
2179de2362d3Smrg			height_align = 8;
2180de2362d3Smrg		else
2181de2362d3Smrg			height_align = 8;
2182de2362d3Smrg	} else {
218318781e08Smrg		if (tiling & RADEON_TILING_MICRO_SQUARE)
218418781e08Smrg			height_align =  32;
218518781e08Smrg		else if (tiling)
2186de2362d3Smrg			height_align = 16;
2187de2362d3Smrg		else
2188de2362d3Smrg			height_align = 1;
2189de2362d3Smrg	}
2190de2362d3Smrg	return height_align;
2191de2362d3Smrg}
2192de2362d3Smrg
2193de2362d3Smrg/* returns pitch alignment in pixels */
2194de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
2195de2362d3Smrg{
2196de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2197de2362d3Smrg	int pitch_align = 1;
2198de2362d3Smrg
2199de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2200de2362d3Smrg		if (tiling & RADEON_TILING_MACRO) {
2201de2362d3Smrg			/* general surface requirements */
2202de2362d3Smrg			pitch_align = MAX(info->num_banks,
2203de2362d3Smrg					  (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8;
2204de2362d3Smrg			/* further restrictions for scanout */
2205de2362d3Smrg			pitch_align = MAX(info->num_banks * 8, pitch_align);
2206de2362d3Smrg		} else if (tiling & RADEON_TILING_MICRO) {
2207de2362d3Smrg			/* general surface requirements */
2208de2362d3Smrg			pitch_align = MAX(8, (info->group_bytes / (8 * bpe)));
2209de2362d3Smrg			/* further restrictions for scanout */
2210de2362d3Smrg			pitch_align = MAX(info->group_bytes / bpe, pitch_align);
2211de2362d3Smrg		} else {
2212de2362d3Smrg			if (info->have_tiling_info)
2213de2362d3Smrg				/* linear aligned requirements */
2214de2362d3Smrg				pitch_align = MAX(64, info->group_bytes / bpe);
2215de2362d3Smrg			else
2216de2362d3Smrg				/* default to 512 elements if we don't know the real
2217de2362d3Smrg				 * group size otherwise the kernel may reject the CS
2218de2362d3Smrg				 * if the group sizes don't match as the pitch won't
2219de2362d3Smrg				 * be aligned properly.
2220de2362d3Smrg				 */
2221de2362d3Smrg				pitch_align = 512;
2222de2362d3Smrg		}
2223de2362d3Smrg	} else {
2224de2362d3Smrg		/* general surface requirements */
2225de2362d3Smrg		if (tiling)
2226de2362d3Smrg			pitch_align = 256 / bpe;
2227de2362d3Smrg		else
2228de2362d3Smrg			pitch_align = 64;
2229de2362d3Smrg	}
2230de2362d3Smrg	return pitch_align;
2231de2362d3Smrg}
2232de2362d3Smrg
2233de2362d3Smrg/* returns base alignment in bytes */
2234de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
2235de2362d3Smrg{
2236de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2237de2362d3Smrg	int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling);
2238de2362d3Smrg	int height_align = drmmode_get_height_align(scrn, tiling);
2239de2362d3Smrg	int base_align = RADEON_GPU_PAGE_SIZE;
2240de2362d3Smrg
2241de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2242de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
2243de2362d3Smrg			base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe,
2244de2362d3Smrg					 pixel_align * bpe * height_align);
2245de2362d3Smrg		else {
2246de2362d3Smrg			if (info->have_tiling_info)
2247de2362d3Smrg				base_align = info->group_bytes;
2248de2362d3Smrg			else
2249de2362d3Smrg				/* default to 512 if we don't know the real
2250de2362d3Smrg				 * group size otherwise the kernel may reject the CS
2251de2362d3Smrg				 * if the group sizes don't match as the base won't
2252de2362d3Smrg				 * be aligned properly.
2253de2362d3Smrg				 */
2254de2362d3Smrg				base_align = 512;
2255de2362d3Smrg		}
2256de2362d3Smrg	}
2257de2362d3Smrg	return base_align;
2258de2362d3Smrg}
2259de2362d3Smrg
2260de2362d3Smrgstatic Bool
2261de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
2262de2362d3Smrg{
2263de2362d3Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2264de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
226539413783Smrg	struct radeon_buffer *old_front = NULL;
2266de2362d3Smrg	ScreenPtr   screen = xf86ScrnToScreen(scrn);
2267de2362d3Smrg	int	    i, pitch, old_width, old_height, old_pitch;
226839413783Smrg	int usage = CREATE_PIXMAP_USAGE_BACKING_PIXMAP;
226918781e08Smrg	int cpp = info->pixel_bytes;
227039413783Smrg	uint32_t tiling_flags;
2271de2362d3Smrg	PixmapPtr ppix = screen->GetScreenPixmap(screen);
2272de2362d3Smrg	void *fb_shadow;
2273de2362d3Smrg
2274de2362d3Smrg	if (scrn->virtualX == width && scrn->virtualY == height)
2275de2362d3Smrg		return TRUE;
2276de2362d3Smrg
227739413783Smrg	if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) {
227839413783Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
227939413783Smrg			   "Xorg tried resizing screen to %dx%d, but maximum "
228039413783Smrg			   "supported is %dx%d\n", width, height,
228139413783Smrg			   xf86_config->maxWidth, xf86_config->maxHeight);
228239413783Smrg		return FALSE;
2283de2362d3Smrg	}
2284de2362d3Smrg
228539413783Smrg	if (info->allowColorTiling && !info->shadow_primary) {
228639413783Smrg		if (info->ChipFamily < CHIP_FAMILY_R600 || info->allowColorTiling2D)
228739413783Smrg			usage |= RADEON_CREATE_PIXMAP_TILING_MACRO;
228839413783Smrg		else
228939413783Smrg			usage |= RADEON_CREATE_PIXMAP_TILING_MICRO;
2290de2362d3Smrg	}
2291de2362d3Smrg
229239413783Smrg	xf86DrvMsg(scrn->scrnIndex, X_INFO, "Allocate new frame buffer %dx%d\n",
229339413783Smrg		   width, height);
2294de2362d3Smrg
2295de2362d3Smrg	old_width = scrn->virtualX;
2296de2362d3Smrg	old_height = scrn->virtualY;
2297de2362d3Smrg	old_pitch = scrn->displayWidth;
229839413783Smrg	old_front = info->front_buffer;
2299de2362d3Smrg
2300de2362d3Smrg	scrn->virtualX = width;
2301de2362d3Smrg	scrn->virtualY = height;
2302de2362d3Smrg
230339413783Smrg	info->front_buffer = radeon_alloc_pixmap_bo(scrn, scrn->virtualX,
230439413783Smrg						    scrn->virtualY, scrn->depth,
230539413783Smrg						    usage, scrn->bitsPerPixel,
230639413783Smrg						    &pitch,
230739413783Smrg						    &info->front_surface,
230839413783Smrg						    &tiling_flags);
230939413783Smrg	if (!info->front_buffer)
2310de2362d3Smrg		goto fail;
2311de2362d3Smrg
231239413783Smrg	scrn->displayWidth = pitch / cpp;
231339413783Smrg
231439413783Smrg	if (!info->use_glamor) {
2315de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
231639413783Smrg		switch (cpp) {
231739413783Smrg		case 4:
231839413783Smrg			tiling_flags |= RADEON_TILING_SWAP_32BIT;
231939413783Smrg			break;
232039413783Smrg		case 2:
232139413783Smrg			tiling_flags |= RADEON_TILING_SWAP_16BIT;
232239413783Smrg			break;
232339413783Smrg		}
232439413783Smrg		if (info->ChipFamily < CHIP_FAMILY_R600 &&
232539413783Smrg		    info->r600_shadow_fb && tiling_flags)
232639413783Smrg			tiling_flags |= RADEON_TILING_SURFACE;
2327de2362d3Smrg#endif
232839413783Smrg		if (tiling_flags)
232939413783Smrg			radeon_bo_set_tiling(info->front_buffer->bo.radeon, tiling_flags, pitch);
233039413783Smrg	}
2331de2362d3Smrg
2332de2362d3Smrg	if (!info->r600_shadow_fb) {
233339413783Smrg		if (info->surf_man && !info->use_glamor)
233439413783Smrg			*radeon_get_pixmap_surface(ppix) = info->front_surface;
2335de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
2336de2362d3Smrg					   width, height, -1, -1, pitch, NULL);
2337de2362d3Smrg	} else {
233839413783Smrg		if (radeon_bo_map(info->front_buffer->bo.radeon, 1))
2339de2362d3Smrg			goto fail;
234039413783Smrg		fb_shadow = calloc(1, pitch * scrn->virtualY);
234139413783Smrg		if (!fb_shadow)
2342de2362d3Smrg			goto fail;
2343de2362d3Smrg		free(info->fb_shadow);
2344de2362d3Smrg		info->fb_shadow = fb_shadow;
2345de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
2346de2362d3Smrg					   width, height, -1, -1, pitch,
2347de2362d3Smrg					   info->fb_shadow);
2348de2362d3Smrg	}
234918781e08Smrg
235018781e08Smrg	if (info->use_glamor)
235118781e08Smrg		radeon_glamor_create_screen_resources(scrn->pScreen);
235218781e08Smrg
235318781e08Smrg	if (!info->r600_shadow_fb) {
235439413783Smrg		if (!radeon_set_pixmap_bo(ppix, info->front_buffer))
235518781e08Smrg			goto fail;
235618781e08Smrg	}
235718781e08Smrg
23588bf5c682Smrg	radeon_pixmap_clear(ppix);
235939413783Smrg	radeon_finish(scrn, info->front_buffer);
23600d16fef4Smrg
2361de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
2362de2362d3Smrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
2363de2362d3Smrg
2364de2362d3Smrg		if (!crtc->enabled)
2365de2362d3Smrg			continue;
2366de2362d3Smrg
2367de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode,
2368de2362d3Smrg				       crtc->rotation, crtc->x, crtc->y);
2369de2362d3Smrg	}
2370de2362d3Smrg
237139413783Smrg	radeon_buffer_unref(&old_front);
2372de2362d3Smrg
237339413783Smrg	radeon_kms_update_vram_limit(scrn, pitch * scrn->virtualY);
2374de2362d3Smrg	return TRUE;
2375de2362d3Smrg
2376de2362d3Smrg fail:
237739413783Smrg	radeon_buffer_unref(&info->front_buffer);
237839413783Smrg	info->front_buffer = old_front;
2379de2362d3Smrg	scrn->virtualX = old_width;
2380de2362d3Smrg	scrn->virtualY = old_height;
2381de2362d3Smrg	scrn->displayWidth = old_pitch;
2382de2362d3Smrg
2383de2362d3Smrg	return FALSE;
2384de2362d3Smrg}
2385de2362d3Smrg
238639413783Smrgstatic void
238739413783Smrgdrmmode_validate_leases(ScrnInfoPtr scrn)
238839413783Smrg{
238939413783Smrg#ifdef XF86_LEASE_VERSION
239039413783Smrg	ScreenPtr screen = scrn->pScreen;
239139413783Smrg	rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
239239413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
239339413783Smrg	drmModeLesseeListPtr lessees;
239439413783Smrg	RRLeasePtr lease, next;
239539413783Smrg	int l;
239639413783Smrg
239739413783Smrg	/* We can't talk to the kernel about leases when VT switched */
239839413783Smrg	if (!scrn->vtSema)
239939413783Smrg		return;
240039413783Smrg
240139413783Smrg	lessees = drmModeListLessees(pRADEONEnt->fd);
240239413783Smrg	if (!lessees)
240339413783Smrg		return;
240439413783Smrg
240539413783Smrg	xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
240639413783Smrg		drmmode_lease_private_ptr lease_private = lease->devPrivate;
240739413783Smrg
240839413783Smrg		for (l = 0; l < lessees->count; l++) {
240939413783Smrg			if (lessees->lessees[l] == lease_private->lessee_id)
241039413783Smrg				break;
241139413783Smrg		}
241239413783Smrg
241339413783Smrg		/* check to see if the lease has gone away */
241439413783Smrg		if (l == lessees->count) {
241539413783Smrg			free(lease_private);
241639413783Smrg			lease->devPrivate = NULL;
241739413783Smrg			xf86CrtcLeaseTerminated(lease);
241839413783Smrg		}
241939413783Smrg	}
242039413783Smrg
242139413783Smrg	free(lessees);
242239413783Smrg#endif
242339413783Smrg}
242439413783Smrg
242539413783Smrg#ifdef XF86_LEASE_VERSION
242639413783Smrg
242739413783Smrgstatic int
242839413783Smrgdrmmode_create_lease(RRLeasePtr lease, int *fd)
242939413783Smrg{
243039413783Smrg	ScreenPtr screen = lease->screen;
243139413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
243239413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
243339413783Smrg	drmmode_lease_private_ptr lease_private;
243439413783Smrg	int noutput = lease->numOutputs;
243539413783Smrg	int ncrtc = lease->numCrtcs;
243639413783Smrg	uint32_t *objects;
243739413783Smrg	size_t nobjects;
243839413783Smrg	int lease_fd;
243939413783Smrg	int c, o;
244039413783Smrg	int i;
244139413783Smrg
244239413783Smrg	nobjects = ncrtc + noutput;
244339413783Smrg	if (nobjects == 0 || nobjects > (SIZE_MAX / 4) ||
244439413783Smrg	    ncrtc > (SIZE_MAX - noutput))
244539413783Smrg		return BadValue;
244639413783Smrg
244739413783Smrg	lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
244839413783Smrg	if (!lease_private)
244939413783Smrg		return BadAlloc;
245039413783Smrg
245139413783Smrg	objects = malloc(nobjects * 4);
245239413783Smrg	if (!objects) {
245339413783Smrg		free(lease_private);
245439413783Smrg		return BadAlloc;
245539413783Smrg	}
245639413783Smrg
245739413783Smrg	i = 0;
245839413783Smrg
245939413783Smrg	/* Add CRTC ids */
246039413783Smrg	for (c = 0; c < ncrtc; c++) {
246139413783Smrg		xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
246239413783Smrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
246339413783Smrg
246439413783Smrg		objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
246539413783Smrg	}
246639413783Smrg
246739413783Smrg	/* Add connector ids */
246839413783Smrg	for (o = 0; o < noutput; o++) {
246939413783Smrg		xf86OutputPtr   output = lease->outputs[o]->devPrivate;
247039413783Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
247139413783Smrg
247239413783Smrg		objects[i++] = drmmode_output->mode_output->connector_id;
247339413783Smrg	}
247439413783Smrg
247539413783Smrg	/* call kernel to create lease */
247639413783Smrg	assert (i == nobjects);
247739413783Smrg
247839413783Smrg	lease_fd = drmModeCreateLease(pRADEONEnt->fd, objects, nobjects, 0,
247939413783Smrg				      &lease_private->lessee_id);
248039413783Smrg
248139413783Smrg	free(objects);
248239413783Smrg
248339413783Smrg	if (lease_fd < 0) {
248439413783Smrg		free(lease_private);
248539413783Smrg		return BadMatch;
248639413783Smrg	}
248739413783Smrg
248839413783Smrg	lease->devPrivate = lease_private;
248939413783Smrg
249039413783Smrg	xf86CrtcLeaseStarted(lease);
249139413783Smrg
249239413783Smrg	*fd = lease_fd;
249339413783Smrg	return Success;
249439413783Smrg}
249539413783Smrg
249639413783Smrgstatic void
249739413783Smrgdrmmode_terminate_lease(RRLeasePtr lease)
249839413783Smrg{
249939413783Smrg	drmmode_lease_private_ptr lease_private = lease->devPrivate;
250039413783Smrg	ScreenPtr screen = lease->screen;
250139413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
250239413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
250339413783Smrg
250439413783Smrg	if (drmModeRevokeLease(pRADEONEnt->fd, lease_private->lessee_id) == 0) {
250539413783Smrg		free(lease_private);
250639413783Smrg		lease->devPrivate = NULL;
250739413783Smrg		xf86CrtcLeaseTerminated(lease);
250839413783Smrg	}
250939413783Smrg}
251039413783Smrg
251139413783Smrg#endif // XF86_LEASE_VERSION
251239413783Smrg
2513de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
251439413783Smrg	.resize = drmmode_xf86crtc_resize,
251539413783Smrg#ifdef XF86_LEASE_VERSION
251639413783Smrg	.create_lease = drmmode_create_lease,
251739413783Smrg	.terminate_lease = drmmode_terminate_lease
251839413783Smrg#endif
2519de2362d3Smrg};
2520de2362d3Smrg
2521de2362d3Smrgstatic void
252218781e08Smrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
2523de2362d3Smrg{
25248bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
25258bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
252618781e08Smrg	drmmode_flipdata_ptr flipdata = event_data;
252739413783Smrg	int crtc_id = drmmode_get_crtc_id(crtc);
252839413783Smrg	struct drmmode_fb **fb = &flipdata->fb[crtc_id];
252939413783Smrg
253039413783Smrg	if (drmmode_crtc->flip_pending == *fb) {
253139413783Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending,
253239413783Smrg				     NULL);
253339413783Smrg	}
253439413783Smrg	drmmode_fb_reference(pRADEONEnt->fd, fb, NULL);
253518781e08Smrg
253618781e08Smrg	if (--flipdata->flip_count == 0) {
253718781e08Smrg		if (!flipdata->fe_crtc)
253818781e08Smrg			flipdata->fe_crtc = crtc;
253918781e08Smrg		flipdata->abort(flipdata->fe_crtc, flipdata->event_data);
254018781e08Smrg		free(flipdata);
254118781e08Smrg	}
2542de2362d3Smrg}
2543de2362d3Smrg
2544de2362d3Smrgstatic void
254518781e08Smrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
2546de2362d3Smrg{
25478bf5c682Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
25488bf5c682Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(crtc->scrn);
254918781e08Smrg	drmmode_flipdata_ptr flipdata = event_data;
255039413783Smrg	int crtc_id = drmmode_get_crtc_id(crtc);
255139413783Smrg	struct drmmode_fb **fb = &flipdata->fb[crtc_id];
2552de2362d3Smrg
2553de2362d3Smrg	/* Is this the event whose info shall be delivered to higher level? */
255418781e08Smrg	if (crtc == flipdata->fe_crtc) {
2555de2362d3Smrg		/* Yes: Cache msc, ust for later delivery. */
2556de2362d3Smrg		flipdata->fe_frame = frame;
255718781e08Smrg		flipdata->fe_usec = usec;
2558de2362d3Smrg	}
2559de2362d3Smrg
256039413783Smrg	if (drmmode_crtc->flip_pending == *fb) {
25618bf5c682Smrg		drmmode_fb_reference(pRADEONEnt->fd,
25628bf5c682Smrg				     &drmmode_crtc->flip_pending, NULL);
25638bf5c682Smrg	}
256439413783Smrg	drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb, *fb);
256539413783Smrg	drmmode_fb_reference(pRADEONEnt->fd, fb, NULL);
25668bf5c682Smrg
256718781e08Smrg	if (--flipdata->flip_count == 0) {
256818781e08Smrg		/* Deliver MSC & UST from reference/current CRTC to flip event
256918781e08Smrg		 * handler
257018781e08Smrg		 */
257118781e08Smrg		if (flipdata->fe_crtc)
257218781e08Smrg			flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame,
257318781e08Smrg					  flipdata->fe_usec, flipdata->event_data);
257418781e08Smrg		else
257518781e08Smrg			flipdata->handler(crtc, frame, usec, flipdata->event_data);
2576de2362d3Smrg
257718781e08Smrg		free(flipdata);
257818781e08Smrg	}
2579de2362d3Smrg}
2580de2362d3Smrg
2581de2362d3Smrg
258218781e08Smrg#if HAVE_NOTIFY_FD
258318781e08Smrgstatic void
258418781e08Smrgdrm_notify_fd(int fd, int ready, void *data)
258518781e08Smrg#else
2586de2362d3Smrgstatic void
2587de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p)
258818781e08Smrg#endif
2589de2362d3Smrg{
259039413783Smrg	drmmode_ptr drmmode = data;
259139413783Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(drmmode->scrn);
25928bf5c682Smrg
259318781e08Smrg#if !HAVE_NOTIFY_FD
2594de2362d3Smrg	fd_set *read_mask = p;
2595de2362d3Smrg
25968bf5c682Smrg	if (err >= 0 && FD_ISSET(pRADEONEnt->fd, read_mask))
259718781e08Smrg#endif
259818781e08Smrg	{
259939413783Smrg		radeon_drm_handle_event(pRADEONEnt->fd, &drmmode->event_context);
2600de2362d3Smrg	}
2601de2362d3Smrg}
2602de2362d3Smrg
26038bf5c682Smrgstatic Bool drmmode_probe_page_flip_target(RADEONEntPtr pRADEONEnt)
26043ed65abbSmrg{
26053ed65abbSmrg#ifdef DRM_CAP_PAGE_FLIP_TARGET
26063ed65abbSmrg	uint64_t cap_value;
26073ed65abbSmrg
26088bf5c682Smrg	return drmGetCap(pRADEONEnt->fd, DRM_CAP_PAGE_FLIP_TARGET,
26093ed65abbSmrg			 &cap_value) == 0 && cap_value != 0;
26103ed65abbSmrg#else
26113ed65abbSmrg	return FALSE;
26123ed65abbSmrg#endif
26133ed65abbSmrg}
26143ed65abbSmrg
26153ed65abbSmrgstatic int
26168bf5c682Smrgdrmmode_page_flip(RADEONEntPtr pRADEONEnt,
26178bf5c682Smrg		  drmmode_crtc_private_ptr drmmode_crtc, int fb_id,
26183ed65abbSmrg		  uint32_t flags, uintptr_t drm_queue_seq)
26193ed65abbSmrg{
26203ed65abbSmrg	flags |= DRM_MODE_PAGE_FLIP_EVENT;
26218bf5c682Smrg	return drmModePageFlip(pRADEONEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
26223ed65abbSmrg			       fb_id, flags, (void*)drm_queue_seq);
26233ed65abbSmrg}
26243ed65abbSmrg
26253ed65abbSmrgint
26263ed65abbSmrgdrmmode_page_flip_target_absolute(RADEONEntPtr pRADEONEnt,
26273ed65abbSmrg				  drmmode_crtc_private_ptr drmmode_crtc,
26283ed65abbSmrg				  int fb_id, uint32_t flags,
26293ed65abbSmrg				  uintptr_t drm_queue_seq, uint32_t target_msc)
26303ed65abbSmrg{
26313ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET
26323ed65abbSmrg	if (pRADEONEnt->has_page_flip_target) {
26333ed65abbSmrg		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE;
26348bf5c682Smrg		return drmModePageFlipTarget(pRADEONEnt->fd,
26353ed65abbSmrg					     drmmode_crtc->mode_crtc->crtc_id,
26363ed65abbSmrg					     fb_id, flags, (void*)drm_queue_seq,
26373ed65abbSmrg					     target_msc);
26383ed65abbSmrg	}
26393ed65abbSmrg#endif
26403ed65abbSmrg
26418bf5c682Smrg	return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags,
26428bf5c682Smrg				 drm_queue_seq);
26433ed65abbSmrg}
26443ed65abbSmrg
26453ed65abbSmrgint
26463ed65abbSmrgdrmmode_page_flip_target_relative(RADEONEntPtr pRADEONEnt,
26473ed65abbSmrg				  drmmode_crtc_private_ptr drmmode_crtc,
26483ed65abbSmrg				  int fb_id, uint32_t flags,
26493ed65abbSmrg				  uintptr_t drm_queue_seq, uint32_t target_msc)
26503ed65abbSmrg{
26513ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET
26523ed65abbSmrg	if (pRADEONEnt->has_page_flip_target) {
26533ed65abbSmrg		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE;
26548bf5c682Smrg		return drmModePageFlipTarget(pRADEONEnt->fd,
26553ed65abbSmrg					     drmmode_crtc->mode_crtc->crtc_id,
26563ed65abbSmrg					     fb_id, flags, (void*)drm_queue_seq,
26573ed65abbSmrg					     target_msc);
26583ed65abbSmrg	}
26593ed65abbSmrg#endif
26603ed65abbSmrg
26618bf5c682Smrg	return drmmode_page_flip(pRADEONEnt, drmmode_crtc, fb_id, flags,
26628bf5c682Smrg				 drm_queue_seq);
26633ed65abbSmrg}
26643ed65abbSmrg
2665de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
2666de2362d3Smrg{
266718781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
266818781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
2669de2362d3Smrg	int i, num_dvi = 0, num_hdmi = 0;
267018781e08Smrg	drmModeResPtr mode_res;
267118781e08Smrg	unsigned int crtcs_needed = 0;
267218781e08Smrg	char *bus_id_string, *provider_name;
2673de2362d3Smrg
2674de2362d3Smrg	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
2675de2362d3Smrg
2676de2362d3Smrg	drmmode->scrn = pScrn;
26778bf5c682Smrg	mode_res = drmModeGetResources(pRADEONEnt->fd);
267818781e08Smrg	if (!mode_res)
2679de2362d3Smrg		return FALSE;
2680de2362d3Smrg
268118781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
268218781e08Smrg		       "Initializing outputs ...\n");
268318781e08Smrg	for (i = 0; i < mode_res->count_connectors; i++)
268418781e08Smrg		crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res,
268518781e08Smrg						    i, &num_dvi, &num_hdmi, 0);
268618781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
268718781e08Smrg		       "%d crtcs needed for screen.\n", crtcs_needed);
268818781e08Smrg
26898bf5c682Smrg	/* Need per-screen drmmode_crtc_funcs, based on our global template,
26908bf5c682Smrg	 * so we can disable some functions, depending on screen settings.
26918bf5c682Smrg	 */
26928bf5c682Smrg	info->drmmode_crtc_funcs = drmmode_crtc_funcs;
26938bf5c682Smrg
269418781e08Smrg	if (info->r600_shadow_fb) {
269518781e08Smrg		/* Rotation requires hardware acceleration */
26968bf5c682Smrg		info->drmmode_crtc_funcs.shadow_allocate = NULL;
26978bf5c682Smrg		info->drmmode_crtc_funcs.shadow_create = NULL;
26988bf5c682Smrg		info->drmmode_crtc_funcs.shadow_destroy = NULL;
269918781e08Smrg	}
270018781e08Smrg
27018bf5c682Smrg	/* Hw gamma lut's are currently bypassed by the hw at color depth 30,
27028bf5c682Smrg	 * so spare the server the effort to compute and update the cluts.
27038bf5c682Smrg	 */
27048bf5c682Smrg	if (pScrn->depth == 30)
27058bf5c682Smrg		info->drmmode_crtc_funcs.gamma_set = NULL;
27068bf5c682Smrg
270718781e08Smrg	drmmode->count_crtcs = mode_res->count_crtcs;
270818781e08Smrg	xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height);
270918781e08Smrg
271018781e08Smrg	for (i = 0; i < mode_res->count_crtcs; i++)
271118781e08Smrg		if (!xf86IsEntityShared(pScrn->entityList[0]) ||
271218781e08Smrg		    (crtcs_needed && !(pRADEONEnt->assigned_crtcs & (1 << i))))
271318781e08Smrg			crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
2714de2362d3Smrg
271518781e08Smrg	/* All ZaphodHeads outputs provided with matching crtcs? */
271618781e08Smrg	if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
271718781e08Smrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
271818781e08Smrg			   "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
271918781e08Smrg			   crtcs_needed);
2720de2362d3Smrg
2721de2362d3Smrg	/* workout clones */
272218781e08Smrg	drmmode_clones_init(pScrn, drmmode, mode_res);
272318781e08Smrg
272418781e08Smrg	bus_id_string = DRICreatePCIBusID(info->PciInfo);
272518781e08Smrg	XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string);
272618781e08Smrg	free(bus_id_string);
272718781e08Smrg	xf86ProviderSetup(pScrn, NULL, provider_name);
272818781e08Smrg	free(provider_name);
2729de2362d3Smrg
2730de2362d3Smrg	xf86InitialConfiguration(pScrn, TRUE);
2731de2362d3Smrg
27328bf5c682Smrg	pRADEONEnt->has_page_flip_target = drmmode_probe_page_flip_target(pRADEONEnt);
27333ed65abbSmrg
273418781e08Smrg	drmModeFreeResources(mode_res);
2735de2362d3Smrg	return TRUE;
2736de2362d3Smrg}
2737de2362d3Smrg
2738de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
2739de2362d3Smrg{
2740de2362d3Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2741de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
2742de2362d3Smrg
274318781e08Smrg	if (info->dri2.pKernelDRMVersion->version_minor < 4)
274418781e08Smrg		return;
274518781e08Smrg
274618781e08Smrg	info->drmmode_inited = TRUE;
274718781e08Smrg	if (pRADEONEnt->fd_wakeup_registered != serverGeneration) {
274818781e08Smrg#if HAVE_NOTIFY_FD
274939413783Smrg		SetNotifyFd(pRADEONEnt->fd, drm_notify_fd, X_NOTIFY_READ,
275039413783Smrg			    &info->drmmode);
275118781e08Smrg#else
27528bf5c682Smrg		AddGeneralSocket(pRADEONEnt->fd);
2753de2362d3Smrg		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
275439413783Smrg					       drm_wakeup_handler,
275539413783Smrg					       &info->drmmode);
275618781e08Smrg#endif
2757de2362d3Smrg		pRADEONEnt->fd_wakeup_registered = serverGeneration;
275818781e08Smrg		pRADEONEnt->fd_wakeup_ref = 1;
275918781e08Smrg	} else
276018781e08Smrg		pRADEONEnt->fd_wakeup_ref++;
276118781e08Smrg}
276218781e08Smrg
276318781e08Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
276418781e08Smrg{
276518781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
276618781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
276718781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
276818781e08Smrg	int c;
276918781e08Smrg
277018781e08Smrg	if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited)
277118781e08Smrg		return;
277218781e08Smrg
277318781e08Smrg	if (pRADEONEnt->fd_wakeup_registered == serverGeneration &&
277418781e08Smrg	    !--pRADEONEnt->fd_wakeup_ref) {
277518781e08Smrg#if HAVE_NOTIFY_FD
27768bf5c682Smrg		RemoveNotifyFd(pRADEONEnt->fd);
277718781e08Smrg#else
27788bf5c682Smrg		RemoveGeneralSocket(pRADEONEnt->fd);
277918781e08Smrg		RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
27808bf5c682Smrg				drm_wakeup_handler, pScrn);
278118781e08Smrg#endif
278218781e08Smrg	}
278318781e08Smrg
27843ed65abbSmrg	for (c = 0; c < config->num_crtc; c++)
27853ed65abbSmrg		drmmode_crtc_scanout_free(config->crtc[c]->driver_private);
2786de2362d3Smrg}
2787de2362d3Smrg
278818781e08Smrg
2789de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr)
2790de2362d3Smrg{
2791de2362d3Smrg	drmmode->bufmgr = bufmgr;
2792de2362d3Smrg	return TRUE;
2793de2362d3Smrg}
2794de2362d3Smrg
2795de2362d3Smrg
27968bf5c682Smrgstatic void drmmode_sprite_do_set_cursor(struct radeon_device_priv *device_priv,
27978bf5c682Smrg					 ScrnInfoPtr scrn, int x, int y)
27988bf5c682Smrg{
27998bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
28008bf5c682Smrg	CursorPtr cursor = device_priv->cursor;
28018bf5c682Smrg	Bool sprite_visible = device_priv->sprite_visible;
28028bf5c682Smrg
28038bf5c682Smrg	if (cursor) {
28048bf5c682Smrg		x -= cursor->bits->xhot;
28058bf5c682Smrg		y -= cursor->bits->yhot;
28068bf5c682Smrg
28078bf5c682Smrg		device_priv->sprite_visible =
28088bf5c682Smrg			x < scrn->virtualX && y < scrn->virtualY &&
28098bf5c682Smrg			(x + cursor->bits->width > 0) &&
28108bf5c682Smrg			(y + cursor->bits->height > 0);
28118bf5c682Smrg	} else {
28128bf5c682Smrg		device_priv->sprite_visible = FALSE;
28138bf5c682Smrg	}
28148bf5c682Smrg
28158bf5c682Smrg	info->sprites_visible += device_priv->sprite_visible - sprite_visible;
28168bf5c682Smrg}
28178bf5c682Smrg
281839413783Smrgstatic void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
281939413783Smrg				      CursorPtr pCursor, int x, int y)
28208bf5c682Smrg{
28218bf5c682Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
28228bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
28238bf5c682Smrg	struct radeon_device_priv *device_priv =
28248bf5c682Smrg		dixLookupScreenPrivate(&pDev->devPrivates,
28258bf5c682Smrg				       &radeon_device_private_key, pScreen);
28268bf5c682Smrg
28278bf5c682Smrg	device_priv->cursor = pCursor;
28288bf5c682Smrg	drmmode_sprite_do_set_cursor(device_priv, scrn, x, y);
28298bf5c682Smrg
283039413783Smrg	info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
28318bf5c682Smrg}
28328bf5c682Smrg
283339413783Smrgstatic void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
283439413783Smrg				       int x, int y)
28358bf5c682Smrg{
28368bf5c682Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
28378bf5c682Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
28388bf5c682Smrg	struct radeon_device_priv *device_priv =
28398bf5c682Smrg		dixLookupScreenPrivate(&pDev->devPrivates,
28408bf5c682Smrg				       &radeon_device_private_key, pScreen);
28418bf5c682Smrg
28428bf5c682Smrg	drmmode_sprite_do_set_cursor(device_priv, scrn, x, y);
28438bf5c682Smrg
284439413783Smrg	info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
284539413783Smrg}
284639413783Smrg
284739413783Smrgstatic Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
284839413783Smrg						  ScreenPtr pScreen,
284939413783Smrg						  CursorPtr pCursor)
285039413783Smrg{
285139413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
285239413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
285339413783Smrg
285439413783Smrg	return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
285539413783Smrg}
285639413783Smrg
285739413783Smrgstatic Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
285839413783Smrg						    ScreenPtr pScreen,
285939413783Smrg						    CursorPtr pCursor)
286039413783Smrg{
286139413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
286239413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
286339413783Smrg
286439413783Smrg	return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
286539413783Smrg}
286639413783Smrg
286739413783Smrgstatic Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
286839413783Smrg						    ScreenPtr pScreen)
286939413783Smrg{
287039413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
287139413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
287239413783Smrg
287339413783Smrg	return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
28748bf5c682Smrg}
2875de2362d3Smrg
287639413783Smrgstatic void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
287739413783Smrg						 ScreenPtr pScreen)
287839413783Smrg{
287939413783Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
288039413783Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
288139413783Smrg
288239413783Smrg	info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
288339413783Smrg}
288439413783Smrg
288539413783SmrgmiPointerSpriteFuncRec drmmode_sprite_funcs = {
288639413783Smrg	.RealizeCursor = drmmode_sprite_realize_realize_cursor,
288739413783Smrg	.UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
288839413783Smrg	.SetCursor = drmmode_sprite_set_cursor,
288939413783Smrg	.MoveCursor = drmmode_sprite_move_cursor,
289039413783Smrg	.DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
289139413783Smrg	.DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
289239413783Smrg};
289339413783Smrg
289439413783Smrg
2895de2362d3Smrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo)
2896de2362d3Smrg{
2897de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2898de2362d3Smrg	xf86CrtcPtr crtc = xf86_config->crtc[id];
2899de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2900de2362d3Smrg
2901de2362d3Smrg	drmmode_crtc->cursor_bo = bo;
2902de2362d3Smrg}
2903de2362d3Smrg
2904de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
2905de2362d3Smrg{
2906de2362d3Smrg	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
2907de2362d3Smrg	xf86OutputPtr  output = config->output[config->compat_output];
2908de2362d3Smrg	xf86CrtcPtr	crtc = output->crtc;
2909de2362d3Smrg
2910de2362d3Smrg	if (crtc && crtc->enabled) {
2911de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
2912de2362d3Smrg				       x, y);
2913de2362d3Smrg	}
2914de2362d3Smrg}
2915de2362d3Smrg
291618781e08SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
291718781e08Smrg			       Bool set_hw)
2918de2362d3Smrg{
2919de2362d3Smrg	xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
29208bf5c682Smrg	unsigned num_desired = 0, num_on = 0;
2921de2362d3Smrg	int c;
2922de2362d3Smrg
29238bf5c682Smrg	/* First, disable all unused CRTCs */
29248bf5c682Smrg	if (set_hw) {
29258bf5c682Smrg		for (c = 0; c < config->num_crtc; c++) {
29268bf5c682Smrg			xf86CrtcPtr crtc = config->crtc[c];
29278bf5c682Smrg
29288bf5c682Smrg			/* Skip disabled CRTCs */
29298bf5c682Smrg			if (crtc->enabled)
29308bf5c682Smrg				continue;
29318bf5c682Smrg
293239413783Smrg			drmmode_crtc_dpms(crtc, DPMSModeOff);
29338bf5c682Smrg		}
29348bf5c682Smrg	}
29358bf5c682Smrg
29368bf5c682Smrg	/* Then, try setting the chosen mode on each CRTC */
2937de2362d3Smrg	for (c = 0; c < config->num_crtc; c++) {
2938de2362d3Smrg		xf86CrtcPtr	crtc = config->crtc[c];
2939de2362d3Smrg		xf86OutputPtr	output = NULL;
2940de2362d3Smrg		int		o;
2941de2362d3Smrg
29428bf5c682Smrg		if (!crtc->enabled)
2943de2362d3Smrg			continue;
2944de2362d3Smrg
2945de2362d3Smrg		if (config->output[config->compat_output]->crtc == crtc)
2946de2362d3Smrg			output = config->output[config->compat_output];
2947de2362d3Smrg		else
2948de2362d3Smrg		{
2949de2362d3Smrg			for (o = 0; o < config->num_output; o++)
2950de2362d3Smrg				if (config->output[o]->crtc == crtc)
2951de2362d3Smrg				{
2952de2362d3Smrg					output = config->output[o];
2953de2362d3Smrg					break;
2954de2362d3Smrg				}
2955de2362d3Smrg		}
2956de2362d3Smrg		/* paranoia */
2957de2362d3Smrg		if (!output)
2958de2362d3Smrg			continue;
2959de2362d3Smrg
29608bf5c682Smrg		num_desired++;
29618bf5c682Smrg
2962de2362d3Smrg		/* Mark that we'll need to re-set the mode for sure */
2963de2362d3Smrg		memset(&crtc->mode, 0, sizeof(crtc->mode));
2964de2362d3Smrg		if (!crtc->desiredMode.CrtcHDisplay)
2965de2362d3Smrg		{
2966de2362d3Smrg			DisplayModePtr  mode = xf86OutputFindClosestMode (output, pScrn->currentMode);
2967de2362d3Smrg
29688bf5c682Smrg			if (!mode) {
29698bf5c682Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
29708bf5c682Smrg					   "Failed to find mode for CRTC %d\n", c);
29718bf5c682Smrg				continue;
29728bf5c682Smrg			}
2973de2362d3Smrg			crtc->desiredMode = *mode;
2974de2362d3Smrg			crtc->desiredRotation = RR_Rotate_0;
2975de2362d3Smrg			crtc->desiredX = 0;
2976de2362d3Smrg			crtc->desiredY = 0;
2977de2362d3Smrg		}
2978de2362d3Smrg
297918781e08Smrg		if (set_hw) {
29808bf5c682Smrg			if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode,
29818bf5c682Smrg							crtc->desiredRotation,
29828bf5c682Smrg							crtc->desiredX,
29838bf5c682Smrg							crtc->desiredY)) {
29848bf5c682Smrg				num_on++;
29858bf5c682Smrg			} else {
29868bf5c682Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
29878bf5c682Smrg					   "Failed to set mode on CRTC %d\n", c);
298839413783Smrg				RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y,
298939413783Smrg					  crtc->rotation, 0, NULL);
29908bf5c682Smrg			}
299118781e08Smrg		} else {
299218781e08Smrg			crtc->mode = crtc->desiredMode;
299318781e08Smrg			crtc->rotation = crtc->desiredRotation;
299418781e08Smrg			crtc->x = crtc->desiredX;
299518781e08Smrg			crtc->y = crtc->desiredY;
29968bf5c682Smrg			if (drmmode_handle_transform(crtc))
29978bf5c682Smrg				num_on++;
299818781e08Smrg		}
2999de2362d3Smrg	}
30008bf5c682Smrg
30018bf5c682Smrg	if (num_on == 0 && num_desired > 0) {
30028bf5c682Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n");
30038bf5c682Smrg		return FALSE;
30048bf5c682Smrg	}
30058bf5c682Smrg
300639413783Smrg	/* Validate leases on VT re-entry */
300739413783Smrg	drmmode_validate_leases(pScrn);
300839413783Smrg
3009de2362d3Smrg	return TRUE;
3010de2362d3Smrg}
3011de2362d3Smrg
301218781e08SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
3013de2362d3Smrg{
3014de2362d3Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
301539413783Smrg    int i;
3016de2362d3Smrg
301718781e08Smrg    if (xf86_config->num_crtc) {
301818781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
301918781e08Smrg		       "Initializing kms color map\n");
302018781e08Smrg	if (!miCreateDefColormap(pScreen))
302118781e08Smrg	    return FALSE;
30228bf5c682Smrg
30238bf5c682Smrg	/* All radeons support 10 bit CLUTs. They get bypassed at depth 30. */
302439413783Smrg	if (pScrn->depth != 30) {
302539413783Smrg	    if (!xf86HandleColormaps(pScreen, 256, 10, NULL, NULL,
302639413783Smrg				     CMAP_PALETTED_TRUECOLOR
302739413783Smrg				     | CMAP_RELOAD_ON_MODE_SWITCH))
302839413783Smrg		return FALSE;
302939413783Smrg
303039413783Smrg	    for (i = 0; i < xf86_config->num_crtc; i++) {
303139413783Smrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
303239413783Smrg
303339413783Smrg		drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red,
303439413783Smrg					  crtc->gamma_green,
303539413783Smrg					  crtc->gamma_blue,
303639413783Smrg					  crtc->gamma_size);
303739413783Smrg	    }
303839413783Smrg	}
303918781e08Smrg    }
304039413783Smrg
304118781e08Smrg    return TRUE;
304218781e08Smrg}
30437314432eSmrg
304418781e08Smrgstatic Bool
304518781e08Smrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi,
304618781e08Smrg		    int *num_hdmi)
304718781e08Smrg{
304818781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
304918781e08Smrg	int i;
30507314432eSmrg
305118781e08Smrg	for (i = 0; i < config->num_output; i++) {
305218781e08Smrg		xf86OutputPtr output = config->output[i];
305318781e08Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
305418781e08Smrg
305518781e08Smrg		if (drmmode_output->output_id == output_id) {
305618781e08Smrg			switch(drmmode_output->mode_output->connector_type) {
305718781e08Smrg			case DRM_MODE_CONNECTOR_DVII:
305818781e08Smrg			case DRM_MODE_CONNECTOR_DVID:
305918781e08Smrg			case DRM_MODE_CONNECTOR_DVIA:
306018781e08Smrg				(*num_dvi)++;
306118781e08Smrg				break;
306218781e08Smrg			case DRM_MODE_CONNECTOR_HDMIA:
306318781e08Smrg			case DRM_MODE_CONNECTOR_HDMIB:
306418781e08Smrg				(*num_hdmi)++;
306518781e08Smrg				break;
306618781e08Smrg			}
306718781e08Smrg
306818781e08Smrg			return TRUE;
306918781e08Smrg		}
307018781e08Smrg	}
307118781e08Smrg
307218781e08Smrg	return FALSE;
30737314432eSmrg}
30747314432eSmrg
307518781e08Smrgvoid
307618781e08Smrgradeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode)
30770d16fef4Smrg{
307818781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
307918781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
308018781e08Smrg	drmModeResPtr mode_res;
308118781e08Smrg	int i, j;
308218781e08Smrg	Bool found;
308318781e08Smrg	Bool changed = FALSE;
308418781e08Smrg	int num_dvi = 0, num_hdmi = 0;
308518781e08Smrg
30868bf5c682Smrg	/* Try to re-set the mode on all the connectors with a BAD link-state:
30878bf5c682Smrg	 * This may happen if a link degrades and a new modeset is necessary, using
30888bf5c682Smrg	 * different link-training parameters. If the kernel found that the current
30898bf5c682Smrg	 * mode is not achievable anymore, it should have pruned the mode before
30908bf5c682Smrg	 * sending the hotplug event. Try to re-set the currently-set mode to keep
30918bf5c682Smrg	 * the display alive, this will fail if the mode has been pruned.
30928bf5c682Smrg	 * In any case, we will send randr events for the Desktop Environment to
30938bf5c682Smrg	 * deal with it, if it wants to.
30948bf5c682Smrg	 */
30958bf5c682Smrg	for (i = 0; i < config->num_output; i++) {
30968bf5c682Smrg		xf86OutputPtr output = config->output[i];
30978bf5c682Smrg		xf86CrtcPtr crtc = output->crtc;
30988bf5c682Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
30998bf5c682Smrg
31008bf5c682Smrg		drmmode_output_detect(output);
31018bf5c682Smrg
31028bf5c682Smrg		if (!crtc || !drmmode_output->mode_output)
31038bf5c682Smrg			continue;
31048bf5c682Smrg
31058bf5c682Smrg		/* Get an updated view of the properties for the current connector and
31068bf5c682Smrg		 * look for the link-status property
31078bf5c682Smrg		 */
31088bf5c682Smrg		for (j = 0; j < drmmode_output->num_props; j++) {
31098bf5c682Smrg			drmmode_prop_ptr p = &drmmode_output->props[j];
31108bf5c682Smrg
31118bf5c682Smrg			if (!strcmp(p->mode_prop->name, "link-status")) {
31128bf5c682Smrg				if (p->value != DRM_MODE_LINK_STATUS_BAD)
31138bf5c682Smrg					break;
31148bf5c682Smrg
31158bf5c682Smrg				/* the connector got a link failure, re-set the current mode */
31168bf5c682Smrg				drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
31178bf5c682Smrg						       crtc->x, crtc->y);
31188bf5c682Smrg
31198bf5c682Smrg				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
31208bf5c682Smrg					   "hotplug event: connector %u's link-state is BAD, "
31218bf5c682Smrg					   "tried resetting the current mode. You may be left"
31228bf5c682Smrg					   "with a black screen if this fails...\n",
31238bf5c682Smrg					   drmmode_output->mode_output->connector_id);
31248bf5c682Smrg
31258bf5c682Smrg				break;
31268bf5c682Smrg			}
31278bf5c682Smrg		}
31288bf5c682Smrg	}
31298bf5c682Smrg
31308bf5c682Smrg	mode_res = drmModeGetResources(pRADEONEnt->fd);
313118781e08Smrg	if (!mode_res)
313218781e08Smrg		goto out;
313318781e08Smrg
313418781e08Smrgrestart_destroy:
313518781e08Smrg	for (i = 0; i < config->num_output; i++) {
313618781e08Smrg		xf86OutputPtr output = config->output[i];
313718781e08Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
313818781e08Smrg		found = FALSE;
313918781e08Smrg		for (j = 0; j < mode_res->count_connectors; j++) {
314018781e08Smrg			if (mode_res->connectors[j] == drmmode_output->output_id) {
314118781e08Smrg				found = TRUE;
314218781e08Smrg				break;
314318781e08Smrg			}
314418781e08Smrg		}
314518781e08Smrg		if (found)
314618781e08Smrg			continue;
314718781e08Smrg
314818781e08Smrg		drmModeFreeConnector(drmmode_output->mode_output);
314918781e08Smrg		drmmode_output->mode_output = NULL;
315018781e08Smrg		drmmode_output->output_id = -1;
315118781e08Smrg
315218781e08Smrg		changed = TRUE;
315318781e08Smrg		if (drmmode->delete_dp_12_displays) {
315418781e08Smrg			RROutputDestroy(output->randr_output);
315518781e08Smrg			xf86OutputDestroy(output);
315618781e08Smrg			goto restart_destroy;
315718781e08Smrg		}
315818781e08Smrg	}
315918781e08Smrg
316018781e08Smrg	/* find new output ids we don't have outputs for */
316118781e08Smrg	for (i = 0; i < mode_res->count_connectors; i++) {
316218781e08Smrg		if (drmmode_find_output(pRADEONEnt->primary_scrn,
316318781e08Smrg					mode_res->connectors[i],
316418781e08Smrg					&num_dvi, &num_hdmi) ||
316518781e08Smrg		    (pRADEONEnt->secondary_scrn &&
316618781e08Smrg		     drmmode_find_output(pRADEONEnt->secondary_scrn,
316718781e08Smrg					 mode_res->connectors[i],
316818781e08Smrg					 &num_dvi, &num_hdmi)))
316918781e08Smrg			continue;
317018781e08Smrg
317118781e08Smrg		if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi,
317218781e08Smrg					&num_hdmi, 1) != 0)
317318781e08Smrg			changed = TRUE;
317418781e08Smrg	}
317518781e08Smrg
317639413783Smrg	/* Check to see if a lessee has disappeared */
317739413783Smrg	drmmode_validate_leases(scrn);
317839413783Smrg
317918781e08Smrg	if (changed && dixPrivateKeyRegistered(rrPrivKey)) {
318018781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0)
318118781e08Smrg		RRSetChanged(xf86ScrnToScreen(scrn));
318218781e08Smrg#else
318318781e08Smrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen);
318418781e08Smrg		rrScrPriv->changed = TRUE;
31850d16fef4Smrg#endif
318618781e08Smrg		RRTellChanged(xf86ScrnToScreen(scrn));
318718781e08Smrg	}
31887821949aSmrg
318918781e08Smrg	drmModeFreeResources(mode_res);
319018781e08Smrgout:
319118781e08Smrg	RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
319218781e08Smrg}
3193de2362d3Smrg#ifdef HAVE_LIBUDEV
3194de2362d3Smrgstatic void
3195de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure)
3196de2362d3Smrg{
3197de2362d3Smrg	drmmode_ptr drmmode = closure;
3198de2362d3Smrg	ScrnInfoPtr scrn = drmmode->scrn;
3199de2362d3Smrg	struct udev_device *dev;
320018781e08Smrg	Bool received = FALSE;
32013ed65abbSmrg	struct timeval tv = { 0, 0 };
32023ed65abbSmrg	fd_set readfd;
32033ed65abbSmrg
32043ed65abbSmrg	FD_ZERO(&readfd);
32053ed65abbSmrg	FD_SET(fd, &readfd);
32063ed65abbSmrg
32073ed65abbSmrg	while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 &&
32083ed65abbSmrg	       FD_ISSET(fd, &readfd)) {
32093ed65abbSmrg		/* select() ensured that this will not block */
32103ed65abbSmrg		dev = udev_monitor_receive_device(drmmode->uevent_monitor);
32113ed65abbSmrg		if (dev) {
32123ed65abbSmrg			udev_device_unref(dev);
32133ed65abbSmrg			received = TRUE;
32143ed65abbSmrg		}
321518781e08Smrg	}
321618781e08Smrg
321718781e08Smrg	if (received)
321818781e08Smrg		radeon_mode_hotplug(scrn, drmmode);
3219de2362d3Smrg}
3220de2362d3Smrg#endif
3221de2362d3Smrg
3222de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3223de2362d3Smrg{
3224de2362d3Smrg#ifdef HAVE_LIBUDEV
3225de2362d3Smrg	struct udev *u;
3226de2362d3Smrg	struct udev_monitor *mon;
3227de2362d3Smrg
3228de2362d3Smrg	u = udev_new();
3229de2362d3Smrg	if (!u)
3230de2362d3Smrg		return;
3231de2362d3Smrg	mon = udev_monitor_new_from_netlink(u, "udev");
3232de2362d3Smrg	if (!mon) {
3233de2362d3Smrg		udev_unref(u);
3234de2362d3Smrg		return;
3235de2362d3Smrg	}
3236de2362d3Smrg
3237de2362d3Smrg	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
3238de2362d3Smrg							    "drm",
3239de2362d3Smrg							    "drm_minor") < 0 ||
3240de2362d3Smrg	    udev_monitor_enable_receiving(mon) < 0) {
3241de2362d3Smrg		udev_monitor_unref(mon);
3242de2362d3Smrg		udev_unref(u);
3243de2362d3Smrg		return;
3244de2362d3Smrg	}
3245de2362d3Smrg
3246de2362d3Smrg	drmmode->uevent_handler =
3247de2362d3Smrg		xf86AddGeneralHandler(udev_monitor_get_fd(mon),
3248de2362d3Smrg				      drmmode_handle_uevents,
3249de2362d3Smrg				      drmmode);
3250de2362d3Smrg
3251de2362d3Smrg	drmmode->uevent_monitor = mon;
3252de2362d3Smrg#endif
3253de2362d3Smrg}
3254de2362d3Smrg
3255de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3256de2362d3Smrg{
3257de2362d3Smrg#ifdef HAVE_LIBUDEV
3258de2362d3Smrg	if (drmmode->uevent_handler) {
3259de2362d3Smrg		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
3260de2362d3Smrg		xf86RemoveGeneralHandler(drmmode->uevent_handler);
3261de2362d3Smrg
3262de2362d3Smrg		udev_monitor_unref(drmmode->uevent_monitor);
3263de2362d3Smrg		udev_unref(u);
3264de2362d3Smrg	}
3265de2362d3Smrg#endif
3266de2362d3Smrg}
3267de2362d3Smrg
326818781e08SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
32698bf5c682Smrg			PixmapPtr new_front, uint64_t id, void *data,
32708bf5c682Smrg			xf86CrtcPtr ref_crtc, radeon_drm_handler_proc handler,
327118781e08Smrg			radeon_drm_abort_proc abort,
32723ed65abbSmrg			enum drmmode_flip_sync flip_sync,
32733ed65abbSmrg			uint32_t target_msc)
3274de2362d3Smrg{
32753ed65abbSmrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
3276de2362d3Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
327718781e08Smrg	xf86CrtcPtr crtc = NULL;
3278de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
32793ed65abbSmrg	uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0;
3280de2362d3Smrg	drmmode_flipdata_ptr flipdata;
328139413783Smrg	Bool handle_deferred = FALSE;
328218781e08Smrg	uintptr_t drm_queue_seq = 0;
328339413783Smrg	struct drmmode_fb *fb;
328439413783Smrg	int i = 0;
3285de2362d3Smrg
328639413783Smrg	flipdata = calloc(1, sizeof(*flipdata) + config->num_crtc *
328739413783Smrg			  sizeof(flipdata->fb[0]));
32887821949aSmrg        if (!flipdata) {
32897821949aSmrg             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
32907821949aSmrg                        "flip queue: data alloc failed.\n");
329118781e08Smrg             goto error;
32927821949aSmrg        }
329318781e08Smrg
329439413783Smrg	fb = radeon_pixmap_get_fb(new_front);
329539413783Smrg	if (!fb) {
32968bf5c682Smrg		ErrorF("Failed to get FB for flip\n");
329718781e08Smrg		goto error;
32988bf5c682Smrg	}
329918781e08Smrg
3300de2362d3Smrg	/*
3301de2362d3Smrg	 * Queue flips on all enabled CRTCs
3302de2362d3Smrg	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
3303de2362d3Smrg	 * Right now it assumes a single shared fb across all CRTCs, with the
3304de2362d3Smrg	 * kernel fixing up the offset of each CRTC as necessary.
3305de2362d3Smrg	 *
3306de2362d3Smrg	 * Also, flips queued on disabled or incorrectly configured displays
3307de2362d3Smrg	 * may never complete; this is a configuration error.
3308de2362d3Smrg	 */
3309de2362d3Smrg
3310de2362d3Smrg        flipdata->event_data = data;
331118781e08Smrg        flipdata->handler = handler;
331218781e08Smrg        flipdata->abort = abort;
33138bf5c682Smrg        flipdata->fe_crtc = ref_crtc;
331418781e08Smrg
3315de2362d3Smrg	for (i = 0; i < config->num_crtc; i++) {
331618781e08Smrg		crtc = config->crtc[i];
33178bf5c682Smrg		drmmode_crtc = crtc->driver_private;
331818781e08Smrg
33198bf5c682Smrg		if (!drmmode_crtc_can_flip(crtc) ||
33208bf5c682Smrg		    (drmmode_crtc->tear_free && crtc != ref_crtc))
3321de2362d3Smrg			continue;
3322de2362d3Smrg
3323de2362d3Smrg		flipdata->flip_count++;
332418781e08Smrg
332518781e08Smrg		drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id,
332618781e08Smrg						       flipdata,
332718781e08Smrg						       drmmode_flip_handler,
332818781e08Smrg						       drmmode_flip_abort);
332918781e08Smrg		if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
333018781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
333118781e08Smrg				   "Allocating DRM queue event entry failed.\n");
333218781e08Smrg			goto error;
333318781e08Smrg		}
3334de2362d3Smrg
33358bf5c682Smrg		if (drmmode_crtc->tear_free) {
33368bf5c682Smrg			BoxRec extents = { .x1 = 0, .y1 = 0,
33378bf5c682Smrg					   .x2 = new_front->drawable.width,
33388bf5c682Smrg					   .y2 = new_front->drawable.height };
33398bf5c682Smrg			int scanout_id = drmmode_crtc->scanout_id ^ 1;
33408bf5c682Smrg
33418bf5c682Smrg			if (flip_sync == FLIP_ASYNC) {
33428bf5c682Smrg				if (!drmmode_wait_vblank(crtc,
33438bf5c682Smrg							 DRM_VBLANK_RELATIVE |
33448bf5c682Smrg							 DRM_VBLANK_EVENT,
33458bf5c682Smrg							 0, drm_queue_seq,
33468bf5c682Smrg							 NULL, NULL))
33478bf5c682Smrg					goto flip_error;
33488bf5c682Smrg				goto next;
33498bf5c682Smrg			}
33508bf5c682Smrg
335139413783Smrg			drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[i],
335239413783Smrg					     radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap));
335339413783Smrg			if (!flipdata->fb[i]) {
33548bf5c682Smrg				ErrorF("Failed to get FB for TearFree flip\n");
33558bf5c682Smrg				goto error;
33568bf5c682Smrg			}
33578bf5c682Smrg
33588bf5c682Smrg			radeon_scanout_do_update(crtc, scanout_id, new_front,
335939413783Smrg						 extents);
336039413783Smrg			radeon_cs_flush_indirect(crtc->scrn);
336139413783Smrg
336239413783Smrg			if (drmmode_crtc->scanout_update_pending) {
336339413783Smrg				radeon_drm_wait_pending_flip(crtc);
336439413783Smrg				handle_deferred = TRUE;
336539413783Smrg				radeon_drm_abort_entry(drmmode_crtc->scanout_update_pending);
336639413783Smrg				drmmode_crtc->scanout_update_pending = 0;
336739413783Smrg			}
336839413783Smrg		} else {
336939413783Smrg			drmmode_fb_reference(pRADEONEnt->fd, &flipdata->fb[i], fb);
33708bf5c682Smrg		}
33718bf5c682Smrg
33728bf5c682Smrg		if (crtc == ref_crtc) {
33733ed65abbSmrg			if (drmmode_page_flip_target_absolute(pRADEONEnt,
33743ed65abbSmrg							      drmmode_crtc,
337539413783Smrg							      flipdata->fb[i]->handle,
33763ed65abbSmrg							      flip_flags,
33773ed65abbSmrg							      drm_queue_seq,
33783ed65abbSmrg							      target_msc) != 0)
33793ed65abbSmrg				goto flip_error;
33803ed65abbSmrg		} else {
33813ed65abbSmrg			if (drmmode_page_flip_target_relative(pRADEONEnt,
33823ed65abbSmrg							      drmmode_crtc,
338339413783Smrg							      flipdata->fb[i]->handle,
33843ed65abbSmrg							      flip_flags,
33853ed65abbSmrg							      drm_queue_seq, 0) != 0)
33863ed65abbSmrg				goto flip_error;
3387de2362d3Smrg		}
33883ed65abbSmrg
33898bf5c682Smrg		if (drmmode_crtc->tear_free) {
33908bf5c682Smrg			drmmode_crtc->scanout_id ^= 1;
33918bf5c682Smrg			drmmode_crtc->ignore_damage = TRUE;
33928bf5c682Smrg		}
33938bf5c682Smrg
33948bf5c682Smrg	next:
339539413783Smrg		drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->flip_pending,
339639413783Smrg				     flipdata->fb[i]);
339718781e08Smrg		drm_queue_seq = 0;
3398de2362d3Smrg	}
3399de2362d3Smrg
340039413783Smrg	if (handle_deferred)
340139413783Smrg		radeon_drm_queue_handle_deferred(ref_crtc);
340218781e08Smrg	if (flipdata->flip_count > 0)
340318781e08Smrg		return TRUE;
34040d16fef4Smrg
34053ed65abbSmrgflip_error:
34063ed65abbSmrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n",
34073ed65abbSmrg		   strerror(errno));
34083ed65abbSmrg
340918781e08Smrgerror:
341018781e08Smrg	if (drm_queue_seq)
341118781e08Smrg		radeon_drm_abort_entry(drm_queue_seq);
341218781e08Smrg	else if (crtc)
341318781e08Smrg		drmmode_flip_abort(crtc, flipdata);
34143ed65abbSmrg	else {
34153ed65abbSmrg		abort(NULL, data);
341618781e08Smrg		free(flipdata);
34173ed65abbSmrg	}
3418de2362d3Smrg
3419de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
3420de2362d3Smrg		   strerror(errno));
342139413783Smrg	if (handle_deferred)
342239413783Smrg		radeon_drm_queue_handle_deferred(ref_crtc);
3423de2362d3Smrg	return FALSE;
3424de2362d3Smrg}
3425