drmmode_display.c revision 7821949a
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>
337821949aSmrg#ifdef XF86DRM_MODE
34de2362d3Smrg#include <sys/ioctl.h>
35de2362d3Smrg#include "micmap.h"
36de2362d3Smrg#include "xf86cmap.h"
37de2362d3Smrg#include "radeon.h"
38de2362d3Smrg#include "radeon_reg.h"
397821949aSmrg#include "radeon_drm.h"
407821949aSmrg#include "sarea.h"
41de2362d3Smrg
42de2362d3Smrg#include "drmmode_display.h"
43de2362d3Smrg
44de2362d3Smrg/* DPMS */
45de2362d3Smrg#ifdef HAVE_XEXTPROTO_71
46de2362d3Smrg#include <X11/extensions/dpmsconst.h>
47de2362d3Smrg#else
48de2362d3Smrg#define DPMS_SERVER
49de2362d3Smrg#include <X11/extensions/dpms.h>
50de2362d3Smrg#endif
51de2362d3Smrg
52de2362d3Smrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
53de2362d3Smrg					  int width, int height,
54de2362d3Smrg					  int depth, int bpp,
557821949aSmrg					  int pitch, int tiling,
56de2362d3Smrg					  struct radeon_bo *bo, struct radeon_surface *psurf)
57de2362d3Smrg{
58de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
59de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
60de2362d3Smrg	PixmapPtr pixmap;
61de2362d3Smrg	struct radeon_surface *surface;
62de2362d3Smrg
637821949aSmrg	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
64de2362d3Smrg	if (!pixmap)
65de2362d3Smrg		return NULL;
66de2362d3Smrg
677314432eSmrg	if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height,
687314432eSmrg					    depth, bpp, pitch, NULL)) {
697821949aSmrg		return NULL;
707314432eSmrg	}
717314432eSmrg
727821949aSmrg	exaMoveInPixmap(pixmap);
737821949aSmrg	radeon_set_pixmap_bo(pixmap, bo);
74de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
75de2362d3Smrg		surface = radeon_get_pixmap_surface(pixmap);
76de2362d3Smrg		if (surface && psurf)
77de2362d3Smrg			*surface = *psurf;
78de2362d3Smrg		else if (surface) {
79de2362d3Smrg			memset(surface, 0, sizeof(struct radeon_surface));
80de2362d3Smrg			surface->npix_x = width;
81de2362d3Smrg			surface->npix_y = height;
82de2362d3Smrg			surface->npix_z = 1;
83de2362d3Smrg			surface->blk_w = 1;
84de2362d3Smrg			surface->blk_h = 1;
85de2362d3Smrg			surface->blk_d = 1;
86de2362d3Smrg			surface->array_size = 1;
87de2362d3Smrg			surface->last_level = 0;
88de2362d3Smrg			surface->bpe = bpp / 8;
89de2362d3Smrg			surface->nsamples = 1;
90de2362d3Smrg			surface->flags = RADEON_SURF_SCANOUT;
91de2362d3Smrg			surface->flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
92de2362d3Smrg			surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE);
93de2362d3Smrg			if (tiling & RADEON_TILING_MICRO) {
94de2362d3Smrg				surface->flags = RADEON_SURF_CLR(surface->flags, MODE);
95de2362d3Smrg				surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
96de2362d3Smrg			}
97de2362d3Smrg			if (tiling & RADEON_TILING_MACRO) {
98de2362d3Smrg				surface->flags = RADEON_SURF_CLR(surface->flags, MODE);
99de2362d3Smrg				surface->flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
100de2362d3Smrg			}
101de2362d3Smrg			if (radeon_surface_best(info->surf_man, surface)) {
1027821949aSmrg				return NULL;
103de2362d3Smrg			}
104de2362d3Smrg			if (radeon_surface_init(info->surf_man, surface)) {
1057821949aSmrg				return NULL;
106de2362d3Smrg			}
107de2362d3Smrg		}
108de2362d3Smrg	}
109de2362d3Smrg
1107821949aSmrg	return pixmap;
111de2362d3Smrg}
112de2362d3Smrg
113de2362d3Smrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
114de2362d3Smrg{
115de2362d3Smrg	ScreenPtr pScreen = pixmap->drawable.pScreen;
116de2362d3Smrg
117de2362d3Smrg	(*pScreen->DestroyPixmap)(pixmap);
118de2362d3Smrg}
119de2362d3Smrg
120de2362d3Smrgstatic void
121de2362d3Smrgdrmmode_ConvertFromKMode(ScrnInfoPtr	scrn,
122de2362d3Smrg		     drmModeModeInfo *kmode,
123de2362d3Smrg		     DisplayModePtr	mode)
124de2362d3Smrg{
125de2362d3Smrg	memset(mode, 0, sizeof(DisplayModeRec));
126de2362d3Smrg	mode->status = MODE_OK;
127de2362d3Smrg
128de2362d3Smrg	mode->Clock = kmode->clock;
129de2362d3Smrg
130de2362d3Smrg	mode->HDisplay = kmode->hdisplay;
131de2362d3Smrg	mode->HSyncStart = kmode->hsync_start;
132de2362d3Smrg	mode->HSyncEnd = kmode->hsync_end;
133de2362d3Smrg	mode->HTotal = kmode->htotal;
134de2362d3Smrg	mode->HSkew = kmode->hskew;
135de2362d3Smrg
136de2362d3Smrg	mode->VDisplay = kmode->vdisplay;
137de2362d3Smrg	mode->VSyncStart = kmode->vsync_start;
138de2362d3Smrg	mode->VSyncEnd = kmode->vsync_end;
139de2362d3Smrg	mode->VTotal = kmode->vtotal;
140de2362d3Smrg	mode->VScan = kmode->vscan;
141de2362d3Smrg
142de2362d3Smrg	mode->Flags = kmode->flags; //& FLAG_BITS;
143de2362d3Smrg	mode->name = strdup(kmode->name);
144de2362d3Smrg
145de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_DRIVER)
146de2362d3Smrg		mode->type = M_T_DRIVER;
147de2362d3Smrg	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
148de2362d3Smrg		mode->type |= M_T_PREFERRED;
149de2362d3Smrg	xf86SetModeCrtc (mode, scrn->adjustFlags);
150de2362d3Smrg}
151de2362d3Smrg
152de2362d3Smrgstatic void
153de2362d3Smrgdrmmode_ConvertToKMode(ScrnInfoPtr	scrn,
154de2362d3Smrg		     drmModeModeInfo *kmode,
155de2362d3Smrg		     DisplayModePtr	mode)
156de2362d3Smrg{
157de2362d3Smrg	memset(kmode, 0, sizeof(*kmode));
158de2362d3Smrg
159de2362d3Smrg	kmode->clock = mode->Clock;
160de2362d3Smrg	kmode->hdisplay = mode->HDisplay;
161de2362d3Smrg	kmode->hsync_start = mode->HSyncStart;
162de2362d3Smrg	kmode->hsync_end = mode->HSyncEnd;
163de2362d3Smrg	kmode->htotal = mode->HTotal;
164de2362d3Smrg	kmode->hskew = mode->HSkew;
165de2362d3Smrg
166de2362d3Smrg	kmode->vdisplay = mode->VDisplay;
167de2362d3Smrg	kmode->vsync_start = mode->VSyncStart;
168de2362d3Smrg	kmode->vsync_end = mode->VSyncEnd;
169de2362d3Smrg	kmode->vtotal = mode->VTotal;
170de2362d3Smrg	kmode->vscan = mode->VScan;
171de2362d3Smrg
172de2362d3Smrg	kmode->flags = mode->Flags; //& FLAG_BITS;
173de2362d3Smrg	if (mode->name)
174de2362d3Smrg		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
175de2362d3Smrg	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
176de2362d3Smrg
177de2362d3Smrg}
178de2362d3Smrg
179de2362d3Smrgstatic void
1807821949aSmrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
181de2362d3Smrg{
182de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1837821949aSmrg//	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1847314432eSmrg
185de2362d3Smrg	drmmode_crtc->dpms_mode = mode;
1860d16fef4Smrg
1877821949aSmrg#if 0
1887821949aSmrg	/* bonghits in the randr 1.2 - uses dpms to disable crtc - bad buzz */
1897821949aSmrg	if (mode == DPMSModeOff) {
1907821949aSmrg//		drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1917821949aSmrg//			       0, 0, 0, NULL, 0, NULL);
1927821949aSmrg	}
1937821949aSmrg#endif
194de2362d3Smrg}
195de2362d3Smrg
196de2362d3Smrgstatic PixmapPtr
197de2362d3Smrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode,
198de2362d3Smrg			ScrnInfoPtr pScrn, int fbcon_id)
199de2362d3Smrg{
2007821949aSmrg	PixmapPtr pixmap = NULL;
201de2362d3Smrg	struct radeon_bo *bo;
202de2362d3Smrg	drmModeFBPtr fbcon;
203de2362d3Smrg	struct drm_gem_flink flink;
204de2362d3Smrg
205de2362d3Smrg	fbcon = drmModeGetFB(drmmode->fd, fbcon_id);
206de2362d3Smrg	if (fbcon == NULL)
207de2362d3Smrg		return NULL;
208de2362d3Smrg
209de2362d3Smrg	if (fbcon->depth != pScrn->depth ||
210de2362d3Smrg	    fbcon->width != pScrn->virtualX ||
211de2362d3Smrg	    fbcon->height != pScrn->virtualY)
212de2362d3Smrg		goto out_free_fb;
213de2362d3Smrg
214de2362d3Smrg	flink.handle = fbcon->handle;
215de2362d3Smrg	if (ioctl(drmmode->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
216de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
217de2362d3Smrg			   "Couldn't flink fbcon handle\n");
218de2362d3Smrg		goto out_free_fb;
219de2362d3Smrg	}
220de2362d3Smrg
221de2362d3Smrg	bo = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0);
222de2362d3Smrg	if (bo == NULL) {
223de2362d3Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
224de2362d3Smrg			   "Couldn't allocate bo for fbcon handle\n");
225de2362d3Smrg		goto out_free_fb;
226de2362d3Smrg	}
227de2362d3Smrg
228de2362d3Smrg	pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height,
2297821949aSmrg					  fbcon->depth, fbcon->bpp,
2307821949aSmrg					  fbcon->pitch, 0, bo, NULL);
231de2362d3Smrg	radeon_bo_unref(bo);
232de2362d3Smrgout_free_fb:
233de2362d3Smrg	drmModeFreeFB(fbcon);
234de2362d3Smrg	return pixmap;
235de2362d3Smrg}
236de2362d3Smrg
237de2362d3Smrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
238de2362d3Smrg{
239de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
240de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
241de2362d3Smrg	PixmapPtr src, dst;
242de2362d3Smrg	ScreenPtr pScreen = pScrn->pScreen;
243de2362d3Smrg	int fbcon_id = 0;
244de2362d3Smrg	int i;
2457821949aSmrg	int pitch;
2467821949aSmrg	uint32_t tiling_flags = 0;
2477821949aSmrg	Bool ret;
2487821949aSmrg
2497821949aSmrg	if (info->accelOn == FALSE)
2507821949aSmrg		goto fallback;
251de2362d3Smrg
252de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
253de2362d3Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
254de2362d3Smrg
255de2362d3Smrg		if (drmmode_crtc->mode_crtc->buffer_id)
256de2362d3Smrg			fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
257de2362d3Smrg	}
258de2362d3Smrg
259de2362d3Smrg	if (!fbcon_id)
2607821949aSmrg		goto fallback;
261de2362d3Smrg
262de2362d3Smrg	src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
263de2362d3Smrg	if (!src)
2647821949aSmrg		goto fallback;
2650d16fef4Smrg
2667821949aSmrg	if (info->allowColorTiling) {
2677821949aSmrg		if (info->ChipFamily >= CHIP_FAMILY_R600) {
2687821949aSmrg			if (info->allowColorTiling2D) {
2697821949aSmrg				tiling_flags |= RADEON_TILING_MACRO;
2707821949aSmrg			} else {
2717821949aSmrg				tiling_flags |= RADEON_TILING_MICRO;
2727821949aSmrg			}
2737821949aSmrg		} else
2747821949aSmrg			tiling_flags |= RADEON_TILING_MACRO;
2757821949aSmrg	}
276de2362d3Smrg
2777821949aSmrg	pitch = RADEON_ALIGN(pScrn->displayWidth,
2787821949aSmrg			     drmmode_get_pitch_align(pScrn, info->CurrentLayout.pixel_bytes, tiling_flags)) *
2797821949aSmrg		info->CurrentLayout.pixel_bytes;
2807821949aSmrg
2817821949aSmrg	dst = drmmode_create_bo_pixmap(pScrn, pScrn->virtualX,
2827821949aSmrg				       pScrn->virtualY, pScrn->depth,
2837821949aSmrg				       pScrn->bitsPerPixel, pitch,
2847821949aSmrg				       tiling_flags, info->front_bo, &info->front_surface);
2857821949aSmrg	if (!dst)
2867821949aSmrg		goto out_free_src;
2877821949aSmrg
2887821949aSmrg	ret = info->accel_state->exa->PrepareCopy (src, dst,
2897821949aSmrg						   -1, -1, GXcopy, FB_ALLONES);
2907821949aSmrg	if (!ret)
2917821949aSmrg	  goto out_free_src;
2927821949aSmrg	info->accel_state->exa->Copy (dst, 0, 0, 0, 0,
2937821949aSmrg				      pScrn->virtualX, pScrn->virtualY);
2947821949aSmrg	info->accel_state->exa->DoneCopy (dst);
295de2362d3Smrg	radeon_cs_flush_indirect(pScrn);
296de2362d3Smrg
2977821949aSmrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10
298de2362d3Smrg	pScreen->canDoBGNoneRoot = TRUE;
2990d16fef4Smrg#endif
3007821949aSmrg	drmmode_destroy_bo_pixmap(dst);
3017821949aSmrg out_free_src:
3027821949aSmrg	drmmode_destroy_bo_pixmap(src);
3037821949aSmrg	return;
3040d16fef4Smrg
3057821949aSmrgfallback:
3067821949aSmrg	/* map and memset the bo */
3077821949aSmrg	if (radeon_bo_map(info->front_bo, 1))
3087821949aSmrg		return;
3090d16fef4Smrg
3107821949aSmrg	memset(info->front_bo->ptr, 0x00, info->front_bo->size);
3117821949aSmrg	radeon_bo_unmap(info->front_bo);
3120d16fef4Smrg}
3130d16fef4Smrg
314de2362d3Smrgstatic Bool
315de2362d3Smrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
316de2362d3Smrg		     Rotation rotation, int x, int y)
317de2362d3Smrg{
318de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
319de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
320de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
321de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
322de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
323de2362d3Smrg	int saved_x, saved_y;
324de2362d3Smrg	Rotation saved_rotation;
325de2362d3Smrg	DisplayModeRec saved_mode;
3267821949aSmrg	uint32_t *output_ids;
327de2362d3Smrg	int output_count = 0;
3287821949aSmrg	Bool ret = TRUE;
329de2362d3Smrg	int i;
330de2362d3Smrg	int fb_id;
331de2362d3Smrg	drmModeModeInfo kmode;
3327821949aSmrg	int pitch;
3337821949aSmrg	uint32_t tiling_flags = 0;
3347821949aSmrg	int height;
3357821949aSmrg
3367821949aSmrg	if (info->allowColorTiling) {
3377821949aSmrg		if (info->ChipFamily >= CHIP_FAMILY_R600)
3387821949aSmrg			tiling_flags |= RADEON_TILING_MICRO;
3397821949aSmrg		else
3407821949aSmrg			tiling_flags |= RADEON_TILING_MACRO;
3417821949aSmrg	}
3427821949aSmrg
3437821949aSmrg	pitch = RADEON_ALIGN(pScrn->displayWidth, drmmode_get_pitch_align(pScrn, info->CurrentLayout.pixel_bytes, tiling_flags)) *
3447821949aSmrg		info->CurrentLayout.pixel_bytes;
3457821949aSmrg	height = RADEON_ALIGN(pScrn->virtualY, drmmode_get_height_align(pScrn, tiling_flags));
3467821949aSmrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
3477821949aSmrg		pitch = info->front_surface.level[0].pitch_bytes;
3487821949aSmrg	}
3497821949aSmrg
3507821949aSmrg	if (drmmode->fb_id == 0) {
3517821949aSmrg		ret = drmModeAddFB(drmmode->fd,
3527821949aSmrg				   pScrn->virtualX, height,
3537821949aSmrg                                   pScrn->depth, pScrn->bitsPerPixel,
3547821949aSmrg				   pitch,
3557821949aSmrg				   info->front_bo->handle,
3567821949aSmrg                                   &drmmode->fb_id);
3577821949aSmrg                if (ret < 0) {
3587821949aSmrg                        ErrorF("failed to add fb\n");
3597821949aSmrg                        return FALSE;
3607821949aSmrg                }
3617821949aSmrg        }
362de2362d3Smrg
363de2362d3Smrg	saved_mode = crtc->mode;
364de2362d3Smrg	saved_x = crtc->x;
365de2362d3Smrg	saved_y = crtc->y;
366de2362d3Smrg	saved_rotation = crtc->rotation;
367de2362d3Smrg
368de2362d3Smrg	if (mode) {
369de2362d3Smrg		crtc->mode = *mode;
370de2362d3Smrg		crtc->x = x;
371de2362d3Smrg		crtc->y = y;
372de2362d3Smrg		crtc->rotation = rotation;
3737821949aSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,99,0,0)
3747821949aSmrg		crtc->transformPresent = FALSE;
3757821949aSmrg#endif
3767821949aSmrg	}
377de2362d3Smrg
3787821949aSmrg	output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
3797821949aSmrg	if (!output_ids) {
3807821949aSmrg		ret = FALSE;
3817821949aSmrg		goto done;
3827821949aSmrg	}
383de2362d3Smrg
3847821949aSmrg	if (mode) {
385de2362d3Smrg		for (i = 0; i < xf86_config->num_output; i++) {
386de2362d3Smrg			xf86OutputPtr output = xf86_config->output[i];
387de2362d3Smrg			drmmode_output_private_ptr drmmode_output;
388de2362d3Smrg
389de2362d3Smrg			if (output->crtc != crtc)
390de2362d3Smrg				continue;
391de2362d3Smrg
392de2362d3Smrg			drmmode_output = output->driver_private;
393de2362d3Smrg			output_ids[output_count] = drmmode_output->mode_output->connector_id;
394de2362d3Smrg			output_count++;
395de2362d3Smrg		}
396de2362d3Smrg
3977821949aSmrg		if (!xf86CrtcRotate(crtc)) {
398de2362d3Smrg			goto done;
3997821949aSmrg		}
4007821949aSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0)
401de2362d3Smrg		crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
402de2362d3Smrg				       crtc->gamma_blue, crtc->gamma_size);
4037821949aSmrg#endif
4047821949aSmrg
405de2362d3Smrg		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
406de2362d3Smrg
407de2362d3Smrg		fb_id = drmmode->fb_id;
4087821949aSmrg		if (drmmode_crtc->rotate_fb_id) {
4097821949aSmrg			fb_id = drmmode_crtc->rotate_fb_id;
410de2362d3Smrg			x = y = 0;
411de2362d3Smrg		}
4127821949aSmrg		ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
4137821949aSmrg				     fb_id, x, y, output_ids, output_count, &kmode);
4147821949aSmrg		if (ret)
415de2362d3Smrg			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
4167821949aSmrg				   "failed to set mode: %s", strerror(-ret));
4177821949aSmrg		else
418de2362d3Smrg			ret = TRUE;
419de2362d3Smrg
4207821949aSmrg		if (crtc->scrn->pScreen)
4217821949aSmrg			xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
422de2362d3Smrg		/* go through all the outputs and force DPMS them back on? */
423de2362d3Smrg		for (i = 0; i < xf86_config->num_output; i++) {
424de2362d3Smrg			xf86OutputPtr output = xf86_config->output[i];
425de2362d3Smrg
426de2362d3Smrg			if (output->crtc != crtc)
427de2362d3Smrg				continue;
428de2362d3Smrg
429de2362d3Smrg			output->funcs->dpms(output, DPMSModeOn);
430de2362d3Smrg		}
431de2362d3Smrg	}
432de2362d3Smrg
4337821949aSmrg	if (pScrn->pScreen &&
4347821949aSmrg		!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
4357821949aSmrg		xf86_reload_cursors(pScrn->pScreen);
436de2362d3Smrg
437de2362d3Smrgdone:
438de2362d3Smrg	if (!ret) {
439de2362d3Smrg		crtc->x = saved_x;
440de2362d3Smrg		crtc->y = saved_y;
441de2362d3Smrg		crtc->rotation = saved_rotation;
442de2362d3Smrg		crtc->mode = saved_mode;
4437314432eSmrg	}
4447821949aSmrg#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3
4457821949aSmrg	else
4467821949aSmrg		crtc->active = TRUE;
4477821949aSmrg#endif
448de2362d3Smrg
449de2362d3Smrg	return ret;
450de2362d3Smrg}
451de2362d3Smrg
452de2362d3Smrgstatic void
453de2362d3Smrgdrmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
454de2362d3Smrg{
455de2362d3Smrg
456de2362d3Smrg}
457de2362d3Smrg
458de2362d3Smrgstatic void
459de2362d3Smrgdrmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
460de2362d3Smrg{
461de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
462de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
463de2362d3Smrg
464de2362d3Smrg	drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
465de2362d3Smrg}
466de2362d3Smrg
467de2362d3Smrgstatic void
468de2362d3Smrgdrmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
469de2362d3Smrg{
470de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4717821949aSmrg	int i;
472de2362d3Smrg	uint32_t *ptr;
473de2362d3Smrg
474de2362d3Smrg	/* cursor should be mapped already */
475de2362d3Smrg	ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr);
476de2362d3Smrg
4777821949aSmrg	for (i = 0; i < 64 * 64; i++)
4787821949aSmrg		ptr[i] = cpu_to_le32(image[i]);
479de2362d3Smrg}
480de2362d3Smrg
481de2362d3Smrg
482de2362d3Smrgstatic void
483de2362d3Smrgdrmmode_hide_cursor (xf86CrtcPtr crtc)
484de2362d3Smrg{
485de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
486de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
487de2362d3Smrg
4887821949aSmrg	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 64, 64);
489de2362d3Smrg
490de2362d3Smrg}
491de2362d3Smrg
492de2362d3Smrgstatic void
493de2362d3Smrgdrmmode_show_cursor (xf86CrtcPtr crtc)
494de2362d3Smrg{
495de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
496de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
497de2362d3Smrg	uint32_t handle = drmmode_crtc->cursor_bo->handle;
4987314432eSmrg
4997821949aSmrg	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 64, 64);
500de2362d3Smrg}
501de2362d3Smrg
502de2362d3Smrgstatic void *
503de2362d3Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
504de2362d3Smrg{
5057821949aSmrg	ScrnInfoPtr pScrn = crtc->scrn;
5067821949aSmrg	RADEONInfoPtr info = RADEONPTR(pScrn);
507de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
5087821949aSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
5097821949aSmrg	int size;
5107821949aSmrg	struct radeon_bo *rotate_bo;
5117821949aSmrg	int ret;
5127821949aSmrg	unsigned long rotate_pitch;
5137821949aSmrg	int base_align;
514de2362d3Smrg
5157821949aSmrg	/* rotation requires acceleration */
5167821949aSmrg	if (info->r600_shadow_fb) {
5177821949aSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5187821949aSmrg			   "Rotation requires acceleration!\n");
5197821949aSmrg		return NULL;
5207821949aSmrg	}
5217821949aSmrg
5227821949aSmrg	rotate_pitch =
5237821949aSmrg		RADEON_ALIGN(width, drmmode_get_pitch_align(crtc->scrn, drmmode->cpp, 0)) * drmmode->cpp;
5247821949aSmrg	height = RADEON_ALIGN(height, drmmode_get_height_align(crtc->scrn, 0));
5257821949aSmrg	base_align = drmmode_get_base_align(crtc->scrn, drmmode->cpp, 0);
5267821949aSmrg	size = RADEON_ALIGN(rotate_pitch * height, RADEON_GPU_PAGE_SIZE);
5277821949aSmrg
5287821949aSmrg	rotate_bo = radeon_bo_open(drmmode->bufmgr, 0, size, base_align, RADEON_GEM_DOMAIN_VRAM, 0);
5297821949aSmrg	if (rotate_bo == NULL)
5307821949aSmrg		return NULL;
5317821949aSmrg
5327821949aSmrg	radeon_bo_map(rotate_bo, 1);
5337821949aSmrg
5347821949aSmrg	ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth,
5357821949aSmrg			   crtc->scrn->bitsPerPixel, rotate_pitch,
5367821949aSmrg			   rotate_bo->handle,
5377821949aSmrg			   &drmmode_crtc->rotate_fb_id);
5387821949aSmrg	if (ret) {
5397821949aSmrg		ErrorF("failed to add rotate fb\n");
5407821949aSmrg	}
5417821949aSmrg
5427821949aSmrg	drmmode_crtc->rotate_bo = rotate_bo;
5437821949aSmrg	return drmmode_crtc->rotate_bo->ptr;
544de2362d3Smrg}
545de2362d3Smrg
546de2362d3Smrgstatic PixmapPtr
547de2362d3Smrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
548de2362d3Smrg{
5497821949aSmrg	ScrnInfoPtr pScrn = crtc->scrn;
550de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
5517821949aSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
5527821949aSmrg	unsigned long rotate_pitch;
5537821949aSmrg	PixmapPtr rotate_pixmap;
554de2362d3Smrg
5557821949aSmrg	if (!data)
5567821949aSmrg		data = drmmode_crtc_shadow_allocate (crtc, width, height);
557de2362d3Smrg
5587821949aSmrg	rotate_pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0)) * drmmode->cpp;
5597821949aSmrg
5607821949aSmrg	rotate_pixmap = drmmode_create_bo_pixmap(pScrn,
5617821949aSmrg						 width, height,
5627821949aSmrg						 pScrn->depth,
5637821949aSmrg						 pScrn->bitsPerPixel,
5647821949aSmrg						 rotate_pitch,
5657821949aSmrg						 0, drmmode_crtc->rotate_bo, NULL);
5667821949aSmrg	if (rotate_pixmap == NULL) {
5677821949aSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
5687821949aSmrg			   "Couldn't allocate shadow pixmap for rotated CRTC\n");
5697821949aSmrg	}
5707821949aSmrg	return rotate_pixmap;
571de2362d3Smrg
572de2362d3Smrg}
573de2362d3Smrg
574de2362d3Smrgstatic void
5757821949aSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
576de2362d3Smrg{
577de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
578de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
579de2362d3Smrg
5807821949aSmrg	if (rotate_pixmap)
5817821949aSmrg		drmmode_destroy_bo_pixmap(rotate_pixmap);
582de2362d3Smrg
5837821949aSmrg	if (data) {
5847821949aSmrg		drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
5857821949aSmrg		drmmode_crtc->rotate_fb_id = 0;
5867821949aSmrg		radeon_bo_unmap(drmmode_crtc->rotate_bo);
5877821949aSmrg		radeon_bo_unref(drmmode_crtc->rotate_bo);
5887821949aSmrg		drmmode_crtc->rotate_bo = NULL;
589de2362d3Smrg	}
590de2362d3Smrg
5917821949aSmrg}
592de2362d3Smrg
5937821949aSmrgstatic void
5947821949aSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
5957821949aSmrg                      uint16_t *blue, int size)
5967821949aSmrg{
5977821949aSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
5987821949aSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
5997314432eSmrg
6007821949aSmrg	drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
6017821949aSmrg			    size, red, green, blue);
602de2362d3Smrg}
603de2362d3Smrg
6047821949aSmrgstatic const xf86CrtcFuncsRec drmmode_crtc_funcs = {
605de2362d3Smrg    .dpms = drmmode_crtc_dpms,
606de2362d3Smrg    .set_mode_major = drmmode_set_mode_major,
607de2362d3Smrg    .set_cursor_colors = drmmode_set_cursor_colors,
608de2362d3Smrg    .set_cursor_position = drmmode_set_cursor_position,
609de2362d3Smrg    .show_cursor = drmmode_show_cursor,
610de2362d3Smrg    .hide_cursor = drmmode_hide_cursor,
611de2362d3Smrg    .load_cursor_argb = drmmode_load_cursor_argb,
612de2362d3Smrg
613de2362d3Smrg    .gamma_set = drmmode_crtc_gamma_set,
614de2362d3Smrg    .shadow_create = drmmode_crtc_shadow_create,
615de2362d3Smrg    .shadow_allocate = drmmode_crtc_shadow_allocate,
616de2362d3Smrg    .shadow_destroy = drmmode_crtc_shadow_destroy,
617de2362d3Smrg    .destroy = NULL, /* XXX */
618de2362d3Smrg};
619de2362d3Smrg
620de2362d3Smrgint drmmode_get_crtc_id(xf86CrtcPtr crtc)
621de2362d3Smrg{
622de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
623de2362d3Smrg	return drmmode_crtc->hw_id;
624de2362d3Smrg}
625de2362d3Smrg
626de2362d3Smrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc)
627de2362d3Smrg{
628de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
629de2362d3Smrg	ScrnInfoPtr pScrn = crtc->scrn;
630de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
631de2362d3Smrg	struct drm_radeon_info ginfo;
632de2362d3Smrg	int r;
633de2362d3Smrg	uint32_t tmp;
634de2362d3Smrg
635de2362d3Smrg	memset(&ginfo, 0, sizeof(ginfo));
636de2362d3Smrg	ginfo.request = 0x4;
637de2362d3Smrg	tmp = drmmode_crtc->mode_crtc->crtc_id;
638de2362d3Smrg	ginfo.value = (uintptr_t)&tmp;
6397821949aSmrg	r = drmCommandWriteRead(info->dri->drmFD, DRM_RADEON_INFO, &ginfo, sizeof(ginfo));
640de2362d3Smrg	if (r) {
641de2362d3Smrg		drmmode_crtc->hw_id = -1;
642de2362d3Smrg		return;
643de2362d3Smrg	}
644de2362d3Smrg	drmmode_crtc->hw_id = tmp;
645de2362d3Smrg}
646de2362d3Smrg
6477821949aSmrgstatic void
6487821949aSmrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
649de2362d3Smrg{
650de2362d3Smrg	xf86CrtcPtr crtc;
651de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc;
652de2362d3Smrg
653de2362d3Smrg	crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
654de2362d3Smrg	if (crtc == NULL)
6557821949aSmrg		return;
656de2362d3Smrg
657de2362d3Smrg	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
6587821949aSmrg	drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
659de2362d3Smrg	drmmode_crtc->drmmode = drmmode;
660de2362d3Smrg	crtc->driver_private = drmmode_crtc;
661de2362d3Smrg	drmmode_crtc_hw_id(crtc);
662de2362d3Smrg
6637821949aSmrg	return;
664de2362d3Smrg}
665de2362d3Smrg
666de2362d3Smrgstatic xf86OutputStatus
667de2362d3Smrgdrmmode_output_detect(xf86OutputPtr output)
668de2362d3Smrg{
669de2362d3Smrg	/* go to the hw and retrieve a new output struct */
670de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
671de2362d3Smrg	drmmode_ptr drmmode = drmmode_output->drmmode;
672de2362d3Smrg	xf86OutputStatus status;
673de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
674de2362d3Smrg
675de2362d3Smrg	drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
676de2362d3Smrg
677de2362d3Smrg	switch (drmmode_output->mode_output->connection) {
678de2362d3Smrg	case DRM_MODE_CONNECTED:
679de2362d3Smrg		status = XF86OutputStatusConnected;
680de2362d3Smrg		break;
681de2362d3Smrg	case DRM_MODE_DISCONNECTED:
682de2362d3Smrg		status = XF86OutputStatusDisconnected;
683de2362d3Smrg		break;
684de2362d3Smrg	default:
685de2362d3Smrg	case DRM_MODE_UNKNOWNCONNECTION:
686de2362d3Smrg		status = XF86OutputStatusUnknown;
687de2362d3Smrg		break;
688de2362d3Smrg	}
689de2362d3Smrg	return status;
690de2362d3Smrg}
691de2362d3Smrg
692de2362d3Smrgstatic Bool
693de2362d3Smrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
694de2362d3Smrg{
695de2362d3Smrg	return MODE_OK;
696de2362d3Smrg}
697de2362d3Smrg
698de2362d3Smrgstatic DisplayModePtr
699de2362d3Smrgdrmmode_output_get_modes(xf86OutputPtr output)
700de2362d3Smrg{
701de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
702de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
703de2362d3Smrg	drmmode_ptr drmmode = drmmode_output->drmmode;
704de2362d3Smrg	int i;
705de2362d3Smrg	DisplayModePtr Modes = NULL, Mode;
706de2362d3Smrg	drmModePropertyPtr props;
707de2362d3Smrg	xf86MonPtr mon = NULL;
708de2362d3Smrg
709de2362d3Smrg	/* look for an EDID property */
710de2362d3Smrg	for (i = 0; i < koutput->count_props; i++) {
711de2362d3Smrg		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
712de2362d3Smrg		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
713de2362d3Smrg			if (!strcmp(props->name, "EDID")) {
714de2362d3Smrg				if (drmmode_output->edid_blob)
715de2362d3Smrg					drmModeFreePropertyBlob(drmmode_output->edid_blob);
716de2362d3Smrg				drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
717de2362d3Smrg			}
718de2362d3Smrg			drmModeFreeProperty(props);
7197821949aSmrg		}
720de2362d3Smrg	}
721de2362d3Smrg
722de2362d3Smrg	if (drmmode_output->edid_blob) {
723de2362d3Smrg		mon = xf86InterpretEDID(output->scrn->scrnIndex,
724de2362d3Smrg					drmmode_output->edid_blob->data);
725de2362d3Smrg		if (mon && drmmode_output->edid_blob->length > 128)
726de2362d3Smrg			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
727de2362d3Smrg	}
728de2362d3Smrg	xf86OutputSetEDID(output, mon);
729de2362d3Smrg
730de2362d3Smrg	/* modes should already be available */
731de2362d3Smrg	for (i = 0; i < koutput->count_modes; i++) {
732de2362d3Smrg		Mode = xnfalloc(sizeof(DisplayModeRec));
733de2362d3Smrg
734de2362d3Smrg		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
735de2362d3Smrg		Modes = xf86ModesAdd(Modes, Mode);
736de2362d3Smrg
737de2362d3Smrg	}
738de2362d3Smrg	return Modes;
739de2362d3Smrg}
740de2362d3Smrg
741de2362d3Smrgstatic void
742de2362d3Smrgdrmmode_output_destroy(xf86OutputPtr output)
743de2362d3Smrg{
744de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
745de2362d3Smrg	int i;
746de2362d3Smrg
747de2362d3Smrg	if (drmmode_output->edid_blob)
748de2362d3Smrg		drmModeFreePropertyBlob(drmmode_output->edid_blob);
749de2362d3Smrg	for (i = 0; i < drmmode_output->num_props; i++) {
750de2362d3Smrg		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
751de2362d3Smrg		free(drmmode_output->props[i].atoms);
752de2362d3Smrg	}
753de2362d3Smrg	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
754de2362d3Smrg		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
7557821949aSmrg		free(drmmode_output->mode_encoders);
756de2362d3Smrg	}
757de2362d3Smrg	free(drmmode_output->props);
758de2362d3Smrg	drmModeFreeConnector(drmmode_output->mode_output);
759de2362d3Smrg	free(drmmode_output);
760de2362d3Smrg	output->driver_private = NULL;
761de2362d3Smrg}
762de2362d3Smrg
763de2362d3Smrgstatic void
764de2362d3Smrgdrmmode_output_dpms(xf86OutputPtr output, int mode)
765de2362d3Smrg{
766de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
767de2362d3Smrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
768de2362d3Smrg	drmmode_ptr drmmode = drmmode_output->drmmode;
769de2362d3Smrg
770de2362d3Smrg	drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
771de2362d3Smrg				    drmmode_output->dpms_enum_id, mode);
7727821949aSmrg	return;
773de2362d3Smrg}
774de2362d3Smrg
775de2362d3Smrg
776de2362d3Smrgstatic Bool
777de2362d3Smrgdrmmode_property_ignore(drmModePropertyPtr prop)
778de2362d3Smrg{
779de2362d3Smrg    if (!prop)
780de2362d3Smrg	return TRUE;
781de2362d3Smrg    /* ignore blob prop */
782de2362d3Smrg    if (prop->flags & DRM_MODE_PROP_BLOB)
783de2362d3Smrg	return TRUE;
784de2362d3Smrg    /* ignore standard property */
785de2362d3Smrg    if (!strcmp(prop->name, "EDID") ||
786de2362d3Smrg	    !strcmp(prop->name, "DPMS"))
787de2362d3Smrg	return TRUE;
788de2362d3Smrg
789de2362d3Smrg    return FALSE;
790de2362d3Smrg}
791de2362d3Smrg
792de2362d3Smrgstatic void
793de2362d3Smrgdrmmode_output_create_resources(xf86OutputPtr output)
794de2362d3Smrg{
795de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
796de2362d3Smrg    drmModeConnectorPtr mode_output = drmmode_output->mode_output;
797de2362d3Smrg    drmmode_ptr drmmode = drmmode_output->drmmode;
798de2362d3Smrg    drmModePropertyPtr drmmode_prop;
799de2362d3Smrg    int i, j, err;
800de2362d3Smrg
801de2362d3Smrg    drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
802de2362d3Smrg    if (!drmmode_output->props)
803de2362d3Smrg	return;
804de2362d3Smrg
805de2362d3Smrg    drmmode_output->num_props = 0;
806de2362d3Smrg    for (i = 0, j = 0; i < mode_output->count_props; i++) {
807de2362d3Smrg	drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
808de2362d3Smrg	if (drmmode_property_ignore(drmmode_prop)) {
809de2362d3Smrg	    drmModeFreeProperty(drmmode_prop);
810de2362d3Smrg	    continue;
811de2362d3Smrg	}
812de2362d3Smrg	drmmode_output->props[j].mode_prop = drmmode_prop;
813de2362d3Smrg	drmmode_output->props[j].value = mode_output->prop_values[i];
814de2362d3Smrg	drmmode_output->num_props++;
815de2362d3Smrg	j++;
816de2362d3Smrg    }
817de2362d3Smrg
818de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
819de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
820de2362d3Smrg	drmmode_prop = p->mode_prop;
821de2362d3Smrg
822de2362d3Smrg	if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
823de2362d3Smrg	    INT32 range[2];
824de2362d3Smrg	    INT32 value = p->value;
825de2362d3Smrg
826de2362d3Smrg	    p->num_atoms = 1;
827de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
828de2362d3Smrg	    if (!p->atoms)
829de2362d3Smrg		continue;
830de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
831de2362d3Smrg	    range[0] = drmmode_prop->values[0];
832de2362d3Smrg	    range[1] = drmmode_prop->values[1];
833de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
834de2362d3Smrg		    FALSE, TRUE,
835de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
836de2362d3Smrg		    2, range);
837de2362d3Smrg	    if (err != 0) {
838de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
839de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
840de2362d3Smrg	    }
841de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
842de2362d3Smrg		    XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE);
843de2362d3Smrg	    if (err != 0) {
844de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
845de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
846de2362d3Smrg	    }
847de2362d3Smrg	} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
848de2362d3Smrg	    p->num_atoms = drmmode_prop->count_enums + 1;
849de2362d3Smrg	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
850de2362d3Smrg	    if (!p->atoms)
851de2362d3Smrg		continue;
852de2362d3Smrg	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
853de2362d3Smrg	    for (j = 1; j <= drmmode_prop->count_enums; j++) {
854de2362d3Smrg		struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
855de2362d3Smrg		p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
856de2362d3Smrg	    }
857de2362d3Smrg	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
858de2362d3Smrg		    FALSE, FALSE,
859de2362d3Smrg		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
860de2362d3Smrg		    p->num_atoms - 1, (INT32 *)&p->atoms[1]);
861de2362d3Smrg	    if (err != 0) {
862de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
863de2362d3Smrg			"RRConfigureOutputProperty error, %d\n", err);
864de2362d3Smrg	    }
865de2362d3Smrg	    for (j = 0; j < drmmode_prop->count_enums; j++)
866de2362d3Smrg		if (drmmode_prop->enums[j].value == p->value)
867de2362d3Smrg		    break;
868de2362d3Smrg	    /* there's always a matching value */
869de2362d3Smrg	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
870de2362d3Smrg		    XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
871de2362d3Smrg	    if (err != 0) {
872de2362d3Smrg		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
873de2362d3Smrg			"RRChangeOutputProperty error, %d\n", err);
874de2362d3Smrg	    }
875de2362d3Smrg	}
876de2362d3Smrg    }
877de2362d3Smrg}
878de2362d3Smrg
879de2362d3Smrgstatic Bool
880de2362d3Smrgdrmmode_output_set_property(xf86OutputPtr output, Atom property,
881de2362d3Smrg		RRPropertyValuePtr value)
882de2362d3Smrg{
883de2362d3Smrg    drmmode_output_private_ptr drmmode_output = output->driver_private;
884de2362d3Smrg    drmmode_ptr drmmode = drmmode_output->drmmode;
885de2362d3Smrg    int i;
886de2362d3Smrg
887de2362d3Smrg    for (i = 0; i < drmmode_output->num_props; i++) {
888de2362d3Smrg	drmmode_prop_ptr p = &drmmode_output->props[i];
889de2362d3Smrg
890de2362d3Smrg	if (p->atoms[0] != property)
891de2362d3Smrg	    continue;
892de2362d3Smrg
893de2362d3Smrg	if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
894de2362d3Smrg	    uint32_t val;
895de2362d3Smrg
896de2362d3Smrg	    if (value->type != XA_INTEGER || value->format != 32 ||
897de2362d3Smrg		    value->size != 1)
898de2362d3Smrg		return FALSE;
899de2362d3Smrg	    val = *(uint32_t *)value->data;
900de2362d3Smrg
901de2362d3Smrg	    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
902de2362d3Smrg		    p->mode_prop->prop_id, (uint64_t)val);
903de2362d3Smrg	    return TRUE;
904de2362d3Smrg	} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
905de2362d3Smrg	    Atom	atom;
906de2362d3Smrg	    const char	*name;
907de2362d3Smrg	    int		j;
908de2362d3Smrg
909de2362d3Smrg	    if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
910de2362d3Smrg		return FALSE;
911de2362d3Smrg	    memcpy(&atom, value->data, 4);
912de2362d3Smrg	    name = NameForAtom(atom);
913de2362d3Smrg
914de2362d3Smrg	    /* search for matching name string, then set its value down */
915de2362d3Smrg	    for (j = 0; j < p->mode_prop->count_enums; j++) {
916de2362d3Smrg		if (!strcmp(p->mode_prop->enums[j].name, name)) {
917de2362d3Smrg		    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
918de2362d3Smrg			    p->mode_prop->prop_id, p->mode_prop->enums[j].value);
919de2362d3Smrg		    return TRUE;
920de2362d3Smrg		}
921de2362d3Smrg	    }
922de2362d3Smrg	}
923de2362d3Smrg    }
924de2362d3Smrg
925de2362d3Smrg    return TRUE;
926de2362d3Smrg}
927de2362d3Smrg
928de2362d3Smrgstatic Bool
929de2362d3Smrgdrmmode_output_get_property(xf86OutputPtr output, Atom property)
930de2362d3Smrg{
931de2362d3Smrg    return TRUE;
932de2362d3Smrg}
933de2362d3Smrg
934de2362d3Smrgstatic const xf86OutputFuncsRec drmmode_output_funcs = {
935de2362d3Smrg    .dpms = drmmode_output_dpms,
936de2362d3Smrg    .create_resources = drmmode_output_create_resources,
9377821949aSmrg#ifdef RANDR_12_INTERFACE
938de2362d3Smrg    .set_property = drmmode_output_set_property,
939de2362d3Smrg    .get_property = drmmode_output_get_property,
9407821949aSmrg#endif
941de2362d3Smrg#if 0
942de2362d3Smrg
943de2362d3Smrg    .save = drmmode_crt_save,
944de2362d3Smrg    .restore = drmmode_crt_restore,
945de2362d3Smrg    .mode_fixup = drmmode_crt_mode_fixup,
946de2362d3Smrg    .prepare = drmmode_output_prepare,
947de2362d3Smrg    .mode_set = drmmode_crt_mode_set,
948de2362d3Smrg    .commit = drmmode_output_commit,
949de2362d3Smrg#endif
950de2362d3Smrg    .detect = drmmode_output_detect,
951de2362d3Smrg    .mode_valid = drmmode_output_mode_valid,
952de2362d3Smrg
953de2362d3Smrg    .get_modes = drmmode_output_get_modes,
954de2362d3Smrg    .destroy = drmmode_output_destroy
955de2362d3Smrg};
956de2362d3Smrg
957de2362d3Smrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown,
958de2362d3Smrg				      SubPixelHorizontalRGB,
959de2362d3Smrg				      SubPixelHorizontalBGR,
960de2362d3Smrg				      SubPixelVerticalRGB,
961de2362d3Smrg				      SubPixelVerticalBGR,
962de2362d3Smrg				      SubPixelNone };
963de2362d3Smrg
964de2362d3Smrgconst char *output_names[] = { "None",
965de2362d3Smrg			       "VGA",
966de2362d3Smrg			       "DVI",
967de2362d3Smrg			       "DVI",
968de2362d3Smrg			       "DVI",
969de2362d3Smrg			       "Composite",
970de2362d3Smrg			       "S-video",
971de2362d3Smrg			       "LVDS",
972de2362d3Smrg			       "CTV",
973de2362d3Smrg			       "DIN",
974de2362d3Smrg			       "DisplayPort",
975de2362d3Smrg			       "HDMI",
976de2362d3Smrg			       "HDMI",
977de2362d3Smrg			       "TV",
978de2362d3Smrg			       "eDP"
979de2362d3Smrg};
980de2362d3Smrg
981de2362d3Smrgstatic void
9827821949aSmrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dvi, int *num_hdmi)
9830d16fef4Smrg{
984de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
985de2362d3Smrg	xf86OutputPtr output;
986de2362d3Smrg	drmModeConnectorPtr koutput;
987de2362d3Smrg	drmModeEncoderPtr *kencoders = NULL;
988de2362d3Smrg	drmmode_output_private_ptr drmmode_output;
989de2362d3Smrg	drmModePropertyPtr props;
990de2362d3Smrg	char name[32];
991de2362d3Smrg	int i;
992de2362d3Smrg	const char *s;
993de2362d3Smrg
9947821949aSmrg	koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
995de2362d3Smrg	if (!koutput)
9967821949aSmrg		return;
997de2362d3Smrg
998de2362d3Smrg	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
999de2362d3Smrg	if (!kencoders) {
1000de2362d3Smrg		goto out_free_encoders;
1001de2362d3Smrg	}
1002de2362d3Smrg
1003de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
1004de2362d3Smrg		kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
1005de2362d3Smrg		if (!kencoders[i]) {
1006de2362d3Smrg			goto out_free_encoders;
1007de2362d3Smrg		}
1008de2362d3Smrg	}
1009de2362d3Smrg
10107821949aSmrg	/* need to do smart conversion here for compat with non-kms ATI driver */
10117821949aSmrg	if (koutput->connector_type_id == 1) {
10127821949aSmrg	    switch(koutput->connector_type) {
10137821949aSmrg	    case DRM_MODE_CONNECTOR_DVII:
10147821949aSmrg	    case DRM_MODE_CONNECTOR_DVID:
10157821949aSmrg	    case DRM_MODE_CONNECTOR_DVIA:
10167821949aSmrg		snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
10177821949aSmrg		(*num_dvi)++;
10187821949aSmrg		break;
10197821949aSmrg	    case DRM_MODE_CONNECTOR_HDMIA:
10207821949aSmrg	    case DRM_MODE_CONNECTOR_HDMIB:
10217821949aSmrg		snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
10227821949aSmrg		(*num_hdmi)++;
10237821949aSmrg		break;
10247821949aSmrg	    case DRM_MODE_CONNECTOR_VGA:
10257821949aSmrg	    case DRM_MODE_CONNECTOR_DisplayPort:
10267821949aSmrg		snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
10277821949aSmrg		break;
10287821949aSmrg	    default:
10297821949aSmrg		snprintf(name, 32, "%s", output_names[koutput->connector_type]);
10307821949aSmrg		break;
10317821949aSmrg	    }
10327821949aSmrg	} else {
10337821949aSmrg	    snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
1034de2362d3Smrg	}
1035de2362d3Smrg
1036de2362d3Smrg	if (xf86IsEntityShared(pScrn->entityList[0])) {
1037de2362d3Smrg		if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
1038de2362d3Smrg			if (!RADEONZaphodStringMatches(pScrn, s, name))
1039de2362d3Smrg				goto out_free_encoders;
1040de2362d3Smrg		} else {
10417821949aSmrg			if (info->IsPrimary && (num != 0))
1042de2362d3Smrg				goto out_free_encoders;
1043de2362d3Smrg			else if (info->IsSecondary && (num != 1))
1044de2362d3Smrg				goto out_free_encoders;
1045de2362d3Smrg		}
1046de2362d3Smrg	}
1047de2362d3Smrg
1048de2362d3Smrg	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
1049de2362d3Smrg	if (!output) {
1050de2362d3Smrg		goto out_free_encoders;
1051de2362d3Smrg	}
1052de2362d3Smrg
1053de2362d3Smrg	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
1054de2362d3Smrg	if (!drmmode_output) {
1055de2362d3Smrg		xf86OutputDestroy(output);
1056de2362d3Smrg		goto out_free_encoders;
1057de2362d3Smrg	}
1058de2362d3Smrg
10597821949aSmrg	drmmode_output->output_id = drmmode->mode_res->connectors[num];
1060de2362d3Smrg	drmmode_output->mode_output = koutput;
1061de2362d3Smrg	drmmode_output->mode_encoders = kencoders;
1062de2362d3Smrg	drmmode_output->drmmode = drmmode;
1063de2362d3Smrg	output->mm_width = koutput->mmWidth;
1064de2362d3Smrg	output->mm_height = koutput->mmHeight;
1065de2362d3Smrg
1066de2362d3Smrg	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
1067de2362d3Smrg	output->interlaceAllowed = TRUE;
1068de2362d3Smrg	output->doubleScanAllowed = TRUE;
1069de2362d3Smrg	output->driver_private = drmmode_output;
1070de2362d3Smrg
1071de2362d3Smrg	output->possible_crtcs = 0xffffffff;
1072de2362d3Smrg	for (i = 0; i < koutput->count_encoders; i++) {
1073de2362d3Smrg		output->possible_crtcs &= kencoders[i]->possible_crtcs;
1074de2362d3Smrg	}
1075de2362d3Smrg	/* work out the possible clones later */
1076de2362d3Smrg	output->possible_clones = 0;
1077de2362d3Smrg
1078de2362d3Smrg	for (i = 0; i < koutput->count_props; i++) {
1079de2362d3Smrg		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
1080de2362d3Smrg		if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
1081de2362d3Smrg			if (!strcmp(props->name, "DPMS")) {
1082de2362d3Smrg				drmmode_output->dpms_enum_id = koutput->props[i];
1083de2362d3Smrg				drmModeFreeProperty(props);
1084de2362d3Smrg				break;
1085de2362d3Smrg			}
1086de2362d3Smrg			drmModeFreeProperty(props);
1087de2362d3Smrg		}
1088de2362d3Smrg	}
1089de2362d3Smrg
10907821949aSmrg	return;
1091de2362d3Smrgout_free_encoders:
1092de2362d3Smrg	if (kencoders){
1093de2362d3Smrg		for (i = 0; i < koutput->count_encoders; i++)
1094de2362d3Smrg			drmModeFreeEncoder(kencoders[i]);
1095de2362d3Smrg		free(kencoders);
1096de2362d3Smrg	}
1097de2362d3Smrg	drmModeFreeConnector(koutput);
10987821949aSmrg
1099de2362d3Smrg}
1100de2362d3Smrg
1101de2362d3Smrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
1102de2362d3Smrg{
1103de2362d3Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout;
1104de2362d3Smrg	int i;
1105de2362d3Smrg	xf86OutputPtr clone_output;
1106de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1107de2362d3Smrg	int index_mask = 0;
1108de2362d3Smrg
1109de2362d3Smrg	if (drmmode_output->enc_clone_mask == 0)
1110de2362d3Smrg		return index_mask;
1111de2362d3Smrg
1112de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
1113de2362d3Smrg		clone_output = xf86_config->output[i];
1114de2362d3Smrg		clone_drmout = clone_output->driver_private;
1115de2362d3Smrg		if (output == clone_output)
1116de2362d3Smrg			continue;
1117de2362d3Smrg
1118de2362d3Smrg		if (clone_drmout->enc_mask == 0)
1119de2362d3Smrg			continue;
1120de2362d3Smrg		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
1121de2362d3Smrg			index_mask |= (1 << i);
1122de2362d3Smrg	}
1123de2362d3Smrg	return index_mask;
1124de2362d3Smrg}
1125de2362d3Smrg
1126de2362d3Smrg
1127de2362d3Smrgstatic void
11287821949aSmrgdrmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1129de2362d3Smrg{
1130de2362d3Smrg	int i, j;
1131de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1132de2362d3Smrg
1133de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
1134de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
1135de2362d3Smrg		drmmode_output_private_ptr drmmode_output;
1136de2362d3Smrg
1137de2362d3Smrg		drmmode_output = output->driver_private;
1138de2362d3Smrg		drmmode_output->enc_clone_mask = 0xff;
1139de2362d3Smrg		/* and all the possible encoder clones for this output together */
1140de2362d3Smrg		for (j = 0; j < drmmode_output->mode_output->count_encoders; j++)
1141de2362d3Smrg		{
1142de2362d3Smrg			int k;
11437821949aSmrg			for (k = 0; k < drmmode->mode_res->count_encoders; k++) {
11447821949aSmrg				if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id)
1145de2362d3Smrg					drmmode_output->enc_mask |= (1 << k);
1146de2362d3Smrg			}
1147de2362d3Smrg
1148de2362d3Smrg			drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones;
1149de2362d3Smrg		}
1150de2362d3Smrg	}
1151de2362d3Smrg
1152de2362d3Smrg	for (i = 0; i < xf86_config->num_output; i++) {
1153de2362d3Smrg		xf86OutputPtr output = xf86_config->output[i];
1154de2362d3Smrg		output->possible_clones = find_clones(scrn, output);
1155de2362d3Smrg	}
1156de2362d3Smrg}
1157de2362d3Smrg
1158de2362d3Smrg/* returns height alignment in pixels */
1159de2362d3Smrgint drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling)
1160de2362d3Smrg{
1161de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
1162de2362d3Smrg	int height_align = 1;
1163de2362d3Smrg
1164de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1165de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
1166de2362d3Smrg			height_align =  info->num_channels * 8;
1167de2362d3Smrg		else if (tiling & RADEON_TILING_MICRO)
1168de2362d3Smrg			height_align = 8;
1169de2362d3Smrg		else
1170de2362d3Smrg			height_align = 8;
1171de2362d3Smrg	} else {
11727821949aSmrg		if (tiling)
1173de2362d3Smrg			height_align = 16;
1174de2362d3Smrg		else
1175de2362d3Smrg			height_align = 1;
1176de2362d3Smrg	}
1177de2362d3Smrg	return height_align;
1178de2362d3Smrg}
1179de2362d3Smrg
1180de2362d3Smrg/* returns pitch alignment in pixels */
1181de2362d3Smrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
1182de2362d3Smrg{
1183de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
1184de2362d3Smrg	int pitch_align = 1;
1185de2362d3Smrg
1186de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1187de2362d3Smrg		if (tiling & RADEON_TILING_MACRO) {
1188de2362d3Smrg			/* general surface requirements */
1189de2362d3Smrg			pitch_align = MAX(info->num_banks,
1190de2362d3Smrg					  (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8;
1191de2362d3Smrg			/* further restrictions for scanout */
1192de2362d3Smrg			pitch_align = MAX(info->num_banks * 8, pitch_align);
1193de2362d3Smrg		} else if (tiling & RADEON_TILING_MICRO) {
1194de2362d3Smrg			/* general surface requirements */
1195de2362d3Smrg			pitch_align = MAX(8, (info->group_bytes / (8 * bpe)));
1196de2362d3Smrg			/* further restrictions for scanout */
1197de2362d3Smrg			pitch_align = MAX(info->group_bytes / bpe, pitch_align);
1198de2362d3Smrg		} else {
1199de2362d3Smrg			if (info->have_tiling_info)
1200de2362d3Smrg				/* linear aligned requirements */
1201de2362d3Smrg				pitch_align = MAX(64, info->group_bytes / bpe);
1202de2362d3Smrg			else
1203de2362d3Smrg				/* default to 512 elements if we don't know the real
1204de2362d3Smrg				 * group size otherwise the kernel may reject the CS
1205de2362d3Smrg				 * if the group sizes don't match as the pitch won't
1206de2362d3Smrg				 * be aligned properly.
1207de2362d3Smrg				 */
1208de2362d3Smrg				pitch_align = 512;
1209de2362d3Smrg		}
1210de2362d3Smrg	} else {
1211de2362d3Smrg		/* general surface requirements */
1212de2362d3Smrg		if (tiling)
1213de2362d3Smrg			pitch_align = 256 / bpe;
1214de2362d3Smrg		else
1215de2362d3Smrg			pitch_align = 64;
1216de2362d3Smrg	}
1217de2362d3Smrg	return pitch_align;
1218de2362d3Smrg}
1219de2362d3Smrg
1220de2362d3Smrg/* returns base alignment in bytes */
1221de2362d3Smrgint drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
1222de2362d3Smrg{
1223de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
1224de2362d3Smrg	int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling);
1225de2362d3Smrg	int height_align = drmmode_get_height_align(scrn, tiling);
1226de2362d3Smrg	int base_align = RADEON_GPU_PAGE_SIZE;
1227de2362d3Smrg
1228de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1229de2362d3Smrg		if (tiling & RADEON_TILING_MACRO)
1230de2362d3Smrg			base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe,
1231de2362d3Smrg					 pixel_align * bpe * height_align);
1232de2362d3Smrg		else {
1233de2362d3Smrg			if (info->have_tiling_info)
1234de2362d3Smrg				base_align = info->group_bytes;
1235de2362d3Smrg			else
1236de2362d3Smrg				/* default to 512 if we don't know the real
1237de2362d3Smrg				 * group size otherwise the kernel may reject the CS
1238de2362d3Smrg				 * if the group sizes don't match as the base won't
1239de2362d3Smrg				 * be aligned properly.
1240de2362d3Smrg				 */
1241de2362d3Smrg				base_align = 512;
1242de2362d3Smrg		}
1243de2362d3Smrg	}
1244de2362d3Smrg	return base_align;
1245de2362d3Smrg}
1246de2362d3Smrg
1247de2362d3Smrgstatic Bool
1248de2362d3Smrgdrmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
1249de2362d3Smrg{
1250de2362d3Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1251de2362d3Smrg	drmmode_crtc_private_ptr
1252de2362d3Smrg		    drmmode_crtc = xf86_config->crtc[0]->driver_private;
1253de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1254de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
1255de2362d3Smrg	struct radeon_bo *old_front = NULL;
12567821949aSmrg	Bool	    ret;
1257de2362d3Smrg	ScreenPtr   screen = xf86ScrnToScreen(scrn);
1258de2362d3Smrg	uint32_t    old_fb_id;
1259de2362d3Smrg	int	    i, pitch, old_width, old_height, old_pitch;
12607821949aSmrg	int screen_size;
12617821949aSmrg	int cpp = info->CurrentLayout.pixel_bytes;
1262de2362d3Smrg	struct radeon_bo *front_bo;
1263de2362d3Smrg	struct radeon_surface surface;
1264de2362d3Smrg	struct radeon_surface *psurface;
1265de2362d3Smrg	uint32_t tiling_flags = 0, base_align;
1266de2362d3Smrg	PixmapPtr ppix = screen->GetScreenPixmap(screen);
1267de2362d3Smrg	void *fb_shadow;
1268de2362d3Smrg
1269de2362d3Smrg	if (scrn->virtualX == width && scrn->virtualY == height)
1270de2362d3Smrg		return TRUE;
1271de2362d3Smrg
1272de2362d3Smrg	front_bo = info->front_bo;
1273de2362d3Smrg	radeon_cs_flush_indirect(scrn);
1274de2362d3Smrg
1275de2362d3Smrg	if (front_bo)
1276de2362d3Smrg		radeon_bo_wait(front_bo);
1277de2362d3Smrg
12787821949aSmrg	if (info->allowColorTiling) {
1279de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_R600) {
1280de2362d3Smrg			if (info->allowColorTiling2D) {
1281de2362d3Smrg				tiling_flags |= RADEON_TILING_MACRO;
1282de2362d3Smrg			} else {
1283de2362d3Smrg				tiling_flags |= RADEON_TILING_MICRO;
1284de2362d3Smrg			}
1285de2362d3Smrg		} else
1286de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
1287de2362d3Smrg	}
1288de2362d3Smrg
1289de2362d3Smrg	pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(scrn, cpp, tiling_flags)) * cpp;
12907821949aSmrg	height = RADEON_ALIGN(height, drmmode_get_height_align(scrn, tiling_flags));
12917821949aSmrg	screen_size = RADEON_ALIGN(pitch * height, RADEON_GPU_PAGE_SIZE);
1292de2362d3Smrg	base_align = 4096;
1293de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1294de2362d3Smrg		memset(&surface, 0, sizeof(struct radeon_surface));
1295de2362d3Smrg		surface.npix_x = width;
1296de2362d3Smrg		surface.npix_y = height;
1297de2362d3Smrg		surface.npix_z = 1;
1298de2362d3Smrg		surface.blk_w = 1;
1299de2362d3Smrg		surface.blk_h = 1;
1300de2362d3Smrg		surface.blk_d = 1;
1301de2362d3Smrg		surface.array_size = 1;
1302de2362d3Smrg		surface.last_level = 0;
1303de2362d3Smrg		surface.bpe = cpp;
1304de2362d3Smrg		surface.nsamples = 1;
1305de2362d3Smrg		surface.flags = RADEON_SURF_SCANOUT;
1306de2362d3Smrg		surface.flags |= RADEON_SURF_SET(RADEON_SURF_TYPE_2D, TYPE);
1307de2362d3Smrg		surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_LINEAR_ALIGNED, MODE);
1308de2362d3Smrg		if (tiling_flags & RADEON_TILING_MICRO) {
1309de2362d3Smrg			surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
1310de2362d3Smrg			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_1D, MODE);
1311de2362d3Smrg		}
1312de2362d3Smrg		if (tiling_flags & RADEON_TILING_MACRO) {
1313de2362d3Smrg			surface.flags = RADEON_SURF_CLR(surface.flags, MODE);
1314de2362d3Smrg			surface.flags |= RADEON_SURF_SET(RADEON_SURF_MODE_2D, MODE);
1315de2362d3Smrg		}
1316de2362d3Smrg		if (radeon_surface_best(info->surf_man, &surface)) {
1317de2362d3Smrg			return FALSE;
1318de2362d3Smrg		}
1319de2362d3Smrg		if (radeon_surface_init(info->surf_man, &surface)) {
1320de2362d3Smrg			return FALSE;
1321de2362d3Smrg		}
1322de2362d3Smrg		screen_size = surface.bo_size;
1323de2362d3Smrg		base_align = surface.bo_alignment;
1324de2362d3Smrg		pitch = surface.level[0].pitch_bytes;
1325de2362d3Smrg		tiling_flags = 0;
1326de2362d3Smrg		switch (surface.level[0].mode) {
1327de2362d3Smrg		case RADEON_SURF_MODE_2D:
1328de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
1329de2362d3Smrg			tiling_flags |= surface.bankw << RADEON_TILING_EG_BANKW_SHIFT;
1330de2362d3Smrg			tiling_flags |= surface.bankh << RADEON_TILING_EG_BANKH_SHIFT;
1331de2362d3Smrg			tiling_flags |= surface.mtilea << RADEON_TILING_EG_MACRO_TILE_ASPECT_SHIFT;
13327821949aSmrg			tiling_flags |= eg_tile_split(surface.tile_split) << RADEON_TILING_EG_TILE_SPLIT_SHIFT;
1333de2362d3Smrg			break;
1334de2362d3Smrg		case RADEON_SURF_MODE_1D:
1335de2362d3Smrg			tiling_flags |= RADEON_TILING_MICRO;
1336de2362d3Smrg			break;
1337de2362d3Smrg		default:
1338de2362d3Smrg			break;
1339de2362d3Smrg		}
1340de2362d3Smrg		info->front_surface = surface;
1341de2362d3Smrg	}
1342de2362d3Smrg
1343de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1344de2362d3Smrg		   "Allocate new frame buffer %dx%d stride %d\n",
1345de2362d3Smrg		   width, height, pitch / cpp);
1346de2362d3Smrg
1347de2362d3Smrg	old_width = scrn->virtualX;
1348de2362d3Smrg	old_height = scrn->virtualY;
1349de2362d3Smrg	old_pitch = scrn->displayWidth;
1350de2362d3Smrg	old_fb_id = drmmode->fb_id;
1351de2362d3Smrg	old_front = info->front_bo;
1352de2362d3Smrg
1353de2362d3Smrg	scrn->virtualX = width;
1354de2362d3Smrg	scrn->virtualY = height;
1355de2362d3Smrg	scrn->displayWidth = pitch / cpp;
1356de2362d3Smrg
13577821949aSmrg	info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, base_align, RADEON_GEM_DOMAIN_VRAM, 0);
1358de2362d3Smrg	if (!info->front_bo)
1359de2362d3Smrg		goto fail;
1360de2362d3Smrg
1361de2362d3Smrg#if X_BYTE_ORDER == X_BIG_ENDIAN
1362de2362d3Smrg	switch (cpp) {
1363de2362d3Smrg	case 4:
1364de2362d3Smrg	    tiling_flags |= RADEON_TILING_SWAP_32BIT;
1365de2362d3Smrg	    break;
1366de2362d3Smrg	case 2:
1367de2362d3Smrg	    tiling_flags |= RADEON_TILING_SWAP_16BIT;
1368de2362d3Smrg	    break;
1369de2362d3Smrg	}
1370de2362d3Smrg#endif
1371de2362d3Smrg	if (tiling_flags)
1372de2362d3Smrg	    radeon_bo_set_tiling(info->front_bo, tiling_flags, pitch);
1373de2362d3Smrg
13747821949aSmrg	ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
13757821949aSmrg			   scrn->bitsPerPixel, pitch,
13767821949aSmrg			   info->front_bo->handle,
13777821949aSmrg			   &drmmode->fb_id);
13787821949aSmrg	if (ret)
13797821949aSmrg		goto fail;
13807821949aSmrg
1381de2362d3Smrg	if (!info->r600_shadow_fb) {
13827821949aSmrg		radeon_set_pixmap_bo(ppix, info->front_bo);
1383de2362d3Smrg		psurface = radeon_get_pixmap_surface(ppix);
1384de2362d3Smrg		*psurface = info->front_surface;
1385de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
1386de2362d3Smrg					   width, height, -1, -1, pitch, NULL);
1387de2362d3Smrg	} else {
1388de2362d3Smrg		if (radeon_bo_map(info->front_bo, 1))
1389de2362d3Smrg			goto fail;
1390de2362d3Smrg		fb_shadow = calloc(1, screen_size);
1391de2362d3Smrg		if (fb_shadow == NULL)
1392de2362d3Smrg			goto fail;
1393de2362d3Smrg		free(info->fb_shadow);
1394de2362d3Smrg		info->fb_shadow = fb_shadow;
1395de2362d3Smrg		screen->ModifyPixmapHeader(ppix,
1396de2362d3Smrg					   width, height, -1, -1, pitch,
1397de2362d3Smrg					   info->fb_shadow);
1398de2362d3Smrg	}
13997821949aSmrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,9,99,1,0)
14007821949aSmrg	scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr;
14017821949aSmrg#endif
14020d16fef4Smrg
1403de2362d3Smrg	for (i = 0; i < xf86_config->num_crtc; i++) {
1404de2362d3Smrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
1405de2362d3Smrg
1406de2362d3Smrg		if (!crtc->enabled)
1407de2362d3Smrg			continue;
1408de2362d3Smrg
1409de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode,
1410de2362d3Smrg				       crtc->rotation, crtc->x, crtc->y);
1411de2362d3Smrg	}
1412de2362d3Smrg
1413de2362d3Smrg	if (old_fb_id)
1414de2362d3Smrg		drmModeRmFB(drmmode->fd, old_fb_id);
1415de2362d3Smrg	if (old_front)
1416de2362d3Smrg		radeon_bo_unref(old_front);
1417de2362d3Smrg
1418de2362d3Smrg	radeon_kms_update_vram_limit(scrn, screen_size);
1419de2362d3Smrg	return TRUE;
1420de2362d3Smrg
1421de2362d3Smrg fail:
1422de2362d3Smrg	if (info->front_bo)
1423de2362d3Smrg		radeon_bo_unref(info->front_bo);
1424de2362d3Smrg	info->front_bo = old_front;
1425de2362d3Smrg	scrn->virtualX = old_width;
1426de2362d3Smrg	scrn->virtualY = old_height;
1427de2362d3Smrg	scrn->displayWidth = old_pitch;
1428de2362d3Smrg	drmmode->fb_id = old_fb_id;
1429de2362d3Smrg
1430de2362d3Smrg	return FALSE;
1431de2362d3Smrg}
1432de2362d3Smrg
1433de2362d3Smrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
1434de2362d3Smrg	drmmode_xf86crtc_resize
1435de2362d3Smrg};
1436de2362d3Smrg
1437de2362d3Smrgstatic void
14387821949aSmrgdrmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
14397821949aSmrg			unsigned int tv_usec, void *event_data)
1440de2362d3Smrg{
14417821949aSmrg	radeon_dri2_frame_event_handler(frame, tv_sec, tv_usec, event_data);
1442de2362d3Smrg}
1443de2362d3Smrg
1444de2362d3Smrgstatic void
14457821949aSmrgdrmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
14467821949aSmrg		     unsigned int tv_usec, void *event_data)
1447de2362d3Smrg{
14487821949aSmrg	drmmode_flipevtcarrier_ptr flipcarrier = event_data;
14497821949aSmrg	drmmode_flipdata_ptr flipdata = flipcarrier->flipdata;
14507821949aSmrg	drmmode_ptr drmmode = flipdata->drmmode;
1451de2362d3Smrg
1452de2362d3Smrg	/* Is this the event whose info shall be delivered to higher level? */
14537821949aSmrg	if (flipcarrier->dispatch_me) {
1454de2362d3Smrg		/* Yes: Cache msc, ust for later delivery. */
1455de2362d3Smrg		flipdata->fe_frame = frame;
14567821949aSmrg		flipdata->fe_tv_sec = tv_sec;
14577821949aSmrg		flipdata->fe_tv_usec = tv_usec;
1458de2362d3Smrg	}
14597821949aSmrg	free(flipcarrier);
1460de2362d3Smrg
14617821949aSmrg	/* Last crtc completed flip? */
14627821949aSmrg	flipdata->flip_count--;
14637821949aSmrg	if (flipdata->flip_count > 0)
14647821949aSmrg		return;
1465de2362d3Smrg
14667821949aSmrg	/* Release framebuffer */
14677821949aSmrg	drmModeRmFB(drmmode->fd, flipdata->old_fb_id);
1468de2362d3Smrg
14697821949aSmrg	if (flipdata->event_data == NULL)
14707821949aSmrg		return;
14717821949aSmrg
14727821949aSmrg	/* Deliver cached msc, ust from reference crtc to flip event handler */
14737821949aSmrg	radeon_dri2_flip_event_handler(flipdata->fe_frame, flipdata->fe_tv_sec,
14747821949aSmrg				       flipdata->fe_tv_usec, flipdata->event_data);
1475de2362d3Smrg
14767821949aSmrg	free(flipdata);
1477de2362d3Smrg}
1478de2362d3Smrg
1479de2362d3Smrg
1480de2362d3Smrgstatic void
1481de2362d3Smrgdrm_wakeup_handler(pointer data, int err, pointer p)
1482de2362d3Smrg{
1483de2362d3Smrg	drmmode_ptr drmmode = data;
1484de2362d3Smrg	fd_set *read_mask = p;
1485de2362d3Smrg
14867821949aSmrg	if (err >= 0 && FD_ISSET(drmmode->fd, read_mask)) {
1487de2362d3Smrg		drmHandleEvent(drmmode->fd, &drmmode->event_context);
1488de2362d3Smrg	}
1489de2362d3Smrg}
1490de2362d3Smrg
1491de2362d3SmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
1492de2362d3Smrg{
14937821949aSmrg	xf86CrtcConfigPtr xf86_config;
1494de2362d3Smrg	int i, num_dvi = 0, num_hdmi = 0;
1495de2362d3Smrg
1496de2362d3Smrg	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
14977821949aSmrg	xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1498de2362d3Smrg
1499de2362d3Smrg	drmmode->scrn = pScrn;
1500de2362d3Smrg	drmmode->cpp = cpp;
15017821949aSmrg	drmmode->mode_res = drmModeGetResources(drmmode->fd);
15027821949aSmrg	if (!drmmode->mode_res)
1503de2362d3Smrg		return FALSE;
1504de2362d3Smrg
15057821949aSmrg	xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height);
15067821949aSmrg	for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
15077821949aSmrg		if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i)
15087821949aSmrg			drmmode_crtc_init(pScrn, drmmode, i);
1509de2362d3Smrg
15107821949aSmrg	for (i = 0; i < drmmode->mode_res->count_connectors; i++)
15117821949aSmrg		drmmode_output_init(pScrn, drmmode, i, &num_dvi, &num_hdmi);
1512de2362d3Smrg
1513de2362d3Smrg	/* workout clones */
15147821949aSmrg	drmmode_clones_init(pScrn, drmmode);
1515de2362d3Smrg
1516de2362d3Smrg	xf86InitialConfiguration(pScrn, TRUE);
1517de2362d3Smrg
1518de2362d3Smrg	drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
15197821949aSmrg	drmmode->event_context.vblank_handler = drmmode_vblank_handler;
15207821949aSmrg	drmmode->event_context.page_flip_handler = drmmode_flip_handler;
1521de2362d3Smrg
1522de2362d3Smrg	return TRUE;
1523de2362d3Smrg}
1524de2362d3Smrg
1525de2362d3Smrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1526de2362d3Smrg{
1527de2362d3Smrg	RADEONEntPtr pRADEONEnt = RADEONEntPriv(pScrn);
1528de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(pScrn);
1529de2362d3Smrg
15307821949aSmrg	if (pRADEONEnt->fd_wakeup_registered != serverGeneration &&
15317821949aSmrg	    info->dri->pKernelDRMVersion->version_minor >= 4) {
1532de2362d3Smrg		AddGeneralSocket(drmmode->fd);
1533de2362d3Smrg		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1534de2362d3Smrg				drm_wakeup_handler, drmmode);
1535de2362d3Smrg		pRADEONEnt->fd_wakeup_registered = serverGeneration;
1536de2362d3Smrg	}
1537de2362d3Smrg}
1538de2362d3Smrg
1539de2362d3SmrgBool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr)
1540de2362d3Smrg{
1541de2362d3Smrg	drmmode->bufmgr = bufmgr;
1542de2362d3Smrg	return TRUE;
1543de2362d3Smrg}
1544de2362d3Smrg
1545de2362d3Smrg
1546de2362d3Smrg
1547de2362d3Smrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo)
1548de2362d3Smrg{
1549de2362d3Smrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1550de2362d3Smrg	xf86CrtcPtr crtc = xf86_config->crtc[id];
1551de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1552de2362d3Smrg
1553de2362d3Smrg	drmmode_crtc->cursor_bo = bo;
1554de2362d3Smrg}
1555de2362d3Smrg
1556de2362d3Smrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
1557de2362d3Smrg{
1558de2362d3Smrg	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
1559de2362d3Smrg	xf86OutputPtr  output = config->output[config->compat_output];
1560de2362d3Smrg	xf86CrtcPtr	crtc = output->crtc;
1561de2362d3Smrg
1562de2362d3Smrg	if (crtc && crtc->enabled) {
1563de2362d3Smrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
1564de2362d3Smrg				       x, y);
1565de2362d3Smrg	}
1566de2362d3Smrg}
1567de2362d3Smrg
15687821949aSmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1569de2362d3Smrg{
1570de2362d3Smrg	xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1571de2362d3Smrg	int c;
1572de2362d3Smrg
15737821949aSmrg	drmmode_copy_fb(pScrn, drmmode);
15747821949aSmrg
1575de2362d3Smrg	for (c = 0; c < config->num_crtc; c++) {
1576de2362d3Smrg		xf86CrtcPtr	crtc = config->crtc[c];
1577de2362d3Smrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1578de2362d3Smrg		xf86OutputPtr	output = NULL;
1579de2362d3Smrg		int		o;
1580de2362d3Smrg
1581de2362d3Smrg		/* Skip disabled CRTCs */
1582de2362d3Smrg		if (!crtc->enabled) {
15837821949aSmrg			drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
15847821949aSmrg				       0, 0, 0, NULL, 0, NULL);
1585de2362d3Smrg			continue;
1586de2362d3Smrg		}
1587de2362d3Smrg
1588de2362d3Smrg		if (config->output[config->compat_output]->crtc == crtc)
1589de2362d3Smrg			output = config->output[config->compat_output];
1590de2362d3Smrg		else
1591de2362d3Smrg		{
1592de2362d3Smrg			for (o = 0; o < config->num_output; o++)
1593de2362d3Smrg				if (config->output[o]->crtc == crtc)
1594de2362d3Smrg				{
1595de2362d3Smrg					output = config->output[o];
1596de2362d3Smrg					break;
1597de2362d3Smrg				}
1598de2362d3Smrg		}
1599de2362d3Smrg		/* paranoia */
1600de2362d3Smrg		if (!output)
1601de2362d3Smrg			continue;
1602de2362d3Smrg
1603de2362d3Smrg		/* Mark that we'll need to re-set the mode for sure */
1604de2362d3Smrg		memset(&crtc->mode, 0, sizeof(crtc->mode));
1605de2362d3Smrg		if (!crtc->desiredMode.CrtcHDisplay)
1606de2362d3Smrg		{
1607de2362d3Smrg			DisplayModePtr  mode = xf86OutputFindClosestMode (output, pScrn->currentMode);
1608de2362d3Smrg
1609de2362d3Smrg			if (!mode)
1610de2362d3Smrg				return FALSE;
1611de2362d3Smrg			crtc->desiredMode = *mode;
1612de2362d3Smrg			crtc->desiredRotation = RR_Rotate_0;
1613de2362d3Smrg			crtc->desiredX = 0;
1614de2362d3Smrg			crtc->desiredY = 0;
1615de2362d3Smrg		}
1616de2362d3Smrg
16177821949aSmrg		if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
16187821949aSmrg						 crtc->desiredX, crtc->desiredY))
16197821949aSmrg			return FALSE;
1620de2362d3Smrg	}
1621de2362d3Smrg	return TRUE;
1622de2362d3Smrg}
1623de2362d3Smrg
16247821949aSmrgstatic void drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
16257821949aSmrg                                 int *indices, LOCO *colors, VisualPtr pVisual)
1626de2362d3Smrg{
1627de2362d3Smrg    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
16287821949aSmrg    uint16_t       lut_r[256], lut_g[256], lut_b[256];
16297821949aSmrg    int index, j, i;
16307821949aSmrg    int c;
1631de2362d3Smrg
16327821949aSmrg    for (c = 0; c < xf86_config->num_crtc; c++) {
16337821949aSmrg        xf86CrtcPtr crtc = xf86_config->crtc[c];
16347821949aSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
16357314432eSmrg
16367821949aSmrg        for (i = 0 ; i < 256; i++) {
16377821949aSmrg            lut_r[i] = drmmode_crtc->lut_r[i] << 6;
16387821949aSmrg            lut_g[i] = drmmode_crtc->lut_g[i] << 6;
16397821949aSmrg            lut_b[i] = drmmode_crtc->lut_b[i] << 6;
16407821949aSmrg        }
16417314432eSmrg
16427821949aSmrg        switch(pScrn->depth) {
16437821949aSmrg        case 15:
16447821949aSmrg            for (i = 0; i < numColors; i++) {
16457821949aSmrg                index = indices[i];
16467821949aSmrg                for (j = 0; j < 8; j++) {
16477821949aSmrg                    lut_r[index * 8 + j] = colors[index].red << 6;
16487821949aSmrg                    lut_g[index * 8 + j] = colors[index].green << 6;
16497821949aSmrg                    lut_b[index * 8 + j] = colors[index].blue << 6;
16507821949aSmrg                }
16517821949aSmrg            }
16527821949aSmrg         break;
16537821949aSmrg         case 16:
16547821949aSmrg             for (i = 0; i < numColors; i++) {
16557821949aSmrg                 index = indices[i];
16567821949aSmrg
16577821949aSmrg                  if (i <= 31) {
16587821949aSmrg                      for (j = 0; j < 8; j++) {
16597821949aSmrg                          lut_r[index * 8 + j] = colors[index].red << 6;
16607821949aSmrg                          lut_b[index * 8 + j] = colors[index].blue << 6;
16617821949aSmrg                      }
16627821949aSmrg                  }
16637821949aSmrg
16647821949aSmrg                  for (j = 0; j < 4; j++) {
16657821949aSmrg                      lut_g[index * 4 + j] = colors[index].green << 6;
16667821949aSmrg                  }
16677821949aSmrg              }
16687821949aSmrg	  break;
16697821949aSmrg          default:
16707821949aSmrg              for (i = 0; i < numColors; i++) {
16717821949aSmrg                  index = indices[i];
16727821949aSmrg                  lut_r[index] = colors[index].red << 6;
16737821949aSmrg                  lut_g[index] = colors[index].green << 6;
16747821949aSmrg                  lut_b[index] = colors[index].blue << 6;
16757821949aSmrg              }
16767821949aSmrg              break;
16777821949aSmrg          }
16787821949aSmrg
16797821949aSmrg    /* Make the change through RandR */
16807821949aSmrg#ifdef RANDR_12_INTERFACE
16817821949aSmrg        if (crtc->randr_crtc)
16827821949aSmrg            RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
16837821949aSmrg        else
16847821949aSmrg#endif
16857821949aSmrg            crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
16867821949aSmrg     }
16877314432eSmrg}
16887314432eSmrg
16897821949aSmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
16900d16fef4Smrg{
16917821949aSmrg    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
16927821949aSmrg                  "Initializing kms color map\n");
16937821949aSmrg    if (!miCreateDefColormap(pScreen))
16947821949aSmrg        return FALSE;
16957821949aSmrg    /* all radeons support 10 bit CLUTs */
16967821949aSmrg    if (!xf86HandleColormaps(pScreen, 256, 10,
16977821949aSmrg                             drmmode_load_palette, NULL,
16987821949aSmrg                             CMAP_PALETTED_TRUECOLOR
16997821949aSmrg#if 0 /* This option messes up text mode! (eich@suse.de) */
17007821949aSmrg                             | CMAP_LOAD_EVEN_IF_OFFSCREEN
17010d16fef4Smrg#endif
17027821949aSmrg                             | CMAP_RELOAD_ON_MODE_SWITCH))
17037821949aSmrg         return FALSE;
17047821949aSmrg    return TRUE;
17050d16fef4Smrg}
17067821949aSmrg
1707de2362d3Smrg#ifdef HAVE_LIBUDEV
1708de2362d3Smrgstatic void
1709de2362d3Smrgdrmmode_handle_uevents(int fd, void *closure)
1710de2362d3Smrg{
1711de2362d3Smrg	drmmode_ptr drmmode = closure;
1712de2362d3Smrg	ScrnInfoPtr scrn = drmmode->scrn;
1713de2362d3Smrg	struct udev_device *dev;
17147821949aSmrg	dev = udev_monitor_receive_device(drmmode->uevent_monitor);
17157821949aSmrg	if (!dev)
17167821949aSmrg		return;
17177314432eSmrg
17187821949aSmrg	RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
17197821949aSmrg	udev_device_unref(dev);
1720de2362d3Smrg}
1721de2362d3Smrg#endif
1722de2362d3Smrg
1723de2362d3Smrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1724de2362d3Smrg{
1725de2362d3Smrg#ifdef HAVE_LIBUDEV
1726de2362d3Smrg	struct udev *u;
1727de2362d3Smrg	struct udev_monitor *mon;
1728de2362d3Smrg
1729de2362d3Smrg	u = udev_new();
1730de2362d3Smrg	if (!u)
1731de2362d3Smrg		return;
1732de2362d3Smrg	mon = udev_monitor_new_from_netlink(u, "udev");
1733de2362d3Smrg	if (!mon) {
1734de2362d3Smrg		udev_unref(u);
1735de2362d3Smrg		return;
1736de2362d3Smrg	}
1737de2362d3Smrg
1738de2362d3Smrg	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1739de2362d3Smrg							    "drm",
1740de2362d3Smrg							    "drm_minor") < 0 ||
1741de2362d3Smrg	    udev_monitor_enable_receiving(mon) < 0) {
1742de2362d3Smrg		udev_monitor_unref(mon);
1743de2362d3Smrg		udev_unref(u);
1744de2362d3Smrg		return;
1745de2362d3Smrg	}
1746de2362d3Smrg
1747de2362d3Smrg	drmmode->uevent_handler =
1748de2362d3Smrg		xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1749de2362d3Smrg				      drmmode_handle_uevents,
1750de2362d3Smrg				      drmmode);
1751de2362d3Smrg
1752de2362d3Smrg	drmmode->uevent_monitor = mon;
1753de2362d3Smrg#endif
1754de2362d3Smrg}
1755de2362d3Smrg
1756de2362d3Smrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1757de2362d3Smrg{
1758de2362d3Smrg#ifdef HAVE_LIBUDEV
1759de2362d3Smrg	if (drmmode->uevent_handler) {
1760de2362d3Smrg		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1761de2362d3Smrg		xf86RemoveGeneralHandler(drmmode->uevent_handler);
1762de2362d3Smrg
1763de2362d3Smrg		udev_monitor_unref(drmmode->uevent_monitor);
1764de2362d3Smrg		udev_unref(u);
1765de2362d3Smrg	}
1766de2362d3Smrg#endif
1767de2362d3Smrg}
1768de2362d3Smrg
17697821949aSmrgBool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id)
1770de2362d3Smrg{
1771de2362d3Smrg	RADEONInfoPtr info = RADEONPTR(scrn);
1772de2362d3Smrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1773de2362d3Smrg	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
1774de2362d3Smrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1775de2362d3Smrg	unsigned int pitch;
17767821949aSmrg	int i, old_fb_id;
1777de2362d3Smrg	uint32_t tiling_flags = 0;
17787821949aSmrg	int height, emitted = 0;
1779de2362d3Smrg	drmmode_flipdata_ptr flipdata;
17807821949aSmrg	drmmode_flipevtcarrier_ptr flipcarrier;
1781de2362d3Smrg
1782de2362d3Smrg	if (info->allowColorTiling) {
1783de2362d3Smrg		if (info->ChipFamily >= CHIP_FAMILY_R600)
1784de2362d3Smrg			tiling_flags |= RADEON_TILING_MICRO;
1785de2362d3Smrg		else
1786de2362d3Smrg			tiling_flags |= RADEON_TILING_MACRO;
1787de2362d3Smrg	}
1788de2362d3Smrg
17897821949aSmrg	pitch = RADEON_ALIGN(scrn->displayWidth, drmmode_get_pitch_align(scrn, info->CurrentLayout.pixel_bytes, tiling_flags)) *
17907821949aSmrg		info->CurrentLayout.pixel_bytes;
17917821949aSmrg	height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags));
1792de2362d3Smrg	if (info->ChipFamily >= CHIP_FAMILY_R600 && info->surf_man) {
1793de2362d3Smrg		pitch = info->front_surface.level[0].pitch_bytes;
1794de2362d3Smrg	}
1795de2362d3Smrg
17960d16fef4Smrg	/*
17970d16fef4Smrg	 * Create a new handle for the back buffer
17980d16fef4Smrg	 */
17997821949aSmrg	old_fb_id = drmmode->fb_id;
18007821949aSmrg	if (drmModeAddFB(drmmode->fd, scrn->virtualX, height,
18010d16fef4Smrg			 scrn->depth, scrn->bitsPerPixel, pitch,
18027821949aSmrg			 new_front->handle, &drmmode->fb_id))
18037821949aSmrg		goto error_out;
18040d16fef4Smrg
18057821949aSmrg        flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
18067821949aSmrg        if (!flipdata) {
18077821949aSmrg             xf86DrvMsg(scrn->scrnIndex, X_WARNING,
18087821949aSmrg                        "flip queue: data alloc failed.\n");
18097821949aSmrg             goto error_undo;
18107821949aSmrg        }
1811de2362d3Smrg	/*
1812de2362d3Smrg	 * Queue flips on all enabled CRTCs
1813de2362d3Smrg	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
1814de2362d3Smrg	 * Right now it assumes a single shared fb across all CRTCs, with the
1815de2362d3Smrg	 * kernel fixing up the offset of each CRTC as necessary.
1816de2362d3Smrg	 *
1817de2362d3Smrg	 * Also, flips queued on disabled or incorrectly configured displays
1818de2362d3Smrg	 * may never complete; this is a configuration error.
1819de2362d3Smrg	 */
1820de2362d3Smrg
1821de2362d3Smrg        flipdata->event_data = data;
18227821949aSmrg        flipdata->drmmode = drmmode;
18237314432eSmrg
1824de2362d3Smrg	for (i = 0; i < config->num_crtc; i++) {
18257821949aSmrg		if (!config->crtc[i]->enabled)
1826de2362d3Smrg			continue;
1827de2362d3Smrg
1828de2362d3Smrg		flipdata->flip_count++;
18297821949aSmrg		drmmode_crtc = config->crtc[i]->driver_private;
18307821949aSmrg
18317821949aSmrg		flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec));
18327821949aSmrg		if (!flipcarrier) {
18337821949aSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
18347821949aSmrg				   "flip queue: carrier alloc failed.\n");
18357821949aSmrg			if (emitted == 0)
18367821949aSmrg				free(flipdata);
18377821949aSmrg			goto error_undo;
18387821949aSmrg		}
1839de2362d3Smrg
1840de2362d3Smrg		/* Only the reference crtc will finally deliver its page flip
1841de2362d3Smrg		 * completion event. All other crtc's events will be discarded.
1842de2362d3Smrg		 */
18437821949aSmrg		flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id);
18447821949aSmrg		flipcarrier->flipdata = flipdata;
1845de2362d3Smrg
1846de2362d3Smrg		if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
18477821949aSmrg				    drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) {
1848de2362d3Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1849de2362d3Smrg				   "flip queue failed: %s\n", strerror(errno));
18507821949aSmrg			free(flipcarrier);
18517821949aSmrg			if (emitted == 0)
18527821949aSmrg				free(flipdata);
18537821949aSmrg			goto error_undo;
1854de2362d3Smrg		}
18557821949aSmrg		emitted++;
1856de2362d3Smrg	}
1857de2362d3Smrg
18587821949aSmrg	flipdata->old_fb_id = old_fb_id;
18597821949aSmrg	return TRUE;
18600d16fef4Smrg
18617821949aSmrgerror_undo:
18627821949aSmrg	drmModeRmFB(drmmode->fd, drmmode->fb_id);
18637821949aSmrg	drmmode->fb_id = old_fb_id;
1864de2362d3Smrg
18657821949aSmrgerror_out:
1866de2362d3Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
1867de2362d3Smrg		   strerror(errno));
1868de2362d3Smrg	return FALSE;
1869de2362d3Smrg}
18707821949aSmrg
18717821949aSmrg#endif
1872