drmmode_display.c revision d6c0b56e
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"
39d6c0b56eSmrg#include "sarea.h"
40d6c0b56eSmrg
41d6c0b56eSmrg#include "drmmode_display.h"
42d6c0b56eSmrg#include "amdgpu_bo_helper.h"
43d6c0b56eSmrg#include "amdgpu_glamor.h"
44d6c0b56eSmrg#include "amdgpu_list.h"
45d6c0b56eSmrg#include "amdgpu_pixmap.h"
46d6c0b56eSmrg
47d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
48d6c0b56eSmrg#include <dri.h>
49d6c0b56eSmrg#endif
50d6c0b56eSmrg
51d6c0b56eSmrg/* DPMS */
52d6c0b56eSmrg#ifdef HAVE_XEXTPROTO_71
53d6c0b56eSmrg#include <X11/extensions/dpmsconst.h>
54d6c0b56eSmrg#else
55d6c0b56eSmrg#define DPMS_SERVER
56d6c0b56eSmrg#include <X11/extensions/dpms.h>
57d6c0b56eSmrg#endif
58d6c0b56eSmrg
59d6c0b56eSmrg#include <gbm.h>
60d6c0b56eSmrg
61d6c0b56eSmrg#define DEFAULT_NOMINAL_FRAME_RATE 60
62d6c0b56eSmrg
63d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
64d6c0b56eSmrg
65d6c0b56eSmrgstatic Bool
66d6c0b56eSmrgAMDGPUZaphodStringMatches(ScrnInfoPtr pScrn, const char *s, char *output_name)
67d6c0b56eSmrg{
68d6c0b56eSmrg	int i = 0;
69d6c0b56eSmrg	char s1[20];
70d6c0b56eSmrg
71d6c0b56eSmrg	do {
72d6c0b56eSmrg		switch (*s) {
73d6c0b56eSmrg		case ',':
74d6c0b56eSmrg			s1[i] = '\0';
75d6c0b56eSmrg			i = 0;
76d6c0b56eSmrg			if (strcmp(s1, output_name) == 0)
77d6c0b56eSmrg				return TRUE;
78d6c0b56eSmrg			break;
79d6c0b56eSmrg		case ' ':
80d6c0b56eSmrg		case '\t':
81d6c0b56eSmrg		case '\n':
82d6c0b56eSmrg		case '\r':
83d6c0b56eSmrg			break;
84d6c0b56eSmrg		default:
85d6c0b56eSmrg			s1[i] = *s;
86d6c0b56eSmrg			i++;
87d6c0b56eSmrg			break;
88d6c0b56eSmrg		}
89d6c0b56eSmrg	} while (*s++);
90d6c0b56eSmrg
91d6c0b56eSmrg	s1[i] = '\0';
92d6c0b56eSmrg	if (strcmp(s1, output_name) == 0)
93d6c0b56eSmrg		return TRUE;
94d6c0b56eSmrg
95d6c0b56eSmrg	return FALSE;
96d6c0b56eSmrg}
97d6c0b56eSmrg
98d6c0b56eSmrgstatic PixmapPtr drmmode_create_bo_pixmap(ScrnInfoPtr pScrn,
99d6c0b56eSmrg					  int width, int height,
100d6c0b56eSmrg					  int depth, int bpp,
101d6c0b56eSmrg					  int pitch,
102d6c0b56eSmrg					  struct amdgpu_buffer *bo)
103d6c0b56eSmrg{
104d6c0b56eSmrg	ScreenPtr pScreen = pScrn->pScreen;
105d6c0b56eSmrg	PixmapPtr pixmap;
106d6c0b56eSmrg
107d6c0b56eSmrg	pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth,
108d6c0b56eSmrg					  AMDGPU_CREATE_PIXMAP_SCANOUT);
109d6c0b56eSmrg	if (!pixmap)
110d6c0b56eSmrg		return NULL;
111d6c0b56eSmrg
112d6c0b56eSmrg	if (!(*pScreen->ModifyPixmapHeader) (pixmap, width, height,
113d6c0b56eSmrg					     depth, bpp, pitch, NULL)) {
114d6c0b56eSmrg		return NULL;
115d6c0b56eSmrg	}
116d6c0b56eSmrg
117d6c0b56eSmrg	amdgpu_set_pixmap_bo(pixmap, bo);
118d6c0b56eSmrg
119d6c0b56eSmrg	if (!amdgpu_glamor_create_textured_pixmap(pixmap,
120d6c0b56eSmrg						  amdgpu_get_pixmap_private(pixmap))) {
121d6c0b56eSmrg		pScreen->DestroyPixmap(pixmap);
122d6c0b56eSmrg		return NULL;
123d6c0b56eSmrg	}
124d6c0b56eSmrg
125d6c0b56eSmrg	return pixmap;
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
252d6c0b56eSmrg	if (drmmode_crtc->dpms_mode == DPMSModeOn && mode != DPMSModeOn) {
253d6c0b56eSmrg		drmVBlank vbl;
254d6c0b56eSmrg
255d6c0b56eSmrg		/*
256d6c0b56eSmrg		 * On->Off transition: record the last vblank time,
257d6c0b56eSmrg		 * sequence number and frame period.
258d6c0b56eSmrg		 */
259d6c0b56eSmrg		vbl.request.type = DRM_VBLANK_RELATIVE;
260d6c0b56eSmrg		vbl.request.type |= amdgpu_populate_vbl_request_type(crtc);
261d6c0b56eSmrg		vbl.request.sequence = 0;
262d6c0b56eSmrg		ret = drmWaitVBlank(pAMDGPUEnt->fd, &vbl);
263d6c0b56eSmrg		if (ret)
264d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
265d6c0b56eSmrg				   "%s cannot get last vblank counter\n",
266d6c0b56eSmrg				   __func__);
267d6c0b56eSmrg		else {
268d6c0b56eSmrg			CARD64 seq = (CARD64) vbl.reply.sequence;
269d6c0b56eSmrg			CARD64 nominal_frame_rate, pix_in_frame;
270d6c0b56eSmrg
271d6c0b56eSmrg			ust = ((CARD64) vbl.reply.tval_sec * 1000000) +
272d6c0b56eSmrg			    vbl.reply.tval_usec;
273d6c0b56eSmrg			drmmode_crtc->dpms_last_ust = ust;
274d6c0b56eSmrg			drmmode_crtc->dpms_last_seq = seq;
275d6c0b56eSmrg			nominal_frame_rate = crtc->mode.Clock;
276d6c0b56eSmrg			nominal_frame_rate *= 1000;
277d6c0b56eSmrg			pix_in_frame = crtc->mode.HTotal * crtc->mode.VTotal;
278d6c0b56eSmrg			if (nominal_frame_rate == 0 || pix_in_frame == 0)
279d6c0b56eSmrg				nominal_frame_rate = DEFAULT_NOMINAL_FRAME_RATE;
280d6c0b56eSmrg			else
281d6c0b56eSmrg				nominal_frame_rate /= pix_in_frame;
282d6c0b56eSmrg			drmmode_crtc->dpms_last_fps = nominal_frame_rate;
283d6c0b56eSmrg		}
284d6c0b56eSmrg	} else if (drmmode_crtc->dpms_mode != DPMSModeOn && mode == DPMSModeOn) {
285d6c0b56eSmrg		/*
286d6c0b56eSmrg		 * Off->On transition: calculate and accumulate the
287d6c0b56eSmrg		 * number of interpolated vblanks while we were in Off state
288d6c0b56eSmrg		 */
289d6c0b56eSmrg		ret = drmmode_get_current_ust(pAMDGPUEnt->fd, &ust);
290d6c0b56eSmrg		if (ret)
291d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_ERROR,
292d6c0b56eSmrg				   "%s cannot get current time\n", __func__);
293d6c0b56eSmrg		else if (drmmode_crtc->dpms_last_ust) {
294d6c0b56eSmrg			CARD64 time_elapsed, delta_seq;
295d6c0b56eSmrg			time_elapsed = ust - drmmode_crtc->dpms_last_ust;
296d6c0b56eSmrg			delta_seq = time_elapsed * drmmode_crtc->dpms_last_fps;
297d6c0b56eSmrg			delta_seq /= 1000000;
298d6c0b56eSmrg			drmmode_crtc->interpolated_vblanks += delta_seq;
299d6c0b56eSmrg
300d6c0b56eSmrg		}
301d6c0b56eSmrg	}
302d6c0b56eSmrg	drmmode_crtc->dpms_mode = mode;
303d6c0b56eSmrg}
304d6c0b56eSmrg
305d6c0b56eSmrgstatic void
306d6c0b56eSmrgdrmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
307d6c0b56eSmrg{
308d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
309d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
310d6c0b56eSmrg
311d6c0b56eSmrg	/* Disable unused CRTCs and enable/disable active CRTCs */
312d6c0b56eSmrg	if (!crtc->enabled || mode != DPMSModeOn)
313d6c0b56eSmrg		drmModeSetCrtc(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
314d6c0b56eSmrg			       0, 0, 0, NULL, 0, NULL);
315d6c0b56eSmrg	else if (drmmode_crtc->dpms_mode != DPMSModeOn)
316d6c0b56eSmrg		crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation,
317d6c0b56eSmrg					    crtc->x, crtc->y);
318d6c0b56eSmrg}
319d6c0b56eSmrg
320d6c0b56eSmrg#if GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10
321d6c0b56eSmrg
322d6c0b56eSmrgstatic PixmapPtr
323d6c0b56eSmrgcreate_pixmap_for_fbcon(drmmode_ptr drmmode,
324d6c0b56eSmrg			ScrnInfoPtr pScrn, int fbcon_id)
325d6c0b56eSmrg{
326d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
327d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
328d6c0b56eSmrg	PixmapPtr pixmap = info->fbcon_pixmap;
329d6c0b56eSmrg	struct amdgpu_buffer *bo;
330d6c0b56eSmrg	drmModeFBPtr fbcon;
331d6c0b56eSmrg	struct drm_gem_flink flink;
332d6c0b56eSmrg	struct amdgpu_bo_import_result import = {0};
333d6c0b56eSmrg
334d6c0b56eSmrg	if (pixmap)
335d6c0b56eSmrg		return pixmap;
336d6c0b56eSmrg
337d6c0b56eSmrg	fbcon = drmModeGetFB(pAMDGPUEnt->fd, fbcon_id);
338d6c0b56eSmrg	if (fbcon == NULL)
339d6c0b56eSmrg		return NULL;
340d6c0b56eSmrg
341d6c0b56eSmrg	if (fbcon->depth != pScrn->depth ||
342d6c0b56eSmrg	    fbcon->width != pScrn->virtualX ||
343d6c0b56eSmrg	    fbcon->height != pScrn->virtualY)
344d6c0b56eSmrg		goto out_free_fb;
345d6c0b56eSmrg
346d6c0b56eSmrg	flink.handle = fbcon->handle;
347d6c0b56eSmrg	if (ioctl(pAMDGPUEnt->fd, DRM_IOCTL_GEM_FLINK, &flink) < 0) {
348d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
349d6c0b56eSmrg			   "Couldn't flink fbcon handle\n");
350d6c0b56eSmrg		goto out_free_fb;
351d6c0b56eSmrg	}
352d6c0b56eSmrg
353d6c0b56eSmrg	bo = calloc(1, sizeof(struct amdgpu_buffer));
354d6c0b56eSmrg	if (bo == NULL) {
355d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
356d6c0b56eSmrg			   "Couldn't allocate bo for fbcon handle\n");
357d6c0b56eSmrg		goto out_free_fb;
358d6c0b56eSmrg	}
359d6c0b56eSmrg	bo->ref_count = 1;
360d6c0b56eSmrg
361d6c0b56eSmrg	if (amdgpu_bo_import(pAMDGPUEnt->pDev,
362d6c0b56eSmrg			     amdgpu_bo_handle_type_gem_flink_name, flink.name,
363d6c0b56eSmrg			     &import) != 0) {
364d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
365d6c0b56eSmrg			   "Couldn't import BO for fbcon handle\n");
366d6c0b56eSmrg		goto out_free_bo;
367d6c0b56eSmrg	}
368d6c0b56eSmrg	bo->bo.amdgpu = import.buf_handle;
369d6c0b56eSmrg
370d6c0b56eSmrg	pixmap = drmmode_create_bo_pixmap(pScrn, fbcon->width, fbcon->height,
371d6c0b56eSmrg					  fbcon->depth, fbcon->bpp,
372d6c0b56eSmrg					  fbcon->pitch, bo);
373d6c0b56eSmrg	info->fbcon_pixmap = pixmap;
374d6c0b56eSmrgout_free_bo:
375d6c0b56eSmrg	amdgpu_bo_unref(&bo);
376d6c0b56eSmrgout_free_fb:
377d6c0b56eSmrg	drmModeFreeFB(fbcon);
378d6c0b56eSmrg	return pixmap;
379d6c0b56eSmrg}
380d6c0b56eSmrg
381d6c0b56eSmrgvoid drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
382d6c0b56eSmrg{
383d6c0b56eSmrg	xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
384d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
385d6c0b56eSmrg	PixmapPtr src, dst;
386d6c0b56eSmrg	ScreenPtr pScreen = pScrn->pScreen;
387d6c0b56eSmrg	int fbcon_id = 0;
388d6c0b56eSmrg	GCPtr gc;
389d6c0b56eSmrg	int i;
390d6c0b56eSmrg
391d6c0b56eSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
392d6c0b56eSmrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
393d6c0b56eSmrg
394d6c0b56eSmrg		if (drmmode_crtc->mode_crtc->buffer_id)
395d6c0b56eSmrg			fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
396d6c0b56eSmrg	}
397d6c0b56eSmrg
398d6c0b56eSmrg	if (!fbcon_id)
399d6c0b56eSmrg		return;
400d6c0b56eSmrg
401d6c0b56eSmrg	if (fbcon_id == drmmode->fb_id) {
402d6c0b56eSmrg		/* in some rare case there might be no fbcon and we might already
403d6c0b56eSmrg		 * be the one with the current fb to avoid a false deadlck in
404d6c0b56eSmrg		 * kernel ttm code just do nothing as anyway there is nothing
405d6c0b56eSmrg		 * to do
406d6c0b56eSmrg		 */
407d6c0b56eSmrg		return;
408d6c0b56eSmrg	}
409d6c0b56eSmrg
410d6c0b56eSmrg	src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
411d6c0b56eSmrg	if (!src)
412d6c0b56eSmrg		return;
413d6c0b56eSmrg
414d6c0b56eSmrg	dst = pScreen->GetScreenPixmap(pScreen);
415d6c0b56eSmrg
416d6c0b56eSmrg	gc = GetScratchGC(pScrn->depth, pScreen);
417d6c0b56eSmrg	ValidateGC(&dst->drawable, gc);
418d6c0b56eSmrg
419d6c0b56eSmrg	(*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0,
420d6c0b56eSmrg			     pScrn->virtualX, pScrn->virtualY, 0, 0);
421d6c0b56eSmrg
422d6c0b56eSmrg	FreeScratchGC(gc);
423d6c0b56eSmrg
424d6c0b56eSmrg	amdgpu_glamor_finish(pScrn);
425d6c0b56eSmrg
426d6c0b56eSmrg	pScreen->canDoBGNoneRoot = TRUE;
427d6c0b56eSmrg
428d6c0b56eSmrg	if (info->fbcon_pixmap)
429d6c0b56eSmrg		pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap);
430d6c0b56eSmrg	info->fbcon_pixmap = NULL;
431d6c0b56eSmrg
432d6c0b56eSmrg	return;
433d6c0b56eSmrg}
434d6c0b56eSmrg
435d6c0b56eSmrg#endif /* GET_ABI_MAJOR(ABI_VIDEODRV_VERSION) >= 10 */
436d6c0b56eSmrg
437d6c0b56eSmrgstatic void
438d6c0b56eSmrgdrmmode_crtc_scanout_destroy(drmmode_ptr drmmode,
439d6c0b56eSmrg			     struct drmmode_scanout *scanout)
440d6c0b56eSmrg{
441d6c0b56eSmrg
442d6c0b56eSmrg	if (scanout->pixmap) {
443d6c0b56eSmrg		drmmode_destroy_bo_pixmap(scanout->pixmap);
444d6c0b56eSmrg		scanout->pixmap = NULL;
445d6c0b56eSmrg	}
446d6c0b56eSmrg
447d6c0b56eSmrg	if (scanout->bo) {
448d6c0b56eSmrg		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn);
449d6c0b56eSmrg
450d6c0b56eSmrg		drmModeRmFB(pAMDGPUEnt->fd, scanout->fb_id);
451d6c0b56eSmrg		scanout->fb_id = 0;
452d6c0b56eSmrg		amdgpu_bo_unref(&scanout->bo);
453d6c0b56eSmrg		scanout->bo = NULL;
454d6c0b56eSmrg	}
455d6c0b56eSmrg
456d6c0b56eSmrg	if (scanout->damage) {
457d6c0b56eSmrg		DamageDestroy(scanout->damage);
458d6c0b56eSmrg		scanout->damage = NULL;
459d6c0b56eSmrg	}
460d6c0b56eSmrg}
461d6c0b56eSmrg
462d6c0b56eSmrgvoid
463d6c0b56eSmrgdrmmode_scanout_free(ScrnInfoPtr scrn)
464d6c0b56eSmrg{
465d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
466d6c0b56eSmrg	int c;
467d6c0b56eSmrg
468d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
469d6c0b56eSmrg		drmmode_crtc_private_ptr drmmode_crtc =
470d6c0b56eSmrg			xf86_config->crtc[c]->driver_private;
471d6c0b56eSmrg
472d6c0b56eSmrg		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
473d6c0b56eSmrg					     &drmmode_crtc->scanout[0]);
474d6c0b56eSmrg		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
475d6c0b56eSmrg					     &drmmode_crtc->scanout[1]);
476d6c0b56eSmrg	}
477d6c0b56eSmrg}
478d6c0b56eSmrg
479d6c0b56eSmrgstatic void *
480d6c0b56eSmrgdrmmode_crtc_scanout_allocate(xf86CrtcPtr crtc,
481d6c0b56eSmrg			      struct drmmode_scanout *scanout,
482d6c0b56eSmrg			      int width, int height)
483d6c0b56eSmrg{
484d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
485d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
486d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
487d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
488d6c0b56eSmrg	int ret;
489d6c0b56eSmrg	int pitch;
490d6c0b56eSmrg	union gbm_bo_handle bo_handle;
491d6c0b56eSmrg
492d6c0b56eSmrg	if (scanout->bo) {
493d6c0b56eSmrg		if (scanout->width == width && scanout->height == height)
494d6c0b56eSmrg			return scanout->bo;
495d6c0b56eSmrg
496d6c0b56eSmrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
497d6c0b56eSmrg	}
498d6c0b56eSmrg
499d6c0b56eSmrg	scanout->bo = amdgpu_alloc_pixmap_bo(pScrn, width, height,
500d6c0b56eSmrg					       pScrn->depth, 0,
501d6c0b56eSmrg					       pScrn->bitsPerPixel, &pitch);
502d6c0b56eSmrg	if (!scanout->bo) {
503d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
504d6c0b56eSmrg			   "Failed to allocate rotation buffer memory\n");
505d6c0b56eSmrg		return NULL;
506d6c0b56eSmrg	}
507d6c0b56eSmrg
508d6c0b56eSmrg	bo_handle = gbm_bo_get_handle(scanout->bo->bo.gbm);
509d6c0b56eSmrg	ret = drmModeAddFB(pAMDGPUEnt->fd, width, height, pScrn->depth,
510d6c0b56eSmrg			   pScrn->bitsPerPixel, pitch,
511d6c0b56eSmrg			   bo_handle.u32, &scanout->fb_id);
512d6c0b56eSmrg	if (ret) {
513d6c0b56eSmrg		ErrorF("failed to add rotate fb\n");
514d6c0b56eSmrg		amdgpu_bo_unref(&scanout->bo);
515d6c0b56eSmrg		scanout->bo = NULL;
516d6c0b56eSmrg		return NULL;
517d6c0b56eSmrg	}
518d6c0b56eSmrg
519d6c0b56eSmrg	scanout->width = width;
520d6c0b56eSmrg	scanout->height = height;
521d6c0b56eSmrg	return scanout->bo;
522d6c0b56eSmrg}
523d6c0b56eSmrg
524d6c0b56eSmrgstatic PixmapPtr
525d6c0b56eSmrgdrmmode_crtc_scanout_create(xf86CrtcPtr crtc,
526d6c0b56eSmrg			    struct drmmode_scanout *scanout,
527d6c0b56eSmrg			    int width, int height)
528d6c0b56eSmrg{
529d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
530d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
531d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
532d6c0b56eSmrg	unsigned long rotate_pitch;
533d6c0b56eSmrg
534d6c0b56eSmrg	if (scanout->pixmap) {
535d6c0b56eSmrg		if (scanout->width == width && scanout->height == height)
536d6c0b56eSmrg			return scanout->pixmap;
537d6c0b56eSmrg
538d6c0b56eSmrg		drmmode_crtc_scanout_destroy(drmmode, scanout);
539d6c0b56eSmrg	}
540d6c0b56eSmrg
541d6c0b56eSmrg	if (!scanout->bo) {
542d6c0b56eSmrg		if (!drmmode_crtc_scanout_allocate(crtc, scanout, width, height))
543d6c0b56eSmrg			return NULL;
544d6c0b56eSmrg	}
545d6c0b56eSmrg
546d6c0b56eSmrg	rotate_pitch = gbm_bo_get_stride(scanout->bo->bo.gbm);
547d6c0b56eSmrg
548d6c0b56eSmrg	scanout->pixmap = drmmode_create_bo_pixmap(pScrn,
549d6c0b56eSmrg						 width, height,
550d6c0b56eSmrg						 pScrn->depth,
551d6c0b56eSmrg						 pScrn->bitsPerPixel,
552d6c0b56eSmrg						 rotate_pitch,
553d6c0b56eSmrg						 scanout->bo);
554d6c0b56eSmrg	if (scanout->pixmap == NULL) {
555d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
556d6c0b56eSmrg			   "Couldn't allocate shadow pixmap for rotated CRTC\n");
557d6c0b56eSmrg	}
558d6c0b56eSmrg	return scanout->pixmap;
559d6c0b56eSmrg
560d6c0b56eSmrg}
561d6c0b56eSmrg
562d6c0b56eSmrgstatic void
563d6c0b56eSmrgamdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
564d6c0b56eSmrg{
565d6c0b56eSmrg	/* Only keep track of the extents */
566d6c0b56eSmrg	RegionUninit(&damage->damage);
567d6c0b56eSmrg	damage->damage.data = NULL;
568d6c0b56eSmrg}
569d6c0b56eSmrg
570d6c0b56eSmrgstatic Bool
571d6c0b56eSmrgdrmmode_can_use_hw_cursor(xf86CrtcPtr crtc)
572d6c0b56eSmrg{
573d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
574d6c0b56eSmrg
575d6c0b56eSmrg	/* Check for Option "SWcursor" */
576d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
577d6c0b56eSmrg		return FALSE;
578d6c0b56eSmrg
579d6c0b56eSmrg	/* Fall back to SW cursor if the CRTC is transformed */
580d6c0b56eSmrg	if (crtc->transformPresent)
581d6c0b56eSmrg		return FALSE;
582d6c0b56eSmrg
583d6c0b56eSmrg#if XF86_CRTC_VERSION >= 4
584d6c0b56eSmrg	/* Xorg doesn't correctly handle cursor position transform in the
585d6c0b56eSmrg	 * rotation case
586d6c0b56eSmrg	 */
587d6c0b56eSmrg	if (crtc->driverIsPerformingTransform &&
588d6c0b56eSmrg	    (crtc->rotation & 0xf) != RR_Rotate_0)
589d6c0b56eSmrg		return FALSE;
590d6c0b56eSmrg#endif
591d6c0b56eSmrg
592d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
593d6c0b56eSmrg	/* HW cursor not supported yet with RandR 1.4 multihead */
594d6c0b56eSmrg	if (!xorg_list_is_empty(&crtc->scrn->pScreen->pixmap_dirty_list))
595d6c0b56eSmrg		return FALSE;
596d6c0b56eSmrg#endif
597d6c0b56eSmrg
598d6c0b56eSmrg	return TRUE;
599d6c0b56eSmrg}
600d6c0b56eSmrg
601d6c0b56eSmrg#if XF86_CRTC_VERSION >= 4
602d6c0b56eSmrg
603d6c0b56eSmrgstatic Bool
604d6c0b56eSmrgdrmmode_handle_transform(xf86CrtcPtr crtc)
605d6c0b56eSmrg{
606d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(crtc->scrn);
607d6c0b56eSmrg	Bool ret;
608d6c0b56eSmrg
609d6c0b56eSmrg	crtc->driverIsPerformingTransform = info->tear_free &&
610d6c0b56eSmrg		!crtc->transformPresent && crtc->rotation != RR_Rotate_0;
611d6c0b56eSmrg
612d6c0b56eSmrg	ret = xf86CrtcRotate(crtc);
613d6c0b56eSmrg
614d6c0b56eSmrg	crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use;
615d6c0b56eSmrg
616d6c0b56eSmrg	return ret;
617d6c0b56eSmrg}
618d6c0b56eSmrg
619d6c0b56eSmrg#else
620d6c0b56eSmrg
621d6c0b56eSmrgstatic Bool
622d6c0b56eSmrgdrmmode_handle_transform(xf86CrtcPtr crtc)
623d6c0b56eSmrg{
624d6c0b56eSmrg	return xf86CrtcRotate(crtc);
625d6c0b56eSmrg}
626d6c0b56eSmrg
627d6c0b56eSmrg#endif
628d6c0b56eSmrg
629d6c0b56eSmrgstatic Bool
630d6c0b56eSmrgdrmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
631d6c0b56eSmrg		       Rotation rotation, int x, int y)
632d6c0b56eSmrg{
633d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
634d6c0b56eSmrg	ScreenPtr pScreen = pScrn->pScreen;
635d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
636d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
637d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
638d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
639d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
640d6c0b56eSmrg	int saved_x, saved_y;
641d6c0b56eSmrg	Rotation saved_rotation;
642d6c0b56eSmrg	DisplayModeRec saved_mode;
643d6c0b56eSmrg	uint32_t *output_ids = NULL;
644d6c0b56eSmrg	int output_count = 0;
645d6c0b56eSmrg	Bool ret = TRUE;
646d6c0b56eSmrg	int i;
647d6c0b56eSmrg	int fb_id;
648d6c0b56eSmrg	drmModeModeInfo kmode;
649d6c0b56eSmrg	uint32_t bo_handle;
650d6c0b56eSmrg
651d6c0b56eSmrg	if (drmmode->fb_id == 0) {
652d6c0b56eSmrg		if (!amdgpu_bo_get_handle(info->front_buffer, &bo_handle)) {
653d6c0b56eSmrg			ErrorF("failed to get BO handle for FB\n");
654d6c0b56eSmrg			return FALSE;
655d6c0b56eSmrg		}
656d6c0b56eSmrg
657d6c0b56eSmrg		ret = drmModeAddFB(pAMDGPUEnt->fd,
658d6c0b56eSmrg				   pScrn->virtualX,
659d6c0b56eSmrg				   pScrn->virtualY,
660d6c0b56eSmrg				   pScrn->depth, pScrn->bitsPerPixel,
661d6c0b56eSmrg				   pScrn->displayWidth * info->pixel_bytes,
662d6c0b56eSmrg				   bo_handle, &drmmode->fb_id);
663d6c0b56eSmrg		if (ret < 0) {
664d6c0b56eSmrg			ErrorF("failed to add fb\n");
665d6c0b56eSmrg			return FALSE;
666d6c0b56eSmrg		}
667d6c0b56eSmrg	}
668d6c0b56eSmrg
669d6c0b56eSmrg	saved_mode = crtc->mode;
670d6c0b56eSmrg	saved_x = crtc->x;
671d6c0b56eSmrg	saved_y = crtc->y;
672d6c0b56eSmrg	saved_rotation = crtc->rotation;
673d6c0b56eSmrg
674d6c0b56eSmrg	if (mode) {
675d6c0b56eSmrg		crtc->mode = *mode;
676d6c0b56eSmrg		crtc->x = x;
677d6c0b56eSmrg		crtc->y = y;
678d6c0b56eSmrg		crtc->rotation = rotation;
679d6c0b56eSmrg
680d6c0b56eSmrg		output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
681d6c0b56eSmrg		if (!output_ids) {
682d6c0b56eSmrg			ret = FALSE;
683d6c0b56eSmrg			goto done;
684d6c0b56eSmrg		}
685d6c0b56eSmrg
686d6c0b56eSmrg		for (i = 0; i < xf86_config->num_output; i++) {
687d6c0b56eSmrg			xf86OutputPtr output = xf86_config->output[i];
688d6c0b56eSmrg			drmmode_output_private_ptr drmmode_output;
689d6c0b56eSmrg
690d6c0b56eSmrg			if (output->crtc != crtc)
691d6c0b56eSmrg				continue;
692d6c0b56eSmrg
693d6c0b56eSmrg			drmmode_output = output->driver_private;
694d6c0b56eSmrg			output_ids[output_count] =
695d6c0b56eSmrg			    drmmode_output->mode_output->connector_id;
696d6c0b56eSmrg			output_count++;
697d6c0b56eSmrg		}
698d6c0b56eSmrg
699d6c0b56eSmrg		if (!drmmode_handle_transform(crtc))
700d6c0b56eSmrg			goto done;
701d6c0b56eSmrg
702d6c0b56eSmrg		crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
703d6c0b56eSmrg				       crtc->gamma_blue, crtc->gamma_size);
704d6c0b56eSmrg
705d6c0b56eSmrg		drmmode_ConvertToKMode(crtc->scrn, &kmode, mode);
706d6c0b56eSmrg
707d6c0b56eSmrg		fb_id = drmmode->fb_id;
708d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
709d6c0b56eSmrg		if (crtc->randr_crtc && crtc->randr_crtc->scanout_pixmap) {
710d6c0b56eSmrg			x = drmmode_crtc->prime_pixmap_x;
711d6c0b56eSmrg			y = 0;
712d6c0b56eSmrg
713d6c0b56eSmrg			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]);
714d6c0b56eSmrg			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]);
715d6c0b56eSmrg		} else
716d6c0b56eSmrg#endif
717d6c0b56eSmrg		if (drmmode_crtc->rotate.fb_id) {
718d6c0b56eSmrg			fb_id = drmmode_crtc->rotate.fb_id;
719d6c0b56eSmrg			x = y = 0;
720d6c0b56eSmrg
721d6c0b56eSmrg			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]);
722d6c0b56eSmrg			drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]);
723d6c0b56eSmrg		} else if (info->tear_free ||
724d6c0b56eSmrg#if XF86_CRTC_VERSION >= 4
725d6c0b56eSmrg			   crtc->driverIsPerformingTransform ||
726d6c0b56eSmrg#endif
727d6c0b56eSmrg			   info->shadow_primary) {
728d6c0b56eSmrg			for (i = 0; i < (info->tear_free ? 2 : 1); i++) {
729d6c0b56eSmrg				drmmode_crtc_scanout_create(crtc,
730d6c0b56eSmrg							    &drmmode_crtc->scanout[i],
731d6c0b56eSmrg							    mode->HDisplay,
732d6c0b56eSmrg							    mode->VDisplay);
733d6c0b56eSmrg
734d6c0b56eSmrg				if (drmmode_crtc->scanout[i].pixmap) {
735d6c0b56eSmrg					RegionPtr pRegion;
736d6c0b56eSmrg					BoxPtr pBox;
737d6c0b56eSmrg
738d6c0b56eSmrg					if (!drmmode_crtc->scanout[i].damage) {
739d6c0b56eSmrg						drmmode_crtc->scanout[i].damage =
740d6c0b56eSmrg							DamageCreate(amdgpu_screen_damage_report,
741d6c0b56eSmrg								     NULL, DamageReportRawRegion,
742d6c0b56eSmrg								     TRUE, pScreen, NULL);
743d6c0b56eSmrg						DamageRegister(&pScreen->GetScreenPixmap(pScreen)->drawable,
744d6c0b56eSmrg							       drmmode_crtc->scanout[i].damage);
745d6c0b56eSmrg					}
746d6c0b56eSmrg
747d6c0b56eSmrg					pRegion = DamageRegion(drmmode_crtc->scanout[i].damage);
748d6c0b56eSmrg					RegionUninit(pRegion);
749d6c0b56eSmrg					pRegion->data = NULL;
750d6c0b56eSmrg					pBox = RegionExtents(pRegion);
751d6c0b56eSmrg					pBox->x1 = min(pBox->x1, x);
752d6c0b56eSmrg					pBox->y1 = min(pBox->y1, y);
753d6c0b56eSmrg
754d6c0b56eSmrg					switch (crtc->rotation & 0xf) {
755d6c0b56eSmrg					case RR_Rotate_90:
756d6c0b56eSmrg					case RR_Rotate_270:
757d6c0b56eSmrg						pBox->x2 = max(pBox->x2, x + mode->VDisplay);
758d6c0b56eSmrg						pBox->y2 = max(pBox->y2, y + mode->HDisplay);
759d6c0b56eSmrg						break;
760d6c0b56eSmrg					default:
761d6c0b56eSmrg						pBox->x2 = max(pBox->x2, x + mode->HDisplay);
762d6c0b56eSmrg						pBox->y2 = max(pBox->y2, y + mode->VDisplay);
763d6c0b56eSmrg					}
764d6c0b56eSmrg				}
765d6c0b56eSmrg			}
766d6c0b56eSmrg
767d6c0b56eSmrg			if (drmmode_crtc->scanout[0].pixmap &&
768d6c0b56eSmrg			    (!info->tear_free || drmmode_crtc->scanout[1].pixmap)) {
769d6c0b56eSmrg				drmmode_crtc->scanout_id = 0;
770d6c0b56eSmrg				fb_id = drmmode_crtc->scanout[0].fb_id;
771d6c0b56eSmrg				x = y = 0;
772d6c0b56eSmrg
773d6c0b56eSmrg				amdgpu_scanout_update_handler(crtc, 0, 0, drmmode_crtc);
774d6c0b56eSmrg				amdgpu_glamor_finish(pScrn);
775d6c0b56eSmrg			}
776d6c0b56eSmrg		}
777d6c0b56eSmrg
778d6c0b56eSmrg		/* Wait for any pending flip to finish */
779d6c0b56eSmrg		do {} while (drmmode_crtc->flip_pending &&
780d6c0b56eSmrg			     drmHandleEvent(pAMDGPUEnt->fd,
781d6c0b56eSmrg					    &drmmode->event_context) > 0);
782d6c0b56eSmrg
783d6c0b56eSmrg		if (drmModeSetCrtc(pAMDGPUEnt->fd,
784d6c0b56eSmrg				   drmmode_crtc->mode_crtc->crtc_id,
785d6c0b56eSmrg				   fb_id, x, y, output_ids,
786d6c0b56eSmrg				   output_count, &kmode) != 0) {
787d6c0b56eSmrg			xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
788d6c0b56eSmrg				   "failed to set mode: %s\n", strerror(errno));
789d6c0b56eSmrg			ret = FALSE;
790d6c0b56eSmrg			goto done;
791d6c0b56eSmrg		} else
792d6c0b56eSmrg			ret = TRUE;
793d6c0b56eSmrg
794d6c0b56eSmrg		if (pScreen)
795d6c0b56eSmrg			xf86CrtcSetScreenSubpixelOrder(pScreen);
796d6c0b56eSmrg
797d6c0b56eSmrg		drmmode_crtc->need_modeset = FALSE;
798d6c0b56eSmrg
799d6c0b56eSmrg		/* go through all the outputs and force DPMS them back on? */
800d6c0b56eSmrg		for (i = 0; i < xf86_config->num_output; i++) {
801d6c0b56eSmrg			xf86OutputPtr output = xf86_config->output[i];
802d6c0b56eSmrg
803d6c0b56eSmrg			if (output->crtc != crtc)
804d6c0b56eSmrg				continue;
805d6c0b56eSmrg
806d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOn);
807d6c0b56eSmrg		}
808d6c0b56eSmrg	}
809d6c0b56eSmrg
810d6c0b56eSmrg	/* Compute index of this CRTC into xf86_config->crtc */
811d6c0b56eSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
812d6c0b56eSmrg		if (xf86_config->crtc[i] != crtc)
813d6c0b56eSmrg			continue;
814d6c0b56eSmrg
815d6c0b56eSmrg		if (!crtc->enabled || drmmode_can_use_hw_cursor(crtc))
816d6c0b56eSmrg			info->hwcursor_disabled &= ~(1 << i);
817d6c0b56eSmrg		else
818d6c0b56eSmrg			info->hwcursor_disabled |= 1 << i;
819d6c0b56eSmrg
820d6c0b56eSmrg		break;
821d6c0b56eSmrg	}
822d6c0b56eSmrg
823d6c0b56eSmrg#ifndef HAVE_XF86_CURSOR_RESET_CURSOR
824d6c0b56eSmrg	if (!info->hwcursor_disabled)
825d6c0b56eSmrg		xf86_reload_cursors(pScreen);
826d6c0b56eSmrg#endif
827d6c0b56eSmrg
828d6c0b56eSmrgdone:
829d6c0b56eSmrg	free(output_ids);
830d6c0b56eSmrg	if (!ret) {
831d6c0b56eSmrg		crtc->x = saved_x;
832d6c0b56eSmrg		crtc->y = saved_y;
833d6c0b56eSmrg		crtc->rotation = saved_rotation;
834d6c0b56eSmrg		crtc->mode = saved_mode;
835d6c0b56eSmrg	} else
836d6c0b56eSmrg		crtc->active = TRUE;
837d6c0b56eSmrg
838d6c0b56eSmrg	return ret;
839d6c0b56eSmrg}
840d6c0b56eSmrg
841d6c0b56eSmrgstatic void drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
842d6c0b56eSmrg{
843d6c0b56eSmrg
844d6c0b56eSmrg}
845d6c0b56eSmrg
846d6c0b56eSmrgstatic void drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
847d6c0b56eSmrg{
848d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
849d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
850d6c0b56eSmrg
851d6c0b56eSmrg#if XF86_CRTC_VERSION >= 4
852d6c0b56eSmrg	if (crtc->driverIsPerformingTransform) {
853d6c0b56eSmrg		x += crtc->x;
854d6c0b56eSmrg		y += crtc->y;
855d6c0b56eSmrg		xf86CrtcTransformCursorPos(crtc, &x, &y);
856d6c0b56eSmrg	}
857d6c0b56eSmrg#endif
858d6c0b56eSmrg
859d6c0b56eSmrg	drmModeMoveCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
860d6c0b56eSmrg}
861d6c0b56eSmrg
862d6c0b56eSmrg#if XF86_CRTC_VERSION >= 4
863d6c0b56eSmrg
864d6c0b56eSmrgstatic int
865d6c0b56eSmrgdrmmode_cursor_src_offset(Rotation rotation, int width, int height,
866d6c0b56eSmrg			  int x_dst, int y_dst)
867d6c0b56eSmrg{
868d6c0b56eSmrg	int t;
869d6c0b56eSmrg
870d6c0b56eSmrg	switch (rotation & 0xf) {
871d6c0b56eSmrg	case RR_Rotate_90:
872d6c0b56eSmrg		t = x_dst;
873d6c0b56eSmrg		x_dst = height - y_dst - 1;
874d6c0b56eSmrg		y_dst = t;
875d6c0b56eSmrg		break;
876d6c0b56eSmrg	case RR_Rotate_180:
877d6c0b56eSmrg		x_dst = width - x_dst - 1;
878d6c0b56eSmrg		y_dst = height - y_dst - 1;
879d6c0b56eSmrg		break;
880d6c0b56eSmrg	case RR_Rotate_270:
881d6c0b56eSmrg		t = x_dst;
882d6c0b56eSmrg		x_dst = y_dst;
883d6c0b56eSmrg		y_dst = width - t - 1;
884d6c0b56eSmrg		break;
885d6c0b56eSmrg	}
886d6c0b56eSmrg
887d6c0b56eSmrg	if (rotation & RR_Reflect_X)
888d6c0b56eSmrg		x_dst = width - x_dst - 1;
889d6c0b56eSmrg	if (rotation & RR_Reflect_Y)
890d6c0b56eSmrg		y_dst = height - y_dst - 1;
891d6c0b56eSmrg
892d6c0b56eSmrg	return y_dst * height + x_dst;
893d6c0b56eSmrg}
894d6c0b56eSmrg
895d6c0b56eSmrg#endif
896d6c0b56eSmrg
897d6c0b56eSmrgstatic void drmmode_do_load_cursor_argb(xf86CrtcPtr crtc, CARD32 *image, uint32_t *ptr)
898d6c0b56eSmrg{
899d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
900d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
901d6c0b56eSmrg
902d6c0b56eSmrg#if XF86_CRTC_VERSION >= 4
903d6c0b56eSmrg	if (crtc->driverIsPerformingTransform) {
904d6c0b56eSmrg		uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
905d6c0b56eSmrg		int dstx, dsty;
906d6c0b56eSmrg		int srcoffset;
907d6c0b56eSmrg
908d6c0b56eSmrg		for (dsty = 0; dsty < cursor_h; dsty++) {
909d6c0b56eSmrg			for (dstx = 0; dstx < cursor_w; dstx++) {
910d6c0b56eSmrg				srcoffset = drmmode_cursor_src_offset(crtc->rotation,
911d6c0b56eSmrg								      cursor_w,
912d6c0b56eSmrg								      cursor_h,
913d6c0b56eSmrg								      dstx, dsty);
914d6c0b56eSmrg
915d6c0b56eSmrg				ptr[dsty * info->cursor_w + dstx] =
916d6c0b56eSmrg					cpu_to_le32(image[srcoffset]);
917d6c0b56eSmrg			}
918d6c0b56eSmrg		}
919d6c0b56eSmrg	} else
920d6c0b56eSmrg#endif
921d6c0b56eSmrg	{
922d6c0b56eSmrg		uint32_t cursor_size = info->cursor_w * info->cursor_h;
923d6c0b56eSmrg		int i;
924d6c0b56eSmrg
925d6c0b56eSmrg		for (i = 0; i < cursor_size; i++)
926d6c0b56eSmrg			ptr[i] = cpu_to_le32(image[i]);
927d6c0b56eSmrg	}
928d6c0b56eSmrg}
929d6c0b56eSmrg
930d6c0b56eSmrgstatic void drmmode_load_cursor_argb(xf86CrtcPtr crtc, CARD32 * image)
931d6c0b56eSmrg{
932d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
933d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
934d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
935d6c0b56eSmrg	uint32_t cursor_size = info->cursor_w * info->cursor_h;
936d6c0b56eSmrg
937d6c0b56eSmrg	if (info->gbm) {
938d6c0b56eSmrg		uint32_t ptr[cursor_size];
939d6c0b56eSmrg
940d6c0b56eSmrg		drmmode_do_load_cursor_argb(crtc, image, ptr);
941d6c0b56eSmrg		gbm_bo_write(drmmode_crtc->cursor_buffer->bo.gbm, ptr, cursor_size * 4);
942d6c0b56eSmrg	} else {
943d6c0b56eSmrg		/* cursor should be mapped already */
944d6c0b56eSmrg		uint32_t *ptr = (uint32_t *) (drmmode_crtc->cursor_buffer->cpu_ptr);
945d6c0b56eSmrg
946d6c0b56eSmrg		drmmode_do_load_cursor_argb(crtc, image, ptr);
947d6c0b56eSmrg	}
948d6c0b56eSmrg}
949d6c0b56eSmrg
950d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
951d6c0b56eSmrg
952d6c0b56eSmrgstatic Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
953d6c0b56eSmrg{
954d6c0b56eSmrg	if (!drmmode_can_use_hw_cursor(crtc))
955d6c0b56eSmrg		return FALSE;
956d6c0b56eSmrg
957d6c0b56eSmrg	drmmode_load_cursor_argb(crtc, image);
958d6c0b56eSmrg	return TRUE;
959d6c0b56eSmrg}
960d6c0b56eSmrg
961d6c0b56eSmrg#endif
962d6c0b56eSmrg
963d6c0b56eSmrgstatic void drmmode_hide_cursor(xf86CrtcPtr crtc)
964d6c0b56eSmrg{
965d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
966d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
967d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
968d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
969d6c0b56eSmrg
970d6c0b56eSmrg	drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
971d6c0b56eSmrg			 info->cursor_w, info->cursor_h);
972d6c0b56eSmrg
973d6c0b56eSmrg}
974d6c0b56eSmrg
975d6c0b56eSmrgstatic void drmmode_show_cursor(xf86CrtcPtr crtc)
976d6c0b56eSmrg{
977d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
978d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
979d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
980d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
981d6c0b56eSmrg	uint32_t bo_handle;
982d6c0b56eSmrg	static Bool use_set_cursor2 = TRUE;
983d6c0b56eSmrg
984d6c0b56eSmrg	if (!amdgpu_bo_get_handle(drmmode_crtc->cursor_buffer, &bo_handle)) {
985d6c0b56eSmrg		ErrorF("failed to get BO handle for cursor\n");
986d6c0b56eSmrg		return;
987d6c0b56eSmrg	}
988d6c0b56eSmrg
989d6c0b56eSmrg	if (use_set_cursor2) {
990d6c0b56eSmrg		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
991d6c0b56eSmrg		CursorPtr cursor = xf86_config->cursor;
992d6c0b56eSmrg		int ret;
993d6c0b56eSmrg
994d6c0b56eSmrg		ret = drmModeSetCursor2(pAMDGPUEnt->fd,
995d6c0b56eSmrg					drmmode_crtc->mode_crtc->crtc_id,
996d6c0b56eSmrg					bo_handle,
997d6c0b56eSmrg					info->cursor_w, info->cursor_h,
998d6c0b56eSmrg					cursor->bits->xhot, cursor->bits->yhot);
999d6c0b56eSmrg		if (ret == -EINVAL)
1000d6c0b56eSmrg			use_set_cursor2 = FALSE;
1001d6c0b56eSmrg		else
1002d6c0b56eSmrg			return;
1003d6c0b56eSmrg	}
1004d6c0b56eSmrg
1005d6c0b56eSmrg	drmModeSetCursor(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, bo_handle,
1006d6c0b56eSmrg			 info->cursor_w, info->cursor_h);
1007d6c0b56eSmrg}
1008d6c0b56eSmrg
1009d6c0b56eSmrgstatic void *drmmode_crtc_shadow_allocate(xf86CrtcPtr crtc, int width,
1010d6c0b56eSmrg					  int height)
1011d6c0b56eSmrg{
1012d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1013d6c0b56eSmrg
1014d6c0b56eSmrg	return drmmode_crtc_scanout_allocate(crtc, &drmmode_crtc->rotate,
1015d6c0b56eSmrg					     width, height);
1016d6c0b56eSmrg}
1017d6c0b56eSmrg
1018d6c0b56eSmrgstatic PixmapPtr
1019d6c0b56eSmrgdrmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1020d6c0b56eSmrg{
1021d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1022d6c0b56eSmrg
1023d6c0b56eSmrg	/* Xorg passes in the return value of drmmode_crtc_shadow_allocate
1024d6c0b56eSmrg	 * for data, but that's redundant for drmmode_crtc_scanout_create.
1025d6c0b56eSmrg	 */
1026d6c0b56eSmrg	return drmmode_crtc_scanout_create(crtc, &drmmode_crtc->rotate, width,
1027d6c0b56eSmrg					   height);
1028d6c0b56eSmrg}
1029d6c0b56eSmrg
1030d6c0b56eSmrgstatic void
1031d6c0b56eSmrgdrmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap,
1032d6c0b56eSmrg			    void *data)
1033d6c0b56eSmrg{
1034d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1035d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1036d6c0b56eSmrg
1037d6c0b56eSmrg	drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->rotate);
1038d6c0b56eSmrg}
1039d6c0b56eSmrg
1040d6c0b56eSmrgstatic void
1041d6c0b56eSmrgdrmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
1042d6c0b56eSmrg		       uint16_t * blue, int size)
1043d6c0b56eSmrg{
1044d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1045d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
1046d6c0b56eSmrg
1047d6c0b56eSmrg	drmModeCrtcSetGamma(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
1048d6c0b56eSmrg			    size, red, green, blue);
1049d6c0b56eSmrg}
1050d6c0b56eSmrg
1051d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
1052d6c0b56eSmrgstatic Bool drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
1053d6c0b56eSmrg{
1054d6c0b56eSmrg	ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
1055d6c0b56eSmrg	PixmapPtr screenpix = screen->GetScreenPixmap(screen);
1056d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1057d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1058d6c0b56eSmrg	int c, total_width = 0, max_height = 0, this_x = 0;
1059d6c0b56eSmrg
1060d6c0b56eSmrg	if (!ppix) {
1061d6c0b56eSmrg		if (crtc->randr_crtc->scanout_pixmap)
1062d6c0b56eSmrg			PixmapStopDirtyTracking(crtc->
1063d6c0b56eSmrg						randr_crtc->scanout_pixmap,
1064d6c0b56eSmrg						screenpix);
1065d6c0b56eSmrg		drmmode_crtc->prime_pixmap_x = 0;
1066d6c0b56eSmrg		return TRUE;
1067d6c0b56eSmrg	}
1068d6c0b56eSmrg
1069d6c0b56eSmrg	/* iterate over all the attached crtcs -
1070d6c0b56eSmrg	   work out bounding box */
1071d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
1072d6c0b56eSmrg		xf86CrtcPtr iter = xf86_config->crtc[c];
1073d6c0b56eSmrg		if (!iter->enabled && iter != crtc)
1074d6c0b56eSmrg			continue;
1075d6c0b56eSmrg		if (iter == crtc) {
1076d6c0b56eSmrg			this_x = total_width;
1077d6c0b56eSmrg			total_width += ppix->drawable.width;
1078d6c0b56eSmrg			if (max_height < ppix->drawable.height)
1079d6c0b56eSmrg				max_height = ppix->drawable.height;
1080d6c0b56eSmrg		} else {
1081d6c0b56eSmrg			total_width += iter->mode.HDisplay;
1082d6c0b56eSmrg			if (max_height < iter->mode.VDisplay)
1083d6c0b56eSmrg				max_height = iter->mode.VDisplay;
1084d6c0b56eSmrg		}
1085d6c0b56eSmrg#if !defined(HAS_DIRTYTRACKING_ROTATION) && !defined(HAS_DIRTYTRACKING2)
1086d6c0b56eSmrg		if (iter != crtc) {
1087d6c0b56eSmrg			ErrorF
1088d6c0b56eSmrg			    ("Cannot do multiple crtcs without X server dirty tracking 2 interface\n");
1089d6c0b56eSmrg			return FALSE;
1090d6c0b56eSmrg		}
1091d6c0b56eSmrg#endif
1092d6c0b56eSmrg	}
1093d6c0b56eSmrg
1094d6c0b56eSmrg	if (total_width != screenpix->drawable.width ||
1095d6c0b56eSmrg	    max_height != screenpix->drawable.height) {
1096d6c0b56eSmrg		Bool ret;
1097d6c0b56eSmrg		ret =
1098d6c0b56eSmrg		    drmmode_xf86crtc_resize(crtc->scrn, total_width,
1099d6c0b56eSmrg					    max_height);
1100d6c0b56eSmrg		if (ret == FALSE)
1101d6c0b56eSmrg			return FALSE;
1102d6c0b56eSmrg
1103d6c0b56eSmrg		screenpix = screen->GetScreenPixmap(screen);
1104d6c0b56eSmrg		screen->width = screenpix->drawable.width = total_width;
1105d6c0b56eSmrg		screen->height = screenpix->drawable.height = max_height;
1106d6c0b56eSmrg	}
1107d6c0b56eSmrg	drmmode_crtc->prime_pixmap_x = this_x;
1108d6c0b56eSmrg#ifdef HAS_DIRTYTRACKING_ROTATION
1109d6c0b56eSmrg	PixmapStartDirtyTracking(ppix, screenpix, 0, 0, this_x, 0, RR_Rotate_0);
1110d6c0b56eSmrg#elif defined(HAS_DIRTYTRACKING2)
1111d6c0b56eSmrg	PixmapStartDirtyTracking2(ppix, screenpix, 0, 0, this_x, 0);
1112d6c0b56eSmrg#else
1113d6c0b56eSmrg	PixmapStartDirtyTracking(ppix, screenpix, 0, 0);
1114d6c0b56eSmrg#endif
1115d6c0b56eSmrg	return TRUE;
1116d6c0b56eSmrg}
1117d6c0b56eSmrg#endif
1118d6c0b56eSmrg
1119d6c0b56eSmrgstatic xf86CrtcFuncsRec drmmode_crtc_funcs = {
1120d6c0b56eSmrg	.dpms = drmmode_crtc_dpms,
1121d6c0b56eSmrg	.set_mode_major = drmmode_set_mode_major,
1122d6c0b56eSmrg	.set_cursor_colors = drmmode_set_cursor_colors,
1123d6c0b56eSmrg	.set_cursor_position = drmmode_set_cursor_position,
1124d6c0b56eSmrg	.show_cursor = drmmode_show_cursor,
1125d6c0b56eSmrg	.hide_cursor = drmmode_hide_cursor,
1126d6c0b56eSmrg	.load_cursor_argb = drmmode_load_cursor_argb,
1127d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
1128d6c0b56eSmrg	.load_cursor_argb_check = drmmode_load_cursor_argb_check,
1129d6c0b56eSmrg#endif
1130d6c0b56eSmrg
1131d6c0b56eSmrg	.gamma_set = drmmode_crtc_gamma_set,
1132d6c0b56eSmrg	.shadow_create = drmmode_crtc_shadow_create,
1133d6c0b56eSmrg	.shadow_allocate = drmmode_crtc_shadow_allocate,
1134d6c0b56eSmrg	.shadow_destroy = drmmode_crtc_shadow_destroy,
1135d6c0b56eSmrg	.destroy = NULL,	/* XXX */
1136d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
1137d6c0b56eSmrg	.set_scanout_pixmap = drmmode_set_scanout_pixmap,
1138d6c0b56eSmrg#endif
1139d6c0b56eSmrg};
1140d6c0b56eSmrg
1141d6c0b56eSmrgint drmmode_get_crtc_id(xf86CrtcPtr crtc)
1142d6c0b56eSmrg{
1143d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1144d6c0b56eSmrg	return drmmode_crtc->hw_id;
1145d6c0b56eSmrg}
1146d6c0b56eSmrg
1147d6c0b56eSmrgvoid drmmode_crtc_hw_id(xf86CrtcPtr crtc)
1148d6c0b56eSmrg{
1149d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1150d6c0b56eSmrg	ScrnInfoPtr pScrn = crtc->scrn;
1151d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1152d6c0b56eSmrg	int r;
1153d6c0b56eSmrg
1154d6c0b56eSmrg	r = amdgpu_query_crtc_from_id(pAMDGPUEnt->pDev,
1155d6c0b56eSmrg				      drmmode_crtc->mode_crtc->crtc_id,
1156d6c0b56eSmrg				      &drmmode_crtc->hw_id);
1157d6c0b56eSmrg	if (r)
1158d6c0b56eSmrg		drmmode_crtc->hw_id = -1;
1159d6c0b56eSmrg}
1160d6c0b56eSmrg
1161d6c0b56eSmrgstatic unsigned int
1162d6c0b56eSmrgdrmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
1163d6c0b56eSmrg{
1164d6c0b56eSmrg	xf86CrtcPtr crtc;
1165d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc;
1166d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1167d6c0b56eSmrg
1168d6c0b56eSmrg	crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
1169d6c0b56eSmrg	if (crtc == NULL)
1170d6c0b56eSmrg		return 0;
1171d6c0b56eSmrg
1172d6c0b56eSmrg	drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
1173d6c0b56eSmrg	drmmode_crtc->mode_crtc =
1174d6c0b56eSmrg	    drmModeGetCrtc(pAMDGPUEnt->fd, mode_res->crtcs[num]);
1175d6c0b56eSmrg	drmmode_crtc->drmmode = drmmode;
1176d6c0b56eSmrg	drmmode_crtc->dpms_mode = DPMSModeOff;
1177d6c0b56eSmrg	crtc->driver_private = drmmode_crtc;
1178d6c0b56eSmrg	drmmode_crtc_hw_id(crtc);
1179d6c0b56eSmrg
1180d6c0b56eSmrg	/* Mark num'th crtc as in use on this device. */
1181d6c0b56eSmrg	pAMDGPUEnt->assigned_crtcs |= (1 << num);
1182d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1183d6c0b56eSmrg		       "Allocated crtc nr. %d to this screen.\n", num);
1184d6c0b56eSmrg
1185d6c0b56eSmrg	return 1;
1186d6c0b56eSmrg}
1187d6c0b56eSmrg
1188d6c0b56eSmrgstatic xf86OutputStatus drmmode_output_detect(xf86OutputPtr output)
1189d6c0b56eSmrg{
1190d6c0b56eSmrg	/* go to the hw and retrieve a new output struct */
1191d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1192d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1193d6c0b56eSmrg	xf86OutputStatus status;
1194d6c0b56eSmrg	drmModeFreeConnector(drmmode_output->mode_output);
1195d6c0b56eSmrg
1196d6c0b56eSmrg	drmmode_output->mode_output =
1197d6c0b56eSmrg	    drmModeGetConnector(pAMDGPUEnt->fd, drmmode_output->output_id);
1198d6c0b56eSmrg	if (!drmmode_output->mode_output)
1199d6c0b56eSmrg		return XF86OutputStatusDisconnected;
1200d6c0b56eSmrg
1201d6c0b56eSmrg	switch (drmmode_output->mode_output->connection) {
1202d6c0b56eSmrg	case DRM_MODE_CONNECTED:
1203d6c0b56eSmrg		status = XF86OutputStatusConnected;
1204d6c0b56eSmrg		break;
1205d6c0b56eSmrg	case DRM_MODE_DISCONNECTED:
1206d6c0b56eSmrg		status = XF86OutputStatusDisconnected;
1207d6c0b56eSmrg		break;
1208d6c0b56eSmrg	default:
1209d6c0b56eSmrg	case DRM_MODE_UNKNOWNCONNECTION:
1210d6c0b56eSmrg		status = XF86OutputStatusUnknown;
1211d6c0b56eSmrg		break;
1212d6c0b56eSmrg	}
1213d6c0b56eSmrg	return status;
1214d6c0b56eSmrg}
1215d6c0b56eSmrg
1216d6c0b56eSmrgstatic Bool
1217d6c0b56eSmrgdrmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
1218d6c0b56eSmrg{
1219d6c0b56eSmrg	return MODE_OK;
1220d6c0b56eSmrg}
1221d6c0b56eSmrg
1222d6c0b56eSmrgstatic DisplayModePtr drmmode_output_get_modes(xf86OutputPtr output)
1223d6c0b56eSmrg{
1224d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1225d6c0b56eSmrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
1226d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1227d6c0b56eSmrg	int i;
1228d6c0b56eSmrg	DisplayModePtr Modes = NULL, Mode;
1229d6c0b56eSmrg	drmModePropertyPtr props;
1230d6c0b56eSmrg	xf86MonPtr mon = NULL;
1231d6c0b56eSmrg
1232d6c0b56eSmrg	if (!koutput)
1233d6c0b56eSmrg		return NULL;
1234d6c0b56eSmrg
1235d6c0b56eSmrg	/* look for an EDID property */
1236d6c0b56eSmrg	for (i = 0; i < koutput->count_props; i++) {
1237d6c0b56eSmrg		props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]);
1238d6c0b56eSmrg		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
1239d6c0b56eSmrg			if (!strcmp(props->name, "EDID")) {
1240d6c0b56eSmrg				if (drmmode_output->edid_blob)
1241d6c0b56eSmrg					drmModeFreePropertyBlob
1242d6c0b56eSmrg					    (drmmode_output->edid_blob);
1243d6c0b56eSmrg				drmmode_output->edid_blob =
1244d6c0b56eSmrg				    drmModeGetPropertyBlob(pAMDGPUEnt->fd,
1245d6c0b56eSmrg							   koutput->prop_values
1246d6c0b56eSmrg							   [i]);
1247d6c0b56eSmrg			}
1248d6c0b56eSmrg		}
1249d6c0b56eSmrg		if (props)
1250d6c0b56eSmrg			drmModeFreeProperty(props);
1251d6c0b56eSmrg	}
1252d6c0b56eSmrg
1253d6c0b56eSmrg	if (drmmode_output->edid_blob) {
1254d6c0b56eSmrg		mon = xf86InterpretEDID(output->scrn->scrnIndex,
1255d6c0b56eSmrg					drmmode_output->edid_blob->data);
1256d6c0b56eSmrg		if (mon && drmmode_output->edid_blob->length > 128)
1257d6c0b56eSmrg			mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
1258d6c0b56eSmrg	}
1259d6c0b56eSmrg	xf86OutputSetEDID(output, mon);
1260d6c0b56eSmrg
1261d6c0b56eSmrg	/* modes should already be available */
1262d6c0b56eSmrg	for (i = 0; i < koutput->count_modes; i++) {
1263d6c0b56eSmrg		Mode = xnfalloc(sizeof(DisplayModeRec));
1264d6c0b56eSmrg
1265d6c0b56eSmrg		drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i],
1266d6c0b56eSmrg					 Mode);
1267d6c0b56eSmrg		Modes = xf86ModesAdd(Modes, Mode);
1268d6c0b56eSmrg
1269d6c0b56eSmrg	}
1270d6c0b56eSmrg	return Modes;
1271d6c0b56eSmrg}
1272d6c0b56eSmrg
1273d6c0b56eSmrgstatic void drmmode_output_destroy(xf86OutputPtr output)
1274d6c0b56eSmrg{
1275d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1276d6c0b56eSmrg	int i;
1277d6c0b56eSmrg
1278d6c0b56eSmrg	if (drmmode_output->edid_blob)
1279d6c0b56eSmrg		drmModeFreePropertyBlob(drmmode_output->edid_blob);
1280d6c0b56eSmrg	for (i = 0; i < drmmode_output->num_props; i++) {
1281d6c0b56eSmrg		drmModeFreeProperty(drmmode_output->props[i].mode_prop);
1282d6c0b56eSmrg		free(drmmode_output->props[i].atoms);
1283d6c0b56eSmrg	}
1284d6c0b56eSmrg	for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
1285d6c0b56eSmrg		drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
1286d6c0b56eSmrg	}
1287d6c0b56eSmrg	free(drmmode_output->mode_encoders);
1288d6c0b56eSmrg	free(drmmode_output->props);
1289d6c0b56eSmrg	drmModeFreeConnector(drmmode_output->mode_output);
1290d6c0b56eSmrg	free(drmmode_output);
1291d6c0b56eSmrg	output->driver_private = NULL;
1292d6c0b56eSmrg}
1293d6c0b56eSmrg
1294d6c0b56eSmrgstatic void drmmode_output_dpms(xf86OutputPtr output, int mode)
1295d6c0b56eSmrg{
1296d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1297d6c0b56eSmrg	xf86CrtcPtr crtc = output->crtc;
1298d6c0b56eSmrg	drmModeConnectorPtr koutput = drmmode_output->mode_output;
1299d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1300d6c0b56eSmrg
1301d6c0b56eSmrg	if (!koutput)
1302d6c0b56eSmrg		return;
1303d6c0b56eSmrg
1304d6c0b56eSmrg	if (mode != DPMSModeOn && crtc)
1305d6c0b56eSmrg		drmmode_do_crtc_dpms(crtc, mode);
1306d6c0b56eSmrg
1307d6c0b56eSmrg	drmModeConnectorSetProperty(pAMDGPUEnt->fd, koutput->connector_id,
1308d6c0b56eSmrg				    drmmode_output->dpms_enum_id, mode);
1309d6c0b56eSmrg
1310d6c0b56eSmrg	if (mode == DPMSModeOn && crtc) {
1311d6c0b56eSmrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1312d6c0b56eSmrg
1313d6c0b56eSmrg		if (drmmode_crtc->need_modeset)
1314d6c0b56eSmrg			drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
1315d6c0b56eSmrg					       crtc->x, crtc->y);
1316d6c0b56eSmrg		else
1317d6c0b56eSmrg			drmmode_do_crtc_dpms(output->crtc, mode);
1318d6c0b56eSmrg	}
1319d6c0b56eSmrg}
1320d6c0b56eSmrg
1321d6c0b56eSmrgstatic Bool drmmode_property_ignore(drmModePropertyPtr prop)
1322d6c0b56eSmrg{
1323d6c0b56eSmrg	if (!prop)
1324d6c0b56eSmrg		return TRUE;
1325d6c0b56eSmrg	/* ignore blob prop */
1326d6c0b56eSmrg	if (prop->flags & DRM_MODE_PROP_BLOB)
1327d6c0b56eSmrg		return TRUE;
1328d6c0b56eSmrg	/* ignore standard property */
1329d6c0b56eSmrg	if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS"))
1330d6c0b56eSmrg		return TRUE;
1331d6c0b56eSmrg
1332d6c0b56eSmrg	return FALSE;
1333d6c0b56eSmrg}
1334d6c0b56eSmrg
1335d6c0b56eSmrgstatic void drmmode_output_create_resources(xf86OutputPtr output)
1336d6c0b56eSmrg{
1337d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1338d6c0b56eSmrg	drmModeConnectorPtr mode_output = drmmode_output->mode_output;
1339d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1340d6c0b56eSmrg	drmModePropertyPtr drmmode_prop;
1341d6c0b56eSmrg	int i, j, err;
1342d6c0b56eSmrg
1343d6c0b56eSmrg	drmmode_output->props =
1344d6c0b56eSmrg	    calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
1345d6c0b56eSmrg	if (!drmmode_output->props)
1346d6c0b56eSmrg		return;
1347d6c0b56eSmrg
1348d6c0b56eSmrg	drmmode_output->num_props = 0;
1349d6c0b56eSmrg	for (i = 0, j = 0; i < mode_output->count_props; i++) {
1350d6c0b56eSmrg		drmmode_prop =
1351d6c0b56eSmrg		    drmModeGetProperty(pAMDGPUEnt->fd, mode_output->props[i]);
1352d6c0b56eSmrg		if (drmmode_property_ignore(drmmode_prop)) {
1353d6c0b56eSmrg			drmModeFreeProperty(drmmode_prop);
1354d6c0b56eSmrg			continue;
1355d6c0b56eSmrg		}
1356d6c0b56eSmrg		drmmode_output->props[j].mode_prop = drmmode_prop;
1357d6c0b56eSmrg		drmmode_output->props[j].value = mode_output->prop_values[i];
1358d6c0b56eSmrg		drmmode_output->num_props++;
1359d6c0b56eSmrg		j++;
1360d6c0b56eSmrg	}
1361d6c0b56eSmrg
1362d6c0b56eSmrg	for (i = 0; i < drmmode_output->num_props; i++) {
1363d6c0b56eSmrg		drmmode_prop_ptr p = &drmmode_output->props[i];
1364d6c0b56eSmrg		drmmode_prop = p->mode_prop;
1365d6c0b56eSmrg
1366d6c0b56eSmrg		if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
1367d6c0b56eSmrg			INT32 range[2];
1368d6c0b56eSmrg			INT32 value = p->value;
1369d6c0b56eSmrg
1370d6c0b56eSmrg			p->num_atoms = 1;
1371d6c0b56eSmrg			p->atoms = calloc(p->num_atoms, sizeof(Atom));
1372d6c0b56eSmrg			if (!p->atoms)
1373d6c0b56eSmrg				continue;
1374d6c0b56eSmrg			p->atoms[0] =
1375d6c0b56eSmrg			    MakeAtom(drmmode_prop->name,
1376d6c0b56eSmrg				     strlen(drmmode_prop->name), TRUE);
1377d6c0b56eSmrg			range[0] = drmmode_prop->values[0];
1378d6c0b56eSmrg			range[1] = drmmode_prop->values[1];
1379d6c0b56eSmrg			err =
1380d6c0b56eSmrg			    RRConfigureOutputProperty(output->randr_output,
1381d6c0b56eSmrg						      p->atoms[0], FALSE, TRUE,
1382d6c0b56eSmrg						      drmmode_prop->flags &
1383d6c0b56eSmrg						      DRM_MODE_PROP_IMMUTABLE ?
1384d6c0b56eSmrg						      TRUE : FALSE, 2, range);
1385d6c0b56eSmrg			if (err != 0) {
1386d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1387d6c0b56eSmrg					   "RRConfigureOutputProperty error, %d\n",
1388d6c0b56eSmrg					   err);
1389d6c0b56eSmrg			}
1390d6c0b56eSmrg			err =
1391d6c0b56eSmrg			    RRChangeOutputProperty(output->randr_output,
1392d6c0b56eSmrg						   p->atoms[0], XA_INTEGER, 32,
1393d6c0b56eSmrg						   PropModeReplace, 1, &value,
1394d6c0b56eSmrg						   FALSE, TRUE);
1395d6c0b56eSmrg			if (err != 0) {
1396d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1397d6c0b56eSmrg					   "RRChangeOutputProperty error, %d\n",
1398d6c0b56eSmrg					   err);
1399d6c0b56eSmrg			}
1400d6c0b56eSmrg		} else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
1401d6c0b56eSmrg			p->num_atoms = drmmode_prop->count_enums + 1;
1402d6c0b56eSmrg			p->atoms = calloc(p->num_atoms, sizeof(Atom));
1403d6c0b56eSmrg			if (!p->atoms)
1404d6c0b56eSmrg				continue;
1405d6c0b56eSmrg			p->atoms[0] =
1406d6c0b56eSmrg			    MakeAtom(drmmode_prop->name,
1407d6c0b56eSmrg				     strlen(drmmode_prop->name), TRUE);
1408d6c0b56eSmrg			for (j = 1; j <= drmmode_prop->count_enums; j++) {
1409d6c0b56eSmrg				struct drm_mode_property_enum *e =
1410d6c0b56eSmrg				    &drmmode_prop->enums[j - 1];
1411d6c0b56eSmrg				p->atoms[j] =
1412d6c0b56eSmrg				    MakeAtom(e->name, strlen(e->name), TRUE);
1413d6c0b56eSmrg			}
1414d6c0b56eSmrg			err =
1415d6c0b56eSmrg			    RRConfigureOutputProperty(output->randr_output,
1416d6c0b56eSmrg						      p->atoms[0], FALSE, FALSE,
1417d6c0b56eSmrg						      drmmode_prop->flags &
1418d6c0b56eSmrg						      DRM_MODE_PROP_IMMUTABLE ?
1419d6c0b56eSmrg						      TRUE : FALSE,
1420d6c0b56eSmrg						      p->num_atoms - 1,
1421d6c0b56eSmrg						      (INT32 *) & p->atoms[1]);
1422d6c0b56eSmrg			if (err != 0) {
1423d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1424d6c0b56eSmrg					   "RRConfigureOutputProperty error, %d\n",
1425d6c0b56eSmrg					   err);
1426d6c0b56eSmrg			}
1427d6c0b56eSmrg			for (j = 0; j < drmmode_prop->count_enums; j++)
1428d6c0b56eSmrg				if (drmmode_prop->enums[j].value == p->value)
1429d6c0b56eSmrg					break;
1430d6c0b56eSmrg			/* there's always a matching value */
1431d6c0b56eSmrg			err =
1432d6c0b56eSmrg			    RRChangeOutputProperty(output->randr_output,
1433d6c0b56eSmrg						   p->atoms[0], XA_ATOM, 32,
1434d6c0b56eSmrg						   PropModeReplace, 1,
1435d6c0b56eSmrg						   &p->atoms[j + 1], FALSE,
1436d6c0b56eSmrg						   TRUE);
1437d6c0b56eSmrg			if (err != 0) {
1438d6c0b56eSmrg				xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
1439d6c0b56eSmrg					   "RRChangeOutputProperty error, %d\n",
1440d6c0b56eSmrg					   err);
1441d6c0b56eSmrg			}
1442d6c0b56eSmrg		}
1443d6c0b56eSmrg	}
1444d6c0b56eSmrg}
1445d6c0b56eSmrg
1446d6c0b56eSmrgstatic Bool
1447d6c0b56eSmrgdrmmode_output_set_property(xf86OutputPtr output, Atom property,
1448d6c0b56eSmrg			    RRPropertyValuePtr value)
1449d6c0b56eSmrg{
1450d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output = output->driver_private;
1451d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(output->scrn);
1452d6c0b56eSmrg	int i;
1453d6c0b56eSmrg
1454d6c0b56eSmrg	for (i = 0; i < drmmode_output->num_props; i++) {
1455d6c0b56eSmrg		drmmode_prop_ptr p = &drmmode_output->props[i];
1456d6c0b56eSmrg
1457d6c0b56eSmrg		if (p->atoms[0] != property)
1458d6c0b56eSmrg			continue;
1459d6c0b56eSmrg
1460d6c0b56eSmrg		if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
1461d6c0b56eSmrg			uint32_t val;
1462d6c0b56eSmrg
1463d6c0b56eSmrg			if (value->type != XA_INTEGER || value->format != 32 ||
1464d6c0b56eSmrg			    value->size != 1)
1465d6c0b56eSmrg				return FALSE;
1466d6c0b56eSmrg			val = *(uint32_t *) value->data;
1467d6c0b56eSmrg
1468d6c0b56eSmrg			drmModeConnectorSetProperty(pAMDGPUEnt->fd,
1469d6c0b56eSmrg						    drmmode_output->output_id,
1470d6c0b56eSmrg						    p->mode_prop->prop_id,
1471d6c0b56eSmrg						    (uint64_t) val);
1472d6c0b56eSmrg			return TRUE;
1473d6c0b56eSmrg		} else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
1474d6c0b56eSmrg			Atom atom;
1475d6c0b56eSmrg			const char *name;
1476d6c0b56eSmrg			int j;
1477d6c0b56eSmrg
1478d6c0b56eSmrg			if (value->type != XA_ATOM || value->format != 32
1479d6c0b56eSmrg			    || value->size != 1)
1480d6c0b56eSmrg				return FALSE;
1481d6c0b56eSmrg			memcpy(&atom, value->data, 4);
1482d6c0b56eSmrg			name = NameForAtom(atom);
1483d6c0b56eSmrg
1484d6c0b56eSmrg			/* search for matching name string, then set its value down */
1485d6c0b56eSmrg			for (j = 0; j < p->mode_prop->count_enums; j++) {
1486d6c0b56eSmrg				if (!strcmp(p->mode_prop->enums[j].name, name)) {
1487d6c0b56eSmrg					drmModeConnectorSetProperty(pAMDGPUEnt->fd,
1488d6c0b56eSmrg								    drmmode_output->output_id,
1489d6c0b56eSmrg								    p->mode_prop->prop_id,
1490d6c0b56eSmrg								    p->mode_prop->enums
1491d6c0b56eSmrg								    [j].value);
1492d6c0b56eSmrg					return TRUE;
1493d6c0b56eSmrg				}
1494d6c0b56eSmrg			}
1495d6c0b56eSmrg		}
1496d6c0b56eSmrg	}
1497d6c0b56eSmrg
1498d6c0b56eSmrg	return TRUE;
1499d6c0b56eSmrg}
1500d6c0b56eSmrg
1501d6c0b56eSmrgstatic Bool drmmode_output_get_property(xf86OutputPtr output, Atom property)
1502d6c0b56eSmrg{
1503d6c0b56eSmrg	return TRUE;
1504d6c0b56eSmrg}
1505d6c0b56eSmrg
1506d6c0b56eSmrgstatic const xf86OutputFuncsRec drmmode_output_funcs = {
1507d6c0b56eSmrg	.dpms = drmmode_output_dpms,
1508d6c0b56eSmrg	.create_resources = drmmode_output_create_resources,
1509d6c0b56eSmrg	.set_property = drmmode_output_set_property,
1510d6c0b56eSmrg	.get_property = drmmode_output_get_property,
1511d6c0b56eSmrg#if 0
1512d6c0b56eSmrg
1513d6c0b56eSmrg	.save = drmmode_crt_save,
1514d6c0b56eSmrg	.restore = drmmode_crt_restore,
1515d6c0b56eSmrg	.mode_fixup = drmmode_crt_mode_fixup,
1516d6c0b56eSmrg	.prepare = drmmode_output_prepare,
1517d6c0b56eSmrg	.mode_set = drmmode_crt_mode_set,
1518d6c0b56eSmrg	.commit = drmmode_output_commit,
1519d6c0b56eSmrg#endif
1520d6c0b56eSmrg	.detect = drmmode_output_detect,
1521d6c0b56eSmrg	.mode_valid = drmmode_output_mode_valid,
1522d6c0b56eSmrg
1523d6c0b56eSmrg	.get_modes = drmmode_output_get_modes,
1524d6c0b56eSmrg	.destroy = drmmode_output_destroy
1525d6c0b56eSmrg};
1526d6c0b56eSmrg
1527d6c0b56eSmrgstatic int subpixel_conv_table[7] = { 0, SubPixelUnknown,
1528d6c0b56eSmrg	SubPixelHorizontalRGB,
1529d6c0b56eSmrg	SubPixelHorizontalBGR,
1530d6c0b56eSmrg	SubPixelVerticalRGB,
1531d6c0b56eSmrg	SubPixelVerticalBGR,
1532d6c0b56eSmrg	SubPixelNone
1533d6c0b56eSmrg};
1534d6c0b56eSmrg
1535d6c0b56eSmrgconst char *output_names[] = { "None",
1536d6c0b56eSmrg	"VGA",
1537d6c0b56eSmrg	"DVI-I",
1538d6c0b56eSmrg	"DVI-D",
1539d6c0b56eSmrg	"DVI-A",
1540d6c0b56eSmrg	"Composite",
1541d6c0b56eSmrg	"S-video",
1542d6c0b56eSmrg	"LVDS",
1543d6c0b56eSmrg	"CTV",
1544d6c0b56eSmrg	"DIN",
1545d6c0b56eSmrg	"DisplayPort",
1546d6c0b56eSmrg	"HDMI-A",
1547d6c0b56eSmrg	"HDMI-B",
1548d6c0b56eSmrg	"TV",
1549d6c0b56eSmrg	"eDP",
1550d6c0b56eSmrg	"Virtual",
1551d6c0b56eSmrg	"DSI",
1552d6c0b56eSmrg};
1553d6c0b56eSmrg
1554d6c0b56eSmrg#define NUM_OUTPUT_NAMES (sizeof(output_names) / sizeof(output_names[0]))
1555d6c0b56eSmrg
1556d6c0b56eSmrgstatic xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
1557d6c0b56eSmrg{
1558d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1559d6c0b56eSmrg	int i;
1560d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
1561d6c0b56eSmrg		xf86OutputPtr output = xf86_config->output[i];
1562d6c0b56eSmrg		drmmode_output_private_ptr drmmode_output;
1563d6c0b56eSmrg		drmmode_output = output->driver_private;
1564d6c0b56eSmrg		if (drmmode_output->output_id == id)
1565d6c0b56eSmrg			return output;
1566d6c0b56eSmrg	}
1567d6c0b56eSmrg	return NULL;
1568d6c0b56eSmrg}
1569d6c0b56eSmrg
1570d6c0b56eSmrgstatic int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
1571d6c0b56eSmrg{
1572d6c0b56eSmrg	char *conn;
1573d6c0b56eSmrg	char conn_id[5];
1574d6c0b56eSmrg	int id, len;
1575d6c0b56eSmrg	char *blob_data;
1576d6c0b56eSmrg
1577d6c0b56eSmrg	if (!path_blob)
1578d6c0b56eSmrg		return -1;
1579d6c0b56eSmrg
1580d6c0b56eSmrg	blob_data = path_blob->data;
1581d6c0b56eSmrg	/* we only handle MST paths for now */
1582d6c0b56eSmrg	if (strncmp(blob_data, "mst:", 4))
1583d6c0b56eSmrg		return -1;
1584d6c0b56eSmrg
1585d6c0b56eSmrg	conn = strchr(blob_data + 4, '-');
1586d6c0b56eSmrg	if (!conn)
1587d6c0b56eSmrg		return -1;
1588d6c0b56eSmrg	len = conn - (blob_data + 4);
1589d6c0b56eSmrg	if (len + 1 > 5)
1590d6c0b56eSmrg		return -1;
1591d6c0b56eSmrg	memcpy(conn_id, blob_data + 4, len);
1592d6c0b56eSmrg	conn_id[len] = '\0';
1593d6c0b56eSmrg	id = strtoul(conn_id, NULL, 10);
1594d6c0b56eSmrg
1595d6c0b56eSmrg	*conn_base_id = id;
1596d6c0b56eSmrg
1597d6c0b56eSmrg	*path = conn + 1;
1598d6c0b56eSmrg	return 0;
1599d6c0b56eSmrg}
1600d6c0b56eSmrg
1601d6c0b56eSmrgstatic void
1602d6c0b56eSmrgdrmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
1603d6c0b56eSmrg		    drmModePropertyBlobPtr path_blob, int *num_dvi, int *num_hdmi)
1604d6c0b56eSmrg{
1605d6c0b56eSmrg	xf86OutputPtr output;
1606d6c0b56eSmrg	int conn_id;
1607d6c0b56eSmrg	char *extra_path;
1608d6c0b56eSmrg
1609d6c0b56eSmrg	output = NULL;
1610d6c0b56eSmrg	if (parse_path_blob(path_blob, &conn_id, &extra_path) == 0)
1611d6c0b56eSmrg		output = find_output(pScrn, conn_id);
1612d6c0b56eSmrg	if (output) {
1613d6c0b56eSmrg		snprintf(name, 32, "%s-%s", output->name, extra_path);
1614d6c0b56eSmrg	} else {
1615d6c0b56eSmrg		if (koutput->connector_type >= NUM_OUTPUT_NAMES)
1616d6c0b56eSmrg			snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id - 1);
1617d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
1618d6c0b56eSmrg		else if (pScrn->is_gpu)
1619d6c0b56eSmrg			snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type],
1620d6c0b56eSmrg				 pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id - 1);
1621d6c0b56eSmrg#endif
1622d6c0b56eSmrg		else {
1623d6c0b56eSmrg			/* need to do smart conversion here for compat with non-kms ATI driver */
1624d6c0b56eSmrg			if (koutput->connector_type_id == 1) {
1625d6c0b56eSmrg				switch(koutput->connector_type) {
1626d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DVII:
1627d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DVID:
1628d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DVIA:
1629d6c0b56eSmrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_dvi);
1630d6c0b56eSmrg					(*num_dvi)++;
1631d6c0b56eSmrg					break;
1632d6c0b56eSmrg				case DRM_MODE_CONNECTOR_HDMIA:
1633d6c0b56eSmrg				case DRM_MODE_CONNECTOR_HDMIB:
1634d6c0b56eSmrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], *num_hdmi);
1635d6c0b56eSmrg					(*num_hdmi)++;
1636d6c0b56eSmrg					break;
1637d6c0b56eSmrg				case DRM_MODE_CONNECTOR_VGA:
1638d6c0b56eSmrg				case DRM_MODE_CONNECTOR_DisplayPort:
1639d6c0b56eSmrg					snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
1640d6c0b56eSmrg					break;
1641d6c0b56eSmrg				default:
1642d6c0b56eSmrg					snprintf(name, 32, "%s", output_names[koutput->connector_type]);
1643d6c0b56eSmrg					break;
1644d6c0b56eSmrg				}
1645d6c0b56eSmrg			} else {
1646d6c0b56eSmrg				snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id - 1);
1647d6c0b56eSmrg			}
1648d6c0b56eSmrg		}
1649d6c0b56eSmrg	}
1650d6c0b56eSmrg}
1651d6c0b56eSmrg
1652d6c0b56eSmrg
1653d6c0b56eSmrgstatic unsigned int
1654d6c0b56eSmrgdrmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, int *num_dvi, int *num_hdmi, int dynamic)
1655d6c0b56eSmrg{
1656d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1657d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1658d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1659d6c0b56eSmrg	xf86OutputPtr output;
1660d6c0b56eSmrg	drmModeConnectorPtr koutput;
1661d6c0b56eSmrg	drmModeEncoderPtr *kencoders = NULL;
1662d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output;
1663d6c0b56eSmrg	drmModePropertyPtr props;
1664d6c0b56eSmrg	drmModePropertyBlobPtr path_blob = NULL;
1665d6c0b56eSmrg	char name[32];
1666d6c0b56eSmrg	int i;
1667d6c0b56eSmrg	const char *s;
1668d6c0b56eSmrg
1669d6c0b56eSmrg	koutput =
1670d6c0b56eSmrg	    drmModeGetConnector(pAMDGPUEnt->fd,
1671d6c0b56eSmrg				mode_res->connectors[num]);
1672d6c0b56eSmrg	if (!koutput)
1673d6c0b56eSmrg		return 0;
1674d6c0b56eSmrg
1675d6c0b56eSmrg	for (i = 0; i < koutput->count_props; i++) {
1676d6c0b56eSmrg		props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]);
1677d6c0b56eSmrg		if (props && (props->flags & DRM_MODE_PROP_BLOB)) {
1678d6c0b56eSmrg			if (!strcmp(props->name, "PATH")) {
1679d6c0b56eSmrg				path_blob = drmModeGetPropertyBlob(pAMDGPUEnt->fd, koutput->prop_values[i]);
1680d6c0b56eSmrg				drmModeFreeProperty(props);
1681d6c0b56eSmrg				break;
1682d6c0b56eSmrg			}
1683d6c0b56eSmrg			drmModeFreeProperty(props);
1684d6c0b56eSmrg		}
1685d6c0b56eSmrg	}
1686d6c0b56eSmrg
1687d6c0b56eSmrg	kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
1688d6c0b56eSmrg	if (!kencoders) {
1689d6c0b56eSmrg		goto out_free_encoders;
1690d6c0b56eSmrg	}
1691d6c0b56eSmrg
1692d6c0b56eSmrg	for (i = 0; i < koutput->count_encoders; i++) {
1693d6c0b56eSmrg		kencoders[i] =
1694d6c0b56eSmrg		    drmModeGetEncoder(pAMDGPUEnt->fd, koutput->encoders[i]);
1695d6c0b56eSmrg		if (!kencoders[i]) {
1696d6c0b56eSmrg			goto out_free_encoders;
1697d6c0b56eSmrg		}
1698d6c0b56eSmrg	}
1699d6c0b56eSmrg
1700d6c0b56eSmrg	drmmode_create_name(pScrn, koutput, name, path_blob, num_dvi, num_hdmi);
1701d6c0b56eSmrg	if (path_blob) {
1702d6c0b56eSmrg		drmModeFreePropertyBlob(path_blob);
1703d6c0b56eSmrg	}
1704d6c0b56eSmrg
1705d6c0b56eSmrg	if (path_blob && dynamic) {
1706d6c0b56eSmrg		/* See if we have an output with this name already
1707d6c0b56eSmrg		 * and hook stuff up.
1708d6c0b56eSmrg		 */
1709d6c0b56eSmrg		for (i = 0; i < xf86_config->num_output; i++) {
1710d6c0b56eSmrg			output = xf86_config->output[i];
1711d6c0b56eSmrg
1712d6c0b56eSmrg			if (strncmp(output->name, name, 32))
1713d6c0b56eSmrg				continue;
1714d6c0b56eSmrg
1715d6c0b56eSmrg			drmmode_output = output->driver_private;
1716d6c0b56eSmrg			drmmode_output->output_id = mode_res->connectors[num];
1717d6c0b56eSmrg			drmmode_output->mode_output = koutput;
1718d6c0b56eSmrg			for (i = 0; i < koutput->count_encoders; i++) {
1719d6c0b56eSmrg				drmModeFreeEncoder(kencoders[i]);
1720d6c0b56eSmrg			}
1721d6c0b56eSmrg			free(kencoders);
1722d6c0b56eSmrg			return 1;
1723d6c0b56eSmrg		}
1724d6c0b56eSmrg	}
1725d6c0b56eSmrg
1726d6c0b56eSmrg	if (xf86IsEntityShared(pScrn->entityList[0])) {
1727d6c0b56eSmrg		if ((s =
1728d6c0b56eSmrg		     xf86GetOptValString(info->Options, OPTION_ZAPHOD_HEADS))) {
1729d6c0b56eSmrg			if (!AMDGPUZaphodStringMatches(pScrn, s, name))
1730d6c0b56eSmrg				goto out_free_encoders;
1731d6c0b56eSmrg		} else {
1732d6c0b56eSmrg			if (!info->IsSecondary && (num != 0))
1733d6c0b56eSmrg				goto out_free_encoders;
1734d6c0b56eSmrg			else if (info->IsSecondary && (num != 1))
1735d6c0b56eSmrg				goto out_free_encoders;
1736d6c0b56eSmrg		}
1737d6c0b56eSmrg	}
1738d6c0b56eSmrg
1739d6c0b56eSmrg	output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
1740d6c0b56eSmrg	if (!output) {
1741d6c0b56eSmrg		goto out_free_encoders;
1742d6c0b56eSmrg	}
1743d6c0b56eSmrg
1744d6c0b56eSmrg	drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
1745d6c0b56eSmrg	if (!drmmode_output) {
1746d6c0b56eSmrg		xf86OutputDestroy(output);
1747d6c0b56eSmrg		goto out_free_encoders;
1748d6c0b56eSmrg	}
1749d6c0b56eSmrg
1750d6c0b56eSmrg	drmmode_output->output_id = mode_res->connectors[num];
1751d6c0b56eSmrg	drmmode_output->mode_output = koutput;
1752d6c0b56eSmrg	drmmode_output->mode_encoders = kencoders;
1753d6c0b56eSmrg	drmmode_output->drmmode = drmmode;
1754d6c0b56eSmrg	output->mm_width = koutput->mmWidth;
1755d6c0b56eSmrg	output->mm_height = koutput->mmHeight;
1756d6c0b56eSmrg
1757d6c0b56eSmrg	output->subpixel_order = subpixel_conv_table[koutput->subpixel];
1758d6c0b56eSmrg	output->interlaceAllowed = TRUE;
1759d6c0b56eSmrg	output->doubleScanAllowed = TRUE;
1760d6c0b56eSmrg	output->driver_private = drmmode_output;
1761d6c0b56eSmrg
1762d6c0b56eSmrg	output->possible_crtcs = 0xffffffff;
1763d6c0b56eSmrg	for (i = 0; i < koutput->count_encoders; i++) {
1764d6c0b56eSmrg		output->possible_crtcs &= kencoders[i]->possible_crtcs;
1765d6c0b56eSmrg	}
1766d6c0b56eSmrg	/* work out the possible clones later */
1767d6c0b56eSmrg	output->possible_clones = 0;
1768d6c0b56eSmrg
1769d6c0b56eSmrg	for (i = 0; i < koutput->count_props; i++) {
1770d6c0b56eSmrg		props = drmModeGetProperty(pAMDGPUEnt->fd, koutput->props[i]);
1771d6c0b56eSmrg		if (props && (props->flags & DRM_MODE_PROP_ENUM)) {
1772d6c0b56eSmrg			if (!strcmp(props->name, "DPMS")) {
1773d6c0b56eSmrg				drmmode_output->dpms_enum_id =
1774d6c0b56eSmrg				    koutput->props[i];
1775d6c0b56eSmrg				drmModeFreeProperty(props);
1776d6c0b56eSmrg				break;
1777d6c0b56eSmrg			}
1778d6c0b56eSmrg			drmModeFreeProperty(props);
1779d6c0b56eSmrg		}
1780d6c0b56eSmrg	}
1781d6c0b56eSmrg
1782d6c0b56eSmrg	if (dynamic) {
1783d6c0b56eSmrg		output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
1784d6c0b56eSmrg		drmmode_output_create_resources(output);
1785d6c0b56eSmrg	}
1786d6c0b56eSmrg
1787d6c0b56eSmrg	return 1;
1788d6c0b56eSmrgout_free_encoders:
1789d6c0b56eSmrg	if (kencoders) {
1790d6c0b56eSmrg		for (i = 0; i < koutput->count_encoders; i++)
1791d6c0b56eSmrg			drmModeFreeEncoder(kencoders[i]);
1792d6c0b56eSmrg		free(kencoders);
1793d6c0b56eSmrg	}
1794d6c0b56eSmrg	drmModeFreeConnector(koutput);
1795d6c0b56eSmrg	return 0;
1796d6c0b56eSmrg}
1797d6c0b56eSmrg
1798d6c0b56eSmrguint32_t find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
1799d6c0b56eSmrg{
1800d6c0b56eSmrg	drmmode_output_private_ptr drmmode_output =
1801d6c0b56eSmrg	    output->driver_private, clone_drmout;
1802d6c0b56eSmrg	int i;
1803d6c0b56eSmrg	xf86OutputPtr clone_output;
1804d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1805d6c0b56eSmrg	int index_mask = 0;
1806d6c0b56eSmrg
1807d6c0b56eSmrg	if (drmmode_output->enc_clone_mask == 0)
1808d6c0b56eSmrg		return index_mask;
1809d6c0b56eSmrg
1810d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
1811d6c0b56eSmrg		clone_output = xf86_config->output[i];
1812d6c0b56eSmrg		clone_drmout = clone_output->driver_private;
1813d6c0b56eSmrg		if (output == clone_output)
1814d6c0b56eSmrg			continue;
1815d6c0b56eSmrg
1816d6c0b56eSmrg		if (clone_drmout->enc_mask == 0)
1817d6c0b56eSmrg			continue;
1818d6c0b56eSmrg		if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
1819d6c0b56eSmrg			index_mask |= (1 << i);
1820d6c0b56eSmrg	}
1821d6c0b56eSmrg	return index_mask;
1822d6c0b56eSmrg}
1823d6c0b56eSmrg
1824d6c0b56eSmrgstatic void drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
1825d6c0b56eSmrg{
1826d6c0b56eSmrg	int i, j;
1827d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1828d6c0b56eSmrg
1829d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
1830d6c0b56eSmrg		xf86OutputPtr output = xf86_config->output[i];
1831d6c0b56eSmrg		drmmode_output_private_ptr drmmode_output;
1832d6c0b56eSmrg
1833d6c0b56eSmrg		drmmode_output = output->driver_private;
1834d6c0b56eSmrg		drmmode_output->enc_clone_mask = 0xff;
1835d6c0b56eSmrg		/* and all the possible encoder clones for this output together */
1836d6c0b56eSmrg		for (j = 0; j < drmmode_output->mode_output->count_encoders;
1837d6c0b56eSmrg		     j++) {
1838d6c0b56eSmrg			int k;
1839d6c0b56eSmrg			for (k = 0; k < mode_res->count_encoders; k++) {
1840d6c0b56eSmrg				if (mode_res->encoders[k] ==
1841d6c0b56eSmrg				    drmmode_output->
1842d6c0b56eSmrg				    mode_encoders[j]->encoder_id)
1843d6c0b56eSmrg					drmmode_output->enc_mask |= (1 << k);
1844d6c0b56eSmrg			}
1845d6c0b56eSmrg
1846d6c0b56eSmrg			drmmode_output->enc_clone_mask &=
1847d6c0b56eSmrg			    drmmode_output->mode_encoders[j]->possible_clones;
1848d6c0b56eSmrg		}
1849d6c0b56eSmrg	}
1850d6c0b56eSmrg
1851d6c0b56eSmrg	for (i = 0; i < xf86_config->num_output; i++) {
1852d6c0b56eSmrg		xf86OutputPtr output = xf86_config->output[i];
1853d6c0b56eSmrg		output->possible_clones = find_clones(scrn, output);
1854d6c0b56eSmrg	}
1855d6c0b56eSmrg}
1856d6c0b56eSmrg
1857d6c0b56eSmrg/* returns pitch alignment in pixels */
1858d6c0b56eSmrgint drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe)
1859d6c0b56eSmrg{
1860d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
1861d6c0b56eSmrg
1862d6c0b56eSmrg	if (info->have_tiling_info)
1863d6c0b56eSmrg		/* linear aligned requirements */
1864d6c0b56eSmrg		return MAX(64, info->group_bytes / bpe);
1865d6c0b56eSmrg	else
1866d6c0b56eSmrg		/* default to 512 elements if we don't know the real
1867d6c0b56eSmrg		 * group size otherwise the kernel may reject the CS
1868d6c0b56eSmrg		 * if the group sizes don't match as the pitch won't
1869d6c0b56eSmrg		 * be aligned properly.
1870d6c0b56eSmrg		 */
1871d6c0b56eSmrg		return 512;
1872d6c0b56eSmrg}
1873d6c0b56eSmrg
1874d6c0b56eSmrgstatic Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
1875d6c0b56eSmrg{
1876d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1877d6c0b56eSmrg	drmmode_crtc_private_ptr
1878d6c0b56eSmrg	    drmmode_crtc = xf86_config->crtc[0]->driver_private;
1879d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
1880d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
1881d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
1882d6c0b56eSmrg	struct amdgpu_buffer *old_front = NULL;
1883d6c0b56eSmrg	ScreenPtr screen = xf86ScrnToScreen(scrn);
1884d6c0b56eSmrg	uint32_t old_fb_id;
1885d6c0b56eSmrg	int i, pitch, old_width, old_height, old_pitch;
1886d6c0b56eSmrg	int cpp = info->pixel_bytes;
1887d6c0b56eSmrg	PixmapPtr ppix = screen->GetScreenPixmap(screen);
1888d6c0b56eSmrg	uint32_t bo_handle;
1889d6c0b56eSmrg	void *fb_shadow;
1890d6c0b56eSmrg	int hint = 0;
1891d6c0b56eSmrg	xRectangle rect;
1892d6c0b56eSmrg	GCPtr gc;
1893d6c0b56eSmrg
1894d6c0b56eSmrg	if (scrn->virtualX == width && scrn->virtualY == height)
1895d6c0b56eSmrg		return TRUE;
1896d6c0b56eSmrg
1897d6c0b56eSmrg	if (info->shadow_primary)
1898d6c0b56eSmrg		hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
1899d6c0b56eSmrg	else if (!info->use_glamor)
1900d6c0b56eSmrg		hint = AMDGPU_CREATE_PIXMAP_LINEAR;
1901d6c0b56eSmrg
1902d6c0b56eSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO,
1903d6c0b56eSmrg		   "Allocate new frame buffer %dx%d\n", width, height);
1904d6c0b56eSmrg
1905d6c0b56eSmrg	old_width = scrn->virtualX;
1906d6c0b56eSmrg	old_height = scrn->virtualY;
1907d6c0b56eSmrg	old_pitch = scrn->displayWidth;
1908d6c0b56eSmrg	old_fb_id = drmmode->fb_id;
1909d6c0b56eSmrg	old_front = info->front_buffer;
1910d6c0b56eSmrg
1911d6c0b56eSmrg	scrn->virtualX = width;
1912d6c0b56eSmrg	scrn->virtualY = height;
1913d6c0b56eSmrg
1914d6c0b56eSmrg	info->front_buffer =
1915d6c0b56eSmrg		amdgpu_alloc_pixmap_bo(scrn, scrn->virtualX, scrn->virtualY,
1916d6c0b56eSmrg				       scrn->depth, hint, scrn->bitsPerPixel,
1917d6c0b56eSmrg				       &pitch);
1918d6c0b56eSmrg	if (!info->front_buffer) {
1919d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1920d6c0b56eSmrg			   "Failed to allocate front buffer memory\n");
1921d6c0b56eSmrg		goto fail;
1922d6c0b56eSmrg	}
1923d6c0b56eSmrg
1924d6c0b56eSmrg	if (!info->use_glamor && amdgpu_bo_map(scrn, info->front_buffer) != 0) {
1925d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1926d6c0b56eSmrg			   "Failed to map front buffer memory\n");
1927d6c0b56eSmrg		goto fail;
1928d6c0b56eSmrg	}
1929d6c0b56eSmrg
1930d6c0b56eSmrg	xf86DrvMsg(scrn->scrnIndex, X_INFO, " => pitch %d bytes\n", pitch);
1931d6c0b56eSmrg	scrn->displayWidth = pitch / cpp;
1932d6c0b56eSmrg
1933d6c0b56eSmrg	if (!amdgpu_bo_get_handle(info->front_buffer, &bo_handle)) {
1934d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1935d6c0b56eSmrg			   "Failed to get front buffer handle\n");
1936d6c0b56eSmrg		goto fail;
1937d6c0b56eSmrg	}
1938d6c0b56eSmrg
1939d6c0b56eSmrg	if (drmModeAddFB(pAMDGPUEnt->fd, width, height, scrn->depth,
1940d6c0b56eSmrg			 scrn->bitsPerPixel, pitch,
1941d6c0b56eSmrg			 bo_handle, &drmmode->fb_id) != 0) {
1942d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1943d6c0b56eSmrg			   "drmModeAddFB failed for front buffer\n");
1944d6c0b56eSmrg		goto fail;
1945d6c0b56eSmrg	}
1946d6c0b56eSmrg
1947d6c0b56eSmrg	if (info->use_glamor ||
1948d6c0b56eSmrg	    (info->front_buffer->flags & AMDGPU_BO_FLAGS_GBM)) {
1949d6c0b56eSmrg		amdgpu_set_pixmap_bo(ppix, info->front_buffer);
1950d6c0b56eSmrg		screen->ModifyPixmapHeader(ppix,
1951d6c0b56eSmrg					   width, height, -1, -1, pitch, info->front_buffer->cpu_ptr);
1952d6c0b56eSmrg	} else {
1953d6c0b56eSmrg		fb_shadow = calloc(1, pitch * scrn->virtualY);
1954d6c0b56eSmrg		if (fb_shadow == NULL)
1955d6c0b56eSmrg			goto fail;
1956d6c0b56eSmrg		free(info->fb_shadow);
1957d6c0b56eSmrg		info->fb_shadow = fb_shadow;
1958d6c0b56eSmrg		screen->ModifyPixmapHeader(ppix,
1959d6c0b56eSmrg					   width, height, -1, -1, pitch,
1960d6c0b56eSmrg					   info->fb_shadow);
1961d6c0b56eSmrg	}
1962d6c0b56eSmrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,9,99,1,0)
1963d6c0b56eSmrg	scrn->pixmapPrivate.ptr = ppix->devPrivate.ptr;
1964d6c0b56eSmrg#endif
1965d6c0b56eSmrg
1966d6c0b56eSmrg	if (info->use_glamor)
1967d6c0b56eSmrg		amdgpu_glamor_create_screen_resources(scrn->pScreen);
1968d6c0b56eSmrg
1969d6c0b56eSmrg	/* Clear new buffer */
1970d6c0b56eSmrg	gc = GetScratchGC(ppix->drawable.depth, scrn->pScreen);
1971d6c0b56eSmrg	ValidateGC(&ppix->drawable, gc);
1972d6c0b56eSmrg	rect.x = 0;
1973d6c0b56eSmrg	rect.y = 0;
1974d6c0b56eSmrg	rect.width = width;
1975d6c0b56eSmrg	rect.height = height;
1976d6c0b56eSmrg	info->force_accel = TRUE;
1977d6c0b56eSmrg	(*gc->ops->PolyFillRect)(&ppix->drawable, gc, 1, &rect);
1978d6c0b56eSmrg	info->force_accel = FALSE;
1979d6c0b56eSmrg	FreeScratchGC(gc);
1980d6c0b56eSmrg	amdgpu_glamor_finish(scrn);
1981d6c0b56eSmrg
1982d6c0b56eSmrg	for (i = 0; i < xf86_config->num_crtc; i++) {
1983d6c0b56eSmrg		xf86CrtcPtr crtc = xf86_config->crtc[i];
1984d6c0b56eSmrg
1985d6c0b56eSmrg		if (!crtc->enabled)
1986d6c0b56eSmrg			continue;
1987d6c0b56eSmrg
1988d6c0b56eSmrg		drmmode_set_mode_major(crtc, &crtc->mode,
1989d6c0b56eSmrg				       crtc->rotation, crtc->x, crtc->y);
1990d6c0b56eSmrg	}
1991d6c0b56eSmrg
1992d6c0b56eSmrg	if (old_fb_id)
1993d6c0b56eSmrg		drmModeRmFB(pAMDGPUEnt->fd, old_fb_id);
1994d6c0b56eSmrg	if (old_front) {
1995d6c0b56eSmrg		amdgpu_bo_unref(&old_front);
1996d6c0b56eSmrg	}
1997d6c0b56eSmrg
1998d6c0b56eSmrg	return TRUE;
1999d6c0b56eSmrg
2000d6c0b56eSmrgfail:
2001d6c0b56eSmrg	if (info->front_buffer) {
2002d6c0b56eSmrg		amdgpu_bo_unref(&info->front_buffer);
2003d6c0b56eSmrg	}
2004d6c0b56eSmrg	info->front_buffer = old_front;
2005d6c0b56eSmrg	scrn->virtualX = old_width;
2006d6c0b56eSmrg	scrn->virtualY = old_height;
2007d6c0b56eSmrg	scrn->displayWidth = old_pitch;
2008d6c0b56eSmrg	drmmode->fb_id = old_fb_id;
2009d6c0b56eSmrg
2010d6c0b56eSmrg	return FALSE;
2011d6c0b56eSmrg}
2012d6c0b56eSmrg
2013d6c0b56eSmrgstatic const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
2014d6c0b56eSmrg	drmmode_xf86crtc_resize
2015d6c0b56eSmrg};
2016d6c0b56eSmrg
2017d6c0b56eSmrgstatic void
2018d6c0b56eSmrgdrmmode_flip_abort(xf86CrtcPtr crtc, void *event_data)
2019d6c0b56eSmrg{
2020d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2021d6c0b56eSmrg	drmmode_flipdata_ptr flipdata = event_data;
2022d6c0b56eSmrg
2023d6c0b56eSmrg	if (--flipdata->flip_count == 0) {
2024d6c0b56eSmrg		if (flipdata->fe_crtc)
2025d6c0b56eSmrg			crtc = flipdata->fe_crtc;
2026d6c0b56eSmrg		flipdata->abort(crtc, flipdata->event_data);
2027d6c0b56eSmrg		free(flipdata);
2028d6c0b56eSmrg	}
2029d6c0b56eSmrg
2030d6c0b56eSmrg	drmmode_crtc->flip_pending = FALSE;
2031d6c0b56eSmrg}
2032d6c0b56eSmrg
2033d6c0b56eSmrgstatic void
2034d6c0b56eSmrgdrmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *event_data)
2035d6c0b56eSmrg{
2036d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2037d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
2038d6c0b56eSmrg	drmmode_flipdata_ptr flipdata = event_data;
2039d6c0b56eSmrg
2040d6c0b56eSmrg	/* Is this the event whose info shall be delivered to higher level? */
2041d6c0b56eSmrg	if (crtc == flipdata->fe_crtc) {
2042d6c0b56eSmrg		/* Yes: Cache msc, ust for later delivery. */
2043d6c0b56eSmrg		flipdata->fe_frame = frame;
2044d6c0b56eSmrg		flipdata->fe_usec = usec;
2045d6c0b56eSmrg	}
2046d6c0b56eSmrg
2047d6c0b56eSmrg	if (--flipdata->flip_count == 0) {
2048d6c0b56eSmrg		/* Deliver cached msc, ust from reference crtc to flip event handler */
2049d6c0b56eSmrg		if (flipdata->fe_crtc)
2050d6c0b56eSmrg			crtc = flipdata->fe_crtc;
2051d6c0b56eSmrg		flipdata->handler(crtc, flipdata->fe_frame, flipdata->fe_usec,
2052d6c0b56eSmrg				  flipdata->event_data);
2053d6c0b56eSmrg
2054d6c0b56eSmrg		/* Release framebuffer */
2055d6c0b56eSmrg		drmModeRmFB(pAMDGPUEnt->fd, flipdata->old_fb_id);
2056d6c0b56eSmrg
2057d6c0b56eSmrg		free(flipdata);
2058d6c0b56eSmrg	}
2059d6c0b56eSmrg
2060d6c0b56eSmrg	drmmode_crtc->flip_pending = FALSE;
2061d6c0b56eSmrg}
2062d6c0b56eSmrg
2063d6c0b56eSmrgstatic void drm_wakeup_handler(pointer data, int err, pointer p)
2064d6c0b56eSmrg{
2065d6c0b56eSmrg	drmmode_ptr drmmode = data;
2066d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(drmmode->scrn);
2067d6c0b56eSmrg	fd_set *read_mask = p;
2068d6c0b56eSmrg
2069d6c0b56eSmrg	if (err >= 0 && FD_ISSET(pAMDGPUEnt->fd, read_mask)) {
2070d6c0b56eSmrg		drmHandleEvent(pAMDGPUEnt->fd, &drmmode->event_context);
2071d6c0b56eSmrg	}
2072d6c0b56eSmrg}
2073d6c0b56eSmrg
2074d6c0b56eSmrgBool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
2075d6c0b56eSmrg{
2076d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2077d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2078d6c0b56eSmrg	int i, num_dvi = 0, num_hdmi = 0;
2079d6c0b56eSmrg	unsigned int crtcs_needed = 0;
2080d6c0b56eSmrg	drmModeResPtr mode_res;
2081d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
2082d6c0b56eSmrg	char *bus_id_string, *provider_name;
2083d6c0b56eSmrg#endif
2084d6c0b56eSmrg
2085d6c0b56eSmrg	xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
2086d6c0b56eSmrg
2087d6c0b56eSmrg	drmmode->scrn = pScrn;
2088d6c0b56eSmrg	drmmode->cpp = cpp;
2089d6c0b56eSmrg	mode_res = drmModeGetResources(pAMDGPUEnt->fd);
2090d6c0b56eSmrg	if (!mode_res)
2091d6c0b56eSmrg		return FALSE;
2092d6c0b56eSmrg
2093d6c0b56eSmrg	drmmode->count_crtcs = mode_res->count_crtcs;
2094d6c0b56eSmrg	xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
2095d6c0b56eSmrg			     mode_res->max_height);
2096d6c0b56eSmrg
2097d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2098d6c0b56eSmrg		       "Initializing outputs ...\n");
2099d6c0b56eSmrg	for (i = 0; i < mode_res->count_connectors; i++)
2100d6c0b56eSmrg		crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, &num_dvi, &num_hdmi, 0);
2101d6c0b56eSmrg
2102d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2103d6c0b56eSmrg		       "%d crtcs needed for screen.\n", crtcs_needed);
2104d6c0b56eSmrg
2105d6c0b56eSmrg	if (!info->use_glamor) {
2106d6c0b56eSmrg		/* Rotation requires hardware acceleration */
2107d6c0b56eSmrg		drmmode_crtc_funcs.shadow_allocate = NULL;
2108d6c0b56eSmrg		drmmode_crtc_funcs.shadow_create = NULL;
2109d6c0b56eSmrg		drmmode_crtc_funcs.shadow_destroy = NULL;
2110d6c0b56eSmrg	}
2111d6c0b56eSmrg
2112d6c0b56eSmrg	for (i = 0; i < mode_res->count_crtcs; i++)
2113d6c0b56eSmrg		if (!xf86IsEntityShared(pScrn->entityList[0]) ||
2114d6c0b56eSmrg		    (crtcs_needed && !(pAMDGPUEnt->assigned_crtcs & (1 << i))))
2115d6c0b56eSmrg			crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
2116d6c0b56eSmrg
2117d6c0b56eSmrg	/* All ZaphodHeads outputs provided with matching crtcs? */
2118d6c0b56eSmrg	if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
2119d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2120d6c0b56eSmrg			   "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
2121d6c0b56eSmrg			   crtcs_needed);
2122d6c0b56eSmrg
2123d6c0b56eSmrg	/* workout clones */
2124d6c0b56eSmrg	drmmode_clones_init(pScrn, drmmode, mode_res);
2125d6c0b56eSmrg
2126d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
2127d6c0b56eSmrg	bus_id_string = DRICreatePCIBusID(info->PciInfo);
2128d6c0b56eSmrg	XNFasprintf(&provider_name, "%s @ %s", pScrn->chipset, bus_id_string);
2129d6c0b56eSmrg	free(bus_id_string);
2130d6c0b56eSmrg	xf86ProviderSetup(pScrn, NULL, provider_name);
2131d6c0b56eSmrg	free(provider_name);
2132d6c0b56eSmrg#endif
2133d6c0b56eSmrg
2134d6c0b56eSmrg	xf86InitialConfiguration(pScrn, TRUE);
2135d6c0b56eSmrg
2136d6c0b56eSmrg	drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
2137d6c0b56eSmrg	drmmode->event_context.vblank_handler = amdgpu_drm_queue_handler;
2138d6c0b56eSmrg	drmmode->event_context.page_flip_handler = amdgpu_drm_queue_handler;
2139d6c0b56eSmrg
2140d6c0b56eSmrg	drmModeFreeResources(mode_res);
2141d6c0b56eSmrg	return TRUE;
2142d6c0b56eSmrg}
2143d6c0b56eSmrg
2144d6c0b56eSmrgvoid drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
2145d6c0b56eSmrg{
2146d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2147d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2148d6c0b56eSmrg
2149d6c0b56eSmrg	info->drmmode_inited = TRUE;
2150d6c0b56eSmrg	if (pAMDGPUEnt->fd_wakeup_registered != serverGeneration) {
2151d6c0b56eSmrg		AddGeneralSocket(pAMDGPUEnt->fd);
2152d6c0b56eSmrg		RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA,
2153d6c0b56eSmrg					       drm_wakeup_handler, drmmode);
2154d6c0b56eSmrg		pAMDGPUEnt->fd_wakeup_registered = serverGeneration;
2155d6c0b56eSmrg		pAMDGPUEnt->fd_wakeup_ref = 1;
2156d6c0b56eSmrg	} else
2157d6c0b56eSmrg		pAMDGPUEnt->fd_wakeup_ref++;
2158d6c0b56eSmrg}
2159d6c0b56eSmrg
2160d6c0b56eSmrgvoid drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
2161d6c0b56eSmrg{
2162d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2163d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2164d6c0b56eSmrg
2165d6c0b56eSmrg	if (!info->drmmode_inited)
2166d6c0b56eSmrg		return;
2167d6c0b56eSmrg
2168d6c0b56eSmrg	if (pAMDGPUEnt->fd_wakeup_registered == serverGeneration &&
2169d6c0b56eSmrg	    !--pAMDGPUEnt->fd_wakeup_ref) {
2170d6c0b56eSmrg		RemoveGeneralSocket(pAMDGPUEnt->fd);
2171d6c0b56eSmrg		RemoveBlockAndWakeupHandlers((BlockHandlerProcPtr) NoopDDA,
2172d6c0b56eSmrg					     drm_wakeup_handler, drmmode);
2173d6c0b56eSmrg	}
2174d6c0b56eSmrg}
2175d6c0b56eSmrg
2176d6c0b56eSmrgvoid drmmode_set_cursor(ScrnInfoPtr scrn, drmmode_ptr drmmode, int id,
2177d6c0b56eSmrg			struct amdgpu_buffer *bo)
2178d6c0b56eSmrg{
2179d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2180d6c0b56eSmrg	xf86CrtcPtr crtc = xf86_config->crtc[id];
2181d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2182d6c0b56eSmrg
2183d6c0b56eSmrg	drmmode_crtc->cursor_buffer = bo;
2184d6c0b56eSmrg}
2185d6c0b56eSmrg
2186d6c0b56eSmrgvoid drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
2187d6c0b56eSmrg{
2188d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2189d6c0b56eSmrg	xf86OutputPtr output = config->output[config->compat_output];
2190d6c0b56eSmrg	xf86CrtcPtr crtc = output->crtc;
2191d6c0b56eSmrg
2192d6c0b56eSmrg	if (crtc && crtc->enabled) {
2193d6c0b56eSmrg		drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
2194d6c0b56eSmrg	}
2195d6c0b56eSmrg}
2196d6c0b56eSmrg
2197d6c0b56eSmrgBool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
2198d6c0b56eSmrg			       Bool set_hw)
2199d6c0b56eSmrg{
2200d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2201d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2202d6c0b56eSmrg	int c;
2203d6c0b56eSmrg
2204d6c0b56eSmrg	for (c = 0; c < config->num_crtc; c++) {
2205d6c0b56eSmrg		xf86CrtcPtr crtc = config->crtc[c];
2206d6c0b56eSmrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2207d6c0b56eSmrg		xf86OutputPtr output = NULL;
2208d6c0b56eSmrg		int o;
2209d6c0b56eSmrg
2210d6c0b56eSmrg		/* Skip disabled CRTCs */
2211d6c0b56eSmrg		if (!crtc->enabled) {
2212d6c0b56eSmrg			if (set_hw) {
2213d6c0b56eSmrg				drmmode_do_crtc_dpms(crtc, DPMSModeOff);
2214d6c0b56eSmrg				drmModeSetCrtc(pAMDGPUEnt->fd,
2215d6c0b56eSmrg					       drmmode_crtc->mode_crtc->crtc_id,
2216d6c0b56eSmrg					       0, 0, 0, NULL, 0, NULL);
2217d6c0b56eSmrg			}
2218d6c0b56eSmrg			continue;
2219d6c0b56eSmrg		}
2220d6c0b56eSmrg
2221d6c0b56eSmrg		if (config->output[config->compat_output]->crtc == crtc)
2222d6c0b56eSmrg			output = config->output[config->compat_output];
2223d6c0b56eSmrg		else {
2224d6c0b56eSmrg			for (o = 0; o < config->num_output; o++)
2225d6c0b56eSmrg				if (config->output[o]->crtc == crtc) {
2226d6c0b56eSmrg					output = config->output[o];
2227d6c0b56eSmrg					break;
2228d6c0b56eSmrg				}
2229d6c0b56eSmrg		}
2230d6c0b56eSmrg		/* paranoia */
2231d6c0b56eSmrg		if (!output)
2232d6c0b56eSmrg			continue;
2233d6c0b56eSmrg
2234d6c0b56eSmrg		/* Mark that we'll need to re-set the mode for sure */
2235d6c0b56eSmrg		memset(&crtc->mode, 0, sizeof(crtc->mode));
2236d6c0b56eSmrg		if (!crtc->desiredMode.CrtcHDisplay) {
2237d6c0b56eSmrg			DisplayModePtr mode = xf86OutputFindClosestMode(output,
2238d6c0b56eSmrg									pScrn->
2239d6c0b56eSmrg									currentMode);
2240d6c0b56eSmrg
2241d6c0b56eSmrg			if (!mode)
2242d6c0b56eSmrg				return FALSE;
2243d6c0b56eSmrg			crtc->desiredMode = *mode;
2244d6c0b56eSmrg			crtc->desiredRotation = RR_Rotate_0;
2245d6c0b56eSmrg			crtc->desiredX = 0;
2246d6c0b56eSmrg			crtc->desiredY = 0;
2247d6c0b56eSmrg		}
2248d6c0b56eSmrg
2249d6c0b56eSmrg		if (set_hw) {
2250d6c0b56eSmrg			if (!crtc->funcs->set_mode_major(crtc, &crtc->desiredMode,
2251d6c0b56eSmrg							 crtc->desiredRotation,
2252d6c0b56eSmrg							 crtc->desiredX,
2253d6c0b56eSmrg							 crtc->desiredY))
2254d6c0b56eSmrg				return FALSE;
2255d6c0b56eSmrg		} else {
2256d6c0b56eSmrg			crtc->mode = crtc->desiredMode;
2257d6c0b56eSmrg			crtc->rotation = crtc->desiredRotation;
2258d6c0b56eSmrg			crtc->x = crtc->desiredX;
2259d6c0b56eSmrg			crtc->y = crtc->desiredY;
2260d6c0b56eSmrg			if (!drmmode_handle_transform(crtc))
2261d6c0b56eSmrg				return FALSE;
2262d6c0b56eSmrg		}
2263d6c0b56eSmrg	}
2264d6c0b56eSmrg	return TRUE;
2265d6c0b56eSmrg}
2266d6c0b56eSmrg
2267d6c0b56eSmrgstatic void drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
2268d6c0b56eSmrg				 int *indices, LOCO * colors, VisualPtr pVisual)
2269d6c0b56eSmrg{
2270d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2271d6c0b56eSmrg	uint16_t lut_r[256], lut_g[256], lut_b[256];
2272d6c0b56eSmrg	int index, j, i;
2273d6c0b56eSmrg	int c;
2274d6c0b56eSmrg
2275d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
2276d6c0b56eSmrg		xf86CrtcPtr crtc = xf86_config->crtc[c];
2277d6c0b56eSmrg		drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2278d6c0b56eSmrg
2279d6c0b56eSmrg		for (i = 0; i < 256; i++) {
2280d6c0b56eSmrg			lut_r[i] = drmmode_crtc->lut_r[i] << 6;
2281d6c0b56eSmrg			lut_g[i] = drmmode_crtc->lut_g[i] << 6;
2282d6c0b56eSmrg			lut_b[i] = drmmode_crtc->lut_b[i] << 6;
2283d6c0b56eSmrg		}
2284d6c0b56eSmrg
2285d6c0b56eSmrg		switch (pScrn->depth) {
2286d6c0b56eSmrg		case 15:
2287d6c0b56eSmrg			for (i = 0; i < numColors; i++) {
2288d6c0b56eSmrg				index = indices[i];
2289d6c0b56eSmrg				for (j = 0; j < 8; j++) {
2290d6c0b56eSmrg					lut_r[index * 8 + j] =
2291d6c0b56eSmrg					    colors[index].red << 6;
2292d6c0b56eSmrg					lut_g[index * 8 + j] =
2293d6c0b56eSmrg					    colors[index].green << 6;
2294d6c0b56eSmrg					lut_b[index * 8 + j] =
2295d6c0b56eSmrg					    colors[index].blue << 6;
2296d6c0b56eSmrg				}
2297d6c0b56eSmrg			}
2298d6c0b56eSmrg			break;
2299d6c0b56eSmrg		case 16:
2300d6c0b56eSmrg			for (i = 0; i < numColors; i++) {
2301d6c0b56eSmrg				index = indices[i];
2302d6c0b56eSmrg
2303d6c0b56eSmrg				if (i <= 31) {
2304d6c0b56eSmrg					for (j = 0; j < 8; j++) {
2305d6c0b56eSmrg						lut_r[index * 8 + j] =
2306d6c0b56eSmrg						    colors[index].red << 6;
2307d6c0b56eSmrg						lut_b[index * 8 + j] =
2308d6c0b56eSmrg						    colors[index].blue << 6;
2309d6c0b56eSmrg					}
2310d6c0b56eSmrg				}
2311d6c0b56eSmrg
2312d6c0b56eSmrg				for (j = 0; j < 4; j++) {
2313d6c0b56eSmrg					lut_g[index * 4 + j] =
2314d6c0b56eSmrg					    colors[index].green << 6;
2315d6c0b56eSmrg				}
2316d6c0b56eSmrg			}
2317d6c0b56eSmrg			break;
2318d6c0b56eSmrg		default:
2319d6c0b56eSmrg			for (i = 0; i < numColors; i++) {
2320d6c0b56eSmrg				index = indices[i];
2321d6c0b56eSmrg				lut_r[index] = colors[index].red << 6;
2322d6c0b56eSmrg				lut_g[index] = colors[index].green << 6;
2323d6c0b56eSmrg				lut_b[index] = colors[index].blue << 6;
2324d6c0b56eSmrg			}
2325d6c0b56eSmrg			break;
2326d6c0b56eSmrg		}
2327d6c0b56eSmrg
2328d6c0b56eSmrg		/* Make the change through RandR */
2329d6c0b56eSmrg		if (crtc->randr_crtc)
2330d6c0b56eSmrg			RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
2331d6c0b56eSmrg		else
2332d6c0b56eSmrg			crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
2333d6c0b56eSmrg	}
2334d6c0b56eSmrg}
2335d6c0b56eSmrg
2336d6c0b56eSmrgBool drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
2337d6c0b56eSmrg{
2338d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2339d6c0b56eSmrg
2340d6c0b56eSmrg	if (xf86_config->num_crtc) {
2341d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2342d6c0b56eSmrg			       "Initializing kms color map\n");
2343d6c0b56eSmrg		if (!miCreateDefColormap(pScreen))
2344d6c0b56eSmrg			return FALSE;
2345d6c0b56eSmrg		/* all amdgpus support 10 bit CLUTs */
2346d6c0b56eSmrg		if (!xf86HandleColormaps(pScreen, 256, 10,
2347d6c0b56eSmrg					 drmmode_load_palette, NULL,
2348d6c0b56eSmrg					 CMAP_PALETTED_TRUECOLOR
2349d6c0b56eSmrg#if 0				/* This option messes up text mode! (eich@suse.de) */
2350d6c0b56eSmrg					 | CMAP_LOAD_EVEN_IF_OFFSCREEN
2351d6c0b56eSmrg#endif
2352d6c0b56eSmrg					 | CMAP_RELOAD_ON_MODE_SWITCH))
2353d6c0b56eSmrg			return FALSE;
2354d6c0b56eSmrg	}
2355d6c0b56eSmrg	return TRUE;
2356d6c0b56eSmrg}
2357d6c0b56eSmrg
2358d6c0b56eSmrg
2359d6c0b56eSmrgvoid
2360d6c0b56eSmrgamdgpu_mode_hotplug(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2361d6c0b56eSmrg{
2362d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2363d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
2364d6c0b56eSmrg	drmModeResPtr mode_res;
2365d6c0b56eSmrg	int i, j;
2366d6c0b56eSmrg	Bool found;
2367d6c0b56eSmrg	Bool changed = FALSE;
2368d6c0b56eSmrg
2369d6c0b56eSmrg	mode_res = drmModeGetResources(pAMDGPUEnt->fd);
2370d6c0b56eSmrg	if (!mode_res)
2371d6c0b56eSmrg		goto out;
2372d6c0b56eSmrg
2373d6c0b56eSmrgrestart_destroy:
2374d6c0b56eSmrg	for (i = 0; i < config->num_output; i++) {
2375d6c0b56eSmrg		xf86OutputPtr output = config->output[i];
2376d6c0b56eSmrg		drmmode_output_private_ptr drmmode_output = output->driver_private;
2377d6c0b56eSmrg		found = FALSE;
2378d6c0b56eSmrg		for (j = 0; j < mode_res->count_connectors; j++) {
2379d6c0b56eSmrg			if (mode_res->connectors[j] == drmmode_output->output_id) {
2380d6c0b56eSmrg				found = TRUE;
2381d6c0b56eSmrg				break;
2382d6c0b56eSmrg			}
2383d6c0b56eSmrg		}
2384d6c0b56eSmrg		if (found)
2385d6c0b56eSmrg			continue;
2386d6c0b56eSmrg
2387d6c0b56eSmrg		drmModeFreeConnector(drmmode_output->mode_output);
2388d6c0b56eSmrg		drmmode_output->mode_output = NULL;
2389d6c0b56eSmrg		drmmode_output->output_id = -1;
2390d6c0b56eSmrg
2391d6c0b56eSmrg		changed = TRUE;
2392d6c0b56eSmrg		if (drmmode->delete_dp_12_displays) {
2393d6c0b56eSmrg			RROutputDestroy(output->randr_output);
2394d6c0b56eSmrg			xf86OutputDestroy(output);
2395d6c0b56eSmrg			goto restart_destroy;
2396d6c0b56eSmrg		}
2397d6c0b56eSmrg	}
2398d6c0b56eSmrg
2399d6c0b56eSmrg	/* find new output ids we don't have outputs for */
2400d6c0b56eSmrg	for (i = 0; i < mode_res->count_connectors; i++) {
2401d6c0b56eSmrg		found = FALSE;
2402d6c0b56eSmrg
2403d6c0b56eSmrg		for (j = 0; j < config->num_output; j++) {
2404d6c0b56eSmrg			xf86OutputPtr output = config->output[j];
2405d6c0b56eSmrg			drmmode_output_private_ptr drmmode_output;
2406d6c0b56eSmrg
2407d6c0b56eSmrg			drmmode_output = output->driver_private;
2408d6c0b56eSmrg			if (mode_res->connectors[i] == drmmode_output->output_id) {
2409d6c0b56eSmrg				found = TRUE;
2410d6c0b56eSmrg				break;
2411d6c0b56eSmrg			}
2412d6c0b56eSmrg		}
2413d6c0b56eSmrg		if (found)
2414d6c0b56eSmrg			continue;
2415d6c0b56eSmrg
2416d6c0b56eSmrg		changed = TRUE;
2417d6c0b56eSmrg		drmmode_output_init(scrn, drmmode, mode_res, i, NULL, NULL, 1);
2418d6c0b56eSmrg	}
2419d6c0b56eSmrg
2420d6c0b56eSmrg	if (changed) {
2421d6c0b56eSmrg#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,14,99,2,0)
2422d6c0b56eSmrg		RRSetChanged(xf86ScrnToScreen(scrn));
2423d6c0b56eSmrg#else
2424d6c0b56eSmrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(scrn->pScreen);
2425d6c0b56eSmrg		rrScrPriv->changed = TRUE;
2426d6c0b56eSmrg#endif
2427d6c0b56eSmrg		RRTellChanged(xf86ScrnToScreen(scrn));
2428d6c0b56eSmrg	}
2429d6c0b56eSmrg
2430d6c0b56eSmrg	drmModeFreeResources(mode_res);
2431d6c0b56eSmrgout:
2432d6c0b56eSmrg	RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
2433d6c0b56eSmrg}
2434d6c0b56eSmrg
2435d6c0b56eSmrg#ifdef HAVE_LIBUDEV
2436d6c0b56eSmrgstatic void drmmode_handle_uevents(int fd, void *closure)
2437d6c0b56eSmrg{
2438d6c0b56eSmrg	drmmode_ptr drmmode = closure;
2439d6c0b56eSmrg	ScrnInfoPtr scrn = drmmode->scrn;
2440d6c0b56eSmrg	struct udev_device *dev;
2441d6c0b56eSmrg	dev = udev_monitor_receive_device(drmmode->uevent_monitor);
2442d6c0b56eSmrg	if (!dev)
2443d6c0b56eSmrg		return;
2444d6c0b56eSmrg
2445d6c0b56eSmrg	amdgpu_mode_hotplug(scrn, drmmode);
2446d6c0b56eSmrg	udev_device_unref(dev);
2447d6c0b56eSmrg}
2448d6c0b56eSmrg#endif
2449d6c0b56eSmrg
2450d6c0b56eSmrgvoid drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2451d6c0b56eSmrg{
2452d6c0b56eSmrg#ifdef HAVE_LIBUDEV
2453d6c0b56eSmrg	struct udev *u;
2454d6c0b56eSmrg	struct udev_monitor *mon;
2455d6c0b56eSmrg
2456d6c0b56eSmrg	u = udev_new();
2457d6c0b56eSmrg	if (!u)
2458d6c0b56eSmrg		return;
2459d6c0b56eSmrg	mon = udev_monitor_new_from_netlink(u, "udev");
2460d6c0b56eSmrg	if (!mon) {
2461d6c0b56eSmrg		udev_unref(u);
2462d6c0b56eSmrg		return;
2463d6c0b56eSmrg	}
2464d6c0b56eSmrg
2465d6c0b56eSmrg	if (udev_monitor_filter_add_match_subsystem_devtype(mon,
2466d6c0b56eSmrg							    "drm",
2467d6c0b56eSmrg							    "drm_minor") < 0 ||
2468d6c0b56eSmrg	    udev_monitor_enable_receiving(mon) < 0) {
2469d6c0b56eSmrg		udev_monitor_unref(mon);
2470d6c0b56eSmrg		udev_unref(u);
2471d6c0b56eSmrg		return;
2472d6c0b56eSmrg	}
2473d6c0b56eSmrg
2474d6c0b56eSmrg	drmmode->uevent_handler =
2475d6c0b56eSmrg	    xf86AddGeneralHandler(udev_monitor_get_fd(mon),
2476d6c0b56eSmrg				  drmmode_handle_uevents, drmmode);
2477d6c0b56eSmrg
2478d6c0b56eSmrg	drmmode->uevent_monitor = mon;
2479d6c0b56eSmrg#endif
2480d6c0b56eSmrg}
2481d6c0b56eSmrg
2482d6c0b56eSmrgvoid drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
2483d6c0b56eSmrg{
2484d6c0b56eSmrg#ifdef HAVE_LIBUDEV
2485d6c0b56eSmrg	if (drmmode->uevent_handler) {
2486d6c0b56eSmrg		struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
2487d6c0b56eSmrg		xf86RemoveGeneralHandler(drmmode->uevent_handler);
2488d6c0b56eSmrg
2489d6c0b56eSmrg		udev_monitor_unref(drmmode->uevent_monitor);
2490d6c0b56eSmrg		udev_unref(u);
2491d6c0b56eSmrg	}
2492d6c0b56eSmrg#endif
2493d6c0b56eSmrg}
2494d6c0b56eSmrg
2495d6c0b56eSmrgBool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
2496d6c0b56eSmrg			PixmapPtr new_front, uint64_t id, void *data,
2497d6c0b56eSmrg			int ref_crtc_hw_id, amdgpu_drm_handler_proc handler,
2498d6c0b56eSmrg			amdgpu_drm_abort_proc abort)
2499d6c0b56eSmrg{
2500d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
2501d6c0b56eSmrg	xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
2502d6c0b56eSmrg	xf86CrtcPtr crtc = NULL;
2503d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
2504d6c0b56eSmrg	drmmode_ptr drmmode = drmmode_crtc->drmmode;
2505d6c0b56eSmrg	int i;
2506d6c0b56eSmrg	drmmode_flipdata_ptr flipdata;
2507d6c0b56eSmrg	uintptr_t drm_queue_seq = 0;
2508d6c0b56eSmrg	uint32_t new_front_handle;
2509d6c0b56eSmrg
2510d6c0b56eSmrg	if (!amdgpu_pixmap_get_handle(new_front, &new_front_handle)) {
2511d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2512d6c0b56eSmrg			   "flip queue: data alloc failed.\n");
2513d6c0b56eSmrg		return FALSE;
2514d6c0b56eSmrg	}
2515d6c0b56eSmrg
2516d6c0b56eSmrg	flipdata = calloc(1, sizeof(drmmode_flipdata_rec));
2517d6c0b56eSmrg	if (!flipdata) {
2518d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2519d6c0b56eSmrg			   "flip queue: data alloc failed.\n");
2520d6c0b56eSmrg		goto error;
2521d6c0b56eSmrg	}
2522d6c0b56eSmrg
2523d6c0b56eSmrg	/*
2524d6c0b56eSmrg	 * Create a new handle for the back buffer
2525d6c0b56eSmrg	 */
2526d6c0b56eSmrg	flipdata->old_fb_id = drmmode->fb_id;
2527d6c0b56eSmrg	if (drmModeAddFB(pAMDGPUEnt->fd, new_front->drawable.width,
2528d6c0b56eSmrg			 new_front->drawable.height, scrn->depth,
2529d6c0b56eSmrg			 scrn->bitsPerPixel, new_front->devKind,
2530d6c0b56eSmrg			 new_front_handle, &drmmode->fb_id))
2531d6c0b56eSmrg		goto error;
2532d6c0b56eSmrg
2533d6c0b56eSmrg	/*
2534d6c0b56eSmrg	 * Queue flips on all enabled CRTCs
2535d6c0b56eSmrg	 * Note that if/when we get per-CRTC buffers, we'll have to update this.
2536d6c0b56eSmrg	 * Right now it assumes a single shared fb across all CRTCs, with the
2537d6c0b56eSmrg	 * kernel fixing up the offset of each CRTC as necessary.
2538d6c0b56eSmrg	 *
2539d6c0b56eSmrg	 * Also, flips queued on disabled or incorrectly configured displays
2540d6c0b56eSmrg	 * may never complete; this is a configuration error.
2541d6c0b56eSmrg	 */
2542d6c0b56eSmrg
2543d6c0b56eSmrg	flipdata->event_data = data;
2544d6c0b56eSmrg	flipdata->handler = handler;
2545d6c0b56eSmrg	flipdata->abort = abort;
2546d6c0b56eSmrg
2547d6c0b56eSmrg	for (i = 0; i < config->num_crtc; i++) {
2548d6c0b56eSmrg		crtc = config->crtc[i];
2549d6c0b56eSmrg
2550d6c0b56eSmrg		if (!crtc->enabled)
2551d6c0b56eSmrg			continue;
2552d6c0b56eSmrg
2553d6c0b56eSmrg		flipdata->flip_count++;
2554d6c0b56eSmrg		drmmode_crtc = crtc->driver_private;
2555d6c0b56eSmrg
2556d6c0b56eSmrg		/* Only the reference crtc will finally deliver its page flip
2557d6c0b56eSmrg		 * completion event. All other crtc's events will be discarded.
2558d6c0b56eSmrg		 */
2559d6c0b56eSmrg		if (drmmode_crtc->hw_id == ref_crtc_hw_id)
2560d6c0b56eSmrg			flipdata->fe_crtc = crtc;
2561d6c0b56eSmrg
2562d6c0b56eSmrg		drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id,
2563d6c0b56eSmrg						       flipdata,
2564d6c0b56eSmrg						       drmmode_flip_handler,
2565d6c0b56eSmrg						       drmmode_flip_abort);
2566d6c0b56eSmrg		if (!drm_queue_seq) {
2567d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2568d6c0b56eSmrg				   "Allocating DRM queue event entry failed.\n");
2569d6c0b56eSmrg			goto error;
2570d6c0b56eSmrg		}
2571d6c0b56eSmrg
2572d6c0b56eSmrg		if (drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id,
2573d6c0b56eSmrg				    drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT,
2574d6c0b56eSmrg				    (void*)drm_queue_seq)) {
2575d6c0b56eSmrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
2576d6c0b56eSmrg				   "flip queue failed: %s\n", strerror(errno));
2577d6c0b56eSmrg			goto error;
2578d6c0b56eSmrg		}
2579d6c0b56eSmrg		drmmode_crtc->flip_pending = TRUE;
2580d6c0b56eSmrg		drm_queue_seq = 0;
2581d6c0b56eSmrg	}
2582d6c0b56eSmrg
2583d6c0b56eSmrg	if (flipdata->flip_count > 0)
2584d6c0b56eSmrg		return TRUE;
2585d6c0b56eSmrg
2586d6c0b56eSmrgerror:
2587d6c0b56eSmrg	if (flipdata && flipdata->flip_count <= 1) {
2588d6c0b56eSmrg		drmModeRmFB(pAMDGPUEnt->fd, drmmode->fb_id);
2589d6c0b56eSmrg		drmmode->fb_id = flipdata->old_fb_id;
2590d6c0b56eSmrg	}
2591d6c0b56eSmrg
2592d6c0b56eSmrg	if (drm_queue_seq)
2593d6c0b56eSmrg		amdgpu_drm_abort_entry(drm_queue_seq);
2594d6c0b56eSmrg	else if (crtc)
2595d6c0b56eSmrg		drmmode_flip_abort(crtc, flipdata);
2596d6c0b56eSmrg	else if (flipdata && flipdata->flip_count <= 1)
2597d6c0b56eSmrg		free(flipdata);
2598d6c0b56eSmrg
2599d6c0b56eSmrg	xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
2600d6c0b56eSmrg		   strerror(errno));
2601d6c0b56eSmrg	return FALSE;
2602d6c0b56eSmrg}
2603