drmmode_display.c revision 24b90cf4
1d6c0b56eSmrg/*
2d6c0b56eSmrg * Copyright © 2007 Red Hat, Inc.
3d6c0b56eSmrg *
4d6c0b56eSmrg * Permission is hereby granted, free of charge, to any person obtaining a
5d6c0b56eSmrg * copy of this software and associated documentation files (the "Software"),
6d6c0b56eSmrg * to deal in the Software without restriction, including without limitation
7d6c0b56eSmrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8d6c0b56eSmrg * and/or sell copies of the Software, and to permit persons to whom the
9d6c0b56eSmrg * Software is furnished to do so, subject to the following conditions:
10d6c0b56eSmrg *
11d6c0b56eSmrg * The above copyright notice and this permission notice (including the next
12d6c0b56eSmrg * paragraph) shall be included in all copies or substantial portions of the
13d6c0b56eSmrg * Software.
14d6c0b56eSmrg *
15d6c0b56eSmrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16d6c0b56eSmrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17d6c0b56eSmrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18d6c0b56eSmrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19d6c0b56eSmrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20d6c0b56eSmrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21d6c0b56eSmrg * SOFTWARE.
22d6c0b56eSmrg *
23d6c0b56eSmrg * Authors:
24d6c0b56eSmrg *    Dave Airlie <airlied@redhat.com>
25d6c0b56eSmrg *
26d6c0b56eSmrg */
27d6c0b56eSmrg
28d6c0b56eSmrg#ifdef HAVE_CONFIG_H
29d6c0b56eSmrg#include "config.h"
30d6c0b56eSmrg#endif
31d6c0b56eSmrg
32d6c0b56eSmrg#include <errno.h>
33d6c0b56eSmrg#include <sys/ioctl.h>
34d6c0b56eSmrg#include <time.h>
35d6c0b56eSmrg#include "cursorstr.h"
36d6c0b56eSmrg#include "damagestr.h"
3724b90cf4Smrg#include "inputstr.h"
3824b90cf4Smrg#include "list.h"
39d6c0b56eSmrg#include "micmap.h"
40d6c0b56eSmrg#include "xf86cmap.h"
41504d986fSmrg#include "xf86Priv.h"
42d6c0b56eSmrg#include "sarea.h"
43d6c0b56eSmrg
44d6c0b56eSmrg#include "drmmode_display.h"
45d6c0b56eSmrg#include "amdgpu_bo_helper.h"
46d6c0b56eSmrg#include "amdgpu_glamor.h"
47d6c0b56eSmrg#include "amdgpu_pixmap.h"
48d6c0b56eSmrg
49d6c0b56eSmrg#include <dri.h>
50d6c0b56eSmrg
51d6c0b56eSmrg/* DPMS */
52d6c0b56eSmrg#ifdef HAVE_XEXTPROTO_71
53d6c0b56eSmrg#include <X11/extensions/dpmsconst.h>
54d6c0b56eSmrg#else
55d6c0b56eSmrg#define DPMS_SERVER
56d6c0b56eSmrg#include <X11/extensions/dpms.h>
57d6c0b56eSmrg#endif
58d6c0b56eSmrg
59d6c0b56eSmrg#include <gbm.h>
60d6c0b56eSmrg
61d6c0b56eSmrg#define DEFAULT_NOMINAL_FRAME_RATE 60
62d6c0b56eSmrg
63d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
64d6c0b56eSmrg
65d6c0b56eSmrgstatic Bool
66d6c0b56eSmrgAMDGPUZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name)
67d6c0b56eSmrg{
68d6c0b56eSmrg	int i = 0;
69d6c0b56eSmrg	char s1[20];
70d6c0b56eSmrg
71d6c0b56eSmrg	do {
72d6c0b56eSmrg		switch (*s) {
73d6c0b56eSmrg		case ',':
74d6c0b56eSmrg			s1[i] = '\0';
75d6c0b56eSmrg			i = 0;
76d6c0b56eSmrg			if (strcmp(s1, output_name) == 0)
77d6c0b56eSmrg				return TRUE;
78d6c0b56eSmrg			break;
79d6c0b56eSmrg		case ' ':
80d6c0b56eSmrg		case '\t':
81d6c0b56eSmrg		case '\n':
82d6c0b56eSmrg		case '\r':
83d6c0b56eSmrg			break;
84d6c0b56eSmrg		default:
85d6c0b56eSmrg			s1[i] = *s;
86d6c0b56eSmrg			i++;
87d6c0b56eSmrg			break;
88d6c0b56eSmrg		}
89d6c0b56eSmrg	} while (*s++);
90d6c0b56eSmrg
91d6c0b56eSmrg	s1[i] = '\0';
92d6c0b56eSmrg	if (strcmp(s1, output_name) == 0)
93d6c0b56eSmrg		return TRUE;
94d6c0b56eSmrg
95d6c0b56eSmrg	return FALSE;
96d6c0b56eSmrg}
97d6c0b56eSmrg
9824b90cf4Smrg
9924b90cf4Smrg/* Wait for the boolean condition to be FALSE */
10024b90cf4Smrg#define drmmode_crtc_wait_pending_event(drmmode_crtc, fd, condition) \
10124b90cf4Smrg	do {} while ((condition) && \
10224b90cf4Smrg		     drmHandleEvent(fd, &drmmode_crtc->drmmode->event_context) \
10324b90cf4Smrg		     > 0);
10424b90cf4Smrg
10524b90cf4Smrg
106d6c0b56eSmrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
107d6c0b56eSmrg					  int width, int height,
108d6c0b56eSmrg					  int depth, int bpp,
109d6c0b56eSmrg					  int pitch,
110d6c0b56eSmrg					  struct amdgpu_buffer *bo)
111d6c0b56eSmrg{
112d6c0b56eSmrg	ScreenPtr pScreen = pScrn->pScreen;
113d6c0b56eSmrg	PixmapPtr pixmap;
114d6c0b56eSmrg
115d6c0b56eSmrg	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth,
116d6c0b56eSmrg					  AMDGPU_CREATE_PIXMAP_SCANOUT);
117d6c0b56eSmrg	if (!pixmap)
118d6c0b56eSmrg		return NULL;
119d6c0b56eSmrg
120d6c0b56eSmrg	if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height,
121504d986fSmrg					     depth, bpp, pitch, NULL))
122504d986fSmrg		goto fail;
123d6c0b56eSmrg
124504d986fSmrg	if (!amdgpu_glamor_create_textured_pixmap(pixmap, bo))
125504d986fSmrg		goto fail;
126d6c0b56eSmrg
127504d986fSmrg	if (amdgpu_set_pixmap_bo(pixmap, bo))
128504d986fSmrg		return pixmap;
129d6c0b56eSmrg
130504d986fSmrgfail:
131504d986fSmrg	pScreen->DestroyPixmap(pixmap);
132504d986fSmrg	return NULL;
133d6c0b56eSmrg}
134d6c0b56eSmrg
135d6c0b56eSmrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
136d6c0b56eSmrg{
137d6c0b56eSmrg	ScreenPtr pScreen = pixmap->drawable.pScreen;
138d6c0b56eSmrg
139d6c0b56eSmrg	(*pScreen->DestroyPixmap) (pixmap);
140d6c0b56eSmrg}
141d6c0b56eSmrg
142d6c0b56eSmrgstatic void
143d6c0b56eSmrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn,
144d6c0b56eSmrg			 drmModeModeInfo * kmode, DisplayModePtr mode)
145d6c0b56eSmrg{
146d6c0b56eSmrg	memset(mode, 0, sizeof(DisplayModeRec));
147d6c0b56eSmrg	mode->status = MODE_OK;
148d6c0b56eSmrg
149d6c0b56eSmrg	mode->Clock = kmode->clock;
150d6c0b56eSmrg
151d6c0b56eSmrg	mode->HDisplay = kmode->hdisplay;
152d6c0b56eSmrg	mode->HSyncStart = kmode->hsync_start;
153d6c0b56eSmrg	mode->HSyncEnd = kmode->hsync_end;
154d6c0b56eSmrg	mode->HTotal = kmode->htotal;
155d6c0b56eSmrg	mode->HSkew = kmode->hskew;
156d6c0b56eSmrg
157d6c0b56eSmrg	mode->VDisplay = kmode->vdisplay;
158d6c0b56eSmrg	mode->VSyncStart = kmode->vsync_start;
159d6c0b56eSmrg	mode->VSyncEnd = kmode->vsync_end;
160d6c0b56eSmrg	mode->VTotal = kmode->vtotal;
161d6c0b56eSmrg	mode->VScan = kmode->vscan;
162d6c0b56eSmrg
163d6c0b56eSmrg	mode->Flags = kmode->flags;	//& FLAG_BITS;
164d6c0b56eSmrg	mode->name = strdup(kmode->name);
165d6c0b56eSmrg
166d6c0b56eSmrg	if (kmode->type & DRM_MODE_TYPE_DRIVER)
167d6c0b56eSmrg		mode->type = M_T_DRIVER;
168d6c0b56eSmrg	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
169d6c0b56eSmrg		mode->type |= M_T_PREFERRED;
170d6c0b56eSmrg	xf86SetModeCrtc(mode, scrn->adjustFlags);
171d6c0b56eSmrg}
172d6c0b56eSmrg
173d6c0b56eSmrgstatic void
174d6c0b56eSmrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn,
175d6c0b56eSmrg		       drmModeModeInfo * kmode, DisplayModePtr mode)
176d6c0b56eSmrg{
177d6c0b56eSmrg	memset(kmode, 0, sizeof(*kmode));
178d6c0b56eSmrg
179d6c0b56eSmrg	kmode->clock = mode->Clock;
180d6c0b56eSmrg	kmode->hdisplay = mode->HDisplay;
181d6c0b56eSmrg	kmode->hsync_start = mode->HSyncStart;
182d6c0b56eSmrg	kmode->hsync_end = mode->HSyncEnd;
183d6c0b56eSmrg	kmode->htotal = mode->HTotal;
184d6c0b56eSmrg	kmode->hskew = mode->HSkew;
185d6c0b56eSmrg
186d6c0b56eSmrg	kmode->vdisplay = mode->VDisplay;
187d6c0b56eSmrg	kmode->vsync_start = mode->VSyncStart;
188d6c0b56eSmrg	kmode->vsync_end = mode->VSyncEnd;
189d6c0b56eSmrg	kmode->vtotal = mode->VTotal;
190d6c0b56eSmrg	kmode->vscan = mode->VScan;
191d6c0b56eSmrg
192d6c0b56eSmrg	kmode->flags = mode->Flags;	//& FLAG_BITS;
193d6c0b56eSmrg	if (mode->name)
194d6c0b56eSmrg		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
195d6c0b56eSmrg	kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0;
196d6c0b56eSmrg
197d6c0b56eSmrg}
198d6c0b56eSmrg
19924b90cf4Smrg/*
20024b90cf4Smrg * Utility helper for drmWaitVBlank
20124b90cf4Smrg */
20224b90cf4SmrgBool
20324b90cf4Smrgdrmmode_wait_vblank(xf86CrtcPtr crtc, drmVBlankSeqType type,
20424b90cf4Smrg		    uint32_t target_seq, unsigned long signal, uint64_t *ust,
20524b90cf4Smrg		    uint32_t *result_seq)
20624b90cf4Smrg{
20724b90cf4Smrg	int crtc_id = drmmode_get_crtc_id(crtc);
20824b90cf4Smrg	ScrnInfoPtr scrn = crtc->scrn;
20924b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
21024b90cf4Smrg	drmVBlank vbl;
21124b90cf4Smrg
21224b90cf4Smrg	if (crtc_id == 1)
21324b90cf4Smrg		type |= DRM_VBLANK_SECONDARY;
21424b90cf4Smrg	else if (crtc_id > 1)
21524b90cf4Smrg		type |= (crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT) &
21624b90cf4Smrg			DRM_VBLANK_HIGH_CRTC_MASK;
21724b90cf4Smrg
21824b90cf4Smrg	vbl.request.type = type;
21924b90cf4Smrg	vbl.request.sequence = target_seq;
22024b90cf4Smrg	vbl.request.signal = signal;
22124b90cf4Smrg
22224b90cf4Smrg	if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl) != 0)
22324b90cf4Smrg		return FALSE;
22424b90cf4Smrg
22524b90cf4Smrg	if (ust)
22624b90cf4Smrg		*ust = (uint64_t)vbl.reply.tval_sec * 1000000 +
22724b90cf4Smrg			vbl.reply.tval_usec;
22824b90cf4Smrg	if (result_seq)
22924b90cf4Smrg		*result_seq = vbl.reply.sequence;
23024b90cf4Smrg
23124b90cf4Smrg	return TRUE;
23224b90cf4Smrg}
23324b90cf4Smrg
234d6c0b56eSmrg/*
235d6c0b56eSmrg * Retrieves present time in microseconds that is compatible
236d6c0b56eSmrg * with units used by vblank timestamps. Depending on the kernel
237d6c0b56eSmrg * version and DRM kernel module configuration, the vblank
238d6c0b56eSmrg * timestamp can either be in real time or monotonic time
239d6c0b56eSmrg */
240d6c0b56eSmrgint drmmode_get_current_ust(int drm_fd, CARD64 * ust)
241d6c0b56eSmrg{
242d6c0b56eSmrg	uint64_t cap_value;
243d6c0b56eSmrg	int ret;
244d6c0b56eSmrg	struct timespec now;
245d6c0b56eSmrg
246d6c0b56eSmrg	ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value);
247d6c0b56eSmrg	if (ret || !cap_value)
248d6c0b56eSmrg		/* old kernel or drm_timestamp_monotonic turned off */
249d6c0b56eSmrg		ret = clock_gettime(CLOCK_REALTIME, &now);
250d6c0b56eSmrg	else
251d6c0b56eSmrg		ret = clock_gettime(CLOCK_MONOTONIC, &now);
252d6c0b56eSmrg	if (ret)
253d6c0b56eSmrg		return ret;
254d6c0b56eSmrg	*ust = ((CARD64) now.tv_sec * 1000000) + ((CARD64) now.tv_nsec / 1000);
255d6c0b56eSmrg	return 0;
256d6c0b56eSmrg}
257d6c0b56eSmrg
258d6c0b56eSmrg/*
259d6c0b56eSmrg * Get current frame count and frame count timestamp of the crtc.
260d6c0b56eSmrg */
261d6c0b56eSmrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)
262d6c0b56eSmrg{
263d6c0b56eSmrg	ScrnInfoPtr scrn = crtc->scrn;
26424b90cf4Smrg	uint32_t seq;
265d6c0b56eSmrg
26624b90cf4Smrg	if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, ust, &seq)) {
267d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
268d6c0b56eSmrg			   "get vblank counter failed: %s\n", strerror(errno));
26924b90cf4Smrg		return -1;
270d6c0b56eSmrg	}
271d6c0b56eSmrg
27224b90cf4Smrg	*msc = seq;
273d6c0b56eSmrg
274d6c0b56eSmrg	return Success;
275d6c0b56eSmrg}
276d6c0b56eSmrg
277d6c0b56eSmrgstatic void
278d6c0b56eSmrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
279d6c0b56eSmrg{
280d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
281d6c0b56eSmrg	ScrnInfoPtr scrn = crtc->scrn;
282d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
283d6c0b56eSmrg	CARD64 ust;
284d6c0b56eSmrg	int ret;
285d6c0b56eSmrg
286d6c0b56eSmrg	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
28724b90cf4Smrg		uint32_t seq;
288d6c0b56eSmrg
28924b90cf4Smrg		drmmode_crtc_wait_pending_event(drmmode_crtc, pAMDGPUEnt->fd,
29024b90cf4Smrg						drmmode_crtc->flip_pending);
291504d986fSmrg
292d6c0b56eSmrg		/*
293d6c0b56eSmrg		 * On->Off transition: record the last vblank time,
294d6c0b56eSmrg		 * sequence number and frame period.
295d6c0b56eSmrg		 */
29624b90cf4Smrg		if (!drmmode_wait_vblank(crtc, DRM_VBLANK_RELATIVE, 0, 0, &ust,
29724b90cf4Smrg					 &seq))
298d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
299d6c0b56eSmrg				   "%s cannot get last vblank counter\n",
300d6c0b56eSmrg				   __func__);
301d6c0b56eSmrg		else {
302d6c0b56eSmrg			CARD64 nominal_frame_rate, pix_in_frame;
303d6c0b56eSmrg
304d6c0b56eSmrg			drmmode_crtc->dpms_last_ust = ust;
305d6c0b56eSmrg			drmmode_crtc->dpms_last_seq = seq;
306d6c0b56eSmrg			nominal_frame_rate = crtc->mode.Clock;
307d6c0b56eSmrg			nominal_frame_rate *= 1000;
308d6c0b56eSmrg			pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal;
309d6c0b56eSmrg			if (nominal_frame_rate == 0 || pix_in_frame == 0)
310d6c0b56eSmrg				nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE;
311d6c0b56eSmrg			else
312d6c0b56eSmrg				nominal_frame_rate /= pix_in_frame;
313d6c0b56eSmrg			drmmode_crtc->dpms_last_fps = nominal_frame_rate;
314d6c0b56eSmrg		}
315d6c0b56eSmrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) {
316d6c0b56eSmrg		/*
317d6c0b56eSmrg		 * Off->On transition: calculate and accumulate the
318d6c0b56eSmrg		 * number of interpolated vblanks while we were in Off state
319d6c0b56eSmrg		 */
320d6c0b56eSmrg		ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust);
321d6c0b56eSmrg		if (ret)
322d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
323d6c0b56eSmrg				   "%s cannot get current time\n", __func__);
324d6c0b56eSmrg		else if (drmmode_crtc->dpms_last_ust) {
325d6c0b56eSmrg			CARD64 time_elapsed, delta_seq;
326d6c0b56eSmrg			time_elapsed = ust - drmmode_crtc->dpms_last_ust;
327d6c0b56eSmrg			delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps;
328d6c0b56eSmrg			delta_seq /= 1000000;
329d6c0b56eSmrg			drmmode_crtc->interpolated_vblanks += delta_seq;
330d6c0b56eSmrg
331d6c0b56eSmrg		}
332d6c0b56eSmrg	}
333d6c0b56eSmrg	drmmode_crtc->dpms_mode = mode;
334d6c0b56eSmrg}
335d6c0b56eSmrg
336d6c0b56eSmrgstatic void
337d6c0b56eSmrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
338d6c0b56eSmrg{
339d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
340d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
341d6c0b56eSmrg
342d6c0b56eSmrg	/* Disable unused CRTCs and enable/disable active CRTCs */
343504d986fSmrg	if (!crtc->enabled || mode != DPMSModeOn) {
34424b90cf4Smrg		drmmode_crtc_wait_pending_event(drmmode_crtc, pAMDGPUEnt->fd,
34524b90cf4Smrg						drmmode_crtc->flip_pending);
346d6c0b56eSmrg		drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
347d6c0b56eSmrg			       0, 0, 0, NULL, 0, NULL);
34824b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL);
349504d986fSmrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn)
350d6c0b56eSmrg		crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
351d6c0b56eSmrg					    crtc->x, crtc->y);
352d6c0b56eSmrg}
353d6c0b56eSmrg
354d6c0b56eSmrgstatic PixmapPtr
355d6c0b56eSmrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode,
356d6c0b56eSmrg			ScrnInfoPtr pScrn, int fbcon_id)
357d6c0b56eSmrg{
358d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
359d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
360d6c0b56eSmrg	PixmapPtr pixmap = info->fbcon_pixmap;
361d6c0b56eSmrg	struct amdgpu_buffer *bo;
362d6c0b56eSmrg	drmModeFBPtr fbcon;
363d6c0b56eSmrg	struct drm_gem_flink flink;
364d6c0b56eSmrg	struct amdgpu_bo_import_result import = {0};
365d6c0b56eSmrg
366d6c0b56eSmrg	if (pixmap)
367d6c0b56eSmrg		return pixmap;
368d6c0b56eSmrg
369d6c0b56eSmrg	fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id);
370d6c0b56eSmrg	if (fbcon == NULL)
371d6c0b56eSmrg		return NULL;
372d6c0b56eSmrg
373d6c0b56eSmrg	if (fbcon->depth != pScrn->depth ||
374d6c0b56eSmrg	    fbcon->width != pScrn->virtualX ||
375d6c0b56eSmrg	    fbcon->height != pScrn->virtualY)
376d6c0b56eSmrg		goto out_free_fb;
377d6c0b56eSmrg
378d6c0b56eSmrg	flink.handle = fbcon->handle;
379d6c0b56eSmrg	if (ioctl(pAMDGPUEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
380d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
381d6c0b56eSmrg			   "Couldn't flink fbcon handle\n");
382d6c0b56eSmrg		goto out_free_fb;
383d6c0b56eSmrg	}
384d6c0b56eSmrg
385d6c0b56eSmrg	bo = calloc(1, sizeof(struct amdgpu_buffer));
386d6c0b56eSmrg	if (bo == NULL) {
387d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
388d6c0b56eSmrg			   "Couldn't allocate bo for fbcon handle\n");
389d6c0b56eSmrg		goto out_free_fb;
390d6c0b56eSmrg	}
391d6c0b56eSmrg	bo->ref_count = 1;
392d6c0b56eSmrg
393d6c0b56eSmrg	if (amdgpu_bo_import(pAMDGPUEnt->pDev,
394d6c0b56eSmrg			     amdgpu_bo_handle_type_gem_flink_name, flink.name,
395d6c0b56eSmrg			     &import) != 0) {
396d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
397d6c0b56eSmrg			   "Couldn't import BO for fbcon handle\n");
398d6c0b56eSmrg		goto out_free_bo;
399d6c0b56eSmrg	}
400d6c0b56eSmrg	bo->bo.amdgpu = import.buf_handle;
401d6c0b56eSmrg
402d6c0b56eSmrg	pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height,
403d6c0b56eSmrg					  fbcon->depth, fbcon->bpp,
404d6c0b56eSmrg					  fbcon->pitch, bo);
405d6c0b56eSmrg	info->fbcon_pixmap = pixmap;
406d6c0b56eSmrgout_free_bo:
407d6c0b56eSmrg	amdgpu_bo_unref(&bo);
408d6c0b56eSmrgout_free_fb:
409d6c0b56eSmrg	drmModeFreeFB(fbcon);
410d6c0b56eSmrg	return pixmap;
411d6c0b56eSmrg}
412d6c0b56eSmrg
413d6c0b56eSmrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
414d6c0b56eSmrg{
415d6c0b56eSmrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
416d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
417d6c0b56eSmrg	ScreenPtr pScreen = pScrn->pScreen;
41824b90cf4Smrg	PixmapPtr src, dst = pScreen->GetScreenPixmap(pScreen);
41924b90cf4Smrg	struct drmmode_fb *fb = amdgpu_pixmap_get_fb(dst);
420d6c0b56eSmrg	int fbcon_id = 0;
421d6c0b56eSmrg	GCPtr gc;
422d6c0b56eSmrg	int i;
423d6c0b56eSmrg
424d6c0b56eSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
425d6c0b56eSmrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
426d6c0b56eSmrg
427d6c0b56eSmrg		if (drmmode_crtc->mode_crtc->buffer_id)
428d6c0b56eSmrg			fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
429d6c0b56eSmrg	}
430d6c0b56eSmrg
431d6c0b56eSmrg	if (!fbcon_id)
432d6c0b56eSmrg		return;
433d6c0b56eSmrg
43424b90cf4Smrg	if (fbcon_id == fb->handle) {
435d6c0b56eSmrg		/* in some rare case there might be no fbcon and we might already
436d6c0b56eSmrg		 * be the one with the current fb to avoid a false deadlck in
437d6c0b56eSmrg		 * kernel ttm code just do nothing as anyway there is nothing
438d6c0b56eSmrg		 * to do
439d6c0b56eSmrg		 */
440d6c0b56eSmrg		return;
441d6c0b56eSmrg	}
442d6c0b56eSmrg
443d6c0b56eSmrg	src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
444d6c0b56eSmrg	if (!src)
445d6c0b56eSmrg		return;
446d6c0b56eSmrg
447d6c0b56eSmrg	gc = GetScratchGC(pScrn->depth, pScreen);
448d6c0b56eSmrg	ValidateGC(&dst->drawable, gc);
449d6c0b56eSmrg
450d6c0b56eSmrg	(*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0,
451d6c0b56eSmrg			     pScrn->virtualX, pScrn->virtualY, 0, 0);
452d6c0b56eSmrg
453d6c0b56eSmrg	FreeScratchGC(gc);
454d6c0b56eSmrg
455d6c0b56eSmrg	pScreen->canDoBGNoneRoot = TRUE;
456d6c0b56eSmrg
457d6c0b56eSmrg	if (info->fbcon_pixmap)
458d6c0b56eSmrg		pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap);
459d6c0b56eSmrg	info->fbcon_pixmap = NULL;
460d6c0b56eSmrg
461d6c0b56eSmrg	return;
462d6c0b56eSmrg}
463d6c0b56eSmrg
46424b90cf4Smrgvoid
465d6c0b56eSmrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
466d6c0b56eSmrg			     struct drmmode_scanout *scanout)
467d6c0b56eSmrg{
468d6c0b56eSmrg
469d6c0b56eSmrg	if (scanout->pixmap) {
470d6c0b56eSmrg		drmmode_destroy_bo_pixmap(scanout->pixmap);
471d6c0b56eSmrg		scanout->pixmap = NULL;
472d6c0b56eSmrg	}
473d6c0b56eSmrg
474d6c0b56eSmrg	if (scanout->bo) {
475d6c0b56eSmrg		amdgpu_bo_unref(&scanout->bo);
476d6c0b56eSmrg		scanout->bo = NULL;
477d6c0b56eSmrg	}
478504d986fSmrg}
479504d986fSmrg
48024b90cf4Smrgvoid
481504d986fSmrgdrmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc)
482504d986fSmrg{
48324b90cf4Smrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
48424b90cf4Smrg				     &drmmode_crtc->scanout[0]);
48524b90cf4Smrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
48624b90cf4Smrg				     &drmmode_crtc->scanout[1]);
487d6c0b56eSmrg
48824b90cf4Smrg	if (drmmode_crtc->scanout_damage)
489504d986fSmrg		DamageDestroy(drmmode_crtc->scanout_damage);
490d6c0b56eSmrg}
491d6c0b56eSmrg
49224b90cf4SmrgPixmapPtr
49311bf0794Smrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc, struct drmmode_scanout *scanout,
49411bf0794Smrg			    int width, int height)
495d6c0b56eSmrg{
496d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
497d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
498d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
49911bf0794Smrg	int pitch;
500d6c0b56eSmrg
50111bf0794Smrg	if (scanout->pixmap) {
502d6c0b56eSmrg		if (scanout->width == width && scanout->height == height)
50311bf0794Smrg			return scanout->pixmap;
504d6c0b56eSmrg
505d6c0b56eSmrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
506d6c0b56eSmrg	}
507d6c0b56eSmrg
508d6c0b56eSmrg	scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height,
50911bf0794Smrg					     pScrn->depth, 0,
51011bf0794Smrg					     pScrn->bitsPerPixel, &pitch);
511d6c0b56eSmrg	if (!scanout->bo) {
512d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
51311bf0794Smrg			   "Failed to allocate scanout buffer memory\n");
51424b90cf4Smrg		return NULL;
515d6c0b56eSmrg	}
516d6c0b56eSmrg
517d6c0b56eSmrg	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
518d6c0b56eSmrg						 width, height,
519d6c0b56eSmrg						 pScrn->depth,
520d6c0b56eSmrg						 pScrn->bitsPerPixel,
52111bf0794Smrg						 pitch, scanout->bo);
52224b90cf4Smrg	if (!scanout->pixmap) {
52324b90cf4Smrg		ErrorF("failed to create CRTC scanout pixmap\n");
52424b90cf4Smrg		goto error;
52524b90cf4Smrg	}
52624b90cf4Smrg
52724b90cf4Smrg	if (amdgpu_pixmap_get_fb(scanout->pixmap)) {
52811bf0794Smrg		scanout->width = width;
52911bf0794Smrg		scanout->height = height;
53011bf0794Smrg	} else {
53124b90cf4Smrg		ErrorF("failed to create CRTC scanout FB\n");
53224b90cf4Smrgerror:
53311bf0794Smrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
534d6c0b56eSmrg	}
535d6c0b56eSmrg
53611bf0794Smrg	return scanout->pixmap;
537d6c0b56eSmrg}
538d6c0b56eSmrg
539d6c0b56eSmrgstatic void
540d6c0b56eSmrgamdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
541d6c0b56eSmrg{
54224b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = closure;
54324b90cf4Smrg
54424b90cf4Smrg	if (drmmode_crtc->ignore_damage) {
54524b90cf4Smrg		RegionEmpty(&damage->damage);
54624b90cf4Smrg		drmmode_crtc->ignore_damage = FALSE;
54724b90cf4Smrg		return;
54824b90cf4Smrg	}
54924b90cf4Smrg
550d6c0b56eSmrg	/* Only keep track of the extents */
551d6c0b56eSmrg	RegionUninit(&damage->damage);
552d6c0b56eSmrg	damage->damage.data = NULL;
553d6c0b56eSmrg}
554d6c0b56eSmrg
55524b90cf4Smrgstatic void
55624b90cf4Smrgdrmmode_screen_damage_destroy(DamagePtr damage, void *closure)
55724b90cf4Smrg{
55824b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = closure;
55924b90cf4Smrg
56024b90cf4Smrg	drmmode_crtc->scanout_damage = NULL;
56124b90cf4Smrg	RegionUninit(&drmmode_crtc->scanout_last_region);
56224b90cf4Smrg}
56324b90cf4Smrg
564d6c0b56eSmrgstatic Bool
565d6c0b56eSmrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc)
566d6c0b56eSmrg{
567d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
568d6c0b56eSmrg
569d6c0b56eSmrg	/* Check for Option "SWcursor" */
570d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
571d6c0b56eSmrg		return FALSE;
572d6c0b56eSmrg
573d6c0b56eSmrg	/* Fall back to SW cursor if the CRTC is transformed */
574d6c0b56eSmrg	if (crtc->transformPresent)
575d6c0b56eSmrg		return FALSE;
576d6c0b56eSmrg
57724b90cf4Smrg#if XF86_CRTC_VERSION < 7
578d6c0b56eSmrg	/* Xorg doesn't correctly handle cursor position transform in the
579d6c0b56eSmrg	 * rotation case
580d6c0b56eSmrg	 */
581d6c0b56eSmrg	if (crtc->driverIsPerformingTransform &&
582d6c0b56eSmrg	    (crtc->rotation & 0xf) != RR_Rotate_0)
583d6c0b56eSmrg		return FALSE;
584d6c0b56eSmrg#endif
585d6c0b56eSmrg
586504d986fSmrg	/* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */
587504d986fSmrg	if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) &&
588504d986fSmrg	    !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list))
589d6c0b56eSmrg		return FALSE;
590d6c0b56eSmrg
591d6c0b56eSmrg	return TRUE;
592d6c0b56eSmrg}
593d6c0b56eSmrg
59411bf0794Smrgstatic void
59511bf0794Smrgdrmmode_crtc_update_tear_free(xf86CrtcPtr crtc)
59611bf0794Smrg{
59711bf0794Smrg	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
59811bf0794Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
59911bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
60011bf0794Smrg	int i;
60111bf0794Smrg
60211bf0794Smrg	drmmode_crtc->tear_free = FALSE;
60311bf0794Smrg
60411bf0794Smrg	for (i = 0; i < xf86_config->num_output; i++) {
60511bf0794Smrg		xf86OutputPtr output = xf86_config->output[i];
60611bf0794Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
60711bf0794Smrg
60811bf0794Smrg		if (output->crtc != crtc)
60911bf0794Smrg			continue;
61011bf0794Smrg
61111bf0794Smrg		if (drmmode_output->tear_free == 1 ||
61211bf0794Smrg		    (drmmode_output->tear_free == 2 &&
61324b90cf4Smrg		     (crtc->scrn->pScreen->isGPU ||
61411bf0794Smrg		      info->shadow_primary ||
61511bf0794Smrg		      crtc->transformPresent || crtc->rotation != RR_Rotate_0))) {
61611bf0794Smrg			drmmode_crtc->tear_free = TRUE;
61711bf0794Smrg			return;
61811bf0794Smrg		}
61911bf0794Smrg	}
62011bf0794Smrg}
62111bf0794Smrg
62211bf0794Smrg#if XF86_CRTC_VERSION < 7
62311bf0794Smrg#define XF86DriverTransformOutput TRUE
62411bf0794Smrg#define XF86DriverTransformNone FALSE
62511bf0794Smrg#endif
62611bf0794Smrg
627d6c0b56eSmrgstatic Bool
628d6c0b56eSmrgdrmmode_handle_transform(xf86CrtcPtr crtc)
629d6c0b56eSmrg{
630d6c0b56eSmrg	Bool ret;
631d6c0b56eSmrg
63224b90cf4Smrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
633504d986fSmrg	if (crtc->transformPresent || crtc->rotation != RR_Rotate_0)
634504d986fSmrg	    crtc->driverIsPerformingTransform = XF86DriverTransformOutput;
635504d986fSmrg	else
636504d986fSmrg	    crtc->driverIsPerformingTransform = XF86DriverTransformNone;
63724b90cf4Smrg#else
63824b90cf4Smrg	crtc->driverIsPerformingTransform = !crtc->transformPresent &&
63924b90cf4Smrg		crtc->rotation != RR_Rotate_0 &&
64024b90cf4Smrg		(crtc->rotation & 0xf) == RR_Rotate_0;
64124b90cf4Smrg#endif
642d6c0b56eSmrg
643d6c0b56eSmrg	ret = xf86CrtcRotate(crtc);
644d6c0b56eSmrg
645d6c0b56eSmrg	crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use;
646d6c0b56eSmrg
647d6c0b56eSmrg	return ret;
648d6c0b56eSmrg}
649d6c0b56eSmrg
65011bf0794Smrg
65111bf0794Smrgstatic void
65211bf0794Smrgdrmmode_crtc_prime_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
65324b90cf4Smrg				  unsigned scanout_id, struct drmmode_fb **fb,
65424b90cf4Smrg				  int *x, int *y)
65511bf0794Smrg{
65611bf0794Smrg	ScrnInfoPtr scrn = crtc->scrn;
65711bf0794Smrg	ScreenPtr screen = scrn->pScreen;
65811bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
65911bf0794Smrg
66011bf0794Smrg	if (drmmode_crtc->tear_free &&
66111bf0794Smrg	    !drmmode_crtc->scanout[1].pixmap) {
66211bf0794Smrg		RegionPtr region;
66311bf0794Smrg		BoxPtr box;
66411bf0794Smrg
66511bf0794Smrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
66611bf0794Smrg					    mode->HDisplay,
66711bf0794Smrg					    mode->VDisplay);
66811bf0794Smrg		region = &drmmode_crtc->scanout_last_region;
66911bf0794Smrg		RegionUninit(region);
67011bf0794Smrg		region->data = NULL;
67111bf0794Smrg		box = RegionExtents(region);
67211bf0794Smrg		box->x1 = crtc->x;
67311bf0794Smrg		box->y1 = crtc->y;
67411bf0794Smrg		box->x2 = crtc->x + mode->HDisplay;
67511bf0794Smrg		box->y2 = crtc->y + mode->VDisplay;
67611bf0794Smrg	}
67711bf0794Smrg
67811bf0794Smrg	if (scanout_id != drmmode_crtc->scanout_id) {
67911bf0794Smrg		PixmapDirtyUpdatePtr dirty = NULL;
68011bf0794Smrg
68111bf0794Smrg		xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list,
68211bf0794Smrg					 ent) {
68324b90cf4Smrg			if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
68411bf0794Smrg				dirty->slave_dst =
68511bf0794Smrg					drmmode_crtc->scanout[scanout_id].pixmap;
68611bf0794Smrg				break;
68711bf0794Smrg			}
68811bf0794Smrg		}
68911bf0794Smrg
69011bf0794Smrg		if (!drmmode_crtc->tear_free) {
69111bf0794Smrg			GCPtr gc = GetScratchGC(scrn->depth, screen);
69211bf0794Smrg
69311bf0794Smrg			ValidateGC(&drmmode_crtc->scanout[0].pixmap->drawable, gc);
69411bf0794Smrg			gc->ops->CopyArea(&drmmode_crtc->scanout[1].pixmap->drawable,
69511bf0794Smrg					  &drmmode_crtc->scanout[0].pixmap->drawable,
69611bf0794Smrg					  gc, 0, 0, mode->HDisplay, mode->VDisplay,
69711bf0794Smrg					  0, 0);
69811bf0794Smrg			FreeScratchGC(gc);
69911bf0794Smrg			amdgpu_glamor_finish(scrn);
70011bf0794Smrg		}
70111bf0794Smrg	}
70211bf0794Smrg
70324b90cf4Smrg	*fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
70411bf0794Smrg	*x = *y = 0;
70511bf0794Smrg	drmmode_crtc->scanout_id = scanout_id;
70611bf0794Smrg}
70711bf0794Smrg
70811bf0794Smrg
70911bf0794Smrgstatic void
71011bf0794Smrgdrmmode_crtc_scanout_update(xf86CrtcPtr crtc, DisplayModePtr mode,
71124b90cf4Smrg			    unsigned scanout_id, struct drmmode_fb **fb, int *x,
71224b90cf4Smrg			    int *y)
71311bf0794Smrg{
71411bf0794Smrg	ScrnInfoPtr scrn = crtc->scrn;
71511bf0794Smrg	ScreenPtr screen = scrn->pScreen;
71611bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
71711bf0794Smrg
71824b90cf4Smrg	drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[scanout_id],
71911bf0794Smrg				    mode->HDisplay, mode->VDisplay);
72011bf0794Smrg	if (drmmode_crtc->tear_free) {
72124b90cf4Smrg		drmmode_crtc_scanout_create(crtc,
72224b90cf4Smrg					    &drmmode_crtc->scanout[scanout_id ^ 1],
72311bf0794Smrg					    mode->HDisplay, mode->VDisplay);
72411bf0794Smrg	}
72511bf0794Smrg
72624b90cf4Smrg	if (drmmode_crtc->scanout[scanout_id].pixmap &&
72724b90cf4Smrg	    (!drmmode_crtc->tear_free ||
72824b90cf4Smrg	     drmmode_crtc->scanout[scanout_id ^ 1].pixmap)) {
72911bf0794Smrg		RegionPtr region;
73011bf0794Smrg		BoxPtr box;
73111bf0794Smrg
73211bf0794Smrg		if (!drmmode_crtc->scanout_damage) {
73311bf0794Smrg			drmmode_crtc->scanout_damage =
73411bf0794Smrg				DamageCreate(amdgpu_screen_damage_report,
73524b90cf4Smrg					     drmmode_screen_damage_destroy,
73624b90cf4Smrg					     DamageReportRawRegion,
73724b90cf4Smrg					     TRUE, screen, drmmode_crtc);
73824b90cf4Smrg			DamageRegister(&screen->root->drawable,
73911bf0794Smrg				       drmmode_crtc->scanout_damage);
74011bf0794Smrg		}
74111bf0794Smrg
74211bf0794Smrg		region = DamageRegion(drmmode_crtc->scanout_damage);
74311bf0794Smrg		RegionUninit(region);
74411bf0794Smrg		region->data = NULL;
74511bf0794Smrg		box = RegionExtents(region);
74611bf0794Smrg		box->x1 = 0;
74711bf0794Smrg		box->y1 = 0;
74811bf0794Smrg		box->x2 = max(box->x2, scrn->virtualX);
74911bf0794Smrg		box->y2 = max(box->y2, scrn->virtualY);
75011bf0794Smrg
75124b90cf4Smrg		*fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
75211bf0794Smrg		*x = *y = 0;
75311bf0794Smrg
75424b90cf4Smrg		amdgpu_scanout_do_update(crtc, scanout_id,
75524b90cf4Smrg					 screen->GetWindowPixmap(screen->root),
75624b90cf4Smrg					 box);
75711bf0794Smrg		amdgpu_glamor_finish(scrn);
75811bf0794Smrg	}
75911bf0794Smrg}
76011bf0794Smrg
76124b90cf4Smrgstatic void
76224b90cf4Smrgdrmmode_crtc_gamma_do_set(xf86CrtcPtr crtc, uint16_t *red, uint16_t *green,
76324b90cf4Smrg			  uint16_t *blue, int size)
76424b90cf4Smrg{
76524b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
76624b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
76724b90cf4Smrg
76824b90cf4Smrg	drmModeCrtcSetGamma(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
76924b90cf4Smrg			    size, red, green, blue);
77024b90cf4Smrg}
77124b90cf4Smrg
77224b90cf4SmrgBool
77324b90cf4Smrgdrmmode_set_mode(xf86CrtcPtr crtc, struct drmmode_fb *fb, DisplayModePtr mode,
77424b90cf4Smrg		 int x, int y)
77524b90cf4Smrg{
77624b90cf4Smrg	ScrnInfoPtr scrn = crtc->scrn;
77724b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
77824b90cf4Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
77924b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
78024b90cf4Smrg	uint32_t *output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
78124b90cf4Smrg	int output_count = 0;
78224b90cf4Smrg	drmModeModeInfo kmode;
78324b90cf4Smrg	Bool ret;
78424b90cf4Smrg	int i;
78524b90cf4Smrg
78624b90cf4Smrg	if (!output_ids)
78724b90cf4Smrg		return FALSE;
78824b90cf4Smrg
78924b90cf4Smrg	for (i = 0; i < xf86_config->num_output; i++) {
79024b90cf4Smrg		xf86OutputPtr output = xf86_config->output[i];
79124b90cf4Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
79224b90cf4Smrg
79324b90cf4Smrg		if (output->crtc != crtc)
79424b90cf4Smrg			continue;
79524b90cf4Smrg
79624b90cf4Smrg		output_ids[output_count] = drmmode_output->mode_output->connector_id;
79724b90cf4Smrg		output_count++;
79824b90cf4Smrg	}
79924b90cf4Smrg
80024b90cf4Smrg	drmmode_ConvertToKMode(scrn, &kmode, mode);
80124b90cf4Smrg
80224b90cf4Smrg	ret = drmModeSetCrtc(pAMDGPUEnt->fd,
80324b90cf4Smrg			     drmmode_crtc->mode_crtc->crtc_id,
80424b90cf4Smrg			     fb->handle, x, y, output_ids,
80524b90cf4Smrg			     output_count, &kmode) == 0;
80624b90cf4Smrg
80724b90cf4Smrg	if (ret) {
80824b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb);
80924b90cf4Smrg	} else {
81024b90cf4Smrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
81124b90cf4Smrg			   "failed to set mode: %s\n", strerror(errno));
81224b90cf4Smrg	}
81324b90cf4Smrg
81424b90cf4Smrg	free(output_ids);
81524b90cf4Smrg	return ret;
81624b90cf4Smrg}
81724b90cf4Smrg
818d6c0b56eSmrgstatic Bool
819d6c0b56eSmrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
820d6c0b56eSmrg		       Rotation rotation, int x, int y)
821d6c0b56eSmrg{
822d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
823d6c0b56eSmrg	ScreenPtr pScreen = pScrn->pScreen;
824d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
825d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
826d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
827d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
82811bf0794Smrg	unsigned scanout_id = 0;
829d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
830d6c0b56eSmrg	int saved_x, saved_y;
831d6c0b56eSmrg	Rotation saved_rotation;
832d6c0b56eSmrg	DisplayModeRec saved_mode;
833504d986fSmrg	Bool ret = FALSE;
834d6c0b56eSmrg	int i;
83524b90cf4Smrg	struct drmmode_fb *fb = NULL;
83624b90cf4Smrg
83724b90cf4Smrg	/* The root window contents may be undefined before the WindowExposures
83824b90cf4Smrg	 * hook is called for it, so bail if we get here before that
83924b90cf4Smrg	 */
84024b90cf4Smrg	if (pScreen->WindowExposures == AMDGPUWindowExposures_oneshot)
84124b90cf4Smrg		return FALSE;
842d6c0b56eSmrg
843d6c0b56eSmrg	saved_mode = crtc->mode;
844d6c0b56eSmrg	saved_x = crtc->x;
845d6c0b56eSmrg	saved_y = crtc->y;
846d6c0b56eSmrg	saved_rotation = crtc->rotation;
847d6c0b56eSmrg
848d6c0b56eSmrg	if (mode) {
849d6c0b56eSmrg		crtc->mode = *mode;
850d6c0b56eSmrg		crtc->x = x;
851d6c0b56eSmrg		crtc->y = y;
852d6c0b56eSmrg		crtc->rotation = rotation;
853d6c0b56eSmrg
854d6c0b56eSmrg		if (!drmmode_handle_transform(crtc))
855d6c0b56eSmrg			goto done;
856d6c0b56eSmrg
85711bf0794Smrg		drmmode_crtc_update_tear_free(crtc);
85811bf0794Smrg		if (drmmode_crtc->tear_free)
85911bf0794Smrg			scanout_id = drmmode_crtc->scanout_id;
86011bf0794Smrg
86124b90cf4Smrg		/* gamma is disabled in kernel driver for deep color */
86224b90cf4Smrg		if (pScrn->depth != 30)
86324b90cf4Smrg			drmmode_crtc_gamma_do_set(
86424b90cf4Smrg				crtc, crtc->gamma_red, crtc->gamma_green,
86524b90cf4Smrg				crtc->gamma_blue, crtc->gamma_size);
866d6c0b56eSmrg
86724b90cf4Smrg		if (drmmode_crtc->prime_scanout_pixmap) {
86811bf0794Smrg			drmmode_crtc_prime_scanout_update(crtc, mode, scanout_id,
86924b90cf4Smrg							  &fb, &x, &y);
87024b90cf4Smrg		} else if (drmmode_crtc->rotate.pixmap) {
87124b90cf4Smrg			fb = amdgpu_pixmap_get_fb(drmmode_crtc->rotate.pixmap);
872d6c0b56eSmrg			x = y = 0;
87311bf0794Smrg
87424b90cf4Smrg		} else if (!pScreen->isGPU &&
87511bf0794Smrg			   (drmmode_crtc->tear_free ||
876504d986fSmrg			    crtc->driverIsPerformingTransform ||
877504d986fSmrg			    info->shadow_primary)) {
87811bf0794Smrg			drmmode_crtc_scanout_update(crtc, mode, scanout_id,
87924b90cf4Smrg						    &fb, &x, &y);
880d6c0b56eSmrg		}
881d6c0b56eSmrg
88224b90cf4Smrg		if (!fb)
88324b90cf4Smrg			fb = amdgpu_pixmap_get_fb(pScreen->GetWindowPixmap(pScreen->root));
88424b90cf4Smrg		if (!fb) {
88524b90cf4Smrg			union gbm_bo_handle bo_handle;
88624b90cf4Smrg
88724b90cf4Smrg			bo_handle = gbm_bo_get_handle(info->front_buffer->bo.gbm);
88824b90cf4Smrg			fb = amdgpu_fb_create(pScrn, pAMDGPUEnt->fd,
88924b90cf4Smrg					      pScrn->virtualX, pScrn->virtualY,
89024b90cf4Smrg					      pScrn->displayWidth * info->pixel_bytes,
89124b90cf4Smrg					      bo_handle.u32);
89224b90cf4Smrg			/* Prevent refcnt of ad-hoc FBs from reaching 2 */
89324b90cf4Smrg			drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL);
89424b90cf4Smrg			drmmode_crtc->fb = fb;
89524b90cf4Smrg		}
89624b90cf4Smrg		if (!fb) {
89724b90cf4Smrg			ErrorF("failed to add FB for modeset\n");
89824b90cf4Smrg			goto done;
899504d986fSmrg		}
900504d986fSmrg
90124b90cf4Smrg		drmmode_crtc_wait_pending_event(drmmode_crtc, pAMDGPUEnt->fd,
90224b90cf4Smrg						drmmode_crtc->flip_pending);
90324b90cf4Smrg
90424b90cf4Smrg		if (!drmmode_set_mode(crtc, fb, mode, x, y))
905d6c0b56eSmrg			goto done;
90624b90cf4Smrg
90724b90cf4Smrg		ret = TRUE;
908d6c0b56eSmrg
909d6c0b56eSmrg		if (pScreen)
910d6c0b56eSmrg			xf86CrtcSetScreenSubpixelOrder(pScreen);
911d6c0b56eSmrg
912d6c0b56eSmrg		drmmode_crtc->need_modeset = FALSE;
913d6c0b56eSmrg
914d6c0b56eSmrg		/* go through all the outputs and force DPMS them back on? */
915d6c0b56eSmrg		for (i = 0; i < xf86_config->num_output; i++) {
916d6c0b56eSmrg			xf86OutputPtr output = xf86_config->output[i];
917d6c0b56eSmrg
918d6c0b56eSmrg			if (output->crtc != crtc)
919d6c0b56eSmrg				continue;
920d6c0b56eSmrg
921d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOn);
922d6c0b56eSmrg		}
923d6c0b56eSmrg	}
924d6c0b56eSmrg
925d6c0b56eSmrg	/* Compute index of this CRTC into xf86_config->crtc */
926d6c0b56eSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
927d6c0b56eSmrg		if (xf86_config->crtc[i] != crtc)
928d6c0b56eSmrg			continue;
929d6c0b56eSmrg
930d6c0b56eSmrg		if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc))
931d6c0b56eSmrg			info->hwcursor_disabled &= ~(1 << i);
932d6c0b56eSmrg		else
933d6c0b56eSmrg			info->hwcursor_disabled |= 1 << i;
934d6c0b56eSmrg
935d6c0b56eSmrg		break;
936d6c0b56eSmrg	}
937d6c0b56eSmrg
938d6c0b56eSmrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR
939d6c0b56eSmrg	if (!info->hwcursor_disabled)
940d6c0b56eSmrg		xf86_reload_cursors(pScreen);
941d6c0b56eSmrg#endif
942d6c0b56eSmrg
943d6c0b56eSmrgdone:
944d6c0b56eSmrg	if (!ret) {
945d6c0b56eSmrg		crtc->x = saved_x;
946d6c0b56eSmrg		crtc->y = saved_y;
947d6c0b56eSmrg		crtc->rotation = saved_rotation;
948d6c0b56eSmrg		crtc->mode = saved_mode;
949504d986fSmrg	} else {
950d6c0b56eSmrg		crtc->active = TRUE;
951d6c0b56eSmrg
95224b90cf4Smrg		if (drmmode_crtc->scanout[scanout_id].pixmap &&
95324b90cf4Smrg		    fb != amdgpu_pixmap_get_fb(drmmode_crtc->
95424b90cf4Smrg					       scanout[scanout_id].pixmap))
955504d986fSmrg			drmmode_crtc_scanout_free(drmmode_crtc);
95611bf0794Smrg		else if (!drmmode_crtc->tear_free) {
95711bf0794Smrg			drmmode_crtc_scanout_destroy(drmmode,
95811bf0794Smrg						     &drmmode_crtc->scanout[1]);
95911bf0794Smrg		}
960504d986fSmrg	}
961504d986fSmrg
962d6c0b56eSmrg	return ret;
963d6c0b56eSmrg}
964d6c0b56eSmrg
965d6c0b56eSmrgstatic void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
966d6c0b56eSmrg{
967d6c0b56eSmrg
968d6c0b56eSmrg}
969d6c0b56eSmrg
970d6c0b56eSmrgstatic void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
971d6c0b56eSmrg{
972d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
973d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
974d6c0b56eSmrg
97524b90cf4Smrg#if XF86_CRTC_VERSION < 7
976d6c0b56eSmrg	if (crtc->driverIsPerformingTransform) {
977d6c0b56eSmrg		x += crtc->x;
978d6c0b56eSmrg		y += crtc->y;
979d6c0b56eSmrg		xf86CrtcTransformCursorPos(crtc, &x, &y);
980d6c0b56eSmrg	}
981d6c0b56eSmrg#endif
982d6c0b56eSmrg
983d6c0b56eSmrg	drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
984d6c0b56eSmrg}
985d6c0b56eSmrg
98624b90cf4Smrg#if XF86_CRTC_VERSION < 7
987d6c0b56eSmrg
988d6c0b56eSmrgstatic int
989d6c0b56eSmrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height,
990d6c0b56eSmrg			  int x_dst, int y_dst)
991d6c0b56eSmrg{
992d6c0b56eSmrg	int t;
993d6c0b56eSmrg
994d6c0b56eSmrg	switch (rotation & 0xf) {
995d6c0b56eSmrg	case RR_Rotate_90:
996d6c0b56eSmrg		t = x_dst;
997d6c0b56eSmrg		x_dst = height - y_dst - 1;
998d6c0b56eSmrg		y_dst = t;
999d6c0b56eSmrg		break;
1000d6c0b56eSmrg	case RR_Rotate_180:
1001d6c0b56eSmrg		x_dst = width - x_dst - 1;
1002d6c0b56eSmrg		y_dst = height - y_dst - 1;
1003d6c0b56eSmrg		break;
1004d6c0b56eSmrg	case RR_Rotate_270:
1005d6c0b56eSmrg		t = x_dst;
1006d6c0b56eSmrg		x_dst = y_dst;
1007d6c0b56eSmrg		y_dst = width - t - 1;
1008d6c0b56eSmrg		break;
1009d6c0b56eSmrg	}
1010d6c0b56eSmrg
1011d6c0b56eSmrg	if (rotation & RR_Reflect_X)
1012d6c0b56eSmrg		x_dst = width - x_dst - 1;
1013d6c0b56eSmrg	if (rotation & RR_Reflect_Y)
1014d6c0b56eSmrg		y_dst = height - y_dst - 1;
1015d6c0b56eSmrg
1016d6c0b56eSmrg	return y_dst * height + x_dst;
1017d6c0b56eSmrg}
1018d6c0b56eSmrg
1019d6c0b56eSmrg#endif
1020d6c0b56eSmrg
102124b90cf4Smrgstatic uint32_t
102224b90cf4Smrgdrmmode_cursor_gamma(xf86CrtcPtr crtc, uint32_t argb)
102324b90cf4Smrg{
102424b90cf4Smrg	uint32_t alpha = argb >> 24;
102524b90cf4Smrg	uint32_t rgb[3];
102624b90cf4Smrg	int i;
102724b90cf4Smrg
102824b90cf4Smrg	if (!alpha)
102924b90cf4Smrg		return 0;
103024b90cf4Smrg
103124b90cf4Smrg	if (crtc->scrn->depth != 24 && crtc->scrn->depth != 32)
103224b90cf4Smrg		return argb;
103324b90cf4Smrg
103424b90cf4Smrg	/* Un-premultiply alpha */
103524b90cf4Smrg	for (i = 0; i < 3; i++)
103624b90cf4Smrg		rgb[i] = ((argb >> (i * 8)) & 0xff) * 0xff / alpha;
103724b90cf4Smrg
103824b90cf4Smrg	/* Apply gamma correction and pre-multiply alpha */
103924b90cf4Smrg	rgb[0] = (crtc->gamma_blue[rgb[0]] >> 8) * alpha / 0xff;
104024b90cf4Smrg	rgb[1] = (crtc->gamma_green[rgb[1]] >> 8) * alpha / 0xff;
104124b90cf4Smrg	rgb[2] = (crtc->gamma_red[rgb[2]] >> 8) * alpha / 0xff;
104224b90cf4Smrg
104324b90cf4Smrg	return alpha << 24 | rgb[2] << 16 | rgb[1] << 8 | rgb[0];
104424b90cf4Smrg}
104524b90cf4Smrg
1046d6c0b56eSmrgstatic void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_t *ptr)
1047d6c0b56eSmrg{
1048d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
1049d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1050d6c0b56eSmrg
105124b90cf4Smrg#if XF86_CRTC_VERSION < 7
1052d6c0b56eSmrg	if (crtc->driverIsPerformingTransform) {
1053d6c0b56eSmrg		uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
1054d6c0b56eSmrg		int dstx, dsty;
1055d6c0b56eSmrg		int srcoffset;
1056d6c0b56eSmrg
1057d6c0b56eSmrg		for (dsty = 0; dsty < cursor_h; dsty++) {
1058d6c0b56eSmrg			for (dstx = 0; dstx < cursor_w; dstx++) {
1059d6c0b56eSmrg				srcoffset = drmmode_cursor_src_offset(crtc->rotation,
1060d6c0b56eSmrg								      cursor_w,
1061d6c0b56eSmrg								      cursor_h,
1062d6c0b56eSmrg								      dstx, dsty);
1063d6c0b56eSmrg
1064d6c0b56eSmrg				ptr[dsty * info->cursor_w + dstx] =
106524b90cf4Smrg					cpu_to_le32(drmmode_cursor_gamma(crtc,
106624b90cf4Smrg									 image[srcoffset]));
1067d6c0b56eSmrg			}
1068d6c0b56eSmrg		}
1069d6c0b56eSmrg	} else
1070d6c0b56eSmrg#endif
1071d6c0b56eSmrg	{
1072d6c0b56eSmrg		uint32_t cursor_size = info->cursor_w * info->cursor_h;
1073d6c0b56eSmrg		int i;
1074d6c0b56eSmrg
1075d6c0b56eSmrg		for (i = 0; i < cursor_size; i++)
107624b90cf4Smrg			ptr[i] = cpu_to_le32(drmmode_cursor_gamma(crtc, image[i]));
1077d6c0b56eSmrg	}
1078d6c0b56eSmrg}
1079d6c0b56eSmrg
1080d6c0b56eSmrgstatic void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image)
1081d6c0b56eSmrg{
1082d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
1083d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1084d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1085d6c0b56eSmrg	uint32_t cursor_size = info->cursor_w * info->cursor_h;
1086d6c0b56eSmrg
1087d6c0b56eSmrg	if (info->gbm) {
1088d6c0b56eSmrg		uint32_t ptr[cursor_size];
1089d6c0b56eSmrg
1090d6c0b56eSmrg		drmmode_do_load_cursor_argb(crtc, image, ptr);
1091d6c0b56eSmrg		gbm_bo_write(drmmode_crtc->cursor_buffer->bo.gbm, ptr, cursor_size * 4);
1092d6c0b56eSmrg	} else {
1093d6c0b56eSmrg		/* cursor should be mapped already */
1094d6c0b56eSmrg		uint32_t *ptr = (uint32_t *) (drmmode_crtc->cursor_buffer->cpu_ptr);
1095d6c0b56eSmrg
1096d6c0b56eSmrg		drmmode_do_load_cursor_argb(crtc, image, ptr);
1097d6c0b56eSmrg	}
1098d6c0b56eSmrg}
1099d6c0b56eSmrg
1100d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
1101d6c0b56eSmrg
1102d6c0b56eSmrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
1103d6c0b56eSmrg{
1104d6c0b56eSmrg	if (!drmmode_can_use_hw_cursor(crtc))
1105d6c0b56eSmrg		return FALSE;
1106d6c0b56eSmrg
1107d6c0b56eSmrg	drmmode_load_cursor_argb(crtc, image);
1108d6c0b56eSmrg	return TRUE;
1109d6c0b56eSmrg}
1110d6c0b56eSmrg
1111d6c0b56eSmrg#endif
1112d6c0b56eSmrg
1113d6c0b56eSmrgstatic void drmmode_hide_cursor(xf86CrtcPtr crtc)
1114d6c0b56eSmrg{
1115d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
1116d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1117d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1118d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1119d6c0b56eSmrg
1120d6c0b56eSmrg	drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
1121d6c0b56eSmrg			 info->cursor_w, info->cursor_h);
1122d6c0b56eSmrg
1123d6c0b56eSmrg}
1124d6c0b56eSmrg
1125d6c0b56eSmrgstatic void drmmode_show_cursor(xf86CrtcPtr crtc)
1126d6c0b56eSmrg{
1127d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
1128d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1129d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1130d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1131d6c0b56eSmrg	uint32_t bo_handle;
1132d6c0b56eSmrg	static Bool use_set_cursor2 = TRUE;
1133d6c0b56eSmrg
1134d6c0b56eSmrg	if (!amdgpu_bo_get_handle(drmmode_crtc->cursor_buffer, &bo_handle)) {
1135d6c0b56eSmrg		ErrorF("failed to get BO handle for cursor\n");
1136d6c0b56eSmrg		return;
1137d6c0b56eSmrg	}
1138d6c0b56eSmrg
1139d6c0b56eSmrg	if (use_set_cursor2) {
1140d6c0b56eSmrg		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1141d6c0b56eSmrg		CursorPtr cursor = xf86_config->cursor;
1142504d986fSmrg		int xhot = cursor->bits->xhot;
1143504d986fSmrg		int yhot = cursor->bits->yhot;
1144d6c0b56eSmrg		int ret;
1145d6c0b56eSmrg
1146504d986fSmrg		if (crtc->rotation != RR_Rotate_0 &&
1147504d986fSmrg		    crtc->rotation != (RR_Rotate_180 | RR_Reflect_X |
1148504d986fSmrg				       RR_Reflect_Y)) {
1149504d986fSmrg			int t;
1150504d986fSmrg
1151504d986fSmrg			/* Reflect & rotate hotspot position */
1152504d986fSmrg			if (crtc->rotation & RR_Reflect_X)
1153504d986fSmrg				xhot = info->cursor_w - xhot - 1;
1154504d986fSmrg			if (crtc->rotation & RR_Reflect_Y)
1155504d986fSmrg				yhot = info->cursor_h - yhot - 1;
1156504d986fSmrg
1157504d986fSmrg			switch (crtc->rotation & 0xf) {
1158504d986fSmrg			case RR_Rotate_90:
1159504d986fSmrg				t = xhot;
1160504d986fSmrg				xhot = yhot;
1161504d986fSmrg				yhot = info->cursor_w - t - 1;
1162504d986fSmrg				break;
1163504d986fSmrg			case RR_Rotate_180:
1164504d986fSmrg				xhot = info->cursor_w - xhot - 1;
1165504d986fSmrg				yhot = info->cursor_h - yhot - 1;
1166504d986fSmrg				break;
1167504d986fSmrg			case RR_Rotate_270:
1168504d986fSmrg				t = xhot;
1169504d986fSmrg				xhot = info->cursor_h - yhot - 1;
1170504d986fSmrg				yhot = t;
1171504d986fSmrg			}
1172504d986fSmrg		}
1173504d986fSmrg
1174d6c0b56eSmrg		ret = drmModeSetCursor2(pAMDGPUEnt->fd,
1175d6c0b56eSmrg					drmmode_crtc->mode_crtc->crtc_id,
1176d6c0b56eSmrg					bo_handle,
1177d6c0b56eSmrg					info->cursor_w, info->cursor_h,
1178504d986fSmrg					xhot, yhot);
1179d6c0b56eSmrg		if (ret == -EINVAL)
1180d6c0b56eSmrg			use_set_cursor2 = FALSE;
1181d6c0b56eSmrg		else
1182d6c0b56eSmrg			return;
1183d6c0b56eSmrg	}
1184d6c0b56eSmrg
1185d6c0b56eSmrg	drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, bo_handle,
1186d6c0b56eSmrg			 info->cursor_w, info->cursor_h);
1187d6c0b56eSmrg}
1188d6c0b56eSmrg
118911bf0794Smrg/* Xorg expects a non-NULL return value from drmmode_crtc_shadow_allocate, and
119011bf0794Smrg * passes that back to drmmode_crtc_scanout_create; it doesn't use it for
119111bf0794Smrg * anything else.
119211bf0794Smrg */
119311bf0794Smrgstatic void *
119411bf0794Smrgdrmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
1195d6c0b56eSmrg{
1196d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1197d6c0b56eSmrg
119811bf0794Smrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
119911bf0794Smrg					 height))
120011bf0794Smrg		return NULL;
120111bf0794Smrg
120211bf0794Smrg	return (void*)~0UL;
1203d6c0b56eSmrg}
1204d6c0b56eSmrg
1205d6c0b56eSmrgstatic PixmapPtr
1206d6c0b56eSmrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1207d6c0b56eSmrg{
1208d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1209d6c0b56eSmrg
121011bf0794Smrg	if (!data) {
121111bf0794Smrg		drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
121211bf0794Smrg					    height);
121311bf0794Smrg	}
121411bf0794Smrg
121511bf0794Smrg	return drmmode_crtc->rotate.pixmap;
1216d6c0b56eSmrg}
1217d6c0b56eSmrg
1218d6c0b56eSmrgstatic void
1219d6c0b56eSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap,
1220d6c0b56eSmrg			    void *data)
1221d6c0b56eSmrg{
1222d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1223d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1224d6c0b56eSmrg
1225d6c0b56eSmrg	drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate);
1226d6c0b56eSmrg}
1227d6c0b56eSmrg
1228d6c0b56eSmrgstatic void
1229d6c0b56eSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
1230d6c0b56eSmrg		       uint16_t * blue, int size)
1231d6c0b56eSmrg{
123224b90cf4Smrg	ScrnInfoPtr scrn = crtc->scrn;
123324b90cf4Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
123424b90cf4Smrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
123524b90cf4Smrg	int i;
1236d6c0b56eSmrg
123724b90cf4Smrg	drmmode_crtc_gamma_do_set(crtc, red, green, blue, size);
123824b90cf4Smrg
123924b90cf4Smrg	/* Compute index of this CRTC into xf86_config->crtc */
124024b90cf4Smrg	for (i = 0; xf86_config->crtc[i] != crtc; i++) {}
124124b90cf4Smrg
124224b90cf4Smrg	if (info->hwcursor_disabled & (1 << i))
124324b90cf4Smrg		return;
124424b90cf4Smrg
124524b90cf4Smrg#ifdef HAVE_XF86_CURSOR_RESET_CURSOR
124624b90cf4Smrg	xf86CursorResetCursor(scrn->pScreen);
124724b90cf4Smrg#else
124824b90cf4Smrg	xf86_reload_cursors(scrn->pScreen);
124924b90cf4Smrg#endif
1250d6c0b56eSmrg}
1251d6c0b56eSmrg
1252d6c0b56eSmrgstatic Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
1253d6c0b56eSmrg{
1254d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
125511bf0794Smrg	unsigned scanout_id = drmmode_crtc->scanout_id;
1256504d986fSmrg	ScreenPtr screen = crtc->scrn->pScreen;
1257504d986fSmrg	PixmapDirtyUpdatePtr dirty;
1258d6c0b56eSmrg
1259504d986fSmrg	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
126024b90cf4Smrg		if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
126124b90cf4Smrg			PixmapStopDirtyTracking(dirty->src, dirty->slave_dst);
126224b90cf4Smrg			break;
126324b90cf4Smrg		}
1264d6c0b56eSmrg	}
1265d6c0b56eSmrg
126624b90cf4Smrg	drmmode_crtc_scanout_free(drmmode_crtc);
126724b90cf4Smrg	drmmode_crtc->prime_scanout_pixmap = NULL;
126824b90cf4Smrg
1269504d986fSmrg	if (!ppix)
1270504d986fSmrg		return TRUE;
1271504d986fSmrg
1272504d986fSmrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0],
1273504d986fSmrg					 ppix->drawable.width,
1274504d986fSmrg					 ppix->drawable.height))
1275504d986fSmrg		return FALSE;
1276d6c0b56eSmrg
127711bf0794Smrg	if (drmmode_crtc->tear_free &&
1278504d986fSmrg	    !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
1279504d986fSmrg					 ppix->drawable.width,
1280504d986fSmrg					 ppix->drawable.height)) {
1281504d986fSmrg		drmmode_crtc_scanout_free(drmmode_crtc);
1282504d986fSmrg		return FALSE;
1283d6c0b56eSmrg	}
1284504d986fSmrg
128524b90cf4Smrg	drmmode_crtc->prime_scanout_pixmap = ppix;
128624b90cf4Smrg
128724b90cf4Smrg#ifdef HAS_DIRTYTRACKING_DRAWABLE_SRC
128824b90cf4Smrg	PixmapStartDirtyTracking(&ppix->drawable,
128924b90cf4Smrg				 drmmode_crtc->scanout[scanout_id].pixmap,
129024b90cf4Smrg				 0, 0, 0, 0, RR_Rotate_0);
129124b90cf4Smrg#elif defined(HAS_DIRTYTRACKING_ROTATION)
129211bf0794Smrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
1293504d986fSmrg				 0, 0, 0, 0, RR_Rotate_0);
1294d6c0b56eSmrg#elif defined(HAS_DIRTYTRACKING2)
129511bf0794Smrg	PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[scanout_id].pixmap,
1296504d986fSmrg				  0, 0, 0, 0);
1297d6c0b56eSmrg#else
129811bf0794Smrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[scanout_id].pixmap, 0, 0);
1299d6c0b56eSmrg#endif
1300d6c0b56eSmrg	return TRUE;
1301d6c0b56eSmrg}
1302d6c0b56eSmrg
1303d6c0b56eSmrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = {
1304d6c0b56eSmrg	.dpms = drmmode_crtc_dpms,
1305d6c0b56eSmrg	.set_mode_major = drmmode_set_mode_major,
1306d6c0b56eSmrg	.set_cursor_colors = drmmode_set_cursor_colors,
1307d6c0b56eSmrg	.set_cursor_position = drmmode_set_cursor_position,
1308d6c0b56eSmrg	.show_cursor = drmmode_show_cursor,
1309d6c0b56eSmrg	.hide_cursor = drmmode_hide_cursor,
1310d6c0b56eSmrg	.load_cursor_argb = drmmode_load_cursor_argb,
1311d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
1312d6c0b56eSmrg	.load_cursor_argb_check = drmmode_load_cursor_argb_check,
1313d6c0b56eSmrg#endif
1314d6c0b56eSmrg
1315d6c0b56eSmrg	.gamma_set = drmmode_crtc_gamma_set,
1316d6c0b56eSmrg	.shadow_create = drmmode_crtc_shadow_create,
1317d6c0b56eSmrg	.shadow_allocate = drmmode_crtc_shadow_allocate,
1318d6c0b56eSmrg	.shadow_destroy = drmmode_crtc_shadow_destroy,
1319d6c0b56eSmrg	.destroy = NULL,	/* XXX */
1320d6c0b56eSmrg	.set_scanout_pixmap = drmmode_set_scanout_pixmap,
1321d6c0b56eSmrg};
1322d6c0b56eSmrg
1323d6c0b56eSmrgint drmmode_get_crtc_id(xf86CrtcPtr crtc)
1324d6c0b56eSmrg{
1325d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1326d6c0b56eSmrg	return drmmode_crtc->hw_id;
1327d6c0b56eSmrg}
1328d6c0b56eSmrg
1329d6c0b56eSmrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc)
1330d6c0b56eSmrg{
1331d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1332d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
1333d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1334d6c0b56eSmrg	int r;
1335d6c0b56eSmrg
1336d6c0b56eSmrg	r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev,
1337d6c0b56eSmrg				      drmmode_crtc->mode_crtc->crtc_id,
1338d6c0b56eSmrg				      &drmmode_crtc->hw_id);
1339d6c0b56eSmrg	if (r)
1340d6c0b56eSmrg		drmmode_crtc->hw_id = -1;
1341d6c0b56eSmrg}
1342d6c0b56eSmrg
1343d6c0b56eSmrgstatic unsigned int
1344d6c0b56eSmrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
1345d6c0b56eSmrg{
1346d6c0b56eSmrg	xf86CrtcPtr crtc;
1347d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc;
1348d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
134924b90cf4Smrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1350d6c0b56eSmrg
135124b90cf4Smrg	crtc = xf86CrtcCreate(pScrn, &info->drmmode_crtc_funcs);
1352d6c0b56eSmrg	if (crtc == NULL)
1353d6c0b56eSmrg		return 0;
1354d6c0b56eSmrg
1355d6c0b56eSmrg	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
1356d6c0b56eSmrg	drmmode_crtc->mode_crtc =
1357d6c0b56eSmrg	    drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]);
1358d6c0b56eSmrg	drmmode_crtc->drmmode = drmmode;
1359d6c0b56eSmrg	drmmode_crtc->dpms_mode = DPMSModeOff;
1360d6c0b56eSmrg	crtc->driver_private = drmmode_crtc;
1361d6c0b56eSmrg	drmmode_crtc_hw_id(crtc);
1362d6c0b56eSmrg
1363d6c0b56eSmrg	/* Mark num'th crtc as in use on this device. */
1364d6c0b56eSmrg	pAMDGPUEnt->assigned_crtcs |= (1 << num);
1365d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1366d6c0b56eSmrg		       "Allocated crtc nr. %d to this screen.\n", num);
1367d6c0b56eSmrg
1368d6c0b56eSmrg	return 1;
1369d6c0b56eSmrg}
1370d6c0b56eSmrg
137124b90cf4Smrg/*
137224b90cf4Smrg * Update all of the property values for an output
137324b90cf4Smrg */
137424b90cf4Smrgstatic void
137524b90cf4Smrgdrmmode_output_update_properties(xf86OutputPtr output)
137624b90cf4Smrg{
137724b90cf4Smrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
137824b90cf4Smrg	int i, j, k;
137924b90cf4Smrg	int err;
138024b90cf4Smrg	drmModeConnectorPtr koutput;
138124b90cf4Smrg
138224b90cf4Smrg	/* Use the most recently fetched values from the kernel */
138324b90cf4Smrg	koutput = drmmode_output->mode_output;
138424b90cf4Smrg
138524b90cf4Smrg	if (!koutput)
138624b90cf4Smrg		return;
138724b90cf4Smrg
138824b90cf4Smrg	for (i = 0; i < drmmode_output->num_props; i++) {
138924b90cf4Smrg		drmmode_prop_ptr p = &drmmode_output->props[i];
139024b90cf4Smrg
139124b90cf4Smrg		for (j = 0; j < koutput->count_props; j++) {
139224b90cf4Smrg			if (koutput->props[j] != p->mode_prop->prop_id)
139324b90cf4Smrg				continue;
139424b90cf4Smrg
139524b90cf4Smrg			/* Check to see if the property value has changed */
139624b90cf4Smrg			if (koutput->prop_values[j] == p->value)
139724b90cf4Smrg				break;
139824b90cf4Smrg
139924b90cf4Smrg			p->value = koutput->prop_values[j];
140024b90cf4Smrg
140124b90cf4Smrg			if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
140224b90cf4Smrg				INT32 value = p->value;
140324b90cf4Smrg
140424b90cf4Smrg				err = RRChangeOutputProperty(output->randr_output,
140524b90cf4Smrg							     p->atoms[0], XA_INTEGER,
140624b90cf4Smrg							     32, PropModeReplace, 1,
140724b90cf4Smrg							     &value, FALSE, TRUE);
140824b90cf4Smrg				if (err != 0) {
140924b90cf4Smrg					xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
141024b90cf4Smrg						   "RRChangeOutputProperty error, %d\n",
141124b90cf4Smrg						   err);
141224b90cf4Smrg				}
141324b90cf4Smrg			} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
141424b90cf4Smrg				for (k = 0; k < p->mode_prop->count_enums; k++) {
141524b90cf4Smrg					if (p->mode_prop->enums[k].value == p->value)
141624b90cf4Smrg						break;
141724b90cf4Smrg				}
141824b90cf4Smrg				if (k < p->mode_prop->count_enums) {
141924b90cf4Smrg					err = RRChangeOutputProperty(output->randr_output,
142024b90cf4Smrg								     p->atoms[0], XA_ATOM,
142124b90cf4Smrg								     32, PropModeReplace, 1,
142224b90cf4Smrg								     &p->atoms[k + 1], FALSE,
142324b90cf4Smrg								     TRUE);
142424b90cf4Smrg					if (err != 0) {
142524b90cf4Smrg						xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
142624b90cf4Smrg							   "RRChangeOutputProperty error, %d\n",
142724b90cf4Smrg							   err);
142824b90cf4Smrg					}
142924b90cf4Smrg				}
143024b90cf4Smrg			}
143124b90cf4Smrg
143224b90cf4Smrg			break;
143324b90cf4Smrg		}
143424b90cf4Smrg        }
143524b90cf4Smrg}
143624b90cf4Smrg
1437d6c0b56eSmrgstatic xf86OutputStatus drmmode_output_detect(xf86OutputPtr output)
1438d6c0b56eSmrg{
1439d6c0b56eSmrg	/* go to the hw and retrieve a new output struct */
1440d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1441d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1442d6c0b56eSmrg	xf86OutputStatus status;
1443d6c0b56eSmrg	drmModeFreeConnector(drmmode_output->mode_output);
1444d6c0b56eSmrg
1445d6c0b56eSmrg	drmmode_output->mode_output =
1446d6c0b56eSmrg	    drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id);
144724b90cf4Smrg	if (!drmmode_output->mode_output) {
144824b90cf4Smrg		drmmode_output->output_id = -1;
1449d6c0b56eSmrg		return XF86OutputStatusDisconnected;
145024b90cf4Smrg	}
145124b90cf4Smrg
145224b90cf4Smrg	drmmode_output_update_properties(output);
1453d6c0b56eSmrg
1454d6c0b56eSmrg	switch (drmmode_output->mode_output->connection) {
1455d6c0b56eSmrg	case DRM_MODE_CONNECTED:
1456d6c0b56eSmrg		status = XF86OutputStatusConnected;
1457d6c0b56eSmrg		break;
1458d6c0b56eSmrg	case DRM_MODE_DISCONNECTED:
1459d6c0b56eSmrg		status = XF86OutputStatusDisconnected;
1460d6c0b56eSmrg		break;
1461d6c0b56eSmrg	default:
1462d6c0b56eSmrg	case DRM_MODE_UNKNOWNCONNECTION:
1463d6c0b56eSmrg		status = XF86OutputStatusUnknown;
1464d6c0b56eSmrg		break;
1465d6c0b56eSmrg	}
1466d6c0b56eSmrg	return status;
1467d6c0b56eSmrg}
1468d6c0b56eSmrg
1469d6c0b56eSmrgstatic Bool
1470d6c0b56eSmrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
1471d6c0b56eSmrg{
1472d6c0b56eSmrg	return MODE_OK;
1473d6c0b56eSmrg}
1474d6c0b56eSmrg
147524b90cf4Smrgstatic int
147624b90cf4Smrgkoutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
147724b90cf4Smrg        int type, const char *name)
147824b90cf4Smrg{
147924b90cf4Smrg    int idx = -1;
148024b90cf4Smrg
148124b90cf4Smrg    for (int i = 0; i < koutput->count_props; i++) {
148224b90cf4Smrg        drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
148324b90cf4Smrg
148424b90cf4Smrg        if (!prop)
148524b90cf4Smrg            continue;
148624b90cf4Smrg
148724b90cf4Smrg        if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
148824b90cf4Smrg            idx = i;
148924b90cf4Smrg
149024b90cf4Smrg        drmModeFreeProperty(prop);
149124b90cf4Smrg
149224b90cf4Smrg        if (idx > -1)
149324b90cf4Smrg            break;
149424b90cf4Smrg    }
149524b90cf4Smrg
149624b90cf4Smrg    return idx;
149724b90cf4Smrg}
149824b90cf4Smrg
149924b90cf4Smrgstatic int
150024b90cf4Smrgkoutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
150124b90cf4Smrg        int type, const char *name)
150224b90cf4Smrg{
150324b90cf4Smrg    int idx = koutput_get_prop_idx(fd, koutput, type, name);
150424b90cf4Smrg
150524b90cf4Smrg    return (idx > -1) ? koutput->props[idx] : -1;
150624b90cf4Smrg}
150724b90cf4Smrg
150824b90cf4Smrgstatic drmModePropertyBlobPtr
150924b90cf4Smrgkoutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
151024b90cf4Smrg{
151124b90cf4Smrg    drmModePropertyBlobPtr blob = NULL;
151224b90cf4Smrg    int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
151324b90cf4Smrg
151424b90cf4Smrg    if (idx > -1)
151524b90cf4Smrg        blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
151624b90cf4Smrg
151724b90cf4Smrg    return blob;
151824b90cf4Smrg}
151924b90cf4Smrg
1520d6c0b56eSmrgstatic DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output)
1521d6c0b56eSmrg{
1522d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1523d6c0b56eSmrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
1524d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1525d6c0b56eSmrg	int i;
1526d6c0b56eSmrg	DisplayModePtr Modes = NULL, Mode;
1527d6c0b56eSmrg	xf86MonPtr mon = NULL;
1528d6c0b56eSmrg
1529d6c0b56eSmrg	if (!koutput)
1530d6c0b56eSmrg		return NULL;
1531d6c0b56eSmrg
153224b90cf4Smrg	drmModeFreePropertyBlob(drmmode_output->edid_blob);
153324b90cf4Smrg
1534d6c0b56eSmrg	/* look for an EDID property */
153524b90cf4Smrg	drmmode_output->edid_blob =
153624b90cf4Smrg		koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "EDID");
1537d6c0b56eSmrg
1538d6c0b56eSmrg	if (drmmode_output->edid_blob) {
1539d6c0b56eSmrg		mon = xf86InterpretEDID(output->scrn->scrnIndex,
1540d6c0b56eSmrg					drmmode_output->edid_blob->data);
1541d6c0b56eSmrg		if (mon && drmmode_output->edid_blob->length > 128)
1542d6c0b56eSmrg			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
1543d6c0b56eSmrg	}
1544d6c0b56eSmrg	xf86OutputSetEDID(output, mon);
1545d6c0b56eSmrg
1546d6c0b56eSmrg	/* modes should already be available */
1547d6c0b56eSmrg	for (i = 0; i < koutput->count_modes; i++) {
1548d6c0b56eSmrg		Mode = xnfalloc(sizeof(DisplayModeRec));
1549d6c0b56eSmrg
1550d6c0b56eSmrg		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i],
1551d6c0b56eSmrg					 Mode);
1552d6c0b56eSmrg		Modes = xf86ModesAdd(Modes, Mode);
1553d6c0b56eSmrg
1554d6c0b56eSmrg	}
1555d6c0b56eSmrg	return Modes;
1556d6c0b56eSmrg}
1557d6c0b56eSmrg
1558d6c0b56eSmrgstatic void drmmode_output_destroy(xf86OutputPtr output)
1559d6c0b56eSmrg{
1560d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1561d6c0b56eSmrg	int i;
1562d6c0b56eSmrg
1563d6c0b56eSmrg	if (drmmode_output->edid_blob)
1564d6c0b56eSmrg		drmModeFreePropertyBlob(drmmode_output->edid_blob);
1565d6c0b56eSmrg	for (i = 0; i < drmmode_output->num_props; i++) {
1566d6c0b56eSmrg		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
1567d6c0b56eSmrg		free(drmmode_output->props[i].atoms);
1568d6c0b56eSmrg	}
1569d6c0b56eSmrg	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
1570d6c0b56eSmrg		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
1571d6c0b56eSmrg	}
1572d6c0b56eSmrg	free(drmmode_output->mode_encoders);
1573d6c0b56eSmrg	free(drmmode_output->props);
1574d6c0b56eSmrg	drmModeFreeConnector(drmmode_output->mode_output);
1575d6c0b56eSmrg	free(drmmode_output);
1576d6c0b56eSmrg	output->driver_private = NULL;
1577d6c0b56eSmrg}
1578d6c0b56eSmrg
1579d6c0b56eSmrgstatic void drmmode_output_dpms(xf86OutputPtr output, int mode)
1580d6c0b56eSmrg{
1581d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1582d6c0b56eSmrg	xf86CrtcPtr crtc = output->crtc;
1583d6c0b56eSmrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
1584d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1585d6c0b56eSmrg
1586d6c0b56eSmrg	if (!koutput)
1587d6c0b56eSmrg		return;
1588d6c0b56eSmrg
158924b90cf4Smrg	if (mode != DPMSModeOn && crtc)
1590d6c0b56eSmrg		drmmode_do_crtc_dpms(crtc, mode);
1591d6c0b56eSmrg
1592d6c0b56eSmrg	drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id,
1593d6c0b56eSmrg				    drmmode_output->dpms_enum_id, mode);
1594d6c0b56eSmrg
1595d6c0b56eSmrg	if (mode == DPMSModeOn && crtc) {
1596d6c0b56eSmrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1597d6c0b56eSmrg
1598d6c0b56eSmrg		if (drmmode_crtc->need_modeset)
1599d6c0b56eSmrg			drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
1600d6c0b56eSmrg					       crtc->x, crtc->y);
1601d6c0b56eSmrg		else
1602d6c0b56eSmrg			drmmode_do_crtc_dpms(output->crtc, mode);
1603d6c0b56eSmrg	}
1604d6c0b56eSmrg}
1605d6c0b56eSmrg
1606d6c0b56eSmrgstatic Bool drmmode_property_ignore(drmModePropertyPtr prop)
1607d6c0b56eSmrg{
1608d6c0b56eSmrg	if (!prop)
1609d6c0b56eSmrg		return TRUE;
1610d6c0b56eSmrg	/* ignore blob prop */
1611d6c0b56eSmrg	if (prop->flags & DRM_MODE_PROP_BLOB)
1612d6c0b56eSmrg		return TRUE;
1613d6c0b56eSmrg	/* ignore standard property */
1614d6c0b56eSmrg	if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS"))
1615d6c0b56eSmrg		return TRUE;
1616d6c0b56eSmrg
1617d6c0b56eSmrg	return FALSE;
1618d6c0b56eSmrg}
1619d6c0b56eSmrg
1620d6c0b56eSmrgstatic void drmmode_output_create_resources(xf86OutputPtr output)
1621d6c0b56eSmrg{
162211bf0794Smrg	AMDGPUInfoPtr info = AMDGPUPTR(output->scrn);
1623d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1624d6c0b56eSmrg	drmModeConnectorPtr mode_output = drmmode_output->mode_output;
1625d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
162611bf0794Smrg	drmModePropertyPtr drmmode_prop, tearfree_prop;
1627d6c0b56eSmrg	int i, j, err;
1628d6c0b56eSmrg
1629d6c0b56eSmrg	drmmode_output->props =
163011bf0794Smrg		calloc(mode_output->count_props + 1, sizeof(drmmode_prop_rec));
1631d6c0b56eSmrg	if (!drmmode_output->props)
1632d6c0b56eSmrg		return;
1633d6c0b56eSmrg
1634d6c0b56eSmrg	drmmode_output->num_props = 0;
1635d6c0b56eSmrg	for (i = 0, j = 0; i < mode_output->count_props; i++) {
1636d6c0b56eSmrg		drmmode_prop =
1637d6c0b56eSmrg		    drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]);
1638d6c0b56eSmrg		if (drmmode_property_ignore(drmmode_prop)) {
1639d6c0b56eSmrg			drmModeFreeProperty(drmmode_prop);
1640d6c0b56eSmrg			continue;
1641d6c0b56eSmrg		}
1642d6c0b56eSmrg		drmmode_output->props[j].mode_prop = drmmode_prop;
1643d6c0b56eSmrg		drmmode_output->props[j].value = mode_output->prop_values[i];
1644d6c0b56eSmrg		drmmode_output->num_props++;
1645d6c0b56eSmrg		j++;
1646d6c0b56eSmrg	}
1647d6c0b56eSmrg
164811bf0794Smrg	/* Userspace-only property for TearFree */
164911bf0794Smrg	tearfree_prop = calloc(1, sizeof(*tearfree_prop));
165011bf0794Smrg	tearfree_prop->flags = DRM_MODE_PROP_ENUM;
165111bf0794Smrg	strncpy(tearfree_prop->name, "TearFree", 8);
165211bf0794Smrg	tearfree_prop->count_enums = 3;
165311bf0794Smrg	tearfree_prop->enums = calloc(tearfree_prop->count_enums,
165411bf0794Smrg				      sizeof(*tearfree_prop->enums));
165511bf0794Smrg	strncpy(tearfree_prop->enums[0].name, "off", 3);
165611bf0794Smrg	strncpy(tearfree_prop->enums[1].name, "on", 2);
165711bf0794Smrg	tearfree_prop->enums[1].value = 1;
165811bf0794Smrg	strncpy(tearfree_prop->enums[2].name, "auto", 4);
165911bf0794Smrg	tearfree_prop->enums[2].value = 2;
166011bf0794Smrg	drmmode_output->props[j].mode_prop = tearfree_prop;
166111bf0794Smrg	drmmode_output->props[j].value = info->tear_free;
166211bf0794Smrg	drmmode_output->tear_free = info->tear_free;
166311bf0794Smrg	drmmode_output->num_props++;
166411bf0794Smrg
1665d6c0b56eSmrg	for (i = 0; i < drmmode_output->num_props; i++) {
1666d6c0b56eSmrg		drmmode_prop_ptr p = &drmmode_output->props[i];
1667d6c0b56eSmrg		drmmode_prop = p->mode_prop;
1668d6c0b56eSmrg
1669d6c0b56eSmrg		if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1670d6c0b56eSmrg			INT32 range[2];
1671d6c0b56eSmrg			INT32 value = p->value;
1672d6c0b56eSmrg
1673d6c0b56eSmrg			p->num_atoms = 1;
1674d6c0b56eSmrg			p->atoms = calloc(p->num_atoms, sizeof(Atom));
1675d6c0b56eSmrg			if (!p->atoms)
1676d6c0b56eSmrg				continue;
1677d6c0b56eSmrg			p->atoms[0] =
1678d6c0b56eSmrg			    MakeAtom(drmmode_prop->name,
1679d6c0b56eSmrg				     strlen(drmmode_prop->name), TRUE);
1680d6c0b56eSmrg			range[0] = drmmode_prop->values[0];
1681d6c0b56eSmrg			range[1] = drmmode_prop->values[1];
1682d6c0b56eSmrg			err =
1683d6c0b56eSmrg			    RRConfigureOutputProperty(output->randr_output,
1684d6c0b56eSmrg						      p->atoms[0], FALSE, TRUE,
1685d6c0b56eSmrg						      drmmode_prop->flags &
1686d6c0b56eSmrg						      DRM_MODE_PROP_IMMUTABLE ?
1687d6c0b56eSmrg						      TRUE : FALSE, 2, range);
1688d6c0b56eSmrg			if (err != 0) {
1689d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1690d6c0b56eSmrg					   "RRConfigureOutputProperty error, %d\n",
1691d6c0b56eSmrg					   err);
1692d6c0b56eSmrg			}
1693d6c0b56eSmrg			err =
1694d6c0b56eSmrg			    RRChangeOutputProperty(output->randr_output,
1695d6c0b56eSmrg						   p->atoms[0], XA_INTEGER, 32,
1696d6c0b56eSmrg						   PropModeReplace, 1, &value,
1697d6c0b56eSmrg						   FALSE, TRUE);
1698d6c0b56eSmrg			if (err != 0) {
1699d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1700d6c0b56eSmrg					   "RRChangeOutputProperty error, %d\n",
1701d6c0b56eSmrg					   err);
1702d6c0b56eSmrg			}
1703d6c0b56eSmrg		} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1704d6c0b56eSmrg			p->num_atoms = drmmode_prop->count_enums + 1;
1705d6c0b56eSmrg			p->atoms = calloc(p->num_atoms, sizeof(Atom));
1706d6c0b56eSmrg			if (!p->atoms)
1707d6c0b56eSmrg				continue;
1708d6c0b56eSmrg			p->atoms[0] =
1709d6c0b56eSmrg			    MakeAtom(drmmode_prop->name,
1710d6c0b56eSmrg				     strlen(drmmode_prop->name), TRUE);
1711d6c0b56eSmrg			for (j = 1; j <= drmmode_prop->count_enums; j++) {
1712d6c0b56eSmrg				struct drm_mode_property_enum *e =
1713d6c0b56eSmrg				    &drmmode_prop->enums[j - 1];
1714d6c0b56eSmrg				p->atoms[j] =
1715d6c0b56eSmrg				    MakeAtom(e->name, strlen(e->name), TRUE);
1716d6c0b56eSmrg			}
1717d6c0b56eSmrg			err =
1718d6c0b56eSmrg			    RRConfigureOutputProperty(output->randr_output,
1719d6c0b56eSmrg						      p->atoms[0], FALSE, FALSE,
1720d6c0b56eSmrg						      drmmode_prop->flags &
1721d6c0b56eSmrg						      DRM_MODE_PROP_IMMUTABLE ?
1722d6c0b56eSmrg						      TRUE : FALSE,
1723d6c0b56eSmrg						      p->num_atoms - 1,
1724d6c0b56eSmrg						      (INT32 *) & p->atoms[1]);
1725d6c0b56eSmrg			if (err != 0) {
1726d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1727d6c0b56eSmrg					   "RRConfigureOutputProperty error, %d\n",
1728d6c0b56eSmrg					   err);
1729d6c0b56eSmrg			}
1730d6c0b56eSmrg			for (j = 0; j < drmmode_prop->count_enums; j++)
1731d6c0b56eSmrg				if (drmmode_prop->enums[j].value == p->value)
1732d6c0b56eSmrg					break;
1733d6c0b56eSmrg			/* there's always a matching value */
1734d6c0b56eSmrg			err =
1735d6c0b56eSmrg			    RRChangeOutputProperty(output->randr_output,
1736d6c0b56eSmrg						   p->atoms[0], XA_ATOM, 32,
1737d6c0b56eSmrg						   PropModeReplace, 1,
1738d6c0b56eSmrg						   &p->atoms[j + 1], FALSE,
1739d6c0b56eSmrg						   TRUE);
1740d6c0b56eSmrg			if (err != 0) {
1741d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1742d6c0b56eSmrg					   "RRChangeOutputProperty error, %d\n",
1743d6c0b56eSmrg					   err);
1744d6c0b56eSmrg			}
1745d6c0b56eSmrg		}
1746d6c0b56eSmrg	}
1747d6c0b56eSmrg}
1748d6c0b56eSmrg
1749d6c0b56eSmrgstatic Bool
1750d6c0b56eSmrgdrmmode_output_set_property(xf86OutputPtr output, Atom property,
1751d6c0b56eSmrg			    RRPropertyValuePtr value)
1752d6c0b56eSmrg{
1753d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1754d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1755d6c0b56eSmrg	int i;
1756d6c0b56eSmrg
1757d6c0b56eSmrg	for (i = 0; i < drmmode_output->num_props; i++) {
1758d6c0b56eSmrg		drmmode_prop_ptr p = &drmmode_output->props[i];
1759d6c0b56eSmrg
1760d6c0b56eSmrg		if (p->atoms[0] != property)
1761d6c0b56eSmrg			continue;
1762d6c0b56eSmrg
1763d6c0b56eSmrg		if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1764d6c0b56eSmrg			uint32_t val;
1765d6c0b56eSmrg
1766d6c0b56eSmrg			if (value->type != XA_INTEGER || value->format != 32 ||
1767d6c0b56eSmrg			    value->size != 1)
1768d6c0b56eSmrg				return FALSE;
1769d6c0b56eSmrg			val = *(uint32_t *) value->data;
1770d6c0b56eSmrg
1771d6c0b56eSmrg			drmModeConnectorSetProperty(pAMDGPUEnt->fd,
1772d6c0b56eSmrg						    drmmode_output->output_id,
1773d6c0b56eSmrg						    p->mode_prop->prop_id,
1774d6c0b56eSmrg						    (uint64_t) val);
1775d6c0b56eSmrg			return TRUE;
1776d6c0b56eSmrg		} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1777d6c0b56eSmrg			Atom atom;
1778d6c0b56eSmrg			const char *name;
1779d6c0b56eSmrg			int j;
1780d6c0b56eSmrg
1781d6c0b56eSmrg			if (value->type != XA_ATOM || value->format != 32
1782d6c0b56eSmrg			    || value->size != 1)
1783d6c0b56eSmrg				return FALSE;
1784d6c0b56eSmrg			memcpy(&atom, value->data, 4);
178524b90cf4Smrg			if (!(name = NameForAtom(atom)))
178624b90cf4Smrg				return FALSE;
1787d6c0b56eSmrg
1788d6c0b56eSmrg			/* search for matching name string, then set its value down */
1789d6c0b56eSmrg			for (j = 0; j < p->mode_prop->count_enums; j++) {
1790d6c0b56eSmrg				if (!strcmp(p->mode_prop->enums[j].name, name)) {
179111bf0794Smrg					if (i == (drmmode_output->num_props - 1)) {
179211bf0794Smrg						if (drmmode_output->tear_free != j) {
179311bf0794Smrg							xf86CrtcPtr crtc = output->crtc;
179411bf0794Smrg
179511bf0794Smrg							drmmode_output->tear_free = j;
179611bf0794Smrg							if (crtc) {
179711bf0794Smrg								drmmode_set_mode_major(crtc,
179811bf0794Smrg										       &crtc->mode,
179911bf0794Smrg										       crtc->rotation,
180011bf0794Smrg										       crtc->x,
180111bf0794Smrg										       crtc->y);
180211bf0794Smrg							}
180311bf0794Smrg						}
180411bf0794Smrg					} else {
180511bf0794Smrg						drmModeConnectorSetProperty(pAMDGPUEnt->fd,
180611bf0794Smrg									    drmmode_output->output_id,
180711bf0794Smrg									    p->mode_prop->prop_id,
180811bf0794Smrg									    p->mode_prop->enums[j].value);
180911bf0794Smrg					}
181011bf0794Smrg
1811d6c0b56eSmrg					return TRUE;
1812d6c0b56eSmrg				}
1813d6c0b56eSmrg			}
1814d6c0b56eSmrg		}
1815d6c0b56eSmrg	}
1816d6c0b56eSmrg
1817d6c0b56eSmrg	return TRUE;
1818d6c0b56eSmrg}
1819d6c0b56eSmrg
1820d6c0b56eSmrgstatic Bool drmmode_output_get_property(xf86OutputPtr output, Atom property)
1821d6c0b56eSmrg{
1822d6c0b56eSmrg	return TRUE;
1823d6c0b56eSmrg}
1824d6c0b56eSmrg
1825d6c0b56eSmrgstatic const xf86OutputFuncsRec drmmode_output_funcs = {
1826d6c0b56eSmrg	.dpms = drmmode_output_dpms,
1827d6c0b56eSmrg	.create_resources = drmmode_output_create_resources,
1828d6c0b56eSmrg	.set_property = drmmode_output_set_property,
1829d6c0b56eSmrg	.get_property = drmmode_output_get_property,
1830d6c0b56eSmrg#if 0
1831d6c0b56eSmrg
1832d6c0b56eSmrg	.save = drmmode_crt_save,
1833d6c0b56eSmrg	.restore = drmmode_crt_restore,
1834d6c0b56eSmrg	.mode_fixup = drmmode_crt_mode_fixup,
1835d6c0b56eSmrg	.prepare = drmmode_output_prepare,
1836d6c0b56eSmrg	.mode_set = drmmode_crt_mode_set,
1837d6c0b56eSmrg	.commit = drmmode_output_commit,
1838d6c0b56eSmrg#endif
1839d6c0b56eSmrg	.detect = drmmode_output_detect,
1840d6c0b56eSmrg	.mode_valid = drmmode_output_mode_valid,
1841d6c0b56eSmrg
1842d6c0b56eSmrg	.get_modes = drmmode_output_get_modes,
1843d6c0b56eSmrg	.destroy = drmmode_output_destroy
1844d6c0b56eSmrg};
1845d6c0b56eSmrg
1846d6c0b56eSmrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown,
1847d6c0b56eSmrg	SubPixelHorizontalRGB,
1848d6c0b56eSmrg	SubPixelHorizontalBGR,
1849d6c0b56eSmrg	SubPixelVerticalRGB,
1850d6c0b56eSmrg	SubPixelVerticalBGR,
1851d6c0b56eSmrg	SubPixelNone
1852d6c0b56eSmrg};
1853d6c0b56eSmrg
1854d6c0b56eSmrgconst char *output_names[] = { "None",
1855d6c0b56eSmrg	"VGA",
1856d6c0b56eSmrg	"DVI-I",
1857d6c0b56eSmrg	"DVI-D",
1858d6c0b56eSmrg	"DVI-A",
1859d6c0b56eSmrg	"Composite",
1860d6c0b56eSmrg	"S-video",
1861d6c0b56eSmrg	"LVDS",
1862d6c0b56eSmrg	"CTV",
1863d6c0b56eSmrg	"DIN",
1864d6c0b56eSmrg	"DisplayPort",
1865d6c0b56eSmrg	"HDMI-A",
1866d6c0b56eSmrg	"HDMI-B",
1867d6c0b56eSmrg	"TV",
1868d6c0b56eSmrg	"eDP",
1869d6c0b56eSmrg	"Virtual",
1870d6c0b56eSmrg	"DSI",
1871d6c0b56eSmrg};
1872d6c0b56eSmrg
1873d6c0b56eSmrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
1874d6c0b56eSmrg
1875d6c0b56eSmrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
1876d6c0b56eSmrg{
1877d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1878d6c0b56eSmrg	int i;
1879d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
1880d6c0b56eSmrg		xf86OutputPtr output = xf86_config->output[i];
1881d6c0b56eSmrg		drmmode_output_private_ptr drmmode_output;
1882d6c0b56eSmrg		drmmode_output = output->driver_private;
1883d6c0b56eSmrg		if (drmmode_output->output_id == id)
1884d6c0b56eSmrg			return output;
1885d6c0b56eSmrg	}
1886d6c0b56eSmrg	return NULL;
1887d6c0b56eSmrg}
1888d6c0b56eSmrg
1889d6c0b56eSmrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
1890d6c0b56eSmrg{
1891d6c0b56eSmrg	char *conn;
1892d6c0b56eSmrg	char conn_id[5];
1893d6c0b56eSmrg	int id, len;
1894d6c0b56eSmrg	char *blob_data;
1895d6c0b56eSmrg
1896d6c0b56eSmrg	if (!path_blob)
1897d6c0b56eSmrg		return -1;
1898d6c0b56eSmrg
1899d6c0b56eSmrg	blob_data = path_blob->data;
1900d6c0b56eSmrg	/* we only handle MST paths for now */
1901d6c0b56eSmrg	if (strncmp(blob_data, "mst:", 4))
1902d6c0b56eSmrg		return -1;
1903d6c0b56eSmrg
1904d6c0b56eSmrg	conn = strchr(blob_data + 4, '-');
1905d6c0b56eSmrg	if (!conn)
1906d6c0b56eSmrg		return -1;
1907d6c0b56eSmrg	len = conn - (blob_data + 4);
1908d6c0b56eSmrg	if (len + 1 > 5)
1909d6c0b56eSmrg		return -1;
1910d6c0b56eSmrg	memcpy(conn_id, blob_data + 4, len);
1911d6c0b56eSmrg	conn_id[len] = '\0';
1912d6c0b56eSmrg	id = strtoul(conn_id, NULL, 10);
1913d6c0b56eSmrg
1914d6c0b56eSmrg	*conn_base_id = id;
1915d6c0b56eSmrg
1916d6c0b56eSmrg	*path = conn + 1;
1917d6c0b56eSmrg	return 0;
1918d6c0b56eSmrg}
1919d6c0b56eSmrg
1920d6c0b56eSmrgstatic void
1921d6c0b56eSmrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
1922d6c0b56eSmrg		    drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi)
1923d6c0b56eSmrg{
1924d6c0b56eSmrg	xf86OutputPtr output;
1925d6c0b56eSmrg	int conn_id;
1926d6c0b56eSmrg	char *extra_path;
1927d6c0b56eSmrg
1928d6c0b56eSmrg	output = NULL;
1929d6c0b56eSmrg	if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
1930d6c0b56eSmrg		output = find_output(pScrn, conn_id);
1931d6c0b56eSmrg	if (output) {
1932d6c0b56eSmrg		snprintf(name, 32, "%s-%s", output->name, extra_path);
1933d6c0b56eSmrg	} else {
193424b90cf4Smrg		if (koutput->connector_type >= NUM_OUTPUT_NAMES) {
1935d6c0b56eSmrg			snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1);
193624b90cf4Smrg		} else if (pScrn->is_gpu) {
1937d6c0b56eSmrg			snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type],
1938d6c0b56eSmrg				 pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1);
193924b90cf4Smrg		} else {
1940d6c0b56eSmrg			/* need to do smart conversion here for compat with non-kms ATI driver */
1941d6c0b56eSmrg			if (koutput->connector_type_id == 1) {
1942d6c0b56eSmrg				switch(koutput->connector_type) {
1943d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DVII:
1944d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DVID:
1945d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DVIA:
1946d6c0b56eSmrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
1947d6c0b56eSmrg					(*num_dvi)++;
1948d6c0b56eSmrg					break;
1949d6c0b56eSmrg				case DRM_MODE_CONNECTOR_HDMIA:
1950d6c0b56eSmrg				case DRM_MODE_CONNECTOR_HDMIB:
1951d6c0b56eSmrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
1952d6c0b56eSmrg					(*num_hdmi)++;
1953d6c0b56eSmrg					break;
1954d6c0b56eSmrg				case DRM_MODE_CONNECTOR_VGA:
1955d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DisplayPort:
1956d6c0b56eSmrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
1957d6c0b56eSmrg					break;
1958d6c0b56eSmrg				default:
1959d6c0b56eSmrg					snprintf(name, 32, "%s", output_names[koutput->connector_type]);
1960d6c0b56eSmrg					break;
1961d6c0b56eSmrg				}
1962d6c0b56eSmrg			} else {
1963d6c0b56eSmrg				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
1964d6c0b56eSmrg			}
1965d6c0b56eSmrg		}
1966d6c0b56eSmrg	}
1967d6c0b56eSmrg}
1968d6c0b56eSmrg
1969d6c0b56eSmrg
1970d6c0b56eSmrgstatic unsigned int
1971d6c0b56eSmrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic)
1972d6c0b56eSmrg{
1973d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1974d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1975d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1976d6c0b56eSmrg	xf86OutputPtr output;
1977d6c0b56eSmrg	drmModeConnectorPtr koutput;
1978d6c0b56eSmrg	drmModeEncoderPtr *kencoders = NULL;
1979d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output;
1980d6c0b56eSmrg	drmModePropertyBlobPtr path_blob = NULL;
1981d6c0b56eSmrg	char name[32];
1982d6c0b56eSmrg	int i;
1983d6c0b56eSmrg	const char *s;
1984d6c0b56eSmrg
1985d6c0b56eSmrg	koutput =
1986d6c0b56eSmrg	    drmModeGetConnector(pAMDGPUEnt->fd,
1987d6c0b56eSmrg				mode_res->connectors[num]);
1988d6c0b56eSmrg	if (!koutput)
1989d6c0b56eSmrg		return 0;
1990d6c0b56eSmrg
199124b90cf4Smrg	path_blob = koutput_get_prop_blob(pAMDGPUEnt->fd, koutput, "PATH");
1992d6c0b56eSmrg
1993d6c0b56eSmrg	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
1994d6c0b56eSmrg	if (!kencoders) {
1995d6c0b56eSmrg		goto out_free_encoders;
1996d6c0b56eSmrg	}
1997d6c0b56eSmrg
1998d6c0b56eSmrg	for (i = 0; i < koutput->count_encoders; i++) {
1999d6c0b56eSmrg		kencoders[i] =
2000d6c0b56eSmrg		    drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]);
2001d6c0b56eSmrg		if (!kencoders[i]) {
2002d6c0b56eSmrg			goto out_free_encoders;
2003d6c0b56eSmrg		}
2004d6c0b56eSmrg	}
2005d6c0b56eSmrg
2006d6c0b56eSmrg	drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi);
2007d6c0b56eSmrg	if (path_blob) {
2008d6c0b56eSmrg		drmModeFreePropertyBlob(path_blob);
2009d6c0b56eSmrg	}
2010d6c0b56eSmrg
2011d6c0b56eSmrg	if (path_blob && dynamic) {
2012d6c0b56eSmrg		/* See if we have an output with this name already
2013d6c0b56eSmrg		 * and hook stuff up.
2014d6c0b56eSmrg		 */
2015d6c0b56eSmrg		for (i = 0; i < xf86_config->num_output; i++) {
2016d6c0b56eSmrg			output = xf86_config->output[i];
2017d6c0b56eSmrg
2018d6c0b56eSmrg			if (strncmp(output->name, name, 32))
2019d6c0b56eSmrg				continue;
2020d6c0b56eSmrg
2021d6c0b56eSmrg			drmmode_output = output->driver_private;
2022d6c0b56eSmrg			drmmode_output->output_id = mode_res->connectors[num];
2023d6c0b56eSmrg			drmmode_output->mode_output = koutput;
2024d6c0b56eSmrg			for (i = 0; i < koutput->count_encoders; i++) {
2025d6c0b56eSmrg				drmModeFreeEncoder(kencoders[i]);
2026d6c0b56eSmrg			}
2027d6c0b56eSmrg			free(kencoders);
2028d6c0b56eSmrg			return 1;
2029d6c0b56eSmrg		}
2030d6c0b56eSmrg	}
2031d6c0b56eSmrg
2032d6c0b56eSmrg	if (xf86IsEntityShared(pScrn->entityList[0])) {
2033d6c0b56eSmrg		if ((s =
2034d6c0b56eSmrg		     xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
2035d6c0b56eSmrg			if (!AMDGPUZaphodStringMatches(pScrn, s, name))
2036d6c0b56eSmrg				goto out_free_encoders;
2037d6c0b56eSmrg		} else {
2038d6c0b56eSmrg			if (!info->IsSecondary && (num != 0))
2039d6c0b56eSmrg				goto out_free_encoders;
2040d6c0b56eSmrg			else if (info->IsSecondary && (num != 1))
2041d6c0b56eSmrg				goto out_free_encoders;
2042d6c0b56eSmrg		}
2043d6c0b56eSmrg	}
2044d6c0b56eSmrg
2045d6c0b56eSmrg	output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
2046d6c0b56eSmrg	if (!output) {
2047d6c0b56eSmrg		goto out_free_encoders;
2048d6c0b56eSmrg	}
2049d6c0b56eSmrg
2050d6c0b56eSmrg	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
2051d6c0b56eSmrg	if (!drmmode_output) {
2052d6c0b56eSmrg		xf86OutputDestroy(output);
2053d6c0b56eSmrg		goto out_free_encoders;
2054d6c0b56eSmrg	}
2055d6c0b56eSmrg
2056d6c0b56eSmrg	drmmode_output->output_id = mode_res->connectors[num];
2057d6c0b56eSmrg	drmmode_output->mode_output = koutput;
2058d6c0b56eSmrg	drmmode_output->mode_encoders = kencoders;
2059d6c0b56eSmrg	drmmode_output->drmmode = drmmode;
2060d6c0b56eSmrg	output->mm_width = koutput->mmWidth;
2061d6c0b56eSmrg	output->mm_height = koutput->mmHeight;
2062d6c0b56eSmrg
2063d6c0b56eSmrg	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
2064d6c0b56eSmrg	output->interlaceAllowed = TRUE;
2065d6c0b56eSmrg	output->doubleScanAllowed = TRUE;
2066d6c0b56eSmrg	output->driver_private = drmmode_output;
2067d6c0b56eSmrg
2068d6c0b56eSmrg	output->possible_crtcs = 0xffffffff;
2069d6c0b56eSmrg	for (i = 0; i < koutput->count_encoders; i++) {
2070d6c0b56eSmrg		output->possible_crtcs &= kencoders[i]->possible_crtcs;
2071d6c0b56eSmrg	}
2072d6c0b56eSmrg	/* work out the possible clones later */
2073d6c0b56eSmrg	output->possible_clones = 0;
2074d6c0b56eSmrg
207524b90cf4Smrg	drmmode_output->dpms_enum_id =
207624b90cf4Smrg		koutput_get_prop_id(pAMDGPUEnt->fd, koutput, DRM_MODE_PROP_ENUM,
207724b90cf4Smrg				    "DPMS");
2078d6c0b56eSmrg
2079d6c0b56eSmrg	if (dynamic) {
2080d6c0b56eSmrg		output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
2081d6c0b56eSmrg		drmmode_output_create_resources(output);
2082d6c0b56eSmrg	}
2083d6c0b56eSmrg
2084d6c0b56eSmrg	return 1;
2085d6c0b56eSmrgout_free_encoders:
2086d6c0b56eSmrg	if (kencoders) {
2087d6c0b56eSmrg		for (i = 0; i < koutput->count_encoders; i++)
2088d6c0b56eSmrg			drmModeFreeEncoder(kencoders[i]);
2089d6c0b56eSmrg		free(kencoders);
2090d6c0b56eSmrg	}
2091d6c0b56eSmrg	drmModeFreeConnector(koutput);
2092d6c0b56eSmrg	return 0;
2093d6c0b56eSmrg}
2094d6c0b56eSmrg
2095d6c0b56eSmrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
2096d6c0b56eSmrg{
2097d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output =
2098d6c0b56eSmrg	    output->driver_private, clone_drmout;
2099d6c0b56eSmrg	int i;
2100d6c0b56eSmrg	xf86OutputPtr clone_output;
2101d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2102d6c0b56eSmrg	int index_mask = 0;
2103d6c0b56eSmrg
2104d6c0b56eSmrg	if (drmmode_output->enc_clone_mask == 0)
2105d6c0b56eSmrg		return index_mask;
2106d6c0b56eSmrg
2107d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
2108d6c0b56eSmrg		clone_output = xf86_config->output[i];
2109d6c0b56eSmrg		clone_drmout = clone_output->driver_private;
2110d6c0b56eSmrg		if (output == clone_output)
2111d6c0b56eSmrg			continue;
2112d6c0b56eSmrg
2113d6c0b56eSmrg		if (clone_drmout->enc_mask == 0)
2114d6c0b56eSmrg			continue;
2115d6c0b56eSmrg		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
2116d6c0b56eSmrg			index_mask |= (1 << i);
2117d6c0b56eSmrg	}
2118d6c0b56eSmrg	return index_mask;
2119d6c0b56eSmrg}
2120d6c0b56eSmrg
2121d6c0b56eSmrgstatic void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
2122d6c0b56eSmrg{
2123d6c0b56eSmrg	int i, j;
2124d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2125d6c0b56eSmrg
2126d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
2127d6c0b56eSmrg		xf86OutputPtr output = xf86_config->output[i];
2128d6c0b56eSmrg		drmmode_output_private_ptr drmmode_output;
2129d6c0b56eSmrg
2130d6c0b56eSmrg		drmmode_output = output->driver_private;
2131d6c0b56eSmrg		drmmode_output->enc_clone_mask = 0xff;
2132d6c0b56eSmrg		/* and all the possible encoder clones for this output together */
2133d6c0b56eSmrg		for (j = 0; j < drmmode_output->mode_output->count_encoders;
2134d6c0b56eSmrg		     j++) {
2135d6c0b56eSmrg			int k;
2136d6c0b56eSmrg			for (k = 0; k < mode_res->count_encoders; k++) {
2137d6c0b56eSmrg				if (mode_res->encoders[k] ==
2138d6c0b56eSmrg				    drmmode_output->
2139d6c0b56eSmrg				    mode_encoders[j]->encoder_id)
2140d6c0b56eSmrg					drmmode_output->enc_mask |= (1 << k);
2141d6c0b56eSmrg			}
2142d6c0b56eSmrg
2143d6c0b56eSmrg			drmmode_output->enc_clone_mask &=
2144d6c0b56eSmrg			    drmmode_output->mode_encoders[j]->possible_clones;
2145d6c0b56eSmrg		}
2146d6c0b56eSmrg	}
2147d6c0b56eSmrg
2148d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
2149d6c0b56eSmrg		xf86OutputPtr output = xf86_config->output[i];
2150d6c0b56eSmrg		output->possible_clones = find_clones(scrn, output);
2151d6c0b56eSmrg	}
2152d6c0b56eSmrg}
2153d6c0b56eSmrg
2154d6c0b56eSmrg/* returns pitch alignment in pixels */
2155d6c0b56eSmrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe)
2156d6c0b56eSmrg{
2157d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
2158d6c0b56eSmrg
2159d6c0b56eSmrg	if (info->have_tiling_info)
2160d6c0b56eSmrg		/* linear aligned requirements */
2161d6c0b56eSmrg		return MAX(64, info->group_bytes / bpe);
2162d6c0b56eSmrg	else
2163d6c0b56eSmrg		/* default to 512 elements if we don't know the real
2164d6c0b56eSmrg		 * group size otherwise the kernel may reject the CS
2165d6c0b56eSmrg		 * if the group sizes don't match as the pitch won't
2166d6c0b56eSmrg		 * be aligned properly.
2167d6c0b56eSmrg		 */
2168d6c0b56eSmrg		return 512;
2169d6c0b56eSmrg}
2170d6c0b56eSmrg
2171d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
2172d6c0b56eSmrg{
2173d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2174d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
2175d6c0b56eSmrg	struct amdgpu_buffer *old_front = NULL;
2176d6c0b56eSmrg	ScreenPtr screen = xf86ScrnToScreen(scrn);
2177d6c0b56eSmrg	int i, pitch, old_width, old_height, old_pitch;
2178d6c0b56eSmrg	int cpp = info->pixel_bytes;
2179d6c0b56eSmrg	PixmapPtr ppix = screen->GetScreenPixmap(screen);
2180d6c0b56eSmrg	void *fb_shadow;
2181d6c0b56eSmrg	int hint = 0;
2182d6c0b56eSmrg
2183d6c0b56eSmrg	if (scrn->virtualX == width && scrn->virtualY == height)
2184d6c0b56eSmrg		return TRUE;
2185d6c0b56eSmrg
2186d6c0b56eSmrg	if (info->shadow_primary)
2187d6c0b56eSmrg		hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
2188d6c0b56eSmrg	else if (!info->use_glamor)
2189d6c0b56eSmrg		hint = AMDGPU_CREATE_PIXMAP_LINEAR;
2190d6c0b56eSmrg
2191d6c0b56eSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
2192d6c0b56eSmrg		   "Allocate new frame buffer %dx%d\n", width, height);
2193d6c0b56eSmrg
2194d6c0b56eSmrg	old_width = scrn->virtualX;
2195d6c0b56eSmrg	old_height = scrn->virtualY;
2196d6c0b56eSmrg	old_pitch = scrn->displayWidth;
2197d6c0b56eSmrg	old_front = info->front_buffer;
2198d6c0b56eSmrg
2199d6c0b56eSmrg	scrn->virtualX = width;
2200d6c0b56eSmrg	scrn->virtualY = height;
2201d6c0b56eSmrg
2202d6c0b56eSmrg	info->front_buffer =
2203d6c0b56eSmrg		amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY,
2204d6c0b56eSmrg				       scrn->depth, hint, scrn->bitsPerPixel,
2205d6c0b56eSmrg				       &pitch);
2206d6c0b56eSmrg	if (!info->front_buffer) {
2207d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2208d6c0b56eSmrg			   "Failed to allocate front buffer memory\n");
2209d6c0b56eSmrg		goto fail;
2210d6c0b56eSmrg	}
2211d6c0b56eSmrg
2212d6c0b56eSmrg	if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) {
2213d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2214d6c0b56eSmrg			   "Failed to map front buffer memory\n");
2215d6c0b56eSmrg		goto fail;
2216d6c0b56eSmrg	}
2217d6c0b56eSmrg
2218d6c0b56eSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch);
2219d6c0b56eSmrg	scrn->displayWidth = pitch / cpp;
2220d6c0b56eSmrg
2221d6c0b56eSmrg	if (info->use_glamor ||
2222d6c0b56eSmrg	    (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) {
2223d6c0b56eSmrg		screen->ModifyPixmapHeader(ppix,
2224d6c0b56eSmrg					   width, height, -1, -1, pitch, info->front_buffer->cpu_ptr);
2225d6c0b56eSmrg	} else {
2226d6c0b56eSmrg		fb_shadow = calloc(1, pitch * scrn->virtualY);
2227d6c0b56eSmrg		if (fb_shadow == NULL)
2228d6c0b56eSmrg			goto fail;
2229d6c0b56eSmrg		free(info->fb_shadow);
2230d6c0b56eSmrg		info->fb_shadow = fb_shadow;
2231d6c0b56eSmrg		screen->ModifyPixmapHeader(ppix,
2232d6c0b56eSmrg					   width, height, -1, -1, pitch,
2233d6c0b56eSmrg					   info->fb_shadow);
2234d6c0b56eSmrg	}
2235d6c0b56eSmrg
2236504d986fSmrg	if (!amdgpu_glamor_create_screen_resources(scrn->pScreen))
2237504d986fSmrg		goto fail;
2238504d986fSmrg
2239504d986fSmrg	if (info->use_glamor ||
2240504d986fSmrg	    (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) {
2241504d986fSmrg		if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer))
2242504d986fSmrg			goto fail;
2243504d986fSmrg	}
2244d6c0b56eSmrg
224524b90cf4Smrg	amdgpu_pixmap_clear(ppix);
2246d6c0b56eSmrg	amdgpu_glamor_finish(scrn);
2247d6c0b56eSmrg
2248d6c0b56eSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
2249d6c0b56eSmrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
2250d6c0b56eSmrg
2251d6c0b56eSmrg		if (!crtc->enabled)
2252d6c0b56eSmrg			continue;
2253d6c0b56eSmrg
2254d6c0b56eSmrg		drmmode_set_mode_major(crtc, &crtc->mode,
2255d6c0b56eSmrg				       crtc->rotation, crtc->x, crtc->y);
2256d6c0b56eSmrg	}
2257d6c0b56eSmrg
2258d6c0b56eSmrg	if (old_front) {
2259d6c0b56eSmrg		amdgpu_bo_unref(&old_front);
2260d6c0b56eSmrg	}
2261d6c0b56eSmrg
2262d6c0b56eSmrg	return TRUE;
2263d6c0b56eSmrg
2264d6c0b56eSmrgfail:
2265d6c0b56eSmrg	if (info->front_buffer) {
2266d6c0b56eSmrg		amdgpu_bo_unref(&info->front_buffer);
2267d6c0b56eSmrg	}
2268d6c0b56eSmrg	info->front_buffer = old_front;
2269d6c0b56eSmrg	scrn->virtualX = old_width;
2270d6c0b56eSmrg	scrn->virtualY = old_height;
2271d6c0b56eSmrg	scrn->displayWidth = old_pitch;
2272d6c0b56eSmrg
2273d6c0b56eSmrg	return FALSE;
2274d6c0b56eSmrg}
2275d6c0b56eSmrg
2276d6c0b56eSmrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
2277d6c0b56eSmrg	drmmode_xf86crtc_resize
2278d6c0b56eSmrg};
2279d6c0b56eSmrg
2280d6c0b56eSmrgstatic void
2281d6c0b56eSmrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
2282d6c0b56eSmrg{
228324b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
228424b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
2285d6c0b56eSmrg	drmmode_flipdata_ptr flipdata = event_data;
2286d6c0b56eSmrg
2287d6c0b56eSmrg	if (--flipdata->flip_count == 0) {
2288504d986fSmrg		if (!flipdata->fe_crtc)
2289504d986fSmrg			flipdata->fe_crtc = crtc;
2290504d986fSmrg		flipdata->abort(flipdata->fe_crtc, flipdata->event_data);
229124b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb, NULL);
2292d6c0b56eSmrg		free(flipdata);
2293d6c0b56eSmrg	}
2294d6c0b56eSmrg
229524b90cf4Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
229624b90cf4Smrg			     NULL);
2297d6c0b56eSmrg}
2298d6c0b56eSmrg
2299d6c0b56eSmrgstatic void
2300d6c0b56eSmrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
2301d6c0b56eSmrg{
2302d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
230324b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2304d6c0b56eSmrg	drmmode_flipdata_ptr flipdata = event_data;
2305d6c0b56eSmrg
2306d6c0b56eSmrg	/* Is this the event whose info shall be delivered to higher level? */
2307d6c0b56eSmrg	if (crtc == flipdata->fe_crtc) {
2308d6c0b56eSmrg		/* Yes: Cache msc, ust for later delivery. */
2309d6c0b56eSmrg		flipdata->fe_frame = frame;
2310d6c0b56eSmrg		flipdata->fe_usec = usec;
2311d6c0b56eSmrg	}
2312d6c0b56eSmrg
231324b90cf4Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb,
231424b90cf4Smrg			     flipdata->fb);
231524b90cf4Smrg	if (drmmode_crtc->tear_free ||
231624b90cf4Smrg	    drmmode_crtc->flip_pending == flipdata->fb) {
231724b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd,
231824b90cf4Smrg				     &drmmode_crtc->flip_pending, NULL);
231924b90cf4Smrg	}
232024b90cf4Smrg
2321d6c0b56eSmrg	if (--flipdata->flip_count == 0) {
2322504d986fSmrg		/* Deliver MSC & UST from reference/current CRTC to flip event
2323504d986fSmrg		 * handler
2324504d986fSmrg		 */
2325d6c0b56eSmrg		if (flipdata->fe_crtc)
2326504d986fSmrg			flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame,
2327504d986fSmrg					  flipdata->fe_usec, flipdata->event_data);
2328504d986fSmrg		else
2329504d986fSmrg			flipdata->handler(crtc, frame, usec, flipdata->event_data);
2330d6c0b56eSmrg
233124b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb, NULL);
2332d6c0b56eSmrg		free(flipdata);
2333d6c0b56eSmrg	}
2334d6c0b56eSmrg}
2335d6c0b56eSmrg
2336504d986fSmrg#if HAVE_NOTIFY_FD
2337504d986fSmrgstatic void drmmode_notify_fd(int fd, int notify, void *data)
2338504d986fSmrg{
2339504d986fSmrg	drmmode_ptr drmmode = data;
2340504d986fSmrg	drmHandleEvent(fd, &drmmode->event_context);
2341504d986fSmrg}
2342504d986fSmrg#else
2343d6c0b56eSmrgstatic void drm_wakeup_handler(pointer data, int err, pointer p)
2344d6c0b56eSmrg{
2345d6c0b56eSmrg	drmmode_ptr drmmode = data;
2346d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn);
2347d6c0b56eSmrg	fd_set *read_mask = p;
2348d6c0b56eSmrg
2349d6c0b56eSmrg	if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) {
2350d6c0b56eSmrg		drmHandleEvent(pAMDGPUEnt->fd, &drmmode->event_context);
2351d6c0b56eSmrg	}
2352d6c0b56eSmrg}
2353504d986fSmrg#endif
2354d6c0b56eSmrg
235511bf0794Smrgstatic Bool drmmode_probe_page_flip_target(AMDGPUEntPtr pAMDGPUEnt)
235611bf0794Smrg{
235711bf0794Smrg	uint64_t cap_value;
235811bf0794Smrg
235911bf0794Smrg	return drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PAGE_FLIP_TARGET,
236011bf0794Smrg			 &cap_value) == 0 && cap_value != 0;
236111bf0794Smrg}
236211bf0794Smrg
236311bf0794Smrgstatic int
236411bf0794Smrgdrmmode_page_flip(AMDGPUEntPtr pAMDGPUEnt, drmmode_crtc_private_ptr drmmode_crtc,
236511bf0794Smrg		  int fb_id, uint32_t flags, uintptr_t drm_queue_seq)
236611bf0794Smrg{
236711bf0794Smrg	flags |= DRM_MODE_PAGE_FLIP_EVENT;
236811bf0794Smrg	return drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
236911bf0794Smrg			       fb_id, flags, (void*)drm_queue_seq);
237011bf0794Smrg}
237111bf0794Smrg
237211bf0794Smrgint
237311bf0794Smrgdrmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt,
237411bf0794Smrg				  drmmode_crtc_private_ptr drmmode_crtc,
237511bf0794Smrg				  int fb_id, uint32_t flags,
237611bf0794Smrg				  uintptr_t drm_queue_seq, uint32_t target_msc)
237711bf0794Smrg{
237811bf0794Smrg	if (pAMDGPUEnt->has_page_flip_target) {
237911bf0794Smrg		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE;
238011bf0794Smrg		return drmModePageFlipTarget(pAMDGPUEnt->fd,
238111bf0794Smrg					     drmmode_crtc->mode_crtc->crtc_id,
238211bf0794Smrg					     fb_id, flags, (void*)drm_queue_seq,
238311bf0794Smrg					     target_msc);
238411bf0794Smrg	}
238511bf0794Smrg
238611bf0794Smrg	return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags,
238711bf0794Smrg				 drm_queue_seq);
238811bf0794Smrg}
238911bf0794Smrg
239011bf0794Smrgint
239111bf0794Smrgdrmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt,
239211bf0794Smrg				  drmmode_crtc_private_ptr drmmode_crtc,
239311bf0794Smrg				  int fb_id, uint32_t flags,
239411bf0794Smrg				  uintptr_t drm_queue_seq, uint32_t target_msc)
239511bf0794Smrg{
239611bf0794Smrg	if (pAMDGPUEnt->has_page_flip_target) {
239711bf0794Smrg		flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE;
239811bf0794Smrg		return drmModePageFlipTarget(pAMDGPUEnt->fd,
239911bf0794Smrg					     drmmode_crtc->mode_crtc->crtc_id,
240011bf0794Smrg					     fb_id, flags, (void*)drm_queue_seq,
240111bf0794Smrg					     target_msc);
240211bf0794Smrg	}
240311bf0794Smrg
240411bf0794Smrg	return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags,
240511bf0794Smrg				 drm_queue_seq);
240611bf0794Smrg}
240711bf0794Smrg
2408d6c0b56eSmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
2409d6c0b56eSmrg{
2410d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2411d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2412d6c0b56eSmrg	int i, num_dvi = 0, num_hdmi = 0;
2413d6c0b56eSmrg	unsigned int crtcs_needed = 0;
2414d6c0b56eSmrg	drmModeResPtr mode_res;
2415d6c0b56eSmrg	char *bus_id_string, *provider_name;
2416d6c0b56eSmrg
2417d6c0b56eSmrg	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
2418d6c0b56eSmrg
2419d6c0b56eSmrg	drmmode->scrn = pScrn;
2420d6c0b56eSmrg	mode_res = drmModeGetResources(pAMDGPUEnt->fd);
2421d6c0b56eSmrg	if (!mode_res)
2422d6c0b56eSmrg		return FALSE;
2423d6c0b56eSmrg
2424d6c0b56eSmrg	drmmode->count_crtcs = mode_res->count_crtcs;
2425d6c0b56eSmrg	xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
2426d6c0b56eSmrg			     mode_res->max_height);
2427d6c0b56eSmrg
2428d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2429d6c0b56eSmrg		       "Initializing outputs ...\n");
2430d6c0b56eSmrg	for (i = 0; i < mode_res->count_connectors; i++)
2431d6c0b56eSmrg		crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0);
2432d6c0b56eSmrg
2433d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2434d6c0b56eSmrg		       "%d crtcs needed for screen.\n", crtcs_needed);
2435d6c0b56eSmrg
243624b90cf4Smrg	/* Need per-screen drmmode_crtc_funcs, based on our global template,
243724b90cf4Smrg	 * so we can disable some functions, depending on screen settings.
243824b90cf4Smrg	 */
243924b90cf4Smrg	info->drmmode_crtc_funcs = drmmode_crtc_funcs;
244024b90cf4Smrg
2441d6c0b56eSmrg	if (!info->use_glamor) {
2442d6c0b56eSmrg		/* Rotation requires hardware acceleration */
244324b90cf4Smrg		info->drmmode_crtc_funcs.shadow_allocate = NULL;
244424b90cf4Smrg		info->drmmode_crtc_funcs.shadow_create = NULL;
244524b90cf4Smrg		info->drmmode_crtc_funcs.shadow_destroy = NULL;
2446d6c0b56eSmrg	}
2447d6c0b56eSmrg
244824b90cf4Smrg	/* Hw gamma lut's are currently bypassed by the hw at color depth 30,
244924b90cf4Smrg	 * so spare the server the effort to compute and update the cluts.
245024b90cf4Smrg	 */
245124b90cf4Smrg	if (pScrn->depth == 30)
245224b90cf4Smrg		info->drmmode_crtc_funcs.gamma_set = NULL;
245324b90cf4Smrg
2454d6c0b56eSmrg	for (i = 0; i < mode_res->count_crtcs; i++)
2455d6c0b56eSmrg		if (!xf86IsEntityShared(pScrn->entityList[0]) ||
2456d6c0b56eSmrg		    (crtcs_needed && !(pAMDGPUEnt->assigned_crtcs & (1 << i))))
2457d6c0b56eSmrg			crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
2458d6c0b56eSmrg
2459d6c0b56eSmrg	/* All ZaphodHeads outputs provided with matching crtcs? */
2460d6c0b56eSmrg	if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
2461d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2462d6c0b56eSmrg			   "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
2463d6c0b56eSmrg			   crtcs_needed);
2464d6c0b56eSmrg
2465d6c0b56eSmrg	/* workout clones */
2466d6c0b56eSmrg	drmmode_clones_init(pScrn, drmmode, mode_res);
2467d6c0b56eSmrg
2468d6c0b56eSmrg	bus_id_string = DRICreatePCIBusID(info->PciInfo);
2469d6c0b56eSmrg	XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string);
2470d6c0b56eSmrg	free(bus_id_string);
2471d6c0b56eSmrg	xf86ProviderSetup(pScrn, NULL, provider_name);
2472d6c0b56eSmrg	free(provider_name);
2473d6c0b56eSmrg
2474d6c0b56eSmrg	xf86InitialConfiguration(pScrn, TRUE);
2475d6c0b56eSmrg
247624b90cf4Smrg	drmmode->event_context.version = 2;
2477d6c0b56eSmrg	drmmode->event_context.vblank_handler = amdgpu_drm_queue_handler;
2478d6c0b56eSmrg	drmmode->event_context.page_flip_handler = amdgpu_drm_queue_handler;
2479d6c0b56eSmrg
248011bf0794Smrg	pAMDGPUEnt->has_page_flip_target = drmmode_probe_page_flip_target(pAMDGPUEnt);
248111bf0794Smrg
2482d6c0b56eSmrg	drmModeFreeResources(mode_res);
2483d6c0b56eSmrg	return TRUE;
2484d6c0b56eSmrg}
2485d6c0b56eSmrg
2486d6c0b56eSmrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
2487d6c0b56eSmrg{
2488d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2489d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2490d6c0b56eSmrg
2491d6c0b56eSmrg	info->drmmode_inited = TRUE;
2492d6c0b56eSmrg	if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) {
2493504d986fSmrg#if HAVE_NOTIFY_FD
2494504d986fSmrg		SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode);
2495504d986fSmrg#else
2496d6c0b56eSmrg		AddGeneralSocket(pAMDGPUEnt->fd);
2497d6c0b56eSmrg		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA,
2498d6c0b56eSmrg					       drm_wakeup_handler, drmmode);
2499504d986fSmrg#endif
2500d6c0b56eSmrg		pAMDGPUEnt->fd_wakeup_registered = serverGeneration;
2501d6c0b56eSmrg		pAMDGPUEnt->fd_wakeup_ref = 1;
2502d6c0b56eSmrg	} else
2503d6c0b56eSmrg		pAMDGPUEnt->fd_wakeup_ref++;
2504d6c0b56eSmrg}
2505d6c0b56eSmrg
2506d6c0b56eSmrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
2507d6c0b56eSmrg{
2508504d986fSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2509d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2510d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2511504d986fSmrg	int c;
2512d6c0b56eSmrg
2513d6c0b56eSmrg	if (!info->drmmode_inited)
2514d6c0b56eSmrg		return;
2515d6c0b56eSmrg
2516d6c0b56eSmrg	if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration &&
2517d6c0b56eSmrg	    !--pAMDGPUEnt->fd_wakeup_ref) {
2518504d986fSmrg#if HAVE_NOTIFY_FD
2519504d986fSmrg		RemoveNotifyFd(pAMDGPUEnt->fd);
2520504d986fSmrg#else
2521d6c0b56eSmrg		RemoveGeneralSocket(pAMDGPUEnt->fd);
2522d6c0b56eSmrg		RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA,
2523d6c0b56eSmrg					     drm_wakeup_handler, drmmode);
2524504d986fSmrg#endif
2525504d986fSmrg	}
2526504d986fSmrg
252711bf0794Smrg	for (c = 0; c < config->num_crtc; c++)
252811bf0794Smrg		drmmode_crtc_scanout_free(config->crtc[c]->driver_private);
2529d6c0b56eSmrg}
2530d6c0b56eSmrg
253124b90cf4Smrgstatic void drmmode_sprite_do_set_cursor(struct amdgpu_device_priv *device_priv,
253224b90cf4Smrg					 ScrnInfoPtr scrn, int x, int y)
253324b90cf4Smrg{
253424b90cf4Smrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
253524b90cf4Smrg	CursorPtr cursor = device_priv->cursor;
253624b90cf4Smrg	Bool sprite_visible = device_priv->sprite_visible;
253724b90cf4Smrg
253824b90cf4Smrg	if (cursor) {
253924b90cf4Smrg		x -= cursor->bits->xhot;
254024b90cf4Smrg		y -= cursor->bits->yhot;
254124b90cf4Smrg
254224b90cf4Smrg		device_priv->sprite_visible =
254324b90cf4Smrg			x < scrn->virtualX && y < scrn->virtualY &&
254424b90cf4Smrg			(x + cursor->bits->width > 0) &&
254524b90cf4Smrg			(y + cursor->bits->height > 0);
254624b90cf4Smrg	} else {
254724b90cf4Smrg		device_priv->sprite_visible = FALSE;
254824b90cf4Smrg	}
254924b90cf4Smrg
255024b90cf4Smrg	info->sprites_visible += device_priv->sprite_visible - sprite_visible;
255124b90cf4Smrg}
255224b90cf4Smrg
255324b90cf4Smrgvoid drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
255424b90cf4Smrg			       CursorPtr pCursor, int x, int y)
255524b90cf4Smrg{
255624b90cf4Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
255724b90cf4Smrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
255824b90cf4Smrg	struct amdgpu_device_priv *device_priv =
255924b90cf4Smrg		dixLookupScreenPrivate(&pDev->devPrivates,
256024b90cf4Smrg				       &amdgpu_device_private_key, pScreen);
256124b90cf4Smrg
256224b90cf4Smrg	device_priv->cursor = pCursor;
256324b90cf4Smrg	drmmode_sprite_do_set_cursor(device_priv, scrn, x, y);
256424b90cf4Smrg
256524b90cf4Smrg	info->SetCursor(pDev, pScreen, pCursor, x, y);
256624b90cf4Smrg}
256724b90cf4Smrg
256824b90cf4Smrgvoid drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen, int x,
256924b90cf4Smrg				int y)
257024b90cf4Smrg{
257124b90cf4Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
257224b90cf4Smrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
257324b90cf4Smrg	struct amdgpu_device_priv *device_priv =
257424b90cf4Smrg		dixLookupScreenPrivate(&pDev->devPrivates,
257524b90cf4Smrg				       &amdgpu_device_private_key, pScreen);
257624b90cf4Smrg
257724b90cf4Smrg	drmmode_sprite_do_set_cursor(device_priv, scrn, x, y);
257824b90cf4Smrg
257924b90cf4Smrg	info->MoveCursor(pDev, pScreen, x, y);
258024b90cf4Smrg}
258124b90cf4Smrg
2582d6c0b56eSmrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id,
2583d6c0b56eSmrg			struct amdgpu_buffer *bo)
2584d6c0b56eSmrg{
2585d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2586d6c0b56eSmrg	xf86CrtcPtr crtc = xf86_config->crtc[id];
2587d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2588d6c0b56eSmrg
2589d6c0b56eSmrg	drmmode_crtc->cursor_buffer = bo;
2590d6c0b56eSmrg}
2591d6c0b56eSmrg
2592d6c0b56eSmrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
2593d6c0b56eSmrg{
2594d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2595d6c0b56eSmrg	xf86OutputPtr output = config->output[config->compat_output];
2596d6c0b56eSmrg	xf86CrtcPtr crtc = output->crtc;
2597d6c0b56eSmrg
2598d6c0b56eSmrg	if (crtc && crtc->enabled) {
2599d6c0b56eSmrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
2600d6c0b56eSmrg	}
2601d6c0b56eSmrg}
2602d6c0b56eSmrg
2603d6c0b56eSmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
2604d6c0b56eSmrg			       Bool set_hw)
2605d6c0b56eSmrg{
2606d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2607d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
260824b90cf4Smrg	unsigned num_desired = 0, num_on = 0;
2609d6c0b56eSmrg	int c;
2610d6c0b56eSmrg
261124b90cf4Smrg	/* First, disable all unused CRTCs */
261224b90cf4Smrg	if (set_hw) {
261324b90cf4Smrg		for (c = 0; c < config->num_crtc; c++) {
261424b90cf4Smrg			xf86CrtcPtr crtc = config->crtc[c];
261524b90cf4Smrg			drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
261624b90cf4Smrg
261724b90cf4Smrg			/* Skip disabled CRTCs */
261824b90cf4Smrg			if (crtc->enabled)
261924b90cf4Smrg				continue;
262024b90cf4Smrg
262124b90cf4Smrg			drmmode_do_crtc_dpms(crtc, DPMSModeOff);
262224b90cf4Smrg			drmModeSetCrtc(pAMDGPUEnt->fd,
262324b90cf4Smrg				       drmmode_crtc->mode_crtc->crtc_id,
262424b90cf4Smrg				       0, 0, 0, NULL, 0, NULL);
262524b90cf4Smrg			drmmode_fb_reference(pAMDGPUEnt->fd,
262624b90cf4Smrg					     &drmmode_crtc->fb, NULL);
262724b90cf4Smrg		}
262824b90cf4Smrg	}
262924b90cf4Smrg
263024b90cf4Smrg	/* Then, try setting the chosen mode on each CRTC */
2631d6c0b56eSmrg	for (c = 0; c < config->num_crtc; c++) {
2632d6c0b56eSmrg		xf86CrtcPtr crtc = config->crtc[c];
2633d6c0b56eSmrg		xf86OutputPtr output = NULL;
2634d6c0b56eSmrg		int o;
2635d6c0b56eSmrg
263624b90cf4Smrg		if (!crtc->enabled)
2637d6c0b56eSmrg			continue;
2638d6c0b56eSmrg
2639d6c0b56eSmrg		if (config->output[config->compat_output]->crtc == crtc)
2640d6c0b56eSmrg			output = config->output[config->compat_output];
2641d6c0b56eSmrg		else {
2642d6c0b56eSmrg			for (o = 0; o < config->num_output; o++)
2643d6c0b56eSmrg				if (config->output[o]->crtc == crtc) {
2644d6c0b56eSmrg					output = config->output[o];
2645d6c0b56eSmrg					break;
2646d6c0b56eSmrg				}
2647d6c0b56eSmrg		}
2648d6c0b56eSmrg		/* paranoia */
2649d6c0b56eSmrg		if (!output)
2650d6c0b56eSmrg			continue;
2651d6c0b56eSmrg
265224b90cf4Smrg		num_desired++;
265324b90cf4Smrg
2654d6c0b56eSmrg		/* Mark that we'll need to re-set the mode for sure */
2655d6c0b56eSmrg		memset(&crtc->mode, 0, sizeof(crtc->mode));
2656d6c0b56eSmrg		if (!crtc->desiredMode.CrtcHDisplay) {
2657d6c0b56eSmrg			DisplayModePtr mode = xf86OutputFindClosestMode(output,
2658d6c0b56eSmrg									pScrn->
2659d6c0b56eSmrg									currentMode);
2660d6c0b56eSmrg
266124b90cf4Smrg			if (!mode) {
266224b90cf4Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
266324b90cf4Smrg					   "Failed to find mode for CRTC %d\n", c);
266424b90cf4Smrg				continue;
266524b90cf4Smrg			}
2666d6c0b56eSmrg			crtc->desiredMode = *mode;
2667d6c0b56eSmrg			crtc->desiredRotation = RR_Rotate_0;
2668d6c0b56eSmrg			crtc->desiredX = 0;
2669d6c0b56eSmrg			crtc->desiredY = 0;
2670d6c0b56eSmrg		}
2671d6c0b56eSmrg
2672d6c0b56eSmrg		if (set_hw) {
267324b90cf4Smrg			if (crtc->funcs->set_mode_major(crtc, &crtc->desiredMode,
267424b90cf4Smrg							crtc->desiredRotation,
267524b90cf4Smrg							crtc->desiredX,
267624b90cf4Smrg							crtc->desiredY)) {
267724b90cf4Smrg				num_on++;
267824b90cf4Smrg			} else {
267924b90cf4Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
268024b90cf4Smrg					   "Failed to set mode on CRTC %d\n", c);
268124b90cf4Smrg			}
2682d6c0b56eSmrg		} else {
2683d6c0b56eSmrg			crtc->mode = crtc->desiredMode;
2684d6c0b56eSmrg			crtc->rotation = crtc->desiredRotation;
2685d6c0b56eSmrg			crtc->x = crtc->desiredX;
2686d6c0b56eSmrg			crtc->y = crtc->desiredY;
268724b90cf4Smrg			if (drmmode_handle_transform(crtc))
268824b90cf4Smrg				num_on++;
2689d6c0b56eSmrg		}
2690d6c0b56eSmrg	}
269124b90cf4Smrg
269224b90cf4Smrg	if (num_on == 0 && num_desired > 0) {
269324b90cf4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Failed to enable any CRTC\n");
269424b90cf4Smrg		return FALSE;
269524b90cf4Smrg	}
269624b90cf4Smrg
2697d6c0b56eSmrg	return TRUE;
2698d6c0b56eSmrg}
2699d6c0b56eSmrg
2700d6c0b56eSmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
2701d6c0b56eSmrg{
2702d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2703d6c0b56eSmrg
2704d6c0b56eSmrg	if (xf86_config->num_crtc) {
2705d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2706d6c0b56eSmrg			       "Initializing kms color map\n");
2707d6c0b56eSmrg		if (!miCreateDefColormap(pScreen))
2708d6c0b56eSmrg			return FALSE;
270924b90cf4Smrg		/* All radeons support 10 bit CLUTs. They get bypassed at depth 30. */
271024b90cf4Smrg		if (pScrn->depth != 30 &&
271124b90cf4Smrg		    !xf86HandleColormaps(pScreen, 256, 10,
2712504d986fSmrg					 NULL, NULL,
2713d6c0b56eSmrg					 CMAP_PALETTED_TRUECOLOR
2714d6c0b56eSmrg#if 0				/* This option messes up text mode! (eich@suse.de) */
2715d6c0b56eSmrg					 | CMAP_LOAD_EVEN_IF_OFFSCREEN
2716d6c0b56eSmrg#endif
2717d6c0b56eSmrg					 | CMAP_RELOAD_ON_MODE_SWITCH))
2718d6c0b56eSmrg			return FALSE;
2719d6c0b56eSmrg	}
2720d6c0b56eSmrg	return TRUE;
2721d6c0b56eSmrg}
2722d6c0b56eSmrg
2723504d986fSmrgstatic Bool
2724504d986fSmrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi,
2725504d986fSmrg		    int *num_hdmi)
2726504d986fSmrg{
2727504d986fSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2728504d986fSmrg	int i;
2729504d986fSmrg
2730504d986fSmrg	for (i = 0; i < config->num_output; i++) {
2731504d986fSmrg		xf86OutputPtr output = config->output[i];
2732504d986fSmrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
2733504d986fSmrg
2734504d986fSmrg		if (drmmode_output->output_id == output_id) {
2735504d986fSmrg			switch(drmmode_output->mode_output->connector_type) {
2736504d986fSmrg			case DRM_MODE_CONNECTOR_DVII:
2737504d986fSmrg			case DRM_MODE_CONNECTOR_DVID:
2738504d986fSmrg			case DRM_MODE_CONNECTOR_DVIA:
2739504d986fSmrg				(*num_dvi)++;
2740504d986fSmrg				break;
2741504d986fSmrg			case DRM_MODE_CONNECTOR_HDMIA:
2742504d986fSmrg			case DRM_MODE_CONNECTOR_HDMIB:
2743504d986fSmrg				(*num_hdmi)++;
2744504d986fSmrg				break;
2745504d986fSmrg			}
2746504d986fSmrg
2747504d986fSmrg			return TRUE;
2748504d986fSmrg		}
2749504d986fSmrg	}
2750504d986fSmrg
2751504d986fSmrg	return FALSE;
2752504d986fSmrg}
2753d6c0b56eSmrg
2754d6c0b56eSmrgvoid
2755d6c0b56eSmrgamdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2756d6c0b56eSmrg{
2757d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2758d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
2759d6c0b56eSmrg	drmModeResPtr mode_res;
2760d6c0b56eSmrg	int i, j;
2761d6c0b56eSmrg	Bool found;
2762d6c0b56eSmrg	Bool changed = FALSE;
2763504d986fSmrg	int num_dvi = 0, num_hdmi = 0;
2764d6c0b56eSmrg
276524b90cf4Smrg	/* Try to re-set the mode on all the connectors with a BAD link-state:
276624b90cf4Smrg	 * This may happen if a link degrades and a new modeset is necessary, using
276724b90cf4Smrg	 * different link-training parameters. If the kernel found that the current
276824b90cf4Smrg	 * mode is not achievable anymore, it should have pruned the mode before
276924b90cf4Smrg	 * sending the hotplug event. Try to re-set the currently-set mode to keep
277024b90cf4Smrg	 * the display alive, this will fail if the mode has been pruned.
277124b90cf4Smrg	 * In any case, we will send randr events for the Desktop Environment to
277224b90cf4Smrg	 * deal with it, if it wants to.
277324b90cf4Smrg	 */
277424b90cf4Smrg	for (i = 0; i < config->num_output; i++) {
277524b90cf4Smrg		xf86OutputPtr output = config->output[i];
277624b90cf4Smrg		xf86CrtcPtr crtc = output->crtc;
277724b90cf4Smrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
277824b90cf4Smrg
277924b90cf4Smrg		drmmode_output_detect(output);
278024b90cf4Smrg
278124b90cf4Smrg		if (!crtc || !drmmode_output->mode_output)
278224b90cf4Smrg			continue;
278324b90cf4Smrg
278424b90cf4Smrg		/* Get an updated view of the properties for the current connector and
278524b90cf4Smrg		 * look for the link-status property
278624b90cf4Smrg		 */
278724b90cf4Smrg		for (j = 0; j < drmmode_output->num_props; j++) {
278824b90cf4Smrg			drmmode_prop_ptr p = &drmmode_output->props[j];
278924b90cf4Smrg
279024b90cf4Smrg			if (!strcmp(p->mode_prop->name, "link-status")) {
279124b90cf4Smrg				if (p->value != DRM_MODE_LINK_STATUS_BAD)
279224b90cf4Smrg					break;
279324b90cf4Smrg
279424b90cf4Smrg				/* the connector got a link failure, re-set the current mode */
279524b90cf4Smrg				drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
279624b90cf4Smrg						       crtc->x, crtc->y);
279724b90cf4Smrg
279824b90cf4Smrg				xf86DrvMsg(scrn->scrnIndex, X_WARNING,
279924b90cf4Smrg					   "hotplug event: connector %u's link-state is BAD, "
280024b90cf4Smrg					   "tried resetting the current mode. You may be left"
280124b90cf4Smrg					   "with a black screen if this fails...\n",
280224b90cf4Smrg					   drmmode_output->mode_output->connector_id);
280324b90cf4Smrg
280424b90cf4Smrg				break;
280524b90cf4Smrg			}
280624b90cf4Smrg		}
280724b90cf4Smrg	}
280824b90cf4Smrg
2809d6c0b56eSmrg	mode_res = drmModeGetResources(pAMDGPUEnt->fd);
2810d6c0b56eSmrg	if (!mode_res)
2811d6c0b56eSmrg		goto out;
2812d6c0b56eSmrg
2813d6c0b56eSmrgrestart_destroy:
2814d6c0b56eSmrg	for (i = 0; i < config->num_output; i++) {
2815d6c0b56eSmrg		xf86OutputPtr output = config->output[i];
2816d6c0b56eSmrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
2817d6c0b56eSmrg		found = FALSE;
2818d6c0b56eSmrg		for (j = 0; j < mode_res->count_connectors; j++) {
2819d6c0b56eSmrg			if (mode_res->connectors[j] == drmmode_output->output_id) {
2820d6c0b56eSmrg				found = TRUE;
2821d6c0b56eSmrg				break;
2822d6c0b56eSmrg			}
2823d6c0b56eSmrg		}
2824d6c0b56eSmrg		if (found)
2825d6c0b56eSmrg			continue;
2826d6c0b56eSmrg
2827d6c0b56eSmrg		drmModeFreeConnector(drmmode_output->mode_output);
2828d6c0b56eSmrg		drmmode_output->mode_output = NULL;
2829d6c0b56eSmrg		drmmode_output->output_id = -1;
2830d6c0b56eSmrg
2831d6c0b56eSmrg		changed = TRUE;
2832d6c0b56eSmrg		if (drmmode->delete_dp_12_displays) {
2833d6c0b56eSmrg			RROutputDestroy(output->randr_output);
2834d6c0b56eSmrg			xf86OutputDestroy(output);
2835d6c0b56eSmrg			goto restart_destroy;
2836d6c0b56eSmrg		}
2837d6c0b56eSmrg	}
2838d6c0b56eSmrg
2839d6c0b56eSmrg	/* find new output ids we don't have outputs for */
2840d6c0b56eSmrg	for (i = 0; i < mode_res->count_connectors; i++) {
2841504d986fSmrg		if (drmmode_find_output(pAMDGPUEnt->primary_scrn,
2842504d986fSmrg					mode_res->connectors[i],
2843504d986fSmrg					&num_dvi, &num_hdmi) ||
2844504d986fSmrg		    (pAMDGPUEnt->secondary_scrn &&
2845504d986fSmrg		     drmmode_find_output(pAMDGPUEnt->secondary_scrn,
2846504d986fSmrg					 mode_res->connectors[i],
2847504d986fSmrg					 &num_dvi, &num_hdmi)))
2848d6c0b56eSmrg			continue;
2849d6c0b56eSmrg
2850504d986fSmrg		if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi,
2851504d986fSmrg					&num_hdmi, 1) != 0)
2852504d986fSmrg			changed = TRUE;
2853d6c0b56eSmrg	}
2854d6c0b56eSmrg
2855504d986fSmrg	if (changed && dixPrivateKeyRegistered(rrPrivKey)) {
2856d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0)
2857d6c0b56eSmrg		RRSetChanged(xf86ScrnToScreen(scrn));
2858d6c0b56eSmrg#else
2859d6c0b56eSmrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen);
2860d6c0b56eSmrg		rrScrPriv->changed = TRUE;
2861d6c0b56eSmrg#endif
2862d6c0b56eSmrg		RRTellChanged(xf86ScrnToScreen(scrn));
2863d6c0b56eSmrg	}
2864d6c0b56eSmrg
2865d6c0b56eSmrg	drmModeFreeResources(mode_res);
2866d6c0b56eSmrgout:
2867d6c0b56eSmrg	RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
2868d6c0b56eSmrg}
2869d6c0b56eSmrg
2870d6c0b56eSmrg#ifdef HAVE_LIBUDEV
2871d6c0b56eSmrgstatic void drmmode_handle_uevents(int fd, void *closure)
2872d6c0b56eSmrg{
2873d6c0b56eSmrg	drmmode_ptr drmmode = closure;
2874d6c0b56eSmrg	ScrnInfoPtr scrn = drmmode->scrn;
2875d6c0b56eSmrg	struct udev_device *dev;
2876504d986fSmrg	Bool received = FALSE;
287711bf0794Smrg	struct timeval tv = { 0, 0 };
287811bf0794Smrg	fd_set readfd;
287911bf0794Smrg
288011bf0794Smrg	FD_ZERO(&readfd);
288111bf0794Smrg	FD_SET(fd, &readfd);
288211bf0794Smrg
288311bf0794Smrg	while (select(fd + 1, &readfd, NULL, NULL, &tv) > 0 &&
288411bf0794Smrg	       FD_ISSET(fd, &readfd)) {
288511bf0794Smrg		/* select() ensured that this will not block */
288611bf0794Smrg		dev = udev_monitor_receive_device(drmmode->uevent_monitor);
288711bf0794Smrg		if (dev) {
288811bf0794Smrg			udev_device_unref(dev);
288911bf0794Smrg			received = TRUE;
289011bf0794Smrg		}
2891504d986fSmrg	}
2892504d986fSmrg
2893504d986fSmrg	if (received)
2894504d986fSmrg		amdgpu_mode_hotplug(scrn, drmmode);
2895d6c0b56eSmrg}
2896d6c0b56eSmrg#endif
2897d6c0b56eSmrg
2898d6c0b56eSmrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2899d6c0b56eSmrg{
2900d6c0b56eSmrg#ifdef HAVE_LIBUDEV
2901d6c0b56eSmrg	struct udev *u;
2902d6c0b56eSmrg	struct udev_monitor *mon;
2903d6c0b56eSmrg
2904d6c0b56eSmrg	u = udev_new();
2905d6c0b56eSmrg	if (!u)
2906d6c0b56eSmrg		return;
2907d6c0b56eSmrg	mon = udev_monitor_new_from_netlink(u, "udev");
2908d6c0b56eSmrg	if (!mon) {
2909d6c0b56eSmrg		udev_unref(u);
2910d6c0b56eSmrg		return;
2911d6c0b56eSmrg	}
2912d6c0b56eSmrg
2913d6c0b56eSmrg	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
2914d6c0b56eSmrg							    "drm",
2915d6c0b56eSmrg							    "drm_minor") < 0 ||
2916d6c0b56eSmrg	    udev_monitor_enable_receiving(mon) < 0) {
2917d6c0b56eSmrg		udev_monitor_unref(mon);
2918d6c0b56eSmrg		udev_unref(u);
2919d6c0b56eSmrg		return;
2920d6c0b56eSmrg	}
2921d6c0b56eSmrg
2922d6c0b56eSmrg	drmmode->uevent_handler =
2923d6c0b56eSmrg	    xf86AddGeneralHandler(udev_monitor_get_fd(mon),
2924d6c0b56eSmrg				  drmmode_handle_uevents, drmmode);
2925d6c0b56eSmrg
2926d6c0b56eSmrg	drmmode->uevent_monitor = mon;
2927d6c0b56eSmrg#endif
2928d6c0b56eSmrg}
2929d6c0b56eSmrg
2930d6c0b56eSmrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2931d6c0b56eSmrg{
2932d6c0b56eSmrg#ifdef HAVE_LIBUDEV
2933d6c0b56eSmrg	if (drmmode->uevent_handler) {
2934d6c0b56eSmrg		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
2935d6c0b56eSmrg		xf86RemoveGeneralHandler(drmmode->uevent_handler);
2936d6c0b56eSmrg
2937d6c0b56eSmrg		udev_monitor_unref(drmmode->uevent_monitor);
2938d6c0b56eSmrg		udev_unref(u);
2939d6c0b56eSmrg	}
2940d6c0b56eSmrg#endif
2941d6c0b56eSmrg}
2942d6c0b56eSmrg
2943d6c0b56eSmrgBool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
2944d6c0b56eSmrg			PixmapPtr new_front, uint64_t id, void *data,
294524b90cf4Smrg			xf86CrtcPtr ref_crtc, amdgpu_drm_handler_proc handler,
2946504d986fSmrg			amdgpu_drm_abort_proc abort,
294711bf0794Smrg			enum drmmode_flip_sync flip_sync,
294811bf0794Smrg			uint32_t target_msc)
2949d6c0b56eSmrg{
2950d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
2951d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2952d6c0b56eSmrg	xf86CrtcPtr crtc = NULL;
2953d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
2954d6c0b56eSmrg	int i;
295511bf0794Smrg	uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0;
2956d6c0b56eSmrg	drmmode_flipdata_ptr flipdata;
2957d6c0b56eSmrg	uintptr_t drm_queue_seq = 0;
2958d6c0b56eSmrg
2959d6c0b56eSmrg	flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
2960d6c0b56eSmrg	if (!flipdata) {
2961d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2962d6c0b56eSmrg			   "flip queue: data alloc failed.\n");
2963d6c0b56eSmrg		goto error;
2964d6c0b56eSmrg	}
2965d6c0b56eSmrg
296624b90cf4Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb,
296724b90cf4Smrg			     amdgpu_pixmap_get_fb(new_front));
296824b90cf4Smrg	if (!flipdata->fb) {
296924b90cf4Smrg		ErrorF("Failed to get FB for flip\n");
2970d6c0b56eSmrg		goto error;
297124b90cf4Smrg	}
2972d6c0b56eSmrg
2973d6c0b56eSmrg	/*
2974d6c0b56eSmrg	 * Queue flips on all enabled CRTCs
2975d6c0b56eSmrg	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
2976d6c0b56eSmrg	 * Right now it assumes a single shared fb across all CRTCs, with the
2977d6c0b56eSmrg	 * kernel fixing up the offset of each CRTC as necessary.
2978d6c0b56eSmrg	 *
2979d6c0b56eSmrg	 * Also, flips queued on disabled or incorrectly configured displays
2980d6c0b56eSmrg	 * may never complete; this is a configuration error.
2981d6c0b56eSmrg	 */
2982d6c0b56eSmrg
2983d6c0b56eSmrg	flipdata->event_data = data;
2984d6c0b56eSmrg	flipdata->handler = handler;
2985d6c0b56eSmrg	flipdata->abort = abort;
298624b90cf4Smrg	flipdata->fe_crtc = ref_crtc;
2987d6c0b56eSmrg
2988d6c0b56eSmrg	for (i = 0; i < config->num_crtc; i++) {
298924b90cf4Smrg		struct drmmode_fb *fb = flipdata->fb;
299024b90cf4Smrg
2991d6c0b56eSmrg		crtc = config->crtc[i];
299224b90cf4Smrg		drmmode_crtc = crtc->driver_private;
2993d6c0b56eSmrg
299424b90cf4Smrg		if (!drmmode_crtc_can_flip(crtc) ||
299524b90cf4Smrg		    (drmmode_crtc->tear_free && crtc != ref_crtc))
2996d6c0b56eSmrg			continue;
2997d6c0b56eSmrg
2998d6c0b56eSmrg		flipdata->flip_count++;
2999d6c0b56eSmrg
3000d6c0b56eSmrg		drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id,
3001d6c0b56eSmrg						       flipdata,
3002d6c0b56eSmrg						       drmmode_flip_handler,
3003d6c0b56eSmrg						       drmmode_flip_abort);
3004504d986fSmrg		if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
3005d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
3006d6c0b56eSmrg				   "Allocating DRM queue event entry failed.\n");
3007d6c0b56eSmrg			goto error;
3008d6c0b56eSmrg		}
3009d6c0b56eSmrg
301024b90cf4Smrg		if (drmmode_crtc->tear_free) {
301124b90cf4Smrg			BoxRec extents = { .x1 = 0, .y1 = 0,
301224b90cf4Smrg					   .x2 = new_front->drawable.width,
301324b90cf4Smrg					   .y2 = new_front->drawable.height };
301424b90cf4Smrg			int scanout_id = drmmode_crtc->scanout_id ^ 1;
301524b90cf4Smrg
301624b90cf4Smrg			if (flip_sync == FLIP_ASYNC) {
301724b90cf4Smrg				if (!drmmode_wait_vblank(crtc,
301824b90cf4Smrg							 DRM_VBLANK_RELATIVE |
301924b90cf4Smrg							 DRM_VBLANK_EVENT,
302024b90cf4Smrg							 0, drm_queue_seq,
302124b90cf4Smrg							 NULL, NULL))
302224b90cf4Smrg					goto flip_error;
302324b90cf4Smrg				goto next;
302424b90cf4Smrg			}
302524b90cf4Smrg
302624b90cf4Smrg			fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
302724b90cf4Smrg			if (!fb) {
302824b90cf4Smrg				ErrorF("Failed to get FB for TearFree flip\n");
302924b90cf4Smrg				goto error;
303024b90cf4Smrg			}
303124b90cf4Smrg
303224b90cf4Smrg			amdgpu_scanout_do_update(crtc, scanout_id, new_front,
303324b90cf4Smrg						 &extents);
303424b90cf4Smrg
303524b90cf4Smrg			drmmode_crtc_wait_pending_event(drmmode_crtc, pAMDGPUEnt->fd,
303624b90cf4Smrg							drmmode_crtc->scanout_update_pending);
303724b90cf4Smrg		}
303824b90cf4Smrg
303924b90cf4Smrg		if (crtc == ref_crtc) {
304011bf0794Smrg			if (drmmode_page_flip_target_absolute(pAMDGPUEnt,
304111bf0794Smrg							      drmmode_crtc,
304224b90cf4Smrg							      fb->handle,
304311bf0794Smrg							      flip_flags,
304411bf0794Smrg							      drm_queue_seq,
304511bf0794Smrg							      target_msc) != 0)
304611bf0794Smrg				goto flip_error;
304711bf0794Smrg		} else {
304811bf0794Smrg			if (drmmode_page_flip_target_relative(pAMDGPUEnt,
304911bf0794Smrg							      drmmode_crtc,
305024b90cf4Smrg							      fb->handle,
305111bf0794Smrg							      flip_flags,
305211bf0794Smrg							      drm_queue_seq, 0) != 0)
305311bf0794Smrg				goto flip_error;
3054d6c0b56eSmrg		}
305511bf0794Smrg
305624b90cf4Smrg		if (drmmode_crtc->tear_free) {
305724b90cf4Smrg			drmmode_crtc->scanout_id ^= 1;
305824b90cf4Smrg			drmmode_crtc->ignore_damage = TRUE;
305924b90cf4Smrg		}
306024b90cf4Smrg
306124b90cf4Smrg	next:
306224b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd,
306324b90cf4Smrg				     &drmmode_crtc->flip_pending, fb);
3064d6c0b56eSmrg		drm_queue_seq = 0;
3065d6c0b56eSmrg	}
3066d6c0b56eSmrg
3067d6c0b56eSmrg	if (flipdata->flip_count > 0)
3068d6c0b56eSmrg		return TRUE;
3069d6c0b56eSmrg
307011bf0794Smrgflip_error:
307111bf0794Smrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n",
307211bf0794Smrg		   strerror(errno));
307311bf0794Smrg
3074d6c0b56eSmrgerror:
3075d6c0b56eSmrg	if (drm_queue_seq)
3076d6c0b56eSmrg		amdgpu_drm_abort_entry(drm_queue_seq);
3077d6c0b56eSmrg	else if (crtc)
3078d6c0b56eSmrg		drmmode_flip_abort(crtc, flipdata);
307911bf0794Smrg	else {
308011bf0794Smrg		abort(NULL, data);
308124b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &flipdata->fb, NULL);
3082d6c0b56eSmrg		free(flipdata);
308311bf0794Smrg	}
3084d6c0b56eSmrg
3085d6c0b56eSmrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
3086d6c0b56eSmrg		   strerror(errno));
3087d6c0b56eSmrg	return FALSE;
3088d6c0b56eSmrg}
3089