drmmode_display.c revision 504d986f
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"
37d6c0b56eSmrg#include "micmap.h"
38d6c0b56eSmrg#include "xf86cmap.h"
39504d986fSmrg#include "xf86Priv.h"
40d6c0b56eSmrg#include "sarea.h"
41d6c0b56eSmrg
42d6c0b56eSmrg#include "drmmode_display.h"
43d6c0b56eSmrg#include "amdgpu_bo_helper.h"
44d6c0b56eSmrg#include "amdgpu_glamor.h"
45d6c0b56eSmrg#include "amdgpu_list.h"
46d6c0b56eSmrg#include "amdgpu_pixmap.h"
47d6c0b56eSmrg
48d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
49d6c0b56eSmrg#include <dri.h>
50d6c0b56eSmrg#endif
51d6c0b56eSmrg
52d6c0b56eSmrg/* DPMS */
53d6c0b56eSmrg#ifdef HAVE_XEXTPROTO_71
54d6c0b56eSmrg#include <X11/extensions/dpmsconst.h>
55d6c0b56eSmrg#else
56d6c0b56eSmrg#define DPMS_SERVER
57d6c0b56eSmrg#include <X11/extensions/dpms.h>
58d6c0b56eSmrg#endif
59d6c0b56eSmrg
60d6c0b56eSmrg#include <gbm.h>
61d6c0b56eSmrg
62d6c0b56eSmrg#define DEFAULT_NOMINAL_FRAME_RATE 60
63d6c0b56eSmrg
64d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
65d6c0b56eSmrg
66d6c0b56eSmrgstatic Bool
67d6c0b56eSmrgAMDGPUZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name)
68d6c0b56eSmrg{
69d6c0b56eSmrg	int i = 0;
70d6c0b56eSmrg	char s1[20];
71d6c0b56eSmrg
72d6c0b56eSmrg	do {
73d6c0b56eSmrg		switch (*s) {
74d6c0b56eSmrg		case ',':
75d6c0b56eSmrg			s1[i] = '\0';
76d6c0b56eSmrg			i = 0;
77d6c0b56eSmrg			if (strcmp(s1, output_name) == 0)
78d6c0b56eSmrg				return TRUE;
79d6c0b56eSmrg			break;
80d6c0b56eSmrg		case ' ':
81d6c0b56eSmrg		case '\t':
82d6c0b56eSmrg		case '\n':
83d6c0b56eSmrg		case '\r':
84d6c0b56eSmrg			break;
85d6c0b56eSmrg		default:
86d6c0b56eSmrg			s1[i] = *s;
87d6c0b56eSmrg			i++;
88d6c0b56eSmrg			break;
89d6c0b56eSmrg		}
90d6c0b56eSmrg	} while (*s++);
91d6c0b56eSmrg
92d6c0b56eSmrg	s1[i] = '\0';
93d6c0b56eSmrg	if (strcmp(s1, output_name) == 0)
94d6c0b56eSmrg		return TRUE;
95d6c0b56eSmrg
96d6c0b56eSmrg	return FALSE;
97d6c0b56eSmrg}
98d6c0b56eSmrg
99d6c0b56eSmrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
100d6c0b56eSmrg					  int width, int height,
101d6c0b56eSmrg					  int depth, int bpp,
102d6c0b56eSmrg					  int pitch,
103d6c0b56eSmrg					  struct amdgpu_buffer *bo)
104d6c0b56eSmrg{
105d6c0b56eSmrg	ScreenPtr pScreen = pScrn->pScreen;
106d6c0b56eSmrg	PixmapPtr pixmap;
107d6c0b56eSmrg
108d6c0b56eSmrg	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth,
109d6c0b56eSmrg					  AMDGPU_CREATE_PIXMAP_SCANOUT);
110d6c0b56eSmrg	if (!pixmap)
111d6c0b56eSmrg		return NULL;
112d6c0b56eSmrg
113d6c0b56eSmrg	if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height,
114504d986fSmrg					     depth, bpp, pitch, NULL))
115504d986fSmrg		goto fail;
116d6c0b56eSmrg
117504d986fSmrg	if (!amdgpu_glamor_create_textured_pixmap(pixmap, bo))
118504d986fSmrg		goto fail;
119d6c0b56eSmrg
120504d986fSmrg	if (amdgpu_set_pixmap_bo(pixmap, bo))
121504d986fSmrg		return pixmap;
122d6c0b56eSmrg
123504d986fSmrgfail:
124504d986fSmrg	pScreen->DestroyPixmap(pixmap);
125504d986fSmrg	return NULL;
126d6c0b56eSmrg}
127d6c0b56eSmrg
128d6c0b56eSmrgstatic void drmmode_destroy_bo_pixmap(PixmapPtr pixmap)
129d6c0b56eSmrg{
130d6c0b56eSmrg	ScreenPtr pScreen = pixmap->drawable.pScreen;
131d6c0b56eSmrg
132d6c0b56eSmrg	(*pScreen->DestroyPixmap) (pixmap);
133d6c0b56eSmrg}
134d6c0b56eSmrg
135d6c0b56eSmrgstatic void
136d6c0b56eSmrgdrmmode_ConvertFromKMode(ScrnInfoPtr scrn,
137d6c0b56eSmrg			 drmModeModeInfo * kmode, DisplayModePtr mode)
138d6c0b56eSmrg{
139d6c0b56eSmrg	memset(mode, 0, sizeof(DisplayModeRec));
140d6c0b56eSmrg	mode->status = MODE_OK;
141d6c0b56eSmrg
142d6c0b56eSmrg	mode->Clock = kmode->clock;
143d6c0b56eSmrg
144d6c0b56eSmrg	mode->HDisplay = kmode->hdisplay;
145d6c0b56eSmrg	mode->HSyncStart = kmode->hsync_start;
146d6c0b56eSmrg	mode->HSyncEnd = kmode->hsync_end;
147d6c0b56eSmrg	mode->HTotal = kmode->htotal;
148d6c0b56eSmrg	mode->HSkew = kmode->hskew;
149d6c0b56eSmrg
150d6c0b56eSmrg	mode->VDisplay = kmode->vdisplay;
151d6c0b56eSmrg	mode->VSyncStart = kmode->vsync_start;
152d6c0b56eSmrg	mode->VSyncEnd = kmode->vsync_end;
153d6c0b56eSmrg	mode->VTotal = kmode->vtotal;
154d6c0b56eSmrg	mode->VScan = kmode->vscan;
155d6c0b56eSmrg
156d6c0b56eSmrg	mode->Flags = kmode->flags;	//& FLAG_BITS;
157d6c0b56eSmrg	mode->name = strdup(kmode->name);
158d6c0b56eSmrg
159d6c0b56eSmrg	if (kmode->type & DRM_MODE_TYPE_DRIVER)
160d6c0b56eSmrg		mode->type = M_T_DRIVER;
161d6c0b56eSmrg	if (kmode->type & DRM_MODE_TYPE_PREFERRED)
162d6c0b56eSmrg		mode->type |= M_T_PREFERRED;
163d6c0b56eSmrg	xf86SetModeCrtc(mode, scrn->adjustFlags);
164d6c0b56eSmrg}
165d6c0b56eSmrg
166d6c0b56eSmrgstatic void
167d6c0b56eSmrgdrmmode_ConvertToKMode(ScrnInfoPtr scrn,
168d6c0b56eSmrg		       drmModeModeInfo * kmode, DisplayModePtr mode)
169d6c0b56eSmrg{
170d6c0b56eSmrg	memset(kmode, 0, sizeof(*kmode));
171d6c0b56eSmrg
172d6c0b56eSmrg	kmode->clock = mode->Clock;
173d6c0b56eSmrg	kmode->hdisplay = mode->HDisplay;
174d6c0b56eSmrg	kmode->hsync_start = mode->HSyncStart;
175d6c0b56eSmrg	kmode->hsync_end = mode->HSyncEnd;
176d6c0b56eSmrg	kmode->htotal = mode->HTotal;
177d6c0b56eSmrg	kmode->hskew = mode->HSkew;
178d6c0b56eSmrg
179d6c0b56eSmrg	kmode->vdisplay = mode->VDisplay;
180d6c0b56eSmrg	kmode->vsync_start = mode->VSyncStart;
181d6c0b56eSmrg	kmode->vsync_end = mode->VSyncEnd;
182d6c0b56eSmrg	kmode->vtotal = mode->VTotal;
183d6c0b56eSmrg	kmode->vscan = mode->VScan;
184d6c0b56eSmrg
185d6c0b56eSmrg	kmode->flags = mode->Flags;	//& FLAG_BITS;
186d6c0b56eSmrg	if (mode->name)
187d6c0b56eSmrg		strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
188d6c0b56eSmrg	kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0;
189d6c0b56eSmrg
190d6c0b56eSmrg}
191d6c0b56eSmrg
192d6c0b56eSmrg/*
193d6c0b56eSmrg * Retrieves present time in microseconds that is compatible
194d6c0b56eSmrg * with units used by vblank timestamps. Depending on the kernel
195d6c0b56eSmrg * version and DRM kernel module configuration, the vblank
196d6c0b56eSmrg * timestamp can either be in real time or monotonic time
197d6c0b56eSmrg */
198d6c0b56eSmrgint drmmode_get_current_ust(int drm_fd, CARD64 * ust)
199d6c0b56eSmrg{
200d6c0b56eSmrg	uint64_t cap_value;
201d6c0b56eSmrg	int ret;
202d6c0b56eSmrg	struct timespec now;
203d6c0b56eSmrg
204d6c0b56eSmrg	ret = drmGetCap(drm_fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap_value);
205d6c0b56eSmrg	if (ret || !cap_value)
206d6c0b56eSmrg		/* old kernel or drm_timestamp_monotonic turned off */
207d6c0b56eSmrg		ret = clock_gettime(CLOCK_REALTIME, &now);
208d6c0b56eSmrg	else
209d6c0b56eSmrg		ret = clock_gettime(CLOCK_MONOTONIC, &now);
210d6c0b56eSmrg	if (ret)
211d6c0b56eSmrg		return ret;
212d6c0b56eSmrg	*ust = ((CARD64) now.tv_sec * 1000000) + ((CARD64) now.tv_nsec / 1000);
213d6c0b56eSmrg	return 0;
214d6c0b56eSmrg}
215d6c0b56eSmrg
216d6c0b56eSmrg/*
217d6c0b56eSmrg * Get current frame count and frame count timestamp of the crtc.
218d6c0b56eSmrg */
219d6c0b56eSmrgint drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc)
220d6c0b56eSmrg{
221d6c0b56eSmrg	ScrnInfoPtr scrn = crtc->scrn;
222d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
223d6c0b56eSmrg	drmVBlank vbl;
224d6c0b56eSmrg	int ret;
225d6c0b56eSmrg
226d6c0b56eSmrg	vbl.request.type = DRM_VBLANK_RELATIVE;
227d6c0b56eSmrg	vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
228d6c0b56eSmrg	vbl.request.sequence = 0;
229d6c0b56eSmrg
230d6c0b56eSmrg	ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
231d6c0b56eSmrg	if (ret) {
232d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
233d6c0b56eSmrg			   "get vblank counter failed: %s\n", strerror(errno));
234d6c0b56eSmrg		return ret;
235d6c0b56eSmrg	}
236d6c0b56eSmrg
237d6c0b56eSmrg	*ust = ((CARD64)vbl.reply.tval_sec * 1000000) + vbl.reply.tval_usec;
238d6c0b56eSmrg	*msc = vbl.reply.sequence;
239d6c0b56eSmrg
240d6c0b56eSmrg	return Success;
241d6c0b56eSmrg}
242d6c0b56eSmrg
243d6c0b56eSmrgstatic void
244d6c0b56eSmrgdrmmode_do_crtc_dpms(xf86CrtcPtr crtc, int mode)
245d6c0b56eSmrg{
246d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
247d6c0b56eSmrg	ScrnInfoPtr scrn = crtc->scrn;
248d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
249d6c0b56eSmrg	CARD64 ust;
250d6c0b56eSmrg	int ret;
251d6c0b56eSmrg
252504d986fSmrg	drmmode_crtc->pending_dpms_mode = mode;
253504d986fSmrg
254d6c0b56eSmrg	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
255d6c0b56eSmrg		drmVBlank vbl;
256d6c0b56eSmrg
257504d986fSmrg		/* Wait for any pending flip to finish */
258504d986fSmrg		if (drmmode_crtc->flip_pending)
259504d986fSmrg			return;
260504d986fSmrg
261d6c0b56eSmrg		/*
262d6c0b56eSmrg		 * On->Off transition: record the last vblank time,
263d6c0b56eSmrg		 * sequence number and frame period.
264d6c0b56eSmrg		 */
265d6c0b56eSmrg		vbl.request.type = DRM_VBLANK_RELATIVE;
266d6c0b56eSmrg		vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
267d6c0b56eSmrg		vbl.request.sequence = 0;
268d6c0b56eSmrg		ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
269d6c0b56eSmrg		if (ret)
270d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
271d6c0b56eSmrg				   "%s cannot get last vblank counter\n",
272d6c0b56eSmrg				   __func__);
273d6c0b56eSmrg		else {
274d6c0b56eSmrg			CARD64 seq = (CARD64) vbl.reply.sequence;
275d6c0b56eSmrg			CARD64 nominal_frame_rate, pix_in_frame;
276d6c0b56eSmrg
277d6c0b56eSmrg			ust = ((CARD64) vbl.reply.tval_sec * 1000000) +
278d6c0b56eSmrg			    vbl.reply.tval_usec;
279d6c0b56eSmrg			drmmode_crtc->dpms_last_ust = ust;
280d6c0b56eSmrg			drmmode_crtc->dpms_last_seq = seq;
281d6c0b56eSmrg			nominal_frame_rate = crtc->mode.Clock;
282d6c0b56eSmrg			nominal_frame_rate *= 1000;
283d6c0b56eSmrg			pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal;
284d6c0b56eSmrg			if (nominal_frame_rate == 0 || pix_in_frame == 0)
285d6c0b56eSmrg				nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE;
286d6c0b56eSmrg			else
287d6c0b56eSmrg				nominal_frame_rate /= pix_in_frame;
288d6c0b56eSmrg			drmmode_crtc->dpms_last_fps = nominal_frame_rate;
289d6c0b56eSmrg		}
290d6c0b56eSmrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) {
291d6c0b56eSmrg		/*
292d6c0b56eSmrg		 * Off->On transition: calculate and accumulate the
293d6c0b56eSmrg		 * number of interpolated vblanks while we were in Off state
294d6c0b56eSmrg		 */
295d6c0b56eSmrg		ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust);
296d6c0b56eSmrg		if (ret)
297d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
298d6c0b56eSmrg				   "%s cannot get current time\n", __func__);
299d6c0b56eSmrg		else if (drmmode_crtc->dpms_last_ust) {
300d6c0b56eSmrg			CARD64 time_elapsed, delta_seq;
301d6c0b56eSmrg			time_elapsed = ust - drmmode_crtc->dpms_last_ust;
302d6c0b56eSmrg			delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps;
303d6c0b56eSmrg			delta_seq /= 1000000;
304d6c0b56eSmrg			drmmode_crtc->interpolated_vblanks += delta_seq;
305d6c0b56eSmrg
306d6c0b56eSmrg		}
307d6c0b56eSmrg	}
308d6c0b56eSmrg	drmmode_crtc->dpms_mode = mode;
309d6c0b56eSmrg}
310d6c0b56eSmrg
311d6c0b56eSmrgstatic void
312d6c0b56eSmrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
313d6c0b56eSmrg{
314d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
315d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
316d6c0b56eSmrg
317d6c0b56eSmrg	/* Disable unused CRTCs and enable/disable active CRTCs */
318504d986fSmrg	if (!crtc->enabled || mode != DPMSModeOn) {
319504d986fSmrg		/* Wait for any pending flip to finish */
320504d986fSmrg		if (drmmode_crtc->flip_pending)
321504d986fSmrg			return;
322504d986fSmrg
323d6c0b56eSmrg		drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
324d6c0b56eSmrg			       0, 0, 0, NULL, 0, NULL);
325504d986fSmrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn)
326d6c0b56eSmrg		crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
327d6c0b56eSmrg					    crtc->x, crtc->y);
328d6c0b56eSmrg}
329d6c0b56eSmrg
330d6c0b56eSmrgstatic PixmapPtr
331d6c0b56eSmrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode,
332d6c0b56eSmrg			ScrnInfoPtr pScrn, int fbcon_id)
333d6c0b56eSmrg{
334d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
335d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
336d6c0b56eSmrg	PixmapPtr pixmap = info->fbcon_pixmap;
337d6c0b56eSmrg	struct amdgpu_buffer *bo;
338d6c0b56eSmrg	drmModeFBPtr fbcon;
339d6c0b56eSmrg	struct drm_gem_flink flink;
340d6c0b56eSmrg	struct amdgpu_bo_import_result import = {0};
341d6c0b56eSmrg
342d6c0b56eSmrg	if (pixmap)
343d6c0b56eSmrg		return pixmap;
344d6c0b56eSmrg
345d6c0b56eSmrg	fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id);
346d6c0b56eSmrg	if (fbcon == NULL)
347d6c0b56eSmrg		return NULL;
348d6c0b56eSmrg
349d6c0b56eSmrg	if (fbcon->depth != pScrn->depth ||
350d6c0b56eSmrg	    fbcon->width != pScrn->virtualX ||
351d6c0b56eSmrg	    fbcon->height != pScrn->virtualY)
352d6c0b56eSmrg		goto out_free_fb;
353d6c0b56eSmrg
354d6c0b56eSmrg	flink.handle = fbcon->handle;
355d6c0b56eSmrg	if (ioctl(pAMDGPUEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
356d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
357d6c0b56eSmrg			   "Couldn't flink fbcon handle\n");
358d6c0b56eSmrg		goto out_free_fb;
359d6c0b56eSmrg	}
360d6c0b56eSmrg
361d6c0b56eSmrg	bo = calloc(1, sizeof(struct amdgpu_buffer));
362d6c0b56eSmrg	if (bo == NULL) {
363d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
364d6c0b56eSmrg			   "Couldn't allocate bo for fbcon handle\n");
365d6c0b56eSmrg		goto out_free_fb;
366d6c0b56eSmrg	}
367d6c0b56eSmrg	bo->ref_count = 1;
368d6c0b56eSmrg
369d6c0b56eSmrg	if (amdgpu_bo_import(pAMDGPUEnt->pDev,
370d6c0b56eSmrg			     amdgpu_bo_handle_type_gem_flink_name, flink.name,
371d6c0b56eSmrg			     &import) != 0) {
372d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
373d6c0b56eSmrg			   "Couldn't import BO for fbcon handle\n");
374d6c0b56eSmrg		goto out_free_bo;
375d6c0b56eSmrg	}
376d6c0b56eSmrg	bo->bo.amdgpu = import.buf_handle;
377d6c0b56eSmrg
378d6c0b56eSmrg	pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height,
379d6c0b56eSmrg					  fbcon->depth, fbcon->bpp,
380d6c0b56eSmrg					  fbcon->pitch, bo);
381d6c0b56eSmrg	info->fbcon_pixmap = pixmap;
382d6c0b56eSmrgout_free_bo:
383d6c0b56eSmrg	amdgpu_bo_unref(&bo);
384d6c0b56eSmrgout_free_fb:
385d6c0b56eSmrg	drmModeFreeFB(fbcon);
386d6c0b56eSmrg	return pixmap;
387d6c0b56eSmrg}
388d6c0b56eSmrg
389d6c0b56eSmrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
390d6c0b56eSmrg{
391d6c0b56eSmrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
392d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
393d6c0b56eSmrg	PixmapPtr src, dst;
394d6c0b56eSmrg	ScreenPtr pScreen = pScrn->pScreen;
395d6c0b56eSmrg	int fbcon_id = 0;
396d6c0b56eSmrg	GCPtr gc;
397d6c0b56eSmrg	int i;
398d6c0b56eSmrg
399d6c0b56eSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
400d6c0b56eSmrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
401d6c0b56eSmrg
402d6c0b56eSmrg		if (drmmode_crtc->mode_crtc->buffer_id)
403d6c0b56eSmrg			fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
404d6c0b56eSmrg	}
405d6c0b56eSmrg
406d6c0b56eSmrg	if (!fbcon_id)
407d6c0b56eSmrg		return;
408d6c0b56eSmrg
409d6c0b56eSmrg	if (fbcon_id == drmmode->fb_id) {
410d6c0b56eSmrg		/* in some rare case there might be no fbcon and we might already
411d6c0b56eSmrg		 * be the one with the current fb to avoid a false deadlck in
412d6c0b56eSmrg		 * kernel ttm code just do nothing as anyway there is nothing
413d6c0b56eSmrg		 * to do
414d6c0b56eSmrg		 */
415d6c0b56eSmrg		return;
416d6c0b56eSmrg	}
417d6c0b56eSmrg
418d6c0b56eSmrg	src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
419d6c0b56eSmrg	if (!src)
420d6c0b56eSmrg		return;
421d6c0b56eSmrg
422d6c0b56eSmrg	dst = pScreen->GetScreenPixmap(pScreen);
423d6c0b56eSmrg
424d6c0b56eSmrg	gc = GetScratchGC(pScrn->depth, pScreen);
425d6c0b56eSmrg	ValidateGC(&dst->drawable, gc);
426d6c0b56eSmrg
427d6c0b56eSmrg	(*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0,
428d6c0b56eSmrg			     pScrn->virtualX, pScrn->virtualY, 0, 0);
429d6c0b56eSmrg
430d6c0b56eSmrg	FreeScratchGC(gc);
431d6c0b56eSmrg
432d6c0b56eSmrg	amdgpu_glamor_finish(pScrn);
433d6c0b56eSmrg
434d6c0b56eSmrg	pScreen->canDoBGNoneRoot = TRUE;
435d6c0b56eSmrg
436d6c0b56eSmrg	if (info->fbcon_pixmap)
437d6c0b56eSmrg		pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap);
438d6c0b56eSmrg	info->fbcon_pixmap = NULL;
439d6c0b56eSmrg
440d6c0b56eSmrg	return;
441d6c0b56eSmrg}
442d6c0b56eSmrg
443d6c0b56eSmrgstatic void
444d6c0b56eSmrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
445d6c0b56eSmrg			     struct drmmode_scanout *scanout)
446d6c0b56eSmrg{
447d6c0b56eSmrg
448d6c0b56eSmrg	if (scanout->pixmap) {
449d6c0b56eSmrg		drmmode_destroy_bo_pixmap(scanout->pixmap);
450d6c0b56eSmrg		scanout->pixmap = NULL;
451d6c0b56eSmrg	}
452d6c0b56eSmrg
453d6c0b56eSmrg	if (scanout->bo) {
454d6c0b56eSmrg		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn);
455d6c0b56eSmrg
456d6c0b56eSmrg		drmModeRmFB(pAMDGPUEnt->fd, scanout->fb_id);
457d6c0b56eSmrg		scanout->fb_id = 0;
458d6c0b56eSmrg		amdgpu_bo_unref(&scanout->bo);
459d6c0b56eSmrg		scanout->bo = NULL;
460d6c0b56eSmrg	}
461504d986fSmrg}
462504d986fSmrg
463504d986fSmrgstatic void
464504d986fSmrgdrmmode_crtc_scanout_free(drmmode_crtc_private_ptr drmmode_crtc)
465504d986fSmrg{
466504d986fSmrg	if (drmmode_crtc->flip_pending) {
467504d986fSmrg		drmmode_crtc->scanout_destroy[0] = drmmode_crtc->scanout[0];
468504d986fSmrg		drmmode_crtc->scanout[0].pixmap = NULL;
469504d986fSmrg		drmmode_crtc->scanout[0].bo = NULL;
470504d986fSmrg		drmmode_crtc->scanout_destroy[1] = drmmode_crtc->scanout[1];
471504d986fSmrg		drmmode_crtc->scanout[1].pixmap = NULL;
472504d986fSmrg		drmmode_crtc->scanout[1].bo = NULL;
473504d986fSmrg	} else {
474504d986fSmrg		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
475504d986fSmrg					     &drmmode_crtc->scanout[0]);
476504d986fSmrg		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
477504d986fSmrg					     &drmmode_crtc->scanout[1]);
478504d986fSmrg	}
479d6c0b56eSmrg
480504d986fSmrg	if (drmmode_crtc->scanout_damage) {
481504d986fSmrg		DamageDestroy(drmmode_crtc->scanout_damage);
482504d986fSmrg		drmmode_crtc->scanout_damage = NULL;
483504d986fSmrg		RegionUninit(&drmmode_crtc->scanout_last_region);
484d6c0b56eSmrg	}
485d6c0b56eSmrg}
486d6c0b56eSmrg
487d6c0b56eSmrgvoid
488d6c0b56eSmrgdrmmode_scanout_free(ScrnInfoPtr scrn)
489d6c0b56eSmrg{
490d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
491d6c0b56eSmrg	int c;
492d6c0b56eSmrg
493504d986fSmrg	for (c = 0; c < xf86_config->num_crtc; c++)
494504d986fSmrg		drmmode_crtc_scanout_free(xf86_config->crtc[c]->driver_private);
495d6c0b56eSmrg}
496d6c0b56eSmrg
497d6c0b56eSmrgstatic void *
498d6c0b56eSmrgdrmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
499d6c0b56eSmrg			      struct drmmode_scanout *scanout,
500d6c0b56eSmrg			      int width, int height)
501d6c0b56eSmrg{
502d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
503d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
504d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
505d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
506d6c0b56eSmrg	int ret;
507d6c0b56eSmrg	int pitch;
508d6c0b56eSmrg	union gbm_bo_handle bo_handle;
509d6c0b56eSmrg
510d6c0b56eSmrg	if (scanout->bo) {
511d6c0b56eSmrg		if (scanout->width == width && scanout->height == height)
512d6c0b56eSmrg			return scanout->bo;
513d6c0b56eSmrg
514d6c0b56eSmrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
515d6c0b56eSmrg	}
516d6c0b56eSmrg
517d6c0b56eSmrg	scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height,
518d6c0b56eSmrg					       pScrn->depth, 0,
519d6c0b56eSmrg					       pScrn->bitsPerPixel, &pitch);
520d6c0b56eSmrg	if (!scanout->bo) {
521d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
522d6c0b56eSmrg			   "Failed to allocate rotation buffer memory\n");
523d6c0b56eSmrg		return NULL;
524d6c0b56eSmrg	}
525d6c0b56eSmrg
526d6c0b56eSmrg	bo_handle = gbm_bo_get_handle(scanout->bo->bo.gbm);
527d6c0b56eSmrg	ret = drmModeAddFB(pAMDGPUEnt->fd, width, height, pScrn->depth,
528d6c0b56eSmrg			   pScrn->bitsPerPixel, pitch,
529d6c0b56eSmrg			   bo_handle.u32, &scanout->fb_id);
530d6c0b56eSmrg	if (ret) {
531d6c0b56eSmrg		ErrorF("failed to add rotate fb\n");
532d6c0b56eSmrg		amdgpu_bo_unref(&scanout->bo);
533d6c0b56eSmrg		scanout->bo = NULL;
534d6c0b56eSmrg		return NULL;
535d6c0b56eSmrg	}
536d6c0b56eSmrg
537d6c0b56eSmrg	scanout->width = width;
538d6c0b56eSmrg	scanout->height = height;
539d6c0b56eSmrg	return scanout->bo;
540d6c0b56eSmrg}
541d6c0b56eSmrg
542d6c0b56eSmrgstatic PixmapPtr
543d6c0b56eSmrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc,
544d6c0b56eSmrg			    struct drmmode_scanout *scanout,
545d6c0b56eSmrg			    int width, int height)
546d6c0b56eSmrg{
547d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
548d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
549d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
550d6c0b56eSmrg	unsigned long rotate_pitch;
551d6c0b56eSmrg
552d6c0b56eSmrg	if (scanout->pixmap) {
553d6c0b56eSmrg		if (scanout->width == width && scanout->height == height)
554d6c0b56eSmrg			return scanout->pixmap;
555d6c0b56eSmrg
556d6c0b56eSmrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
557d6c0b56eSmrg	}
558d6c0b56eSmrg
559d6c0b56eSmrg	if (!scanout->bo) {
560d6c0b56eSmrg		if (!drmmode_crtc_scanout_allocate(crtc, scanout, width, height))
561d6c0b56eSmrg			return NULL;
562d6c0b56eSmrg	}
563d6c0b56eSmrg
564d6c0b56eSmrg	rotate_pitch = gbm_bo_get_stride(scanout->bo->bo.gbm);
565d6c0b56eSmrg
566d6c0b56eSmrg	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
567d6c0b56eSmrg						 width, height,
568d6c0b56eSmrg						 pScrn->depth,
569d6c0b56eSmrg						 pScrn->bitsPerPixel,
570d6c0b56eSmrg						 rotate_pitch,
571d6c0b56eSmrg						 scanout->bo);
572d6c0b56eSmrg	if (scanout->pixmap == NULL) {
573d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
574d6c0b56eSmrg			   "Couldn't allocate shadow pixmap for rotated CRTC\n");
575d6c0b56eSmrg	}
576d6c0b56eSmrg	return scanout->pixmap;
577d6c0b56eSmrg
578d6c0b56eSmrg}
579d6c0b56eSmrg
580d6c0b56eSmrgstatic void
581d6c0b56eSmrgamdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
582d6c0b56eSmrg{
583d6c0b56eSmrg	/* Only keep track of the extents */
584d6c0b56eSmrg	RegionUninit(&damage->damage);
585d6c0b56eSmrg	damage->damage.data = NULL;
586d6c0b56eSmrg}
587d6c0b56eSmrg
588d6c0b56eSmrgstatic Bool
589d6c0b56eSmrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc)
590d6c0b56eSmrg{
591d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
592d6c0b56eSmrg
593d6c0b56eSmrg	/* Check for Option "SWcursor" */
594d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
595d6c0b56eSmrg		return FALSE;
596d6c0b56eSmrg
597d6c0b56eSmrg	/* Fall back to SW cursor if the CRTC is transformed */
598d6c0b56eSmrg	if (crtc->transformPresent)
599d6c0b56eSmrg		return FALSE;
600d6c0b56eSmrg
601504d986fSmrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7
602d6c0b56eSmrg	/* Xorg doesn't correctly handle cursor position transform in the
603d6c0b56eSmrg	 * rotation case
604d6c0b56eSmrg	 */
605d6c0b56eSmrg	if (crtc->driverIsPerformingTransform &&
606d6c0b56eSmrg	    (crtc->rotation & 0xf) != RR_Rotate_0)
607d6c0b56eSmrg		return FALSE;
608d6c0b56eSmrg#endif
609d6c0b56eSmrg
610504d986fSmrg#if defined(AMDGPU_PIXMAP_SHARING)
611504d986fSmrg	/* HW cursor not supported with RandR 1.4 multihead up to 1.18.99.901 */
612504d986fSmrg	if (xorgGetVersion() <= XORG_VERSION_NUMERIC(1,18,99,901,0) &&
613504d986fSmrg	    !xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list))
614d6c0b56eSmrg		return FALSE;
615d6c0b56eSmrg#endif
616d6c0b56eSmrg
617d6c0b56eSmrg	return TRUE;
618d6c0b56eSmrg}
619d6c0b56eSmrg
620d6c0b56eSmrg#if XF86_CRTC_VERSION >= 4
621d6c0b56eSmrg
622d6c0b56eSmrgstatic Bool
623d6c0b56eSmrgdrmmode_handle_transform(xf86CrtcPtr crtc)
624d6c0b56eSmrg{
625d6c0b56eSmrg	Bool ret;
626d6c0b56eSmrg
627504d986fSmrg#if XF86_CRTC_VERSION >= 7
628504d986fSmrg	if (crtc->transformPresent || crtc->rotation != RR_Rotate_0)
629504d986fSmrg	    crtc->driverIsPerformingTransform = XF86DriverTransformOutput;
630504d986fSmrg	else
631504d986fSmrg	    crtc->driverIsPerformingTransform = XF86DriverTransformNone;
632504d986fSmrg#else
633504d986fSmrg	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
634504d986fSmrg
635504d986fSmrg	crtc->driverIsPerformingTransform = crtc->transformPresent ||
636504d986fSmrg		(info->tear_free && crtc->rotation != RR_Rotate_0);
637504d986fSmrg#endif
638d6c0b56eSmrg
639d6c0b56eSmrg	ret = xf86CrtcRotate(crtc);
640d6c0b56eSmrg
641d6c0b56eSmrg	crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use;
642d6c0b56eSmrg
643d6c0b56eSmrg	return ret;
644d6c0b56eSmrg}
645d6c0b56eSmrg
646d6c0b56eSmrg#else
647d6c0b56eSmrg
648d6c0b56eSmrgstatic Bool
649d6c0b56eSmrgdrmmode_handle_transform(xf86CrtcPtr crtc)
650d6c0b56eSmrg{
651d6c0b56eSmrg	return xf86CrtcRotate(crtc);
652d6c0b56eSmrg}
653d6c0b56eSmrg
654d6c0b56eSmrg#endif
655d6c0b56eSmrg
656d6c0b56eSmrgstatic Bool
657d6c0b56eSmrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
658d6c0b56eSmrg		       Rotation rotation, int x, int y)
659d6c0b56eSmrg{
660d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
661d6c0b56eSmrg	ScreenPtr pScreen = pScrn->pScreen;
662d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
663d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
664d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
665d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
666d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
667d6c0b56eSmrg	int saved_x, saved_y;
668d6c0b56eSmrg	Rotation saved_rotation;
669d6c0b56eSmrg	DisplayModeRec saved_mode;
670d6c0b56eSmrg	uint32_t *output_ids = NULL;
671d6c0b56eSmrg	int output_count = 0;
672504d986fSmrg	Bool ret = FALSE;
673d6c0b56eSmrg	int i;
674d6c0b56eSmrg	int fb_id;
675d6c0b56eSmrg	drmModeModeInfo kmode;
676d6c0b56eSmrg	uint32_t bo_handle;
677d6c0b56eSmrg
678d6c0b56eSmrg	saved_mode = crtc->mode;
679d6c0b56eSmrg	saved_x = crtc->x;
680d6c0b56eSmrg	saved_y = crtc->y;
681d6c0b56eSmrg	saved_rotation = crtc->rotation;
682d6c0b56eSmrg
683d6c0b56eSmrg	if (mode) {
684d6c0b56eSmrg		crtc->mode = *mode;
685d6c0b56eSmrg		crtc->x = x;
686d6c0b56eSmrg		crtc->y = y;
687d6c0b56eSmrg		crtc->rotation = rotation;
688d6c0b56eSmrg
689d6c0b56eSmrg		output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
690504d986fSmrg		if (!output_ids)
691d6c0b56eSmrg			goto done;
692d6c0b56eSmrg
693d6c0b56eSmrg		for (i = 0; i < xf86_config->num_output; i++) {
694d6c0b56eSmrg			xf86OutputPtr output = xf86_config->output[i];
695d6c0b56eSmrg			drmmode_output_private_ptr drmmode_output;
696d6c0b56eSmrg
697d6c0b56eSmrg			if (output->crtc != crtc)
698d6c0b56eSmrg				continue;
699d6c0b56eSmrg
700d6c0b56eSmrg			drmmode_output = output->driver_private;
701d6c0b56eSmrg			output_ids[output_count] =
702d6c0b56eSmrg			    drmmode_output->mode_output->connector_id;
703d6c0b56eSmrg			output_count++;
704d6c0b56eSmrg		}
705d6c0b56eSmrg
706d6c0b56eSmrg		if (!drmmode_handle_transform(crtc))
707d6c0b56eSmrg			goto done;
708d6c0b56eSmrg
709d6c0b56eSmrg		crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
710d6c0b56eSmrg				       crtc->gamma_blue, crtc->gamma_size);
711d6c0b56eSmrg
712d6c0b56eSmrg		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
713d6c0b56eSmrg
714d6c0b56eSmrg		fb_id = drmmode->fb_id;
715d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
716d6c0b56eSmrg		if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
717504d986fSmrg			fb_id = drmmode_crtc->scanout[0].fb_id;
718504d986fSmrg			x = y = 0;
719d6c0b56eSmrg		} else
720d6c0b56eSmrg#endif
721d6c0b56eSmrg		if (drmmode_crtc->rotate.fb_id) {
722d6c0b56eSmrg			fb_id = drmmode_crtc->rotate.fb_id;
723d6c0b56eSmrg			x = y = 0;
724504d986fSmrg		} else if (
725504d986fSmrg#ifdef AMDGPU_PIXMAP_SHARING
726504d986fSmrg			   !pScreen->isGPU &&
727504d986fSmrg#endif
728504d986fSmrg			   (info->tear_free ||
729d6c0b56eSmrg#if XF86_CRTC_VERSION >= 4
730504d986fSmrg			    crtc->driverIsPerformingTransform ||
731d6c0b56eSmrg#endif
732504d986fSmrg			    info->shadow_primary)) {
733d6c0b56eSmrg			for (i = 0; i < (info->tear_free ? 2 : 1); i++) {
734d6c0b56eSmrg				drmmode_crtc_scanout_create(crtc,
735d6c0b56eSmrg							    &drmmode_crtc->scanout[i],
736d6c0b56eSmrg							    mode->HDisplay,
737d6c0b56eSmrg							    mode->VDisplay);
738d6c0b56eSmrg			}
739d6c0b56eSmrg
740d6c0b56eSmrg			if (drmmode_crtc->scanout[0].pixmap &&
741d6c0b56eSmrg			    (!info->tear_free || drmmode_crtc->scanout[1].pixmap)) {
742504d986fSmrg				RegionPtr pRegion;
743504d986fSmrg				BoxPtr pBox;
744504d986fSmrg
745504d986fSmrg				if (!drmmode_crtc->scanout_damage) {
746504d986fSmrg					drmmode_crtc->scanout_damage =
747504d986fSmrg						DamageCreate(amdgpu_screen_damage_report,
748504d986fSmrg							     NULL, DamageReportRawRegion,
749504d986fSmrg							     TRUE, pScreen, NULL);
750504d986fSmrg					DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
751504d986fSmrg						       drmmode_crtc->scanout_damage);
752504d986fSmrg				}
753504d986fSmrg
754504d986fSmrg				pRegion = DamageRegion(drmmode_crtc->scanout_damage);
755504d986fSmrg				RegionUninit(pRegion);
756504d986fSmrg				pRegion->data = NULL;
757504d986fSmrg				pBox = RegionExtents(pRegion);
758504d986fSmrg				pBox->x1 = 0;
759504d986fSmrg				pBox->y1 = 0;
760504d986fSmrg				pBox->x2 = max(pBox->x2, pScrn->virtualX);
761504d986fSmrg				pBox->y2 = max(pBox->y2, pScrn->virtualY);
762504d986fSmrg
763d6c0b56eSmrg				drmmode_crtc->scanout_id = 0;
764d6c0b56eSmrg				fb_id = drmmode_crtc->scanout[0].fb_id;
765d6c0b56eSmrg				x = y = 0;
766d6c0b56eSmrg
767d6c0b56eSmrg				amdgpu_scanout_update_handler(crtc, 0, 0, drmmode_crtc);
768d6c0b56eSmrg				amdgpu_glamor_finish(pScrn);
769d6c0b56eSmrg			}
770d6c0b56eSmrg		}
771d6c0b56eSmrg
772504d986fSmrg		if (fb_id == 0) {
773504d986fSmrg			if (!amdgpu_bo_get_handle(info->front_buffer, &bo_handle)) {
774504d986fSmrg				ErrorF("failed to get BO handle for FB\n");
775504d986fSmrg				goto done;
776504d986fSmrg			}
777504d986fSmrg
778504d986fSmrg			if (drmModeAddFB(pAMDGPUEnt->fd,
779504d986fSmrg				   pScrn->virtualX,
780504d986fSmrg				   pScrn->virtualY,
781504d986fSmrg				   pScrn->depth, pScrn->bitsPerPixel,
782504d986fSmrg				   pScrn->displayWidth * info->pixel_bytes,
783504d986fSmrg				   bo_handle, &drmmode->fb_id) < 0) {
784504d986fSmrg				ErrorF("failed to add fb\n");
785504d986fSmrg				goto done;
786504d986fSmrg			}
787504d986fSmrg
788504d986fSmrg			fb_id = drmmode->fb_id;
789504d986fSmrg		}
790504d986fSmrg
791d6c0b56eSmrg		/* Wait for any pending flip to finish */
792d6c0b56eSmrg		do {} while (drmmode_crtc->flip_pending &&
793d6c0b56eSmrg			     drmHandleEvent(pAMDGPUEnt->fd,
794d6c0b56eSmrg					    &drmmode->event_context) > 0);
795d6c0b56eSmrg
796d6c0b56eSmrg		if (drmModeSetCrtc(pAMDGPUEnt->fd,
797d6c0b56eSmrg				   drmmode_crtc->mode_crtc->crtc_id,
798d6c0b56eSmrg				   fb_id, x, y, output_ids,
799d6c0b56eSmrg				   output_count, &kmode) != 0) {
800d6c0b56eSmrg			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
801d6c0b56eSmrg				   "failed to set mode: %s\n", strerror(errno));
802d6c0b56eSmrg			goto done;
803d6c0b56eSmrg		} else
804d6c0b56eSmrg			ret = TRUE;
805d6c0b56eSmrg
806d6c0b56eSmrg		if (pScreen)
807d6c0b56eSmrg			xf86CrtcSetScreenSubpixelOrder(pScreen);
808d6c0b56eSmrg
809d6c0b56eSmrg		drmmode_crtc->need_modeset = FALSE;
810d6c0b56eSmrg
811d6c0b56eSmrg		/* go through all the outputs and force DPMS them back on? */
812d6c0b56eSmrg		for (i = 0; i < xf86_config->num_output; i++) {
813d6c0b56eSmrg			xf86OutputPtr output = xf86_config->output[i];
814d6c0b56eSmrg
815d6c0b56eSmrg			if (output->crtc != crtc)
816d6c0b56eSmrg				continue;
817d6c0b56eSmrg
818d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOn);
819d6c0b56eSmrg		}
820d6c0b56eSmrg	}
821d6c0b56eSmrg
822d6c0b56eSmrg	/* Compute index of this CRTC into xf86_config->crtc */
823d6c0b56eSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
824d6c0b56eSmrg		if (xf86_config->crtc[i] != crtc)
825d6c0b56eSmrg			continue;
826d6c0b56eSmrg
827d6c0b56eSmrg		if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc))
828d6c0b56eSmrg			info->hwcursor_disabled &= ~(1 << i);
829d6c0b56eSmrg		else
830d6c0b56eSmrg			info->hwcursor_disabled |= 1 << i;
831d6c0b56eSmrg
832d6c0b56eSmrg		break;
833d6c0b56eSmrg	}
834d6c0b56eSmrg
835d6c0b56eSmrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR
836d6c0b56eSmrg	if (!info->hwcursor_disabled)
837d6c0b56eSmrg		xf86_reload_cursors(pScreen);
838d6c0b56eSmrg#endif
839d6c0b56eSmrg
840d6c0b56eSmrgdone:
841d6c0b56eSmrg	free(output_ids);
842d6c0b56eSmrg	if (!ret) {
843d6c0b56eSmrg		crtc->x = saved_x;
844d6c0b56eSmrg		crtc->y = saved_y;
845d6c0b56eSmrg		crtc->rotation = saved_rotation;
846d6c0b56eSmrg		crtc->mode = saved_mode;
847504d986fSmrg	} else {
848d6c0b56eSmrg		crtc->active = TRUE;
849d6c0b56eSmrg
850504d986fSmrg		if (fb_id != drmmode_crtc->scanout[0].fb_id)
851504d986fSmrg			drmmode_crtc_scanout_free(drmmode_crtc);
852504d986fSmrg	}
853504d986fSmrg
854d6c0b56eSmrg	return ret;
855d6c0b56eSmrg}
856d6c0b56eSmrg
857d6c0b56eSmrgstatic void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
858d6c0b56eSmrg{
859d6c0b56eSmrg
860d6c0b56eSmrg}
861d6c0b56eSmrg
862d6c0b56eSmrgstatic void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
863d6c0b56eSmrg{
864d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
865d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
866d6c0b56eSmrg
867504d986fSmrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7
868d6c0b56eSmrg	if (crtc->driverIsPerformingTransform) {
869d6c0b56eSmrg		x += crtc->x;
870d6c0b56eSmrg		y += crtc->y;
871d6c0b56eSmrg		xf86CrtcTransformCursorPos(crtc, &x, &y);
872d6c0b56eSmrg	}
873d6c0b56eSmrg#endif
874d6c0b56eSmrg
875d6c0b56eSmrg	drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
876d6c0b56eSmrg}
877d6c0b56eSmrg
878504d986fSmrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7
879d6c0b56eSmrg
880d6c0b56eSmrgstatic int
881d6c0b56eSmrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height,
882d6c0b56eSmrg			  int x_dst, int y_dst)
883d6c0b56eSmrg{
884d6c0b56eSmrg	int t;
885d6c0b56eSmrg
886d6c0b56eSmrg	switch (rotation & 0xf) {
887d6c0b56eSmrg	case RR_Rotate_90:
888d6c0b56eSmrg		t = x_dst;
889d6c0b56eSmrg		x_dst = height - y_dst - 1;
890d6c0b56eSmrg		y_dst = t;
891d6c0b56eSmrg		break;
892d6c0b56eSmrg	case RR_Rotate_180:
893d6c0b56eSmrg		x_dst = width - x_dst - 1;
894d6c0b56eSmrg		y_dst = height - y_dst - 1;
895d6c0b56eSmrg		break;
896d6c0b56eSmrg	case RR_Rotate_270:
897d6c0b56eSmrg		t = x_dst;
898d6c0b56eSmrg		x_dst = y_dst;
899d6c0b56eSmrg		y_dst = width - t - 1;
900d6c0b56eSmrg		break;
901d6c0b56eSmrg	}
902d6c0b56eSmrg
903d6c0b56eSmrg	if (rotation & RR_Reflect_X)
904d6c0b56eSmrg		x_dst = width - x_dst - 1;
905d6c0b56eSmrg	if (rotation & RR_Reflect_Y)
906d6c0b56eSmrg		y_dst = height - y_dst - 1;
907d6c0b56eSmrg
908d6c0b56eSmrg	return y_dst * height + x_dst;
909d6c0b56eSmrg}
910d6c0b56eSmrg
911d6c0b56eSmrg#endif
912d6c0b56eSmrg
913d6c0b56eSmrgstatic void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_t *ptr)
914d6c0b56eSmrg{
915d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
916d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
917d6c0b56eSmrg
918504d986fSmrg#if XF86_CRTC_VERSION >= 4 && XF86_CRTC_VERSION < 7
919d6c0b56eSmrg	if (crtc->driverIsPerformingTransform) {
920d6c0b56eSmrg		uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
921d6c0b56eSmrg		int dstx, dsty;
922d6c0b56eSmrg		int srcoffset;
923d6c0b56eSmrg
924d6c0b56eSmrg		for (dsty = 0; dsty < cursor_h; dsty++) {
925d6c0b56eSmrg			for (dstx = 0; dstx < cursor_w; dstx++) {
926d6c0b56eSmrg				srcoffset = drmmode_cursor_src_offset(crtc->rotation,
927d6c0b56eSmrg								      cursor_w,
928d6c0b56eSmrg								      cursor_h,
929d6c0b56eSmrg								      dstx, dsty);
930d6c0b56eSmrg
931d6c0b56eSmrg				ptr[dsty * info->cursor_w + dstx] =
932d6c0b56eSmrg					cpu_to_le32(image[srcoffset]);
933d6c0b56eSmrg			}
934d6c0b56eSmrg		}
935d6c0b56eSmrg	} else
936d6c0b56eSmrg#endif
937d6c0b56eSmrg	{
938d6c0b56eSmrg		uint32_t cursor_size = info->cursor_w * info->cursor_h;
939d6c0b56eSmrg		int i;
940d6c0b56eSmrg
941d6c0b56eSmrg		for (i = 0; i < cursor_size; i++)
942d6c0b56eSmrg			ptr[i] = cpu_to_le32(image[i]);
943d6c0b56eSmrg	}
944d6c0b56eSmrg}
945d6c0b56eSmrg
946d6c0b56eSmrgstatic void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image)
947d6c0b56eSmrg{
948d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
949d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
950d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
951d6c0b56eSmrg	uint32_t cursor_size = info->cursor_w * info->cursor_h;
952d6c0b56eSmrg
953d6c0b56eSmrg	if (info->gbm) {
954d6c0b56eSmrg		uint32_t ptr[cursor_size];
955d6c0b56eSmrg
956d6c0b56eSmrg		drmmode_do_load_cursor_argb(crtc, image, ptr);
957d6c0b56eSmrg		gbm_bo_write(drmmode_crtc->cursor_buffer->bo.gbm, ptr, cursor_size * 4);
958d6c0b56eSmrg	} else {
959d6c0b56eSmrg		/* cursor should be mapped already */
960d6c0b56eSmrg		uint32_t *ptr = (uint32_t *) (drmmode_crtc->cursor_buffer->cpu_ptr);
961d6c0b56eSmrg
962d6c0b56eSmrg		drmmode_do_load_cursor_argb(crtc, image, ptr);
963d6c0b56eSmrg	}
964d6c0b56eSmrg}
965d6c0b56eSmrg
966d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
967d6c0b56eSmrg
968d6c0b56eSmrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
969d6c0b56eSmrg{
970d6c0b56eSmrg	if (!drmmode_can_use_hw_cursor(crtc))
971d6c0b56eSmrg		return FALSE;
972d6c0b56eSmrg
973d6c0b56eSmrg	drmmode_load_cursor_argb(crtc, image);
974d6c0b56eSmrg	return TRUE;
975d6c0b56eSmrg}
976d6c0b56eSmrg
977d6c0b56eSmrg#endif
978d6c0b56eSmrg
979d6c0b56eSmrgstatic void drmmode_hide_cursor(xf86CrtcPtr crtc)
980d6c0b56eSmrg{
981d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
982d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
983d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
984d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
985d6c0b56eSmrg
986d6c0b56eSmrg	drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
987d6c0b56eSmrg			 info->cursor_w, info->cursor_h);
988d6c0b56eSmrg
989d6c0b56eSmrg}
990d6c0b56eSmrg
991d6c0b56eSmrgstatic void drmmode_show_cursor(xf86CrtcPtr crtc)
992d6c0b56eSmrg{
993d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
994d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
995d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
996d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
997d6c0b56eSmrg	uint32_t bo_handle;
998d6c0b56eSmrg	static Bool use_set_cursor2 = TRUE;
999d6c0b56eSmrg
1000d6c0b56eSmrg	if (!amdgpu_bo_get_handle(drmmode_crtc->cursor_buffer, &bo_handle)) {
1001d6c0b56eSmrg		ErrorF("failed to get BO handle for cursor\n");
1002d6c0b56eSmrg		return;
1003d6c0b56eSmrg	}
1004d6c0b56eSmrg
1005d6c0b56eSmrg	if (use_set_cursor2) {
1006d6c0b56eSmrg		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1007d6c0b56eSmrg		CursorPtr cursor = xf86_config->cursor;
1008504d986fSmrg		int xhot = cursor->bits->xhot;
1009504d986fSmrg		int yhot = cursor->bits->yhot;
1010d6c0b56eSmrg		int ret;
1011d6c0b56eSmrg
1012504d986fSmrg		if (crtc->rotation != RR_Rotate_0 &&
1013504d986fSmrg		    crtc->rotation != (RR_Rotate_180 | RR_Reflect_X |
1014504d986fSmrg				       RR_Reflect_Y)) {
1015504d986fSmrg			int t;
1016504d986fSmrg
1017504d986fSmrg			/* Reflect & rotate hotspot position */
1018504d986fSmrg			if (crtc->rotation & RR_Reflect_X)
1019504d986fSmrg				xhot = info->cursor_w - xhot - 1;
1020504d986fSmrg			if (crtc->rotation & RR_Reflect_Y)
1021504d986fSmrg				yhot = info->cursor_h - yhot - 1;
1022504d986fSmrg
1023504d986fSmrg			switch (crtc->rotation & 0xf) {
1024504d986fSmrg			case RR_Rotate_90:
1025504d986fSmrg				t = xhot;
1026504d986fSmrg				xhot = yhot;
1027504d986fSmrg				yhot = info->cursor_w - t - 1;
1028504d986fSmrg				break;
1029504d986fSmrg			case RR_Rotate_180:
1030504d986fSmrg				xhot = info->cursor_w - xhot - 1;
1031504d986fSmrg				yhot = info->cursor_h - yhot - 1;
1032504d986fSmrg				break;
1033504d986fSmrg			case RR_Rotate_270:
1034504d986fSmrg				t = xhot;
1035504d986fSmrg				xhot = info->cursor_h - yhot - 1;
1036504d986fSmrg				yhot = t;
1037504d986fSmrg			}
1038504d986fSmrg		}
1039504d986fSmrg
1040d6c0b56eSmrg		ret = drmModeSetCursor2(pAMDGPUEnt->fd,
1041d6c0b56eSmrg					drmmode_crtc->mode_crtc->crtc_id,
1042d6c0b56eSmrg					bo_handle,
1043d6c0b56eSmrg					info->cursor_w, info->cursor_h,
1044504d986fSmrg					xhot, yhot);
1045d6c0b56eSmrg		if (ret == -EINVAL)
1046d6c0b56eSmrg			use_set_cursor2 = FALSE;
1047d6c0b56eSmrg		else
1048d6c0b56eSmrg			return;
1049d6c0b56eSmrg	}
1050d6c0b56eSmrg
1051d6c0b56eSmrg	drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, bo_handle,
1052d6c0b56eSmrg			 info->cursor_w, info->cursor_h);
1053d6c0b56eSmrg}
1054d6c0b56eSmrg
1055d6c0b56eSmrgstatic void *drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width,
1056d6c0b56eSmrg					  int height)
1057d6c0b56eSmrg{
1058d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1059d6c0b56eSmrg
1060d6c0b56eSmrg	return drmmode_crtc_scanout_allocate(crtc, &drmmode_crtc->rotate,
1061d6c0b56eSmrg					     width, height);
1062d6c0b56eSmrg}
1063d6c0b56eSmrg
1064d6c0b56eSmrgstatic PixmapPtr
1065d6c0b56eSmrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1066d6c0b56eSmrg{
1067d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1068d6c0b56eSmrg
1069d6c0b56eSmrg	/* Xorg passes in the return value of drmmode_crtc_shadow_allocate
1070d6c0b56eSmrg	 * for data, but that's redundant for drmmode_crtc_scanout_create.
1071d6c0b56eSmrg	 */
1072d6c0b56eSmrg	return drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
1073d6c0b56eSmrg					   height);
1074d6c0b56eSmrg}
1075d6c0b56eSmrg
1076d6c0b56eSmrgstatic void
1077d6c0b56eSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap,
1078d6c0b56eSmrg			    void *data)
1079d6c0b56eSmrg{
1080d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1081d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1082d6c0b56eSmrg
1083d6c0b56eSmrg	drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate);
1084d6c0b56eSmrg}
1085d6c0b56eSmrg
1086d6c0b56eSmrgstatic void
1087d6c0b56eSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
1088d6c0b56eSmrg		       uint16_t * blue, int size)
1089d6c0b56eSmrg{
1090d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1091d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
1092d6c0b56eSmrg
1093d6c0b56eSmrg	drmModeCrtcSetGamma(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
1094d6c0b56eSmrg			    size, red, green, blue);
1095d6c0b56eSmrg}
1096d6c0b56eSmrg
1097d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
1098d6c0b56eSmrgstatic Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
1099d6c0b56eSmrg{
1100d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1101504d986fSmrg	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
1102504d986fSmrg	ScreenPtr screen = crtc->scrn->pScreen;
1103504d986fSmrg	PixmapDirtyUpdatePtr dirty;
1104d6c0b56eSmrg
1105504d986fSmrg	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
1106504d986fSmrg		if (dirty->slave_dst !=
1107504d986fSmrg		    drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap)
1108d6c0b56eSmrg			continue;
1109504d986fSmrg
1110504d986fSmrg		PixmapStopDirtyTracking(dirty->src, dirty->slave_dst);
1111504d986fSmrg		drmmode_crtc_scanout_free(drmmode_crtc);
1112504d986fSmrg		break;
1113d6c0b56eSmrg	}
1114d6c0b56eSmrg
1115504d986fSmrg	if (!ppix)
1116504d986fSmrg		return TRUE;
1117504d986fSmrg
1118504d986fSmrg	if (!drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[0],
1119504d986fSmrg					 ppix->drawable.width,
1120504d986fSmrg					 ppix->drawable.height))
1121504d986fSmrg		return FALSE;
1122d6c0b56eSmrg
1123504d986fSmrg	if (info->tear_free &&
1124504d986fSmrg	    !drmmode_crtc_scanout_create(crtc, &drmmode_crtc->scanout[1],
1125504d986fSmrg					 ppix->drawable.width,
1126504d986fSmrg					 ppix->drawable.height)) {
1127504d986fSmrg		drmmode_crtc_scanout_free(drmmode_crtc);
1128504d986fSmrg		return FALSE;
1129d6c0b56eSmrg	}
1130504d986fSmrg
1131d6c0b56eSmrg#ifdef HAS_DIRTYTRACKING_ROTATION
1132504d986fSmrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[0].pixmap,
1133504d986fSmrg				 0, 0, 0, 0, RR_Rotate_0);
1134d6c0b56eSmrg#elif defined(HAS_DIRTYTRACKING2)
1135504d986fSmrg	PixmapStartDirtyTracking2(ppix, drmmode_crtc->scanout[0].pixmap,
1136504d986fSmrg				  0, 0, 0, 0);
1137d6c0b56eSmrg#else
1138504d986fSmrg	PixmapStartDirtyTracking(ppix, drmmode_crtc->scanout[0].pixmap, 0, 0);
1139d6c0b56eSmrg#endif
1140d6c0b56eSmrg	return TRUE;
1141d6c0b56eSmrg}
1142d6c0b56eSmrg#endif
1143d6c0b56eSmrg
1144d6c0b56eSmrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = {
1145d6c0b56eSmrg	.dpms = drmmode_crtc_dpms,
1146d6c0b56eSmrg	.set_mode_major = drmmode_set_mode_major,
1147d6c0b56eSmrg	.set_cursor_colors = drmmode_set_cursor_colors,
1148d6c0b56eSmrg	.set_cursor_position = drmmode_set_cursor_position,
1149d6c0b56eSmrg	.show_cursor = drmmode_show_cursor,
1150d6c0b56eSmrg	.hide_cursor = drmmode_hide_cursor,
1151d6c0b56eSmrg	.load_cursor_argb = drmmode_load_cursor_argb,
1152d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
1153d6c0b56eSmrg	.load_cursor_argb_check = drmmode_load_cursor_argb_check,
1154d6c0b56eSmrg#endif
1155d6c0b56eSmrg
1156d6c0b56eSmrg	.gamma_set = drmmode_crtc_gamma_set,
1157d6c0b56eSmrg	.shadow_create = drmmode_crtc_shadow_create,
1158d6c0b56eSmrg	.shadow_allocate = drmmode_crtc_shadow_allocate,
1159d6c0b56eSmrg	.shadow_destroy = drmmode_crtc_shadow_destroy,
1160d6c0b56eSmrg	.destroy = NULL,	/* XXX */
1161d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
1162d6c0b56eSmrg	.set_scanout_pixmap = drmmode_set_scanout_pixmap,
1163d6c0b56eSmrg#endif
1164d6c0b56eSmrg};
1165d6c0b56eSmrg
1166d6c0b56eSmrgint drmmode_get_crtc_id(xf86CrtcPtr crtc)
1167d6c0b56eSmrg{
1168d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1169d6c0b56eSmrg	return drmmode_crtc->hw_id;
1170d6c0b56eSmrg}
1171d6c0b56eSmrg
1172d6c0b56eSmrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc)
1173d6c0b56eSmrg{
1174d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1175d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
1176d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1177d6c0b56eSmrg	int r;
1178d6c0b56eSmrg
1179d6c0b56eSmrg	r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev,
1180d6c0b56eSmrg				      drmmode_crtc->mode_crtc->crtc_id,
1181d6c0b56eSmrg				      &drmmode_crtc->hw_id);
1182d6c0b56eSmrg	if (r)
1183d6c0b56eSmrg		drmmode_crtc->hw_id = -1;
1184d6c0b56eSmrg}
1185d6c0b56eSmrg
1186d6c0b56eSmrgstatic unsigned int
1187d6c0b56eSmrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
1188d6c0b56eSmrg{
1189d6c0b56eSmrg	xf86CrtcPtr crtc;
1190d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc;
1191d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1192d6c0b56eSmrg
1193d6c0b56eSmrg	crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
1194d6c0b56eSmrg	if (crtc == NULL)
1195d6c0b56eSmrg		return 0;
1196d6c0b56eSmrg
1197d6c0b56eSmrg	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
1198d6c0b56eSmrg	drmmode_crtc->mode_crtc =
1199d6c0b56eSmrg	    drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]);
1200d6c0b56eSmrg	drmmode_crtc->drmmode = drmmode;
1201d6c0b56eSmrg	drmmode_crtc->dpms_mode = DPMSModeOff;
1202504d986fSmrg	drmmode_crtc->pending_dpms_mode = DPMSModeOff;
1203d6c0b56eSmrg	crtc->driver_private = drmmode_crtc;
1204d6c0b56eSmrg	drmmode_crtc_hw_id(crtc);
1205d6c0b56eSmrg
1206d6c0b56eSmrg	/* Mark num'th crtc as in use on this device. */
1207d6c0b56eSmrg	pAMDGPUEnt->assigned_crtcs |= (1 << num);
1208d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1209d6c0b56eSmrg		       "Allocated crtc nr. %d to this screen.\n", num);
1210d6c0b56eSmrg
1211d6c0b56eSmrg	return 1;
1212d6c0b56eSmrg}
1213d6c0b56eSmrg
1214d6c0b56eSmrgstatic xf86OutputStatus drmmode_output_detect(xf86OutputPtr output)
1215d6c0b56eSmrg{
1216d6c0b56eSmrg	/* go to the hw and retrieve a new output struct */
1217d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1218d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1219d6c0b56eSmrg	xf86OutputStatus status;
1220d6c0b56eSmrg	drmModeFreeConnector(drmmode_output->mode_output);
1221d6c0b56eSmrg
1222d6c0b56eSmrg	drmmode_output->mode_output =
1223d6c0b56eSmrg	    drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id);
1224d6c0b56eSmrg	if (!drmmode_output->mode_output)
1225d6c0b56eSmrg		return XF86OutputStatusDisconnected;
1226d6c0b56eSmrg
1227d6c0b56eSmrg	switch (drmmode_output->mode_output->connection) {
1228d6c0b56eSmrg	case DRM_MODE_CONNECTED:
1229d6c0b56eSmrg		status = XF86OutputStatusConnected;
1230d6c0b56eSmrg		break;
1231d6c0b56eSmrg	case DRM_MODE_DISCONNECTED:
1232d6c0b56eSmrg		status = XF86OutputStatusDisconnected;
1233d6c0b56eSmrg		break;
1234d6c0b56eSmrg	default:
1235d6c0b56eSmrg	case DRM_MODE_UNKNOWNCONNECTION:
1236d6c0b56eSmrg		status = XF86OutputStatusUnknown;
1237d6c0b56eSmrg		break;
1238d6c0b56eSmrg	}
1239d6c0b56eSmrg	return status;
1240d6c0b56eSmrg}
1241d6c0b56eSmrg
1242d6c0b56eSmrgstatic Bool
1243d6c0b56eSmrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
1244d6c0b56eSmrg{
1245d6c0b56eSmrg	return MODE_OK;
1246d6c0b56eSmrg}
1247d6c0b56eSmrg
1248d6c0b56eSmrgstatic DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output)
1249d6c0b56eSmrg{
1250d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1251d6c0b56eSmrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
1252d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1253d6c0b56eSmrg	int i;
1254d6c0b56eSmrg	DisplayModePtr Modes = NULL, Mode;
1255d6c0b56eSmrg	drmModePropertyPtr props;
1256d6c0b56eSmrg	xf86MonPtr mon = NULL;
1257d6c0b56eSmrg
1258d6c0b56eSmrg	if (!koutput)
1259d6c0b56eSmrg		return NULL;
1260d6c0b56eSmrg
1261d6c0b56eSmrg	/* look for an EDID property */
1262d6c0b56eSmrg	for (i = 0; i < koutput->count_props; i++) {
1263d6c0b56eSmrg		props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]);
1264d6c0b56eSmrg		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
1265d6c0b56eSmrg			if (!strcmp(props->name, "EDID")) {
1266d6c0b56eSmrg				if (drmmode_output->edid_blob)
1267d6c0b56eSmrg					drmModeFreePropertyBlob
1268d6c0b56eSmrg					    (drmmode_output->edid_blob);
1269d6c0b56eSmrg				drmmode_output->edid_blob =
1270d6c0b56eSmrg				    drmModeGetPropertyBlob(pAMDGPUEnt->fd,
1271d6c0b56eSmrg							   koutput->prop_values
1272d6c0b56eSmrg							   [i]);
1273d6c0b56eSmrg			}
1274d6c0b56eSmrg		}
1275d6c0b56eSmrg		if (props)
1276d6c0b56eSmrg			drmModeFreeProperty(props);
1277d6c0b56eSmrg	}
1278d6c0b56eSmrg
1279d6c0b56eSmrg	if (drmmode_output->edid_blob) {
1280d6c0b56eSmrg		mon = xf86InterpretEDID(output->scrn->scrnIndex,
1281d6c0b56eSmrg					drmmode_output->edid_blob->data);
1282d6c0b56eSmrg		if (mon && drmmode_output->edid_blob->length > 128)
1283d6c0b56eSmrg			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
1284d6c0b56eSmrg	}
1285d6c0b56eSmrg	xf86OutputSetEDID(output, mon);
1286d6c0b56eSmrg
1287d6c0b56eSmrg	/* modes should already be available */
1288d6c0b56eSmrg	for (i = 0; i < koutput->count_modes; i++) {
1289d6c0b56eSmrg		Mode = xnfalloc(sizeof(DisplayModeRec));
1290d6c0b56eSmrg
1291d6c0b56eSmrg		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i],
1292d6c0b56eSmrg					 Mode);
1293d6c0b56eSmrg		Modes = xf86ModesAdd(Modes, Mode);
1294d6c0b56eSmrg
1295d6c0b56eSmrg	}
1296d6c0b56eSmrg	return Modes;
1297d6c0b56eSmrg}
1298d6c0b56eSmrg
1299d6c0b56eSmrgstatic void drmmode_output_destroy(xf86OutputPtr output)
1300d6c0b56eSmrg{
1301d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1302d6c0b56eSmrg	int i;
1303d6c0b56eSmrg
1304d6c0b56eSmrg	if (drmmode_output->edid_blob)
1305d6c0b56eSmrg		drmModeFreePropertyBlob(drmmode_output->edid_blob);
1306d6c0b56eSmrg	for (i = 0; i < drmmode_output->num_props; i++) {
1307d6c0b56eSmrg		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
1308d6c0b56eSmrg		free(drmmode_output->props[i].atoms);
1309d6c0b56eSmrg	}
1310d6c0b56eSmrg	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
1311d6c0b56eSmrg		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
1312d6c0b56eSmrg	}
1313d6c0b56eSmrg	free(drmmode_output->mode_encoders);
1314d6c0b56eSmrg	free(drmmode_output->props);
1315d6c0b56eSmrg	drmModeFreeConnector(drmmode_output->mode_output);
1316d6c0b56eSmrg	free(drmmode_output);
1317d6c0b56eSmrg	output->driver_private = NULL;
1318d6c0b56eSmrg}
1319d6c0b56eSmrg
1320d6c0b56eSmrgstatic void drmmode_output_dpms(xf86OutputPtr output, int mode)
1321d6c0b56eSmrg{
1322d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1323d6c0b56eSmrg	xf86CrtcPtr crtc = output->crtc;
1324d6c0b56eSmrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
1325d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1326d6c0b56eSmrg
1327d6c0b56eSmrg	if (!koutput)
1328d6c0b56eSmrg		return;
1329d6c0b56eSmrg
1330504d986fSmrg	if (mode != DPMSModeOn && crtc) {
1331504d986fSmrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1332504d986fSmrg
1333d6c0b56eSmrg		drmmode_do_crtc_dpms(crtc, mode);
1334d6c0b56eSmrg
1335504d986fSmrg		/* Wait for any pending flip to finish */
1336504d986fSmrg		if (drmmode_crtc->flip_pending)
1337504d986fSmrg			return;
1338504d986fSmrg	}
1339504d986fSmrg
1340d6c0b56eSmrg	drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id,
1341d6c0b56eSmrg				    drmmode_output->dpms_enum_id, mode);
1342d6c0b56eSmrg
1343d6c0b56eSmrg	if (mode == DPMSModeOn && crtc) {
1344d6c0b56eSmrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1345d6c0b56eSmrg
1346d6c0b56eSmrg		if (drmmode_crtc->need_modeset)
1347d6c0b56eSmrg			drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
1348d6c0b56eSmrg					       crtc->x, crtc->y);
1349d6c0b56eSmrg		else
1350d6c0b56eSmrg			drmmode_do_crtc_dpms(output->crtc, mode);
1351d6c0b56eSmrg	}
1352d6c0b56eSmrg}
1353d6c0b56eSmrg
1354d6c0b56eSmrgstatic Bool drmmode_property_ignore(drmModePropertyPtr prop)
1355d6c0b56eSmrg{
1356d6c0b56eSmrg	if (!prop)
1357d6c0b56eSmrg		return TRUE;
1358d6c0b56eSmrg	/* ignore blob prop */
1359d6c0b56eSmrg	if (prop->flags & DRM_MODE_PROP_BLOB)
1360d6c0b56eSmrg		return TRUE;
1361d6c0b56eSmrg	/* ignore standard property */
1362d6c0b56eSmrg	if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS"))
1363d6c0b56eSmrg		return TRUE;
1364d6c0b56eSmrg
1365d6c0b56eSmrg	return FALSE;
1366d6c0b56eSmrg}
1367d6c0b56eSmrg
1368d6c0b56eSmrgstatic void drmmode_output_create_resources(xf86OutputPtr output)
1369d6c0b56eSmrg{
1370d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1371d6c0b56eSmrg	drmModeConnectorPtr mode_output = drmmode_output->mode_output;
1372d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1373d6c0b56eSmrg	drmModePropertyPtr drmmode_prop;
1374d6c0b56eSmrg	int i, j, err;
1375d6c0b56eSmrg
1376d6c0b56eSmrg	drmmode_output->props =
1377d6c0b56eSmrg	    calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
1378d6c0b56eSmrg	if (!drmmode_output->props)
1379d6c0b56eSmrg		return;
1380d6c0b56eSmrg
1381d6c0b56eSmrg	drmmode_output->num_props = 0;
1382d6c0b56eSmrg	for (i = 0, j = 0; i < mode_output->count_props; i++) {
1383d6c0b56eSmrg		drmmode_prop =
1384d6c0b56eSmrg		    drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]);
1385d6c0b56eSmrg		if (drmmode_property_ignore(drmmode_prop)) {
1386d6c0b56eSmrg			drmModeFreeProperty(drmmode_prop);
1387d6c0b56eSmrg			continue;
1388d6c0b56eSmrg		}
1389d6c0b56eSmrg		drmmode_output->props[j].mode_prop = drmmode_prop;
1390d6c0b56eSmrg		drmmode_output->props[j].value = mode_output->prop_values[i];
1391d6c0b56eSmrg		drmmode_output->num_props++;
1392d6c0b56eSmrg		j++;
1393d6c0b56eSmrg	}
1394d6c0b56eSmrg
1395d6c0b56eSmrg	for (i = 0; i < drmmode_output->num_props; i++) {
1396d6c0b56eSmrg		drmmode_prop_ptr p = &drmmode_output->props[i];
1397d6c0b56eSmrg		drmmode_prop = p->mode_prop;
1398d6c0b56eSmrg
1399d6c0b56eSmrg		if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1400d6c0b56eSmrg			INT32 range[2];
1401d6c0b56eSmrg			INT32 value = p->value;
1402d6c0b56eSmrg
1403d6c0b56eSmrg			p->num_atoms = 1;
1404d6c0b56eSmrg			p->atoms = calloc(p->num_atoms, sizeof(Atom));
1405d6c0b56eSmrg			if (!p->atoms)
1406d6c0b56eSmrg				continue;
1407d6c0b56eSmrg			p->atoms[0] =
1408d6c0b56eSmrg			    MakeAtom(drmmode_prop->name,
1409d6c0b56eSmrg				     strlen(drmmode_prop->name), TRUE);
1410d6c0b56eSmrg			range[0] = drmmode_prop->values[0];
1411d6c0b56eSmrg			range[1] = drmmode_prop->values[1];
1412d6c0b56eSmrg			err =
1413d6c0b56eSmrg			    RRConfigureOutputProperty(output->randr_output,
1414d6c0b56eSmrg						      p->atoms[0], FALSE, TRUE,
1415d6c0b56eSmrg						      drmmode_prop->flags &
1416d6c0b56eSmrg						      DRM_MODE_PROP_IMMUTABLE ?
1417d6c0b56eSmrg						      TRUE : FALSE, 2, range);
1418d6c0b56eSmrg			if (err != 0) {
1419d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1420d6c0b56eSmrg					   "RRConfigureOutputProperty error, %d\n",
1421d6c0b56eSmrg					   err);
1422d6c0b56eSmrg			}
1423d6c0b56eSmrg			err =
1424d6c0b56eSmrg			    RRChangeOutputProperty(output->randr_output,
1425d6c0b56eSmrg						   p->atoms[0], XA_INTEGER, 32,
1426d6c0b56eSmrg						   PropModeReplace, 1, &value,
1427d6c0b56eSmrg						   FALSE, TRUE);
1428d6c0b56eSmrg			if (err != 0) {
1429d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1430d6c0b56eSmrg					   "RRChangeOutputProperty error, %d\n",
1431d6c0b56eSmrg					   err);
1432d6c0b56eSmrg			}
1433d6c0b56eSmrg		} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1434d6c0b56eSmrg			p->num_atoms = drmmode_prop->count_enums + 1;
1435d6c0b56eSmrg			p->atoms = calloc(p->num_atoms, sizeof(Atom));
1436d6c0b56eSmrg			if (!p->atoms)
1437d6c0b56eSmrg				continue;
1438d6c0b56eSmrg			p->atoms[0] =
1439d6c0b56eSmrg			    MakeAtom(drmmode_prop->name,
1440d6c0b56eSmrg				     strlen(drmmode_prop->name), TRUE);
1441d6c0b56eSmrg			for (j = 1; j <= drmmode_prop->count_enums; j++) {
1442d6c0b56eSmrg				struct drm_mode_property_enum *e =
1443d6c0b56eSmrg				    &drmmode_prop->enums[j - 1];
1444d6c0b56eSmrg				p->atoms[j] =
1445d6c0b56eSmrg				    MakeAtom(e->name, strlen(e->name), TRUE);
1446d6c0b56eSmrg			}
1447d6c0b56eSmrg			err =
1448d6c0b56eSmrg			    RRConfigureOutputProperty(output->randr_output,
1449d6c0b56eSmrg						      p->atoms[0], FALSE, FALSE,
1450d6c0b56eSmrg						      drmmode_prop->flags &
1451d6c0b56eSmrg						      DRM_MODE_PROP_IMMUTABLE ?
1452d6c0b56eSmrg						      TRUE : FALSE,
1453d6c0b56eSmrg						      p->num_atoms - 1,
1454d6c0b56eSmrg						      (INT32 *) & p->atoms[1]);
1455d6c0b56eSmrg			if (err != 0) {
1456d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1457d6c0b56eSmrg					   "RRConfigureOutputProperty error, %d\n",
1458d6c0b56eSmrg					   err);
1459d6c0b56eSmrg			}
1460d6c0b56eSmrg			for (j = 0; j < drmmode_prop->count_enums; j++)
1461d6c0b56eSmrg				if (drmmode_prop->enums[j].value == p->value)
1462d6c0b56eSmrg					break;
1463d6c0b56eSmrg			/* there's always a matching value */
1464d6c0b56eSmrg			err =
1465d6c0b56eSmrg			    RRChangeOutputProperty(output->randr_output,
1466d6c0b56eSmrg						   p->atoms[0], XA_ATOM, 32,
1467d6c0b56eSmrg						   PropModeReplace, 1,
1468d6c0b56eSmrg						   &p->atoms[j + 1], FALSE,
1469d6c0b56eSmrg						   TRUE);
1470d6c0b56eSmrg			if (err != 0) {
1471d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1472d6c0b56eSmrg					   "RRChangeOutputProperty error, %d\n",
1473d6c0b56eSmrg					   err);
1474d6c0b56eSmrg			}
1475d6c0b56eSmrg		}
1476d6c0b56eSmrg	}
1477d6c0b56eSmrg}
1478d6c0b56eSmrg
1479d6c0b56eSmrgstatic Bool
1480d6c0b56eSmrgdrmmode_output_set_property(xf86OutputPtr output, Atom property,
1481d6c0b56eSmrg			    RRPropertyValuePtr value)
1482d6c0b56eSmrg{
1483d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1484d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1485d6c0b56eSmrg	int i;
1486d6c0b56eSmrg
1487d6c0b56eSmrg	for (i = 0; i < drmmode_output->num_props; i++) {
1488d6c0b56eSmrg		drmmode_prop_ptr p = &drmmode_output->props[i];
1489d6c0b56eSmrg
1490d6c0b56eSmrg		if (p->atoms[0] != property)
1491d6c0b56eSmrg			continue;
1492d6c0b56eSmrg
1493d6c0b56eSmrg		if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1494d6c0b56eSmrg			uint32_t val;
1495d6c0b56eSmrg
1496d6c0b56eSmrg			if (value->type != XA_INTEGER || value->format != 32 ||
1497d6c0b56eSmrg			    value->size != 1)
1498d6c0b56eSmrg				return FALSE;
1499d6c0b56eSmrg			val = *(uint32_t *) value->data;
1500d6c0b56eSmrg
1501d6c0b56eSmrg			drmModeConnectorSetProperty(pAMDGPUEnt->fd,
1502d6c0b56eSmrg						    drmmode_output->output_id,
1503d6c0b56eSmrg						    p->mode_prop->prop_id,
1504d6c0b56eSmrg						    (uint64_t) val);
1505d6c0b56eSmrg			return TRUE;
1506d6c0b56eSmrg		} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1507d6c0b56eSmrg			Atom atom;
1508d6c0b56eSmrg			const char *name;
1509d6c0b56eSmrg			int j;
1510d6c0b56eSmrg
1511d6c0b56eSmrg			if (value->type != XA_ATOM || value->format != 32
1512d6c0b56eSmrg			    || value->size != 1)
1513d6c0b56eSmrg				return FALSE;
1514d6c0b56eSmrg			memcpy(&atom, value->data, 4);
1515d6c0b56eSmrg			name = NameForAtom(atom);
1516d6c0b56eSmrg
1517d6c0b56eSmrg			/* search for matching name string, then set its value down */
1518d6c0b56eSmrg			for (j = 0; j < p->mode_prop->count_enums; j++) {
1519d6c0b56eSmrg				if (!strcmp(p->mode_prop->enums[j].name, name)) {
1520d6c0b56eSmrg					drmModeConnectorSetProperty(pAMDGPUEnt->fd,
1521d6c0b56eSmrg								    drmmode_output->output_id,
1522d6c0b56eSmrg								    p->mode_prop->prop_id,
1523d6c0b56eSmrg								    p->mode_prop->enums
1524d6c0b56eSmrg								    [j].value);
1525d6c0b56eSmrg					return TRUE;
1526d6c0b56eSmrg				}
1527d6c0b56eSmrg			}
1528d6c0b56eSmrg		}
1529d6c0b56eSmrg	}
1530d6c0b56eSmrg
1531d6c0b56eSmrg	return TRUE;
1532d6c0b56eSmrg}
1533d6c0b56eSmrg
1534d6c0b56eSmrgstatic Bool drmmode_output_get_property(xf86OutputPtr output, Atom property)
1535d6c0b56eSmrg{
1536d6c0b56eSmrg	return TRUE;
1537d6c0b56eSmrg}
1538d6c0b56eSmrg
1539d6c0b56eSmrgstatic const xf86OutputFuncsRec drmmode_output_funcs = {
1540d6c0b56eSmrg	.dpms = drmmode_output_dpms,
1541d6c0b56eSmrg	.create_resources = drmmode_output_create_resources,
1542d6c0b56eSmrg	.set_property = drmmode_output_set_property,
1543d6c0b56eSmrg	.get_property = drmmode_output_get_property,
1544d6c0b56eSmrg#if 0
1545d6c0b56eSmrg
1546d6c0b56eSmrg	.save = drmmode_crt_save,
1547d6c0b56eSmrg	.restore = drmmode_crt_restore,
1548d6c0b56eSmrg	.mode_fixup = drmmode_crt_mode_fixup,
1549d6c0b56eSmrg	.prepare = drmmode_output_prepare,
1550d6c0b56eSmrg	.mode_set = drmmode_crt_mode_set,
1551d6c0b56eSmrg	.commit = drmmode_output_commit,
1552d6c0b56eSmrg#endif
1553d6c0b56eSmrg	.detect = drmmode_output_detect,
1554d6c0b56eSmrg	.mode_valid = drmmode_output_mode_valid,
1555d6c0b56eSmrg
1556d6c0b56eSmrg	.get_modes = drmmode_output_get_modes,
1557d6c0b56eSmrg	.destroy = drmmode_output_destroy
1558d6c0b56eSmrg};
1559d6c0b56eSmrg
1560d6c0b56eSmrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown,
1561d6c0b56eSmrg	SubPixelHorizontalRGB,
1562d6c0b56eSmrg	SubPixelHorizontalBGR,
1563d6c0b56eSmrg	SubPixelVerticalRGB,
1564d6c0b56eSmrg	SubPixelVerticalBGR,
1565d6c0b56eSmrg	SubPixelNone
1566d6c0b56eSmrg};
1567d6c0b56eSmrg
1568d6c0b56eSmrgconst char *output_names[] = { "None",
1569d6c0b56eSmrg	"VGA",
1570d6c0b56eSmrg	"DVI-I",
1571d6c0b56eSmrg	"DVI-D",
1572d6c0b56eSmrg	"DVI-A",
1573d6c0b56eSmrg	"Composite",
1574d6c0b56eSmrg	"S-video",
1575d6c0b56eSmrg	"LVDS",
1576d6c0b56eSmrg	"CTV",
1577d6c0b56eSmrg	"DIN",
1578d6c0b56eSmrg	"DisplayPort",
1579d6c0b56eSmrg	"HDMI-A",
1580d6c0b56eSmrg	"HDMI-B",
1581d6c0b56eSmrg	"TV",
1582d6c0b56eSmrg	"eDP",
1583d6c0b56eSmrg	"Virtual",
1584d6c0b56eSmrg	"DSI",
1585d6c0b56eSmrg};
1586d6c0b56eSmrg
1587d6c0b56eSmrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
1588d6c0b56eSmrg
1589d6c0b56eSmrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
1590d6c0b56eSmrg{
1591d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1592d6c0b56eSmrg	int i;
1593d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
1594d6c0b56eSmrg		xf86OutputPtr output = xf86_config->output[i];
1595d6c0b56eSmrg		drmmode_output_private_ptr drmmode_output;
1596d6c0b56eSmrg		drmmode_output = output->driver_private;
1597d6c0b56eSmrg		if (drmmode_output->output_id == id)
1598d6c0b56eSmrg			return output;
1599d6c0b56eSmrg	}
1600d6c0b56eSmrg	return NULL;
1601d6c0b56eSmrg}
1602d6c0b56eSmrg
1603d6c0b56eSmrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
1604d6c0b56eSmrg{
1605d6c0b56eSmrg	char *conn;
1606d6c0b56eSmrg	char conn_id[5];
1607d6c0b56eSmrg	int id, len;
1608d6c0b56eSmrg	char *blob_data;
1609d6c0b56eSmrg
1610d6c0b56eSmrg	if (!path_blob)
1611d6c0b56eSmrg		return -1;
1612d6c0b56eSmrg
1613d6c0b56eSmrg	blob_data = path_blob->data;
1614d6c0b56eSmrg	/* we only handle MST paths for now */
1615d6c0b56eSmrg	if (strncmp(blob_data, "mst:", 4))
1616d6c0b56eSmrg		return -1;
1617d6c0b56eSmrg
1618d6c0b56eSmrg	conn = strchr(blob_data + 4, '-');
1619d6c0b56eSmrg	if (!conn)
1620d6c0b56eSmrg		return -1;
1621d6c0b56eSmrg	len = conn - (blob_data + 4);
1622d6c0b56eSmrg	if (len + 1 > 5)
1623d6c0b56eSmrg		return -1;
1624d6c0b56eSmrg	memcpy(conn_id, blob_data + 4, len);
1625d6c0b56eSmrg	conn_id[len] = '\0';
1626d6c0b56eSmrg	id = strtoul(conn_id, NULL, 10);
1627d6c0b56eSmrg
1628d6c0b56eSmrg	*conn_base_id = id;
1629d6c0b56eSmrg
1630d6c0b56eSmrg	*path = conn + 1;
1631d6c0b56eSmrg	return 0;
1632d6c0b56eSmrg}
1633d6c0b56eSmrg
1634d6c0b56eSmrgstatic void
1635d6c0b56eSmrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
1636d6c0b56eSmrg		    drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi)
1637d6c0b56eSmrg{
1638d6c0b56eSmrg	xf86OutputPtr output;
1639d6c0b56eSmrg	int conn_id;
1640d6c0b56eSmrg	char *extra_path;
1641d6c0b56eSmrg
1642d6c0b56eSmrg	output = NULL;
1643d6c0b56eSmrg	if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
1644d6c0b56eSmrg		output = find_output(pScrn, conn_id);
1645d6c0b56eSmrg	if (output) {
1646d6c0b56eSmrg		snprintf(name, 32, "%s-%s", output->name, extra_path);
1647d6c0b56eSmrg	} else {
1648d6c0b56eSmrg		if (koutput->connector_type >= NUM_OUTPUT_NAMES)
1649d6c0b56eSmrg			snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1);
1650d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
1651d6c0b56eSmrg		else if (pScrn->is_gpu)
1652d6c0b56eSmrg			snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type],
1653d6c0b56eSmrg				 pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1);
1654d6c0b56eSmrg#endif
1655d6c0b56eSmrg		else {
1656d6c0b56eSmrg			/* need to do smart conversion here for compat with non-kms ATI driver */
1657d6c0b56eSmrg			if (koutput->connector_type_id == 1) {
1658d6c0b56eSmrg				switch(koutput->connector_type) {
1659d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DVII:
1660d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DVID:
1661d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DVIA:
1662d6c0b56eSmrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
1663d6c0b56eSmrg					(*num_dvi)++;
1664d6c0b56eSmrg					break;
1665d6c0b56eSmrg				case DRM_MODE_CONNECTOR_HDMIA:
1666d6c0b56eSmrg				case DRM_MODE_CONNECTOR_HDMIB:
1667d6c0b56eSmrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
1668d6c0b56eSmrg					(*num_hdmi)++;
1669d6c0b56eSmrg					break;
1670d6c0b56eSmrg				case DRM_MODE_CONNECTOR_VGA:
1671d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DisplayPort:
1672d6c0b56eSmrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
1673d6c0b56eSmrg					break;
1674d6c0b56eSmrg				default:
1675d6c0b56eSmrg					snprintf(name, 32, "%s", output_names[koutput->connector_type]);
1676d6c0b56eSmrg					break;
1677d6c0b56eSmrg				}
1678d6c0b56eSmrg			} else {
1679d6c0b56eSmrg				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
1680d6c0b56eSmrg			}
1681d6c0b56eSmrg		}
1682d6c0b56eSmrg	}
1683d6c0b56eSmrg}
1684d6c0b56eSmrg
1685d6c0b56eSmrg
1686d6c0b56eSmrgstatic unsigned int
1687d6c0b56eSmrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic)
1688d6c0b56eSmrg{
1689d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1690d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1691d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1692d6c0b56eSmrg	xf86OutputPtr output;
1693d6c0b56eSmrg	drmModeConnectorPtr koutput;
1694d6c0b56eSmrg	drmModeEncoderPtr *kencoders = NULL;
1695d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output;
1696d6c0b56eSmrg	drmModePropertyPtr props;
1697d6c0b56eSmrg	drmModePropertyBlobPtr path_blob = NULL;
1698d6c0b56eSmrg	char name[32];
1699d6c0b56eSmrg	int i;
1700d6c0b56eSmrg	const char *s;
1701d6c0b56eSmrg
1702d6c0b56eSmrg	koutput =
1703d6c0b56eSmrg	    drmModeGetConnector(pAMDGPUEnt->fd,
1704d6c0b56eSmrg				mode_res->connectors[num]);
1705d6c0b56eSmrg	if (!koutput)
1706d6c0b56eSmrg		return 0;
1707d6c0b56eSmrg
1708d6c0b56eSmrg	for (i = 0; i < koutput->count_props; i++) {
1709d6c0b56eSmrg		props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]);
1710d6c0b56eSmrg		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
1711d6c0b56eSmrg			if (!strcmp(props->name, "PATH")) {
1712d6c0b56eSmrg				path_blob = drmModeGetPropertyBlob(pAMDGPUEnt->fd, koutput->prop_values[i]);
1713d6c0b56eSmrg				drmModeFreeProperty(props);
1714d6c0b56eSmrg				break;
1715d6c0b56eSmrg			}
1716d6c0b56eSmrg			drmModeFreeProperty(props);
1717d6c0b56eSmrg		}
1718d6c0b56eSmrg	}
1719d6c0b56eSmrg
1720d6c0b56eSmrg	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
1721d6c0b56eSmrg	if (!kencoders) {
1722d6c0b56eSmrg		goto out_free_encoders;
1723d6c0b56eSmrg	}
1724d6c0b56eSmrg
1725d6c0b56eSmrg	for (i = 0; i < koutput->count_encoders; i++) {
1726d6c0b56eSmrg		kencoders[i] =
1727d6c0b56eSmrg		    drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]);
1728d6c0b56eSmrg		if (!kencoders[i]) {
1729d6c0b56eSmrg			goto out_free_encoders;
1730d6c0b56eSmrg		}
1731d6c0b56eSmrg	}
1732d6c0b56eSmrg
1733d6c0b56eSmrg	drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi);
1734d6c0b56eSmrg	if (path_blob) {
1735d6c0b56eSmrg		drmModeFreePropertyBlob(path_blob);
1736d6c0b56eSmrg	}
1737d6c0b56eSmrg
1738d6c0b56eSmrg	if (path_blob && dynamic) {
1739d6c0b56eSmrg		/* See if we have an output with this name already
1740d6c0b56eSmrg		 * and hook stuff up.
1741d6c0b56eSmrg		 */
1742d6c0b56eSmrg		for (i = 0; i < xf86_config->num_output; i++) {
1743d6c0b56eSmrg			output = xf86_config->output[i];
1744d6c0b56eSmrg
1745d6c0b56eSmrg			if (strncmp(output->name, name, 32))
1746d6c0b56eSmrg				continue;
1747d6c0b56eSmrg
1748d6c0b56eSmrg			drmmode_output = output->driver_private;
1749d6c0b56eSmrg			drmmode_output->output_id = mode_res->connectors[num];
1750d6c0b56eSmrg			drmmode_output->mode_output = koutput;
1751d6c0b56eSmrg			for (i = 0; i < koutput->count_encoders; i++) {
1752d6c0b56eSmrg				drmModeFreeEncoder(kencoders[i]);
1753d6c0b56eSmrg			}
1754d6c0b56eSmrg			free(kencoders);
1755d6c0b56eSmrg			return 1;
1756d6c0b56eSmrg		}
1757d6c0b56eSmrg	}
1758d6c0b56eSmrg
1759d6c0b56eSmrg	if (xf86IsEntityShared(pScrn->entityList[0])) {
1760d6c0b56eSmrg		if ((s =
1761d6c0b56eSmrg		     xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
1762d6c0b56eSmrg			if (!AMDGPUZaphodStringMatches(pScrn, s, name))
1763d6c0b56eSmrg				goto out_free_encoders;
1764d6c0b56eSmrg		} else {
1765d6c0b56eSmrg			if (!info->IsSecondary && (num != 0))
1766d6c0b56eSmrg				goto out_free_encoders;
1767d6c0b56eSmrg			else if (info->IsSecondary && (num != 1))
1768d6c0b56eSmrg				goto out_free_encoders;
1769d6c0b56eSmrg		}
1770d6c0b56eSmrg	}
1771d6c0b56eSmrg
1772d6c0b56eSmrg	output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
1773d6c0b56eSmrg	if (!output) {
1774d6c0b56eSmrg		goto out_free_encoders;
1775d6c0b56eSmrg	}
1776d6c0b56eSmrg
1777d6c0b56eSmrg	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
1778d6c0b56eSmrg	if (!drmmode_output) {
1779d6c0b56eSmrg		xf86OutputDestroy(output);
1780d6c0b56eSmrg		goto out_free_encoders;
1781d6c0b56eSmrg	}
1782d6c0b56eSmrg
1783d6c0b56eSmrg	drmmode_output->output_id = mode_res->connectors[num];
1784d6c0b56eSmrg	drmmode_output->mode_output = koutput;
1785d6c0b56eSmrg	drmmode_output->mode_encoders = kencoders;
1786d6c0b56eSmrg	drmmode_output->drmmode = drmmode;
1787d6c0b56eSmrg	output->mm_width = koutput->mmWidth;
1788d6c0b56eSmrg	output->mm_height = koutput->mmHeight;
1789d6c0b56eSmrg
1790d6c0b56eSmrg	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
1791d6c0b56eSmrg	output->interlaceAllowed = TRUE;
1792d6c0b56eSmrg	output->doubleScanAllowed = TRUE;
1793d6c0b56eSmrg	output->driver_private = drmmode_output;
1794d6c0b56eSmrg
1795d6c0b56eSmrg	output->possible_crtcs = 0xffffffff;
1796d6c0b56eSmrg	for (i = 0; i < koutput->count_encoders; i++) {
1797d6c0b56eSmrg		output->possible_crtcs &= kencoders[i]->possible_crtcs;
1798d6c0b56eSmrg	}
1799d6c0b56eSmrg	/* work out the possible clones later */
1800d6c0b56eSmrg	output->possible_clones = 0;
1801d6c0b56eSmrg
1802d6c0b56eSmrg	for (i = 0; i < koutput->count_props; i++) {
1803d6c0b56eSmrg		props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]);
1804d6c0b56eSmrg		if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
1805d6c0b56eSmrg			if (!strcmp(props->name, "DPMS")) {
1806d6c0b56eSmrg				drmmode_output->dpms_enum_id =
1807d6c0b56eSmrg				    koutput->props[i];
1808d6c0b56eSmrg				drmModeFreeProperty(props);
1809d6c0b56eSmrg				break;
1810d6c0b56eSmrg			}
1811d6c0b56eSmrg			drmModeFreeProperty(props);
1812d6c0b56eSmrg		}
1813d6c0b56eSmrg	}
1814d6c0b56eSmrg
1815d6c0b56eSmrg	if (dynamic) {
1816d6c0b56eSmrg		output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
1817d6c0b56eSmrg		drmmode_output_create_resources(output);
1818d6c0b56eSmrg	}
1819d6c0b56eSmrg
1820d6c0b56eSmrg	return 1;
1821d6c0b56eSmrgout_free_encoders:
1822d6c0b56eSmrg	if (kencoders) {
1823d6c0b56eSmrg		for (i = 0; i < koutput->count_encoders; i++)
1824d6c0b56eSmrg			drmModeFreeEncoder(kencoders[i]);
1825d6c0b56eSmrg		free(kencoders);
1826d6c0b56eSmrg	}
1827d6c0b56eSmrg	drmModeFreeConnector(koutput);
1828d6c0b56eSmrg	return 0;
1829d6c0b56eSmrg}
1830d6c0b56eSmrg
1831d6c0b56eSmrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
1832d6c0b56eSmrg{
1833d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output =
1834d6c0b56eSmrg	    output->driver_private, clone_drmout;
1835d6c0b56eSmrg	int i;
1836d6c0b56eSmrg	xf86OutputPtr clone_output;
1837d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1838d6c0b56eSmrg	int index_mask = 0;
1839d6c0b56eSmrg
1840d6c0b56eSmrg	if (drmmode_output->enc_clone_mask == 0)
1841d6c0b56eSmrg		return index_mask;
1842d6c0b56eSmrg
1843d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
1844d6c0b56eSmrg		clone_output = xf86_config->output[i];
1845d6c0b56eSmrg		clone_drmout = clone_output->driver_private;
1846d6c0b56eSmrg		if (output == clone_output)
1847d6c0b56eSmrg			continue;
1848d6c0b56eSmrg
1849d6c0b56eSmrg		if (clone_drmout->enc_mask == 0)
1850d6c0b56eSmrg			continue;
1851d6c0b56eSmrg		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
1852d6c0b56eSmrg			index_mask |= (1 << i);
1853d6c0b56eSmrg	}
1854d6c0b56eSmrg	return index_mask;
1855d6c0b56eSmrg}
1856d6c0b56eSmrg
1857d6c0b56eSmrgstatic void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
1858d6c0b56eSmrg{
1859d6c0b56eSmrg	int i, j;
1860d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1861d6c0b56eSmrg
1862d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
1863d6c0b56eSmrg		xf86OutputPtr output = xf86_config->output[i];
1864d6c0b56eSmrg		drmmode_output_private_ptr drmmode_output;
1865d6c0b56eSmrg
1866d6c0b56eSmrg		drmmode_output = output->driver_private;
1867d6c0b56eSmrg		drmmode_output->enc_clone_mask = 0xff;
1868d6c0b56eSmrg		/* and all the possible encoder clones for this output together */
1869d6c0b56eSmrg		for (j = 0; j < drmmode_output->mode_output->count_encoders;
1870d6c0b56eSmrg		     j++) {
1871d6c0b56eSmrg			int k;
1872d6c0b56eSmrg			for (k = 0; k < mode_res->count_encoders; k++) {
1873d6c0b56eSmrg				if (mode_res->encoders[k] ==
1874d6c0b56eSmrg				    drmmode_output->
1875d6c0b56eSmrg				    mode_encoders[j]->encoder_id)
1876d6c0b56eSmrg					drmmode_output->enc_mask |= (1 << k);
1877d6c0b56eSmrg			}
1878d6c0b56eSmrg
1879d6c0b56eSmrg			drmmode_output->enc_clone_mask &=
1880d6c0b56eSmrg			    drmmode_output->mode_encoders[j]->possible_clones;
1881d6c0b56eSmrg		}
1882d6c0b56eSmrg	}
1883d6c0b56eSmrg
1884d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
1885d6c0b56eSmrg		xf86OutputPtr output = xf86_config->output[i];
1886d6c0b56eSmrg		output->possible_clones = find_clones(scrn, output);
1887d6c0b56eSmrg	}
1888d6c0b56eSmrg}
1889d6c0b56eSmrg
1890d6c0b56eSmrg/* returns pitch alignment in pixels */
1891d6c0b56eSmrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe)
1892d6c0b56eSmrg{
1893d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
1894d6c0b56eSmrg
1895d6c0b56eSmrg	if (info->have_tiling_info)
1896d6c0b56eSmrg		/* linear aligned requirements */
1897d6c0b56eSmrg		return MAX(64, info->group_bytes / bpe);
1898d6c0b56eSmrg	else
1899d6c0b56eSmrg		/* default to 512 elements if we don't know the real
1900d6c0b56eSmrg		 * group size otherwise the kernel may reject the CS
1901d6c0b56eSmrg		 * if the group sizes don't match as the pitch won't
1902d6c0b56eSmrg		 * be aligned properly.
1903d6c0b56eSmrg		 */
1904d6c0b56eSmrg		return 512;
1905d6c0b56eSmrg}
1906d6c0b56eSmrg
1907d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
1908d6c0b56eSmrg{
1909d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1910d6c0b56eSmrg	drmmode_crtc_private_ptr
1911d6c0b56eSmrg	    drmmode_crtc = xf86_config->crtc[0]->driver_private;
1912d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1913d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
1914d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
1915d6c0b56eSmrg	struct amdgpu_buffer *old_front = NULL;
1916d6c0b56eSmrg	ScreenPtr screen = xf86ScrnToScreen(scrn);
1917d6c0b56eSmrg	uint32_t old_fb_id;
1918d6c0b56eSmrg	int i, pitch, old_width, old_height, old_pitch;
1919d6c0b56eSmrg	int cpp = info->pixel_bytes;
1920d6c0b56eSmrg	PixmapPtr ppix = screen->GetScreenPixmap(screen);
1921d6c0b56eSmrg	void *fb_shadow;
1922d6c0b56eSmrg	int hint = 0;
1923d6c0b56eSmrg	xRectangle rect;
1924d6c0b56eSmrg	GCPtr gc;
1925d6c0b56eSmrg
1926d6c0b56eSmrg	if (scrn->virtualX == width && scrn->virtualY == height)
1927d6c0b56eSmrg		return TRUE;
1928d6c0b56eSmrg
1929d6c0b56eSmrg	if (info->shadow_primary)
1930d6c0b56eSmrg		hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
1931d6c0b56eSmrg	else if (!info->use_glamor)
1932d6c0b56eSmrg		hint = AMDGPU_CREATE_PIXMAP_LINEAR;
1933d6c0b56eSmrg
1934d6c0b56eSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1935d6c0b56eSmrg		   "Allocate new frame buffer %dx%d\n", width, height);
1936d6c0b56eSmrg
1937d6c0b56eSmrg	old_width = scrn->virtualX;
1938d6c0b56eSmrg	old_height = scrn->virtualY;
1939d6c0b56eSmrg	old_pitch = scrn->displayWidth;
1940d6c0b56eSmrg	old_fb_id = drmmode->fb_id;
1941504d986fSmrg	drmmode->fb_id = 0;
1942d6c0b56eSmrg	old_front = info->front_buffer;
1943d6c0b56eSmrg
1944d6c0b56eSmrg	scrn->virtualX = width;
1945d6c0b56eSmrg	scrn->virtualY = height;
1946d6c0b56eSmrg
1947d6c0b56eSmrg	info->front_buffer =
1948d6c0b56eSmrg		amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY,
1949d6c0b56eSmrg				       scrn->depth, hint, scrn->bitsPerPixel,
1950d6c0b56eSmrg				       &pitch);
1951d6c0b56eSmrg	if (!info->front_buffer) {
1952d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1953d6c0b56eSmrg			   "Failed to allocate front buffer memory\n");
1954d6c0b56eSmrg		goto fail;
1955d6c0b56eSmrg	}
1956d6c0b56eSmrg
1957d6c0b56eSmrg	if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) {
1958d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1959d6c0b56eSmrg			   "Failed to map front buffer memory\n");
1960d6c0b56eSmrg		goto fail;
1961d6c0b56eSmrg	}
1962d6c0b56eSmrg
1963d6c0b56eSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch);
1964d6c0b56eSmrg	scrn->displayWidth = pitch / cpp;
1965d6c0b56eSmrg
1966d6c0b56eSmrg	if (info->use_glamor ||
1967d6c0b56eSmrg	    (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) {
1968d6c0b56eSmrg		screen->ModifyPixmapHeader(ppix,
1969d6c0b56eSmrg					   width, height, -1, -1, pitch, info->front_buffer->cpu_ptr);
1970d6c0b56eSmrg	} else {
1971d6c0b56eSmrg		fb_shadow = calloc(1, pitch * scrn->virtualY);
1972d6c0b56eSmrg		if (fb_shadow == NULL)
1973d6c0b56eSmrg			goto fail;
1974d6c0b56eSmrg		free(info->fb_shadow);
1975d6c0b56eSmrg		info->fb_shadow = fb_shadow;
1976d6c0b56eSmrg		screen->ModifyPixmapHeader(ppix,
1977d6c0b56eSmrg					   width, height, -1, -1, pitch,
1978d6c0b56eSmrg					   info->fb_shadow);
1979d6c0b56eSmrg	}
1980d6c0b56eSmrg
1981504d986fSmrg	if (!amdgpu_glamor_create_screen_resources(scrn->pScreen))
1982504d986fSmrg		goto fail;
1983504d986fSmrg
1984504d986fSmrg	if (info->use_glamor ||
1985504d986fSmrg	    (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) {
1986504d986fSmrg		if (!amdgpu_set_pixmap_bo(ppix, info->front_buffer))
1987504d986fSmrg			goto fail;
1988504d986fSmrg	}
1989d6c0b56eSmrg
1990d6c0b56eSmrg	/* Clear new buffer */
1991d6c0b56eSmrg	gc = GetScratchGC(ppix->drawable.depth, scrn->pScreen);
1992d6c0b56eSmrg	ValidateGC(&ppix->drawable, gc);
1993d6c0b56eSmrg	rect.x = 0;
1994d6c0b56eSmrg	rect.y = 0;
1995d6c0b56eSmrg	rect.width = width;
1996d6c0b56eSmrg	rect.height = height;
1997d6c0b56eSmrg	info->force_accel = TRUE;
1998d6c0b56eSmrg	(*gc->ops->PolyFillRect)(&ppix->drawable, gc, 1, &rect);
1999d6c0b56eSmrg	info->force_accel = FALSE;
2000d6c0b56eSmrg	FreeScratchGC(gc);
2001d6c0b56eSmrg	amdgpu_glamor_finish(scrn);
2002d6c0b56eSmrg
2003d6c0b56eSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
2004d6c0b56eSmrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
2005d6c0b56eSmrg
2006d6c0b56eSmrg		if (!crtc->enabled)
2007d6c0b56eSmrg			continue;
2008d6c0b56eSmrg
2009d6c0b56eSmrg		drmmode_set_mode_major(crtc, &crtc->mode,
2010d6c0b56eSmrg				       crtc->rotation, crtc->x, crtc->y);
2011d6c0b56eSmrg	}
2012d6c0b56eSmrg
2013d6c0b56eSmrg	if (old_fb_id)
2014d6c0b56eSmrg		drmModeRmFB(pAMDGPUEnt->fd, old_fb_id);
2015d6c0b56eSmrg	if (old_front) {
2016d6c0b56eSmrg		amdgpu_bo_unref(&old_front);
2017d6c0b56eSmrg	}
2018d6c0b56eSmrg
2019d6c0b56eSmrg	return TRUE;
2020d6c0b56eSmrg
2021d6c0b56eSmrgfail:
2022d6c0b56eSmrg	if (info->front_buffer) {
2023d6c0b56eSmrg		amdgpu_bo_unref(&info->front_buffer);
2024d6c0b56eSmrg	}
2025d6c0b56eSmrg	info->front_buffer = old_front;
2026d6c0b56eSmrg	scrn->virtualX = old_width;
2027d6c0b56eSmrg	scrn->virtualY = old_height;
2028d6c0b56eSmrg	scrn->displayWidth = old_pitch;
2029d6c0b56eSmrg	drmmode->fb_id = old_fb_id;
2030d6c0b56eSmrg
2031d6c0b56eSmrg	return FALSE;
2032d6c0b56eSmrg}
2033d6c0b56eSmrg
2034d6c0b56eSmrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
2035d6c0b56eSmrg	drmmode_xf86crtc_resize
2036d6c0b56eSmrg};
2037d6c0b56eSmrg
2038504d986fSmrgvoid
2039504d986fSmrgdrmmode_clear_pending_flip(xf86CrtcPtr crtc)
2040504d986fSmrg{
2041504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2042504d986fSmrg
2043504d986fSmrg	drmmode_crtc->flip_pending = FALSE;
2044504d986fSmrg
2045504d986fSmrg	if (!crtc->enabled ||
2046504d986fSmrg	    (drmmode_crtc->pending_dpms_mode != DPMSModeOn &&
2047504d986fSmrg	     drmmode_crtc->dpms_mode != drmmode_crtc->pending_dpms_mode)) {
2048504d986fSmrg		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
2049504d986fSmrg		int o;
2050504d986fSmrg
2051504d986fSmrg		for (o = 0; o < xf86_config->num_output; o++) {
2052504d986fSmrg			xf86OutputPtr output = xf86_config->output[o];
2053504d986fSmrg
2054504d986fSmrg			if (output->crtc != crtc)
2055504d986fSmrg				continue;
2056504d986fSmrg
2057504d986fSmrg			drmmode_output_dpms(output, drmmode_crtc->pending_dpms_mode);
2058504d986fSmrg		}
2059504d986fSmrg
2060504d986fSmrg		drmmode_crtc_dpms(crtc, drmmode_crtc->pending_dpms_mode);
2061504d986fSmrg	}
2062504d986fSmrg
2063504d986fSmrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
2064504d986fSmrg				     &drmmode_crtc->scanout_destroy[0]);
2065504d986fSmrg	drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
2066504d986fSmrg				     &drmmode_crtc->scanout_destroy[1]);
2067504d986fSmrg}
2068504d986fSmrg
2069d6c0b56eSmrgstatic void
2070d6c0b56eSmrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
2071d6c0b56eSmrg{
2072d6c0b56eSmrg	drmmode_flipdata_ptr flipdata = event_data;
2073d6c0b56eSmrg
2074d6c0b56eSmrg	if (--flipdata->flip_count == 0) {
2075504d986fSmrg		if (!flipdata->fe_crtc)
2076504d986fSmrg			flipdata->fe_crtc = crtc;
2077504d986fSmrg		flipdata->abort(flipdata->fe_crtc, flipdata->event_data);
2078d6c0b56eSmrg		free(flipdata);
2079d6c0b56eSmrg	}
2080d6c0b56eSmrg
2081504d986fSmrg	drmmode_clear_pending_flip(crtc);
2082d6c0b56eSmrg}
2083d6c0b56eSmrg
2084d6c0b56eSmrgstatic void
2085d6c0b56eSmrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
2086d6c0b56eSmrg{
2087d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
2088d6c0b56eSmrg	drmmode_flipdata_ptr flipdata = event_data;
2089d6c0b56eSmrg
2090d6c0b56eSmrg	/* Is this the event whose info shall be delivered to higher level? */
2091d6c0b56eSmrg	if (crtc == flipdata->fe_crtc) {
2092d6c0b56eSmrg		/* Yes: Cache msc, ust for later delivery. */
2093d6c0b56eSmrg		flipdata->fe_frame = frame;
2094d6c0b56eSmrg		flipdata->fe_usec = usec;
2095d6c0b56eSmrg	}
2096d6c0b56eSmrg
2097d6c0b56eSmrg	if (--flipdata->flip_count == 0) {
2098504d986fSmrg		/* Deliver MSC & UST from reference/current CRTC to flip event
2099504d986fSmrg		 * handler
2100504d986fSmrg		 */
2101d6c0b56eSmrg		if (flipdata->fe_crtc)
2102504d986fSmrg			flipdata->handler(flipdata->fe_crtc, flipdata->fe_frame,
2103504d986fSmrg					  flipdata->fe_usec, flipdata->event_data);
2104504d986fSmrg		else
2105504d986fSmrg			flipdata->handler(crtc, frame, usec, flipdata->event_data);
2106d6c0b56eSmrg
2107d6c0b56eSmrg		/* Release framebuffer */
2108d6c0b56eSmrg		drmModeRmFB(pAMDGPUEnt->fd, flipdata->old_fb_id);
2109d6c0b56eSmrg
2110d6c0b56eSmrg		free(flipdata);
2111d6c0b56eSmrg	}
2112d6c0b56eSmrg
2113504d986fSmrg	drmmode_clear_pending_flip(crtc);
2114d6c0b56eSmrg}
2115d6c0b56eSmrg
2116504d986fSmrg#if HAVE_NOTIFY_FD
2117504d986fSmrgstatic void drmmode_notify_fd(int fd, int notify, void *data)
2118504d986fSmrg{
2119504d986fSmrg	drmmode_ptr drmmode = data;
2120504d986fSmrg	drmHandleEvent(fd, &drmmode->event_context);
2121504d986fSmrg}
2122504d986fSmrg#else
2123d6c0b56eSmrgstatic void drm_wakeup_handler(pointer data, int err, pointer p)
2124d6c0b56eSmrg{
2125d6c0b56eSmrg	drmmode_ptr drmmode = data;
2126d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn);
2127d6c0b56eSmrg	fd_set *read_mask = p;
2128d6c0b56eSmrg
2129d6c0b56eSmrg	if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) {
2130d6c0b56eSmrg		drmHandleEvent(pAMDGPUEnt->fd, &drmmode->event_context);
2131d6c0b56eSmrg	}
2132d6c0b56eSmrg}
2133504d986fSmrg#endif
2134d6c0b56eSmrg
2135d6c0b56eSmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
2136d6c0b56eSmrg{
2137d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2138d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2139d6c0b56eSmrg	int i, num_dvi = 0, num_hdmi = 0;
2140d6c0b56eSmrg	unsigned int crtcs_needed = 0;
2141d6c0b56eSmrg	drmModeResPtr mode_res;
2142d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
2143d6c0b56eSmrg	char *bus_id_string, *provider_name;
2144d6c0b56eSmrg#endif
2145d6c0b56eSmrg
2146d6c0b56eSmrg	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
2147d6c0b56eSmrg
2148d6c0b56eSmrg	drmmode->scrn = pScrn;
2149d6c0b56eSmrg	drmmode->cpp = cpp;
2150d6c0b56eSmrg	mode_res = drmModeGetResources(pAMDGPUEnt->fd);
2151d6c0b56eSmrg	if (!mode_res)
2152d6c0b56eSmrg		return FALSE;
2153d6c0b56eSmrg
2154d6c0b56eSmrg	drmmode->count_crtcs = mode_res->count_crtcs;
2155d6c0b56eSmrg	xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
2156d6c0b56eSmrg			     mode_res->max_height);
2157d6c0b56eSmrg
2158d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2159d6c0b56eSmrg		       "Initializing outputs ...\n");
2160d6c0b56eSmrg	for (i = 0; i < mode_res->count_connectors; i++)
2161d6c0b56eSmrg		crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0);
2162d6c0b56eSmrg
2163d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2164d6c0b56eSmrg		       "%d crtcs needed for screen.\n", crtcs_needed);
2165d6c0b56eSmrg
2166d6c0b56eSmrg	if (!info->use_glamor) {
2167d6c0b56eSmrg		/* Rotation requires hardware acceleration */
2168d6c0b56eSmrg		drmmode_crtc_funcs.shadow_allocate = NULL;
2169d6c0b56eSmrg		drmmode_crtc_funcs.shadow_create = NULL;
2170d6c0b56eSmrg		drmmode_crtc_funcs.shadow_destroy = NULL;
2171d6c0b56eSmrg	}
2172d6c0b56eSmrg
2173d6c0b56eSmrg	for (i = 0; i < mode_res->count_crtcs; i++)
2174d6c0b56eSmrg		if (!xf86IsEntityShared(pScrn->entityList[0]) ||
2175d6c0b56eSmrg		    (crtcs_needed && !(pAMDGPUEnt->assigned_crtcs & (1 << i))))
2176d6c0b56eSmrg			crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
2177d6c0b56eSmrg
2178d6c0b56eSmrg	/* All ZaphodHeads outputs provided with matching crtcs? */
2179d6c0b56eSmrg	if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
2180d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2181d6c0b56eSmrg			   "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
2182d6c0b56eSmrg			   crtcs_needed);
2183d6c0b56eSmrg
2184d6c0b56eSmrg	/* workout clones */
2185d6c0b56eSmrg	drmmode_clones_init(pScrn, drmmode, mode_res);
2186d6c0b56eSmrg
2187d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
2188d6c0b56eSmrg	bus_id_string = DRICreatePCIBusID(info->PciInfo);
2189d6c0b56eSmrg	XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string);
2190d6c0b56eSmrg	free(bus_id_string);
2191d6c0b56eSmrg	xf86ProviderSetup(pScrn, NULL, provider_name);
2192d6c0b56eSmrg	free(provider_name);
2193d6c0b56eSmrg#endif
2194d6c0b56eSmrg
2195d6c0b56eSmrg	xf86InitialConfiguration(pScrn, TRUE);
2196d6c0b56eSmrg
2197d6c0b56eSmrg	drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
2198d6c0b56eSmrg	drmmode->event_context.vblank_handler = amdgpu_drm_queue_handler;
2199d6c0b56eSmrg	drmmode->event_context.page_flip_handler = amdgpu_drm_queue_handler;
2200d6c0b56eSmrg
2201d6c0b56eSmrg	drmModeFreeResources(mode_res);
2202d6c0b56eSmrg	return TRUE;
2203d6c0b56eSmrg}
2204d6c0b56eSmrg
2205d6c0b56eSmrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
2206d6c0b56eSmrg{
2207d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2208d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2209d6c0b56eSmrg
2210d6c0b56eSmrg	info->drmmode_inited = TRUE;
2211d6c0b56eSmrg	if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) {
2212504d986fSmrg#if HAVE_NOTIFY_FD
2213504d986fSmrg		SetNotifyFd(pAMDGPUEnt->fd, drmmode_notify_fd, X_NOTIFY_READ, drmmode);
2214504d986fSmrg#else
2215d6c0b56eSmrg		AddGeneralSocket(pAMDGPUEnt->fd);
2216d6c0b56eSmrg		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA,
2217d6c0b56eSmrg					       drm_wakeup_handler, drmmode);
2218504d986fSmrg#endif
2219d6c0b56eSmrg		pAMDGPUEnt->fd_wakeup_registered = serverGeneration;
2220d6c0b56eSmrg		pAMDGPUEnt->fd_wakeup_ref = 1;
2221d6c0b56eSmrg	} else
2222d6c0b56eSmrg		pAMDGPUEnt->fd_wakeup_ref++;
2223d6c0b56eSmrg}
2224d6c0b56eSmrg
2225d6c0b56eSmrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
2226d6c0b56eSmrg{
2227504d986fSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2228d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2229d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2230504d986fSmrg	int c;
2231d6c0b56eSmrg
2232d6c0b56eSmrg	if (!info->drmmode_inited)
2233d6c0b56eSmrg		return;
2234d6c0b56eSmrg
2235d6c0b56eSmrg	if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration &&
2236d6c0b56eSmrg	    !--pAMDGPUEnt->fd_wakeup_ref) {
2237504d986fSmrg#if HAVE_NOTIFY_FD
2238504d986fSmrg		RemoveNotifyFd(pAMDGPUEnt->fd);
2239504d986fSmrg#else
2240d6c0b56eSmrg		RemoveGeneralSocket(pAMDGPUEnt->fd);
2241d6c0b56eSmrg		RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA,
2242d6c0b56eSmrg					     drm_wakeup_handler, drmmode);
2243504d986fSmrg#endif
2244504d986fSmrg	}
2245504d986fSmrg
2246504d986fSmrg	for (c = 0; c < config->num_crtc; c++) {
2247504d986fSmrg		xf86CrtcPtr crtc = config->crtc[c];
2248504d986fSmrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2249504d986fSmrg
2250504d986fSmrg		drmmode_crtc_scanout_destroy(&info->drmmode, &drmmode_crtc->scanout[0]);
2251504d986fSmrg		drmmode_crtc_scanout_destroy(&info->drmmode, &drmmode_crtc->scanout[1]);
2252d6c0b56eSmrg	}
2253d6c0b56eSmrg}
2254d6c0b56eSmrg
2255d6c0b56eSmrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id,
2256d6c0b56eSmrg			struct amdgpu_buffer *bo)
2257d6c0b56eSmrg{
2258d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2259d6c0b56eSmrg	xf86CrtcPtr crtc = xf86_config->crtc[id];
2260d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2261d6c0b56eSmrg
2262d6c0b56eSmrg	drmmode_crtc->cursor_buffer = bo;
2263d6c0b56eSmrg}
2264d6c0b56eSmrg
2265d6c0b56eSmrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
2266d6c0b56eSmrg{
2267d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2268d6c0b56eSmrg	xf86OutputPtr output = config->output[config->compat_output];
2269d6c0b56eSmrg	xf86CrtcPtr crtc = output->crtc;
2270d6c0b56eSmrg
2271d6c0b56eSmrg	if (crtc && crtc->enabled) {
2272d6c0b56eSmrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
2273d6c0b56eSmrg	}
2274d6c0b56eSmrg}
2275d6c0b56eSmrg
2276d6c0b56eSmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
2277d6c0b56eSmrg			       Bool set_hw)
2278d6c0b56eSmrg{
2279d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2280d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2281d6c0b56eSmrg	int c;
2282d6c0b56eSmrg
2283d6c0b56eSmrg	for (c = 0; c < config->num_crtc; c++) {
2284d6c0b56eSmrg		xf86CrtcPtr crtc = config->crtc[c];
2285d6c0b56eSmrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2286d6c0b56eSmrg		xf86OutputPtr output = NULL;
2287d6c0b56eSmrg		int o;
2288d6c0b56eSmrg
2289d6c0b56eSmrg		/* Skip disabled CRTCs */
2290d6c0b56eSmrg		if (!crtc->enabled) {
2291d6c0b56eSmrg			if (set_hw) {
2292d6c0b56eSmrg				drmmode_do_crtc_dpms(crtc, DPMSModeOff);
2293d6c0b56eSmrg				drmModeSetCrtc(pAMDGPUEnt->fd,
2294d6c0b56eSmrg					       drmmode_crtc->mode_crtc->crtc_id,
2295d6c0b56eSmrg					       0, 0, 0, NULL, 0, NULL);
2296d6c0b56eSmrg			}
2297d6c0b56eSmrg			continue;
2298d6c0b56eSmrg		}
2299d6c0b56eSmrg
2300d6c0b56eSmrg		if (config->output[config->compat_output]->crtc == crtc)
2301d6c0b56eSmrg			output = config->output[config->compat_output];
2302d6c0b56eSmrg		else {
2303d6c0b56eSmrg			for (o = 0; o < config->num_output; o++)
2304d6c0b56eSmrg				if (config->output[o]->crtc == crtc) {
2305d6c0b56eSmrg					output = config->output[o];
2306d6c0b56eSmrg					break;
2307d6c0b56eSmrg				}
2308d6c0b56eSmrg		}
2309d6c0b56eSmrg		/* paranoia */
2310d6c0b56eSmrg		if (!output)
2311d6c0b56eSmrg			continue;
2312d6c0b56eSmrg
2313d6c0b56eSmrg		/* Mark that we'll need to re-set the mode for sure */
2314d6c0b56eSmrg		memset(&crtc->mode, 0, sizeof(crtc->mode));
2315d6c0b56eSmrg		if (!crtc->desiredMode.CrtcHDisplay) {
2316d6c0b56eSmrg			DisplayModePtr mode = xf86OutputFindClosestMode(output,
2317d6c0b56eSmrg									pScrn->
2318d6c0b56eSmrg									currentMode);
2319d6c0b56eSmrg
2320d6c0b56eSmrg			if (!mode)
2321d6c0b56eSmrg				return FALSE;
2322d6c0b56eSmrg			crtc->desiredMode = *mode;
2323d6c0b56eSmrg			crtc->desiredRotation = RR_Rotate_0;
2324d6c0b56eSmrg			crtc->desiredX = 0;
2325d6c0b56eSmrg			crtc->desiredY = 0;
2326d6c0b56eSmrg		}
2327d6c0b56eSmrg
2328d6c0b56eSmrg		if (set_hw) {
2329d6c0b56eSmrg			if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode,
2330d6c0b56eSmrg							 crtc->desiredRotation,
2331d6c0b56eSmrg							 crtc->desiredX,
2332d6c0b56eSmrg							 crtc->desiredY))
2333d6c0b56eSmrg				return FALSE;
2334d6c0b56eSmrg		} else {
2335d6c0b56eSmrg			crtc->mode = crtc->desiredMode;
2336d6c0b56eSmrg			crtc->rotation = crtc->desiredRotation;
2337d6c0b56eSmrg			crtc->x = crtc->desiredX;
2338d6c0b56eSmrg			crtc->y = crtc->desiredY;
2339d6c0b56eSmrg			if (!drmmode_handle_transform(crtc))
2340d6c0b56eSmrg				return FALSE;
2341d6c0b56eSmrg		}
2342d6c0b56eSmrg	}
2343d6c0b56eSmrg	return TRUE;
2344d6c0b56eSmrg}
2345d6c0b56eSmrg
2346d6c0b56eSmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
2347d6c0b56eSmrg{
2348d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2349d6c0b56eSmrg
2350d6c0b56eSmrg	if (xf86_config->num_crtc) {
2351d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2352d6c0b56eSmrg			       "Initializing kms color map\n");
2353d6c0b56eSmrg		if (!miCreateDefColormap(pScreen))
2354d6c0b56eSmrg			return FALSE;
2355d6c0b56eSmrg		/* all amdgpus support 10 bit CLUTs */
2356d6c0b56eSmrg		if (!xf86HandleColormaps(pScreen, 256, 10,
2357504d986fSmrg					 NULL, NULL,
2358d6c0b56eSmrg					 CMAP_PALETTED_TRUECOLOR
2359d6c0b56eSmrg#if 0				/* This option messes up text mode! (eich@suse.de) */
2360d6c0b56eSmrg					 | CMAP_LOAD_EVEN_IF_OFFSCREEN
2361d6c0b56eSmrg#endif
2362d6c0b56eSmrg					 | CMAP_RELOAD_ON_MODE_SWITCH))
2363d6c0b56eSmrg			return FALSE;
2364d6c0b56eSmrg	}
2365d6c0b56eSmrg	return TRUE;
2366d6c0b56eSmrg}
2367d6c0b56eSmrg
2368504d986fSmrgstatic Bool
2369504d986fSmrgdrmmode_find_output(ScrnInfoPtr scrn, int output_id, int *num_dvi,
2370504d986fSmrg		    int *num_hdmi)
2371504d986fSmrg{
2372504d986fSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2373504d986fSmrg	int i;
2374504d986fSmrg
2375504d986fSmrg	for (i = 0; i < config->num_output; i++) {
2376504d986fSmrg		xf86OutputPtr output = config->output[i];
2377504d986fSmrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
2378504d986fSmrg
2379504d986fSmrg		if (drmmode_output->output_id == output_id) {
2380504d986fSmrg			switch(drmmode_output->mode_output->connector_type) {
2381504d986fSmrg			case DRM_MODE_CONNECTOR_DVII:
2382504d986fSmrg			case DRM_MODE_CONNECTOR_DVID:
2383504d986fSmrg			case DRM_MODE_CONNECTOR_DVIA:
2384504d986fSmrg				(*num_dvi)++;
2385504d986fSmrg				break;
2386504d986fSmrg			case DRM_MODE_CONNECTOR_HDMIA:
2387504d986fSmrg			case DRM_MODE_CONNECTOR_HDMIB:
2388504d986fSmrg				(*num_hdmi)++;
2389504d986fSmrg				break;
2390504d986fSmrg			}
2391504d986fSmrg
2392504d986fSmrg			return TRUE;
2393504d986fSmrg		}
2394504d986fSmrg	}
2395504d986fSmrg
2396504d986fSmrg	return FALSE;
2397504d986fSmrg}
2398d6c0b56eSmrg
2399d6c0b56eSmrgvoid
2400d6c0b56eSmrgamdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2401d6c0b56eSmrg{
2402d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2403d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
2404d6c0b56eSmrg	drmModeResPtr mode_res;
2405d6c0b56eSmrg	int i, j;
2406d6c0b56eSmrg	Bool found;
2407d6c0b56eSmrg	Bool changed = FALSE;
2408504d986fSmrg	int num_dvi = 0, num_hdmi = 0;
2409d6c0b56eSmrg
2410d6c0b56eSmrg	mode_res = drmModeGetResources(pAMDGPUEnt->fd);
2411d6c0b56eSmrg	if (!mode_res)
2412d6c0b56eSmrg		goto out;
2413d6c0b56eSmrg
2414d6c0b56eSmrgrestart_destroy:
2415d6c0b56eSmrg	for (i = 0; i < config->num_output; i++) {
2416d6c0b56eSmrg		xf86OutputPtr output = config->output[i];
2417d6c0b56eSmrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
2418d6c0b56eSmrg		found = FALSE;
2419d6c0b56eSmrg		for (j = 0; j < mode_res->count_connectors; j++) {
2420d6c0b56eSmrg			if (mode_res->connectors[j] == drmmode_output->output_id) {
2421d6c0b56eSmrg				found = TRUE;
2422d6c0b56eSmrg				break;
2423d6c0b56eSmrg			}
2424d6c0b56eSmrg		}
2425d6c0b56eSmrg		if (found)
2426d6c0b56eSmrg			continue;
2427d6c0b56eSmrg
2428d6c0b56eSmrg		drmModeFreeConnector(drmmode_output->mode_output);
2429d6c0b56eSmrg		drmmode_output->mode_output = NULL;
2430d6c0b56eSmrg		drmmode_output->output_id = -1;
2431d6c0b56eSmrg
2432d6c0b56eSmrg		changed = TRUE;
2433d6c0b56eSmrg		if (drmmode->delete_dp_12_displays) {
2434d6c0b56eSmrg			RROutputDestroy(output->randr_output);
2435d6c0b56eSmrg			xf86OutputDestroy(output);
2436d6c0b56eSmrg			goto restart_destroy;
2437d6c0b56eSmrg		}
2438d6c0b56eSmrg	}
2439d6c0b56eSmrg
2440d6c0b56eSmrg	/* find new output ids we don't have outputs for */
2441d6c0b56eSmrg	for (i = 0; i < mode_res->count_connectors; i++) {
2442504d986fSmrg		if (drmmode_find_output(pAMDGPUEnt->primary_scrn,
2443504d986fSmrg					mode_res->connectors[i],
2444504d986fSmrg					&num_dvi, &num_hdmi) ||
2445504d986fSmrg		    (pAMDGPUEnt->secondary_scrn &&
2446504d986fSmrg		     drmmode_find_output(pAMDGPUEnt->secondary_scrn,
2447504d986fSmrg					 mode_res->connectors[i],
2448504d986fSmrg					 &num_dvi, &num_hdmi)))
2449d6c0b56eSmrg			continue;
2450d6c0b56eSmrg
2451504d986fSmrg		if (drmmode_output_init(scrn, drmmode, mode_res, i, &num_dvi,
2452504d986fSmrg					&num_hdmi, 1) != 0)
2453504d986fSmrg			changed = TRUE;
2454d6c0b56eSmrg	}
2455d6c0b56eSmrg
2456504d986fSmrg	if (changed && dixPrivateKeyRegistered(rrPrivKey)) {
2457d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0)
2458d6c0b56eSmrg		RRSetChanged(xf86ScrnToScreen(scrn));
2459d6c0b56eSmrg#else
2460d6c0b56eSmrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen);
2461d6c0b56eSmrg		rrScrPriv->changed = TRUE;
2462d6c0b56eSmrg#endif
2463d6c0b56eSmrg		RRTellChanged(xf86ScrnToScreen(scrn));
2464d6c0b56eSmrg	}
2465d6c0b56eSmrg
2466d6c0b56eSmrg	drmModeFreeResources(mode_res);
2467d6c0b56eSmrgout:
2468d6c0b56eSmrg	RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
2469d6c0b56eSmrg}
2470d6c0b56eSmrg
2471d6c0b56eSmrg#ifdef HAVE_LIBUDEV
2472d6c0b56eSmrgstatic void drmmode_handle_uevents(int fd, void *closure)
2473d6c0b56eSmrg{
2474d6c0b56eSmrg	drmmode_ptr drmmode = closure;
2475d6c0b56eSmrg	ScrnInfoPtr scrn = drmmode->scrn;
2476d6c0b56eSmrg	struct udev_device *dev;
2477504d986fSmrg	Bool received = FALSE;
2478d6c0b56eSmrg
2479504d986fSmrg	while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) {
2480504d986fSmrg		udev_device_unref(dev);
2481504d986fSmrg		received = TRUE;
2482504d986fSmrg	}
2483504d986fSmrg
2484504d986fSmrg	if (received)
2485504d986fSmrg		amdgpu_mode_hotplug(scrn, drmmode);
2486d6c0b56eSmrg}
2487d6c0b56eSmrg#endif
2488d6c0b56eSmrg
2489d6c0b56eSmrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2490d6c0b56eSmrg{
2491d6c0b56eSmrg#ifdef HAVE_LIBUDEV
2492d6c0b56eSmrg	struct udev *u;
2493d6c0b56eSmrg	struct udev_monitor *mon;
2494d6c0b56eSmrg
2495d6c0b56eSmrg	u = udev_new();
2496d6c0b56eSmrg	if (!u)
2497d6c0b56eSmrg		return;
2498d6c0b56eSmrg	mon = udev_monitor_new_from_netlink(u, "udev");
2499d6c0b56eSmrg	if (!mon) {
2500d6c0b56eSmrg		udev_unref(u);
2501d6c0b56eSmrg		return;
2502d6c0b56eSmrg	}
2503d6c0b56eSmrg
2504d6c0b56eSmrg	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
2505d6c0b56eSmrg							    "drm",
2506d6c0b56eSmrg							    "drm_minor") < 0 ||
2507d6c0b56eSmrg	    udev_monitor_enable_receiving(mon) < 0) {
2508d6c0b56eSmrg		udev_monitor_unref(mon);
2509d6c0b56eSmrg		udev_unref(u);
2510d6c0b56eSmrg		return;
2511d6c0b56eSmrg	}
2512d6c0b56eSmrg
2513d6c0b56eSmrg	drmmode->uevent_handler =
2514d6c0b56eSmrg	    xf86AddGeneralHandler(udev_monitor_get_fd(mon),
2515d6c0b56eSmrg				  drmmode_handle_uevents, drmmode);
2516d6c0b56eSmrg
2517d6c0b56eSmrg	drmmode->uevent_monitor = mon;
2518d6c0b56eSmrg#endif
2519d6c0b56eSmrg}
2520d6c0b56eSmrg
2521d6c0b56eSmrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2522d6c0b56eSmrg{
2523d6c0b56eSmrg#ifdef HAVE_LIBUDEV
2524d6c0b56eSmrg	if (drmmode->uevent_handler) {
2525d6c0b56eSmrg		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
2526d6c0b56eSmrg		xf86RemoveGeneralHandler(drmmode->uevent_handler);
2527d6c0b56eSmrg
2528d6c0b56eSmrg		udev_monitor_unref(drmmode->uevent_monitor);
2529d6c0b56eSmrg		udev_unref(u);
2530d6c0b56eSmrg	}
2531d6c0b56eSmrg#endif
2532d6c0b56eSmrg}
2533d6c0b56eSmrg
2534d6c0b56eSmrgBool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
2535d6c0b56eSmrg			PixmapPtr new_front, uint64_t id, void *data,
2536d6c0b56eSmrg			int ref_crtc_hw_id, amdgpu_drm_handler_proc handler,
2537504d986fSmrg			amdgpu_drm_abort_proc abort,
2538504d986fSmrg			enum drmmode_flip_sync flip_sync)
2539d6c0b56eSmrg{
2540d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
2541d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2542d6c0b56eSmrg	xf86CrtcPtr crtc = NULL;
2543d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
2544d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
2545d6c0b56eSmrg	int i;
2546504d986fSmrg	uint32_t flip_flags = DRM_MODE_PAGE_FLIP_EVENT;
2547d6c0b56eSmrg	drmmode_flipdata_ptr flipdata;
2548d6c0b56eSmrg	uintptr_t drm_queue_seq = 0;
2549d6c0b56eSmrg	uint32_t new_front_handle;
2550d6c0b56eSmrg
2551d6c0b56eSmrg	if (!amdgpu_pixmap_get_handle(new_front, &new_front_handle)) {
2552d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2553d6c0b56eSmrg			   "flip queue: data alloc failed.\n");
2554d6c0b56eSmrg		return FALSE;
2555d6c0b56eSmrg	}
2556d6c0b56eSmrg
2557d6c0b56eSmrg	flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
2558d6c0b56eSmrg	if (!flipdata) {
2559d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2560d6c0b56eSmrg			   "flip queue: data alloc failed.\n");
2561d6c0b56eSmrg		goto error;
2562d6c0b56eSmrg	}
2563d6c0b56eSmrg
2564d6c0b56eSmrg	/*
2565d6c0b56eSmrg	 * Create a new handle for the back buffer
2566d6c0b56eSmrg	 */
2567d6c0b56eSmrg	flipdata->old_fb_id = drmmode->fb_id;
2568d6c0b56eSmrg	if (drmModeAddFB(pAMDGPUEnt->fd, new_front->drawable.width,
2569d6c0b56eSmrg			 new_front->drawable.height, scrn->depth,
2570d6c0b56eSmrg			 scrn->bitsPerPixel, new_front->devKind,
2571d6c0b56eSmrg			 new_front_handle, &drmmode->fb_id))
2572d6c0b56eSmrg		goto error;
2573d6c0b56eSmrg
2574d6c0b56eSmrg	/*
2575d6c0b56eSmrg	 * Queue flips on all enabled CRTCs
2576d6c0b56eSmrg	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
2577d6c0b56eSmrg	 * Right now it assumes a single shared fb across all CRTCs, with the
2578d6c0b56eSmrg	 * kernel fixing up the offset of each CRTC as necessary.
2579d6c0b56eSmrg	 *
2580d6c0b56eSmrg	 * Also, flips queued on disabled or incorrectly configured displays
2581d6c0b56eSmrg	 * may never complete; this is a configuration error.
2582d6c0b56eSmrg	 */
2583d6c0b56eSmrg
2584d6c0b56eSmrg	flipdata->event_data = data;
2585d6c0b56eSmrg	flipdata->handler = handler;
2586d6c0b56eSmrg	flipdata->abort = abort;
2587d6c0b56eSmrg
2588504d986fSmrg	if (flip_sync == FLIP_ASYNC)
2589504d986fSmrg		flip_flags |= DRM_MODE_PAGE_FLIP_ASYNC;
2590504d986fSmrg
2591d6c0b56eSmrg	for (i = 0; i < config->num_crtc; i++) {
2592d6c0b56eSmrg		crtc = config->crtc[i];
2593d6c0b56eSmrg
2594d6c0b56eSmrg		if (!crtc->enabled)
2595d6c0b56eSmrg			continue;
2596d6c0b56eSmrg
2597d6c0b56eSmrg		flipdata->flip_count++;
2598d6c0b56eSmrg		drmmode_crtc = crtc->driver_private;
2599d6c0b56eSmrg
2600d6c0b56eSmrg		/* Only the reference crtc will finally deliver its page flip
2601d6c0b56eSmrg		 * completion event. All other crtc's events will be discarded.
2602d6c0b56eSmrg		 */
2603d6c0b56eSmrg		if (drmmode_crtc->hw_id == ref_crtc_hw_id)
2604d6c0b56eSmrg			flipdata->fe_crtc = crtc;
2605d6c0b56eSmrg
2606d6c0b56eSmrg		drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id,
2607d6c0b56eSmrg						       flipdata,
2608d6c0b56eSmrg						       drmmode_flip_handler,
2609d6c0b56eSmrg						       drmmode_flip_abort);
2610504d986fSmrg		if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
2611d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2612d6c0b56eSmrg				   "Allocating DRM queue event entry failed.\n");
2613d6c0b56eSmrg			goto error;
2614d6c0b56eSmrg		}
2615d6c0b56eSmrg
2616d6c0b56eSmrg		if (drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
2617504d986fSmrg				    drmmode->fb_id, flip_flags,
2618d6c0b56eSmrg				    (void*)drm_queue_seq)) {
2619d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2620d6c0b56eSmrg				   "flip queue failed: %s\n", strerror(errno));
2621d6c0b56eSmrg			goto error;
2622d6c0b56eSmrg		}
2623d6c0b56eSmrg		drmmode_crtc->flip_pending = TRUE;
2624d6c0b56eSmrg		drm_queue_seq = 0;
2625d6c0b56eSmrg	}
2626d6c0b56eSmrg
2627d6c0b56eSmrg	if (flipdata->flip_count > 0)
2628d6c0b56eSmrg		return TRUE;
2629d6c0b56eSmrg
2630d6c0b56eSmrgerror:
2631d6c0b56eSmrg	if (flipdata && flipdata->flip_count <= 1) {
2632d6c0b56eSmrg		drmModeRmFB(pAMDGPUEnt->fd, drmmode->fb_id);
2633d6c0b56eSmrg		drmmode->fb_id = flipdata->old_fb_id;
2634d6c0b56eSmrg	}
2635d6c0b56eSmrg
2636d6c0b56eSmrg	if (drm_queue_seq)
2637d6c0b56eSmrg		amdgpu_drm_abort_entry(drm_queue_seq);
2638d6c0b56eSmrg	else if (crtc)
2639d6c0b56eSmrg		drmmode_flip_abort(crtc, flipdata);
2640d6c0b56eSmrg	else if (flipdata && flipdata->flip_count <= 1)
2641d6c0b56eSmrg		free(flipdata);
2642d6c0b56eSmrg
2643d6c0b56eSmrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
2644d6c0b56eSmrg		   strerror(errno));
2645d6c0b56eSmrg	return FALSE;
2646d6c0b56eSmrg}
2647