drmmode_display.c revision c4ae5be6
1/*
2 * Copyright © 2007 Red Hat, Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 *    Dave Airlie <airlied@redhat.com>
25 *
26 */
27
28#ifdef HAVE_CONFIG_H
29#include "config.h"
30#endif
31
32#include <errno.h>
33#ifdef XF86DRM_MODE
34#include <sys/ioctl.h>
35#include "micmap.h"
36#include "xf86cmap.h"
37#include "radeon.h"
38#include "radeon_reg.h"
39#include "radeon_drm.h"
40#include "sarea.h"
41
42#include "drmmode_display.h"
43
44/* DPMS */
45#ifdef HAVE_XEXTPROTO_71
46#include <X11/extensions/dpmsconst.h>
47#else
48#define DPMS_SERVER
49#include <X11/extensions/dpms.h>
50#endif
51
52static PixmapPtr drmmode_create_bo_pixmap(ScreenPtr pScreen,
53					  int width, int height,
54					  int depth, int bpp,
55					  int pitch, struct radeon_bo *bo)
56{
57	PixmapPtr pixmap;
58
59	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
60	if (!pixmap)
61		return NULL;
62
63	if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height,
64					    depth, bpp, pitch, NULL)) {
65		return NULL;
66	}
67
68	exaMoveInPixmap(pixmap);
69	radeon_set_pixmap_bo(pixmap, bo);
70
71	return pixmap;
72}
73
74static void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
75{
76	ScreenPtr pScreen = pixmap->drawable.pScreen;
77
78	(*pScreen->DestroyPixmap)(pixmap);
79}
80
81static void
82drmmode_ConvertFromKMode(ScrnInfoPtr	scrn,
83		     drmModeModeInfo *kmode,
84		     DisplayModePtr	mode)
85{
86	memset(mode, 0, sizeof(DisplayModeRec));
87	mode->status = MODE_OK;
88
89	mode->Clock = kmode->clock;
90
91	mode->HDisplay = kmode->hdisplay;
92	mode->HSyncStart = kmode->hsync_start;
93	mode->HSyncEnd = kmode->hsync_end;
94	mode->HTotal = kmode->htotal;
95	mode->HSkew = kmode->hskew;
96
97	mode->VDisplay = kmode->vdisplay;
98	mode->VSyncStart = kmode->vsync_start;
99	mode->VSyncEnd = kmode->vsync_end;
100	mode->VTotal = kmode->vtotal;
101	mode->VScan = kmode->vscan;
102
103	mode->Flags = kmode->flags; //& FLAG_BITS;
104	mode->name = strdup(kmode->name);
105
106	if (kmode->type & DRM_MODE_TYPE_DRIVER)
107		mode->type = M_T_DRIVER;
108	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
109		mode->type |= M_T_PREFERRED;
110	xf86SetModeCrtc (mode, scrn->adjustFlags);
111}
112
113static void
114drmmode_ConvertToKMode(ScrnInfoPtr	scrn,
115		     drmModeModeInfo *kmode,
116		     DisplayModePtr	mode)
117{
118	memset(kmode, 0, sizeof(*kmode));
119
120	kmode->clock = mode->Clock;
121	kmode->hdisplay = mode->HDisplay;
122	kmode->hsync_start = mode->HSyncStart;
123	kmode->hsync_end = mode->HSyncEnd;
124	kmode->htotal = mode->HTotal;
125	kmode->hskew = mode->HSkew;
126
127	kmode->vdisplay = mode->VDisplay;
128	kmode->vsync_start = mode->VSyncStart;
129	kmode->vsync_end = mode->VSyncEnd;
130	kmode->vtotal = mode->VTotal;
131	kmode->vscan = mode->VScan;
132
133	kmode->flags = mode->Flags; //& FLAG_BITS;
134	if (mode->name)
135		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
136	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
137
138}
139
140static void
141drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
142{
143#if 0
144	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
145//	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
146//	drmmode_ptr drmmode = drmmode_crtc->drmmode;
147
148	/* bonghits in the randr 1.2 - uses dpms to disable crtc - bad buzz */
149	if (mode == DPMSModeOff) {
150//		drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
151//			       0, 0, 0, NULL, 0, NULL);
152	}
153#endif
154}
155
156static PixmapPtr
157create_pixmap_for_fbcon(drmmode_ptr drmmode,
158			ScrnInfoPtr pScrn, int crtc_id)
159{
160	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
161	drmmode_crtc_private_ptr drmmode_crtc;
162	ScreenPtr pScreen = pScrn->pScreen;
163	PixmapPtr pixmap;
164	struct radeon_bo *bo;
165	drmModeFBPtr fbcon;
166	struct drm_gem_flink flink;
167
168	drmmode_crtc = xf86_config->crtc[crtc_id]->driver_private;
169
170	fbcon = drmModeGetFB(drmmode->fd, drmmode_crtc->mode_crtc->buffer_id);
171	if (fbcon == NULL)
172		return NULL;
173
174	flink.handle = fbcon->handle;
175	if (ioctl(drmmode->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
176		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
177			   "Couldn't flink fbcon handle\n");
178		return NULL;
179	}
180
181	bo = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0);
182	if (bo == NULL) {
183		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
184			   "Couldn't allocate bo for fbcon handle\n");
185		return NULL;
186	}
187
188	pixmap = drmmode_create_bo_pixmap(pScreen, fbcon->width, fbcon->height,
189					  fbcon->depth, fbcon->bpp,
190					  fbcon->pitch, bo);
191	if (!pixmap)
192		return NULL;
193
194	radeon_bo_unref(bo);
195	drmModeFreeFB(fbcon);
196	return pixmap;
197}
198
199void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
200{
201	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
202	RADEONInfoPtr info = RADEONPTR(pScrn);
203	PixmapPtr src, dst;
204	ScreenPtr pScreen = pScrn->pScreen;
205	int crtc_id = 0;
206	int i;
207	int pitch;
208	uint32_t tiling_flags = 0;
209	Bool ret;
210
211	if (info->accelOn == FALSE)
212		return;
213
214	for (i = 0; i < xf86_config->num_crtc; i++) {
215		xf86CrtcPtr crtc = xf86_config->crtc[i];
216		drmmode_crtc_private_ptr drmmode_crtc;
217
218		drmmode_crtc = crtc->driver_private;
219		if (drmmode_crtc->mode_crtc->buffer_id)
220			crtc_id = i;
221	}
222
223	src = create_pixmap_for_fbcon(drmmode, pScrn, crtc_id);
224	if (!src)
225		return;
226
227	if (info->allowColorTiling) {
228		if (info->ChipFamily >= CHIP_FAMILY_R600)
229			tiling_flags |= RADEON_TILING_MICRO;
230		else
231			tiling_flags |= RADEON_TILING_MACRO;
232	}
233
234	pitch = RADEON_ALIGN(pScrn->displayWidth,
235			     drmmode_get_pitch_align(pScrn, info->CurrentLayout.pixel_bytes, tiling_flags)) *
236		info->CurrentLayout.pixel_bytes;
237
238	dst = drmmode_create_bo_pixmap(pScreen, pScrn->virtualX,
239				       pScrn->virtualY, pScrn->depth,
240				       pScrn->bitsPerPixel, pitch,
241				       info->front_bo);
242	if (!dst)
243		goto out_free_src;
244
245	ret = info->accel_state->exa->PrepareCopy (src, dst,
246						   -1, -1, GXcopy, FB_ALLONES);
247	if (!ret)
248	  goto out_free_src;
249	info->accel_state->exa->Copy (dst, 0, 0, 0, 0,
250				      pScrn->virtualX, pScrn->virtualY);
251	info->accel_state->exa->DoneCopy (dst);
252	radeon_cs_flush_indirect(pScrn);
253
254	drmmode_destroy_bo_pixmap(dst);
255 out_free_src:
256	drmmode_destroy_bo_pixmap(src);
257
258}
259
260static Bool
261drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
262		     Rotation rotation, int x, int y)
263{
264	ScrnInfoPtr pScrn = crtc->scrn;
265	RADEONInfoPtr info = RADEONPTR(pScrn);
266	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
267	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
268	drmmode_ptr drmmode = drmmode_crtc->drmmode;
269	int saved_x, saved_y;
270	Rotation saved_rotation;
271	DisplayModeRec saved_mode;
272	uint32_t *output_ids;
273	int output_count = 0;
274	Bool ret = TRUE;
275	int i;
276	int fb_id;
277	drmModeModeInfo kmode;
278	int pitch;
279	uint32_t tiling_flags = 0;
280	int height;
281
282	if (info->allowColorTiling) {
283		if (info->ChipFamily >= CHIP_FAMILY_R600)
284			tiling_flags |= RADEON_TILING_MICRO;
285		else
286			tiling_flags |= RADEON_TILING_MACRO;
287	}
288
289	pitch = RADEON_ALIGN(pScrn->displayWidth, drmmode_get_pitch_align(pScrn, info->CurrentLayout.pixel_bytes, tiling_flags)) *
290		info->CurrentLayout.pixel_bytes;
291	height = RADEON_ALIGN(pScrn->virtualY, drmmode_get_height_align(pScrn, tiling_flags));
292
293	if (drmmode->fb_id == 0) {
294		ret = drmModeAddFB(drmmode->fd,
295				   pScrn->virtualX, height,
296                                   pScrn->depth, pScrn->bitsPerPixel,
297				   pitch,
298				   info->front_bo->handle,
299                                   &drmmode->fb_id);
300                if (ret < 0) {
301                        ErrorF("failed to add fb\n");
302                        return FALSE;
303                }
304        }
305
306	saved_mode = crtc->mode;
307	saved_x = crtc->x;
308	saved_y = crtc->y;
309	saved_rotation = crtc->rotation;
310
311	if (mode) {
312		crtc->mode = *mode;
313		crtc->x = x;
314		crtc->y = y;
315		crtc->rotation = rotation;
316#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,99,0,0)
317		crtc->transformPresent = FALSE;
318#endif
319	}
320
321	output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
322	if (!output_ids) {
323		ret = FALSE;
324		goto done;
325	}
326
327	if (mode) {
328		for (i = 0; i < xf86_config->num_output; i++) {
329			xf86OutputPtr output = xf86_config->output[i];
330			drmmode_output_private_ptr drmmode_output;
331
332			if (output->crtc != crtc)
333				continue;
334
335			drmmode_output = output->driver_private;
336			output_ids[output_count] = drmmode_output->mode_output->connector_id;
337			output_count++;
338		}
339
340		if (!xf86CrtcRotate(crtc)) {
341			goto done;
342		}
343#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0)
344		crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
345				       crtc->gamma_blue, crtc->gamma_size);
346#endif
347
348		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
349
350		fb_id = drmmode->fb_id;
351		if (drmmode_crtc->rotate_fb_id) {
352			fb_id = drmmode_crtc->rotate_fb_id;
353			x = y = 0;
354		}
355		ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
356				     fb_id, x, y, output_ids, output_count, &kmode);
357		if (ret)
358			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
359				   "failed to set mode: %s", strerror(-ret));
360		else
361			ret = TRUE;
362
363		if (crtc->scrn->pScreen)
364			xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
365		/* go through all the outputs and force DPMS them back on? */
366		for (i = 0; i < xf86_config->num_output; i++) {
367			xf86OutputPtr output = xf86_config->output[i];
368
369			if (output->crtc != crtc)
370				continue;
371
372			output->funcs->dpms(output, DPMSModeOn);
373		}
374	}
375
376	if (pScrn->pScreen &&
377		!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
378		xf86_reload_cursors(pScrn->pScreen);
379
380done:
381	if (!ret) {
382		crtc->x = saved_x;
383		crtc->y = saved_y;
384		crtc->rotation = saved_rotation;
385		crtc->mode = saved_mode;
386	}
387#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3
388	else
389		crtc->active = TRUE;
390#endif
391
392	return ret;
393}
394
395static void
396drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
397{
398
399}
400
401static void
402drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
403{
404	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
405	drmmode_ptr drmmode = drmmode_crtc->drmmode;
406
407	drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
408}
409
410static void
411drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
412{
413	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
414	int i;
415	uint32_t *ptr;
416
417	/* cursor should be mapped already */
418	ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr);
419
420	for (i = 0; i < 64 * 64; i++)
421		ptr[i] = cpu_to_le32(image[i]);
422}
423
424
425static void
426drmmode_hide_cursor (xf86CrtcPtr crtc)
427{
428	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
429	drmmode_ptr drmmode = drmmode_crtc->drmmode;
430
431	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 64, 64);
432
433}
434
435static void
436drmmode_show_cursor (xf86CrtcPtr crtc)
437{
438	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
439	drmmode_ptr drmmode = drmmode_crtc->drmmode;
440	uint32_t handle = drmmode_crtc->cursor_bo->handle;
441
442	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 64, 64);
443}
444
445static void *
446drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
447{
448	ScrnInfoPtr pScrn = crtc->scrn;
449	RADEONInfoPtr info = RADEONPTR(pScrn);
450	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
451	drmmode_ptr drmmode = drmmode_crtc->drmmode;
452	int size;
453	struct radeon_bo *rotate_bo;
454	int ret;
455	unsigned long rotate_pitch;
456	int base_align;
457
458	/* rotation requires acceleration */
459	if (info->r600_shadow_fb) {
460		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
461			   "Rotation requires acceleration!\n");
462		return NULL;
463	}
464
465	rotate_pitch =
466		RADEON_ALIGN(width, drmmode_get_pitch_align(crtc->scrn, drmmode->cpp, 0)) * drmmode->cpp;
467	height = RADEON_ALIGN(height, drmmode_get_height_align(crtc->scrn, 0));
468	base_align = drmmode_get_base_align(crtc->scrn, drmmode->cpp, 0);
469	size = RADEON_ALIGN(rotate_pitch * height, RADEON_GPU_PAGE_SIZE);
470
471	rotate_bo = radeon_bo_open(drmmode->bufmgr, 0, size, base_align, RADEON_GEM_DOMAIN_VRAM, 0);
472	if (rotate_bo == NULL)
473		return NULL;
474
475	radeon_bo_map(rotate_bo, 1);
476
477	ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth,
478			   crtc->scrn->bitsPerPixel, rotate_pitch,
479			   rotate_bo->handle,
480			   &drmmode_crtc->rotate_fb_id);
481	if (ret) {
482		ErrorF("failed to add rotate fb\n");
483	}
484
485	drmmode_crtc->rotate_bo = rotate_bo;
486	return drmmode_crtc->rotate_bo->ptr;
487}
488
489static PixmapPtr
490drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
491{
492	ScrnInfoPtr pScrn = crtc->scrn;
493	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
494	drmmode_ptr drmmode = drmmode_crtc->drmmode;
495	unsigned long rotate_pitch;
496	PixmapPtr rotate_pixmap;
497
498	if (!data)
499		data = drmmode_crtc_shadow_allocate (crtc, width, height);
500
501	rotate_pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(pScrn, drmmode->cpp, 0)) * drmmode->cpp;
502
503	rotate_pixmap = drmmode_create_bo_pixmap(pScrn->pScreen,
504						 width, height,
505						 pScrn->depth,
506						 pScrn->bitsPerPixel,
507						 rotate_pitch,
508						 drmmode_crtc->rotate_bo);
509	if (rotate_pixmap == NULL) {
510		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
511			   "Couldn't allocate shadow pixmap for rotated CRTC\n");
512	}
513	return rotate_pixmap;
514
515}
516
517static void
518drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
519{
520	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
521	drmmode_ptr drmmode = drmmode_crtc->drmmode;
522
523	if (rotate_pixmap)
524		drmmode_destroy_bo_pixmap(rotate_pixmap);
525
526	if (data) {
527		drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
528		drmmode_crtc->rotate_fb_id = 0;
529		radeon_bo_unmap(drmmode_crtc->rotate_bo);
530		radeon_bo_unref(drmmode_crtc->rotate_bo);
531		drmmode_crtc->rotate_bo = NULL;
532	}
533
534}
535
536static void
537drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
538                      uint16_t *blue, int size)
539{
540	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
541	drmmode_ptr drmmode = drmmode_crtc->drmmode;
542
543	drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
544			    size, red, green, blue);
545}
546
547static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
548    .dpms = drmmode_crtc_dpms,
549    .set_mode_major = drmmode_set_mode_major,
550    .set_cursor_colors = drmmode_set_cursor_colors,
551    .set_cursor_position = drmmode_set_cursor_position,
552    .show_cursor = drmmode_show_cursor,
553    .hide_cursor = drmmode_hide_cursor,
554    .load_cursor_argb = drmmode_load_cursor_argb,
555
556    .gamma_set = drmmode_crtc_gamma_set,
557    .shadow_create = drmmode_crtc_shadow_create,
558    .shadow_allocate = drmmode_crtc_shadow_allocate,
559    .shadow_destroy = drmmode_crtc_shadow_destroy,
560    .destroy = NULL, /* XXX */
561};
562
563int drmmode_get_crtc_id(xf86CrtcPtr crtc)
564{
565	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
566	return drmmode_crtc->hw_id;
567}
568
569void drmmode_crtc_hw_id(xf86CrtcPtr crtc)
570{
571	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
572	ScrnInfoPtr pScrn = crtc->scrn;
573	RADEONInfoPtr info = RADEONPTR(pScrn);
574	struct drm_radeon_info ginfo;
575	int r;
576	uint32_t tmp;
577
578	memset(&ginfo, 0, sizeof(ginfo));
579	ginfo.request = 0x4;
580	tmp = drmmode_crtc->mode_crtc->crtc_id;
581	ginfo.value = (uintptr_t)&tmp;
582	r = drmCommandWriteRead(info->dri->drmFD, DRM_RADEON_INFO, &ginfo, sizeof(ginfo));
583	if (r) {
584		drmmode_crtc->hw_id = -1;
585		return;
586	}
587	drmmode_crtc->hw_id = tmp;
588}
589
590static void
591drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
592{
593	xf86CrtcPtr crtc;
594	drmmode_crtc_private_ptr drmmode_crtc;
595
596	crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
597	if (crtc == NULL)
598		return;
599
600	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
601	drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
602	drmmode_crtc->drmmode = drmmode;
603	crtc->driver_private = drmmode_crtc;
604	drmmode_crtc_hw_id(crtc);
605
606	return;
607}
608
609static xf86OutputStatus
610drmmode_output_detect(xf86OutputPtr output)
611{
612	/* go to the hw and retrieve a new output struct */
613	drmmode_output_private_ptr drmmode_output = output->driver_private;
614	drmmode_ptr drmmode = drmmode_output->drmmode;
615	xf86OutputStatus status;
616	drmModeFreeConnector(drmmode_output->mode_output);
617
618	drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
619
620	switch (drmmode_output->mode_output->connection) {
621	case DRM_MODE_CONNECTED:
622		status = XF86OutputStatusConnected;
623		break;
624	case DRM_MODE_DISCONNECTED:
625		status = XF86OutputStatusDisconnected;
626		break;
627	default:
628	case DRM_MODE_UNKNOWNCONNECTION:
629		status = XF86OutputStatusUnknown;
630		break;
631	}
632	return status;
633}
634
635static Bool
636drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
637{
638	return MODE_OK;
639}
640
641static DisplayModePtr
642drmmode_output_get_modes(xf86OutputPtr output)
643{
644	drmmode_output_private_ptr drmmode_output = output->driver_private;
645	drmModeConnectorPtr koutput = drmmode_output->mode_output;
646	drmmode_ptr drmmode = drmmode_output->drmmode;
647	int i;
648	DisplayModePtr Modes = NULL, Mode;
649	drmModePropertyPtr props;
650	xf86MonPtr mon = NULL;
651
652	/* look for an EDID property */
653	for (i = 0; i < koutput->count_props; i++) {
654		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
655		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
656			if (!strcmp(props->name, "EDID")) {
657				if (drmmode_output->edid_blob)
658					drmModeFreePropertyBlob(drmmode_output->edid_blob);
659				drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
660			}
661			drmModeFreeProperty(props);
662		}
663	}
664
665	if (drmmode_output->edid_blob) {
666		mon = xf86InterpretEDID(output->scrn->scrnIndex,
667					drmmode_output->edid_blob->data);
668		if (mon && drmmode_output->edid_blob->length > 128)
669			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
670	}
671	xf86OutputSetEDID(output, mon);
672
673	/* modes should already be available */
674	for (i = 0; i < koutput->count_modes; i++) {
675		Mode = xnfalloc(sizeof(DisplayModeRec));
676
677		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
678		Modes = xf86ModesAdd(Modes, Mode);
679
680	}
681	return Modes;
682}
683
684static void
685drmmode_output_destroy(xf86OutputPtr output)
686{
687	drmmode_output_private_ptr drmmode_output = output->driver_private;
688	int i;
689
690	if (drmmode_output->edid_blob)
691		drmModeFreePropertyBlob(drmmode_output->edid_blob);
692	for (i = 0; i < drmmode_output->num_props; i++) {
693		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
694		free(drmmode_output->props[i].atoms);
695	}
696	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
697		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
698		free(drmmode_output->mode_encoders);
699	}
700	free(drmmode_output->props);
701	drmModeFreeConnector(drmmode_output->mode_output);
702	free(drmmode_output);
703	output->driver_private = NULL;
704}
705
706static void
707drmmode_output_dpms(xf86OutputPtr output, int mode)
708{
709	drmmode_output_private_ptr drmmode_output = output->driver_private;
710	drmModeConnectorPtr koutput = drmmode_output->mode_output;
711	drmmode_ptr drmmode = drmmode_output->drmmode;
712
713	drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
714				    drmmode_output->dpms_enum_id, mode);
715	return;
716}
717
718
719static Bool
720drmmode_property_ignore(drmModePropertyPtr prop)
721{
722    if (!prop)
723	return TRUE;
724    /* ignore blob prop */
725    if (prop->flags & DRM_MODE_PROP_BLOB)
726	return TRUE;
727    /* ignore standard property */
728    if (!strcmp(prop->name, "EDID") ||
729	    !strcmp(prop->name, "DPMS"))
730	return TRUE;
731
732    return FALSE;
733}
734
735static void
736drmmode_output_create_resources(xf86OutputPtr output)
737{
738    drmmode_output_private_ptr drmmode_output = output->driver_private;
739    drmModeConnectorPtr mode_output = drmmode_output->mode_output;
740    drmmode_ptr drmmode = drmmode_output->drmmode;
741    drmModePropertyPtr drmmode_prop;
742    int i, j, err;
743
744    drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
745    if (!drmmode_output->props)
746	return;
747
748    drmmode_output->num_props = 0;
749    for (i = 0, j = 0; i < mode_output->count_props; i++) {
750	drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
751	if (drmmode_property_ignore(drmmode_prop)) {
752	    drmModeFreeProperty(drmmode_prop);
753	    continue;
754	}
755	drmmode_output->props[j].mode_prop = drmmode_prop;
756	drmmode_output->props[j].value = mode_output->prop_values[i];
757	drmmode_output->num_props++;
758	j++;
759    }
760
761    for (i = 0; i < drmmode_output->num_props; i++) {
762	drmmode_prop_ptr p = &drmmode_output->props[i];
763	drmmode_prop = p->mode_prop;
764
765	if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
766	    INT32 range[2];
767	    INT32 value = p->value;
768
769	    p->num_atoms = 1;
770	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
771	    if (!p->atoms)
772		continue;
773	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
774	    range[0] = drmmode_prop->values[0];
775	    range[1] = drmmode_prop->values[1];
776	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
777		    FALSE, TRUE,
778		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
779		    2, range);
780	    if (err != 0) {
781		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
782			"RRConfigureOutputProperty error, %d\n", err);
783	    }
784	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
785		    XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE);
786	    if (err != 0) {
787		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
788			"RRChangeOutputProperty error, %d\n", err);
789	    }
790	} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
791	    p->num_atoms = drmmode_prop->count_enums + 1;
792	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
793	    if (!p->atoms)
794		continue;
795	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
796	    for (j = 1; j <= drmmode_prop->count_enums; j++) {
797		struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
798		p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
799	    }
800	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
801		    FALSE, FALSE,
802		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
803		    p->num_atoms - 1, (INT32 *)&p->atoms[1]);
804	    if (err != 0) {
805		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
806			"RRConfigureOutputProperty error, %d\n", err);
807	    }
808	    for (j = 0; j < drmmode_prop->count_enums; j++)
809		if (drmmode_prop->enums[j].value == p->value)
810		    break;
811	    /* there's always a matching value */
812	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
813		    XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
814	    if (err != 0) {
815		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
816			"RRChangeOutputProperty error, %d\n", err);
817	    }
818	}
819    }
820}
821
822static Bool
823drmmode_output_set_property(xf86OutputPtr output, Atom property,
824		RRPropertyValuePtr value)
825{
826    drmmode_output_private_ptr drmmode_output = output->driver_private;
827    drmmode_ptr drmmode = drmmode_output->drmmode;
828    int i;
829
830    for (i = 0; i < drmmode_output->num_props; i++) {
831	drmmode_prop_ptr p = &drmmode_output->props[i];
832
833	if (p->atoms[0] != property)
834	    continue;
835
836	if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
837	    uint32_t val;
838
839	    if (value->type != XA_INTEGER || value->format != 32 ||
840		    value->size != 1)
841		return FALSE;
842	    val = *(uint32_t *)value->data;
843
844	    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
845		    p->mode_prop->prop_id, (uint64_t)val);
846	    return TRUE;
847	} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
848	    Atom	atom;
849	    const char	*name;
850	    int		j;
851
852	    if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
853		return FALSE;
854	    memcpy(&atom, value->data, 4);
855	    name = NameForAtom(atom);
856
857	    /* search for matching name string, then set its value down */
858	    for (j = 0; j < p->mode_prop->count_enums; j++) {
859		if (!strcmp(p->mode_prop->enums[j].name, name)) {
860		    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
861			    p->mode_prop->prop_id, p->mode_prop->enums[j].value);
862		    return TRUE;
863		}
864	    }
865	}
866    }
867
868    return TRUE;
869}
870
871static Bool
872drmmode_output_get_property(xf86OutputPtr output, Atom property)
873{
874    return TRUE;
875}
876
877static const xf86OutputFuncsRec drmmode_output_funcs = {
878    .dpms = drmmode_output_dpms,
879    .create_resources = drmmode_output_create_resources,
880#ifdef RANDR_12_INTERFACE
881    .set_property = drmmode_output_set_property,
882    .get_property = drmmode_output_get_property,
883#endif
884#if 0
885
886    .save = drmmode_crt_save,
887    .restore = drmmode_crt_restore,
888    .mode_fixup = drmmode_crt_mode_fixup,
889    .prepare = drmmode_output_prepare,
890    .mode_set = drmmode_crt_mode_set,
891    .commit = drmmode_output_commit,
892#endif
893    .detect = drmmode_output_detect,
894    .mode_valid = drmmode_output_mode_valid,
895
896    .get_modes = drmmode_output_get_modes,
897    .destroy = drmmode_output_destroy
898};
899
900static int subpixel_conv_table[7] = { 0, SubPixelUnknown,
901				      SubPixelHorizontalRGB,
902				      SubPixelHorizontalBGR,
903				      SubPixelVerticalRGB,
904				      SubPixelVerticalBGR,
905				      SubPixelNone };
906
907const char *output_names[] = { "None",
908			       "VGA",
909			       "DVI",
910			       "DVI",
911			       "DVI",
912			       "Composite",
913			       "S-video",
914			       "LVDS",
915			       "CTV",
916			       "DIN",
917			       "DisplayPort",
918			       "HDMI",
919			       "HDMI",
920			       "TV",
921			       "eDP"
922};
923
924static void
925drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num, int *num_dvi, int *num_hdmi)
926{
927	RADEONInfoPtr info = RADEONPTR(pScrn);
928	xf86OutputPtr output;
929	drmModeConnectorPtr koutput;
930	drmModeEncoderPtr *kencoders = NULL;
931	drmmode_output_private_ptr drmmode_output;
932	drmModePropertyPtr props;
933	char name[32];
934	int i;
935	const char *s;
936
937	koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
938	if (!koutput)
939		return;
940
941	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
942	if (!kencoders) {
943		goto out_free_encoders;
944	}
945
946	for (i = 0; i < koutput->count_encoders; i++) {
947		kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
948		if (!kencoders[i]) {
949			goto out_free_encoders;
950		}
951	}
952
953	/* need to do smart conversion here for compat with non-kms ATI driver */
954	if (koutput->connector_type_id == 1) {
955	    switch(koutput->connector_type) {
956	    case DRM_MODE_CONNECTOR_DVII:
957	    case DRM_MODE_CONNECTOR_DVID:
958	    case DRM_MODE_CONNECTOR_DVIA:
959		snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
960		(*num_dvi)++;
961		break;
962	    case DRM_MODE_CONNECTOR_HDMIA:
963	    case DRM_MODE_CONNECTOR_HDMIB:
964		snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
965		(*num_hdmi)++;
966		break;
967	    case DRM_MODE_CONNECTOR_VGA:
968	    case DRM_MODE_CONNECTOR_DisplayPort:
969		snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
970		break;
971	    default:
972		snprintf(name, 32, "%s", output_names[koutput->connector_type]);
973		break;
974	    }
975	} else {
976	    snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
977	}
978
979	if (xf86IsEntityShared(pScrn->entityList[0])) {
980		if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
981			if (!RADEONZaphodStringMatches(pScrn, s, name))
982				goto out_free_encoders;
983		} else {
984			if (info->IsPrimary && (num != 0))
985				goto out_free_encoders;
986			else if (info->IsSecondary && (num != 1))
987				goto out_free_encoders;
988		}
989	}
990
991	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
992	if (!output) {
993		goto out_free_encoders;
994	}
995
996	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
997	if (!drmmode_output) {
998		xf86OutputDestroy(output);
999		goto out_free_encoders;
1000	}
1001
1002	drmmode_output->output_id = drmmode->mode_res->connectors[num];
1003	drmmode_output->mode_output = koutput;
1004	drmmode_output->mode_encoders = kencoders;
1005	drmmode_output->drmmode = drmmode;
1006	output->mm_width = koutput->mmWidth;
1007	output->mm_height = koutput->mmHeight;
1008
1009	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
1010	output->interlaceAllowed = TRUE;
1011	output->doubleScanAllowed = TRUE;
1012	output->driver_private = drmmode_output;
1013
1014	output->possible_crtcs = 0x7f;
1015	for (i = 0; i < koutput->count_encoders; i++) {
1016		output->possible_crtcs &= kencoders[i]->possible_crtcs;
1017	}
1018	/* work out the possible clones later */
1019	output->possible_clones = 0;
1020
1021	for (i = 0; i < koutput->count_props; i++) {
1022		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
1023		if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
1024			if (!strcmp(props->name, "DPMS")) {
1025				drmmode_output->dpms_enum_id = koutput->props[i];
1026				drmModeFreeProperty(props);
1027				break;
1028			}
1029			drmModeFreeProperty(props);
1030		}
1031	}
1032
1033	return;
1034out_free_encoders:
1035	if (kencoders){
1036		for (i = 0; i < koutput->count_encoders; i++)
1037			drmModeFreeEncoder(kencoders[i]);
1038		free(kencoders);
1039	}
1040	drmModeFreeConnector(koutput);
1041
1042}
1043
1044uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
1045{
1046	drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout;
1047	int i;
1048	xf86OutputPtr clone_output;
1049	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1050	int index_mask = 0;
1051
1052	if (drmmode_output->enc_clone_mask == 0)
1053		return index_mask;
1054
1055	for (i = 0; i < xf86_config->num_output; i++) {
1056		clone_output = xf86_config->output[i];
1057		clone_drmout = clone_output->driver_private;
1058		if (output == clone_output)
1059			continue;
1060
1061		if (clone_drmout->enc_mask == 0)
1062			continue;
1063		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
1064			index_mask |= (1 << i);
1065	}
1066	return index_mask;
1067}
1068
1069
1070static void
1071drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1072{
1073	int i, j;
1074	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1075
1076	for (i = 0; i < xf86_config->num_output; i++) {
1077		xf86OutputPtr output = xf86_config->output[i];
1078		drmmode_output_private_ptr drmmode_output;
1079
1080		drmmode_output = output->driver_private;
1081		drmmode_output->enc_clone_mask = 0xff;
1082		/* and all the possible encoder clones for this output together */
1083		for (j = 0; j < drmmode_output->mode_output->count_encoders; j++)
1084		{
1085			int k;
1086			for (k = 0; k < drmmode->mode_res->count_encoders; k++) {
1087				if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id)
1088					drmmode_output->enc_mask |= (1 << k);
1089			}
1090
1091			drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones;
1092		}
1093	}
1094
1095	for (i = 0; i < xf86_config->num_output; i++) {
1096		xf86OutputPtr output = xf86_config->output[i];
1097		output->possible_clones = find_clones(scrn, output);
1098	}
1099}
1100
1101/* returns height alignment in pixels */
1102int drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling)
1103{
1104	RADEONInfoPtr info = RADEONPTR(scrn);
1105	int height_align = 1;
1106
1107	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1108		if (tiling & RADEON_TILING_MACRO)
1109			height_align =  info->num_channels * 8;
1110		else if (tiling & RADEON_TILING_MICRO)
1111			height_align = 8;
1112		else
1113			height_align = 8;
1114	} else {
1115		if (tiling)
1116			height_align = 16;
1117		else
1118			height_align = 1;
1119	}
1120	return height_align;
1121}
1122
1123/* returns pitch alignment in pixels */
1124int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
1125{
1126	RADEONInfoPtr info = RADEONPTR(scrn);
1127	int pitch_align = 1;
1128
1129	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1130		if (tiling & RADEON_TILING_MACRO) {
1131			/* general surface requirements */
1132			pitch_align = MAX(info->num_banks,
1133					  (((info->group_bytes / 8) / bpe) * info->num_banks)) * 8;
1134			/* further restrictions for scanout */
1135			pitch_align = MAX(info->num_banks * 8, pitch_align);
1136		} else if (tiling & RADEON_TILING_MICRO) {
1137			/* general surface requirements */
1138			pitch_align = MAX(8, (info->group_bytes / (8 * bpe)));
1139			/* further restrictions for scanout */
1140			pitch_align = MAX(info->group_bytes / bpe, pitch_align);
1141		} else {
1142			if (info->have_tiling_info)
1143				/* linear aligned requirements */
1144				pitch_align = MAX(64, info->group_bytes / bpe);
1145			else
1146				/* default to 512 elements if we don't know the real
1147				 * group size otherwise the kernel may reject the CS
1148				 * if the group sizes don't match as the pitch won't
1149				 * be aligned properly.
1150				 */
1151				pitch_align = 512;
1152		}
1153	} else {
1154		/* general surface requirements */
1155		if (tiling)
1156			pitch_align = 256 / bpe;
1157		else
1158			pitch_align = 64;
1159	}
1160	return pitch_align;
1161}
1162
1163/* returns base alignment in bytes */
1164int drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling)
1165{
1166	RADEONInfoPtr info = RADEONPTR(scrn);
1167	int pixel_align = drmmode_get_pitch_align(scrn, bpe, tiling);
1168	int height_align = drmmode_get_height_align(scrn, tiling);
1169	int base_align = RADEON_GPU_PAGE_SIZE;
1170
1171	if (info->ChipFamily >= CHIP_FAMILY_R600) {
1172		if (tiling & RADEON_TILING_MACRO)
1173			base_align = MAX(info->num_banks * info->num_channels * 8 * 8 * bpe,
1174					 pixel_align * bpe * height_align);
1175		else {
1176			if (info->have_tiling_info)
1177				base_align = info->group_bytes;
1178			else
1179				/* default to 512 if we don't know the real
1180				 * group size otherwise the kernel may reject the CS
1181				 * if the group sizes don't match as the base won't
1182				 * be aligned properly.
1183				 */
1184				base_align = 512;
1185		}
1186	}
1187	return base_align;
1188}
1189
1190static Bool
1191drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
1192{
1193	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1194	drmmode_crtc_private_ptr
1195		    drmmode_crtc = xf86_config->crtc[0]->driver_private;
1196	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1197	RADEONInfoPtr info = RADEONPTR(scrn);
1198	struct radeon_bo *old_front = NULL;
1199	Bool	    ret;
1200	ScreenPtr   screen = screenInfo.screens[scrn->scrnIndex];
1201	uint32_t    old_fb_id;
1202	int	    i, pitch, old_width, old_height, old_pitch;
1203	int screen_size;
1204	int cpp = info->CurrentLayout.pixel_bytes;
1205	struct radeon_bo *front_bo;
1206	uint32_t tiling_flags = 0;
1207	PixmapPtr ppix = screen->GetScreenPixmap(screen);
1208	void *fb_shadow;
1209
1210	if (scrn->virtualX == width && scrn->virtualY == height)
1211		return TRUE;
1212
1213	front_bo = info->front_bo;
1214	radeon_cs_flush_indirect(scrn);
1215
1216	if (front_bo)
1217		radeon_bo_wait(front_bo);
1218
1219	if (info->allowColorTiling) {
1220		if (info->ChipFamily >= CHIP_FAMILY_R600)
1221			tiling_flags |= RADEON_TILING_MICRO;
1222		else
1223			tiling_flags |= RADEON_TILING_MACRO;
1224	}
1225
1226	pitch = RADEON_ALIGN(width, drmmode_get_pitch_align(scrn, cpp, tiling_flags)) * cpp;
1227	height = RADEON_ALIGN(height, drmmode_get_height_align(scrn, tiling_flags));
1228	screen_size = RADEON_ALIGN(pitch * height, RADEON_GPU_PAGE_SIZE);
1229
1230	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1231		   "Allocate new frame buffer %dx%d stride %d\n",
1232		   width, height, pitch / cpp);
1233
1234	old_width = scrn->virtualX;
1235	old_height = scrn->virtualY;
1236	old_pitch = scrn->displayWidth;
1237	old_fb_id = drmmode->fb_id;
1238	old_front = info->front_bo;
1239
1240	scrn->virtualX = width;
1241	scrn->virtualY = height;
1242	scrn->displayWidth = pitch / cpp;
1243
1244	info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
1245	if (!info->front_bo)
1246		goto fail;
1247
1248#if X_BYTE_ORDER == X_BIG_ENDIAN
1249	switch (cpp) {
1250	case 4:
1251	    tiling_flags |= RADEON_TILING_SWAP_32BIT;
1252	    break;
1253	case 2:
1254	    tiling_flags |= RADEON_TILING_SWAP_16BIT;
1255	    break;
1256	}
1257#endif
1258	if (tiling_flags)
1259	    radeon_bo_set_tiling(info->front_bo, tiling_flags, pitch);
1260
1261	ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
1262			   scrn->bitsPerPixel, pitch,
1263			   info->front_bo->handle,
1264			   &drmmode->fb_id);
1265	if (ret)
1266		goto fail;
1267
1268	if (!info->r600_shadow_fb) {
1269		radeon_set_pixmap_bo(ppix, info->front_bo);
1270		screen->ModifyPixmapHeader(ppix,
1271					   width, height, -1, -1, pitch, NULL);
1272	} else {
1273		if (radeon_bo_map(info->front_bo, 1))
1274			goto fail;
1275		fb_shadow = calloc(1, screen_size);
1276		if (fb_shadow == NULL)
1277			goto fail;
1278		free(info->fb_shadow);
1279		info->fb_shadow = fb_shadow;
1280		screen->ModifyPixmapHeader(ppix,
1281					   width, height, -1, -1, pitch,
1282					   info->fb_shadow);
1283	}
1284#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,9,99,1,0)
1285	scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr;
1286#endif
1287
1288	for (i = 0; i < xf86_config->num_crtc; i++) {
1289		xf86CrtcPtr crtc = xf86_config->crtc[i];
1290
1291		if (!crtc->enabled)
1292			continue;
1293
1294		drmmode_set_mode_major(crtc, &crtc->mode,
1295				       crtc->rotation, crtc->x, crtc->y);
1296	}
1297
1298	if (old_fb_id)
1299		drmModeRmFB(drmmode->fd, old_fb_id);
1300	if (old_front)
1301		radeon_bo_unref(old_front);
1302
1303	radeon_kms_update_vram_limit(scrn, screen_size);
1304	return TRUE;
1305
1306 fail:
1307	if (info->front_bo)
1308		radeon_bo_unref(info->front_bo);
1309	info->front_bo = old_front;
1310	scrn->virtualX = old_width;
1311	scrn->virtualY = old_height;
1312	scrn->displayWidth = old_pitch;
1313	drmmode->fb_id = old_fb_id;
1314
1315	return FALSE;
1316}
1317
1318static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
1319	drmmode_xf86crtc_resize
1320};
1321
1322static void
1323drmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
1324			unsigned int tv_usec, void *event_data)
1325{
1326	radeon_dri2_frame_event_handler(frame, tv_sec, tv_usec, event_data);
1327}
1328
1329static void
1330drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
1331		     unsigned int tv_usec, void *event_data)
1332{
1333	drmmode_flipevtcarrier_ptr flipcarrier = event_data;
1334	drmmode_ptr drmmode = flipcarrier->drmmode;
1335
1336	/* Is this the event whose info shall be delivered to higher level? */
1337	if (flipcarrier->dispatch_me) {
1338		/* Yes: Cache msc, ust for later delivery. */
1339		drmmode->fe_frame = frame;
1340		drmmode->fe_tv_sec = tv_sec;
1341		drmmode->fe_tv_usec = tv_usec;
1342	}
1343	free(flipcarrier);
1344
1345	/* Last crtc completed flip? */
1346	drmmode->flip_count--;
1347	if (drmmode->flip_count > 0)
1348		return;
1349
1350	/* Release framebuffer */
1351	drmModeRmFB(drmmode->fd, drmmode->old_fb_id);
1352
1353	if (drmmode->event_data == NULL)
1354		return;
1355
1356	/* Deliver cached msc, ust from reference crtc to flip event handler */
1357	radeon_dri2_flip_event_handler(drmmode->fe_frame, drmmode->fe_tv_sec,
1358				       drmmode->fe_tv_usec, drmmode->event_data);
1359}
1360
1361
1362static void
1363drm_wakeup_handler(pointer data, int err, pointer p)
1364{
1365	drmmode_ptr drmmode = data;
1366	fd_set *read_mask = p;
1367
1368	if (err >= 0 && FD_ISSET(drmmode->fd, read_mask)) {
1369		drmHandleEvent(drmmode->fd, &drmmode->event_context);
1370	}
1371}
1372
1373Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
1374{
1375	RADEONEntPtr pRADEONEnt   = RADEONEntPriv(pScrn);
1376	xf86CrtcConfigPtr xf86_config;
1377	RADEONInfoPtr info = RADEONPTR(pScrn);
1378	int i, num_dvi = 0, num_hdmi = 0;
1379
1380	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
1381	xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1382
1383	drmmode->scrn = pScrn;
1384	drmmode->cpp = cpp;
1385	drmmode->mode_res = drmModeGetResources(drmmode->fd);
1386	if (!drmmode->mode_res)
1387		return FALSE;
1388
1389	xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height);
1390	for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
1391		if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i)
1392			drmmode_crtc_init(pScrn, drmmode, i);
1393
1394	for (i = 0; i < drmmode->mode_res->count_connectors; i++)
1395		drmmode_output_init(pScrn, drmmode, i, &num_dvi, &num_hdmi);
1396
1397	/* workout clones */
1398	drmmode_clones_init(pScrn, drmmode);
1399
1400	xf86InitialConfiguration(pScrn, TRUE);
1401
1402	drmmode->flip_count = 0;
1403	drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
1404	drmmode->event_context.vblank_handler = drmmode_vblank_handler;
1405	drmmode->event_context.page_flip_handler = drmmode_flip_handler;
1406	if (!pRADEONEnt->fd_wakeup_registered && info->dri->pKernelDRMVersion->version_minor >= 4) {
1407		drmmode->flip_count = 0;
1408		AddGeneralSocket(drmmode->fd);
1409		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1410				drm_wakeup_handler, drmmode);
1411		pRADEONEnt->fd_wakeup_registered = TRUE;
1412	}
1413
1414	return TRUE;
1415}
1416
1417Bool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr)
1418{
1419	drmmode->bufmgr = bufmgr;
1420	return TRUE;
1421}
1422
1423
1424
1425void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo)
1426{
1427	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1428	xf86CrtcPtr crtc = xf86_config->crtc[id];
1429	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1430
1431	drmmode_crtc->cursor_bo = bo;
1432}
1433
1434void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y, int flags)
1435{
1436	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
1437	xf86OutputPtr  output = config->output[config->compat_output];
1438	xf86CrtcPtr	crtc = output->crtc;
1439
1440	if (crtc && crtc->enabled) {
1441		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
1442				       x, y);
1443	}
1444}
1445
1446Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1447{
1448	xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1449	int c;
1450
1451	drmmode_copy_fb(pScrn, drmmode);
1452
1453	for (c = 0; c < config->num_crtc; c++) {
1454		xf86CrtcPtr	crtc = config->crtc[c];
1455		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1456		xf86OutputPtr	output = NULL;
1457		int		o;
1458
1459		/* Skip disabled CRTCs */
1460		if (!crtc->enabled) {
1461			drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1462				       0, 0, 0, NULL, 0, NULL);
1463			continue;
1464		}
1465
1466		if (config->output[config->compat_output]->crtc == crtc)
1467			output = config->output[config->compat_output];
1468		else
1469		{
1470			for (o = 0; o < config->num_output; o++)
1471				if (config->output[o]->crtc == crtc)
1472				{
1473					output = config->output[o];
1474					break;
1475				}
1476		}
1477		/* paranoia */
1478		if (!output)
1479			continue;
1480
1481		/* Mark that we'll need to re-set the mode for sure */
1482		memset(&crtc->mode, 0, sizeof(crtc->mode));
1483		if (!crtc->desiredMode.CrtcHDisplay)
1484		{
1485			DisplayModePtr  mode = xf86OutputFindClosestMode (output, pScrn->currentMode);
1486
1487			if (!mode)
1488				return FALSE;
1489			crtc->desiredMode = *mode;
1490			crtc->desiredRotation = RR_Rotate_0;
1491			crtc->desiredX = 0;
1492			crtc->desiredY = 0;
1493		}
1494
1495		if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
1496						 crtc->desiredX, crtc->desiredY))
1497			return FALSE;
1498	}
1499	return TRUE;
1500}
1501
1502static void drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
1503                                 int *indices, LOCO *colors, VisualPtr pVisual)
1504{
1505    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1506    uint16_t       lut_r[256], lut_g[256], lut_b[256];
1507    int index, j, i;
1508    int c;
1509
1510    for (c = 0; c < xf86_config->num_crtc; c++) {
1511        xf86CrtcPtr crtc = xf86_config->crtc[c];
1512	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1513
1514        for (i = 0 ; i < 256; i++) {
1515            lut_r[i] = drmmode_crtc->lut_r[i] << 6;
1516            lut_g[i] = drmmode_crtc->lut_g[i] << 6;
1517            lut_b[i] = drmmode_crtc->lut_b[i] << 6;
1518        }
1519
1520        switch(pScrn->depth) {
1521        case 15:
1522            for (i = 0; i < numColors; i++) {
1523                index = indices[i];
1524                for (j = 0; j < 8; j++) {
1525                    lut_r[index * 8 + j] = colors[index].red << 6;
1526                    lut_g[index * 8 + j] = colors[index].green << 6;
1527                    lut_b[index * 8 + j] = colors[index].blue << 6;
1528                }
1529            }
1530         break;
1531         case 16:
1532             for (i = 0; i < numColors; i++) {
1533                 index = indices[i];
1534
1535                  if (i <= 31) {
1536                      for (j = 0; j < 8; j++) {
1537                          lut_r[index * 8 + j] = colors[index].red << 6;
1538                          lut_b[index * 8 + j] = colors[index].blue << 6;
1539                      }
1540                  }
1541
1542                  for (j = 0; j < 4; j++) {
1543                      lut_g[index * 4 + j] = colors[index].green << 6;
1544                  }
1545              }
1546	  break;
1547          default:
1548              for (i = 0; i < numColors; i++) {
1549                  index = indices[i];
1550                  lut_r[index] = colors[index].red << 6;
1551                  lut_g[index] = colors[index].green << 6;
1552                  lut_b[index] = colors[index].blue << 6;
1553              }
1554              break;
1555          }
1556
1557    /* Make the change through RandR */
1558#ifdef RANDR_12_INTERFACE
1559        if (crtc->randr_crtc)
1560            RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
1561        else
1562#endif
1563            crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
1564     }
1565}
1566
1567Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
1568{
1569    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1570                  "Initializing kms color map\n");
1571    if (!miCreateDefColormap(pScreen))
1572        return FALSE;
1573    /* all radeons support 10 bit CLUTs */
1574    if (!xf86HandleColormaps(pScreen, 256, 10,
1575                             drmmode_load_palette, NULL,
1576                             CMAP_PALETTED_TRUECOLOR
1577#if 0 /* This option messes up text mode! (eich@suse.de) */
1578                             | CMAP_LOAD_EVEN_IF_OFFSCREEN
1579#endif
1580                             | CMAP_RELOAD_ON_MODE_SWITCH))
1581         return FALSE;
1582    return TRUE;
1583}
1584
1585#ifdef HAVE_LIBUDEV
1586static void
1587drmmode_handle_uevents(int fd, void *closure)
1588{
1589	drmmode_ptr drmmode = closure;
1590	ScrnInfoPtr scrn = drmmode->scrn;
1591	struct udev_device *dev;
1592	dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1593	if (!dev)
1594		return;
1595
1596	RRGetInfo(screenInfo.screens[scrn->scrnIndex], TRUE);
1597	udev_device_unref(dev);
1598}
1599#endif
1600
1601void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1602{
1603#ifdef HAVE_LIBUDEV
1604	struct udev *u;
1605	struct udev_monitor *mon;
1606
1607	u = udev_new();
1608	if (!u)
1609		return;
1610	mon = udev_monitor_new_from_netlink(u, "udev");
1611	if (!mon) {
1612		udev_unref(u);
1613		return;
1614	}
1615
1616	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1617							    "drm",
1618							    "drm_minor") < 0 ||
1619	    udev_monitor_enable_receiving(mon) < 0) {
1620		udev_monitor_unref(mon);
1621		udev_unref(u);
1622		return;
1623	}
1624
1625	drmmode->uevent_handler =
1626		xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1627				      drmmode_handle_uevents,
1628				      drmmode);
1629
1630	drmmode->uevent_monitor = mon;
1631#endif
1632}
1633
1634void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1635{
1636#ifdef HAVE_LIBUDEV
1637	if (drmmode->uevent_handler) {
1638		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1639		xf86RemoveGeneralHandler(drmmode->uevent_handler);
1640
1641		udev_monitor_unref(drmmode->uevent_monitor);
1642		udev_unref(u);
1643	}
1644#endif
1645}
1646
1647Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id)
1648{
1649	RADEONInfoPtr info = RADEONPTR(scrn);
1650	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
1651	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
1652	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1653	unsigned int pitch;
1654	int i, old_fb_id;
1655	uint32_t tiling_flags = 0;
1656	int height;
1657	drmmode_flipevtcarrier_ptr flipcarrier;
1658
1659	if (info->allowColorTiling) {
1660		if (info->ChipFamily >= CHIP_FAMILY_R600)
1661			tiling_flags |= RADEON_TILING_MICRO;
1662		else
1663			tiling_flags |= RADEON_TILING_MACRO;
1664	}
1665
1666	pitch = RADEON_ALIGN(scrn->displayWidth, drmmode_get_pitch_align(scrn, info->CurrentLayout.pixel_bytes, tiling_flags)) *
1667		info->CurrentLayout.pixel_bytes;
1668	height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags));
1669
1670	/*
1671	 * Create a new handle for the back buffer
1672	 */
1673	old_fb_id = drmmode->fb_id;
1674	if (drmModeAddFB(drmmode->fd, scrn->virtualX, height,
1675			 scrn->depth, scrn->bitsPerPixel, pitch,
1676			 new_front->handle, &drmmode->fb_id))
1677		goto error_out;
1678
1679	/*
1680	 * Queue flips on all enabled CRTCs
1681	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
1682	 * Right now it assumes a single shared fb across all CRTCs, with the
1683	 * kernel fixing up the offset of each CRTC as necessary.
1684	 *
1685	 * Also, flips queued on disabled or incorrectly configured displays
1686	 * may never complete; this is a configuration error.
1687	 */
1688	drmmode->fe_frame = 0;
1689	drmmode->fe_tv_sec = 0;
1690	drmmode->fe_tv_usec = 0;
1691
1692	for (i = 0; i < config->num_crtc; i++) {
1693		if (!config->crtc[i]->enabled)
1694			continue;
1695
1696		drmmode->event_data = data;
1697		drmmode->flip_count++;
1698		drmmode_crtc = config->crtc[i]->driver_private;
1699
1700		flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec));
1701		if (!flipcarrier) {
1702			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1703				   "flip queue: carrier alloc failed.\n");
1704			goto error_undo;
1705		}
1706
1707		/* Only the reference crtc will finally deliver its page flip
1708		 * completion event. All other crtc's events will be discarded.
1709		 */
1710		flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id);
1711		flipcarrier->drmmode = drmmode;
1712
1713		if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1714				    drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) {
1715			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1716				   "flip queue failed: %s\n", strerror(errno));
1717			free(flipcarrier);
1718			goto error_undo;
1719		}
1720	}
1721
1722	drmmode->old_fb_id = old_fb_id;
1723	return TRUE;
1724
1725error_undo:
1726	drmModeRmFB(drmmode->fd, drmmode->fb_id);
1727	drmmode->fb_id = old_fb_id;
1728
1729error_out:
1730	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
1731		   strerror(errno));
1732	return FALSE;
1733}
1734
1735#endif
1736