drmmode_display.c revision 2f39173d
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#ifdef XF86DRM_MODE
33#include <sys/ioctl.h>
34#include "micmap.h"
35#include "xf86cmap.h"
36#include "radeon.h"
37#include "radeon_reg.h"
38#include "radeon_drm.h"
39#include "sarea.h"
40
41#include "drmmode_display.h"
42
43/* DPMS */
44#ifdef HAVE_XEXTPROTO_71
45#include <X11/extensions/dpmsconst.h>
46#else
47#define DPMS_SERVER
48#include <X11/extensions/dpms.h>
49#endif
50
51static PixmapPtr drmmode_create_bo_pixmap(ScreenPtr pScreen,
52					  int width, int height,
53					  int depth, int bpp,
54					  int pitch, struct radeon_bo *bo)
55{
56	PixmapPtr pixmap;
57
58	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
59	if (!pixmap)
60		return NULL;
61
62	if (!(*pScreen->ModifyPixmapHeader)(pixmap, width, height,
63					    depth, bpp, pitch, NULL)) {
64		return NULL;
65	}
66
67	exaMoveInPixmap(pixmap);
68	radeon_set_pixmap_bo(pixmap, bo);
69
70	return pixmap;
71}
72
73static void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
74{
75	ScreenPtr pScreen = pixmap->drawable.pScreen;
76
77	(*pScreen->DestroyPixmap)(pixmap);
78}
79
80static void
81drmmode_ConvertFromKMode(ScrnInfoPtr	scrn,
82		     drmModeModeInfo *kmode,
83		     DisplayModePtr	mode)
84{
85	memset(mode, 0, sizeof(DisplayModeRec));
86	mode->status = MODE_OK;
87
88	mode->Clock = kmode->clock;
89
90	mode->HDisplay = kmode->hdisplay;
91	mode->HSyncStart = kmode->hsync_start;
92	mode->HSyncEnd = kmode->hsync_end;
93	mode->HTotal = kmode->htotal;
94	mode->HSkew = kmode->hskew;
95
96	mode->VDisplay = kmode->vdisplay;
97	mode->VSyncStart = kmode->vsync_start;
98	mode->VSyncEnd = kmode->vsync_end;
99	mode->VTotal = kmode->vtotal;
100	mode->VScan = kmode->vscan;
101
102	mode->Flags = kmode->flags; //& FLAG_BITS;
103	mode->name = strdup(kmode->name);
104
105	if (kmode->type & DRM_MODE_TYPE_DRIVER)
106		mode->type = M_T_DRIVER;
107	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
108		mode->type |= M_T_PREFERRED;
109	xf86SetModeCrtc (mode, scrn->adjustFlags);
110}
111
112static void
113drmmode_ConvertToKMode(ScrnInfoPtr	scrn,
114		     drmModeModeInfo *kmode,
115		     DisplayModePtr	mode)
116{
117	memset(kmode, 0, sizeof(*kmode));
118
119	kmode->clock = mode->Clock;
120	kmode->hdisplay = mode->HDisplay;
121	kmode->hsync_start = mode->HSyncStart;
122	kmode->hsync_end = mode->HSyncEnd;
123	kmode->htotal = mode->HTotal;
124	kmode->hskew = mode->HSkew;
125
126	kmode->vdisplay = mode->VDisplay;
127	kmode->vsync_start = mode->VSyncStart;
128	kmode->vsync_end = mode->VSyncEnd;
129	kmode->vtotal = mode->VTotal;
130	kmode->vscan = mode->VScan;
131
132	kmode->flags = mode->Flags; //& FLAG_BITS;
133	if (mode->name)
134		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
135	kmode->name[DRM_DISPLAY_MODE_LEN-1] = 0;
136
137}
138
139static void
140drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
141{
142#if 0
143	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
144//	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
145//	drmmode_ptr drmmode = drmmode_crtc->drmmode;
146
147	/* bonghits in the randr 1.2 - uses dpms to disable crtc - bad buzz */
148	if (mode == DPMSModeOff) {
149//		drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
150//			       0, 0, 0, NULL, 0, NULL);
151	}
152#endif
153}
154
155static PixmapPtr
156create_pixmap_for_fbcon(drmmode_ptr drmmode,
157			ScrnInfoPtr pScrn, int crtc_id)
158{
159	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
160	drmmode_crtc_private_ptr drmmode_crtc;
161	ScreenPtr pScreen = pScrn->pScreen;
162	PixmapPtr pixmap;
163	struct radeon_bo *bo;
164	drmModeFBPtr fbcon;
165	struct drm_gem_flink flink;
166
167	drmmode_crtc = xf86_config->crtc[crtc_id]->driver_private;
168
169	fbcon = drmModeGetFB(drmmode->fd, drmmode_crtc->mode_crtc->buffer_id);
170	if (fbcon == NULL)
171		return NULL;
172
173	flink.handle = fbcon->handle;
174	if (ioctl(drmmode->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
175		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
176			   "Couldn't flink fbcon handle\n");
177		return NULL;
178	}
179
180	bo = radeon_bo_open(drmmode->bufmgr, flink.name, 0, 0, 0, 0);
181	if (bo == NULL) {
182		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
183			   "Couldn't allocate bo for fbcon handle\n");
184		return NULL;
185	}
186
187	pixmap = drmmode_create_bo_pixmap(pScreen, fbcon->width, fbcon->height,
188					  fbcon->depth, fbcon->bpp,
189					  fbcon->pitch, bo);
190	if (!pixmap)
191		return NULL;
192
193	radeon_bo_unref(bo);
194	drmModeFreeFB(fbcon);
195	return pixmap;
196}
197
198void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
199{
200	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
201	RADEONInfoPtr info = RADEONPTR(pScrn);
202	PixmapPtr src, dst;
203	ScreenPtr pScreen = pScrn->pScreen;
204	int crtc_id = 0;
205	int i;
206	int pitch = pScrn->displayWidth * info->CurrentLayout.pixel_bytes;
207	Bool ret;
208
209	if (info->accelOn == FALSE)
210		return;
211
212	for (i = 0; i < xf86_config->num_crtc; i++) {
213		xf86CrtcPtr crtc = xf86_config->crtc[i];
214		drmmode_crtc_private_ptr drmmode_crtc;
215
216		drmmode_crtc = crtc->driver_private;
217		if (drmmode_crtc->mode_crtc->buffer_id)
218			crtc_id = i;
219	}
220
221	src = create_pixmap_for_fbcon(drmmode, pScrn, crtc_id);
222	if (!src)
223		return;
224
225	dst = drmmode_create_bo_pixmap(pScreen, pScrn->virtualX,
226				       pScrn->virtualY, pScrn->depth,
227				       pScrn->bitsPerPixel, pitch,
228				       info->front_bo);
229	if (!dst)
230		goto out_free_src;
231
232	ret = info->accel_state->exa->PrepareCopy (src, dst,
233						   -1, -1, GXcopy, FB_ALLONES);
234	if (!ret)
235	  goto out_free_src;
236	info->accel_state->exa->Copy (dst, 0, 0, 0, 0,
237				      pScrn->virtualX, pScrn->virtualY);
238	info->accel_state->exa->DoneCopy (dst);
239	radeon_cs_flush_indirect(pScrn);
240
241	drmmode_destroy_bo_pixmap(dst);
242 out_free_src:
243	drmmode_destroy_bo_pixmap(src);
244
245}
246
247static Bool
248drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
249		     Rotation rotation, int x, int y)
250{
251	ScrnInfoPtr pScrn = crtc->scrn;
252	RADEONInfoPtr info = RADEONPTR(pScrn);
253	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
254	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
255	drmmode_ptr drmmode = drmmode_crtc->drmmode;
256	int saved_x, saved_y;
257	Rotation saved_rotation;
258	DisplayModeRec saved_mode;
259	uint32_t *output_ids;
260	int output_count = 0;
261	Bool ret = TRUE;
262	int i;
263	int fb_id;
264	drmModeModeInfo kmode;
265	int pitch = pScrn->displayWidth * info->CurrentLayout.pixel_bytes;
266
267	if (drmmode->fb_id == 0) {
268		ret = drmModeAddFB(drmmode->fd,
269				   pScrn->virtualX, pScrn->virtualY,
270                                   pScrn->depth, pScrn->bitsPerPixel,
271				   pitch,
272				   info->front_bo->handle,
273                                   &drmmode->fb_id);
274                if (ret < 0) {
275                        ErrorF("failed to add fb\n");
276                        return FALSE;
277                }
278        }
279
280	saved_mode = crtc->mode;
281	saved_x = crtc->x;
282	saved_y = crtc->y;
283	saved_rotation = crtc->rotation;
284
285	if (mode) {
286		crtc->mode = *mode;
287		crtc->x = x;
288		crtc->y = y;
289		crtc->rotation = rotation;
290#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,5,99,0,0)
291		crtc->transformPresent = FALSE;
292#endif
293	}
294
295	output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
296	if (!output_ids) {
297		ret = FALSE;
298		goto done;
299	}
300
301	if (mode) {
302		for (i = 0; i < xf86_config->num_output; i++) {
303			xf86OutputPtr output = xf86_config->output[i];
304			drmmode_output_private_ptr drmmode_output;
305
306			if (output->crtc != crtc)
307				continue;
308
309			drmmode_output = output->driver_private;
310			output_ids[output_count] = drmmode_output->mode_output->connector_id;
311			output_count++;
312		}
313
314		if (!xf86CrtcRotate(crtc)) {
315			goto done;
316		}
317#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,7,0,0,0)
318		crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
319				       crtc->gamma_blue, crtc->gamma_size);
320#endif
321
322		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
323
324		fb_id = drmmode->fb_id;
325		if (drmmode_crtc->rotate_fb_id) {
326			fb_id = drmmode_crtc->rotate_fb_id;
327			x = y = 0;
328		}
329		ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
330				     fb_id, x, y, output_ids, output_count, &kmode);
331		if (ret)
332			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
333				   "failed to set mode: %s", strerror(-ret));
334		else
335			ret = TRUE;
336
337		if (crtc->scrn->pScreen)
338			xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
339		/* go through all the outputs and force DPMS them back on? */
340		for (i = 0; i < xf86_config->num_output; i++) {
341			xf86OutputPtr output = xf86_config->output[i];
342
343			if (output->crtc != crtc)
344				continue;
345
346			output->funcs->dpms(output, DPMSModeOn);
347		}
348	}
349
350	if (pScrn->pScreen)
351		xf86_reload_cursors(pScrn->pScreen);
352
353done:
354	if (!ret) {
355		crtc->x = saved_x;
356		crtc->y = saved_y;
357		crtc->rotation = saved_rotation;
358		crtc->mode = saved_mode;
359	}
360#if defined(XF86_CRTC_VERSION) && XF86_CRTC_VERSION >= 3
361	else
362		crtc->active = TRUE;
363#endif
364
365	return ret;
366}
367
368static void
369drmmode_set_cursor_colors (xf86CrtcPtr crtc, int bg, int fg)
370{
371
372}
373
374static void
375drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
376{
377	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
378	drmmode_ptr drmmode = drmmode_crtc->drmmode;
379
380	drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
381}
382
383static void
384drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
385{
386	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
387	void *ptr;
388
389	/* cursor should be mapped already */
390	ptr = drmmode_crtc->cursor_bo->ptr;
391
392	memcpy (ptr, image, 64 * 64 * 4);
393
394	return;
395}
396
397
398static void
399drmmode_hide_cursor (xf86CrtcPtr crtc)
400{
401	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
402	drmmode_ptr drmmode = drmmode_crtc->drmmode;
403
404	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 64, 64);
405
406}
407
408static void
409drmmode_show_cursor (xf86CrtcPtr crtc)
410{
411	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
412	drmmode_ptr drmmode = drmmode_crtc->drmmode;
413	uint32_t handle = drmmode_crtc->cursor_bo->handle;
414
415	drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, handle, 64, 64);
416}
417
418static void *
419drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
420{
421	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
422	drmmode_ptr drmmode = drmmode_crtc->drmmode;
423	int size;
424	struct radeon_bo *rotate_bo;
425	int ret;
426	unsigned long rotate_pitch;
427
428	width = RADEON_ALIGN(width, 64);
429	rotate_pitch = width * drmmode->cpp;
430
431	size = rotate_pitch * height;
432
433	rotate_bo = radeon_bo_open(drmmode->bufmgr, 0, size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
434	if (rotate_bo == NULL)
435		return NULL;
436
437	radeon_bo_map(rotate_bo, 1);
438
439	ret = drmModeAddFB(drmmode->fd, width, height, crtc->scrn->depth,
440			   crtc->scrn->bitsPerPixel, rotate_pitch,
441			   rotate_bo->handle,
442			   &drmmode_crtc->rotate_fb_id);
443	if (ret) {
444		ErrorF("failed to add rotate fb\n");
445	}
446
447	drmmode_crtc->rotate_bo = rotate_bo;
448	return drmmode_crtc->rotate_bo->ptr;
449}
450
451static PixmapPtr
452drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
453{
454	ScrnInfoPtr pScrn = crtc->scrn;
455	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
456	drmmode_ptr drmmode = drmmode_crtc->drmmode;
457	unsigned long rotate_pitch;
458	PixmapPtr rotate_pixmap;
459
460	if (!data)
461		data = drmmode_crtc_shadow_allocate (crtc, width, height);
462
463	rotate_pitch = RADEON_ALIGN(width, 64) * drmmode->cpp;
464
465	rotate_pixmap = drmmode_create_bo_pixmap(pScrn->pScreen,
466						 width, height,
467						 pScrn->depth,
468						 pScrn->bitsPerPixel,
469						 rotate_pitch,
470						 drmmode_crtc->rotate_bo);
471	if (rotate_pixmap == NULL) {
472		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
473			   "Couldn't allocate shadow pixmap for rotated CRTC\n");
474	}
475	return rotate_pixmap;
476
477}
478
479static void
480drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
481{
482	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
483	drmmode_ptr drmmode = drmmode_crtc->drmmode;
484
485	if (rotate_pixmap)
486		drmmode_destroy_bo_pixmap(rotate_pixmap);
487
488	if (data) {
489		drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
490		drmmode_crtc->rotate_fb_id = 0;
491		radeon_bo_unmap(drmmode_crtc->rotate_bo);
492		radeon_bo_unref(drmmode_crtc->rotate_bo);
493		drmmode_crtc->rotate_bo = NULL;
494	}
495
496}
497
498static void
499drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
500                      uint16_t *blue, int size)
501{
502	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
503	drmmode_ptr drmmode = drmmode_crtc->drmmode;
504
505	drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
506			    size, red, green, blue);
507}
508
509static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
510    .dpms = drmmode_crtc_dpms,
511    .set_mode_major = drmmode_set_mode_major,
512    .set_cursor_colors = drmmode_set_cursor_colors,
513    .set_cursor_position = drmmode_set_cursor_position,
514    .show_cursor = drmmode_show_cursor,
515    .hide_cursor = drmmode_hide_cursor,
516    .load_cursor_argb = drmmode_load_cursor_argb,
517
518    .gamma_set = drmmode_crtc_gamma_set,
519    .shadow_create = drmmode_crtc_shadow_create,
520    .shadow_allocate = drmmode_crtc_shadow_allocate,
521    .shadow_destroy = drmmode_crtc_shadow_destroy,
522    .destroy = NULL, /* XXX */
523};
524
525int drmmode_get_crtc_id(xf86CrtcPtr crtc)
526{
527	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
528	return drmmode_crtc->hw_id;
529}
530
531void drmmode_crtc_hw_id(xf86CrtcPtr crtc)
532{
533	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
534	ScrnInfoPtr pScrn = crtc->scrn;
535	RADEONInfoPtr info = RADEONPTR(pScrn);
536	struct drm_radeon_info ginfo;
537	int r;
538	uint32_t tmp;
539
540	memset(&ginfo, 0, sizeof(ginfo));
541	ginfo.request = 0x4;
542	tmp = drmmode_crtc->mode_crtc->crtc_id;
543	ginfo.value = (uintptr_t)&tmp;
544	r = drmCommandWriteRead(info->dri->drmFD, DRM_RADEON_INFO, &ginfo, sizeof(ginfo));
545	if (r) {
546		drmmode_crtc->hw_id = -1;
547		return;
548	}
549	drmmode_crtc->hw_id = tmp;
550}
551
552static void
553drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
554{
555	xf86CrtcPtr crtc;
556	drmmode_crtc_private_ptr drmmode_crtc;
557
558	crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
559	if (crtc == NULL)
560		return;
561
562	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
563	drmmode_crtc->mode_crtc = drmModeGetCrtc(drmmode->fd, drmmode->mode_res->crtcs[num]);
564	drmmode_crtc->drmmode = drmmode;
565	crtc->driver_private = drmmode_crtc;
566	drmmode_crtc_hw_id(crtc);
567
568	return;
569}
570
571static xf86OutputStatus
572drmmode_output_detect(xf86OutputPtr output)
573{
574	/* go to the hw and retrieve a new output struct */
575	drmmode_output_private_ptr drmmode_output = output->driver_private;
576	drmmode_ptr drmmode = drmmode_output->drmmode;
577	xf86OutputStatus status;
578	drmModeFreeConnector(drmmode_output->mode_output);
579
580	drmmode_output->mode_output = drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
581
582	switch (drmmode_output->mode_output->connection) {
583	case DRM_MODE_CONNECTED:
584		status = XF86OutputStatusConnected;
585		break;
586	case DRM_MODE_DISCONNECTED:
587		status = XF86OutputStatusDisconnected;
588		break;
589	default:
590	case DRM_MODE_UNKNOWNCONNECTION:
591		status = XF86OutputStatusUnknown;
592		break;
593	}
594	return status;
595}
596
597static Bool
598drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
599{
600	return MODE_OK;
601}
602
603static DisplayModePtr
604drmmode_output_get_modes(xf86OutputPtr output)
605{
606	drmmode_output_private_ptr drmmode_output = output->driver_private;
607	drmModeConnectorPtr koutput = drmmode_output->mode_output;
608	drmmode_ptr drmmode = drmmode_output->drmmode;
609	int i;
610	DisplayModePtr Modes = NULL, Mode;
611	drmModePropertyPtr props;
612
613	/* look for an EDID property */
614	for (i = 0; i < koutput->count_props; i++) {
615		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
616		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
617			if (!strcmp(props->name, "EDID")) {
618				if (drmmode_output->edid_blob)
619					drmModeFreePropertyBlob(drmmode_output->edid_blob);
620				drmmode_output->edid_blob = drmModeGetPropertyBlob(drmmode->fd, koutput->prop_values[i]);
621			}
622			drmModeFreeProperty(props);
623		}
624	}
625
626	if (drmmode_output->edid_blob)
627		xf86OutputSetEDID(output, xf86InterpretEDID(output->scrn->scrnIndex, drmmode_output->edid_blob->data));
628	else
629		xf86OutputSetEDID(output, xf86InterpretEDID(output->scrn->scrnIndex, NULL));
630
631	/* modes should already be available */
632	for (i = 0; i < koutput->count_modes; i++) {
633		Mode = xnfalloc(sizeof(DisplayModeRec));
634
635		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
636		Modes = xf86ModesAdd(Modes, Mode);
637
638	}
639	return Modes;
640}
641
642static void
643drmmode_output_destroy(xf86OutputPtr output)
644{
645	drmmode_output_private_ptr drmmode_output = output->driver_private;
646	int i;
647
648	if (drmmode_output->edid_blob)
649		drmModeFreePropertyBlob(drmmode_output->edid_blob);
650	for (i = 0; i < drmmode_output->num_props; i++) {
651		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
652		free(drmmode_output->props[i].atoms);
653	}
654	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
655		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
656		free(drmmode_output->mode_encoders);
657	}
658	free(drmmode_output->props);
659	drmModeFreeConnector(drmmode_output->mode_output);
660	free(drmmode_output);
661	output->driver_private = NULL;
662}
663
664static void
665drmmode_output_dpms(xf86OutputPtr output, int mode)
666{
667	drmmode_output_private_ptr drmmode_output = output->driver_private;
668	drmModeConnectorPtr koutput = drmmode_output->mode_output;
669	drmmode_ptr drmmode = drmmode_output->drmmode;
670
671	drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
672				    drmmode_output->dpms_enum_id, mode);
673	return;
674}
675
676
677static Bool
678drmmode_property_ignore(drmModePropertyPtr prop)
679{
680    if (!prop)
681	return TRUE;
682    /* ignore blob prop */
683    if (prop->flags & DRM_MODE_PROP_BLOB)
684	return TRUE;
685    /* ignore standard property */
686    if (!strcmp(prop->name, "EDID") ||
687	    !strcmp(prop->name, "DPMS"))
688	return TRUE;
689
690    return FALSE;
691}
692
693static void
694drmmode_output_create_resources(xf86OutputPtr output)
695{
696    drmmode_output_private_ptr drmmode_output = output->driver_private;
697    drmModeConnectorPtr mode_output = drmmode_output->mode_output;
698    drmmode_ptr drmmode = drmmode_output->drmmode;
699    drmModePropertyPtr drmmode_prop;
700    int i, j, err;
701
702    drmmode_output->props = calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
703    if (!drmmode_output->props)
704	return;
705
706    drmmode_output->num_props = 0;
707    for (i = 0, j = 0; i < mode_output->count_props; i++) {
708	drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
709	if (drmmode_property_ignore(drmmode_prop)) {
710	    drmModeFreeProperty(drmmode_prop);
711	    continue;
712	}
713	drmmode_output->props[j].mode_prop = drmmode_prop;
714	drmmode_output->props[j].value = mode_output->prop_values[i];
715	drmmode_output->num_props++;
716	j++;
717    }
718
719    for (i = 0; i < drmmode_output->num_props; i++) {
720	drmmode_prop_ptr p = &drmmode_output->props[i];
721	drmmode_prop = p->mode_prop;
722
723	if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
724	    INT32 range[2];
725	    INT32 value = p->value;
726
727	    p->num_atoms = 1;
728	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
729	    if (!p->atoms)
730		continue;
731	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
732	    range[0] = drmmode_prop->values[0];
733	    range[1] = drmmode_prop->values[1];
734	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
735		    FALSE, TRUE,
736		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
737		    2, range);
738	    if (err != 0) {
739		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
740			"RRConfigureOutputProperty error, %d\n", err);
741	    }
742	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
743		    XA_INTEGER, 32, PropModeReplace, 1, &value, FALSE, TRUE);
744	    if (err != 0) {
745		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
746			"RRChangeOutputProperty error, %d\n", err);
747	    }
748	} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
749	    p->num_atoms = drmmode_prop->count_enums + 1;
750	    p->atoms = calloc(p->num_atoms, sizeof(Atom));
751	    if (!p->atoms)
752		continue;
753	    p->atoms[0] = MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
754	    for (j = 1; j <= drmmode_prop->count_enums; j++) {
755		struct drm_mode_property_enum *e = &drmmode_prop->enums[j-1];
756		p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
757	    }
758	    err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
759		    FALSE, FALSE,
760		    drmmode_prop->flags & DRM_MODE_PROP_IMMUTABLE ? TRUE : FALSE,
761		    p->num_atoms - 1, (INT32 *)&p->atoms[1]);
762	    if (err != 0) {
763		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
764			"RRConfigureOutputProperty error, %d\n", err);
765	    }
766	    for (j = 0; j < drmmode_prop->count_enums; j++)
767		if (drmmode_prop->enums[j].value == p->value)
768		    break;
769	    /* there's always a matching value */
770	    err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
771		    XA_ATOM, 32, PropModeReplace, 1, &p->atoms[j+1], FALSE, TRUE);
772	    if (err != 0) {
773		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
774			"RRChangeOutputProperty error, %d\n", err);
775	    }
776	}
777    }
778}
779
780static Bool
781drmmode_output_set_property(xf86OutputPtr output, Atom property,
782		RRPropertyValuePtr value)
783{
784    drmmode_output_private_ptr drmmode_output = output->driver_private;
785    drmmode_ptr drmmode = drmmode_output->drmmode;
786    int i;
787
788    for (i = 0; i < drmmode_output->num_props; i++) {
789	drmmode_prop_ptr p = &drmmode_output->props[i];
790
791	if (p->atoms[0] != property)
792	    continue;
793
794	if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
795	    uint32_t val;
796
797	    if (value->type != XA_INTEGER || value->format != 32 ||
798		    value->size != 1)
799		return FALSE;
800	    val = *(uint32_t *)value->data;
801
802	    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
803		    p->mode_prop->prop_id, (uint64_t)val);
804	    return TRUE;
805	} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
806	    Atom	atom;
807	    const char	*name;
808	    int		j;
809
810	    if (value->type != XA_ATOM || value->format != 32 || value->size != 1)
811		return FALSE;
812	    memcpy(&atom, value->data, 4);
813	    name = NameForAtom(atom);
814
815	    /* search for matching name string, then set its value down */
816	    for (j = 0; j < p->mode_prop->count_enums; j++) {
817		if (!strcmp(p->mode_prop->enums[j].name, name)) {
818		    drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
819			    p->mode_prop->prop_id, p->mode_prop->enums[j].value);
820		    return TRUE;
821		}
822	    }
823	}
824    }
825
826    return TRUE;
827}
828
829static Bool
830drmmode_output_get_property(xf86OutputPtr output, Atom property)
831{
832    return TRUE;
833}
834
835static const xf86OutputFuncsRec drmmode_output_funcs = {
836    .dpms = drmmode_output_dpms,
837    .create_resources = drmmode_output_create_resources,
838#ifdef RANDR_12_INTERFACE
839    .set_property = drmmode_output_set_property,
840    .get_property = drmmode_output_get_property,
841#endif
842#if 0
843
844    .save = drmmode_crt_save,
845    .restore = drmmode_crt_restore,
846    .mode_fixup = drmmode_crt_mode_fixup,
847    .prepare = drmmode_output_prepare,
848    .mode_set = drmmode_crt_mode_set,
849    .commit = drmmode_output_commit,
850#endif
851    .detect = drmmode_output_detect,
852    .mode_valid = drmmode_output_mode_valid,
853
854    .get_modes = drmmode_output_get_modes,
855    .destroy = drmmode_output_destroy
856};
857
858static int subpixel_conv_table[7] = { 0, SubPixelUnknown,
859				      SubPixelHorizontalRGB,
860				      SubPixelHorizontalBGR,
861				      SubPixelVerticalRGB,
862				      SubPixelVerticalBGR,
863				      SubPixelNone };
864
865const char *output_names[] = { "None",
866			       "VGA",
867			       "DVI",
868			       "DVI",
869			       "DVI",
870			       "Composite",
871			       "S-video",
872			       "LVDS",
873			       "CTV",
874			       "DIN",
875			       "DisplayPort",
876			       "HDMI",
877			       "HDMI",
878			       "TV",
879			       "eDP"
880};
881
882static void
883drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int num)
884{
885	RADEONInfoPtr info = RADEONPTR(pScrn);
886	xf86OutputPtr output;
887	drmModeConnectorPtr koutput;
888	drmModeEncoderPtr *kencoders = NULL;
889	drmmode_output_private_ptr drmmode_output;
890	drmModePropertyPtr props;
891	char name[32];
892	int i;
893	const char *s;
894
895	koutput = drmModeGetConnector(drmmode->fd, drmmode->mode_res->connectors[num]);
896	if (!koutput)
897		return;
898
899	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
900	if (!kencoders) {
901		goto out_free_encoders;
902	}
903
904	for (i = 0; i < koutput->count_encoders; i++) {
905		kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
906		if (!kencoders[i]) {
907			goto out_free_encoders;
908		}
909	}
910
911	/* need to do smart conversion here for compat with non-kms ATI driver */
912	if (koutput->connector_type_id == 1) {
913	    switch(koutput->connector_type) {
914	    case DRM_MODE_CONNECTOR_VGA:
915	    case DRM_MODE_CONNECTOR_DVII:
916	    case DRM_MODE_CONNECTOR_DVID:
917	    case DRM_MODE_CONNECTOR_DVIA:
918	    case DRM_MODE_CONNECTOR_HDMIA:
919	    case DRM_MODE_CONNECTOR_HDMIB:
920	    case DRM_MODE_CONNECTOR_DisplayPort:
921		snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
922		break;
923	    default:
924		snprintf(name, 32, "%s", output_names[koutput->connector_type]);
925		break;
926	    }
927	} else {
928	    snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
929	}
930
931	if (xf86IsEntityShared(pScrn->entityList[0])) {
932		if ((s = xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
933			if (!RADEONZaphodStringMatches(pScrn, s, name))
934				goto out_free_encoders;
935		} else {
936			if (info->IsPrimary && (num != 0))
937				goto out_free_encoders;
938			else if (info->IsSecondary && (num != 1))
939				goto out_free_encoders;
940		}
941	}
942
943	output = xf86OutputCreate (pScrn, &drmmode_output_funcs, name);
944	if (!output) {
945		goto out_free_encoders;
946	}
947
948	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
949	if (!drmmode_output) {
950		xf86OutputDestroy(output);
951		goto out_free_encoders;
952	}
953
954	drmmode_output->output_id = drmmode->mode_res->connectors[num];
955	drmmode_output->mode_output = koutput;
956	drmmode_output->mode_encoders = kencoders;
957	drmmode_output->drmmode = drmmode;
958	output->mm_width = koutput->mmWidth;
959	output->mm_height = koutput->mmHeight;
960
961	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
962	output->driver_private = drmmode_output;
963
964	output->possible_crtcs = 0x7f;
965	for (i = 0; i < koutput->count_encoders; i++) {
966		output->possible_crtcs &= kencoders[i]->possible_crtcs;
967	}
968	/* work out the possible clones later */
969	output->possible_clones = 0;
970
971	for (i = 0; i < koutput->count_props; i++) {
972		props = drmModeGetProperty(drmmode->fd, koutput->props[i]);
973		if (props && (props->flags && DRM_MODE_PROP_ENUM)) {
974			if (!strcmp(props->name, "DPMS")) {
975				drmmode_output->dpms_enum_id = koutput->props[i];
976				drmModeFreeProperty(props);
977				break;
978			}
979			drmModeFreeProperty(props);
980		}
981	}
982
983	return;
984out_free_encoders:
985	if (kencoders){
986		for (i = 0; i < koutput->count_encoders; i++)
987			drmModeFreeEncoder(kencoders[i]);
988		free(kencoders);
989	}
990	drmModeFreeConnector(koutput);
991
992}
993
994uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
995{
996	drmmode_output_private_ptr drmmode_output = output->driver_private, clone_drmout;
997	int i;
998	xf86OutputPtr clone_output;
999	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1000	int index_mask = 0;
1001
1002	if (drmmode_output->enc_clone_mask == 0)
1003		return index_mask;
1004
1005	for (i = 0; i < xf86_config->num_output; i++) {
1006		clone_output = xf86_config->output[i];
1007		clone_drmout = clone_output->driver_private;
1008		if (output == clone_output)
1009			continue;
1010
1011		if (clone_drmout->enc_mask == 0)
1012			continue;
1013		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
1014			index_mask |= (1 << i);
1015	}
1016	return index_mask;
1017}
1018
1019
1020static void
1021drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1022{
1023	int i, j;
1024	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1025
1026	for (i = 0; i < xf86_config->num_output; i++) {
1027		xf86OutputPtr output = xf86_config->output[i];
1028		drmmode_output_private_ptr drmmode_output;
1029
1030		drmmode_output = output->driver_private;
1031		drmmode_output->enc_clone_mask = 0xff;
1032		/* and all the possible encoder clones for this output together */
1033		for (j = 0; j < drmmode_output->mode_output->count_encoders; j++)
1034		{
1035			int k;
1036			for (k = 0; k < drmmode->mode_res->count_encoders; k++) {
1037				if (drmmode->mode_res->encoders[k] == drmmode_output->mode_encoders[j]->encoder_id)
1038					drmmode_output->enc_mask |= (1 << k);
1039			}
1040
1041			drmmode_output->enc_clone_mask &= drmmode_output->mode_encoders[j]->possible_clones;
1042		}
1043	}
1044
1045	for (i = 0; i < xf86_config->num_output; i++) {
1046		xf86OutputPtr output = xf86_config->output[i];
1047		output->possible_clones = find_clones(scrn, output);
1048	}
1049}
1050
1051static Bool
1052drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
1053{
1054	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1055	drmmode_crtc_private_ptr
1056		    drmmode_crtc = xf86_config->crtc[0]->driver_private;
1057	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1058	RADEONInfoPtr info = RADEONPTR(scrn);
1059	struct radeon_bo *old_front = NULL;
1060	Bool	    ret;
1061	ScreenPtr   screen = screenInfo.screens[scrn->scrnIndex];
1062	uint32_t    old_fb_id;
1063	int	    i, pitch, old_width, old_height, old_pitch;
1064	int screen_size;
1065	int cpp = info->CurrentLayout.pixel_bytes;
1066	struct radeon_bo *front_bo;
1067	uint32_t tiling_flags = 0;
1068	PixmapPtr ppix = screen->GetScreenPixmap(screen);
1069	void *fb_shadow;
1070
1071	if (scrn->virtualX == width && scrn->virtualY == height)
1072		return TRUE;
1073
1074	front_bo = info->front_bo;
1075	radeon_cs_flush_indirect(scrn);
1076
1077	if (front_bo)
1078		radeon_bo_wait(front_bo);
1079
1080	pitch = RADEON_ALIGN(width, 64);
1081	height = RADEON_ALIGN(height, 16);
1082
1083	screen_size = pitch * height * cpp;
1084
1085	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1086		   "Allocate new frame buffer %dx%d stride %d\n",
1087		   width, height, pitch);
1088
1089	old_width = scrn->virtualX;
1090	old_height = scrn->virtualY;
1091	old_pitch = scrn->displayWidth;
1092	old_fb_id = drmmode->fb_id;
1093	old_front = info->front_bo;
1094
1095	scrn->virtualX = width;
1096	scrn->virtualY = height;
1097	scrn->displayWidth = pitch;
1098
1099	info->front_bo = radeon_bo_open(info->bufmgr, 0, screen_size, 0, RADEON_GEM_DOMAIN_VRAM, 0);
1100	if (!info->front_bo)
1101		goto fail;
1102
1103	if (info->allowColorTiling)
1104	    tiling_flags |= RADEON_TILING_MACRO;
1105#if X_BYTE_ORDER == X_BIG_ENDIAN
1106	switch (cpp) {
1107	case 4:
1108	    tiling_flags |= RADEON_TILING_SWAP_32BIT;
1109	    break;
1110	case 2:
1111	    tiling_flags |= RADEON_TILING_SWAP_16BIT;
1112	    break;
1113	}
1114#endif
1115	if (tiling_flags)
1116	    radeon_bo_set_tiling(info->front_bo,
1117				 tiling_flags | RADEON_TILING_SURFACE, pitch * cpp);
1118
1119	ret = drmModeAddFB(drmmode->fd, width, height, scrn->depth,
1120			   scrn->bitsPerPixel, pitch * cpp,
1121			   info->front_bo->handle,
1122			   &drmmode->fb_id);
1123	if (ret)
1124		goto fail;
1125
1126	if (!info->r600_shadow_fb) {
1127		radeon_set_pixmap_bo(screen->GetScreenPixmap(screen), info->front_bo);
1128		screen->ModifyPixmapHeader(screen->GetScreenPixmap(screen),
1129					   width, height, -1, -1, pitch * cpp, NULL);
1130	} else {
1131		if (radeon_bo_map(info->front_bo, 1))
1132			goto fail;
1133		fb_shadow = calloc(1, screen_size);
1134		if (fb_shadow == NULL)
1135			goto fail;
1136		free(info->fb_shadow);
1137		info->fb_shadow = fb_shadow;
1138		screen->ModifyPixmapHeader(screen->GetScreenPixmap(screen),
1139					   width, height, -1, -1, pitch * cpp,
1140					   info->fb_shadow);
1141	}
1142	scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr;
1143
1144	//	xf86DrvMsg(scrn->scrnIndex, X_INFO, "New front buffer at 0x%lx\n",
1145	//		   info->front_bo-);
1146
1147	for (i = 0; i < xf86_config->num_crtc; i++) {
1148		xf86CrtcPtr crtc = xf86_config->crtc[i];
1149
1150		if (!crtc->enabled)
1151			continue;
1152
1153		drmmode_set_mode_major(crtc, &crtc->mode,
1154				       crtc->rotation, crtc->x, crtc->y);
1155	}
1156
1157	if (old_fb_id)
1158		drmModeRmFB(drmmode->fd, old_fb_id);
1159	if (old_front)
1160		radeon_bo_unref(old_front);
1161
1162	radeon_kms_update_vram_limit(scrn, screen_size);
1163	return TRUE;
1164
1165 fail:
1166	if (info->front_bo)
1167		radeon_bo_unref(info->front_bo);
1168	info->front_bo = old_front;
1169	scrn->virtualX = old_width;
1170	scrn->virtualY = old_height;
1171	scrn->displayWidth = old_pitch;
1172	drmmode->fb_id = old_fb_id;
1173
1174	return FALSE;
1175}
1176
1177static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
1178	drmmode_xf86crtc_resize
1179};
1180
1181static void
1182drmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
1183			unsigned int tv_usec, void *event_data)
1184{
1185	radeon_dri2_frame_event_handler(frame, tv_sec, tv_usec, event_data);
1186}
1187
1188static void
1189drm_wakeup_handler(pointer data, int err, pointer p)
1190{
1191	drmmode_ptr drmmode = data;
1192	fd_set *read_mask = p;
1193
1194	if (err >= 0 && FD_ISSET(drmmode->fd, read_mask)) {
1195		drmHandleEvent(drmmode->fd, &drmmode->event_context);
1196	}
1197}
1198
1199Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
1200{
1201	xf86CrtcConfigPtr xf86_config;
1202	RADEONInfoPtr info = RADEONPTR(pScrn);
1203	int i;
1204
1205	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
1206	xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1207
1208	drmmode->scrn = pScrn;
1209	drmmode->cpp = cpp;
1210	drmmode->mode_res = drmModeGetResources(drmmode->fd);
1211	if (!drmmode->mode_res)
1212		return FALSE;
1213
1214	xf86CrtcSetSizeRange(pScrn, 320, 200, drmmode->mode_res->max_width, drmmode->mode_res->max_height);
1215	for (i = 0; i < drmmode->mode_res->count_crtcs; i++)
1216		if (!xf86IsEntityShared(pScrn->entityList[0]) || pScrn->confScreen->device->screen == i)
1217			drmmode_crtc_init(pScrn, drmmode, i);
1218
1219	for (i = 0; i < drmmode->mode_res->count_connectors; i++)
1220		drmmode_output_init(pScrn, drmmode, i);
1221
1222	/* workout clones */
1223	drmmode_clones_init(pScrn, drmmode);
1224
1225	xf86InitialConfiguration(pScrn, TRUE);
1226
1227	drmmode->flip_count = 0;
1228	drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
1229	drmmode->event_context.vblank_handler = drmmode_vblank_handler;
1230	drmmode->event_context.page_flip_handler = NULL;
1231	if (info->dri->pKernelDRMVersion->version_minor >= 4) {
1232		AddGeneralSocket(drmmode->fd);
1233		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
1234				drm_wakeup_handler, drmmode);
1235	}
1236
1237	return TRUE;
1238}
1239
1240Bool drmmode_set_bufmgr(ScrnInfoPtr pScrn, drmmode_ptr drmmode, struct radeon_bo_manager *bufmgr)
1241{
1242	drmmode->bufmgr = bufmgr;
1243	return TRUE;
1244}
1245
1246
1247
1248void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id, struct radeon_bo *bo)
1249{
1250	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1251	xf86CrtcPtr crtc = xf86_config->crtc[id];
1252	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1253
1254	drmmode_crtc->cursor_bo = bo;
1255}
1256
1257void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y, int flags)
1258{
1259	xf86CrtcConfigPtr	config = XF86_CRTC_CONFIG_PTR(pScrn);
1260	xf86OutputPtr  output = config->output[config->compat_output];
1261	xf86CrtcPtr	crtc = output->crtc;
1262
1263	if (crtc && crtc->enabled) {
1264		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
1265				       x, y);
1266	}
1267}
1268
1269Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1270{
1271	xf86CrtcConfigPtr   config = XF86_CRTC_CONFIG_PTR(pScrn);
1272	int c;
1273
1274	drmmode_copy_fb(pScrn, drmmode);
1275
1276	for (c = 0; c < config->num_crtc; c++) {
1277		xf86CrtcPtr	crtc = config->crtc[c];
1278		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1279		xf86OutputPtr	output = NULL;
1280		int		o;
1281
1282		/* Skip disabled CRTCs */
1283		if (!crtc->enabled) {
1284			drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1285				       0, 0, 0, NULL, 0, NULL);
1286			continue;
1287		}
1288
1289		if (config->output[config->compat_output]->crtc == crtc)
1290			output = config->output[config->compat_output];
1291		else
1292		{
1293			for (o = 0; o < config->num_output; o++)
1294				if (config->output[o]->crtc == crtc)
1295				{
1296					output = config->output[o];
1297					break;
1298				}
1299		}
1300		/* paranoia */
1301		if (!output)
1302			continue;
1303
1304		/* Mark that we'll need to re-set the mode for sure */
1305		memset(&crtc->mode, 0, sizeof(crtc->mode));
1306		if (!crtc->desiredMode.CrtcHDisplay)
1307		{
1308			DisplayModePtr  mode = xf86OutputFindClosestMode (output, pScrn->currentMode);
1309
1310			if (!mode)
1311				return FALSE;
1312			crtc->desiredMode = *mode;
1313			crtc->desiredRotation = RR_Rotate_0;
1314			crtc->desiredX = 0;
1315			crtc->desiredY = 0;
1316		}
1317
1318		if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
1319						 crtc->desiredX, crtc->desiredY))
1320			return FALSE;
1321	}
1322	return TRUE;
1323}
1324
1325static void drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
1326                                 int *indices, LOCO *colors, VisualPtr pVisual)
1327{
1328    xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1329    uint16_t       lut_r[256], lut_g[256], lut_b[256];
1330    int index, j, i;
1331    int c;
1332
1333    for (c = 0; c < xf86_config->num_crtc; c++) {
1334        xf86CrtcPtr crtc = xf86_config->crtc[c];
1335	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1336
1337        for (i = 0 ; i < 256; i++) {
1338            lut_r[i] = drmmode_crtc->lut_r[i] << 6;
1339            lut_g[i] = drmmode_crtc->lut_g[i] << 6;
1340            lut_b[i] = drmmode_crtc->lut_b[i] << 6;
1341        }
1342
1343        switch(pScrn->depth) {
1344        case 15:
1345            for (i = 0; i < numColors; i++) {
1346                index = indices[i];
1347                for (j = 0; j < 8; j++) {
1348                    lut_r[index * 8 + j] = colors[index].red << 6;
1349                    lut_g[index * 8 + j] = colors[index].green << 6;
1350                    lut_b[index * 8 + j] = colors[index].blue << 6;
1351                }
1352            }
1353         break;
1354         case 16:
1355             for (i = 0; i < numColors; i++) {
1356                 index = indices[i];
1357
1358                  if (i <= 31) {
1359                      for (j = 0; j < 8; j++) {
1360                          lut_r[index * 8 + j] = colors[index].red << 6;
1361                          lut_b[index * 8 + j] = colors[index].blue << 6;
1362                      }
1363                  }
1364
1365                  for (j = 0; j < 4; j++) {
1366                      lut_g[index * 4 + j] = colors[index].green << 6;
1367                  }
1368              }
1369	  break;
1370          default:
1371              for (i = 0; i < numColors; i++) {
1372                  index = indices[i];
1373                  lut_r[index] = colors[index].red << 6;
1374                  lut_g[index] = colors[index].green << 6;
1375                  lut_b[index] = colors[index].blue << 6;
1376              }
1377              break;
1378          }
1379
1380    /* Make the change through RandR */
1381#ifdef RANDR_12_INTERFACE
1382        if (crtc->randr_crtc)
1383            RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
1384        else
1385#endif
1386            crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
1387     }
1388}
1389
1390Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
1391{
1392    xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
1393                  "Initializing kms color map\n");
1394    if (!miCreateDefColormap(pScreen))
1395        return FALSE;
1396    /* all radeons support 10 bit CLUTs */
1397    if (!xf86HandleColormaps(pScreen, 256, 10,
1398                             drmmode_load_palette, NULL,
1399                             CMAP_PALETTED_TRUECOLOR
1400#if 0 /* This option messes up text mode! (eich@suse.de) */
1401                             | CMAP_LOAD_EVEN_IF_OFFSCREEN
1402#endif
1403                             | CMAP_RELOAD_ON_MODE_SWITCH))
1404         return FALSE;
1405    return TRUE;
1406}
1407
1408#ifdef HAVE_LIBUDEV
1409static void
1410drmmode_handle_uevents(int fd, void *closure)
1411{
1412	drmmode_ptr drmmode = closure;
1413	ScrnInfoPtr scrn = drmmode->scrn;
1414	struct udev_device *dev;
1415	dev = udev_monitor_receive_device(drmmode->uevent_monitor);
1416	if (!dev)
1417		return;
1418
1419	RRGetInfo(screenInfo.screens[scrn->scrnIndex], TRUE);
1420	udev_device_unref(dev);
1421}
1422#endif
1423
1424void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1425{
1426#ifdef HAVE_LIBUDEV
1427	struct udev *u;
1428	struct udev_monitor *mon;
1429
1430	u = udev_new();
1431	if (!u)
1432		return;
1433	mon = udev_monitor_new_from_netlink(u, "udev");
1434	if (!mon) {
1435		udev_unref(u);
1436		return;
1437	}
1438
1439	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
1440							    "drm",
1441							    "drm_minor") < 0 ||
1442	    udev_monitor_enable_receiving(mon) < 0) {
1443		udev_monitor_unref(mon);
1444		udev_unref(u);
1445		return;
1446	}
1447
1448	drmmode->uevent_handler =
1449		xf86AddGeneralHandler(udev_monitor_get_fd(mon),
1450				      drmmode_handle_uevents,
1451				      drmmode);
1452
1453	drmmode->uevent_monitor = mon;
1454#endif
1455}
1456
1457void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
1458{
1459#ifdef HAVE_LIBUDEV
1460	if (drmmode->uevent_handler) {
1461		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
1462		xf86RemoveGeneralHandler(drmmode->uevent_handler);
1463
1464		udev_monitor_unref(drmmode->uevent_monitor);
1465		udev_unref(u);
1466	}
1467#endif
1468}
1469
1470#endif
1471