amdgpu_kms.c revision 11bf0794
1d6c0b56eSmrg/*
2d6c0b56eSmrg * Copyright © 2009 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#ifdef HAVE_CONFIG_H
28d6c0b56eSmrg#include "config.h"
29d6c0b56eSmrg#endif
30d6c0b56eSmrg
31d6c0b56eSmrg#include <errno.h>
32d6c0b56eSmrg#include <sys/ioctl.h>
33d6c0b56eSmrg/* Driver data structures */
34d6c0b56eSmrg#include "amdgpu_drv.h"
35d6c0b56eSmrg#include "amdgpu_drm_queue.h"
36d6c0b56eSmrg#include "amdgpu_glamor.h"
37d6c0b56eSmrg#include "amdgpu_probe.h"
38d6c0b56eSmrg#include "micmap.h"
39d6c0b56eSmrg
40d6c0b56eSmrg#include "amdgpu_version.h"
41d6c0b56eSmrg#include "shadow.h"
42504d986fSmrg#include <xf86Priv.h>
43d6c0b56eSmrg
44d6c0b56eSmrg/* DPMS */
45d6c0b56eSmrg#ifdef HAVE_XEXTPROTO_71
46d6c0b56eSmrg#include <X11/extensions/dpmsconst.h>
47d6c0b56eSmrg#else
48d6c0b56eSmrg#define DPMS_SERVER
49d6c0b56eSmrg#include <X11/extensions/dpms.h>
50d6c0b56eSmrg#endif
51d6c0b56eSmrg
52504d986fSmrg#include <X11/extensions/damageproto.h>
53504d986fSmrg
54d6c0b56eSmrg#include "amdgpu_bo_helper.h"
55d6c0b56eSmrg#include "amdgpu_pixmap.h"
56d6c0b56eSmrg
57d6c0b56eSmrg#include <gbm.h>
58d6c0b56eSmrg
59504d986fSmrgstatic DevScreenPrivateKeyRec amdgpu_client_private_key;
60504d986fSmrg
61d6c0b56eSmrgstatic Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen);
62d6c0b56eSmrg
63d6c0b56eSmrgconst OptionInfoRec AMDGPUOptions_KMS[] = {
64d6c0b56eSmrg	{OPTION_ACCEL, "Accel", OPTV_BOOLEAN, {0}, FALSE},
65d6c0b56eSmrg	{OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
66d6c0b56eSmrg	{OPTION_PAGE_FLIP, "EnablePageFlip", OPTV_BOOLEAN, {0}, FALSE},
67d6c0b56eSmrg	{OPTION_SUBPIXEL_ORDER, "SubPixelOrder", OPTV_ANYSTR, {0}, FALSE},
68d6c0b56eSmrg	{OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE},
69d6c0b56eSmrg	{OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
70d6c0b56eSmrg	{OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE},
71d6c0b56eSmrg	{OPTION_DRI, "DRI", OPTV_INTEGER, {0}, FALSE},
72d6c0b56eSmrg	{OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE},
73d6c0b56eSmrg	{OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE},
74d6c0b56eSmrg	{OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, FALSE},
75d6c0b56eSmrg	{-1, NULL, OPTV_NONE, {0}, FALSE}
76d6c0b56eSmrg};
77d6c0b56eSmrg
78d6c0b56eSmrgconst OptionInfoRec *AMDGPUOptionsWeak(void)
79d6c0b56eSmrg{
80d6c0b56eSmrg	return AMDGPUOptions_KMS;
81d6c0b56eSmrg}
82d6c0b56eSmrg
83d6c0b56eSmrgextern _X_EXPORT int gAMDGPUEntityIndex;
84d6c0b56eSmrg
85d6c0b56eSmrgstatic int getAMDGPUEntityIndex(void)
86d6c0b56eSmrg{
87d6c0b56eSmrg	return gAMDGPUEntityIndex;
88d6c0b56eSmrg}
89d6c0b56eSmrg
90d6c0b56eSmrgAMDGPUEntPtr AMDGPUEntPriv(ScrnInfoPtr pScrn)
91d6c0b56eSmrg{
92d6c0b56eSmrg	DevUnion *pPriv;
93d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
94d6c0b56eSmrg	pPriv = xf86GetEntityPrivate(info->pEnt->index, getAMDGPUEntityIndex());
95d6c0b56eSmrg	return pPriv->ptr;
96d6c0b56eSmrg}
97d6c0b56eSmrg
98d6c0b56eSmrg/* Allocate our private AMDGPUInfoRec */
99d6c0b56eSmrgstatic Bool AMDGPUGetRec(ScrnInfoPtr pScrn)
100d6c0b56eSmrg{
101d6c0b56eSmrg	if (pScrn->driverPrivate)
102d6c0b56eSmrg		return TRUE;
103d6c0b56eSmrg
104d6c0b56eSmrg	pScrn->driverPrivate = xnfcalloc(sizeof(AMDGPUInfoRec), 1);
105d6c0b56eSmrg	return TRUE;
106d6c0b56eSmrg}
107d6c0b56eSmrg
108d6c0b56eSmrg/* Free our private AMDGPUInfoRec */
109d6c0b56eSmrgstatic void AMDGPUFreeRec(ScrnInfoPtr pScrn)
110d6c0b56eSmrg{
111d6c0b56eSmrg	DevUnion *pPriv;
112d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt;
113d6c0b56eSmrg	AMDGPUInfoPtr info;
114d6c0b56eSmrg
115d6c0b56eSmrg	if (!pScrn)
116d6c0b56eSmrg		return;
117d6c0b56eSmrg
118d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
119d6c0b56eSmrg	if (info && info->fbcon_pixmap)
120d6c0b56eSmrg		pScrn->pScreen->DestroyPixmap(info->fbcon_pixmap);
121d6c0b56eSmrg
122d6c0b56eSmrg	pPriv = xf86GetEntityPrivate(xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1])->index,
123d6c0b56eSmrg				     gAMDGPUEntityIndex);
124d6c0b56eSmrg	pAMDGPUEnt = pPriv->ptr;
125d6c0b56eSmrg	if (pAMDGPUEnt->fd > 0) {
126d6c0b56eSmrg		DevUnion *pPriv;
127d6c0b56eSmrg		AMDGPUEntPtr pAMDGPUEnt;
128d6c0b56eSmrg		pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
129d6c0b56eSmrg					     getAMDGPUEntityIndex());
130d6c0b56eSmrg
131d6c0b56eSmrg		pAMDGPUEnt = pPriv->ptr;
132d6c0b56eSmrg		pAMDGPUEnt->fd_ref--;
133d6c0b56eSmrg		if (!pAMDGPUEnt->fd_ref) {
134d6c0b56eSmrg			amdgpu_device_deinitialize(pAMDGPUEnt->pDev);
13511bf0794Smrg			amdgpu_kernel_close_fd(pAMDGPUEnt);
136d6c0b56eSmrg		}
137d6c0b56eSmrg	}
138d6c0b56eSmrg
139d6c0b56eSmrg	free(pScrn->driverPrivate);
140d6c0b56eSmrg	pScrn->driverPrivate = NULL;
141d6c0b56eSmrg}
142d6c0b56eSmrg
143d6c0b56eSmrgstatic void *amdgpuShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset,
144d6c0b56eSmrg				int mode, CARD32 * size, void *closure)
145d6c0b56eSmrg{
146d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
147d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
148d6c0b56eSmrg	int stride;
149d6c0b56eSmrg
150d6c0b56eSmrg	stride = (pScrn->displayWidth * pScrn->bitsPerPixel) / 8;
151d6c0b56eSmrg	*size = stride;
152d6c0b56eSmrg
153d6c0b56eSmrg	return ((uint8_t *) info->front_buffer->cpu_ptr + row * stride + offset);
154d6c0b56eSmrg}
155d6c0b56eSmrg
156d6c0b56eSmrgstatic void
157d6c0b56eSmrgamdgpuUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
158d6c0b56eSmrg{
159d6c0b56eSmrg	shadowUpdatePacked(pScreen, pBuf);
160d6c0b56eSmrg}
161d6c0b56eSmrg
162504d986fSmrgstatic Bool
163504d986fSmrgcallback_needs_flush(AMDGPUInfoPtr info, struct amdgpu_client_priv *client_priv)
164504d986fSmrg{
165504d986fSmrg	return (int)(client_priv->needs_flush - info->gpu_flushed) > 0;
166504d986fSmrg}
167504d986fSmrg
168504d986fSmrgstatic void
169504d986fSmrgamdgpu_event_callback(CallbackListPtr *list,
170504d986fSmrg		      pointer user_data, pointer call_data)
171504d986fSmrg{
172504d986fSmrg	EventInfoRec *eventinfo = call_data;
173504d986fSmrg	ScrnInfoPtr pScrn = user_data;
174504d986fSmrg	ScreenPtr pScreen = pScrn->pScreen;
175504d986fSmrg	struct amdgpu_client_priv *client_priv =
176504d986fSmrg		dixLookupScreenPrivate(&eventinfo->client->devPrivates,
177504d986fSmrg				       &amdgpu_client_private_key, pScreen);
178504d986fSmrg	struct amdgpu_client_priv *server_priv =
179504d986fSmrg		dixLookupScreenPrivate(&serverClient->devPrivates,
180504d986fSmrg				       &amdgpu_client_private_key, pScreen);
181504d986fSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
182504d986fSmrg	int i;
183504d986fSmrg
184504d986fSmrg	if (callback_needs_flush(info, client_priv) ||
185504d986fSmrg	    callback_needs_flush(info, server_priv))
186504d986fSmrg		return;
187504d986fSmrg
188504d986fSmrg	/* Don't let gpu_flushed get too far ahead of needs_flush, in order
189504d986fSmrg	 * to prevent false positives in callback_needs_flush()
190504d986fSmrg	 */
191504d986fSmrg	client_priv->needs_flush = info->gpu_flushed;
192504d986fSmrg	server_priv->needs_flush = info->gpu_flushed;
193504d986fSmrg
194504d986fSmrg	for (i = 0; i < eventinfo->count; i++) {
195504d986fSmrg		if (eventinfo->events[i].u.u.type == info->callback_event_type) {
196504d986fSmrg			client_priv->needs_flush++;
197504d986fSmrg			server_priv->needs_flush++;
198504d986fSmrg			return;
199504d986fSmrg		}
200504d986fSmrg	}
201504d986fSmrg}
202504d986fSmrg
203504d986fSmrgstatic void
204504d986fSmrgamdgpu_flush_callback(CallbackListPtr *list,
205504d986fSmrg		      pointer user_data, pointer call_data)
206504d986fSmrg{
207504d986fSmrg	ScrnInfoPtr pScrn = user_data;
208504d986fSmrg	ScreenPtr pScreen = pScrn->pScreen;
209504d986fSmrg	ClientPtr client = call_data ? call_data : serverClient;
210504d986fSmrg	struct amdgpu_client_priv *client_priv =
211504d986fSmrg		dixLookupScreenPrivate(&client->devPrivates,
212504d986fSmrg				       &amdgpu_client_private_key, pScreen);
213504d986fSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
214504d986fSmrg
215504d986fSmrg	if (pScrn->vtSema && callback_needs_flush(info, client_priv))
216504d986fSmrg		amdgpu_glamor_flush(pScrn);
217504d986fSmrg}
218504d986fSmrg
219d6c0b56eSmrgstatic Bool AMDGPUCreateScreenResources_KMS(ScreenPtr pScreen)
220d6c0b56eSmrg{
22111bf0794Smrg	ExtensionEntry *damage_ext;
222d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
223d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
224d6c0b56eSmrg	PixmapPtr pixmap;
225d6c0b56eSmrg
226d6c0b56eSmrg	pScreen->CreateScreenResources = info->CreateScreenResources;
227d6c0b56eSmrg	if (!(*pScreen->CreateScreenResources) (pScreen))
228d6c0b56eSmrg		return FALSE;
229d6c0b56eSmrg	pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS;
230d6c0b56eSmrg
231d6c0b56eSmrg	/* Set the RandR primary output if Xorg hasn't */
232504d986fSmrg	if (dixPrivateKeyRegistered(rrPrivKey)) {
233504d986fSmrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(pScreen);
234504d986fSmrg
23511bf0794Smrg		if (!amdgpu_is_gpu_screen(pScreen) &&
236504d986fSmrg		    !rrScrPriv->primaryOutput)
237504d986fSmrg		{
238504d986fSmrg			xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
239d6c0b56eSmrg
240504d986fSmrg			rrScrPriv->primaryOutput = xf86_config->output[0]->randr_output;
241504d986fSmrg			RROutputChanged(rrScrPriv->primaryOutput, FALSE);
242504d986fSmrg			rrScrPriv->layoutChanged = TRUE;
243504d986fSmrg		}
244d6c0b56eSmrg	}
245d6c0b56eSmrg
24611bf0794Smrg	if (!drmmode_set_desired_modes(pScrn, &info->drmmode,
24711bf0794Smrg				       amdgpu_is_gpu_screen(pScreen)))
248d6c0b56eSmrg		return FALSE;
249d6c0b56eSmrg
250d6c0b56eSmrg	drmmode_uevent_init(pScrn, &info->drmmode);
251d6c0b56eSmrg
252d6c0b56eSmrg	if (info->shadow_fb) {
253d6c0b56eSmrg		pixmap = pScreen->GetScreenPixmap(pScreen);
254d6c0b56eSmrg
255d6c0b56eSmrg		if (!shadowAdd(pScreen, pixmap, amdgpuUpdatePacked,
256d6c0b56eSmrg			       amdgpuShadowWindow, 0, NULL))
257d6c0b56eSmrg			return FALSE;
258d6c0b56eSmrg	}
259d6c0b56eSmrg
260d6c0b56eSmrg	if (info->dri2.enabled || info->use_glamor) {
261d6c0b56eSmrg		if (info->front_buffer) {
262d6c0b56eSmrg			PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen);
263504d986fSmrg
264504d986fSmrg			if (!amdgpu_set_pixmap_bo(pPix, info->front_buffer))
265504d986fSmrg				return FALSE;
266d6c0b56eSmrg		}
267d6c0b56eSmrg	}
268d6c0b56eSmrg
269d6c0b56eSmrg	if (info->use_glamor)
270d6c0b56eSmrg		amdgpu_glamor_create_screen_resources(pScreen);
271d6c0b56eSmrg
272504d986fSmrg	info->callback_event_type = -1;
27311bf0794Smrg	if (!amdgpu_is_gpu_screen(pScreen) &&
27411bf0794Smrg		(damage_ext = CheckExtension("DAMAGE"))) {
275504d986fSmrg		info->callback_event_type = damage_ext->eventBase + XDamageNotify;
276504d986fSmrg
277504d986fSmrg		if (!AddCallback(&FlushCallback, amdgpu_flush_callback, pScrn))
278504d986fSmrg			return FALSE;
279504d986fSmrg
280504d986fSmrg		if (!AddCallback(&EventCallback, amdgpu_event_callback, pScrn)) {
281504d986fSmrg			DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
282504d986fSmrg			return FALSE;
283504d986fSmrg		}
284504d986fSmrg
285504d986fSmrg		if (!dixRegisterScreenPrivateKey(&amdgpu_client_private_key, pScreen,
286504d986fSmrg						 PRIVATE_CLIENT, sizeof(struct amdgpu_client_priv))) {
287504d986fSmrg			DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
288504d986fSmrg			DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn);
289504d986fSmrg			return FALSE;
290504d986fSmrg		}
291504d986fSmrg	}
292504d986fSmrg
293d6c0b56eSmrg	return TRUE;
294d6c0b56eSmrg}
295d6c0b56eSmrg
296504d986fSmrgstatic Bool
297504d986fSmrgamdgpu_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents)
298504d986fSmrg{
29911bf0794Smrg#ifdef AMDGPU_PIXMAP_SHARING
30011bf0794Smrg	if (xf86_crtc->scrn->is_gpu) {
30111bf0794Smrg		extents->x1 -= xf86_crtc->x;
30211bf0794Smrg		extents->y1 -= xf86_crtc->y;
30311bf0794Smrg		extents->x2 -= xf86_crtc->x;
30411bf0794Smrg		extents->y2 -= xf86_crtc->y;
30511bf0794Smrg	} else
30611bf0794Smrg#endif
30711bf0794Smrg	{
30811bf0794Smrg		extents->x1 -= xf86_crtc->filter_width >> 1;
30911bf0794Smrg		extents->x2 += xf86_crtc->filter_width >> 1;
31011bf0794Smrg		extents->y1 -= xf86_crtc->filter_height >> 1;
31111bf0794Smrg		extents->y2 += xf86_crtc->filter_height >> 1;
31211bf0794Smrg		pixman_f_transform_bounds(&xf86_crtc->f_framebuffer_to_crtc, extents);
31311bf0794Smrg	}
314504d986fSmrg
315504d986fSmrg	extents->x1 = max(extents->x1, 0);
316504d986fSmrg	extents->y1 = max(extents->y1, 0);
317504d986fSmrg	extents->x2 = min(extents->x2, xf86_crtc->mode.HDisplay);
318504d986fSmrg	extents->y2 = min(extents->y2, xf86_crtc->mode.VDisplay);
319504d986fSmrg
320504d986fSmrg	return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
321504d986fSmrg}
322504d986fSmrg
32311bf0794Smrg#if XF86_CRTC_VERSION >= 4
32411bf0794Smrg
325504d986fSmrgstatic RegionPtr
326504d986fSmrgtransform_region(RegionPtr region, struct pict_f_transform *transform,
327504d986fSmrg		 int w, int h)
328504d986fSmrg{
329504d986fSmrg	BoxPtr boxes = RegionRects(region);
330504d986fSmrg	int nboxes = RegionNumRects(region);
331504d986fSmrg	xRectanglePtr rects = malloc(nboxes * sizeof(*rects));
332504d986fSmrg	RegionPtr transformed;
333504d986fSmrg	int nrects = 0;
334504d986fSmrg	BoxRec box;
335504d986fSmrg	int i;
336504d986fSmrg
337504d986fSmrg	for (i = 0; i < nboxes; i++) {
338504d986fSmrg		box.x1 = boxes[i].x1;
339504d986fSmrg		box.x2 = boxes[i].x2;
340504d986fSmrg		box.y1 = boxes[i].y1;
341504d986fSmrg		box.y2 = boxes[i].y2;
342504d986fSmrg		pixman_f_transform_bounds(transform, &box);
343504d986fSmrg
344504d986fSmrg		box.x1 = max(box.x1, 0);
345504d986fSmrg		box.y1 = max(box.y1, 0);
346504d986fSmrg		box.x2 = min(box.x2, w);
347504d986fSmrg		box.y2 = min(box.y2, h);
348504d986fSmrg		if (box.x1 >= box.x2 || box.y1 >= box.y2)
349504d986fSmrg			continue;
350504d986fSmrg
351504d986fSmrg		rects[nrects].x = box.x1;
352504d986fSmrg		rects[nrects].y = box.y1;
353504d986fSmrg		rects[nrects].width = box.x2 - box.x1;
354504d986fSmrg		rects[nrects].height = box.y2 - box.y1;
355504d986fSmrg		nrects++;
356504d986fSmrg	}
357504d986fSmrg
358504d986fSmrg	transformed = RegionFromRects(nrects, rects, CT_UNSORTED);
359504d986fSmrg	free(rects);
360504d986fSmrg	return transformed;
361504d986fSmrg}
362504d986fSmrg
36311bf0794Smrg#endif
36411bf0794Smrg
365504d986fSmrgstatic void
366504d986fSmrgamdgpu_sync_scanout_pixmaps(xf86CrtcPtr xf86_crtc, RegionPtr new_region,
367504d986fSmrg							int scanout_id)
368504d986fSmrg{
369504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
370504d986fSmrg	DrawablePtr dst = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
371504d986fSmrg	DrawablePtr src = &drmmode_crtc->scanout[scanout_id ^ 1].pixmap->drawable;
372504d986fSmrg	RegionPtr last_region = &drmmode_crtc->scanout_last_region;
373504d986fSmrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
374504d986fSmrg	ScreenPtr pScreen = scrn->pScreen;
375504d986fSmrg	RegionRec remaining;
376504d986fSmrg	RegionPtr sync_region = NULL;
377504d986fSmrg	BoxRec extents;
378504d986fSmrg	GCPtr gc;
379504d986fSmrg
380504d986fSmrg	if (RegionNil(last_region))
381504d986fSmrg		return;
382504d986fSmrg
383504d986fSmrg	RegionNull(&remaining);
384504d986fSmrg	RegionSubtract(&remaining, last_region, new_region);
385504d986fSmrg	if (RegionNil(&remaining))
386504d986fSmrg		goto uninit;
387504d986fSmrg
388504d986fSmrg	extents = *RegionExtents(&remaining);
389504d986fSmrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents))
390504d986fSmrg		goto uninit;
391504d986fSmrg
392504d986fSmrg#if XF86_CRTC_VERSION >= 4
393504d986fSmrg	if (xf86_crtc->driverIsPerformingTransform) {
394504d986fSmrg		sync_region = transform_region(&remaining,
395504d986fSmrg					       &xf86_crtc->f_framebuffer_to_crtc,
396504d986fSmrg					       dst->width, dst->height);
397504d986fSmrg	} else
398504d986fSmrg#endif /* XF86_CRTC_VERSION >= 4 */
399504d986fSmrg	{
400504d986fSmrg		sync_region = RegionDuplicate(&remaining);
401504d986fSmrg		RegionTranslate(sync_region, -xf86_crtc->x, -xf86_crtc->y);
402504d986fSmrg	}
403504d986fSmrg
404504d986fSmrg	gc = GetScratchGC(dst->depth, pScreen);
405504d986fSmrg	if (gc) {
406504d986fSmrg		gc->funcs->ChangeClip(gc, CT_REGION, sync_region, 0);
40711bf0794Smrg		ValidateGC(dst, gc);
408504d986fSmrg		sync_region = NULL;
409504d986fSmrg		gc->ops->CopyArea(src, dst, gc, 0, 0, dst->width, dst->height, 0, 0);
410504d986fSmrg		FreeScratchGC(gc);
411504d986fSmrg	}
412504d986fSmrg
413504d986fSmrg uninit:
414504d986fSmrg	if (sync_region)
415504d986fSmrg		RegionDestroy(sync_region);
416504d986fSmrg	RegionUninit(&remaining);
417504d986fSmrg}
418504d986fSmrg
419d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
420504d986fSmrg
421504d986fSmrgstatic RegionPtr
422504d986fSmrgdirty_region(PixmapDirtyUpdatePtr dirty)
423d6c0b56eSmrg{
424504d986fSmrg	RegionPtr damageregion = DamageRegion(dirty->damage);
425504d986fSmrg	RegionPtr dstregion;
426504d986fSmrg
427504d986fSmrg#ifdef HAS_DIRTYTRACKING_ROTATION
428504d986fSmrg	if (dirty->rotation != RR_Rotate_0) {
429504d986fSmrg		dstregion = transform_region(damageregion,
430504d986fSmrg					     &dirty->f_inverse,
431504d986fSmrg					     dirty->slave_dst->drawable.width,
432504d986fSmrg					     dirty->slave_dst->drawable.height);
433504d986fSmrg	} else
434504d986fSmrg#endif
435504d986fSmrg	{
436504d986fSmrg		RegionRec pixregion;
437504d986fSmrg
438504d986fSmrg		dstregion = RegionDuplicate(damageregion);
439504d986fSmrg		RegionTranslate(dstregion, -dirty->x, -dirty->y);
440504d986fSmrg		PixmapRegionInit(&pixregion, dirty->slave_dst);
441504d986fSmrg		RegionIntersect(dstregion, dstregion, &pixregion);
442504d986fSmrg		RegionUninit(&pixregion);
443504d986fSmrg	}
444504d986fSmrg
445504d986fSmrg	return dstregion;
446504d986fSmrg}
447504d986fSmrg
448504d986fSmrgstatic void
449504d986fSmrgredisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region)
450504d986fSmrg{
451504d986fSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(dirty->src->drawable.pScreen);
452504d986fSmrg
453504d986fSmrg	if (RegionNil(region))
454504d986fSmrg		goto out;
455504d986fSmrg
456504d986fSmrg	if (dirty->slave_dst->master_pixmap)
457504d986fSmrg		DamageRegionAppend(&dirty->slave_dst->drawable, region);
458d6c0b56eSmrg
459d6c0b56eSmrg#ifdef HAS_DIRTYTRACKING_ROTATION
460d6c0b56eSmrg	PixmapSyncDirtyHelper(dirty);
461d6c0b56eSmrg#else
462504d986fSmrg	PixmapSyncDirtyHelper(dirty, region);
463d6c0b56eSmrg#endif
464d6c0b56eSmrg
465504d986fSmrg	amdgpu_glamor_flush(scrn);
466504d986fSmrg	if (dirty->slave_dst->master_pixmap)
467504d986fSmrg		DamageRegionProcessPending(&dirty->slave_dst->drawable);
468504d986fSmrg
469504d986fSmrgout:
470504d986fSmrg	DamageEmpty(dirty->damage);
471d6c0b56eSmrg}
472d6c0b56eSmrg
473504d986fSmrgstatic void
474504d986fSmrgamdgpu_prime_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
475d6c0b56eSmrg{
476504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
477504d986fSmrg
478504d986fSmrg	drmmode_crtc->scanout_update_pending = FALSE;
479504d986fSmrg}
480504d986fSmrg
481504d986fSmrgvoid
482504d986fSmrgamdgpu_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
483504d986fSmrg{
484504d986fSmrg	ScreenPtr master_screen = dirty->src->master_pixmap->drawable.pScreen;
485d6c0b56eSmrg	PixmapDirtyUpdatePtr ent;
486504d986fSmrg	RegionPtr region;
487d6c0b56eSmrg
488504d986fSmrg	xorg_list_for_each_entry(ent, &master_screen->pixmap_dirty_list, ent) {
489504d986fSmrg		if (ent->slave_dst != dirty->src)
490504d986fSmrg			continue;
491d6c0b56eSmrg
492504d986fSmrg		region = dirty_region(ent);
493504d986fSmrg		redisplay_dirty(ent, region);
494504d986fSmrg		RegionDestroy(region);
495d6c0b56eSmrg	}
496d6c0b56eSmrg}
497504d986fSmrg
498504d986fSmrg
499504d986fSmrg#if HAS_SYNC_SHARED_PIXMAP
500d6c0b56eSmrg
501d6c0b56eSmrgstatic Bool
502504d986fSmrgmaster_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
503d6c0b56eSmrg{
504504d986fSmrg	ScreenPtr master_screen = dirty->src->master_pixmap->drawable.pScreen;
505504d986fSmrg
506504d986fSmrg	return master_screen->SyncSharedPixmap != NULL;
507504d986fSmrg}
508504d986fSmrg
509504d986fSmrgstatic Bool
510504d986fSmrgslave_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
511504d986fSmrg{
512504d986fSmrg	ScreenPtr slave_screen = dirty->slave_dst->drawable.pScreen;
513504d986fSmrg
514504d986fSmrg	return slave_screen->SyncSharedPixmap != NULL;
515504d986fSmrg}
516504d986fSmrg
517504d986fSmrgstatic void
518504d986fSmrgcall_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
519504d986fSmrg{
520504d986fSmrg	ScreenPtr master_screen = dirty->src->master_pixmap->drawable.pScreen;
521504d986fSmrg
522504d986fSmrg	master_screen->SyncSharedPixmap(dirty);
523504d986fSmrg}
524504d986fSmrg
525504d986fSmrg#else /* !HAS_SYNC_SHARED_PIXMAP */
526504d986fSmrg
527504d986fSmrgstatic Bool
528504d986fSmrgmaster_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
529504d986fSmrg{
530504d986fSmrg	ScrnInfoPtr master_scrn = xf86ScreenToScrn(dirty->src->master_pixmap->drawable.pScreen);
531504d986fSmrg
532504d986fSmrg	return master_scrn->driverName == scrn->driverName;
533504d986fSmrg}
534504d986fSmrg
535504d986fSmrgstatic Bool
536504d986fSmrgslave_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
537504d986fSmrg{
538504d986fSmrg	ScrnInfoPtr slave_scrn = xf86ScreenToScrn(dirty->slave_dst->drawable.pScreen);
539504d986fSmrg
540504d986fSmrg	return slave_scrn->driverName == scrn->driverName;
541504d986fSmrg}
542504d986fSmrg
543504d986fSmrgstatic void
544504d986fSmrgcall_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
545504d986fSmrg{
546504d986fSmrg	amdgpu_sync_shared_pixmap(dirty);
547504d986fSmrg}
548504d986fSmrg
549504d986fSmrg#endif /* HAS_SYNC_SHARED_PIXMAPS */
550504d986fSmrg
551504d986fSmrg
55211bf0794Smrgstatic xf86CrtcPtr
55311bf0794Smrgamdgpu_prime_dirty_to_crtc(PixmapDirtyUpdatePtr dirty)
55411bf0794Smrg{
55511bf0794Smrg	ScreenPtr screen = dirty->slave_dst->drawable.pScreen;
55611bf0794Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
55711bf0794Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
55811bf0794Smrg	int c;
55911bf0794Smrg
56011bf0794Smrg	/* Find the CRTC which is scanning out from this slave pixmap */
56111bf0794Smrg	for (c = 0; c < xf86_config->num_crtc; c++) {
56211bf0794Smrg		xf86CrtcPtr xf86_crtc = xf86_config->crtc[c];
56311bf0794Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
56411bf0794Smrg
56511bf0794Smrg		if (drmmode_crtc->scanout[0].pixmap == dirty->slave_dst ||
56611bf0794Smrg			drmmode_crtc->scanout[1].pixmap == dirty->slave_dst)
56711bf0794Smrg			return xf86_crtc;
56811bf0794Smrg	}
56911bf0794Smrg
57011bf0794Smrg	return NULL;
57111bf0794Smrg}
57211bf0794Smrg
573504d986fSmrgstatic Bool
574504d986fSmrgamdgpu_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id)
575504d986fSmrg{
576504d986fSmrg	ScrnInfoPtr scrn = crtc->scrn;
577504d986fSmrg	ScreenPtr screen = scrn->pScreen;
578504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
579504d986fSmrg	PixmapPtr scanoutpix = crtc->randr_crtc->scanout_pixmap;
580504d986fSmrg	PixmapDirtyUpdatePtr dirty;
581504d986fSmrg	Bool ret = FALSE;
582504d986fSmrg
583504d986fSmrg	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
584504d986fSmrg		if (dirty->src == scanoutpix && dirty->slave_dst ==
58511bf0794Smrg		    drmmode_crtc->scanout[scanout_id ^ drmmode_crtc->tear_free].pixmap) {
586504d986fSmrg			RegionPtr region;
587504d986fSmrg
588504d986fSmrg			if (master_has_sync_shared_pixmap(scrn, dirty))
589504d986fSmrg				call_sync_shared_pixmap(dirty);
590504d986fSmrg
591504d986fSmrg			region = dirty_region(dirty);
592504d986fSmrg			if (RegionNil(region))
593504d986fSmrg				goto destroy;
594504d986fSmrg
59511bf0794Smrg			if (drmmode_crtc->tear_free) {
596504d986fSmrg				RegionTranslate(region, crtc->x, crtc->y);
597504d986fSmrg				amdgpu_sync_scanout_pixmaps(crtc, region, scanout_id);
598504d986fSmrg				amdgpu_glamor_flush(scrn);
599504d986fSmrg				RegionCopy(&drmmode_crtc->scanout_last_region, region);
600504d986fSmrg				RegionTranslate(region, -crtc->x, -crtc->y);
601504d986fSmrg				dirty->slave_dst = drmmode_crtc->scanout[scanout_id].pixmap;
602504d986fSmrg			}
603504d986fSmrg
604504d986fSmrg			redisplay_dirty(dirty, region);
605504d986fSmrg			ret = TRUE;
606504d986fSmrg		destroy:
607504d986fSmrg			RegionDestroy(region);
608504d986fSmrg			break;
609504d986fSmrg		}
610d6c0b56eSmrg	}
611d6c0b56eSmrg
612504d986fSmrg	return ret;
613504d986fSmrg}
614504d986fSmrg
61511bf0794Smrgstatic void
616504d986fSmrgamdgpu_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
617504d986fSmrg				     void *event_data)
618504d986fSmrg{
619504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
620504d986fSmrg
621504d986fSmrg	amdgpu_prime_scanout_do_update(crtc, 0);
622504d986fSmrg	drmmode_crtc->scanout_update_pending = FALSE;
623504d986fSmrg}
624504d986fSmrg
625504d986fSmrgstatic void
626504d986fSmrgamdgpu_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
627504d986fSmrg{
628504d986fSmrg	ScreenPtr screen = dirty->slave_dst->drawable.pScreen;
629504d986fSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
630504d986fSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
63111bf0794Smrg	xf86CrtcPtr xf86_crtc = amdgpu_prime_dirty_to_crtc(dirty);
63211bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc;
633504d986fSmrg	uintptr_t drm_queue_seq;
634504d986fSmrg	drmVBlank vbl;
635504d986fSmrg
63611bf0794Smrg	if (!xf86_crtc || !xf86_crtc->enabled)
63711bf0794Smrg		return;
638504d986fSmrg
63911bf0794Smrg	drmmode_crtc = xf86_crtc->driver_private;
64011bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
641504d986fSmrg	    !drmmode_crtc->scanout[0].pixmap ||
642504d986fSmrg	    drmmode_crtc->pending_dpms_mode != DPMSModeOn)
643504d986fSmrg		return;
644504d986fSmrg
645504d986fSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
646504d986fSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
647504d986fSmrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT, NULL,
648504d986fSmrg					       amdgpu_prime_scanout_update_handler,
649504d986fSmrg					       amdgpu_prime_scanout_update_abort);
650504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
651504d986fSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
652504d986fSmrg			   "amdgpu_drm_queue_alloc failed for PRIME update\n");
653504d986fSmrg		return;
654504d986fSmrg	}
655504d986fSmrg
656504d986fSmrg	vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
657504d986fSmrg	vbl.request.type |= amdgpu_populate_vbl_request_type(xf86_crtc);
658504d986fSmrg	vbl.request.sequence = 1;
659504d986fSmrg	vbl.request.signal = drm_queue_seq;
660504d986fSmrg	if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl)) {
661504d986fSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
662504d986fSmrg			   "drmWaitVBlank failed for PRIME update: %s\n",
663504d986fSmrg			   strerror(errno));
664504d986fSmrg		amdgpu_drm_abort_entry(drm_queue_seq);
665504d986fSmrg		return;
666504d986fSmrg	}
667504d986fSmrg
668504d986fSmrg	drmmode_crtc->scanout_update_pending = TRUE;
669504d986fSmrg}
670504d986fSmrg
671504d986fSmrgstatic void
672504d986fSmrgamdgpu_prime_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
673504d986fSmrg{
674504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = event_data;
675504d986fSmrg
676504d986fSmrg	drmmode_crtc->scanout_update_pending = FALSE;
677504d986fSmrg	drmmode_clear_pending_flip(crtc);
678d6c0b56eSmrg}
679d6c0b56eSmrg
680504d986fSmrgstatic void
681504d986fSmrgamdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
682504d986fSmrg{
683504d986fSmrg	ScreenPtr screen = ent->slave_dst->drawable.pScreen;
684504d986fSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
685504d986fSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
68611bf0794Smrg	xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent);
68711bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc;
688504d986fSmrg	uintptr_t drm_queue_seq;
689504d986fSmrg	unsigned scanout_id;
690504d986fSmrg
69111bf0794Smrg	if (!crtc || !crtc->enabled)
69211bf0794Smrg		return;
693504d986fSmrg
69411bf0794Smrg	drmmode_crtc = crtc->driver_private;
69511bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
696504d986fSmrg	    !drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap ||
697504d986fSmrg	    drmmode_crtc->pending_dpms_mode != DPMSModeOn)
698504d986fSmrg		return;
699504d986fSmrg
700504d986fSmrg	scanout_id = drmmode_crtc->scanout_id ^ 1;
701504d986fSmrg	if (!amdgpu_prime_scanout_do_update(crtc, scanout_id))
702504d986fSmrg		return;
703504d986fSmrg
704504d986fSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(crtc,
705504d986fSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
706504d986fSmrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT,
707504d986fSmrg					       drmmode_crtc, NULL,
708504d986fSmrg					       amdgpu_prime_scanout_flip_abort);
709504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
710504d986fSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
711504d986fSmrg			   "Allocating DRM event queue entry failed for PRIME flip.\n");
712504d986fSmrg		return;
713504d986fSmrg	}
714504d986fSmrg
71511bf0794Smrg	if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc,
71611bf0794Smrg					      drmmode_crtc->scanout[scanout_id].fb_id,
71711bf0794Smrg					      0, drm_queue_seq, 0) != 0) {
718504d986fSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s\n",
719504d986fSmrg			   __func__, strerror(errno));
72011bf0794Smrg		amdgpu_drm_abort_entry(drm_queue_seq);
721504d986fSmrg		return;
722504d986fSmrg	}
723504d986fSmrg
724504d986fSmrg	drmmode_crtc->scanout_id = scanout_id;
725504d986fSmrg	drmmode_crtc->scanout_update_pending = TRUE;
726504d986fSmrg	drmmode_crtc->flip_pending = TRUE;
727504d986fSmrg}
728504d986fSmrg
729504d986fSmrgstatic void
730504d986fSmrgamdgpu_dirty_update(ScrnInfoPtr scrn)
731504d986fSmrg{
732504d986fSmrg	ScreenPtr screen = scrn->pScreen;
733504d986fSmrg	PixmapDirtyUpdatePtr ent;
734504d986fSmrg	RegionPtr region;
735504d986fSmrg
736504d986fSmrg	xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
737504d986fSmrg		if (screen->isGPU) {
738504d986fSmrg			PixmapDirtyUpdatePtr region_ent = ent;
739504d986fSmrg
740504d986fSmrg			if (master_has_sync_shared_pixmap(scrn, ent)) {
741504d986fSmrg				ScreenPtr master_screen = ent->src->master_pixmap->drawable.pScreen;
742504d986fSmrg
743504d986fSmrg				xorg_list_for_each_entry(region_ent, &master_screen->pixmap_dirty_list, ent) {
744504d986fSmrg					if (region_ent->slave_dst == ent->src)
745504d986fSmrg						break;
746504d986fSmrg				}
747504d986fSmrg			}
748504d986fSmrg
749504d986fSmrg			region = dirty_region(region_ent);
750504d986fSmrg
751504d986fSmrg			if (RegionNotEmpty(region)) {
75211bf0794Smrg				xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent);
75311bf0794Smrg				drmmode_crtc_private_ptr drmmode_crtc = NULL;
75411bf0794Smrg
75511bf0794Smrg				if (crtc)
75611bf0794Smrg					drmmode_crtc = crtc->driver_private;
75711bf0794Smrg
75811bf0794Smrg				if (drmmode_crtc && drmmode_crtc->tear_free)
759504d986fSmrg					amdgpu_prime_scanout_flip(ent);
760504d986fSmrg				else
761504d986fSmrg					amdgpu_prime_scanout_update(ent);
762504d986fSmrg			} else {
763504d986fSmrg				DamageEmpty(region_ent->damage);
764504d986fSmrg			}
765504d986fSmrg
766504d986fSmrg			RegionDestroy(region);
767504d986fSmrg		} else {
768504d986fSmrg			if (slave_has_sync_shared_pixmap(scrn, ent))
769504d986fSmrg				continue;
770504d986fSmrg
771504d986fSmrg			region = dirty_region(ent);
772504d986fSmrg			redisplay_dirty(ent, region);
773504d986fSmrg			RegionDestroy(region);
774504d986fSmrg		}
775504d986fSmrg	}
776504d986fSmrg}
777504d986fSmrg#endif
778504d986fSmrg
77911bf0794SmrgBool
780d6c0b56eSmrgamdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
781d6c0b56eSmrg{
782d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
783504d986fSmrg	RegionPtr pRegion = DamageRegion(drmmode_crtc->scanout_damage);
784504d986fSmrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
785504d986fSmrg	ScreenPtr pScreen = scrn->pScreen;
786d6c0b56eSmrg	DrawablePtr pDraw;
787d6c0b56eSmrg	BoxRec extents;
788d6c0b56eSmrg
789d6c0b56eSmrg	if (!xf86_crtc->enabled ||
790d6c0b56eSmrg	    !drmmode_crtc->scanout[scanout_id].pixmap)
791d6c0b56eSmrg		return FALSE;
792d6c0b56eSmrg
793d6c0b56eSmrg	if (!RegionNotEmpty(pRegion))
794d6c0b56eSmrg		return FALSE;
795d6c0b56eSmrg
796d6c0b56eSmrg	pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
797d6c0b56eSmrg	extents = *RegionExtents(pRegion);
798504d986fSmrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents))
799d6c0b56eSmrg		return FALSE;
800d6c0b56eSmrg
80111bf0794Smrg	if (drmmode_crtc->tear_free) {
802504d986fSmrg		amdgpu_sync_scanout_pixmaps(xf86_crtc, pRegion, scanout_id);
803504d986fSmrg		RegionCopy(&drmmode_crtc->scanout_last_region, pRegion);
804504d986fSmrg	}
805504d986fSmrg	RegionEmpty(pRegion);
806504d986fSmrg
807d6c0b56eSmrg#if XF86_CRTC_VERSION >= 4
808d6c0b56eSmrg	if (xf86_crtc->driverIsPerformingTransform) {
809d6c0b56eSmrg		SourceValidateProcPtr SourceValidate = pScreen->SourceValidate;
810d6c0b56eSmrg		PictFormatPtr format = PictureWindowFormat(pScreen->root);
811d6c0b56eSmrg		int error;
812d6c0b56eSmrg		PicturePtr src, dst;
813d6c0b56eSmrg		XID include_inferiors = IncludeInferiors;
814d6c0b56eSmrg
815d6c0b56eSmrg		src = CreatePicture(None,
816d6c0b56eSmrg				    &pScreen->root->drawable,
817d6c0b56eSmrg				    format,
818d6c0b56eSmrg				    CPSubwindowMode,
819d6c0b56eSmrg				    &include_inferiors, serverClient, &error);
820d6c0b56eSmrg		if (!src) {
821d6c0b56eSmrg			ErrorF("Failed to create source picture for transformed scanout "
822d6c0b56eSmrg			       "update\n");
823d6c0b56eSmrg			goto out;
824d6c0b56eSmrg		}
825d6c0b56eSmrg
826d6c0b56eSmrg		dst = CreatePicture(None, pDraw, format, 0L, NULL, serverClient, &error);
827d6c0b56eSmrg		if (!dst) {
828d6c0b56eSmrg			ErrorF("Failed to create destination picture for transformed scanout "
829d6c0b56eSmrg			       "update\n");
830d6c0b56eSmrg			goto free_src;
831d6c0b56eSmrg		}
832d6c0b56eSmrg		error = SetPictureTransform(src, &xf86_crtc->crtc_to_framebuffer);
833d6c0b56eSmrg		if (error) {
834d6c0b56eSmrg			ErrorF("SetPictureTransform failed for transformed scanout "
835d6c0b56eSmrg			       "update\n");
836d6c0b56eSmrg			goto free_dst;
837d6c0b56eSmrg		}
838d6c0b56eSmrg
839d6c0b56eSmrg		if (xf86_crtc->filter)
840d6c0b56eSmrg			SetPicturePictFilter(src, xf86_crtc->filter, xf86_crtc->params,
841d6c0b56eSmrg					     xf86_crtc->nparams);
842d6c0b56eSmrg
843d6c0b56eSmrg		pScreen->SourceValidate = NULL;
844d6c0b56eSmrg		CompositePicture(PictOpSrc,
845d6c0b56eSmrg				 src, NULL, dst,
846d6c0b56eSmrg				 extents.x1, extents.y1, 0, 0, extents.x1,
847d6c0b56eSmrg				 extents.y1, extents.x2 - extents.x1,
848d6c0b56eSmrg				 extents.y2 - extents.y1);
849d6c0b56eSmrg		pScreen->SourceValidate = SourceValidate;
850d6c0b56eSmrg
851d6c0b56eSmrg free_dst:
852d6c0b56eSmrg		FreePicture(dst, None);
853d6c0b56eSmrg free_src:
854d6c0b56eSmrg		FreePicture(src, None);
855d6c0b56eSmrg	} else
856d6c0b56eSmrg out:
857d6c0b56eSmrg#endif /* XF86_CRTC_VERSION >= 4 */
858d6c0b56eSmrg	{
859d6c0b56eSmrg		GCPtr gc = GetScratchGC(pDraw->depth, pScreen);
860d6c0b56eSmrg
861d6c0b56eSmrg		ValidateGC(pDraw, gc);
862d6c0b56eSmrg		(*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable,
863d6c0b56eSmrg				     pDraw, gc,
864d6c0b56eSmrg				     xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
865d6c0b56eSmrg				     extents.x2 - extents.x1, extents.y2 - extents.y1,
866d6c0b56eSmrg				     extents.x1, extents.y1);
867d6c0b56eSmrg		FreeScratchGC(gc);
868d6c0b56eSmrg	}
869d6c0b56eSmrg
870d6c0b56eSmrg	amdgpu_glamor_flush(xf86_crtc->scrn);
871d6c0b56eSmrg
872d6c0b56eSmrg	return TRUE;
873d6c0b56eSmrg}
874d6c0b56eSmrg
875d6c0b56eSmrgstatic void
876d6c0b56eSmrgamdgpu_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
877d6c0b56eSmrg{
878d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = event_data;
879d6c0b56eSmrg
880d6c0b56eSmrg	drmmode_crtc->scanout_update_pending = FALSE;
881d6c0b56eSmrg}
882d6c0b56eSmrg
88311bf0794Smrgstatic void
884d6c0b56eSmrgamdgpu_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
885d6c0b56eSmrg							  void *event_data)
886d6c0b56eSmrg{
887d6c0b56eSmrg	amdgpu_scanout_do_update(crtc, 0);
888d6c0b56eSmrg
889d6c0b56eSmrg	amdgpu_scanout_update_abort(crtc, event_data);
890d6c0b56eSmrg}
891d6c0b56eSmrg
892d6c0b56eSmrgstatic void
893d6c0b56eSmrgamdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
894d6c0b56eSmrg{
895d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
896d6c0b56eSmrg	uintptr_t drm_queue_seq;
897d6c0b56eSmrg	ScrnInfoPtr scrn;
898d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt;
899d6c0b56eSmrg	drmVBlank vbl;
900d6c0b56eSmrg	DamagePtr pDamage;
901d6c0b56eSmrg	RegionPtr pRegion;
902d6c0b56eSmrg	BoxRec extents;
903d6c0b56eSmrg
904d6c0b56eSmrg	if (!xf86_crtc->enabled ||
905d6c0b56eSmrg	    drmmode_crtc->scanout_update_pending ||
906d6c0b56eSmrg	    !drmmode_crtc->scanout[0].pixmap ||
907504d986fSmrg	    drmmode_crtc->pending_dpms_mode != DPMSModeOn)
908d6c0b56eSmrg		return;
909d6c0b56eSmrg
910504d986fSmrg	pDamage = drmmode_crtc->scanout_damage;
911d6c0b56eSmrg	if (!pDamage)
912d6c0b56eSmrg		return;
913d6c0b56eSmrg
914d6c0b56eSmrg	pRegion = DamageRegion(pDamage);
915d6c0b56eSmrg	if (!RegionNotEmpty(pRegion))
916d6c0b56eSmrg		return;
917d6c0b56eSmrg
918d6c0b56eSmrg	extents = *RegionExtents(pRegion);
919504d986fSmrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents)) {
920504d986fSmrg		RegionEmpty(pRegion);
921d6c0b56eSmrg		return;
922504d986fSmrg	}
923d6c0b56eSmrg
924d6c0b56eSmrg	scrn = xf86_crtc->scrn;
925d6c0b56eSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
926d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
927d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT,
928d6c0b56eSmrg					       drmmode_crtc,
929d6c0b56eSmrg					       amdgpu_scanout_update_handler,
930d6c0b56eSmrg					       amdgpu_scanout_update_abort);
931504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
932d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
933d6c0b56eSmrg			   "amdgpu_drm_queue_alloc failed for scanout update\n");
934d6c0b56eSmrg		return;
935d6c0b56eSmrg	}
936d6c0b56eSmrg
937d6c0b56eSmrg	pAMDGPUEnt = AMDGPUEntPriv(scrn);
938d6c0b56eSmrg	vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
939d6c0b56eSmrg	vbl.request.type |= amdgpu_populate_vbl_request_type(xf86_crtc);
940d6c0b56eSmrg	vbl.request.sequence = 1;
941d6c0b56eSmrg	vbl.request.signal = drm_queue_seq;
942d6c0b56eSmrg	if (drmWaitVBlank(pAMDGPUEnt->fd, &vbl)) {
943d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
944d6c0b56eSmrg			   "drmWaitVBlank failed for scanout update: %s\n",
945d6c0b56eSmrg			   strerror(errno));
946d6c0b56eSmrg		amdgpu_drm_abort_entry(drm_queue_seq);
947d6c0b56eSmrg		return;
948d6c0b56eSmrg	}
949d6c0b56eSmrg
950d6c0b56eSmrg	drmmode_crtc->scanout_update_pending = TRUE;
951d6c0b56eSmrg}
952d6c0b56eSmrg
953d6c0b56eSmrgstatic void
954d6c0b56eSmrgamdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
955d6c0b56eSmrg{
956d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = event_data;
957d6c0b56eSmrg
958d6c0b56eSmrg	drmmode_crtc->scanout_update_pending = FALSE;
959504d986fSmrg	drmmode_clear_pending_flip(crtc);
960d6c0b56eSmrg}
961d6c0b56eSmrg
962d6c0b56eSmrgstatic void
963d6c0b56eSmrgamdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
964d6c0b56eSmrg					xf86CrtcPtr xf86_crtc)
965d6c0b56eSmrg{
966d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
96711bf0794Smrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
96811bf0794Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
969d6c0b56eSmrg	uintptr_t drm_queue_seq;
970d6c0b56eSmrg	unsigned scanout_id;
971d6c0b56eSmrg
97211bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
97311bf0794Smrg	    drmmode_crtc->pending_dpms_mode != DPMSModeOn)
974d6c0b56eSmrg		return;
975d6c0b56eSmrg
976d6c0b56eSmrg	scanout_id = drmmode_crtc->scanout_id ^ 1;
977d6c0b56eSmrg	if (!amdgpu_scanout_do_update(xf86_crtc, scanout_id))
978d6c0b56eSmrg		return;
979d6c0b56eSmrg
980d6c0b56eSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
981d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
982d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT,
983d6c0b56eSmrg					       drmmode_crtc, NULL,
984d6c0b56eSmrg					       amdgpu_scanout_flip_abort);
985504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
986d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
987d6c0b56eSmrg			   "Allocating DRM event queue entry failed.\n");
988d6c0b56eSmrg		return;
989d6c0b56eSmrg	}
990d6c0b56eSmrg
99111bf0794Smrg	if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc,
99211bf0794Smrg					      drmmode_crtc->scanout[scanout_id].fb_id,
99311bf0794Smrg					      0, drm_queue_seq, 0) != 0) {
994d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s\n",
995d6c0b56eSmrg			   __func__, strerror(errno));
99611bf0794Smrg		amdgpu_drm_abort_entry(drm_queue_seq);
997d6c0b56eSmrg		return;
998d6c0b56eSmrg	}
999d6c0b56eSmrg
1000d6c0b56eSmrg	drmmode_crtc->scanout_id = scanout_id;
1001d6c0b56eSmrg	drmmode_crtc->scanout_update_pending = TRUE;
1002d6c0b56eSmrg	drmmode_crtc->flip_pending = TRUE;
1003d6c0b56eSmrg}
1004d6c0b56eSmrg
1005d6c0b56eSmrgstatic void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
1006d6c0b56eSmrg{
1007d6c0b56eSmrg	SCREEN_PTR(arg);
1008d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1009d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1010d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1011d6c0b56eSmrg	int c;
1012d6c0b56eSmrg
1013d6c0b56eSmrg	pScreen->BlockHandler = info->BlockHandler;
1014d6c0b56eSmrg	(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
1015d6c0b56eSmrg	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
1016d6c0b56eSmrg
101711bf0794Smrg	if (!amdgpu_is_gpu_screen(pScreen))
1018504d986fSmrg	{
1019504d986fSmrg		for (c = 0; c < xf86_config->num_crtc; c++) {
102011bf0794Smrg			xf86CrtcPtr crtc = xf86_config->crtc[c];
102111bf0794Smrg			drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
102211bf0794Smrg
102311bf0794Smrg			if (drmmode_crtc->tear_free)
102411bf0794Smrg				amdgpu_scanout_flip(pScreen, info, crtc);
1025504d986fSmrg			else if (info->shadow_primary
1026d6c0b56eSmrg#if XF86_CRTC_VERSION >= 4
102711bf0794Smrg				 || crtc->driverIsPerformingTransform
1028d6c0b56eSmrg#endif
1029504d986fSmrg				)
103011bf0794Smrg				amdgpu_scanout_update(crtc);
1031504d986fSmrg		}
1032d6c0b56eSmrg	}
1033d6c0b56eSmrg
103411bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,0,0,0)
1035d6c0b56eSmrg	if (info->use_glamor)
1036d6c0b56eSmrg		amdgpu_glamor_flush(pScrn);
103711bf0794Smrg#endif
1038d6c0b56eSmrg
1039d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
1040504d986fSmrg	amdgpu_dirty_update(pScrn);
1041d6c0b56eSmrg#endif
1042d6c0b56eSmrg}
1043d6c0b56eSmrg
1044d6c0b56eSmrg/* This is called by AMDGPUPreInit to set up the default visual */
1045d6c0b56eSmrgstatic Bool AMDGPUPreInitVisual(ScrnInfoPtr pScrn)
1046d6c0b56eSmrg{
1047d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1048d6c0b56eSmrg
1049d6c0b56eSmrg	if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb))
1050d6c0b56eSmrg		return FALSE;
1051d6c0b56eSmrg
1052d6c0b56eSmrg	switch (pScrn->depth) {
1053d6c0b56eSmrg	case 8:
1054d6c0b56eSmrg	case 15:
1055d6c0b56eSmrg	case 16:
1056d6c0b56eSmrg	case 24:
1057d6c0b56eSmrg		break;
1058d6c0b56eSmrg
1059d6c0b56eSmrg	default:
1060d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1061d6c0b56eSmrg			   "Given depth (%d) is not supported by %s driver\n",
1062d6c0b56eSmrg			   pScrn->depth, AMDGPU_DRIVER_NAME);
1063d6c0b56eSmrg		return FALSE;
1064d6c0b56eSmrg	}
1065d6c0b56eSmrg
1066d6c0b56eSmrg	xf86PrintDepthBpp(pScrn);
1067d6c0b56eSmrg
1068d6c0b56eSmrg	info->pix24bpp = xf86GetBppFromDepth(pScrn, pScrn->depth);
1069d6c0b56eSmrg	info->pixel_bytes = pScrn->bitsPerPixel / 8;
1070d6c0b56eSmrg
1071d6c0b56eSmrg	if (info->pix24bpp == 24) {
1072d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1073d6c0b56eSmrg			   "Amdgpu does NOT support 24bpp\n");
1074d6c0b56eSmrg		return FALSE;
1075d6c0b56eSmrg	}
1076d6c0b56eSmrg
1077d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1078d6c0b56eSmrg		   "Pixel depth = %d bits stored in %d byte%s (%d bpp pixmaps)\n",
1079d6c0b56eSmrg		   pScrn->depth,
1080d6c0b56eSmrg		   info->pixel_bytes,
1081d6c0b56eSmrg		   info->pixel_bytes > 1 ? "s" : "", info->pix24bpp);
1082d6c0b56eSmrg
1083d6c0b56eSmrg	if (!xf86SetDefaultVisual(pScrn, -1))
1084d6c0b56eSmrg		return FALSE;
1085d6c0b56eSmrg
1086d6c0b56eSmrg	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
1087d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1088d6c0b56eSmrg			   "Default visual (%s) is not supported at depth %d\n",
1089d6c0b56eSmrg			   xf86GetVisualName(pScrn->defaultVisual),
1090d6c0b56eSmrg			   pScrn->depth);
1091d6c0b56eSmrg		return FALSE;
1092d6c0b56eSmrg	}
1093d6c0b56eSmrg	return TRUE;
1094d6c0b56eSmrg}
1095d6c0b56eSmrg
1096d6c0b56eSmrg/* This is called by AMDGPUPreInit to handle all color weight issues */
1097d6c0b56eSmrgstatic Bool AMDGPUPreInitWeight(ScrnInfoPtr pScrn)
1098d6c0b56eSmrg{
1099d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1100d6c0b56eSmrg
1101d6c0b56eSmrg	/* Save flag for 6 bit DAC to use for
1102d6c0b56eSmrg	   setting CRTC registers.  Otherwise use
1103d6c0b56eSmrg	   an 8 bit DAC, even if xf86SetWeight sets
1104d6c0b56eSmrg	   pScrn->rgbBits to some value other than
1105d6c0b56eSmrg	   8. */
1106d6c0b56eSmrg	info->dac6bits = FALSE;
1107d6c0b56eSmrg
1108d6c0b56eSmrg	if (pScrn->depth > 8) {
1109d6c0b56eSmrg		rgb defaultWeight = { 0, 0, 0 };
1110d6c0b56eSmrg
1111d6c0b56eSmrg		if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
1112d6c0b56eSmrg			return FALSE;
1113d6c0b56eSmrg	} else {
1114d6c0b56eSmrg		pScrn->rgbBits = 8;
1115d6c0b56eSmrg	}
1116d6c0b56eSmrg
1117d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1118d6c0b56eSmrg		   "Using %d bits per RGB (%d bit DAC)\n",
1119d6c0b56eSmrg		   pScrn->rgbBits, info->dac6bits ? 6 : 8);
1120d6c0b56eSmrg
1121d6c0b56eSmrg	return TRUE;
1122d6c0b56eSmrg}
1123d6c0b56eSmrg
1124d6c0b56eSmrgstatic Bool AMDGPUPreInitAccel_KMS(ScrnInfoPtr pScrn)
1125d6c0b56eSmrg{
1126d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1127d6c0b56eSmrg
1128d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_ACCEL, TRUE)) {
1129d6c0b56eSmrg		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1130d6c0b56eSmrg		Bool use_glamor = TRUE;
1131d6c0b56eSmrg#ifdef HAVE_GBM_BO_USE_LINEAR
1132d6c0b56eSmrg		const char *accel_method;
1133d6c0b56eSmrg
1134d6c0b56eSmrg		accel_method = xf86GetOptValString(info->Options, OPTION_ACCEL_METHOD);
1135d6c0b56eSmrg		if ((accel_method && !strcmp(accel_method, "none")))
1136d6c0b56eSmrg			use_glamor = FALSE;
1137d6c0b56eSmrg#endif
1138d6c0b56eSmrg
1139d6c0b56eSmrg#ifdef DRI2
1140d6c0b56eSmrg		info->dri2.available = ! !xf86LoadSubModule(pScrn, "dri2");
1141d6c0b56eSmrg#endif
1142d6c0b56eSmrg
1143d6c0b56eSmrg		if (info->dri2.available)
1144d6c0b56eSmrg			info->gbm = gbm_create_device(pAMDGPUEnt->fd);
1145d6c0b56eSmrg		if (info->gbm == NULL)
1146d6c0b56eSmrg			info->dri2.available = FALSE;
1147d6c0b56eSmrg
1148d6c0b56eSmrg		if (use_glamor &&
1149d6c0b56eSmrg			amdgpu_glamor_pre_init(pScrn))
1150d6c0b56eSmrg			return TRUE;
1151d6c0b56eSmrg
1152d6c0b56eSmrg		if (info->dri2.available)
1153d6c0b56eSmrg			return TRUE;
1154d6c0b56eSmrg	}
1155d6c0b56eSmrg
1156d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1157d6c0b56eSmrg		   "GPU accel disabled or not working, using shadowfb for KMS\n");
1158d6c0b56eSmrg	info->shadow_fb = TRUE;
1159d6c0b56eSmrg	if (!xf86LoadSubModule(pScrn, "shadow"))
1160d6c0b56eSmrg		info->shadow_fb = FALSE;
1161d6c0b56eSmrg
1162d6c0b56eSmrg	return TRUE;
1163d6c0b56eSmrg}
1164d6c0b56eSmrg
116511bf0794Smrgstatic Bool AMDGPUPreInitChipType_KMS(ScrnInfoPtr pScrn,
116611bf0794Smrg				      struct amdgpu_gpu_info *gpu_info)
1167d6c0b56eSmrg{
1168d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
116911bf0794Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1170d6c0b56eSmrg
117111bf0794Smrg	info->Chipset = info->PciInfo->device_id;
117211bf0794Smrg	pScrn->chipset = amdgpu_get_marketing_name(pAMDGPUEnt->pDev);
117311bf0794Smrg	if (!pScrn->chipset)
117411bf0794Smrg		pScrn->chipset = "Unknown AMD Radeon GPU";
1175d6c0b56eSmrg
1176d6c0b56eSmrg	if (info->Chipset < 0) {
1177d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1178d6c0b56eSmrg			   "Chipset \"%s\" is not recognized\n",
1179d6c0b56eSmrg			   pScrn->chipset);
1180d6c0b56eSmrg		return FALSE;
1181d6c0b56eSmrg	}
1182d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1183d6c0b56eSmrg		   "Chipset: \"%s\" (ChipID = 0x%04x)\n",
1184d6c0b56eSmrg		   pScrn->chipset, info->Chipset);
1185d6c0b56eSmrg
118611bf0794Smrg	info->family = gpu_info->family_id;
1187d6c0b56eSmrg
1188d6c0b56eSmrg	return TRUE;
1189d6c0b56eSmrg}
1190d6c0b56eSmrg
119111bf0794Smrgstatic Bool amdgpu_get_tile_config(AMDGPUInfoPtr info,
119211bf0794Smrg				   struct amdgpu_gpu_info *gpu_info)
1193d6c0b56eSmrg{
119411bf0794Smrg	switch ((gpu_info->gb_addr_cfg & 0x70) >> 4) {
1195d6c0b56eSmrg	case 0:
1196d6c0b56eSmrg		info->group_bytes = 256;
1197d6c0b56eSmrg		break;
1198d6c0b56eSmrg	case 1:
1199d6c0b56eSmrg		info->group_bytes = 512;
1200d6c0b56eSmrg		break;
1201d6c0b56eSmrg	default:
1202d6c0b56eSmrg		return FALSE;
1203d6c0b56eSmrg	}
1204d6c0b56eSmrg
1205d6c0b56eSmrg	info->have_tiling_info = TRUE;
1206d6c0b56eSmrg	return TRUE;
1207d6c0b56eSmrg}
1208d6c0b56eSmrg
1209d6c0b56eSmrgstatic void AMDGPUSetupCapabilities(ScrnInfoPtr pScrn)
1210d6c0b56eSmrg{
1211d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
1212d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1213d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1214d6c0b56eSmrg	uint64_t value;
1215d6c0b56eSmrg	int ret;
1216d6c0b56eSmrg
1217d6c0b56eSmrg	pScrn->capabilities = 0;
1218d6c0b56eSmrg
1219d6c0b56eSmrg	/* PRIME offloading requires acceleration */
1220d6c0b56eSmrg	if (!info->use_glamor)
1221d6c0b56eSmrg		return;
1222d6c0b56eSmrg
1223d6c0b56eSmrg	ret = drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PRIME, &value);
1224d6c0b56eSmrg	if (ret == 0) {
1225d6c0b56eSmrg		if (value & DRM_PRIME_CAP_EXPORT)
1226504d986fSmrg			pScrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SourceOffload;
1227504d986fSmrg		if (value & DRM_PRIME_CAP_IMPORT) {
1228504d986fSmrg			pScrn->capabilities |= RR_Capability_SinkOffload;
1229504d986fSmrg			if (info->drmmode.count_crtcs)
1230504d986fSmrg				pScrn->capabilities |= RR_Capability_SinkOutput;
1231504d986fSmrg		}
1232d6c0b56eSmrg	}
1233d6c0b56eSmrg#endif
1234d6c0b56eSmrg}
1235d6c0b56eSmrg
1236d6c0b56eSmrg/* When the root window is created, initialize the screen contents from
1237d6c0b56eSmrg * console if -background none was specified on the command line
1238d6c0b56eSmrg */
1239d6c0b56eSmrgstatic Bool AMDGPUCreateWindow_oneshot(WindowPtr pWin)
1240d6c0b56eSmrg{
1241d6c0b56eSmrg	ScreenPtr pScreen = pWin->drawable.pScreen;
1242d6c0b56eSmrg	ScrnInfoPtr pScrn;
1243d6c0b56eSmrg	AMDGPUInfoPtr info;
1244d6c0b56eSmrg	Bool ret;
1245d6c0b56eSmrg
1246d6c0b56eSmrg	if (pWin != pScreen->root)
1247d6c0b56eSmrg		ErrorF("%s called for non-root window %p\n", __func__, pWin);
1248d6c0b56eSmrg
1249d6c0b56eSmrg	pScrn = xf86ScreenToScrn(pScreen);
1250d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
1251d6c0b56eSmrg	pScreen->CreateWindow = info->CreateWindow;
1252d6c0b56eSmrg	ret = pScreen->CreateWindow(pWin);
1253d6c0b56eSmrg
1254d6c0b56eSmrg	if (ret)
1255d6c0b56eSmrg		drmmode_copy_fb(pScrn, &info->drmmode);
1256d6c0b56eSmrg
1257d6c0b56eSmrg	return ret;
1258d6c0b56eSmrg}
1259d6c0b56eSmrg
126011bf0794Smrg/* When the root window is mapped, set the initial modes */
126111bf0794Smrgstatic void AMDGPUWindowExposures_oneshot(WindowPtr pWin, RegionPtr pRegion
126211bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
126311bf0794Smrg					  , RegionPtr pBSRegion
126411bf0794Smrg#endif
126511bf0794Smrg	)
126611bf0794Smrg{
126711bf0794Smrg	ScreenPtr pScreen = pWin->drawable.pScreen;
126811bf0794Smrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
126911bf0794Smrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
127011bf0794Smrg
127111bf0794Smrg	if (pWin != pScreen->root)
127211bf0794Smrg		ErrorF("%s called for non-root window %p\n", __func__, pWin);
127311bf0794Smrg
127411bf0794Smrg	pScreen->WindowExposures = info->WindowExposures;
127511bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
127611bf0794Smrg	pScreen->WindowExposures(pWin, pRegion, pBSRegion);
127711bf0794Smrg#else
127811bf0794Smrg	pScreen->WindowExposures(pWin, pRegion);
127911bf0794Smrg#endif
128011bf0794Smrg
128111bf0794Smrg	amdgpu_glamor_finish(pScrn);
128211bf0794Smrg	drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE);
128311bf0794Smrg}
128411bf0794Smrg
1285d6c0b56eSmrgBool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
1286d6c0b56eSmrg{
1287d6c0b56eSmrg	AMDGPUInfoPtr info;
1288d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt;
128911bf0794Smrg	struct amdgpu_gpu_info gpu_info;
129011bf0794Smrg	MessageType from;
1291d6c0b56eSmrg	DevUnion *pPriv;
1292d6c0b56eSmrg	Gamma zeros = { 0.0, 0.0, 0.0 };
1293d6c0b56eSmrg	int cpp;
1294d6c0b56eSmrg	uint64_t heap_size = 0;
1295d6c0b56eSmrg	uint64_t max_allocation = 0;
1296d6c0b56eSmrg	Bool sw_cursor;
1297d6c0b56eSmrg
1298d6c0b56eSmrg	if (flags & PROBE_DETECT)
1299d6c0b56eSmrg		return TRUE;
1300d6c0b56eSmrg
1301d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1302d6c0b56eSmrg		       "AMDGPUPreInit_KMS\n");
1303d6c0b56eSmrg	if (pScrn->numEntities != 1)
1304d6c0b56eSmrg		return FALSE;
1305d6c0b56eSmrg	if (!AMDGPUGetRec(pScrn))
1306d6c0b56eSmrg		return FALSE;
1307d6c0b56eSmrg
1308d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
1309d6c0b56eSmrg	info->IsSecondary = FALSE;
1310d6c0b56eSmrg	info->pEnt =
1311d6c0b56eSmrg	    xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
1312d6c0b56eSmrg	if (info->pEnt->location.type != BUS_PCI
1313d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS
1314d6c0b56eSmrg	    && info->pEnt->location.type != BUS_PLATFORM
1315d6c0b56eSmrg#endif
1316d6c0b56eSmrg	    )
1317d6c0b56eSmrg		goto fail;
1318d6c0b56eSmrg
1319d6c0b56eSmrg	pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
1320d6c0b56eSmrg				     getAMDGPUEntityIndex());
1321d6c0b56eSmrg	pAMDGPUEnt = pPriv->ptr;
1322d6c0b56eSmrg
1323d6c0b56eSmrg	if (xf86IsEntityShared(pScrn->entityList[0])) {
1324d6c0b56eSmrg		if (xf86IsPrimInitDone(pScrn->entityList[0])) {
1325d6c0b56eSmrg			info->IsSecondary = TRUE;
1326d6c0b56eSmrg		} else {
1327d6c0b56eSmrg			xf86SetPrimInitDone(pScrn->entityList[0]);
1328d6c0b56eSmrg		}
1329d6c0b56eSmrg	}
1330d6c0b56eSmrg
1331504d986fSmrg	if (info->IsSecondary)
1332504d986fSmrg		pAMDGPUEnt->secondary_scrn = pScrn;
1333504d986fSmrg	else
1334504d986fSmrg		pAMDGPUEnt->primary_scrn = pScrn;
1335504d986fSmrg
1336d6c0b56eSmrg	info->PciInfo = xf86GetPciInfoForEntity(info->pEnt->index);
1337d6c0b56eSmrg	pScrn->monitor = pScrn->confScreen->monitor;
1338d6c0b56eSmrg
1339d6c0b56eSmrg	if (!AMDGPUPreInitVisual(pScrn))
1340d6c0b56eSmrg		goto fail;
1341d6c0b56eSmrg
1342d6c0b56eSmrg	xf86CollectOptions(pScrn, NULL);
1343d6c0b56eSmrg	if (!(info->Options = malloc(sizeof(AMDGPUOptions_KMS))))
1344d6c0b56eSmrg		goto fail;
1345d6c0b56eSmrg
1346d6c0b56eSmrg	memcpy(info->Options, AMDGPUOptions_KMS, sizeof(AMDGPUOptions_KMS));
1347d6c0b56eSmrg	xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options);
1348d6c0b56eSmrg
1349d6c0b56eSmrg	if (!AMDGPUPreInitWeight(pScrn))
1350d6c0b56eSmrg		goto fail;
1351d6c0b56eSmrg
135211bf0794Smrg	memset(&gpu_info, 0, sizeof(gpu_info));
135311bf0794Smrg	amdgpu_query_gpu_info(pAMDGPUEnt->pDev, &gpu_info);
135411bf0794Smrg
135511bf0794Smrg	if (!AMDGPUPreInitChipType_KMS(pScrn, &gpu_info))
1356d6c0b56eSmrg		goto fail;
1357d6c0b56eSmrg
1358d6c0b56eSmrg	info->dri2.available = FALSE;
1359d6c0b56eSmrg	info->dri2.enabled = FALSE;
1360d6c0b56eSmrg	info->dri2.pKernelDRMVersion = drmGetVersion(pAMDGPUEnt->fd);
1361d6c0b56eSmrg	if (info->dri2.pKernelDRMVersion == NULL) {
1362d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1363d6c0b56eSmrg			   "AMDGPUDRIGetVersion failed to get the DRM version\n");
1364d6c0b56eSmrg		goto fail;
1365d6c0b56eSmrg	}
1366d6c0b56eSmrg
1367d6c0b56eSmrg	/* Get ScreenInit function */
1368d6c0b56eSmrg	if (!xf86LoadSubModule(pScrn, "fb"))
1369d6c0b56eSmrg		return FALSE;
1370d6c0b56eSmrg
1371d6c0b56eSmrg	if (!AMDGPUPreInitAccel_KMS(pScrn))
1372d6c0b56eSmrg		goto fail;
1373d6c0b56eSmrg
1374d6c0b56eSmrg	amdgpu_drm_queue_init();
1375d6c0b56eSmrg
1376d6c0b56eSmrg	/* don't enable tiling if accel is not enabled */
1377d6c0b56eSmrg	if (info->use_glamor) {
1378d6c0b56eSmrg		/* set default group bytes, overridden by kernel info below */
1379d6c0b56eSmrg		info->group_bytes = 256;
1380d6c0b56eSmrg		info->have_tiling_info = FALSE;
138111bf0794Smrg		amdgpu_get_tile_config(info, &gpu_info);
1382d6c0b56eSmrg	}
1383d6c0b56eSmrg
1384d6c0b56eSmrg	if (info->use_glamor) {
138511bf0794Smrg		from = X_DEFAULT;
1386d6c0b56eSmrg
138711bf0794Smrg		info->tear_free = 2;
138811bf0794Smrg		if (xf86GetOptValBool(info->Options, OPTION_TEAR_FREE,
138911bf0794Smrg				      &info->tear_free))
139011bf0794Smrg			from = X_CONFIG;
139111bf0794Smrg		xf86DrvMsg(pScrn->scrnIndex, from, "TearFree property default: %s\n",
139211bf0794Smrg			   info->tear_free == 2 ? "auto" : (info->tear_free ? "on" : "off"));
1393d6c0b56eSmrg
1394d6c0b56eSmrg		info->shadow_primary =
1395d6c0b56eSmrg			xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE);
1396d6c0b56eSmrg
1397d6c0b56eSmrg		if (info->shadow_primary)
1398d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowPrimary enabled\n");
1399d6c0b56eSmrg	}
1400d6c0b56eSmrg
140111bf0794Smrg	if (!amdgpu_is_gpu_scrn(pScrn)) {
140211bf0794Smrg		sw_cursor = xf86ReturnOptValBool(info->Options,
140311bf0794Smrg						 OPTION_SW_CURSOR, FALSE);
140411bf0794Smrg
140511bf0794Smrg		info->allowPageFlip = xf86ReturnOptValBool(info->Options,
140611bf0794Smrg							   OPTION_PAGE_FLIP,
140711bf0794Smrg							   TRUE);
140811bf0794Smrg		if (sw_cursor || info->shadow_primary) {
140911bf0794Smrg			xf86DrvMsg(pScrn->scrnIndex,
141011bf0794Smrg				   info->allowPageFlip ? X_WARNING : X_DEFAULT,
141111bf0794Smrg				   "KMS Pageflipping: disabled%s\n",
141211bf0794Smrg				   info->allowPageFlip ?
141311bf0794Smrg				   (sw_cursor ? " because of SWcursor" :
141411bf0794Smrg				    " because of ShadowPrimary") : "");
141511bf0794Smrg			info->allowPageFlip = FALSE;
141611bf0794Smrg		} else {
141711bf0794Smrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
141811bf0794Smrg				   "KMS Pageflipping: %sabled\n",
141911bf0794Smrg				   info->allowPageFlip ? "en" : "dis");
142011bf0794Smrg		}
1421d6c0b56eSmrg	}
1422d6c0b56eSmrg
1423d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_DELETE_DP12, FALSE)) {
1424d6c0b56eSmrg		info->drmmode.delete_dp_12_displays = TRUE;
1425d6c0b56eSmrg	}
1426d6c0b56eSmrg
1427d6c0b56eSmrg	if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) ==
1428d6c0b56eSmrg	    FALSE) {
1429d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1430d6c0b56eSmrg			   "Kernel modesetting setup failed\n");
1431d6c0b56eSmrg		goto fail;
1432d6c0b56eSmrg	}
1433d6c0b56eSmrg
1434504d986fSmrg	AMDGPUSetupCapabilities(pScrn);
1435504d986fSmrg
1436d6c0b56eSmrg	if (info->drmmode.count_crtcs == 1)
1437d6c0b56eSmrg		pAMDGPUEnt->HasCRTC2 = FALSE;
1438d6c0b56eSmrg	else
1439d6c0b56eSmrg		pAMDGPUEnt->HasCRTC2 = TRUE;
1440d6c0b56eSmrg
144111bf0794Smrg	if (info->family < AMDGPU_FAMILY_CI) {
1442504d986fSmrg		info->cursor_w = CURSOR_WIDTH;
1443504d986fSmrg		info->cursor_h = CURSOR_HEIGHT;
1444504d986fSmrg	} else {
1445504d986fSmrg		info->cursor_w = CURSOR_WIDTH_CIK;
1446504d986fSmrg		info->cursor_h = CURSOR_HEIGHT_CIK;
1447504d986fSmrg	}
1448d6c0b56eSmrg
1449d6c0b56eSmrg	amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_GTT,
1450d6c0b56eSmrg				&heap_size, &max_allocation);
1451d6c0b56eSmrg	info->gart_size = heap_size;
1452d6c0b56eSmrg	amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_VRAM,
1453d6c0b56eSmrg				&heap_size, &max_allocation);
1454d6c0b56eSmrg	info->vram_size = max_allocation;
1455d6c0b56eSmrg
1456d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1457d6c0b56eSmrg		   "mem size init: gart size :%llx vram size: s:%llx visible:%llx\n",
1458d6c0b56eSmrg		   (unsigned long long)info->gart_size,
1459d6c0b56eSmrg		   (unsigned long long)heap_size,
1460d6c0b56eSmrg		   (unsigned long long)max_allocation);
1461d6c0b56eSmrg
1462d6c0b56eSmrg	cpp = pScrn->bitsPerPixel / 8;
1463d6c0b56eSmrg	pScrn->displayWidth =
1464d6c0b56eSmrg	    AMDGPU_ALIGN(pScrn->virtualX, drmmode_get_pitch_align(pScrn, cpp));
1465d6c0b56eSmrg
1466d6c0b56eSmrg	/* Set display resolution */
1467d6c0b56eSmrg	xf86SetDpi(pScrn, 0, 0);
1468d6c0b56eSmrg
1469d6c0b56eSmrg	if (!xf86SetGamma(pScrn, zeros))
1470d6c0b56eSmrg		return FALSE;
1471d6c0b56eSmrg
1472d6c0b56eSmrg	if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
1473d6c0b56eSmrg		if (!xf86LoadSubModule(pScrn, "ramdac"))
1474d6c0b56eSmrg			return FALSE;
1475d6c0b56eSmrg	}
1476d6c0b56eSmrg
1477d6c0b56eSmrg	if (pScrn->modes == NULL
1478d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS
1479d6c0b56eSmrg	    && !pScrn->is_gpu
1480d6c0b56eSmrg#endif
1481d6c0b56eSmrg	    ) {
1482d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
1483d6c0b56eSmrg		goto fail;
1484d6c0b56eSmrg	}
1485d6c0b56eSmrg
1486d6c0b56eSmrg	return TRUE;
1487d6c0b56eSmrgfail:
1488d6c0b56eSmrg	AMDGPUFreeRec(pScrn);
1489d6c0b56eSmrg	return FALSE;
1490d6c0b56eSmrg
1491d6c0b56eSmrg}
1492d6c0b56eSmrg
1493d6c0b56eSmrgstatic Bool AMDGPUCursorInit_KMS(ScreenPtr pScreen)
1494d6c0b56eSmrg{
1495d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1496d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1497d6c0b56eSmrg
1498d6c0b56eSmrg	return xf86_cursors_init(pScreen, info->cursor_w, info->cursor_h,
1499d6c0b56eSmrg				 (HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
1500d6c0b56eSmrg				  HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
1501d6c0b56eSmrg				  HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
1502d6c0b56eSmrg				  HARDWARE_CURSOR_UPDATE_UNHIDDEN |
1503d6c0b56eSmrg				  HARDWARE_CURSOR_ARGB));
1504d6c0b56eSmrg}
1505d6c0b56eSmrg
1506d6c0b56eSmrgvoid AMDGPUBlank(ScrnInfoPtr pScrn)
1507d6c0b56eSmrg{
1508d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1509d6c0b56eSmrg	xf86OutputPtr output;
1510d6c0b56eSmrg	xf86CrtcPtr crtc;
1511d6c0b56eSmrg	int o, c;
1512d6c0b56eSmrg
1513d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
1514d6c0b56eSmrg		crtc = xf86_config->crtc[c];
1515d6c0b56eSmrg		for (o = 0; o < xf86_config->num_output; o++) {
1516d6c0b56eSmrg			output = xf86_config->output[o];
1517d6c0b56eSmrg			if (output->crtc != crtc)
1518d6c0b56eSmrg				continue;
1519d6c0b56eSmrg
1520d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOff);
1521d6c0b56eSmrg		}
1522d6c0b56eSmrg		crtc->funcs->dpms(crtc, DPMSModeOff);
1523d6c0b56eSmrg	}
1524d6c0b56eSmrg}
1525d6c0b56eSmrg
1526d6c0b56eSmrgvoid AMDGPUUnblank(ScrnInfoPtr pScrn)
1527d6c0b56eSmrg{
1528d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1529d6c0b56eSmrg	xf86OutputPtr output;
1530d6c0b56eSmrg	xf86CrtcPtr crtc;
1531d6c0b56eSmrg	int o, c;
1532d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
1533d6c0b56eSmrg		crtc = xf86_config->crtc[c];
1534d6c0b56eSmrg		if (!crtc->enabled)
1535d6c0b56eSmrg			continue;
1536d6c0b56eSmrg		crtc->funcs->dpms(crtc, DPMSModeOn);
1537d6c0b56eSmrg		for (o = 0; o < xf86_config->num_output; o++) {
1538d6c0b56eSmrg			output = xf86_config->output[o];
1539d6c0b56eSmrg			if (output->crtc != crtc)
1540d6c0b56eSmrg				continue;
1541d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOn);
1542d6c0b56eSmrg		}
1543d6c0b56eSmrg	}
1544d6c0b56eSmrg}
1545d6c0b56eSmrg
1546d6c0b56eSmrgstatic Bool amdgpu_set_drm_master(ScrnInfoPtr pScrn)
1547d6c0b56eSmrg{
1548d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1549d6c0b56eSmrg	int err;
1550d6c0b56eSmrg
1551d6c0b56eSmrg#ifdef XF86_PDEV_SERVER_FD
1552d6c0b56eSmrg	if (pAMDGPUEnt->platform_dev &&
1553d6c0b56eSmrg	    (pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
1554d6c0b56eSmrg		return TRUE;
1555d6c0b56eSmrg#endif
1556d6c0b56eSmrg
1557d6c0b56eSmrg	err = drmSetMaster(pAMDGPUEnt->fd);
1558d6c0b56eSmrg	if (err)
1559d6c0b56eSmrg		ErrorF("Unable to retrieve master\n");
1560d6c0b56eSmrg
1561d6c0b56eSmrg	return err == 0;
1562d6c0b56eSmrg}
1563d6c0b56eSmrg
1564d6c0b56eSmrgstatic void amdgpu_drop_drm_master(ScrnInfoPtr pScrn)
1565d6c0b56eSmrg{
1566d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1567d6c0b56eSmrg
1568d6c0b56eSmrg#ifdef XF86_PDEV_SERVER_FD
1569d6c0b56eSmrg	if (pAMDGPUEnt->platform_dev &&
1570d6c0b56eSmrg	    (pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
1571d6c0b56eSmrg		return;
1572d6c0b56eSmrg#endif
1573d6c0b56eSmrg
1574d6c0b56eSmrg	drmDropMaster(pAMDGPUEnt->fd);
1575d6c0b56eSmrg}
1576d6c0b56eSmrg
1577d6c0b56eSmrg
1578d6c0b56eSmrg
1579d6c0b56eSmrgstatic Bool AMDGPUSaveScreen_KMS(ScreenPtr pScreen, int mode)
1580d6c0b56eSmrg{
1581d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1582d6c0b56eSmrg	Bool unblank;
1583d6c0b56eSmrg
1584d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1585d6c0b56eSmrg		       "AMDGPUSaveScreen(%d)\n", mode);
1586d6c0b56eSmrg
1587d6c0b56eSmrg	unblank = xf86IsUnblank(mode);
1588d6c0b56eSmrg	if (unblank)
1589d6c0b56eSmrg		SetTimeSinceLastInputEvent();
1590d6c0b56eSmrg
1591d6c0b56eSmrg	if ((pScrn != NULL) && pScrn->vtSema) {
1592d6c0b56eSmrg		if (unblank)
1593d6c0b56eSmrg			AMDGPUUnblank(pScrn);
1594d6c0b56eSmrg		else
1595d6c0b56eSmrg			AMDGPUBlank(pScrn);
1596d6c0b56eSmrg	}
1597d6c0b56eSmrg	return TRUE;
1598d6c0b56eSmrg}
1599d6c0b56eSmrg
1600d6c0b56eSmrg/* Called at the end of each server generation.  Restore the original
1601d6c0b56eSmrg * text mode, unmap video memory, and unwrap and call the saved
1602d6c0b56eSmrg * CloseScreen function.
1603d6c0b56eSmrg */
1604d6c0b56eSmrgstatic Bool AMDGPUCloseScreen_KMS(CLOSE_SCREEN_ARGS_DECL)
1605d6c0b56eSmrg{
1606d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1607d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1608d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1609d6c0b56eSmrg
1610d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1611d6c0b56eSmrg		       "AMDGPUCloseScreen\n");
1612d6c0b56eSmrg
1613d6c0b56eSmrg	/* Clear mask of assigned crtc's in this generation */
1614d6c0b56eSmrg	pAMDGPUEnt->assigned_crtcs = 0;
1615d6c0b56eSmrg
1616d6c0b56eSmrg	drmmode_uevent_fini(pScrn, &info->drmmode);
1617d6c0b56eSmrg	amdgpu_drm_queue_close(pScrn);
1618d6c0b56eSmrg
1619504d986fSmrg	if (info->callback_event_type != -1) {
1620504d986fSmrg		DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn);
1621504d986fSmrg		DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
1622504d986fSmrg	}
1623d6c0b56eSmrg
1624d6c0b56eSmrg	amdgpu_sync_close(pScreen);
1625d6c0b56eSmrg	amdgpu_drop_drm_master(pScrn);
1626d6c0b56eSmrg
1627d6c0b56eSmrg	drmmode_fini(pScrn, &info->drmmode);
1628d6c0b56eSmrg	if (info->dri2.enabled) {
1629d6c0b56eSmrg		amdgpu_dri2_close_screen(pScreen);
1630d6c0b56eSmrg	}
1631d6c0b56eSmrg	amdgpu_glamor_fini(pScreen);
1632d6c0b56eSmrg	pScrn->vtSema = FALSE;
1633d6c0b56eSmrg	xf86ClearPrimInitDone(info->pEnt->index);
1634d6c0b56eSmrg	pScreen->BlockHandler = info->BlockHandler;
1635d6c0b56eSmrg	pScreen->CloseScreen = info->CloseScreen;
1636d6c0b56eSmrg	return (*pScreen->CloseScreen) (CLOSE_SCREEN_ARGS);
1637d6c0b56eSmrg}
1638d6c0b56eSmrg
1639d6c0b56eSmrgvoid AMDGPUFreeScreen_KMS(FREE_SCREEN_ARGS_DECL)
1640d6c0b56eSmrg{
1641d6c0b56eSmrg	SCRN_INFO_PTR(arg);
1642d6c0b56eSmrg
1643d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1644d6c0b56eSmrg		       "AMDGPUFreeScreen\n");
1645d6c0b56eSmrg
1646d6c0b56eSmrg	AMDGPUFreeRec(pScrn);
1647d6c0b56eSmrg}
1648d6c0b56eSmrg
1649d6c0b56eSmrgBool AMDGPUScreenInit_KMS(SCREEN_INIT_ARGS_DECL)
1650d6c0b56eSmrg{
1651d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1652d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1653d6c0b56eSmrg	int subPixelOrder = SubPixelUnknown;
1654d6c0b56eSmrg	MessageType from;
1655d6c0b56eSmrg	Bool value;
1656d6c0b56eSmrg	int driLevel;
1657d6c0b56eSmrg	const char *s;
1658d6c0b56eSmrg	void *front_ptr;
1659d6c0b56eSmrg
1660d6c0b56eSmrg	pScrn->fbOffset = 0;
1661d6c0b56eSmrg
1662d6c0b56eSmrg	miClearVisualTypes();
1663d6c0b56eSmrg	if (!miSetVisualTypes(pScrn->depth,
1664d6c0b56eSmrg			      miGetDefaultVisualMask(pScrn->depth),
1665d6c0b56eSmrg			      pScrn->rgbBits, pScrn->defaultVisual))
1666d6c0b56eSmrg		return FALSE;
1667d6c0b56eSmrg	miSetPixmapDepths();
1668d6c0b56eSmrg
1669d6c0b56eSmrg	if (!amdgpu_set_drm_master(pScrn))
1670d6c0b56eSmrg		return FALSE;
1671d6c0b56eSmrg
1672d6c0b56eSmrg	info->directRenderingEnabled = FALSE;
1673d6c0b56eSmrg	if (info->shadow_fb == FALSE)
1674d6c0b56eSmrg		info->directRenderingEnabled = amdgpu_dri2_screen_init(pScreen);
1675d6c0b56eSmrg
1676d6c0b56eSmrg	if (!amdgpu_setup_kernel_mem(pScreen)) {
1677d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1678d6c0b56eSmrg			   "amdgpu_setup_kernel_mem failed\n");
1679d6c0b56eSmrg		return FALSE;
1680d6c0b56eSmrg	}
1681d6c0b56eSmrg	front_ptr = info->front_buffer->cpu_ptr;
1682d6c0b56eSmrg
1683d6c0b56eSmrg	if (info->shadow_fb) {
1684d6c0b56eSmrg		info->fb_shadow = calloc(1,
1685d6c0b56eSmrg					 pScrn->displayWidth * pScrn->virtualY *
1686d6c0b56eSmrg					 ((pScrn->bitsPerPixel + 7) >> 3));
1687d6c0b56eSmrg		if (info->fb_shadow == NULL) {
1688d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1689d6c0b56eSmrg				   "Failed to allocate shadow framebuffer\n");
1690d6c0b56eSmrg			info->shadow_fb = FALSE;
1691d6c0b56eSmrg		} else {
1692d6c0b56eSmrg			if (!fbScreenInit(pScreen, info->fb_shadow,
1693d6c0b56eSmrg					  pScrn->virtualX, pScrn->virtualY,
1694d6c0b56eSmrg					  pScrn->xDpi, pScrn->yDpi,
1695d6c0b56eSmrg					  pScrn->displayWidth,
1696d6c0b56eSmrg					  pScrn->bitsPerPixel))
1697d6c0b56eSmrg				return FALSE;
1698d6c0b56eSmrg		}
1699d6c0b56eSmrg	}
1700d6c0b56eSmrg
1701d6c0b56eSmrg	if (info->shadow_fb == FALSE) {
1702d6c0b56eSmrg		/* Init fb layer */
1703d6c0b56eSmrg		if (!fbScreenInit(pScreen, front_ptr,
1704d6c0b56eSmrg				  pScrn->virtualX, pScrn->virtualY,
1705d6c0b56eSmrg				  pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,
1706d6c0b56eSmrg				  pScrn->bitsPerPixel))
1707d6c0b56eSmrg			return FALSE;
1708d6c0b56eSmrg	}
1709d6c0b56eSmrg
1710d6c0b56eSmrg	xf86SetBlackWhitePixels(pScreen);
1711d6c0b56eSmrg
1712d6c0b56eSmrg	if (pScrn->bitsPerPixel > 8) {
1713d6c0b56eSmrg		VisualPtr visual;
1714d6c0b56eSmrg
1715d6c0b56eSmrg		visual = pScreen->visuals + pScreen->numVisuals;
1716d6c0b56eSmrg		while (--visual >= pScreen->visuals) {
1717d6c0b56eSmrg			if ((visual->class | DynamicClass) == DirectColor) {
1718d6c0b56eSmrg				visual->offsetRed = pScrn->offset.red;
1719d6c0b56eSmrg				visual->offsetGreen = pScrn->offset.green;
1720d6c0b56eSmrg				visual->offsetBlue = pScrn->offset.blue;
1721d6c0b56eSmrg				visual->redMask = pScrn->mask.red;
1722d6c0b56eSmrg				visual->greenMask = pScrn->mask.green;
1723d6c0b56eSmrg				visual->blueMask = pScrn->mask.blue;
1724d6c0b56eSmrg			}
1725d6c0b56eSmrg		}
1726d6c0b56eSmrg	}
1727d6c0b56eSmrg
1728d6c0b56eSmrg	/* Must be after RGB order fixed */
1729d6c0b56eSmrg	fbPictureInit(pScreen, 0, 0);
1730d6c0b56eSmrg
1731d6c0b56eSmrg#ifdef RENDER
1732d6c0b56eSmrg	if ((s = xf86GetOptValString(info->Options, OPTION_SUBPIXEL_ORDER))) {
1733d6c0b56eSmrg		if (strcmp(s, "RGB") == 0)
1734d6c0b56eSmrg			subPixelOrder = SubPixelHorizontalRGB;
1735d6c0b56eSmrg		else if (strcmp(s, "BGR") == 0)
1736d6c0b56eSmrg			subPixelOrder = SubPixelHorizontalBGR;
1737d6c0b56eSmrg		else if (strcmp(s, "NONE") == 0)
1738d6c0b56eSmrg			subPixelOrder = SubPixelNone;
1739d6c0b56eSmrg		PictureSetSubpixelOrder(pScreen, subPixelOrder);
1740d6c0b56eSmrg	}
1741d6c0b56eSmrg#endif
1742d6c0b56eSmrg
174311bf0794Smrg	if (!amdgpu_is_gpu_screen(pScreen)) {
174411bf0794Smrg		value = xorgGetVersion() >= XORG_VERSION_NUMERIC(1,18,3,0,0);
174511bf0794Smrg		from = X_DEFAULT;
1746d6c0b56eSmrg
174711bf0794Smrg		if (info->use_glamor) {
174811bf0794Smrg			if (xf86GetOptValBool(info->Options, OPTION_DRI3, &value))
174911bf0794Smrg				from = X_CONFIG;
1750d6c0b56eSmrg
175111bf0794Smrg			if (xf86GetOptValInteger(info->Options, OPTION_DRI, &driLevel) &&
175211bf0794Smrg			    (driLevel == 2 || driLevel == 3)) {
175311bf0794Smrg				from = X_CONFIG;
175411bf0794Smrg				value = driLevel == 3;
175511bf0794Smrg			}
1756d6c0b56eSmrg		}
1757d6c0b56eSmrg
175811bf0794Smrg		if (value) {
175911bf0794Smrg			value = amdgpu_sync_init(pScreen) &&
176011bf0794Smrg				amdgpu_present_screen_init(pScreen) &&
176111bf0794Smrg				amdgpu_dri3_screen_init(pScreen);
1762d6c0b56eSmrg
176311bf0794Smrg			if (!value)
176411bf0794Smrg				from = X_WARNING;
176511bf0794Smrg		}
1766d6c0b56eSmrg
176711bf0794Smrg		xf86DrvMsg(pScrn->scrnIndex, from, "DRI3 %sabled\n", value ? "en" : "dis");
176811bf0794Smrg	}
1769d6c0b56eSmrg
1770d6c0b56eSmrg	pScrn->vtSema = TRUE;
1771d6c0b56eSmrg	xf86SetBackingStore(pScreen);
1772d6c0b56eSmrg
1773d6c0b56eSmrg	if (info->directRenderingEnabled) {
1774d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1775d6c0b56eSmrg			   "Direct rendering enabled\n");
1776d6c0b56eSmrg	} else {
1777d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
1778d6c0b56eSmrg			   "Direct rendering disabled\n");
1779d6c0b56eSmrg	}
1780d6c0b56eSmrg
1781d6c0b56eSmrg	if (info->use_glamor && info->directRenderingEnabled) {
1782d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1783d6c0b56eSmrg			       "Initializing Acceleration\n");
1784d6c0b56eSmrg		if (amdgpu_glamor_init(pScreen)) {
1785d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1786d6c0b56eSmrg				   "Acceleration enabled\n");
1787d6c0b56eSmrg		} else {
1788d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1789d6c0b56eSmrg				   "Acceleration initialization failed\n");
1790d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1791d6c0b56eSmrg				   "2D and 3D acceleration disabled\n");
1792d6c0b56eSmrg			info->use_glamor = FALSE;
1793d6c0b56eSmrg		}
1794d6c0b56eSmrg	} else if (info->directRenderingEnabled) {
1795d6c0b56eSmrg		if (!amdgpu_pixmap_init(pScreen))
1796d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D acceleration disabled\n");
1797d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration disabled\n");
1798d6c0b56eSmrg	} else {
1799d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D and 3D cceleration disabled\n");
1800d6c0b56eSmrg	}
1801d6c0b56eSmrg
1802d6c0b56eSmrg	/* Init DPMS */
1803d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1804d6c0b56eSmrg		       "Initializing DPMS\n");
1805d6c0b56eSmrg	xf86DPMSInit(pScreen, xf86DPMSSet, 0);
1806d6c0b56eSmrg
1807d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1808d6c0b56eSmrg		       "Initializing Cursor\n");
1809d6c0b56eSmrg
1810d6c0b56eSmrg	/* Set Silken Mouse */
1811d6c0b56eSmrg	xf86SetSilkenMouse(pScreen);
1812d6c0b56eSmrg
1813d6c0b56eSmrg	/* Cursor setup */
1814d6c0b56eSmrg	miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1815d6c0b56eSmrg
1816d6c0b56eSmrg	if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
1817d6c0b56eSmrg		if (AMDGPUCursorInit_KMS(pScreen)) {
1818d6c0b56eSmrg		}
1819d6c0b56eSmrg	}
1820d6c0b56eSmrg
1821d6c0b56eSmrg	/* DGA setup */
1822d6c0b56eSmrg#ifdef XFreeXDGA
1823d6c0b56eSmrg	/* DGA is dangerous on kms as the base and framebuffer location may change:
1824d6c0b56eSmrg	 * http://lists.freedesktop.org/archives/xorg-devel/2009-September/002113.html
1825d6c0b56eSmrg	 */
1826d6c0b56eSmrg	/* xf86DiDGAInit(pScreen, info->LinearAddr + pScrn->fbOffset); */
1827d6c0b56eSmrg#endif
182811bf0794Smrg	if (info->shadow_fb == FALSE &&
182911bf0794Smrg	    !amdgpu_is_gpu_screen(pScreen)) {
1830d6c0b56eSmrg		/* Init Xv */
1831d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1832d6c0b56eSmrg			       "Initializing Xv\n");
1833d6c0b56eSmrg		AMDGPUInitVideo(pScreen);
1834d6c0b56eSmrg	}
1835d6c0b56eSmrg
1836d6c0b56eSmrg	if (info->shadow_fb == TRUE) {
1837d6c0b56eSmrg		if (!shadowSetup(pScreen)) {
1838d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1839d6c0b56eSmrg				   "Shadowfb initialization failed\n");
1840d6c0b56eSmrg			return FALSE;
1841d6c0b56eSmrg		}
1842d6c0b56eSmrg	}
1843d6c0b56eSmrg	pScrn->pScreen = pScreen;
1844d6c0b56eSmrg
184511bf0794Smrg	if (!amdgpu_is_gpu_screen(pScreen)) {
184611bf0794Smrg		if (serverGeneration == 1 && bgNoneRoot && info->use_glamor) {
184711bf0794Smrg			info->CreateWindow = pScreen->CreateWindow;
184811bf0794Smrg			pScreen->CreateWindow = AMDGPUCreateWindow_oneshot;
184911bf0794Smrg		}
185011bf0794Smrg		info->WindowExposures = pScreen->WindowExposures;
185111bf0794Smrg		pScreen->WindowExposures = AMDGPUWindowExposures_oneshot;
1852d6c0b56eSmrg	}
1853d6c0b56eSmrg
1854d6c0b56eSmrg	/* Provide SaveScreen & wrap BlockHandler and CloseScreen */
1855d6c0b56eSmrg	/* Wrap CloseScreen */
1856d6c0b56eSmrg	info->CloseScreen = pScreen->CloseScreen;
1857d6c0b56eSmrg	pScreen->CloseScreen = AMDGPUCloseScreen_KMS;
1858d6c0b56eSmrg	pScreen->SaveScreen = AMDGPUSaveScreen_KMS;
1859d6c0b56eSmrg	info->BlockHandler = pScreen->BlockHandler;
186011bf0794Smrg	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
1861d6c0b56eSmrg
1862d6c0b56eSmrg	info->CreateScreenResources = pScreen->CreateScreenResources;
1863d6c0b56eSmrg	pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS;
1864d6c0b56eSmrg
1865d6c0b56eSmrg#ifdef AMDGPU_PIXMAP_SHARING
1866d6c0b56eSmrg	pScreen->StartPixmapTracking = PixmapStartDirtyTracking;
1867d6c0b56eSmrg	pScreen->StopPixmapTracking = PixmapStopDirtyTracking;
1868504d986fSmrg#if HAS_SYNC_SHARED_PIXMAP
1869504d986fSmrg	pScreen->SyncSharedPixmap = amdgpu_sync_shared_pixmap;
1870504d986fSmrg#endif
1871d6c0b56eSmrg#endif
1872d6c0b56eSmrg
1873d6c0b56eSmrg	if (!xf86CrtcScreenInit(pScreen))
1874d6c0b56eSmrg		return FALSE;
1875d6c0b56eSmrg
1876d6c0b56eSmrg	/* Wrap pointer motion to flip touch screen around */
1877d6c0b56eSmrg//    info->PointerMoved = pScrn->PointerMoved;
1878d6c0b56eSmrg//    pScrn->PointerMoved = AMDGPUPointerMoved;
1879d6c0b56eSmrg
1880d6c0b56eSmrg	if (!drmmode_setup_colormap(pScreen, pScrn))
1881d6c0b56eSmrg		return FALSE;
1882d6c0b56eSmrg
1883d6c0b56eSmrg	/* Note unused options */
1884d6c0b56eSmrg	if (serverGeneration == 1)
1885d6c0b56eSmrg		xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1886d6c0b56eSmrg
1887d6c0b56eSmrg	drmmode_init(pScrn, &info->drmmode);
1888d6c0b56eSmrg
1889d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1890d6c0b56eSmrg		       "AMDGPUScreenInit finished\n");
1891d6c0b56eSmrg
1892d6c0b56eSmrg	return TRUE;
1893d6c0b56eSmrg}
1894d6c0b56eSmrg
1895d6c0b56eSmrgBool AMDGPUEnterVT_KMS(VT_FUNC_ARGS_DECL)
1896d6c0b56eSmrg{
1897d6c0b56eSmrg	SCRN_INFO_PTR(arg);
1898d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1899d6c0b56eSmrg
1900d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1901d6c0b56eSmrg		       "AMDGPUEnterVT_KMS\n");
1902d6c0b56eSmrg
1903d6c0b56eSmrg	amdgpu_set_drm_master(pScrn);
1904d6c0b56eSmrg
1905d6c0b56eSmrg	pScrn->vtSema = TRUE;
1906d6c0b56eSmrg
1907d6c0b56eSmrg	if (!drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE))
1908d6c0b56eSmrg		return FALSE;
1909d6c0b56eSmrg
1910d6c0b56eSmrg	return TRUE;
1911d6c0b56eSmrg}
1912d6c0b56eSmrg
1913d6c0b56eSmrgvoid AMDGPULeaveVT_KMS(VT_FUNC_ARGS_DECL)
1914d6c0b56eSmrg{
1915d6c0b56eSmrg	SCRN_INFO_PTR(arg);
1916d6c0b56eSmrg
1917d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1918d6c0b56eSmrg		       "AMDGPULeaveVT_KMS\n");
1919d6c0b56eSmrg
1920d6c0b56eSmrg	amdgpu_drop_drm_master(pScrn);
1921d6c0b56eSmrg
1922d6c0b56eSmrg	xf86RotateFreeShadow(pScrn);
1923d6c0b56eSmrg	drmmode_scanout_free(pScrn);
1924d6c0b56eSmrg
1925d6c0b56eSmrg	xf86_hide_cursors(pScrn);
1926d6c0b56eSmrg
1927d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1928d6c0b56eSmrg		       "Ok, leaving now...\n");
1929d6c0b56eSmrg}
1930d6c0b56eSmrg
1931d6c0b56eSmrgBool AMDGPUSwitchMode_KMS(SWITCH_MODE_ARGS_DECL)
1932d6c0b56eSmrg{
1933d6c0b56eSmrg	SCRN_INFO_PTR(arg);
1934d6c0b56eSmrg	Bool ret;
1935d6c0b56eSmrg	ret = xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
1936d6c0b56eSmrg	return ret;
1937d6c0b56eSmrg
1938d6c0b56eSmrg}
1939d6c0b56eSmrg
1940d6c0b56eSmrgvoid AMDGPUAdjustFrame_KMS(ADJUST_FRAME_ARGS_DECL)
1941d6c0b56eSmrg{
1942d6c0b56eSmrg	SCRN_INFO_PTR(arg);
1943d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1944d6c0b56eSmrg	drmmode_adjust_frame(pScrn, &info->drmmode, x, y);
1945d6c0b56eSmrg	return;
1946d6c0b56eSmrg}
1947d6c0b56eSmrg
1948d6c0b56eSmrgstatic Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen)
1949d6c0b56eSmrg{
1950d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1951d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1952d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1953d6c0b56eSmrg	int cpp = info->pixel_bytes;
1954d6c0b56eSmrg	int cursor_size;
1955d6c0b56eSmrg	int c;
1956d6c0b56eSmrg
1957d6c0b56eSmrg	cursor_size = info->cursor_w * info->cursor_h * 4;
1958d6c0b56eSmrg	cursor_size = AMDGPU_ALIGN(cursor_size, AMDGPU_GPU_PAGE_SIZE);
1959d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
1960d6c0b56eSmrg		/* cursor objects */
1961d6c0b56eSmrg		if (info->cursor_buffer[c] == NULL) {
1962d6c0b56eSmrg			if (info->gbm) {
1963d6c0b56eSmrg				info->cursor_buffer[c] = (struct amdgpu_buffer *)calloc(1, sizeof(struct amdgpu_buffer));
1964d6c0b56eSmrg				if (!info->cursor_buffer[c]) {
1965d6c0b56eSmrg					return FALSE;
1966d6c0b56eSmrg				}
1967d6c0b56eSmrg				info->cursor_buffer[c]->ref_count = 1;
1968d6c0b56eSmrg				info->cursor_buffer[c]->flags = AMDGPU_BO_FLAGS_GBM;
1969d6c0b56eSmrg
1970d6c0b56eSmrg				info->cursor_buffer[c]->bo.gbm = gbm_bo_create(info->gbm,
1971d6c0b56eSmrg									       info->cursor_w,
1972d6c0b56eSmrg									       info->cursor_h,
1973d6c0b56eSmrg									       GBM_FORMAT_ARGB8888,
1974d6c0b56eSmrg									       GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE);
1975d6c0b56eSmrg				if (!info->cursor_buffer[c]->bo.gbm) {
1976d6c0b56eSmrg					xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1977d6c0b56eSmrg						   "Failed to allocate cursor buffer memory\n");
1978d6c0b56eSmrg					free(info->cursor_buffer[c]);
1979d6c0b56eSmrg					return FALSE;
1980d6c0b56eSmrg				}
1981d6c0b56eSmrg			} else {
1982d6c0b56eSmrg				AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1983d6c0b56eSmrg				info->cursor_buffer[c] = amdgpu_bo_open(pAMDGPUEnt->pDev,
1984d6c0b56eSmrg									cursor_size,
1985d6c0b56eSmrg									0,
1986d6c0b56eSmrg									AMDGPU_GEM_DOMAIN_VRAM);
1987d6c0b56eSmrg				if (!(info->cursor_buffer[c])) {
1988d6c0b56eSmrg					ErrorF("Failed to allocate cursor buffer memory\n");
1989d6c0b56eSmrg					return FALSE;
1990d6c0b56eSmrg				}
1991d6c0b56eSmrg
1992d6c0b56eSmrg				if (amdgpu_bo_cpu_map(info->cursor_buffer[c]->bo.amdgpu,
1993d6c0b56eSmrg							&info->cursor_buffer[c]->cpu_ptr)) {
1994d6c0b56eSmrg					ErrorF("Failed to map cursor buffer memory\n");
1995d6c0b56eSmrg				}
1996d6c0b56eSmrg			}
1997d6c0b56eSmrg
1998d6c0b56eSmrg			drmmode_set_cursor(pScrn, &info->drmmode, c,
1999d6c0b56eSmrg					   info->cursor_buffer[c]);
2000d6c0b56eSmrg		}
2001d6c0b56eSmrg	}
2002d6c0b56eSmrg
2003d6c0b56eSmrg	if (info->front_buffer == NULL) {
2004d6c0b56eSmrg		int pitch;
2005d6c0b56eSmrg		int hint = 0;
2006d6c0b56eSmrg
2007d6c0b56eSmrg		if (info->shadow_primary)
2008d6c0b56eSmrg			hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
2009d6c0b56eSmrg		else if (!info->use_glamor)
2010d6c0b56eSmrg			hint = AMDGPU_CREATE_PIXMAP_LINEAR;
2011d6c0b56eSmrg
2012d6c0b56eSmrg		info->front_buffer =
2013d6c0b56eSmrg			amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,
2014d6c0b56eSmrg					       pScrn->virtualY, pScrn->depth,
2015d6c0b56eSmrg					       hint, pScrn->bitsPerPixel,
2016d6c0b56eSmrg					       &pitch);
2017d6c0b56eSmrg		if (!(info->front_buffer)) {
2018d6c0b56eSmrg			ErrorF("Failed to allocate front buffer memory\n");
2019d6c0b56eSmrg			return FALSE;
2020d6c0b56eSmrg		}
2021d6c0b56eSmrg
2022d6c0b56eSmrg		if (!info->use_glamor &&
2023d6c0b56eSmrg		    amdgpu_bo_map(pScrn, info->front_buffer) != 0) {
2024d6c0b56eSmrg			ErrorF("Failed to map front buffer memory\n");
2025d6c0b56eSmrg			return FALSE;
2026d6c0b56eSmrg		}
2027d6c0b56eSmrg
2028d6c0b56eSmrg		pScrn->displayWidth = pitch / cpp;
2029d6c0b56eSmrg	}
2030d6c0b56eSmrg
2031d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Front buffer pitch: %d bytes\n",
2032d6c0b56eSmrg		   pScrn->displayWidth * cpp);
2033d6c0b56eSmrg	return TRUE;
2034d6c0b56eSmrg}
2035d6c0b56eSmrg
2036d6c0b56eSmrg/* Used to disallow modes that are not supported by the hardware */
2037d6c0b56eSmrgModeStatus AMDGPUValidMode(SCRN_ARG_TYPE arg, DisplayModePtr mode,
2038d6c0b56eSmrg			   Bool verbose, int flag)
2039d6c0b56eSmrg{
2040d6c0b56eSmrg	/* There are problems with double scan mode at high clocks
2041d6c0b56eSmrg	 * They're likely related PLL and display buffer settings.
2042d6c0b56eSmrg	 * Disable these modes for now.
2043d6c0b56eSmrg	 */
2044d6c0b56eSmrg	if (mode->Flags & V_DBLSCAN) {
2045d6c0b56eSmrg		if ((mode->CrtcHDisplay >= 1024) || (mode->CrtcVDisplay >= 768))
2046d6c0b56eSmrg			return MODE_CLOCK_RANGE;
2047d6c0b56eSmrg	}
2048d6c0b56eSmrg	return MODE_OK;
2049d6c0b56eSmrg}
2050