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"
3524b90cf4Smrg#include "amdgpu_bo_helper.h"
36d6c0b56eSmrg#include "amdgpu_drm_queue.h"
37d6c0b56eSmrg#include "amdgpu_glamor.h"
38d6c0b56eSmrg#include "amdgpu_probe.h"
39d6c0b56eSmrg#include "micmap.h"
4024b90cf4Smrg#include "mipointrst.h"
41d6c0b56eSmrg
42d6c0b56eSmrg#include "amdgpu_version.h"
43d6c0b56eSmrg#include "shadow.h"
44504d986fSmrg#include <xf86Priv.h>
45d6c0b56eSmrg
4624b90cf4Smrg#if HAVE_PRESENT_H
4724b90cf4Smrg#include <present.h>
4824b90cf4Smrg#endif
4924b90cf4Smrg
50d6c0b56eSmrg/* DPMS */
51d6c0b56eSmrg#ifdef HAVE_XEXTPROTO_71
52d6c0b56eSmrg#include <X11/extensions/dpmsconst.h>
53d6c0b56eSmrg#else
54d6c0b56eSmrg#define DPMS_SERVER
55d6c0b56eSmrg#include <X11/extensions/dpms.h>
56d6c0b56eSmrg#endif
57d6c0b56eSmrg
58504d986fSmrg#include <X11/extensions/damageproto.h>
59504d986fSmrg
60d6c0b56eSmrg#include "amdgpu_bo_helper.h"
61d6c0b56eSmrg#include "amdgpu_pixmap.h"
62d6c0b56eSmrg
63d6c0b56eSmrg#include <gbm.h>
64d6c0b56eSmrg
6590f2b693Smrgstatic DevPrivateKeyRec amdgpu_window_private_key;
66504d986fSmrgstatic DevScreenPrivateKeyRec amdgpu_client_private_key;
6724b90cf4SmrgDevScreenPrivateKeyRec amdgpu_device_private_key;
68504d986fSmrg
6990f2b693Smrgstatic Atom amdgpu_vrr_atom;
7090f2b693Smrgstatic Bool amdgpu_property_vectors_wrapped;
7190f2b693Smrgstatic Bool restore_property_vector;
7290f2b693Smrgstatic int (*saved_change_property) (ClientPtr client);
7390f2b693Smrgstatic int (*saved_delete_property) (ClientPtr client);
7490f2b693Smrg
75d6c0b56eSmrgstatic Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen);
76d6c0b56eSmrg
77d6c0b56eSmrgconst OptionInfoRec AMDGPUOptions_KMS[] = {
78d6c0b56eSmrg	{OPTION_ACCEL, "Accel", OPTV_BOOLEAN, {0}, FALSE},
79d6c0b56eSmrg	{OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
80d6c0b56eSmrg	{OPTION_PAGE_FLIP, "EnablePageFlip", OPTV_BOOLEAN, {0}, FALSE},
81d6c0b56eSmrg	{OPTION_SUBPIXEL_ORDER, "SubPixelOrder", OPTV_ANYSTR, {0}, FALSE},
82d6c0b56eSmrg	{OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE},
83d6c0b56eSmrg	{OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
84d6c0b56eSmrg	{OPTION_DRI3, "DRI3", OPTV_BOOLEAN, {0}, FALSE},
85d6c0b56eSmrg	{OPTION_DRI, "DRI", OPTV_INTEGER, {0}, FALSE},
86d6c0b56eSmrg	{OPTION_SHADOW_PRIMARY, "ShadowPrimary", OPTV_BOOLEAN, {0}, FALSE},
87d6c0b56eSmrg	{OPTION_TEAR_FREE, "TearFree", OPTV_BOOLEAN, {0}, FALSE},
88d6c0b56eSmrg	{OPTION_DELETE_DP12, "DeleteUnusedDP12Displays", OPTV_BOOLEAN, {0}, FALSE},
8990f2b693Smrg	{OPTION_VARIABLE_REFRESH, "VariableRefresh", OPTV_BOOLEAN, {0}, FALSE },
90e49c54bcSmrg	{OPTION_ASYNC_FLIP_SECONDARIES, "AsyncFlipSecondaries", OPTV_BOOLEAN, {0}, FALSE},
91d6c0b56eSmrg	{-1, NULL, OPTV_NONE, {0}, FALSE}
92d6c0b56eSmrg};
93d6c0b56eSmrg
94d6c0b56eSmrgconst OptionInfoRec *AMDGPUOptionsWeak(void)
95d6c0b56eSmrg{
96d6c0b56eSmrg	return AMDGPUOptions_KMS;
97d6c0b56eSmrg}
98d6c0b56eSmrg
9990f2b693Smrgstatic inline struct amdgpu_window_priv *get_window_priv(WindowPtr win) {
10090f2b693Smrg	return dixLookupPrivate(&win->devPrivates, &amdgpu_window_private_key);
10190f2b693Smrg}
10290f2b693Smrg
10390f2b693Smrgstatic void
10490f2b693Smrgamdgpu_vrr_property_update(WindowPtr window, Bool variable_refresh)
10590f2b693Smrg{
10690f2b693Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
10790f2b693Smrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
10890f2b693Smrg
10990f2b693Smrg	get_window_priv(window)->variable_refresh = variable_refresh;
11090f2b693Smrg
11190f2b693Smrg	if (info->flip_window == window &&
11290f2b693Smrg	    info->drmmode.present_flipping)
11390f2b693Smrg		amdgpu_present_set_screen_vrr(scrn, variable_refresh);
11490f2b693Smrg}
11590f2b693Smrg
11690f2b693Smrg/* Wrapper for xserver/dix/property.c:ProcChangeProperty */
11790f2b693Smrgstatic int
11890f2b693Smrgamdgpu_change_property(ClientPtr client)
11990f2b693Smrg{
12090f2b693Smrg	WindowPtr window;
12190f2b693Smrg	int ret;
12290f2b693Smrg
12390f2b693Smrg	REQUEST(xChangePropertyReq);
12490f2b693Smrg
12590f2b693Smrg	client->requestVector[X_ChangeProperty] = saved_change_property;
12690f2b693Smrg	ret = saved_change_property(client);
12790f2b693Smrg
12890f2b693Smrg	if (restore_property_vector)
12990f2b693Smrg		return ret;
13090f2b693Smrg
13190f2b693Smrg	client->requestVector[X_ChangeProperty] = amdgpu_change_property;
13290f2b693Smrg
13390f2b693Smrg	if (ret != Success)
13490f2b693Smrg		return ret;
13590f2b693Smrg
13690f2b693Smrg	ret = dixLookupWindow(&window, stuff->window, client, DixSetPropAccess);
13790f2b693Smrg	if (ret != Success)
13890f2b693Smrg		return ret;
13990f2b693Smrg
14090f2b693Smrg	if (stuff->property == amdgpu_vrr_atom &&
14190f2b693Smrg	    xf86ScreenToScrn(window->drawable.pScreen)->PreInit ==
14290f2b693Smrg	    AMDGPUPreInit_KMS && stuff->format == 32 && stuff->nUnits == 1) {
14390f2b693Smrg		uint32_t *value = (uint32_t*)(stuff + 1);
14490f2b693Smrg
14590f2b693Smrg		amdgpu_vrr_property_update(window, *value != 0);
14690f2b693Smrg	}
14790f2b693Smrg
14890f2b693Smrg	return ret;
14990f2b693Smrg}
15090f2b693Smrg
15190f2b693Smrg/* Wrapper for xserver/dix/property.c:ProcDeleteProperty */
15290f2b693Smrgstatic int
15390f2b693Smrgamdgpu_delete_property(ClientPtr client)
15490f2b693Smrg{
15590f2b693Smrg	WindowPtr window;
15690f2b693Smrg	int ret;
15790f2b693Smrg
15890f2b693Smrg	REQUEST(xDeletePropertyReq);
15990f2b693Smrg
16090f2b693Smrg	client->requestVector[X_DeleteProperty] = saved_delete_property;
16190f2b693Smrg	ret = saved_delete_property(client);
16290f2b693Smrg
16390f2b693Smrg	if (restore_property_vector)
16490f2b693Smrg		return ret;
16590f2b693Smrg
16690f2b693Smrg	client->requestVector[X_DeleteProperty] = amdgpu_delete_property;
16790f2b693Smrg
16890f2b693Smrg	if (ret != Success)
16990f2b693Smrg		return ret;
17090f2b693Smrg
17190f2b693Smrg	ret = dixLookupWindow(&window, stuff->window, client, DixSetPropAccess);
17290f2b693Smrg	if (ret != Success)
17390f2b693Smrg		return ret;
17490f2b693Smrg
17590f2b693Smrg	if (stuff->property == amdgpu_vrr_atom &&
17690f2b693Smrg	    xf86ScreenToScrn(window->drawable.pScreen)->PreInit ==
17790f2b693Smrg	    AMDGPUPreInit_KMS)
17890f2b693Smrg		amdgpu_vrr_property_update(window, FALSE);
17990f2b693Smrg
18090f2b693Smrg	return ret;
18190f2b693Smrg}
18290f2b693Smrg
18390f2b693Smrgstatic void
18490f2b693Smrgamdgpu_unwrap_property_requests(ScrnInfoPtr scrn)
18590f2b693Smrg{
18690f2b693Smrg	int i;
18790f2b693Smrg
18890f2b693Smrg	if (!amdgpu_property_vectors_wrapped)
18990f2b693Smrg		return;
19090f2b693Smrg
19190f2b693Smrg	if (ProcVector[X_ChangeProperty] == amdgpu_change_property)
19290f2b693Smrg		ProcVector[X_ChangeProperty] = saved_change_property;
19390f2b693Smrg	else
19490f2b693Smrg		restore_property_vector = TRUE;
19590f2b693Smrg
19690f2b693Smrg	if (ProcVector[X_DeleteProperty] == amdgpu_delete_property)
19790f2b693Smrg		ProcVector[X_DeleteProperty] = saved_delete_property;
19890f2b693Smrg	else
19990f2b693Smrg		restore_property_vector = TRUE;
20090f2b693Smrg
20190f2b693Smrg	for (i = 0; i < currentMaxClients; i++) {
20290f2b693Smrg		if (clients[i]->requestVector[X_ChangeProperty] ==
20390f2b693Smrg		    amdgpu_change_property) {
20490f2b693Smrg			clients[i]->requestVector[X_ChangeProperty] =
20590f2b693Smrg				saved_change_property;
20690f2b693Smrg		} else {
20790f2b693Smrg			restore_property_vector = TRUE;
20890f2b693Smrg		}
20990f2b693Smrg
21090f2b693Smrg		if (clients[i]->requestVector[X_DeleteProperty] ==
21190f2b693Smrg		    amdgpu_delete_property) {
21290f2b693Smrg			clients[i]->requestVector[X_DeleteProperty] =
21390f2b693Smrg				saved_delete_property;
21490f2b693Smrg		} else {
21590f2b693Smrg			restore_property_vector = TRUE;
21690f2b693Smrg		}
21790f2b693Smrg	}
21890f2b693Smrg
21990f2b693Smrg	if (restore_property_vector) {
22090f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
22190f2b693Smrg			   "Couldn't unwrap some window property request vectors\n");
22290f2b693Smrg	}
22390f2b693Smrg
22490f2b693Smrg	amdgpu_property_vectors_wrapped = FALSE;
22590f2b693Smrg}
22690f2b693Smrg
227d6c0b56eSmrgextern _X_EXPORT int gAMDGPUEntityIndex;
228d6c0b56eSmrg
229d6c0b56eSmrgstatic int getAMDGPUEntityIndex(void)
230d6c0b56eSmrg{
231d6c0b56eSmrg	return gAMDGPUEntityIndex;
232d6c0b56eSmrg}
233d6c0b56eSmrg
234d6c0b56eSmrgAMDGPUEntPtr AMDGPUEntPriv(ScrnInfoPtr pScrn)
235d6c0b56eSmrg{
236d6c0b56eSmrg	DevUnion *pPriv;
237d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
238d6c0b56eSmrg	pPriv = xf86GetEntityPrivate(info->pEnt->index, getAMDGPUEntityIndex());
239d6c0b56eSmrg	return pPriv->ptr;
240d6c0b56eSmrg}
241d6c0b56eSmrg
242d6c0b56eSmrg/* Allocate our private AMDGPUInfoRec */
243d6c0b56eSmrgstatic Bool AMDGPUGetRec(ScrnInfoPtr pScrn)
244d6c0b56eSmrg{
245d6c0b56eSmrg	if (pScrn->driverPrivate)
246d6c0b56eSmrg		return TRUE;
247d6c0b56eSmrg
248d6c0b56eSmrg	pScrn->driverPrivate = xnfcalloc(sizeof(AMDGPUInfoRec), 1);
249d6c0b56eSmrg	return TRUE;
250d6c0b56eSmrg}
251d6c0b56eSmrg
252d6c0b56eSmrg/* Free our private AMDGPUInfoRec */
253d6c0b56eSmrgstatic void AMDGPUFreeRec(ScrnInfoPtr pScrn)
254d6c0b56eSmrg{
255d6c0b56eSmrg	DevUnion *pPriv;
256d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt;
257d6c0b56eSmrg	AMDGPUInfoPtr info;
25824b90cf4Smrg	EntityInfoPtr pEnt;
259d6c0b56eSmrg
260d6c0b56eSmrg	if (!pScrn)
261d6c0b56eSmrg		return;
262d6c0b56eSmrg
26390f2b693Smrg	pEnt = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
26490f2b693Smrg	pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex);
26590f2b693Smrg	pAMDGPUEnt = pPriv->ptr;
26690f2b693Smrg
267d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
26824b90cf4Smrg	if (info) {
26990f2b693Smrg		pAMDGPUEnt->scrn[info->instance_id] = NULL;
27090f2b693Smrg		pAMDGPUEnt->num_scrns--;
27124b90cf4Smrg		free(pScrn->driverPrivate);
27224b90cf4Smrg		pScrn->driverPrivate = NULL;
27324b90cf4Smrg	}
27424b90cf4Smrg
275d6c0b56eSmrg	if (pAMDGPUEnt->fd > 0) {
276d6c0b56eSmrg		DevUnion *pPriv;
277d6c0b56eSmrg		AMDGPUEntPtr pAMDGPUEnt;
278d6c0b56eSmrg		pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
279d6c0b56eSmrg					     getAMDGPUEntityIndex());
280d6c0b56eSmrg
281d6c0b56eSmrg		pAMDGPUEnt = pPriv->ptr;
282d6c0b56eSmrg		pAMDGPUEnt->fd_ref--;
283d6c0b56eSmrg		if (!pAMDGPUEnt->fd_ref) {
28490f2b693Smrg			amdgpu_unwrap_property_requests(pScrn);
285d6c0b56eSmrg			amdgpu_device_deinitialize(pAMDGPUEnt->pDev);
28611bf0794Smrg			amdgpu_kernel_close_fd(pAMDGPUEnt);
28746845023Smrg			free(pAMDGPUEnt->busid);
28824b90cf4Smrg			free(pPriv->ptr);
28924b90cf4Smrg			pPriv->ptr = NULL;
290d6c0b56eSmrg		}
291d6c0b56eSmrg	}
292d6c0b56eSmrg
29324b90cf4Smrg	free(pEnt);
294d6c0b56eSmrg}
295d6c0b56eSmrg
29690f2b693SmrgBool amdgpu_window_has_variable_refresh(WindowPtr win) {
29790f2b693Smrg	struct amdgpu_window_priv *priv = get_window_priv(win);
29890f2b693Smrg
29990f2b693Smrg	return priv->variable_refresh;
30090f2b693Smrg}
30190f2b693Smrg
302d6c0b56eSmrgstatic void *amdgpuShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset,
303d6c0b56eSmrg				int mode, CARD32 * size, void *closure)
304d6c0b56eSmrg{
305d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
306d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
307d6c0b56eSmrg	int stride;
308d6c0b56eSmrg
309d6c0b56eSmrg	stride = (pScrn->displayWidth * pScrn->bitsPerPixel) / 8;
310d6c0b56eSmrg	*size = stride;
311d6c0b56eSmrg
312d6c0b56eSmrg	return ((uint8_t *) info->front_buffer->cpu_ptr + row * stride + offset);
313d6c0b56eSmrg}
314d6c0b56eSmrg
315d6c0b56eSmrgstatic void
316d6c0b56eSmrgamdgpuUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
317d6c0b56eSmrg{
318d6c0b56eSmrg	shadowUpdatePacked(pScreen, pBuf);
319d6c0b56eSmrg}
320d6c0b56eSmrg
321504d986fSmrgstatic Bool
322504d986fSmrgcallback_needs_flush(AMDGPUInfoPtr info, struct amdgpu_client_priv *client_priv)
323504d986fSmrg{
324504d986fSmrg	return (int)(client_priv->needs_flush - info->gpu_flushed) > 0;
325504d986fSmrg}
326504d986fSmrg
327504d986fSmrgstatic void
328504d986fSmrgamdgpu_event_callback(CallbackListPtr *list,
329504d986fSmrg		      pointer user_data, pointer call_data)
330504d986fSmrg{
331504d986fSmrg	EventInfoRec *eventinfo = call_data;
332504d986fSmrg	ScrnInfoPtr pScrn = user_data;
333504d986fSmrg	ScreenPtr pScreen = pScrn->pScreen;
334504d986fSmrg	struct amdgpu_client_priv *client_priv =
335504d986fSmrg		dixLookupScreenPrivate(&eventinfo->client->devPrivates,
336504d986fSmrg				       &amdgpu_client_private_key, pScreen);
337504d986fSmrg	struct amdgpu_client_priv *server_priv =
338504d986fSmrg		dixLookupScreenPrivate(&serverClient->devPrivates,
339504d986fSmrg				       &amdgpu_client_private_key, pScreen);
340504d986fSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
341504d986fSmrg	int i;
342504d986fSmrg
343504d986fSmrg	if (callback_needs_flush(info, client_priv) ||
344504d986fSmrg	    callback_needs_flush(info, server_priv))
345504d986fSmrg		return;
346504d986fSmrg
347504d986fSmrg	/* Don't let gpu_flushed get too far ahead of needs_flush, in order
348504d986fSmrg	 * to prevent false positives in callback_needs_flush()
349504d986fSmrg	 */
350504d986fSmrg	client_priv->needs_flush = info->gpu_flushed;
351504d986fSmrg	server_priv->needs_flush = info->gpu_flushed;
352504d986fSmrg
353504d986fSmrg	for (i = 0; i < eventinfo->count; i++) {
354504d986fSmrg		if (eventinfo->events[i].u.u.type == info->callback_event_type) {
355504d986fSmrg			client_priv->needs_flush++;
356504d986fSmrg			server_priv->needs_flush++;
357504d986fSmrg			return;
358504d986fSmrg		}
359504d986fSmrg	}
360504d986fSmrg}
361504d986fSmrg
362504d986fSmrgstatic void
363504d986fSmrgamdgpu_flush_callback(CallbackListPtr *list,
364504d986fSmrg		      pointer user_data, pointer call_data)
365504d986fSmrg{
366504d986fSmrg	ScrnInfoPtr pScrn = user_data;
367504d986fSmrg	ScreenPtr pScreen = pScrn->pScreen;
368504d986fSmrg	ClientPtr client = call_data ? call_data : serverClient;
369504d986fSmrg	struct amdgpu_client_priv *client_priv =
370504d986fSmrg		dixLookupScreenPrivate(&client->devPrivates,
371504d986fSmrg				       &amdgpu_client_private_key, pScreen);
372504d986fSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
373504d986fSmrg
374504d986fSmrg	if (pScrn->vtSema && callback_needs_flush(info, client_priv))
375504d986fSmrg		amdgpu_glamor_flush(pScrn);
376504d986fSmrg}
377504d986fSmrg
378d6c0b56eSmrgstatic Bool AMDGPUCreateScreenResources_KMS(ScreenPtr pScreen)
379d6c0b56eSmrg{
38011bf0794Smrg	ExtensionEntry *damage_ext;
381d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
382d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
383d6c0b56eSmrg	PixmapPtr pixmap;
384d6c0b56eSmrg
385d6c0b56eSmrg	pScreen->CreateScreenResources = info->CreateScreenResources;
386d6c0b56eSmrg	if (!(*pScreen->CreateScreenResources) (pScreen))
387d6c0b56eSmrg		return FALSE;
388d6c0b56eSmrg	pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS;
389d6c0b56eSmrg
390d6c0b56eSmrg	/* Set the RandR primary output if Xorg hasn't */
391504d986fSmrg	if (dixPrivateKeyRegistered(rrPrivKey)) {
392504d986fSmrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(pScreen);
393504d986fSmrg
39424b90cf4Smrg		if (!pScreen->isGPU && !rrScrPriv->primaryOutput) {
395504d986fSmrg			xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
396d6c0b56eSmrg
397504d986fSmrg			rrScrPriv->primaryOutput = xf86_config->output[0]->randr_output;
398504d986fSmrg			RROutputChanged(rrScrPriv->primaryOutput, FALSE);
399504d986fSmrg			rrScrPriv->layoutChanged = TRUE;
400504d986fSmrg		}
40190f2b693Smrg
40290f2b693Smrg		drmmode_uevent_init(pScrn, &info->drmmode);
403d6c0b56eSmrg	}
404d6c0b56eSmrg
40524b90cf4Smrg	if (!drmmode_set_desired_modes(pScrn, &info->drmmode, pScreen->isGPU))
406d6c0b56eSmrg		return FALSE;
407d6c0b56eSmrg
408d6c0b56eSmrg	if (info->shadow_fb) {
409d6c0b56eSmrg		pixmap = pScreen->GetScreenPixmap(pScreen);
410d6c0b56eSmrg
411d6c0b56eSmrg		if (!shadowAdd(pScreen, pixmap, amdgpuUpdatePacked,
412d6c0b56eSmrg			       amdgpuShadowWindow, 0, NULL))
413d6c0b56eSmrg			return FALSE;
414d6c0b56eSmrg	}
415d6c0b56eSmrg
416d6c0b56eSmrg	if (info->dri2.enabled || info->use_glamor) {
417d6c0b56eSmrg		if (info->front_buffer) {
418d6c0b56eSmrg			PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen);
419504d986fSmrg
420504d986fSmrg			if (!amdgpu_set_pixmap_bo(pPix, info->front_buffer))
421504d986fSmrg				return FALSE;
422d6c0b56eSmrg		}
423d6c0b56eSmrg	}
424d6c0b56eSmrg
425d6c0b56eSmrg	if (info->use_glamor)
426d6c0b56eSmrg		amdgpu_glamor_create_screen_resources(pScreen);
427d6c0b56eSmrg
428504d986fSmrg	info->callback_event_type = -1;
42924b90cf4Smrg	if (!pScreen->isGPU && (damage_ext = CheckExtension("DAMAGE"))) {
430504d986fSmrg		info->callback_event_type = damage_ext->eventBase + XDamageNotify;
431504d986fSmrg
432504d986fSmrg		if (!AddCallback(&FlushCallback, amdgpu_flush_callback, pScrn))
433504d986fSmrg			return FALSE;
434504d986fSmrg
435504d986fSmrg		if (!AddCallback(&EventCallback, amdgpu_event_callback, pScrn)) {
436504d986fSmrg			DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
437504d986fSmrg			return FALSE;
438504d986fSmrg		}
439504d986fSmrg
440504d986fSmrg		if (!dixRegisterScreenPrivateKey(&amdgpu_client_private_key, pScreen,
441504d986fSmrg						 PRIVATE_CLIENT, sizeof(struct amdgpu_client_priv))) {
442504d986fSmrg			DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
443504d986fSmrg			DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn);
444504d986fSmrg			return FALSE;
445504d986fSmrg		}
446504d986fSmrg	}
447504d986fSmrg
44890f2b693Smrg	if (info->vrr_support &&
44990f2b693Smrg	    !dixRegisterPrivateKey(&amdgpu_window_private_key,
45090f2b693Smrg				   PRIVATE_WINDOW,
45190f2b693Smrg				   sizeof(struct amdgpu_window_priv)))
45290f2b693Smrg		return FALSE;
45390f2b693Smrg
454d6c0b56eSmrg	return TRUE;
455d6c0b56eSmrg}
456d6c0b56eSmrg
457504d986fSmrgstatic Bool
458504d986fSmrgamdgpu_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents)
459504d986fSmrg{
46011bf0794Smrg	if (xf86_crtc->scrn->is_gpu) {
46111bf0794Smrg		extents->x1 -= xf86_crtc->x;
46211bf0794Smrg		extents->y1 -= xf86_crtc->y;
46311bf0794Smrg		extents->x2 -= xf86_crtc->x;
46411bf0794Smrg		extents->y2 -= xf86_crtc->y;
46524b90cf4Smrg	} else {
46611bf0794Smrg		extents->x1 -= xf86_crtc->filter_width >> 1;
46711bf0794Smrg		extents->x2 += xf86_crtc->filter_width >> 1;
46811bf0794Smrg		extents->y1 -= xf86_crtc->filter_height >> 1;
46911bf0794Smrg		extents->y2 += xf86_crtc->filter_height >> 1;
47011bf0794Smrg		pixman_f_transform_bounds(&xf86_crtc->f_framebuffer_to_crtc, extents);
47111bf0794Smrg	}
472504d986fSmrg
473504d986fSmrg	extents->x1 = max(extents->x1, 0);
474504d986fSmrg	extents->y1 = max(extents->y1, 0);
475504d986fSmrg	extents->x2 = min(extents->x2, xf86_crtc->mode.HDisplay);
476504d986fSmrg	extents->y2 = min(extents->y2, xf86_crtc->mode.VDisplay);
477504d986fSmrg
478504d986fSmrg	return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
479504d986fSmrg}
480504d986fSmrg
481504d986fSmrgstatic RegionPtr
482504d986fSmrgtransform_region(RegionPtr region, struct pict_f_transform *transform,
483504d986fSmrg		 int w, int h)
484504d986fSmrg{
485504d986fSmrg	BoxPtr boxes = RegionRects(region);
486504d986fSmrg	int nboxes = RegionNumRects(region);
487504d986fSmrg	xRectanglePtr rects = malloc(nboxes * sizeof(*rects));
488504d986fSmrg	RegionPtr transformed;
489504d986fSmrg	int nrects = 0;
490504d986fSmrg	BoxRec box;
491504d986fSmrg	int i;
492504d986fSmrg
493504d986fSmrg	for (i = 0; i < nboxes; i++) {
494504d986fSmrg		box.x1 = boxes[i].x1;
495504d986fSmrg		box.x2 = boxes[i].x2;
496504d986fSmrg		box.y1 = boxes[i].y1;
497504d986fSmrg		box.y2 = boxes[i].y2;
498504d986fSmrg		pixman_f_transform_bounds(transform, &box);
499504d986fSmrg
500504d986fSmrg		box.x1 = max(box.x1, 0);
501504d986fSmrg		box.y1 = max(box.y1, 0);
502504d986fSmrg		box.x2 = min(box.x2, w);
503504d986fSmrg		box.y2 = min(box.y2, h);
504504d986fSmrg		if (box.x1 >= box.x2 || box.y1 >= box.y2)
505504d986fSmrg			continue;
506504d986fSmrg
507504d986fSmrg		rects[nrects].x = box.x1;
508504d986fSmrg		rects[nrects].y = box.y1;
509504d986fSmrg		rects[nrects].width = box.x2 - box.x1;
510504d986fSmrg		rects[nrects].height = box.y2 - box.y1;
511504d986fSmrg		nrects++;
512504d986fSmrg	}
513504d986fSmrg
514504d986fSmrg	transformed = RegionFromRects(nrects, rects, CT_UNSORTED);
515504d986fSmrg	free(rects);
516504d986fSmrg	return transformed;
517504d986fSmrg}
518504d986fSmrg
519504d986fSmrgstatic void
520504d986fSmrgamdgpu_sync_scanout_pixmaps(xf86CrtcPtr xf86_crtc, RegionPtr new_region,
521504d986fSmrg							int scanout_id)
522504d986fSmrg{
523504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
52446845023Smrg	DrawablePtr dst = &drmmode_crtc->scanout[scanout_id]->drawable;
52546845023Smrg	DrawablePtr src = &drmmode_crtc->scanout[scanout_id ^ 1]->drawable;
526504d986fSmrg	RegionPtr last_region = &drmmode_crtc->scanout_last_region;
527504d986fSmrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
528504d986fSmrg	ScreenPtr pScreen = scrn->pScreen;
529504d986fSmrg	RegionRec remaining;
530504d986fSmrg	RegionPtr sync_region = NULL;
531504d986fSmrg	BoxRec extents;
532504d986fSmrg	GCPtr gc;
533504d986fSmrg
534504d986fSmrg	if (RegionNil(last_region))
535504d986fSmrg		return;
536504d986fSmrg
537504d986fSmrg	RegionNull(&remaining);
538504d986fSmrg	RegionSubtract(&remaining, last_region, new_region);
539504d986fSmrg	if (RegionNil(&remaining))
540504d986fSmrg		goto uninit;
541504d986fSmrg
542504d986fSmrg	extents = *RegionExtents(&remaining);
543504d986fSmrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents))
544504d986fSmrg		goto uninit;
545504d986fSmrg
546504d986fSmrg	if (xf86_crtc->driverIsPerformingTransform) {
547504d986fSmrg		sync_region = transform_region(&remaining,
548504d986fSmrg					       &xf86_crtc->f_framebuffer_to_crtc,
549504d986fSmrg					       dst->width, dst->height);
55024b90cf4Smrg	} else {
551504d986fSmrg		sync_region = RegionDuplicate(&remaining);
552504d986fSmrg		RegionTranslate(sync_region, -xf86_crtc->x, -xf86_crtc->y);
553504d986fSmrg	}
554504d986fSmrg
555504d986fSmrg	gc = GetScratchGC(dst->depth, pScreen);
556504d986fSmrg	if (gc) {
557504d986fSmrg		gc->funcs->ChangeClip(gc, CT_REGION, sync_region, 0);
55811bf0794Smrg		ValidateGC(dst, gc);
559504d986fSmrg		sync_region = NULL;
560504d986fSmrg		gc->ops->CopyArea(src, dst, gc, 0, 0, dst->width, dst->height, 0, 0);
561504d986fSmrg		FreeScratchGC(gc);
562504d986fSmrg	}
563504d986fSmrg
564504d986fSmrg uninit:
565504d986fSmrg	if (sync_region)
566504d986fSmrg		RegionDestroy(sync_region);
567504d986fSmrg	RegionUninit(&remaining);
568504d986fSmrg}
569504d986fSmrg
57024b90cf4Smrgstatic void
57124b90cf4Smrgamdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
57224b90cf4Smrg{
57324b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
57424b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
57590f2b693Smrg	struct drmmode_fb *fb = event_data;
57624b90cf4Smrg
57735d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
57890f2b693Smrg
57990f2b693Smrg	if (drmmode_crtc->flip_pending == fb) {
58090f2b693Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
58190f2b693Smrg				     NULL);
58290f2b693Smrg	}
58324b90cf4Smrg}
58424b90cf4Smrg
58524b90cf4Smrgstatic void
58624b90cf4Smrgamdgpu_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec,
58724b90cf4Smrg			    void *event_data)
58824b90cf4Smrg{
58924b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
59024b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
59190f2b693Smrg	struct drmmode_fb *fb = event_data;
59224b90cf4Smrg
59390f2b693Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb);
59424b90cf4Smrg	amdgpu_scanout_flip_abort(crtc, event_data);
59524b90cf4Smrg}
59624b90cf4Smrg
597504d986fSmrg
598504d986fSmrgstatic RegionPtr
599504d986fSmrgdirty_region(PixmapDirtyUpdatePtr dirty)
600d6c0b56eSmrg{
601504d986fSmrg	RegionPtr damageregion = DamageRegion(dirty->damage);
602504d986fSmrg	RegionPtr dstregion;
603504d986fSmrg
604504d986fSmrg#ifdef HAS_DIRTYTRACKING_ROTATION
605504d986fSmrg	if (dirty->rotation != RR_Rotate_0) {
606504d986fSmrg		dstregion = transform_region(damageregion,
607504d986fSmrg					     &dirty->f_inverse,
60846845023Smrg					     dirty->secondary_dst->drawable.width,
60946845023Smrg					     dirty->secondary_dst->drawable.height);
610504d986fSmrg	} else
611504d986fSmrg#endif
612504d986fSmrg	{
613504d986fSmrg		RegionRec pixregion;
614504d986fSmrg
615504d986fSmrg		dstregion = RegionDuplicate(damageregion);
616504d986fSmrg		RegionTranslate(dstregion, -dirty->x, -dirty->y);
61746845023Smrg		PixmapRegionInit(&pixregion, dirty->secondary_dst);
618504d986fSmrg		RegionIntersect(dstregion, dstregion, &pixregion);
619504d986fSmrg		RegionUninit(&pixregion);
620504d986fSmrg	}
621504d986fSmrg
622504d986fSmrg	return dstregion;
623504d986fSmrg}
624504d986fSmrg
625504d986fSmrgstatic void
626504d986fSmrgredisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region)
627504d986fSmrg{
62824b90cf4Smrg	ScrnInfoPtr src_scrn =
62924b90cf4Smrg		xf86ScreenToScrn(amdgpu_dirty_src_drawable(dirty)->pScreen);
630504d986fSmrg
631504d986fSmrg	if (RegionNil(region))
632504d986fSmrg		goto out;
633504d986fSmrg
63446845023Smrg	if (dirty->secondary_dst->primary_pixmap)
63546845023Smrg		DamageRegionAppend(&dirty->secondary_dst->drawable, region);
636d6c0b56eSmrg
637d6c0b56eSmrg#ifdef HAS_DIRTYTRACKING_ROTATION
638d6c0b56eSmrg	PixmapSyncDirtyHelper(dirty);
639d6c0b56eSmrg#else
640504d986fSmrg	PixmapSyncDirtyHelper(dirty, region);
641d6c0b56eSmrg#endif
642d6c0b56eSmrg
64324b90cf4Smrg	amdgpu_glamor_flush(src_scrn);
64446845023Smrg	if (dirty->secondary_dst->primary_pixmap)
64546845023Smrg		DamageRegionProcessPending(&dirty->secondary_dst->drawable);
646504d986fSmrg
647504d986fSmrgout:
648504d986fSmrg	DamageEmpty(dirty->damage);
649d6c0b56eSmrg}
650d6c0b56eSmrg
651504d986fSmrgstatic void
652504d986fSmrgamdgpu_prime_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
653d6c0b56eSmrg{
654504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
655504d986fSmrg
65635d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
657504d986fSmrg}
658504d986fSmrg
659504d986fSmrgvoid
660504d986fSmrgamdgpu_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
661504d986fSmrg{
66246845023Smrg	ScreenPtr primary_screen = amdgpu_dirty_primary(dirty);
663d6c0b56eSmrg	PixmapDirtyUpdatePtr ent;
664504d986fSmrg	RegionPtr region;
665d6c0b56eSmrg
66646845023Smrg	xorg_list_for_each_entry(ent, &primary_screen->pixmap_dirty_list, ent) {
66746845023Smrg		if (!amdgpu_dirty_src_equals(dirty, ent->secondary_dst))
668504d986fSmrg			continue;
669d6c0b56eSmrg
670504d986fSmrg		region = dirty_region(ent);
671504d986fSmrg		redisplay_dirty(ent, region);
672504d986fSmrg		RegionDestroy(region);
673d6c0b56eSmrg	}
674d6c0b56eSmrg}
675504d986fSmrg
676504d986fSmrg
677504d986fSmrg#if HAS_SYNC_SHARED_PIXMAP
678d6c0b56eSmrg
679d6c0b56eSmrgstatic Bool
68046845023Smrgprimary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
681d6c0b56eSmrg{
68246845023Smrg	ScreenPtr primary_screen = amdgpu_dirty_primary(dirty);
683504d986fSmrg
68446845023Smrg	return primary_screen->SyncSharedPixmap != NULL;
685504d986fSmrg}
686504d986fSmrg
687504d986fSmrgstatic Bool
68846845023Smrgsecondary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
689504d986fSmrg{
69046845023Smrg	ScreenPtr secondary_screen = dirty->secondary_dst->drawable.pScreen;
691504d986fSmrg
69246845023Smrg	return secondary_screen->SyncSharedPixmap != NULL;
693504d986fSmrg}
694504d986fSmrg
695504d986fSmrgstatic void
696504d986fSmrgcall_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
697504d986fSmrg{
69846845023Smrg	ScreenPtr primary_screen = amdgpu_dirty_primary(dirty);
699504d986fSmrg
70046845023Smrg	primary_screen->SyncSharedPixmap(dirty);
701504d986fSmrg}
702504d986fSmrg
703504d986fSmrg#else /* !HAS_SYNC_SHARED_PIXMAP */
704504d986fSmrg
705504d986fSmrgstatic Bool
70646845023Smrgprimary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
707504d986fSmrg{
70846845023Smrg	ScrnInfoPtr primary_scrn = xf86ScreenToScrn(amdgpu_dirty_primary(dirty));
709504d986fSmrg
71046845023Smrg	return primary_scrn->driverName == scrn->driverName;
711504d986fSmrg}
712504d986fSmrg
713504d986fSmrgstatic Bool
71446845023Smrgsecondary_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
715504d986fSmrg{
71646845023Smrg	ScrnInfoPtr secondary_scrn = xf86ScreenToScrn(dirty->secondary_dst->drawable.pScreen);
717504d986fSmrg
71846845023Smrg	return secondary_scrn->driverName == scrn->driverName;
719504d986fSmrg}
720504d986fSmrg
721504d986fSmrgstatic void
722504d986fSmrgcall_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
723504d986fSmrg{
724504d986fSmrg	amdgpu_sync_shared_pixmap(dirty);
725504d986fSmrg}
726504d986fSmrg
727504d986fSmrg#endif /* HAS_SYNC_SHARED_PIXMAPS */
728504d986fSmrg
729504d986fSmrg
73011bf0794Smrgstatic xf86CrtcPtr
73111bf0794Smrgamdgpu_prime_dirty_to_crtc(PixmapDirtyUpdatePtr dirty)
73211bf0794Smrg{
73346845023Smrg	ScreenPtr screen = dirty->secondary_dst->drawable.pScreen;
73411bf0794Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
73511bf0794Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
73611bf0794Smrg	int c;
73711bf0794Smrg
73846845023Smrg	/* Find the CRTC which is scanning out from this secondary pixmap */
73911bf0794Smrg	for (c = 0; c < xf86_config->num_crtc; c++) {
74011bf0794Smrg		xf86CrtcPtr xf86_crtc = xf86_config->crtc[c];
74111bf0794Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
74211bf0794Smrg
74324b90cf4Smrg		if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap))
74411bf0794Smrg			return xf86_crtc;
74511bf0794Smrg	}
74611bf0794Smrg
74711bf0794Smrg	return NULL;
74811bf0794Smrg}
74911bf0794Smrg
750504d986fSmrgstatic Bool
751504d986fSmrgamdgpu_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id)
752504d986fSmrg{
753504d986fSmrg	ScrnInfoPtr scrn = crtc->scrn;
754504d986fSmrg	ScreenPtr screen = scrn->pScreen;
755504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
756504d986fSmrg	PixmapDirtyUpdatePtr dirty;
757504d986fSmrg	Bool ret = FALSE;
758504d986fSmrg
759504d986fSmrg	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
76024b90cf4Smrg		if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
761504d986fSmrg			RegionPtr region;
762504d986fSmrg
76346845023Smrg			if (primary_has_sync_shared_pixmap(scrn, dirty))
764504d986fSmrg				call_sync_shared_pixmap(dirty);
765504d986fSmrg
766504d986fSmrg			region = dirty_region(dirty);
767504d986fSmrg			if (RegionNil(region))
768504d986fSmrg				goto destroy;
769504d986fSmrg
77011bf0794Smrg			if (drmmode_crtc->tear_free) {
771504d986fSmrg				RegionTranslate(region, crtc->x, crtc->y);
772504d986fSmrg				amdgpu_sync_scanout_pixmaps(crtc, region, scanout_id);
773504d986fSmrg				amdgpu_glamor_flush(scrn);
774504d986fSmrg				RegionCopy(&drmmode_crtc->scanout_last_region, region);
775504d986fSmrg				RegionTranslate(region, -crtc->x, -crtc->y);
77646845023Smrg				dirty->secondary_dst = drmmode_crtc->scanout[scanout_id];
777504d986fSmrg			}
778504d986fSmrg
779504d986fSmrg			redisplay_dirty(dirty, region);
780504d986fSmrg			ret = TRUE;
781504d986fSmrg		destroy:
782504d986fSmrg			RegionDestroy(region);
783504d986fSmrg			break;
784504d986fSmrg		}
785d6c0b56eSmrg	}
786d6c0b56eSmrg
787504d986fSmrg	return ret;
788504d986fSmrg}
789504d986fSmrg
79011bf0794Smrgstatic void
791504d986fSmrgamdgpu_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
792504d986fSmrg				     void *event_data)
793504d986fSmrg{
794504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
795504d986fSmrg
796504d986fSmrg	amdgpu_prime_scanout_do_update(crtc, 0);
79735d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
798504d986fSmrg}
799504d986fSmrg
800504d986fSmrgstatic void
801504d986fSmrgamdgpu_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
802504d986fSmrg{
80346845023Smrg	ScreenPtr screen = dirty->secondary_dst->drawable.pScreen;
804504d986fSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
80590f2b693Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
80611bf0794Smrg	xf86CrtcPtr xf86_crtc = amdgpu_prime_dirty_to_crtc(dirty);
80711bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc;
808504d986fSmrg	uintptr_t drm_queue_seq;
809504d986fSmrg
81011bf0794Smrg	if (!xf86_crtc || !xf86_crtc->enabled)
81111bf0794Smrg		return;
812504d986fSmrg
81311bf0794Smrg	drmmode_crtc = xf86_crtc->driver_private;
81411bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
81546845023Smrg	    !drmmode_crtc->scanout[drmmode_crtc->scanout_id] ||
81624b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
817504d986fSmrg		return;
818504d986fSmrg
819504d986fSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
820504d986fSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
821504d986fSmrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT, NULL,
822504d986fSmrg					       amdgpu_prime_scanout_update_handler,
82390f2b693Smrg					       amdgpu_prime_scanout_update_abort,
82490f2b693Smrg					       FALSE);
825504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
826504d986fSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
827504d986fSmrg			   "amdgpu_drm_queue_alloc failed for PRIME update\n");
82890f2b693Smrg		amdgpu_prime_scanout_update_handler(xf86_crtc, 0, 0, NULL);
829504d986fSmrg		return;
830504d986fSmrg	}
831504d986fSmrg
83290f2b693Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
83390f2b693Smrg
83424b90cf4Smrg	if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
83524b90cf4Smrg				 1, drm_queue_seq, NULL, NULL)) {
83690f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) {
83790f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
83890f2b693Smrg				   "drmmode_wait_vblank failed for PRIME update: %s\n",
83990f2b693Smrg				   strerror(errno));
84090f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED;
84190f2b693Smrg		}
84290f2b693Smrg
84390f2b693Smrg		drmmode_crtc->drmmode->event_context.vblank_handler(pAMDGPUEnt->fd,
84490f2b693Smrg								    0, 0, 0,
84590f2b693Smrg								    (void*)drm_queue_seq);
84690f2b693Smrg		drmmode_crtc->wait_flip_nesting_level++;
84790f2b693Smrg		amdgpu_drm_queue_handle_deferred(xf86_crtc);
848504d986fSmrg		return;
849504d986fSmrg	}
850504d986fSmrg
85190f2b693Smrg	if (drmmode_crtc->scanout_status ==
85290f2b693Smrg	    (DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) {
85390f2b693Smrg		/* The page flip and vblank ioctls failed before, but the vblank
85490f2b693Smrg		 * ioctl is working again, so we can try re-enabling TearFree
85590f2b693Smrg		 */
85690f2b693Smrg		xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode,
85790f2b693Smrg						 xf86_crtc->rotation,
85890f2b693Smrg						 xf86_crtc->x, xf86_crtc->y);
85990f2b693Smrg	}
86090f2b693Smrg
86190f2b693Smrg	drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED;
862504d986fSmrg}
863504d986fSmrg
864504d986fSmrgstatic void
865504d986fSmrgamdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
866504d986fSmrg{
86746845023Smrg	ScreenPtr screen = ent->secondary_dst->drawable.pScreen;
868504d986fSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
869504d986fSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
87011bf0794Smrg	xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent);
87111bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc;
872504d986fSmrg	uintptr_t drm_queue_seq;
873504d986fSmrg	unsigned scanout_id;
87490f2b693Smrg	struct drmmode_fb *fb;
875504d986fSmrg
87611bf0794Smrg	if (!crtc || !crtc->enabled)
87711bf0794Smrg		return;
878504d986fSmrg
87911bf0794Smrg	drmmode_crtc = crtc->driver_private;
88090f2b693Smrg	scanout_id = drmmode_crtc->scanout_id ^ 1;
88111bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
88246845023Smrg	    !drmmode_crtc->scanout[scanout_id] ||
88324b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
884504d986fSmrg		return;
885504d986fSmrg
886504d986fSmrg	if (!amdgpu_prime_scanout_do_update(crtc, scanout_id))
887504d986fSmrg		return;
888504d986fSmrg
88946845023Smrg	fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id]);
89090f2b693Smrg	if (!fb) {
89190f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
89290f2b693Smrg			   "Failed to get FB for PRIME flip.\n");
89390f2b693Smrg		return;
89490f2b693Smrg	}
89590f2b693Smrg
896504d986fSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(crtc,
897504d986fSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
89890f2b693Smrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT, fb,
89924b90cf4Smrg					       amdgpu_scanout_flip_handler,
90090f2b693Smrg					       amdgpu_scanout_flip_abort, TRUE);
901504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
902504d986fSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
903504d986fSmrg			   "Allocating DRM event queue entry failed for PRIME flip.\n");
904504d986fSmrg		return;
905504d986fSmrg	}
906504d986fSmrg
90790f2b693Smrg	if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc,
90890f2b693Smrg					      fb->handle, 0, drm_queue_seq, 1)
90990f2b693Smrg	    != 0) {
91090f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) {
91190f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
91290f2b693Smrg				   "flip queue failed in %s: %s, TearFree inactive\n",
91390f2b693Smrg				   __func__, strerror(errno));
91490f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED;
91590f2b693Smrg		}
91690f2b693Smrg
91724b90cf4Smrg		amdgpu_drm_abort_entry(drm_queue_seq);
91824b90cf4Smrg		return;
91924b90cf4Smrg	}
92024b90cf4Smrg
92190f2b693Smrg	if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) {
92290f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n");
92390f2b693Smrg		drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED;
924504d986fSmrg	}
925504d986fSmrg
926504d986fSmrg	drmmode_crtc->scanout_id = scanout_id;
92735d5b7c7Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
92890f2b693Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, fb);
929504d986fSmrg}
930504d986fSmrg
931504d986fSmrgstatic void
932504d986fSmrgamdgpu_dirty_update(ScrnInfoPtr scrn)
933504d986fSmrg{
934504d986fSmrg	ScreenPtr screen = scrn->pScreen;
935504d986fSmrg	PixmapDirtyUpdatePtr ent;
936504d986fSmrg	RegionPtr region;
937504d986fSmrg
938504d986fSmrg	xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
939504d986fSmrg		if (screen->isGPU) {
940504d986fSmrg			PixmapDirtyUpdatePtr region_ent = ent;
941504d986fSmrg
94246845023Smrg			if (primary_has_sync_shared_pixmap(scrn, ent)) {
94346845023Smrg				ScreenPtr primary_screen = amdgpu_dirty_primary(ent);
944504d986fSmrg
94546845023Smrg				xorg_list_for_each_entry(region_ent, &primary_screen->pixmap_dirty_list, ent) {
94646845023Smrg					if (amdgpu_dirty_src_equals(ent, region_ent->secondary_dst))
947504d986fSmrg						break;
948504d986fSmrg				}
949504d986fSmrg			}
950504d986fSmrg
951504d986fSmrg			region = dirty_region(region_ent);
952504d986fSmrg
953504d986fSmrg			if (RegionNotEmpty(region)) {
95411bf0794Smrg				xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent);
95511bf0794Smrg				drmmode_crtc_private_ptr drmmode_crtc = NULL;
95611bf0794Smrg
95711bf0794Smrg				if (crtc)
95811bf0794Smrg					drmmode_crtc = crtc->driver_private;
95911bf0794Smrg
96011bf0794Smrg				if (drmmode_crtc && drmmode_crtc->tear_free)
961504d986fSmrg					amdgpu_prime_scanout_flip(ent);
962504d986fSmrg				else
963504d986fSmrg					amdgpu_prime_scanout_update(ent);
964504d986fSmrg			} else {
965504d986fSmrg				DamageEmpty(region_ent->damage);
966504d986fSmrg			}
967504d986fSmrg
968504d986fSmrg			RegionDestroy(region);
969504d986fSmrg		} else {
97046845023Smrg			if (secondary_has_sync_shared_pixmap(scrn, ent))
971504d986fSmrg				continue;
972504d986fSmrg
973504d986fSmrg			region = dirty_region(ent);
974504d986fSmrg			redisplay_dirty(ent, region);
975504d986fSmrg			RegionDestroy(region);
976504d986fSmrg		}
977504d986fSmrg	}
978504d986fSmrg}
97924b90cf4Smrg
98046845023Smrgstatic void
98146845023SmrgamdgpuSourceValidate(DrawablePtr draw, int x, int y, int w, int h,
98246845023Smrg		     unsigned int subWindowMode)
98346845023Smrg{
98446845023Smrg}
985504d986fSmrg
98611bf0794SmrgBool
98724b90cf4Smrgamdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id,
98835d5b7c7Smrg			 PixmapPtr src_pix, BoxRec extents)
989d6c0b56eSmrg{
990d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
99135d5b7c7Smrg	RegionRec region = { .extents = extents, .data = NULL };
992504d986fSmrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
993504d986fSmrg	ScreenPtr pScreen = scrn->pScreen;
994d6c0b56eSmrg	DrawablePtr pDraw;
995d6c0b56eSmrg
996d6c0b56eSmrg	if (!xf86_crtc->enabled ||
99746845023Smrg	    !drmmode_crtc->scanout[scanout_id] ||
99835d5b7c7Smrg	    extents.x1 >= extents.x2 || extents.y1 >= extents.y2)
999d6c0b56eSmrg		return FALSE;
1000d6c0b56eSmrg
100146845023Smrg	pDraw = &drmmode_crtc->scanout[scanout_id]->drawable;
100235d5b7c7Smrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents))
1003d6c0b56eSmrg		return FALSE;
1004d6c0b56eSmrg
100511bf0794Smrg	if (drmmode_crtc->tear_free) {
100624b90cf4Smrg		amdgpu_sync_scanout_pixmaps(xf86_crtc, &region, scanout_id);
100724b90cf4Smrg		RegionCopy(&drmmode_crtc->scanout_last_region, &region);
1008504d986fSmrg	}
1009504d986fSmrg
1010d6c0b56eSmrg	if (xf86_crtc->driverIsPerformingTransform) {
1011d6c0b56eSmrg		SourceValidateProcPtr SourceValidate = pScreen->SourceValidate;
1012d6c0b56eSmrg		PictFormatPtr format = PictureWindowFormat(pScreen->root);
1013d6c0b56eSmrg		int error;
1014d6c0b56eSmrg		PicturePtr src, dst;
1015d6c0b56eSmrg
101624b90cf4Smrg		src = CreatePicture(None, &src_pix->drawable, format, 0L, NULL,
101724b90cf4Smrg				    serverClient, &error);
1018d6c0b56eSmrg		if (!src) {
1019d6c0b56eSmrg			ErrorF("Failed to create source picture for transformed scanout "
1020d6c0b56eSmrg			       "update\n");
1021d6c0b56eSmrg			goto out;
1022d6c0b56eSmrg		}
1023d6c0b56eSmrg
1024d6c0b56eSmrg		dst = CreatePicture(None, pDraw, format, 0L, NULL, serverClient, &error);
1025d6c0b56eSmrg		if (!dst) {
1026d6c0b56eSmrg			ErrorF("Failed to create destination picture for transformed scanout "
1027d6c0b56eSmrg			       "update\n");
1028d6c0b56eSmrg			goto free_src;
1029d6c0b56eSmrg		}
1030d6c0b56eSmrg		error = SetPictureTransform(src, &xf86_crtc->crtc_to_framebuffer);
1031d6c0b56eSmrg		if (error) {
1032d6c0b56eSmrg			ErrorF("SetPictureTransform failed for transformed scanout "
1033d6c0b56eSmrg			       "update\n");
1034d6c0b56eSmrg			goto free_dst;
1035d6c0b56eSmrg		}
1036d6c0b56eSmrg
1037d6c0b56eSmrg		if (xf86_crtc->filter)
1038d6c0b56eSmrg			SetPicturePictFilter(src, xf86_crtc->filter, xf86_crtc->params,
1039d6c0b56eSmrg					     xf86_crtc->nparams);
1040d6c0b56eSmrg
104146845023Smrg		pScreen->SourceValidate = amdgpuSourceValidate;
1042d6c0b56eSmrg		CompositePicture(PictOpSrc,
1043d6c0b56eSmrg				 src, NULL, dst,
104435d5b7c7Smrg				 extents.x1, extents.y1, 0, 0, extents.x1,
104535d5b7c7Smrg				 extents.y1, extents.x2 - extents.x1,
104635d5b7c7Smrg				 extents.y2 - extents.y1);
1047d6c0b56eSmrg		pScreen->SourceValidate = SourceValidate;
1048d6c0b56eSmrg
1049d6c0b56eSmrg free_dst:
1050d6c0b56eSmrg		FreePicture(dst, None);
1051d6c0b56eSmrg free_src:
1052d6c0b56eSmrg		FreePicture(src, None);
1053d6c0b56eSmrg	} else
1054d6c0b56eSmrg out:
1055d6c0b56eSmrg	{
1056d6c0b56eSmrg		GCPtr gc = GetScratchGC(pDraw->depth, pScreen);
1057d6c0b56eSmrg
1058d6c0b56eSmrg		ValidateGC(pDraw, gc);
105924b90cf4Smrg		(*gc->ops->CopyArea)(&src_pix->drawable, pDraw, gc,
106035d5b7c7Smrg				     xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
106135d5b7c7Smrg				     extents.x2 - extents.x1, extents.y2 - extents.y1,
106235d5b7c7Smrg				     extents.x1, extents.y1);
1063d6c0b56eSmrg		FreeScratchGC(gc);
1064d6c0b56eSmrg	}
1065d6c0b56eSmrg
1066d6c0b56eSmrg	return TRUE;
1067d6c0b56eSmrg}
1068d6c0b56eSmrg
1069d6c0b56eSmrgstatic void
1070d6c0b56eSmrgamdgpu_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
1071d6c0b56eSmrg{
1072d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = event_data;
1073d6c0b56eSmrg
107435d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
1075d6c0b56eSmrg}
1076d6c0b56eSmrg
107711bf0794Smrgstatic void
1078d6c0b56eSmrgamdgpu_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
1079d6c0b56eSmrg							  void *event_data)
1080d6c0b56eSmrg{
108124b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = event_data;
108224b90cf4Smrg	ScreenPtr screen = crtc->scrn->pScreen;
108324b90cf4Smrg	RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage);
108424b90cf4Smrg
108524b90cf4Smrg	if (crtc->enabled &&
108624b90cf4Smrg	    !drmmode_crtc->flip_pending &&
108724b90cf4Smrg	    drmmode_crtc->dpms_mode == DPMSModeOn) {
108824b90cf4Smrg		if (amdgpu_scanout_do_update(crtc, drmmode_crtc->scanout_id,
108924b90cf4Smrg					     screen->GetWindowPixmap(screen->root),
109035d5b7c7Smrg					     region->extents)) {
109135d5b7c7Smrg			amdgpu_glamor_flush(crtc->scrn);
109224b90cf4Smrg			RegionEmpty(region);
109335d5b7c7Smrg		}
109424b90cf4Smrg	}
1095d6c0b56eSmrg
1096d6c0b56eSmrg	amdgpu_scanout_update_abort(crtc, event_data);
1097d6c0b56eSmrg}
1098d6c0b56eSmrg
1099d6c0b56eSmrgstatic void
1100d6c0b56eSmrgamdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
1101d6c0b56eSmrg{
1102d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
110390f2b693Smrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
110490f2b693Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
1105d6c0b56eSmrg	uintptr_t drm_queue_seq;
1106d6c0b56eSmrg	DamagePtr pDamage;
1107d6c0b56eSmrg	RegionPtr pRegion;
1108d6c0b56eSmrg	BoxRec extents;
1109d6c0b56eSmrg
1110d6c0b56eSmrg	if (!xf86_crtc->enabled ||
1111d6c0b56eSmrg	    drmmode_crtc->scanout_update_pending ||
111224b90cf4Smrg	    drmmode_crtc->flip_pending ||
111324b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
1114d6c0b56eSmrg		return;
1115d6c0b56eSmrg
1116504d986fSmrg	pDamage = drmmode_crtc->scanout_damage;
1117d6c0b56eSmrg	if (!pDamage)
1118d6c0b56eSmrg		return;
1119d6c0b56eSmrg
1120d6c0b56eSmrg	pRegion = DamageRegion(pDamage);
1121d6c0b56eSmrg	if (!RegionNotEmpty(pRegion))
1122d6c0b56eSmrg		return;
1123d6c0b56eSmrg
1124d6c0b56eSmrg	extents = *RegionExtents(pRegion);
1125504d986fSmrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents)) {
1126504d986fSmrg		RegionEmpty(pRegion);
1127d6c0b56eSmrg		return;
1128504d986fSmrg	}
1129d6c0b56eSmrg
1130d6c0b56eSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
1131d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
1132d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT,
1133d6c0b56eSmrg					       drmmode_crtc,
1134d6c0b56eSmrg					       amdgpu_scanout_update_handler,
113590f2b693Smrg					       amdgpu_scanout_update_abort,
113690f2b693Smrg					       FALSE);
1137504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
1138d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1139d6c0b56eSmrg			   "amdgpu_drm_queue_alloc failed for scanout update\n");
114090f2b693Smrg		amdgpu_scanout_update_handler(xf86_crtc, 0, 0, drmmode_crtc);
1141d6c0b56eSmrg		return;
1142d6c0b56eSmrg	}
1143d6c0b56eSmrg
114490f2b693Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
114590f2b693Smrg
114624b90cf4Smrg	if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
114724b90cf4Smrg				 1, drm_queue_seq, NULL, NULL)) {
114890f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) {
114990f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
115090f2b693Smrg				   "drmmode_wait_vblank failed for scanout update: %s\n",
115190f2b693Smrg				   strerror(errno));
115290f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED;
115390f2b693Smrg		}
115490f2b693Smrg
115590f2b693Smrg		drmmode_crtc->drmmode->event_context.vblank_handler(pAMDGPUEnt->fd,
115690f2b693Smrg								    0, 0, 0,
115790f2b693Smrg								    (void*)drm_queue_seq);
115890f2b693Smrg		drmmode_crtc->wait_flip_nesting_level++;
115990f2b693Smrg		amdgpu_drm_queue_handle_deferred(xf86_crtc);
1160d6c0b56eSmrg		return;
1161d6c0b56eSmrg	}
1162d6c0b56eSmrg
116390f2b693Smrg	if (drmmode_crtc->scanout_status ==
116490f2b693Smrg	    (DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) {
116590f2b693Smrg		/* The page flip and vblank ioctls failed before, but the vblank
116690f2b693Smrg		 * ioctl is working again, so we can try re-enabling TearFree
116790f2b693Smrg		 */
116890f2b693Smrg		xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode,
116990f2b693Smrg						 xf86_crtc->rotation,
117090f2b693Smrg						 xf86_crtc->x, xf86_crtc->y);
117190f2b693Smrg	}
117290f2b693Smrg
117390f2b693Smrg	drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED;
1174d6c0b56eSmrg}
1175d6c0b56eSmrg
1176d6c0b56eSmrgstatic void
1177d6c0b56eSmrgamdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
1178d6c0b56eSmrg					xf86CrtcPtr xf86_crtc)
1179d6c0b56eSmrg{
1180d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
118124b90cf4Smrg	RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage);
118211bf0794Smrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
118311bf0794Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
1184d6c0b56eSmrg	uintptr_t drm_queue_seq;
1185d6c0b56eSmrg	unsigned scanout_id;
118690f2b693Smrg	struct drmmode_fb *fb;
1187d6c0b56eSmrg
118811bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
118924b90cf4Smrg	    drmmode_crtc->flip_pending ||
119024b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
1191d6c0b56eSmrg		return;
1192d6c0b56eSmrg
1193d6c0b56eSmrg	scanout_id = drmmode_crtc->scanout_id ^ 1;
119424b90cf4Smrg	if (!amdgpu_scanout_do_update(xf86_crtc, scanout_id,
119524b90cf4Smrg				      pScreen->GetWindowPixmap(pScreen->root),
119635d5b7c7Smrg				      region->extents))
1197d6c0b56eSmrg		return;
119835d5b7c7Smrg
119935d5b7c7Smrg	amdgpu_glamor_flush(scrn);
120024b90cf4Smrg	RegionEmpty(region);
1201d6c0b56eSmrg
120246845023Smrg	fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id]);
120390f2b693Smrg	if (!fb) {
120490f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
120590f2b693Smrg			   "Failed to get FB for scanout flip.\n");
120690f2b693Smrg		return;
120790f2b693Smrg	}
120890f2b693Smrg
1209d6c0b56eSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
1210d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
121190f2b693Smrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT, fb,
121224b90cf4Smrg					       amdgpu_scanout_flip_handler,
121390f2b693Smrg					       amdgpu_scanout_flip_abort, TRUE);
1214504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
1215d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1216d6c0b56eSmrg			   "Allocating DRM event queue entry failed.\n");
1217d6c0b56eSmrg		return;
1218d6c0b56eSmrg	}
1219d6c0b56eSmrg
122011bf0794Smrg	if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc,
122190f2b693Smrg					      fb->handle, 0, drm_queue_seq, 1)
122290f2b693Smrg	    != 0) {
122390f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) {
122490f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
122590f2b693Smrg				   "flip queue failed in %s: %s, TearFree inactive\n",
122690f2b693Smrg				   __func__, strerror(errno));
122790f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED;
122890f2b693Smrg		}
122990f2b693Smrg
123011bf0794Smrg		amdgpu_drm_abort_entry(drm_queue_seq);
123124b90cf4Smrg		RegionCopy(DamageRegion(drmmode_crtc->scanout_damage),
123224b90cf4Smrg			   &drmmode_crtc->scanout_last_region);
123324b90cf4Smrg		RegionEmpty(&drmmode_crtc->scanout_last_region);
123424b90cf4Smrg		amdgpu_scanout_update(xf86_crtc);
123546845023Smrg		drmmode_crtc_scanout_destroy(&drmmode_crtc->scanout[scanout_id]);
123624b90cf4Smrg		drmmode_crtc->tear_free = FALSE;
1237d6c0b56eSmrg		return;
1238d6c0b56eSmrg	}
1239d6c0b56eSmrg
124090f2b693Smrg	if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) {
124190f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n");
124290f2b693Smrg		drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED;
124390f2b693Smrg	}
124490f2b693Smrg
1245d6c0b56eSmrg	drmmode_crtc->scanout_id = scanout_id;
124635d5b7c7Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
124790f2b693Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, fb);
1248d6c0b56eSmrg}
1249d6c0b56eSmrg
1250d6c0b56eSmrgstatic void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
1251d6c0b56eSmrg{
1252d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1253d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1254d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1255d6c0b56eSmrg	int c;
1256d6c0b56eSmrg
1257d6c0b56eSmrg	pScreen->BlockHandler = info->BlockHandler;
1258d6c0b56eSmrg	(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
1259d6c0b56eSmrg	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
1260d6c0b56eSmrg
126146845023Smrg	if (!xf86ScreenToScrn(amdgpu_primary_screen(pScreen))->vtSema)
126224b90cf4Smrg		return;
126324b90cf4Smrg
126424b90cf4Smrg	if (!pScreen->isGPU)
1265504d986fSmrg	{
1266504d986fSmrg		for (c = 0; c < xf86_config->num_crtc; c++) {
126711bf0794Smrg			xf86CrtcPtr crtc = xf86_config->crtc[c];
126811bf0794Smrg			drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
126911bf0794Smrg
127046845023Smrg			if (drmmode_crtc->rotate)
127135d5b7c7Smrg				continue;
127235d5b7c7Smrg
127311bf0794Smrg			if (drmmode_crtc->tear_free)
127411bf0794Smrg				amdgpu_scanout_flip(pScreen, info, crtc);
127546845023Smrg			else if (drmmode_crtc->scanout[drmmode_crtc->scanout_id])
127611bf0794Smrg				amdgpu_scanout_update(crtc);
1277504d986fSmrg		}
1278d6c0b56eSmrg	}
1279d6c0b56eSmrg
128011bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,0,0,0)
1281d6c0b56eSmrg	if (info->use_glamor)
1282d6c0b56eSmrg		amdgpu_glamor_flush(pScrn);
128311bf0794Smrg#endif
1284d6c0b56eSmrg
1285504d986fSmrg	amdgpu_dirty_update(pScrn);
1286d6c0b56eSmrg}
1287d6c0b56eSmrg
1288d6c0b56eSmrg/* This is called by AMDGPUPreInit to set up the default visual */
1289d6c0b56eSmrgstatic Bool AMDGPUPreInitVisual(ScrnInfoPtr pScrn)
1290d6c0b56eSmrg{
1291d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1292d6c0b56eSmrg
1293d6c0b56eSmrg	if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb))
1294d6c0b56eSmrg		return FALSE;
1295d6c0b56eSmrg
1296d6c0b56eSmrg	switch (pScrn->depth) {
1297d6c0b56eSmrg	case 8:
1298d6c0b56eSmrg	case 15:
1299d6c0b56eSmrg	case 16:
1300d6c0b56eSmrg	case 24:
130124b90cf4Smrg	case 30:
1302d6c0b56eSmrg		break;
1303d6c0b56eSmrg
1304d6c0b56eSmrg	default:
1305d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1306d6c0b56eSmrg			   "Given depth (%d) is not supported by %s driver\n",
1307d6c0b56eSmrg			   pScrn->depth, AMDGPU_DRIVER_NAME);
1308d6c0b56eSmrg		return FALSE;
1309d6c0b56eSmrg	}
1310d6c0b56eSmrg
1311d6c0b56eSmrg	xf86PrintDepthBpp(pScrn);
1312d6c0b56eSmrg
1313d6c0b56eSmrg	info->pix24bpp = xf86GetBppFromDepth(pScrn, pScrn->depth);
1314d6c0b56eSmrg	info->pixel_bytes = pScrn->bitsPerPixel / 8;
1315d6c0b56eSmrg
1316d6c0b56eSmrg	if (info->pix24bpp == 24) {
1317d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1318d6c0b56eSmrg			   "Amdgpu does NOT support 24bpp\n");
1319d6c0b56eSmrg		return FALSE;
1320d6c0b56eSmrg	}
1321d6c0b56eSmrg
1322d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1323d6c0b56eSmrg		   "Pixel depth = %d bits stored in %d byte%s (%d bpp pixmaps)\n",
1324d6c0b56eSmrg		   pScrn->depth,
1325d6c0b56eSmrg		   info->pixel_bytes,
1326d6c0b56eSmrg		   info->pixel_bytes > 1 ? "s" : "", info->pix24bpp);
1327d6c0b56eSmrg
1328d6c0b56eSmrg	if (!xf86SetDefaultVisual(pScrn, -1))
1329d6c0b56eSmrg		return FALSE;
1330d6c0b56eSmrg
1331d6c0b56eSmrg	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
1332d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1333d6c0b56eSmrg			   "Default visual (%s) is not supported at depth %d\n",
1334d6c0b56eSmrg			   xf86GetVisualName(pScrn->defaultVisual),
1335d6c0b56eSmrg			   pScrn->depth);
1336d6c0b56eSmrg		return FALSE;
1337d6c0b56eSmrg	}
1338d6c0b56eSmrg	return TRUE;
1339d6c0b56eSmrg}
1340d6c0b56eSmrg
1341d6c0b56eSmrg/* This is called by AMDGPUPreInit to handle all color weight issues */
1342d6c0b56eSmrgstatic Bool AMDGPUPreInitWeight(ScrnInfoPtr pScrn)
1343d6c0b56eSmrg{
1344d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1345d6c0b56eSmrg
1346d6c0b56eSmrg	/* Save flag for 6 bit DAC to use for
1347d6c0b56eSmrg	   setting CRTC registers.  Otherwise use
1348d6c0b56eSmrg	   an 8 bit DAC, even if xf86SetWeight sets
1349d6c0b56eSmrg	   pScrn->rgbBits to some value other than
1350d6c0b56eSmrg	   8. */
1351d6c0b56eSmrg	info->dac6bits = FALSE;
1352d6c0b56eSmrg
1353d6c0b56eSmrg	if (pScrn->depth > 8) {
1354d6c0b56eSmrg		rgb defaultWeight = { 0, 0, 0 };
1355d6c0b56eSmrg
1356d6c0b56eSmrg		if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
1357d6c0b56eSmrg			return FALSE;
1358d6c0b56eSmrg	} else {
1359d6c0b56eSmrg		pScrn->rgbBits = 8;
1360d6c0b56eSmrg	}
1361d6c0b56eSmrg
1362d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1363d6c0b56eSmrg		   "Using %d bits per RGB (%d bit DAC)\n",
1364d6c0b56eSmrg		   pScrn->rgbBits, info->dac6bits ? 6 : 8);
1365d6c0b56eSmrg
1366d6c0b56eSmrg	return TRUE;
1367d6c0b56eSmrg}
1368d6c0b56eSmrg
1369d6c0b56eSmrgstatic Bool AMDGPUPreInitAccel_KMS(ScrnInfoPtr pScrn)
1370d6c0b56eSmrg{
1371d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1372d6c0b56eSmrg
1373d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_ACCEL, TRUE)) {
1374d6c0b56eSmrg		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1375d6c0b56eSmrg		Bool use_glamor = TRUE;
1376d6c0b56eSmrg#ifdef HAVE_GBM_BO_USE_LINEAR
1377d6c0b56eSmrg		const char *accel_method;
1378d6c0b56eSmrg
1379d6c0b56eSmrg		accel_method = xf86GetOptValString(info->Options, OPTION_ACCEL_METHOD);
1380d6c0b56eSmrg		if ((accel_method && !strcmp(accel_method, "none")))
1381d6c0b56eSmrg			use_glamor = FALSE;
1382d6c0b56eSmrg#endif
1383d6c0b56eSmrg
1384d6c0b56eSmrg#ifdef DRI2
1385d6c0b56eSmrg		info->dri2.available = ! !xf86LoadSubModule(pScrn, "dri2");
1386d6c0b56eSmrg#endif
1387d6c0b56eSmrg
1388d6c0b56eSmrg		if (info->dri2.available)
1389d6c0b56eSmrg			info->gbm = gbm_create_device(pAMDGPUEnt->fd);
1390d6c0b56eSmrg
139124b90cf4Smrg		if (info->gbm) {
139235d5b7c7Smrg			if (use_glamor) {
139335d5b7c7Smrg				if (amdgpu_glamor_pre_init(pScrn))
139435d5b7c7Smrg					return TRUE;
139535d5b7c7Smrg
139635d5b7c7Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
139735d5b7c7Smrg					   "amdgpu_glamor_pre_init returned "
139835d5b7c7Smrg					   "FALSE, using ShadowFB\n");
139935d5b7c7Smrg			}
140024b90cf4Smrg		} else {
140124b90cf4Smrg			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
140224b90cf4Smrg				   "gbm_create_device returned NULL, using "
140324b90cf4Smrg				   "ShadowFB\n");
140424b90cf4Smrg		}
140524b90cf4Smrg	} else {
140624b90cf4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
140724b90cf4Smrg			   "GPU acceleration disabled, using ShadowFB\n");
1408d6c0b56eSmrg	}
1409d6c0b56eSmrg
1410d6c0b56eSmrg	if (!xf86LoadSubModule(pScrn, "shadow"))
141124b90cf4Smrg		return FALSE;
1412d6c0b56eSmrg
141324b90cf4Smrg	info->dri2.available = FALSE;
141424b90cf4Smrg	info->shadow_fb = TRUE;
1415d6c0b56eSmrg	return TRUE;
1416d6c0b56eSmrg}
1417d6c0b56eSmrg
141811bf0794Smrgstatic Bool AMDGPUPreInitChipType_KMS(ScrnInfoPtr pScrn,
141911bf0794Smrg				      struct amdgpu_gpu_info *gpu_info)
1420d6c0b56eSmrg{
1421d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
142211bf0794Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1423d6c0b56eSmrg
142490f2b693Smrg	pScrn->chipset = (char*)amdgpu_get_marketing_name(pAMDGPUEnt->pDev);
142511bf0794Smrg	if (!pScrn->chipset)
142611bf0794Smrg		pScrn->chipset = "Unknown AMD Radeon GPU";
1427d6c0b56eSmrg
1428d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1429d6c0b56eSmrg		   "Chipset: \"%s\" (ChipID = 0x%04x)\n",
143046845023Smrg		   pScrn->chipset, gpu_info->asic_id);
1431d6c0b56eSmrg
143211bf0794Smrg	info->family = gpu_info->family_id;
1433d6c0b56eSmrg
1434d6c0b56eSmrg	return TRUE;
1435d6c0b56eSmrg}
1436d6c0b56eSmrg
143711bf0794Smrgstatic Bool amdgpu_get_tile_config(AMDGPUInfoPtr info,
143811bf0794Smrg				   struct amdgpu_gpu_info *gpu_info)
1439d6c0b56eSmrg{
144011bf0794Smrg	switch ((gpu_info->gb_addr_cfg & 0x70) >> 4) {
1441d6c0b56eSmrg	case 0:
1442d6c0b56eSmrg		info->group_bytes = 256;
1443d6c0b56eSmrg		break;
1444d6c0b56eSmrg	case 1:
1445d6c0b56eSmrg		info->group_bytes = 512;
1446d6c0b56eSmrg		break;
1447d6c0b56eSmrg	default:
1448d6c0b56eSmrg		return FALSE;
1449d6c0b56eSmrg	}
1450d6c0b56eSmrg
1451d6c0b56eSmrg	info->have_tiling_info = TRUE;
1452d6c0b56eSmrg	return TRUE;
1453d6c0b56eSmrg}
1454d6c0b56eSmrg
1455d6c0b56eSmrgstatic void AMDGPUSetupCapabilities(ScrnInfoPtr pScrn)
1456d6c0b56eSmrg{
1457d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1458d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1459d6c0b56eSmrg	uint64_t value;
1460d6c0b56eSmrg	int ret;
1461d6c0b56eSmrg
1462d6c0b56eSmrg	pScrn->capabilities = 0;
1463d6c0b56eSmrg
1464d6c0b56eSmrg	/* PRIME offloading requires acceleration */
1465d6c0b56eSmrg	if (!info->use_glamor)
1466d6c0b56eSmrg		return;
1467d6c0b56eSmrg
1468d6c0b56eSmrg	ret = drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PRIME, &value);
1469d6c0b56eSmrg	if (ret == 0) {
1470d6c0b56eSmrg		if (value & DRM_PRIME_CAP_EXPORT)
1471504d986fSmrg			pScrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SourceOffload;
1472504d986fSmrg		if (value & DRM_PRIME_CAP_IMPORT) {
1473504d986fSmrg			pScrn->capabilities |= RR_Capability_SinkOffload;
1474504d986fSmrg			if (info->drmmode.count_crtcs)
1475504d986fSmrg				pScrn->capabilities |= RR_Capability_SinkOutput;
1476504d986fSmrg		}
1477d6c0b56eSmrg	}
1478d6c0b56eSmrg}
1479d6c0b56eSmrg
1480d6c0b56eSmrg/* When the root window is created, initialize the screen contents from
1481d6c0b56eSmrg * console if -background none was specified on the command line
1482d6c0b56eSmrg */
1483d6c0b56eSmrgstatic Bool AMDGPUCreateWindow_oneshot(WindowPtr pWin)
1484d6c0b56eSmrg{
1485d6c0b56eSmrg	ScreenPtr pScreen = pWin->drawable.pScreen;
1486d6c0b56eSmrg	ScrnInfoPtr pScrn;
1487d6c0b56eSmrg	AMDGPUInfoPtr info;
1488d6c0b56eSmrg	Bool ret;
1489d6c0b56eSmrg
1490d6c0b56eSmrg	if (pWin != pScreen->root)
1491d6c0b56eSmrg		ErrorF("%s called for non-root window %p\n", __func__, pWin);
1492d6c0b56eSmrg
1493d6c0b56eSmrg	pScrn = xf86ScreenToScrn(pScreen);
1494d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
1495d6c0b56eSmrg	pScreen->CreateWindow = info->CreateWindow;
1496d6c0b56eSmrg	ret = pScreen->CreateWindow(pWin);
1497d6c0b56eSmrg
1498d6c0b56eSmrg	if (ret)
1499d6c0b56eSmrg		drmmode_copy_fb(pScrn, &info->drmmode);
1500d6c0b56eSmrg
1501d6c0b56eSmrg	return ret;
1502d6c0b56eSmrg}
1503d6c0b56eSmrg
1504e49c54bcSmrgstatic void amdgpu_determine_cursor_size(int fd, AMDGPUInfoPtr info)
1505e49c54bcSmrg{
1506e49c54bcSmrg	uint64_t value;
1507e49c54bcSmrg
1508e49c54bcSmrg	if (drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &value) == 0)
1509e49c54bcSmrg		info->cursor_w = value;
1510e49c54bcSmrg	else if (info->family < AMDGPU_FAMILY_CI)
1511e49c54bcSmrg		info->cursor_w = CURSOR_WIDTH;
1512e49c54bcSmrg	else
1513e49c54bcSmrg		info->cursor_w = CURSOR_WIDTH_CIK;
1514e49c54bcSmrg
1515e49c54bcSmrg	if (drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &value) == 0)
1516e49c54bcSmrg		info->cursor_h = value;
1517e49c54bcSmrg	else if (info->family < AMDGPU_FAMILY_CI)
1518e49c54bcSmrg		info->cursor_h = CURSOR_HEIGHT;
1519e49c54bcSmrg	else
1520e49c54bcSmrg		info->cursor_h = CURSOR_HEIGHT_CIK;
1521e49c54bcSmrg}
1522e49c54bcSmrg
152311bf0794Smrg/* When the root window is mapped, set the initial modes */
152424b90cf4Smrgvoid AMDGPUWindowExposures_oneshot(WindowPtr pWin, RegionPtr pRegion
152511bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
152624b90cf4Smrg				   , RegionPtr pBSRegion
152711bf0794Smrg#endif
152824b90cf4Smrg				   )
152911bf0794Smrg{
153011bf0794Smrg	ScreenPtr pScreen = pWin->drawable.pScreen;
153111bf0794Smrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
153211bf0794Smrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
153311bf0794Smrg
153411bf0794Smrg	if (pWin != pScreen->root)
153511bf0794Smrg		ErrorF("%s called for non-root window %p\n", __func__, pWin);
153611bf0794Smrg
153711bf0794Smrg	pScreen->WindowExposures = info->WindowExposures;
153811bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
153911bf0794Smrg	pScreen->WindowExposures(pWin, pRegion, pBSRegion);
154011bf0794Smrg#else
154111bf0794Smrg	pScreen->WindowExposures(pWin, pRegion);
154211bf0794Smrg#endif
154311bf0794Smrg
154411bf0794Smrg	amdgpu_glamor_finish(pScrn);
154511bf0794Smrg	drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE);
154611bf0794Smrg}
154711bf0794Smrg
1548d6c0b56eSmrgBool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
1549d6c0b56eSmrg{
1550d6c0b56eSmrg	AMDGPUInfoPtr info;
1551d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt;
155211bf0794Smrg	struct amdgpu_gpu_info gpu_info;
155311bf0794Smrg	MessageType from;
1554d6c0b56eSmrg	Gamma zeros = { 0.0, 0.0, 0.0 };
1555d6c0b56eSmrg	int cpp;
1556d6c0b56eSmrg	uint64_t heap_size = 0;
1557d6c0b56eSmrg	uint64_t max_allocation = 0;
1558d6c0b56eSmrg
1559d6c0b56eSmrg	if (flags & PROBE_DETECT)
1560d6c0b56eSmrg		return TRUE;
1561d6c0b56eSmrg
1562d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1563d6c0b56eSmrg		       "AMDGPUPreInit_KMS\n");
1564d6c0b56eSmrg	if (pScrn->numEntities != 1)
1565d6c0b56eSmrg		return FALSE;
156690f2b693Smrg
156790f2b693Smrg	pAMDGPUEnt = xf86GetEntityPrivate(pScrn->entityList[0],
156890f2b693Smrg					  getAMDGPUEntityIndex())->ptr;
156990f2b693Smrg
1570d6c0b56eSmrg	if (!AMDGPUGetRec(pScrn))
1571d6c0b56eSmrg		return FALSE;
1572d6c0b56eSmrg
1573d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
157490f2b693Smrg	info->instance_id = pAMDGPUEnt->num_scrns++;
157590f2b693Smrg	pAMDGPUEnt->scrn[info->instance_id] = pScrn;
157690f2b693Smrg
1577d6c0b56eSmrg	info->pEnt =
1578d6c0b56eSmrg	    xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
1579d6c0b56eSmrg	if (info->pEnt->location.type != BUS_PCI
1580d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS
1581d6c0b56eSmrg	    && info->pEnt->location.type != BUS_PLATFORM
1582d6c0b56eSmrg#endif
1583d6c0b56eSmrg	    )
158424b90cf4Smrg		return FALSE;
1585d6c0b56eSmrg
158690f2b693Smrg	if (xf86IsEntityShared(pScrn->entityList[0]) &&
158790f2b693Smrg	    info->instance_id == 0) {
158890f2b693Smrg		xf86SetPrimInitDone(pScrn->entityList[0]);
1589d6c0b56eSmrg	}
1590d6c0b56eSmrg
1591d6c0b56eSmrg	pScrn->monitor = pScrn->confScreen->monitor;
1592d6c0b56eSmrg
1593d6c0b56eSmrg	if (!AMDGPUPreInitVisual(pScrn))
159424b90cf4Smrg		return FALSE;
1595d6c0b56eSmrg
1596d6c0b56eSmrg	xf86CollectOptions(pScrn, NULL);
1597d6c0b56eSmrg	if (!(info->Options = malloc(sizeof(AMDGPUOptions_KMS))))
159824b90cf4Smrg		return FALSE;
1599d6c0b56eSmrg
1600d6c0b56eSmrg	memcpy(info->Options, AMDGPUOptions_KMS, sizeof(AMDGPUOptions_KMS));
1601d6c0b56eSmrg	xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options);
1602d6c0b56eSmrg
1603d6c0b56eSmrg	if (!AMDGPUPreInitWeight(pScrn))
160424b90cf4Smrg		return FALSE;
1605d6c0b56eSmrg
160611bf0794Smrg	memset(&gpu_info, 0, sizeof(gpu_info));
160711bf0794Smrg	amdgpu_query_gpu_info(pAMDGPUEnt->pDev, &gpu_info);
160811bf0794Smrg
160911bf0794Smrg	if (!AMDGPUPreInitChipType_KMS(pScrn, &gpu_info))
161024b90cf4Smrg		return FALSE;
1611d6c0b56eSmrg
1612d6c0b56eSmrg	info->dri2.available = FALSE;
1613d6c0b56eSmrg	info->dri2.enabled = FALSE;
161490f2b693Smrg	info->dri2.pKernelDRMVersion = drmGetVersion(pAMDGPUEnt->fd);
161590f2b693Smrg	if (info->dri2.pKernelDRMVersion == NULL) {
161690f2b693Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
161790f2b693Smrg			   "AMDGPUDRIGetVersion failed to get the DRM version\n");
161890f2b693Smrg		return FALSE;
161990f2b693Smrg	}
1620d6c0b56eSmrg
1621d6c0b56eSmrg	/* Get ScreenInit function */
1622d6c0b56eSmrg	if (!xf86LoadSubModule(pScrn, "fb"))
1623d6c0b56eSmrg		return FALSE;
1624d6c0b56eSmrg
1625d6c0b56eSmrg	if (!AMDGPUPreInitAccel_KMS(pScrn))
162624b90cf4Smrg		return FALSE;
1627d6c0b56eSmrg
162835d5b7c7Smrg	amdgpu_drm_queue_init(pScrn);
1629d6c0b56eSmrg
1630d6c0b56eSmrg	/* don't enable tiling if accel is not enabled */
1631d6c0b56eSmrg	if (info->use_glamor) {
1632d6c0b56eSmrg		/* set default group bytes, overridden by kernel info below */
1633d6c0b56eSmrg		info->group_bytes = 256;
1634d6c0b56eSmrg		info->have_tiling_info = FALSE;
163511bf0794Smrg		amdgpu_get_tile_config(info, &gpu_info);
1636d6c0b56eSmrg	}
1637d6c0b56eSmrg
1638d6c0b56eSmrg	if (info->use_glamor) {
163911bf0794Smrg		from = X_DEFAULT;
1640d6c0b56eSmrg
164111bf0794Smrg		info->tear_free = 2;
164211bf0794Smrg		if (xf86GetOptValBool(info->Options, OPTION_TEAR_FREE,
164311bf0794Smrg				      &info->tear_free))
164411bf0794Smrg			from = X_CONFIG;
164511bf0794Smrg		xf86DrvMsg(pScrn->scrnIndex, from, "TearFree property default: %s\n",
164611bf0794Smrg			   info->tear_free == 2 ? "auto" : (info->tear_free ? "on" : "off"));
1647d6c0b56eSmrg
1648d6c0b56eSmrg		info->shadow_primary =
1649d6c0b56eSmrg			xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE);
1650d6c0b56eSmrg
1651d6c0b56eSmrg		if (info->shadow_primary)
1652d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowPrimary enabled\n");
165390f2b693Smrg
165490f2b693Smrg		if (!pScrn->is_gpu) {
165590f2b693Smrg			from = xf86GetOptValBool(info->Options, OPTION_VARIABLE_REFRESH,
165690f2b693Smrg						 &info->vrr_support) ? X_CONFIG : X_DEFAULT;
165790f2b693Smrg
165890f2b693Smrg			xf86DrvMsg(pScrn->scrnIndex, from, "VariableRefresh: %sabled\n",
165990f2b693Smrg				   info->vrr_support ? "en" : "dis");
1660e49c54bcSmrg
1661e49c54bcSmrg			info->async_flip_secondaries = FALSE;
1662e49c54bcSmrg			from = xf86GetOptValBool(info->Options, OPTION_ASYNC_FLIP_SECONDARIES,
1663e49c54bcSmrg						 &info->async_flip_secondaries) ? X_CONFIG : X_DEFAULT;
1664e49c54bcSmrg
1665e49c54bcSmrg			xf86DrvMsg(pScrn->scrnIndex, from, "AsyncFlipSecondaries: %sabled\n",
1666e49c54bcSmrg				   info->async_flip_secondaries ? "en" : "dis");
166790f2b693Smrg		}
1668d6c0b56eSmrg	}
1669d6c0b56eSmrg
167024b90cf4Smrg	if (!pScrn->is_gpu) {
167111bf0794Smrg		info->allowPageFlip = xf86ReturnOptValBool(info->Options,
167211bf0794Smrg							   OPTION_PAGE_FLIP,
167311bf0794Smrg							   TRUE);
167477d6d1ecSmrg		if (info->shadow_primary) {
167511bf0794Smrg			xf86DrvMsg(pScrn->scrnIndex,
167611bf0794Smrg				   info->allowPageFlip ? X_WARNING : X_DEFAULT,
167711bf0794Smrg				   "KMS Pageflipping: disabled%s\n",
167811bf0794Smrg				   info->allowPageFlip ?
167977d6d1ecSmrg				   " because of ShadowPrimary" : "");
168011bf0794Smrg			info->allowPageFlip = FALSE;
168111bf0794Smrg		} else {
168211bf0794Smrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
168311bf0794Smrg				   "KMS Pageflipping: %sabled\n",
168411bf0794Smrg				   info->allowPageFlip ? "en" : "dis");
168511bf0794Smrg		}
1686d6c0b56eSmrg	}
1687d6c0b56eSmrg
1688d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_DELETE_DP12, FALSE)) {
1689d6c0b56eSmrg		info->drmmode.delete_dp_12_displays = TRUE;
1690d6c0b56eSmrg	}
1691d6c0b56eSmrg
1692d6c0b56eSmrg	if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) ==
1693d6c0b56eSmrg	    FALSE) {
1694d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1695d6c0b56eSmrg			   "Kernel modesetting setup failed\n");
169624b90cf4Smrg		return FALSE;
1697d6c0b56eSmrg	}
1698d6c0b56eSmrg
1699504d986fSmrg	AMDGPUSetupCapabilities(pScrn);
1700504d986fSmrg
1701d6c0b56eSmrg	if (info->drmmode.count_crtcs == 1)
1702d6c0b56eSmrg		pAMDGPUEnt->HasCRTC2 = FALSE;
1703d6c0b56eSmrg	else
1704d6c0b56eSmrg		pAMDGPUEnt->HasCRTC2 = TRUE;
1705d6c0b56eSmrg
1706e49c54bcSmrg	amdgpu_determine_cursor_size(pAMDGPUEnt->fd, info);
1707d6c0b56eSmrg
1708d6c0b56eSmrg	amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_GTT,
1709d6c0b56eSmrg				&heap_size, &max_allocation);
1710d6c0b56eSmrg	info->gart_size = heap_size;
1711d6c0b56eSmrg	amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_VRAM,
1712d6c0b56eSmrg				&heap_size, &max_allocation);
1713d6c0b56eSmrg	info->vram_size = max_allocation;
1714d6c0b56eSmrg
1715d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1716d6c0b56eSmrg		   "mem size init: gart size :%llx vram size: s:%llx visible:%llx\n",
1717d6c0b56eSmrg		   (unsigned long long)info->gart_size,
1718d6c0b56eSmrg		   (unsigned long long)heap_size,
1719d6c0b56eSmrg		   (unsigned long long)max_allocation);
1720d6c0b56eSmrg
1721d6c0b56eSmrg	cpp = pScrn->bitsPerPixel / 8;
1722d6c0b56eSmrg	pScrn->displayWidth =
1723d6c0b56eSmrg	    AMDGPU_ALIGN(pScrn->virtualX, drmmode_get_pitch_align(pScrn, cpp));
1724d6c0b56eSmrg
1725d6c0b56eSmrg	/* Set display resolution */
1726d6c0b56eSmrg	xf86SetDpi(pScrn, 0, 0);
1727d6c0b56eSmrg
1728d6c0b56eSmrg	if (!xf86SetGamma(pScrn, zeros))
1729d6c0b56eSmrg		return FALSE;
1730d6c0b56eSmrg
1731d6c0b56eSmrg	if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
1732d6c0b56eSmrg		if (!xf86LoadSubModule(pScrn, "ramdac"))
1733d6c0b56eSmrg			return FALSE;
1734d6c0b56eSmrg	}
1735d6c0b56eSmrg
173635d5b7c7Smrg	if (!pScrn->modes
1737d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS
1738d6c0b56eSmrg	    && !pScrn->is_gpu
1739d6c0b56eSmrg#endif
1740d6c0b56eSmrg	    ) {
1741d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
174224b90cf4Smrg		return FALSE;
1743d6c0b56eSmrg	}
1744d6c0b56eSmrg
1745d6c0b56eSmrg	return TRUE;
1746d6c0b56eSmrg}
1747d6c0b56eSmrg
1748d6c0b56eSmrgstatic Bool AMDGPUCursorInit_KMS(ScreenPtr pScreen)
1749d6c0b56eSmrg{
1750d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1751d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1752d6c0b56eSmrg
175324b90cf4Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
175424b90cf4Smrg		       "Initializing Cursor\n");
175524b90cf4Smrg
175624b90cf4Smrg	/* Set Silken Mouse */
175724b90cf4Smrg	xf86SetSilkenMouse(pScreen);
175824b90cf4Smrg
175924b90cf4Smrg	/* Cursor setup */
176024b90cf4Smrg	miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
176124b90cf4Smrg
176224b90cf4Smrg	if (info->allowPageFlip) {
176324b90cf4Smrg		miPointerScreenPtr PointPriv =
176424b90cf4Smrg			dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
176524b90cf4Smrg
176624b90cf4Smrg		if (!dixRegisterScreenPrivateKey(&amdgpu_device_private_key, pScreen,
176724b90cf4Smrg						 PRIVATE_DEVICE,
176824b90cf4Smrg						 sizeof(struct amdgpu_device_priv))) {
176924b90cf4Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "dixRegisterScreenPrivateKey failed\n");
177024b90cf4Smrg			return FALSE;
177124b90cf4Smrg		}
177224b90cf4Smrg
177335d5b7c7Smrg		info->SpriteFuncs = PointPriv->spriteFuncs;
177435d5b7c7Smrg		PointPriv->spriteFuncs = &drmmode_sprite_funcs;
177524b90cf4Smrg	}
177624b90cf4Smrg
177724b90cf4Smrg	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
177824b90cf4Smrg		return TRUE;
177924b90cf4Smrg
178024b90cf4Smrg	if (!xf86_cursors_init(pScreen, info->cursor_w, info->cursor_h,
178124b90cf4Smrg			       HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
178224b90cf4Smrg			       HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
178324b90cf4Smrg			       HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
178424b90cf4Smrg			       HARDWARE_CURSOR_UPDATE_UNHIDDEN |
178524b90cf4Smrg			       HARDWARE_CURSOR_ARGB)) {
178624b90cf4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86_cursors_init failed\n");
178724b90cf4Smrg		return FALSE;
178824b90cf4Smrg	}
178924b90cf4Smrg
179024b90cf4Smrg	return TRUE;
1791d6c0b56eSmrg}
1792d6c0b56eSmrg
1793d6c0b56eSmrgvoid AMDGPUBlank(ScrnInfoPtr pScrn)
1794d6c0b56eSmrg{
1795d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1796d6c0b56eSmrg	xf86OutputPtr output;
1797d6c0b56eSmrg	xf86CrtcPtr crtc;
1798d6c0b56eSmrg	int o, c;
1799d6c0b56eSmrg
1800d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
1801d6c0b56eSmrg		crtc = xf86_config->crtc[c];
1802d6c0b56eSmrg		for (o = 0; o < xf86_config->num_output; o++) {
1803d6c0b56eSmrg			output = xf86_config->output[o];
1804d6c0b56eSmrg			if (output->crtc != crtc)
1805d6c0b56eSmrg				continue;
1806d6c0b56eSmrg
1807d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOff);
1808d6c0b56eSmrg		}
1809d6c0b56eSmrg		crtc->funcs->dpms(crtc, DPMSModeOff);
1810d6c0b56eSmrg	}
1811d6c0b56eSmrg}
1812d6c0b56eSmrg
1813d6c0b56eSmrgvoid AMDGPUUnblank(ScrnInfoPtr pScrn)
1814d6c0b56eSmrg{
1815d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1816d6c0b56eSmrg	xf86OutputPtr output;
1817d6c0b56eSmrg	xf86CrtcPtr crtc;
1818d6c0b56eSmrg	int o, c;
1819d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
1820d6c0b56eSmrg		crtc = xf86_config->crtc[c];
1821d6c0b56eSmrg		if (!crtc->enabled)
1822d6c0b56eSmrg			continue;
1823d6c0b56eSmrg		crtc->funcs->dpms(crtc, DPMSModeOn);
1824d6c0b56eSmrg		for (o = 0; o < xf86_config->num_output; o++) {
1825d6c0b56eSmrg			output = xf86_config->output[o];
1826d6c0b56eSmrg			if (output->crtc != crtc)
1827d6c0b56eSmrg				continue;
1828d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOn);
1829d6c0b56eSmrg		}
1830d6c0b56eSmrg	}
1831d6c0b56eSmrg}
1832d6c0b56eSmrg
1833d6c0b56eSmrgstatic Bool amdgpu_set_drm_master(ScrnInfoPtr pScrn)
1834d6c0b56eSmrg{
1835d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1836d6c0b56eSmrg	int err;
1837d6c0b56eSmrg
1838d6c0b56eSmrg#ifdef XF86_PDEV_SERVER_FD
1839d6c0b56eSmrg	if (pAMDGPUEnt->platform_dev &&
1840d6c0b56eSmrg	    (pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
1841d6c0b56eSmrg		return TRUE;
1842d6c0b56eSmrg#endif
1843d6c0b56eSmrg
1844d6c0b56eSmrg	err = drmSetMaster(pAMDGPUEnt->fd);
1845d6c0b56eSmrg	if (err)
1846d6c0b56eSmrg		ErrorF("Unable to retrieve master\n");
1847d6c0b56eSmrg
1848d6c0b56eSmrg	return err == 0;
1849d6c0b56eSmrg}
1850d6c0b56eSmrg
1851d6c0b56eSmrgstatic void amdgpu_drop_drm_master(ScrnInfoPtr pScrn)
1852d6c0b56eSmrg{
1853d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1854d6c0b56eSmrg
1855d6c0b56eSmrg#ifdef XF86_PDEV_SERVER_FD
1856d6c0b56eSmrg	if (pAMDGPUEnt->platform_dev &&
1857d6c0b56eSmrg	    (pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
1858d6c0b56eSmrg		return;
1859d6c0b56eSmrg#endif
1860d6c0b56eSmrg
1861d6c0b56eSmrg	drmDropMaster(pAMDGPUEnt->fd);
1862d6c0b56eSmrg}
1863d6c0b56eSmrg
1864d6c0b56eSmrg
186524b90cf4Smrgstatic
186624b90cf4SmrgCARD32 cleanup_black_fb(OsTimerPtr timer, CARD32 now, pointer data)
186724b90cf4Smrg{
186824b90cf4Smrg	ScreenPtr screen = data;
186924b90cf4Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
187024b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
187124b90cf4Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
187224b90cf4Smrg	int c;
187324b90cf4Smrg
187446845023Smrg	if (xf86ScreenToScrn(amdgpu_primary_screen(screen))->vtSema)
187524b90cf4Smrg		return 0;
187624b90cf4Smrg
187724b90cf4Smrg	/* Unreference the all-black FB created by AMDGPULeaveVT_KMS. After
187824b90cf4Smrg	 * this, there should be no FB left created by this driver.
187924b90cf4Smrg	 */
188024b90cf4Smrg	for (c = 0; c < xf86_config->num_crtc; c++) {
188124b90cf4Smrg		drmmode_crtc_private_ptr drmmode_crtc =
188224b90cf4Smrg			xf86_config->crtc[c]->driver_private;
188324b90cf4Smrg
188424b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL);
188524b90cf4Smrg	}
188624b90cf4Smrg
188724b90cf4Smrg	TimerFree(timer);
188824b90cf4Smrg	return 0;
188924b90cf4Smrg}
1890d6c0b56eSmrg
1891d6c0b56eSmrgstatic Bool AMDGPUSaveScreen_KMS(ScreenPtr pScreen, int mode)
1892d6c0b56eSmrg{
1893d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1894d6c0b56eSmrg	Bool unblank;
1895d6c0b56eSmrg
1896d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1897d6c0b56eSmrg		       "AMDGPUSaveScreen(%d)\n", mode);
1898d6c0b56eSmrg
1899d6c0b56eSmrg	unblank = xf86IsUnblank(mode);
1900d6c0b56eSmrg	if (unblank)
1901d6c0b56eSmrg		SetTimeSinceLastInputEvent();
1902d6c0b56eSmrg
1903d6c0b56eSmrg	if ((pScrn != NULL) && pScrn->vtSema) {
1904d6c0b56eSmrg		if (unblank)
1905d6c0b56eSmrg			AMDGPUUnblank(pScrn);
1906d6c0b56eSmrg		else
1907d6c0b56eSmrg			AMDGPUBlank(pScrn);
1908d6c0b56eSmrg	}
1909d6c0b56eSmrg	return TRUE;
1910d6c0b56eSmrg}
1911d6c0b56eSmrg
1912d6c0b56eSmrg/* Called at the end of each server generation.  Restore the original
1913d6c0b56eSmrg * text mode, unmap video memory, and unwrap and call the saved
1914d6c0b56eSmrg * CloseScreen function.
1915d6c0b56eSmrg */
191624b90cf4Smrgstatic Bool AMDGPUCloseScreen_KMS(ScreenPtr pScreen)
1917d6c0b56eSmrg{
1918d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1919d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1920d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1921d6c0b56eSmrg
1922d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1923d6c0b56eSmrg		       "AMDGPUCloseScreen\n");
1924d6c0b56eSmrg
1925d6c0b56eSmrg	/* Clear mask of assigned crtc's in this generation */
1926d6c0b56eSmrg	pAMDGPUEnt->assigned_crtcs = 0;
1927d6c0b56eSmrg
1928d6c0b56eSmrg	drmmode_uevent_fini(pScrn, &info->drmmode);
1929d6c0b56eSmrg	amdgpu_drm_queue_close(pScrn);
1930d6c0b56eSmrg
1931504d986fSmrg	if (info->callback_event_type != -1) {
1932504d986fSmrg		DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn);
1933504d986fSmrg		DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
1934504d986fSmrg	}
1935d6c0b56eSmrg
1936d6c0b56eSmrg	amdgpu_sync_close(pScreen);
1937d6c0b56eSmrg	amdgpu_drop_drm_master(pScrn);
1938d6c0b56eSmrg
1939d6c0b56eSmrg	drmmode_fini(pScrn, &info->drmmode);
1940d6c0b56eSmrg	if (info->dri2.enabled) {
1941d6c0b56eSmrg		amdgpu_dri2_close_screen(pScreen);
1942d6c0b56eSmrg	}
1943d6c0b56eSmrg	amdgpu_glamor_fini(pScreen);
1944d6c0b56eSmrg	pScrn->vtSema = FALSE;
1945d6c0b56eSmrg	xf86ClearPrimInitDone(info->pEnt->index);
194624b90cf4Smrg
194724b90cf4Smrg	if (info->allowPageFlip) {
194824b90cf4Smrg		miPointerScreenPtr PointPriv =
194924b90cf4Smrg			dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
195024b90cf4Smrg
195135d5b7c7Smrg		if (PointPriv->spriteFuncs == &drmmode_sprite_funcs)
195235d5b7c7Smrg			PointPriv->spriteFuncs = info->SpriteFuncs;
195324b90cf4Smrg	}
195424b90cf4Smrg
1955d6c0b56eSmrg	pScreen->BlockHandler = info->BlockHandler;
1956d6c0b56eSmrg	pScreen->CloseScreen = info->CloseScreen;
195724b90cf4Smrg	return pScreen->CloseScreen(pScreen);
1958d6c0b56eSmrg}
1959d6c0b56eSmrg
196024b90cf4Smrgvoid AMDGPUFreeScreen_KMS(ScrnInfoPtr pScrn)
1961d6c0b56eSmrg{
1962d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1963d6c0b56eSmrg		       "AMDGPUFreeScreen\n");
1964d6c0b56eSmrg
1965d6c0b56eSmrg	AMDGPUFreeRec(pScrn);
1966d6c0b56eSmrg}
1967d6c0b56eSmrg
196824b90cf4SmrgBool AMDGPUScreenInit_KMS(ScreenPtr pScreen, int argc, char **argv)
1969d6c0b56eSmrg{
1970d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1971d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1972d6c0b56eSmrg	int subPixelOrder = SubPixelUnknown;
1973d6c0b56eSmrg	MessageType from;
1974d6c0b56eSmrg	Bool value;
1975d6c0b56eSmrg	int driLevel;
1976d6c0b56eSmrg	const char *s;
1977d6c0b56eSmrg	void *front_ptr;
1978d6c0b56eSmrg
1979d6c0b56eSmrg	pScrn->fbOffset = 0;
1980d6c0b56eSmrg
1981d6c0b56eSmrg	miClearVisualTypes();
1982d6c0b56eSmrg	if (!miSetVisualTypes(pScrn->depth,
1983d6c0b56eSmrg			      miGetDefaultVisualMask(pScrn->depth),
1984d6c0b56eSmrg			      pScrn->rgbBits, pScrn->defaultVisual))
1985d6c0b56eSmrg		return FALSE;
1986d6c0b56eSmrg	miSetPixmapDepths();
1987d6c0b56eSmrg
1988d6c0b56eSmrg	if (!amdgpu_set_drm_master(pScrn))
1989d6c0b56eSmrg		return FALSE;
1990d6c0b56eSmrg
1991d6c0b56eSmrg	info->directRenderingEnabled = FALSE;
1992d6c0b56eSmrg	if (info->shadow_fb == FALSE)
1993d6c0b56eSmrg		info->directRenderingEnabled = amdgpu_dri2_screen_init(pScreen);
1994d6c0b56eSmrg
1995d6c0b56eSmrg	if (!amdgpu_setup_kernel_mem(pScreen)) {
1996d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1997d6c0b56eSmrg			   "amdgpu_setup_kernel_mem failed\n");
1998d6c0b56eSmrg		return FALSE;
1999d6c0b56eSmrg	}
2000d6c0b56eSmrg	front_ptr = info->front_buffer->cpu_ptr;
2001d6c0b56eSmrg
2002d6c0b56eSmrg	if (info->shadow_fb) {
2003d6c0b56eSmrg		info->fb_shadow = calloc(1,
2004d6c0b56eSmrg					 pScrn->displayWidth * pScrn->virtualY *
2005d6c0b56eSmrg					 ((pScrn->bitsPerPixel + 7) >> 3));
200635d5b7c7Smrg		if (!info->fb_shadow) {
2007d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2008d6c0b56eSmrg				   "Failed to allocate shadow framebuffer\n");
200924b90cf4Smrg			return FALSE;
2010d6c0b56eSmrg		} else {
2011d6c0b56eSmrg			if (!fbScreenInit(pScreen, info->fb_shadow,
2012d6c0b56eSmrg					  pScrn->virtualX, pScrn->virtualY,
2013d6c0b56eSmrg					  pScrn->xDpi, pScrn->yDpi,
2014d6c0b56eSmrg					  pScrn->displayWidth,
2015d6c0b56eSmrg					  pScrn->bitsPerPixel))
2016d6c0b56eSmrg				return FALSE;
2017d6c0b56eSmrg		}
2018d6c0b56eSmrg	}
2019d6c0b56eSmrg
2020d6c0b56eSmrg	if (info->shadow_fb == FALSE) {
2021d6c0b56eSmrg		/* Init fb layer */
2022d6c0b56eSmrg		if (!fbScreenInit(pScreen, front_ptr,
2023d6c0b56eSmrg				  pScrn->virtualX, pScrn->virtualY,
2024d6c0b56eSmrg				  pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,
2025d6c0b56eSmrg				  pScrn->bitsPerPixel))
2026d6c0b56eSmrg			return FALSE;
2027d6c0b56eSmrg	}
2028d6c0b56eSmrg
2029d6c0b56eSmrg	xf86SetBlackWhitePixels(pScreen);
2030d6c0b56eSmrg
2031d6c0b56eSmrg	if (pScrn->bitsPerPixel > 8) {
2032d6c0b56eSmrg		VisualPtr visual;
2033d6c0b56eSmrg
2034d6c0b56eSmrg		visual = pScreen->visuals + pScreen->numVisuals;
2035d6c0b56eSmrg		while (--visual >= pScreen->visuals) {
2036d6c0b56eSmrg			if ((visual->class | DynamicClass) == DirectColor) {
2037d6c0b56eSmrg				visual->offsetRed = pScrn->offset.red;
2038d6c0b56eSmrg				visual->offsetGreen = pScrn->offset.green;
2039d6c0b56eSmrg				visual->offsetBlue = pScrn->offset.blue;
2040d6c0b56eSmrg				visual->redMask = pScrn->mask.red;
2041d6c0b56eSmrg				visual->greenMask = pScrn->mask.green;
2042d6c0b56eSmrg				visual->blueMask = pScrn->mask.blue;
2043d6c0b56eSmrg			}
2044d6c0b56eSmrg		}
2045d6c0b56eSmrg	}
2046d6c0b56eSmrg
2047d6c0b56eSmrg	/* Must be after RGB order fixed */
2048d6c0b56eSmrg	fbPictureInit(pScreen, 0, 0);
2049d6c0b56eSmrg
2050d6c0b56eSmrg#ifdef RENDER
2051d6c0b56eSmrg	if ((s = xf86GetOptValString(info->Options, OPTION_SUBPIXEL_ORDER))) {
2052d6c0b56eSmrg		if (strcmp(s, "RGB") == 0)
2053d6c0b56eSmrg			subPixelOrder = SubPixelHorizontalRGB;
2054d6c0b56eSmrg		else if (strcmp(s, "BGR") == 0)
2055d6c0b56eSmrg			subPixelOrder = SubPixelHorizontalBGR;
2056d6c0b56eSmrg		else if (strcmp(s, "NONE") == 0)
2057d6c0b56eSmrg			subPixelOrder = SubPixelNone;
2058d6c0b56eSmrg		PictureSetSubpixelOrder(pScreen, subPixelOrder);
2059d6c0b56eSmrg	}
2060d6c0b56eSmrg#endif
2061d6c0b56eSmrg
2062e49c54bcSmrg	if (xorgGetVersion() >= XORG_VERSION_NUMERIC(1,18,3,0,0))
2063e49c54bcSmrg		value = info->use_glamor;
2064e49c54bcSmrg	else
2065e49c54bcSmrg		value = FALSE;
2066e49c54bcSmrg	from = X_DEFAULT;
2067d6c0b56eSmrg
2068e49c54bcSmrg	if (info->use_glamor) {
2069e49c54bcSmrg		if (xf86GetOptValBool(info->Options, OPTION_DRI3, &value))
2070e49c54bcSmrg			from = X_CONFIG;
2071d6c0b56eSmrg
2072e49c54bcSmrg		if (xf86GetOptValInteger(info->Options, OPTION_DRI, &driLevel) &&
2073e49c54bcSmrg				(driLevel == 2 || driLevel == 3)) {
2074e49c54bcSmrg			from = X_CONFIG;
2075e49c54bcSmrg			value = driLevel == 3;
2076d6c0b56eSmrg		}
2077e49c54bcSmrg	}
2078d6c0b56eSmrg
2079e49c54bcSmrg	if (value) {
2080e49c54bcSmrg		value = amdgpu_sync_init(pScreen) &&
2081e49c54bcSmrg			amdgpu_present_screen_init(pScreen) &&
2082e49c54bcSmrg			amdgpu_dri3_screen_init(pScreen);
2083d6c0b56eSmrg
2084e49c54bcSmrg		if (!value)
2085e49c54bcSmrg			from = X_WARNING;
208611bf0794Smrg	}
2087d6c0b56eSmrg
2088e49c54bcSmrg	xf86DrvMsg(pScrn->scrnIndex, from, "DRI3 %sabled\n", value ? "en" : "dis");
2089e49c54bcSmrg
2090d6c0b56eSmrg	pScrn->vtSema = TRUE;
2091d6c0b56eSmrg	xf86SetBackingStore(pScreen);
2092d6c0b56eSmrg
2093d6c0b56eSmrg	if (info->directRenderingEnabled) {
2094d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2095d6c0b56eSmrg			   "Direct rendering enabled\n");
2096d6c0b56eSmrg	} else {
2097d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2098d6c0b56eSmrg			   "Direct rendering disabled\n");
2099d6c0b56eSmrg	}
2100d6c0b56eSmrg
2101d6c0b56eSmrg	if (info->use_glamor && info->directRenderingEnabled) {
2102d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2103d6c0b56eSmrg			       "Initializing Acceleration\n");
2104d6c0b56eSmrg		if (amdgpu_glamor_init(pScreen)) {
2105d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2106d6c0b56eSmrg				   "Acceleration enabled\n");
2107d6c0b56eSmrg		} else {
2108d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2109d6c0b56eSmrg				   "Acceleration initialization failed\n");
2110d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2111d6c0b56eSmrg				   "2D and 3D acceleration disabled\n");
2112d6c0b56eSmrg			info->use_glamor = FALSE;
2113d6c0b56eSmrg		}
2114d6c0b56eSmrg	} else if (info->directRenderingEnabled) {
2115d6c0b56eSmrg		if (!amdgpu_pixmap_init(pScreen))
2116d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D acceleration disabled\n");
2117d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration disabled\n");
2118d6c0b56eSmrg	} else {
211924b90cf4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D and 3D acceleration disabled\n");
2120d6c0b56eSmrg	}
2121d6c0b56eSmrg
2122d6c0b56eSmrg	/* Init DPMS */
2123d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2124d6c0b56eSmrg		       "Initializing DPMS\n");
2125d6c0b56eSmrg	xf86DPMSInit(pScreen, xf86DPMSSet, 0);
2126d6c0b56eSmrg
212724b90cf4Smrg	if (!AMDGPUCursorInit_KMS(pScreen))
212824b90cf4Smrg		return FALSE;
2129d6c0b56eSmrg
2130d6c0b56eSmrg	/* DGA setup */
2131d6c0b56eSmrg#ifdef XFreeXDGA
2132d6c0b56eSmrg	/* DGA is dangerous on kms as the base and framebuffer location may change:
2133d6c0b56eSmrg	 * http://lists.freedesktop.org/archives/xorg-devel/2009-September/002113.html
2134d6c0b56eSmrg	 */
2135d6c0b56eSmrg	/* xf86DiDGAInit(pScreen, info->LinearAddr + pScrn->fbOffset); */
2136d6c0b56eSmrg#endif
213724b90cf4Smrg	if (info->shadow_fb == FALSE && !pScreen->isGPU) {
2138d6c0b56eSmrg		/* Init Xv */
2139d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2140d6c0b56eSmrg			       "Initializing Xv\n");
2141d6c0b56eSmrg		AMDGPUInitVideo(pScreen);
2142d6c0b56eSmrg	}
2143d6c0b56eSmrg
2144d6c0b56eSmrg	if (info->shadow_fb == TRUE) {
2145d6c0b56eSmrg		if (!shadowSetup(pScreen)) {
2146d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2147d6c0b56eSmrg				   "Shadowfb initialization failed\n");
2148d6c0b56eSmrg			return FALSE;
2149d6c0b56eSmrg		}
2150d6c0b56eSmrg	}
2151d6c0b56eSmrg	pScrn->pScreen = pScreen;
2152d6c0b56eSmrg
215324b90cf4Smrg	if (!pScreen->isGPU) {
215411bf0794Smrg		if (serverGeneration == 1 && bgNoneRoot && info->use_glamor) {
215511bf0794Smrg			info->CreateWindow = pScreen->CreateWindow;
215611bf0794Smrg			pScreen->CreateWindow = AMDGPUCreateWindow_oneshot;
215711bf0794Smrg		}
215811bf0794Smrg		info->WindowExposures = pScreen->WindowExposures;
215911bf0794Smrg		pScreen->WindowExposures = AMDGPUWindowExposures_oneshot;
2160d6c0b56eSmrg	}
2161d6c0b56eSmrg
2162d6c0b56eSmrg	/* Provide SaveScreen & wrap BlockHandler and CloseScreen */
2163d6c0b56eSmrg	/* Wrap CloseScreen */
2164d6c0b56eSmrg	info->CloseScreen = pScreen->CloseScreen;
2165d6c0b56eSmrg	pScreen->CloseScreen = AMDGPUCloseScreen_KMS;
2166d6c0b56eSmrg	pScreen->SaveScreen = AMDGPUSaveScreen_KMS;
2167d6c0b56eSmrg	info->BlockHandler = pScreen->BlockHandler;
216811bf0794Smrg	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
2169d6c0b56eSmrg
2170d6c0b56eSmrg	info->CreateScreenResources = pScreen->CreateScreenResources;
2171d6c0b56eSmrg	pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS;
2172d6c0b56eSmrg
2173d6c0b56eSmrg	pScreen->StartPixmapTracking = PixmapStartDirtyTracking;
2174d6c0b56eSmrg	pScreen->StopPixmapTracking = PixmapStopDirtyTracking;
2175504d986fSmrg#if HAS_SYNC_SHARED_PIXMAP
2176504d986fSmrg	pScreen->SyncSharedPixmap = amdgpu_sync_shared_pixmap;
2177d6c0b56eSmrg#endif
2178d6c0b56eSmrg
2179d6c0b56eSmrg	if (!xf86CrtcScreenInit(pScreen))
2180d6c0b56eSmrg		return FALSE;
2181d6c0b56eSmrg
2182d6c0b56eSmrg	/* Wrap pointer motion to flip touch screen around */
2183d6c0b56eSmrg//    info->PointerMoved = pScrn->PointerMoved;
2184d6c0b56eSmrg//    pScrn->PointerMoved = AMDGPUPointerMoved;
2185d6c0b56eSmrg
2186d6c0b56eSmrg	if (!drmmode_setup_colormap(pScreen, pScrn))
2187d6c0b56eSmrg		return FALSE;
2188d6c0b56eSmrg
2189d6c0b56eSmrg	/* Note unused options */
2190d6c0b56eSmrg	if (serverGeneration == 1)
2191d6c0b56eSmrg		xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
2192d6c0b56eSmrg
219390f2b693Smrg	if (info->vrr_support) {
219490f2b693Smrg		if (!amdgpu_property_vectors_wrapped) {
219590f2b693Smrg			saved_change_property = ProcVector[X_ChangeProperty];
219690f2b693Smrg			ProcVector[X_ChangeProperty] = amdgpu_change_property;
219790f2b693Smrg			saved_delete_property = ProcVector[X_DeleteProperty];
219890f2b693Smrg			ProcVector[X_DeleteProperty] = amdgpu_delete_property;
219990f2b693Smrg			amdgpu_property_vectors_wrapped = TRUE;
220090f2b693Smrg		}
220190f2b693Smrg
220290f2b693Smrg		amdgpu_vrr_atom = MakeAtom("_VARIABLE_REFRESH",
220390f2b693Smrg					   strlen("_VARIABLE_REFRESH"), TRUE);
220490f2b693Smrg	}
220590f2b693Smrg
2206d6c0b56eSmrg	drmmode_init(pScrn, &info->drmmode);
2207d6c0b56eSmrg
2208d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2209d6c0b56eSmrg		       "AMDGPUScreenInit finished\n");
2210d6c0b56eSmrg
2211d6c0b56eSmrg	return TRUE;
2212d6c0b56eSmrg}
2213d6c0b56eSmrg
221424b90cf4SmrgBool AMDGPUEnterVT_KMS(ScrnInfoPtr pScrn)
2215d6c0b56eSmrg{
2216d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2217d6c0b56eSmrg
2218d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2219d6c0b56eSmrg		       "AMDGPUEnterVT_KMS\n");
2220d6c0b56eSmrg
2221d6c0b56eSmrg	amdgpu_set_drm_master(pScrn);
2222d6c0b56eSmrg
222324b90cf4Smrg	if (info->shadow_fb) {
222424b90cf4Smrg		int pitch;
222524b90cf4Smrg		struct amdgpu_buffer *front_buffer =
222624b90cf4Smrg			amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,
222724b90cf4Smrg					       pScrn->virtualY, pScrn->depth,
222846845023Smrg					       AMDGPU_CREATE_PIXMAP_SCANOUT |
222924b90cf4Smrg					       AMDGPU_CREATE_PIXMAP_LINEAR,
223024b90cf4Smrg					       pScrn->bitsPerPixel,
223124b90cf4Smrg					       &pitch);
223224b90cf4Smrg
223324b90cf4Smrg		if (front_buffer) {
223424b90cf4Smrg			if (amdgpu_bo_map(pScrn, front_buffer) == 0) {
223524b90cf4Smrg				memset(front_buffer->cpu_ptr, 0, pitch * pScrn->virtualY);
223624b90cf4Smrg				amdgpu_bo_unref(&info->front_buffer);
223724b90cf4Smrg				info->front_buffer = front_buffer;
223824b90cf4Smrg			} else {
223924b90cf4Smrg				amdgpu_bo_unref(&front_buffer);
224024b90cf4Smrg				front_buffer = NULL;
224124b90cf4Smrg			}
224224b90cf4Smrg		}
224324b90cf4Smrg
224424b90cf4Smrg		if (!front_buffer) {
224524b90cf4Smrg			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
224624b90cf4Smrg				   "Failed to allocate new scanout BO after VT switch, "
224724b90cf4Smrg				   "other DRM masters may see screen contents\n");
224824b90cf4Smrg		}
224924b90cf4Smrg	}
225024b90cf4Smrg
2251d6c0b56eSmrg	pScrn->vtSema = TRUE;
2252d6c0b56eSmrg
2253d6c0b56eSmrg	if (!drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE))
2254d6c0b56eSmrg		return FALSE;
2255d6c0b56eSmrg
2256d6c0b56eSmrg	return TRUE;
2257d6c0b56eSmrg}
2258d6c0b56eSmrg
225924b90cf4Smrgstatic void
226077d6d1ecSmrgpixmap_unref_fb(PixmapPtr pixmap)
226124b90cf4Smrg{
226277d6d1ecSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(pixmap->drawable.pScreen);
226324b90cf4Smrg	struct drmmode_fb **fb_ptr = amdgpu_pixmap_get_fb_ptr(pixmap);
226477d6d1ecSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
226524b90cf4Smrg
226624b90cf4Smrg	if (fb_ptr)
226724b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, fb_ptr, NULL);
226824b90cf4Smrg}
226924b90cf4Smrg
227077d6d1ecSmrgstatic void
227177d6d1ecSmrgclient_pixmap_unref_fb(void *value, XID id, void *pScreen)
227277d6d1ecSmrg{
227377d6d1ecSmrg	PixmapPtr pixmap = value;
227477d6d1ecSmrg
227577d6d1ecSmrg	if (pixmap->drawable.pScreen == pScreen)
227677d6d1ecSmrg		pixmap_unref_fb(pixmap);
227777d6d1ecSmrg}
227877d6d1ecSmrg
227924b90cf4Smrgvoid AMDGPULeaveVT_KMS(ScrnInfoPtr pScrn)
2280d6c0b56eSmrg{
228124b90cf4Smrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
228224b90cf4Smrg	ScreenPtr pScreen = pScrn->pScreen;
2283d6c0b56eSmrg
2284d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2285d6c0b56eSmrg		       "AMDGPULeaveVT_KMS\n");
2286d6c0b56eSmrg
228724b90cf4Smrg	if (!info->shadow_fb) {
228824b90cf4Smrg		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
228924b90cf4Smrg		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
229024b90cf4Smrg		xf86CrtcPtr crtc;
229124b90cf4Smrg		drmmode_crtc_private_ptr drmmode_crtc;
229224b90cf4Smrg		unsigned w = 0, h = 0;
229324b90cf4Smrg		int i;
229424b90cf4Smrg
229577d6d1ecSmrg		/* If we're called from CloseScreen, trying to clear the black
229677d6d1ecSmrg		 * scanout BO will likely crash and burn
229777d6d1ecSmrg		 */
229877d6d1ecSmrg		if (!pScreen->GCperDepth[0])
229977d6d1ecSmrg			goto hide_cursors;
230077d6d1ecSmrg
230124b90cf4Smrg		/* Compute maximum scanout dimensions of active CRTCs */
230224b90cf4Smrg		for (i = 0; i < xf86_config->num_crtc; i++) {
230324b90cf4Smrg			crtc = xf86_config->crtc[i];
230424b90cf4Smrg			drmmode_crtc = crtc->driver_private;
230524b90cf4Smrg
230624b90cf4Smrg			if (!drmmode_crtc->fb)
230724b90cf4Smrg				continue;
230824b90cf4Smrg
230924b90cf4Smrg			w = max(w, crtc->mode.HDisplay);
231024b90cf4Smrg			h = max(h, crtc->mode.VDisplay);
231124b90cf4Smrg		}
2312d6c0b56eSmrg
231324b90cf4Smrg		/* Make all active CRTCs scan out from an all-black framebuffer */
231424b90cf4Smrg		if (w > 0 && h > 0) {
231546845023Smrg			PixmapPtr black_scanout =
231646845023Smrg				pScreen->CreatePixmap(pScreen, w, h, pScrn->depth,
231746845023Smrg						      AMDGPU_CREATE_PIXMAP_SCANOUT);
231846845023Smrg
231946845023Smrg			if (black_scanout) {
232024b90cf4Smrg				struct drmmode_fb *black_fb =
232146845023Smrg					amdgpu_pixmap_get_fb(black_scanout);
232224b90cf4Smrg
232346845023Smrg				amdgpu_pixmap_clear(black_scanout);
232424b90cf4Smrg				amdgpu_glamor_finish(pScrn);
232524b90cf4Smrg
232624b90cf4Smrg				for (i = 0; i < xf86_config->num_crtc; i++) {
232724b90cf4Smrg					crtc = xf86_config->crtc[i];
232824b90cf4Smrg					drmmode_crtc = crtc->driver_private;
232924b90cf4Smrg
233024b90cf4Smrg					if (drmmode_crtc->fb) {
233124b90cf4Smrg						if (black_fb) {
233224b90cf4Smrg							drmmode_set_mode(crtc, black_fb, &crtc->mode, 0, 0);
233324b90cf4Smrg						} else {
233424b90cf4Smrg							drmModeSetCrtc(pAMDGPUEnt->fd,
233524b90cf4Smrg								       drmmode_crtc->mode_crtc->crtc_id, 0,
233624b90cf4Smrg								       0, 0, NULL, 0, NULL);
233724b90cf4Smrg							drmmode_fb_reference(pAMDGPUEnt->fd,
233824b90cf4Smrg									     &drmmode_crtc->fb, NULL);
233924b90cf4Smrg						}
234024b90cf4Smrg
234124b90cf4Smrg						if (pScrn->is_gpu) {
234246845023Smrg							if (drmmode_crtc->scanout[0])
234346845023Smrg								pixmap_unref_fb(drmmode_crtc->scanout[0]);
234446845023Smrg							if (drmmode_crtc->scanout[1])
234546845023Smrg								pixmap_unref_fb(drmmode_crtc->scanout[1]);
234624b90cf4Smrg						} else {
234790f2b693Smrg							drmmode_crtc_scanout_free(crtc);
234824b90cf4Smrg						}
234924b90cf4Smrg					}
235024b90cf4Smrg				}
235146845023Smrg
235246845023Smrg				pScreen->DestroyPixmap(black_scanout);
235324b90cf4Smrg			}
235424b90cf4Smrg		}
235524b90cf4Smrg
235624b90cf4Smrg		xf86RotateFreeShadow(pScrn);
235724b90cf4Smrg
235824b90cf4Smrg		/* Unreference FBs of all pixmaps. After this, the only FB remaining
235924b90cf4Smrg		 * should be the all-black one being scanned out by active CRTCs
236024b90cf4Smrg		 */
236124b90cf4Smrg		for (i = 0; i < currentMaxClients; i++) {
236224b90cf4Smrg			if (i > 0 &&
236324b90cf4Smrg			    (!clients[i] || clients[i]->clientState != ClientStateRunning))
236424b90cf4Smrg				continue;
236524b90cf4Smrg
236677d6d1ecSmrg			FindClientResourcesByType(clients[i], RT_PIXMAP,
236777d6d1ecSmrg						  client_pixmap_unref_fb, pScreen);
236824b90cf4Smrg		}
236924b90cf4Smrg
237077d6d1ecSmrg		pixmap_unref_fb(pScreen->GetScreenPixmap(pScreen));
237124b90cf4Smrg	} else {
237224b90cf4Smrg		memset(info->front_buffer->cpu_ptr, 0, pScrn->virtualX *
237324b90cf4Smrg		       info->pixel_bytes * pScrn->virtualY);
237424b90cf4Smrg	}
237524b90cf4Smrg
237677d6d1ecSmrg	if (pScreen->GCperDepth[0])
237777d6d1ecSmrg		TimerSet(NULL, 0, 1000, cleanup_black_fb, pScreen);
2378d6c0b56eSmrg
237977d6d1ecSmrg hide_cursors:
2380d6c0b56eSmrg	xf86_hide_cursors(pScrn);
2381d6c0b56eSmrg
238224b90cf4Smrg	amdgpu_drop_drm_master(pScrn);
238324b90cf4Smrg
2384d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2385d6c0b56eSmrg		       "Ok, leaving now...\n");
2386d6c0b56eSmrg}
2387d6c0b56eSmrg
238824b90cf4SmrgBool AMDGPUSwitchMode_KMS(ScrnInfoPtr pScrn, DisplayModePtr mode)
2389d6c0b56eSmrg{
2390d6c0b56eSmrg	Bool ret;
2391d6c0b56eSmrg	ret = xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
2392d6c0b56eSmrg	return ret;
2393d6c0b56eSmrg
2394d6c0b56eSmrg}
2395d6c0b56eSmrg
239624b90cf4Smrgvoid AMDGPUAdjustFrame_KMS(ScrnInfoPtr pScrn, int x, int y)
2397d6c0b56eSmrg{
2398d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2399d6c0b56eSmrg	drmmode_adjust_frame(pScrn, &info->drmmode, x, y);
2400d6c0b56eSmrg	return;
2401d6c0b56eSmrg}
2402d6c0b56eSmrg
2403d6c0b56eSmrgstatic Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen)
2404d6c0b56eSmrg{
2405d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
240690f2b693Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2407d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2408d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2409d6c0b56eSmrg	int cpp = info->pixel_bytes;
2410d6c0b56eSmrg	int cursor_size;
241190f2b693Smrg	int c, i;
2412d6c0b56eSmrg
2413d6c0b56eSmrg	cursor_size = info->cursor_w * info->cursor_h * 4;
2414d6c0b56eSmrg	cursor_size = AMDGPU_ALIGN(cursor_size, AMDGPU_GPU_PAGE_SIZE);
2415d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
241690f2b693Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[c]->driver_private;
241790f2b693Smrg
241890f2b693Smrg		for (i = 0; i < 2; i++) {
241990f2b693Smrg			if (!drmmode_crtc->cursor_buffer[i]) {
242090f2b693Smrg				drmmode_crtc->cursor_buffer[i] =
242190f2b693Smrg					amdgpu_bo_open(pAMDGPUEnt->pDev,
242290f2b693Smrg						       cursor_size, 0,
242390f2b693Smrg						       AMDGPU_GEM_DOMAIN_VRAM);
242490f2b693Smrg
242590f2b693Smrg				if (!(drmmode_crtc->cursor_buffer[i])) {
2426d6c0b56eSmrg					ErrorF("Failed to allocate cursor buffer memory\n");
2427d6c0b56eSmrg					return FALSE;
2428d6c0b56eSmrg				}
2429d6c0b56eSmrg
243090f2b693Smrg				if (amdgpu_bo_cpu_map(drmmode_crtc->cursor_buffer[i]->bo.amdgpu,
243190f2b693Smrg						      &drmmode_crtc->cursor_buffer[i]->cpu_ptr))
2432d6c0b56eSmrg					ErrorF("Failed to map cursor buffer memory\n");
2433d6c0b56eSmrg			}
2434d6c0b56eSmrg		}
2435d6c0b56eSmrg	}
2436d6c0b56eSmrg
243735d5b7c7Smrg	if (!info->front_buffer) {
2438d6c0b56eSmrg		int pitch;
243946845023Smrg		int hint = AMDGPU_CREATE_PIXMAP_SCANOUT;
2440d6c0b56eSmrg
2441d6c0b56eSmrg		if (info->shadow_primary)
244246845023Smrg			hint |= AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
2443d6c0b56eSmrg		else if (!info->use_glamor)
244446845023Smrg			hint |= AMDGPU_CREATE_PIXMAP_LINEAR;
2445d6c0b56eSmrg
2446d6c0b56eSmrg		info->front_buffer =
2447d6c0b56eSmrg			amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,
2448d6c0b56eSmrg					       pScrn->virtualY, pScrn->depth,
2449d6c0b56eSmrg					       hint, pScrn->bitsPerPixel,
2450d6c0b56eSmrg					       &pitch);
2451d6c0b56eSmrg		if (!(info->front_buffer)) {
2452d6c0b56eSmrg			ErrorF("Failed to allocate front buffer memory\n");
2453d6c0b56eSmrg			return FALSE;
2454d6c0b56eSmrg		}
2455d6c0b56eSmrg
2456d6c0b56eSmrg		if (!info->use_glamor &&
2457d6c0b56eSmrg		    amdgpu_bo_map(pScrn, info->front_buffer) != 0) {
2458d6c0b56eSmrg			ErrorF("Failed to map front buffer memory\n");
2459d6c0b56eSmrg			return FALSE;
2460d6c0b56eSmrg		}
2461d6c0b56eSmrg
2462d6c0b56eSmrg		pScrn->displayWidth = pitch / cpp;
2463d6c0b56eSmrg	}
2464d6c0b56eSmrg
2465d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Front buffer pitch: %d bytes\n",
2466d6c0b56eSmrg		   pScrn->displayWidth * cpp);
2467d6c0b56eSmrg	return TRUE;
2468d6c0b56eSmrg}
2469d6c0b56eSmrg
2470d6c0b56eSmrg/* Used to disallow modes that are not supported by the hardware */
247124b90cf4SmrgModeStatus AMDGPUValidMode(ScrnInfoPtr pScrn, DisplayModePtr mode,
2472d6c0b56eSmrg			   Bool verbose, int flag)
2473d6c0b56eSmrg{
2474d6c0b56eSmrg	/* There are problems with double scan mode at high clocks
2475d6c0b56eSmrg	 * They're likely related PLL and display buffer settings.
2476d6c0b56eSmrg	 * Disable these modes for now.
2477d6c0b56eSmrg	 */
2478d6c0b56eSmrg	if (mode->Flags & V_DBLSCAN) {
2479d6c0b56eSmrg		if ((mode->CrtcHDisplay >= 1024) || (mode->CrtcVDisplay >= 768))
2480d6c0b56eSmrg			return MODE_CLOCK_RANGE;
2481d6c0b56eSmrg	}
2482d6c0b56eSmrg	return MODE_OK;
2483d6c0b56eSmrg}
2484