amdgpu_kms.c revision 90f2b693
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 },
90d6c0b56eSmrg	{-1, NULL, OPTV_NONE, {0}, FALSE}
91d6c0b56eSmrg};
92d6c0b56eSmrg
93d6c0b56eSmrgconst OptionInfoRec *AMDGPUOptionsWeak(void)
94d6c0b56eSmrg{
95d6c0b56eSmrg	return AMDGPUOptions_KMS;
96d6c0b56eSmrg}
97d6c0b56eSmrg
9890f2b693Smrgstatic inline struct amdgpu_window_priv *get_window_priv(WindowPtr win) {
9990f2b693Smrg	return dixLookupPrivate(&win->devPrivates, &amdgpu_window_private_key);
10090f2b693Smrg}
10190f2b693Smrg
10290f2b693Smrgstatic void
10390f2b693Smrgamdgpu_vrr_property_update(WindowPtr window, Bool variable_refresh)
10490f2b693Smrg{
10590f2b693Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(window->drawable.pScreen);
10690f2b693Smrg	AMDGPUInfoPtr info = AMDGPUPTR(scrn);
10790f2b693Smrg
10890f2b693Smrg	get_window_priv(window)->variable_refresh = variable_refresh;
10990f2b693Smrg
11090f2b693Smrg	if (info->flip_window == window &&
11190f2b693Smrg	    info->drmmode.present_flipping)
11290f2b693Smrg		amdgpu_present_set_screen_vrr(scrn, variable_refresh);
11390f2b693Smrg}
11490f2b693Smrg
11590f2b693Smrg/* Wrapper for xserver/dix/property.c:ProcChangeProperty */
11690f2b693Smrgstatic int
11790f2b693Smrgamdgpu_change_property(ClientPtr client)
11890f2b693Smrg{
11990f2b693Smrg	WindowPtr window;
12090f2b693Smrg	int ret;
12190f2b693Smrg
12290f2b693Smrg	REQUEST(xChangePropertyReq);
12390f2b693Smrg
12490f2b693Smrg	client->requestVector[X_ChangeProperty] = saved_change_property;
12590f2b693Smrg	ret = saved_change_property(client);
12690f2b693Smrg
12790f2b693Smrg	if (restore_property_vector)
12890f2b693Smrg		return ret;
12990f2b693Smrg
13090f2b693Smrg	client->requestVector[X_ChangeProperty] = amdgpu_change_property;
13190f2b693Smrg
13290f2b693Smrg	if (ret != Success)
13390f2b693Smrg		return ret;
13490f2b693Smrg
13590f2b693Smrg	ret = dixLookupWindow(&window, stuff->window, client, DixSetPropAccess);
13690f2b693Smrg	if (ret != Success)
13790f2b693Smrg		return ret;
13890f2b693Smrg
13990f2b693Smrg	if (stuff->property == amdgpu_vrr_atom &&
14090f2b693Smrg	    xf86ScreenToScrn(window->drawable.pScreen)->PreInit ==
14190f2b693Smrg	    AMDGPUPreInit_KMS && stuff->format == 32 && stuff->nUnits == 1) {
14290f2b693Smrg		uint32_t *value = (uint32_t*)(stuff + 1);
14390f2b693Smrg
14490f2b693Smrg		amdgpu_vrr_property_update(window, *value != 0);
14590f2b693Smrg	}
14690f2b693Smrg
14790f2b693Smrg	return ret;
14890f2b693Smrg}
14990f2b693Smrg
15090f2b693Smrg/* Wrapper for xserver/dix/property.c:ProcDeleteProperty */
15190f2b693Smrgstatic int
15290f2b693Smrgamdgpu_delete_property(ClientPtr client)
15390f2b693Smrg{
15490f2b693Smrg	WindowPtr window;
15590f2b693Smrg	int ret;
15690f2b693Smrg
15790f2b693Smrg	REQUEST(xDeletePropertyReq);
15890f2b693Smrg
15990f2b693Smrg	client->requestVector[X_DeleteProperty] = saved_delete_property;
16090f2b693Smrg	ret = saved_delete_property(client);
16190f2b693Smrg
16290f2b693Smrg	if (restore_property_vector)
16390f2b693Smrg		return ret;
16490f2b693Smrg
16590f2b693Smrg	client->requestVector[X_DeleteProperty] = amdgpu_delete_property;
16690f2b693Smrg
16790f2b693Smrg	if (ret != Success)
16890f2b693Smrg		return ret;
16990f2b693Smrg
17090f2b693Smrg	ret = dixLookupWindow(&window, stuff->window, client, DixSetPropAccess);
17190f2b693Smrg	if (ret != Success)
17290f2b693Smrg		return ret;
17390f2b693Smrg
17490f2b693Smrg	if (stuff->property == amdgpu_vrr_atom &&
17590f2b693Smrg	    xf86ScreenToScrn(window->drawable.pScreen)->PreInit ==
17690f2b693Smrg	    AMDGPUPreInit_KMS)
17790f2b693Smrg		amdgpu_vrr_property_update(window, FALSE);
17890f2b693Smrg
17990f2b693Smrg	return ret;
18090f2b693Smrg}
18190f2b693Smrg
18290f2b693Smrgstatic void
18390f2b693Smrgamdgpu_unwrap_property_requests(ScrnInfoPtr scrn)
18490f2b693Smrg{
18590f2b693Smrg	int i;
18690f2b693Smrg
18790f2b693Smrg	if (!amdgpu_property_vectors_wrapped)
18890f2b693Smrg		return;
18990f2b693Smrg
19090f2b693Smrg	if (ProcVector[X_ChangeProperty] == amdgpu_change_property)
19190f2b693Smrg		ProcVector[X_ChangeProperty] = saved_change_property;
19290f2b693Smrg	else
19390f2b693Smrg		restore_property_vector = TRUE;
19490f2b693Smrg
19590f2b693Smrg	if (ProcVector[X_DeleteProperty] == amdgpu_delete_property)
19690f2b693Smrg		ProcVector[X_DeleteProperty] = saved_delete_property;
19790f2b693Smrg	else
19890f2b693Smrg		restore_property_vector = TRUE;
19990f2b693Smrg
20090f2b693Smrg	for (i = 0; i < currentMaxClients; i++) {
20190f2b693Smrg		if (clients[i]->requestVector[X_ChangeProperty] ==
20290f2b693Smrg		    amdgpu_change_property) {
20390f2b693Smrg			clients[i]->requestVector[X_ChangeProperty] =
20490f2b693Smrg				saved_change_property;
20590f2b693Smrg		} else {
20690f2b693Smrg			restore_property_vector = TRUE;
20790f2b693Smrg		}
20890f2b693Smrg
20990f2b693Smrg		if (clients[i]->requestVector[X_DeleteProperty] ==
21090f2b693Smrg		    amdgpu_delete_property) {
21190f2b693Smrg			clients[i]->requestVector[X_DeleteProperty] =
21290f2b693Smrg				saved_delete_property;
21390f2b693Smrg		} else {
21490f2b693Smrg			restore_property_vector = TRUE;
21590f2b693Smrg		}
21690f2b693Smrg	}
21790f2b693Smrg
21890f2b693Smrg	if (restore_property_vector) {
21990f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
22090f2b693Smrg			   "Couldn't unwrap some window property request vectors\n");
22190f2b693Smrg	}
22290f2b693Smrg
22390f2b693Smrg	amdgpu_property_vectors_wrapped = FALSE;
22490f2b693Smrg}
22590f2b693Smrg
226d6c0b56eSmrgextern _X_EXPORT int gAMDGPUEntityIndex;
227d6c0b56eSmrg
228d6c0b56eSmrgstatic int getAMDGPUEntityIndex(void)
229d6c0b56eSmrg{
230d6c0b56eSmrg	return gAMDGPUEntityIndex;
231d6c0b56eSmrg}
232d6c0b56eSmrg
233d6c0b56eSmrgAMDGPUEntPtr AMDGPUEntPriv(ScrnInfoPtr pScrn)
234d6c0b56eSmrg{
235d6c0b56eSmrg	DevUnion *pPriv;
236d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
237d6c0b56eSmrg	pPriv = xf86GetEntityPrivate(info->pEnt->index, getAMDGPUEntityIndex());
238d6c0b56eSmrg	return pPriv->ptr;
239d6c0b56eSmrg}
240d6c0b56eSmrg
241d6c0b56eSmrg/* Allocate our private AMDGPUInfoRec */
242d6c0b56eSmrgstatic Bool AMDGPUGetRec(ScrnInfoPtr pScrn)
243d6c0b56eSmrg{
244d6c0b56eSmrg	if (pScrn->driverPrivate)
245d6c0b56eSmrg		return TRUE;
246d6c0b56eSmrg
247d6c0b56eSmrg	pScrn->driverPrivate = xnfcalloc(sizeof(AMDGPUInfoRec), 1);
248d6c0b56eSmrg	return TRUE;
249d6c0b56eSmrg}
250d6c0b56eSmrg
251d6c0b56eSmrg/* Free our private AMDGPUInfoRec */
252d6c0b56eSmrgstatic void AMDGPUFreeRec(ScrnInfoPtr pScrn)
253d6c0b56eSmrg{
254d6c0b56eSmrg	DevUnion *pPriv;
255d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt;
256d6c0b56eSmrg	AMDGPUInfoPtr info;
25724b90cf4Smrg	EntityInfoPtr pEnt;
258d6c0b56eSmrg
259d6c0b56eSmrg	if (!pScrn)
260d6c0b56eSmrg		return;
261d6c0b56eSmrg
26290f2b693Smrg	pEnt = xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
26390f2b693Smrg	pPriv = xf86GetEntityPrivate(pEnt->index, gAMDGPUEntityIndex);
26490f2b693Smrg	pAMDGPUEnt = pPriv->ptr;
26590f2b693Smrg
266d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
26724b90cf4Smrg	if (info) {
26890f2b693Smrg		pAMDGPUEnt->scrn[info->instance_id] = NULL;
26990f2b693Smrg		pAMDGPUEnt->num_scrns--;
27024b90cf4Smrg		free(pScrn->driverPrivate);
27124b90cf4Smrg		pScrn->driverPrivate = NULL;
27224b90cf4Smrg	}
27324b90cf4Smrg
274d6c0b56eSmrg	if (pAMDGPUEnt->fd > 0) {
275d6c0b56eSmrg		DevUnion *pPriv;
276d6c0b56eSmrg		AMDGPUEntPtr pAMDGPUEnt;
277d6c0b56eSmrg		pPriv = xf86GetEntityPrivate(pScrn->entityList[0],
278d6c0b56eSmrg					     getAMDGPUEntityIndex());
279d6c0b56eSmrg
280d6c0b56eSmrg		pAMDGPUEnt = pPriv->ptr;
281d6c0b56eSmrg		pAMDGPUEnt->fd_ref--;
282d6c0b56eSmrg		if (!pAMDGPUEnt->fd_ref) {
28390f2b693Smrg			amdgpu_unwrap_property_requests(pScrn);
284d6c0b56eSmrg			amdgpu_device_deinitialize(pAMDGPUEnt->pDev);
28511bf0794Smrg			amdgpu_kernel_close_fd(pAMDGPUEnt);
28624b90cf4Smrg			free(pPriv->ptr);
28724b90cf4Smrg			pPriv->ptr = NULL;
288d6c0b56eSmrg		}
289d6c0b56eSmrg	}
290d6c0b56eSmrg
29124b90cf4Smrg	free(pEnt);
292d6c0b56eSmrg}
293d6c0b56eSmrg
29490f2b693SmrgBool amdgpu_window_has_variable_refresh(WindowPtr win) {
29590f2b693Smrg	struct amdgpu_window_priv *priv = get_window_priv(win);
29690f2b693Smrg
29790f2b693Smrg	return priv->variable_refresh;
29890f2b693Smrg}
29990f2b693Smrg
300d6c0b56eSmrgstatic void *amdgpuShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset,
301d6c0b56eSmrg				int mode, CARD32 * size, void *closure)
302d6c0b56eSmrg{
303d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
304d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
305d6c0b56eSmrg	int stride;
306d6c0b56eSmrg
307d6c0b56eSmrg	stride = (pScrn->displayWidth * pScrn->bitsPerPixel) / 8;
308d6c0b56eSmrg	*size = stride;
309d6c0b56eSmrg
310d6c0b56eSmrg	return ((uint8_t *) info->front_buffer->cpu_ptr + row * stride + offset);
311d6c0b56eSmrg}
312d6c0b56eSmrg
313d6c0b56eSmrgstatic void
314d6c0b56eSmrgamdgpuUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
315d6c0b56eSmrg{
316d6c0b56eSmrg	shadowUpdatePacked(pScreen, pBuf);
317d6c0b56eSmrg}
318d6c0b56eSmrg
319504d986fSmrgstatic Bool
320504d986fSmrgcallback_needs_flush(AMDGPUInfoPtr info, struct amdgpu_client_priv *client_priv)
321504d986fSmrg{
322504d986fSmrg	return (int)(client_priv->needs_flush - info->gpu_flushed) > 0;
323504d986fSmrg}
324504d986fSmrg
325504d986fSmrgstatic void
326504d986fSmrgamdgpu_event_callback(CallbackListPtr *list,
327504d986fSmrg		      pointer user_data, pointer call_data)
328504d986fSmrg{
329504d986fSmrg	EventInfoRec *eventinfo = call_data;
330504d986fSmrg	ScrnInfoPtr pScrn = user_data;
331504d986fSmrg	ScreenPtr pScreen = pScrn->pScreen;
332504d986fSmrg	struct amdgpu_client_priv *client_priv =
333504d986fSmrg		dixLookupScreenPrivate(&eventinfo->client->devPrivates,
334504d986fSmrg				       &amdgpu_client_private_key, pScreen);
335504d986fSmrg	struct amdgpu_client_priv *server_priv =
336504d986fSmrg		dixLookupScreenPrivate(&serverClient->devPrivates,
337504d986fSmrg				       &amdgpu_client_private_key, pScreen);
338504d986fSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
339504d986fSmrg	int i;
340504d986fSmrg
341504d986fSmrg	if (callback_needs_flush(info, client_priv) ||
342504d986fSmrg	    callback_needs_flush(info, server_priv))
343504d986fSmrg		return;
344504d986fSmrg
345504d986fSmrg	/* Don't let gpu_flushed get too far ahead of needs_flush, in order
346504d986fSmrg	 * to prevent false positives in callback_needs_flush()
347504d986fSmrg	 */
348504d986fSmrg	client_priv->needs_flush = info->gpu_flushed;
349504d986fSmrg	server_priv->needs_flush = info->gpu_flushed;
350504d986fSmrg
351504d986fSmrg	for (i = 0; i < eventinfo->count; i++) {
352504d986fSmrg		if (eventinfo->events[i].u.u.type == info->callback_event_type) {
353504d986fSmrg			client_priv->needs_flush++;
354504d986fSmrg			server_priv->needs_flush++;
355504d986fSmrg			return;
356504d986fSmrg		}
357504d986fSmrg	}
358504d986fSmrg}
359504d986fSmrg
360504d986fSmrgstatic void
361504d986fSmrgamdgpu_flush_callback(CallbackListPtr *list,
362504d986fSmrg		      pointer user_data, pointer call_data)
363504d986fSmrg{
364504d986fSmrg	ScrnInfoPtr pScrn = user_data;
365504d986fSmrg	ScreenPtr pScreen = pScrn->pScreen;
366504d986fSmrg	ClientPtr client = call_data ? call_data : serverClient;
367504d986fSmrg	struct amdgpu_client_priv *client_priv =
368504d986fSmrg		dixLookupScreenPrivate(&client->devPrivates,
369504d986fSmrg				       &amdgpu_client_private_key, pScreen);
370504d986fSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
371504d986fSmrg
372504d986fSmrg	if (pScrn->vtSema && callback_needs_flush(info, client_priv))
373504d986fSmrg		amdgpu_glamor_flush(pScrn);
374504d986fSmrg}
375504d986fSmrg
376d6c0b56eSmrgstatic Bool AMDGPUCreateScreenResources_KMS(ScreenPtr pScreen)
377d6c0b56eSmrg{
37811bf0794Smrg	ExtensionEntry *damage_ext;
379d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
380d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
381d6c0b56eSmrg	PixmapPtr pixmap;
382d6c0b56eSmrg
383d6c0b56eSmrg	pScreen->CreateScreenResources = info->CreateScreenResources;
384d6c0b56eSmrg	if (!(*pScreen->CreateScreenResources) (pScreen))
385d6c0b56eSmrg		return FALSE;
386d6c0b56eSmrg	pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS;
387d6c0b56eSmrg
388d6c0b56eSmrg	/* Set the RandR primary output if Xorg hasn't */
389504d986fSmrg	if (dixPrivateKeyRegistered(rrPrivKey)) {
390504d986fSmrg		rrScrPrivPtr rrScrPriv = rrGetScrPriv(pScreen);
391504d986fSmrg
39224b90cf4Smrg		if (!pScreen->isGPU && !rrScrPriv->primaryOutput) {
393504d986fSmrg			xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
394d6c0b56eSmrg
395504d986fSmrg			rrScrPriv->primaryOutput = xf86_config->output[0]->randr_output;
396504d986fSmrg			RROutputChanged(rrScrPriv->primaryOutput, FALSE);
397504d986fSmrg			rrScrPriv->layoutChanged = TRUE;
398504d986fSmrg		}
39990f2b693Smrg
40090f2b693Smrg		drmmode_uevent_init(pScrn, &info->drmmode);
401d6c0b56eSmrg	}
402d6c0b56eSmrg
40324b90cf4Smrg	if (!drmmode_set_desired_modes(pScrn, &info->drmmode, pScreen->isGPU))
404d6c0b56eSmrg		return FALSE;
405d6c0b56eSmrg
406d6c0b56eSmrg	if (info->shadow_fb) {
407d6c0b56eSmrg		pixmap = pScreen->GetScreenPixmap(pScreen);
408d6c0b56eSmrg
409d6c0b56eSmrg		if (!shadowAdd(pScreen, pixmap, amdgpuUpdatePacked,
410d6c0b56eSmrg			       amdgpuShadowWindow, 0, NULL))
411d6c0b56eSmrg			return FALSE;
412d6c0b56eSmrg	}
413d6c0b56eSmrg
414d6c0b56eSmrg	if (info->dri2.enabled || info->use_glamor) {
415d6c0b56eSmrg		if (info->front_buffer) {
416d6c0b56eSmrg			PixmapPtr pPix = pScreen->GetScreenPixmap(pScreen);
417504d986fSmrg
418504d986fSmrg			if (!amdgpu_set_pixmap_bo(pPix, info->front_buffer))
419504d986fSmrg				return FALSE;
420d6c0b56eSmrg		}
421d6c0b56eSmrg	}
422d6c0b56eSmrg
423d6c0b56eSmrg	if (info->use_glamor)
424d6c0b56eSmrg		amdgpu_glamor_create_screen_resources(pScreen);
425d6c0b56eSmrg
426504d986fSmrg	info->callback_event_type = -1;
42724b90cf4Smrg	if (!pScreen->isGPU && (damage_ext = CheckExtension("DAMAGE"))) {
428504d986fSmrg		info->callback_event_type = damage_ext->eventBase + XDamageNotify;
429504d986fSmrg
430504d986fSmrg		if (!AddCallback(&FlushCallback, amdgpu_flush_callback, pScrn))
431504d986fSmrg			return FALSE;
432504d986fSmrg
433504d986fSmrg		if (!AddCallback(&EventCallback, amdgpu_event_callback, pScrn)) {
434504d986fSmrg			DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
435504d986fSmrg			return FALSE;
436504d986fSmrg		}
437504d986fSmrg
438504d986fSmrg		if (!dixRegisterScreenPrivateKey(&amdgpu_client_private_key, pScreen,
439504d986fSmrg						 PRIVATE_CLIENT, sizeof(struct amdgpu_client_priv))) {
440504d986fSmrg			DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
441504d986fSmrg			DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn);
442504d986fSmrg			return FALSE;
443504d986fSmrg		}
444504d986fSmrg	}
445504d986fSmrg
44690f2b693Smrg	if (info->vrr_support &&
44790f2b693Smrg	    !dixRegisterPrivateKey(&amdgpu_window_private_key,
44890f2b693Smrg				   PRIVATE_WINDOW,
44990f2b693Smrg				   sizeof(struct amdgpu_window_priv)))
45090f2b693Smrg		return FALSE;
45190f2b693Smrg
452d6c0b56eSmrg	return TRUE;
453d6c0b56eSmrg}
454d6c0b56eSmrg
455504d986fSmrgstatic Bool
456504d986fSmrgamdgpu_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents)
457504d986fSmrg{
45811bf0794Smrg	if (xf86_crtc->scrn->is_gpu) {
45911bf0794Smrg		extents->x1 -= xf86_crtc->x;
46011bf0794Smrg		extents->y1 -= xf86_crtc->y;
46111bf0794Smrg		extents->x2 -= xf86_crtc->x;
46211bf0794Smrg		extents->y2 -= xf86_crtc->y;
46324b90cf4Smrg	} else {
46411bf0794Smrg		extents->x1 -= xf86_crtc->filter_width >> 1;
46511bf0794Smrg		extents->x2 += xf86_crtc->filter_width >> 1;
46611bf0794Smrg		extents->y1 -= xf86_crtc->filter_height >> 1;
46711bf0794Smrg		extents->y2 += xf86_crtc->filter_height >> 1;
46811bf0794Smrg		pixman_f_transform_bounds(&xf86_crtc->f_framebuffer_to_crtc, extents);
46911bf0794Smrg	}
470504d986fSmrg
471504d986fSmrg	extents->x1 = max(extents->x1, 0);
472504d986fSmrg	extents->y1 = max(extents->y1, 0);
473504d986fSmrg	extents->x2 = min(extents->x2, xf86_crtc->mode.HDisplay);
474504d986fSmrg	extents->y2 = min(extents->y2, xf86_crtc->mode.VDisplay);
475504d986fSmrg
476504d986fSmrg	return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
477504d986fSmrg}
478504d986fSmrg
479504d986fSmrgstatic RegionPtr
480504d986fSmrgtransform_region(RegionPtr region, struct pict_f_transform *transform,
481504d986fSmrg		 int w, int h)
482504d986fSmrg{
483504d986fSmrg	BoxPtr boxes = RegionRects(region);
484504d986fSmrg	int nboxes = RegionNumRects(region);
485504d986fSmrg	xRectanglePtr rects = malloc(nboxes * sizeof(*rects));
486504d986fSmrg	RegionPtr transformed;
487504d986fSmrg	int nrects = 0;
488504d986fSmrg	BoxRec box;
489504d986fSmrg	int i;
490504d986fSmrg
491504d986fSmrg	for (i = 0; i < nboxes; i++) {
492504d986fSmrg		box.x1 = boxes[i].x1;
493504d986fSmrg		box.x2 = boxes[i].x2;
494504d986fSmrg		box.y1 = boxes[i].y1;
495504d986fSmrg		box.y2 = boxes[i].y2;
496504d986fSmrg		pixman_f_transform_bounds(transform, &box);
497504d986fSmrg
498504d986fSmrg		box.x1 = max(box.x1, 0);
499504d986fSmrg		box.y1 = max(box.y1, 0);
500504d986fSmrg		box.x2 = min(box.x2, w);
501504d986fSmrg		box.y2 = min(box.y2, h);
502504d986fSmrg		if (box.x1 >= box.x2 || box.y1 >= box.y2)
503504d986fSmrg			continue;
504504d986fSmrg
505504d986fSmrg		rects[nrects].x = box.x1;
506504d986fSmrg		rects[nrects].y = box.y1;
507504d986fSmrg		rects[nrects].width = box.x2 - box.x1;
508504d986fSmrg		rects[nrects].height = box.y2 - box.y1;
509504d986fSmrg		nrects++;
510504d986fSmrg	}
511504d986fSmrg
512504d986fSmrg	transformed = RegionFromRects(nrects, rects, CT_UNSORTED);
513504d986fSmrg	free(rects);
514504d986fSmrg	return transformed;
515504d986fSmrg}
516504d986fSmrg
517504d986fSmrgstatic void
518504d986fSmrgamdgpu_sync_scanout_pixmaps(xf86CrtcPtr xf86_crtc, RegionPtr new_region,
519504d986fSmrg							int scanout_id)
520504d986fSmrg{
521504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
522504d986fSmrg	DrawablePtr dst = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
523504d986fSmrg	DrawablePtr src = &drmmode_crtc->scanout[scanout_id ^ 1].pixmap->drawable;
524504d986fSmrg	RegionPtr last_region = &drmmode_crtc->scanout_last_region;
525504d986fSmrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
526504d986fSmrg	ScreenPtr pScreen = scrn->pScreen;
527504d986fSmrg	RegionRec remaining;
528504d986fSmrg	RegionPtr sync_region = NULL;
529504d986fSmrg	BoxRec extents;
530504d986fSmrg	GCPtr gc;
531504d986fSmrg
532504d986fSmrg	if (RegionNil(last_region))
533504d986fSmrg		return;
534504d986fSmrg
535504d986fSmrg	RegionNull(&remaining);
536504d986fSmrg	RegionSubtract(&remaining, last_region, new_region);
537504d986fSmrg	if (RegionNil(&remaining))
538504d986fSmrg		goto uninit;
539504d986fSmrg
540504d986fSmrg	extents = *RegionExtents(&remaining);
541504d986fSmrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents))
542504d986fSmrg		goto uninit;
543504d986fSmrg
544504d986fSmrg	if (xf86_crtc->driverIsPerformingTransform) {
545504d986fSmrg		sync_region = transform_region(&remaining,
546504d986fSmrg					       &xf86_crtc->f_framebuffer_to_crtc,
547504d986fSmrg					       dst->width, dst->height);
54824b90cf4Smrg	} else {
549504d986fSmrg		sync_region = RegionDuplicate(&remaining);
550504d986fSmrg		RegionTranslate(sync_region, -xf86_crtc->x, -xf86_crtc->y);
551504d986fSmrg	}
552504d986fSmrg
553504d986fSmrg	gc = GetScratchGC(dst->depth, pScreen);
554504d986fSmrg	if (gc) {
555504d986fSmrg		gc->funcs->ChangeClip(gc, CT_REGION, sync_region, 0);
55611bf0794Smrg		ValidateGC(dst, gc);
557504d986fSmrg		sync_region = NULL;
558504d986fSmrg		gc->ops->CopyArea(src, dst, gc, 0, 0, dst->width, dst->height, 0, 0);
559504d986fSmrg		FreeScratchGC(gc);
560504d986fSmrg	}
561504d986fSmrg
562504d986fSmrg uninit:
563504d986fSmrg	if (sync_region)
564504d986fSmrg		RegionDestroy(sync_region);
565504d986fSmrg	RegionUninit(&remaining);
566504d986fSmrg}
567504d986fSmrg
56824b90cf4Smrgstatic void
56924b90cf4Smrgamdgpu_scanout_flip_abort(xf86CrtcPtr crtc, void *event_data)
57024b90cf4Smrg{
57124b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
57224b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
57390f2b693Smrg	struct drmmode_fb *fb = event_data;
57424b90cf4Smrg
57535d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
57690f2b693Smrg
57790f2b693Smrg	if (drmmode_crtc->flip_pending == fb) {
57890f2b693Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
57990f2b693Smrg				     NULL);
58090f2b693Smrg	}
58124b90cf4Smrg}
58224b90cf4Smrg
58324b90cf4Smrgstatic void
58424b90cf4Smrgamdgpu_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec,
58524b90cf4Smrg			    void *event_data)
58624b90cf4Smrg{
58724b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(crtc->scrn);
58824b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
58990f2b693Smrg	struct drmmode_fb *fb = event_data;
59024b90cf4Smrg
59190f2b693Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, fb);
59224b90cf4Smrg	amdgpu_scanout_flip_abort(crtc, event_data);
59324b90cf4Smrg}
59424b90cf4Smrg
595504d986fSmrg
596504d986fSmrgstatic RegionPtr
597504d986fSmrgdirty_region(PixmapDirtyUpdatePtr dirty)
598d6c0b56eSmrg{
599504d986fSmrg	RegionPtr damageregion = DamageRegion(dirty->damage);
600504d986fSmrg	RegionPtr dstregion;
601504d986fSmrg
602504d986fSmrg#ifdef HAS_DIRTYTRACKING_ROTATION
603504d986fSmrg	if (dirty->rotation != RR_Rotate_0) {
604504d986fSmrg		dstregion = transform_region(damageregion,
605504d986fSmrg					     &dirty->f_inverse,
606504d986fSmrg					     dirty->slave_dst->drawable.width,
607504d986fSmrg					     dirty->slave_dst->drawable.height);
608504d986fSmrg	} else
609504d986fSmrg#endif
610504d986fSmrg	{
611504d986fSmrg		RegionRec pixregion;
612504d986fSmrg
613504d986fSmrg		dstregion = RegionDuplicate(damageregion);
614504d986fSmrg		RegionTranslate(dstregion, -dirty->x, -dirty->y);
615504d986fSmrg		PixmapRegionInit(&pixregion, dirty->slave_dst);
616504d986fSmrg		RegionIntersect(dstregion, dstregion, &pixregion);
617504d986fSmrg		RegionUninit(&pixregion);
618504d986fSmrg	}
619504d986fSmrg
620504d986fSmrg	return dstregion;
621504d986fSmrg}
622504d986fSmrg
623504d986fSmrgstatic void
624504d986fSmrgredisplay_dirty(PixmapDirtyUpdatePtr dirty, RegionPtr region)
625504d986fSmrg{
62624b90cf4Smrg	ScrnInfoPtr src_scrn =
62724b90cf4Smrg		xf86ScreenToScrn(amdgpu_dirty_src_drawable(dirty)->pScreen);
628504d986fSmrg
629504d986fSmrg	if (RegionNil(region))
630504d986fSmrg		goto out;
631504d986fSmrg
632504d986fSmrg	if (dirty->slave_dst->master_pixmap)
633504d986fSmrg		DamageRegionAppend(&dirty->slave_dst->drawable, region);
634d6c0b56eSmrg
635d6c0b56eSmrg#ifdef HAS_DIRTYTRACKING_ROTATION
636d6c0b56eSmrg	PixmapSyncDirtyHelper(dirty);
637d6c0b56eSmrg#else
638504d986fSmrg	PixmapSyncDirtyHelper(dirty, region);
639d6c0b56eSmrg#endif
640d6c0b56eSmrg
64124b90cf4Smrg	amdgpu_glamor_flush(src_scrn);
642504d986fSmrg	if (dirty->slave_dst->master_pixmap)
643504d986fSmrg		DamageRegionProcessPending(&dirty->slave_dst->drawable);
644504d986fSmrg
645504d986fSmrgout:
646504d986fSmrg	DamageEmpty(dirty->damage);
647d6c0b56eSmrg}
648d6c0b56eSmrg
649504d986fSmrgstatic void
650504d986fSmrgamdgpu_prime_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
651d6c0b56eSmrg{
652504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
653504d986fSmrg
65435d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
655504d986fSmrg}
656504d986fSmrg
657504d986fSmrgvoid
658504d986fSmrgamdgpu_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
659504d986fSmrg{
66024b90cf4Smrg	ScreenPtr master_screen = amdgpu_dirty_master(dirty);
661d6c0b56eSmrg	PixmapDirtyUpdatePtr ent;
662504d986fSmrg	RegionPtr region;
663d6c0b56eSmrg
664504d986fSmrg	xorg_list_for_each_entry(ent, &master_screen->pixmap_dirty_list, ent) {
66524b90cf4Smrg		if (!amdgpu_dirty_src_equals(dirty, ent->slave_dst))
666504d986fSmrg			continue;
667d6c0b56eSmrg
668504d986fSmrg		region = dirty_region(ent);
669504d986fSmrg		redisplay_dirty(ent, region);
670504d986fSmrg		RegionDestroy(region);
671d6c0b56eSmrg	}
672d6c0b56eSmrg}
673504d986fSmrg
674504d986fSmrg
675504d986fSmrg#if HAS_SYNC_SHARED_PIXMAP
676d6c0b56eSmrg
677d6c0b56eSmrgstatic Bool
678504d986fSmrgmaster_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
679d6c0b56eSmrg{
68024b90cf4Smrg	ScreenPtr master_screen = amdgpu_dirty_master(dirty);
681504d986fSmrg
682504d986fSmrg	return master_screen->SyncSharedPixmap != NULL;
683504d986fSmrg}
684504d986fSmrg
685504d986fSmrgstatic Bool
686504d986fSmrgslave_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
687504d986fSmrg{
688504d986fSmrg	ScreenPtr slave_screen = dirty->slave_dst->drawable.pScreen;
689504d986fSmrg
690504d986fSmrg	return slave_screen->SyncSharedPixmap != NULL;
691504d986fSmrg}
692504d986fSmrg
693504d986fSmrgstatic void
694504d986fSmrgcall_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
695504d986fSmrg{
69624b90cf4Smrg	ScreenPtr master_screen = amdgpu_dirty_master(dirty);
697504d986fSmrg
698504d986fSmrg	master_screen->SyncSharedPixmap(dirty);
699504d986fSmrg}
700504d986fSmrg
701504d986fSmrg#else /* !HAS_SYNC_SHARED_PIXMAP */
702504d986fSmrg
703504d986fSmrgstatic Bool
704504d986fSmrgmaster_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
705504d986fSmrg{
70624b90cf4Smrg	ScrnInfoPtr master_scrn = xf86ScreenToScrn(amdgpu_dirty_master(dirty));
707504d986fSmrg
708504d986fSmrg	return master_scrn->driverName == scrn->driverName;
709504d986fSmrg}
710504d986fSmrg
711504d986fSmrgstatic Bool
712504d986fSmrgslave_has_sync_shared_pixmap(ScrnInfoPtr scrn, PixmapDirtyUpdatePtr dirty)
713504d986fSmrg{
714504d986fSmrg	ScrnInfoPtr slave_scrn = xf86ScreenToScrn(dirty->slave_dst->drawable.pScreen);
715504d986fSmrg
716504d986fSmrg	return slave_scrn->driverName == scrn->driverName;
717504d986fSmrg}
718504d986fSmrg
719504d986fSmrgstatic void
720504d986fSmrgcall_sync_shared_pixmap(PixmapDirtyUpdatePtr dirty)
721504d986fSmrg{
722504d986fSmrg	amdgpu_sync_shared_pixmap(dirty);
723504d986fSmrg}
724504d986fSmrg
725504d986fSmrg#endif /* HAS_SYNC_SHARED_PIXMAPS */
726504d986fSmrg
727504d986fSmrg
72811bf0794Smrgstatic xf86CrtcPtr
72911bf0794Smrgamdgpu_prime_dirty_to_crtc(PixmapDirtyUpdatePtr dirty)
73011bf0794Smrg{
73111bf0794Smrg	ScreenPtr screen = dirty->slave_dst->drawable.pScreen;
73211bf0794Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
73311bf0794Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
73411bf0794Smrg	int c;
73511bf0794Smrg
73611bf0794Smrg	/* Find the CRTC which is scanning out from this slave pixmap */
73711bf0794Smrg	for (c = 0; c < xf86_config->num_crtc; c++) {
73811bf0794Smrg		xf86CrtcPtr xf86_crtc = xf86_config->crtc[c];
73911bf0794Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
74011bf0794Smrg
74124b90cf4Smrg		if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap))
74211bf0794Smrg			return xf86_crtc;
74311bf0794Smrg	}
74411bf0794Smrg
74511bf0794Smrg	return NULL;
74611bf0794Smrg}
74711bf0794Smrg
748504d986fSmrgstatic Bool
749504d986fSmrgamdgpu_prime_scanout_do_update(xf86CrtcPtr crtc, unsigned scanout_id)
750504d986fSmrg{
751504d986fSmrg	ScrnInfoPtr scrn = crtc->scrn;
752504d986fSmrg	ScreenPtr screen = scrn->pScreen;
753504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
754504d986fSmrg	PixmapDirtyUpdatePtr dirty;
755504d986fSmrg	Bool ret = FALSE;
756504d986fSmrg
757504d986fSmrg	xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
75824b90cf4Smrg		if (amdgpu_dirty_src_equals(dirty, drmmode_crtc->prime_scanout_pixmap)) {
759504d986fSmrg			RegionPtr region;
760504d986fSmrg
761504d986fSmrg			if (master_has_sync_shared_pixmap(scrn, dirty))
762504d986fSmrg				call_sync_shared_pixmap(dirty);
763504d986fSmrg
764504d986fSmrg			region = dirty_region(dirty);
765504d986fSmrg			if (RegionNil(region))
766504d986fSmrg				goto destroy;
767504d986fSmrg
76811bf0794Smrg			if (drmmode_crtc->tear_free) {
769504d986fSmrg				RegionTranslate(region, crtc->x, crtc->y);
770504d986fSmrg				amdgpu_sync_scanout_pixmaps(crtc, region, scanout_id);
771504d986fSmrg				amdgpu_glamor_flush(scrn);
772504d986fSmrg				RegionCopy(&drmmode_crtc->scanout_last_region, region);
773504d986fSmrg				RegionTranslate(region, -crtc->x, -crtc->y);
774504d986fSmrg				dirty->slave_dst = drmmode_crtc->scanout[scanout_id].pixmap;
775504d986fSmrg			}
776504d986fSmrg
777504d986fSmrg			redisplay_dirty(dirty, region);
778504d986fSmrg			ret = TRUE;
779504d986fSmrg		destroy:
780504d986fSmrg			RegionDestroy(region);
781504d986fSmrg			break;
782504d986fSmrg		}
783d6c0b56eSmrg	}
784d6c0b56eSmrg
785504d986fSmrg	return ret;
786504d986fSmrg}
787504d986fSmrg
78811bf0794Smrgstatic void
789504d986fSmrgamdgpu_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
790504d986fSmrg				     void *event_data)
791504d986fSmrg{
792504d986fSmrg	drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
793504d986fSmrg
794504d986fSmrg	amdgpu_prime_scanout_do_update(crtc, 0);
79535d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
796504d986fSmrg}
797504d986fSmrg
798504d986fSmrgstatic void
799504d986fSmrgamdgpu_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
800504d986fSmrg{
801504d986fSmrg	ScreenPtr screen = dirty->slave_dst->drawable.pScreen;
802504d986fSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
80390f2b693Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
80411bf0794Smrg	xf86CrtcPtr xf86_crtc = amdgpu_prime_dirty_to_crtc(dirty);
80511bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc;
806504d986fSmrg	uintptr_t drm_queue_seq;
807504d986fSmrg
80811bf0794Smrg	if (!xf86_crtc || !xf86_crtc->enabled)
80911bf0794Smrg		return;
810504d986fSmrg
81111bf0794Smrg	drmmode_crtc = xf86_crtc->driver_private;
81211bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
81324b90cf4Smrg	    !drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap ||
81424b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
815504d986fSmrg		return;
816504d986fSmrg
817504d986fSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
818504d986fSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
819504d986fSmrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT, NULL,
820504d986fSmrg					       amdgpu_prime_scanout_update_handler,
82190f2b693Smrg					       amdgpu_prime_scanout_update_abort,
82290f2b693Smrg					       FALSE);
823504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
824504d986fSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
825504d986fSmrg			   "amdgpu_drm_queue_alloc failed for PRIME update\n");
82690f2b693Smrg		amdgpu_prime_scanout_update_handler(xf86_crtc, 0, 0, NULL);
827504d986fSmrg		return;
828504d986fSmrg	}
829504d986fSmrg
83090f2b693Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
83190f2b693Smrg
83224b90cf4Smrg	if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
83324b90cf4Smrg				 1, drm_queue_seq, NULL, NULL)) {
83490f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) {
83590f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
83690f2b693Smrg				   "drmmode_wait_vblank failed for PRIME update: %s\n",
83790f2b693Smrg				   strerror(errno));
83890f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED;
83990f2b693Smrg		}
84090f2b693Smrg
84190f2b693Smrg		drmmode_crtc->drmmode->event_context.vblank_handler(pAMDGPUEnt->fd,
84290f2b693Smrg								    0, 0, 0,
84390f2b693Smrg								    (void*)drm_queue_seq);
84490f2b693Smrg		drmmode_crtc->wait_flip_nesting_level++;
84590f2b693Smrg		amdgpu_drm_queue_handle_deferred(xf86_crtc);
846504d986fSmrg		return;
847504d986fSmrg	}
848504d986fSmrg
84990f2b693Smrg	if (drmmode_crtc->scanout_status ==
85090f2b693Smrg	    (DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) {
85190f2b693Smrg		/* The page flip and vblank ioctls failed before, but the vblank
85290f2b693Smrg		 * ioctl is working again, so we can try re-enabling TearFree
85390f2b693Smrg		 */
85490f2b693Smrg		xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode,
85590f2b693Smrg						 xf86_crtc->rotation,
85690f2b693Smrg						 xf86_crtc->x, xf86_crtc->y);
85790f2b693Smrg	}
85890f2b693Smrg
85990f2b693Smrg	drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED;
860504d986fSmrg}
861504d986fSmrg
862504d986fSmrgstatic void
863504d986fSmrgamdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent)
864504d986fSmrg{
865504d986fSmrg	ScreenPtr screen = ent->slave_dst->drawable.pScreen;
866504d986fSmrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
867504d986fSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
86811bf0794Smrg	xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent);
86911bf0794Smrg	drmmode_crtc_private_ptr drmmode_crtc;
870504d986fSmrg	uintptr_t drm_queue_seq;
871504d986fSmrg	unsigned scanout_id;
87290f2b693Smrg	struct drmmode_fb *fb;
873504d986fSmrg
87411bf0794Smrg	if (!crtc || !crtc->enabled)
87511bf0794Smrg		return;
876504d986fSmrg
87711bf0794Smrg	drmmode_crtc = crtc->driver_private;
87890f2b693Smrg	scanout_id = drmmode_crtc->scanout_id ^ 1;
87911bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
88090f2b693Smrg	    !drmmode_crtc->scanout[scanout_id].pixmap ||
88124b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
882504d986fSmrg		return;
883504d986fSmrg
884504d986fSmrg	if (!amdgpu_prime_scanout_do_update(crtc, scanout_id))
885504d986fSmrg		return;
886504d986fSmrg
88790f2b693Smrg	fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
88890f2b693Smrg	if (!fb) {
88990f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
89090f2b693Smrg			   "Failed to get FB for PRIME flip.\n");
89190f2b693Smrg		return;
89290f2b693Smrg	}
89390f2b693Smrg
894504d986fSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(crtc,
895504d986fSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
89690f2b693Smrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT, fb,
89724b90cf4Smrg					       amdgpu_scanout_flip_handler,
89890f2b693Smrg					       amdgpu_scanout_flip_abort, TRUE);
899504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
900504d986fSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
901504d986fSmrg			   "Allocating DRM event queue entry failed for PRIME flip.\n");
902504d986fSmrg		return;
903504d986fSmrg	}
904504d986fSmrg
90590f2b693Smrg	if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc,
90690f2b693Smrg					      fb->handle, 0, drm_queue_seq, 1)
90790f2b693Smrg	    != 0) {
90890f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) {
90990f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
91090f2b693Smrg				   "flip queue failed in %s: %s, TearFree inactive\n",
91190f2b693Smrg				   __func__, strerror(errno));
91290f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED;
91390f2b693Smrg		}
91490f2b693Smrg
91524b90cf4Smrg		amdgpu_drm_abort_entry(drm_queue_seq);
91624b90cf4Smrg		return;
91724b90cf4Smrg	}
91824b90cf4Smrg
91990f2b693Smrg	if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) {
92090f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n");
92190f2b693Smrg		drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED;
922504d986fSmrg	}
923504d986fSmrg
924504d986fSmrg	drmmode_crtc->scanout_id = scanout_id;
92535d5b7c7Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
92690f2b693Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, fb);
927504d986fSmrg}
928504d986fSmrg
929504d986fSmrgstatic void
930504d986fSmrgamdgpu_dirty_update(ScrnInfoPtr scrn)
931504d986fSmrg{
932504d986fSmrg	ScreenPtr screen = scrn->pScreen;
933504d986fSmrg	PixmapDirtyUpdatePtr ent;
934504d986fSmrg	RegionPtr region;
935504d986fSmrg
936504d986fSmrg	xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
937504d986fSmrg		if (screen->isGPU) {
938504d986fSmrg			PixmapDirtyUpdatePtr region_ent = ent;
939504d986fSmrg
940504d986fSmrg			if (master_has_sync_shared_pixmap(scrn, ent)) {
94124b90cf4Smrg				ScreenPtr master_screen = amdgpu_dirty_master(ent);
942504d986fSmrg
943504d986fSmrg				xorg_list_for_each_entry(region_ent, &master_screen->pixmap_dirty_list, ent) {
94424b90cf4Smrg					if (amdgpu_dirty_src_equals(ent, region_ent->slave_dst))
945504d986fSmrg						break;
946504d986fSmrg				}
947504d986fSmrg			}
948504d986fSmrg
949504d986fSmrg			region = dirty_region(region_ent);
950504d986fSmrg
951504d986fSmrg			if (RegionNotEmpty(region)) {
95211bf0794Smrg				xf86CrtcPtr crtc = amdgpu_prime_dirty_to_crtc(ent);
95311bf0794Smrg				drmmode_crtc_private_ptr drmmode_crtc = NULL;
95411bf0794Smrg
95511bf0794Smrg				if (crtc)
95611bf0794Smrg					drmmode_crtc = crtc->driver_private;
95711bf0794Smrg
95811bf0794Smrg				if (drmmode_crtc && drmmode_crtc->tear_free)
959504d986fSmrg					amdgpu_prime_scanout_flip(ent);
960504d986fSmrg				else
961504d986fSmrg					amdgpu_prime_scanout_update(ent);
962504d986fSmrg			} else {
963504d986fSmrg				DamageEmpty(region_ent->damage);
964504d986fSmrg			}
965504d986fSmrg
966504d986fSmrg			RegionDestroy(region);
967504d986fSmrg		} else {
968504d986fSmrg			if (slave_has_sync_shared_pixmap(scrn, ent))
969504d986fSmrg				continue;
970504d986fSmrg
971504d986fSmrg			region = dirty_region(ent);
972504d986fSmrg			redisplay_dirty(ent, region);
973504d986fSmrg			RegionDestroy(region);
974504d986fSmrg		}
975504d986fSmrg	}
976504d986fSmrg}
97724b90cf4Smrg
978504d986fSmrg
97911bf0794SmrgBool
98024b90cf4Smrgamdgpu_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id,
98135d5b7c7Smrg			 PixmapPtr src_pix, BoxRec extents)
982d6c0b56eSmrg{
983d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
98435d5b7c7Smrg	RegionRec region = { .extents = extents, .data = NULL };
985504d986fSmrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
986504d986fSmrg	ScreenPtr pScreen = scrn->pScreen;
987d6c0b56eSmrg	DrawablePtr pDraw;
988d6c0b56eSmrg
989d6c0b56eSmrg	if (!xf86_crtc->enabled ||
99024b90cf4Smrg	    !drmmode_crtc->scanout[scanout_id].pixmap ||
99135d5b7c7Smrg	    extents.x1 >= extents.x2 || extents.y1 >= extents.y2)
992d6c0b56eSmrg		return FALSE;
993d6c0b56eSmrg
994d6c0b56eSmrg	pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
99535d5b7c7Smrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents))
996d6c0b56eSmrg		return FALSE;
997d6c0b56eSmrg
99811bf0794Smrg	if (drmmode_crtc->tear_free) {
99924b90cf4Smrg		amdgpu_sync_scanout_pixmaps(xf86_crtc, &region, scanout_id);
100024b90cf4Smrg		RegionCopy(&drmmode_crtc->scanout_last_region, &region);
1001504d986fSmrg	}
1002504d986fSmrg
1003d6c0b56eSmrg	if (xf86_crtc->driverIsPerformingTransform) {
1004d6c0b56eSmrg		SourceValidateProcPtr SourceValidate = pScreen->SourceValidate;
1005d6c0b56eSmrg		PictFormatPtr format = PictureWindowFormat(pScreen->root);
1006d6c0b56eSmrg		int error;
1007d6c0b56eSmrg		PicturePtr src, dst;
1008d6c0b56eSmrg
100924b90cf4Smrg		src = CreatePicture(None, &src_pix->drawable, format, 0L, NULL,
101024b90cf4Smrg				    serverClient, &error);
1011d6c0b56eSmrg		if (!src) {
1012d6c0b56eSmrg			ErrorF("Failed to create source picture for transformed scanout "
1013d6c0b56eSmrg			       "update\n");
1014d6c0b56eSmrg			goto out;
1015d6c0b56eSmrg		}
1016d6c0b56eSmrg
1017d6c0b56eSmrg		dst = CreatePicture(None, pDraw, format, 0L, NULL, serverClient, &error);
1018d6c0b56eSmrg		if (!dst) {
1019d6c0b56eSmrg			ErrorF("Failed to create destination picture for transformed scanout "
1020d6c0b56eSmrg			       "update\n");
1021d6c0b56eSmrg			goto free_src;
1022d6c0b56eSmrg		}
1023d6c0b56eSmrg		error = SetPictureTransform(src, &xf86_crtc->crtc_to_framebuffer);
1024d6c0b56eSmrg		if (error) {
1025d6c0b56eSmrg			ErrorF("SetPictureTransform failed for transformed scanout "
1026d6c0b56eSmrg			       "update\n");
1027d6c0b56eSmrg			goto free_dst;
1028d6c0b56eSmrg		}
1029d6c0b56eSmrg
1030d6c0b56eSmrg		if (xf86_crtc->filter)
1031d6c0b56eSmrg			SetPicturePictFilter(src, xf86_crtc->filter, xf86_crtc->params,
1032d6c0b56eSmrg					     xf86_crtc->nparams);
1033d6c0b56eSmrg
1034d6c0b56eSmrg		pScreen->SourceValidate = NULL;
1035d6c0b56eSmrg		CompositePicture(PictOpSrc,
1036d6c0b56eSmrg				 src, NULL, dst,
103735d5b7c7Smrg				 extents.x1, extents.y1, 0, 0, extents.x1,
103835d5b7c7Smrg				 extents.y1, extents.x2 - extents.x1,
103935d5b7c7Smrg				 extents.y2 - extents.y1);
1040d6c0b56eSmrg		pScreen->SourceValidate = SourceValidate;
1041d6c0b56eSmrg
1042d6c0b56eSmrg free_dst:
1043d6c0b56eSmrg		FreePicture(dst, None);
1044d6c0b56eSmrg free_src:
1045d6c0b56eSmrg		FreePicture(src, None);
1046d6c0b56eSmrg	} else
1047d6c0b56eSmrg out:
1048d6c0b56eSmrg	{
1049d6c0b56eSmrg		GCPtr gc = GetScratchGC(pDraw->depth, pScreen);
1050d6c0b56eSmrg
1051d6c0b56eSmrg		ValidateGC(pDraw, gc);
105224b90cf4Smrg		(*gc->ops->CopyArea)(&src_pix->drawable, pDraw, gc,
105335d5b7c7Smrg				     xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
105435d5b7c7Smrg				     extents.x2 - extents.x1, extents.y2 - extents.y1,
105535d5b7c7Smrg				     extents.x1, extents.y1);
1056d6c0b56eSmrg		FreeScratchGC(gc);
1057d6c0b56eSmrg	}
1058d6c0b56eSmrg
1059d6c0b56eSmrg	return TRUE;
1060d6c0b56eSmrg}
1061d6c0b56eSmrg
1062d6c0b56eSmrgstatic void
1063d6c0b56eSmrgamdgpu_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
1064d6c0b56eSmrg{
1065d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = event_data;
1066d6c0b56eSmrg
106735d5b7c7Smrg	drmmode_crtc->scanout_update_pending = 0;
1068d6c0b56eSmrg}
1069d6c0b56eSmrg
107011bf0794Smrgstatic void
1071d6c0b56eSmrgamdgpu_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
1072d6c0b56eSmrg							  void *event_data)
1073d6c0b56eSmrg{
107424b90cf4Smrg	drmmode_crtc_private_ptr drmmode_crtc = event_data;
107524b90cf4Smrg	ScreenPtr screen = crtc->scrn->pScreen;
107624b90cf4Smrg	RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage);
107724b90cf4Smrg
107824b90cf4Smrg	if (crtc->enabled &&
107924b90cf4Smrg	    !drmmode_crtc->flip_pending &&
108024b90cf4Smrg	    drmmode_crtc->dpms_mode == DPMSModeOn) {
108124b90cf4Smrg		if (amdgpu_scanout_do_update(crtc, drmmode_crtc->scanout_id,
108224b90cf4Smrg					     screen->GetWindowPixmap(screen->root),
108335d5b7c7Smrg					     region->extents)) {
108435d5b7c7Smrg			amdgpu_glamor_flush(crtc->scrn);
108524b90cf4Smrg			RegionEmpty(region);
108635d5b7c7Smrg		}
108724b90cf4Smrg	}
1088d6c0b56eSmrg
1089d6c0b56eSmrg	amdgpu_scanout_update_abort(crtc, event_data);
1090d6c0b56eSmrg}
1091d6c0b56eSmrg
1092d6c0b56eSmrgstatic void
1093d6c0b56eSmrgamdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
1094d6c0b56eSmrg{
1095d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
109690f2b693Smrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
109790f2b693Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
1098d6c0b56eSmrg	uintptr_t drm_queue_seq;
1099d6c0b56eSmrg	DamagePtr pDamage;
1100d6c0b56eSmrg	RegionPtr pRegion;
1101d6c0b56eSmrg	BoxRec extents;
1102d6c0b56eSmrg
1103d6c0b56eSmrg	if (!xf86_crtc->enabled ||
1104d6c0b56eSmrg	    drmmode_crtc->scanout_update_pending ||
110524b90cf4Smrg	    drmmode_crtc->flip_pending ||
110624b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
1107d6c0b56eSmrg		return;
1108d6c0b56eSmrg
1109504d986fSmrg	pDamage = drmmode_crtc->scanout_damage;
1110d6c0b56eSmrg	if (!pDamage)
1111d6c0b56eSmrg		return;
1112d6c0b56eSmrg
1113d6c0b56eSmrg	pRegion = DamageRegion(pDamage);
1114d6c0b56eSmrg	if (!RegionNotEmpty(pRegion))
1115d6c0b56eSmrg		return;
1116d6c0b56eSmrg
1117d6c0b56eSmrg	extents = *RegionExtents(pRegion);
1118504d986fSmrg	if (!amdgpu_scanout_extents_intersect(xf86_crtc, &extents)) {
1119504d986fSmrg		RegionEmpty(pRegion);
1120d6c0b56eSmrg		return;
1121504d986fSmrg	}
1122d6c0b56eSmrg
1123d6c0b56eSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
1124d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
1125d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT,
1126d6c0b56eSmrg					       drmmode_crtc,
1127d6c0b56eSmrg					       amdgpu_scanout_update_handler,
112890f2b693Smrg					       amdgpu_scanout_update_abort,
112990f2b693Smrg					       FALSE);
1130504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
1131d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1132d6c0b56eSmrg			   "amdgpu_drm_queue_alloc failed for scanout update\n");
113390f2b693Smrg		amdgpu_scanout_update_handler(xf86_crtc, 0, 0, drmmode_crtc);
1134d6c0b56eSmrg		return;
1135d6c0b56eSmrg	}
1136d6c0b56eSmrg
113790f2b693Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
113890f2b693Smrg
113924b90cf4Smrg	if (!drmmode_wait_vblank(xf86_crtc, DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
114024b90cf4Smrg				 1, drm_queue_seq, NULL, NULL)) {
114190f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_VBLANK_FAILED)) {
114290f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
114390f2b693Smrg				   "drmmode_wait_vblank failed for scanout update: %s\n",
114490f2b693Smrg				   strerror(errno));
114590f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_VBLANK_FAILED;
114690f2b693Smrg		}
114790f2b693Smrg
114890f2b693Smrg		drmmode_crtc->drmmode->event_context.vblank_handler(pAMDGPUEnt->fd,
114990f2b693Smrg								    0, 0, 0,
115090f2b693Smrg								    (void*)drm_queue_seq);
115190f2b693Smrg		drmmode_crtc->wait_flip_nesting_level++;
115290f2b693Smrg		amdgpu_drm_queue_handle_deferred(xf86_crtc);
1153d6c0b56eSmrg		return;
1154d6c0b56eSmrg	}
1155d6c0b56eSmrg
115690f2b693Smrg	if (drmmode_crtc->scanout_status ==
115790f2b693Smrg	    (DRMMODE_SCANOUT_FLIP_FAILED | DRMMODE_SCANOUT_VBLANK_FAILED)) {
115890f2b693Smrg		/* The page flip and vblank ioctls failed before, but the vblank
115990f2b693Smrg		 * ioctl is working again, so we can try re-enabling TearFree
116090f2b693Smrg		 */
116190f2b693Smrg		xf86_crtc->funcs->set_mode_major(xf86_crtc, &xf86_crtc->mode,
116290f2b693Smrg						 xf86_crtc->rotation,
116390f2b693Smrg						 xf86_crtc->x, xf86_crtc->y);
116490f2b693Smrg	}
116590f2b693Smrg
116690f2b693Smrg	drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_VBLANK_FAILED;
1167d6c0b56eSmrg}
1168d6c0b56eSmrg
1169d6c0b56eSmrgstatic void
1170d6c0b56eSmrgamdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
1171d6c0b56eSmrg					xf86CrtcPtr xf86_crtc)
1172d6c0b56eSmrg{
1173d6c0b56eSmrg	drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
117424b90cf4Smrg	RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage);
117511bf0794Smrg	ScrnInfoPtr scrn = xf86_crtc->scrn;
117611bf0794Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
1177d6c0b56eSmrg	uintptr_t drm_queue_seq;
1178d6c0b56eSmrg	unsigned scanout_id;
117990f2b693Smrg	struct drmmode_fb *fb;
1180d6c0b56eSmrg
118111bf0794Smrg	if (drmmode_crtc->scanout_update_pending ||
118224b90cf4Smrg	    drmmode_crtc->flip_pending ||
118324b90cf4Smrg	    drmmode_crtc->dpms_mode != DPMSModeOn)
1184d6c0b56eSmrg		return;
1185d6c0b56eSmrg
1186d6c0b56eSmrg	scanout_id = drmmode_crtc->scanout_id ^ 1;
118724b90cf4Smrg	if (!amdgpu_scanout_do_update(xf86_crtc, scanout_id,
118824b90cf4Smrg				      pScreen->GetWindowPixmap(pScreen->root),
118935d5b7c7Smrg				      region->extents))
1190d6c0b56eSmrg		return;
119135d5b7c7Smrg
119235d5b7c7Smrg	amdgpu_glamor_flush(scrn);
119324b90cf4Smrg	RegionEmpty(region);
1194d6c0b56eSmrg
119590f2b693Smrg	fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
119690f2b693Smrg	if (!fb) {
119790f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
119890f2b693Smrg			   "Failed to get FB for scanout flip.\n");
119990f2b693Smrg		return;
120090f2b693Smrg	}
120190f2b693Smrg
1202d6c0b56eSmrg	drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
1203d6c0b56eSmrg					       AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
120490f2b693Smrg					       AMDGPU_DRM_QUEUE_ID_DEFAULT, fb,
120524b90cf4Smrg					       amdgpu_scanout_flip_handler,
120690f2b693Smrg					       amdgpu_scanout_flip_abort, TRUE);
1207504d986fSmrg	if (drm_queue_seq == AMDGPU_DRM_QUEUE_ERROR) {
1208d6c0b56eSmrg		xf86DrvMsg(scrn->scrnIndex, X_WARNING,
1209d6c0b56eSmrg			   "Allocating DRM event queue entry failed.\n");
1210d6c0b56eSmrg		return;
1211d6c0b56eSmrg	}
1212d6c0b56eSmrg
121311bf0794Smrg	if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc,
121490f2b693Smrg					      fb->handle, 0, drm_queue_seq, 1)
121590f2b693Smrg	    != 0) {
121690f2b693Smrg		if (!(drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED)) {
121790f2b693Smrg			xf86DrvMsg(scrn->scrnIndex, X_WARNING,
121890f2b693Smrg				   "flip queue failed in %s: %s, TearFree inactive\n",
121990f2b693Smrg				   __func__, strerror(errno));
122090f2b693Smrg			drmmode_crtc->scanout_status |= DRMMODE_SCANOUT_FLIP_FAILED;
122190f2b693Smrg		}
122290f2b693Smrg
122311bf0794Smrg		amdgpu_drm_abort_entry(drm_queue_seq);
122424b90cf4Smrg		RegionCopy(DamageRegion(drmmode_crtc->scanout_damage),
122524b90cf4Smrg			   &drmmode_crtc->scanout_last_region);
122624b90cf4Smrg		RegionEmpty(&drmmode_crtc->scanout_last_region);
122724b90cf4Smrg		amdgpu_scanout_update(xf86_crtc);
122824b90cf4Smrg		drmmode_crtc_scanout_destroy(drmmode_crtc->drmmode,
122924b90cf4Smrg					     &drmmode_crtc->scanout[scanout_id]);
123024b90cf4Smrg		drmmode_crtc->tear_free = FALSE;
1231d6c0b56eSmrg		return;
1232d6c0b56eSmrg	}
1233d6c0b56eSmrg
123490f2b693Smrg	if (drmmode_crtc->scanout_status & DRMMODE_SCANOUT_FLIP_FAILED) {
123590f2b693Smrg		xf86DrvMsg(scrn->scrnIndex, X_INFO, "TearFree active again\n");
123690f2b693Smrg		drmmode_crtc->scanout_status &= ~DRMMODE_SCANOUT_FLIP_FAILED;
123790f2b693Smrg	}
123890f2b693Smrg
1239d6c0b56eSmrg	drmmode_crtc->scanout_id = scanout_id;
124035d5b7c7Smrg	drmmode_crtc->scanout_update_pending = drm_queue_seq;
124190f2b693Smrg	drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending, fb);
1242d6c0b56eSmrg}
1243d6c0b56eSmrg
1244d6c0b56eSmrgstatic void AMDGPUBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
1245d6c0b56eSmrg{
1246d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1247d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1248d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1249d6c0b56eSmrg	int c;
1250d6c0b56eSmrg
1251d6c0b56eSmrg	pScreen->BlockHandler = info->BlockHandler;
1252d6c0b56eSmrg	(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
1253d6c0b56eSmrg	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
1254d6c0b56eSmrg
125524b90cf4Smrg	if (!xf86ScreenToScrn(amdgpu_master_screen(pScreen))->vtSema)
125624b90cf4Smrg		return;
125724b90cf4Smrg
125824b90cf4Smrg	if (!pScreen->isGPU)
1259504d986fSmrg	{
1260504d986fSmrg		for (c = 0; c < xf86_config->num_crtc; c++) {
126111bf0794Smrg			xf86CrtcPtr crtc = xf86_config->crtc[c];
126211bf0794Smrg			drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
126311bf0794Smrg
126435d5b7c7Smrg			if (drmmode_crtc->rotate.pixmap)
126535d5b7c7Smrg				continue;
126635d5b7c7Smrg
126711bf0794Smrg			if (drmmode_crtc->tear_free)
126811bf0794Smrg				amdgpu_scanout_flip(pScreen, info, crtc);
126924b90cf4Smrg			else if (drmmode_crtc->scanout[drmmode_crtc->scanout_id].pixmap)
127011bf0794Smrg				amdgpu_scanout_update(crtc);
1271504d986fSmrg		}
1272d6c0b56eSmrg	}
1273d6c0b56eSmrg
127411bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,19,0,0,0)
1275d6c0b56eSmrg	if (info->use_glamor)
1276d6c0b56eSmrg		amdgpu_glamor_flush(pScrn);
127711bf0794Smrg#endif
1278d6c0b56eSmrg
1279504d986fSmrg	amdgpu_dirty_update(pScrn);
1280d6c0b56eSmrg}
1281d6c0b56eSmrg
1282d6c0b56eSmrg/* This is called by AMDGPUPreInit to set up the default visual */
1283d6c0b56eSmrgstatic Bool AMDGPUPreInitVisual(ScrnInfoPtr pScrn)
1284d6c0b56eSmrg{
1285d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1286d6c0b56eSmrg
1287d6c0b56eSmrg	if (!xf86SetDepthBpp(pScrn, 0, 0, 0, Support32bppFb))
1288d6c0b56eSmrg		return FALSE;
1289d6c0b56eSmrg
1290d6c0b56eSmrg	switch (pScrn->depth) {
1291d6c0b56eSmrg	case 8:
1292d6c0b56eSmrg	case 15:
1293d6c0b56eSmrg	case 16:
1294d6c0b56eSmrg	case 24:
129524b90cf4Smrg	case 30:
1296d6c0b56eSmrg		break;
1297d6c0b56eSmrg
1298d6c0b56eSmrg	default:
1299d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1300d6c0b56eSmrg			   "Given depth (%d) is not supported by %s driver\n",
1301d6c0b56eSmrg			   pScrn->depth, AMDGPU_DRIVER_NAME);
1302d6c0b56eSmrg		return FALSE;
1303d6c0b56eSmrg	}
1304d6c0b56eSmrg
1305d6c0b56eSmrg	xf86PrintDepthBpp(pScrn);
1306d6c0b56eSmrg
1307d6c0b56eSmrg	info->pix24bpp = xf86GetBppFromDepth(pScrn, pScrn->depth);
1308d6c0b56eSmrg	info->pixel_bytes = pScrn->bitsPerPixel / 8;
1309d6c0b56eSmrg
1310d6c0b56eSmrg	if (info->pix24bpp == 24) {
1311d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1312d6c0b56eSmrg			   "Amdgpu does NOT support 24bpp\n");
1313d6c0b56eSmrg		return FALSE;
1314d6c0b56eSmrg	}
1315d6c0b56eSmrg
1316d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1317d6c0b56eSmrg		   "Pixel depth = %d bits stored in %d byte%s (%d bpp pixmaps)\n",
1318d6c0b56eSmrg		   pScrn->depth,
1319d6c0b56eSmrg		   info->pixel_bytes,
1320d6c0b56eSmrg		   info->pixel_bytes > 1 ? "s" : "", info->pix24bpp);
1321d6c0b56eSmrg
1322d6c0b56eSmrg	if (!xf86SetDefaultVisual(pScrn, -1))
1323d6c0b56eSmrg		return FALSE;
1324d6c0b56eSmrg
1325d6c0b56eSmrg	if (pScrn->depth > 8 && pScrn->defaultVisual != TrueColor) {
1326d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1327d6c0b56eSmrg			   "Default visual (%s) is not supported at depth %d\n",
1328d6c0b56eSmrg			   xf86GetVisualName(pScrn->defaultVisual),
1329d6c0b56eSmrg			   pScrn->depth);
1330d6c0b56eSmrg		return FALSE;
1331d6c0b56eSmrg	}
1332d6c0b56eSmrg	return TRUE;
1333d6c0b56eSmrg}
1334d6c0b56eSmrg
1335d6c0b56eSmrg/* This is called by AMDGPUPreInit to handle all color weight issues */
1336d6c0b56eSmrgstatic Bool AMDGPUPreInitWeight(ScrnInfoPtr pScrn)
1337d6c0b56eSmrg{
1338d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1339d6c0b56eSmrg
1340d6c0b56eSmrg	/* Save flag for 6 bit DAC to use for
1341d6c0b56eSmrg	   setting CRTC registers.  Otherwise use
1342d6c0b56eSmrg	   an 8 bit DAC, even if xf86SetWeight sets
1343d6c0b56eSmrg	   pScrn->rgbBits to some value other than
1344d6c0b56eSmrg	   8. */
1345d6c0b56eSmrg	info->dac6bits = FALSE;
1346d6c0b56eSmrg
1347d6c0b56eSmrg	if (pScrn->depth > 8) {
1348d6c0b56eSmrg		rgb defaultWeight = { 0, 0, 0 };
1349d6c0b56eSmrg
1350d6c0b56eSmrg		if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
1351d6c0b56eSmrg			return FALSE;
1352d6c0b56eSmrg	} else {
1353d6c0b56eSmrg		pScrn->rgbBits = 8;
1354d6c0b56eSmrg	}
1355d6c0b56eSmrg
1356d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1357d6c0b56eSmrg		   "Using %d bits per RGB (%d bit DAC)\n",
1358d6c0b56eSmrg		   pScrn->rgbBits, info->dac6bits ? 6 : 8);
1359d6c0b56eSmrg
1360d6c0b56eSmrg	return TRUE;
1361d6c0b56eSmrg}
1362d6c0b56eSmrg
1363d6c0b56eSmrgstatic Bool AMDGPUPreInitAccel_KMS(ScrnInfoPtr pScrn)
1364d6c0b56eSmrg{
1365d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1366d6c0b56eSmrg
1367d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_ACCEL, TRUE)) {
1368d6c0b56eSmrg		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1369d6c0b56eSmrg		Bool use_glamor = TRUE;
1370d6c0b56eSmrg#ifdef HAVE_GBM_BO_USE_LINEAR
1371d6c0b56eSmrg		const char *accel_method;
1372d6c0b56eSmrg
1373d6c0b56eSmrg		accel_method = xf86GetOptValString(info->Options, OPTION_ACCEL_METHOD);
1374d6c0b56eSmrg		if ((accel_method && !strcmp(accel_method, "none")))
1375d6c0b56eSmrg			use_glamor = FALSE;
1376d6c0b56eSmrg#endif
1377d6c0b56eSmrg
1378d6c0b56eSmrg#ifdef DRI2
1379d6c0b56eSmrg		info->dri2.available = ! !xf86LoadSubModule(pScrn, "dri2");
1380d6c0b56eSmrg#endif
1381d6c0b56eSmrg
1382d6c0b56eSmrg		if (info->dri2.available)
1383d6c0b56eSmrg			info->gbm = gbm_create_device(pAMDGPUEnt->fd);
1384d6c0b56eSmrg
138524b90cf4Smrg		if (info->gbm) {
138635d5b7c7Smrg			if (use_glamor) {
138735d5b7c7Smrg				if (amdgpu_glamor_pre_init(pScrn))
138835d5b7c7Smrg					return TRUE;
138935d5b7c7Smrg
139035d5b7c7Smrg				xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
139135d5b7c7Smrg					   "amdgpu_glamor_pre_init returned "
139235d5b7c7Smrg					   "FALSE, using ShadowFB\n");
139335d5b7c7Smrg			}
139424b90cf4Smrg		} else {
139524b90cf4Smrg			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
139624b90cf4Smrg				   "gbm_create_device returned NULL, using "
139724b90cf4Smrg				   "ShadowFB\n");
139824b90cf4Smrg		}
139924b90cf4Smrg	} else {
140024b90cf4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_CONFIG,
140124b90cf4Smrg			   "GPU acceleration disabled, using ShadowFB\n");
1402d6c0b56eSmrg	}
1403d6c0b56eSmrg
1404d6c0b56eSmrg	if (!xf86LoadSubModule(pScrn, "shadow"))
140524b90cf4Smrg		return FALSE;
1406d6c0b56eSmrg
140724b90cf4Smrg	info->dri2.available = FALSE;
140824b90cf4Smrg	info->shadow_fb = TRUE;
1409d6c0b56eSmrg	return TRUE;
1410d6c0b56eSmrg}
1411d6c0b56eSmrg
141211bf0794Smrgstatic Bool AMDGPUPreInitChipType_KMS(ScrnInfoPtr pScrn,
141311bf0794Smrg				      struct amdgpu_gpu_info *gpu_info)
1414d6c0b56eSmrg{
1415d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
141611bf0794Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1417d6c0b56eSmrg
141811bf0794Smrg	info->Chipset = info->PciInfo->device_id;
141990f2b693Smrg	pScrn->chipset = (char*)amdgpu_get_marketing_name(pAMDGPUEnt->pDev);
142011bf0794Smrg	if (!pScrn->chipset)
142111bf0794Smrg		pScrn->chipset = "Unknown AMD Radeon GPU";
1422d6c0b56eSmrg
1423d6c0b56eSmrg	if (info->Chipset < 0) {
1424d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1425d6c0b56eSmrg			   "Chipset \"%s\" is not recognized\n",
1426d6c0b56eSmrg			   pScrn->chipset);
1427d6c0b56eSmrg		return FALSE;
1428d6c0b56eSmrg	}
1429d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_PROBED,
1430d6c0b56eSmrg		   "Chipset: \"%s\" (ChipID = 0x%04x)\n",
1431d6c0b56eSmrg		   pScrn->chipset, info->Chipset);
1432d6c0b56eSmrg
143311bf0794Smrg	info->family = gpu_info->family_id;
1434d6c0b56eSmrg
1435d6c0b56eSmrg	return TRUE;
1436d6c0b56eSmrg}
1437d6c0b56eSmrg
143811bf0794Smrgstatic Bool amdgpu_get_tile_config(AMDGPUInfoPtr info,
143911bf0794Smrg				   struct amdgpu_gpu_info *gpu_info)
1440d6c0b56eSmrg{
144111bf0794Smrg	switch ((gpu_info->gb_addr_cfg & 0x70) >> 4) {
1442d6c0b56eSmrg	case 0:
1443d6c0b56eSmrg		info->group_bytes = 256;
1444d6c0b56eSmrg		break;
1445d6c0b56eSmrg	case 1:
1446d6c0b56eSmrg		info->group_bytes = 512;
1447d6c0b56eSmrg		break;
1448d6c0b56eSmrg	default:
1449d6c0b56eSmrg		return FALSE;
1450d6c0b56eSmrg	}
1451d6c0b56eSmrg
1452d6c0b56eSmrg	info->have_tiling_info = TRUE;
1453d6c0b56eSmrg	return TRUE;
1454d6c0b56eSmrg}
1455d6c0b56eSmrg
1456d6c0b56eSmrgstatic void AMDGPUSetupCapabilities(ScrnInfoPtr pScrn)
1457d6c0b56eSmrg{
1458d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1459d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1460d6c0b56eSmrg	uint64_t value;
1461d6c0b56eSmrg	int ret;
1462d6c0b56eSmrg
1463d6c0b56eSmrg	pScrn->capabilities = 0;
1464d6c0b56eSmrg
1465d6c0b56eSmrg	/* PRIME offloading requires acceleration */
1466d6c0b56eSmrg	if (!info->use_glamor)
1467d6c0b56eSmrg		return;
1468d6c0b56eSmrg
1469d6c0b56eSmrg	ret = drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PRIME, &value);
1470d6c0b56eSmrg	if (ret == 0) {
1471d6c0b56eSmrg		if (value & DRM_PRIME_CAP_EXPORT)
1472504d986fSmrg			pScrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SourceOffload;
1473504d986fSmrg		if (value & DRM_PRIME_CAP_IMPORT) {
1474504d986fSmrg			pScrn->capabilities |= RR_Capability_SinkOffload;
1475504d986fSmrg			if (info->drmmode.count_crtcs)
1476504d986fSmrg				pScrn->capabilities |= RR_Capability_SinkOutput;
1477504d986fSmrg		}
1478d6c0b56eSmrg	}
1479d6c0b56eSmrg}
1480d6c0b56eSmrg
1481d6c0b56eSmrg/* When the root window is created, initialize the screen contents from
1482d6c0b56eSmrg * console if -background none was specified on the command line
1483d6c0b56eSmrg */
1484d6c0b56eSmrgstatic Bool AMDGPUCreateWindow_oneshot(WindowPtr pWin)
1485d6c0b56eSmrg{
1486d6c0b56eSmrg	ScreenPtr pScreen = pWin->drawable.pScreen;
1487d6c0b56eSmrg	ScrnInfoPtr pScrn;
1488d6c0b56eSmrg	AMDGPUInfoPtr info;
1489d6c0b56eSmrg	Bool ret;
1490d6c0b56eSmrg
1491d6c0b56eSmrg	if (pWin != pScreen->root)
1492d6c0b56eSmrg		ErrorF("%s called for non-root window %p\n", __func__, pWin);
1493d6c0b56eSmrg
1494d6c0b56eSmrg	pScrn = xf86ScreenToScrn(pScreen);
1495d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
1496d6c0b56eSmrg	pScreen->CreateWindow = info->CreateWindow;
1497d6c0b56eSmrg	ret = pScreen->CreateWindow(pWin);
1498d6c0b56eSmrg
1499d6c0b56eSmrg	if (ret)
1500d6c0b56eSmrg		drmmode_copy_fb(pScrn, &info->drmmode);
1501d6c0b56eSmrg
1502d6c0b56eSmrg	return ret;
1503d6c0b56eSmrg}
1504d6c0b56eSmrg
150511bf0794Smrg/* When the root window is mapped, set the initial modes */
150624b90cf4Smrgvoid AMDGPUWindowExposures_oneshot(WindowPtr pWin, RegionPtr pRegion
150711bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
150824b90cf4Smrg				   , RegionPtr pBSRegion
150911bf0794Smrg#endif
151024b90cf4Smrg				   )
151111bf0794Smrg{
151211bf0794Smrg	ScreenPtr pScreen = pWin->drawable.pScreen;
151311bf0794Smrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
151411bf0794Smrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
151511bf0794Smrg
151611bf0794Smrg	if (pWin != pScreen->root)
151711bf0794Smrg		ErrorF("%s called for non-root window %p\n", __func__, pWin);
151811bf0794Smrg
151911bf0794Smrg	pScreen->WindowExposures = info->WindowExposures;
152011bf0794Smrg#if XORG_VERSION_CURRENT < XORG_VERSION_NUMERIC(1,16,99,901,0)
152111bf0794Smrg	pScreen->WindowExposures(pWin, pRegion, pBSRegion);
152211bf0794Smrg#else
152311bf0794Smrg	pScreen->WindowExposures(pWin, pRegion);
152411bf0794Smrg#endif
152511bf0794Smrg
152611bf0794Smrg	amdgpu_glamor_finish(pScrn);
152711bf0794Smrg	drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE);
152811bf0794Smrg}
152911bf0794Smrg
1530d6c0b56eSmrgBool AMDGPUPreInit_KMS(ScrnInfoPtr pScrn, int flags)
1531d6c0b56eSmrg{
1532d6c0b56eSmrg	AMDGPUInfoPtr info;
1533d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt;
153411bf0794Smrg	struct amdgpu_gpu_info gpu_info;
153511bf0794Smrg	MessageType from;
1536d6c0b56eSmrg	Gamma zeros = { 0.0, 0.0, 0.0 };
1537d6c0b56eSmrg	int cpp;
1538d6c0b56eSmrg	uint64_t heap_size = 0;
1539d6c0b56eSmrg	uint64_t max_allocation = 0;
1540d6c0b56eSmrg	Bool sw_cursor;
1541d6c0b56eSmrg
1542d6c0b56eSmrg	if (flags & PROBE_DETECT)
1543d6c0b56eSmrg		return TRUE;
1544d6c0b56eSmrg
1545d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1546d6c0b56eSmrg		       "AMDGPUPreInit_KMS\n");
1547d6c0b56eSmrg	if (pScrn->numEntities != 1)
1548d6c0b56eSmrg		return FALSE;
154990f2b693Smrg
155090f2b693Smrg	pAMDGPUEnt = xf86GetEntityPrivate(pScrn->entityList[0],
155190f2b693Smrg					  getAMDGPUEntityIndex())->ptr;
155290f2b693Smrg
1553d6c0b56eSmrg	if (!AMDGPUGetRec(pScrn))
1554d6c0b56eSmrg		return FALSE;
1555d6c0b56eSmrg
1556d6c0b56eSmrg	info = AMDGPUPTR(pScrn);
155790f2b693Smrg	info->instance_id = pAMDGPUEnt->num_scrns++;
155890f2b693Smrg	pAMDGPUEnt->scrn[info->instance_id] = pScrn;
155990f2b693Smrg
1560d6c0b56eSmrg	info->pEnt =
1561d6c0b56eSmrg	    xf86GetEntityInfo(pScrn->entityList[pScrn->numEntities - 1]);
1562d6c0b56eSmrg	if (info->pEnt->location.type != BUS_PCI
1563d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS
1564d6c0b56eSmrg	    && info->pEnt->location.type != BUS_PLATFORM
1565d6c0b56eSmrg#endif
1566d6c0b56eSmrg	    )
156724b90cf4Smrg		return FALSE;
1568d6c0b56eSmrg
156990f2b693Smrg	if (xf86IsEntityShared(pScrn->entityList[0]) &&
157090f2b693Smrg	    info->instance_id == 0) {
157190f2b693Smrg		xf86SetPrimInitDone(pScrn->entityList[0]);
1572d6c0b56eSmrg	}
1573d6c0b56eSmrg
1574d6c0b56eSmrg	info->PciInfo = xf86GetPciInfoForEntity(info->pEnt->index);
1575d6c0b56eSmrg	pScrn->monitor = pScrn->confScreen->monitor;
1576d6c0b56eSmrg
1577d6c0b56eSmrg	if (!AMDGPUPreInitVisual(pScrn))
157824b90cf4Smrg		return FALSE;
1579d6c0b56eSmrg
1580d6c0b56eSmrg	xf86CollectOptions(pScrn, NULL);
1581d6c0b56eSmrg	if (!(info->Options = malloc(sizeof(AMDGPUOptions_KMS))))
158224b90cf4Smrg		return FALSE;
1583d6c0b56eSmrg
1584d6c0b56eSmrg	memcpy(info->Options, AMDGPUOptions_KMS, sizeof(AMDGPUOptions_KMS));
1585d6c0b56eSmrg	xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, info->Options);
1586d6c0b56eSmrg
1587d6c0b56eSmrg	if (!AMDGPUPreInitWeight(pScrn))
158824b90cf4Smrg		return FALSE;
1589d6c0b56eSmrg
159011bf0794Smrg	memset(&gpu_info, 0, sizeof(gpu_info));
159111bf0794Smrg	amdgpu_query_gpu_info(pAMDGPUEnt->pDev, &gpu_info);
159211bf0794Smrg
159311bf0794Smrg	if (!AMDGPUPreInitChipType_KMS(pScrn, &gpu_info))
159424b90cf4Smrg		return FALSE;
1595d6c0b56eSmrg
1596d6c0b56eSmrg	info->dri2.available = FALSE;
1597d6c0b56eSmrg	info->dri2.enabled = FALSE;
159890f2b693Smrg	info->dri2.pKernelDRMVersion = drmGetVersion(pAMDGPUEnt->fd);
159990f2b693Smrg	if (info->dri2.pKernelDRMVersion == NULL) {
160090f2b693Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
160190f2b693Smrg			   "AMDGPUDRIGetVersion failed to get the DRM version\n");
160290f2b693Smrg		return FALSE;
160390f2b693Smrg	}
1604d6c0b56eSmrg
1605d6c0b56eSmrg	/* Get ScreenInit function */
1606d6c0b56eSmrg	if (!xf86LoadSubModule(pScrn, "fb"))
1607d6c0b56eSmrg		return FALSE;
1608d6c0b56eSmrg
1609d6c0b56eSmrg	if (!AMDGPUPreInitAccel_KMS(pScrn))
161024b90cf4Smrg		return FALSE;
1611d6c0b56eSmrg
161235d5b7c7Smrg	amdgpu_drm_queue_init(pScrn);
1613d6c0b56eSmrg
1614d6c0b56eSmrg	/* don't enable tiling if accel is not enabled */
1615d6c0b56eSmrg	if (info->use_glamor) {
1616d6c0b56eSmrg		/* set default group bytes, overridden by kernel info below */
1617d6c0b56eSmrg		info->group_bytes = 256;
1618d6c0b56eSmrg		info->have_tiling_info = FALSE;
161911bf0794Smrg		amdgpu_get_tile_config(info, &gpu_info);
1620d6c0b56eSmrg	}
1621d6c0b56eSmrg
1622d6c0b56eSmrg	if (info->use_glamor) {
162311bf0794Smrg		from = X_DEFAULT;
1624d6c0b56eSmrg
162511bf0794Smrg		info->tear_free = 2;
162611bf0794Smrg		if (xf86GetOptValBool(info->Options, OPTION_TEAR_FREE,
162711bf0794Smrg				      &info->tear_free))
162811bf0794Smrg			from = X_CONFIG;
162911bf0794Smrg		xf86DrvMsg(pScrn->scrnIndex, from, "TearFree property default: %s\n",
163011bf0794Smrg			   info->tear_free == 2 ? "auto" : (info->tear_free ? "on" : "off"));
1631d6c0b56eSmrg
1632d6c0b56eSmrg		info->shadow_primary =
1633d6c0b56eSmrg			xf86ReturnOptValBool(info->Options, OPTION_SHADOW_PRIMARY, FALSE);
1634d6c0b56eSmrg
1635d6c0b56eSmrg		if (info->shadow_primary)
1636d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "ShadowPrimary enabled\n");
163790f2b693Smrg
163890f2b693Smrg		if (!pScrn->is_gpu) {
163990f2b693Smrg			from = xf86GetOptValBool(info->Options, OPTION_VARIABLE_REFRESH,
164090f2b693Smrg						 &info->vrr_support) ? X_CONFIG : X_DEFAULT;
164190f2b693Smrg
164290f2b693Smrg			xf86DrvMsg(pScrn->scrnIndex, from, "VariableRefresh: %sabled\n",
164390f2b693Smrg				   info->vrr_support ? "en" : "dis");
164490f2b693Smrg		}
1645d6c0b56eSmrg	}
1646d6c0b56eSmrg
164724b90cf4Smrg	if (!pScrn->is_gpu) {
164811bf0794Smrg		sw_cursor = xf86ReturnOptValBool(info->Options,
164911bf0794Smrg						 OPTION_SW_CURSOR, FALSE);
165011bf0794Smrg
165111bf0794Smrg		info->allowPageFlip = xf86ReturnOptValBool(info->Options,
165211bf0794Smrg							   OPTION_PAGE_FLIP,
165311bf0794Smrg							   TRUE);
165411bf0794Smrg		if (sw_cursor || info->shadow_primary) {
165511bf0794Smrg			xf86DrvMsg(pScrn->scrnIndex,
165611bf0794Smrg				   info->allowPageFlip ? X_WARNING : X_DEFAULT,
165711bf0794Smrg				   "KMS Pageflipping: disabled%s\n",
165811bf0794Smrg				   info->allowPageFlip ?
165911bf0794Smrg				   (sw_cursor ? " because of SWcursor" :
166011bf0794Smrg				    " because of ShadowPrimary") : "");
166111bf0794Smrg			info->allowPageFlip = FALSE;
166211bf0794Smrg		} else {
166311bf0794Smrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
166411bf0794Smrg				   "KMS Pageflipping: %sabled\n",
166511bf0794Smrg				   info->allowPageFlip ? "en" : "dis");
166611bf0794Smrg		}
1667d6c0b56eSmrg	}
1668d6c0b56eSmrg
1669d6c0b56eSmrg	if (xf86ReturnOptValBool(info->Options, OPTION_DELETE_DP12, FALSE)) {
1670d6c0b56eSmrg		info->drmmode.delete_dp_12_displays = TRUE;
1671d6c0b56eSmrg	}
1672d6c0b56eSmrg
1673d6c0b56eSmrg	if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) ==
1674d6c0b56eSmrg	    FALSE) {
1675d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1676d6c0b56eSmrg			   "Kernel modesetting setup failed\n");
167724b90cf4Smrg		return FALSE;
1678d6c0b56eSmrg	}
1679d6c0b56eSmrg
1680504d986fSmrg	AMDGPUSetupCapabilities(pScrn);
1681504d986fSmrg
1682d6c0b56eSmrg	if (info->drmmode.count_crtcs == 1)
1683d6c0b56eSmrg		pAMDGPUEnt->HasCRTC2 = FALSE;
1684d6c0b56eSmrg	else
1685d6c0b56eSmrg		pAMDGPUEnt->HasCRTC2 = TRUE;
1686d6c0b56eSmrg
168711bf0794Smrg	if (info->family < AMDGPU_FAMILY_CI) {
1688504d986fSmrg		info->cursor_w = CURSOR_WIDTH;
1689504d986fSmrg		info->cursor_h = CURSOR_HEIGHT;
1690504d986fSmrg	} else {
1691504d986fSmrg		info->cursor_w = CURSOR_WIDTH_CIK;
1692504d986fSmrg		info->cursor_h = CURSOR_HEIGHT_CIK;
1693504d986fSmrg	}
1694d6c0b56eSmrg
1695d6c0b56eSmrg	amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_GTT,
1696d6c0b56eSmrg				&heap_size, &max_allocation);
1697d6c0b56eSmrg	info->gart_size = heap_size;
1698d6c0b56eSmrg	amdgpu_query_heap_size(pAMDGPUEnt->pDev, AMDGPU_GEM_DOMAIN_VRAM,
1699d6c0b56eSmrg				&heap_size, &max_allocation);
1700d6c0b56eSmrg	info->vram_size = max_allocation;
1701d6c0b56eSmrg
1702d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1703d6c0b56eSmrg		   "mem size init: gart size :%llx vram size: s:%llx visible:%llx\n",
1704d6c0b56eSmrg		   (unsigned long long)info->gart_size,
1705d6c0b56eSmrg		   (unsigned long long)heap_size,
1706d6c0b56eSmrg		   (unsigned long long)max_allocation);
1707d6c0b56eSmrg
1708d6c0b56eSmrg	cpp = pScrn->bitsPerPixel / 8;
1709d6c0b56eSmrg	pScrn->displayWidth =
1710d6c0b56eSmrg	    AMDGPU_ALIGN(pScrn->virtualX, drmmode_get_pitch_align(pScrn, cpp));
1711d6c0b56eSmrg
1712d6c0b56eSmrg	/* Set display resolution */
1713d6c0b56eSmrg	xf86SetDpi(pScrn, 0, 0);
1714d6c0b56eSmrg
1715d6c0b56eSmrg	if (!xf86SetGamma(pScrn, zeros))
1716d6c0b56eSmrg		return FALSE;
1717d6c0b56eSmrg
1718d6c0b56eSmrg	if (!xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE)) {
1719d6c0b56eSmrg		if (!xf86LoadSubModule(pScrn, "ramdac"))
1720d6c0b56eSmrg			return FALSE;
1721d6c0b56eSmrg	}
1722d6c0b56eSmrg
172335d5b7c7Smrg	if (!pScrn->modes
1724d6c0b56eSmrg#ifdef XSERVER_PLATFORM_BUS
1725d6c0b56eSmrg	    && !pScrn->is_gpu
1726d6c0b56eSmrg#endif
1727d6c0b56eSmrg	    ) {
1728d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
172924b90cf4Smrg		return FALSE;
1730d6c0b56eSmrg	}
1731d6c0b56eSmrg
1732d6c0b56eSmrg	return TRUE;
1733d6c0b56eSmrg}
1734d6c0b56eSmrg
1735d6c0b56eSmrgstatic Bool AMDGPUCursorInit_KMS(ScreenPtr pScreen)
1736d6c0b56eSmrg{
1737d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1738d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1739d6c0b56eSmrg
174024b90cf4Smrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
174124b90cf4Smrg		       "Initializing Cursor\n");
174224b90cf4Smrg
174324b90cf4Smrg	/* Set Silken Mouse */
174424b90cf4Smrg	xf86SetSilkenMouse(pScreen);
174524b90cf4Smrg
174624b90cf4Smrg	/* Cursor setup */
174724b90cf4Smrg	miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
174824b90cf4Smrg
174924b90cf4Smrg	if (info->allowPageFlip) {
175024b90cf4Smrg		miPointerScreenPtr PointPriv =
175124b90cf4Smrg			dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
175224b90cf4Smrg
175324b90cf4Smrg		if (!dixRegisterScreenPrivateKey(&amdgpu_device_private_key, pScreen,
175424b90cf4Smrg						 PRIVATE_DEVICE,
175524b90cf4Smrg						 sizeof(struct amdgpu_device_priv))) {
175624b90cf4Smrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "dixRegisterScreenPrivateKey failed\n");
175724b90cf4Smrg			return FALSE;
175824b90cf4Smrg		}
175924b90cf4Smrg
176035d5b7c7Smrg		info->SpriteFuncs = PointPriv->spriteFuncs;
176135d5b7c7Smrg		PointPriv->spriteFuncs = &drmmode_sprite_funcs;
176224b90cf4Smrg	}
176324b90cf4Smrg
176424b90cf4Smrg	if (xf86ReturnOptValBool(info->Options, OPTION_SW_CURSOR, FALSE))
176524b90cf4Smrg		return TRUE;
176624b90cf4Smrg
176724b90cf4Smrg	if (!xf86_cursors_init(pScreen, info->cursor_w, info->cursor_h,
176824b90cf4Smrg			       HARDWARE_CURSOR_TRUECOLOR_AT_8BPP |
176924b90cf4Smrg			       HARDWARE_CURSOR_AND_SOURCE_WITH_MASK |
177024b90cf4Smrg			       HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_1 |
177124b90cf4Smrg			       HARDWARE_CURSOR_UPDATE_UNHIDDEN |
177224b90cf4Smrg			       HARDWARE_CURSOR_ARGB)) {
177324b90cf4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "xf86_cursors_init failed\n");
177424b90cf4Smrg		return FALSE;
177524b90cf4Smrg	}
177624b90cf4Smrg
177724b90cf4Smrg	return TRUE;
1778d6c0b56eSmrg}
1779d6c0b56eSmrg
1780d6c0b56eSmrgvoid AMDGPUBlank(ScrnInfoPtr pScrn)
1781d6c0b56eSmrg{
1782d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1783d6c0b56eSmrg	xf86OutputPtr output;
1784d6c0b56eSmrg	xf86CrtcPtr crtc;
1785d6c0b56eSmrg	int o, c;
1786d6c0b56eSmrg
1787d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
1788d6c0b56eSmrg		crtc = xf86_config->crtc[c];
1789d6c0b56eSmrg		for (o = 0; o < xf86_config->num_output; o++) {
1790d6c0b56eSmrg			output = xf86_config->output[o];
1791d6c0b56eSmrg			if (output->crtc != crtc)
1792d6c0b56eSmrg				continue;
1793d6c0b56eSmrg
1794d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOff);
1795d6c0b56eSmrg		}
1796d6c0b56eSmrg		crtc->funcs->dpms(crtc, DPMSModeOff);
1797d6c0b56eSmrg	}
1798d6c0b56eSmrg}
1799d6c0b56eSmrg
1800d6c0b56eSmrgvoid AMDGPUUnblank(ScrnInfoPtr pScrn)
1801d6c0b56eSmrg{
1802d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1803d6c0b56eSmrg	xf86OutputPtr output;
1804d6c0b56eSmrg	xf86CrtcPtr crtc;
1805d6c0b56eSmrg	int o, c;
1806d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
1807d6c0b56eSmrg		crtc = xf86_config->crtc[c];
1808d6c0b56eSmrg		if (!crtc->enabled)
1809d6c0b56eSmrg			continue;
1810d6c0b56eSmrg		crtc->funcs->dpms(crtc, DPMSModeOn);
1811d6c0b56eSmrg		for (o = 0; o < xf86_config->num_output; o++) {
1812d6c0b56eSmrg			output = xf86_config->output[o];
1813d6c0b56eSmrg			if (output->crtc != crtc)
1814d6c0b56eSmrg				continue;
1815d6c0b56eSmrg			output->funcs->dpms(output, DPMSModeOn);
1816d6c0b56eSmrg		}
1817d6c0b56eSmrg	}
1818d6c0b56eSmrg}
1819d6c0b56eSmrg
1820d6c0b56eSmrgstatic Bool amdgpu_set_drm_master(ScrnInfoPtr pScrn)
1821d6c0b56eSmrg{
1822d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1823d6c0b56eSmrg	int err;
1824d6c0b56eSmrg
1825d6c0b56eSmrg#ifdef XF86_PDEV_SERVER_FD
1826d6c0b56eSmrg	if (pAMDGPUEnt->platform_dev &&
1827d6c0b56eSmrg	    (pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
1828d6c0b56eSmrg		return TRUE;
1829d6c0b56eSmrg#endif
1830d6c0b56eSmrg
1831d6c0b56eSmrg	err = drmSetMaster(pAMDGPUEnt->fd);
1832d6c0b56eSmrg	if (err)
1833d6c0b56eSmrg		ErrorF("Unable to retrieve master\n");
1834d6c0b56eSmrg
1835d6c0b56eSmrg	return err == 0;
1836d6c0b56eSmrg}
1837d6c0b56eSmrg
1838d6c0b56eSmrgstatic void amdgpu_drop_drm_master(ScrnInfoPtr pScrn)
1839d6c0b56eSmrg{
1840d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1841d6c0b56eSmrg
1842d6c0b56eSmrg#ifdef XF86_PDEV_SERVER_FD
1843d6c0b56eSmrg	if (pAMDGPUEnt->platform_dev &&
1844d6c0b56eSmrg	    (pAMDGPUEnt->platform_dev->flags & XF86_PDEV_SERVER_FD))
1845d6c0b56eSmrg		return;
1846d6c0b56eSmrg#endif
1847d6c0b56eSmrg
1848d6c0b56eSmrg	drmDropMaster(pAMDGPUEnt->fd);
1849d6c0b56eSmrg}
1850d6c0b56eSmrg
1851d6c0b56eSmrg
185224b90cf4Smrgstatic
185324b90cf4SmrgCARD32 cleanup_black_fb(OsTimerPtr timer, CARD32 now, pointer data)
185424b90cf4Smrg{
185524b90cf4Smrg	ScreenPtr screen = data;
185624b90cf4Smrg	ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
185724b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn);
185824b90cf4Smrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
185924b90cf4Smrg	int c;
186024b90cf4Smrg
186124b90cf4Smrg	if (xf86ScreenToScrn(amdgpu_master_screen(screen))->vtSema)
186224b90cf4Smrg		return 0;
186324b90cf4Smrg
186424b90cf4Smrg	/* Unreference the all-black FB created by AMDGPULeaveVT_KMS. After
186524b90cf4Smrg	 * this, there should be no FB left created by this driver.
186624b90cf4Smrg	 */
186724b90cf4Smrg	for (c = 0; c < xf86_config->num_crtc; c++) {
186824b90cf4Smrg		drmmode_crtc_private_ptr drmmode_crtc =
186924b90cf4Smrg			xf86_config->crtc[c]->driver_private;
187024b90cf4Smrg
187124b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb, NULL);
187224b90cf4Smrg	}
187324b90cf4Smrg
187424b90cf4Smrg	TimerFree(timer);
187524b90cf4Smrg	return 0;
187624b90cf4Smrg}
1877d6c0b56eSmrg
1878d6c0b56eSmrgstatic Bool AMDGPUSaveScreen_KMS(ScreenPtr pScreen, int mode)
1879d6c0b56eSmrg{
1880d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1881d6c0b56eSmrg	Bool unblank;
1882d6c0b56eSmrg
1883d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1884d6c0b56eSmrg		       "AMDGPUSaveScreen(%d)\n", mode);
1885d6c0b56eSmrg
1886d6c0b56eSmrg	unblank = xf86IsUnblank(mode);
1887d6c0b56eSmrg	if (unblank)
1888d6c0b56eSmrg		SetTimeSinceLastInputEvent();
1889d6c0b56eSmrg
1890d6c0b56eSmrg	if ((pScrn != NULL) && pScrn->vtSema) {
1891d6c0b56eSmrg		if (unblank)
1892d6c0b56eSmrg			AMDGPUUnblank(pScrn);
1893d6c0b56eSmrg		else
1894d6c0b56eSmrg			AMDGPUBlank(pScrn);
1895d6c0b56eSmrg	}
1896d6c0b56eSmrg	return TRUE;
1897d6c0b56eSmrg}
1898d6c0b56eSmrg
1899d6c0b56eSmrg/* Called at the end of each server generation.  Restore the original
1900d6c0b56eSmrg * text mode, unmap video memory, and unwrap and call the saved
1901d6c0b56eSmrg * CloseScreen function.
1902d6c0b56eSmrg */
190324b90cf4Smrgstatic Bool AMDGPUCloseScreen_KMS(ScreenPtr pScreen)
1904d6c0b56eSmrg{
1905d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1906d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1907d6c0b56eSmrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
1908d6c0b56eSmrg
1909d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1910d6c0b56eSmrg		       "AMDGPUCloseScreen\n");
1911d6c0b56eSmrg
1912d6c0b56eSmrg	/* Clear mask of assigned crtc's in this generation */
1913d6c0b56eSmrg	pAMDGPUEnt->assigned_crtcs = 0;
1914d6c0b56eSmrg
1915d6c0b56eSmrg	drmmode_uevent_fini(pScrn, &info->drmmode);
1916d6c0b56eSmrg	amdgpu_drm_queue_close(pScrn);
1917d6c0b56eSmrg
1918504d986fSmrg	if (info->callback_event_type != -1) {
1919504d986fSmrg		DeleteCallback(&EventCallback, amdgpu_event_callback, pScrn);
1920504d986fSmrg		DeleteCallback(&FlushCallback, amdgpu_flush_callback, pScrn);
1921504d986fSmrg	}
1922d6c0b56eSmrg
1923d6c0b56eSmrg	amdgpu_sync_close(pScreen);
1924d6c0b56eSmrg	amdgpu_drop_drm_master(pScrn);
1925d6c0b56eSmrg
1926d6c0b56eSmrg	drmmode_fini(pScrn, &info->drmmode);
1927d6c0b56eSmrg	if (info->dri2.enabled) {
1928d6c0b56eSmrg		amdgpu_dri2_close_screen(pScreen);
1929d6c0b56eSmrg	}
1930d6c0b56eSmrg	amdgpu_glamor_fini(pScreen);
1931d6c0b56eSmrg	pScrn->vtSema = FALSE;
1932d6c0b56eSmrg	xf86ClearPrimInitDone(info->pEnt->index);
193324b90cf4Smrg
193424b90cf4Smrg	if (info->allowPageFlip) {
193524b90cf4Smrg		miPointerScreenPtr PointPriv =
193624b90cf4Smrg			dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
193724b90cf4Smrg
193835d5b7c7Smrg		if (PointPriv->spriteFuncs == &drmmode_sprite_funcs)
193935d5b7c7Smrg			PointPriv->spriteFuncs = info->SpriteFuncs;
194024b90cf4Smrg	}
194124b90cf4Smrg
1942d6c0b56eSmrg	pScreen->BlockHandler = info->BlockHandler;
1943d6c0b56eSmrg	pScreen->CloseScreen = info->CloseScreen;
194424b90cf4Smrg	return pScreen->CloseScreen(pScreen);
1945d6c0b56eSmrg}
1946d6c0b56eSmrg
194724b90cf4Smrgvoid AMDGPUFreeScreen_KMS(ScrnInfoPtr pScrn)
1948d6c0b56eSmrg{
1949d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
1950d6c0b56eSmrg		       "AMDGPUFreeScreen\n");
1951d6c0b56eSmrg
1952d6c0b56eSmrg	AMDGPUFreeRec(pScrn);
1953d6c0b56eSmrg}
1954d6c0b56eSmrg
195524b90cf4SmrgBool AMDGPUScreenInit_KMS(ScreenPtr pScreen, int argc, char **argv)
1956d6c0b56eSmrg{
1957d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1958d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
1959d6c0b56eSmrg	int subPixelOrder = SubPixelUnknown;
1960d6c0b56eSmrg	MessageType from;
1961d6c0b56eSmrg	Bool value;
1962d6c0b56eSmrg	int driLevel;
1963d6c0b56eSmrg	const char *s;
1964d6c0b56eSmrg	void *front_ptr;
1965d6c0b56eSmrg
1966d6c0b56eSmrg	pScrn->fbOffset = 0;
1967d6c0b56eSmrg
1968d6c0b56eSmrg	miClearVisualTypes();
1969d6c0b56eSmrg	if (!miSetVisualTypes(pScrn->depth,
1970d6c0b56eSmrg			      miGetDefaultVisualMask(pScrn->depth),
1971d6c0b56eSmrg			      pScrn->rgbBits, pScrn->defaultVisual))
1972d6c0b56eSmrg		return FALSE;
1973d6c0b56eSmrg	miSetPixmapDepths();
1974d6c0b56eSmrg
1975d6c0b56eSmrg	if (!amdgpu_set_drm_master(pScrn))
1976d6c0b56eSmrg		return FALSE;
1977d6c0b56eSmrg
1978d6c0b56eSmrg	info->directRenderingEnabled = FALSE;
1979d6c0b56eSmrg	if (info->shadow_fb == FALSE)
1980d6c0b56eSmrg		info->directRenderingEnabled = amdgpu_dri2_screen_init(pScreen);
1981d6c0b56eSmrg
1982d6c0b56eSmrg	if (!amdgpu_setup_kernel_mem(pScreen)) {
1983d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1984d6c0b56eSmrg			   "amdgpu_setup_kernel_mem failed\n");
1985d6c0b56eSmrg		return FALSE;
1986d6c0b56eSmrg	}
1987d6c0b56eSmrg	front_ptr = info->front_buffer->cpu_ptr;
1988d6c0b56eSmrg
1989d6c0b56eSmrg	if (info->shadow_fb) {
1990d6c0b56eSmrg		info->fb_shadow = calloc(1,
1991d6c0b56eSmrg					 pScrn->displayWidth * pScrn->virtualY *
1992d6c0b56eSmrg					 ((pScrn->bitsPerPixel + 7) >> 3));
199335d5b7c7Smrg		if (!info->fb_shadow) {
1994d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1995d6c0b56eSmrg				   "Failed to allocate shadow framebuffer\n");
199624b90cf4Smrg			return FALSE;
1997d6c0b56eSmrg		} else {
1998d6c0b56eSmrg			if (!fbScreenInit(pScreen, info->fb_shadow,
1999d6c0b56eSmrg					  pScrn->virtualX, pScrn->virtualY,
2000d6c0b56eSmrg					  pScrn->xDpi, pScrn->yDpi,
2001d6c0b56eSmrg					  pScrn->displayWidth,
2002d6c0b56eSmrg					  pScrn->bitsPerPixel))
2003d6c0b56eSmrg				return FALSE;
2004d6c0b56eSmrg		}
2005d6c0b56eSmrg	}
2006d6c0b56eSmrg
2007d6c0b56eSmrg	if (info->shadow_fb == FALSE) {
2008d6c0b56eSmrg		/* Init fb layer */
2009d6c0b56eSmrg		if (!fbScreenInit(pScreen, front_ptr,
2010d6c0b56eSmrg				  pScrn->virtualX, pScrn->virtualY,
2011d6c0b56eSmrg				  pScrn->xDpi, pScrn->yDpi, pScrn->displayWidth,
2012d6c0b56eSmrg				  pScrn->bitsPerPixel))
2013d6c0b56eSmrg			return FALSE;
2014d6c0b56eSmrg	}
2015d6c0b56eSmrg
2016d6c0b56eSmrg	xf86SetBlackWhitePixels(pScreen);
2017d6c0b56eSmrg
2018d6c0b56eSmrg	if (pScrn->bitsPerPixel > 8) {
2019d6c0b56eSmrg		VisualPtr visual;
2020d6c0b56eSmrg
2021d6c0b56eSmrg		visual = pScreen->visuals + pScreen->numVisuals;
2022d6c0b56eSmrg		while (--visual >= pScreen->visuals) {
2023d6c0b56eSmrg			if ((visual->class | DynamicClass) == DirectColor) {
2024d6c0b56eSmrg				visual->offsetRed = pScrn->offset.red;
2025d6c0b56eSmrg				visual->offsetGreen = pScrn->offset.green;
2026d6c0b56eSmrg				visual->offsetBlue = pScrn->offset.blue;
2027d6c0b56eSmrg				visual->redMask = pScrn->mask.red;
2028d6c0b56eSmrg				visual->greenMask = pScrn->mask.green;
2029d6c0b56eSmrg				visual->blueMask = pScrn->mask.blue;
2030d6c0b56eSmrg			}
2031d6c0b56eSmrg		}
2032d6c0b56eSmrg	}
2033d6c0b56eSmrg
2034d6c0b56eSmrg	/* Must be after RGB order fixed */
2035d6c0b56eSmrg	fbPictureInit(pScreen, 0, 0);
2036d6c0b56eSmrg
2037d6c0b56eSmrg#ifdef RENDER
2038d6c0b56eSmrg	if ((s = xf86GetOptValString(info->Options, OPTION_SUBPIXEL_ORDER))) {
2039d6c0b56eSmrg		if (strcmp(s, "RGB") == 0)
2040d6c0b56eSmrg			subPixelOrder = SubPixelHorizontalRGB;
2041d6c0b56eSmrg		else if (strcmp(s, "BGR") == 0)
2042d6c0b56eSmrg			subPixelOrder = SubPixelHorizontalBGR;
2043d6c0b56eSmrg		else if (strcmp(s, "NONE") == 0)
2044d6c0b56eSmrg			subPixelOrder = SubPixelNone;
2045d6c0b56eSmrg		PictureSetSubpixelOrder(pScreen, subPixelOrder);
2046d6c0b56eSmrg	}
2047d6c0b56eSmrg#endif
2048d6c0b56eSmrg
204924b90cf4Smrg	if (!pScreen->isGPU) {
205024b90cf4Smrg		if (xorgGetVersion() >= XORG_VERSION_NUMERIC(1,18,3,0,0))
205124b90cf4Smrg			value = info->use_glamor;
205224b90cf4Smrg		else
205324b90cf4Smrg			value = FALSE;
205411bf0794Smrg		from = X_DEFAULT;
2055d6c0b56eSmrg
205611bf0794Smrg		if (info->use_glamor) {
205711bf0794Smrg			if (xf86GetOptValBool(info->Options, OPTION_DRI3, &value))
205811bf0794Smrg				from = X_CONFIG;
2059d6c0b56eSmrg
206011bf0794Smrg			if (xf86GetOptValInteger(info->Options, OPTION_DRI, &driLevel) &&
206111bf0794Smrg			    (driLevel == 2 || driLevel == 3)) {
206211bf0794Smrg				from = X_CONFIG;
206311bf0794Smrg				value = driLevel == 3;
206411bf0794Smrg			}
2065d6c0b56eSmrg		}
2066d6c0b56eSmrg
206711bf0794Smrg		if (value) {
206811bf0794Smrg			value = amdgpu_sync_init(pScreen) &&
206911bf0794Smrg				amdgpu_present_screen_init(pScreen) &&
207011bf0794Smrg				amdgpu_dri3_screen_init(pScreen);
2071d6c0b56eSmrg
207211bf0794Smrg			if (!value)
207311bf0794Smrg				from = X_WARNING;
207411bf0794Smrg		}
2075d6c0b56eSmrg
207611bf0794Smrg		xf86DrvMsg(pScrn->scrnIndex, from, "DRI3 %sabled\n", value ? "en" : "dis");
207711bf0794Smrg	}
2078d6c0b56eSmrg
2079d6c0b56eSmrg	pScrn->vtSema = TRUE;
2080d6c0b56eSmrg	xf86SetBackingStore(pScreen);
2081d6c0b56eSmrg
2082d6c0b56eSmrg	if (info->directRenderingEnabled) {
2083d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2084d6c0b56eSmrg			   "Direct rendering enabled\n");
2085d6c0b56eSmrg	} else {
2086d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
2087d6c0b56eSmrg			   "Direct rendering disabled\n");
2088d6c0b56eSmrg	}
2089d6c0b56eSmrg
2090d6c0b56eSmrg	if (info->use_glamor && info->directRenderingEnabled) {
2091d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2092d6c0b56eSmrg			       "Initializing Acceleration\n");
2093d6c0b56eSmrg		if (amdgpu_glamor_init(pScreen)) {
2094d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2095d6c0b56eSmrg				   "Acceleration enabled\n");
2096d6c0b56eSmrg		} else {
2097d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2098d6c0b56eSmrg				   "Acceleration initialization failed\n");
2099d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO,
2100d6c0b56eSmrg				   "2D and 3D acceleration disabled\n");
2101d6c0b56eSmrg			info->use_glamor = FALSE;
2102d6c0b56eSmrg		}
2103d6c0b56eSmrg	} else if (info->directRenderingEnabled) {
2104d6c0b56eSmrg		if (!amdgpu_pixmap_init(pScreen))
2105d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D acceleration disabled\n");
2106d6c0b56eSmrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D acceleration disabled\n");
2107d6c0b56eSmrg	} else {
210824b90cf4Smrg		xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D and 3D acceleration disabled\n");
2109d6c0b56eSmrg	}
2110d6c0b56eSmrg
2111d6c0b56eSmrg	/* Init DPMS */
2112d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2113d6c0b56eSmrg		       "Initializing DPMS\n");
2114d6c0b56eSmrg	xf86DPMSInit(pScreen, xf86DPMSSet, 0);
2115d6c0b56eSmrg
211624b90cf4Smrg	if (!AMDGPUCursorInit_KMS(pScreen))
211724b90cf4Smrg		return FALSE;
2118d6c0b56eSmrg
2119d6c0b56eSmrg	/* DGA setup */
2120d6c0b56eSmrg#ifdef XFreeXDGA
2121d6c0b56eSmrg	/* DGA is dangerous on kms as the base and framebuffer location may change:
2122d6c0b56eSmrg	 * http://lists.freedesktop.org/archives/xorg-devel/2009-September/002113.html
2123d6c0b56eSmrg	 */
2124d6c0b56eSmrg	/* xf86DiDGAInit(pScreen, info->LinearAddr + pScrn->fbOffset); */
2125d6c0b56eSmrg#endif
212624b90cf4Smrg	if (info->shadow_fb == FALSE && !pScreen->isGPU) {
2127d6c0b56eSmrg		/* Init Xv */
2128d6c0b56eSmrg		xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2129d6c0b56eSmrg			       "Initializing Xv\n");
2130d6c0b56eSmrg		AMDGPUInitVideo(pScreen);
2131d6c0b56eSmrg	}
2132d6c0b56eSmrg
2133d6c0b56eSmrg	if (info->shadow_fb == TRUE) {
2134d6c0b56eSmrg		if (!shadowSetup(pScreen)) {
2135d6c0b56eSmrg			xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
2136d6c0b56eSmrg				   "Shadowfb initialization failed\n");
2137d6c0b56eSmrg			return FALSE;
2138d6c0b56eSmrg		}
2139d6c0b56eSmrg	}
2140d6c0b56eSmrg	pScrn->pScreen = pScreen;
2141d6c0b56eSmrg
214224b90cf4Smrg	if (!pScreen->isGPU) {
214311bf0794Smrg		if (serverGeneration == 1 && bgNoneRoot && info->use_glamor) {
214411bf0794Smrg			info->CreateWindow = pScreen->CreateWindow;
214511bf0794Smrg			pScreen->CreateWindow = AMDGPUCreateWindow_oneshot;
214611bf0794Smrg		}
214711bf0794Smrg		info->WindowExposures = pScreen->WindowExposures;
214811bf0794Smrg		pScreen->WindowExposures = AMDGPUWindowExposures_oneshot;
2149d6c0b56eSmrg	}
2150d6c0b56eSmrg
2151d6c0b56eSmrg	/* Provide SaveScreen & wrap BlockHandler and CloseScreen */
2152d6c0b56eSmrg	/* Wrap CloseScreen */
2153d6c0b56eSmrg	info->CloseScreen = pScreen->CloseScreen;
2154d6c0b56eSmrg	pScreen->CloseScreen = AMDGPUCloseScreen_KMS;
2155d6c0b56eSmrg	pScreen->SaveScreen = AMDGPUSaveScreen_KMS;
2156d6c0b56eSmrg	info->BlockHandler = pScreen->BlockHandler;
215711bf0794Smrg	pScreen->BlockHandler = AMDGPUBlockHandler_KMS;
2158d6c0b56eSmrg
2159d6c0b56eSmrg	info->CreateScreenResources = pScreen->CreateScreenResources;
2160d6c0b56eSmrg	pScreen->CreateScreenResources = AMDGPUCreateScreenResources_KMS;
2161d6c0b56eSmrg
2162d6c0b56eSmrg	pScreen->StartPixmapTracking = PixmapStartDirtyTracking;
2163d6c0b56eSmrg	pScreen->StopPixmapTracking = PixmapStopDirtyTracking;
2164504d986fSmrg#if HAS_SYNC_SHARED_PIXMAP
2165504d986fSmrg	pScreen->SyncSharedPixmap = amdgpu_sync_shared_pixmap;
2166d6c0b56eSmrg#endif
2167d6c0b56eSmrg
2168d6c0b56eSmrg	if (!xf86CrtcScreenInit(pScreen))
2169d6c0b56eSmrg		return FALSE;
2170d6c0b56eSmrg
2171d6c0b56eSmrg	/* Wrap pointer motion to flip touch screen around */
2172d6c0b56eSmrg//    info->PointerMoved = pScrn->PointerMoved;
2173d6c0b56eSmrg//    pScrn->PointerMoved = AMDGPUPointerMoved;
2174d6c0b56eSmrg
2175d6c0b56eSmrg	if (!drmmode_setup_colormap(pScreen, pScrn))
2176d6c0b56eSmrg		return FALSE;
2177d6c0b56eSmrg
2178d6c0b56eSmrg	/* Note unused options */
2179d6c0b56eSmrg	if (serverGeneration == 1)
2180d6c0b56eSmrg		xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
2181d6c0b56eSmrg
218290f2b693Smrg	if (info->vrr_support) {
218390f2b693Smrg		if (!amdgpu_property_vectors_wrapped) {
218490f2b693Smrg			saved_change_property = ProcVector[X_ChangeProperty];
218590f2b693Smrg			ProcVector[X_ChangeProperty] = amdgpu_change_property;
218690f2b693Smrg			saved_delete_property = ProcVector[X_DeleteProperty];
218790f2b693Smrg			ProcVector[X_DeleteProperty] = amdgpu_delete_property;
218890f2b693Smrg			amdgpu_property_vectors_wrapped = TRUE;
218990f2b693Smrg		}
219090f2b693Smrg
219190f2b693Smrg		amdgpu_vrr_atom = MakeAtom("_VARIABLE_REFRESH",
219290f2b693Smrg					   strlen("_VARIABLE_REFRESH"), TRUE);
219390f2b693Smrg	}
219490f2b693Smrg
2195d6c0b56eSmrg	drmmode_init(pScrn, &info->drmmode);
2196d6c0b56eSmrg
2197d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2198d6c0b56eSmrg		       "AMDGPUScreenInit finished\n");
2199d6c0b56eSmrg
2200d6c0b56eSmrg	return TRUE;
2201d6c0b56eSmrg}
2202d6c0b56eSmrg
220324b90cf4SmrgBool AMDGPUEnterVT_KMS(ScrnInfoPtr pScrn)
2204d6c0b56eSmrg{
2205d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2206d6c0b56eSmrg
2207d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2208d6c0b56eSmrg		       "AMDGPUEnterVT_KMS\n");
2209d6c0b56eSmrg
2210d6c0b56eSmrg	amdgpu_set_drm_master(pScrn);
2211d6c0b56eSmrg
221224b90cf4Smrg	if (info->shadow_fb) {
221324b90cf4Smrg		int pitch;
221424b90cf4Smrg		struct amdgpu_buffer *front_buffer =
221524b90cf4Smrg			amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,
221624b90cf4Smrg					       pScrn->virtualY, pScrn->depth,
221724b90cf4Smrg					       AMDGPU_CREATE_PIXMAP_LINEAR,
221824b90cf4Smrg					       pScrn->bitsPerPixel,
221924b90cf4Smrg					       &pitch);
222024b90cf4Smrg
222124b90cf4Smrg		if (front_buffer) {
222224b90cf4Smrg			if (amdgpu_bo_map(pScrn, front_buffer) == 0) {
222324b90cf4Smrg				memset(front_buffer->cpu_ptr, 0, pitch * pScrn->virtualY);
222424b90cf4Smrg				amdgpu_bo_unref(&info->front_buffer);
222524b90cf4Smrg				info->front_buffer = front_buffer;
222624b90cf4Smrg			} else {
222724b90cf4Smrg				amdgpu_bo_unref(&front_buffer);
222824b90cf4Smrg				front_buffer = NULL;
222924b90cf4Smrg			}
223024b90cf4Smrg		}
223124b90cf4Smrg
223224b90cf4Smrg		if (!front_buffer) {
223324b90cf4Smrg			xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
223424b90cf4Smrg				   "Failed to allocate new scanout BO after VT switch, "
223524b90cf4Smrg				   "other DRM masters may see screen contents\n");
223624b90cf4Smrg		}
223724b90cf4Smrg	}
223824b90cf4Smrg
2239d6c0b56eSmrg	pScrn->vtSema = TRUE;
2240d6c0b56eSmrg
2241d6c0b56eSmrg	if (!drmmode_set_desired_modes(pScrn, &info->drmmode, TRUE))
2242d6c0b56eSmrg		return FALSE;
2243d6c0b56eSmrg
2244d6c0b56eSmrg	return TRUE;
2245d6c0b56eSmrg}
2246d6c0b56eSmrg
224724b90cf4Smrgstatic void
224824b90cf4Smrgpixmap_unref_fb(void *value, XID id, void *cdata)
224924b90cf4Smrg{
225024b90cf4Smrg	PixmapPtr pixmap = value;
225124b90cf4Smrg	AMDGPUEntPtr pAMDGPUEnt = cdata;
225224b90cf4Smrg	struct drmmode_fb **fb_ptr = amdgpu_pixmap_get_fb_ptr(pixmap);
225324b90cf4Smrg
225424b90cf4Smrg	if (fb_ptr)
225524b90cf4Smrg		drmmode_fb_reference(pAMDGPUEnt->fd, fb_ptr, NULL);
225624b90cf4Smrg}
225724b90cf4Smrg
225824b90cf4Smrgvoid AMDGPULeaveVT_KMS(ScrnInfoPtr pScrn)
2259d6c0b56eSmrg{
226024b90cf4Smrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
226124b90cf4Smrg	ScreenPtr pScreen = pScrn->pScreen;
2262d6c0b56eSmrg
2263d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2264d6c0b56eSmrg		       "AMDGPULeaveVT_KMS\n");
2265d6c0b56eSmrg
226624b90cf4Smrg	if (!info->shadow_fb) {
226724b90cf4Smrg		AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
226824b90cf4Smrg		xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
226924b90cf4Smrg		struct drmmode_scanout black_scanout = { .pixmap = NULL, .bo = NULL };
227024b90cf4Smrg		xf86CrtcPtr crtc;
227124b90cf4Smrg		drmmode_crtc_private_ptr drmmode_crtc;
227224b90cf4Smrg		unsigned w = 0, h = 0;
227324b90cf4Smrg		int i;
227424b90cf4Smrg
227524b90cf4Smrg		/* Compute maximum scanout dimensions of active CRTCs */
227624b90cf4Smrg		for (i = 0; i < xf86_config->num_crtc; i++) {
227724b90cf4Smrg			crtc = xf86_config->crtc[i];
227824b90cf4Smrg			drmmode_crtc = crtc->driver_private;
227924b90cf4Smrg
228024b90cf4Smrg			if (!drmmode_crtc->fb)
228124b90cf4Smrg				continue;
228224b90cf4Smrg
228324b90cf4Smrg			w = max(w, crtc->mode.HDisplay);
228424b90cf4Smrg			h = max(h, crtc->mode.VDisplay);
228524b90cf4Smrg		}
2286d6c0b56eSmrg
228724b90cf4Smrg		/* Make all active CRTCs scan out from an all-black framebuffer */
228824b90cf4Smrg		if (w > 0 && h > 0) {
228924b90cf4Smrg			if (drmmode_crtc_scanout_create(crtc, &black_scanout, w, h)) {
229024b90cf4Smrg				struct drmmode_fb *black_fb =
229124b90cf4Smrg					amdgpu_pixmap_get_fb(black_scanout.pixmap);
229224b90cf4Smrg
229324b90cf4Smrg				amdgpu_pixmap_clear(black_scanout.pixmap);
229424b90cf4Smrg				amdgpu_glamor_finish(pScrn);
229524b90cf4Smrg
229624b90cf4Smrg				for (i = 0; i < xf86_config->num_crtc; i++) {
229724b90cf4Smrg					crtc = xf86_config->crtc[i];
229824b90cf4Smrg					drmmode_crtc = crtc->driver_private;
229924b90cf4Smrg
230024b90cf4Smrg					if (drmmode_crtc->fb) {
230124b90cf4Smrg						if (black_fb) {
230224b90cf4Smrg							drmmode_set_mode(crtc, black_fb, &crtc->mode, 0, 0);
230324b90cf4Smrg						} else {
230424b90cf4Smrg							drmModeSetCrtc(pAMDGPUEnt->fd,
230524b90cf4Smrg								       drmmode_crtc->mode_crtc->crtc_id, 0,
230624b90cf4Smrg								       0, 0, NULL, 0, NULL);
230724b90cf4Smrg							drmmode_fb_reference(pAMDGPUEnt->fd,
230824b90cf4Smrg									     &drmmode_crtc->fb, NULL);
230924b90cf4Smrg						}
231024b90cf4Smrg
231124b90cf4Smrg						if (pScrn->is_gpu) {
231224b90cf4Smrg							if (drmmode_crtc->scanout[0].pixmap)
231324b90cf4Smrg								pixmap_unref_fb(drmmode_crtc->scanout[0].pixmap,
231424b90cf4Smrg										None, pAMDGPUEnt);
231524b90cf4Smrg							if (drmmode_crtc->scanout[1].pixmap)
231624b90cf4Smrg								pixmap_unref_fb(drmmode_crtc->scanout[1].pixmap,
231724b90cf4Smrg										None, pAMDGPUEnt);
231824b90cf4Smrg						} else {
231990f2b693Smrg							drmmode_crtc_scanout_free(crtc);
232024b90cf4Smrg						}
232124b90cf4Smrg					}
232224b90cf4Smrg				}
232324b90cf4Smrg			}
232424b90cf4Smrg		}
232524b90cf4Smrg
232624b90cf4Smrg		xf86RotateFreeShadow(pScrn);
232724b90cf4Smrg		drmmode_crtc_scanout_destroy(&info->drmmode, &black_scanout);
232824b90cf4Smrg
232924b90cf4Smrg		/* Unreference FBs of all pixmaps. After this, the only FB remaining
233024b90cf4Smrg		 * should be the all-black one being scanned out by active CRTCs
233124b90cf4Smrg		 */
233224b90cf4Smrg		for (i = 0; i < currentMaxClients; i++) {
233324b90cf4Smrg			if (i > 0 &&
233424b90cf4Smrg			    (!clients[i] || clients[i]->clientState != ClientStateRunning))
233524b90cf4Smrg				continue;
233624b90cf4Smrg
233724b90cf4Smrg			FindClientResourcesByType(clients[i], RT_PIXMAP, pixmap_unref_fb,
233824b90cf4Smrg						  pAMDGPUEnt);
233924b90cf4Smrg		}
234024b90cf4Smrg
234124b90cf4Smrg		pixmap_unref_fb(pScreen->GetScreenPixmap(pScreen), None, pAMDGPUEnt);
234224b90cf4Smrg	} else {
234324b90cf4Smrg		memset(info->front_buffer->cpu_ptr, 0, pScrn->virtualX *
234424b90cf4Smrg		       info->pixel_bytes * pScrn->virtualY);
234524b90cf4Smrg	}
234624b90cf4Smrg
234724b90cf4Smrg	TimerSet(NULL, 0, 1000, cleanup_black_fb, pScreen);
2348d6c0b56eSmrg
2349d6c0b56eSmrg	xf86_hide_cursors(pScrn);
2350d6c0b56eSmrg
235124b90cf4Smrg	amdgpu_drop_drm_master(pScrn);
235224b90cf4Smrg
2353d6c0b56eSmrg	xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, AMDGPU_LOGLEVEL_DEBUG,
2354d6c0b56eSmrg		       "Ok, leaving now...\n");
2355d6c0b56eSmrg}
2356d6c0b56eSmrg
235724b90cf4SmrgBool AMDGPUSwitchMode_KMS(ScrnInfoPtr pScrn, DisplayModePtr mode)
2358d6c0b56eSmrg{
2359d6c0b56eSmrg	Bool ret;
2360d6c0b56eSmrg	ret = xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
2361d6c0b56eSmrg	return ret;
2362d6c0b56eSmrg
2363d6c0b56eSmrg}
2364d6c0b56eSmrg
236524b90cf4Smrgvoid AMDGPUAdjustFrame_KMS(ScrnInfoPtr pScrn, int x, int y)
2366d6c0b56eSmrg{
2367d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2368d6c0b56eSmrg	drmmode_adjust_frame(pScrn, &info->drmmode, x, y);
2369d6c0b56eSmrg	return;
2370d6c0b56eSmrg}
2371d6c0b56eSmrg
2372d6c0b56eSmrgstatic Bool amdgpu_setup_kernel_mem(ScreenPtr pScreen)
2373d6c0b56eSmrg{
2374d6c0b56eSmrg	ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
237590f2b693Smrg	AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn);
2376d6c0b56eSmrg	AMDGPUInfoPtr info = AMDGPUPTR(pScrn);
2377d6c0b56eSmrg	xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2378d6c0b56eSmrg	int cpp = info->pixel_bytes;
2379d6c0b56eSmrg	int cursor_size;
238090f2b693Smrg	int c, i;
2381d6c0b56eSmrg
2382d6c0b56eSmrg	cursor_size = info->cursor_w * info->cursor_h * 4;
2383d6c0b56eSmrg	cursor_size = AMDGPU_ALIGN(cursor_size, AMDGPU_GPU_PAGE_SIZE);
2384d6c0b56eSmrg	for (c = 0; c < xf86_config->num_crtc; c++) {
238590f2b693Smrg		drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[c]->driver_private;
238690f2b693Smrg
238790f2b693Smrg		for (i = 0; i < 2; i++) {
238890f2b693Smrg			if (!drmmode_crtc->cursor_buffer[i]) {
238990f2b693Smrg				drmmode_crtc->cursor_buffer[i] =
239090f2b693Smrg					amdgpu_bo_open(pAMDGPUEnt->pDev,
239190f2b693Smrg						       cursor_size, 0,
239290f2b693Smrg						       AMDGPU_GEM_DOMAIN_VRAM);
239390f2b693Smrg
239490f2b693Smrg				if (!(drmmode_crtc->cursor_buffer[i])) {
2395d6c0b56eSmrg					ErrorF("Failed to allocate cursor buffer memory\n");
2396d6c0b56eSmrg					return FALSE;
2397d6c0b56eSmrg				}
2398d6c0b56eSmrg
239990f2b693Smrg				if (amdgpu_bo_cpu_map(drmmode_crtc->cursor_buffer[i]->bo.amdgpu,
240090f2b693Smrg						      &drmmode_crtc->cursor_buffer[i]->cpu_ptr))
2401d6c0b56eSmrg					ErrorF("Failed to map cursor buffer memory\n");
2402d6c0b56eSmrg			}
2403d6c0b56eSmrg		}
2404d6c0b56eSmrg	}
2405d6c0b56eSmrg
240635d5b7c7Smrg	if (!info->front_buffer) {
2407d6c0b56eSmrg		int pitch;
2408d6c0b56eSmrg		int hint = 0;
2409d6c0b56eSmrg
2410d6c0b56eSmrg		if (info->shadow_primary)
2411d6c0b56eSmrg			hint = AMDGPU_CREATE_PIXMAP_LINEAR | AMDGPU_CREATE_PIXMAP_GTT;
2412d6c0b56eSmrg		else if (!info->use_glamor)
2413d6c0b56eSmrg			hint = AMDGPU_CREATE_PIXMAP_LINEAR;
2414d6c0b56eSmrg
2415d6c0b56eSmrg		info->front_buffer =
2416d6c0b56eSmrg			amdgpu_alloc_pixmap_bo(pScrn, pScrn->virtualX,
2417d6c0b56eSmrg					       pScrn->virtualY, pScrn->depth,
2418d6c0b56eSmrg					       hint, pScrn->bitsPerPixel,
2419d6c0b56eSmrg					       &pitch);
2420d6c0b56eSmrg		if (!(info->front_buffer)) {
2421d6c0b56eSmrg			ErrorF("Failed to allocate front buffer memory\n");
2422d6c0b56eSmrg			return FALSE;
2423d6c0b56eSmrg		}
2424d6c0b56eSmrg
2425d6c0b56eSmrg		if (!info->use_glamor &&
2426d6c0b56eSmrg		    amdgpu_bo_map(pScrn, info->front_buffer) != 0) {
2427d6c0b56eSmrg			ErrorF("Failed to map front buffer memory\n");
2428d6c0b56eSmrg			return FALSE;
2429d6c0b56eSmrg		}
2430d6c0b56eSmrg
2431d6c0b56eSmrg		pScrn->displayWidth = pitch / cpp;
2432d6c0b56eSmrg	}
2433d6c0b56eSmrg
2434d6c0b56eSmrg	xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Front buffer pitch: %d bytes\n",
2435d6c0b56eSmrg		   pScrn->displayWidth * cpp);
2436d6c0b56eSmrg	return TRUE;
2437d6c0b56eSmrg}
2438d6c0b56eSmrg
2439d6c0b56eSmrg/* Used to disallow modes that are not supported by the hardware */
244024b90cf4SmrgModeStatus AMDGPUValidMode(ScrnInfoPtr pScrn, DisplayModePtr mode,
2441d6c0b56eSmrg			   Bool verbose, int flag)
2442d6c0b56eSmrg{
2443d6c0b56eSmrg	/* There are problems with double scan mode at high clocks
2444d6c0b56eSmrg	 * They're likely related PLL and display buffer settings.
2445d6c0b56eSmrg	 * Disable these modes for now.
2446d6c0b56eSmrg	 */
2447d6c0b56eSmrg	if (mode->Flags & V_DBLSCAN) {
2448d6c0b56eSmrg		if ((mode->CrtcHDisplay >= 1024) || (mode->CrtcVDisplay >= 768))
2449d6c0b56eSmrg			return MODE_CLOCK_RANGE;
2450d6c0b56eSmrg	}
2451d6c0b56eSmrg	return MODE_OK;
2452d6c0b56eSmrg}
2453