drmmode_display.c revision 3ed65abb
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"
37de2362d3Smrg#include "micmap.h"
38de2362d3Smrg#include "xf86cmap.h"
3918781e08Smrg#include "xf86Priv.h"
40de2362d3Smrg#include "radeon.h"
4118781e08Smrg#include "radeon_bo_helper.h"
4218781e08Smrg#include "radeon_glamor.h"
4318781e08Smrg#include "radeon_list.h"
44de2362d3Smrg#include "radeon_reg.h"
4518781e08Smrg
4618781e08Smrg#ifdef RADEON_PIXMAP_SHARING
4718781e08Smrg#include <dri.h>
4818781e08Smrg#endif
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
102de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
103de2362d3Smrg					  int width, int height,
104de2362d3Smrg					  int depth, int bpp,
10518781e08Smrg					  int pitch,
106de2362d3Smrg					  struct radeon_bo *bo, struct radeon_surface *psurf)
107de2362d3Smrg{
108de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
109de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
110de2362d3Smrg	PixmapPtr pixmap;
111de2362d3Smrg	struct radeon_surface *surface;
11218781e08Smrg	uint32_t tiling;
113de2362d3Smrg
11418781e08Smrg	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth,
11518781e08Smrg					  RADEON_CREATE_PIXMAP_SCANOUT);
116de2362d3Smrg	if (!pixmap)
117de2362d3Smrg		return NULL;
118de2362d3Smrg
1197314432eSmrg	if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height,
1207314432eSmrg					    depth, bpp, pitch, NULL)) {
12118781e08Smrg		goto fail;
1227314432eSmrg	}
1237314432eSmrg
12418781e08Smrg	if (!info->use_glamor)
12518781e08Smrg		exaMoveInPixmap(pixmap);
12618781e08Smrg
12718781e08Smrg	if (!radeon_set_pixmap_bo(pixmap, bo))
12818781e08Smrg		goto fail;
12918781e08Smrg
130de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
131de2362d3Smrg		surface = radeon_get_pixmap_surface(pixmap);
132de2362d3Smrg		if (surface && psurf)
133de2362d3Smrg			*surface = *psurf;
134de2362d3Smrg		else if (surface) {
135de2362d3Smrg			memset(surface, 0, sizeof(struct radeon_surface));
136de2362d3Smrg			surface->npix_x = width;
137de2362d3Smrg			surface->npix_y = height;
138de2362d3Smrg			surface->npix_z = 1;
139de2362d3Smrg			surface->blk_w = 1;
140de2362d3Smrg			surface->blk_h = 1;
141de2362d3Smrg			surface->blk_d = 1;
142de2362d3Smrg			surface->array_size = 1;
143de2362d3Smrg			surface->last_level = 0;
144de2362d3Smrg			surface->bpe = bpp / 8;
145de2362d3Smrg			surface->nsamples = 1;
146de2362d3Smrg			surface->flags = RADEON_SURF_SCANOUT;
14718781e08Smrg			/* we are requiring a recent enough libdrm version */
14818781e08Smrg			surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX;
149de2362d3Smrg			surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
150de2362d3Smrg			surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE);
15118781e08Smrg			tiling = radeon_get_pixmap_tiling_flags(pixmap);
152de2362d3Smrg			if (tiling & RADEON_TILING_MICRO) {
153de2362d3Smrg				surface->flags = RADEON_SURF_CLR(surface->flags, MODE);
154de2362d3Smrg				surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
155de2362d3Smrg			}
156de2362d3Smrg			if (tiling & RADEON_TILING_MACRO) {
157de2362d3Smrg				surface->flags = RADEON_SURF_CLR(surface->flags, MODE);
158de2362d3Smrg				surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
159de2362d3Smrg			}
160de2362d3Smrg			if (radeon_surface_best(info->surf_man, surface)) {
16118781e08Smrg				goto fail;
162de2362d3Smrg			}
163de2362d3Smrg			if (radeon_surface_init(info->surf_man, surface)) {
16418781e08Smrg				goto fail;
165de2362d3Smrg			}
166de2362d3Smrg		}
167de2362d3Smrg	}
168de2362d3Smrg
16918781e08Smrg	if (!info->use_glamor ||
17018781e08Smrg	    radeon_glamor_create_textured_pixmap(pixmap,
17118781e08Smrg						 radeon_get_pixmap_private(pixmap)))
17218781e08Smrg		return pixmap;
17318781e08Smrg
17418781e08Smrgfail:
17518781e08Smrg	pScreen->DestroyPixmap(pixmap);
17618781e08Smrg	return NULL;
177de2362d3Smrg}
178de2362d3Smrg
179de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
180de2362d3Smrg{
181de2362d3Smrg	ScreenPtr pScreen = pixmap->drawable.pScreen;
182de2362d3Smrg
183de2362d3Smrg	(*pScreen->DestroyPixmap)(pixmap);
184de2362d3Smrg}
185de2362d3Smrg
186de2362d3Smrgstatic void
187de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr	scrn,
188de2362d3Smrg		     drmModeModeInfo *kmode,
189de2362d3Smrg		     DisplayModePtr	mode)
190de2362d3Smrg{
191de2362d3Smrg	memset(mode, 0, sizeof(DisplayModeRec));
192de2362d3Smrg	mode->status = MODE_OK;
193de2362d3Smrg
194de2362d3Smrg	mode->Clock = kmode->clock;
195de2362d3Smrg
196de2362d3Smrg	mode->HDisplay = kmode->hdisplay;
197de2362d3Smrg	mode->HSyncStart = kmode->hsync_start;
198de2362d3Smrg	mode->HSyncEnd = kmode->hsync_end;
199de2362d3Smrg	mode->HTotal = kmode->htotal;
200de2362d3Smrg	mode->HSkew = kmode->hskew;
201de2362d3Smrg
202de2362d3Smrg	mode->VDisplay = kmode->vdisplay;
203de2362d3Smrg	mode->VSyncStart = kmode->vsync_start;
204de2362d3Smrg	mode->VSyncEnd = kmode->vsync_end;
205de2362d3Smrg	mode->VTotal = kmode->vtotal;
206de2362d3Smrg	mode->VScan = kmode->vscan;
207de2362d3Smrg
208de2362d3Smrg	mode->Flags = kmode->flags; //& FLAG_BITS;
209de2362d3Smrg	mode->name = strdup(kmode->name);
210de2362d3Smrg
211de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_DRIVER)
212de2362d3Smrg		mode->type = M_T_DRIVER;
213de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
214de2362d3Smrg		mode->type |= M_T_PREFERRED;
215de2362d3Smrg	xf86SetModeCrtc (mode, scrn->adjustFlags);
216de2362d3Smrg}
217de2362d3Smrg
218de2362d3Smrgstatic void
219de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr	scrn,
220de2362d3Smrg		     drmModeModeInfo *kmode,
221de2362d3Smrg		     DisplayModePtr	mode)
222de2362d3Smrg{
223de2362d3Smrg	memset(kmode, 0, sizeof(*kmode));
224de2362d3Smrg
225de2362d3Smrg	kmode->clock = mode->Clock;
226de2362d3Smrg	kmode->hdisplay = mode->HDisplay;
227de2362d3Smrg	kmode->hsync_start = mode->HSyncStart;
228de2362d3Smrg	kmode->hsync_end = mode->HSyncEnd;
229de2362d3Smrg	kmode->htotal = mode->HTotal;
230de2362d3Smrg	kmode->hskew = mode->HSkew;
231de2362d3Smrg
232de2362d3Smrg	kmode->vdisplay = mode->VDisplay;
233de2362d3Smrg	kmode->vsync_start = mode->VSyncStart;
234de2362d3Smrg	kmode->vsync_end = mode->VSyncEnd;
235de2362d3Smrg	kmode->vtotal = mode->VTotal;
236de2362d3Smrg	kmode->vscan = mode->VScan;
237de2362d3Smrg
238de2362d3Smrg	kmode->flags = mode->Flags; //& FLAG_BITS;
239de2362d3Smrg	if (mode->name)
240de2362d3Smrg		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
241de2362d3Smrg	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
242de2362d3Smrg
243de2362d3Smrg}
244de2362d3Smrg
24518781e08Smrg/*
24618781e08Smrg * Retrieves present time in microseconds that is compatible
24718781e08Smrg * with units used by vblank timestamps. Depending on the kernel
24818781e08Smrg * version and DRM kernel module configuration, the vblank
24918781e08Smrg * timestamp can either be in real time or monotonic time
25018781e08Smrg */
25118781e08Smrgint drmmode_get_current_ust(int drm_fd, CARD64 *ust)
25218781e08Smrg{
25318781e08Smrg	uint64_t cap_value;
25418781e08Smrg	int ret;
25518781e08Smrg	struct timespec now;
25618781e08Smrg
25718781e08Smrg	ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value);
25818781e08Smrg	if (ret || !cap_value)
25918781e08Smrg		/* old kernel or drm_timestamp_monotonic turned off */
26018781e08Smrg		ret = clock_gettime(CLOCK_REALTIME, &now);
26118781e08Smrg	else
26218781e08Smrg		ret = clock_gettime(CLOCK_MONOTONIC, &now);
26318781e08Smrg	if (ret)
26418781e08Smrg		return ret;
26518781e08Smrg	*ust = ((CARD64)now.tv_sec * 1000000) + ((CARD64)now.tv_nsec / 1000);
26618781e08Smrg	return 0;
26718781e08Smrg}
26818781e08Smrg
26918781e08Smrg/*
27018781e08Smrg * Get current frame count and frame count timestamp of the crtc.
27118781e08Smrg */
27218781e08Smrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)
27318781e08Smrg{
27418781e08Smrg    ScrnInfoPtr scrn = crtc->scrn;
27518781e08Smrg    RADEONInfoPtr info = RADEONPTR(scrn);
27618781e08Smrg    drmVBlank vbl;
27718781e08Smrg    int ret;
27818781e08Smrg
27918781e08Smrg    vbl.request.type = DRM_VBLANK_RELATIVE;
28018781e08Smrg    vbl.request.type |= radeon_populate_vbl_request_type(crtc);
28118781e08Smrg    vbl.request.sequence = 0;
28218781e08Smrg
28318781e08Smrg    ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
28418781e08Smrg    if (ret) {
28518781e08Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING,
28618781e08Smrg		   "get vblank counter failed: %s\n", strerror(errno));
28718781e08Smrg	return ret;
28818781e08Smrg    }
28918781e08Smrg
29018781e08Smrg    *ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec;
29118781e08Smrg    *msc = vbl.reply.sequence;
29218781e08Smrg
29318781e08Smrg    return Success;
29418781e08Smrg}
29518781e08Smrg
296de2362d3Smrgstatic void
29718781e08Smrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
298de2362d3Smrg{
299de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
30018781e08Smrg	ScrnInfoPtr scrn = crtc->scrn;
30118781e08Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
30218781e08Smrg	CARD64 ust;
30318781e08Smrg	int ret;
3047314432eSmrg
30518781e08Smrg	drmmode_crtc->pending_dpms_mode = mode;
3060d16fef4Smrg
30718781e08Smrg	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
30818781e08Smrg		drmVBlank vbl;
30918781e08Smrg
31018781e08Smrg		/* Wait for any pending flip to finish */
31118781e08Smrg		if (drmmode_crtc->flip_pending)
31218781e08Smrg			return;
31318781e08Smrg
31418781e08Smrg		/*
31518781e08Smrg		 * On->Off transition: record the last vblank time,
31618781e08Smrg		 * sequence number and frame period.
31718781e08Smrg		 */
31818781e08Smrg		vbl.request.type = DRM_VBLANK_RELATIVE;
31918781e08Smrg		vbl.request.type |= radeon_populate_vbl_request_type(crtc);
32018781e08Smrg		vbl.request.sequence = 0;
32118781e08Smrg		ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
32218781e08Smrg		if (ret)
32318781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
32418781e08Smrg				   "%s cannot get last vblank counter\n",
32518781e08Smrg				   __func__);
32618781e08Smrg		else {
32718781e08Smrg			CARD64 seq = (CARD64)vbl.reply.sequence;
32818781e08Smrg			CARD64 nominal_frame_rate, pix_in_frame;
32918781e08Smrg
33018781e08Smrg			ust = ((CARD64)vbl.reply.tval_sec * 1000000) +
33118781e08Smrg				vbl.reply.tval_usec;
33218781e08Smrg			drmmode_crtc->dpms_last_ust = ust;
33318781e08Smrg			drmmode_crtc->dpms_last_seq = seq;
33418781e08Smrg			nominal_frame_rate = crtc->mode.Clock;
33518781e08Smrg			nominal_frame_rate *= 1000;
33618781e08Smrg			pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal;
33718781e08Smrg			if (nominal_frame_rate == 0 || pix_in_frame == 0)
33818781e08Smrg				nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE;
33918781e08Smrg			else
34018781e08Smrg				nominal_frame_rate /= pix_in_frame;
34118781e08Smrg			drmmode_crtc->dpms_last_fps = nominal_frame_rate;
34218781e08Smrg		}
34318781e08Smrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) {
34418781e08Smrg		/*
34518781e08Smrg		 * Off->On transition: calculate and accumulate the
34618781e08Smrg		 * number of interpolated vblanks while we were in Off state
34718781e08Smrg		 */
34818781e08Smrg		ret = drmmode_get_current_ust(info->dri2.drm_fd, &ust);
34918781e08Smrg		if (ret)
35018781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
35118781e08Smrg				   "%s cannot get current time\n", __func__);
35218781e08Smrg		else if (drmmode_crtc->dpms_last_ust) {
35318781e08Smrg			CARD64 time_elapsed, delta_seq;
35418781e08Smrg			time_elapsed = ust - drmmode_crtc->dpms_last_ust;
35518781e08Smrg			delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps;
35618781e08Smrg			delta_seq /= 1000000;
35718781e08Smrg			drmmode_crtc->interpolated_vblanks += delta_seq;
35818781e08Smrg
35918781e08Smrg		}
3607821949aSmrg	}
36118781e08Smrg	drmmode_crtc->dpms_mode = mode;
36218781e08Smrg}
36318781e08Smrg
36418781e08Smrgstatic void
36518781e08Smrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
36618781e08Smrg{
36718781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
36818781e08Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
36918781e08Smrg
37018781e08Smrg	/* Disable unused CRTCs */
37118781e08Smrg	if (!crtc->enabled || mode != DPMSModeOn) {
37218781e08Smrg		/* Wait for any pending flip to finish */
37318781e08Smrg		if (drmmode_crtc->flip_pending)
37418781e08Smrg			return;
37518781e08Smrg
37618781e08Smrg		drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
37718781e08Smrg			       0, 0, 0, NULL, 0, NULL);
37818781e08Smrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn)
37918781e08Smrg		crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
38018781e08Smrg					    crtc->x, crtc->y);
381de2362d3Smrg}
382de2362d3Smrg
383de2362d3Smrgstatic PixmapPtr
384de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode,
385de2362d3Smrg			ScrnInfoPtr pScrn, int fbcon_id)
386de2362d3Smrg{
38718781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
38818781e08Smrg	PixmapPtr pixmap = info->fbcon_pixmap;
389de2362d3Smrg	struct radeon_bo *bo;
390de2362d3Smrg	drmModeFBPtr fbcon;
391de2362d3Smrg	struct drm_gem_flink flink;
392de2362d3Smrg
39318781e08Smrg	if (pixmap)
39418781e08Smrg	    return pixmap;
39518781e08Smrg
396de2362d3Smrg	fbcon = drmModeGetFB(drmmode->fd, fbcon_id);
397de2362d3Smrg	if (fbcon == NULL)
398de2362d3Smrg		return NULL;
399de2362d3Smrg
400de2362d3Smrg	if (fbcon->depth != pScrn->depth ||
401de2362d3Smrg	    fbcon->width != pScrn->virtualX ||
402de2362d3Smrg	    fbcon->height != pScrn->virtualY)
403de2362d3Smrg		goto out_free_fb;
404de2362d3Smrg
405de2362d3Smrg	flink.handle = fbcon->handle;
406de2362d3Smrg	if (ioctl(drmmode->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
407de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
408de2362d3Smrg			   "Couldn't flink fbcon handle\n");
409de2362d3Smrg		goto out_free_fb;
410de2362d3Smrg	}
411de2362d3Smrg
412de2362d3Smrg	bo = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0);
413de2362d3Smrg	if (bo == NULL) {
414de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
415de2362d3Smrg			   "Couldn't allocate bo for fbcon handle\n");
416de2362d3Smrg		goto out_free_fb;
417de2362d3Smrg	}
418de2362d3Smrg
419de2362d3Smrg	pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height,
42018781e08Smrg					  fbcon->depth, fbcon->bpp, fbcon->pitch,
42118781e08Smrg					  bo, NULL);
42218781e08Smrg	info->fbcon_pixmap = pixmap;
423de2362d3Smrg	radeon_bo_unref(bo);
424de2362d3Smrgout_free_fb:
425de2362d3Smrg	drmModeFreeFB(fbcon);
426de2362d3Smrg	return pixmap;
427de2362d3Smrg}
428de2362d3Smrg
42918781e08Smrgstatic void
43018781e08Smrgdestroy_pixmap_for_fbcon(ScrnInfoPtr pScrn)
43118781e08Smrg{
43218781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
43318781e08Smrg
43418781e08Smrg	/* XXX: The current GPUVM support in the kernel doesn't allow removing
43518781e08Smrg	 * the virtual address range for this BO, so we need to keep around
43618781e08Smrg	 * the pixmap to avoid breaking glamor with GPUVM
43718781e08Smrg	 */
43818781e08Smrg	if (info->use_glamor && info->ChipFamily >= CHIP_FAMILY_CAYMAN)
43918781e08Smrg		return;
44018781e08Smrg
44118781e08Smrg	if (info->fbcon_pixmap)
44218781e08Smrg		pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap);
44318781e08Smrg	info->fbcon_pixmap = NULL;
44418781e08Smrg}
44518781e08Smrg
446de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
447de2362d3Smrg{
448de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
449de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
450de2362d3Smrg	PixmapPtr src, dst;
451de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
452de2362d3Smrg	int fbcon_id = 0;
45318781e08Smrg	Bool force;
45418781e08Smrg	GCPtr gc;
455de2362d3Smrg	int i;
456de2362d3Smrg
457de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
458de2362d3Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
459de2362d3Smrg
460de2362d3Smrg		if (drmmode_crtc->mode_crtc->buffer_id)
461de2362d3Smrg			fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
462de2362d3Smrg	}
463de2362d3Smrg
464de2362d3Smrg	if (!fbcon_id)
46518781e08Smrg		return;
46618781e08Smrg
46718781e08Smrg	if (fbcon_id == drmmode->fb_id) {
46818781e08Smrg		/* in some rare case there might be no fbcon and we might already
46918781e08Smrg		 * be the one with the current fb to avoid a false deadlck in
47018781e08Smrg		 * kernel ttm code just do nothing as anyway there is nothing
47118781e08Smrg		 * to do
47218781e08Smrg		 */
47318781e08Smrg		return;
47418781e08Smrg	}
475de2362d3Smrg
476de2362d3Smrg	src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
477de2362d3Smrg	if (!src)
47818781e08Smrg		return;
4790d16fef4Smrg
48018781e08Smrg	dst = pScreen->GetScreenPixmap(pScreen);
48118781e08Smrg
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
49818781e08Smrgstatic void
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
50718781e08Smrg	if (scanout->bo) {
50818781e08Smrg		drmModeRmFB(drmmode->fd, scanout->fb_id);
50918781e08Smrg		scanout->fb_id = 0;
51018781e08Smrg		radeon_bo_unmap(scanout->bo);
51118781e08Smrg		radeon_bo_unref(scanout->bo);
51218781e08Smrg		scanout->bo = NULL;
51318781e08Smrg	}
51418781e08Smrg}
51518781e08Smrg
51618781e08Smrgstatic void
51718781e08Smrgdrmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc)
51818781e08Smrg{
51918781e08Smrg	if (drmmode_crtc->flip_pending) {
52018781e08Smrg		drmmode_crtc->scanout_destroy[0] = drmmode_crtc->scanout[0];
52118781e08Smrg		drmmode_crtc->scanout[0].pixmap = NULL;
52218781e08Smrg		drmmode_crtc->scanout[0].bo = NULL;
52318781e08Smrg		drmmode_crtc->scanout_destroy[1] = drmmode_crtc->scanout[1];
52418781e08Smrg		drmmode_crtc->scanout[1].pixmap = NULL;
52518781e08Smrg		drmmode_crtc->scanout[1].bo = NULL;
52618781e08Smrg	} else {
52718781e08Smrg		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
52818781e08Smrg					     &drmmode_crtc->scanout[0]);
52918781e08Smrg		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
53018781e08Smrg					     &drmmode_crtc->scanout[1]);
53118781e08Smrg	}
53218781e08Smrg
53318781e08Smrg	if (drmmode_crtc->scanout_damage) {
53418781e08Smrg		DamageDestroy(drmmode_crtc->scanout_damage);
53518781e08Smrg		drmmode_crtc->scanout_damage = NULL;
53618781e08Smrg		RegionUninit(&drmmode_crtc->scanout_last_region);
53718781e08Smrg	}
53818781e08Smrg}
53918781e08Smrg
54018781e08Smrgvoid
54118781e08Smrgdrmmode_scanout_free(ScrnInfoPtr scrn)
54218781e08Smrg{
54318781e08Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
54418781e08Smrg	int c;
54518781e08Smrg
54618781e08Smrg	for (c = 0; c < xf86_config->num_crtc; c++)
54718781e08Smrg		drmmode_crtc_scanout_free(xf86_config->crtc[c]->driver_private);
54818781e08Smrg}
54918781e08Smrg
5503ed65abbSmrgstatic PixmapPtr
5513ed65abbSmrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
5523ed65abbSmrg			    int width, int height)
55318781e08Smrg{
55418781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
55518781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
55618781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
55718781e08Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
55818781e08Smrg	struct radeon_surface surface;
55918781e08Smrg	uint32_t tiling = RADEON_CREATE_PIXMAP_TILING_MACRO;
56018781e08Smrg	int pitch;
56118781e08Smrg
5623ed65abbSmrg	if (scanout->pixmap) {
56318781e08Smrg		if (scanout->width == width && scanout->height == height)
5643ed65abbSmrg			return scanout->pixmap;
56518781e08Smrg
56618781e08Smrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
56718781e08Smrg	}
56818781e08Smrg
56918781e08Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600)
57018781e08Smrg		tiling |= RADEON_CREATE_PIXMAP_TILING_MICRO;
57118781e08Smrg	scanout->bo = radeon_alloc_pixmap_bo(pScrn, width, height, pScrn->depth,
57218781e08Smrg					     tiling, pScrn->bitsPerPixel,
57318781e08Smrg					     &pitch, &surface, &tiling);
57418781e08Smrg	if (scanout->bo == NULL)
5753ed65abbSmrg		goto error;
57618781e08Smrg
5773ed65abbSmrg	if (drmModeAddFB(drmmode->fd, width, height, pScrn->depth,
57818781e08Smrg			   pScrn->bitsPerPixel, pitch,
57918781e08Smrg			   scanout->bo->handle,
5803ed65abbSmrg			   &scanout->fb_id) != 0) {
58118781e08Smrg		ErrorF("failed to add scanout fb\n");
5823ed65abbSmrg		goto error;
58318781e08Smrg	}
58418781e08Smrg
58518781e08Smrg	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
58618781e08Smrg						 width, height,
58718781e08Smrg						 pScrn->depth,
58818781e08Smrg						 pScrn->bitsPerPixel,
5893ed65abbSmrg						 pitch, scanout->bo, NULL);
5903ed65abbSmrg	if (scanout->pixmap) {
5913ed65abbSmrg		scanout->width = width;
5923ed65abbSmrg		scanout->height = height;
5933ed65abbSmrg	} else {
59418781e08Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
59518781e08Smrg			   "Couldn't allocate scanout pixmap for CRTC\n");
5963ed65abbSmrgerror:
5973ed65abbSmrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
5983ed65abbSmrg	}
59918781e08Smrg
60018781e08Smrg	return scanout->pixmap;
60118781e08Smrg}
60218781e08Smrg
60318781e08Smrgstatic void
60418781e08Smrgradeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
60518781e08Smrg{
60618781e08Smrg	/* Only keep track of the extents */
60718781e08Smrg	RegionUninit(&damage->damage);
60818781e08Smrg	damage->damage.data = NULL;
60918781e08Smrg}
61018781e08Smrg
61118781e08Smrgstatic Bool
61218781e08Smrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc)
61318781e08Smrg{
61418781e08Smrg	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
61518781e08Smrg
61618781e08Smrg	/* Check for Option "SWcursor" */
61718781e08Smrg	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
61818781e08Smrg		return FALSE;
61918781e08Smrg
62018781e08Smrg	/* Fall back to SW cursor if the CRTC is transformed */
62118781e08Smrg	if (crtc->transformPresent)
62218781e08Smrg		return FALSE;
6230d16fef4Smrg
62418781e08Smrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7
62518781e08Smrg	/* Xorg doesn't correctly handle cursor position transform in the
62618781e08Smrg	 * rotation case
62718781e08Smrg	 */
62818781e08Smrg	if (crtc->driverIsPerformingTransform &&
62918781e08Smrg	    (crtc->rotation & 0xf) != RR_Rotate_0)
63018781e08Smrg		return FALSE;
63118781e08Smrg#endif
63218781e08Smrg
63318781e08Smrg#if defined(RADEON_PIXMAP_SHARING)
63418781e08Smrg	/* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */
63518781e08Smrg	if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) &&
63618781e08Smrg	    !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list))
63718781e08Smrg		return FALSE;
63818781e08Smrg#endif
63918781e08Smrg
64018781e08Smrg	return TRUE;
64118781e08Smrg}
64218781e08Smrg
6433ed65abbSmrgstatic void
6443ed65abbSmrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc)
6453ed65abbSmrg{
6463ed65abbSmrg	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
6473ed65abbSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
6483ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
6493ed65abbSmrg	int i;
6503ed65abbSmrg
6513ed65abbSmrg	drmmode_crtc->tear_free = FALSE;
6523ed65abbSmrg
6533ed65abbSmrg	for (i = 0; i < xf86_config->num_output; i++) {
6543ed65abbSmrg		xf86OutputPtr output = xf86_config->output[i];
6553ed65abbSmrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
6563ed65abbSmrg
6573ed65abbSmrg		if (output->crtc != crtc)
6583ed65abbSmrg			continue;
6593ed65abbSmrg
6603ed65abbSmrg		if (drmmode_output->tear_free == 1 ||
6613ed65abbSmrg		    (drmmode_output->tear_free == 2 &&
6623ed65abbSmrg		     (radeon_is_gpu_screen(crtc->scrn->pScreen) ||
6633ed65abbSmrg		      info->shadow_primary ||
6643ed65abbSmrg		      crtc->transformPresent || crtc->rotation != RR_Rotate_0))) {
6653ed65abbSmrg			drmmode_crtc->tear_free = TRUE;
6663ed65abbSmrg			return;
6673ed65abbSmrg		}
6683ed65abbSmrg	}
6693ed65abbSmrg}
6703ed65abbSmrg
67118781e08Smrg#if XF86_CRTC_VERSION >= 4
67218781e08Smrg
6733ed65abbSmrg#if XF86_CRTC_VERSION < 7
6743ed65abbSmrg#define XF86DriverTransformOutput TRUE
6753ed65abbSmrg#define XF86DriverTransformNone FALSE
6763ed65abbSmrg#endif
6773ed65abbSmrg
67818781e08Smrgstatic Bool
67918781e08Smrgdrmmode_handle_transform(xf86CrtcPtr crtc)
68018781e08Smrg{
68118781e08Smrg	Bool ret;
68218781e08Smrg
68318781e08Smrg	if (crtc->transformPresent || crtc->rotation != RR_Rotate_0)
68418781e08Smrg	    crtc->driverIsPerformingTransform = XF86DriverTransformOutput;
68518781e08Smrg	else
68618781e08Smrg	    crtc->driverIsPerformingTransform = XF86DriverTransformNone;
68718781e08Smrg
68818781e08Smrg	ret = xf86CrtcRotate(crtc);
68918781e08Smrg
69018781e08Smrg	crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use;
69118781e08Smrg
69218781e08Smrg	return ret;
6930d16fef4Smrg}
6940d16fef4Smrg
69518781e08Smrg#else
69618781e08Smrg
69718781e08Smrgstatic Bool
69818781e08Smrgdrmmode_handle_transform(xf86CrtcPtr crtc)
69918781e08Smrg{
70018781e08Smrg	return xf86CrtcRotate(crtc);
70118781e08Smrg}
70218781e08Smrg
70318781e08Smrg#endif
70418781e08Smrg
7053ed65abbSmrg#ifdef RADEON_PIXMAP_SHARING
7063ed65abbSmrg
7073ed65abbSmrgstatic void
7083ed65abbSmrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
7093ed65abbSmrg				  unsigned scanout_id, int *fb_id, int *x,
7103ed65abbSmrg				  int *y)
7113ed65abbSmrg{
7123ed65abbSmrg	ScrnInfoPtr scrn = crtc->scrn;
7133ed65abbSmrg	ScreenPtr screen = scrn->pScreen;
7143ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
7153ed65abbSmrg
7163ed65abbSmrg	if (drmmode_crtc->tear_free &&
7173ed65abbSmrg	    !drmmode_crtc->scanout[1].pixmap) {
7183ed65abbSmrg		RegionPtr region;
7193ed65abbSmrg		BoxPtr box;
7203ed65abbSmrg
7213ed65abbSmrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
7223ed65abbSmrg					    mode->HDisplay,
7233ed65abbSmrg					    mode->VDisplay);
7243ed65abbSmrg		region = &drmmode_crtc->scanout_last_region;
7253ed65abbSmrg		RegionUninit(region);
7263ed65abbSmrg		region->data = NULL;
7273ed65abbSmrg		box = RegionExtents(region);
7283ed65abbSmrg		box->x1 = crtc->x;
7293ed65abbSmrg		box->y1 = crtc->y;
7303ed65abbSmrg		box->x2 = crtc->x + mode->HDisplay;
7313ed65abbSmrg		box->y2 = crtc->y + mode->VDisplay;
7323ed65abbSmrg	}
7333ed65abbSmrg
7343ed65abbSmrg	if (scanout_id != drmmode_crtc->scanout_id) {
7353ed65abbSmrg		PixmapDirtyUpdatePtr dirty = NULL;
7363ed65abbSmrg
7373ed65abbSmrg		xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list,
7383ed65abbSmrg					 ent) {
7393ed65abbSmrg			if (dirty->src == crtc->randr_crtc->scanout_pixmap &&
7403ed65abbSmrg			    dirty->slave_dst ==
7413ed65abbSmrg			    drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap) {
7423ed65abbSmrg				dirty->slave_dst =
7433ed65abbSmrg					drmmode_crtc->scanout[scanout_id].pixmap;
7443ed65abbSmrg				break;
7453ed65abbSmrg			}
7463ed65abbSmrg		}
7473ed65abbSmrg
7483ed65abbSmrg		if (!drmmode_crtc->tear_free) {
7493ed65abbSmrg			GCPtr gc = GetScratchGC(scrn->depth, screen);
7503ed65abbSmrg
7513ed65abbSmrg			ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc);
7523ed65abbSmrg			gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable,
7533ed65abbSmrg					  &drmmode_crtc->scanout[0].pixmap->drawable,
7543ed65abbSmrg					  gc, 0, 0, mode->HDisplay, mode->VDisplay,
7553ed65abbSmrg					  0, 0);
7563ed65abbSmrg			FreeScratchGC(gc);
7573ed65abbSmrg			radeon_cs_flush_indirect(scrn);
7583ed65abbSmrg			radeon_bo_wait(drmmode_crtc->scanout[0].bo);
7593ed65abbSmrg		}
7603ed65abbSmrg	}
7613ed65abbSmrg
7623ed65abbSmrg	*fb_id = drmmode_crtc->scanout[scanout_id].fb_id;
7633ed65abbSmrg	*x = *y = 0;
7643ed65abbSmrg	drmmode_crtc->scanout_id = scanout_id;
7653ed65abbSmrg}
7663ed65abbSmrg
7673ed65abbSmrg#endif /* RADEON_PIXMAP_SHARING */
7683ed65abbSmrg
7693ed65abbSmrgstatic void
7703ed65abbSmrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
7713ed65abbSmrg			    unsigned scanout_id, int *fb_id, int *x, int *y)
7723ed65abbSmrg{
7733ed65abbSmrg	ScrnInfoPtr scrn = crtc->scrn;
7743ed65abbSmrg	ScreenPtr screen = scrn->pScreen;
7753ed65abbSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
7763ed65abbSmrg
7773ed65abbSmrg	drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0],
7783ed65abbSmrg				    mode->HDisplay, mode->VDisplay);
7793ed65abbSmrg	if (drmmode_crtc->tear_free) {
7803ed65abbSmrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
7813ed65abbSmrg					    mode->HDisplay, mode->VDisplay);
7823ed65abbSmrg	}
7833ed65abbSmrg
7843ed65abbSmrg	if (drmmode_crtc->scanout[0].pixmap &&
7853ed65abbSmrg	    (!drmmode_crtc->tear_free || drmmode_crtc->scanout[1].pixmap)) {
7863ed65abbSmrg		RegionPtr region;
7873ed65abbSmrg		BoxPtr box;
7883ed65abbSmrg
7893ed65abbSmrg		if (!drmmode_crtc->scanout_damage) {
7903ed65abbSmrg			drmmode_crtc->scanout_damage =
7913ed65abbSmrg				DamageCreate(radeon_screen_damage_report,
7923ed65abbSmrg					     NULL, DamageReportRawRegion,
7933ed65abbSmrg					     TRUE, screen, NULL);
7943ed65abbSmrg			DamageRegister(&screen->GetScreenPixmap(screen)->drawable,
7953ed65abbSmrg				       drmmode_crtc->scanout_damage);
7963ed65abbSmrg		}
7973ed65abbSmrg
7983ed65abbSmrg		region = DamageRegion(drmmode_crtc->scanout_damage);
7993ed65abbSmrg		RegionUninit(region);
8003ed65abbSmrg		region->data = NULL;
8013ed65abbSmrg		box = RegionExtents(region);
8023ed65abbSmrg		box->x1 = 0;
8033ed65abbSmrg		box->y1 = 0;
8043ed65abbSmrg		box->x2 = max(box->x2, scrn->virtualX);
8053ed65abbSmrg		box->y2 = max(box->y2, scrn->virtualY);
8063ed65abbSmrg
8073ed65abbSmrg		*fb_id = drmmode_crtc->scanout[scanout_id].fb_id;
8083ed65abbSmrg		*x = *y = 0;
8093ed65abbSmrg
8103ed65abbSmrg		radeon_scanout_do_update(crtc, scanout_id);
8113ed65abbSmrg		radeon_bo_wait(drmmode_crtc->scanout[scanout_id].bo);
8123ed65abbSmrg	}
8133ed65abbSmrg}
8143ed65abbSmrg
815de2362d3Smrgstatic Bool
816de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
817de2362d3Smrg		     Rotation rotation, int x, int y)
818de2362d3Smrg{
819de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
82018781e08Smrg	ScreenPtr pScreen = pScrn->pScreen;
821de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
822de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
823de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
8243ed65abbSmrg	unsigned scanout_id = 0;
825de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
826de2362d3Smrg	int saved_x, saved_y;
827de2362d3Smrg	Rotation saved_rotation;
828de2362d3Smrg	DisplayModeRec saved_mode;
82918781e08Smrg	uint32_t *output_ids = NULL;
830de2362d3Smrg	int output_count = 0;
83118781e08Smrg	Bool ret = FALSE;
832de2362d3Smrg	int i;
833de2362d3Smrg	int fb_id;
834de2362d3Smrg	drmModeModeInfo kmode;
835de2362d3Smrg
836de2362d3Smrg	saved_mode = crtc->mode;
837de2362d3Smrg	saved_x = crtc->x;
838de2362d3Smrg	saved_y = crtc->y;
839de2362d3Smrg	saved_rotation = crtc->rotation;
840de2362d3Smrg
841de2362d3Smrg	if (mode) {
842de2362d3Smrg		crtc->mode = *mode;
843de2362d3Smrg		crtc->x = x;
844de2362d3Smrg		crtc->y = y;
845de2362d3Smrg		crtc->rotation = rotation;
846de2362d3Smrg
84718781e08Smrg		output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
84818781e08Smrg		if (!output_ids)
84918781e08Smrg			goto done;
850de2362d3Smrg
851de2362d3Smrg		for (i = 0; i < xf86_config->num_output; i++) {
852de2362d3Smrg			xf86OutputPtr output = xf86_config->output[i];
853de2362d3Smrg			drmmode_output_private_ptr drmmode_output;
854de2362d3Smrg
855de2362d3Smrg			if (output->crtc != crtc)
856de2362d3Smrg				continue;
857de2362d3Smrg
858de2362d3Smrg			drmmode_output = output->driver_private;
859de2362d3Smrg			output_ids[output_count] = drmmode_output->mode_output->connector_id;
860de2362d3Smrg			output_count++;
861de2362d3Smrg		}
862de2362d3Smrg
86318781e08Smrg		if (!drmmode_handle_transform(crtc))
864de2362d3Smrg			goto done;
86518781e08Smrg
8663ed65abbSmrg		drmmode_crtc_update_tear_free(crtc);
8673ed65abbSmrg		if (drmmode_crtc->tear_free)
8683ed65abbSmrg			scanout_id = drmmode_crtc->scanout_id;
8693ed65abbSmrg
870de2362d3Smrg		crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
871de2362d3Smrg				       crtc->gamma_blue, crtc->gamma_size);
87218781e08Smrg
873de2362d3Smrg		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
874de2362d3Smrg
875de2362d3Smrg		fb_id = drmmode->fb_id;
87618781e08Smrg#ifdef RADEON_PIXMAP_SHARING
87718781e08Smrg		if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
8783ed65abbSmrg			drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id,
8793ed65abbSmrg							  &fb_id, &x, &y);
88018781e08Smrg		} else
88118781e08Smrg#endif
88218781e08Smrg		if (drmmode_crtc->rotate.fb_id) {
88318781e08Smrg			fb_id = drmmode_crtc->rotate.fb_id;
88418781e08Smrg			x = y = 0;
88518781e08Smrg
8863ed65abbSmrg		} else if (!radeon_is_gpu_screen(pScreen) &&
8873ed65abbSmrg			   (drmmode_crtc->tear_free ||
88818781e08Smrg#if XF86_CRTC_VERSION >= 4
88918781e08Smrg			    crtc->driverIsPerformingTransform ||
89018781e08Smrg#endif
89118781e08Smrg			    info->shadow_primary)) {
8923ed65abbSmrg			drmmode_crtc_scanout_update(crtc, mode, scanout_id,
8933ed65abbSmrg						    &fb_id, &x, &y);
894de2362d3Smrg		}
89518781e08Smrg
89618781e08Smrg		if (fb_id == 0) {
89718781e08Smrg			if (drmModeAddFB(drmmode->fd,
89818781e08Smrg					 pScrn->virtualX,
89918781e08Smrg					 pScrn->virtualY,
90018781e08Smrg					 pScrn->depth, pScrn->bitsPerPixel,
90118781e08Smrg					 pScrn->displayWidth * info->pixel_bytes,
90218781e08Smrg					 info->front_bo->handle,
90318781e08Smrg					 &drmmode->fb_id) < 0) {
90418781e08Smrg				ErrorF("failed to add fb\n");
90518781e08Smrg				goto done;
90618781e08Smrg			}
90718781e08Smrg
90818781e08Smrg			fb_id = drmmode->fb_id;
90918781e08Smrg		}
91018781e08Smrg
91118781e08Smrg		/* Wait for any pending flip to finish */
91218781e08Smrg		do {} while (drmmode_crtc->flip_pending &&
91318781e08Smrg			     drmHandleEvent(drmmode->fd,
91418781e08Smrg					    &drmmode->event_context) > 0);
91518781e08Smrg
91618781e08Smrg		if (drmModeSetCrtc(drmmode->fd,
91718781e08Smrg				   drmmode_crtc->mode_crtc->crtc_id,
91818781e08Smrg				   fb_id, x, y, output_ids,
91918781e08Smrg				   output_count, &kmode) != 0) {
920de2362d3Smrg			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
92118781e08Smrg				   "failed to set mode: %s\n", strerror(errno));
92218781e08Smrg			goto done;
92318781e08Smrg		} else
924de2362d3Smrg			ret = TRUE;
925de2362d3Smrg
92618781e08Smrg		if (pScreen)
92718781e08Smrg			xf86CrtcSetScreenSubpixelOrder(pScreen);
92818781e08Smrg
92918781e08Smrg		drmmode_crtc->need_modeset = FALSE;
93018781e08Smrg
931de2362d3Smrg		/* go through all the outputs and force DPMS them back on? */
932de2362d3Smrg		for (i = 0; i < xf86_config->num_output; i++) {
933de2362d3Smrg			xf86OutputPtr output = xf86_config->output[i];
934de2362d3Smrg
935de2362d3Smrg			if (output->crtc != crtc)
936de2362d3Smrg				continue;
937de2362d3Smrg
938de2362d3Smrg			output->funcs->dpms(output, DPMSModeOn);
939de2362d3Smrg		}
940de2362d3Smrg	}
941de2362d3Smrg
94218781e08Smrg	/* Compute index of this CRTC into xf86_config->crtc */
94318781e08Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
94418781e08Smrg		if (xf86_config->crtc[i] != crtc)
94518781e08Smrg			continue;
94618781e08Smrg
94718781e08Smrg		if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc))
94818781e08Smrg			info->hwcursor_disabled &= ~(1 << i);
94918781e08Smrg		else
95018781e08Smrg			info->hwcursor_disabled |= 1 << i;
95118781e08Smrg
95218781e08Smrg		break;
95318781e08Smrg	}
95418781e08Smrg
95518781e08Smrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR
95618781e08Smrg	if (!info->hwcursor_disabled)
95718781e08Smrg		xf86_reload_cursors(pScreen);
95818781e08Smrg#endif
959de2362d3Smrg
960de2362d3Smrgdone:
961de2362d3Smrg	if (!ret) {
962de2362d3Smrg		crtc->x = saved_x;
963de2362d3Smrg		crtc->y = saved_y;
964de2362d3Smrg		crtc->rotation = saved_rotation;
965de2362d3Smrg		crtc->mode = saved_mode;
96618781e08Smrg	} else {
9677821949aSmrg		crtc->active = TRUE;
96818781e08Smrg
9693ed65abbSmrg		if (fb_id != drmmode_crtc->scanout[scanout_id].fb_id)
97018781e08Smrg			drmmode_crtc_scanout_free(drmmode_crtc);
9713ed65abbSmrg		else if (!drmmode_crtc->tear_free) {
9723ed65abbSmrg			drmmode_crtc_scanout_destroy(drmmode,
9733ed65abbSmrg						     &drmmode_crtc->scanout[1]);
9743ed65abbSmrg		}
97518781e08Smrg	}
97618781e08Smrg
97718781e08Smrg	free(output_ids);
978de2362d3Smrg
979de2362d3Smrg	return ret;
980de2362d3Smrg}
981de2362d3Smrg
982de2362d3Smrgstatic void
983de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
984de2362d3Smrg{
985de2362d3Smrg
986de2362d3Smrg}
987de2362d3Smrg
988de2362d3Smrgstatic void
989de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
990de2362d3Smrg{
991de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
992de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
993de2362d3Smrg
99418781e08Smrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7
99518781e08Smrg	if (crtc->driverIsPerformingTransform) {
99618781e08Smrg		x += crtc->x;
99718781e08Smrg		y += crtc->y;
99818781e08Smrg		xf86CrtcTransformCursorPos(crtc, &x, &y);
99918781e08Smrg	}
100018781e08Smrg#endif
100118781e08Smrg
1002de2362d3Smrg	drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
1003de2362d3Smrg}
1004de2362d3Smrg
100518781e08Smrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7
100618781e08Smrg
100718781e08Smrgstatic int
100818781e08Smrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height,
100918781e08Smrg			  int x_dst, int y_dst)
101018781e08Smrg{
101118781e08Smrg	int t;
101218781e08Smrg
101318781e08Smrg	switch (rotation & 0xf) {
101418781e08Smrg	case RR_Rotate_90:
101518781e08Smrg		t = x_dst;
101618781e08Smrg		x_dst = height - y_dst - 1;
101718781e08Smrg		y_dst = t;
101818781e08Smrg		break;
101918781e08Smrg	case RR_Rotate_180:
102018781e08Smrg		x_dst = width - x_dst - 1;
102118781e08Smrg		y_dst = height - y_dst - 1;
102218781e08Smrg		break;
102318781e08Smrg	case RR_Rotate_270:
102418781e08Smrg		t = x_dst;
102518781e08Smrg		x_dst = y_dst;
102618781e08Smrg		y_dst = width - t - 1;
102718781e08Smrg		break;
102818781e08Smrg	}
102918781e08Smrg
103018781e08Smrg	if (rotation & RR_Reflect_X)
103118781e08Smrg		x_dst = width - x_dst - 1;
103218781e08Smrg	if (rotation & RR_Reflect_Y)
103318781e08Smrg		y_dst = height - y_dst - 1;
103418781e08Smrg
103518781e08Smrg	return y_dst * height + x_dst;
103618781e08Smrg}
103718781e08Smrg
103818781e08Smrg#endif
103918781e08Smrg
1040de2362d3Smrgstatic void
1041de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
1042de2362d3Smrg{
104318781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
104418781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1045de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1046de2362d3Smrg	uint32_t *ptr;
1047de2362d3Smrg
1048de2362d3Smrg	/* cursor should be mapped already */
1049de2362d3Smrg	ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr);
1050de2362d3Smrg
105118781e08Smrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7
105218781e08Smrg	if (crtc->driverIsPerformingTransform) {
105318781e08Smrg		uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
105418781e08Smrg		int dstx, dsty;
105518781e08Smrg		int srcoffset;
105618781e08Smrg
105718781e08Smrg		for (dsty = 0; dsty < cursor_h; dsty++) {
105818781e08Smrg			for (dstx = 0; dstx < cursor_w; dstx++) {
105918781e08Smrg				srcoffset = drmmode_cursor_src_offset(crtc->rotation,
106018781e08Smrg								      cursor_w,
106118781e08Smrg								      cursor_h,
106218781e08Smrg								      dstx, dsty);
106318781e08Smrg
106418781e08Smrg				ptr[dsty * info->cursor_w + dstx] =
106518781e08Smrg					cpu_to_le32(image[srcoffset]);
106618781e08Smrg			}
106718781e08Smrg		}
106818781e08Smrg	} else
106918781e08Smrg#endif
107018781e08Smrg	{
107118781e08Smrg		uint32_t cursor_size = info->cursor_w * info->cursor_h;
107218781e08Smrg		int i;
107318781e08Smrg
107418781e08Smrg		for (i = 0; i < cursor_size; i++)
107518781e08Smrg			ptr[i] = cpu_to_le32(image[i]);
107618781e08Smrg	}
1077de2362d3Smrg}
1078de2362d3Smrg
107918781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
108018781e08Smrg
108118781e08Smrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
108218781e08Smrg{
108318781e08Smrg	if (!drmmode_can_use_hw_cursor(crtc))
108418781e08Smrg		return FALSE;
108518781e08Smrg
108618781e08Smrg	drmmode_load_cursor_argb(crtc, image);
108718781e08Smrg	return TRUE;
108818781e08Smrg}
108918781e08Smrg
109018781e08Smrg#endif
1091de2362d3Smrg
1092de2362d3Smrgstatic void
1093de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc)
1094de2362d3Smrg{
109518781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
109618781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1097de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1098de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1099de2362d3Smrg
110018781e08Smrg	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
110118781e08Smrg			 info->cursor_w, info->cursor_h);
1102de2362d3Smrg
1103de2362d3Smrg}
1104de2362d3Smrg
1105de2362d3Smrgstatic void
1106de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc)
1107de2362d3Smrg{
110818781e08Smrg	ScrnInfoPtr pScrn = crtc->scrn;
110918781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1110de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1111de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1112de2362d3Smrg	uint32_t handle = drmmode_crtc->cursor_bo->handle;
111318781e08Smrg	static Bool use_set_cursor2 = TRUE;
111418781e08Smrg
111518781e08Smrg	if (use_set_cursor2) {
111618781e08Smrg	    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
111718781e08Smrg	    CursorPtr cursor = xf86_config->cursor;
111818781e08Smrg	    int xhot = cursor->bits->xhot;
111918781e08Smrg	    int yhot = cursor->bits->yhot;
112018781e08Smrg	    int ret;
112118781e08Smrg
112218781e08Smrg	    if (crtc->rotation != RR_Rotate_0 &&
112318781e08Smrg		crtc->rotation != (RR_Rotate_180 | RR_Reflect_X |
112418781e08Smrg				   RR_Reflect_Y)) {
112518781e08Smrg		int t;
112618781e08Smrg
112718781e08Smrg		/* Reflect & rotate hotspot position */
112818781e08Smrg		if (crtc->rotation & RR_Reflect_X)
112918781e08Smrg		    xhot = info->cursor_w - xhot - 1;
113018781e08Smrg		if (crtc->rotation & RR_Reflect_Y)
113118781e08Smrg		    yhot = info->cursor_h - yhot - 1;
113218781e08Smrg
113318781e08Smrg		switch (crtc->rotation & 0xf) {
113418781e08Smrg		case RR_Rotate_90:
113518781e08Smrg		    t = xhot;
113618781e08Smrg		    xhot = yhot;
113718781e08Smrg		    yhot = info->cursor_w - t - 1;
113818781e08Smrg		    break;
113918781e08Smrg		case RR_Rotate_180:
114018781e08Smrg		    xhot = info->cursor_w - xhot - 1;
114118781e08Smrg		    yhot = info->cursor_h - yhot - 1;
114218781e08Smrg		    break;
114318781e08Smrg		case RR_Rotate_270:
114418781e08Smrg		    t = xhot;
114518781e08Smrg		    xhot = info->cursor_h - yhot - 1;
114618781e08Smrg		    yhot = t;
114718781e08Smrg		}
114818781e08Smrg	    }
11497314432eSmrg
115018781e08Smrg	    ret =
115118781e08Smrg		drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
115218781e08Smrg				  handle, info->cursor_w, info->cursor_h,
115318781e08Smrg				  xhot, yhot);
115418781e08Smrg	    if (ret == -EINVAL)
115518781e08Smrg		use_set_cursor2 = FALSE;
115618781e08Smrg	    else
115718781e08Smrg		return;
115818781e08Smrg	}
115918781e08Smrg
116018781e08Smrg	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle,
116118781e08Smrg			 info->cursor_w, info->cursor_h);
1162de2362d3Smrg}
1163de2362d3Smrg
11643ed65abbSmrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and
11653ed65abbSmrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for
11663ed65abbSmrg * anything else.
11673ed65abbSmrg */
1168de2362d3Smrgstatic void *
1169de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
1170de2362d3Smrg{
1171de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
11727821949aSmrg
11733ed65abbSmrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
11743ed65abbSmrg					 height))
11753ed65abbSmrg		return NULL;
11763ed65abbSmrg
11773ed65abbSmrg	return (void*)~0UL;
1178de2362d3Smrg}
1179de2362d3Smrg
1180de2362d3Smrgstatic PixmapPtr
1181de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1182de2362d3Smrg{
1183de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1184de2362d3Smrg
11853ed65abbSmrg	if (!data) {
11863ed65abbSmrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
11873ed65abbSmrg					    height);
11883ed65abbSmrg	}
11893ed65abbSmrg
11903ed65abbSmrg	return drmmode_crtc->rotate.pixmap;
1191de2362d3Smrg}
1192de2362d3Smrg
1193de2362d3Smrgstatic void
11947821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
1195de2362d3Smrg{
1196de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1197de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1198de2362d3Smrg
119918781e08Smrg	drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate);
12007821949aSmrg}
1201de2362d3Smrg
12027821949aSmrgstatic void
12037821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
12047821949aSmrg                      uint16_t *blue, int size)
12057821949aSmrg{
12067821949aSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
12077821949aSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
12087314432eSmrg
120918781e08Smrg	drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
121018781e08Smrg			    size, red, green, blue);
121118781e08Smrg}
121218781e08Smrg
121318781e08Smrg#ifdef RADEON_PIXMAP_SHARING
121418781e08Smrgstatic Bool
121518781e08Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
121618781e08Smrg{
121718781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
12183ed65abbSmrg	unsigned scanout_id = drmmode_crtc->scanout_id;
121918781e08Smrg	ScreenPtr screen = crtc->scrn->pScreen;
122018781e08Smrg	PixmapDirtyUpdatePtr dirty;
122118781e08Smrg
122218781e08Smrg	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
12233ed65abbSmrg		if (dirty->slave_dst != drmmode_crtc->scanout[scanout_id].pixmap)
122418781e08Smrg			continue;
122518781e08Smrg
122618781e08Smrg		PixmapStopDirtyTracking(dirty->src, dirty->slave_dst);
122718781e08Smrg		drmmode_crtc_scanout_free(drmmode_crtc);
122818781e08Smrg		break;
122918781e08Smrg	}
123018781e08Smrg
123118781e08Smrg	if (!ppix)
123218781e08Smrg		return TRUE;
123318781e08Smrg
123418781e08Smrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0],
123518781e08Smrg					 ppix->drawable.width,
123618781e08Smrg					 ppix->drawable.height))
123718781e08Smrg		return FALSE;
123818781e08Smrg
12393ed65abbSmrg	if (drmmode_crtc->tear_free &&
124018781e08Smrg	    !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
124118781e08Smrg					 ppix->drawable.width,
124218781e08Smrg					 ppix->drawable.height)) {
124318781e08Smrg		drmmode_crtc_scanout_free(drmmode_crtc);
124418781e08Smrg		return FALSE;
124518781e08Smrg	}
124618781e08Smrg
124718781e08Smrg#ifdef HAS_DIRTYTRACKING_ROTATION
12483ed65abbSmrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
124918781e08Smrg				 0, 0, 0, 0, RR_Rotate_0);
125018781e08Smrg#elif defined(HAS_DIRTYTRACKING2)
12513ed65abbSmrg	PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
125218781e08Smrg				  0, 0, 0, 0);
125318781e08Smrg#else
12543ed65abbSmrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0);
125518781e08Smrg#endif
125618781e08Smrg	return TRUE;
1257de2362d3Smrg}
125818781e08Smrg#endif
1259de2362d3Smrg
126018781e08Smrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = {
1261de2362d3Smrg    .dpms = drmmode_crtc_dpms,
1262de2362d3Smrg    .set_mode_major = drmmode_set_mode_major,
1263de2362d3Smrg    .set_cursor_colors = drmmode_set_cursor_colors,
1264de2362d3Smrg    .set_cursor_position = drmmode_set_cursor_position,
1265de2362d3Smrg    .show_cursor = drmmode_show_cursor,
1266de2362d3Smrg    .hide_cursor = drmmode_hide_cursor,
1267de2362d3Smrg    .load_cursor_argb = drmmode_load_cursor_argb,
126818781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
126918781e08Smrg    .load_cursor_argb_check = drmmode_load_cursor_argb_check,
127018781e08Smrg#endif
1271de2362d3Smrg
1272de2362d3Smrg    .gamma_set = drmmode_crtc_gamma_set,
1273de2362d3Smrg    .shadow_create = drmmode_crtc_shadow_create,
1274de2362d3Smrg    .shadow_allocate = drmmode_crtc_shadow_allocate,
1275de2362d3Smrg    .shadow_destroy = drmmode_crtc_shadow_destroy,
1276de2362d3Smrg    .destroy = NULL, /* XXX */
127718781e08Smrg#ifdef RADEON_PIXMAP_SHARING
127818781e08Smrg    .set_scanout_pixmap = drmmode_set_scanout_pixmap,
127918781e08Smrg#endif
1280de2362d3Smrg};
1281de2362d3Smrg
1282de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc)
1283de2362d3Smrg{
1284de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1285de2362d3Smrg	return drmmode_crtc->hw_id;
1286de2362d3Smrg}
1287de2362d3Smrg
1288de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc)
1289de2362d3Smrg{
1290de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1291de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
1292de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1293de2362d3Smrg	struct drm_radeon_info ginfo;
1294de2362d3Smrg	int r;
1295de2362d3Smrg	uint32_t tmp;
1296de2362d3Smrg
1297de2362d3Smrg	memset(&ginfo, 0, sizeof(ginfo));
1298de2362d3Smrg	ginfo.request = 0x4;
1299de2362d3Smrg	tmp = drmmode_crtc->mode_crtc->crtc_id;
1300de2362d3Smrg	ginfo.value = (uintptr_t)&tmp;
130118781e08Smrg	r = drmCommandWriteRead(info->dri2.drm_fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo));
1302de2362d3Smrg	if (r) {
1303de2362d3Smrg		drmmode_crtc->hw_id = -1;
1304de2362d3Smrg		return;
1305de2362d3Smrg	}
1306de2362d3Smrg	drmmode_crtc->hw_id = tmp;
1307de2362d3Smrg}
1308de2362d3Smrg
130918781e08Smrgstatic unsigned int
131018781e08Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
1311de2362d3Smrg{
1312de2362d3Smrg	xf86CrtcPtr crtc;
1313de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc;
131418781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1315de2362d3Smrg
1316de2362d3Smrg	crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
1317de2362d3Smrg	if (crtc == NULL)
131818781e08Smrg		return 0;
1319de2362d3Smrg
1320de2362d3Smrg	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
132118781e08Smrg	drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
1322de2362d3Smrg	drmmode_crtc->drmmode = drmmode;
132318781e08Smrg	drmmode_crtc->dpms_mode = DPMSModeOff;
132418781e08Smrg	drmmode_crtc->pending_dpms_mode = DPMSModeOff;
1325de2362d3Smrg	crtc->driver_private = drmmode_crtc;
1326de2362d3Smrg	drmmode_crtc_hw_id(crtc);
1327de2362d3Smrg
132818781e08Smrg	/* Mark num'th crtc as in use on this device. */
132918781e08Smrg	pRADEONEnt->assigned_crtcs |= (1 << num);
133018781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
133118781e08Smrg		       "Allocated crtc nr. %d to this screen.\n", num);
133218781e08Smrg
133318781e08Smrg	return 1;
1334de2362d3Smrg}
1335de2362d3Smrg
1336de2362d3Smrgstatic xf86OutputStatus
1337de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output)
1338de2362d3Smrg{
1339de2362d3Smrg	/* go to the hw and retrieve a new output struct */
1340de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1341de2362d3Smrg	drmmode_ptr drmmode = drmmode_output->drmmode;
1342de2362d3Smrg	xf86OutputStatus status;
1343de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
1344de2362d3Smrg
1345de2362d3Smrg	drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
134618781e08Smrg	if (!drmmode_output->mode_output)
134718781e08Smrg		return XF86OutputStatusDisconnected;
1348de2362d3Smrg
1349de2362d3Smrg	switch (drmmode_output->mode_output->connection) {
1350de2362d3Smrg	case DRM_MODE_CONNECTED:
1351de2362d3Smrg		status = XF86OutputStatusConnected;
1352de2362d3Smrg		break;
1353de2362d3Smrg	case DRM_MODE_DISCONNECTED:
1354de2362d3Smrg		status = XF86OutputStatusDisconnected;
1355de2362d3Smrg		break;
1356de2362d3Smrg	default:
1357de2362d3Smrg	case DRM_MODE_UNKNOWNCONNECTION:
1358de2362d3Smrg		status = XF86OutputStatusUnknown;
1359de2362d3Smrg		break;
1360de2362d3Smrg	}
1361de2362d3Smrg	return status;
1362de2362d3Smrg}
1363de2362d3Smrg
1364de2362d3Smrgstatic Bool
1365de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
1366de2362d3Smrg{
1367de2362d3Smrg	return MODE_OK;
1368de2362d3Smrg}
1369de2362d3Smrg
1370de2362d3Smrgstatic DisplayModePtr
1371de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output)
1372de2362d3Smrg{
1373de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1374de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
1375de2362d3Smrg	drmmode_ptr drmmode = drmmode_output->drmmode;
1376de2362d3Smrg	int i;
1377de2362d3Smrg	DisplayModePtr Modes = NULL, Mode;
1378de2362d3Smrg	drmModePropertyPtr props;
1379de2362d3Smrg	xf86MonPtr mon = NULL;
1380de2362d3Smrg
138118781e08Smrg	if (!koutput)
138218781e08Smrg		return NULL;
138318781e08Smrg
1384de2362d3Smrg	/* look for an EDID property */
1385de2362d3Smrg	for (i = 0; i < koutput->count_props; i++) {
1386de2362d3Smrg		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
1387de2362d3Smrg		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
1388de2362d3Smrg			if (!strcmp(props->name, "EDID")) {
1389de2362d3Smrg				if (drmmode_output->edid_blob)
1390de2362d3Smrg					drmModeFreePropertyBlob(drmmode_output->edid_blob);
1391de2362d3Smrg				drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
1392de2362d3Smrg			}
13937821949aSmrg		}
139418781e08Smrg		if (props)
139518781e08Smrg			drmModeFreeProperty(props);
1396de2362d3Smrg	}
1397de2362d3Smrg
1398de2362d3Smrg	if (drmmode_output->edid_blob) {
1399de2362d3Smrg		mon = xf86InterpretEDID(output->scrn->scrnIndex,
1400de2362d3Smrg					drmmode_output->edid_blob->data);
1401de2362d3Smrg		if (mon && drmmode_output->edid_blob->length > 128)
1402de2362d3Smrg			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
1403de2362d3Smrg	}
1404de2362d3Smrg	xf86OutputSetEDID(output, mon);
1405de2362d3Smrg
1406de2362d3Smrg	/* modes should already be available */
1407de2362d3Smrg	for (i = 0; i < koutput->count_modes; i++) {
1408de2362d3Smrg		Mode = xnfalloc(sizeof(DisplayModeRec));
1409de2362d3Smrg
1410de2362d3Smrg		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
1411de2362d3Smrg		Modes = xf86ModesAdd(Modes, Mode);
1412de2362d3Smrg
1413de2362d3Smrg	}
1414de2362d3Smrg	return Modes;
1415de2362d3Smrg}
1416de2362d3Smrg
1417de2362d3Smrgstatic void
1418de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output)
1419de2362d3Smrg{
1420de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1421de2362d3Smrg	int i;
1422de2362d3Smrg
1423de2362d3Smrg	if (drmmode_output->edid_blob)
1424de2362d3Smrg		drmModeFreePropertyBlob(drmmode_output->edid_blob);
1425de2362d3Smrg	for (i = 0; i < drmmode_output->num_props; i++) {
1426de2362d3Smrg		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
1427de2362d3Smrg		free(drmmode_output->props[i].atoms);
1428de2362d3Smrg	}
1429de2362d3Smrg	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
1430de2362d3Smrg		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
1431de2362d3Smrg	}
143218781e08Smrg	free(drmmode_output->mode_encoders);
1433de2362d3Smrg	free(drmmode_output->props);
1434de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
1435de2362d3Smrg	free(drmmode_output);
1436de2362d3Smrg	output->driver_private = NULL;
1437de2362d3Smrg}
1438de2362d3Smrg
1439de2362d3Smrgstatic void
1440de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode)
1441de2362d3Smrg{
1442de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
144318781e08Smrg	xf86CrtcPtr crtc = output->crtc;
1444de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
1445de2362d3Smrg	drmmode_ptr drmmode = drmmode_output->drmmode;
1446de2362d3Smrg
144718781e08Smrg	if (!koutput)
144818781e08Smrg		return;
144918781e08Smrg
145018781e08Smrg	if (mode != DPMSModeOn && crtc) {
145118781e08Smrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
145218781e08Smrg
145318781e08Smrg		drmmode_do_crtc_dpms(crtc, mode);
145418781e08Smrg
145518781e08Smrg		/* Wait for any pending flip to finish */
145618781e08Smrg		if (drmmode_crtc->flip_pending)
145718781e08Smrg			return;
145818781e08Smrg	}
145918781e08Smrg
1460de2362d3Smrg	drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
1461de2362d3Smrg				    drmmode_output->dpms_enum_id, mode);
146218781e08Smrg
146318781e08Smrg	if (mode == DPMSModeOn && crtc) {
146418781e08Smrg	    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
146518781e08Smrg
146618781e08Smrg	    if (drmmode_crtc->need_modeset)
146718781e08Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x,
146818781e08Smrg				       crtc->y);
146918781e08Smrg	    else
147018781e08Smrg		drmmode_do_crtc_dpms(crtc, mode);
147118781e08Smrg	}
1472de2362d3Smrg}
1473de2362d3Smrg
1474de2362d3Smrg
1475de2362d3Smrgstatic Bool
1476de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop)
1477de2362d3Smrg{
1478de2362d3Smrg    if (!prop)
1479de2362d3Smrg	return TRUE;
1480de2362d3Smrg    /* ignore blob prop */
1481de2362d3Smrg    if (prop->flags & DRM_MODE_PROP_BLOB)
1482de2362d3Smrg	return TRUE;
1483de2362d3Smrg    /* ignore standard property */
1484de2362d3Smrg    if (!strcmp(prop->name, "EDID") ||
1485de2362d3Smrg	    !strcmp(prop->name, "DPMS"))
1486de2362d3Smrg	return TRUE;
1487de2362d3Smrg
1488de2362d3Smrg    return FALSE;
1489de2362d3Smrg}
1490de2362d3Smrg
1491de2362d3Smrgstatic void
1492de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output)
1493de2362d3Smrg{
14943ed65abbSmrg    RADEONInfoPtr info = RADEONPTR(output->scrn);
1495de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
1496de2362d3Smrg    drmModeConnectorPtr mode_output = drmmode_output->mode_output;
1497de2362d3Smrg    drmmode_ptr drmmode = drmmode_output->drmmode;
14983ed65abbSmrg    drmModePropertyPtr drmmode_prop, tearfree_prop;
1499de2362d3Smrg    int i, j, err;
1500de2362d3Smrg
15013ed65abbSmrg    drmmode_output->props = calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec));
1502de2362d3Smrg    if (!drmmode_output->props)
1503de2362d3Smrg	return;
1504de2362d3Smrg
1505de2362d3Smrg    drmmode_output->num_props = 0;
1506de2362d3Smrg    for (i = 0, j = 0; i < mode_output->count_props; i++) {
1507de2362d3Smrg	drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
1508de2362d3Smrg	if (drmmode_property_ignore(drmmode_prop)) {
1509de2362d3Smrg	    drmModeFreeProperty(drmmode_prop);
1510de2362d3Smrg	    continue;
1511de2362d3Smrg	}
1512de2362d3Smrg	drmmode_output->props[j].mode_prop = drmmode_prop;
1513de2362d3Smrg	drmmode_output->props[j].value = mode_output->prop_values[i];
1514de2362d3Smrg	drmmode_output->num_props++;
1515de2362d3Smrg	j++;
1516de2362d3Smrg    }
1517de2362d3Smrg
15183ed65abbSmrg    /* Userspace-only property for TearFree */
15193ed65abbSmrg    tearfree_prop = calloc(1, sizeof(*tearfree_prop));
15203ed65abbSmrg    tearfree_prop->flags = DRM_MODE_PROP_ENUM;
15213ed65abbSmrg    strncpy(tearfree_prop->name, "TearFree", 8);
15223ed65abbSmrg    tearfree_prop->count_enums = 3;
15233ed65abbSmrg    tearfree_prop->enums = calloc(tearfree_prop->count_enums,
15243ed65abbSmrg				  sizeof(*tearfree_prop->enums));
15253ed65abbSmrg    strncpy(tearfree_prop->enums[0].name, "off", 3);
15263ed65abbSmrg    strncpy(tearfree_prop->enums[1].name, "on", 2);
15273ed65abbSmrg    tearfree_prop->enums[1].value = 1;
15283ed65abbSmrg    strncpy(tearfree_prop->enums[2].name, "auto", 4);
15293ed65abbSmrg    tearfree_prop->enums[2].value = 2;
15303ed65abbSmrg    drmmode_output->props[j].mode_prop = tearfree_prop;
15313ed65abbSmrg    drmmode_output->props[j].value = info->tear_free;
15323ed65abbSmrg    drmmode_output->tear_free = info->tear_free;
15333ed65abbSmrg    drmmode_output->num_props++;
15343ed65abbSmrg
1535de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
1536de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
1537de2362d3Smrg	drmmode_prop = p->mode_prop;
1538de2362d3Smrg
1539de2362d3Smrg	if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1540de2362d3Smrg	    INT32 range[2];
1541de2362d3Smrg	    INT32 value = p->value;
1542de2362d3Smrg
1543de2362d3Smrg	    p->num_atoms = 1;
1544de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
1545de2362d3Smrg	    if (!p->atoms)
1546de2362d3Smrg		continue;
1547de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1548de2362d3Smrg	    range[0] = drmmode_prop->values[0];
1549de2362d3Smrg	    range[1] = drmmode_prop->values[1];
1550de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1551de2362d3Smrg		    FALSE, TRUE,
1552de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1553de2362d3Smrg		    2, range);
1554de2362d3Smrg	    if (err != 0) {
1555de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1556de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
1557de2362d3Smrg	    }
1558de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1559de2362d3Smrg		    XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE);
1560de2362d3Smrg	    if (err != 0) {
1561de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1562de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
1563de2362d3Smrg	    }
1564de2362d3Smrg	} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1565de2362d3Smrg	    p->num_atoms = drmmode_prop->count_enums + 1;
1566de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
1567de2362d3Smrg	    if (!p->atoms)
1568de2362d3Smrg		continue;
1569de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1570de2362d3Smrg	    for (j = 1; j <= drmmode_prop->count_enums; j++) {
1571de2362d3Smrg		struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
1572de2362d3Smrg		p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
1573de2362d3Smrg	    }
1574de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1575de2362d3Smrg		    FALSE, FALSE,
1576de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1577de2362d3Smrg		    p->num_atoms - 1, (INT32 *)&p->atoms[1]);
1578de2362d3Smrg	    if (err != 0) {
1579de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1580de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
1581de2362d3Smrg	    }
1582de2362d3Smrg	    for (j = 0; j < drmmode_prop->count_enums; j++)
1583de2362d3Smrg		if (drmmode_prop->enums[j].value == p->value)
1584de2362d3Smrg		    break;
1585de2362d3Smrg	    /* there's always a matching value */
1586de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1587de2362d3Smrg		    XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
1588de2362d3Smrg	    if (err != 0) {
1589de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1590de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
1591de2362d3Smrg	    }
1592de2362d3Smrg	}
1593de2362d3Smrg    }
1594de2362d3Smrg}
1595de2362d3Smrg
1596de2362d3Smrgstatic Bool
1597de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property,
1598de2362d3Smrg		RRPropertyValuePtr value)
1599de2362d3Smrg{
1600de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
1601de2362d3Smrg    drmmode_ptr drmmode = drmmode_output->drmmode;
1602de2362d3Smrg    int i;
1603de2362d3Smrg
1604de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
1605de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
1606de2362d3Smrg
1607de2362d3Smrg	if (p->atoms[0] != property)
1608de2362d3Smrg	    continue;
1609de2362d3Smrg
1610de2362d3Smrg	if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1611de2362d3Smrg	    uint32_t val;
1612de2362d3Smrg
1613de2362d3Smrg	    if (value->type != XA_INTEGER || value->format != 32 ||
1614de2362d3Smrg		    value->size != 1)
1615de2362d3Smrg		return FALSE;
1616de2362d3Smrg	    val = *(uint32_t *)value->data;
1617de2362d3Smrg
1618de2362d3Smrg	    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
1619de2362d3Smrg		    p->mode_prop->prop_id, (uint64_t)val);
1620de2362d3Smrg	    return TRUE;
1621de2362d3Smrg	} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1622de2362d3Smrg	    Atom	atom;
1623de2362d3Smrg	    const char	*name;
1624de2362d3Smrg	    int		j;
1625de2362d3Smrg
1626de2362d3Smrg	    if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
1627de2362d3Smrg		return FALSE;
1628de2362d3Smrg	    memcpy(&atom, value->data, 4);
1629de2362d3Smrg	    name = NameForAtom(atom);
1630de2362d3Smrg
1631de2362d3Smrg	    /* search for matching name string, then set its value down */
1632de2362d3Smrg	    for (j = 0; j < p->mode_prop->count_enums; j++) {
1633de2362d3Smrg		if (!strcmp(p->mode_prop->enums[j].name, name)) {
16343ed65abbSmrg		    if (i == (drmmode_output->num_props - 1)) {
16353ed65abbSmrg			if (drmmode_output->tear_free != j) {
16363ed65abbSmrg			    xf86CrtcPtr crtc = output->crtc;
16373ed65abbSmrg
16383ed65abbSmrg			    drmmode_output->tear_free = j;
16393ed65abbSmrg			    if (crtc) {
16403ed65abbSmrg				drmmode_set_mode_major(crtc, &crtc->mode,
16413ed65abbSmrg						       crtc->rotation,
16423ed65abbSmrg						       crtc->x, crtc->y);
16433ed65abbSmrg			    }
16443ed65abbSmrg			}
16453ed65abbSmrg		    } else {
16463ed65abbSmrg			drmModeConnectorSetProperty(drmmode->fd,
16473ed65abbSmrg						    drmmode_output->output_id,
16483ed65abbSmrg						    p->mode_prop->prop_id,
16493ed65abbSmrg						    p->mode_prop->enums[j].value);
16503ed65abbSmrg		    }
16513ed65abbSmrg
1652de2362d3Smrg		    return TRUE;
1653de2362d3Smrg		}
1654de2362d3Smrg	    }
1655de2362d3Smrg	}
1656de2362d3Smrg    }
1657de2362d3Smrg
1658de2362d3Smrg    return TRUE;
1659de2362d3Smrg}
1660de2362d3Smrg
1661de2362d3Smrgstatic Bool
1662de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property)
1663de2362d3Smrg{
1664de2362d3Smrg    return TRUE;
1665de2362d3Smrg}
1666de2362d3Smrg
1667de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = {
1668de2362d3Smrg    .dpms = drmmode_output_dpms,
1669de2362d3Smrg    .create_resources = drmmode_output_create_resources,
1670de2362d3Smrg    .set_property = drmmode_output_set_property,
1671de2362d3Smrg    .get_property = drmmode_output_get_property,
1672de2362d3Smrg#if 0
1673de2362d3Smrg
1674de2362d3Smrg    .save = drmmode_crt_save,
1675de2362d3Smrg    .restore = drmmode_crt_restore,
1676de2362d3Smrg    .mode_fixup = drmmode_crt_mode_fixup,
1677de2362d3Smrg    .prepare = drmmode_output_prepare,
1678de2362d3Smrg    .mode_set = drmmode_crt_mode_set,
1679de2362d3Smrg    .commit = drmmode_output_commit,
1680de2362d3Smrg#endif
1681de2362d3Smrg    .detect = drmmode_output_detect,
1682de2362d3Smrg    .mode_valid = drmmode_output_mode_valid,
1683de2362d3Smrg
1684de2362d3Smrg    .get_modes = drmmode_output_get_modes,
1685de2362d3Smrg    .destroy = drmmode_output_destroy
1686de2362d3Smrg};
1687de2362d3Smrg
1688de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown,
1689de2362d3Smrg				      SubPixelHorizontalRGB,
1690de2362d3Smrg				      SubPixelHorizontalBGR,
1691de2362d3Smrg				      SubPixelVerticalRGB,
1692de2362d3Smrg				      SubPixelVerticalBGR,
1693de2362d3Smrg				      SubPixelNone };
1694de2362d3Smrg
1695de2362d3Smrgconst char *output_names[] = { "None",
1696de2362d3Smrg			       "VGA",
1697de2362d3Smrg			       "DVI",
1698de2362d3Smrg			       "DVI",
1699de2362d3Smrg			       "DVI",
1700de2362d3Smrg			       "Composite",
1701de2362d3Smrg			       "S-video",
1702de2362d3Smrg			       "LVDS",
1703de2362d3Smrg			       "CTV",
1704de2362d3Smrg			       "DIN",
1705de2362d3Smrg			       "DisplayPort",
1706de2362d3Smrg			       "HDMI",
1707de2362d3Smrg			       "HDMI",
1708de2362d3Smrg			       "TV",
1709de2362d3Smrg			       "eDP"
1710de2362d3Smrg};
1711de2362d3Smrg
171218781e08Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
171318781e08Smrg
171418781e08Smrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
171518781e08Smrg{
171618781e08Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
171718781e08Smrg	int i;
171818781e08Smrg	for (i = 0; i < xf86_config->num_output; i++) {
171918781e08Smrg		xf86OutputPtr output = xf86_config->output[i];
172018781e08Smrg		drmmode_output_private_ptr drmmode_output;
172118781e08Smrg
172218781e08Smrg		drmmode_output = output->driver_private;
172318781e08Smrg		if (drmmode_output->output_id == id)
172418781e08Smrg			return output;
172518781e08Smrg	}
172618781e08Smrg	return NULL;
172718781e08Smrg}
172818781e08Smrg
172918781e08Smrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
173018781e08Smrg{
173118781e08Smrg	char *conn;
173218781e08Smrg	char conn_id[5];
173318781e08Smrg	int id, len;
173418781e08Smrg	char *blob_data;
173518781e08Smrg
173618781e08Smrg	if (!path_blob)
173718781e08Smrg		return -1;
173818781e08Smrg
173918781e08Smrg	blob_data = path_blob->data;
174018781e08Smrg	/* we only handle MST paths for now */
174118781e08Smrg	if (strncmp(blob_data, "mst:", 4))
174218781e08Smrg		return -1;
174318781e08Smrg
174418781e08Smrg	conn = strchr(blob_data + 4, '-');
174518781e08Smrg	if (!conn)
174618781e08Smrg		return -1;
174718781e08Smrg	len = conn - (blob_data + 4);
174818781e08Smrg	if (len + 1 > 5)
174918781e08Smrg		return -1;
175018781e08Smrg	memcpy(conn_id, blob_data + 4, len);
175118781e08Smrg	conn_id[len] = '\0';
175218781e08Smrg	id = strtoul(conn_id, NULL, 10);
175318781e08Smrg
175418781e08Smrg	*conn_base_id = id;
175518781e08Smrg
175618781e08Smrg	*path = conn + 1;
175718781e08Smrg	return 0;
175818781e08Smrg}
175918781e08Smrg
1760de2362d3Smrgstatic void
176118781e08Smrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
176218781e08Smrg		    drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi)
176318781e08Smrg{
176418781e08Smrg	xf86OutputPtr output;
176518781e08Smrg	int conn_id;
176618781e08Smrg	char *extra_path;
176718781e08Smrg
176818781e08Smrg	output = NULL;
176918781e08Smrg	if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
177018781e08Smrg		output = find_output(pScrn, conn_id);
177118781e08Smrg	if (output) {
177218781e08Smrg		snprintf(name, 32, "%s-%s", output->name, extra_path);
177318781e08Smrg	} else {
177418781e08Smrg		if (koutput->connector_type >= NUM_OUTPUT_NAMES)
177518781e08Smrg			snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
177618781e08Smrg				 koutput->connector_type_id - 1);
177718781e08Smrg#ifdef RADEON_PIXMAP_SHARING
177818781e08Smrg		else if (pScrn->is_gpu)
177918781e08Smrg			snprintf(name, 32, "%s-%d-%d",
178018781e08Smrg				 output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1,
178118781e08Smrg				 koutput->connector_type_id - 1);
178218781e08Smrg#endif
178318781e08Smrg		else {
178418781e08Smrg			/* need to do smart conversion here for compat with non-kms ATI driver */
178518781e08Smrg			if (koutput->connector_type_id == 1) {
178618781e08Smrg				switch(koutput->connector_type) {
178718781e08Smrg				case DRM_MODE_CONNECTOR_DVII:
178818781e08Smrg				case DRM_MODE_CONNECTOR_DVID:
178918781e08Smrg				case DRM_MODE_CONNECTOR_DVIA:
179018781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
179118781e08Smrg					(*num_dvi)++;
179218781e08Smrg					break;
179318781e08Smrg				case DRM_MODE_CONNECTOR_HDMIA:
179418781e08Smrg				case DRM_MODE_CONNECTOR_HDMIB:
179518781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
179618781e08Smrg					(*num_hdmi)++;
179718781e08Smrg					break;
179818781e08Smrg				case DRM_MODE_CONNECTOR_VGA:
179918781e08Smrg				case DRM_MODE_CONNECTOR_DisplayPort:
180018781e08Smrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
180118781e08Smrg						 koutput->connector_type_id - 1);
180218781e08Smrg					break;
180318781e08Smrg				default:
180418781e08Smrg					snprintf(name, 32, "%s", output_names[koutput->connector_type]);
180518781e08Smrg					break;
180618781e08Smrg				}
180718781e08Smrg			} else {
180818781e08Smrg				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
180918781e08Smrg					 koutput->connector_type_id - 1);
181018781e08Smrg			}
181118781e08Smrg		}
181218781e08Smrg	}
181318781e08Smrg}
181418781e08Smrg
181518781e08Smrgstatic unsigned int
181618781e08Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic)
18170d16fef4Smrg{
181818781e08Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1819de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1820de2362d3Smrg	xf86OutputPtr output;
1821de2362d3Smrg	drmModeConnectorPtr koutput;
1822de2362d3Smrg	drmModeEncoderPtr *kencoders = NULL;
1823de2362d3Smrg	drmmode_output_private_ptr drmmode_output;
1824de2362d3Smrg	drmModePropertyPtr props;
182518781e08Smrg	drmModePropertyBlobPtr path_blob = NULL;
1826de2362d3Smrg	char name[32];
1827de2362d3Smrg	int i;
1828de2362d3Smrg	const char *s;
1829de2362d3Smrg
183018781e08Smrg	koutput = drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
1831de2362d3Smrg	if (!koutput)
183218781e08Smrg		return 0;
183318781e08Smrg
183418781e08Smrg	for (i = 0; i < koutput->count_props; i++) {
183518781e08Smrg		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
183618781e08Smrg		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
183718781e08Smrg			if (!strcmp(props->name, "PATH")) {
183818781e08Smrg				path_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
183918781e08Smrg				drmModeFreeProperty(props);
184018781e08Smrg				break;
184118781e08Smrg			}
184218781e08Smrg			drmModeFreeProperty(props);
184318781e08Smrg		}
184418781e08Smrg	}
1845de2362d3Smrg
1846de2362d3Smrg	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
1847de2362d3Smrg	if (!kencoders) {
1848de2362d3Smrg		goto out_free_encoders;
1849de2362d3Smrg	}
1850de2362d3Smrg
1851de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
1852de2362d3Smrg		kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
1853de2362d3Smrg		if (!kencoders[i]) {
1854de2362d3Smrg			goto out_free_encoders;
1855de2362d3Smrg		}
1856de2362d3Smrg	}
1857de2362d3Smrg
185818781e08Smrg	drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi);
185918781e08Smrg	if (path_blob)
186018781e08Smrg		drmModeFreePropertyBlob(path_blob);
186118781e08Smrg
186218781e08Smrg	if (path_blob && dynamic) {
186318781e08Smrg		/* See if we have an output with this name already
186418781e08Smrg		 * and hook stuff up.
186518781e08Smrg		 */
186618781e08Smrg		for (i = 0; i < xf86_config->num_output; i++) {
186718781e08Smrg			output = xf86_config->output[i];
186818781e08Smrg
186918781e08Smrg			if (strncmp(output->name, name, 32))
187018781e08Smrg				continue;
187118781e08Smrg
187218781e08Smrg			drmmode_output = output->driver_private;
187318781e08Smrg			drmmode_output->output_id = mode_res->connectors[num];
187418781e08Smrg			drmmode_output->mode_output = koutput;
187518781e08Smrg			for (i = 0; i < koutput->count_encoders; i++)
187618781e08Smrg				drmModeFreeEncoder(kencoders[i]);
187718781e08Smrg			free(kencoders);
187818781e08Smrg			return 0;
187918781e08Smrg		}
1880de2362d3Smrg	}
1881de2362d3Smrg
1882de2362d3Smrg	if (xf86IsEntityShared(pScrn->entityList[0])) {
1883de2362d3Smrg		if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
1884de2362d3Smrg			if (!RADEONZaphodStringMatches(pScrn, s, name))
1885de2362d3Smrg				goto out_free_encoders;
1886de2362d3Smrg		} else {
188718781e08Smrg			if (!info->IsSecondary && (num != 0))
1888de2362d3Smrg				goto out_free_encoders;
1889de2362d3Smrg			else if (info->IsSecondary && (num != 1))
1890de2362d3Smrg				goto out_free_encoders;
1891de2362d3Smrg		}
1892de2362d3Smrg	}
1893de2362d3Smrg
1894de2362d3Smrg	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
1895de2362d3Smrg	if (!output) {
1896de2362d3Smrg		goto out_free_encoders;
1897de2362d3Smrg	}
1898de2362d3Smrg
1899de2362d3Smrg	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
1900de2362d3Smrg	if (!drmmode_output) {
1901de2362d3Smrg		xf86OutputDestroy(output);
1902de2362d3Smrg		goto out_free_encoders;
1903de2362d3Smrg	}
1904de2362d3Smrg
190518781e08Smrg	drmmode_output->output_id = mode_res->connectors[num];
1906de2362d3Smrg	drmmode_output->mode_output = koutput;
1907de2362d3Smrg	drmmode_output->mode_encoders = kencoders;
1908de2362d3Smrg	drmmode_output->drmmode = drmmode;
1909de2362d3Smrg	output->mm_width = koutput->mmWidth;
1910de2362d3Smrg	output->mm_height = koutput->mmHeight;
1911de2362d3Smrg
1912de2362d3Smrg	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
1913de2362d3Smrg	output->interlaceAllowed = TRUE;
1914de2362d3Smrg	output->doubleScanAllowed = TRUE;
1915de2362d3Smrg	output->driver_private = drmmode_output;
1916de2362d3Smrg
1917de2362d3Smrg	output->possible_crtcs = 0xffffffff;
1918de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
1919de2362d3Smrg		output->possible_crtcs &= kencoders[i]->possible_crtcs;
1920de2362d3Smrg	}
1921de2362d3Smrg	/* work out the possible clones later */
1922de2362d3Smrg	output->possible_clones = 0;
1923de2362d3Smrg
1924de2362d3Smrg	for (i = 0; i < koutput->count_props; i++) {
1925de2362d3Smrg		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
1926de2362d3Smrg		if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
1927de2362d3Smrg			if (!strcmp(props->name, "DPMS")) {
1928de2362d3Smrg				drmmode_output->dpms_enum_id = koutput->props[i];
1929de2362d3Smrg				drmModeFreeProperty(props);
1930de2362d3Smrg				break;
1931de2362d3Smrg			}
1932de2362d3Smrg			drmModeFreeProperty(props);
1933de2362d3Smrg		}
1934de2362d3Smrg	}
1935de2362d3Smrg
193618781e08Smrg	if (dynamic) {
193718781e08Smrg		output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
193818781e08Smrg		drmmode_output_create_resources(output);
193918781e08Smrg	}
194018781e08Smrg
194118781e08Smrg	return 1;
1942de2362d3Smrgout_free_encoders:
1943de2362d3Smrg	if (kencoders){
1944de2362d3Smrg		for (i = 0; i < koutput->count_encoders; i++)
1945de2362d3Smrg			drmModeFreeEncoder(kencoders[i]);
1946de2362d3Smrg		free(kencoders);
1947de2362d3Smrg	}
1948de2362d3Smrg	drmModeFreeConnector(koutput);
194918781e08Smrg	return 0;
1950de2362d3Smrg}
1951de2362d3Smrg
1952de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
1953de2362d3Smrg{
1954de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout;
1955de2362d3Smrg	int i;
1956de2362d3Smrg	xf86OutputPtr clone_output;
1957de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1958de2362d3Smrg	int index_mask = 0;
1959de2362d3Smrg
1960de2362d3Smrg	if (drmmode_output->enc_clone_mask == 0)
1961de2362d3Smrg		return index_mask;
1962de2362d3Smrg
1963de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
1964de2362d3Smrg		clone_output = xf86_config->output[i];
1965de2362d3Smrg		clone_drmout = clone_output->driver_private;
1966de2362d3Smrg		if (output == clone_output)
1967de2362d3Smrg			continue;
1968de2362d3Smrg
1969de2362d3Smrg		if (clone_drmout->enc_mask == 0)
1970de2362d3Smrg			continue;
1971de2362d3Smrg		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
1972de2362d3Smrg			index_mask |= (1 << i);
1973de2362d3Smrg	}
1974de2362d3Smrg	return index_mask;
1975de2362d3Smrg}
1976de2362d3Smrg
1977de2362d3Smrg
1978de2362d3Smrgstatic void
197918781e08Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
1980de2362d3Smrg{
1981de2362d3Smrg	int i, j;
1982de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1983de2362d3Smrg
1984de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
1985de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
1986de2362d3Smrg		drmmode_output_private_ptr drmmode_output;
1987de2362d3Smrg
1988de2362d3Smrg		drmmode_output = output->driver_private;
1989de2362d3Smrg		drmmode_output->enc_clone_mask = 0xff;
1990de2362d3Smrg		/* and all the possible encoder clones for this output together */
1991de2362d3Smrg		for (j = 0; j < drmmode_output->mode_output->count_encoders; j++)
1992de2362d3Smrg		{
1993de2362d3Smrg			int k;
199418781e08Smrg			for (k = 0; k < mode_res->count_encoders; k++) {
199518781e08Smrg				if (mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id)
1996de2362d3Smrg					drmmode_output->enc_mask |= (1 << k);
1997de2362d3Smrg			}
1998de2362d3Smrg
1999de2362d3Smrg			drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones;
2000de2362d3Smrg		}
2001de2362d3Smrg	}
2002de2362d3Smrg
2003de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
2004de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
2005de2362d3Smrg		output->possible_clones = find_clones(scrn, output);
2006de2362d3Smrg	}
2007de2362d3Smrg}
2008de2362d3Smrg
2009de2362d3Smrg/* returns height alignment in pixels */
2010de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling)
2011de2362d3Smrg{
2012de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2013de2362d3Smrg	int height_align = 1;
2014de2362d3Smrg
2015de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2016de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
2017de2362d3Smrg			height_align =  info->num_channels * 8;
2018de2362d3Smrg		else if (tiling & RADEON_TILING_MICRO)
2019de2362d3Smrg			height_align = 8;
2020de2362d3Smrg		else
2021de2362d3Smrg			height_align = 8;
2022de2362d3Smrg	} else {
202318781e08Smrg		if (tiling & RADEON_TILING_MICRO_SQUARE)
202418781e08Smrg			height_align =  32;
202518781e08Smrg		else if (tiling)
2026de2362d3Smrg			height_align = 16;
2027de2362d3Smrg		else
2028de2362d3Smrg			height_align = 1;
2029de2362d3Smrg	}
2030de2362d3Smrg	return height_align;
2031de2362d3Smrg}
2032de2362d3Smrg
2033de2362d3Smrg/* returns pitch alignment in pixels */
2034de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
2035de2362d3Smrg{
2036de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2037de2362d3Smrg	int pitch_align = 1;
2038de2362d3Smrg
2039de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2040de2362d3Smrg		if (tiling & RADEON_TILING_MACRO) {
2041de2362d3Smrg			/* general surface requirements */
2042de2362d3Smrg			pitch_align = MAX(info->num_banks,
2043de2362d3Smrg					  (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8;
2044de2362d3Smrg			/* further restrictions for scanout */
2045de2362d3Smrg			pitch_align = MAX(info->num_banks * 8, pitch_align);
2046de2362d3Smrg		} else if (tiling & RADEON_TILING_MICRO) {
2047de2362d3Smrg			/* general surface requirements */
2048de2362d3Smrg			pitch_align = MAX(8, (info->group_bytes / (8 * bpe)));
2049de2362d3Smrg			/* further restrictions for scanout */
2050de2362d3Smrg			pitch_align = MAX(info->group_bytes / bpe, pitch_align);
2051de2362d3Smrg		} else {
2052de2362d3Smrg			if (info->have_tiling_info)
2053de2362d3Smrg				/* linear aligned requirements */
2054de2362d3Smrg				pitch_align = MAX(64, info->group_bytes / bpe);
2055de2362d3Smrg			else
2056de2362d3Smrg				/* default to 512 elements if we don't know the real
2057de2362d3Smrg				 * group size otherwise the kernel may reject the CS
2058de2362d3Smrg				 * if the group sizes don't match as the pitch won't
2059de2362d3Smrg				 * be aligned properly.
2060de2362d3Smrg				 */
2061de2362d3Smrg				pitch_align = 512;
2062de2362d3Smrg		}
2063de2362d3Smrg	} else {
2064de2362d3Smrg		/* general surface requirements */
2065de2362d3Smrg		if (tiling)
2066de2362d3Smrg			pitch_align = 256 / bpe;
2067de2362d3Smrg		else
2068de2362d3Smrg			pitch_align = 64;
2069de2362d3Smrg	}
2070de2362d3Smrg	return pitch_align;
2071de2362d3Smrg}
2072de2362d3Smrg
2073de2362d3Smrg/* returns base alignment in bytes */
2074de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
2075de2362d3Smrg{
2076de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2077de2362d3Smrg	int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling);
2078de2362d3Smrg	int height_align = drmmode_get_height_align(scrn, tiling);
2079de2362d3Smrg	int base_align = RADEON_GPU_PAGE_SIZE;
2080de2362d3Smrg
2081de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2082de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
2083de2362d3Smrg			base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe,
2084de2362d3Smrg					 pixel_align * bpe * height_align);
2085de2362d3Smrg		else {
2086de2362d3Smrg			if (info->have_tiling_info)
2087de2362d3Smrg				base_align = info->group_bytes;
2088de2362d3Smrg			else
2089de2362d3Smrg				/* default to 512 if we don't know the real
2090de2362d3Smrg				 * group size otherwise the kernel may reject the CS
2091de2362d3Smrg				 * if the group sizes don't match as the base won't
2092de2362d3Smrg				 * be aligned properly.
2093de2362d3Smrg				 */
2094de2362d3Smrg				base_align = 512;
2095de2362d3Smrg		}
2096de2362d3Smrg	}
2097de2362d3Smrg	return base_align;
2098de2362d3Smrg}
2099de2362d3Smrg
2100de2362d3Smrgstatic Bool
2101de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
2102de2362d3Smrg{
2103de2362d3Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2104de2362d3Smrg	drmmode_crtc_private_ptr
2105de2362d3Smrg		    drmmode_crtc = xf86_config->crtc[0]->driver_private;
2106de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
2107de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2108de2362d3Smrg	struct radeon_bo *old_front = NULL;
2109de2362d3Smrg	ScreenPtr   screen = xf86ScrnToScreen(scrn);
2110de2362d3Smrg	uint32_t    old_fb_id;
2111de2362d3Smrg	int	    i, pitch, old_width, old_height, old_pitch;
211218781e08Smrg	int aligned_height;
211318781e08Smrg	uint32_t screen_size;
211418781e08Smrg	int cpp = info->pixel_bytes;
2115de2362d3Smrg	struct radeon_bo *front_bo;
2116de2362d3Smrg	struct radeon_surface surface;
2117de2362d3Smrg	struct radeon_surface *psurface;
2118de2362d3Smrg	uint32_t tiling_flags = 0, base_align;
2119de2362d3Smrg	PixmapPtr ppix = screen->GetScreenPixmap(screen);
2120de2362d3Smrg	void *fb_shadow;
212118781e08Smrg	xRectangle rect;
212218781e08Smrg	Bool force;
212318781e08Smrg	GCPtr gc;
2124de2362d3Smrg
2125de2362d3Smrg	if (scrn->virtualX == width && scrn->virtualY == height)
2126de2362d3Smrg		return TRUE;
2127de2362d3Smrg
2128de2362d3Smrg	front_bo = info->front_bo;
2129de2362d3Smrg	radeon_cs_flush_indirect(scrn);
2130de2362d3Smrg
2131de2362d3Smrg	if (front_bo)
2132de2362d3Smrg		radeon_bo_wait(front_bo);
2133de2362d3Smrg
213418781e08Smrg	if (info->allowColorTiling && !info->shadow_primary) {
2135de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_R600) {
2136de2362d3Smrg			if (info->allowColorTiling2D) {
2137de2362d3Smrg				tiling_flags |= RADEON_TILING_MACRO;
2138de2362d3Smrg			} else {
2139de2362d3Smrg				tiling_flags |= RADEON_TILING_MICRO;
2140de2362d3Smrg			}
2141de2362d3Smrg		} else
2142de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
2143de2362d3Smrg	}
2144de2362d3Smrg
2145de2362d3Smrg	pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(scrn, cpp, tiling_flags)) * cpp;
214618781e08Smrg	aligned_height = RADEON_ALIGN(height, drmmode_get_height_align(scrn, tiling_flags));
214718781e08Smrg	screen_size = RADEON_ALIGN(pitch * aligned_height, RADEON_GPU_PAGE_SIZE);
2148de2362d3Smrg	base_align = 4096;
2149de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
2150de2362d3Smrg		memset(&surface, 0, sizeof(struct radeon_surface));
2151de2362d3Smrg		surface.npix_x = width;
2152de2362d3Smrg		surface.npix_y = height;
2153de2362d3Smrg		surface.npix_z = 1;
2154de2362d3Smrg		surface.blk_w = 1;
2155de2362d3Smrg		surface.blk_h = 1;
2156de2362d3Smrg		surface.blk_d = 1;
2157de2362d3Smrg		surface.array_size = 1;
2158de2362d3Smrg		surface.last_level = 0;
2159de2362d3Smrg		surface.bpe = cpp;
2160de2362d3Smrg		surface.nsamples = 1;
2161de2362d3Smrg		surface.flags = RADEON_SURF_SCANOUT;
216218781e08Smrg		/* we are requiring a recent enough libdrm version */
216318781e08Smrg		surface.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX;
2164de2362d3Smrg		surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
2165de2362d3Smrg		surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE);
2166de2362d3Smrg		if (tiling_flags & RADEON_TILING_MICRO) {
2167de2362d3Smrg			surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
2168de2362d3Smrg			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
2169de2362d3Smrg		}
2170de2362d3Smrg		if (tiling_flags & RADEON_TILING_MACRO) {
2171de2362d3Smrg			surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
2172de2362d3Smrg			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
2173de2362d3Smrg		}
2174de2362d3Smrg		if (radeon_surface_best(info->surf_man, &surface)) {
2175de2362d3Smrg			return FALSE;
2176de2362d3Smrg		}
2177de2362d3Smrg		if (radeon_surface_init(info->surf_man, &surface)) {
2178de2362d3Smrg			return FALSE;
2179de2362d3Smrg		}
2180de2362d3Smrg		screen_size = surface.bo_size;
2181de2362d3Smrg		base_align = surface.bo_alignment;
2182de2362d3Smrg		pitch = surface.level[0].pitch_bytes;
2183de2362d3Smrg		tiling_flags = 0;
2184de2362d3Smrg		switch (surface.level[0].mode) {
2185de2362d3Smrg		case RADEON_SURF_MODE_2D:
2186de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
2187de2362d3Smrg			tiling_flags |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT;
2188de2362d3Smrg			tiling_flags |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT;
2189de2362d3Smrg			tiling_flags |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT;
219018781e08Smrg			if (surface.tile_split)
219118781e08Smrg				tiling_flags |= eg_tile_split(surface.tile_split)
219218781e08Smrg						<< RADEON_TILING_EG_TILE_SPLIT_SHIFT;
2193de2362d3Smrg			break;
2194de2362d3Smrg		case RADEON_SURF_MODE_1D:
2195de2362d3Smrg			tiling_flags |= RADEON_TILING_MICRO;
2196de2362d3Smrg			break;
2197de2362d3Smrg		default:
2198de2362d3Smrg			break;
2199de2362d3Smrg		}
2200de2362d3Smrg		info->front_surface = surface;
2201de2362d3Smrg	}
2202de2362d3Smrg
2203de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
2204de2362d3Smrg		   "Allocate new frame buffer %dx%d stride %d\n",
2205de2362d3Smrg		   width, height, pitch / cpp);
2206de2362d3Smrg
2207de2362d3Smrg	old_width = scrn->virtualX;
2208de2362d3Smrg	old_height = scrn->virtualY;
2209de2362d3Smrg	old_pitch = scrn->displayWidth;
2210de2362d3Smrg	old_fb_id = drmmode->fb_id;
221118781e08Smrg	drmmode->fb_id = 0;
2212de2362d3Smrg	old_front = info->front_bo;
2213de2362d3Smrg
2214de2362d3Smrg	scrn->virtualX = width;
2215de2362d3Smrg	scrn->virtualY = height;
2216de2362d3Smrg	scrn->displayWidth = pitch / cpp;
2217de2362d3Smrg
221818781e08Smrg	info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align,
221918781e08Smrg					info->shadow_primary ?
222018781e08Smrg					RADEON_GEM_DOMAIN_GTT :
222118781e08Smrg					RADEON_GEM_DOMAIN_VRAM,
222218781e08Smrg					tiling_flags ? RADEON_GEM_NO_CPU_ACCESS : 0);
2223de2362d3Smrg	if (!info->front_bo)
2224de2362d3Smrg		goto fail;
2225de2362d3Smrg
2226de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
2227de2362d3Smrg	switch (cpp) {
2228de2362d3Smrg	case 4:
2229de2362d3Smrg	    tiling_flags |= RADEON_TILING_SWAP_32BIT;
2230de2362d3Smrg	    break;
2231de2362d3Smrg	case 2:
2232de2362d3Smrg	    tiling_flags |= RADEON_TILING_SWAP_16BIT;
2233de2362d3Smrg	    break;
2234de2362d3Smrg	}
223518781e08Smrg	if (info->ChipFamily < CHIP_FAMILY_R600 &&
223618781e08Smrg	    info->r600_shadow_fb && tiling_flags)
223718781e08Smrg	    tiling_flags |= RADEON_TILING_SURFACE;
2238de2362d3Smrg#endif
2239de2362d3Smrg	if (tiling_flags)
2240de2362d3Smrg	    radeon_bo_set_tiling(info->front_bo, tiling_flags, pitch);
2241de2362d3Smrg
2242de2362d3Smrg	if (!info->r600_shadow_fb) {
2243de2362d3Smrg		psurface = radeon_get_pixmap_surface(ppix);
2244de2362d3Smrg		*psurface = info->front_surface;
2245de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
2246de2362d3Smrg					   width, height, -1, -1, pitch, NULL);
2247de2362d3Smrg	} else {
2248de2362d3Smrg		if (radeon_bo_map(info->front_bo, 1))
2249de2362d3Smrg			goto fail;
2250de2362d3Smrg		fb_shadow = calloc(1, screen_size);
2251de2362d3Smrg		if (fb_shadow == NULL)
2252de2362d3Smrg			goto fail;
2253de2362d3Smrg		free(info->fb_shadow);
2254de2362d3Smrg		info->fb_shadow = fb_shadow;
2255de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
2256de2362d3Smrg					   width, height, -1, -1, pitch,
2257de2362d3Smrg					   info->fb_shadow);
2258de2362d3Smrg	}
225918781e08Smrg
226018781e08Smrg	if (info->use_glamor)
226118781e08Smrg		radeon_glamor_create_screen_resources(scrn->pScreen);
226218781e08Smrg
226318781e08Smrg	if (!info->r600_shadow_fb) {
226418781e08Smrg		if (!radeon_set_pixmap_bo(ppix, info->front_bo))
226518781e08Smrg			goto fail;
226618781e08Smrg	}
226718781e08Smrg
226818781e08Smrg	/* Clear new buffer */
226918781e08Smrg	gc = GetScratchGC(ppix->drawable.depth, scrn->pScreen);
227018781e08Smrg	force = info->accel_state->force;
227118781e08Smrg	info->accel_state->force = TRUE;
227218781e08Smrg	ValidateGC(&ppix->drawable, gc);
227318781e08Smrg	rect.x = 0;
227418781e08Smrg	rect.y = 0;
227518781e08Smrg	rect.width = width;
227618781e08Smrg	rect.height = height;
227718781e08Smrg	(*gc->ops->PolyFillRect)(&ppix->drawable, gc, 1, &rect);
227818781e08Smrg	FreeScratchGC(gc);
227918781e08Smrg	info->accel_state->force = force;
228018781e08Smrg	radeon_cs_flush_indirect(scrn);
228118781e08Smrg	radeon_bo_wait(info->front_bo);
22820d16fef4Smrg
2283de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
2284de2362d3Smrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
2285de2362d3Smrg
2286de2362d3Smrg		if (!crtc->enabled)
2287de2362d3Smrg			continue;
2288de2362d3Smrg
2289de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode,
2290de2362d3Smrg				       crtc->rotation, crtc->x, crtc->y);
2291de2362d3Smrg	}
2292de2362d3Smrg
2293de2362d3Smrg	if (old_fb_id)
2294de2362d3Smrg		drmModeRmFB(drmmode->fd, old_fb_id);
2295de2362d3Smrg	if (old_front)
2296de2362d3Smrg		radeon_bo_unref(old_front);
2297de2362d3Smrg
2298de2362d3Smrg	radeon_kms_update_vram_limit(scrn, screen_size);
2299de2362d3Smrg	return TRUE;
2300de2362d3Smrg
2301de2362d3Smrg fail:
2302de2362d3Smrg	if (info->front_bo)
2303de2362d3Smrg		radeon_bo_unref(info->front_bo);
2304de2362d3Smrg	info->front_bo = old_front;
2305de2362d3Smrg	scrn->virtualX = old_width;
2306de2362d3Smrg	scrn->virtualY = old_height;
2307de2362d3Smrg	scrn->displayWidth = old_pitch;
2308de2362d3Smrg	drmmode->fb_id = old_fb_id;
2309de2362d3Smrg
2310de2362d3Smrg	return FALSE;
2311de2362d3Smrg}
2312de2362d3Smrg
2313de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
2314de2362d3Smrg	drmmode_xf86crtc_resize
2315de2362d3Smrg};
2316de2362d3Smrg
231718781e08Smrgvoid
231818781e08Smrgdrmmode_clear_pending_flip(xf86CrtcPtr crtc)
231918781e08Smrg{
232018781e08Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
232118781e08Smrg
232218781e08Smrg	drmmode_crtc->flip_pending = FALSE;
232318781e08Smrg
232418781e08Smrg	if (!crtc->enabled ||
232518781e08Smrg	    (drmmode_crtc->pending_dpms_mode != DPMSModeOn &&
232618781e08Smrg	     drmmode_crtc->dpms_mode != drmmode_crtc->pending_dpms_mode)) {
232718781e08Smrg		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
232818781e08Smrg		int o;
232918781e08Smrg
233018781e08Smrg		for (o = 0; o < xf86_config->num_output; o++) {
233118781e08Smrg			xf86OutputPtr output = xf86_config->output[o];
233218781e08Smrg
233318781e08Smrg			if (output->crtc != crtc)
233418781e08Smrg				continue;
233518781e08Smrg
233618781e08Smrg			drmmode_output_dpms(output, drmmode_crtc->pending_dpms_mode);
233718781e08Smrg		}
233818781e08Smrg
233918781e08Smrg		drmmode_crtc_dpms(crtc, drmmode_crtc->pending_dpms_mode);
234018781e08Smrg	}
234118781e08Smrg
234218781e08Smrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
234318781e08Smrg				     &drmmode_crtc->scanout_destroy[0]);
234418781e08Smrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
234518781e08Smrg				     &drmmode_crtc->scanout_destroy[1]);
234618781e08Smrg}
234718781e08Smrg
2348de2362d3Smrgstatic void
234918781e08Smrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
2350de2362d3Smrg{
235118781e08Smrg	drmmode_flipdata_ptr flipdata = event_data;
235218781e08Smrg
235318781e08Smrg	if (--flipdata->flip_count == 0) {
235418781e08Smrg		if (!flipdata->fe_crtc)
235518781e08Smrg			flipdata->fe_crtc = crtc;
235618781e08Smrg		flipdata->abort(flipdata->fe_crtc, flipdata->event_data);
235718781e08Smrg		free(flipdata);
235818781e08Smrg	}
235918781e08Smrg
236018781e08Smrg	drmmode_clear_pending_flip(crtc);
2361de2362d3Smrg}
2362de2362d3Smrg
2363de2362d3Smrgstatic void
236418781e08Smrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
2365de2362d3Smrg{
236618781e08Smrg	RADEONInfoPtr info = RADEONPTR(crtc->scrn);
236718781e08Smrg	drmmode_flipdata_ptr flipdata = event_data;
2368de2362d3Smrg
2369de2362d3Smrg	/* Is this the event whose info shall be delivered to higher level? */
237018781e08Smrg	if (crtc == flipdata->fe_crtc) {
2371de2362d3Smrg		/* Yes: Cache msc, ust for later delivery. */
2372de2362d3Smrg		flipdata->fe_frame = frame;
237318781e08Smrg		flipdata->fe_usec = usec;
2374de2362d3Smrg	}
2375de2362d3Smrg
237618781e08Smrg	if (--flipdata->flip_count == 0) {
237718781e08Smrg		/* Deliver MSC & UST from reference/current CRTC to flip event
237818781e08Smrg		 * handler
237918781e08Smrg		 */
238018781e08Smrg		if (flipdata->fe_crtc)
238118781e08Smrg			flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame,
238218781e08Smrg					  flipdata->fe_usec, flipdata->event_data);
238318781e08Smrg		else
238418781e08Smrg			flipdata->handler(crtc, frame, usec, flipdata->event_data);
2385de2362d3Smrg
238618781e08Smrg		/* Release framebuffer */
238718781e08Smrg		drmModeRmFB(info->drmmode.fd, flipdata->old_fb_id);
23887821949aSmrg
238918781e08Smrg		free(flipdata);
239018781e08Smrg	}
2391de2362d3Smrg
239218781e08Smrg	drmmode_clear_pending_flip(crtc);
2393de2362d3Smrg}
2394de2362d3Smrg
2395de2362d3Smrg
239618781e08Smrg#if HAVE_NOTIFY_FD
239718781e08Smrgstatic void
239818781e08Smrgdrm_notify_fd(int fd, int ready, void *data)
239918781e08Smrg#else
2400de2362d3Smrgstatic void
2401de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p)
240218781e08Smrg#endif
2403de2362d3Smrg{
2404de2362d3Smrg	drmmode_ptr drmmode = data;
240518781e08Smrg#if !HAVE_NOTIFY_FD
2406de2362d3Smrg	fd_set *read_mask = p;
2407de2362d3Smrg
240818781e08Smrg	if (err >= 0 && FD_ISSET(drmmode->fd, read_mask))
240918781e08Smrg#endif
241018781e08Smrg	{
2411de2362d3Smrg		drmHandleEvent(drmmode->fd, &drmmode->event_context);
2412de2362d3Smrg	}
2413de2362d3Smrg}
2414de2362d3Smrg
24153ed65abbSmrgstatic Bool drmmode_probe_page_flip_target(drmmode_ptr drmmode)
24163ed65abbSmrg{
24173ed65abbSmrg#ifdef DRM_CAP_PAGE_FLIP_TARGET
24183ed65abbSmrg	uint64_t cap_value;
24193ed65abbSmrg
24203ed65abbSmrg	return drmGetCap(drmmode->fd, DRM_CAP_PAGE_FLIP_TARGET,
24213ed65abbSmrg			 &cap_value) == 0 && cap_value != 0;
24223ed65abbSmrg#else
24233ed65abbSmrg	return FALSE;
24243ed65abbSmrg#endif
24253ed65abbSmrg}
24263ed65abbSmrg
24273ed65abbSmrgstatic int
24283ed65abbSmrgdrmmode_page_flip(drmmode_crtc_private_ptr drmmode_crtc, int fb_id,
24293ed65abbSmrg		  uint32_t flags, uintptr_t drm_queue_seq)
24303ed65abbSmrg{
24313ed65abbSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
24323ed65abbSmrg
24333ed65abbSmrg	flags |= DRM_MODE_PAGE_FLIP_EVENT;
24343ed65abbSmrg	return drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
24353ed65abbSmrg			       fb_id, flags, (void*)drm_queue_seq);
24363ed65abbSmrg}
24373ed65abbSmrg
24383ed65abbSmrgint
24393ed65abbSmrgdrmmode_page_flip_target_absolute(RADEONEntPtr pRADEONEnt,
24403ed65abbSmrg				  drmmode_crtc_private_ptr drmmode_crtc,
24413ed65abbSmrg				  int fb_id, uint32_t flags,
24423ed65abbSmrg				  uintptr_t drm_queue_seq, uint32_t target_msc)
24433ed65abbSmrg{
24443ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET
24453ed65abbSmrg	if (pRADEONEnt->has_page_flip_target) {
24463ed65abbSmrg		drmmode_ptr drmmode = drmmode_crtc->drmmode;
24473ed65abbSmrg
24483ed65abbSmrg		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE;
24493ed65abbSmrg		return drmModePageFlipTarget(drmmode->fd,
24503ed65abbSmrg					     drmmode_crtc->mode_crtc->crtc_id,
24513ed65abbSmrg					     fb_id, flags, (void*)drm_queue_seq,
24523ed65abbSmrg					     target_msc);
24533ed65abbSmrg	}
24543ed65abbSmrg#endif
24553ed65abbSmrg
24563ed65abbSmrg	return drmmode_page_flip(drmmode_crtc, fb_id, flags, drm_queue_seq);
24573ed65abbSmrg}
24583ed65abbSmrg
24593ed65abbSmrgint
24603ed65abbSmrgdrmmode_page_flip_target_relative(RADEONEntPtr pRADEONEnt,
24613ed65abbSmrg				  drmmode_crtc_private_ptr drmmode_crtc,
24623ed65abbSmrg				  int fb_id, uint32_t flags,
24633ed65abbSmrg				  uintptr_t drm_queue_seq, uint32_t target_msc)
24643ed65abbSmrg{
24653ed65abbSmrg#ifdef DRM_MODE_PAGE_FLIP_TARGET
24663ed65abbSmrg	if (pRADEONEnt->has_page_flip_target) {
24673ed65abbSmrg		drmmode_ptr drmmode = drmmode_crtc->drmmode;
24683ed65abbSmrg
24693ed65abbSmrg		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE;
24703ed65abbSmrg		return drmModePageFlipTarget(drmmode->fd,
24713ed65abbSmrg					     drmmode_crtc->mode_crtc->crtc_id,
24723ed65abbSmrg					     fb_id, flags, (void*)drm_queue_seq,
24733ed65abbSmrg					     target_msc);
24743ed65abbSmrg	}
24753ed65abbSmrg#endif
24763ed65abbSmrg
24773ed65abbSmrg	return drmmode_page_flip(drmmode_crtc, fb_id, flags, drm_queue_seq);
24783ed65abbSmrg}
24793ed65abbSmrg
2480de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
2481de2362d3Smrg{
248218781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
248318781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
2484de2362d3Smrg	int i, num_dvi = 0, num_hdmi = 0;
248518781e08Smrg	drmModeResPtr mode_res;
248618781e08Smrg	unsigned int crtcs_needed = 0;
248718781e08Smrg#ifdef RADEON_PIXMAP_SHARING
248818781e08Smrg	char *bus_id_string, *provider_name;
248918781e08Smrg#endif
2490de2362d3Smrg
2491de2362d3Smrg	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
2492de2362d3Smrg
2493de2362d3Smrg	drmmode->scrn = pScrn;
2494de2362d3Smrg	drmmode->cpp = cpp;
249518781e08Smrg	mode_res = drmModeGetResources(drmmode->fd);
249618781e08Smrg	if (!mode_res)
2497de2362d3Smrg		return FALSE;
2498de2362d3Smrg
249918781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
250018781e08Smrg		       "Initializing outputs ...\n");
250118781e08Smrg	for (i = 0; i < mode_res->count_connectors; i++)
250218781e08Smrg		crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res,
250318781e08Smrg						    i, &num_dvi, &num_hdmi, 0);
250418781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
250518781e08Smrg		       "%d crtcs needed for screen.\n", crtcs_needed);
250618781e08Smrg
250718781e08Smrg	if (info->r600_shadow_fb) {
250818781e08Smrg		/* Rotation requires hardware acceleration */
250918781e08Smrg		drmmode_crtc_funcs.shadow_allocate = NULL;
251018781e08Smrg		drmmode_crtc_funcs.shadow_create = NULL;
251118781e08Smrg		drmmode_crtc_funcs.shadow_destroy = NULL;
251218781e08Smrg	}
251318781e08Smrg
251418781e08Smrg	drmmode->count_crtcs = mode_res->count_crtcs;
251518781e08Smrg	xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width, mode_res->max_height);
251618781e08Smrg
251718781e08Smrg	for (i = 0; i < mode_res->count_crtcs; i++)
251818781e08Smrg		if (!xf86IsEntityShared(pScrn->entityList[0]) ||
251918781e08Smrg		    (crtcs_needed && !(pRADEONEnt->assigned_crtcs & (1 << i))))
252018781e08Smrg			crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
2521de2362d3Smrg
252218781e08Smrg	/* All ZaphodHeads outputs provided with matching crtcs? */
252318781e08Smrg	if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
252418781e08Smrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
252518781e08Smrg			   "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
252618781e08Smrg			   crtcs_needed);
2527de2362d3Smrg
2528de2362d3Smrg	/* workout clones */
252918781e08Smrg	drmmode_clones_init(pScrn, drmmode, mode_res);
253018781e08Smrg
253118781e08Smrg#ifdef RADEON_PIXMAP_SHARING
253218781e08Smrg	bus_id_string = DRICreatePCIBusID(info->PciInfo);
253318781e08Smrg	XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string);
253418781e08Smrg	free(bus_id_string);
253518781e08Smrg	xf86ProviderSetup(pScrn, NULL, provider_name);
253618781e08Smrg	free(provider_name);
253718781e08Smrg#endif
2538de2362d3Smrg
2539de2362d3Smrg	xf86InitialConfiguration(pScrn, TRUE);
2540de2362d3Smrg
2541de2362d3Smrg	drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
254218781e08Smrg	drmmode->event_context.vblank_handler = radeon_drm_queue_handler;
254318781e08Smrg	drmmode->event_context.page_flip_handler = radeon_drm_queue_handler;
2544de2362d3Smrg
25453ed65abbSmrg	pRADEONEnt->has_page_flip_target = drmmode_probe_page_flip_target(drmmode);
25463ed65abbSmrg
254718781e08Smrg	drmModeFreeResources(mode_res);
2548de2362d3Smrg	return TRUE;
2549de2362d3Smrg}
2550de2362d3Smrg
2551de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
2552de2362d3Smrg{
2553de2362d3Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
2554de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
2555de2362d3Smrg
255618781e08Smrg	if (info->dri2.pKernelDRMVersion->version_minor < 4)
255718781e08Smrg		return;
255818781e08Smrg
255918781e08Smrg	info->drmmode_inited = TRUE;
256018781e08Smrg	if (pRADEONEnt->fd_wakeup_registered != serverGeneration) {
256118781e08Smrg#if HAVE_NOTIFY_FD
256218781e08Smrg		SetNotifyFd(drmmode->fd, drm_notify_fd, X_NOTIFY_READ, drmmode);
256318781e08Smrg#else
2564de2362d3Smrg		AddGeneralSocket(drmmode->fd);
2565de2362d3Smrg		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
2566de2362d3Smrg				drm_wakeup_handler, drmmode);
256718781e08Smrg#endif
2568de2362d3Smrg		pRADEONEnt->fd_wakeup_registered = serverGeneration;
256918781e08Smrg		pRADEONEnt->fd_wakeup_ref = 1;
257018781e08Smrg	} else
257118781e08Smrg		pRADEONEnt->fd_wakeup_ref++;
257218781e08Smrg}
257318781e08Smrg
257418781e08Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
257518781e08Smrg{
257618781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
257718781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
257818781e08Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
257918781e08Smrg	int c;
258018781e08Smrg
258118781e08Smrg	if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited)
258218781e08Smrg		return;
258318781e08Smrg
258418781e08Smrg	if (pRADEONEnt->fd_wakeup_registered == serverGeneration &&
258518781e08Smrg	    !--pRADEONEnt->fd_wakeup_ref) {
258618781e08Smrg#if HAVE_NOTIFY_FD
258718781e08Smrg		RemoveNotifyFd(drmmode->fd);
258818781e08Smrg#else
258918781e08Smrg		RemoveGeneralSocket(drmmode->fd);
259018781e08Smrg		RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
259118781e08Smrg				drm_wakeup_handler, drmmode);
259218781e08Smrg#endif
259318781e08Smrg	}
259418781e08Smrg
25953ed65abbSmrg	for (c = 0; c < config->num_crtc; c++)
25963ed65abbSmrg		drmmode_crtc_scanout_free(config->crtc[c]->driver_private);
2597de2362d3Smrg}
2598de2362d3Smrg
259918781e08Smrg
2600de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr)
2601de2362d3Smrg{
2602de2362d3Smrg	drmmode->bufmgr = bufmgr;
2603de2362d3Smrg	return TRUE;
2604de2362d3Smrg}
2605de2362d3Smrg
2606de2362d3Smrg
2607de2362d3Smrg
2608de2362d3Smrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo)
2609de2362d3Smrg{
2610de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2611de2362d3Smrg	xf86CrtcPtr crtc = xf86_config->crtc[id];
2612de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2613de2362d3Smrg
2614de2362d3Smrg	drmmode_crtc->cursor_bo = bo;
2615de2362d3Smrg}
2616de2362d3Smrg
2617de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
2618de2362d3Smrg{
2619de2362d3Smrg	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
2620de2362d3Smrg	xf86OutputPtr  output = config->output[config->compat_output];
2621de2362d3Smrg	xf86CrtcPtr	crtc = output->crtc;
2622de2362d3Smrg
2623de2362d3Smrg	if (crtc && crtc->enabled) {
2624de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
2625de2362d3Smrg				       x, y);
2626de2362d3Smrg	}
2627de2362d3Smrg}
2628de2362d3Smrg
262918781e08SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
263018781e08Smrg			       Bool set_hw)
2631de2362d3Smrg{
2632de2362d3Smrg	xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
2633de2362d3Smrg	int c;
2634de2362d3Smrg
2635de2362d3Smrg	for (c = 0; c < config->num_crtc; c++) {
2636de2362d3Smrg		xf86CrtcPtr	crtc = config->crtc[c];
2637de2362d3Smrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2638de2362d3Smrg		xf86OutputPtr	output = NULL;
2639de2362d3Smrg		int		o;
2640de2362d3Smrg
2641de2362d3Smrg		/* Skip disabled CRTCs */
2642de2362d3Smrg		if (!crtc->enabled) {
264318781e08Smrg			if (set_hw) {
264418781e08Smrg				drmmode_do_crtc_dpms(crtc, DPMSModeOff);
264518781e08Smrg				drmModeSetCrtc(drmmode->fd,
264618781e08Smrg					       drmmode_crtc->mode_crtc->crtc_id,
264718781e08Smrg					       0, 0, 0, NULL, 0, NULL);
264818781e08Smrg			}
2649de2362d3Smrg			continue;
2650de2362d3Smrg		}
2651de2362d3Smrg
2652de2362d3Smrg		if (config->output[config->compat_output]->crtc == crtc)
2653de2362d3Smrg			output = config->output[config->compat_output];
2654de2362d3Smrg		else
2655de2362d3Smrg		{
2656de2362d3Smrg			for (o = 0; o < config->num_output; o++)
2657de2362d3Smrg				if (config->output[o]->crtc == crtc)
2658de2362d3Smrg				{
2659de2362d3Smrg					output = config->output[o];
2660de2362d3Smrg					break;
2661de2362d3Smrg				}
2662de2362d3Smrg		}
2663de2362d3Smrg		/* paranoia */
2664de2362d3Smrg		if (!output)
2665de2362d3Smrg			continue;
2666de2362d3Smrg
2667de2362d3Smrg		/* Mark that we'll need to re-set the mode for sure */
2668de2362d3Smrg		memset(&crtc->mode, 0, sizeof(crtc->mode));
2669de2362d3Smrg		if (!crtc->desiredMode.CrtcHDisplay)
2670de2362d3Smrg		{
2671de2362d3Smrg			DisplayModePtr  mode = xf86OutputFindClosestMode (output, pScrn->currentMode);
2672de2362d3Smrg
2673de2362d3Smrg			if (!mode)
2674de2362d3Smrg				return FALSE;
2675de2362d3Smrg			crtc->desiredMode = *mode;
2676de2362d3Smrg			crtc->desiredRotation = RR_Rotate_0;
2677de2362d3Smrg			crtc->desiredX = 0;
2678de2362d3Smrg			crtc->desiredY = 0;
2679de2362d3Smrg		}
2680de2362d3Smrg
268118781e08Smrg		if (set_hw) {
268218781e08Smrg			if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
268318781e08Smrg							 crtc->desiredX, crtc->desiredY))
268418781e08Smrg				return FALSE;
268518781e08Smrg		} else {
268618781e08Smrg			crtc->mode = crtc->desiredMode;
268718781e08Smrg			crtc->rotation = crtc->desiredRotation;
268818781e08Smrg			crtc->x = crtc->desiredX;
268918781e08Smrg			crtc->y = crtc->desiredY;
269018781e08Smrg			if (!drmmode_handle_transform(crtc))
269118781e08Smrg				return FALSE;
269218781e08Smrg		}
2693de2362d3Smrg	}
2694de2362d3Smrg	return TRUE;
2695de2362d3Smrg}
2696de2362d3Smrg
269718781e08SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
2698de2362d3Smrg{
2699de2362d3Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2700de2362d3Smrg
270118781e08Smrg    if (xf86_config->num_crtc) {
270218781e08Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
270318781e08Smrg		       "Initializing kms color map\n");
270418781e08Smrg	if (!miCreateDefColormap(pScreen))
270518781e08Smrg	    return FALSE;
270618781e08Smrg	/* all radeons support 10 bit CLUTs */
270718781e08Smrg	if (!xf86HandleColormaps(pScreen, 256, 10,
270818781e08Smrg				 NULL, NULL,
270918781e08Smrg				 CMAP_PALETTED_TRUECOLOR
271018781e08Smrg#if 0 /* This option messes up text mode! (eich@suse.de) */
271118781e08Smrg				 | CMAP_LOAD_EVEN_IF_OFFSCREEN
271218781e08Smrg#endif
271318781e08Smrg				 | CMAP_RELOAD_ON_MODE_SWITCH))
271418781e08Smrg	    return FALSE;
271518781e08Smrg    }
271618781e08Smrg    return TRUE;
271718781e08Smrg}
27187314432eSmrg
271918781e08Smrgstatic Bool
272018781e08Smrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi,
272118781e08Smrg		    int *num_hdmi)
272218781e08Smrg{
272318781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
272418781e08Smrg	int i;
27257314432eSmrg
272618781e08Smrg	for (i = 0; i < config->num_output; i++) {
272718781e08Smrg		xf86OutputPtr output = config->output[i];
272818781e08Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
272918781e08Smrg
273018781e08Smrg		if (drmmode_output->output_id == output_id) {
273118781e08Smrg			switch(drmmode_output->mode_output->connector_type) {
273218781e08Smrg			case DRM_MODE_CONNECTOR_DVII:
273318781e08Smrg			case DRM_MODE_CONNECTOR_DVID:
273418781e08Smrg			case DRM_MODE_CONNECTOR_DVIA:
273518781e08Smrg				(*num_dvi)++;
273618781e08Smrg				break;
273718781e08Smrg			case DRM_MODE_CONNECTOR_HDMIA:
273818781e08Smrg			case DRM_MODE_CONNECTOR_HDMIB:
273918781e08Smrg				(*num_hdmi)++;
274018781e08Smrg				break;
274118781e08Smrg			}
274218781e08Smrg
274318781e08Smrg			return TRUE;
274418781e08Smrg		}
274518781e08Smrg	}
274618781e08Smrg
274718781e08Smrg	return FALSE;
27487314432eSmrg}
27497314432eSmrg
275018781e08Smrgvoid
275118781e08Smrgradeon_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode)
27520d16fef4Smrg{
275318781e08Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
275418781e08Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
275518781e08Smrg	drmModeResPtr mode_res;
275618781e08Smrg	int i, j;
275718781e08Smrg	Bool found;
275818781e08Smrg	Bool changed = FALSE;
275918781e08Smrg	int num_dvi = 0, num_hdmi = 0;
276018781e08Smrg
276118781e08Smrg	mode_res = drmModeGetResources(drmmode->fd);
276218781e08Smrg	if (!mode_res)
276318781e08Smrg		goto out;
276418781e08Smrg
276518781e08Smrgrestart_destroy:
276618781e08Smrg	for (i = 0; i < config->num_output; i++) {
276718781e08Smrg		xf86OutputPtr output = config->output[i];
276818781e08Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
276918781e08Smrg		found = FALSE;
277018781e08Smrg		for (j = 0; j < mode_res->count_connectors; j++) {
277118781e08Smrg			if (mode_res->connectors[j] == drmmode_output->output_id) {
277218781e08Smrg				found = TRUE;
277318781e08Smrg				break;
277418781e08Smrg			}
277518781e08Smrg		}
277618781e08Smrg		if (found)
277718781e08Smrg			continue;
277818781e08Smrg
277918781e08Smrg		drmModeFreeConnector(drmmode_output->mode_output);
278018781e08Smrg		drmmode_output->mode_output = NULL;
278118781e08Smrg		drmmode_output->output_id = -1;
278218781e08Smrg
278318781e08Smrg		changed = TRUE;
278418781e08Smrg		if (drmmode->delete_dp_12_displays) {
278518781e08Smrg			RROutputDestroy(output->randr_output);
278618781e08Smrg			xf86OutputDestroy(output);
278718781e08Smrg			goto restart_destroy;
278818781e08Smrg		}
278918781e08Smrg	}
279018781e08Smrg
279118781e08Smrg	/* find new output ids we don't have outputs for */
279218781e08Smrg	for (i = 0; i < mode_res->count_connectors; i++) {
279318781e08Smrg		if (drmmode_find_output(pRADEONEnt->primary_scrn,
279418781e08Smrg					mode_res->connectors[i],
279518781e08Smrg					&num_dvi, &num_hdmi) ||
279618781e08Smrg		    (pRADEONEnt->secondary_scrn &&
279718781e08Smrg		     drmmode_find_output(pRADEONEnt->secondary_scrn,
279818781e08Smrg					 mode_res->connectors[i],
279918781e08Smrg					 &num_dvi, &num_hdmi)))
280018781e08Smrg			continue;
280118781e08Smrg
280218781e08Smrg		if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi,
280318781e08Smrg					&num_hdmi, 1) != 0)
280418781e08Smrg			changed = TRUE;
280518781e08Smrg	}
280618781e08Smrg
280718781e08Smrg	if (changed && dixPrivateKeyRegistered(rrPrivKey)) {
280818781e08Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0)
280918781e08Smrg		RRSetChanged(xf86ScrnToScreen(scrn));
281018781e08Smrg#else
281118781e08Smrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen);
281218781e08Smrg		rrScrPriv->changed = TRUE;
28130d16fef4Smrg#endif
281418781e08Smrg		RRTellChanged(xf86ScrnToScreen(scrn));
281518781e08Smrg	}
28167821949aSmrg
281718781e08Smrg	drmModeFreeResources(mode_res);
281818781e08Smrgout:
281918781e08Smrg	RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
282018781e08Smrg}
2821de2362d3Smrg#ifdef HAVE_LIBUDEV
2822de2362d3Smrgstatic void
2823de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure)
2824de2362d3Smrg{
2825de2362d3Smrg	drmmode_ptr drmmode = closure;
2826de2362d3Smrg	ScrnInfoPtr scrn = drmmode->scrn;
2827de2362d3Smrg	struct udev_device *dev;
282818781e08Smrg	Bool received = FALSE;
28293ed65abbSmrg	struct timeval tv = { 0, 0 };
28303ed65abbSmrg	fd_set readfd;
28313ed65abbSmrg
28323ed65abbSmrg	FD_ZERO(&readfd);
28333ed65abbSmrg	FD_SET(fd, &readfd);
28343ed65abbSmrg
28353ed65abbSmrg	while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 &&
28363ed65abbSmrg	       FD_ISSET(fd, &readfd)) {
28373ed65abbSmrg		/* select() ensured that this will not block */
28383ed65abbSmrg		dev = udev_monitor_receive_device(drmmode->uevent_monitor);
28393ed65abbSmrg		if (dev) {
28403ed65abbSmrg			udev_device_unref(dev);
28413ed65abbSmrg			received = TRUE;
28423ed65abbSmrg		}
284318781e08Smrg	}
284418781e08Smrg
284518781e08Smrg	if (received)
284618781e08Smrg		radeon_mode_hotplug(scrn, drmmode);
2847de2362d3Smrg}
2848de2362d3Smrg#endif
2849de2362d3Smrg
2850de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2851de2362d3Smrg{
2852de2362d3Smrg#ifdef HAVE_LIBUDEV
2853de2362d3Smrg	struct udev *u;
2854de2362d3Smrg	struct udev_monitor *mon;
2855de2362d3Smrg
2856de2362d3Smrg	u = udev_new();
2857de2362d3Smrg	if (!u)
2858de2362d3Smrg		return;
2859de2362d3Smrg	mon = udev_monitor_new_from_netlink(u, "udev");
2860de2362d3Smrg	if (!mon) {
2861de2362d3Smrg		udev_unref(u);
2862de2362d3Smrg		return;
2863de2362d3Smrg	}
2864de2362d3Smrg
2865de2362d3Smrg	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
2866de2362d3Smrg							    "drm",
2867de2362d3Smrg							    "drm_minor") < 0 ||
2868de2362d3Smrg	    udev_monitor_enable_receiving(mon) < 0) {
2869de2362d3Smrg		udev_monitor_unref(mon);
2870de2362d3Smrg		udev_unref(u);
2871de2362d3Smrg		return;
2872de2362d3Smrg	}
2873de2362d3Smrg
2874de2362d3Smrg	drmmode->uevent_handler =
2875de2362d3Smrg		xf86AddGeneralHandler(udev_monitor_get_fd(mon),
2876de2362d3Smrg				      drmmode_handle_uevents,
2877de2362d3Smrg				      drmmode);
2878de2362d3Smrg
2879de2362d3Smrg	drmmode->uevent_monitor = mon;
2880de2362d3Smrg#endif
2881de2362d3Smrg}
2882de2362d3Smrg
2883de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2884de2362d3Smrg{
2885de2362d3Smrg#ifdef HAVE_LIBUDEV
2886de2362d3Smrg	if (drmmode->uevent_handler) {
2887de2362d3Smrg		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
2888de2362d3Smrg		xf86RemoveGeneralHandler(drmmode->uevent_handler);
2889de2362d3Smrg
2890de2362d3Smrg		udev_monitor_unref(drmmode->uevent_monitor);
2891de2362d3Smrg		udev_unref(u);
2892de2362d3Smrg	}
2893de2362d3Smrg#endif
2894de2362d3Smrg}
2895de2362d3Smrg
289618781e08SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
289718781e08Smrg			uint32_t new_front_handle, uint64_t id, void *data,
289818781e08Smrg			int ref_crtc_hw_id, radeon_drm_handler_proc handler,
289918781e08Smrg			radeon_drm_abort_proc abort,
29003ed65abbSmrg			enum drmmode_flip_sync flip_sync,
29013ed65abbSmrg			uint32_t target_msc)
2902de2362d3Smrg{
29033ed65abbSmrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(scrn);
2904de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2905de2362d3Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
290618781e08Smrg	xf86CrtcPtr crtc = NULL;
2907de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
2908de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
2909de2362d3Smrg	unsigned int pitch;
291018781e08Smrg	int i;
2911de2362d3Smrg	uint32_t tiling_flags = 0;
29123ed65abbSmrg	uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0;
2913de2362d3Smrg	drmmode_flipdata_ptr flipdata;
291418781e08Smrg	uintptr_t drm_queue_seq = 0;
2915de2362d3Smrg
2916de2362d3Smrg	if (info->allowColorTiling) {
2917de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_R600)
2918de2362d3Smrg			tiling_flags |= RADEON_TILING_MICRO;
2919de2362d3Smrg		else
2920de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
2921de2362d3Smrg	}
2922de2362d3Smrg
292318781e08Smrg	pitch = RADEON_ALIGN(scrn->displayWidth, drmmode_get_pitch_align(scrn, info->pixel_bytes, tiling_flags)) *
292418781e08Smrg		info->pixel_bytes;
2925de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
2926de2362d3Smrg		pitch = info->front_surface.level[0].pitch_bytes;
2927de2362d3Smrg	}
2928de2362d3Smrg
29297821949aSmrg        flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
29307821949aSmrg        if (!flipdata) {
29317821949aSmrg             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
29327821949aSmrg                        "flip queue: data alloc failed.\n");
293318781e08Smrg             goto error;
29347821949aSmrg        }
293518781e08Smrg
293618781e08Smrg	/*
293718781e08Smrg	 * Create a new handle for the back buffer
293818781e08Smrg	 */
293918781e08Smrg	flipdata->old_fb_id = drmmode->fb_id;
294018781e08Smrg	if (drmModeAddFB(drmmode->fd, scrn->virtualX, scrn->virtualY,
294118781e08Smrg			 scrn->depth, scrn->bitsPerPixel, pitch,
294218781e08Smrg			 new_front_handle, &drmmode->fb_id))
294318781e08Smrg		goto error;
294418781e08Smrg
2945de2362d3Smrg	/*
2946de2362d3Smrg	 * Queue flips on all enabled CRTCs
2947de2362d3Smrg	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
2948de2362d3Smrg	 * Right now it assumes a single shared fb across all CRTCs, with the
2949de2362d3Smrg	 * kernel fixing up the offset of each CRTC as necessary.
2950de2362d3Smrg	 *
2951de2362d3Smrg	 * Also, flips queued on disabled or incorrectly configured displays
2952de2362d3Smrg	 * may never complete; this is a configuration error.
2953de2362d3Smrg	 */
2954de2362d3Smrg
2955de2362d3Smrg        flipdata->event_data = data;
295618781e08Smrg        flipdata->handler = handler;
295718781e08Smrg        flipdata->abort = abort;
295818781e08Smrg
2959de2362d3Smrg	for (i = 0; i < config->num_crtc; i++) {
296018781e08Smrg		crtc = config->crtc[i];
296118781e08Smrg
296218781e08Smrg		if (!crtc->enabled)
2963de2362d3Smrg			continue;
2964de2362d3Smrg
2965de2362d3Smrg		flipdata->flip_count++;
296618781e08Smrg		drmmode_crtc = crtc->driver_private;
2967de2362d3Smrg
2968de2362d3Smrg		/* Only the reference crtc will finally deliver its page flip
2969de2362d3Smrg		 * completion event. All other crtc's events will be discarded.
2970de2362d3Smrg		 */
297118781e08Smrg		if (drmmode_crtc->hw_id == ref_crtc_hw_id)
297218781e08Smrg			flipdata->fe_crtc = crtc;
297318781e08Smrg
297418781e08Smrg		drm_queue_seq = radeon_drm_queue_alloc(crtc, client, id,
297518781e08Smrg						       flipdata,
297618781e08Smrg						       drmmode_flip_handler,
297718781e08Smrg						       drmmode_flip_abort);
297818781e08Smrg		if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
297918781e08Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
298018781e08Smrg				   "Allocating DRM queue event entry failed.\n");
298118781e08Smrg			goto error;
298218781e08Smrg		}
2983de2362d3Smrg
29843ed65abbSmrg		if (drmmode_crtc->hw_id == ref_crtc_hw_id) {
29853ed65abbSmrg			if (drmmode_page_flip_target_absolute(pRADEONEnt,
29863ed65abbSmrg							      drmmode_crtc,
29873ed65abbSmrg							      drmmode->fb_id,
29883ed65abbSmrg							      flip_flags,
29893ed65abbSmrg							      drm_queue_seq,
29903ed65abbSmrg							      target_msc) != 0)
29913ed65abbSmrg				goto flip_error;
29923ed65abbSmrg		} else {
29933ed65abbSmrg			if (drmmode_page_flip_target_relative(pRADEONEnt,
29943ed65abbSmrg							      drmmode_crtc,
29953ed65abbSmrg							      drmmode->fb_id,
29963ed65abbSmrg							      flip_flags,
29973ed65abbSmrg							      drm_queue_seq, 0) != 0)
29983ed65abbSmrg				goto flip_error;
2999de2362d3Smrg		}
30003ed65abbSmrg
300118781e08Smrg		drmmode_crtc->flip_pending = TRUE;
300218781e08Smrg		drm_queue_seq = 0;
3003de2362d3Smrg	}
3004de2362d3Smrg
300518781e08Smrg	if (flipdata->flip_count > 0)
300618781e08Smrg		return TRUE;
30070d16fef4Smrg
30083ed65abbSmrgflip_error:
30093ed65abbSmrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n",
30103ed65abbSmrg		   strerror(errno));
30113ed65abbSmrg
301218781e08Smrgerror:
30133ed65abbSmrg	if (flipdata && flipdata->flip_count <= 1 &&
30143ed65abbSmrg	    drmmode->fb_id != flipdata->old_fb_id) {
301518781e08Smrg		drmModeRmFB(drmmode->fd, drmmode->fb_id);
301618781e08Smrg		drmmode->fb_id = flipdata->old_fb_id;
301718781e08Smrg	}
301818781e08Smrg
301918781e08Smrg	if (drm_queue_seq)
302018781e08Smrg		radeon_drm_abort_entry(drm_queue_seq);
302118781e08Smrg	else if (crtc)
302218781e08Smrg		drmmode_flip_abort(crtc, flipdata);
30233ed65abbSmrg	else {
30243ed65abbSmrg		abort(NULL, data);
302518781e08Smrg		free(flipdata);
30263ed65abbSmrg	}
3027de2362d3Smrg
3028de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
3029de2362d3Smrg		   strerror(errno));
3030de2362d3Smrg	return FALSE;
3031de2362d3Smrg}
3032