drmmode_display.c revision de2362d3
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>
34de2362d3Smrg#include <time.h>
35de2362d3Smrg#include "micmap.h"
36de2362d3Smrg#include "xf86cmap.h"
37de2362d3Smrg#include "radeon.h"
38de2362d3Smrg#include "radeon_reg.h"
39de2362d3Smrg#include "sarea.h"
40de2362d3Smrg
41de2362d3Smrg#include "drmmode_display.h"
42de2362d3Smrg
43de2362d3Smrg/* DPMS */
44de2362d3Smrg#ifdef HAVE_XEXTPROTO_71
45de2362d3Smrg#include <X11/extensions/dpmsconst.h>
46de2362d3Smrg#else
47de2362d3Smrg#define DPMS_SERVER
48de2362d3Smrg#include <X11/extensions/dpms.h>
49de2362d3Smrg#endif
50de2362d3Smrg
51de2362d3Smrg#define DEFAULT_NOMINAL_FRAME_RATE 60
52de2362d3Smrg
53de2362d3Smrgstatic Bool
54de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height);
55de2362d3Smrg
56de2362d3Smrgstatic Bool
57de2362d3SmrgRADEONZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name)
58de2362d3Smrg{
59de2362d3Smrg    int i = 0;
60de2362d3Smrg    char s1[20];
61de2362d3Smrg
62de2362d3Smrg    do {
63de2362d3Smrg	switch(*s) {
64de2362d3Smrg	case ',':
65de2362d3Smrg  	    s1[i] = '\0';
66de2362d3Smrg	    i = 0;
67de2362d3Smrg	    if (strcmp(s1, output_name) == 0)
68de2362d3Smrg		return TRUE;
69de2362d3Smrg	    break;
70de2362d3Smrg	case ' ':
71de2362d3Smrg	case '\t':
72de2362d3Smrg	case '\n':
73de2362d3Smrg	case '\r':
74de2362d3Smrg	    break;
75de2362d3Smrg	default:
76de2362d3Smrg	    s1[i] = *s;
77de2362d3Smrg	    i++;
78de2362d3Smrg	    break;
79de2362d3Smrg	}
80de2362d3Smrg    } while(*s++);
81de2362d3Smrg
82de2362d3Smrg    s1[i] = '\0';
83de2362d3Smrg    if (strcmp(s1, output_name) == 0)
84de2362d3Smrg	return TRUE;
85de2362d3Smrg
86de2362d3Smrg    return FALSE;
87de2362d3Smrg}
88de2362d3Smrg
89de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
90de2362d3Smrg					  int width, int height,
91de2362d3Smrg					  int depth, int bpp,
92de2362d3Smrg					  int pitch, int tiling,
93de2362d3Smrg					  struct radeon_bo *bo, struct radeon_surface *psurf)
94de2362d3Smrg{
95de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
96de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
97de2362d3Smrg	PixmapPtr pixmap;
98de2362d3Smrg	struct radeon_surface *surface;
99de2362d3Smrg
100de2362d3Smrg	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
101de2362d3Smrg	if (!pixmap)
102de2362d3Smrg		return NULL;
103de2362d3Smrg
104de2362d3Smrg	if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height,
105de2362d3Smrg					    depth, bpp, pitch, NULL)) {
106de2362d3Smrg		return NULL;
107de2362d3Smrg	}
108de2362d3Smrg
109de2362d3Smrg	if (!info->use_glamor)
110de2362d3Smrg		exaMoveInPixmap(pixmap);
111de2362d3Smrg	radeon_set_pixmap_bo(pixmap, bo);
112de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
113de2362d3Smrg		surface = radeon_get_pixmap_surface(pixmap);
114de2362d3Smrg		if (surface && psurf)
115de2362d3Smrg			*surface = *psurf;
116de2362d3Smrg		else if (surface) {
117de2362d3Smrg			memset(surface, 0, sizeof(struct radeon_surface));
118de2362d3Smrg			surface->npix_x = width;
119de2362d3Smrg			surface->npix_y = height;
120de2362d3Smrg			surface->npix_z = 1;
121de2362d3Smrg			surface->blk_w = 1;
122de2362d3Smrg			surface->blk_h = 1;
123de2362d3Smrg			surface->blk_d = 1;
124de2362d3Smrg			surface->array_size = 1;
125de2362d3Smrg			surface->last_level = 0;
126de2362d3Smrg			surface->bpe = bpp / 8;
127de2362d3Smrg			surface->nsamples = 1;
128de2362d3Smrg			surface->flags = RADEON_SURF_SCANOUT;
129de2362d3Smrg			/* we are requiring a recent enough libdrm version */
130de2362d3Smrg			surface->flags |= RADEON_SURF_HAS_TILE_MODE_INDEX;
131de2362d3Smrg			surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
132de2362d3Smrg			surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE);
133de2362d3Smrg			if (tiling & RADEON_TILING_MICRO) {
134de2362d3Smrg				surface->flags = RADEON_SURF_CLR(surface->flags, MODE);
135de2362d3Smrg				surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
136de2362d3Smrg			}
137de2362d3Smrg			if (tiling & RADEON_TILING_MACRO) {
138de2362d3Smrg				surface->flags = RADEON_SURF_CLR(surface->flags, MODE);
139de2362d3Smrg				surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
140de2362d3Smrg			}
141de2362d3Smrg			if (radeon_surface_best(info->surf_man, surface)) {
142de2362d3Smrg				return NULL;
143de2362d3Smrg			}
144de2362d3Smrg			if (radeon_surface_init(info->surf_man, surface)) {
145de2362d3Smrg				return NULL;
146de2362d3Smrg			}
147de2362d3Smrg		}
148de2362d3Smrg	}
149de2362d3Smrg
150de2362d3Smrg	if (!radeon_glamor_create_textured_pixmap(pixmap)) {
151de2362d3Smrg		pScreen->DestroyPixmap(pixmap);
152de2362d3Smrg	  	return NULL;
153de2362d3Smrg	}
154de2362d3Smrg
155de2362d3Smrg	return pixmap;
156de2362d3Smrg}
157de2362d3Smrg
158de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
159de2362d3Smrg{
160de2362d3Smrg	ScreenPtr pScreen = pixmap->drawable.pScreen;
161de2362d3Smrg
162de2362d3Smrg	(*pScreen->DestroyPixmap)(pixmap);
163de2362d3Smrg}
164de2362d3Smrg
165de2362d3Smrgstatic void
166de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr	scrn,
167de2362d3Smrg		     drmModeModeInfo *kmode,
168de2362d3Smrg		     DisplayModePtr	mode)
169de2362d3Smrg{
170de2362d3Smrg	memset(mode, 0, sizeof(DisplayModeRec));
171de2362d3Smrg	mode->status = MODE_OK;
172de2362d3Smrg
173de2362d3Smrg	mode->Clock = kmode->clock;
174de2362d3Smrg
175de2362d3Smrg	mode->HDisplay = kmode->hdisplay;
176de2362d3Smrg	mode->HSyncStart = kmode->hsync_start;
177de2362d3Smrg	mode->HSyncEnd = kmode->hsync_end;
178de2362d3Smrg	mode->HTotal = kmode->htotal;
179de2362d3Smrg	mode->HSkew = kmode->hskew;
180de2362d3Smrg
181de2362d3Smrg	mode->VDisplay = kmode->vdisplay;
182de2362d3Smrg	mode->VSyncStart = kmode->vsync_start;
183de2362d3Smrg	mode->VSyncEnd = kmode->vsync_end;
184de2362d3Smrg	mode->VTotal = kmode->vtotal;
185de2362d3Smrg	mode->VScan = kmode->vscan;
186de2362d3Smrg
187de2362d3Smrg	mode->Flags = kmode->flags; //& FLAG_BITS;
188de2362d3Smrg	mode->name = strdup(kmode->name);
189de2362d3Smrg
190de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_DRIVER)
191de2362d3Smrg		mode->type = M_T_DRIVER;
192de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
193de2362d3Smrg		mode->type |= M_T_PREFERRED;
194de2362d3Smrg	xf86SetModeCrtc (mode, scrn->adjustFlags);
195de2362d3Smrg}
196de2362d3Smrg
197de2362d3Smrgstatic void
198de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr	scrn,
199de2362d3Smrg		     drmModeModeInfo *kmode,
200de2362d3Smrg		     DisplayModePtr	mode)
201de2362d3Smrg{
202de2362d3Smrg	memset(kmode, 0, sizeof(*kmode));
203de2362d3Smrg
204de2362d3Smrg	kmode->clock = mode->Clock;
205de2362d3Smrg	kmode->hdisplay = mode->HDisplay;
206de2362d3Smrg	kmode->hsync_start = mode->HSyncStart;
207de2362d3Smrg	kmode->hsync_end = mode->HSyncEnd;
208de2362d3Smrg	kmode->htotal = mode->HTotal;
209de2362d3Smrg	kmode->hskew = mode->HSkew;
210de2362d3Smrg
211de2362d3Smrg	kmode->vdisplay = mode->VDisplay;
212de2362d3Smrg	kmode->vsync_start = mode->VSyncStart;
213de2362d3Smrg	kmode->vsync_end = mode->VSyncEnd;
214de2362d3Smrg	kmode->vtotal = mode->VTotal;
215de2362d3Smrg	kmode->vscan = mode->VScan;
216de2362d3Smrg
217de2362d3Smrg	kmode->flags = mode->Flags; //& FLAG_BITS;
218de2362d3Smrg	if (mode->name)
219de2362d3Smrg		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
220de2362d3Smrg	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
221de2362d3Smrg
222de2362d3Smrg}
223de2362d3Smrg
224de2362d3Smrg/*
225de2362d3Smrg * Retrieves present time in microseconds that is compatible
226de2362d3Smrg * with units used by vblank timestamps. Depending on the kernel
227de2362d3Smrg * version and DRM kernel module configuration, the vblank
228de2362d3Smrg * timestamp can either be in real time or monotonic time
229de2362d3Smrg */
230de2362d3Smrgint drmmode_get_current_ust(int drm_fd, CARD64 *ust)
231de2362d3Smrg{
232de2362d3Smrg	uint64_t cap_value;
233de2362d3Smrg	int ret;
234de2362d3Smrg	struct timespec now;
235de2362d3Smrg
236de2362d3Smrg	ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value);
237de2362d3Smrg	if (ret || !cap_value)
238de2362d3Smrg		/* old kernel or drm_timestamp_monotonic turned off */
239de2362d3Smrg		ret = clock_gettime(CLOCK_REALTIME, &now);
240de2362d3Smrg	else
241de2362d3Smrg		ret = clock_gettime(CLOCK_MONOTONIC, &now);
242de2362d3Smrg	if (ret)
243de2362d3Smrg		return ret;
244de2362d3Smrg	*ust = ((CARD64)now.tv_sec * 1000000) + ((CARD64)now.tv_nsec / 1000);
245de2362d3Smrg	return 0;
246de2362d3Smrg}
247de2362d3Smrg
248de2362d3Smrgstatic void
249de2362d3Smrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
250de2362d3Smrg{
251de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
252de2362d3Smrg	ScrnInfoPtr scrn = crtc->scrn;
253de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
254de2362d3Smrg	CARD64 ust;
255de2362d3Smrg	int ret;
256de2362d3Smrg
257de2362d3Smrg	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
258de2362d3Smrg		drmVBlank vbl;
259de2362d3Smrg
260de2362d3Smrg		/*
261de2362d3Smrg		 * On->Off transition: record the last vblank time,
262de2362d3Smrg		 * sequence number and frame period.
263de2362d3Smrg		 */
264de2362d3Smrg		vbl.request.type = DRM_VBLANK_RELATIVE;
265de2362d3Smrg		vbl.request.type |= radeon_populate_vbl_request_type(crtc);
266de2362d3Smrg		vbl.request.sequence = 0;
267de2362d3Smrg		ret = drmWaitVBlank(info->dri2.drm_fd, &vbl);
268de2362d3Smrg		if (ret)
269de2362d3Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
270de2362d3Smrg				   "%s cannot get last vblank counter\n",
271de2362d3Smrg				   __func__);
272de2362d3Smrg		else {
273de2362d3Smrg			CARD64 seq = (CARD64)vbl.reply.sequence;
274de2362d3Smrg			CARD64 nominal_frame_rate, pix_in_frame;
275de2362d3Smrg
276de2362d3Smrg			ust = ((CARD64)vbl.reply.tval_sec * 1000000) +
277de2362d3Smrg				vbl.reply.tval_usec;
278de2362d3Smrg			drmmode_crtc->dpms_last_ust = ust;
279de2362d3Smrg			drmmode_crtc->dpms_last_seq = seq;
280de2362d3Smrg			nominal_frame_rate = crtc->mode.Clock;
281de2362d3Smrg			nominal_frame_rate *= 1000;
282de2362d3Smrg			pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal;
283de2362d3Smrg			if (nominal_frame_rate == 0 || pix_in_frame == 0)
284de2362d3Smrg				nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE;
285de2362d3Smrg			else
286de2362d3Smrg				nominal_frame_rate /= pix_in_frame;
287de2362d3Smrg			drmmode_crtc->dpms_last_fps = nominal_frame_rate;
288de2362d3Smrg		}
289de2362d3Smrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) {
290de2362d3Smrg		/*
291de2362d3Smrg		 * Off->On transition: calculate and accumulate the
292de2362d3Smrg		 * number of interpolated vblanks while we were in Off state
293de2362d3Smrg		 */
294de2362d3Smrg		ret = drmmode_get_current_ust(info->dri2.drm_fd, &ust);
295de2362d3Smrg		if (ret)
296de2362d3Smrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
297de2362d3Smrg				   "%s cannot get current time\n", __func__);
298de2362d3Smrg		else if (drmmode_crtc->dpms_last_ust) {
299de2362d3Smrg			CARD64 time_elapsed, delta_seq;
300de2362d3Smrg			time_elapsed = ust - drmmode_crtc->dpms_last_ust;
301de2362d3Smrg			delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps;
302de2362d3Smrg			delta_seq /= 1000000;
303de2362d3Smrg			drmmode_crtc->interpolated_vblanks += delta_seq;
304de2362d3Smrg
305de2362d3Smrg		}
306de2362d3Smrg	}
307de2362d3Smrg	drmmode_crtc->dpms_mode = mode;
308de2362d3Smrg}
309de2362d3Smrg
310de2362d3Smrgstatic void
311de2362d3Smrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
312de2362d3Smrg{
313de2362d3Smrg	/* Nothing to do. drmmode_do_crtc_dpms() is called as appropriate */
314de2362d3Smrg}
315de2362d3Smrg
316de2362d3Smrgstatic PixmapPtr
317de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode,
318de2362d3Smrg			ScrnInfoPtr pScrn, int fbcon_id)
319de2362d3Smrg{
320de2362d3Smrg	PixmapPtr pixmap = NULL;
321de2362d3Smrg	struct radeon_bo *bo;
322de2362d3Smrg	drmModeFBPtr fbcon;
323de2362d3Smrg	struct drm_gem_flink flink;
324de2362d3Smrg
325de2362d3Smrg	fbcon = drmModeGetFB(drmmode->fd, fbcon_id);
326de2362d3Smrg	if (fbcon == NULL)
327de2362d3Smrg		return NULL;
328de2362d3Smrg
329de2362d3Smrg	if (fbcon->depth != pScrn->depth ||
330de2362d3Smrg	    fbcon->width != pScrn->virtualX ||
331de2362d3Smrg	    fbcon->height != pScrn->virtualY)
332de2362d3Smrg		goto out_free_fb;
333de2362d3Smrg
334de2362d3Smrg	flink.handle = fbcon->handle;
335de2362d3Smrg	if (ioctl(drmmode->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
336de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
337de2362d3Smrg			   "Couldn't flink fbcon handle\n");
338de2362d3Smrg		goto out_free_fb;
339de2362d3Smrg	}
340de2362d3Smrg
341de2362d3Smrg	bo = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0);
342de2362d3Smrg	if (bo == NULL) {
343de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
344de2362d3Smrg			   "Couldn't allocate bo for fbcon handle\n");
345de2362d3Smrg		goto out_free_fb;
346de2362d3Smrg	}
347de2362d3Smrg
348de2362d3Smrg	pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height,
349de2362d3Smrg					  fbcon->depth, fbcon->bpp,
350de2362d3Smrg					  fbcon->pitch, 0, bo, NULL);
351de2362d3Smrg	radeon_bo_unref(bo);
352de2362d3Smrgout_free_fb:
353de2362d3Smrg	drmModeFreeFB(fbcon);
354de2362d3Smrg	return pixmap;
355de2362d3Smrg}
356de2362d3Smrg
357de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
358de2362d3Smrg{
359de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
360de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
361de2362d3Smrg	PixmapPtr src, dst;
362de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
363de2362d3Smrg	int fbcon_id = 0;
364de2362d3Smrg	int i;
365de2362d3Smrg	int pitch;
366de2362d3Smrg	uint32_t tiling_flags = 0;
367de2362d3Smrg	Bool ret;
368de2362d3Smrg
369de2362d3Smrg	if (info->accelOn == FALSE || info->use_glamor)
370de2362d3Smrg		goto fallback;
371de2362d3Smrg
372de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
373de2362d3Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
374de2362d3Smrg
375de2362d3Smrg		if (drmmode_crtc->mode_crtc->buffer_id)
376de2362d3Smrg			fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
377de2362d3Smrg	}
378de2362d3Smrg
379de2362d3Smrg	if (!fbcon_id)
380de2362d3Smrg		goto fallback;
381de2362d3Smrg
382de2362d3Smrg	if (fbcon_id == drmmode->fb_id) {
383de2362d3Smrg		/* in some rare case there might be no fbcon and we might already
384de2362d3Smrg		 * be the one with the current fb to avoid a false deadlck in
385de2362d3Smrg		 * kernel ttm code just do nothing as anyway there is nothing
386de2362d3Smrg		 * to do
387de2362d3Smrg		 */
388de2362d3Smrg		return;
389de2362d3Smrg	}
390de2362d3Smrg
391de2362d3Smrg	src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
392de2362d3Smrg	if (!src)
393de2362d3Smrg		goto fallback;
394de2362d3Smrg
395de2362d3Smrg	if (info->allowColorTiling) {
396de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_R600) {
397de2362d3Smrg			if (info->allowColorTiling2D) {
398de2362d3Smrg				tiling_flags |= RADEON_TILING_MACRO;
399de2362d3Smrg			} else {
400de2362d3Smrg				tiling_flags |= RADEON_TILING_MICRO;
401de2362d3Smrg			}
402de2362d3Smrg		} else
403de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
404de2362d3Smrg	}
405de2362d3Smrg
406de2362d3Smrg	pitch = RADEON_ALIGN(pScrn->displayWidth,
407de2362d3Smrg			     drmmode_get_pitch_align(pScrn, info->pixel_bytes, tiling_flags)) *
408de2362d3Smrg		info->pixel_bytes;
409de2362d3Smrg
410de2362d3Smrg	dst = drmmode_create_bo_pixmap(pScrn, pScrn->virtualX,
411de2362d3Smrg				       pScrn->virtualY, pScrn->depth,
412de2362d3Smrg				       pScrn->bitsPerPixel, pitch,
413de2362d3Smrg				       tiling_flags, info->front_bo, &info->front_surface);
414de2362d3Smrg	if (!dst)
415de2362d3Smrg		goto out_free_src;
416de2362d3Smrg
417de2362d3Smrg	ret = info->accel_state->exa->PrepareCopy (src, dst,
418de2362d3Smrg						   -1, -1, GXcopy, FB_ALLONES);
419de2362d3Smrg	if (!ret)
420de2362d3Smrg	  goto out_free_src;
421de2362d3Smrg	info->accel_state->exa->Copy (dst, 0, 0, 0, 0,
422de2362d3Smrg				      pScrn->virtualX, pScrn->virtualY);
423de2362d3Smrg	info->accel_state->exa->DoneCopy (dst);
424de2362d3Smrg	radeon_cs_flush_indirect(pScrn);
425de2362d3Smrg
426de2362d3Smrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10
427de2362d3Smrg	pScreen->canDoBGNoneRoot = TRUE;
428de2362d3Smrg#endif
429de2362d3Smrg	drmmode_destroy_bo_pixmap(dst);
430de2362d3Smrg out_free_src:
431de2362d3Smrg	drmmode_destroy_bo_pixmap(src);
432de2362d3Smrg	return;
433de2362d3Smrg
434de2362d3Smrgfallback:
435de2362d3Smrg	/* map and memset the bo */
436de2362d3Smrg	if (radeon_bo_map(info->front_bo, 1))
437de2362d3Smrg		return;
438de2362d3Smrg
439de2362d3Smrg	memset(info->front_bo->ptr, 0x00, info->front_bo->size);
440de2362d3Smrg	radeon_bo_unmap(info->front_bo);
441de2362d3Smrg}
442de2362d3Smrg
443de2362d3Smrgstatic Bool
444de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
445de2362d3Smrg		     Rotation rotation, int x, int y)
446de2362d3Smrg{
447de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
448de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
449de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
450de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
451de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
452de2362d3Smrg	int saved_x, saved_y;
453de2362d3Smrg	Rotation saved_rotation;
454de2362d3Smrg	DisplayModeRec saved_mode;
455de2362d3Smrg	uint32_t *output_ids;
456de2362d3Smrg	int output_count = 0;
457de2362d3Smrg	Bool ret = TRUE;
458de2362d3Smrg	int i;
459de2362d3Smrg	int fb_id;
460de2362d3Smrg	drmModeModeInfo kmode;
461de2362d3Smrg	int pitch;
462de2362d3Smrg	uint32_t tiling_flags = 0;
463de2362d3Smrg	int height;
464de2362d3Smrg
465de2362d3Smrg	if (info->allowColorTiling) {
466de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_R600)
467de2362d3Smrg			tiling_flags |= RADEON_TILING_MICRO;
468de2362d3Smrg		else
469de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
470de2362d3Smrg	}
471de2362d3Smrg
472de2362d3Smrg	pitch = RADEON_ALIGN(pScrn->displayWidth, drmmode_get_pitch_align(pScrn, info->pixel_bytes, tiling_flags)) *
473de2362d3Smrg		info->pixel_bytes;
474de2362d3Smrg	height = RADEON_ALIGN(pScrn->virtualY, drmmode_get_height_align(pScrn, tiling_flags));
475de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
476de2362d3Smrg		pitch = info->front_surface.level[0].pitch_bytes;
477de2362d3Smrg	}
478de2362d3Smrg
479de2362d3Smrg	if (drmmode->fb_id == 0) {
480de2362d3Smrg		ret = drmModeAddFB(drmmode->fd,
481de2362d3Smrg				   pScrn->virtualX, height,
482de2362d3Smrg                                   pScrn->depth, pScrn->bitsPerPixel,
483de2362d3Smrg				   pitch,
484de2362d3Smrg				   info->front_bo->handle,
485de2362d3Smrg                                   &drmmode->fb_id);
486de2362d3Smrg                if (ret < 0) {
487de2362d3Smrg                        ErrorF("failed to add fb\n");
488de2362d3Smrg                        return FALSE;
489de2362d3Smrg                }
490de2362d3Smrg        }
491de2362d3Smrg
492de2362d3Smrg	saved_mode = crtc->mode;
493de2362d3Smrg	saved_x = crtc->x;
494de2362d3Smrg	saved_y = crtc->y;
495de2362d3Smrg	saved_rotation = crtc->rotation;
496de2362d3Smrg
497de2362d3Smrg	if (mode) {
498de2362d3Smrg		crtc->mode = *mode;
499de2362d3Smrg		crtc->x = x;
500de2362d3Smrg		crtc->y = y;
501de2362d3Smrg		crtc->rotation = rotation;
502de2362d3Smrg		crtc->transformPresent = FALSE;
503de2362d3Smrg	}
504de2362d3Smrg
505de2362d3Smrg	output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
506de2362d3Smrg	if (!output_ids) {
507de2362d3Smrg		ret = FALSE;
508de2362d3Smrg		goto done;
509de2362d3Smrg	}
510de2362d3Smrg
511de2362d3Smrg	if (mode) {
512de2362d3Smrg		for (i = 0; i < xf86_config->num_output; i++) {
513de2362d3Smrg			xf86OutputPtr output = xf86_config->output[i];
514de2362d3Smrg			drmmode_output_private_ptr drmmode_output;
515de2362d3Smrg
516de2362d3Smrg			if (output->crtc != crtc)
517de2362d3Smrg				continue;
518de2362d3Smrg
519de2362d3Smrg			drmmode_output = output->driver_private;
520de2362d3Smrg			output_ids[output_count] = drmmode_output->mode_output->connector_id;
521de2362d3Smrg			output_count++;
522de2362d3Smrg		}
523de2362d3Smrg
524de2362d3Smrg		if (!xf86CrtcRotate(crtc)) {
525de2362d3Smrg			goto done;
526de2362d3Smrg		}
527de2362d3Smrg		crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
528de2362d3Smrg				       crtc->gamma_blue, crtc->gamma_size);
529de2362d3Smrg
530de2362d3Smrg		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
531de2362d3Smrg
532de2362d3Smrg		fb_id = drmmode->fb_id;
533de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING
534de2362d3Smrg		if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
535de2362d3Smrg			x = drmmode_crtc->scanout_pixmap_x;
536de2362d3Smrg			y = 0;
537de2362d3Smrg		} else
538de2362d3Smrg#endif
539de2362d3Smrg		if (drmmode_crtc->rotate_fb_id) {
540de2362d3Smrg			fb_id = drmmode_crtc->rotate_fb_id;
541de2362d3Smrg			x = y = 0;
542de2362d3Smrg		}
543de2362d3Smrg		ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
544de2362d3Smrg				     fb_id, x, y, output_ids, output_count, &kmode);
545de2362d3Smrg		if (ret)
546de2362d3Smrg			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
547de2362d3Smrg				   "failed to set mode: %s", strerror(-ret));
548de2362d3Smrg		else
549de2362d3Smrg			ret = TRUE;
550de2362d3Smrg
551de2362d3Smrg		if (crtc->scrn->pScreen)
552de2362d3Smrg			xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
553de2362d3Smrg		/* go through all the outputs and force DPMS them back on? */
554de2362d3Smrg		for (i = 0; i < xf86_config->num_output; i++) {
555de2362d3Smrg			xf86OutputPtr output = xf86_config->output[i];
556de2362d3Smrg
557de2362d3Smrg			if (output->crtc != crtc)
558de2362d3Smrg				continue;
559de2362d3Smrg
560de2362d3Smrg			output->funcs->dpms(output, DPMSModeOn);
561de2362d3Smrg		}
562de2362d3Smrg	}
563de2362d3Smrg
564de2362d3Smrg	if (pScrn->pScreen &&
565de2362d3Smrg		!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
566de2362d3Smrg		xf86_reload_cursors(pScrn->pScreen);
567de2362d3Smrg
568de2362d3Smrgdone:
569de2362d3Smrg	if (!ret) {
570de2362d3Smrg		crtc->x = saved_x;
571de2362d3Smrg		crtc->y = saved_y;
572de2362d3Smrg		crtc->rotation = saved_rotation;
573de2362d3Smrg		crtc->mode = saved_mode;
574de2362d3Smrg	}
575de2362d3Smrg#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3
576de2362d3Smrg	else
577de2362d3Smrg		crtc->active = TRUE;
578de2362d3Smrg#endif
579de2362d3Smrg
580de2362d3Smrg	return ret;
581de2362d3Smrg}
582de2362d3Smrg
583de2362d3Smrgstatic void
584de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
585de2362d3Smrg{
586de2362d3Smrg
587de2362d3Smrg}
588de2362d3Smrg
589de2362d3Smrgstatic void
590de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
591de2362d3Smrg{
592de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
593de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
594de2362d3Smrg
595de2362d3Smrg	drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
596de2362d3Smrg}
597de2362d3Smrg
598de2362d3Smrgstatic void
599de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
600de2362d3Smrg{
601de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
602de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
603de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
604de2362d3Smrg	int i;
605de2362d3Smrg	uint32_t *ptr;
606de2362d3Smrg	uint32_t cursor_size = info->cursor_w * info->cursor_h;
607de2362d3Smrg
608de2362d3Smrg	/* cursor should be mapped already */
609de2362d3Smrg	ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr);
610de2362d3Smrg
611de2362d3Smrg	for (i = 0; i < cursor_size; i++)
612de2362d3Smrg		ptr[i] = cpu_to_le32(image[i]);
613de2362d3Smrg}
614de2362d3Smrg
615de2362d3Smrg
616de2362d3Smrgstatic void
617de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc)
618de2362d3Smrg{
619de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
620de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
621de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
622de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
623de2362d3Smrg
624de2362d3Smrg	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
625de2362d3Smrg			 info->cursor_w, info->cursor_h);
626de2362d3Smrg
627de2362d3Smrg}
628de2362d3Smrg
629de2362d3Smrgstatic void
630de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc)
631de2362d3Smrg{
632de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
633de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
634de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
635de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
636de2362d3Smrg	uint32_t handle = drmmode_crtc->cursor_bo->handle;
637de2362d3Smrg
638de2362d3Smrg	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle,
639de2362d3Smrg			 info->cursor_w, info->cursor_h);
640de2362d3Smrg}
641de2362d3Smrg
642de2362d3Smrgstatic void *
643de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
644de2362d3Smrg{
645de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
646de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
647de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
648de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
649de2362d3Smrg	int size;
650de2362d3Smrg	struct radeon_bo *rotate_bo;
651de2362d3Smrg	int ret;
652de2362d3Smrg	unsigned long rotate_pitch;
653de2362d3Smrg	int base_align;
654de2362d3Smrg
655de2362d3Smrg	/* rotation requires acceleration */
656de2362d3Smrg	if (info->r600_shadow_fb) {
657de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
658de2362d3Smrg			   "Rotation requires acceleration!\n");
659de2362d3Smrg		return NULL;
660de2362d3Smrg	}
661de2362d3Smrg
662de2362d3Smrg	rotate_pitch =
663de2362d3Smrg		RADEON_ALIGN(width, drmmode_get_pitch_align(crtc->scrn, drmmode->cpp, 0)) * drmmode->cpp;
664de2362d3Smrg	height = RADEON_ALIGN(height, drmmode_get_height_align(crtc->scrn, 0));
665de2362d3Smrg	base_align = drmmode_get_base_align(crtc->scrn, drmmode->cpp, 0);
666de2362d3Smrg	size = RADEON_ALIGN(rotate_pitch * height, RADEON_GPU_PAGE_SIZE);
667de2362d3Smrg
668de2362d3Smrg	rotate_bo = radeon_bo_open(drmmode->bufmgr, 0, size, base_align, RADEON_GEM_DOMAIN_VRAM, 0);
669de2362d3Smrg	if (rotate_bo == NULL)
670de2362d3Smrg		return NULL;
671de2362d3Smrg
672de2362d3Smrg	radeon_bo_map(rotate_bo, 1);
673de2362d3Smrg
674de2362d3Smrg	ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth,
675de2362d3Smrg			   crtc->scrn->bitsPerPixel, rotate_pitch,
676de2362d3Smrg			   rotate_bo->handle,
677de2362d3Smrg			   &drmmode_crtc->rotate_fb_id);
678de2362d3Smrg	if (ret) {
679de2362d3Smrg		ErrorF("failed to add rotate fb\n");
680de2362d3Smrg	}
681de2362d3Smrg
682de2362d3Smrg	drmmode_crtc->rotate_bo = rotate_bo;
683de2362d3Smrg	return drmmode_crtc->rotate_bo->ptr;
684de2362d3Smrg}
685de2362d3Smrg
686de2362d3Smrgstatic PixmapPtr
687de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
688de2362d3Smrg{
689de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
690de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
691de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
692de2362d3Smrg	unsigned long rotate_pitch;
693de2362d3Smrg	PixmapPtr rotate_pixmap;
694de2362d3Smrg
695de2362d3Smrg	if (!data)
696de2362d3Smrg		data = drmmode_crtc_shadow_allocate (crtc, width, height);
697de2362d3Smrg
698de2362d3Smrg	rotate_pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0)) * drmmode->cpp;
699de2362d3Smrg
700de2362d3Smrg	rotate_pixmap = drmmode_create_bo_pixmap(pScrn,
701de2362d3Smrg						 width, height,
702de2362d3Smrg						 pScrn->depth,
703de2362d3Smrg						 pScrn->bitsPerPixel,
704de2362d3Smrg						 rotate_pitch,
705de2362d3Smrg						 0, drmmode_crtc->rotate_bo, NULL);
706de2362d3Smrg	if (rotate_pixmap == NULL) {
707de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
708de2362d3Smrg			   "Couldn't allocate shadow pixmap for rotated CRTC\n");
709de2362d3Smrg	}
710de2362d3Smrg	return rotate_pixmap;
711de2362d3Smrg
712de2362d3Smrg}
713de2362d3Smrg
714de2362d3Smrgstatic void
715de2362d3Smrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
716de2362d3Smrg{
717de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
718de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
719de2362d3Smrg
720de2362d3Smrg	if (rotate_pixmap)
721de2362d3Smrg		drmmode_destroy_bo_pixmap(rotate_pixmap);
722de2362d3Smrg
723de2362d3Smrg	if (data) {
724de2362d3Smrg		drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
725de2362d3Smrg		drmmode_crtc->rotate_fb_id = 0;
726de2362d3Smrg		radeon_bo_unmap(drmmode_crtc->rotate_bo);
727de2362d3Smrg		radeon_bo_unref(drmmode_crtc->rotate_bo);
728de2362d3Smrg		drmmode_crtc->rotate_bo = NULL;
729de2362d3Smrg	}
730de2362d3Smrg
731de2362d3Smrg}
732de2362d3Smrg
733de2362d3Smrgstatic void
734de2362d3Smrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
735de2362d3Smrg                      uint16_t *blue, int size)
736de2362d3Smrg{
737de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
738de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
739de2362d3Smrg
740de2362d3Smrg	drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
741de2362d3Smrg			    size, red, green, blue);
742de2362d3Smrg}
743de2362d3Smrg
744de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING
745de2362d3Smrgstatic Bool
746de2362d3Smrgdrmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
747de2362d3Smrg{
748de2362d3Smrg	ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
749de2362d3Smrg	PixmapPtr screenpix = screen->GetScreenPixmap(screen);
750de2362d3Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
751de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
752de2362d3Smrg	int c, total_width = 0, max_height = 0, this_x = 0;
753de2362d3Smrg
754de2362d3Smrg	if (!ppix) {
755de2362d3Smrg		if (crtc->randr_crtc->scanout_pixmap)
756de2362d3Smrg			PixmapStopDirtyTracking(crtc->randr_crtc->scanout_pixmap, screenpix);
757de2362d3Smrg		drmmode_crtc->scanout_pixmap_x = 0;
758de2362d3Smrg		return TRUE;
759de2362d3Smrg	}
760de2362d3Smrg
761de2362d3Smrg	/* iterate over all the attached crtcs -
762de2362d3Smrg	   work out bounding box */
763de2362d3Smrg	for (c = 0; c < xf86_config->num_crtc; c++) {
764de2362d3Smrg		xf86CrtcPtr iter = xf86_config->crtc[c];
765de2362d3Smrg		if (!iter->enabled && iter != crtc)
766de2362d3Smrg			continue;
767de2362d3Smrg		if (iter == crtc) {
768de2362d3Smrg			this_x = total_width;
769de2362d3Smrg			total_width += ppix->drawable.width;
770de2362d3Smrg			if (max_height < ppix->drawable.height)
771de2362d3Smrg				max_height = ppix->drawable.height;
772de2362d3Smrg		} else {
773de2362d3Smrg			total_width += iter->mode.HDisplay;
774de2362d3Smrg			if (max_height < iter->mode.VDisplay)
775de2362d3Smrg				max_height = iter->mode.VDisplay;
776de2362d3Smrg		}
777de2362d3Smrg#ifndef HAS_DIRTYTRACKING2
778de2362d3Smrg		if (iter != crtc) {
779de2362d3Smrg			ErrorF("Cannot do multiple crtcs without X server dirty tracking 2 interface\n");
780de2362d3Smrg			return FALSE;
781de2362d3Smrg		}
782de2362d3Smrg#endif
783de2362d3Smrg	}
784de2362d3Smrg
785de2362d3Smrg	if (total_width != screenpix->drawable.width ||
786de2362d3Smrg	    max_height != screenpix->drawable.height) {
787de2362d3Smrg		Bool ret;
788de2362d3Smrg		ret = drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height);
789de2362d3Smrg		if (ret == FALSE)
790de2362d3Smrg			return FALSE;
791de2362d3Smrg
792de2362d3Smrg		screenpix = screen->GetScreenPixmap(screen);
793de2362d3Smrg		screen->width = screenpix->drawable.width = total_width;
794de2362d3Smrg		screen->height = screenpix->drawable.height = max_height;
795de2362d3Smrg	}
796de2362d3Smrg	drmmode_crtc->scanout_pixmap_x = this_x;
797de2362d3Smrg#ifdef HAS_DIRTYTRACKING2
798de2362d3Smrg	PixmapStartDirtyTracking2(ppix, screenpix, 0, 0, this_x, 0);
799de2362d3Smrg#else
800de2362d3Smrg	PixmapStartDirtyTracking(ppix, screenpix, 0, 0);
801de2362d3Smrg#endif
802de2362d3Smrg	return TRUE;
803de2362d3Smrg}
804de2362d3Smrg#endif
805de2362d3Smrg
806de2362d3Smrgstatic const xf86CrtcFuncsRec drmmode_crtc_funcs = {
807de2362d3Smrg    .dpms = drmmode_crtc_dpms,
808de2362d3Smrg    .set_mode_major = drmmode_set_mode_major,
809de2362d3Smrg    .set_cursor_colors = drmmode_set_cursor_colors,
810de2362d3Smrg    .set_cursor_position = drmmode_set_cursor_position,
811de2362d3Smrg    .show_cursor = drmmode_show_cursor,
812de2362d3Smrg    .hide_cursor = drmmode_hide_cursor,
813de2362d3Smrg    .load_cursor_argb = drmmode_load_cursor_argb,
814de2362d3Smrg
815de2362d3Smrg    .gamma_set = drmmode_crtc_gamma_set,
816de2362d3Smrg    .shadow_create = drmmode_crtc_shadow_create,
817de2362d3Smrg    .shadow_allocate = drmmode_crtc_shadow_allocate,
818de2362d3Smrg    .shadow_destroy = drmmode_crtc_shadow_destroy,
819de2362d3Smrg    .destroy = NULL, /* XXX */
820de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING
821de2362d3Smrg    .set_scanout_pixmap = drmmode_set_scanout_pixmap,
822de2362d3Smrg#endif
823de2362d3Smrg};
824de2362d3Smrg
825de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc)
826de2362d3Smrg{
827de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
828de2362d3Smrg	return drmmode_crtc->hw_id;
829de2362d3Smrg}
830de2362d3Smrg
831de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc)
832de2362d3Smrg{
833de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
834de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
835de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
836de2362d3Smrg	struct drm_radeon_info ginfo;
837de2362d3Smrg	int r;
838de2362d3Smrg	uint32_t tmp;
839de2362d3Smrg
840de2362d3Smrg	memset(&ginfo, 0, sizeof(ginfo));
841de2362d3Smrg	ginfo.request = 0x4;
842de2362d3Smrg	tmp = drmmode_crtc->mode_crtc->crtc_id;
843de2362d3Smrg	ginfo.value = (uintptr_t)&tmp;
844de2362d3Smrg	r = drmCommandWriteRead(info->dri2.drm_fd, DRM_RADEON_INFO, &ginfo, sizeof(ginfo));
845de2362d3Smrg	if (r) {
846de2362d3Smrg		drmmode_crtc->hw_id = -1;
847de2362d3Smrg		return;
848de2362d3Smrg	}
849de2362d3Smrg	drmmode_crtc->hw_id = tmp;
850de2362d3Smrg}
851de2362d3Smrg
852de2362d3Smrgstatic void
853de2362d3Smrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
854de2362d3Smrg{
855de2362d3Smrg	xf86CrtcPtr crtc;
856de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc;
857de2362d3Smrg
858de2362d3Smrg	crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
859de2362d3Smrg	if (crtc == NULL)
860de2362d3Smrg		return;
861de2362d3Smrg
862de2362d3Smrg	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
863de2362d3Smrg	drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
864de2362d3Smrg	drmmode_crtc->drmmode = drmmode;
865de2362d3Smrg	crtc->driver_private = drmmode_crtc;
866de2362d3Smrg	drmmode_crtc_hw_id(crtc);
867de2362d3Smrg
868de2362d3Smrg	return;
869de2362d3Smrg}
870de2362d3Smrg
871de2362d3Smrgstatic xf86OutputStatus
872de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output)
873de2362d3Smrg{
874de2362d3Smrg	/* go to the hw and retrieve a new output struct */
875de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
876de2362d3Smrg	drmmode_ptr drmmode = drmmode_output->drmmode;
877de2362d3Smrg	xf86OutputStatus status;
878de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
879de2362d3Smrg
880de2362d3Smrg	drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
881de2362d3Smrg	if (!drmmode_output->mode_output)
882de2362d3Smrg		return XF86OutputStatusDisconnected;
883de2362d3Smrg
884de2362d3Smrg	switch (drmmode_output->mode_output->connection) {
885de2362d3Smrg	case DRM_MODE_CONNECTED:
886de2362d3Smrg		status = XF86OutputStatusConnected;
887de2362d3Smrg		break;
888de2362d3Smrg	case DRM_MODE_DISCONNECTED:
889de2362d3Smrg		status = XF86OutputStatusDisconnected;
890de2362d3Smrg		break;
891de2362d3Smrg	default:
892de2362d3Smrg	case DRM_MODE_UNKNOWNCONNECTION:
893de2362d3Smrg		status = XF86OutputStatusUnknown;
894de2362d3Smrg		break;
895de2362d3Smrg	}
896de2362d3Smrg	return status;
897de2362d3Smrg}
898de2362d3Smrg
899de2362d3Smrgstatic Bool
900de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
901de2362d3Smrg{
902de2362d3Smrg	return MODE_OK;
903de2362d3Smrg}
904de2362d3Smrg
905de2362d3Smrgstatic DisplayModePtr
906de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output)
907de2362d3Smrg{
908de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
909de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
910de2362d3Smrg	drmmode_ptr drmmode = drmmode_output->drmmode;
911de2362d3Smrg	int i;
912de2362d3Smrg	DisplayModePtr Modes = NULL, Mode;
913de2362d3Smrg	drmModePropertyPtr props;
914de2362d3Smrg	xf86MonPtr mon = NULL;
915de2362d3Smrg
916de2362d3Smrg	if (!koutput)
917de2362d3Smrg		return NULL;
918de2362d3Smrg
919de2362d3Smrg	/* look for an EDID property */
920de2362d3Smrg	for (i = 0; i < koutput->count_props; i++) {
921de2362d3Smrg		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
922de2362d3Smrg		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
923de2362d3Smrg			if (!strcmp(props->name, "EDID")) {
924de2362d3Smrg				if (drmmode_output->edid_blob)
925de2362d3Smrg					drmModeFreePropertyBlob(drmmode_output->edid_blob);
926de2362d3Smrg				drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
927de2362d3Smrg			}
928de2362d3Smrg		}
929de2362d3Smrg		if (props)
930de2362d3Smrg			drmModeFreeProperty(props);
931de2362d3Smrg	}
932de2362d3Smrg
933de2362d3Smrg	if (drmmode_output->edid_blob) {
934de2362d3Smrg		mon = xf86InterpretEDID(output->scrn->scrnIndex,
935de2362d3Smrg					drmmode_output->edid_blob->data);
936de2362d3Smrg		if (mon && drmmode_output->edid_blob->length > 128)
937de2362d3Smrg			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
938de2362d3Smrg	}
939de2362d3Smrg	xf86OutputSetEDID(output, mon);
940de2362d3Smrg
941de2362d3Smrg	/* modes should already be available */
942de2362d3Smrg	for (i = 0; i < koutput->count_modes; i++) {
943de2362d3Smrg		Mode = xnfalloc(sizeof(DisplayModeRec));
944de2362d3Smrg
945de2362d3Smrg		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
946de2362d3Smrg		Modes = xf86ModesAdd(Modes, Mode);
947de2362d3Smrg
948de2362d3Smrg	}
949de2362d3Smrg	return Modes;
950de2362d3Smrg}
951de2362d3Smrg
952de2362d3Smrgstatic void
953de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output)
954de2362d3Smrg{
955de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
956de2362d3Smrg	int i;
957de2362d3Smrg
958de2362d3Smrg	if (drmmode_output->edid_blob)
959de2362d3Smrg		drmModeFreePropertyBlob(drmmode_output->edid_blob);
960de2362d3Smrg	for (i = 0; i < drmmode_output->num_props; i++) {
961de2362d3Smrg		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
962de2362d3Smrg		free(drmmode_output->props[i].atoms);
963de2362d3Smrg	}
964de2362d3Smrg	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
965de2362d3Smrg		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
966de2362d3Smrg	}
967de2362d3Smrg	free(drmmode_output->mode_encoders);
968de2362d3Smrg	free(drmmode_output->props);
969de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
970de2362d3Smrg	free(drmmode_output);
971de2362d3Smrg	output->driver_private = NULL;
972de2362d3Smrg}
973de2362d3Smrg
974de2362d3Smrgstatic void
975de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode)
976de2362d3Smrg{
977de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
978de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
979de2362d3Smrg	drmmode_ptr drmmode = drmmode_output->drmmode;
980de2362d3Smrg
981de2362d3Smrg	if (mode != DPMSModeOn && output->crtc)
982de2362d3Smrg		drmmode_do_crtc_dpms(output->crtc, mode);
983de2362d3Smrg
984de2362d3Smrg	drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
985de2362d3Smrg				    drmmode_output->dpms_enum_id, mode);
986de2362d3Smrg
987de2362d3Smrg	if (mode == DPMSModeOn && output->crtc)
988de2362d3Smrg		drmmode_do_crtc_dpms(output->crtc, mode);
989de2362d3Smrg}
990de2362d3Smrg
991de2362d3Smrg
992de2362d3Smrgstatic Bool
993de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop)
994de2362d3Smrg{
995de2362d3Smrg    if (!prop)
996de2362d3Smrg	return TRUE;
997de2362d3Smrg    /* ignore blob prop */
998de2362d3Smrg    if (prop->flags & DRM_MODE_PROP_BLOB)
999de2362d3Smrg	return TRUE;
1000de2362d3Smrg    /* ignore standard property */
1001de2362d3Smrg    if (!strcmp(prop->name, "EDID") ||
1002de2362d3Smrg	    !strcmp(prop->name, "DPMS"))
1003de2362d3Smrg	return TRUE;
1004de2362d3Smrg
1005de2362d3Smrg    return FALSE;
1006de2362d3Smrg}
1007de2362d3Smrg
1008de2362d3Smrgstatic void
1009de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output)
1010de2362d3Smrg{
1011de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
1012de2362d3Smrg    drmModeConnectorPtr mode_output = drmmode_output->mode_output;
1013de2362d3Smrg    drmmode_ptr drmmode = drmmode_output->drmmode;
1014de2362d3Smrg    drmModePropertyPtr drmmode_prop;
1015de2362d3Smrg    int i, j, err;
1016de2362d3Smrg
1017de2362d3Smrg    drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
1018de2362d3Smrg    if (!drmmode_output->props)
1019de2362d3Smrg	return;
1020de2362d3Smrg
1021de2362d3Smrg    drmmode_output->num_props = 0;
1022de2362d3Smrg    for (i = 0, j = 0; i < mode_output->count_props; i++) {
1023de2362d3Smrg	drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
1024de2362d3Smrg	if (drmmode_property_ignore(drmmode_prop)) {
1025de2362d3Smrg	    drmModeFreeProperty(drmmode_prop);
1026de2362d3Smrg	    continue;
1027de2362d3Smrg	}
1028de2362d3Smrg	drmmode_output->props[j].mode_prop = drmmode_prop;
1029de2362d3Smrg	drmmode_output->props[j].value = mode_output->prop_values[i];
1030de2362d3Smrg	drmmode_output->num_props++;
1031de2362d3Smrg	j++;
1032de2362d3Smrg    }
1033de2362d3Smrg
1034de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
1035de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
1036de2362d3Smrg	drmmode_prop = p->mode_prop;
1037de2362d3Smrg
1038de2362d3Smrg	if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1039de2362d3Smrg	    INT32 range[2];
1040de2362d3Smrg	    INT32 value = p->value;
1041de2362d3Smrg
1042de2362d3Smrg	    p->num_atoms = 1;
1043de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
1044de2362d3Smrg	    if (!p->atoms)
1045de2362d3Smrg		continue;
1046de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1047de2362d3Smrg	    range[0] = drmmode_prop->values[0];
1048de2362d3Smrg	    range[1] = drmmode_prop->values[1];
1049de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1050de2362d3Smrg		    FALSE, TRUE,
1051de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1052de2362d3Smrg		    2, range);
1053de2362d3Smrg	    if (err != 0) {
1054de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1055de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
1056de2362d3Smrg	    }
1057de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1058de2362d3Smrg		    XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE);
1059de2362d3Smrg	    if (err != 0) {
1060de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1061de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
1062de2362d3Smrg	    }
1063de2362d3Smrg	} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1064de2362d3Smrg	    p->num_atoms = drmmode_prop->count_enums + 1;
1065de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
1066de2362d3Smrg	    if (!p->atoms)
1067de2362d3Smrg		continue;
1068de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
1069de2362d3Smrg	    for (j = 1; j <= drmmode_prop->count_enums; j++) {
1070de2362d3Smrg		struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
1071de2362d3Smrg		p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
1072de2362d3Smrg	    }
1073de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
1074de2362d3Smrg		    FALSE, FALSE,
1075de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
1076de2362d3Smrg		    p->num_atoms - 1, (INT32 *)&p->atoms[1]);
1077de2362d3Smrg	    if (err != 0) {
1078de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1079de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
1080de2362d3Smrg	    }
1081de2362d3Smrg	    for (j = 0; j < drmmode_prop->count_enums; j++)
1082de2362d3Smrg		if (drmmode_prop->enums[j].value == p->value)
1083de2362d3Smrg		    break;
1084de2362d3Smrg	    /* there's always a matching value */
1085de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
1086de2362d3Smrg		    XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
1087de2362d3Smrg	    if (err != 0) {
1088de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1089de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
1090de2362d3Smrg	    }
1091de2362d3Smrg	}
1092de2362d3Smrg    }
1093de2362d3Smrg}
1094de2362d3Smrg
1095de2362d3Smrgstatic Bool
1096de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property,
1097de2362d3Smrg		RRPropertyValuePtr value)
1098de2362d3Smrg{
1099de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
1100de2362d3Smrg    drmmode_ptr drmmode = drmmode_output->drmmode;
1101de2362d3Smrg    int i;
1102de2362d3Smrg
1103de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
1104de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
1105de2362d3Smrg
1106de2362d3Smrg	if (p->atoms[0] != property)
1107de2362d3Smrg	    continue;
1108de2362d3Smrg
1109de2362d3Smrg	if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1110de2362d3Smrg	    uint32_t val;
1111de2362d3Smrg
1112de2362d3Smrg	    if (value->type != XA_INTEGER || value->format != 32 ||
1113de2362d3Smrg		    value->size != 1)
1114de2362d3Smrg		return FALSE;
1115de2362d3Smrg	    val = *(uint32_t *)value->data;
1116de2362d3Smrg
1117de2362d3Smrg	    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
1118de2362d3Smrg		    p->mode_prop->prop_id, (uint64_t)val);
1119de2362d3Smrg	    return TRUE;
1120de2362d3Smrg	} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1121de2362d3Smrg	    Atom	atom;
1122de2362d3Smrg	    const char	*name;
1123de2362d3Smrg	    int		j;
1124de2362d3Smrg
1125de2362d3Smrg	    if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
1126de2362d3Smrg		return FALSE;
1127de2362d3Smrg	    memcpy(&atom, value->data, 4);
1128de2362d3Smrg	    name = NameForAtom(atom);
1129de2362d3Smrg
1130de2362d3Smrg	    /* search for matching name string, then set its value down */
1131de2362d3Smrg	    for (j = 0; j < p->mode_prop->count_enums; j++) {
1132de2362d3Smrg		if (!strcmp(p->mode_prop->enums[j].name, name)) {
1133de2362d3Smrg		    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
1134de2362d3Smrg			    p->mode_prop->prop_id, p->mode_prop->enums[j].value);
1135de2362d3Smrg		    return TRUE;
1136de2362d3Smrg		}
1137de2362d3Smrg	    }
1138de2362d3Smrg	}
1139de2362d3Smrg    }
1140de2362d3Smrg
1141de2362d3Smrg    return TRUE;
1142de2362d3Smrg}
1143de2362d3Smrg
1144de2362d3Smrgstatic Bool
1145de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property)
1146de2362d3Smrg{
1147de2362d3Smrg    return TRUE;
1148de2362d3Smrg}
1149de2362d3Smrg
1150de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = {
1151de2362d3Smrg    .dpms = drmmode_output_dpms,
1152de2362d3Smrg    .create_resources = drmmode_output_create_resources,
1153de2362d3Smrg    .set_property = drmmode_output_set_property,
1154de2362d3Smrg    .get_property = drmmode_output_get_property,
1155de2362d3Smrg#if 0
1156de2362d3Smrg
1157de2362d3Smrg    .save = drmmode_crt_save,
1158de2362d3Smrg    .restore = drmmode_crt_restore,
1159de2362d3Smrg    .mode_fixup = drmmode_crt_mode_fixup,
1160de2362d3Smrg    .prepare = drmmode_output_prepare,
1161de2362d3Smrg    .mode_set = drmmode_crt_mode_set,
1162de2362d3Smrg    .commit = drmmode_output_commit,
1163de2362d3Smrg#endif
1164de2362d3Smrg    .detect = drmmode_output_detect,
1165de2362d3Smrg    .mode_valid = drmmode_output_mode_valid,
1166de2362d3Smrg
1167de2362d3Smrg    .get_modes = drmmode_output_get_modes,
1168de2362d3Smrg    .destroy = drmmode_output_destroy
1169de2362d3Smrg};
1170de2362d3Smrg
1171de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown,
1172de2362d3Smrg				      SubPixelHorizontalRGB,
1173de2362d3Smrg				      SubPixelHorizontalBGR,
1174de2362d3Smrg				      SubPixelVerticalRGB,
1175de2362d3Smrg				      SubPixelVerticalBGR,
1176de2362d3Smrg				      SubPixelNone };
1177de2362d3Smrg
1178de2362d3Smrgconst char *output_names[] = { "None",
1179de2362d3Smrg			       "VGA",
1180de2362d3Smrg			       "DVI",
1181de2362d3Smrg			       "DVI",
1182de2362d3Smrg			       "DVI",
1183de2362d3Smrg			       "Composite",
1184de2362d3Smrg			       "S-video",
1185de2362d3Smrg			       "LVDS",
1186de2362d3Smrg			       "CTV",
1187de2362d3Smrg			       "DIN",
1188de2362d3Smrg			       "DisplayPort",
1189de2362d3Smrg			       "HDMI",
1190de2362d3Smrg			       "HDMI",
1191de2362d3Smrg			       "TV",
1192de2362d3Smrg			       "eDP"
1193de2362d3Smrg};
1194de2362d3Smrg
1195de2362d3Smrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
1196de2362d3Smrg
1197de2362d3Smrgstatic void
1198de2362d3Smrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dvi, int *num_hdmi)
1199de2362d3Smrg{
1200de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1201de2362d3Smrg	xf86OutputPtr output;
1202de2362d3Smrg	drmModeConnectorPtr koutput;
1203de2362d3Smrg	drmModeEncoderPtr *kencoders = NULL;
1204de2362d3Smrg	drmmode_output_private_ptr drmmode_output;
1205de2362d3Smrg	drmModePropertyPtr props;
1206de2362d3Smrg	char name[32];
1207de2362d3Smrg	int i;
1208de2362d3Smrg	const char *s;
1209de2362d3Smrg
1210de2362d3Smrg	koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
1211de2362d3Smrg	if (!koutput)
1212de2362d3Smrg		return;
1213de2362d3Smrg
1214de2362d3Smrg	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
1215de2362d3Smrg	if (!kencoders) {
1216de2362d3Smrg		goto out_free_encoders;
1217de2362d3Smrg	}
1218de2362d3Smrg
1219de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
1220de2362d3Smrg		kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
1221de2362d3Smrg		if (!kencoders[i]) {
1222de2362d3Smrg			goto out_free_encoders;
1223de2362d3Smrg		}
1224de2362d3Smrg	}
1225de2362d3Smrg
1226de2362d3Smrg	if (koutput->connector_type >= NUM_OUTPUT_NAMES)
1227de2362d3Smrg		snprintf(name, 32, "Unknown%d-%d", koutput->connector_type,
1228de2362d3Smrg			 koutput->connector_type_id - 1);
1229de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING
1230de2362d3Smrg	else if (pScrn->is_gpu)
1231de2362d3Smrg		snprintf(name, 32, "%s-%d-%d",
1232de2362d3Smrg			 output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1,
1233de2362d3Smrg			 koutput->connector_type_id - 1);
1234de2362d3Smrg#endif
1235de2362d3Smrg	else {
1236de2362d3Smrg		/* need to do smart conversion here for compat with non-kms ATI driver */
1237de2362d3Smrg		if (koutput->connector_type_id == 1) {
1238de2362d3Smrg			switch(koutput->connector_type) {
1239de2362d3Smrg			case DRM_MODE_CONNECTOR_DVII:
1240de2362d3Smrg			case DRM_MODE_CONNECTOR_DVID:
1241de2362d3Smrg			case DRM_MODE_CONNECTOR_DVIA:
1242de2362d3Smrg				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
1243de2362d3Smrg				(*num_dvi)++;
1244de2362d3Smrg				break;
1245de2362d3Smrg			case DRM_MODE_CONNECTOR_HDMIA:
1246de2362d3Smrg			case DRM_MODE_CONNECTOR_HDMIB:
1247de2362d3Smrg				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
1248de2362d3Smrg				(*num_hdmi)++;
1249de2362d3Smrg				break;
1250de2362d3Smrg			case DRM_MODE_CONNECTOR_VGA:
1251de2362d3Smrg			case DRM_MODE_CONNECTOR_DisplayPort:
1252de2362d3Smrg				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
1253de2362d3Smrg					 koutput->connector_type_id - 1);
1254de2362d3Smrg				break;
1255de2362d3Smrg			default:
1256de2362d3Smrg				snprintf(name, 32, "%s", output_names[koutput->connector_type]);
1257de2362d3Smrg				break;
1258de2362d3Smrg			}
1259de2362d3Smrg		} else {
1260de2362d3Smrg			snprintf(name, 32, "%s-%d", output_names[koutput->connector_type],
1261de2362d3Smrg				 koutput->connector_type_id - 1);
1262de2362d3Smrg		}
1263de2362d3Smrg	}
1264de2362d3Smrg
1265de2362d3Smrg	if (xf86IsEntityShared(pScrn->entityList[0])) {
1266de2362d3Smrg		if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
1267de2362d3Smrg			if (!RADEONZaphodStringMatches(pScrn, s, name))
1268de2362d3Smrg				goto out_free_encoders;
1269de2362d3Smrg		} else {
1270de2362d3Smrg			if (info->IsPrimary && (num != 0))
1271de2362d3Smrg				goto out_free_encoders;
1272de2362d3Smrg			else if (info->IsSecondary && (num != 1))
1273de2362d3Smrg				goto out_free_encoders;
1274de2362d3Smrg		}
1275de2362d3Smrg	}
1276de2362d3Smrg
1277de2362d3Smrg	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
1278de2362d3Smrg	if (!output) {
1279de2362d3Smrg		goto out_free_encoders;
1280de2362d3Smrg	}
1281de2362d3Smrg
1282de2362d3Smrg	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
1283de2362d3Smrg	if (!drmmode_output) {
1284de2362d3Smrg		xf86OutputDestroy(output);
1285de2362d3Smrg		goto out_free_encoders;
1286de2362d3Smrg	}
1287de2362d3Smrg
1288de2362d3Smrg	drmmode_output->output_id = drmmode->mode_res->connectors[num];
1289de2362d3Smrg	drmmode_output->mode_output = koutput;
1290de2362d3Smrg	drmmode_output->mode_encoders = kencoders;
1291de2362d3Smrg	drmmode_output->drmmode = drmmode;
1292de2362d3Smrg	output->mm_width = koutput->mmWidth;
1293de2362d3Smrg	output->mm_height = koutput->mmHeight;
1294de2362d3Smrg
1295de2362d3Smrg	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
1296de2362d3Smrg	output->interlaceAllowed = TRUE;
1297de2362d3Smrg	output->doubleScanAllowed = TRUE;
1298de2362d3Smrg	output->driver_private = drmmode_output;
1299de2362d3Smrg
1300de2362d3Smrg	output->possible_crtcs = 0xffffffff;
1301de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
1302de2362d3Smrg		output->possible_crtcs &= kencoders[i]->possible_crtcs;
1303de2362d3Smrg	}
1304de2362d3Smrg	/* work out the possible clones later */
1305de2362d3Smrg	output->possible_clones = 0;
1306de2362d3Smrg
1307de2362d3Smrg	for (i = 0; i < koutput->count_props; i++) {
1308de2362d3Smrg		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
1309de2362d3Smrg		if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
1310de2362d3Smrg			if (!strcmp(props->name, "DPMS")) {
1311de2362d3Smrg				drmmode_output->dpms_enum_id = koutput->props[i];
1312de2362d3Smrg				drmModeFreeProperty(props);
1313de2362d3Smrg				break;
1314de2362d3Smrg			}
1315de2362d3Smrg			drmModeFreeProperty(props);
1316de2362d3Smrg		}
1317de2362d3Smrg	}
1318de2362d3Smrg
1319de2362d3Smrg	return;
1320de2362d3Smrgout_free_encoders:
1321de2362d3Smrg	if (kencoders){
1322de2362d3Smrg		for (i = 0; i < koutput->count_encoders; i++)
1323de2362d3Smrg			drmModeFreeEncoder(kencoders[i]);
1324de2362d3Smrg		free(kencoders);
1325de2362d3Smrg	}
1326de2362d3Smrg	drmModeFreeConnector(koutput);
1327de2362d3Smrg
1328de2362d3Smrg}
1329de2362d3Smrg
1330de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
1331de2362d3Smrg{
1332de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout;
1333de2362d3Smrg	int i;
1334de2362d3Smrg	xf86OutputPtr clone_output;
1335de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1336de2362d3Smrg	int index_mask = 0;
1337de2362d3Smrg
1338de2362d3Smrg	if (drmmode_output->enc_clone_mask == 0)
1339de2362d3Smrg		return index_mask;
1340de2362d3Smrg
1341de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
1342de2362d3Smrg		clone_output = xf86_config->output[i];
1343de2362d3Smrg		clone_drmout = clone_output->driver_private;
1344de2362d3Smrg		if (output == clone_output)
1345de2362d3Smrg			continue;
1346de2362d3Smrg
1347de2362d3Smrg		if (clone_drmout->enc_mask == 0)
1348de2362d3Smrg			continue;
1349de2362d3Smrg		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
1350de2362d3Smrg			index_mask |= (1 << i);
1351de2362d3Smrg	}
1352de2362d3Smrg	return index_mask;
1353de2362d3Smrg}
1354de2362d3Smrg
1355de2362d3Smrg
1356de2362d3Smrgstatic void
1357de2362d3Smrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1358de2362d3Smrg{
1359de2362d3Smrg	int i, j;
1360de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1361de2362d3Smrg
1362de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
1363de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
1364de2362d3Smrg		drmmode_output_private_ptr drmmode_output;
1365de2362d3Smrg
1366de2362d3Smrg		drmmode_output = output->driver_private;
1367de2362d3Smrg		drmmode_output->enc_clone_mask = 0xff;
1368de2362d3Smrg		/* and all the possible encoder clones for this output together */
1369de2362d3Smrg		for (j = 0; j < drmmode_output->mode_output->count_encoders; j++)
1370de2362d3Smrg		{
1371de2362d3Smrg			int k;
1372de2362d3Smrg			for (k = 0; k < drmmode->mode_res->count_encoders; k++) {
1373de2362d3Smrg				if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id)
1374de2362d3Smrg					drmmode_output->enc_mask |= (1 << k);
1375de2362d3Smrg			}
1376de2362d3Smrg
1377de2362d3Smrg			drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones;
1378de2362d3Smrg		}
1379de2362d3Smrg	}
1380de2362d3Smrg
1381de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
1382de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
1383de2362d3Smrg		output->possible_clones = find_clones(scrn, output);
1384de2362d3Smrg	}
1385de2362d3Smrg}
1386de2362d3Smrg
1387de2362d3Smrg/* returns height alignment in pixels */
1388de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling)
1389de2362d3Smrg{
1390de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
1391de2362d3Smrg	int height_align = 1;
1392de2362d3Smrg
1393de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1394de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
1395de2362d3Smrg			height_align =  info->num_channels * 8;
1396de2362d3Smrg		else if (tiling & RADEON_TILING_MICRO)
1397de2362d3Smrg			height_align = 8;
1398de2362d3Smrg		else
1399de2362d3Smrg			height_align = 8;
1400de2362d3Smrg	} else {
1401de2362d3Smrg		if (tiling & RADEON_TILING_MICRO_SQUARE)
1402de2362d3Smrg			height_align =  32;
1403de2362d3Smrg		else if (tiling)
1404de2362d3Smrg			height_align = 16;
1405de2362d3Smrg		else
1406de2362d3Smrg			height_align = 1;
1407de2362d3Smrg	}
1408de2362d3Smrg	return height_align;
1409de2362d3Smrg}
1410de2362d3Smrg
1411de2362d3Smrg/* returns pitch alignment in pixels */
1412de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
1413de2362d3Smrg{
1414de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
1415de2362d3Smrg	int pitch_align = 1;
1416de2362d3Smrg
1417de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1418de2362d3Smrg		if (tiling & RADEON_TILING_MACRO) {
1419de2362d3Smrg			/* general surface requirements */
1420de2362d3Smrg			pitch_align = MAX(info->num_banks,
1421de2362d3Smrg					  (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8;
1422de2362d3Smrg			/* further restrictions for scanout */
1423de2362d3Smrg			pitch_align = MAX(info->num_banks * 8, pitch_align);
1424de2362d3Smrg		} else if (tiling & RADEON_TILING_MICRO) {
1425de2362d3Smrg			/* general surface requirements */
1426de2362d3Smrg			pitch_align = MAX(8, (info->group_bytes / (8 * bpe)));
1427de2362d3Smrg			/* further restrictions for scanout */
1428de2362d3Smrg			pitch_align = MAX(info->group_bytes / bpe, pitch_align);
1429de2362d3Smrg		} else {
1430de2362d3Smrg			if (info->have_tiling_info)
1431de2362d3Smrg				/* linear aligned requirements */
1432de2362d3Smrg				pitch_align = MAX(64, info->group_bytes / bpe);
1433de2362d3Smrg			else
1434de2362d3Smrg				/* default to 512 elements if we don't know the real
1435de2362d3Smrg				 * group size otherwise the kernel may reject the CS
1436de2362d3Smrg				 * if the group sizes don't match as the pitch won't
1437de2362d3Smrg				 * be aligned properly.
1438de2362d3Smrg				 */
1439de2362d3Smrg				pitch_align = 512;
1440de2362d3Smrg		}
1441de2362d3Smrg	} else {
1442de2362d3Smrg		/* general surface requirements */
1443de2362d3Smrg		if (tiling)
1444de2362d3Smrg			pitch_align = 256 / bpe;
1445de2362d3Smrg		else
1446de2362d3Smrg			pitch_align = 64;
1447de2362d3Smrg	}
1448de2362d3Smrg	return pitch_align;
1449de2362d3Smrg}
1450de2362d3Smrg
1451de2362d3Smrg/* returns base alignment in bytes */
1452de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
1453de2362d3Smrg{
1454de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
1455de2362d3Smrg	int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling);
1456de2362d3Smrg	int height_align = drmmode_get_height_align(scrn, tiling);
1457de2362d3Smrg	int base_align = RADEON_GPU_PAGE_SIZE;
1458de2362d3Smrg
1459de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1460de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
1461de2362d3Smrg			base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe,
1462de2362d3Smrg					 pixel_align * bpe * height_align);
1463de2362d3Smrg		else {
1464de2362d3Smrg			if (info->have_tiling_info)
1465de2362d3Smrg				base_align = info->group_bytes;
1466de2362d3Smrg			else
1467de2362d3Smrg				/* default to 512 if we don't know the real
1468de2362d3Smrg				 * group size otherwise the kernel may reject the CS
1469de2362d3Smrg				 * if the group sizes don't match as the base won't
1470de2362d3Smrg				 * be aligned properly.
1471de2362d3Smrg				 */
1472de2362d3Smrg				base_align = 512;
1473de2362d3Smrg		}
1474de2362d3Smrg	}
1475de2362d3Smrg	return base_align;
1476de2362d3Smrg}
1477de2362d3Smrg
1478de2362d3Smrgstatic Bool
1479de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
1480de2362d3Smrg{
1481de2362d3Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1482de2362d3Smrg	drmmode_crtc_private_ptr
1483de2362d3Smrg		    drmmode_crtc = xf86_config->crtc[0]->driver_private;
1484de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1485de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
1486de2362d3Smrg	struct radeon_bo *old_front = NULL;
1487de2362d3Smrg	Bool	    ret;
1488de2362d3Smrg	ScreenPtr   screen = xf86ScrnToScreen(scrn);
1489de2362d3Smrg	uint32_t    old_fb_id;
1490de2362d3Smrg	int	    i, pitch, old_width, old_height, old_pitch;
1491de2362d3Smrg	uint32_t screen_size;
1492de2362d3Smrg	int cpp = info->pixel_bytes;
1493de2362d3Smrg	struct radeon_bo *front_bo;
1494de2362d3Smrg	struct radeon_surface surface;
1495de2362d3Smrg	struct radeon_surface *psurface;
1496de2362d3Smrg	uint32_t tiling_flags = 0, base_align;
1497de2362d3Smrg	PixmapPtr ppix = screen->GetScreenPixmap(screen);
1498de2362d3Smrg	void *fb_shadow;
1499de2362d3Smrg
1500de2362d3Smrg	if (scrn->virtualX == width && scrn->virtualY == height)
1501de2362d3Smrg		return TRUE;
1502de2362d3Smrg
1503de2362d3Smrg	front_bo = info->front_bo;
1504de2362d3Smrg	radeon_cs_flush_indirect(scrn);
1505de2362d3Smrg
1506de2362d3Smrg	if (front_bo)
1507de2362d3Smrg		radeon_bo_wait(front_bo);
1508de2362d3Smrg
1509de2362d3Smrg	if (info->allowColorTiling) {
1510de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_R600) {
1511de2362d3Smrg			if (info->allowColorTiling2D) {
1512de2362d3Smrg				tiling_flags |= RADEON_TILING_MACRO;
1513de2362d3Smrg			} else {
1514de2362d3Smrg				tiling_flags |= RADEON_TILING_MICRO;
1515de2362d3Smrg			}
1516de2362d3Smrg		} else
1517de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
1518de2362d3Smrg	}
1519de2362d3Smrg
1520de2362d3Smrg	pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(scrn, cpp, tiling_flags)) * cpp;
1521de2362d3Smrg	height = RADEON_ALIGN(height, drmmode_get_height_align(scrn, tiling_flags));
1522de2362d3Smrg	screen_size = RADEON_ALIGN(pitch * height, RADEON_GPU_PAGE_SIZE);
1523de2362d3Smrg	base_align = 4096;
1524de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1525de2362d3Smrg		memset(&surface, 0, sizeof(struct radeon_surface));
1526de2362d3Smrg		surface.npix_x = width;
1527de2362d3Smrg		surface.npix_y = height;
1528de2362d3Smrg		surface.npix_z = 1;
1529de2362d3Smrg		surface.blk_w = 1;
1530de2362d3Smrg		surface.blk_h = 1;
1531de2362d3Smrg		surface.blk_d = 1;
1532de2362d3Smrg		surface.array_size = 1;
1533de2362d3Smrg		surface.last_level = 0;
1534de2362d3Smrg		surface.bpe = cpp;
1535de2362d3Smrg		surface.nsamples = 1;
1536de2362d3Smrg		surface.flags = RADEON_SURF_SCANOUT;
1537de2362d3Smrg		/* we are requiring a recent enough libdrm version */
1538de2362d3Smrg		surface.flags |= RADEON_SURF_HAS_TILE_MODE_INDEX;
1539de2362d3Smrg		surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
1540de2362d3Smrg		surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE);
1541de2362d3Smrg		if (tiling_flags & RADEON_TILING_MICRO) {
1542de2362d3Smrg			surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
1543de2362d3Smrg			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
1544de2362d3Smrg		}
1545de2362d3Smrg		if (tiling_flags & RADEON_TILING_MACRO) {
1546de2362d3Smrg			surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
1547de2362d3Smrg			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
1548de2362d3Smrg		}
1549de2362d3Smrg		if (radeon_surface_best(info->surf_man, &surface)) {
1550de2362d3Smrg			return FALSE;
1551de2362d3Smrg		}
1552de2362d3Smrg		if (radeon_surface_init(info->surf_man, &surface)) {
1553de2362d3Smrg			return FALSE;
1554de2362d3Smrg		}
1555de2362d3Smrg		screen_size = surface.bo_size;
1556de2362d3Smrg		base_align = surface.bo_alignment;
1557de2362d3Smrg		pitch = surface.level[0].pitch_bytes;
1558de2362d3Smrg		tiling_flags = 0;
1559de2362d3Smrg		switch (surface.level[0].mode) {
1560de2362d3Smrg		case RADEON_SURF_MODE_2D:
1561de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
1562de2362d3Smrg			tiling_flags |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT;
1563de2362d3Smrg			tiling_flags |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT;
1564de2362d3Smrg			tiling_flags |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT;
1565de2362d3Smrg			tiling_flags |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT;
1566de2362d3Smrg			break;
1567de2362d3Smrg		case RADEON_SURF_MODE_1D:
1568de2362d3Smrg			tiling_flags |= RADEON_TILING_MICRO;
1569de2362d3Smrg			break;
1570de2362d3Smrg		default:
1571de2362d3Smrg			break;
1572de2362d3Smrg		}
1573de2362d3Smrg		info->front_surface = surface;
1574de2362d3Smrg	}
1575de2362d3Smrg
1576de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1577de2362d3Smrg		   "Allocate new frame buffer %dx%d stride %d\n",
1578de2362d3Smrg		   width, height, pitch / cpp);
1579de2362d3Smrg
1580de2362d3Smrg	old_width = scrn->virtualX;
1581de2362d3Smrg	old_height = scrn->virtualY;
1582de2362d3Smrg	old_pitch = scrn->displayWidth;
1583de2362d3Smrg	old_fb_id = drmmode->fb_id;
1584de2362d3Smrg	old_front = info->front_bo;
1585de2362d3Smrg
1586de2362d3Smrg	scrn->virtualX = width;
1587de2362d3Smrg	scrn->virtualY = height;
1588de2362d3Smrg	scrn->displayWidth = pitch / cpp;
1589de2362d3Smrg
1590de2362d3Smrg	info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align, RADEON_GEM_DOMAIN_VRAM, 0);
1591de2362d3Smrg	if (!info->front_bo)
1592de2362d3Smrg		goto fail;
1593de2362d3Smrg
1594de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
1595de2362d3Smrg	switch (cpp) {
1596de2362d3Smrg	case 4:
1597de2362d3Smrg	    tiling_flags |= RADEON_TILING_SWAP_32BIT;
1598de2362d3Smrg	    break;
1599de2362d3Smrg	case 2:
1600de2362d3Smrg	    tiling_flags |= RADEON_TILING_SWAP_16BIT;
1601de2362d3Smrg	    break;
1602de2362d3Smrg	}
1603de2362d3Smrg	if (info->ChipFamily < CHIP_FAMILY_R600 &&
1604de2362d3Smrg	    info->r600_shadow_fb && tiling_flags)
1605de2362d3Smrg	    tiling_flags |= RADEON_TILING_SURFACE;
1606de2362d3Smrg#endif
1607de2362d3Smrg	if (tiling_flags)
1608de2362d3Smrg	    radeon_bo_set_tiling(info->front_bo, tiling_flags, pitch);
1609de2362d3Smrg
1610de2362d3Smrg	ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
1611de2362d3Smrg			   scrn->bitsPerPixel, pitch,
1612de2362d3Smrg			   info->front_bo->handle,
1613de2362d3Smrg			   &drmmode->fb_id);
1614de2362d3Smrg	if (ret)
1615de2362d3Smrg		goto fail;
1616de2362d3Smrg
1617de2362d3Smrg	if (!info->r600_shadow_fb) {
1618de2362d3Smrg		radeon_set_pixmap_bo(ppix, info->front_bo);
1619de2362d3Smrg		psurface = radeon_get_pixmap_surface(ppix);
1620de2362d3Smrg		*psurface = info->front_surface;
1621de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
1622de2362d3Smrg					   width, height, -1, -1, pitch, NULL);
1623de2362d3Smrg	} else {
1624de2362d3Smrg		if (radeon_bo_map(info->front_bo, 1))
1625de2362d3Smrg			goto fail;
1626de2362d3Smrg		fb_shadow = calloc(1, screen_size);
1627de2362d3Smrg		if (fb_shadow == NULL)
1628de2362d3Smrg			goto fail;
1629de2362d3Smrg		free(info->fb_shadow);
1630de2362d3Smrg		info->fb_shadow = fb_shadow;
1631de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
1632de2362d3Smrg					   width, height, -1, -1, pitch,
1633de2362d3Smrg					   info->fb_shadow);
1634de2362d3Smrg	}
1635de2362d3Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,9,99,1,0)
1636de2362d3Smrg	scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr;
1637de2362d3Smrg#endif
1638de2362d3Smrg
1639de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
1640de2362d3Smrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
1641de2362d3Smrg
1642de2362d3Smrg		if (!crtc->enabled)
1643de2362d3Smrg			continue;
1644de2362d3Smrg
1645de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode,
1646de2362d3Smrg				       crtc->rotation, crtc->x, crtc->y);
1647de2362d3Smrg	}
1648de2362d3Smrg
1649de2362d3Smrg	if (info->use_glamor)
1650de2362d3Smrg		radeon_glamor_create_screen_resources(scrn->pScreen);
1651de2362d3Smrg
1652de2362d3Smrg	if (old_fb_id)
1653de2362d3Smrg		drmModeRmFB(drmmode->fd, old_fb_id);
1654de2362d3Smrg	if (old_front)
1655de2362d3Smrg		radeon_bo_unref(old_front);
1656de2362d3Smrg
1657de2362d3Smrg	radeon_kms_update_vram_limit(scrn, screen_size);
1658de2362d3Smrg	return TRUE;
1659de2362d3Smrg
1660de2362d3Smrg fail:
1661de2362d3Smrg	if (info->front_bo)
1662de2362d3Smrg		radeon_bo_unref(info->front_bo);
1663de2362d3Smrg	info->front_bo = old_front;
1664de2362d3Smrg	scrn->virtualX = old_width;
1665de2362d3Smrg	scrn->virtualY = old_height;
1666de2362d3Smrg	scrn->displayWidth = old_pitch;
1667de2362d3Smrg	drmmode->fb_id = old_fb_id;
1668de2362d3Smrg
1669de2362d3Smrg	return FALSE;
1670de2362d3Smrg}
1671de2362d3Smrg
1672de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
1673de2362d3Smrg	drmmode_xf86crtc_resize
1674de2362d3Smrg};
1675de2362d3Smrg
1676de2362d3Smrgstatic void
1677de2362d3Smrgdrmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
1678de2362d3Smrg			unsigned int tv_usec, void *event_data)
1679de2362d3Smrg{
1680de2362d3Smrg	radeon_dri2_frame_event_handler(frame, tv_sec, tv_usec, event_data);
1681de2362d3Smrg}
1682de2362d3Smrg
1683de2362d3Smrgstatic void
1684de2362d3Smrgdrmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
1685de2362d3Smrg		     unsigned int tv_usec, void *event_data)
1686de2362d3Smrg{
1687de2362d3Smrg	drmmode_flipevtcarrier_ptr flipcarrier = event_data;
1688de2362d3Smrg	drmmode_flipdata_ptr flipdata = flipcarrier->flipdata;
1689de2362d3Smrg	drmmode_ptr drmmode = flipdata->drmmode;
1690de2362d3Smrg
1691de2362d3Smrg	/* Is this the event whose info shall be delivered to higher level? */
1692de2362d3Smrg	if (flipcarrier->dispatch_me) {
1693de2362d3Smrg		/* Yes: Cache msc, ust for later delivery. */
1694de2362d3Smrg		flipdata->fe_frame = frame;
1695de2362d3Smrg		flipdata->fe_tv_sec = tv_sec;
1696de2362d3Smrg		flipdata->fe_tv_usec = tv_usec;
1697de2362d3Smrg	}
1698de2362d3Smrg	free(flipcarrier);
1699de2362d3Smrg
1700de2362d3Smrg	/* Last crtc completed flip? */
1701de2362d3Smrg	flipdata->flip_count--;
1702de2362d3Smrg	if (flipdata->flip_count > 0)
1703de2362d3Smrg		return;
1704de2362d3Smrg
1705de2362d3Smrg	/* Release framebuffer */
1706de2362d3Smrg	drmModeRmFB(drmmode->fd, flipdata->old_fb_id);
1707de2362d3Smrg
1708de2362d3Smrg	if (flipdata->event_data == NULL)
1709de2362d3Smrg		return;
1710de2362d3Smrg
1711de2362d3Smrg	/* Deliver cached msc, ust from reference crtc to flip event handler */
1712de2362d3Smrg	radeon_dri2_flip_event_handler(flipdata->fe_frame, flipdata->fe_tv_sec,
1713de2362d3Smrg				       flipdata->fe_tv_usec, flipdata->event_data);
1714de2362d3Smrg
1715de2362d3Smrg	free(flipdata);
1716de2362d3Smrg}
1717de2362d3Smrg
1718de2362d3Smrg
1719de2362d3Smrgstatic void
1720de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p)
1721de2362d3Smrg{
1722de2362d3Smrg	drmmode_ptr drmmode = data;
1723de2362d3Smrg	fd_set *read_mask = p;
1724de2362d3Smrg
1725de2362d3Smrg	if (err >= 0 && FD_ISSET(drmmode->fd, read_mask)) {
1726de2362d3Smrg		drmHandleEvent(drmmode->fd, &drmmode->event_context);
1727de2362d3Smrg	}
1728de2362d3Smrg}
1729de2362d3Smrg
1730de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
1731de2362d3Smrg{
1732de2362d3Smrg	int i, num_dvi = 0, num_hdmi = 0;
1733de2362d3Smrg
1734de2362d3Smrg	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
1735de2362d3Smrg
1736de2362d3Smrg	drmmode->scrn = pScrn;
1737de2362d3Smrg	drmmode->cpp = cpp;
1738de2362d3Smrg	drmmode->mode_res = drmModeGetResources(drmmode->fd);
1739de2362d3Smrg	if (!drmmode->mode_res)
1740de2362d3Smrg		return FALSE;
1741de2362d3Smrg
1742de2362d3Smrg	xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height);
1743de2362d3Smrg	for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
1744de2362d3Smrg		if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i)
1745de2362d3Smrg			drmmode_crtc_init(pScrn, drmmode, i);
1746de2362d3Smrg
1747de2362d3Smrg	for (i = 0; i < drmmode->mode_res->count_connectors; i++)
1748de2362d3Smrg		drmmode_output_init(pScrn, drmmode, i, &num_dvi, &num_hdmi);
1749de2362d3Smrg
1750de2362d3Smrg	/* workout clones */
1751de2362d3Smrg	drmmode_clones_init(pScrn, drmmode);
1752de2362d3Smrg
1753de2362d3Smrg#ifdef RADEON_PIXMAP_SHARING
1754de2362d3Smrg	xf86ProviderSetup(pScrn, NULL, "radeon");
1755de2362d3Smrg#endif
1756de2362d3Smrg
1757de2362d3Smrg	xf86InitialConfiguration(pScrn, TRUE);
1758de2362d3Smrg
1759de2362d3Smrg	drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
1760de2362d3Smrg	drmmode->event_context.vblank_handler = drmmode_vblank_handler;
1761de2362d3Smrg	drmmode->event_context.page_flip_handler = drmmode_flip_handler;
1762de2362d3Smrg
1763de2362d3Smrg	return TRUE;
1764de2362d3Smrg}
1765de2362d3Smrg
1766de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1767de2362d3Smrg{
1768de2362d3Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1769de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1770de2362d3Smrg
1771de2362d3Smrg	if (info->dri2.pKernelDRMVersion->version_minor < 4)
1772de2362d3Smrg		return;
1773de2362d3Smrg
1774de2362d3Smrg	info->drmmode_inited = TRUE;
1775de2362d3Smrg	if (pRADEONEnt->fd_wakeup_registered != serverGeneration) {
1776de2362d3Smrg		AddGeneralSocket(drmmode->fd);
1777de2362d3Smrg		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1778de2362d3Smrg				drm_wakeup_handler, drmmode);
1779de2362d3Smrg		pRADEONEnt->fd_wakeup_registered = serverGeneration;
1780de2362d3Smrg		pRADEONEnt->fd_wakeup_ref = 1;
1781de2362d3Smrg	} else
1782de2362d3Smrg		pRADEONEnt->fd_wakeup_ref++;
1783de2362d3Smrg}
1784de2362d3Smrg
1785de2362d3Smrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1786de2362d3Smrg{
1787de2362d3Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1788de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1789de2362d3Smrg
1790de2362d3Smrg	if (info->dri2.pKernelDRMVersion->version_minor < 4 || !info->drmmode_inited)
1791de2362d3Smrg		return;
1792de2362d3Smrg
1793de2362d3Smrg	if (pRADEONEnt->fd_wakeup_registered == serverGeneration &&
1794de2362d3Smrg	    !--pRADEONEnt->fd_wakeup_ref) {
1795de2362d3Smrg		RemoveGeneralSocket(drmmode->fd);
1796de2362d3Smrg		RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1797de2362d3Smrg				drm_wakeup_handler, drmmode);
1798de2362d3Smrg	}
1799de2362d3Smrg}
1800de2362d3Smrg
1801de2362d3Smrg
1802de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr)
1803de2362d3Smrg{
1804de2362d3Smrg	drmmode->bufmgr = bufmgr;
1805de2362d3Smrg	return TRUE;
1806de2362d3Smrg}
1807de2362d3Smrg
1808de2362d3Smrg
1809de2362d3Smrg
1810de2362d3Smrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo)
1811de2362d3Smrg{
1812de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1813de2362d3Smrg	xf86CrtcPtr crtc = xf86_config->crtc[id];
1814de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1815de2362d3Smrg
1816de2362d3Smrg	drmmode_crtc->cursor_bo = bo;
1817de2362d3Smrg}
1818de2362d3Smrg
1819de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
1820de2362d3Smrg{
1821de2362d3Smrg	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
1822de2362d3Smrg	xf86OutputPtr  output = config->output[config->compat_output];
1823de2362d3Smrg	xf86CrtcPtr	crtc = output->crtc;
1824de2362d3Smrg
1825de2362d3Smrg	if (crtc && crtc->enabled) {
1826de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
1827de2362d3Smrg				       x, y);
1828de2362d3Smrg	}
1829de2362d3Smrg}
1830de2362d3Smrg
1831de2362d3SmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1832de2362d3Smrg{
1833de2362d3Smrg	xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1834de2362d3Smrg	int c;
1835de2362d3Smrg
1836de2362d3Smrg	drmmode_copy_fb(pScrn, drmmode);
1837de2362d3Smrg
1838de2362d3Smrg	for (c = 0; c < config->num_crtc; c++) {
1839de2362d3Smrg		xf86CrtcPtr	crtc = config->crtc[c];
1840de2362d3Smrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1841de2362d3Smrg		xf86OutputPtr	output = NULL;
1842de2362d3Smrg		int		o;
1843de2362d3Smrg
1844de2362d3Smrg		/* Skip disabled CRTCs */
1845de2362d3Smrg		if (!crtc->enabled) {
1846de2362d3Smrg			drmmode_do_crtc_dpms(crtc, DPMSModeOff);
1847de2362d3Smrg			drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1848de2362d3Smrg				       0, 0, 0, NULL, 0, NULL);
1849de2362d3Smrg			continue;
1850de2362d3Smrg		}
1851de2362d3Smrg
1852de2362d3Smrg		if (config->output[config->compat_output]->crtc == crtc)
1853de2362d3Smrg			output = config->output[config->compat_output];
1854de2362d3Smrg		else
1855de2362d3Smrg		{
1856de2362d3Smrg			for (o = 0; o < config->num_output; o++)
1857de2362d3Smrg				if (config->output[o]->crtc == crtc)
1858de2362d3Smrg				{
1859de2362d3Smrg					output = config->output[o];
1860de2362d3Smrg					break;
1861de2362d3Smrg				}
1862de2362d3Smrg		}
1863de2362d3Smrg		/* paranoia */
1864de2362d3Smrg		if (!output)
1865de2362d3Smrg			continue;
1866de2362d3Smrg
1867de2362d3Smrg		/* Mark that we'll need to re-set the mode for sure */
1868de2362d3Smrg		memset(&crtc->mode, 0, sizeof(crtc->mode));
1869de2362d3Smrg		if (!crtc->desiredMode.CrtcHDisplay)
1870de2362d3Smrg		{
1871de2362d3Smrg			DisplayModePtr  mode = xf86OutputFindClosestMode (output, pScrn->currentMode);
1872de2362d3Smrg
1873de2362d3Smrg			if (!mode)
1874de2362d3Smrg				return FALSE;
1875de2362d3Smrg			crtc->desiredMode = *mode;
1876de2362d3Smrg			crtc->desiredRotation = RR_Rotate_0;
1877de2362d3Smrg			crtc->desiredX = 0;
1878de2362d3Smrg			crtc->desiredY = 0;
1879de2362d3Smrg		}
1880de2362d3Smrg
1881de2362d3Smrg		if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
1882de2362d3Smrg						 crtc->desiredX, crtc->desiredY))
1883de2362d3Smrg			return FALSE;
1884de2362d3Smrg	}
1885de2362d3Smrg	return TRUE;
1886de2362d3Smrg}
1887de2362d3Smrg
1888de2362d3Smrgstatic void drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
1889de2362d3Smrg                                 int *indices, LOCO *colors, VisualPtr pVisual)
1890de2362d3Smrg{
1891de2362d3Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1892de2362d3Smrg    uint16_t       lut_r[256], lut_g[256], lut_b[256];
1893de2362d3Smrg    int index, j, i;
1894de2362d3Smrg    int c;
1895de2362d3Smrg
1896de2362d3Smrg    for (c = 0; c < xf86_config->num_crtc; c++) {
1897de2362d3Smrg        xf86CrtcPtr crtc = xf86_config->crtc[c];
1898de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1899de2362d3Smrg
1900de2362d3Smrg        for (i = 0 ; i < 256; i++) {
1901de2362d3Smrg            lut_r[i] = drmmode_crtc->lut_r[i] << 6;
1902de2362d3Smrg            lut_g[i] = drmmode_crtc->lut_g[i] << 6;
1903de2362d3Smrg            lut_b[i] = drmmode_crtc->lut_b[i] << 6;
1904de2362d3Smrg        }
1905de2362d3Smrg
1906de2362d3Smrg        switch(pScrn->depth) {
1907de2362d3Smrg        case 15:
1908de2362d3Smrg            for (i = 0; i < numColors; i++) {
1909de2362d3Smrg                index = indices[i];
1910de2362d3Smrg                for (j = 0; j < 8; j++) {
1911de2362d3Smrg                    lut_r[index * 8 + j] = colors[index].red << 6;
1912de2362d3Smrg                    lut_g[index * 8 + j] = colors[index].green << 6;
1913de2362d3Smrg                    lut_b[index * 8 + j] = colors[index].blue << 6;
1914de2362d3Smrg                }
1915de2362d3Smrg            }
1916de2362d3Smrg         break;
1917de2362d3Smrg         case 16:
1918de2362d3Smrg             for (i = 0; i < numColors; i++) {
1919de2362d3Smrg                 index = indices[i];
1920de2362d3Smrg
1921de2362d3Smrg                  if (i <= 31) {
1922de2362d3Smrg                      for (j = 0; j < 8; j++) {
1923de2362d3Smrg                          lut_r[index * 8 + j] = colors[index].red << 6;
1924de2362d3Smrg                          lut_b[index * 8 + j] = colors[index].blue << 6;
1925de2362d3Smrg                      }
1926de2362d3Smrg                  }
1927de2362d3Smrg
1928de2362d3Smrg                  for (j = 0; j < 4; j++) {
1929de2362d3Smrg                      lut_g[index * 4 + j] = colors[index].green << 6;
1930de2362d3Smrg                  }
1931de2362d3Smrg              }
1932de2362d3Smrg	  break;
1933de2362d3Smrg          default:
1934de2362d3Smrg              for (i = 0; i < numColors; i++) {
1935de2362d3Smrg                  index = indices[i];
1936de2362d3Smrg                  lut_r[index] = colors[index].red << 6;
1937de2362d3Smrg                  lut_g[index] = colors[index].green << 6;
1938de2362d3Smrg                  lut_b[index] = colors[index].blue << 6;
1939de2362d3Smrg              }
1940de2362d3Smrg              break;
1941de2362d3Smrg          }
1942de2362d3Smrg
1943de2362d3Smrg    /* Make the change through RandR */
1944de2362d3Smrg        if (crtc->randr_crtc)
1945de2362d3Smrg            RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
1946de2362d3Smrg        else
1947de2362d3Smrg            crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
1948de2362d3Smrg     }
1949de2362d3Smrg}
1950de2362d3Smrg
1951de2362d3SmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
1952de2362d3Smrg{
1953de2362d3Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1954de2362d3Smrg
1955de2362d3Smrg    if (xf86_config->num_crtc) {
1956de2362d3Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1957de2362d3Smrg		       "Initializing kms color map\n");
1958de2362d3Smrg	if (!miCreateDefColormap(pScreen))
1959de2362d3Smrg	    return FALSE;
1960de2362d3Smrg	/* all radeons support 10 bit CLUTs */
1961de2362d3Smrg	if (!xf86HandleColormaps(pScreen, 256, 10,
1962de2362d3Smrg				 drmmode_load_palette, NULL,
1963de2362d3Smrg				 CMAP_PALETTED_TRUECOLOR
1964de2362d3Smrg#if 0 /* This option messes up text mode! (eich@suse.de) */
1965de2362d3Smrg				 | CMAP_LOAD_EVEN_IF_OFFSCREEN
1966de2362d3Smrg#endif
1967de2362d3Smrg				 | CMAP_RELOAD_ON_MODE_SWITCH))
1968de2362d3Smrg	    return FALSE;
1969de2362d3Smrg    }
1970de2362d3Smrg    return TRUE;
1971de2362d3Smrg}
1972de2362d3Smrg
1973de2362d3Smrg#ifdef HAVE_LIBUDEV
1974de2362d3Smrgstatic void
1975de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure)
1976de2362d3Smrg{
1977de2362d3Smrg	drmmode_ptr drmmode = closure;
1978de2362d3Smrg	ScrnInfoPtr scrn = drmmode->scrn;
1979de2362d3Smrg	struct udev_device *dev;
1980de2362d3Smrg	dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1981de2362d3Smrg	if (!dev)
1982de2362d3Smrg		return;
1983de2362d3Smrg
1984de2362d3Smrg	RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
1985de2362d3Smrg	udev_device_unref(dev);
1986de2362d3Smrg}
1987de2362d3Smrg#endif
1988de2362d3Smrg
1989de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1990de2362d3Smrg{
1991de2362d3Smrg#ifdef HAVE_LIBUDEV
1992de2362d3Smrg	struct udev *u;
1993de2362d3Smrg	struct udev_monitor *mon;
1994de2362d3Smrg
1995de2362d3Smrg	u = udev_new();
1996de2362d3Smrg	if (!u)
1997de2362d3Smrg		return;
1998de2362d3Smrg	mon = udev_monitor_new_from_netlink(u, "udev");
1999de2362d3Smrg	if (!mon) {
2000de2362d3Smrg		udev_unref(u);
2001de2362d3Smrg		return;
2002de2362d3Smrg	}
2003de2362d3Smrg
2004de2362d3Smrg	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
2005de2362d3Smrg							    "drm",
2006de2362d3Smrg							    "drm_minor") < 0 ||
2007de2362d3Smrg	    udev_monitor_enable_receiving(mon) < 0) {
2008de2362d3Smrg		udev_monitor_unref(mon);
2009de2362d3Smrg		udev_unref(u);
2010de2362d3Smrg		return;
2011de2362d3Smrg	}
2012de2362d3Smrg
2013de2362d3Smrg	drmmode->uevent_handler =
2014de2362d3Smrg		xf86AddGeneralHandler(udev_monitor_get_fd(mon),
2015de2362d3Smrg				      drmmode_handle_uevents,
2016de2362d3Smrg				      drmmode);
2017de2362d3Smrg
2018de2362d3Smrg	drmmode->uevent_monitor = mon;
2019de2362d3Smrg#endif
2020de2362d3Smrg}
2021de2362d3Smrg
2022de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2023de2362d3Smrg{
2024de2362d3Smrg#ifdef HAVE_LIBUDEV
2025de2362d3Smrg	if (drmmode->uevent_handler) {
2026de2362d3Smrg		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
2027de2362d3Smrg		xf86RemoveGeneralHandler(drmmode->uevent_handler);
2028de2362d3Smrg
2029de2362d3Smrg		udev_monitor_unref(drmmode->uevent_monitor);
2030de2362d3Smrg		udev_unref(u);
2031de2362d3Smrg	}
2032de2362d3Smrg#endif
2033de2362d3Smrg}
2034de2362d3Smrg
2035de2362d3SmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id)
2036de2362d3Smrg{
2037de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
2038de2362d3Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2039de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
2040de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
2041de2362d3Smrg	unsigned int pitch;
2042de2362d3Smrg	int i, old_fb_id;
2043de2362d3Smrg	uint32_t tiling_flags = 0;
2044de2362d3Smrg	int height, emitted = 0;
2045de2362d3Smrg	drmmode_flipdata_ptr flipdata;
2046de2362d3Smrg	drmmode_flipevtcarrier_ptr flipcarrier;
2047de2362d3Smrg
2048de2362d3Smrg	if (info->allowColorTiling) {
2049de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_R600)
2050de2362d3Smrg			tiling_flags |= RADEON_TILING_MICRO;
2051de2362d3Smrg		else
2052de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
2053de2362d3Smrg	}
2054de2362d3Smrg
2055de2362d3Smrg	pitch = RADEON_ALIGN(scrn->displayWidth, drmmode_get_pitch_align(scrn, info->pixel_bytes, tiling_flags)) *
2056de2362d3Smrg		info->pixel_bytes;
2057de2362d3Smrg	height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags));
2058de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
2059de2362d3Smrg		pitch = info->front_surface.level[0].pitch_bytes;
2060de2362d3Smrg	}
2061de2362d3Smrg
2062de2362d3Smrg	/*
2063de2362d3Smrg	 * Create a new handle for the back buffer
2064de2362d3Smrg	 */
2065de2362d3Smrg	old_fb_id = drmmode->fb_id;
2066de2362d3Smrg	if (drmModeAddFB(drmmode->fd, scrn->virtualX, height,
2067de2362d3Smrg			 scrn->depth, scrn->bitsPerPixel, pitch,
2068de2362d3Smrg			 new_front->handle, &drmmode->fb_id))
2069de2362d3Smrg		goto error_out;
2070de2362d3Smrg
2071de2362d3Smrg        flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
2072de2362d3Smrg        if (!flipdata) {
2073de2362d3Smrg             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2074de2362d3Smrg                        "flip queue: data alloc failed.\n");
2075de2362d3Smrg             goto error_undo;
2076de2362d3Smrg        }
2077de2362d3Smrg	/*
2078de2362d3Smrg	 * Queue flips on all enabled CRTCs
2079de2362d3Smrg	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
2080de2362d3Smrg	 * Right now it assumes a single shared fb across all CRTCs, with the
2081de2362d3Smrg	 * kernel fixing up the offset of each CRTC as necessary.
2082de2362d3Smrg	 *
2083de2362d3Smrg	 * Also, flips queued on disabled or incorrectly configured displays
2084de2362d3Smrg	 * may never complete; this is a configuration error.
2085de2362d3Smrg	 */
2086de2362d3Smrg
2087de2362d3Smrg        flipdata->event_data = data;
2088de2362d3Smrg        flipdata->drmmode = drmmode;
2089de2362d3Smrg
2090de2362d3Smrg	for (i = 0; i < config->num_crtc; i++) {
2091de2362d3Smrg		if (!config->crtc[i]->enabled)
2092de2362d3Smrg			continue;
2093de2362d3Smrg
2094de2362d3Smrg		flipdata->flip_count++;
2095de2362d3Smrg		drmmode_crtc = config->crtc[i]->driver_private;
2096de2362d3Smrg
2097de2362d3Smrg		flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec));
2098de2362d3Smrg		if (!flipcarrier) {
2099de2362d3Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2100de2362d3Smrg				   "flip queue: carrier alloc failed.\n");
2101de2362d3Smrg			if (emitted == 0)
2102de2362d3Smrg				free(flipdata);
2103de2362d3Smrg			goto error_undo;
2104de2362d3Smrg		}
2105de2362d3Smrg
2106de2362d3Smrg		/* Only the reference crtc will finally deliver its page flip
2107de2362d3Smrg		 * completion event. All other crtc's events will be discarded.
2108de2362d3Smrg		 */
2109de2362d3Smrg		flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id);
2110de2362d3Smrg		flipcarrier->flipdata = flipdata;
2111de2362d3Smrg
2112de2362d3Smrg		if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
2113de2362d3Smrg				    drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) {
2114de2362d3Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2115de2362d3Smrg				   "flip queue failed: %s\n", strerror(errno));
2116de2362d3Smrg			free(flipcarrier);
2117de2362d3Smrg			if (emitted == 0)
2118de2362d3Smrg				free(flipdata);
2119de2362d3Smrg			goto error_undo;
2120de2362d3Smrg		}
2121de2362d3Smrg		emitted++;
2122de2362d3Smrg	}
2123de2362d3Smrg
2124de2362d3Smrg	flipdata->old_fb_id = old_fb_id;
2125de2362d3Smrg	return TRUE;
2126de2362d3Smrg
2127de2362d3Smrgerror_undo:
2128de2362d3Smrg	drmModeRmFB(drmmode->fd, drmmode->fb_id);
2129de2362d3Smrg	drmmode->fb_id = old_fb_id;
2130de2362d3Smrg
2131de2362d3Smrgerror_out:
2132de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
2133de2362d3Smrg		   strerror(errno));
2134de2362d3Smrg	return FALSE;
2135de2362d3Smrg}
2136de2362d3Smrg
2137