drmmode_display.c revision 35d5b7c7
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#include <sys/ioctl.h>
34#include <time.h>
35#include "cursorstr.h"
36#include "damagestr.h"
37#include "inputstr.h"
38#include "list.h"
39#include "micmap.h"
40#include "mipointrst.h"
41#include "xf86cmap.h"
42#include "xf86Priv.h"
43#include "sarea.h"
44
45#include "drmmode_display.h"
46#include "amdgpu_bo_helper.h"
47#include "amdgpu_glamor.h"
48#include "amdgpu_pixmap.h"
49
50#include <dri.h>
51
52/* DPMS */
53#ifdef HAVE_XEXTPROTO_71
54#include <X11/extensions/dpmsconst.h>
55#else
56#define DPMS_SERVER
57#include <X11/extensions/dpms.h>
58#endif
59
60#include <gbm.h>
61
62#define DEFAULT_NOMINAL_FRAME_RATE 60
63
64static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
65
66static Bool
67AMDGPUZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name)
68{
69	int i = 0;
70	char s1[20];
71
72	do {
73		switch (*s) {
74		case ',':
75			s1[i] = '\0';
76			i = 0;
77			if (strcmp(s1, output_name) == 0)
78				return TRUE;
79			break;
80		case ' ':
81		case '\t':
82		case '\n':
83		case '\r':
84			break;
85		default:
86			s1[i] = *s;
87			i++;
88			break;
89		}
90	} while (*s++);
91
92	s1[i] = '\0';
93	if (strcmp(s1, output_name) == 0)
94		return TRUE;
95
96	return FALSE;
97}
98
99
100static PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
101					  int width, int height,
102					  int depth, int bpp,
103					  int pitch,
104					  struct amdgpu_buffer *bo)
105{
106	ScreenPtr pScreen = pScrn->pScreen;
107	PixmapPtr pixmap;
108
109	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth,
110					  AMDGPU_CREATE_PIXMAP_SCANOUT);
111	if (!pixmap)
112		return NULL;
113
114	if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height,
115					     depth, bpp, pitch, NULL))
116		goto fail;
117
118	if (!amdgpu_glamor_create_textured_pixmap(pixmap, bo))
119		goto fail;
120
121	if (amdgpu_set_pixmap_bo(pixmap, bo))
122		return pixmap;
123
124fail:
125	pScreen->DestroyPixmap(pixmap);
126	return NULL;
127}
128
129static void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
130{
131	ScreenPtr pScreen = pixmap->drawable.pScreen;
132
133	(*pScreen->DestroyPixmap) (pixmap);
134}
135
136static void
137drmmode_ConvertFromKMode(ScrnInfoPtr scrn,
138			 drmModeModeInfo * kmode, DisplayModePtr mode)
139{
140	memset(mode, 0, sizeof(DisplayModeRec));
141	mode->status = MODE_OK;
142
143	mode->Clock = kmode->clock;
144
145	mode->HDisplay = kmode->hdisplay;
146	mode->HSyncStart = kmode->hsync_start;
147	mode->HSyncEnd = kmode->hsync_end;
148	mode->HTotal = kmode->htotal;
149	mode->HSkew = kmode->hskew;
150
151	mode->VDisplay = kmode->vdisplay;
152	mode->VSyncStart = kmode->vsync_start;
153	mode->VSyncEnd = kmode->vsync_end;
154	mode->VTotal = kmode->vtotal;
155	mode->VScan = kmode->vscan;
156
157	mode->Flags = kmode->flags;	//& FLAG_BITS;
158	mode->name = strdup(kmode->name);
159
160	if (kmode->type & DRM_MODE_TYPE_DRIVER)
161		mode->type = M_T_DRIVER;
162	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
163		mode->type |= M_T_PREFERRED;
164	xf86SetModeCrtc(mode, scrn->adjustFlags);
165}
166
167static void
168drmmode_ConvertToKMode(ScrnInfoPtr scrn,
169		       drmModeModeInfo * kmode, DisplayModePtr mode)
170{
171	memset(kmode, 0, sizeof(*kmode));
172
173	kmode->clock = mode->Clock;
174	kmode->hdisplay = mode->HDisplay;
175	kmode->hsync_start = mode->HSyncStart;
176	kmode->hsync_end = mode->HSyncEnd;
177	kmode->htotal = mode->HTotal;
178	kmode->hskew = mode->HSkew;
179
180	kmode->vdisplay = mode->VDisplay;
181	kmode->vsync_start = mode->VSyncStart;
182	kmode->vsync_end = mode->VSyncEnd;
183	kmode->vtotal = mode->VTotal;
184	kmode->vscan = mode->VScan;
185
186	kmode->flags = mode->Flags;	//& FLAG_BITS;
187	if (mode->name)
188		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
189	kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0;
190
191}
192
193/*
194 * Utility helper for drmWaitVBlank
195 */
196Bool
197drmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type,
198		    uint32_t target_seq, unsigned long signal, uint64_t *ust,
199		    uint32_t *result_seq)
200{
201	int crtc_id = drmmode_get_crtc_id(crtc);
202	ScrnInfoPtr scrn = crtc->scrn;
203	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
204	drmVBlank vbl;
205
206	if (crtc_id == 1)
207		type |= DRM_VBLANK_SECONDARY;
208	else if (crtc_id > 1)
209		type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) &
210			DRM_VBLANK_HIGH_CRTC_MASK;
211
212	vbl.request.type = type;
213	vbl.request.sequence = target_seq;
214	vbl.request.signal = signal;
215
216	if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl) != 0)
217		return FALSE;
218
219	if (ust)
220		*ust = (uint64_t)vbl.reply.tval_sec * 1000000 +
221			vbl.reply.tval_usec;
222	if (result_seq)
223		*result_seq = vbl.reply.sequence;
224
225	return TRUE;
226}
227
228/*
229 * Retrieves present time in microseconds that is compatible
230 * with units used by vblank timestamps. Depending on the kernel
231 * version and DRM kernel module configuration, the vblank
232 * timestamp can either be in real time or monotonic time
233 */
234int drmmode_get_current_ust(int drm_fd, CARD64 * ust)
235{
236	uint64_t cap_value;
237	int ret;
238	struct timespec now;
239
240	ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value);
241	if (ret || !cap_value)
242		/* old kernel or drm_timestamp_monotonic turned off */
243		ret = clock_gettime(CLOCK_REALTIME, &now);
244	else
245		ret = clock_gettime(CLOCK_MONOTONIC, &now);
246	if (ret)
247		return ret;
248	*ust = ((CARD64) now.tv_sec * 1000000) + ((CARD64) now.tv_nsec / 1000);
249	return 0;
250}
251
252/*
253 * Get current frame count and frame count timestamp of the crtc.
254 */
255int drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)
256{
257	ScrnInfoPtr scrn = crtc->scrn;
258	uint32_t seq;
259
260	if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) {
261		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
262			   "get vblank counter failed: %s\n", strerror(errno));
263		return -1;
264	}
265
266	*msc = seq;
267
268	return Success;
269}
270
271static void
272drmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
273{
274	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
275	ScrnInfoPtr scrn = crtc->scrn;
276	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
277	CARD64 ust;
278	int ret;
279
280	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
281		uint32_t seq;
282
283		amdgpu_drm_wait_pending_flip(crtc);
284
285		/*
286		 * On->Off transition: record the last vblank time,
287		 * sequence number and frame period.
288		 */
289		if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust,
290					 &seq))
291			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
292				   "%s cannot get last vblank counter\n",
293				   __func__);
294		else {
295			CARD64 nominal_frame_rate, pix_in_frame;
296
297			drmmode_crtc->dpms_last_ust = ust;
298			drmmode_crtc->dpms_last_seq = seq;
299			nominal_frame_rate = crtc->mode.Clock;
300			nominal_frame_rate *= 1000;
301			pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal;
302			if (nominal_frame_rate == 0 || pix_in_frame == 0)
303				nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE;
304			else
305				nominal_frame_rate /= pix_in_frame;
306			drmmode_crtc->dpms_last_fps = nominal_frame_rate;
307		}
308
309		drmmode_crtc->dpms_mode = mode;
310		amdgpu_drm_queue_handle_deferred(crtc);
311	} else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) {
312		/*
313		 * Off->On transition: calculate and accumulate the
314		 * number of interpolated vblanks while we were in Off state
315		 */
316		ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust);
317		if (ret)
318			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
319				   "%s cannot get current time\n", __func__);
320		else if (drmmode_crtc->dpms_last_ust) {
321			CARD64 time_elapsed, delta_seq;
322			time_elapsed = ust - drmmode_crtc->dpms_last_ust;
323			delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps;
324			delta_seq /= 1000000;
325			drmmode_crtc->interpolated_vblanks += delta_seq;
326
327		}
328
329		drmmode_crtc->dpms_mode = DPMSModeOn;
330	}
331}
332
333static void
334drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
335{
336	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
337	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
338
339	/* Disable unused CRTCs and enable/disable active CRTCs */
340	if (!crtc->enabled || mode != DPMSModeOn) {
341		drmmode_do_crtc_dpms(crtc, DPMSModeOff);
342		drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
343			       0, 0, 0, NULL, 0, NULL);
344		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL);
345	} else if (drmmode_crtc->dpms_mode != DPMSModeOn)
346		crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
347					    crtc->x, crtc->y);
348}
349
350static PixmapPtr
351create_pixmap_for_fbcon(drmmode_ptr drmmode,
352			ScrnInfoPtr pScrn, int fbcon_id)
353{
354	ScreenPtr pScreen = pScrn->pScreen;
355	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
356	PixmapPtr pixmap = NULL;
357	drmModeFBPtr fbcon;
358
359	fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id);
360	if (!fbcon)
361		return NULL;
362
363	if (fbcon->depth != pScrn->depth ||
364	    fbcon->width != pScrn->virtualX ||
365	    fbcon->height != pScrn->virtualY)
366		goto out_free_fb;
367
368	pixmap = fbCreatePixmap(pScreen, 0, 0, fbcon->depth, 0);
369	if (!pixmap)
370		goto out_free_fb;
371
372	pScreen->ModifyPixmapHeader(pixmap, fbcon->width, fbcon->height, 0, 0,
373				    fbcon->pitch, NULL);
374	pixmap->devPrivate.ptr = NULL;
375
376	if (!glamor_egl_create_textured_pixmap(pixmap, fbcon->handle,
377					       pixmap->devKind)) {
378		pScreen->DestroyPixmap(pixmap);
379		pixmap = NULL;
380	}
381
382out_free_fb:
383	drmModeFreeFB(fbcon);
384	return pixmap;
385}
386
387void drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
388{
389	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
390	ScreenPtr pScreen = pScrn->pScreen;
391	PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen);
392	struct drmmode_fb *fb = amdgpu_pixmap_get_fb(dst);
393	int fbcon_id = 0;
394	GCPtr gc;
395	int i;
396
397	for (i = 0; i < xf86_config->num_crtc; i++) {
398		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
399
400		if (drmmode_crtc->mode_crtc->buffer_id)
401			fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
402	}
403
404	if (!fbcon_id)
405		return;
406
407	if (fbcon_id == fb->handle) {
408		/* in some rare case there might be no fbcon and we might already
409		 * be the one with the current fb to avoid a false deadlck in
410		 * kernel ttm code just do nothing as anyway there is nothing
411		 * to do
412		 */
413		return;
414	}
415
416	src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
417	if (!src)
418		return;
419
420	gc = GetScratchGC(pScrn->depth, pScreen);
421	ValidateGC(&dst->drawable, gc);
422
423	(*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0,
424			     pScrn->virtualX, pScrn->virtualY, 0, 0);
425
426	FreeScratchGC(gc);
427
428	pScreen->canDoBGNoneRoot = TRUE;
429	pScreen->DestroyPixmap(src);
430
431	return;
432}
433
434void
435drmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
436			     struct drmmode_scanout *scanout)
437{
438
439	if (scanout->pixmap) {
440		drmmode_destroy_bo_pixmap(scanout->pixmap);
441		scanout->pixmap = NULL;
442	}
443
444	if (scanout->bo) {
445		amdgpu_bo_unref(&scanout->bo);
446		scanout->bo = NULL;
447	}
448}
449
450void
451drmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc)
452{
453	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
454				     &drmmode_crtc->scanout[0]);
455	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
456				     &drmmode_crtc->scanout[1]);
457
458	if (drmmode_crtc->scanout_damage)
459		DamageDestroy(drmmode_crtc->scanout_damage);
460}
461
462PixmapPtr
463drmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
464			    int width, int height)
465{
466	ScrnInfoPtr pScrn = crtc->scrn;
467	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
468	drmmode_ptr drmmode = drmmode_crtc->drmmode;
469	int pitch;
470
471	if (scanout->pixmap) {
472		if (scanout->width == width && scanout->height == height)
473			return scanout->pixmap;
474
475		drmmode_crtc_scanout_destroy(drmmode, scanout);
476	}
477
478	scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height,
479					     pScrn->depth, 0,
480					     pScrn->bitsPerPixel, &pitch);
481	if (!scanout->bo) {
482		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
483			   "Failed to allocate scanout buffer memory\n");
484		return NULL;
485	}
486
487	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
488						 width, height,
489						 pScrn->depth,
490						 pScrn->bitsPerPixel,
491						 pitch, scanout->bo);
492	if (!scanout->pixmap) {
493		ErrorF("failed to create CRTC scanout pixmap\n");
494		goto error;
495	}
496
497	if (amdgpu_pixmap_get_fb(scanout->pixmap)) {
498		scanout->width = width;
499		scanout->height = height;
500	} else {
501		ErrorF("failed to create CRTC scanout FB\n");
502error:
503		drmmode_crtc_scanout_destroy(drmmode, scanout);
504	}
505
506	return scanout->pixmap;
507}
508
509static void
510amdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
511{
512	drmmode_crtc_private_ptr drmmode_crtc = closure;
513
514	if (drmmode_crtc->ignore_damage) {
515		RegionEmpty(&damage->damage);
516		drmmode_crtc->ignore_damage = FALSE;
517		return;
518	}
519
520	/* Only keep track of the extents */
521	RegionUninit(&damage->damage);
522	damage->damage.data = NULL;
523}
524
525static void
526drmmode_screen_damage_destroy(DamagePtr damage, void *closure)
527{
528	drmmode_crtc_private_ptr drmmode_crtc = closure;
529
530	drmmode_crtc->scanout_damage = NULL;
531	RegionUninit(&drmmode_crtc->scanout_last_region);
532}
533
534static Bool
535drmmode_can_use_hw_cursor(xf86CrtcPtr crtc)
536{
537	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
538
539	/* Check for Option "SWcursor" */
540	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
541		return FALSE;
542
543	/* Fall back to SW cursor if the CRTC is transformed */
544	if (crtc->transformPresent)
545		return FALSE;
546
547#if XF86_CRTC_VERSION < 7
548	/* Xorg doesn't correctly handle cursor position transform in the
549	 * rotation case
550	 */
551	if (crtc->driverIsPerformingTransform &&
552	    (crtc->rotation & 0xf) != RR_Rotate_0)
553		return FALSE;
554#endif
555
556	/* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */
557	if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) &&
558	    !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list))
559		return FALSE;
560
561	return TRUE;
562}
563
564static void
565drmmode_crtc_update_tear_free(xf86CrtcPtr crtc)
566{
567	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
568	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
569	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
570	int i;
571
572	drmmode_crtc->tear_free = FALSE;
573
574	for (i = 0; i < xf86_config->num_output; i++) {
575		xf86OutputPtr output = xf86_config->output[i];
576		drmmode_output_private_ptr drmmode_output = output->driver_private;
577
578		if (output->crtc != crtc)
579			continue;
580
581		if (drmmode_output->tear_free == 1 ||
582		    (drmmode_output->tear_free == 2 &&
583		     (crtc->scrn->pScreen->isGPU ||
584		      info->shadow_primary ||
585		      crtc->transformPresent || crtc->rotation != RR_Rotate_0))) {
586			drmmode_crtc->tear_free = TRUE;
587			return;
588		}
589	}
590}
591
592#if XF86_CRTC_VERSION < 7
593#define XF86DriverTransformOutput TRUE
594#define XF86DriverTransformNone FALSE
595#endif
596
597static Bool
598drmmode_handle_transform(xf86CrtcPtr crtc)
599{
600	Bool ret;
601
602#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
603	crtc->driverIsPerformingTransform = XF86DriverTransformOutput;
604#else
605	crtc->driverIsPerformingTransform = !crtc->transformPresent &&
606		(crtc->rotation & 0xf) == RR_Rotate_0;
607#endif
608
609	ret = xf86CrtcRotate(crtc);
610
611	crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use;
612
613	return ret;
614}
615
616
617static void
618drmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
619				  unsigned scanout_id, struct drmmode_fb **fb,
620				  int *x, int *y)
621{
622	ScrnInfoPtr scrn = crtc->scrn;
623	ScreenPtr screen = scrn->pScreen;
624	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
625
626	if (drmmode_crtc->tear_free &&
627	    !drmmode_crtc->scanout[1].pixmap) {
628		RegionPtr region;
629		BoxPtr box;
630
631		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
632					    mode->HDisplay,
633					    mode->VDisplay);
634		region = &drmmode_crtc->scanout_last_region;
635		RegionUninit(region);
636		region->data = NULL;
637		box = RegionExtents(region);
638		box->x1 = crtc->x;
639		box->y1 = crtc->y;
640		box->x2 = crtc->x + mode->HDisplay;
641		box->y2 = crtc->y + mode->VDisplay;
642	}
643
644	if (scanout_id != drmmode_crtc->scanout_id) {
645		PixmapDirtyUpdatePtr dirty = NULL;
646
647		xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list,
648					 ent) {
649			if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
650				dirty->slave_dst =
651					drmmode_crtc->scanout[scanout_id].pixmap;
652				break;
653			}
654		}
655
656		if (!drmmode_crtc->tear_free) {
657			GCPtr gc = GetScratchGC(scrn->depth, screen);
658
659			ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc);
660			gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable,
661					  &drmmode_crtc->scanout[0].pixmap->drawable,
662					  gc, 0, 0, mode->HDisplay, mode->VDisplay,
663					  0, 0);
664			FreeScratchGC(gc);
665			amdgpu_glamor_finish(scrn);
666		}
667	}
668
669	*fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
670	*x = *y = 0;
671	drmmode_crtc->scanout_id = scanout_id;
672}
673
674
675static void
676drmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
677			    unsigned scanout_id, struct drmmode_fb **fb, int *x,
678			    int *y)
679{
680	ScrnInfoPtr scrn = crtc->scrn;
681	ScreenPtr screen = scrn->pScreen;
682	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
683
684	drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id],
685				    mode->HDisplay, mode->VDisplay);
686	if (drmmode_crtc->tear_free) {
687		drmmode_crtc_scanout_create(crtc,
688					    &drmmode_crtc->scanout[scanout_id ^ 1],
689					    mode->HDisplay, mode->VDisplay);
690	}
691
692	if (drmmode_crtc->scanout[scanout_id].pixmap &&
693	    (!drmmode_crtc->tear_free ||
694	     drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) {
695		BoxRec extents = { .x1 = 0, .y1 = 0,
696				   .x2 = scrn->virtualX, .y2 = scrn->virtualY };
697
698		if (!drmmode_crtc->scanout_damage) {
699			drmmode_crtc->scanout_damage =
700				DamageCreate(amdgpu_screen_damage_report,
701					     drmmode_screen_damage_destroy,
702					     DamageReportRawRegion,
703					     TRUE, screen, drmmode_crtc);
704			DamageRegister(&screen->root->drawable,
705				       drmmode_crtc->scanout_damage);
706		}
707
708		*fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
709		*x = *y = 0;
710
711		amdgpu_scanout_do_update(crtc, scanout_id,
712					 screen->GetWindowPixmap(screen->root),
713					 extents);
714		RegionEmpty(DamageRegion(drmmode_crtc->scanout_damage));
715		amdgpu_glamor_finish(scrn);
716	}
717}
718
719static char *cm_prop_names[] = {
720	"DEGAMMA_LUT",
721	"CTM",
722	"GAMMA_LUT",
723	"DEGAMMA_LUT_SIZE",
724	"GAMMA_LUT_SIZE",
725};
726
727/**
728 * Return the enum of the color management property with the given name.
729 */
730static enum drmmode_cm_prop get_cm_enum_from_str(const char *prop_name)
731{
732	enum drmmode_cm_prop ret;
733
734	for (ret = 0; ret < CM_NUM_PROPS; ret++) {
735		if (!strcmp(prop_name, cm_prop_names[ret]))
736			return ret;
737	}
738	return CM_INVALID_PROP;
739}
740
741/**
742 * Return TRUE if kernel supports non-legacy color management.
743 */
744static Bool drmmode_cm_enabled(drmmode_ptr drmmode)
745{
746	return drmmode->cm_prop_ids[CM_GAMMA_LUT_SIZE] != 0;
747}
748
749/**
750 * If legacy LUT is a, and non-legacy LUT is b, then the result of b(a(x)) is
751 * returned in out_lut. out_lut's length is expected to be the same as the
752 * non-legacy LUT b.
753 *
754 * @a_(red|green|blue): The red, green, and blue components of the legacy LUT.
755 * @b_lut: The non-legacy LUT, in DRM's color LUT format.
756 * @out_lut: The composed LUT, in DRM's color LUT format.
757 * @len_a: Length of legacy lut.
758 * @len_b: Length of non-legacy lut.
759 */
760static void drmmode_lut_compose(uint16_t *a_red,
761				uint16_t *a_green,
762				uint16_t *a_blue,
763				struct drm_color_lut *b_lut,
764				struct drm_color_lut *out_lut,
765				uint32_t len_a, uint32_t len_b)
766{
767	uint32_t i_l, i_r, i;
768	uint32_t i_amax, i_bmax;
769	uint32_t coeff_ibmax;
770	uint32_t j;
771	uint64_t a_out_ibmax;
772	int color;
773	size_t struct_size = sizeof(struct drm_color_lut);
774
775	uint32_t max_lut = (1 << 16) - 1;
776
777	i_amax = len_a - 1;
778	i_bmax = len_b - 1;
779
780	/* A linear interpolation is done on the legacy LUT before it is
781	 * composed, to bring it up-to-size with the non-legacy LUT. The
782	 * interpolation uses integers by keeping things multiplied until the
783	 * last moment.
784	 */
785	for (color = 0; color < 3; color++) {
786		uint16_t *a, *b, *out;
787
788		/* Set the initial pointers to the right color components. The
789		 * inner for-loop will then maintain the correct offset from
790		 * the initial element.
791		 */
792		if (color == 0) {
793			a = a_red;
794			b = &b_lut[0].red;
795			out = &out_lut[0].red;
796		} else if (color == 1) {
797			a = a_green;
798			b = &b_lut[0].green;
799			out = &out_lut[0].green;
800		} else {
801			a = a_blue;
802			b = &b_lut[0].blue;
803			out = &out_lut[0].blue;
804		}
805
806		for (i = 0; i < len_b; i++) {
807			/* i_l and i_r tracks the left and right elements in
808			 * a_lut, to the sample point i. Also handle last
809			 * element edge case, when i_l = i_amax.
810			 */
811			i_l = i * i_amax / i_bmax;
812			i_r = i_l + !!(i_amax - i_l);
813
814			/* coeff is intended to be in [0, 1), depending on
815			 * where sample i is between i_l and i_r. We keep it
816			 * multiplied with i_bmax throughout to maintain
817			 * precision */
818			coeff_ibmax = (i * i_amax) - (i_l * i_bmax);
819			a_out_ibmax = i_bmax * a[i_l] +
820				      coeff_ibmax * (a[i_r] - a[i_l]);
821
822			/* j = floor((a_out/max_lut)*i_bmax).
823			 * i.e. the element in LUT b that a_out maps to. We
824			 * have to divide by max_lut to normalize a_out, since
825			 * values in the LUTs are [0, 1<<16)
826			 */
827			j = a_out_ibmax / max_lut;
828			*(uint16_t*)((void*)out + (i*struct_size)) =
829				*(uint16_t*)((void*)b + (j*struct_size));
830		}
831	}
832
833	for (i = 0; i < len_b; i++)
834		out_lut[i].reserved = 0;
835}
836
837/**
838 * Resize a LUT, using linear interpolation.
839 *
840 * @in_(red|green|blue): Legacy LUT components
841 * @out_lut: The resized LUT is returned here, in DRM color LUT format.
842 * @len_in: Length of legacy LUT.
843 * @len_out: Length of out_lut, i.e. the target size.
844 */
845static void drmmode_lut_interpolate(uint16_t *in_red,
846				    uint16_t *in_green,
847				    uint16_t *in_blue,
848				    struct drm_color_lut *out_lut,
849				    uint32_t len_in, uint32_t len_out)
850{
851	uint32_t i_l, i_r, i;
852	uint32_t i_amax, i_bmax;
853	uint32_t coeff_ibmax;
854	uint64_t out_ibmax;
855	int color;
856	size_t struct_size = sizeof(struct drm_color_lut);
857
858	i_amax = len_in - 1;
859	i_bmax = len_out - 1;
860
861	/* See @drmmode_lut_compose for details */
862	for (color = 0; color < 3; color++) {
863		uint16_t *in, *out;
864
865		if (color == 0) {
866			in = in_red;
867			out = &out_lut[0].red;
868		} else if (color == 1) {
869			in = in_green;
870			out = &out_lut[0].green;
871		} else {
872			in = in_blue;
873			out = &out_lut[0].blue;
874		}
875
876		for (i = 0; i < len_out; i++) {
877			i_l = i * i_amax / i_bmax;
878			i_r = i_l + !!(i_amax - i_l);
879
880			coeff_ibmax = (i * i_amax) - (i_l * i_bmax);
881			out_ibmax = i_bmax * in[i_l] +
882				      coeff_ibmax * (in[i_r] - in[i_l]);
883
884			*(uint16_t*)((void*)out + (i*struct_size)) =
885				out_ibmax / i_bmax;
886		}
887	}
888
889	for (i = 0; i < len_out; i++)
890		out_lut[i].reserved = 0;
891}
892
893/**
894 * Configure and change a color property on a CRTC, through RandR. Only the
895 * specified output will be affected, even if the CRTC is attached to multiple
896 * outputs. Note that changes will be non-pending: the changes won't be pushed
897 * to kernel driver.
898 *
899 * @output: RandR output to set the property on.
900 * @crtc: The driver-private CRTC object containing the color properties.
901 *        If this is NULL, "disabled" values of 0 will be used.
902 * @cm_prop_index: Color management property to configure and change.
903 *
904 * Return 0 on success, X-defined error code otherwise.
905 */
906static int rr_configure_and_change_cm_property(xf86OutputPtr output,
907					       drmmode_crtc_private_ptr crtc,
908					       enum drmmode_cm_prop cm_prop_index)
909{
910	drmmode_output_private_ptr drmmode_output = output->driver_private;
911	drmmode_ptr drmmode = drmmode_output->drmmode;
912	Bool need_configure = TRUE;
913	unsigned long length = 0;
914	void *data = NULL;
915	int format = 0;
916	uint32_t zero = 0;
917	INT32 range[2];
918	Atom atom;
919	int err;
920
921	if (cm_prop_index == CM_INVALID_PROP)
922		return BadName;
923
924	switch(cm_prop_index) {
925	case CM_GAMMA_LUT_SIZE:
926		format = 32;
927		length = 1;
928		data = &drmmode->gamma_lut_size;
929		range[0] = 0;
930		range[1] = -1;
931		break;
932	case CM_DEGAMMA_LUT_SIZE:
933		format = 32;
934		length = 1;
935		data = &drmmode->degamma_lut_size;
936		range[0] = 0;
937		range[1] = -1;
938		break;
939	case CM_GAMMA_LUT:
940		format = 16;
941		range[0] = 0;
942		range[1] = (1 << 16) - 1; // Max 16 bit unsigned int.
943		if (crtc && crtc->gamma_lut) {
944			/* Convert from 8bit size to 16bit size */
945			length = sizeof(*crtc->gamma_lut) >> 1;
946			length *= drmmode->gamma_lut_size;
947			data = crtc->gamma_lut;
948		} else {
949			length = 1;
950			data = &zero;
951		}
952		break;
953	case CM_DEGAMMA_LUT:
954		format = 16;
955		range[0] = 0;
956		range[1] = (1 << 16) - 1;
957		if (crtc && crtc->degamma_lut) {
958			length = sizeof(*crtc->degamma_lut) >> 1;
959			length *= drmmode->degamma_lut_size;
960			data = crtc->degamma_lut;
961		} else {
962			length = 1;
963			data = &zero;
964		}
965		break;
966	case CM_CTM:
967		/* CTM is fixed-point S31.32 format. */
968		format = 32;
969		need_configure = FALSE;
970		if (crtc && crtc->ctm) {
971			/* Convert from 8bit size to 32bit size */
972			length = sizeof(*crtc->ctm) >> 2;
973			data = crtc->ctm;
974		} else {
975			length = 1;
976			data = &zero;
977		}
978		break;
979	default:
980		return BadName;
981	}
982
983	atom = MakeAtom(cm_prop_names[cm_prop_index],
984			strlen(cm_prop_names[cm_prop_index]),
985			TRUE);
986	if (!atom)
987		return BadAlloc;
988
989	if (need_configure) {
990		err = RRConfigureOutputProperty(output->randr_output, atom,
991						FALSE, TRUE, FALSE, 2, range);
992		if (err) {
993			xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
994				   "Configuring color management property %s failed with %d\n",
995				   cm_prop_names[cm_prop_index], err);
996			return err;
997		}
998	}
999
1000	/* Always issue a non-pending change. We'll push cm properties
1001	 * ourselves.
1002	 */
1003	err = RRChangeOutputProperty(output->randr_output, atom,
1004				     XA_INTEGER, format,
1005				     PropModeReplace,
1006				     length, data, FALSE, FALSE);
1007	if (err)
1008		xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1009			   "Changing color management property %s failed with %d\n",
1010			   cm_prop_names[cm_prop_index], err);
1011	return err;
1012}
1013
1014/**
1015* Stage a color management property. This parses the property value, according
1016* to the cm property type, then stores it within the driver-private CRTC
1017* object.
1018*
1019* @crtc: The CRTC to stage the new color management properties in
1020* @cm_prop_index: The color property to stage
1021* @value: The RandR property value to stage
1022*
1023* Return 0 on success, X-defined error code on failure.
1024*/
1025static int drmmode_crtc_stage_cm_prop(xf86CrtcPtr crtc,
1026				      enum drmmode_cm_prop cm_prop_index,
1027				      RRPropertyValuePtr value)
1028{
1029	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1030	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1031	size_t expected_bytes = 0;
1032	void **blob_data = NULL;
1033	Bool use_default = FALSE;
1034
1035	/* Update properties on the driver-private CRTC */
1036	switch (cm_prop_index) {
1037	case CM_GAMMA_LUT:
1038		/* Calculate the expected size of value in bytes */
1039		expected_bytes = sizeof(struct drm_color_lut) *
1040					drmmode->gamma_lut_size;
1041
1042		/* For gamma and degamma, we allow a default SRGB curve to be
1043		 * set via setting a single element
1044		 *
1045		 * Otherwise, value size is in terms of the value format.
1046		 * Ensure it's also in bytes (<< 1) before comparing with the
1047		 * expected bytes.
1048		 */
1049		if (value->size == 1)
1050			use_default = TRUE;
1051		else if (value->type != XA_INTEGER || value->format != 16 ||
1052			 (size_t)(value->size << 1) != expected_bytes)
1053			return BadLength;
1054
1055		blob_data = (void**)&drmmode_crtc->gamma_lut;
1056		break;
1057	case CM_DEGAMMA_LUT:
1058		expected_bytes = sizeof(struct drm_color_lut) *
1059					drmmode->degamma_lut_size;
1060
1061		if (value->size == 1)
1062			use_default = TRUE;
1063		else if (value->type != XA_INTEGER || value->format != 16 ||
1064			 (size_t)(value->size << 1) != expected_bytes)
1065			return BadLength;
1066
1067		blob_data = (void**)&drmmode_crtc->degamma_lut;
1068		break;
1069	case CM_CTM:
1070		expected_bytes = sizeof(struct drm_color_ctm);
1071
1072		if (value->size == 1)
1073			use_default = TRUE;
1074		if (value->type != XA_INTEGER || value->format != 32 ||
1075		    (size_t)(value->size << 2) != expected_bytes)
1076			return BadLength;
1077
1078		blob_data = (void**)&drmmode_crtc->ctm;
1079		break;
1080	default:
1081		return BadName;
1082	}
1083
1084	free(*blob_data);
1085	if (!use_default) {
1086		*blob_data = malloc(expected_bytes);
1087		if (!*blob_data)
1088			return BadAlloc;
1089		memcpy(*blob_data, value->data, expected_bytes);
1090	} else
1091		*blob_data = NULL;
1092
1093	return Success;
1094}
1095
1096/**
1097 * Push staged color management properties on the CRTC to DRM.
1098 *
1099 * @crtc: The CRTC containing staged properties
1100 * @cm_prop_index: The color property to push
1101 *
1102 * Return 0 on success, X-defined error codes on failure.
1103 */
1104static int drmmode_crtc_push_cm_prop(xf86CrtcPtr crtc,
1105				     enum drmmode_cm_prop cm_prop_index)
1106{
1107	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1108	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
1109	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1110	Bool free_blob_data = FALSE;
1111	uint32_t created_blob_id = 0;
1112	uint32_t drm_prop_id;
1113	size_t expected_bytes = 0;
1114	void *blob_data = NULL;
1115	int ret;
1116
1117	switch (cm_prop_index) {
1118	case CM_GAMMA_LUT:
1119		/* Calculate the expected size of value in bytes */
1120		expected_bytes = sizeof(struct drm_color_lut) *
1121					drmmode->gamma_lut_size;
1122
1123		/* Legacy gamma LUT is disabled on deep 30bpp color. In which
1124		 * case, directly use non-legacy LUT.
1125		 */
1126		if (!crtc->funcs->gamma_set) {
1127			blob_data = drmmode_crtc->gamma_lut;
1128			goto do_push;
1129		}
1130
1131		blob_data = malloc(expected_bytes);
1132		if (!blob_data)
1133			return BadAlloc;
1134
1135		free_blob_data = TRUE;
1136		/*
1137		 * Compose legacy and non-legacy LUT if non-legacy was set.
1138		 * Otherwise, interpolate legacy LUT to non-legacy size.
1139		 */
1140		if (drmmode_crtc->gamma_lut) {
1141			drmmode_lut_compose(crtc->gamma_red,
1142					    crtc->gamma_green,
1143					    crtc->gamma_blue,
1144					    drmmode_crtc->gamma_lut,
1145					    blob_data, crtc->gamma_size,
1146					    drmmode->gamma_lut_size);
1147		} else {
1148			drmmode_lut_interpolate(crtc->gamma_red,
1149						crtc->gamma_green,
1150						crtc->gamma_blue,
1151						blob_data,
1152						crtc->gamma_size,
1153						drmmode->gamma_lut_size);
1154		}
1155		break;
1156	case CM_DEGAMMA_LUT:
1157		expected_bytes = sizeof(struct drm_color_lut) *
1158					drmmode->degamma_lut_size;
1159		blob_data = drmmode_crtc->degamma_lut;
1160		break;
1161	case CM_CTM:
1162		expected_bytes = sizeof(struct drm_color_ctm);
1163		blob_data = drmmode_crtc->ctm;
1164		break;
1165	default:
1166		return BadName;
1167	}
1168
1169do_push:
1170	if (blob_data) {
1171		ret = drmModeCreatePropertyBlob(pAMDGPUEnt->fd,
1172						blob_data, expected_bytes,
1173						&created_blob_id);
1174		if (ret) {
1175			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1176				   "Creating DRM blob failed with errno %d\n",
1177				   ret);
1178			if (free_blob_data)
1179				free(blob_data);
1180			return BadRequest;
1181		}
1182	}
1183
1184	drm_prop_id = drmmode_crtc->drmmode->cm_prop_ids[cm_prop_index];
1185	ret = drmModeObjectSetProperty(pAMDGPUEnt->fd,
1186				       drmmode_crtc->mode_crtc->crtc_id,
1187				       DRM_MODE_OBJECT_CRTC,
1188				       drm_prop_id,
1189				       (uint64_t)created_blob_id);
1190
1191	/* If successful, kernel will have a reference already. Safe to destroy
1192	 * the blob either way.
1193	 */
1194	if (blob_data)
1195		drmModeDestroyPropertyBlob(pAMDGPUEnt->fd, created_blob_id);
1196
1197	if (ret) {
1198		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1199			   "Setting DRM property blob failed with errno %d\n",
1200			   ret);
1201		if (free_blob_data)
1202			free(blob_data);
1203		return BadRequest;
1204	}
1205
1206	if (free_blob_data)
1207		free(blob_data);
1208
1209	return Success;
1210}
1211
1212static void
1213drmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
1214			  uint16_t *blue, int size)
1215{
1216	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1217	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
1218	int ret;
1219
1220	/* Use legacy if no support for non-legacy gamma */
1221	if (!drmmode_cm_enabled(drmmode_crtc->drmmode)) {
1222		drmModeCrtcSetGamma(pAMDGPUEnt->fd,
1223				    drmmode_crtc->mode_crtc->crtc_id,
1224				    size, red, green, blue);
1225		return;
1226	}
1227
1228	ret = drmmode_crtc_push_cm_prop(crtc, CM_GAMMA_LUT);
1229	if (ret)
1230		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1231			   "Setting Gamma LUT failed with errno %d\n",
1232			   ret);
1233}
1234
1235Bool
1236drmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode,
1237		 int x, int y)
1238{
1239	ScrnInfoPtr scrn = crtc->scrn;
1240	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
1241	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1242	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1243	uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
1244	int output_count = 0;
1245	drmModeModeInfo kmode;
1246	Bool ret;
1247	int i;
1248
1249	if (!output_ids)
1250		return FALSE;
1251
1252	for (i = 0; i < xf86_config->num_output; i++) {
1253		xf86OutputPtr output = xf86_config->output[i];
1254		drmmode_output_private_ptr drmmode_output = output->driver_private;
1255
1256		if (output->crtc != crtc)
1257			continue;
1258
1259		output_ids[output_count] = drmmode_output->mode_output->connector_id;
1260		output_count++;
1261	}
1262
1263	drmmode_ConvertToKMode(scrn, &kmode, mode);
1264
1265	ret = drmModeSetCrtc(pAMDGPUEnt->fd,
1266			     drmmode_crtc->mode_crtc->crtc_id,
1267			     fb->handle, x, y, output_ids,
1268			     output_count, &kmode) == 0;
1269
1270	if (ret) {
1271		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb);
1272	} else {
1273		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1274			   "failed to set mode: %s\n", strerror(errno));
1275	}
1276
1277	free(output_ids);
1278	return ret;
1279}
1280
1281static Bool
1282drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
1283		       Rotation rotation, int x, int y)
1284{
1285	ScrnInfoPtr pScrn = crtc->scrn;
1286	ScreenPtr pScreen = pScrn->pScreen;
1287	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1288	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1289	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1290	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1291	unsigned scanout_id = 0;
1292	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1293	int saved_x, saved_y;
1294	Rotation saved_rotation;
1295	DisplayModeRec saved_mode;
1296	Bool ret = FALSE;
1297	int i;
1298	struct drmmode_fb *fb = NULL;
1299
1300	/* The root window contents may be undefined before the WindowExposures
1301	 * hook is called for it, so bail if we get here before that
1302	 */
1303	if (pScreen->WindowExposures == AMDGPUWindowExposures_oneshot)
1304		return FALSE;
1305
1306	saved_mode = crtc->mode;
1307	saved_x = crtc->x;
1308	saved_y = crtc->y;
1309	saved_rotation = crtc->rotation;
1310
1311	if (mode) {
1312		crtc->mode = *mode;
1313		crtc->x = x;
1314		crtc->y = y;
1315		crtc->rotation = rotation;
1316
1317		if (!drmmode_handle_transform(crtc))
1318			goto done;
1319
1320		drmmode_crtc_update_tear_free(crtc);
1321		if (drmmode_crtc->tear_free)
1322			scanout_id = drmmode_crtc->scanout_id;
1323		else
1324			drmmode_crtc->scanout_id = 0;
1325
1326		if (drmmode_crtc->prime_scanout_pixmap) {
1327			drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id,
1328							  &fb, &x, &y);
1329		} else if (drmmode_crtc->rotate.pixmap) {
1330			fb = amdgpu_pixmap_get_fb(drmmode_crtc->rotate.pixmap);
1331			x = y = 0;
1332
1333		} else if (!pScreen->isGPU &&
1334			   (drmmode_crtc->tear_free ||
1335			    crtc->driverIsPerformingTransform ||
1336			    info->shadow_primary)) {
1337			drmmode_crtc_scanout_update(crtc, mode, scanout_id,
1338						    &fb, &x, &y);
1339		}
1340
1341		if (!fb)
1342			fb = amdgpu_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root));
1343		if (!fb) {
1344			union gbm_bo_handle bo_handle;
1345
1346			bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm);
1347			fb = amdgpu_fb_create(pScrn, pAMDGPUEnt->fd,
1348					      pScrn->virtualX, pScrn->virtualY,
1349					      pScrn->displayWidth * info->pixel_bytes,
1350					      bo_handle.u32);
1351			/* Prevent refcnt of ad-hoc FBs from reaching 2 */
1352			drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL);
1353			drmmode_crtc->fb = fb;
1354		}
1355		if (!fb) {
1356			ErrorF("failed to add FB for modeset\n");
1357			goto done;
1358		}
1359
1360		amdgpu_drm_wait_pending_flip(crtc);
1361
1362		if (!drmmode_set_mode(crtc, fb, mode, x, y))
1363			goto done;
1364
1365		ret = TRUE;
1366
1367		if (pScreen)
1368			xf86CrtcSetScreenSubpixelOrder(pScreen);
1369
1370		drmmode_crtc->need_modeset = FALSE;
1371
1372		/* go through all the outputs and force DPMS them back on? */
1373		for (i = 0; i < xf86_config->num_output; i++) {
1374			xf86OutputPtr output = xf86_config->output[i];
1375
1376			if (output->crtc != crtc)
1377				continue;
1378
1379			output->funcs->dpms(output, DPMSModeOn);
1380		}
1381	}
1382
1383	/* Compute index of this CRTC into xf86_config->crtc */
1384	for (i = 0; i < xf86_config->num_crtc; i++) {
1385		if (xf86_config->crtc[i] != crtc)
1386			continue;
1387
1388		if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc))
1389			info->hwcursor_disabled &= ~(1 << i);
1390		else
1391			info->hwcursor_disabled |= 1 << i;
1392
1393		break;
1394	}
1395
1396#ifndef HAVE_XF86_CURSOR_RESET_CURSOR
1397	if (!info->hwcursor_disabled)
1398		xf86_reload_cursors(pScreen);
1399#endif
1400
1401done:
1402	if (!ret) {
1403		crtc->x = saved_x;
1404		crtc->y = saved_y;
1405		crtc->rotation = saved_rotation;
1406		crtc->mode = saved_mode;
1407	} else {
1408		crtc->active = TRUE;
1409
1410		if (drmmode_crtc->scanout[scanout_id].pixmap &&
1411		    fb != amdgpu_pixmap_get_fb(drmmode_crtc->
1412					       scanout[scanout_id].pixmap)) {
1413			amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending);
1414			drmmode_crtc->scanout_update_pending = 0;
1415			drmmode_crtc_scanout_free(drmmode_crtc);
1416		} else if (!drmmode_crtc->tear_free) {
1417			drmmode_crtc_scanout_destroy(drmmode,
1418						     &drmmode_crtc->scanout[1]);
1419		}
1420	}
1421
1422	amdgpu_drm_queue_handle_deferred(crtc);
1423	return ret;
1424}
1425
1426static void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
1427{
1428
1429}
1430
1431static void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
1432{
1433	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1434	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
1435
1436#if XF86_CRTC_VERSION < 7
1437	if (crtc->driverIsPerformingTransform) {
1438		x += crtc->x;
1439		y += crtc->y;
1440		xf86CrtcTransformCursorPos(crtc, &x, &y);
1441	}
1442#endif
1443
1444	drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
1445}
1446
1447#if XF86_CRTC_VERSION < 7
1448
1449static int
1450drmmode_cursor_src_offset(Rotation rotation, int width, int height,
1451			  int x_dst, int y_dst)
1452{
1453	int t;
1454
1455	switch (rotation & 0xf) {
1456	case RR_Rotate_90:
1457		t = x_dst;
1458		x_dst = height - y_dst - 1;
1459		y_dst = t;
1460		break;
1461	case RR_Rotate_180:
1462		x_dst = width - x_dst - 1;
1463		y_dst = height - y_dst - 1;
1464		break;
1465	case RR_Rotate_270:
1466		t = x_dst;
1467		x_dst = y_dst;
1468		y_dst = width - t - 1;
1469		break;
1470	}
1471
1472	if (rotation & RR_Reflect_X)
1473		x_dst = width - x_dst - 1;
1474	if (rotation & RR_Reflect_Y)
1475		y_dst = height - y_dst - 1;
1476
1477	return y_dst * height + x_dst;
1478}
1479
1480#endif
1481
1482static uint32_t
1483drmmode_cursor_gamma_passthrough(xf86CrtcPtr crtc, uint32_t argb)
1484{
1485	uint32_t alpha = argb >> 24;
1486
1487	if (!alpha)
1488		return 0;
1489
1490	return argb;
1491}
1492
1493static uint32_t
1494drmmode_cursor_gamma(xf86CrtcPtr crtc, uint32_t argb)
1495{
1496	uint32_t alpha = argb >> 24;
1497	uint32_t rgb[3];
1498	int i;
1499
1500	if (!alpha)
1501		return 0;
1502
1503	/* Un-premultiply alpha */
1504	for (i = 0; i < 3; i++)
1505		rgb[i] = ((argb >> (i * 8)) & 0xff) * 0xff / alpha;
1506
1507	/* Apply gamma correction and pre-multiply alpha */
1508	rgb[0] = (crtc->gamma_blue[rgb[0]] >> 8) * alpha / 0xff;
1509	rgb[1] = (crtc->gamma_green[rgb[1]] >> 8) * alpha / 0xff;
1510	rgb[2] = (crtc->gamma_red[rgb[2]] >> 8) * alpha / 0xff;
1511
1512	return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
1513}
1514
1515static void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_t *ptr)
1516{
1517	ScrnInfoPtr pScrn = crtc->scrn;
1518	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1519	uint32_t (*cursor_gamma)(xf86CrtcPtr crtc, uint32_t argb) =
1520		drmmode_cursor_gamma;
1521
1522	if ((crtc->scrn->depth != 24 && crtc->scrn->depth != 32) ||
1523	    drmmode_cm_enabled(&info->drmmode))
1524		cursor_gamma = drmmode_cursor_gamma_passthrough;
1525
1526#if XF86_CRTC_VERSION < 7
1527	if (crtc->driverIsPerformingTransform) {
1528		uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
1529		int dstx, dsty;
1530		int srcoffset;
1531
1532		for (dsty = 0; dsty < cursor_h; dsty++) {
1533			for (dstx = 0; dstx < cursor_w; dstx++) {
1534				srcoffset = drmmode_cursor_src_offset(crtc->rotation,
1535								      cursor_w,
1536								      cursor_h,
1537								      dstx, dsty);
1538
1539				ptr[dsty * info->cursor_w + dstx] =
1540					cpu_to_le32(cursor_gamma(crtc, image[srcoffset]));
1541			}
1542		}
1543	} else
1544#endif
1545	{
1546		uint32_t cursor_size = info->cursor_w * info->cursor_h;
1547		int i;
1548
1549		for (i = 0; i < cursor_size; i++)
1550			ptr[i] = cpu_to_le32(cursor_gamma(crtc, image[i]));
1551	}
1552}
1553
1554static void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image)
1555{
1556	ScrnInfoPtr pScrn = crtc->scrn;
1557	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1558	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1559	uint32_t cursor_size = info->cursor_w * info->cursor_h;
1560
1561	if (info->gbm) {
1562		uint32_t ptr[cursor_size];
1563
1564		drmmode_do_load_cursor_argb(crtc, image, ptr);
1565		gbm_bo_write(drmmode_crtc->cursor_buffer->bo.gbm, ptr, cursor_size * 4);
1566	} else {
1567		/* cursor should be mapped already */
1568		uint32_t *ptr = (uint32_t *) (drmmode_crtc->cursor_buffer->cpu_ptr);
1569
1570		drmmode_do_load_cursor_argb(crtc, image, ptr);
1571	}
1572}
1573
1574#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
1575
1576static Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
1577{
1578	if (!drmmode_can_use_hw_cursor(crtc))
1579		return FALSE;
1580
1581	drmmode_load_cursor_argb(crtc, image);
1582	return TRUE;
1583}
1584
1585#endif
1586
1587static void drmmode_hide_cursor(xf86CrtcPtr crtc)
1588{
1589	ScrnInfoPtr pScrn = crtc->scrn;
1590	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1591	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1592	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1593
1594	drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
1595			 info->cursor_w, info->cursor_h);
1596
1597}
1598
1599static void drmmode_show_cursor(xf86CrtcPtr crtc)
1600{
1601	ScrnInfoPtr pScrn = crtc->scrn;
1602	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1603	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1604	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1605	uint32_t bo_handle;
1606	static Bool use_set_cursor2 = TRUE;
1607
1608	if (!amdgpu_bo_get_handle(drmmode_crtc->cursor_buffer, &bo_handle)) {
1609		ErrorF("failed to get BO handle for cursor\n");
1610		return;
1611	}
1612
1613	if (use_set_cursor2) {
1614		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1615		CursorPtr cursor = xf86_config->cursor;
1616		int xhot = cursor->bits->xhot;
1617		int yhot = cursor->bits->yhot;
1618		int ret;
1619
1620		if (crtc->rotation != RR_Rotate_0 &&
1621		    crtc->rotation != (RR_Rotate_180 | RR_Reflect_X |
1622				       RR_Reflect_Y)) {
1623			int t;
1624
1625			/* Reflect & rotate hotspot position */
1626			if (crtc->rotation & RR_Reflect_X)
1627				xhot = info->cursor_w - xhot - 1;
1628			if (crtc->rotation & RR_Reflect_Y)
1629				yhot = info->cursor_h - yhot - 1;
1630
1631			switch (crtc->rotation & 0xf) {
1632			case RR_Rotate_90:
1633				t = xhot;
1634				xhot = yhot;
1635				yhot = info->cursor_w - t - 1;
1636				break;
1637			case RR_Rotate_180:
1638				xhot = info->cursor_w - xhot - 1;
1639				yhot = info->cursor_h - yhot - 1;
1640				break;
1641			case RR_Rotate_270:
1642				t = xhot;
1643				xhot = info->cursor_h - yhot - 1;
1644				yhot = t;
1645			}
1646		}
1647
1648		ret = drmModeSetCursor2(pAMDGPUEnt->fd,
1649					drmmode_crtc->mode_crtc->crtc_id,
1650					bo_handle,
1651					info->cursor_w, info->cursor_h,
1652					xhot, yhot);
1653		if (ret == -EINVAL)
1654			use_set_cursor2 = FALSE;
1655		else
1656			return;
1657	}
1658
1659	drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, bo_handle,
1660			 info->cursor_w, info->cursor_h);
1661}
1662
1663/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and
1664 * passes that back to drmmode_crtc_scanout_create; it doesn't use it for
1665 * anything else.
1666 */
1667static void *
1668drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
1669{
1670	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1671
1672	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
1673					 height))
1674		return NULL;
1675
1676	return (void*)~0UL;
1677}
1678
1679static PixmapPtr
1680drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1681{
1682	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1683
1684	if (!data) {
1685		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
1686					    height);
1687	}
1688
1689	return drmmode_crtc->rotate.pixmap;
1690}
1691
1692static void
1693drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap,
1694			    void *data)
1695{
1696	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1697	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1698
1699	drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate);
1700}
1701
1702static void
1703drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
1704		       uint16_t * blue, int size)
1705{
1706	ScrnInfoPtr scrn = crtc->scrn;
1707	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1708	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
1709	int i;
1710
1711	drmmode_crtc_gamma_do_set(crtc, red, green, blue, size);
1712
1713	/* Compute index of this CRTC into xf86_config->crtc */
1714	for (i = 0; xf86_config->crtc[i] != crtc; i++) {}
1715
1716	if (info->hwcursor_disabled & (1 << i))
1717		return;
1718
1719#ifdef HAVE_XF86_CURSOR_RESET_CURSOR
1720	xf86CursorResetCursor(scrn->pScreen);
1721#else
1722	xf86_reload_cursors(scrn->pScreen);
1723#endif
1724}
1725
1726static Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
1727{
1728	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1729	unsigned scanout_id = drmmode_crtc->scanout_id;
1730	ScreenPtr screen = crtc->scrn->pScreen;
1731	PixmapDirtyUpdatePtr dirty;
1732
1733	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
1734		if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
1735			PixmapStopDirtyTracking(dirty->src, dirty->slave_dst);
1736			break;
1737		}
1738	}
1739
1740	drmmode_crtc_scanout_free(drmmode_crtc);
1741	drmmode_crtc->prime_scanout_pixmap = NULL;
1742
1743	if (!ppix)
1744		return TRUE;
1745
1746	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0],
1747					 ppix->drawable.width,
1748					 ppix->drawable.height))
1749		return FALSE;
1750
1751	if (drmmode_crtc->tear_free &&
1752	    !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
1753					 ppix->drawable.width,
1754					 ppix->drawable.height)) {
1755		drmmode_crtc_scanout_free(drmmode_crtc);
1756		return FALSE;
1757	}
1758
1759	drmmode_crtc->prime_scanout_pixmap = ppix;
1760
1761#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC
1762	PixmapStartDirtyTracking(&ppix->drawable,
1763				 drmmode_crtc->scanout[scanout_id].pixmap,
1764				 0, 0, 0, 0, RR_Rotate_0);
1765#elif defined(HAS_DIRTYTRACKING_ROTATION)
1766	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
1767				 0, 0, 0, 0, RR_Rotate_0);
1768#elif defined(HAS_DIRTYTRACKING2)
1769	PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
1770				  0, 0, 0, 0);
1771#else
1772	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0);
1773#endif
1774	return TRUE;
1775}
1776
1777static void drmmode_crtc_destroy(xf86CrtcPtr crtc)
1778{
1779	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1780
1781	drmModeFreeCrtc(drmmode_crtc->mode_crtc);
1782
1783	/* Free LUTs and CTM */
1784	free(drmmode_crtc->gamma_lut);
1785	free(drmmode_crtc->degamma_lut);
1786	free(drmmode_crtc->ctm);
1787
1788	free(drmmode_crtc);
1789	crtc->driver_private = NULL;
1790}
1791
1792
1793static xf86CrtcFuncsRec drmmode_crtc_funcs = {
1794	.dpms = drmmode_crtc_dpms,
1795	.set_mode_major = drmmode_set_mode_major,
1796	.set_cursor_colors = drmmode_set_cursor_colors,
1797	.set_cursor_position = drmmode_set_cursor_position,
1798	.show_cursor = drmmode_show_cursor,
1799	.hide_cursor = drmmode_hide_cursor,
1800	.load_cursor_argb = drmmode_load_cursor_argb,
1801#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
1802	.load_cursor_argb_check = drmmode_load_cursor_argb_check,
1803#endif
1804
1805	.gamma_set = drmmode_crtc_gamma_set,
1806	.shadow_create = drmmode_crtc_shadow_create,
1807	.shadow_allocate = drmmode_crtc_shadow_allocate,
1808	.shadow_destroy = drmmode_crtc_shadow_destroy,
1809	.destroy = drmmode_crtc_destroy,
1810	.set_scanout_pixmap = drmmode_set_scanout_pixmap,
1811};
1812
1813int drmmode_get_crtc_id(xf86CrtcPtr crtc)
1814{
1815	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1816	return drmmode_crtc->hw_id;
1817}
1818
1819void drmmode_crtc_hw_id(xf86CrtcPtr crtc)
1820{
1821	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1822	ScrnInfoPtr pScrn = crtc->scrn;
1823	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1824	int r;
1825
1826	r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev,
1827				      drmmode_crtc->mode_crtc->crtc_id,
1828				      &drmmode_crtc->hw_id);
1829	if (r)
1830		drmmode_crtc->hw_id = -1;
1831}
1832
1833/**
1834 * Initialize color management properties for the given CRTC by programming
1835 * the default gamma/degamma LUTs and CTM.
1836 *
1837 * If the CRTC does not support color management, or if errors occur during
1838 * initialization, all color properties on the driver-private CRTC will left
1839 * as NULL.
1840 *
1841 * @drm_fd: DRM file descriptor
1842 * @crtc: CRTC to initialize color management on.
1843 */
1844static void drmmode_crtc_cm_init(int drm_fd, xf86CrtcPtr crtc)
1845{
1846	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1847	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1848	int i;
1849
1850	if (!drmmode_cm_enabled(drmmode))
1851		return;
1852
1853	/* Init CTM to identity. Values are in S31.32 fixed-point format */
1854	drmmode_crtc->ctm = calloc(1, sizeof(*drmmode_crtc->ctm));
1855	if (!drmmode_crtc->ctm) {
1856		xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1857			   "Memory error initializing CTM for CRTC%d",
1858			   drmmode_get_crtc_id(crtc));
1859		return;
1860	}
1861
1862	drmmode_crtc->ctm->matrix[0] = drmmode_crtc->ctm->matrix[4] =
1863		drmmode_crtc->ctm->matrix[8] = (uint64_t)1 << 32;
1864
1865	/* Push properties to reset properties currently in hardware */
1866	for (i = 0; i < CM_GAMMA_LUT; i++) {
1867		if (drmmode_crtc_push_cm_prop(crtc, i))
1868			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1869				   "Failed to initialize color management "
1870				   "property %s on CRTC%d. Property value may "
1871				   "not reflect actual hardware state.\n",
1872				   cm_prop_names[i],
1873				   drmmode_get_crtc_id(crtc));
1874	}
1875}
1876
1877static unsigned int
1878drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
1879{
1880	xf86CrtcPtr crtc;
1881	drmmode_crtc_private_ptr drmmode_crtc;
1882	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1883	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1884
1885	crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs);
1886	if (!crtc)
1887		return 0;
1888
1889	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
1890	drmmode_crtc->mode_crtc =
1891	    drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]);
1892	drmmode_crtc->drmmode = drmmode;
1893	drmmode_crtc->dpms_mode = DPMSModeOff;
1894	crtc->driver_private = drmmode_crtc;
1895	drmmode_crtc_hw_id(crtc);
1896
1897	drmmode_crtc_cm_init(pAMDGPUEnt->fd, crtc);
1898
1899	/* Mark num'th crtc as in use on this device. */
1900	pAMDGPUEnt->assigned_crtcs |= (1 << num);
1901	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1902		       "Allocated crtc nr. %d to this screen.\n", num);
1903
1904	return 1;
1905}
1906
1907/*
1908 * Update all of the property values for an output
1909 */
1910static void
1911drmmode_output_update_properties(xf86OutputPtr output)
1912{
1913	drmmode_output_private_ptr drmmode_output = output->driver_private;
1914	int i, j, k;
1915	int err;
1916	drmModeConnectorPtr koutput;
1917
1918	/* Use the most recently fetched values from the kernel */
1919	koutput = drmmode_output->mode_output;
1920
1921	if (!koutput)
1922		return;
1923
1924	for (i = 0; i < drmmode_output->num_props; i++) {
1925		drmmode_prop_ptr p = &drmmode_output->props[i];
1926
1927		for (j = 0; j < koutput->count_props; j++) {
1928			if (koutput->props[j] != p->mode_prop->prop_id)
1929				continue;
1930
1931			/* Check to see if the property value has changed */
1932			if (koutput->prop_values[j] == p->value)
1933				break;
1934
1935			p->value = koutput->prop_values[j];
1936
1937			if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1938				INT32 value = p->value;
1939
1940				err = RRChangeOutputProperty(output->randr_output,
1941							     p->atoms[0], XA_INTEGER,
1942							     32, PropModeReplace, 1,
1943							     &value, FALSE, TRUE);
1944				if (err != 0) {
1945					xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1946						   "RRChangeOutputProperty error, %d\n",
1947						   err);
1948				}
1949			} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1950				for (k = 0; k < p->mode_prop->count_enums; k++) {
1951					if (p->mode_prop->enums[k].value == p->value)
1952						break;
1953				}
1954				if (k < p->mode_prop->count_enums) {
1955					err = RRChangeOutputProperty(output->randr_output,
1956								     p->atoms[0], XA_ATOM,
1957								     32, PropModeReplace, 1,
1958								     &p->atoms[k + 1], FALSE,
1959								     TRUE);
1960					if (err != 0) {
1961						xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1962							   "RRChangeOutputProperty error, %d\n",
1963							   err);
1964					}
1965				}
1966			}
1967
1968			break;
1969		}
1970        }
1971}
1972
1973static xf86OutputStatus drmmode_output_detect(xf86OutputPtr output)
1974{
1975	/* go to the hw and retrieve a new output struct */
1976	drmmode_output_private_ptr drmmode_output = output->driver_private;
1977	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1978	xf86OutputStatus status;
1979	drmModeFreeConnector(drmmode_output->mode_output);
1980
1981	drmmode_output->mode_output =
1982	    drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id);
1983	if (!drmmode_output->mode_output) {
1984		drmmode_output->output_id = -1;
1985		return XF86OutputStatusDisconnected;
1986	}
1987
1988	drmmode_output_update_properties(output);
1989
1990	switch (drmmode_output->mode_output->connection) {
1991	case DRM_MODE_CONNECTED:
1992		status = XF86OutputStatusConnected;
1993		break;
1994	case DRM_MODE_DISCONNECTED:
1995		status = XF86OutputStatusDisconnected;
1996		break;
1997	default:
1998	case DRM_MODE_UNKNOWNCONNECTION:
1999		status = XF86OutputStatusUnknown;
2000		break;
2001	}
2002	return status;
2003}
2004
2005static Bool
2006drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
2007{
2008	return MODE_OK;
2009}
2010
2011static int
2012koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
2013        int type, const char *name)
2014{
2015    int idx = -1;
2016
2017    for (int i = 0; i < koutput->count_props; i++) {
2018        drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
2019
2020        if (!prop)
2021            continue;
2022
2023        if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
2024            idx = i;
2025
2026        drmModeFreeProperty(prop);
2027
2028        if (idx > -1)
2029            break;
2030    }
2031
2032    return idx;
2033}
2034
2035static int
2036koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
2037        int type, const char *name)
2038{
2039    int idx = koutput_get_prop_idx(fd, koutput, type, name);
2040
2041    return (idx > -1) ? koutput->props[idx] : -1;
2042}
2043
2044static drmModePropertyBlobPtr
2045koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
2046{
2047    drmModePropertyBlobPtr blob = NULL;
2048    int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
2049
2050    if (idx > -1)
2051        blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
2052
2053    return blob;
2054}
2055
2056static DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output)
2057{
2058	drmmode_output_private_ptr drmmode_output = output->driver_private;
2059	drmModeConnectorPtr koutput = drmmode_output->mode_output;
2060	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
2061	int i;
2062	DisplayModePtr Modes = NULL, Mode;
2063	xf86MonPtr mon = NULL;
2064
2065	if (!koutput)
2066		return NULL;
2067
2068	drmModeFreePropertyBlob(drmmode_output->edid_blob);
2069
2070	/* look for an EDID property */
2071	drmmode_output->edid_blob =
2072		koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "EDID");
2073
2074	if (drmmode_output->edid_blob) {
2075		mon = xf86InterpretEDID(output->scrn->scrnIndex,
2076					drmmode_output->edid_blob->data);
2077		if (mon && drmmode_output->edid_blob->length > 128)
2078			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
2079	}
2080	xf86OutputSetEDID(output, mon);
2081
2082	/* modes should already be available */
2083	for (i = 0; i < koutput->count_modes; i++) {
2084		Mode = xnfalloc(sizeof(DisplayModeRec));
2085
2086		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i],
2087					 Mode);
2088		Modes = xf86ModesAdd(Modes, Mode);
2089
2090	}
2091	return Modes;
2092}
2093
2094static void drmmode_output_destroy(xf86OutputPtr output)
2095{
2096	drmmode_output_private_ptr drmmode_output = output->driver_private;
2097	int i;
2098
2099	if (drmmode_output->edid_blob)
2100		drmModeFreePropertyBlob(drmmode_output->edid_blob);
2101	for (i = 0; i < drmmode_output->num_props; i++) {
2102		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
2103		free(drmmode_output->props[i].atoms);
2104	}
2105	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
2106		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
2107	}
2108	free(drmmode_output->mode_encoders);
2109	free(drmmode_output->props);
2110	drmModeFreeConnector(drmmode_output->mode_output);
2111	free(drmmode_output);
2112	output->driver_private = NULL;
2113}
2114
2115static void drmmode_output_dpms(xf86OutputPtr output, int mode)
2116{
2117	drmmode_output_private_ptr drmmode_output = output->driver_private;
2118	xf86CrtcPtr crtc = output->crtc;
2119	drmModeConnectorPtr koutput = drmmode_output->mode_output;
2120	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
2121
2122	if (!koutput)
2123		return;
2124
2125	if (mode != DPMSModeOn && crtc)
2126		drmmode_do_crtc_dpms(crtc, mode);
2127
2128	drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id,
2129				    drmmode_output->dpms_enum_id, mode);
2130
2131	if (mode == DPMSModeOn && crtc) {
2132		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2133
2134		if (drmmode_crtc->need_modeset)
2135			drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
2136					       crtc->x, crtc->y);
2137		else
2138			drmmode_do_crtc_dpms(output->crtc, mode);
2139	}
2140}
2141
2142static Bool drmmode_property_ignore(drmModePropertyPtr prop)
2143{
2144	if (!prop)
2145		return TRUE;
2146	/* ignore blob prop */
2147	if (prop->flags & DRM_MODE_PROP_BLOB)
2148		return TRUE;
2149	/* ignore standard property */
2150	if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS"))
2151		return TRUE;
2152
2153	return FALSE;
2154}
2155
2156static void drmmode_output_create_resources(xf86OutputPtr output)
2157{
2158	AMDGPUInfoPtr info = AMDGPUPTR(output->scrn);
2159	drmmode_output_private_ptr drmmode_output = output->driver_private;
2160	drmmode_crtc_private_ptr drmmode_crtc;
2161	drmModeConnectorPtr mode_output = drmmode_output->mode_output;
2162	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
2163	drmModePropertyPtr drmmode_prop, tearfree_prop;
2164	int i, j, err;
2165	Atom name;
2166
2167	/* Create CONNECTOR_ID property */
2168	name = MakeAtom("CONNECTOR_ID", 12, TRUE);
2169	if (name != BAD_RESOURCE) {
2170		INT32 value = mode_output->connector_id;
2171
2172		err = RRConfigureOutputProperty(output->randr_output, name,
2173						FALSE, FALSE, TRUE, 1, &value);
2174		if (err != Success) {
2175			xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2176				   "RRConfigureOutputProperty error, %d\n", err);
2177		}
2178
2179		err = RRChangeOutputProperty(output->randr_output, name,
2180					     XA_INTEGER, 32, PropModeReplace, 1,
2181					     &value, FALSE, FALSE);
2182		if (err != Success) {
2183			xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2184				   "RRChangeOutputProperty error, %d\n", err);
2185		}
2186	}
2187
2188	drmmode_output->props =
2189		calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec));
2190	if (!drmmode_output->props)
2191		return;
2192
2193	drmmode_output->num_props = 0;
2194	for (i = 0, j = 0; i < mode_output->count_props; i++) {
2195		drmmode_prop =
2196		    drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]);
2197		if (drmmode_property_ignore(drmmode_prop)) {
2198			drmModeFreeProperty(drmmode_prop);
2199			continue;
2200		}
2201		drmmode_output->props[j].mode_prop = drmmode_prop;
2202		drmmode_output->props[j].value = mode_output->prop_values[i];
2203		drmmode_output->num_props++;
2204		j++;
2205	}
2206
2207	/* Userspace-only property for TearFree */
2208	tearfree_prop = calloc(1, sizeof(*tearfree_prop));
2209	tearfree_prop->flags = DRM_MODE_PROP_ENUM;
2210	strcpy(tearfree_prop->name, "TearFree");
2211	tearfree_prop->count_enums = 3;
2212	tearfree_prop->enums = calloc(tearfree_prop->count_enums,
2213				      sizeof(*tearfree_prop->enums));
2214	strcpy(tearfree_prop->enums[0].name, "off");
2215	strcpy(tearfree_prop->enums[1].name, "on");
2216	tearfree_prop->enums[1].value = 1;
2217	strcpy(tearfree_prop->enums[2].name, "auto");
2218	tearfree_prop->enums[2].value = 2;
2219	drmmode_output->props[j].mode_prop = tearfree_prop;
2220	drmmode_output->props[j].value = info->tear_free;
2221	drmmode_output->tear_free = info->tear_free;
2222	drmmode_output->num_props++;
2223
2224	for (i = 0; i < drmmode_output->num_props; i++) {
2225		drmmode_prop_ptr p = &drmmode_output->props[i];
2226		drmmode_prop = p->mode_prop;
2227
2228		if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
2229			INT32 range[2];
2230			INT32 value = p->value;
2231
2232			p->num_atoms = 1;
2233			p->atoms = calloc(p->num_atoms, sizeof(Atom));
2234			if (!p->atoms)
2235				continue;
2236			p->atoms[0] =
2237			    MakeAtom(drmmode_prop->name,
2238				     strlen(drmmode_prop->name), TRUE);
2239			range[0] = drmmode_prop->values[0];
2240			range[1] = drmmode_prop->values[1];
2241			err =
2242			    RRConfigureOutputProperty(output->randr_output,
2243						      p->atoms[0], FALSE, TRUE,
2244						      drmmode_prop->flags &
2245						      DRM_MODE_PROP_IMMUTABLE ?
2246						      TRUE : FALSE, 2, range);
2247			if (err != 0) {
2248				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2249					   "RRConfigureOutputProperty error, %d\n",
2250					   err);
2251			}
2252			err =
2253			    RRChangeOutputProperty(output->randr_output,
2254						   p->atoms[0], XA_INTEGER, 32,
2255						   PropModeReplace, 1, &value,
2256						   FALSE, TRUE);
2257			if (err != 0) {
2258				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2259					   "RRChangeOutputProperty error, %d\n",
2260					   err);
2261			}
2262		} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
2263			p->num_atoms = drmmode_prop->count_enums + 1;
2264			p->atoms = calloc(p->num_atoms, sizeof(Atom));
2265			if (!p->atoms)
2266				continue;
2267			p->atoms[0] =
2268			    MakeAtom(drmmode_prop->name,
2269				     strlen(drmmode_prop->name), TRUE);
2270			for (j = 1; j <= drmmode_prop->count_enums; j++) {
2271				struct drm_mode_property_enum *e =
2272				    &drmmode_prop->enums[j - 1];
2273				p->atoms[j] =
2274				    MakeAtom(e->name, strlen(e->name), TRUE);
2275			}
2276			err =
2277			    RRConfigureOutputProperty(output->randr_output,
2278						      p->atoms[0], FALSE, FALSE,
2279						      drmmode_prop->flags &
2280						      DRM_MODE_PROP_IMMUTABLE ?
2281						      TRUE : FALSE,
2282						      p->num_atoms - 1,
2283						      (INT32 *) & p->atoms[1]);
2284			if (err != 0) {
2285				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2286					   "RRConfigureOutputProperty error, %d\n",
2287					   err);
2288			}
2289			for (j = 0; j < drmmode_prop->count_enums; j++)
2290				if (drmmode_prop->enums[j].value == p->value)
2291					break;
2292			/* there's always a matching value */
2293			err =
2294			    RRChangeOutputProperty(output->randr_output,
2295						   p->atoms[0], XA_ATOM, 32,
2296						   PropModeReplace, 1,
2297						   &p->atoms[j + 1], FALSE,
2298						   TRUE);
2299			if (err != 0) {
2300				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2301					   "RRChangeOutputProperty error, %d\n",
2302					   err);
2303			}
2304		}
2305	}
2306
2307	/* Do not configure cm properties on output if there's no support. */
2308	if (!drmmode_cm_enabled(drmmode_output->drmmode))
2309		return;
2310
2311	drmmode_crtc = output->crtc ? output->crtc->driver_private : NULL;
2312
2313	for (i = 0; i < CM_NUM_PROPS; i++)
2314		rr_configure_and_change_cm_property(output, drmmode_crtc, i);
2315}
2316
2317static void
2318drmmode_output_set_tear_free(AMDGPUEntPtr pAMDGPUEnt,
2319			     drmmode_output_private_ptr drmmode_output,
2320			     xf86CrtcPtr crtc, int tear_free)
2321{
2322	if (drmmode_output->tear_free == tear_free)
2323		return;
2324
2325	drmmode_output->tear_free = tear_free;
2326
2327	if (crtc) {
2328		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
2329				       crtc->x, crtc->y);
2330	}
2331}
2332
2333static Bool
2334drmmode_output_set_property(xf86OutputPtr output, Atom property,
2335			    RRPropertyValuePtr value)
2336{
2337	drmmode_output_private_ptr drmmode_output = output->driver_private;
2338	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
2339	enum drmmode_cm_prop cm_prop_index;
2340	int i;
2341
2342	cm_prop_index = get_cm_enum_from_str(NameForAtom(property));
2343	if (cm_prop_index >= 0 && cm_prop_index < CM_DEGAMMA_LUT_SIZE) {
2344		if (!output->crtc)
2345			return FALSE;
2346		if (drmmode_crtc_stage_cm_prop(output->crtc, cm_prop_index,
2347					       value))
2348			return FALSE;
2349		if (drmmode_crtc_push_cm_prop(output->crtc, cm_prop_index))
2350			return FALSE;
2351		return TRUE;
2352	}
2353
2354	for (i = 0; i < drmmode_output->num_props; i++) {
2355		drmmode_prop_ptr p = &drmmode_output->props[i];
2356
2357		if (p->atoms[0] != property)
2358			continue;
2359
2360		if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
2361			uint32_t val;
2362
2363			if (value->type != XA_INTEGER || value->format != 32 ||
2364			    value->size != 1)
2365				return FALSE;
2366			val = *(uint32_t *) value->data;
2367
2368			drmModeConnectorSetProperty(pAMDGPUEnt->fd,
2369						    drmmode_output->output_id,
2370						    p->mode_prop->prop_id,
2371						    (uint64_t) val);
2372			return TRUE;
2373		} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
2374			Atom atom;
2375			const char *name;
2376			int j;
2377
2378			if (value->type != XA_ATOM || value->format != 32
2379			    || value->size != 1)
2380				return FALSE;
2381			memcpy(&atom, value->data, 4);
2382			if (!(name = NameForAtom(atom)))
2383				return FALSE;
2384
2385			/* search for matching name string, then set its value down */
2386			for (j = 0; j < p->mode_prop->count_enums; j++) {
2387				if (!strcmp(p->mode_prop->enums[j].name, name)) {
2388					if (i == (drmmode_output->num_props - 1)) {
2389						drmmode_output_set_tear_free(pAMDGPUEnt,
2390									     drmmode_output,
2391									     output->crtc, j);
2392					} else {
2393						drmModeConnectorSetProperty(pAMDGPUEnt->fd,
2394									    drmmode_output->output_id,
2395									    p->mode_prop->prop_id,
2396									    p->mode_prop->enums[j].value);
2397					}
2398
2399					return TRUE;
2400				}
2401			}
2402		}
2403	}
2404
2405	return TRUE;
2406}
2407
2408static Bool drmmode_output_get_property(xf86OutputPtr output, Atom property)
2409{
2410	drmmode_crtc_private_ptr drmmode_crtc;
2411	enum drmmode_cm_prop cm_prop_id;
2412	int ret;
2413
2414	/* First, see if it's a cm property */
2415	cm_prop_id = get_cm_enum_from_str(NameForAtom(property));
2416	if (output->crtc && cm_prop_id != CM_INVALID_PROP) {
2417		drmmode_crtc = output->crtc->driver_private;
2418
2419		ret = rr_configure_and_change_cm_property(output, drmmode_crtc,
2420							  cm_prop_id);
2421		if (ret) {
2422			xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2423				   "Error getting color property: %d\n",
2424				   ret);
2425			return FALSE;
2426		}
2427		return TRUE;
2428	}
2429
2430	/* Otherwise, must be an output property. */
2431	return TRUE;
2432}
2433
2434static const xf86OutputFuncsRec drmmode_output_funcs = {
2435	.dpms = drmmode_output_dpms,
2436	.create_resources = drmmode_output_create_resources,
2437	.set_property = drmmode_output_set_property,
2438	.get_property = drmmode_output_get_property,
2439	.detect = drmmode_output_detect,
2440	.mode_valid = drmmode_output_mode_valid,
2441
2442	.get_modes = drmmode_output_get_modes,
2443	.destroy = drmmode_output_destroy
2444};
2445
2446static int subpixel_conv_table[7] = { 0, SubPixelUnknown,
2447	SubPixelHorizontalRGB,
2448	SubPixelHorizontalBGR,
2449	SubPixelVerticalRGB,
2450	SubPixelVerticalBGR,
2451	SubPixelNone
2452};
2453
2454const char *output_names[] = { "None",
2455	"VGA",
2456	"DVI-I",
2457	"DVI-D",
2458	"DVI-A",
2459	"Composite",
2460	"S-video",
2461	"LVDS",
2462	"CTV",
2463	"DIN",
2464	"DisplayPort",
2465	"HDMI-A",
2466	"HDMI-B",
2467	"TV",
2468	"eDP",
2469	"Virtual",
2470	"DSI",
2471};
2472
2473#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
2474
2475static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
2476{
2477	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2478	int i;
2479	for (i = 0; i < xf86_config->num_output; i++) {
2480		xf86OutputPtr output = xf86_config->output[i];
2481		drmmode_output_private_ptr drmmode_output;
2482		drmmode_output = output->driver_private;
2483		if (drmmode_output->output_id == id)
2484			return output;
2485	}
2486	return NULL;
2487}
2488
2489static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
2490{
2491	char *conn;
2492	char conn_id[5];
2493	int id, len;
2494	char *blob_data;
2495
2496	if (!path_blob)
2497		return -1;
2498
2499	blob_data = path_blob->data;
2500	/* we only handle MST paths for now */
2501	if (strncmp(blob_data, "mst:", 4))
2502		return -1;
2503
2504	conn = strchr(blob_data + 4, '-');
2505	if (!conn)
2506		return -1;
2507	len = conn - (blob_data + 4);
2508	if (len + 1 > 5)
2509		return -1;
2510	memcpy(conn_id, blob_data + 4, len);
2511	conn_id[len] = '\0';
2512	id = strtoul(conn_id, NULL, 10);
2513
2514	*conn_base_id = id;
2515
2516	*path = conn + 1;
2517	return 0;
2518}
2519
2520static void
2521drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
2522		    drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi)
2523{
2524	xf86OutputPtr output;
2525	int conn_id;
2526	char *extra_path;
2527
2528	output = NULL;
2529	if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
2530		output = find_output(pScrn, conn_id);
2531	if (output) {
2532		snprintf(name, 32, "%s-%s", output->name, extra_path);
2533	} else {
2534		if (koutput->connector_type >= NUM_OUTPUT_NAMES) {
2535			snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1);
2536		} else if (pScrn->is_gpu) {
2537			snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type],
2538				 pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1);
2539		} else {
2540			/* need to do smart conversion here for compat with non-kms ATI driver */
2541			if (koutput->connector_type_id == 1) {
2542				switch(koutput->connector_type) {
2543				case DRM_MODE_CONNECTOR_DVII:
2544				case DRM_MODE_CONNECTOR_DVID:
2545				case DRM_MODE_CONNECTOR_DVIA:
2546					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
2547					(*num_dvi)++;
2548					break;
2549				case DRM_MODE_CONNECTOR_HDMIA:
2550				case DRM_MODE_CONNECTOR_HDMIB:
2551					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
2552					(*num_hdmi)++;
2553					break;
2554				case DRM_MODE_CONNECTOR_VGA:
2555				case DRM_MODE_CONNECTOR_DisplayPort:
2556					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
2557					break;
2558				default:
2559					snprintf(name, 32, "%s", output_names[koutput->connector_type]);
2560					break;
2561				}
2562			} else {
2563				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
2564			}
2565		}
2566	}
2567}
2568
2569
2570static unsigned int
2571drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic)
2572{
2573	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2574	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2575	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2576	xf86OutputPtr output;
2577	drmModeConnectorPtr koutput;
2578	drmModeEncoderPtr *kencoders = NULL;
2579	drmmode_output_private_ptr drmmode_output;
2580	drmModePropertyBlobPtr path_blob = NULL;
2581#if XF86_CRTC_VERSION >= 8
2582	Bool nonDesktop = FALSE;
2583#endif
2584	char name[32];
2585	int i;
2586	const char *s;
2587
2588	koutput =
2589	    drmModeGetConnector(pAMDGPUEnt->fd,
2590				mode_res->connectors[num]);
2591	if (!koutput)
2592		return 0;
2593
2594	path_blob = koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "PATH");
2595
2596#if XF86_CRTC_VERSION >= 8
2597	i = koutput_get_prop_idx(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_RANGE,
2598				 "non-desktop");
2599	if (i >= 0)
2600        	nonDesktop = koutput->prop_values[i] != 0;
2601#endif
2602
2603	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
2604	if (!kencoders) {
2605		goto out_free_encoders;
2606	}
2607
2608	for (i = 0; i < koutput->count_encoders; i++) {
2609		kencoders[i] =
2610		    drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]);
2611		if (!kencoders[i]) {
2612			goto out_free_encoders;
2613		}
2614	}
2615
2616	drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi);
2617	if (path_blob) {
2618		drmModeFreePropertyBlob(path_blob);
2619	}
2620
2621	if (path_blob && dynamic) {
2622		/* See if we have an output with this name already
2623		 * and hook stuff up.
2624		 */
2625		for (i = 0; i < xf86_config->num_output; i++) {
2626			output = xf86_config->output[i];
2627
2628			if (strncmp(output->name, name, 32))
2629				continue;
2630
2631			drmmode_output = output->driver_private;
2632			drmmode_output->output_id = mode_res->connectors[num];
2633			drmmode_output->mode_output = koutput;
2634#if XF86_CRTC_VERSION >= 8
2635			output->non_desktop = nonDesktop;
2636#endif
2637			for (i = 0; i < koutput->count_encoders; i++) {
2638				drmModeFreeEncoder(kencoders[i]);
2639			}
2640			free(kencoders);
2641			return 1;
2642		}
2643	}
2644
2645	if (xf86IsEntityShared(pScrn->entityList[0])) {
2646		if ((s =
2647		     xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
2648			if (!AMDGPUZaphodStringMatches(pScrn, s, name))
2649				goto out_free_encoders;
2650		} else {
2651			if (!info->IsSecondary && (num != 0))
2652				goto out_free_encoders;
2653			else if (info->IsSecondary && (num != 1))
2654				goto out_free_encoders;
2655		}
2656	}
2657
2658	output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
2659	if (!output) {
2660		goto out_free_encoders;
2661	}
2662
2663	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
2664	if (!drmmode_output) {
2665		xf86OutputDestroy(output);
2666		goto out_free_encoders;
2667	}
2668
2669	drmmode_output->output_id = mode_res->connectors[num];
2670	drmmode_output->mode_output = koutput;
2671	drmmode_output->mode_encoders = kencoders;
2672	drmmode_output->drmmode = drmmode;
2673	output->mm_width = koutput->mmWidth;
2674	output->mm_height = koutput->mmHeight;
2675
2676	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
2677	output->interlaceAllowed = TRUE;
2678	output->doubleScanAllowed = TRUE;
2679	output->driver_private = drmmode_output;
2680#if XF86_CRTC_VERSION >= 8
2681	output->non_desktop = nonDesktop;
2682#endif
2683
2684	output->possible_crtcs = 0xffffffff;
2685	for (i = 0; i < koutput->count_encoders; i++) {
2686		output->possible_crtcs &= kencoders[i]->possible_crtcs;
2687	}
2688	/* work out the possible clones later */
2689	output->possible_clones = 0;
2690
2691	drmmode_output->dpms_enum_id =
2692		koutput_get_prop_id(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_ENUM,
2693				    "DPMS");
2694
2695	if (dynamic) {
2696		output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
2697		drmmode_output_create_resources(output);
2698	}
2699
2700	return 1;
2701out_free_encoders:
2702	if (kencoders) {
2703		for (i = 0; i < koutput->count_encoders; i++)
2704			drmModeFreeEncoder(kencoders[i]);
2705		free(kencoders);
2706	}
2707	drmModeFreeConnector(koutput);
2708	return 0;
2709}
2710
2711uint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
2712{
2713	drmmode_output_private_ptr drmmode_output =
2714	    output->driver_private, clone_drmout;
2715	int i;
2716	xf86OutputPtr clone_output;
2717	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2718	int index_mask = 0;
2719
2720	if (drmmode_output->enc_clone_mask == 0)
2721		return index_mask;
2722
2723	for (i = 0; i < xf86_config->num_output; i++) {
2724		clone_output = xf86_config->output[i];
2725		clone_drmout = clone_output->driver_private;
2726		if (output == clone_output)
2727			continue;
2728
2729		if (clone_drmout->enc_mask == 0)
2730			continue;
2731		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
2732			index_mask |= (1 << i);
2733	}
2734	return index_mask;
2735}
2736
2737static void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
2738{
2739	int i, j;
2740	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2741
2742	for (i = 0; i < xf86_config->num_output; i++) {
2743		xf86OutputPtr output = xf86_config->output[i];
2744		drmmode_output_private_ptr drmmode_output;
2745
2746		drmmode_output = output->driver_private;
2747		drmmode_output->enc_clone_mask = 0xff;
2748		/* and all the possible encoder clones for this output together */
2749		for (j = 0; j < drmmode_output->mode_output->count_encoders;
2750		     j++) {
2751			int k;
2752			for (k = 0; k < mode_res->count_encoders; k++) {
2753				if (mode_res->encoders[k] ==
2754				    drmmode_output->
2755				    mode_encoders[j]->encoder_id)
2756					drmmode_output->enc_mask |= (1 << k);
2757			}
2758
2759			drmmode_output->enc_clone_mask &=
2760			    drmmode_output->mode_encoders[j]->possible_clones;
2761		}
2762	}
2763
2764	for (i = 0; i < xf86_config->num_output; i++) {
2765		xf86OutputPtr output = xf86_config->output[i];
2766		output->possible_clones = find_clones(scrn, output);
2767	}
2768}
2769
2770/* returns pitch alignment in pixels */
2771int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe)
2772{
2773	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
2774
2775	if (info->have_tiling_info)
2776		/* linear aligned requirements */
2777		return MAX(64, info->group_bytes / bpe);
2778	else
2779		/* default to 512 elements if we don't know the real
2780		 * group size otherwise the kernel may reject the CS
2781		 * if the group sizes don't match as the pitch won't
2782		 * be aligned properly.
2783		 */
2784		return 512;
2785}
2786
2787static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
2788{
2789	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2790	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
2791	struct amdgpu_buffer *old_front = NULL;
2792	ScreenPtr screen = xf86ScrnToScreen(scrn);
2793	int i, pitch, old_width, old_height, old_pitch;
2794	int cpp = info->pixel_bytes;
2795	PixmapPtr ppix = screen->GetScreenPixmap(screen);
2796	void *fb_shadow;
2797	int hint = 0;
2798
2799	if (scrn->virtualX == width && scrn->virtualY == height)
2800		return TRUE;
2801
2802	if (width > xf86_config->maxWidth || height > xf86_config->maxHeight) {
2803		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2804			   "Xorg tried resizing screen to %dx%d, but maximum "
2805			   "supported is %dx%d\n", width, height,
2806			   xf86_config->maxWidth, xf86_config->maxHeight);
2807		return FALSE;
2808	}
2809
2810	if (info->shadow_primary)
2811		hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
2812	else if (!info->use_glamor)
2813		hint = AMDGPU_CREATE_PIXMAP_LINEAR;
2814
2815	xf86DrvMsg(scrn->scrnIndex, X_INFO,
2816		   "Allocate new frame buffer %dx%d\n", width, height);
2817
2818	old_width = scrn->virtualX;
2819	old_height = scrn->virtualY;
2820	old_pitch = scrn->displayWidth;
2821	old_front = info->front_buffer;
2822
2823	scrn->virtualX = width;
2824	scrn->virtualY = height;
2825
2826	info->front_buffer =
2827		amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY,
2828				       scrn->depth, hint, scrn->bitsPerPixel,
2829				       &pitch);
2830	if (!info->front_buffer) {
2831		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2832			   "Failed to allocate front buffer memory\n");
2833		goto fail;
2834	}
2835
2836	if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) {
2837		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2838			   "Failed to map front buffer memory\n");
2839		goto fail;
2840	}
2841
2842	xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch);
2843	scrn->displayWidth = pitch / cpp;
2844
2845	if (info->use_glamor ||
2846	    (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) {
2847		screen->ModifyPixmapHeader(ppix,
2848					   width, height, -1, -1, pitch, info->front_buffer->cpu_ptr);
2849	} else {
2850		fb_shadow = calloc(1, pitch * scrn->virtualY);
2851		if (!fb_shadow)
2852			goto fail;
2853		free(info->fb_shadow);
2854		info->fb_shadow = fb_shadow;
2855		screen->ModifyPixmapHeader(ppix,
2856					   width, height, -1, -1, pitch,
2857					   info->fb_shadow);
2858	}
2859
2860	if (!amdgpu_glamor_create_screen_resources(scrn->pScreen))
2861		goto fail;
2862
2863	if (info->use_glamor ||
2864	    (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) {
2865		if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer))
2866			goto fail;
2867	}
2868
2869	amdgpu_pixmap_clear(ppix);
2870	amdgpu_glamor_finish(scrn);
2871
2872	for (i = 0; i < xf86_config->num_crtc; i++) {
2873		xf86CrtcPtr crtc = xf86_config->crtc[i];
2874
2875		if (!crtc->enabled)
2876			continue;
2877
2878		drmmode_set_mode_major(crtc, &crtc->mode,
2879				       crtc->rotation, crtc->x, crtc->y);
2880	}
2881
2882	if (old_front) {
2883		amdgpu_bo_unref(&old_front);
2884	}
2885
2886	return TRUE;
2887
2888fail:
2889	if (info->front_buffer) {
2890		amdgpu_bo_unref(&info->front_buffer);
2891	}
2892	info->front_buffer = old_front;
2893	scrn->virtualX = old_width;
2894	scrn->virtualY = old_height;
2895	scrn->displayWidth = old_pitch;
2896
2897	return FALSE;
2898}
2899
2900static void
2901drmmode_validate_leases(ScrnInfoPtr scrn)
2902{
2903#ifdef XF86_LEASE_VERSION
2904	ScreenPtr screen = scrn->pScreen;
2905	rrScrPrivPtr scr_priv = rrGetScrPriv(screen);
2906	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
2907	drmModeLesseeListPtr lessees;
2908	RRLeasePtr lease, next;
2909	int l;
2910
2911	/* We can't talk to the kernel about leases when VT switched */
2912	if (!scrn->vtSema)
2913		return;
2914
2915	lessees = drmModeListLessees(pAMDGPUEnt->fd);
2916	if (!lessees)
2917		return;
2918
2919	xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
2920		drmmode_lease_private_ptr lease_private = lease->devPrivate;
2921
2922		for (l = 0; l < lessees->count; l++) {
2923			if (lessees->lessees[l] == lease_private->lessee_id)
2924				break;
2925		}
2926
2927		/* check to see if the lease has gone away */
2928		if (l == lessees->count) {
2929			free(lease_private);
2930			lease->devPrivate = NULL;
2931			xf86CrtcLeaseTerminated(lease);
2932		}
2933	}
2934
2935	free(lessees);
2936#endif
2937}
2938
2939#ifdef XF86_LEASE_VERSION
2940
2941static int
2942drmmode_create_lease(RRLeasePtr lease, int *fd)
2943{
2944	ScreenPtr screen = lease->screen;
2945	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
2946	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
2947	drmmode_lease_private_ptr lease_private;
2948	int noutput = lease->numOutputs;
2949	int ncrtc = lease->numCrtcs;
2950	uint32_t *objects;
2951	size_t nobjects;
2952	int lease_fd;
2953	int c, o;
2954	int i;
2955
2956	nobjects = ncrtc + noutput;
2957	if (nobjects == 0 || nobjects > (SIZE_MAX / 4) ||
2958	    ncrtc > (SIZE_MAX - noutput))
2959		return BadValue;
2960
2961	lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
2962	if (!lease_private)
2963		return BadAlloc;
2964
2965	objects = malloc(nobjects * 4);
2966	if (!objects) {
2967		free(lease_private);
2968		return BadAlloc;
2969	}
2970
2971	i = 0;
2972
2973	/* Add CRTC ids */
2974	for (c = 0; c < ncrtc; c++) {
2975		xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
2976		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2977
2978		objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
2979	}
2980
2981	/* Add connector ids */
2982	for (o = 0; o < noutput; o++) {
2983		xf86OutputPtr   output = lease->outputs[o]->devPrivate;
2984		drmmode_output_private_ptr drmmode_output = output->driver_private;
2985
2986		objects[i++] = drmmode_output->mode_output->connector_id;
2987	}
2988
2989	/* call kernel to create lease */
2990	assert (i == nobjects);
2991
2992	lease_fd = drmModeCreateLease(pAMDGPUEnt->fd, objects, nobjects, 0,
2993				      &lease_private->lessee_id);
2994
2995	free(objects);
2996
2997	if (lease_fd < 0) {
2998		free(lease_private);
2999		return BadMatch;
3000	}
3001
3002	lease->devPrivate = lease_private;
3003
3004	xf86CrtcLeaseStarted(lease);
3005
3006	*fd = lease_fd;
3007	return Success;
3008}
3009
3010static void
3011drmmode_terminate_lease(RRLeasePtr lease)
3012{
3013	drmmode_lease_private_ptr lease_private = lease->devPrivate;
3014	ScreenPtr screen = lease->screen;
3015	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3016	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
3017
3018	if (drmModeRevokeLease(pAMDGPUEnt->fd, lease_private->lessee_id) == 0) {
3019		free(lease_private);
3020		lease->devPrivate = NULL;
3021		xf86CrtcLeaseTerminated(lease);
3022	}
3023}
3024
3025#endif // XF86_LEASE_VERSION
3026
3027static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
3028	.resize = drmmode_xf86crtc_resize,
3029#ifdef XF86_LEASE_VERSION
3030	.create_lease = drmmode_create_lease,
3031	.terminate_lease = drmmode_terminate_lease
3032#endif
3033};
3034
3035static void
3036drmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
3037{
3038	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3039	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
3040	drmmode_flipdata_ptr flipdata = event_data;
3041	int crtc_id = drmmode_get_crtc_id(crtc);
3042	struct drmmode_fb **fb = &flipdata->fb[crtc_id];
3043
3044	if (drmmode_crtc->flip_pending == *fb) {
3045		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
3046				     NULL);
3047	}
3048	drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL);
3049
3050	if (--flipdata->flip_count == 0) {
3051		if (!flipdata->fe_crtc)
3052			flipdata->fe_crtc = crtc;
3053		flipdata->abort(flipdata->fe_crtc, flipdata->event_data);
3054		free(flipdata);
3055	}
3056}
3057
3058static void
3059drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
3060{
3061	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
3062	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3063	drmmode_flipdata_ptr flipdata = event_data;
3064	int crtc_id = drmmode_get_crtc_id(crtc);
3065	struct drmmode_fb **fb = &flipdata->fb[crtc_id];
3066
3067	/* Is this the event whose info shall be delivered to higher level? */
3068	if (crtc == flipdata->fe_crtc) {
3069		/* Yes: Cache msc, ust for later delivery. */
3070		flipdata->fe_frame = frame;
3071		flipdata->fe_usec = usec;
3072	}
3073
3074	if (drmmode_crtc->flip_pending == *fb) {
3075		drmmode_fb_reference(pAMDGPUEnt->fd,
3076				     &drmmode_crtc->flip_pending, NULL);
3077	}
3078	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, *fb);
3079	drmmode_fb_reference(pAMDGPUEnt->fd, fb, NULL);
3080
3081	if (--flipdata->flip_count == 0) {
3082		/* Deliver MSC & UST from reference/current CRTC to flip event
3083		 * handler
3084		 */
3085		if (flipdata->fe_crtc)
3086			flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame,
3087					  flipdata->fe_usec, flipdata->event_data);
3088		else
3089			flipdata->handler(crtc, frame, usec, flipdata->event_data);
3090
3091		free(flipdata);
3092	}
3093}
3094
3095#if HAVE_NOTIFY_FD
3096static void drmmode_notify_fd(int fd, int notify, void *data)
3097{
3098	drmmode_ptr drmmode = data;
3099	amdgpu_drm_handle_event(fd, &drmmode->event_context);
3100}
3101#else
3102static void drm_wakeup_handler(pointer data, int err, pointer p)
3103{
3104	drmmode_ptr drmmode = data;
3105	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn);
3106	fd_set *read_mask = p;
3107
3108	if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) {
3109		amdgpu_drm_handle_event(pAMDGPUEnt->fd, &drmmode->event_context);
3110	}
3111}
3112#endif
3113
3114static Bool drmmode_probe_page_flip_target(AMDGPUEntPtr pAMDGPUEnt)
3115{
3116	uint64_t cap_value;
3117
3118	return drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PAGE_FLIP_TARGET,
3119			 &cap_value) == 0 && cap_value != 0;
3120}
3121
3122static int
3123drmmode_page_flip(AMDGPUEntPtr pAMDGPUEnt, drmmode_crtc_private_ptr drmmode_crtc,
3124		  int fb_id, uint32_t flags, uintptr_t drm_queue_seq)
3125{
3126	flags |= DRM_MODE_PAGE_FLIP_EVENT;
3127	return drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
3128			       fb_id, flags, (void*)drm_queue_seq);
3129}
3130
3131int
3132drmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt,
3133				  drmmode_crtc_private_ptr drmmode_crtc,
3134				  int fb_id, uint32_t flags,
3135				  uintptr_t drm_queue_seq, uint32_t target_msc)
3136{
3137	if (pAMDGPUEnt->has_page_flip_target) {
3138		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE;
3139		return drmModePageFlipTarget(pAMDGPUEnt->fd,
3140					     drmmode_crtc->mode_crtc->crtc_id,
3141					     fb_id, flags, (void*)drm_queue_seq,
3142					     target_msc);
3143	}
3144
3145	return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags,
3146				 drm_queue_seq);
3147}
3148
3149int
3150drmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt,
3151				  drmmode_crtc_private_ptr drmmode_crtc,
3152				  int fb_id, uint32_t flags,
3153				  uintptr_t drm_queue_seq, uint32_t target_msc)
3154{
3155	if (pAMDGPUEnt->has_page_flip_target) {
3156		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE;
3157		return drmModePageFlipTarget(pAMDGPUEnt->fd,
3158					     drmmode_crtc->mode_crtc->crtc_id,
3159					     fb_id, flags, (void*)drm_queue_seq,
3160					     target_msc);
3161	}
3162
3163	return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags,
3164				 drm_queue_seq);
3165}
3166
3167/**
3168 * Initialize DDX color management support. It does two things:
3169 *
3170 * 1. Cache DRM color management property type IDs, as they do not change. They
3171 *    will be used later to modify color management via DRM, or to determine if
3172 *    there's kernel support for color management.
3173 *
3174 * 2. Cache degamma/gamma LUT sizes, since all CRTCs have the same LUT sizes on
3175 *    AMD hardware.
3176 *
3177 * If the cached ID's are all 0 after calling this function, then color
3178 * management is not supported. For short, checking if the gamma LUT size
3179 * property ID == 0 is sufficient.
3180 *
3181 * This should be called before CRTCs are initialized within pre_init, as the
3182 * cached values will be used there.
3183 *
3184 * @drm_fd: DRM file descriptor
3185 * @drmmode: drmmode object, where the cached IDs are stored
3186 * @mode_res: The DRM mode resource containing the CRTC ids
3187 */
3188static void drmmode_cm_init(int drm_fd, drmmode_ptr drmmode,
3189			    drmModeResPtr mode_res)
3190{
3191	drmModeObjectPropertiesPtr drm_props;
3192	drmModePropertyPtr drm_prop;
3193	enum drmmode_cm_prop cm_prop;
3194	uint32_t cm_enabled = 0;
3195	uint32_t cm_all_enabled = (1 << CM_NUM_PROPS) - 1;
3196	int i;
3197
3198	memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids));
3199	drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0;
3200
3201	if (!mode_res->crtcs)
3202		return;
3203
3204	/* AMD hardware has color management support on all pipes. It is
3205	 * therefore sufficient to only check the first CRTC.
3206	 */
3207	drm_props = drmModeObjectGetProperties(drm_fd,
3208					       mode_res->crtcs[0],
3209					       DRM_MODE_OBJECT_CRTC);
3210	if (!drm_props)
3211		return;
3212
3213	for (i = 0; i < drm_props->count_props; i++) {
3214		drm_prop = drmModeGetProperty(drm_fd,
3215					      drm_props->props[i]);
3216		if (!drm_prop)
3217			continue;
3218
3219		cm_prop = get_cm_enum_from_str(drm_prop->name);
3220		if (cm_prop == CM_INVALID_PROP)
3221			continue;
3222
3223		if (cm_prop == CM_DEGAMMA_LUT_SIZE)
3224			drmmode->degamma_lut_size = drm_props->prop_values[i];
3225		else if (cm_prop == CM_GAMMA_LUT_SIZE)
3226			drmmode->gamma_lut_size = drm_props->prop_values[i];
3227
3228		drmmode->cm_prop_ids[cm_prop] = drm_props->props[i];
3229		cm_enabled |= 1 << cm_prop;
3230
3231		drmModeFreeProperty(drm_prop);
3232	}
3233	drmModeFreeObjectProperties(drm_props);
3234
3235	/* cm is enabled only if all prop ids are found */
3236	if (cm_enabled == cm_all_enabled)
3237		return;
3238
3239	/* Otherwise, disable DDX cm support */
3240	memset(drmmode->cm_prop_ids, 0, sizeof(drmmode->cm_prop_ids));
3241	drmmode->gamma_lut_size = drmmode->degamma_lut_size = 0;
3242}
3243
3244Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
3245{
3246	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
3247	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
3248	int i, num_dvi = 0, num_hdmi = 0;
3249	unsigned int crtcs_needed = 0;
3250	drmModeResPtr mode_res;
3251	char *bus_id_string, *provider_name;
3252
3253	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
3254
3255	drmmode->scrn = pScrn;
3256	mode_res = drmModeGetResources(pAMDGPUEnt->fd);
3257	if (!mode_res)
3258		return FALSE;
3259
3260	drmmode->count_crtcs = mode_res->count_crtcs;
3261	xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
3262			     mode_res->max_height);
3263
3264	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
3265		       "Initializing outputs ...\n");
3266	for (i = 0; i < mode_res->count_connectors; i++)
3267		crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0);
3268
3269	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
3270		       "%d crtcs needed for screen.\n", crtcs_needed);
3271
3272	/* Need per-screen drmmode_crtc_funcs, based on our global template,
3273	 * so we can disable some functions, depending on screen settings.
3274	 */
3275	info->drmmode_crtc_funcs = drmmode_crtc_funcs;
3276
3277	if (!info->use_glamor) {
3278		/* Rotation requires hardware acceleration */
3279		info->drmmode_crtc_funcs.shadow_allocate = NULL;
3280		info->drmmode_crtc_funcs.shadow_create = NULL;
3281		info->drmmode_crtc_funcs.shadow_destroy = NULL;
3282	}
3283
3284	drmmode_cm_init(pAMDGPUEnt->fd, drmmode, mode_res);
3285
3286	/* Spare the server the effort to compute and update unused CLUTs. */
3287	if (pScrn->depth == 30 && !drmmode_cm_enabled(drmmode))
3288		info->drmmode_crtc_funcs.gamma_set = NULL;
3289
3290	for (i = 0; i < mode_res->count_crtcs; i++)
3291		if (!xf86IsEntityShared(pScrn->entityList[0]) ||
3292		    (crtcs_needed && !(pAMDGPUEnt->assigned_crtcs & (1 << i))))
3293			crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
3294
3295	/* All ZaphodHeads outputs provided with matching crtcs? */
3296	if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
3297		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3298			   "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
3299			   crtcs_needed);
3300
3301	/* workout clones */
3302	drmmode_clones_init(pScrn, drmmode, mode_res);
3303
3304	bus_id_string = DRICreatePCIBusID(info->PciInfo);
3305	XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string);
3306	free(bus_id_string);
3307	xf86ProviderSetup(pScrn, NULL, provider_name);
3308	free(provider_name);
3309
3310	xf86InitialConfiguration(pScrn, TRUE);
3311
3312	pAMDGPUEnt->has_page_flip_target = drmmode_probe_page_flip_target(pAMDGPUEnt);
3313
3314	drmModeFreeResources(mode_res);
3315	return TRUE;
3316}
3317
3318void drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3319{
3320	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
3321	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
3322
3323	info->drmmode_inited = TRUE;
3324	if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) {
3325#if HAVE_NOTIFY_FD
3326		SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode);
3327#else
3328		AddGeneralSocket(pAMDGPUEnt->fd);
3329		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA,
3330					       drm_wakeup_handler, drmmode);
3331#endif
3332		pAMDGPUEnt->fd_wakeup_registered = serverGeneration;
3333		pAMDGPUEnt->fd_wakeup_ref = 1;
3334	} else
3335		pAMDGPUEnt->fd_wakeup_ref++;
3336}
3337
3338void drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3339{
3340	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3341	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
3342	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
3343	int c;
3344
3345	if (!info->drmmode_inited)
3346		return;
3347
3348	if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration &&
3349	    !--pAMDGPUEnt->fd_wakeup_ref) {
3350#if HAVE_NOTIFY_FD
3351		RemoveNotifyFd(pAMDGPUEnt->fd);
3352#else
3353		RemoveGeneralSocket(pAMDGPUEnt->fd);
3354		RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA,
3355					     drm_wakeup_handler, drmmode);
3356#endif
3357	}
3358
3359	for (c = 0; c < config->num_crtc; c++)
3360		drmmode_crtc_scanout_free(config->crtc[c]->driver_private);
3361}
3362
3363static void drmmode_sprite_do_set_cursor(struct amdgpu_device_priv *device_priv,
3364					 ScrnInfoPtr scrn, int x, int y)
3365{
3366	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
3367	CursorPtr cursor = device_priv->cursor;
3368	Bool sprite_visible = device_priv->sprite_visible;
3369
3370	if (cursor) {
3371		x -= cursor->bits->xhot;
3372		y -= cursor->bits->yhot;
3373
3374		device_priv->sprite_visible =
3375			x < scrn->virtualX && y < scrn->virtualY &&
3376			(x + cursor->bits->width > 0) &&
3377			(y + cursor->bits->height > 0);
3378	} else {
3379		device_priv->sprite_visible = FALSE;
3380	}
3381
3382	info->sprites_visible += device_priv->sprite_visible - sprite_visible;
3383}
3384
3385static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
3386				      CursorPtr pCursor, int x, int y)
3387{
3388	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
3389	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
3390	struct amdgpu_device_priv *device_priv =
3391		dixLookupScreenPrivate(&pDev->devPrivates,
3392				       &amdgpu_device_private_key, pScreen);
3393
3394	device_priv->cursor = pCursor;
3395	drmmode_sprite_do_set_cursor(device_priv, scrn, x, y);
3396
3397	info->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
3398}
3399
3400static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
3401				       int x, int y)
3402{
3403	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
3404	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
3405	struct amdgpu_device_priv *device_priv =
3406		dixLookupScreenPrivate(&pDev->devPrivates,
3407				       &amdgpu_device_private_key, pScreen);
3408
3409	drmmode_sprite_do_set_cursor(device_priv, scrn, x, y);
3410
3411	info->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
3412}
3413
3414static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
3415						  ScreenPtr pScreen,
3416						  CursorPtr pCursor)
3417{
3418	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
3419	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
3420
3421	return info->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
3422}
3423
3424static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
3425						    ScreenPtr pScreen,
3426						    CursorPtr pCursor)
3427{
3428	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
3429	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
3430
3431	return info->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
3432}
3433
3434static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
3435						    ScreenPtr pScreen)
3436{
3437	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
3438	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
3439
3440	return info->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
3441}
3442
3443static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
3444						 ScreenPtr pScreen)
3445{
3446	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
3447	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
3448
3449	info->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
3450}
3451
3452miPointerSpriteFuncRec drmmode_sprite_funcs = {
3453	.RealizeCursor = drmmode_sprite_realize_realize_cursor,
3454	.UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
3455	.SetCursor = drmmode_sprite_set_cursor,
3456	.MoveCursor = drmmode_sprite_move_cursor,
3457	.DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
3458	.DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
3459};
3460
3461
3462void drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id,
3463			struct amdgpu_buffer *bo)
3464{
3465	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3466	xf86CrtcPtr crtc = xf86_config->crtc[id];
3467	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3468
3469	drmmode_crtc->cursor_buffer = bo;
3470}
3471
3472void drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
3473{
3474	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3475	xf86OutputPtr output = config->output[config->compat_output];
3476	xf86CrtcPtr crtc = output->crtc;
3477
3478	if (crtc && crtc->enabled) {
3479		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
3480	}
3481}
3482
3483Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
3484			       Bool set_hw)
3485{
3486	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3487	unsigned num_desired = 0, num_on = 0;
3488	int c;
3489
3490	/* First, disable all unused CRTCs */
3491	if (set_hw) {
3492		for (c = 0; c < config->num_crtc; c++) {
3493			xf86CrtcPtr crtc = config->crtc[c];
3494
3495			/* Skip disabled CRTCs */
3496			if (crtc->enabled)
3497				continue;
3498
3499			drmmode_crtc_dpms(crtc, DPMSModeOff);
3500		}
3501	}
3502
3503	/* Then, try setting the chosen mode on each CRTC */
3504	for (c = 0; c < config->num_crtc; c++) {
3505		xf86CrtcPtr crtc = config->crtc[c];
3506		xf86OutputPtr output = NULL;
3507		int o;
3508
3509		if (!crtc->enabled)
3510			continue;
3511
3512		if (config->output[config->compat_output]->crtc == crtc)
3513			output = config->output[config->compat_output];
3514		else {
3515			for (o = 0; o < config->num_output; o++)
3516				if (config->output[o]->crtc == crtc) {
3517					output = config->output[o];
3518					break;
3519				}
3520		}
3521		/* paranoia */
3522		if (!output)
3523			continue;
3524
3525		num_desired++;
3526
3527		/* Mark that we'll need to re-set the mode for sure */
3528		memset(&crtc->mode, 0, sizeof(crtc->mode));
3529		if (!crtc->desiredMode.CrtcHDisplay) {
3530			DisplayModePtr mode = xf86OutputFindClosestMode(output,
3531									pScrn->
3532									currentMode);
3533
3534			if (!mode) {
3535				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3536					   "Failed to find mode for CRTC %d\n", c);
3537				continue;
3538			}
3539			crtc->desiredMode = *mode;
3540			crtc->desiredRotation = RR_Rotate_0;
3541			crtc->desiredX = 0;
3542			crtc->desiredY = 0;
3543		}
3544
3545		if (set_hw) {
3546			if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode,
3547							crtc->desiredRotation,
3548							crtc->desiredX,
3549							crtc->desiredY)) {
3550				num_on++;
3551			} else {
3552				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3553					   "Failed to set mode on CRTC %d\n", c);
3554				RRCrtcSet(crtc->randr_crtc, NULL, crtc->x, crtc->y,
3555					  crtc->rotation, 0, NULL);
3556			}
3557		} else {
3558			crtc->mode = crtc->desiredMode;
3559			crtc->rotation = crtc->desiredRotation;
3560			crtc->x = crtc->desiredX;
3561			crtc->y = crtc->desiredY;
3562			if (drmmode_handle_transform(crtc))
3563				num_on++;
3564		}
3565	}
3566
3567	if (num_on == 0 && num_desired > 0) {
3568		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n");
3569		return FALSE;
3570	}
3571
3572	/* Validate leases on VT re-entry */
3573	drmmode_validate_leases(pScrn);
3574
3575	return TRUE;
3576}
3577
3578Bool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
3579{
3580	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3581	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
3582	int i;
3583
3584	if (xf86_config->num_crtc) {
3585		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
3586			       "Initializing kms color map\n");
3587		if (!miCreateDefColormap(pScreen))
3588			return FALSE;
3589
3590		if (pScrn->depth == 30) {
3591			if (!drmmode_cm_enabled(&info->drmmode))
3592				return TRUE;
3593
3594			for (i = 0; i < xf86_config->num_crtc; i++) {
3595				xf86CrtcPtr crtc = xf86_config->crtc[i];
3596				void *gamma;
3597
3598				if (crtc->gamma_size == 1024)
3599					continue;
3600
3601				gamma = malloc(1024 * 3 * sizeof(CARD16));
3602				if (!gamma) {
3603					ErrorF("Failed to allocate gamma LUT memory\n");
3604					return FALSE;
3605				}
3606
3607				free(crtc->gamma_red);
3608				crtc->gamma_size = 1024;
3609				crtc->gamma_red = gamma;
3610				crtc->gamma_green = crtc->gamma_red + crtc->gamma_size;
3611				crtc->gamma_blue = crtc->gamma_green + crtc->gamma_size;
3612			}
3613		}
3614
3615		/* All Radeons support 10 bit CLUTs. */
3616		if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10,
3617					 NULL, NULL, CMAP_PALETTED_TRUECOLOR
3618					 | CMAP_RELOAD_ON_MODE_SWITCH))
3619			return FALSE;
3620
3621		for (i = 0; i < xf86_config->num_crtc; i++) {
3622			xf86CrtcPtr crtc = xf86_config->crtc[i];
3623
3624			drmmode_crtc_gamma_do_set(crtc, crtc->gamma_red,
3625						  crtc->gamma_green,
3626						  crtc->gamma_blue,
3627						  crtc->gamma_size);
3628		}
3629	}
3630
3631	return TRUE;
3632}
3633
3634static Bool
3635drmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi,
3636		    int *num_hdmi)
3637{
3638	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3639	int i;
3640
3641	for (i = 0; i < config->num_output; i++) {
3642		xf86OutputPtr output = config->output[i];
3643		drmmode_output_private_ptr drmmode_output = output->driver_private;
3644
3645		if (drmmode_output->output_id == output_id) {
3646			switch(drmmode_output->mode_output->connector_type) {
3647			case DRM_MODE_CONNECTOR_DVII:
3648			case DRM_MODE_CONNECTOR_DVID:
3649			case DRM_MODE_CONNECTOR_DVIA:
3650				(*num_dvi)++;
3651				break;
3652			case DRM_MODE_CONNECTOR_HDMIA:
3653			case DRM_MODE_CONNECTOR_HDMIB:
3654				(*num_hdmi)++;
3655				break;
3656			}
3657
3658			return TRUE;
3659		}
3660	}
3661
3662	return FALSE;
3663}
3664
3665void
3666amdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3667{
3668	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3669	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
3670	drmModeResPtr mode_res;
3671	int i, j;
3672	Bool found;
3673	Bool changed = FALSE;
3674	int num_dvi = 0, num_hdmi = 0;
3675
3676	/* Try to re-set the mode on all the connectors with a BAD link-state:
3677	 * This may happen if a link degrades and a new modeset is necessary, using
3678	 * different link-training parameters. If the kernel found that the current
3679	 * mode is not achievable anymore, it should have pruned the mode before
3680	 * sending the hotplug event. Try to re-set the currently-set mode to keep
3681	 * the display alive, this will fail if the mode has been pruned.
3682	 * In any case, we will send randr events for the Desktop Environment to
3683	 * deal with it, if it wants to.
3684	 */
3685	for (i = 0; i < config->num_output; i++) {
3686		xf86OutputPtr output = config->output[i];
3687		xf86CrtcPtr crtc = output->crtc;
3688		drmmode_output_private_ptr drmmode_output = output->driver_private;
3689
3690		drmmode_output_detect(output);
3691
3692		if (!crtc || !drmmode_output->mode_output)
3693			continue;
3694
3695		/* Get an updated view of the properties for the current connector and
3696		 * look for the link-status property
3697		 */
3698		for (j = 0; j < drmmode_output->num_props; j++) {
3699			drmmode_prop_ptr p = &drmmode_output->props[j];
3700
3701			if (!strcmp(p->mode_prop->name, "link-status")) {
3702				if (p->value != DRM_MODE_LINK_STATUS_BAD)
3703					break;
3704
3705				/* the connector got a link failure, re-set the current mode */
3706				drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
3707						       crtc->x, crtc->y);
3708
3709				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
3710					   "hotplug event: connector %u's link-state is BAD, "
3711					   "tried resetting the current mode. You may be left"
3712					   "with a black screen if this fails...\n",
3713					   drmmode_output->mode_output->connector_id);
3714
3715				break;
3716			}
3717		}
3718	}
3719
3720	mode_res = drmModeGetResources(pAMDGPUEnt->fd);
3721	if (!mode_res)
3722		goto out;
3723
3724restart_destroy:
3725	for (i = 0; i < config->num_output; i++) {
3726		xf86OutputPtr output = config->output[i];
3727		drmmode_output_private_ptr drmmode_output = output->driver_private;
3728		found = FALSE;
3729		for (j = 0; j < mode_res->count_connectors; j++) {
3730			if (mode_res->connectors[j] == drmmode_output->output_id) {
3731				found = TRUE;
3732				break;
3733			}
3734		}
3735		if (found)
3736			continue;
3737
3738		drmModeFreeConnector(drmmode_output->mode_output);
3739		drmmode_output->mode_output = NULL;
3740		drmmode_output->output_id = -1;
3741
3742		changed = TRUE;
3743		if (drmmode->delete_dp_12_displays) {
3744			RROutputDestroy(output->randr_output);
3745			xf86OutputDestroy(output);
3746			goto restart_destroy;
3747		}
3748	}
3749
3750	/* find new output ids we don't have outputs for */
3751	for (i = 0; i < mode_res->count_connectors; i++) {
3752		if (drmmode_find_output(pAMDGPUEnt->primary_scrn,
3753					mode_res->connectors[i],
3754					&num_dvi, &num_hdmi) ||
3755		    (pAMDGPUEnt->secondary_scrn &&
3756		     drmmode_find_output(pAMDGPUEnt->secondary_scrn,
3757					 mode_res->connectors[i],
3758					 &num_dvi, &num_hdmi)))
3759			continue;
3760
3761		if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi,
3762					&num_hdmi, 1) != 0)
3763			changed = TRUE;
3764	}
3765
3766	/* Check to see if a lessee has disappeared */
3767	drmmode_validate_leases(scrn);
3768
3769	if (changed && dixPrivateKeyRegistered(rrPrivKey)) {
3770#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0)
3771		RRSetChanged(xf86ScrnToScreen(scrn));
3772#else
3773		rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen);
3774		rrScrPriv->changed = TRUE;
3775#endif
3776		RRTellChanged(xf86ScrnToScreen(scrn));
3777	}
3778
3779	drmModeFreeResources(mode_res);
3780out:
3781	RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
3782}
3783
3784#ifdef HAVE_LIBUDEV
3785static void drmmode_handle_uevents(int fd, void *closure)
3786{
3787	drmmode_ptr drmmode = closure;
3788	ScrnInfoPtr scrn = drmmode->scrn;
3789	struct udev_device *dev;
3790	Bool received = FALSE;
3791	struct timeval tv = { 0, 0 };
3792	fd_set readfd;
3793
3794	FD_ZERO(&readfd);
3795	FD_SET(fd, &readfd);
3796
3797	while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 &&
3798	       FD_ISSET(fd, &readfd)) {
3799		/* select() ensured that this will not block */
3800		dev = udev_monitor_receive_device(drmmode->uevent_monitor);
3801		if (dev) {
3802			udev_device_unref(dev);
3803			received = TRUE;
3804		}
3805	}
3806
3807	if (received)
3808		amdgpu_mode_hotplug(scrn, drmmode);
3809}
3810#endif
3811
3812void drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3813{
3814#ifdef HAVE_LIBUDEV
3815	struct udev *u;
3816	struct udev_monitor *mon;
3817
3818	u = udev_new();
3819	if (!u)
3820		return;
3821	mon = udev_monitor_new_from_netlink(u, "udev");
3822	if (!mon) {
3823		udev_unref(u);
3824		return;
3825	}
3826
3827	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
3828							    "drm",
3829							    "drm_minor") < 0 ||
3830	    udev_monitor_enable_receiving(mon) < 0) {
3831		udev_monitor_unref(mon);
3832		udev_unref(u);
3833		return;
3834	}
3835
3836	drmmode->uevent_handler =
3837	    xf86AddGeneralHandler(udev_monitor_get_fd(mon),
3838				  drmmode_handle_uevents, drmmode);
3839
3840	drmmode->uevent_monitor = mon;
3841#endif
3842}
3843
3844void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3845{
3846#ifdef HAVE_LIBUDEV
3847	if (drmmode->uevent_handler) {
3848		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
3849		xf86RemoveGeneralHandler(drmmode->uevent_handler);
3850
3851		udev_monitor_unref(drmmode->uevent_monitor);
3852		udev_unref(u);
3853	}
3854#endif
3855}
3856
3857Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
3858			PixmapPtr new_front, uint64_t id, void *data,
3859			xf86CrtcPtr ref_crtc, amdgpu_drm_handler_proc handler,
3860			amdgpu_drm_abort_proc abort,
3861			enum drmmode_flip_sync flip_sync,
3862			uint32_t target_msc)
3863{
3864	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
3865	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
3866	xf86CrtcPtr crtc = NULL;
3867	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
3868	uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0;
3869	drmmode_flipdata_ptr flipdata;
3870	Bool handle_deferred = FALSE;
3871	uintptr_t drm_queue_seq = 0;
3872	struct drmmode_fb *fb;
3873	int i = 0;
3874
3875	flipdata = calloc(1, sizeof(*flipdata) + config->num_crtc *
3876			  sizeof(flipdata->fb[0]));
3877	if (!flipdata) {
3878		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
3879			   "flip queue: data alloc failed.\n");
3880		goto error;
3881	}
3882
3883	fb = amdgpu_pixmap_get_fb(new_front);
3884	if (!fb) {
3885		ErrorF("Failed to get FB for flip\n");
3886		goto error;
3887	}
3888
3889	/*
3890	 * Queue flips on all enabled CRTCs
3891	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
3892	 * Right now it assumes a single shared fb across all CRTCs, with the
3893	 * kernel fixing up the offset of each CRTC as necessary.
3894	 *
3895	 * Also, flips queued on disabled or incorrectly configured displays
3896	 * may never complete; this is a configuration error.
3897	 */
3898
3899	flipdata->event_data = data;
3900	flipdata->handler = handler;
3901	flipdata->abort = abort;
3902	flipdata->fe_crtc = ref_crtc;
3903
3904	for (i = 0; i < config->num_crtc; i++) {
3905		crtc = config->crtc[i];
3906		drmmode_crtc = crtc->driver_private;
3907
3908		if (!drmmode_crtc_can_flip(crtc) ||
3909		    (drmmode_crtc->tear_free && crtc != ref_crtc))
3910			continue;
3911
3912		flipdata->flip_count++;
3913
3914		drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id,
3915						       flipdata,
3916						       drmmode_flip_handler,
3917						       drmmode_flip_abort);
3918		if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
3919			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
3920				   "Allocating DRM queue event entry failed.\n");
3921			goto error;
3922		}
3923
3924		if (drmmode_crtc->tear_free) {
3925			BoxRec extents = { .x1 = 0, .y1 = 0,
3926					   .x2 = new_front->drawable.width,
3927					   .y2 = new_front->drawable.height };
3928			int scanout_id = drmmode_crtc->scanout_id ^ 1;
3929
3930			if (flip_sync == FLIP_ASYNC) {
3931				if (!drmmode_wait_vblank(crtc,
3932							 DRM_VBLANK_RELATIVE |
3933							 DRM_VBLANK_EVENT,
3934							 0, drm_queue_seq,
3935							 NULL, NULL))
3936					goto flip_error;
3937				goto next;
3938			}
3939
3940			drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[i],
3941					     amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap));
3942			if (!flipdata->fb[i]) {
3943				ErrorF("Failed to get FB for TearFree flip\n");
3944				goto error;
3945			}
3946
3947			amdgpu_scanout_do_update(crtc, scanout_id, new_front,
3948						 extents);
3949			amdgpu_glamor_flush(crtc->scrn);
3950
3951			if (drmmode_crtc->scanout_update_pending) {
3952				amdgpu_drm_wait_pending_flip(crtc);
3953				handle_deferred = TRUE;
3954				amdgpu_drm_abort_entry(drmmode_crtc->scanout_update_pending);
3955				drmmode_crtc->scanout_update_pending = 0;
3956			}
3957		} else {
3958			drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb[i], fb);
3959		}
3960
3961		if (crtc == ref_crtc) {
3962			if (drmmode_page_flip_target_absolute(pAMDGPUEnt,
3963							      drmmode_crtc,
3964							      flipdata->fb[i]->handle,
3965							      flip_flags,
3966							      drm_queue_seq,
3967							      target_msc) != 0)
3968				goto flip_error;
3969		} else {
3970			if (drmmode_page_flip_target_relative(pAMDGPUEnt,
3971							      drmmode_crtc,
3972							      flipdata->fb[i]->handle,
3973							      flip_flags,
3974							      drm_queue_seq, 0) != 0)
3975				goto flip_error;
3976		}
3977
3978		if (drmmode_crtc->tear_free) {
3979			drmmode_crtc->scanout_id ^= 1;
3980			drmmode_crtc->ignore_damage = TRUE;
3981		}
3982
3983	next:
3984		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
3985				     flipdata->fb[i]);
3986		drm_queue_seq = 0;
3987	}
3988
3989	if (handle_deferred)
3990		amdgpu_drm_queue_handle_deferred(ref_crtc);
3991	if (flipdata->flip_count > 0)
3992		return TRUE;
3993
3994flip_error:
3995	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n",
3996		   strerror(errno));
3997
3998error:
3999	if (drm_queue_seq)
4000		amdgpu_drm_abort_entry(drm_queue_seq);
4001	else if (crtc)
4002		drmmode_flip_abort(crtc, flipdata);
4003	else {
4004		abort(NULL, data);
4005		free(flipdata);
4006	}
4007
4008	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
4009		   strerror(errno));
4010	if (handle_deferred)
4011		amdgpu_drm_queue_handle_deferred(ref_crtc);
4012	return FALSE;
4013}
4014